76 lines
2.8 KiB
Python
76 lines
2.8 KiB
Python
|
|
#!/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())
|