72 lines
2.5 KiB
Python
72 lines
2.5 KiB
Python
# YAML/JSON 差异对比工具
|
|
|
|
import yaml
|
|
|
|
|
|
def compute_diff(doc_a: dict | str, doc_b: dict | str) -> dict:
|
|
"""Compute diff between two dicts or YAML strings."""
|
|
if isinstance(doc_a, str):
|
|
try:
|
|
doc_a = yaml.safe_load(doc_a) or {}
|
|
except yaml.YAMLError:
|
|
doc_a = {}
|
|
if isinstance(doc_b, str):
|
|
try:
|
|
doc_b = yaml.safe_load(doc_b) or {}
|
|
except yaml.YAMLError:
|
|
doc_b = {}
|
|
|
|
added, removed, modified = _recursive_diff(doc_a, doc_b, "")
|
|
return {
|
|
"added": added,
|
|
"removed": removed,
|
|
"modified": modified,
|
|
}
|
|
|
|
|
|
def _recursive_diff(a: dict | list, b: dict | list, path: str) -> tuple[list, list, list]:
|
|
added, removed, modified = [], [], []
|
|
|
|
if isinstance(a, dict) and isinstance(b, dict):
|
|
all_keys = set(a.keys()) | set(b.keys())
|
|
for key in sorted(all_keys):
|
|
new_path = f"{path}.{key}" if path else key
|
|
if key not in a:
|
|
added.append({"path": new_path, "value": b[key]})
|
|
elif key not in b:
|
|
removed.append({"path": new_path, "value": a[key]})
|
|
elif a[key] != b[key]:
|
|
if isinstance(a[key], (dict, list)) and isinstance(b[key], (dict, list)):
|
|
a_sub, r_sub, m_sub = _recursive_diff(a[key], b[key], new_path)
|
|
added.extend(a_sub)
|
|
removed.extend(r_sub)
|
|
modified.extend(m_sub)
|
|
else:
|
|
modified.append({
|
|
"path": new_path,
|
|
"old_value": a[key],
|
|
"new_value": b[key],
|
|
})
|
|
|
|
elif isinstance(a, list) and isinstance(b, list):
|
|
for i in range(max(len(a), len(b))):
|
|
new_path = f"{path}[{i}]"
|
|
if i >= len(a):
|
|
added.append({"path": new_path, "value": b[i]})
|
|
elif i >= len(b):
|
|
removed.append({"path": new_path, "value": a[i]})
|
|
elif a[i] != b[i]:
|
|
if isinstance(a[i], (dict, list)) and isinstance(b[i], (dict, list)):
|
|
a_sub, r_sub, m_sub = _recursive_diff(a[i], b[i], new_path)
|
|
added.extend(a_sub)
|
|
removed.extend(r_sub)
|
|
modified.extend(m_sub)
|
|
else:
|
|
modified.append({
|
|
"path": new_path,
|
|
"old_value": a[i],
|
|
"new_value": b[i],
|
|
})
|
|
|
|
return added, removed, modified
|