feat(compiler): SYN011 — warn on dynamic import() calls that bypass the module capability model (?bs 0.7+)#156
Merged
Merged
Conversation
…he module capability model (?bs 0.7+) Integrates SYN011 into the single dispatch loop introduced in #155 (no extra per-body scan). Detection: `import` token (kind=ident) not preceded by `.`/`?.`, followed by `(` or `?.(`. Excluded: `import.meta` property accesses (followed by `.`), object method shorthands, `fn import(...)` declarations (checks `kind==='keyword'` for the preceding `fn` token). Suppressed inside `unsafe {}` blocks and `unsafe "reason" fn` bodies. Closes #153 (replaces the conflicted branch botkowski/syn011-dynamic-import). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 tasks
There was a problem hiding this comment.
Pull request overview
Adds a new compiler diagnostic SYN011 to warn when a function body uses dynamic import() (including optional-call import?.()), since runtime module loads bypass the static module capability model; this is integrated into the existing single-pass syn-check dispatch loop and documented/tested across the compiler + MCP surfaces.
Changes:
- Add SYN011 error-code registry entry plus MCP long-form explanation text.
- Implement SYN011 detection in
passSynCheck(with unsafe suppression, exclusions forimport.meta, member calls, and method shorthands). - Add comprehensive test coverage and update public docs/lists that enumerate known diagnostic codes.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds SYN011 to the list of codes supported by the explain tool. |
| AGENTS.md | Adds SYN011 to the diagnostic table. |
| packages/mcp/tests/server.test.ts | Registers SYN011 in the MCP server’s known-codes test list. |
| packages/mcp/src/explanations.ts | Adds a long-form MCP explanation entry for SYN011. |
| packages/compiler/src/error-codes.ts | Adds the canonical compiler registry entry for SYN011 (rule/idiom/rewrite/example). |
| packages/compiler/src/passes/syn-check.ts | Implements token-scan detection and warning emission for SYN011. |
| packages/compiler/tests/syn011-check.test.ts | Adds new test suite covering positive/negative cases, suppression, and version gating for SYN011. |
| packages/compiler/tests/error-codes.test.ts | Updates the exhaustive allowlist to include SYN011. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+541
to
+549
| if (callTok11.matchedAt !== undefined) { | ||
| const afterCloseIdx = nextSignificant(tokens, callTok11.matchedAt + 1); | ||
| const afterClose = tokens[afterCloseIdx]; | ||
| if (afterClose && ( | ||
| (afterClose.kind === "open" && afterClose.text === "{") || | ||
| afterClose.kind === "fatArrow" || | ||
| (afterClose.kind === "punct" && afterClose.text === ":") | ||
| )) continue; | ||
| } |
… when trailing ':' follows
The ':' exclusion (designed to skip TypeScript method signatures like
`{ import(x): T }`) was incorrectly suppressing SYN011 for `import()`
calls in ternary consequent position: `cond ? import(a) : import(b)`.
Fix: only apply the ':' suppression when the preceding token is not a
ternary '?' (kind==="question"). Adds regression test covering both
import() calls in a ternary expression.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
import(specifier)— the dynamic import form (?bs 0.7+)unsafe {}blocks andunsafe "reason" fnbodiesDetection logic
importtoken (kind=ident) not preceded by./?., followed by(or?.(.Excluded:
import.metaproperty accesses (followed by.){ import(x) { ... } }(parens followed by{)fn import(...)botscript declarations (checksprev.kind === "keyword"forfn)Changes
packages/compiler/src/error-codes.tspackages/compiler/src/passes/syn-check.tscase "import":in the dispatch switch; add SYN011 to header commentpackages/compiler/tests/syn011-check.test.tspackages/compiler/tests/error-codes.test.tspackages/mcp/src/explanations.tspackages/mcp/tests/server.test.tsAGENTS.mdREADME.mdexplaintool code listTest plan
pnpm -r build && pnpm test— 1250 tests pass (43 test files)import(specifier)import(`./module`)const mod = await import(path)import?.(path)unsafe {}blocks andunsafe fnbodiesimport.meta.url(property access, not a call){ import(x) {} }fn import(specifier: string) -> anydeclarations?bs 0.7Closes #153 (supersedes the conflicted branch
botkowski/syn011-dynamic-importwhich was incompatible with the #155 refactor).🤖 Generated with Claude Code