#!/usr/bin/env python3 """ Batch convert legacy [DEF:...] / [/DEF:...] annotations to #region/#endregion format. Handles Python, JS, and Svelte files. Removes [SECTION:...] / [/SECTION] markers. """ from pathlib import Path import re ROOT = Path(__file__).resolve().parent.parent def process_file(filepath: Path) -> int: """Process a single file. Returns number of DEF blocks converted.""" with open(filepath, encoding='utf-8') as f: text = f.read() lines = text.split('\n') result = [] blocks_converted = 0 i = 0 n = len(lines) while i < n: line = lines[i] stripped = line.rstrip() # Extract leading whitespace for indentation preservation indent = re.match(r'^(\s*)', line).group(1) # Check for [/DEF:Name] or [/DEF:Name:Type] m = re.match(r'^\s*(#|//)\s*\[/DEF:(\w+(?:\.\w+)*)(?::\w+)?\]\s*$', stripped) if m: name = m.group(2) result.append(f'{indent}# #endregion {name}') blocks_converted += 1 i += 1 continue # Check for [DEF:Name:Type] m = re.match(r'^\s*(#|//)\s*\[DEF:(\w+(?:\.\w+)*):(\w+)\]\s*$', stripped) if m: name = m.group(2) typ = m.group(3) result.append(f'{indent}# #region {name} [C:2] [TYPE {typ}]') blocks_converted += 1 i += 1 continue # Skip [SECTION: ...] and [/SECTION] lines entirely if re.match(r'^\s*(#|//)\s*\[SECTION:', stripped) or re.match(r'^\s*(#|//)\s*\[/SECTION\]', stripped): i += 1 continue # Fix @RELATION BELONGS_TO -> @RELATION BINDS_TO (not handled by earlier passes) if re.match(r'^\s*(#|//)\s*@RELATION\s+BELONGS_TO\b', stripped): line = re.sub(r'(@RELATION\s+)BELONGS_TO\b', r'\1BINDS_TO', line) # Fix @RELATION CONTAINS -> @RELATION DEPENDS_ON (not handled by earlier passes) if re.match(r'^\s*(#|//)\s*@RELATION\s+CONTAINS\b', stripped): line = re.sub(r'(@RELATION\s+)CONTAINS\b', r'\1DEPENDS_ON', line) # Pass through everything else result.append(line) i += 1 new_text = '\n'.join(result) if new_text == text: return 0 with open(filepath, 'w', encoding='utf-8') as f: f.write(new_text) return blocks_converted def main(): total_blocks = 0 total_files = 0 # Process all test files and other files with DEF contracts patterns = [ 'backend/tests/**/*.py', 'frontend/src/**/__tests__/*.js', 'frontend/src/**/*.test.js', 'merge_spec.py', ] for pattern in patterns: for filepath in sorted(ROOT.glob(pattern)): if '.venv' in str(filepath) or '__pycache__' in str(filepath): continue try: blocks = process_file(filepath) if blocks > 0: total_files += 1 total_blocks += blocks rel = filepath.relative_to(ROOT) print(f" {rel}: {blocks} blocks converted") except Exception as e: print(f" ERROR {filepath}: {e}") print(f"\nTotal: {total_files} files, {total_blocks} DEF blocks converted") if __name__ == "__main__": main()