#!/usr/bin/env python3 """Convert ./cvar_list (cvarlist dump) to static/data/srccfg-vocab.json. Usage: ./l4d2web/scripts/build-vocab.py Reads from the repo root (auto-detected via this script's path). Writes idempotently. Run after regenerating cvar_list.""" from __future__ import annotations import hashlib import json import pathlib import re import sys HERE = pathlib.Path(__file__).resolve().parent REPO_ROOT = HERE.parent.parent SOURCE = REPO_ROOT / "cvar_list" DEST = REPO_ROOT / "l4d2web" / "l4d2web" / "static" / "data" / "srccfg-vocab.json" def parse(text: str) -> tuple[list[dict], list[dict]]: cvars: list[dict] = [] commands: list[dict] = [] for raw in text.splitlines()[2:]: # skip "cvar list" + "--------…" if not raw.strip(): continue parts = [p.strip() for p in re.split(r"\s*:\s*", raw, maxsplit=3)] if len(parts) < 3: continue name = parts[0] value = parts[1] desc = parts[3] if len(parts) >= 4 else "" target = commands if value == "cmd" else cvars target.append({"name": name, "desc": desc} if desc else {"name": name}) return cvars, commands def main() -> int: if not SOURCE.exists(): print(f"ERROR: {SOURCE} not found", file=sys.stderr) return 1 text = SOURCE.read_text(encoding="utf-8", errors="replace") cvars, commands = parse(text) src_sha = hashlib.sha256(text.encode("utf-8")).hexdigest() payload = { "version": 1, "generated_from": "cvar_list", "source_sha256": src_sha, "cvars": cvars, "commands": commands, } DEST.parent.mkdir(parents=True, exist_ok=True) DEST.write_text(json.dumps(payload, indent=2, sort_keys=False) + "\n", encoding="utf-8") print(f"wrote {DEST}: {len(cvars)} cvars + {len(commands)} commands") return 0 if __name__ == "__main__": raise SystemExit(main())