Files
2026-05-25 15:09:42 +08:00

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