#!/usr/bin/env python3 from __future__ import annotations import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] DOCS = ROOT / "docs" ID_FILES = { "SysRS": DOCS / "requirements" / "sysrs.md", "SysDes": DOCS / "architecture" / "sysdes.md", "SRS": DOCS / "requirements" / "srs.md", "SAD": DOCS / "architecture" / "sad.md", "SDD": DOCS / "architecture" / "sdd.md", } def read(path: Path) -> str: if not path.exists(): return "" return path.read_text(encoding="utf-8") def defined_ids(prefix: str, text: str) -> set[str]: return set(re.findall(rf"\*\*({prefix}-\d{{3}})\*\*:", text)) def all_refs(prefix: str, text: str) -> set[str]: return set(re.findall(rf"{prefix}-\d{{3}}", text)) def main() -> int: if not DOCS.exists(): print("docs/ does not exist; skipping documentation validation.") return 0 all_text = "\n".join(p.read_text(encoding="utf-8") for p in DOCS.rglob("*.md")) defined = { prefix: defined_ids(prefix, read(path)) for prefix, path in ID_FILES.items() } failed = False for prefix, ids in defined.items(): refs = all_refs(prefix, all_text) undefined = sorted(refs - ids) if undefined: failed = True print(f"[FAIL] Undefined {prefix} references: {', '.join(undefined)}") else: print(f"[OK] {prefix}: {len(ids)} defined, 0 undefined references") srs = read(DOCS / "requirements" / "srs.md") sad = read(DOCS / "architecture" / "sad.md") sdd = read(DOCS / "architecture" / "sdd.md") checks = [ ("SRS direct SysRS references", re.findall(r"SysRS-\d{3}", srs)), ("SAD direct SysRS references", re.findall(r"SysRS-\d{3}", sad)), ("SAD direct SysDes references", re.findall(r"SysDes-\d{3}", sad)), ("SDD direct SysRS references", re.findall(r"SysRS-\d{3}", sdd)), ("SDD direct SysDes references", re.findall(r"SysDes-\d{3}", sdd)), ("SDD direct SRS references", re.findall(r"SRS-\d{3}", sdd)), ] for name, matches in checks: if matches: failed = True print(f"[FAIL] {name}: {len(matches)}") else: print(f"[OK] {name}: 0") old_names = re.findall(r"CHANORA_[A-Za-z0-9_]+_v\d+\.\d+(?:\.\d+)?\.md", all_text) if old_names: failed = True print(f"[FAIL] Old package-style filenames found: {len(set(old_names))}") else: print("[OK] No old package-style filenames found") cjk = re.findall(r"[\u4e00-\u9fff]", all_text) if cjk: failed = True print(f"[FAIL] CJK characters found: {len(cjk)}") else: print("[OK] English-only CJK check passed") return 1 if failed else 0 if __name__ == "__main__": sys.exit(main())