///|
/// Produce deterministic patches. Arrays are replaced as a whole in v0.1.
pub fn diff(old : Json, new : Json) -> Array[Operation] raise ConfigError {
validate_document(old)
validate_document(new)
let out : Array[Operation] = []
diff_at(old, new, "", out)
// Keep generated patches usable by apply's operation limit.
if out.length() > 10000 {
[Replace("", clone_json(new))]
} else {
out
}
}
///|
fn diff_at(
old : Json,
new : Json,
path : String,
out : Array[Operation],
) -> Unit {
if same(old, new) {
return
}
match (old, new) {
(Object(a), Object(b)) =>
for key in keys_union(a, b) {
let child_path = append_path(path, key)
match (a.get(key), b.get(key)) {
(Some(x), Some(y)) => diff_at(x, y, child_path, out)
(Some(_), None) => out.push(Remove(child_path))
(None, Some(y)) => out.push(Add(child_path, clone_json(y)))
_ => ()
}
}
_ => out.push(Replace(path, clone_json(new)))
}
}