Commit 10bd788
* fix: detect namespace hook calls (React.useState, React.useEffect) in all rules
Fixes #117: isHookCall now handles MemberExpression callee types
(e.g. React.useEffect, React.useState) in addition to plain Identifier
callee types. This fixes silent misses in no-derived-state-effect,
no-fetch-in-effect, no-cascading-set-state, no-effect-event-handler,
rerender-functional-setstate, rendering-hydration-no-flicker, and
the countSetStateCalls helper.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* fix: remove unsupported jsx-a11y/no-noninteractive-element-interactions rule
Fixes #113, #119: This rule does not exist in the bundled oxlint
binary, causing 'Failed to parse oxlint configuration file' errors
and score suppression on all scans.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* feat: add --no flag to skip prompts and always run full scan
Fixes #106: Adds -n/--no flag that skips all interactive prompts
(like --yes) but specifically declines the diff-only scan prompt,
ensuring a full project scan runs. Useful for CI agents that cannot
interact with TTY prompts.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* test: add namespace hook detection tests (React.useEffect, React.useState, etc.)
Adds 13 tests verifying that all rules correctly detect namespace-style
hook calls (import * as React; React.useEffect, React.useState, etc.).
Covers: no-derived-state-effect, no-fetch-in-effect, no-cascading-set-state,
no-effect-event-handler, no-derived-useState, rerender-lazy-state-init,
rerender-functional-setstate, rerender-dependencies, rendering-hydration-no-flicker,
no-usememo-simple-expression, prefer-useReducer, plus a regression guard for
direct-import fixtures.
Relates to #117.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* test: add edge case tests for project discovery and catalog resolution
Adds tests for:
- peerDependencies-only with catalog reference resolution
- Catalog reference to nonexistent catalog name (fallback to default)
- Empty pnpm-workspace.yaml handling
- Malformed package.json in workspace subdirectories
- Nonexistent root directory for discoverReactSubprojects
- File entries mixed with directory entries in project root
Relates to #101, #87, #105, #71.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* fix: handle malformed JSON in workspace package.json files gracefully
readPackageJson now catches SyntaxError from malformed JSON and returns
an empty object instead of crashing. This prevents workspace discovery
from aborting when a subdirectory has an invalid package.json.
Previously, a broken package.json in any workspace subdirectory would
crash the entire scan with an unhandled SyntaxError.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* feat: add customRulesOnly config to disable builtin react/jsx-a11y rules
Fixes #109: Teams with existing ESLint setups can now set
customRulesOnly: true in react-doctor.config.json to only run
react-doctor/* custom rules, skipping the bundled react/, jsx-a11y/,
react-perf, and react-compiler rules.
This avoids rule duplication for projects that already lint with
eslint-plugin-react, eslint-plugin-jsx-a11y, etc.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* feat: inherit config from ancestor directories for monorepo support
Fixes #73: loadConfig now walks up the directory tree to find
react-doctor.config.json or package.json reactDoctor key from
ancestor directories. This means a single config at the monorepo
root applies to all workspace packages without needing to duplicate
the config in each package.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* feat: add --annotations flag for GitHub Actions annotation output
Fixes #81: The --annotations flag outputs diagnostics in GitHub
Actions annotation format (::error / ::warning) so they appear
as inline annotations on PR diffs. Example:
::error file=src/App.tsx,line=42,title=react-doctor/no-fetch-in-effect::fetch() inside useEffect
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* refactor: remove Ami integration
Removes all Ami-related code:
- --ami flag, --fix flag, fix subcommand, install-ami subcommand
- Ami detection, installation, deeplinks, and open-URL helpers
- Fix prompt (maybePromptFix) with Ami banners
- Skill installation prompt (maybePromptSkillInstall)
- fetchEstimatedScore and EstimatedScoreResult
- AMI_WEBSITE_URL, AMI_INSTALL_URL, AMI_RELEASES_URL, OPEN_BASE_URL,
ESTIMATE_SCORE_API_URL, ERROR_ESTIMATED_FIX_RATE, WARNING_ESTIMATED_FIX_RATE
- skill-prompt.ts utility
CLI bundle reduced by ~39KB (324KB → 285KB).
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* chore: remove .ami directory and all remaining Ami references
- Delete .ami/ directory (42 skill/config files)
- Delete packages/website/src/app/open/ (Ami redirect page)
- Remove Ami references from README.md, share page, install-skill
route, llms.txt, and install-skill.sh
- Zero Ami references remain in the codebase
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* chore: move .ami/skills to .agents/skills
Relocates all skill files from the deleted .ami/ directory into
.agents/skills/ and removes .agents from .gitignore so they are
tracked in version control.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* fix: recognize custom text components in rn-no-raw-text rule
Fixes #93: The rn-no-raw-text rule now recognizes a much wider set of
text-handling components:
1. Expanded built-in names: Typography, Paragraph, Span, H1-H6
2. Keyword matching instead of suffix-only: any component whose name
contains Text, Title, Label, Heading, Caption, Subtitle, Typography,
Paragraph, Description, or Body is treated as text-handling
(e.g. StyledText, BodyText, CustomLabel, MyTypography)
3. New textComponents config option: users can specify arbitrary
component names in react-doctor.config.json that should be treated
as text-handling:
{
"textComponents": ["MyCustomComp", "NativeWindText"]
}
Diagnostics inside these components are filtered out post-lint.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* chore: upgrade dependencies
- oxlint: 1.47.0 → 1.59.0 (fixes SIGABRT crashes on large projects #84/#77)
- oxfmt: 0.32.0 → 0.44.0
- typescript: 5.9.3 → 6.0.2
- vitest: 4.0.18 → 4.1.4
- tsdown: 0.20.3 → 0.21.7
- knip: 5.83.1 → 6.3.1
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* fix: add file count limit per oxlint batch to prevent OOM crashes
Mitigates #84/#77: Adds OXLINT_MAX_FILES_PER_BATCH (500) to cap the
number of files per oxlint invocation. Combined with the oxlint upgrade
from 1.47 to 1.59, this prevents SIGABRT/OOM crashes on large projects
with 100+ source files.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* feat: add --staged flag for pre-commit hook scanning
Fixes #115: The --staged flag scans only files in the git index
(staged with git add). It materializes staged content to a temp
directory so oxlint reads the exact index version, not the working
tree version. This is critical for pre-commit hooks where the working
tree may differ from what's being committed.
Usage:
npx react-doctor . --staged --fail-on error
For lint-staged:
"*.{tsx,jsx}": "npx react-doctor . --staged --fail-on error"
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* refactor: code review fixes per AGENTS.md rules
- DRY: Extract shared createFileLinesCache in filter-diagnostics.ts
- DRY: Extract resolveFailOnLevel in cli.ts (was duplicated in
staged and normal paths)
- DRY: Reuse exported getCalleeName from helpers.ts instead of
duplicating in state-and-effects.ts and performance.ts
- Magic number: Move maxBuffer 10MB to GIT_SHOW_MAX_BUFFER_BYTES constant
- Variable naming: prevLine → previousLine, tagName → fullTagName,
leafName → leafTagName, configFiles → projectConfigFilenames
- Remove .pop()! non-null assertion in favor of .at(-1) with fallback
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* fix: prevent shell injection in staged file content reading
Replace execSync with string interpolation with spawnSync using an
args array. File paths with shell metacharacters (quotes, semicolons,
etc.) in their names are now passed safely without shell interpretation.
Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
* fix: pass resolved config to staged scan to preserve ancestor inheritance
The staged scan materializes files to /tmp, where loadConfig's ancestor
traversal would never find a monorepo root's config. Now the CLI resolves
config from the real project directory first and passes it via the new
configOverride ScanOption, so customRulesOnly, share, ignore rules,
and textComponents all apply correctly during --staged scans.
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>
1 parent 66e1318 commit 10bd788
File tree
75 files changed
+1632
-1236
lines changed- .agents/skills
- animation-best-practices
- remotion-best-practices
- rules
- assets
- packages
- react-doctor
- src
- plugin
- rules
- utils
- tests
- fixtures/basic-react/src
- website
- public
- src/app
- install-skill
- open
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
75 files changed
+1632
-1236
lines changed
0 commit comments