magicciv/tools/audit-id-refs.py

76 lines
2.8 KiB
Python
Raw Permalink Normal View History

#!/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())