Commit Graph

1536 Commits

Author SHA1 Message Date
Aiden Bai b5a84468db perf(core): port config and JSX optimizations from #1781
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.
2026-09-09 05:25:32 -07:00
Aiden Bai 7ba92adbd4 perf(native): reduce analysis overhead and preserve effect parity 2026-09-08 03:55:08 -07:00
Aiden Bai 1fb96dad4e perf(native): streamline JSX and reduced-motion analysis 2026-09-07 21:33:08 -07:00
Aiden Bai 4ee14c5903 perf(native): extract duplicate JSX candidates with Oxc 2026-09-07 04:14:19 -07:00
Aiden Bai 1477bc8323 perf(native): reduce startup across large lint passes 2026-09-07 02:15:36 -07:00
Aiden Bai cf25c64a92 perf(native): bound threads across lint batches 2026-09-07 01:12:33 -07:00
Aiden Bai 5ebbcf6352 perf(native): overlap security scanning with lint 2026-09-07 00:00:46 -07:00
Aiden Bai 5feea7bd60 perf(native): analyze project motion with Oxc 2026-09-06 22:58:17 -07:00
Aiden Bai 07298cc9a4 perf(core): batch duplicate JSX fingerprint hashing 2026-09-06 21:11:43 -07:00
Aiden Bai 6811509483 perf(core): reuse security scan file metadata 2026-09-06 19:28:45 -07:00
Aiden Bai 30df518386 perf(core): skip unnecessary source preprocessing
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.
2026-09-06 18:31:24 -07:00
Aiden Bai 1e347721f4 perf(native): reduce scan serialization and regex fallback 2026-09-06 16:44:34 -07:00
Aiden Bai 40dee92818 perf(native): skip unused JavaScript plugin loads 2026-09-06 14:48:54 -07:00
Aiden Bai 56f576b82c fix(native): close callback and state guard parity gaps 2026-09-05 19:44:12 -07:00
Aiden Bai 2f45687444 fix(native): harden effect and project-resolution parity 2026-09-05 18:38:22 -07:00
Aiden Bai 3ced1c98d3 fix(native): sync upstream rule boundaries 2026-09-05 16:43:28 -07:00
Aiden Bai 32377782c4 Merge commit 'ff7dd679e' into codex/oxc-source-patch 2026-09-05 14:59:28 -07:00
Aiden Bai 82a4d26458 fix(native): preserve runtime diagnostic boundaries 2026-09-05 14:59:23 -07:00
Skosh ff7dd679e8 fix(rule): recognize owned effect cleanup paths (#1762)
* 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>
2026-09-05 14:37:32 -07:00
Skosh 6ac8b71985 fix(rule): scope GET helper safety to exact calls (#1761)
* 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>
2026-09-05 14:29:42 -07:00
Skosh 0fbef9b011 fix(rule): narrow live cancellation guards (#1763)
* 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>
2026-09-05 14:29:24 -07:00
Skosh 2e3f6eb98a fix(rule): narrow magic-link mutation exemption (#1760)
* 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>
2026-09-05 14:28:55 -07:00
Aiden Bai d030b11330 fix(core): detect Sentry-wrapped compiler config (#1755) 2026-09-05 14:22:48 -07:00
Skosh ce5ce930de fix(cli): increase runtime trace finalization timeout to 60s (#1753)
* 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>
2026-09-05 14:22:43 -07:00
Skosh 576d7563ff fix: respect 'use no memo' directive in react-compiler-no-manual-memoization rule (#1750)
* 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>
2026-09-05 14:22:39 -07:00
Skosh fa72869c6c fix: treat Sanity blueprint files as convention entries (#1748)
* 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>
2026-09-05 14:22:36 -07:00
Aiden Bai fb0f962ced fix(native): preserve canonical diagnostic URLs 2026-09-05 12:15:39 -07:00
Aiden Bai 4611492b7a fix(native): preserve multiline HTML template parity 2026-09-05 12:05:00 -07:00
Aiden Bai 1b3f93d254 fix(native): harden scan parity and artifact provenance 2026-09-05 01:13:56 -07:00
Aiden Bai 83f13f4cf2 feat(native): port non-socket security rules 2026-09-03 02:16:18 -07:00
Aiden Bai a4ccc7512f fix(native): cover Windows root route parity 2026-09-02 21:41:14 -07:00
Aiden Bai b179fbda41 fix(native): preserve Windows server entry parity 2026-09-02 21:20:09 -07:00
Aiden Bai b404f030e3 fix(native): preserve Windows route module parity 2026-09-02 20:38:24 -07:00
Aiden Bai 384ff2a4e9 fix(native): preserve Windows router parity 2026-09-02 18:59:02 -07:00
Aiden Bai 6e6945b875 feat(native): package react-doctor-rust 2026-09-02 18:15:59 -07:00
Aiden Bai 0ce8d9b500 fix(native): sync rule fixes from main 2026-09-02 01:29:54 -07:00
Aiden Bai bb66fd1bbf perf(native): complete retained rule ports 2026-09-01 22:52:53 -07:00
github-actions[bot] fd23edca7e chore: version packages (#1649) 2026-09-01 21:34:33 -07:00
Aiden Bai ca30808bd3 feat(cli): accept positional file paths (#1746) 2026-09-01 21:23:42 -07:00
Aiden Bai 6f3dd033d5 fix: normalize diagnostic file URLs (#1743) 2026-09-01 21:01:43 -07:00
Aiden Bai 28d4343e4d fix: recognize indirect effect cleanup (#1742) 2026-09-01 14:07:52 -07:00
Aiden Bai a04b933c02 fix: ignore vendored source map env examples (#1739) 2026-09-01 13:16:03 -07:00
Aiden Bai a3d27cd572 perf(native): port React hook and parent data rules 2026-09-01 08:06:38 -07:00
Aiden Bai 69c6f7e348 perf(native): port effect chain and memo default rules 2026-09-01 01:37:16 -07:00
Aiden Bai 85db853c2f perf(native): port hydration guard rules 2026-09-01 00:08:37 -07:00
Skosh 2c4560fc0a fix: classify fragment returns of translation text as text-producing (#1732)
* fix: classify fragment returns of translation text as text-producing

Fragment returns mixing translation text elements (fbt/fbs) with literal
text now classify correctly as text-producing components. The fragment
is render-transparent, so both halves land in the caller's <Text>.

Fixes #1731

- Extract isTranslationTextJsxRoot helper that recursively checks
  fragments
- Fragment children that are all translation elements (plus literals)
  pass the check
- Fragment children with non-text elements still fail (guard test added)
- Add regression coverage for the reported mixed-literal case

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* chore: add changeset for fragment translation text fix

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* fix: keep fragment translation classification conservative

---------

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>
2026-08-31 21:40:35 -07:00
Skosh 025d69d701 fix: recognize global String substring lookups (#1734)
* fix: prevent false positive in js-set-map-lookups for String().includes()

- Add check to ensure String() refers to global constructor, not shadowed variable
- Add regression tests for the String() constructor case
- Add corpus regression test file

Closes #1733

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* fix: recognize global String substring lookups

---------

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>
2026-08-31 20:59:48 -07:00
Aiden Bai 074af61e79 perf(native): port Fast Refresh export rule 2026-08-31 20:38:20 -07:00
Aiden Bai 4e9cd83914 perf(native): port derived state rules 2026-08-31 16:55:55 -07:00
Aiden Bai 82799f65b6 fix(native): sync type-only browser globals 2026-08-31 14:58:22 -07:00