82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import re
|
|
import json
|
|
from collections import defaultdict
|
|
|
|
ROOT = os.path.join(os.path.dirname(__file__), "..", "app", "src", "main", "assets", "story")
|
|
ROOT = os.path.abspath(ROOT)
|
|
|
|
NODE_DEF_RE = re.compile(r"^@node\s+([A-Za-z0-9_]+)")
|
|
TARGET_RE = re.compile(r"->\s*([A-Za-z0-9_]+)\b")
|
|
|
|
def scan():
|
|
node_defs = {}
|
|
refs = []
|
|
for dirpath, _, filenames in os.walk(ROOT):
|
|
for fn in filenames:
|
|
if not fn.endswith('.story'):
|
|
continue
|
|
path = os.path.join(dirpath, fn)
|
|
try:
|
|
with open(path, 'r', encoding='utf-8') as f:
|
|
for ln, raw in enumerate(f, 1):
|
|
line = raw.strip()
|
|
m = NODE_DEF_RE.match(line)
|
|
if m:
|
|
node_defs[m.group(1)] = path
|
|
for rm in TARGET_RE.finditer(line):
|
|
refs.append((rm.group(1), path, ln))
|
|
except Exception as e:
|
|
print(f"! failed to read {path}: {e}")
|
|
invalid = defaultdict(list)
|
|
for target, path, ln in refs:
|
|
if target not in node_defs:
|
|
invalid[target].append({"file": path, "line": ln})
|
|
return node_defs, refs, invalid
|
|
|
|
def module_hint(file_path: str) -> str:
|
|
base = os.path.basename(file_path)
|
|
name, _ = os.path.splitext(base)
|
|
return name
|
|
|
|
def main():
|
|
node_defs, refs, invalid = scan()
|
|
items = []
|
|
for t in sorted(invalid.keys()):
|
|
locs = invalid[t]
|
|
modules = sorted({module_hint(l['file']) for l in locs})
|
|
items.append({
|
|
"node": t,
|
|
"modules": modules,
|
|
"references": locs,
|
|
"ref_count": len(locs)
|
|
})
|
|
|
|
report = {
|
|
"story_root": ROOT,
|
|
"defined_nodes": len(node_defs),
|
|
"total_refs": len(refs),
|
|
"invalid_count": len(items),
|
|
"items": items,
|
|
}
|
|
|
|
# Print a human-readable summary followed by JSON
|
|
print("=== Invalid (referenced but undefined) nodes ===")
|
|
if not items:
|
|
print("None")
|
|
else:
|
|
for it in items:
|
|
mods = ",".join(it["modules"]) or "unknown"
|
|
print(f"- {it['node']} [modules: {mods}] refs: {it['ref_count']}")
|
|
for r in it["references"]:
|
|
file_rel = os.path.relpath(r["file"], os.path.dirname(ROOT))
|
|
print(f" · {file_rel}:{r['line']}")
|
|
print("\n--- JSON ---")
|
|
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|