Spaces:
Running
Running
| """scripts/validate_design_tokens.py — T010 / SC-006 token validator. | |
| Pure-Python (no Node/npm linter). Confirms that: | |
| 1. every CSS custom property defined in the app's injected ``:root`` block | |
| resolves to a real DESIGN.md token with a matching value, and | |
| 2. every ``var(--token)`` referenced anywhere in ``app/app.py`` is defined in | |
| that ``:root`` block (no undefined / dangling tokens). | |
| Exit code 0 = all tokens resolve; 1 = at least one mismatch or dangling var. | |
| Usage:: | |
| python scripts/validate_design_tokens.py | |
| """ | |
| from __future__ import annotations | |
| import re | |
| import sys | |
| from pathlib import Path | |
| REPO_ROOT = Path(__file__).resolve().parent.parent | |
| sys.path.insert(0, str(REPO_ROOT)) | |
| from app.design_tokens import load_tokens, root_css # noqa: E402 | |
| # Every Python module that injects CSS using var(--token) references. | |
| CSS_SOURCES = [ | |
| REPO_ROOT / "app" / "app.py", | |
| REPO_ROOT / "app" / "phases" / "intake.py", | |
| REPO_ROOT / "app" / "phases" / "interview.py", | |
| REPO_ROOT / "app" / "phases" / "assessment.py", | |
| REPO_ROOT / "app" / "phases" / "recommendations.py", | |
| REPO_ROOT / "app" / "phases" / "documents.py", | |
| ] | |
| _ROOT_DEF_RE = re.compile(r"--([a-z0-9-]+):\s*([^;]+);") | |
| _VAR_USE_RE = re.compile(r"var\(\s*--([a-z0-9-]+)\s*\)") | |
| def main() -> int: | |
| design_tokens = load_tokens() | |
| root_block = root_css() | |
| # 1. Parse the :root definitions the app actually injects. | |
| root_defs = {name: value.strip() for name, value in _ROOT_DEF_RE.findall(root_block)} | |
| errors: list[str] = [] | |
| # Every :root definition must match a DESIGN.md token value exactly. | |
| for name, value in root_defs.items(): | |
| if name not in design_tokens: | |
| errors.append(f" :root defines --{name} but DESIGN.md has no such token") | |
| elif design_tokens[name] != value: | |
| errors.append( | |
| f" --{name}: app value {value!r} != DESIGN.md value {design_tokens[name]!r}" | |
| ) | |
| # Every var(--x) used in any CSS-bearing module must be defined in :root. | |
| used: set[str] = set() | |
| for src in CSS_SOURCES: | |
| for name in _VAR_USE_RE.findall(src.read_text(encoding="utf-8")): | |
| used.add(name) | |
| if name not in root_defs: | |
| errors.append( | |
| f" {src.relative_to(REPO_ROOT)} uses var(--{name}) not defined in :root" | |
| ) | |
| print(f"DESIGN.md tokens: {len(design_tokens)}") | |
| print(f":root definitions: {len(root_defs)}") | |
| print(f"var(--) refs (all CSS): {len(used)}") | |
| if errors: | |
| print("\nFAIL — token validation errors:") | |
| print("\n".join(errors)) | |
| return 1 | |
| print("\nPASS — every :root token resolves to DESIGN.md and every var(--) is defined.") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |