Use the strict confbox parser before JSON5 while preserving formatting
metadata and Unicode separator warnings. Avoid exceptions for missing
filesystem probes and use one-shot hashing within the existing JSX buffer
bound, retaining incremental hashing for oversized frames.
Validate parser behavior, hash boundaries, and exact native runtime parity.
Avoid UTF-8 decoding when a byte bound proves a source is not minified. Stop reduced-motion traversal after both evidence fields are complete, skip its program when accepted CSS settles the project check, and skip duplicate-JSX parsing for sources without an opening token.
Omit the canonical JavaScript rule plugin when the only additional plugin is the built-in React Compiler. Preserve unknown plugins, configuration inheritance, source limits, aborts, and directory failures.
Match nested state-member mutation and prior setter invalidation semantics, preserve TypeScript wrapper boundaries in hydration comparisons, and adapt verbatim Windows importer paths at the Next image ownership resolver boundary. Add 46 exact positive and negative AST controls.
Share per-input comment masking and JavaScript regex normalization, and skip normalization when no necessary raw candidate exists. Preserve exact key-lifecycle whitespace, case, comment and placeholder behavior with firing controls and forward/reverse scan parity.
* test: add failing tests for issue #1756 false positives
Covers three patterns:
- Chained timer cleared by helper (timer reassigned, helper clears current value)
- Timer allocated in nested function after await with guard
- AbortController cleanup via abort event handler
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* docs: document issue #1756 root causes with failing regression tests
Three false positive patterns in effect-needs-cleanup:
1. **Chained timer**: Timer reassigned inside its own callback, cleared by
helper. Rule doesn't recognize mutable handle semantics - clearTimeout(timer)
clears whatever is currently in the variable.
2. **Async guarded allocation**: Guard in async caller protects sync callee
allocation. Rule recognizes guards inside promise callbacks (#1241) but not
guards protecting function calls that contain allocations.
3. **AbortController delegation**: signal.addEventListener('abort', ...) removes
listener, cleanup calls controller.abort(). Rule recognizes direct {signal}
but not event-based delegation pattern.
Tests currently fail as expected. Implementations need to extend:
- Timer cleanup to understand mutable handles
- Guard tracking to follow call boundaries
- AbortController detection to recognize abort event delegation
Related: #306, #1241, #1594, #1736
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* wip: partial AbortController delegation fix (needs debugging)
Added `hasAbortSignalDelegatedCleanup` helper to recognize the pattern:
- signal.addEventListener('abort', () => removeEventListener(...))
- cleanup calls controller.abort()
Logic handles both direct (controller.signal) and destructured
(const { signal } = controller) signal references.
Current status: Helper added and integrated into effectHasCleanupForUsage,
but tests still fail. Needs debugging of AST traversal logic to correctly
identify and match the abort listener with the cleanup abort() call.
The other two patterns (chained timer, async guard) still need implementation.
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(rule): recognize owned effect cleanup paths
* fix(rule): preserve unsafe timer diagnostics
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix(nextjs-no-side-effect-in-get-handler): track safe Headers passed through helpers
Fixes#1757
The rule now tracks when a locally-constructed safe object (like
`new Headers()`) is passed as an argument to a same-file helper
function. The corresponding parameter in that helper is treated as
safe, preventing false positives when the helper mutates the response
headers.
Added `collectHelperParameterSafeBindings` utility that maps call
arguments to helper parameters, extending the set of safe bindings
when scanning helper bodies.
Regression tests added for:
- Headers passed to helper as first parameter
- Headers passed as second parameter
- Headers passed via destructured parameter
- Module-level Map still correctly flagged (not locally scoped)
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for #1757 fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(rule): scope GET helper safety by call
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix(async-defer-await): recognize 'live' as a liveness guard name
The async-defer-await rule was firing on post-await liveness guards that
check a 'live' flag, commonly used in React effects to detect unmounting
during async operations.
The issue: 'live' was not in the CANCELLATION_NAME_FRAGMENTS list, so
guards like 'if (!run.live) return' were not recognized as staleness
checks.
The fix adds 'live' to the fragments list so it matches patterns like:
- run.live
- isLive
- liveness
- stillLive
Closes#1758
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for async-defer-await fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(rule): narrow live cancellation guards
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix: exempt send/resend/notify/email mutations from cache invalidation requirement
These operations are cache-effect-free (sending emails, notifications, codes)
with no server data that could go stale. Added send, resend, notify, and email
to READ_ONLY_MUTATION_WORDS alongside download, export, validate, etc.
Closes#1759
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for send/resend/notify/email exemption
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(rule): narrow magic link mutations
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix(cli): increase runtime trace finalization timeout to 60s
Chrome needs more time to finalize large performance traces, especially
for longer recording sessions (up to 5 minutes). The previous 10-second
timeout was insufficient for complex React applications generating
substantial trace data.
Increased timeout from 10s to 60s, which:
- Aligns with industry best practices for CDP trace finalization
- Accommodates traces from the max 5-minute recording duration
- Prevents spurious timeouts on large/complex applications
Also improved the error message to be more actionable.
Closes#1752
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(cli): harden runtime trace finalization
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix: respect 'use no memo' directive in react-compiler-no-manual-memoization rule
When a component has the 'use no memo' directive, React Compiler skips
optimization for that component, so manual memoization (useMemo,
useCallback, memo) is still needed.
This change adds support for detecting the 'use no memo' directive and
suppresses the react-compiler-no-manual-memoization rule in those cases.
- Add hasUseNoMemoDirective utility function
- Update rule to check for directive in enclosing function (useMemo/useCallback)
- Update rule to check for directive in wrapped component (memo)
- Add comprehensive tests including regression tests
Fixes#1749
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for use no memo directive fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix: respect React Compiler opt-out directives
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix: treat Sanity blueprint files as convention entries
Fixes#1747
sanity.blueprint.ts is a Sanity Studio convention file loaded by
filename by the Sanity CLI (sanity blueprints deploy), similar to
sanity.config.ts and sanity.cli.ts. It was incorrectly reported as
unused by react-doctor/unused-file.
Added sanity.blueprint.{ts,js} to the alwaysUsed list in
FRAMEWORK_PATTERNS for Sanity, with a regression test.
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for Sanity blueprint fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>