* feat(rules): add 8 mined correctness, performance, a11y, and security rules
Mined from a 12-cluster pass over the design/engineering brain and
synthesized into docs/rule-candidates-backlog.md. Ships the highest-signal,
lowest-noise batch, each with adversarial + FP-regression tests:
- no-call-component-as-function (Bugs)
- no-create-ref-in-function-component (Bugs)
- no-async-effect-callback (Bugs)
- no-json-parse-stringify-clone (Performance)
- img-missing-dimensions (Performance)
- no-img-lazy-with-high-fetchpriority (Performance)
- dialog-has-accessible-name (Accessibility)
- auth-token-in-web-storage (Security)
Adds the shared has-jsx-spread-attribute util and registers the three
in-house ported-bucket rules in RULES_NOT_PORTED_FROM_EXTERNAL.
* fix(rules): drop img-missing-dimensions; make component rules shadow-safe
- Drop `img-missing-dimensions`: width/height attributes are only one of
several valid ways to reserve space (CSS aspect-ratio, container sizing),
and the authoritative signal lives in stylesheets a static linter can't
see. This is a runtime check (Lighthouse `unsized-images`), so a syntax
rule would false-positive on any CSS-sized image.
- `no-call-component-as-function`: resolve the callee through its scope
symbol instead of by name, so a parameter/local shadowing a component
name is no longer flagged. The component signal is the binding's
declaration (same-file component returning JSX) or an imported binding
also rendered as JSX.
- `no-create-ref-in-function-component`: skip a shadowing local `createRef`
(only flag React's import / `React.createRef`).
- Adds shadow-safety regression tests for both.
* fix(rules): tag no-call-component-as-function test-noise (eval finding)
An OSS eval sweep (react-use, radix primitives, excalidraw, mantine;
~2.8k diagnostics) showed every real-world hit of this rule was a test
render-helper (`render(Wrapper({...}))` in `.test.tsx`/`.story.tsx`) —
harmless for hookless wrappers and the dominant firing surface. Tag it
`test-noise` so it skips test/story/playground files and only nags
shipped code. The sweep also confirmed dialog-has-accessible-name (2 real
a11y bugs in excalidraw) and no-create-ref-in-function-component (1 real
bug in a mantine story) as true positives with zero false positives.
* fix(only-export-components): skip framework route/special files (#776)
Recognize the route/special files of every file-routing framework
react-doctor covers (Next.js, Expo Router, TanStack Router, Remix /
React Router) via a single `isFrameworkRouteOrSpecialFilename` helper,
so the documented "co-export config/metadata next to the default
component" shape no longer triggers false-positive non-component-export
warnings. Fixes the `alt` / `size` / `contentType` / `revalidate`
exports in `opengraph-image.tsx`.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: change variable name
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: update usages as well
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>