Commit Graph

1865 Commits

Author SHA1 Message Date
Aiden Bai d16d2c7b7a fix(score): gzip score payload to avoid 413 on large projects (#305)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-20 15:04:16 -07:00
Aiden Bai aae328cc98 feat: add dead-code analysis via deslop-js (#291) 2026-05-20 14:29:19 -07:00
Aiden Bai 19afa9ba3b fix(core): support detached HEAD in --diff mode (closes #298)
`--diff <base>` silently fell back to a full repo scan on GitHub Actions
`pull_request` runs because `actions/checkout@v4` leaves HEAD detached
at `refs/pull/N/merge`. `getCurrentBranch` returned null, `getDiffInfo`
bailed early, and a one-file PR produced hundreds of unrelated findings.

Only require a named branch when no explicit base was given — `git
merge-base <base> HEAD` resolves on a bare commit hash. Surface
`currentBranch: null` to callers (typed as `string | null`) and render
it as "(detached HEAD)" in the CLI. When `--diff <base>` was explicit
and still failed, the warning now names the base instead of the
misleading "no feature branch detected" message so silent CI scope
drops surface immediately.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 20:21:10 -07:00
Aiden Bai 831f280000 fix(react-doctor): stop spinner hang at 99% CPU in non-interactive TTYs (#293) (#296) 2026-05-18 14:44:34 -07:00
Aiden Bai 549e4d2132 0.2.1 2026-05-18 07:44:52 -07:00
Aiden Bai 4920dc0a3e fix(project-info): make filesystem walks tolerate EPERM/EACCES (macOS Library) (#295)
* fix(project-info): swallow EPERM/EACCES from filesystem walks

Recursive directory walks in discoverReactSubprojects, listSourceFiles,
countSourceFiles, neutralize-disable-directives, resolveWorkspaceDirectories
and getNxWorkspaceDirectories called fs.readdirSync without guarding
against permission errors. On macOS, TCC-protected directories like
~/Library/Accounts throw EPERM on scandir even for the owning user.
Running react-doctor from a parent directory (/home/ubuntu) crashed the entire
scan with:

  EPERM: operation not permitted, scandir '/Users/<user>/Library/Accounts'

Introduce readDirectoryEntries() that wraps fs.readdirSync({withFileTypes})
and returns [] for ignorable errors (EPERM, EACCES, ENOENT, ENOTDIR),
rethrowing anything else. Route every recursive walk through it so a
single unreadable directory can't take down the whole run.

Closes #275, #290.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* fix(project-info): close adjacent EPERM gaps (manifest reads, stat guards)

Follow-up to the readdir EPERM fix — the same TCC-protected directory
that crashed scandir would also throw on:

1. Reading any package.json inside it. readPackageJsonUncached caught
   EISDIR and EACCES but not EPERM (macOS TCC) or ENOENT (race during
   long walks), so a manifest under ~/Library/<protected>/package.json
   would still take down the scan one step after our readdir fix.

2. The 'fs.existsSync(p) && fs.statSync(p).isDirectory()' guard used
   in discoverReactSubprojects, resolveWorkspaceDirectories,
   getNxWorkspaceDirectories, and resolveConfigRootDir. existsSync
   returns false on most denials, but if it ever returns true while
   statSync is denied (narrow race / TCC interaction) the whole call
   throws.

Introduce an isDirectory() helper that swallows stat errors and returns
false, paralleling the existing isFile() helper, and route every guard
through it. Add EPERM + ENOENT to the readPackageJsonUncached recovery
list.

Adds three regression tests under issue #275 + #290:
- readPackageJson returns {} for a chmod-0 manifest (EPERM/EACCES)
- readPackageJson returns {} for a missing manifest (ENOENT)
- isDirectory returns false rather than throwing for an inaccessible
  path (parent chmod 0)

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-18 07:43:56 -07:00
Aiden Bai 19c42891f3 0.2.0 2026-05-18 07:43:34 -07:00
Aiden Bai 66acef8d75 0.2.0 2026-05-18 07:38:50 -07:00
Aiden Bai 72d194d434 fix 2026-05-18 07:24:12 -07:00
Aiden Bai 67f1f1e8f2 fix: surface React Review CTA in CLI summary 2026-05-18 07:23:11 -07:00
github-actions[bot] 39ae1cb261 chore(readme): refresh leaderboard top 10 2026-05-18 08:36:13 +00:00
Nisarg Patel 638a0663c9 remove(oxlint-plugin-react-doctor): drop design-no-default-tailwind-palette rule
The rule flagged every `indigo-*` / `gray-*` / `slate-*` token in a
className as "the Tailwind template default" and pushed users toward
zinc / neutral / stone (or a brand color). In practice the choice
between those neutral scales is a deliberate brand decision rather
than a code-health signal, and the Radix-Colors carve-out it shipped
with (anchoring the regex to the canonical 50…950 stops) didn't help
teams that customize the default Tailwind palette to a different
numeric scale.

Removes the rule file, the now-unused TAILWIND_DEFAULT_PALETTE_*
/ TAILWIND_PALETTE_UTILITY_PREFIXES constants, the entry in the
generated rule-registry, and the dedicated regression-test describe
block. Also adds an AGENTS.md rule forbidding agents from authoring
changesets or editing CHANGELOG.md — those belong to humans at
release time.

Closes MIL-1543.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 21:25:17 -07:00
Aiden Bai 5be2eadd90 fix 2026-05-16 23:51:48 -07:00
Aiden Bai dafe231e24 feat: add category-level rule controls (severity overrides + family tags) (#285)
* feat(core): add severityOverrides config with per-rule / per-category / per-tag channels

Introduces a unified severity-override resolver that lets users
promote, demote, or fully disable rules across every diagnostic
surface (CLI, PR comment, score, --fail-on) without editing source.

- New `severityOverrides` field on `ReactDoctorConfig` with `rules`,
  `categories`, and `tags` channels. Values: `error` | `warn` | `off`.
  Precedence: `rules` > `categories` > `tags`; within the tag channel
  the most permissive override wins (`off` > `warn` > `error`).
- `resolveRuleSeverityOverride` is a pure resolver shared between the
  oxlint config builder (next commit) and the post-lint diagnostic
  filter, so external-plugin rules (`react/*`, `jsx-a11y/*`) honor
  `off` too even though their severities live outside our control.
- `applySeverityOverrides` drops `off` diagnostics, re-stamps
  `warn` / `error` severities, and short-circuits to the input
  array when no overrides are configured so the common path stays
  allocation-free.
- `validateConfigTypes` coerces stringy mistakes and warns on
  invalid severities / channel shapes; `mergeAndFilterDiagnostics`
  runs the override before the existing ignore pipeline.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* feat(core): apply severityOverrides at oxlint config time

Threads `severityOverrides` from the user config through `runOxlint`
into `createOxlintConfig`, where it short-circuits `off` rules
before registration (so they never run, never emit, and never reach
any surface) and re-stamps the registered severity for `warn` /
`error` overrides. The retry-without-extends fallback honors the
same overrides so a crashed adopt-extends path doesn't quietly
reactivate a silenced rule family.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* feat(plugin): bucket-derived auto-tags and migration-hint family

Cross-cutting controls (`severityOverrides.tags`,
`surfaces.*.excludeTags`, `config.ignore.tags`) need a way to target
whole rule families without each rule file repeating the same tag.
The codegen now merges bucket-derived tags into every entry:

- `react-native/` bucket rules get `"react-native"`
- `server/` bucket rules get `"server-action"`

Tags authored on the rule (e.g. `test-noise` on
`no-react19-deprecated-apis`) are preserved and deduped at registry
build time. The four migration-prompt rules now carry an explicit
`migration-hint` tag too:

- `no-react19-deprecated-apis`
- `no-react-dom-deprecated-apis`
- `no-legacy-class-lifecycles`
- `no-legacy-context-api`

`formatAutoTagsLine` mirrors prettier's wrap-at-100-cols decision at
codegen time so the regen-equals-formatted contract enforced by
`gen:check` stays stable.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* test: cover severityOverrides resolution, post-lint apply, and tag registration

- `resolve-rule-severity-override.test.ts` checks precedence,
  empty-overrides short-circuit, the multi-tag most-permissive-wins
  rule, and category / tag fallback.
- `apply-severity-overrides.test.ts` verifies `off` drops both
  react-doctor and external-plugin diagnostics; `warn` / `error`
  re-stamps the severity; and the no-overrides path returns the
  input array by identity.
- `rule-tag-registration.test.ts` guards the bucket-derived auto-tags
  (`react-native` on every RN rule, `server-action` on every server
  rule) and the explicit `migration-hint` tags on the four migration
  rules, plus that authored tags survive the bucket merge.
- `validate-config-types.test.ts` extends the existing surfaces
  coverage with severityOverrides happy / invalid / partial-channel
  paths.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* docs: document severityOverrides and the five rule-family tags

Adds a README section right after the surface controls explaining
when to use `severityOverrides` (single value applied across every
channel) vs `surfaces` (visibility-only, per channel), with a
copy-pasteable JSON example covering the five tag families called
out in the original TODO — `design`, `test-noise`, `react-native`,
`server-action`, `migration-hint`. Updates the TODOs entry to
landed status and adds a minor-bump changeset.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* refactor: tighten severity-override surface for elegance

Net -58 lines while making each path read more directly:

- New `get-diagnostic-rule-identity.ts` projects a diagnostic onto
  the three axes every rule-targeted control reasons about
  (`ruleKey`, `category`, `tags`). `filter-for-surface` and
  `apply-severity-overrides` both consume it instead of repeating
  the plugin-aware tag lookup inline.
- `resolve-rule-severity-override` drops the two-level
  `pickMostPermissive` / `collectTagOverride` helpers in favor of a
  single linear scan with a small `isMorePermissive` predicate;
  reads top-to-bottom in rule > category > tags precedence order.
- `apply-severity-overrides` factors a `restampSeverity` helper
  driven by a `SEVERITY_FOR_OVERRIDE` map, keeping the main loop to
  three lines of decision logic.
- `createOxlintConfig` collapses the override-then-fallback into one
  `?? rule.severity` expression so the "\"off\" skips registration"
  check is the only branch left.
- Codegen drops the manual prettier-width math entirely — the
  shorter `[...new Set(...)]` form always fits under 100 cols, so
  `gen:check` stays idempotent without the wrap-aware fork.
- `validate-config-types` extracts `applyFieldValidator`,
  `isPlainObject`, and `formatType` so the four "if undefined skip;
  validate; store or delete" blocks at the bottom collapse into one
  expression each, and the three "must be plain object" guards stop
  duplicating their type check.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* test: dogfood js-combine-iterations in rule-tag-registration test

React Review flagged two .filter().map() chains in the test file as
`js-combine-iterations` warnings (we eat our own dogfood). Replaces
both chains with a shared `collectRuleIdsMatching` helper that walks
`Object.entries(plugin.rules)` once and pushes ids into a single
result array — same behavior, single pass.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* fix(core): warn on unknown severityOverrides channel keys

Bugbot caught an asymmetry: `validateSurfacesField` iterates the
user-provided keys via `Object.entries` and warns on unknown surface
names, but `validateSeverityOverridesField` only iterated the
allowlist — so a typo like `"rule"` instead of `"rules"` or
`"category"` instead of `"categories"` silently dropped the
override with no signal to the user.

Switches the iteration to walk the user's keys (matching surfaces)
and emits `config field "severityOverrides.<key>" is not a known
channel (expected one of: rules, categories, tags); ignoring.` when
the key isn't recognized. Adds a regression test for the typo path.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* refactor: rename severityOverrides config to severity for ESLint/oxlint idiomacy

The wrapper key `severityOverrides` was the only non-idiomatic part of
the design — ESLint exposes severity under top-level `rules`, oxlint
exposes it under top-level `rules` + `categories`, and Biome under
`linter.rules`. None wrap it in a multi-word `*Overrides` namespace,
and our own project's existing wrapper namespaces (`ignore`,
`surfaces`) are single-word.

Renames:

- Config field `severityOverrides` → `severity`. The triple
  `ignore` / `surfaces` / `severity` reads as a coherent set of
  single-word namespaces parallel to the rest of the project.
- Type `SeverityOverrideControls` → `RuleSeverityControls`. The value
  type stays `RuleSeverityOverride` so it doesn't collide with the
  plugin's existing `RuleSeverity = "error" | "warn"` (the
  registrable subset).
- File `apply-severity-overrides.ts` → `apply-severity-controls.ts`,
  function `applySeverityOverrides` → `applySeverityControls`. Matches
  the config field's noun form.
- Validation error messages updated from
  `config field "severityOverrides.<x>"` to
  `config field "severity.<x>"`.
- README, changeset, and TODOs.md updated to draw the explicit
  parallel to ESLint's `rules: { ... }` and oxlint's
  `rules: { ... } + categories: { ... }`, plus the extra `tags`
  channel for behavioral families.

All 1158 tests pass.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* refactor: promote severity controls to top-level rules / categories / tags (ESLint shape)

The wrapper namespace was the last non-idiomatic piece. ESLint exposes
severity under top-level `rules` (its hallmark field name and shape).
oxlint exposes `rules` + `categories` at the top level. Promoting our
three channels to the config root gives users the exact field they
already know from ESLint, plus oxlint-shaped `categories` and a
`tags` extension with the same Record-of-severity shape.

Before:

  {
    "severity": {
      "rules":      { "react-doctor/no-array-index-as-key": "error" },
      "categories": { "React Native": "warn" },
      "tags":       { "design": "off" }
    }
  }

After (matches ESLint's flat-config / .eslintrc shape exactly, plus
oxlint's `categories`):

  {
    "rules":      { "react-doctor/no-array-index-as-key": "error" },
    "categories": { "React Native": "warn" },
    "tags":       { "design": "off" }
  }

Changes:

- `ReactDoctorConfig` drops `severity` and gains three top-level
  fields `rules`, `categories`, `tags`. Each is a
  `Record<string, RuleSeverityOverride>`.
- New `buildRuleSeverityControls(config)` adapter assembles the
  internal `RuleSeverityControls` shape from the three top-level
  fields so the resolver and the oxlint config builder don't need
  to know about the public API shape.
- `applySeverityControls` and `runOxlint` switch to the adapter;
  `resolveRuleSeverityOverride` is unchanged (still takes
  `RuleSeverityControls` directly).
- Validation: drops the `severity` wrapper validator; adds a
  shared `validateSeverityMap(fieldName, value)` invoked once per
  top-level field. Error messages now read `config field "rules"` /
  `config field "tags.design"` — matching what the user typed.
- Tests, README, changeset, and TODOs.md updated. README now opens
  the section with "The exact ESLint / oxlint shape" so the parity
  is the first thing a reader sees.

All 1161 tests pass (gained 3 from build-rule-severity-controls.test.ts).

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* ci: retrigger workflow after path filter miss

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* ci: nudge actions queue

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* chore: drop changeset for category-level rule controls

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* docs(readme): tighten severity-controls section

Previous version was 32 lines of intro + 5-bullet behavior reference
+ full tag/category enumeration. Cuts to one intro sentence, a
compact JSON example, and a single paragraph covering precedence and
where the value applies. The full tag/category list is implicit from
the example; the precedence and most-permissive-wins rule are now
one sentence each.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* refactor: drop user-facing severity-by-tag (tags are internal metadata)

Per-tag severity at the top level exposed an internal grouping
concept that doesn't exist in ESLint or oxlint. Tags are
behavioral labels rule authors invent; surfacing them as a
first-class user config field made `react-doctor.config.json`
depend on internal labeling decisions.

Drops the top-level `tags` field. The severity surface is now
strictly ESLint + oxlint shaped:

  - `rules`      — ESLint's exact field
  - `categories` — oxlint's exact field

Recovers the dropped functionality via existing fields:

  - whole-family suppression: `ignore.tags: ["design", ...]`
    (existing field, unchanged)
  - per-channel visibility:   `surfaces.*.{include,exclude}Tags`
    (existing field, unchanged)
  - per-rule severity:        list rules explicitly in `rules`

Code falls out:

  - `RuleSeverityControls.tags` removed
  - `resolveRuleSeverityOverride` collapses to a two-line lookup
    (`rules` -> `categories`); drops the most-permissive-wins
    machinery and the `SEVERITY_RANK` map entirely
  - `buildRuleSeverityControls` drops the tag merge
  - `validate-config-types` SEVERITY_FIELD_NAMES = ["rules", "categories"]
  - `applySeverityControls` destructures only the two channels it
    needs from `getDiagnosticRuleIdentity` (which keeps returning
    tags for surface filters / ignore.tags consumers)

Tests, README, and TODOs updated to reflect the smaller surface.
1169 tests still passing.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-16 22:55:28 -07:00
Aiden Bai ba9c1d4793 fix v0.4.1 2026-05-16 22:31:14 -07:00
Aiden Bai 85969d00c5 fix 2026-05-16 21:42:16 -07:00
Aiden Bai b34c5c4db2 fix(core): replace hand-rolled glob compiler with picomatch + pathological-pattern caps (#284) 2026-05-16 21:15:55 -07:00
Aiden Bai 53e2544870 feat(action): expose --annotations through action.yml (#281)
* feat(action): expose --annotations through action.yml

Adds an opt-in 'annotations' input to the composite action so users
can surface findings as inline GitHub Actions annotations on the PR's
Files changed view. The flag is forwarded to the CLI as --annotations.

When 'github-token' is also set, the captured PR-comment body now
filters out '::error' / '::warning' workflow-command lines so the
sticky summary stays human-readable while the runner still parses
annotations from the live step log.

README documents the three resulting modes: sticky-comment-only
(default), annotations-only, and both.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* docs: tighten action annotations docs, remove em dashes

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* test(action): update contract test for split tee/sed and annotations

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
v0.4.0
2026-05-16 20:43:13 -07:00
Aiden Bai d15cfa761b fix 2026-05-16 20:30:16 -07:00
Aiden Bai afe086a449 fix 2026-05-16 20:27:41 -07:00
Aiden Bai 679e2b01c0 docs: document PR blocking and fail-on semantics (#282) v0.3.2 2026-05-16 20:23:37 -07:00
Aiden Bai 28db33f320 Simplify npx usage (#280) v0.3.1 2026-05-16 20:18:03 -07:00
Aiden Bai 08063c0a62 docs: remove stale dead-code claims after Knip removal (#246) (#283)
* docs: remove stale dead-code claims after Knip removal (#246)

PR #246 removed the bundled knip integration, but several user-facing
docs still advertised dead-code coverage and exposed the removed
`--dead-code` / `--no-dead-code` CLI flags:

- packages/react-doctor/README.md ("and dead code" in the categories list)
- skills/react-doctor/SKILL.md (skill description)
- packages/website/public/llms.txt (CLI options block)

Strips those claims and adds a short migration note pointing users to
`npx knip` directly for dead-code analysis.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

* chore(todos): mark stale dead-code doc cleanup as resolved

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-16 20:16:40 -07:00
Aiden Bai 118741e260 Simplify rule set exports (#277) 2026-05-16 19:58:10 -07:00
Cursor Agent 3bb230f752 Revert "feat(oxlint): add effect/ analyzer primitives for upstream rule port"
This reverts commit 891088c1b0.
2026-05-17 02:08:42 +00:00
Cursor Agent d7efa43fb8 Revert "feat(oxlint): port 8 rules from eslint-plugin-react-you-might-not-need-an-effect"
This reverts commit 86a2a98e7c.
2026-05-17 02:08:42 +00:00
Cursor Agent 86a2a98e7c feat(oxlint): port 8 rules from eslint-plugin-react-you-might-not-need-an-effect
1:1 ports of:
- no-derived-state (avoidDerivedState + avoidSingleSetter branches)
- no-chain-state-updates
- no-event-handler (per-test-identifier reporting, state vs prop variants)
- no-adjust-state-on-prop-change
- no-reset-all-state-on-prop-change (custom-hook skip, full-reset detection)
- no-pass-live-state-to-parent (hook vs component message variants)
- no-pass-data-to-parent (leaf classification, ref/refCurrent exclusions)
- no-initialize-state (mount-only deps detection)

Diagnostic messages match upstream verbatim with template-variable
substitution done in JS. Rules coexist with our existing thematically
related rules (no-derived-state-effect, no-effect-chain,
no-event-trigger-state, no-prop-callback-in-effect); the IDs are
distinct.

Total rule count rises from 179 → 187.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:58:54 +00:00
Cursor Agent 891088c1b0 feat(oxlint): add effect/ analyzer primitives for upstream rule port
Builds the AST-only foundation needed to port the 8 rules from
eslint-plugin-react-you-might-not-need-an-effect (NickvanDyke,
v0.10.1, upstream SHA 4c71faaa7623d2d5feb33983dc2ebcc08206bcc5).

Upstream is ESLint-native and uses context.sourceCode.getScope()
references / resolved.defs[].node.init recursively to chase the
ultimate source of every value. Oxlint plugins have no scope
manager. This commit ports the impedance-bridging analyzer:

- get-effect-deps-array.ts: typed accessor for useEffect(..., deps)
- has-effect-cleanup.ts: matches upstream's loose hasCleanup shape
- is-custom-hook-name.ts: `use[A-Z]` predicate
- is-synchronous.ts: parent-pointer walk bailing on await / void /
  nested function-likes
- get-containing-component-or-hook.ts: classifies the surrounding
  function as component / HOC-wrapped component / custom hook
  (mirrors upstream's pure-HOC short-circuit for memo/forwardRef)
- collect-use-ref-bindings.ts: top-level useRef binding collector
- collect-local-function-bindings.ts: FunctionDeclaration / arrow /
  useCallback bindings with param names + body for indirect-call
  reasoning
- analyze-component-bindings.ts: the cornerstone — classifies every
  component-scope name as state / setter / ref / prop / constant /
  local-function and precomputes localFunctionCalls{StateSetter,
  PropFunction,RefMethod} flags so callees like setX(...) inside an
  intermediateSetter() still register as state-setter calls
- classify-effect-callee-argument.ts: leaf / transitive upstream
  classification used by every rule for argument and deps analysis
- stringify-expression-snippet.ts: bounded AST → text formatter for
  the no-initialize-state "set to ..." message
- create-effect-analyzer-tracker.ts: function-entry / -exit visitor
  pair that maintains the ComponentBindingTable stack

Plus rules/state-and-effects/effect/SOURCE.md with upstream commit
SHA, license attribution, and known divergences.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:54:09 +00:00
Cursor Agent 013d8b060b docs(changelog): replace em-dashes with hyphens across all changelog content
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:52:54 +00:00
Cursor Agent 1ece85187e docs(changelog): rewrite react-doctor 0.0.1..0.0.47 from version diffs
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:49:25 +00:00
Cursor Agent 2f4e722074 docs(changelog): rewrite react-doctor 0.1.0..0.1.6 from version diffs
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:44:45 +00:00
Cursor Agent 9add2d4771 docs(changelog): drop @aidenybai attribution per user request
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:41:00 +00:00
Cursor Agent fad39ccd8a docs(changeset): refresh placeholder changeset bodies with real descriptions
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:08:43 +00:00
Cursor Agent 687b52d9af docs(changelog): rewrite react-doctor 0.2.0-beta.2..beta.5 from version diffs
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:07:52 +00:00
Cursor Agent 65553614fc docs(changelog): rewrite @react-doctor/types 0.2.0-beta.2..beta.3
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:06:09 +00:00
Cursor Agent 60ae4f8b3d docs(changelog): rewrite @react-doctor/project-info 0.2.0-beta.2..beta.3
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:05:42 +00:00
Cursor Agent cbe1dacb64 docs(changelog): rewrite @react-doctor/core 0.2.0-beta.2..beta.5
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:04:56 +00:00
Cursor Agent ede38a3864 docs(changelog): rewrite eslint-plugin-react-doctor 0.2.0-beta.2..beta.5
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:03:47 +00:00
Cursor Agent 56a916c8bb docs(changelog): rewrite oxlint-plugin-react-doctor 0.2.0-beta.2..beta.5 from version diffs
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
2026-05-17 01:03:06 +00:00
Aiden Bai 99f6a6ad1c chore: align all package versions to 0.2.0-beta.5
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-16 04:51:57 -07:00
Aiden Bai 4cbf436848 fix(async-parallel): suppress in tests, browser fixtures, and ordered UI flows (#270) 2026-05-16 04:48:23 -07:00
Nisarg Patel b53d873045 fix(nextjs): stop flagging response.headers and local Map/Set/Headers in GET handlers (#206) (#260)
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-05-16 04:42:49 -07:00
Aiden Bai 838c7f4174 fix(js-length-check-first): detect length guards in larger && chains (#269) 2026-05-16 04:37:17 -07:00
Aiden Bai 3b7cc7c373 fix(no-prevent-default): make rule framework-aware (#274) 2026-05-16 04:29:51 -07:00
Aiden Bai 7a7ec84fad feat: demote design/Tailwind cleanup from default PR comments via per-surface controls (#271) v0.3.0 2026-05-16 04:23:30 -07:00
Aiden Bai d821ca2a82 fix(oxlint): skip js-combine-iterations on lazy Iterator helper chains (#205) (#272) 2026-05-16 04:23:18 -07:00
Aiden Bai 529015d1d8 Scope React Native rules to RN/Expo packages (#266) 2026-05-16 00:30:39 -07:00
Aiden Bai 18b7033e9e fix: avoid async defer await destructuring false positives (#265) 2026-05-15 21:45:34 -07:00
Aiden Bai 8a3a1bee7e update todos 2026-05-15 17:26:49 -07:00
Aiden Bai 2d90c1c5ae fix: scope client secret diagnostics (#252)
* fix: scope client secret diagnostics

Avoid reporting weak secret-name heuristics in config and tooling files, and render framework-specific public env guidance so non-Next.js projects get actionable output.

* fix: broaden secret false-positive guards

Extend the weak client-secret heuristic boundary to common server and tooling paths while keeping exact secret-shape detection active, and move recommendation helpers into focused utilities.

* fix: tighten rc file secret heuristic

Require rc config filenames to be explicit so normal source files like src.ts still use the weak secret-name heuristic.

* test: cover explicit rc secret heuristic

Add regression coverage that explicit rc config files remain outside the weak client-secret name heuristic while regular src.ts files still report.

* fix: refine secret heuristic boundaries

Keep client API helpers covered while making the server-only heuristic exclusions easier to audit.

* chore: format TODO tracker

Format the inherited TODO tracker so PR merge-commit checks can pass.

* fix: classify client secret exposure

Gate the weak secret-name heuristic on explicit client exposure while keeping high-confidence secret values active everywhere.

* test: cover secret exposure boundaries

Lock down client, server, ambiguous-source, and App Router cases for the client-secret heuristic.

* fix: pass framework to secret classifier

Use detected framework settings to avoid path-only client exposure guesses for app directories and server-owned source roots.

* fix: respect use server in secret classifier

Classify use-server modules as server code so client-path heuristics do not report server action constants.

* fix: harden secret exposure edges

Cover mixed server-only scopes, server-owned source roots, and additional client entry shapes so the weak secret heuristic stays scoped to bundled client code.

* fix: refine secret classifier precedence

Classify secret exposure from project-relative paths and gate Next-only route heuristics so explicit client signals win over broad server path names.

* fix: suppress secret label false positives

Avoid weak secret-name diagnostics for UI copy and storage-key prefixes found during evals while preserving client secret fallback coverage.

* fix: preserve api key secret detection

Keep camel-case apiKey variables eligible for the weak secret heuristic while retaining UI text and storage prefix suppressions.

* chore: format changeset prerelease metadata

Keep the new prerelease metadata from main aligned with the repository formatter so CI can pass on the PR merge commit.
2026-05-16 00:32:54 +03:00