@@ -17,38 +17,85 @@ jobs:
1717 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
1818 - name : Check for TypeScript
1919 run : |
20- # Allowlist (TS legitimate as a bridge/adapter to a non-ReScript ecosystem):
21- # bindings/ - language bindings (Deno/TS/AssemblyScript FFI)
22- # *.d.ts - TypeScript type declarations for ReScript FFI
23- # tests/, test/ - Deno test runners
24- # scripts/ - Deno build scripts
25- # mcp-adapter/ - MCP server adapters (MCP is Deno/TS-typed by spec)
26- # *vscode* - VSCode extensions (TS is the ecosystem default)
27- # cli/ - CLI entry points (Deno scripts)
28- # mod.ts - canonical Deno module entrypoint
29- # *lsp-server.ts, *lsp.ts - Language Server Protocol implementations
30- # deno-*/ - subprojects explicitly named for Deno
31- TS_FILES=$(find . \( -name "*.ts" -o -name "*.tsx" \) \
32- | grep -v node_modules \
33- | grep -v '/bindings/' \
34- | grep -v '\.d\.ts$' \
35- | grep -v '/tests/' \
36- | grep -v '/test/' \
37- | grep -v '/scripts/' \
38- | grep -v '/mcp-adapter/' \
39- | grep -Ev '/[^/]*vscode[^/]*/' \
40- | grep -v '/cli/' \
41- | grep -v '/mod\.ts$' \
42- | grep -Ev 'lsp[-_]?server\.ts$' \
43- | grep -Ev '[/-]lsp\.ts$' \
44- | grep -Ev '/deno-[^/]+/' \
45- || true)
46- if [ -n "$TS_FILES" ]; then
47- echo "❌ TypeScript files detected - use ReScript instead"
48- echo "$TS_FILES"
49- exit 1
50- fi
51- echo "✅ No TypeScript files outside allowlisted bridge/adapter paths"
20+ python3 << 'PYEOF'
21+ import re, sys, fnmatch, pathlib
22+
23+ # Universal builtin allowlist — bridges that need no per-repo declaration.
24+ # Files matching any of these patterns are always allowed.
25+ BUILTIN_GLOBS = [
26+ '*.d.ts',
27+ '**/bindings/**',
28+ '**/tests/**', '**/test/**',
29+ '**/scripts/**',
30+ '**/mcp-adapter/**',
31+ '**/*vscode*/**',
32+ '**/cli/**',
33+ '**/mod.ts',
34+ '**/lsp-server.ts', '**/lsp_server.ts', '**/lsp.ts', '**/*-lsp.ts',
35+ '**/deno-*/**',
36+ '**/node_modules/**',
37+ '**/vendor/**',
38+ '**/examples/**',
39+ '**/ffi/**',
40+ ]
41+
42+ # Per-repo exemptions parsed from .claude/CLAUDE.md "TypeScript Exemptions" table.
43+ # Single source of truth — adding a row here unblocks CI for that path.
44+ # Format expected:
45+ # ### TypeScript Exemptions ...
46+ # | Path | Files | Rationale | Unblock condition |
47+ # |---|---|---|---|
48+ # | `path/to/file.ts` | 1 | ... | ... |
49+ # | `dir/*.ts` | 6 | ... | ... |
50+ exemptions = []
51+ claude_md = pathlib.Path('.claude/CLAUDE.md')
52+ if claude_md.exists():
53+ in_table = False
54+ for line in claude_md.read_text(encoding='utf-8').splitlines():
55+ if re.search(r'TypeScript [Ee]xemptions', line):
56+ in_table = True
57+ continue
58+ if in_table and line.startswith(('### ', '## ', '# ')):
59+ break
60+ if in_table and line.startswith('|'):
61+ m = re.match(r'\|\s*`([^`]+)`', line)
62+ if m:
63+ exemptions.append(m.group(1))
64+
65+ # Find all .ts and .tsx files
66+ found = []
67+ for ext in ('ts', 'tsx'):
68+ found.extend(str(p) for p in pathlib.Path('.').rglob(f'*.{ext}'))
69+
70+ def allowed(path):
71+ p = path.lstrip('./')
72+ for g in BUILTIN_GLOBS + exemptions:
73+ if fnmatch.fnmatchcase(p, g):
74+ return True
75+ # also treat glob ending with / as a directory prefix
76+ base = g.rstrip('/').rstrip('*').rstrip('/')
77+ if base and (p == base or p.startswith(base + '/')):
78+ return True
79+ return False
80+
81+ bad = sorted(f for f in found if not allowed(f))
82+ if bad:
83+ print("❌ TypeScript files detected outside the allowlist.\n")
84+ for f in bad:
85+ print(f" {f}")
86+ print()
87+ print("To resolve, either:")
88+ print(" (a) migrate the file to AffineScript")
89+ print(" (see Human_Programming_Guide.adoc migration chapter), OR")
90+ print(" (b) move it to an allowlisted bridge path")
91+ print(" (bindings/, tests/, scripts/, mcp-adapter/, *vscode*/, cli/, deno-*/, etc.), OR")
92+ print(" (c) add an entry to the 'TypeScript Exemptions' table in .claude/CLAUDE.md")
93+ print(" with rationale + unblock condition.")
94+ if exemptions:
95+ print(f"\n(Currently {len(exemptions)} exemption(s) parsed from .claude/CLAUDE.md.)")
96+ sys.exit(1)
97+ print(f"✅ No TypeScript files outside allowlist ({len(exemptions)} per-repo exemption(s) parsed).")
98+ PYEOF
5299 - name : Check for Go
53100 run : |
54101 if find . -name "*.go" | grep -q .; then
0 commit comments