use toml_edit::{DocumentMut, Item, Table};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct MergeReport {
pub added: Vec<String>,
}
impl MergeReport {
pub fn is_empty(&self) -> bool {
self.added.is_empty()
}
}
pub fn merge_additive(local: &str, upstream: &str) -> Result<(String, MergeReport), String> {
let mut local_doc: DocumentMut = local
.parse()
.map_err(|e| format!("local file is not valid TOML: {e}"))?;
let upstream_doc: DocumentMut = upstream
.parse()
.map_err(|e| format!("upstream template is not valid TOML: {e}"))?;
let mut report = MergeReport::default();
merge_table(
local_doc.as_table_mut(),
upstream_doc.as_table(),
"",
&mut report,
);
Ok((local_doc.to_string(), report))
}
fn merge_table(loc: &mut Table, up: &Table, prefix: &str, report: &mut MergeReport) {
for (key, up_item) in up.iter() {
let path = if prefix.is_empty() {
key.to_string()
} else {
format!("{prefix}.{key}")
};
match loc.get_mut(key) {
Some(Item::Table(loc_sub)) => {
if let Item::Table(up_sub) = up_item {
merge_table(loc_sub, up_sub, &path, report);
}
}
Some(_) => {}
None => {
loc.insert(key, up_item.clone());
report.added.push(path);
}
}
}
}