|
5 | 5 | # Enforces: No TypeScript, No Go, No Python (except SaltStack), No npm |
6 | 6 | # Allows: ReScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme |
7 | 7 |
|
8 | | -permissions: read-all |
9 | | - |
10 | 8 | name: RSR Anti-Pattern Check |
11 | 9 |
|
12 | 10 | on: |
|
15 | 13 | pull_request: |
16 | 14 | branches: [main, master, develop] |
17 | 15 |
|
| 16 | + |
| 17 | +permissions: |
| 18 | + contents: read |
| 19 | + |
18 | 20 | jobs: |
19 | 21 | antipattern-check: |
20 | 22 | runs-on: ubuntu-latest |
| 23 | + permissions: |
| 24 | + contents: read |
21 | 25 | steps: |
22 | 26 | - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
23 | 27 |
|
@@ -134,83 +138,6 @@ jobs: |
134 | 138 | print(f"✅ No TypeScript files outside allowlist ({len(exemption_patterns)} per-repo exemption(s) parsed).") |
135 | 139 | PYEOF |
136 | 140 |
|
137 | | - # Universal builtin allowlist — bridges that need no per-repo declaration. |
138 | | - # Files matching any of these patterns are always allowed. |
139 | | - BUILTIN_GLOBS = [ |
140 | | - '*.d.ts', |
141 | | - '**/bindings/**', |
142 | | - '**/tests/**', '**/test/**', |
143 | | - '**/scripts/**', |
144 | | - '**/mcp-adapter/**', |
145 | | - '**/*vscode*/**', |
146 | | - '**/cli/**', |
147 | | - '**/mod.ts', |
148 | | - '**/lsp-server.ts', '**/lsp_server.ts', '**/lsp.ts', '**/*-lsp.ts', |
149 | | - '**/deno-*/**', |
150 | | - '**/node_modules/**', |
151 | | - '**/vendor/**', |
152 | | - '**/examples/**', |
153 | | - '**/ffi/**', |
154 | | - ] |
155 | | -
|
156 | | - # Per-repo exemptions parsed from .claude/CLAUDE.md "TypeScript Exemptions" table. |
157 | | - # Single source of truth — adding a row here unblocks CI for that path. |
158 | | - # Format expected: |
159 | | - # ### TypeScript Exemptions ... |
160 | | - # | Path | Files | Rationale | Unblock condition | |
161 | | - # |---|---|---|---| |
162 | | - # | `path/to/file.ts` | 1 | ... | ... | |
163 | | - # | `dir/*.ts` | 6 | ... | ... | |
164 | | - exemptions = [] |
165 | | - claude_md = pathlib.Path('.claude/CLAUDE.md') |
166 | | - if claude_md.exists(): |
167 | | - in_table = False |
168 | | - for line in claude_md.read_text(encoding='utf-8').splitlines(): |
169 | | - if re.search(r'TypeScript [Ee]xemptions', line): |
170 | | - in_table = True |
171 | | - continue |
172 | | - if in_table and line.startswith(('### ', '## ', '# ')): |
173 | | - break |
174 | | - if in_table and line.startswith('|'): |
175 | | - m = re.match(r'\|\s*`([^`]+)`', line) |
176 | | - if m: |
177 | | - exemptions.append(m.group(1)) |
178 | | -
|
179 | | - # Find all .ts and .tsx files |
180 | | - found = [] |
181 | | - for ext in ('ts', 'tsx'): |
182 | | - found.extend(str(p) for p in pathlib.Path('.').rglob(f'*.{ext}')) |
183 | | -
|
184 | | - def allowed(path): |
185 | | - p = path.lstrip('./') |
186 | | - for g in BUILTIN_GLOBS + exemptions: |
187 | | - if fnmatch.fnmatchcase(p, g): |
188 | | - return True |
189 | | - # also treat glob ending with / as a directory prefix |
190 | | - base = g.rstrip('/').rstrip('*').rstrip('/') |
191 | | - if base and (p == base or p.startswith(base + '/')): |
192 | | - return True |
193 | | - return False |
194 | | -
|
195 | | - bad = sorted(f for f in found if not allowed(f)) |
196 | | - if bad: |
197 | | - print("❌ TypeScript files detected outside the allowlist.\n") |
198 | | - for f in bad: |
199 | | - print(f" {f}") |
200 | | - print() |
201 | | - print("To resolve, either:") |
202 | | - print(" (a) migrate the file to AffineScript") |
203 | | - print(" (see Human_Programming_Guide.adoc migration chapter), OR") |
204 | | - print(" (b) move it to an allowlisted bridge path") |
205 | | - print(" (bindings/, tests/, scripts/, mcp-adapter/, *vscode*/, cli/, deno-*/, etc.), OR") |
206 | | - print(" (c) add an entry to the 'TypeScript Exemptions' table in .claude/CLAUDE.md") |
207 | | - print(" with rationale + unblock condition.") |
208 | | - if exemptions: |
209 | | - print(f"\n(Currently {len(exemptions)} exemption(s) parsed from .claude/CLAUDE.md.)") |
210 | | - sys.exit(1) |
211 | | - print(f"✅ No TypeScript files outside allowlist ({len(exemptions)} per-repo exemption(s) parsed).") |
212 | | - PYEOF |
213 | | -
|
214 | 141 | - name: Check for Go |
215 | 142 | run: | |
216 | 143 | if find . -name "*.go" | grep -q .; then |
|
0 commit comments