#!/usr/bin/env python3 """ Regenerate manifest.json for LinkML schema frontend. This script scans the LinkML schema directory and generates a complete manifest of all class, enum, and slot files for the frontend to load. The manifest structure matches what the frontend LinkMLSchemaService expects: - schemaRoot: Base path for schema files - totalFiles: Total count of all files - categoryCounts: Per-category file counts - categories: Array of category objects with files """ import json from datetime import datetime, timezone from pathlib import Path # Schema paths SCHEMA_DIR = Path(__file__).parent.parent / "schemas" / "20251121" / "linkml" CLASSES_DIR = SCHEMA_DIR / "modules" / "classes" ENUMS_DIR = SCHEMA_DIR / "modules" / "enums" SLOTS_DIR = SCHEMA_DIR / "modules" / "slots" / "20260202_matang" MANIFEST_PATH = SCHEMA_DIR / "manifest.json" def get_yaml_files(directory: Path) -> list[str]: """Get all .yaml files in a directory, sorted alphabetically.""" if not directory.exists(): return [] return sorted([f.stem for f in directory.glob("*.yaml")]) def get_main_yaml_files(directory: Path) -> list[str]: """Get top-level .yaml files in schema directory.""" if not directory.exists(): return [] return sorted([f.stem for f in directory.glob("*.yaml") if f.is_file()]) def main(): # Get all main schema files (top-level .yaml files) main_files = get_main_yaml_files(SCHEMA_DIR) print(f"Found {len(main_files)} main schema files") # Get all class files class_files = get_yaml_files(CLASSES_DIR) print(f"Found {len(class_files)} class files") # Get all enum files enum_files = get_yaml_files(ENUMS_DIR) print(f"Found {len(enum_files)} enum files") # Get all slot files slot_files = get_yaml_files(SLOTS_DIR) print(f"Found {len(slot_files)} slot files") # Calculate totals total_files = len(main_files) + len(class_files) + len(enum_files) + len(slot_files) # Build manifest structure matching frontend expectations manifest = { "generated": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z", "schemaRoot": "/schemas/20251121/linkml", "totalFiles": total_files, "categoryCounts": { "main": len(main_files), "class": len(class_files), "enum": len(enum_files), "slot": len(slot_files), "module": 4 # Fixed count for module imports }, "categories": [ { "name": "main", "displayName": "Main Schemas", "files": [ { "name": name, "path": f"{name}.yaml", "category": "main" } for name in main_files ] }, { "name": "class", "displayName": "Classes", "files": [ { "name": name, "path": f"modules/classes/{name}.yaml", "category": "class" } for name in class_files ] }, { "name": "enum", "displayName": "Enumerations", "files": [ { "name": name, "path": f"modules/enums/{name}.yaml", "category": "enum" } for name in enum_files ] }, { "name": "slot", "displayName": "Slots", "files": [ { "name": name, "path": f"modules/slots/20260202_matang/{name}.yaml", "category": "slot" } for name in slot_files ] } ] } # Write manifest with open(MANIFEST_PATH, 'w', encoding='utf-8') as f: json.dump(manifest, f, indent=2) print(f"\n✅ Manifest written to {MANIFEST_PATH}") print(f" - Main schemas: {len(main_files)} files") print(f" - Classes: {len(class_files)} files") print(f" - Enums: {len(enum_files)} files") print(f" - Slots: {len(slot_files)} files") print(f" - Total: {total_files} files") if __name__ == "__main__": main()