Commit Graph

1536 Commits

Author SHA1 Message Date
Aiden Bai 3bc63ea399 fix(rule): preserve ordered async traversal output (#1477) 2026-07-29 23:45:33 -07:00
Aiden Bai 811a2ff33a RDFPFN792026 Narrow repeated array lookup diagnostics (#1476)
* fix: narrow repeated array lookup diagnostics

* fix: handle wrapped and empty lookup inputs
2026-07-29 23:43:50 -07:00
Aiden Bai 01ca0b3f1e fix(security): skip root test-prefixed source files (#1505) 2026-07-29 23:41:45 -07:00
Aiden Bai 1098b9c10e RDFPFN792026 detect dynamic array index keys (#1475)
* fix: detect dynamic array index keys

* fix: validate React children normalization inputs

* fix: unwrap React children normalization
2026-07-29 23:37:46 -07:00
Aiden Bai 444e177e2f RDFPFN792026: detect unescaped RegExp path segments (#1474)
* fix: detect unescaped RegExp path segments

* fix: address RegExp review findings
2026-07-29 23:35:11 -07:00
Aiden Bai b10cd4c6a1 RDFPFN792026: recognize conditional focus forwarding wrappers (#1504)
* fix(a11y): recognize conditional focus forwarding wrappers

* fix(a11y): unwrap focus forwarding receivers
2026-07-29 23:30:22 -07:00
Aiden Bai 83f3ff8ac7 fix: support Astro project scans (#1519) 2026-07-29 23:09:02 -07:00
Aiden Bai 86add14268 fix: honor project scope in Git hook scans (#1516) 2026-07-29 16:54:20 -07:00
Skosh b1352a2be4 fix(core): resolve file URL diagnostic paths (#1473)
* fix(core): handle invisible Unicode characters in disable comments (#1472)

When TERMINAL_EMULATOR=JetBrains-JediTerm is set (or similar IDE/terminal
configurations), invisible Unicode characters like zero-width spaces
(U+200B, U+200C, U+200D) and zero-width no-break spaces (U+FEFF/BOM) can
appear at the end of lines. These characters are not matched by JavaScript's
\s regex class, causing the $ anchor in react-doctor-disable patterns to
fail despite the characters being invisible in editors and terminal output.

This fix adds explicit matching for common invisible Unicode characters
before the $ anchor in both DISABLE_NEXT_LINE_PATTERN and DISABLE_LINE_PATTERN,
making them resilient to these characters while maintaining the $ precision
that near-miss detection relies on.

The foreign disable patterns (eslint-disable, oxlint-disable) never anchored
to $ and were unaffected, which is why oxlint-disable-next-line worked while
react-doctor-disable-next-line failed in the reproduction case.

Fixes #1472

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

* chore: add changeset for invisible Unicode fix

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

* fix(core): resolve file URL diagnostic paths

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-29 00:09:06 -07:00
Aiden Bai f1a1b16eb5 fix: detect React Compiler through bundled config wrappers (#1470) 2026-07-28 03:12:57 -07:00
Aiden Bai 3728102af1 chore: upgrade Oxc toolchain (#1467) 2026-07-27 19:03:34 -07:00
Skosh b31fd85b9e fix: adjust changed file paths after rootDir redirect for baseline mode (#1457)
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-26 21:17:14 -07:00
Aiden Bai 3f3197f8e3 fix(cli): improve interactive startup and short-terminal TUI (#1426) 2026-07-26 21:00:36 -07:00
github-actions[bot] 201106e0e8 chore: version packages (#1442) 2026-07-26 20:43:07 -07:00
Skosh 80e89c5ff5 fix: prevent stack overflow in config analysis with cycle detection (#1461) 2026-07-26 04:39:34 -07:00
Aiden Bai 846c2df844 feat: add parsed Three.js shader lint rules (#1455)
* feat: add parsed Three.js shader lint rules

* fix: tighten shader rule precision

* fix: address shader rule review findings

* fix: harden parsed shader edge cases

* fix: harden shader variant analysis

* fix: complete parsed shader edge coverage

* fix: close shader control-flow gaps

* fix: tighten shader interface analysis

* fix: recognize GLSL3 integer samplers

* fix: close shader control-flow gaps

* fix: close remaining shader rule gaps

* fix: close shader review gaps

* fix: track shader cache key invalidation

* fix: handle shader material review edge cases

* fix: close remaining shader review gaps

* fix: skip uncertain shader position writes

* fix: harden shader position analysis

* fix: track divergent shader loop controls

* fix: track parameter shader variants

* fix: complete shader variant detection

* fix: identify and clean up parity sandboxes

* fix: tolerate Daytona cleanup races

* fix: restore complete parity corpus

* fix: tighten Three shader diagnostics

* fix: download large eval reports

* fix: trace shader variant aliases
2026-07-25 22:04:43 -07:00
Aiden Bai 6904ff12f1 fix: avoid invalid Tailwind length regex (#1459) 2026-07-25 22:04:15 -07:00
Aiden Bai 1aa6b12fd6 fix: detect React Compiler through dependency configs (#1458) 2026-07-25 19:48:27 -07:00
Aiden Bai 4ebd0a0706 feat: expand design quality rules (#1454) 2026-07-25 16:43:38 -07:00
Aiden Bai 49c5c1e837 fix: improve effect provenance diagnostics (#1452) 2026-07-25 16:43:28 -07:00
Aiden Bai 4fbab2ddc8 feat: add missing scripts and path containment rules (#1451) 2026-07-24 19:08:06 -07:00
Aiden Bai 7ee59d3125 fix: detect React Compiler through require.resolve (#1450) 2026-07-24 17:19:32 -07:00
Aiden Bai b1b62db71d fix: recognize unplugin auto-import JSX globals (#1445) 2026-07-24 15:55:17 -07:00
Aiden Bai 8534d864e4 feat: scan inline scripts in HTML files (#1443) 2026-07-24 03:52:18 -07:00
Aiden Bai 5d2f66d055 Add React Native diagnostics (#1427) 2026-07-23 13:55:48 -07:00
github-actions[bot] 54ba416f83 chore: version packages (#1433) 2026-07-23 03:44:25 -07:00
Aiden Bai 8765ca3274 fix: ignore caseless body text in all-caps rule (#1431) 2026-07-23 03:37:25 -07:00
Skosh 707378adbf fix: prevent stack overflow in AST traversal on deeply nested code (#1439)
* fix(oxlint-plugin): prevent stack overflow in walkAst on deeply nested code

Issue #1438: react-doctor 0.9.0 crashes with 'RangeError: Maximum call stack
size exceeded' when analyzing deeply nested async functions with multiple
try/catch blocks.

Root cause: walkAst() used recursive tree traversal via nested function calls,
hitting V8's stack limit (~10k-15k frames) on pathological but real code —
large orchestrator functions with nested async helpers, each wrapped in
try/catch, plus deep if/else branching.

Fix: Convert walkAst() to iterative traversal using an explicit stack. This
eliminates unbounded recursion while preserving identical visitor semantics
(early-exit via 'return false', depth-first left-to-right order).

Also add memoization to subtreeCanThrowSynchronously's isInsideAbsorbingTry
to cache (node, boundary) results and avoid redundant ancestor walks + catch
handler analysis.

The iterative walkAst benefits all 745 rules that traverse ASTs, not just the
throw-analysis rules that triggered this report.

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

* chore: add changeset for walkAst stack overflow fix

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

* fix: keep AST traversal stack-safe patch minimal

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-23 03:37:05 -07:00
Skosh 30369b6000 fix: detect React Compiler from compatibility runtime (#1437)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-23 02:55:52 -07:00
Aiden Bai db9d300343 Make all design rules opt-in by default (#1434) 2026-07-23 01:55:55 -07:00
Aiden Bai 9b532015f0 perf(fuzz): reuse parsed rule fixtures (#1435) 2026-07-23 01:35:47 -07:00
Aiden Bai 1e67af03fe feat: add deterministic design diagnostics (#1428) 2026-07-23 00:27:13 -07:00
github-actions[bot] d2cd2f41b2 chore: version packages (#1425) 2026-07-22 15:46:10 -07:00
Skosh 599e30d9e1 fix: share safe built-in control-flow proof across async rules (#1422)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
2026-07-22 04:15:57 -07:00
Skosh 01820bb4fd fix(action): upgrade actions/cache to v6.1.0 for Node.js 24 support (#1417)
Co-authored-by: Aiden Bai <aiden@million.dev>
2026-07-22 03:41:26 -07:00
Aiden Bai 9155bc0bc9 feat(cli): add experimental interactive Ink TUI (#979)
* feat(cli): add experimental interactive TUI

* fix(tui): isolate concurrent project reporters

* fix(tui): preserve project scoring config

* fix(tui): merge monorepo rule priorities

* fix(tui): finalize terminal lifecycle

* fix(tui): surface lint hard failures

* fix(tui): preserve monorepo project selection

* fix(tui): address interactive review findings

* fix(tui): constrain report to terminal height

* test(tui): tolerate colored code frames

* fix(tui): address final review findings

* fix(tui): honor configured blocking gate

---------

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-07-22 02:13:58 -07:00
Aiden Bai 76263ecc08 Add direct Three.js and WebGL diagnostics (#1424)
* add direct Three.js and WebGL rules

* fix parity-discovered config cycle

* fix Three render construction false positives

* fix(rules): preserve JSX-referenced Three components

* fix(rules): address Three.js review findings

* feat(rules): add Three.js resource cleanup diagnostics
2026-07-22 01:48:13 -07:00
Aiden Bai 3d7ea66c3f perf: speed up React Doctor scans (#1423) 2026-07-21 20:35:22 -07:00
github-actions[bot] 84b999002a chore: version packages (#1420)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-21 01:36:31 -07:00
Aiden Bai 8d4d5a82d9 docs: simplify package README 2026-07-21 01:33:21 -07:00
github-actions[bot] d489fa081a chore: version packages (#1382) 2026-07-21 00:29:21 -07:00
Aiden Bai 8c4959bb74 fix(rules): harden parity diagnostics (#1419)
* fix(rules): harden parity diagnostics

* fix(evals): keep parity artifacts parseable

* fix(evals): support Windows harness tests

* fix(fuzz): parse CRLF corpus directives
2026-07-20 22:28:25 -07:00
cursor[bot] 412377e473 RD CLEANUP: simplify Ink rule helpers (#1414)
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-07-20 14:37:00 -07:00
Aiden Bai f5f13b877a feat(rules): add version-aware React Router diagnostics (#1411) 2026-07-20 13:43:35 -07:00
Aiden Bai 284b4e4e93 fix: harden recent detector foundations (#1415) 2026-07-20 10:01:10 -07:00
Aiden Bai 5b468f8a92 feat(rules): add React Three Fiber diagnostics (#1371) 2026-07-20 09:22:48 -07:00
Aiden Bai fc1b3a3984 feat(rules): add version-gated Ink diagnostics (#1404) 2026-07-20 08:41:26 -07:00
Aiden Bai af33723287 fix(rules): harden MobX diagnostics (#1412) 2026-07-20 08:39:27 -07:00
Aiden Bai 0b0b5ac523 feat(rules): add deterministic UI, accessibility, and animation diagnostics (#1337)
* feat(rules): add 10 motion, accessibility, and design lint rules

Derived from a cross-resource design reference (every principle from the
design knowledge base), deduped against the full existing rule inventory.

Motion: extend no-transition-all to the Tailwind `transition-all` class
(was inline-only) and add no-tailwind-layout-transition for arbitrary
`transition-[<layout-prop>]`.

Accessibility: no-autoplay-without-muted, no-uninformative-aria-label,
no-target-blank-without-rel, and no-low-contrast-inline-style (computes the
real WCAG 2.1 ratio from co-located inline color + backgroundColor).

Design/Tailwind hygiene: no-redundant-display-class, prefer-truncate-shorthand,
no-full-viewport-width, and no-svg-currentcolor-with-fill-class.

All register via codegen (388 rules); 77 co-located tests pass; typecheck,
lint, and format clean.

* fix(rules): correct two false positives found in rule-validate

- no-low-contrast-inline-style: when the inline style has no `fontSize`,
  the text may be sized large via a class (`text-5xl`), so fall back to the
  lenient 3:1 large-text threshold instead of 4.5:1 to avoid flagging large
  text that only needs 3:1. Stricter 4.5:1 applies only when the size is a
  visible normal size.
- no-redundant-display-class: `<li>` defaults to `display: list-item`, not
  `block`, so `block` on an `<li>` is meaningful — removed `li` from the
  block-default set.

Adds regression tests for both.

* fix(rules): resolve Cursor Bugbot findings

- no-low-contrast-inline-style: use a solid `background` shorthand color as
  the background (was skipped entirely, missing low-contrast pairs); skip only
  gradients/images/ambiguous (both backgroundColor + background). Also treat a
  string `fontWeight: "700"` as bold for the large-text threshold.
- no-transition-all: match `transition-all` as a whole Tailwind token (segment
  after variant prefixes) so compound classes like `transition-all-custom` are
  not falsely flagged.
- no-svg-currentcolor-with-fill-class: exclude stroke-WIDTH utilities
  (`stroke-2`, `stroke-[1.5]`) — they set thickness, not color — so they no
  longer false-conflict with `stroke="currentColor"`.

Adds regression tests for each.

* feat(rules): add 3 Tailwind-canonicalization rules from ui.sh guidance

- no-deprecated-tailwind-class: flag Tailwind v4 renames (bg-gradient-* →
  bg-linear-*, flex-shrink-* → shrink-*, flex-grow-* → grow-*,
  overflow-ellipsis → text-ellipsis). Gated on a new `tailwind:4` capability.
- no-arbitrary-px-font-size: `text-[13px]` → rem so text scales with the
  user's root font size (px stays fine for border-*/outline-*).
- prefer-dvh-over-vh: `h-screen`/`min-h-screen`/`h-[100vh]` → dvh (tailwind:3.4).

Adds `tailwind:4` capability to @react-doctor/core and extracts a shared
`get-class-name-tokens` util (variant-aware token splitting), reused by
no-transition-all and no-svg-currentcolor-with-fill-class.

* fix(rules): adversarial-review false positives in the new design rules

- no-tailwind-layout-transition: match transition-[…] property names exactly
  (comma-split + set) so SVG `stroke-width` / `border-width` — which merely
  contain "width" — are no longer flagged as HTML layout thrash.
- no-full-viewport-width: drop `max-w-*` / `maxWidth` (a defensive cap, not the
  overflow footgun); keep `w-screen`/`w-[100vw]`/`width`/`minWidth`.
- prefer-dvh-over-vh: drop `max-h-*` / `maxHeight` (a valid height cap, e.g. a
  scrollable modal); keep `h-screen`/`min-h-screen`/`height`/`minHeight`.
- no-deprecated-tailwind-class: only rename `bg-gradient-to-*` → `bg-linear-to-*`
  (v4 radial/conic are `bg-radial`/`bg-conic`, not `bg-linear-radial`).

Adds regression tests for each false positive.

* fix(rules): resolve thermo-review false positives

- no-svg-currentcolor-with-fill-class: only treat UNPREFIXED `fill-*`/`stroke-*`
  color classes as conflicts; `hover:fill-blue-600` / `dark:fill-white` (state-
  gated, no static conflict with the base `fill="currentColor"`) are no longer
  flagged — a very common icon pattern.
- no-low-contrast-inline-style: reject 4-arg `rgb(0,0,0,0.5)` / slash-form alpha
  (was judged opaque), and bail when the style object contains a `{...spread}`
  that could override the colors. Tag `test-noise` to match sibling no-tiny-text.
- no-full-viewport-width: drop the redundant `category: "Architecture"` override
  (it's the design-bucket default).
- Extract `has-jsx-spread-attribute` util; use it in the two a11y rules.

Adds regression tests for the variant-prefixed svg classes, rgb-alpha, opaque
rgb, and the style-spread bail.

* refactor(rules): deslop the design/motion/a11y rule additions

Consolidate duplication surfaced by an adversarial deslop pass; no behavior
change (the same diagnostics fire for the same inputs):

- no-autoplay-without-muted: fold isStaticallyTrue/isStaticallyFalse into one
  tri-state resolveStaticBoolean, mirroring the existing parseJsxValue idiom
- no-svg-currentcolor-with-fill-class: collapse the duplicated fill/stroke
  branches into a single loop over the two paint attributes
- no-low-contrast-inline-style: hoist the repeated `properties` fallback
- no-uncontrolled-input: drop the local hasJsxSpreadAttribute copy in favor of
  the branch's new shared utils/has-jsx-spread-attribute, completing the extraction

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(rules): no-deprecated-tailwind-class stops flagging overflow-clip

`overflow-clip` is a current Tailwind utility for `overflow: clip` (v3.1+,
still present in v4) — it was never renamed to `text-clip`, which sets the
unrelated `text-overflow: clip`. The stray mapping produced an incorrect
"renamed in v4" suggestion (Cursor Bugbot). Only `overflow-ellipsis ->
text-ellipsis` is a real rename; keep that. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(capabilities): require a confirmed Tailwind major for the tailwind:4 gate

`tailwind:4` gates no-deprecated-tailwind-class, which tells users a class was
renamed/removed in v4. The optimistic-on-null policy (assume latest for an
unparseable spec like `workspace:*`) is right for the suggestion rule behind
`tailwind:3.4`, but for a deprecation rule it surfaces confidently-wrong
"renamed in v4" warnings on a v3 project. Require a CONFIRMED parsed major >= 4
for tailwind:4 — favor a false negative over a false positive (Cursor Bugbot).
`tailwind:3.4` stays optimistic. Adds an unparseable-version regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(rules): resolve Bugbot/Devin review findings on design/a11y rules

- no-full-viewport-width: match variant-prefixed `md:w-screen` / `lg:min-w-screen`, mirroring the sibling `prefer-dvh-over-vh` regex (overflow happens at every breakpoint).
- no-target-blank-without-rel: resolve `rel={'noopener'}` expression-container literals instead of treating them as dynamic, so reverse-tabnabbing isn't silently missed; share one literal resolver with the `target` check.
- Extract the bare `16` root-font-size divisor into `ROOT_FONT_SIZE_PX` per the magic-number convention.

* fix(rules): no-uninformative-aria-label resolves braced string literals

Extracts no-target-blank-without-rel's inline getStringLiteralAttributeValue
into a shared util and uses it in no-uninformative-aria-label, so a static
braced literal like aria-label={'icon'} is judged instead of silently skipped
(getJsxPropStringValue only handles plain string literals). Adds regression
tests for the braced uninformative and braced descriptive cases.

Addresses Bugbot review on #850.

* test(rules): add liveness fixtures after rebase

* fix(rules): address automated review findings

* fix(rules): handle leading-dot stroke widths

* fix(rules): skip dynamic background overrides

* fix(rules): address target blank and transition reviews

* fix(rules): skip svg layout transitions

* fix(rules): preserve font line height suggestion

* fix(rules): match complete transition utilities

* fix(rules): share layout transition properties

* fix(rules): bound deprecated utility prefixes

* fix(rules): clear dynamically overridden colors

* fix(rules): tighten style and svg precision

* fix(rules): preserve competing display utilities

* fix(rules): preserve animation property scopes

* feat(rules): expand deterministic design checks

* feat(rules): add structural design diagnostics

* feat(rules): complete source-auditable design checks

* fix(rules): skip unresolved input types

* fix(rules): tighten layout and boundary detection

* fix(rules): close motion and padding gaps

* fix(rules): tighten surface and line-height proofs

* fix(rules): evaluate opaque hsl contrast

* fix(rules): honor effective static values

* fix(rules): honor final inline style declarations

* fix(rules): respect variants and share surface checks

* fix(rules): traverse fragments and preserve variant scope

* feat(rules): deepen UI quality diagnostics

* feat(rules): add deterministic animation diagnostics

* fix(rules): retain in-house accessibility checks

* feat(rules): expand deterministic UI diagnostics

* feat(rules): detect generated interface patterns

* fix(rules): respect dynamic style overrides

* feat(rules): expand deterministic design diagnostics

* fix(rules): close design precision gaps

* feat(rules): expand deterministic design and accessibility checks

* feat(rules): detect unsafe Motion API usage

* test(fuzz): remove duplicate module snippets

* feat(cli): add focused design command

* fix(design): include the complete rule bucket

* fix(core): align opt-in rule gates

* feat(rules): expand deterministic motion and interaction checks

* feat(rules): harden deterministic design diagnostics

* fix(rules): harden design expansion diagnostics

* fix(rules): apply large-corpus precision review

* fix(rules): suppress large-corpus accessibility noise

* fix(core): detect compiler in rstack configs

* fix(a11y): avoid responsive navigation false positives

* fix(rules): reduce design corpus false positives

* fix(rules): restore will-change build after rebase

* fix(rules): harden all-rules corpus precision

---------

Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 01:09:01 -07:00
Aiden Bai cd9ca68faa NEW_RULES: Add rule analysis foundation and 56 rules (#1402)
* NEW_RULES: Reapply rule analysis foundation

Reapply the complete reviewed NEW_RULES stack on top of current main after the rollback.

* fix(rules): harden new diagnostics against false positives

* fix(rules): preserve dynamic context providers

* fix(core): resolve styled-components workspace versions

* fix(rules): harden new diagnostics after deep audit
2026-07-20 00:54:55 -07:00