#!/usr/bin/env python3 """Validate generated/fragments/**/*.json against schemas/*.schema.json. .venv/bin/python scripts/validate_fragments.py # report (exit 1 on schema errors) .venv/bin/python scripts/validate_fragments.py --lenient # report only Kind → schema mapping is by directory name. Kinds without a schema are only checked for JSON validity and the presence of `provider`. """ from __future__ import annotations import argparse import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent SCHEMAS = ROOT / "schemas" FRAG = ROOT / "generated" / "fragments" KIND_TO_SCHEMA = {"models": "model", "endpoints": "endpoint", "parameters": "parameter", "tools": "tool", "streaming-events": "streaming-event", "errors": "error", "pricing": "price"} def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--lenient", action="store_true") args = ap.parse_args() try: import jsonschema from jsonschema import Draft202012Validator from referencing import Registry, Resource except ImportError: print("jsonschema not installed: .venv/bin/pip install jsonschema", file=sys.stderr) return 2 resources = [] for sf in SCHEMAS.glob("*.schema.json"): s = json.loads(sf.read_text()) resources.append((s["$id"], Resource.from_contents(s))) resources.append((sf.name, Resource.from_contents(s))) registry = Registry().with_resources(resources) errors = 0 records = 0 for kind_dir in sorted(p for p in FRAG.iterdir() if p.is_dir()) if FRAG.exists() else []: schema_name = KIND_TO_SCHEMA.get(kind_dir.name) validator = None if schema_name: schema = json.loads((SCHEMAS / f"{schema_name}.schema.json").read_text()) validator = Draft202012Validator(schema, registry=registry) for f in sorted(kind_dir.glob("*.json")): try: data = json.loads(f.read_text()) except Exception as e: # noqa: BLE001 print(f"INVALID JSON {f.relative_to(ROOT)}: {e}") errors += 1 continue if isinstance(data, dict): data = data.get("records") or data.get("items") or data.get("data") or [data] if not isinstance(data, list): print(f"NOT A LIST {f.relative_to(ROOT)}") errors += 1 continue for i, rec in enumerate(data): records += 1 if not isinstance(rec, dict) or "provider" not in rec: print(f"{f.relative_to(ROOT)}[{i}]: missing provider") errors += 1 continue if validator: for err in sorted(validator.iter_errors(rec), key=lambda e: e.path): loc = "/".join(str(p) for p in err.path) or "" print(f"{f.relative_to(ROOT)}[{i}] {loc}: {err.message[:160]}") errors += 1 print(f"records={records} errors={errors}") return 0 if (args.lenient or errors == 0) else 1 if __name__ == "__main__": sys.exit(main())