#!/usr/bin/env python3 """Find every JSON field across public/resources that holds a unit/building id reference.""" from __future__ import annotations import json, glob, collections, sys from pathlib import Path REPO = Path(__file__).resolve().parents[1] def load_known_ids() -> set[str]: ids: set[str] = set() for sub in ("units", "buildings", "improvements", "items", "techs"): for fp in (REPO / "public" / "resources" / sub).glob("*.json"): if fp.name.endswith(".schema.json"): continue try: d = json.loads(fp.read_text()) except Exception: continue items = d if isinstance(d, list) else [d] for it in items: if isinstance(it, dict) and isinstance(it.get("id"), str): ids.add(it["id"]) return ids def main() -> int: known_ids = load_known_ids() print(f"loaded {len(known_ids)} ids from units/buildings/improvements/items/techs") field_count: collections.Counter[str] = collections.Counter() by_field_examples: dict[str, set[str]] = collections.defaultdict(set) for fp in sorted(glob.glob(str(REPO / "public" / "**" / "*.json"), recursive=True)): if fp.endswith(".schema.json"): continue try: data = json.loads(Path(fp).read_text()) except Exception: continue rel = Path(fp).relative_to(REPO).as_posix() # Skip the resource files themselves to focus on cross-refs if rel.startswith("public/resources/units/") or rel.startswith("public/resources/buildings/"): continue def walk(o): if isinstance(o, dict): for k, v in o.items(): if isinstance(v, str) and v in known_ids: field_count[k] += 1 if len(by_field_examples[k]) < 3: by_field_examples[k].add(v) elif isinstance(v, list): for x in v: if isinstance(x, str) and x in known_ids: field_count[f"{k}[]"] += 1 if len(by_field_examples[f"{k}[]"]) < 3: by_field_examples[f"{k}[]"].add(x) else: walk(x) elif isinstance(v, dict): walk(v) walk(data) print("\n=== id-bearing fields (top 30, across non-units/buildings JSON) ===") for field, n in field_count.most_common(30): examples = ", ".join(sorted(by_field_examples[field])[:3]) print(f" {n:5d} {field:32s} e.g. {examples}") return 0 if __name__ == "__main__": sys.exit(main())