From a7552036417e4bb643bd5f7d2993cf1bbd81498d Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Mon, 19 Jan 2026 11:05:00 +0000 Subject: [PATCH] feat: enhance snippet merging with diff patching support- replace _append_unique with _merge_snippet for better merging logic- add difflib for generating unified diff patches- create patch files in a new 'patches' directory if specified- ensure unique content is merged without duplicates --- scripts/component_migration_orchestrator.py | 59 +++++++++++++++++---- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/scripts/component_migration_orchestrator.py b/scripts/component_migration_orchestrator.py index 737faf4..b98a00f 100644 --- a/scripts/component_migration_orchestrator.py +++ b/scripts/component_migration_orchestrator.py @@ -14,6 +14,7 @@ import re import sys import textwrap import shutil +import difflib from concurrent.futures import ThreadPoolExecutor, as_completed from dataclasses import dataclass from pathlib import Path @@ -178,15 +179,39 @@ def _write_if_content(path: Path, content: str) -> None: path.write_text(content, encoding="utf-8") -def _append_unique(path: Path, content: str) -> None: +def _merge_snippet(path: Path, content: str, patches_dir: Optional[Path] = None) -> None: if not content.strip(): return path.parent.mkdir(parents=True, exist_ok=True) existing = path.read_text(encoding="utf-8") if path.exists() else "" - if content.strip() in existing: + existing_lines = existing.splitlines() + new_lines = content.strip().splitlines() + if not new_lines: return - separator = "\n" if existing.endswith("\n") or not existing else "\n\n" - path.write_text(existing + separator + content.strip() + "\n", encoding="utf-8") + matcher = difflib.SequenceMatcher(None, existing_lines, new_lines) + match = matcher.find_longest_match(0, len(existing_lines), 0, len(new_lines)) + if match.size == len(new_lines): + return + if match.a + match.size == len(existing_lines) and match.b == 0: + merged_lines = existing_lines + new_lines[match.size:] + else: + merged_lines = existing_lines + ([""] if existing_lines else []) + new_lines + merged_text = "\n".join(merged_lines).rstrip() + "\n" + if merged_text == existing: + return + path.write_text(merged_text, encoding="utf-8") + if patches_dir is not None: + rel_path = path.relative_to(patches_dir.parent) + patch_path = patches_dir / (str(rel_path) + ".patch") + patch_path.parent.mkdir(parents=True, exist_ok=True) + diff = difflib.unified_diff( + existing.splitlines(), + merged_text.splitlines(), + fromfile=str(rel_path), + tofile=str(rel_path), + lineterm="", + ) + patch_path.write_text("\n".join(diff) + "\n", encoding="utf-8") def write_output(out_dir: Path, data: Dict[str, Any], target: ComponentTarget) -> None: @@ -219,16 +244,32 @@ def write_output(out_dir: Path, data: Dict[str, Any], target: ComponentTarget) - ) _write_if_content(interface_path, interface.get("source", "")) + patches_dir = out_dir / "patches" + json_component_export = (data.get("jsonComponentExport") or {}).get("source", "") - _append_unique(out_dir / "src/lib/json-ui/json-components.ts", json_component_export) + _merge_snippet( + out_dir / "src/lib/json-ui/json-components.ts", + json_component_export, + patches_dir, + ) exports = data.get("exports") or {} - _append_unique(out_dir / "src/lib/json-ui/interfaces/index.ts", exports.get("interfacesIndex", "")) - _append_unique(out_dir / "src/hooks/index.ts", exports.get("hooksIndex", "") or "") - _append_unique(out_dir / "src/lib/json-ui/hooks-registry.ts", exports.get("hooksRegistry", "") or "") + _merge_snippet( + out_dir / "src/lib/json-ui/interfaces/index.ts", + exports.get("interfacesIndex", ""), + patches_dir, + ) + _merge_snippet( + out_dir / "src/hooks/index.ts", exports.get("hooksIndex", "") or "", patches_dir + ) + _merge_snippet( + out_dir / "src/lib/json-ui/hooks-registry.ts", + exports.get("hooksRegistry", "") or "", + patches_dir, + ) components_index_path = out_dir / "src/components" / target.category / "index.ts" - _append_unique(components_index_path, exports.get("componentsIndex", "")) + _merge_snippet(components_index_path, exports.get("componentsIndex", ""), patches_dir) def parse_args() -> argparse.Namespace: