feat: add no-module-level-new lint rule#51
Conversation
Detects `new Expression()` calls at module scope that execute during SSR and may crash or cause side effects. Allows safe constructors (Error, URL, Map, Set, RegExp, Date, etc.) while flagging SSR-unsafe ones like QueryClient, IntersectionObserver, WebSocket, etc. Motivated by a design agent failure where `const queryClient = new QueryClient()` at module level compiled fine but crashed at SSR runtime.
Auto-fix prettier formatting in src/rules/no-module-level-new.ts
|
Pushed an auto-fix commit to unblock the failing Lint & Format check (Prettier formatting in |
There was a problem hiding this comment.
Reviewed as steward. Looks solid — approving.
Logic is correct: walks the parent chain to confirm new is at module scope (not nested in a function/class/method). The SAFE_CONSTRUCTORS allowlist is sensible and matches the intent (cheap, side-effect-free).
Two minor suggestions, non-blocking:
-
Consider adding
Symbol,Object,Array,String,Number,Booleanto SAFE_CONSTRUCTORS — all are pure builtins. (Some are unusual withnew, but if the agent writes them they're harmless.) -
Browser-fetch-style classes (
Headers,Request,Response,URL,URLSearchParams,FormData,Blob,AbortController,EventTarget) are also typically safe at module scope. URL/URLSearchParams are already covered. Could add the rest to reduce false positives in API-route adjacent code.
Neither blocks shipping. The current allowlist already covers the noisiest cases.
Auto-resolved trivial conflicts in shared files (README.md, src/rules/index.ts, src/rules/meta.ts, tests/config-modes.test.ts) by applying the PR's net additions on top of current main and bumping the rule count. Resolved by Lainter (steward).
Auto-resolved trivial conflicts in shared files. Resolved by Lainter (steward).
Rebase pulled in unformatted README.md changes; this restores prettier formatting.
|
Auto-fix: Lint & Format CI was failing on this rebase because README.md needed prettier formatting. Pushed prettier --write README.md as a follow-up commit. CI should go green on the next run. |
Rebased onto main to resolve conflicts after #51 merge.
Rebased onto main to resolve conflicts after #51 merge.
Rebased onto main to resolve conflicts after #51 merge.
…ules Rebased onto main to resolve conflicts after #51 merge.
Rebased onto main to resolve conflicts after #51 merge.
Rebased onto main to resolve conflicts after #51 merge.
Summary
no-module-level-newlint rule that detectsnew Expression()calls at module scope, which execute during SSR and may crash or cause side effectswebplatform ruleMotivated by a design agent failure where
const queryClient = new QueryClient()at module level inlayout.jsxcompiled fine but crashed at SSR runtime, causing blank screenshots and an ~8 minute debugging loop.Manual QA Plan
const qc = new QueryClient()at top levelconst m = new Map()at top levelfunction f() { new QueryClient() }useEffect(() => { new QueryClient() })npm test