Commit 8556b31
authored
feat: address user feedback — reduce false positives, improve scoring transparency, and add config options (#208)
* feat(browser-poc): add AST normalizers for production React analysis
Add 12 AST normalizers that transform minified production code into
patterns the react-doctor plugin rules can analyze. Enables 30+ rules
to fire on production bundles with 0 parse errors and 0 rule failures
across 6 tested sites (vercel, notion, linear, discord, shopify, ami).
Normalizers: SequenceExpression callee unwrap, OXC literal type
normalization, boolean/void recovery, return/expression sequence
splitting, JSX reconstruction (jsx/jsxs/createElement → JSXElement
tree with Fragment, ExpressionContainer, key extraction), setter
binding + reference rename, and component name uppercase recovery.
Also adds parent reference tracking in visitAst, "use client"
directive injection, WASM failure caching for CSP-blocked sites,
truncated source skip, score calculation, and a null-safety fix
for prefer-useReducer.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: address user feedback — reduce false positives, improve scoring transparency, and add config options
- Add `offline`, `designRules`, and `entryFiles` config options
- Suppress React 19 deprecation rules on React 18 (migration-hint gate)
- Skip `rn-no-raw-text` for `.web.*` files (RN platform convention)
- Add sleep/delay and paginated-fetch heuristics to `asyncAwaitInLoop`
- Remove `noEmDashInJsxText` rule (em dashes are standard punctuation)
- Add `designRules` toggle to disable opinionated design rules
- Thread `entryFiles` to knip for dead-code false positive reduction
- Export `calculateScoreBreakdown` and show formula in `--verbose`
- Document scoring formula, diff/staged modes, and agent integration
- Switch to `@changesets/changelog-github` for richer changelogs
- Add GitHub Releases workflow
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor: capabilities-based rule gating system
Replace bespoke flags and filter functions with a unified
capabilities + tags system:
- Add buildCapabilities(project) that derives a flat Set<string>
from ProjectInfo (react:19, nextjs, tanstack-query, etc.)
- Add RULE_METADATA map with requires[] (capability gates) and
tags (static classification like "design", "test-noise")
- Replace filterRulesByReactMajor, filterDesignRules, VERSION_GATED_RULE_IDS,
VersionGateMode, and conditional spreads with one shouldEnableRule predicate
- Replace 9 individual fields on RunOxlintOptions/OxlintConfigOptions
with project: ProjectInfo
- Add ignore.tags to user config (replaces designRules boolean)
- Cherry-pick from cursor/library-aware-deprecation-rules-ec3b:
peerRangeSupportsLegacyReact, isTestFilePath, isLikelyBuildEntry,
parseTailwindMajorMinor, isLikelyStringReceiver (js-set-map-lookups fix)
- Compute effective React version from min(installed, peerRangeFloor)
so library-targeting-legacy is handled by version gating alone
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: library peer-range detection + README designRules cleanup
- Fix Bugbot: peerRangeMinMajor computes the floor major from the peer
range so effective version is min(installed, peerFloor) instead of null
- Fix Bugbot: replace designRules config key with ignore.tags in README
- Add peerRangeMinMajor tests
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: wire isLikelyBuildEntry + isTestFilePath into post-scan suppression
- Add auto-suppression in mergeAndFilterDiagnostics: suppress knip/files
diagnostics when a matching build artifact exists, suppress test-noise
tagged rules in test/fixture files
- Tag deprecation and design rules with "test-noise" in RULE_METADATA
- Fixes Bugbot: isLikelyBuildEntry is no longer dead code
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: remove dead DESIGN_TAGS constant, clear auto-suppression caches
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: remove dead peerRangeSupportsLegacyReact, unused ruleKey param, new Promise false negative
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: forward ignoredTags and entryFiles in diagnose() programmatic API
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: handle destructuring in loop-carried dependency detection
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: apply sleep/dependency heuristics to callback-based iteration
The loopBodyHasOnlySleepLikeAwaits and hasLoopCarriedDependency checks
were only applied in inspectLoopBody (for/while/do-while) but skipped
for callback-based iteration (.forEach, .map, etc.), causing false
positives on patterns like arr.forEach(async item => { await sleep(500) }).
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: guard framework-specific rules against missing RULE_METADATA
Rules from framework-specific maps (NEXTJS_RULES, REACT_NATIVE_RULES,
etc.) without a RULE_METADATA entry were unconditionally enabled for
all projects. Now they are skipped at runtime, and
validateRuleRegistration warns about the gap at dev time.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: scope RULE_METADATA validation to framework-specific rules only
Global rules intentionally omit RULE_METADATA entries since they're
unconditionally enabled. Extracted FRAMEWORK_SPECIFIC_RULE_KEYS to
share the set between the runtime guard and the validation check.
---------1 parent 052cd20 commit 8556b31
45 files changed
Lines changed: 2479 additions & 490 deletions
File tree
- .changeset
- .github/workflows
- packages/react-doctor
- src
- plugin
- rules
- utils
- tests
- fixtures
- basic-react/src
- browser-poc
- regressions
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
234 | 234 | | |
235 | 235 | | |
236 | 236 | | |
| 237 | + | |
237 | 238 | | |
238 | 239 | | |
239 | 240 | | |
240 | 241 | | |
| 242 | + | |
| 243 | + | |
241 | 244 | | |
242 | 245 | | |
243 | 246 | | |
244 | 247 | | |
245 | 248 | | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
246 | 295 | | |
247 | 296 | | |
248 | 297 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
58 | 62 | | |
59 | 63 | | |
60 | 64 | | |
61 | 65 | | |
62 | | - | |
| 66 | + | |
| 67 | + | |
63 | 68 | | |
64 | 69 | | |
65 | 70 | | |
66 | 71 | | |
| 72 | + | |
67 | 73 | | |
| 74 | + | |
68 | 75 | | |
69 | 76 | | |
70 | 77 | | |
| |||
0 commit comments