#!/usr/bin/env python3 from __future__ import annotations import argparse import json from pathlib import Path from typing import Any def load_entries(path: Path) -> list[dict[str, Any]]: report = json.loads(path.read_text(encoding="utf-8")) matrix = report.get("matrix") if isinstance(report.get("matrix"), dict) else report entries = matrix.get("entries") if isinstance(matrix.get("entries"), list) else [] return [entry for entry in entries if isinstance(entry, dict)] def target_map(entries: list[dict[str, Any]]) -> dict[tuple[str, str, str], dict[str, Any]]: result: dict[tuple[str, str, str], dict[str, Any]] = {} for entry in entries: target = entry.get("requested_target") if isinstance(entry.get("requested_target"), dict) else {} key = (str(target.get("section") or ""), str(target.get("name") or ""), str(target.get("id") or "")) if key == ("", "", "") or key in result: continue result[key] = {field: target.get(field) for field in ("section", "name", "id", "path", "marker", "type_name", "title")} return result def main() -> int: parser = argparse.ArgumentParser(description="Compare 1C write matrix reports for structural target moves.") parser.add_argument("--before", type=Path, required=True, help="Before write matrix report.") parser.add_argument("--after", type=Path, required=True, help="After write matrix report.") parser.add_argument("--output", type=Path, required=True, help="Output structural diff JSON path.") args = parser.parse_args() before_targets = target_map(load_entries(args.before)) after_targets = target_map(load_entries(args.after)) moves = [] for key, after in after_targets.items(): before = before_targets.get(key) if not before: continue if str(before.get("path") or "") == str(after.get("path") or ""): continue moves.append( { "target": { "section": after.get("section"), "name": after.get("name"), "id": after.get("id"), "marker": after.get("marker"), "type_name": after.get("type_name"), }, "old_path": before.get("path"), "new_path": after.get("path"), "presentation": f"{after.get('name') or after.get('path')}: {before.get('path')} -> {after.get('path')}", } ) result = { "schema": "onec_form_write_matrix_structural_diff.v1", "status": "changed" if moves else "no_changes", "before": str(args.before), "after": str(args.after), "target_moves": moves, "counts": { "target_moves": len(moves), "before_targets": len(before_targets), "after_targets": len(after_targets), }, } args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print(json.dumps({"schema": result["schema"], "status": result["status"], "counts": result["counts"], "path": str(args.output)}, ensure_ascii=False, indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())