use fhir_diff::{Node, Pool, load};
fn find<'a>(node: &'a Node, parts: &[&str]) -> Option<&'a Node> {
let Some((head, rest)) = parts.split_first() else {
return Some(node);
};
let (name, slice) = head
.split_once(':')
.map_or((*head, None), |(n, s)| (n, Some(s)));
let name = name.trim_end_matches("[x]");
let child = node.children.get(name)?;
let child = match slice {
Some(s) => child.slices.get(s)?,
None => child,
};
find(child, rest)
}
fn main() {
let spec = std::env::args().nth(1).expect("package");
let loaded = load(&spec).expect("load");
let pool = Pool::new(&loaded);
let (mut checked, mut differ) = (0, 0);
for profile in pool.profiles() {
let Some(definition) = loaded
.package
.definitions
.iter()
.find(|d| d.file == profile.file)
else {
continue;
};
for element in definition.json["snapshot"]["element"]
.as_array()
.into_iter()
.flatten()
{
let id = element["id"].as_str().unwrap_or_default();
let parts: Vec<&str> = id.split('.').skip(1).collect();
if parts.is_empty() || parts.iter().any(|p| p.contains("[x]:")) {
continue;
}
let Some(node) = find(&profile.tree, &parts) else {
continue;
};
checked += 1;
let min = element["min"].as_u64().unwrap_or(0) as u32;
let max = match element["max"].as_str() {
Some("*") => None,
Some(m) => m.parse().ok(),
None => None,
};
let ms = element["mustSupport"].as_bool().unwrap_or(false);
if node.min != min || node.max != max || node.must_support != ms {
differ += 1;
if differ <= 25 {
println!(
"{} {id}: tree {}..{:?} ms={} / snapshot {min}..{max:?} ms={ms}",
profile.name, node.min, node.max, node.must_support
);
}
}
}
}
println!("checked {checked} elements, {differ} differ");
}