chore(deps): update dependency react-doctor to v0.5.6 - #25
Merged
Conversation
renovate
Bot
force-pushed
the
renovate/react-doctor-0.x
branch
2 times, most recently
from
June 16, 2026 17:54
1fcd80d to
f2909ea
Compare
renovate
Bot
force-pushed
the
renovate/react-doctor-0.x
branch
from
June 17, 2026 03:46
f2909ea to
8e0f6e9
Compare
renovate
Bot
force-pushed
the
renovate/react-doctor-0.x
branch
from
June 20, 2026 04:47
8e0f6e9 to
93dcb76
Compare
renovate
Bot
force-pushed
the
renovate/react-doctor-0.x
branch
from
June 20, 2026 11:23
93dcb76 to
94db681
Compare
renovate
Bot
force-pushed
the
renovate/react-doctor-0.x
branch
from
June 21, 2026 04:55
94db681 to
5ad8ab6
Compare
renovate
Bot
force-pushed
the
renovate/react-doctor-0.x
branch
from
June 22, 2026 14:01
5ad8ab6 to
578f540
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
0.2.8→0.5.6Release Notes
millionco/react-doctor (react-doctor)
v0.5.6Compare Source
Patch Changes
#812
ea3b827Thanks @aidenybai! - Add fivesecurity-scanrules distilled from security-researcher writeups and the deepsec scanner-matcher catalog, closing CWE shapes the bucket didn't cover:unsafe-json-in-html—JSON.stringify(...)embedded indangerouslySetInnerHTMLor inline<script>markup.JSON.stringifydoes not HTML-escape, so data containing</script>or<breaks out — the classic SSR data-hydration XSS. Suppressed when an HTML-safe serializer (serialize-javascript, devalue, superjson) or\u003cescaping is used.jwt-insecure-verification— the JWTnonealgorithm (alg: none/algorithms: ["none"]), which disables signature verification and lets any forged token through. (Detecting an unpinnedjwt.verifyprecisely needs scope-aware analysis, so that is left to a future AST rule.)secret-in-fallback— a secret-shaped env var with a hardcoded string fallback (process.env.STRIPE_SECRET_KEY ?? "<hardcoded>"): a committed secret that also makes the app fail open when the var is unset. Skips public vars (PUBLIC/PUBLISHABLE/ANON) and placeholder defaults.request-body-mass-assignment— spreading or merging request input ({ ...req.body },Object.assign(target, req.body), lodashmerge/defaultsDeep) without a field allowlist: mass assignment (client-set owner/role/price columns) or prototype pollution.insecure-session-cookie— auth/session cookies exposed to JavaScript:httpOnly: false, set viadocument.cookie, or a bareres.cookie("session", value)/cookies().set(...)with no options.All five register through
defineRulewith a project-levelscan, carry theSecuritycategory andsecurity-scantag, and are silenced byreact-doctor rules ignore-tag security-scanlike the rest of the family.#824
cf9e05bThanks @aidenybai! - Show the full file total when the scan hands off to dead-code analysis, so the live counter no longer looks stuck belowN(#815).The linter already emits a final
(N, N)progress tick when its last batch finishes, but ora throttles renders to its frame interval — that last frame was overwritten by the"Analyzing dead code…"text before it ever painted, so the spinner appeared to freeze at whatever value the smooth-creep timer last drew (e.g.80/165). Every file was always scanned; only the counter looked short. The dead-code phase now readsScanned N files, analyzing dead code…, keeping the complete count visible for the whole (longer) dead-code pass.#819
5fc0e27Thanks @aidenybai! - Fix false positives reported in the security and TanStack rules:query-destructure-result(#818): only flagsuseQuery/useSuspenseQuery/… when they actually come from a TanStack Query package (@tanstack/*-query, legacyreact-query). A same-named hook imported from elsewhere — notably Convex'suseQueryfromconvex/react, which returns the data directly — is no longer flagged.artifact-env-leak/artifact-secret-leak(#816, #817): no longer treat server-side or dev-mode Next.js output as browser artifacts..next/dev/server/**(dev source maps), any.next/**/server/**,.output/server/**, and the dev server's.next/dev/**output are excluded; production browser bundles (.next/static,dist/assets,public/, …) are still scanned.repository-secret-file/key-lifecycle-risk(#813): no longer flag a credential/key file that git ignores — a local-only, gitignored.envis not "checked into the repository". Findings are dropped only when git definitively reports the path as ignored (the finding stands when there is no repo or git is unavailable).webhook-signature-risk(#814): recognizes a delegated verification helper (a call pairing a verify-ish verb with a security noun, e.g.isValidSecret(...),verifySignature(...),checkWebhookHmac(...)) as verification evidence, so an extractedtimingSafeEqualcomparison in another module no longer trips the rule.#812
ea3b827Thanks @aidenybai! - Add asupabase-table-missing-rlssecurity-scan rule. It flags a Supabase migration (supabase/migrations/**,supabase/schemas/**) that runscreate tablefor a public-schema table but never enables Row Level Security — the highest-impact and most common Supabase misconfiguration, because RLS is OFF by default for SQL-created tables, so every row is readable and writable with the public anon key. It targets the same misconfiguration Supabase's ownrls_disabled_in_publicdatabase linter flags, and the gap that turns the public anon key into the service key.The existing
supabase-rls-policy-riskonly caught an explicitdisable row level security; this complements it by catching the far more common "never enabled it" case. RLS is checked per table — eachcreate tablemust have analter table <name> enable row level securityfor that same table, after the create (a sibling table enabling RLS, or a policy without enabling it, does not vouch). SQL comments and string literals are ignored, non-public/Supabase-managed schemas (auth.,storage., aprivate.schema, …) are skipped, and the rule is scoped to thesupabase/directory so plain Drizzle/Prisma.sqlmigrations are not flagged. The scan runs per migration file, so enabling RLS in a different migration than thecreate tableis not detected — the same-file pattern (what Supabase tooling emits) is the supported case. Like the rest of the family it carries thesecurity-scantag and is silenced byreact-doctor rules ignore-tag security-scan.#823
bac7c82Thanks @rayhanadev! - Fix a supply-chain scan crash on npm dist-tags and wildcards (#807).resolveConcreteVersioncalledsemver.minVersion(spec)directly, butsemverthrows (TypeError: Invalid comparator: latest) on a non-range spec instead of returningnull. Any full scan — or PR scan touchingpackage.json— containing a dist-tag like"trigger.dev": "latest"(or"next") crashed before the Socket fail-open path could run (regression from #804, affecting 0.5.3–0.5.5).The spec is now validated with
semver.validRangebefore resolving its floor: dist-tags and other non-ranges are skipped (nothing to score), as is a wildcard-only range (*/x/X), which previously resolved to a synthetic0.0.0and scored a version nobody pinned. Real ranges (^1.2.3,1.x,>=2 <3) and protocol/URL specs (workspace:,file:,npm:,git+…) are unchanged.Updated dependencies [
ea3b827,5fc0e27,ea3b827]:v0.5.5Compare Source
Patch Changes
e90eb7a]:v0.5.4Compare Source
Patch Changes
#744
eacdcf2Thanks @aidenybai! - Add a project-level security file scan: 36 first-class scan rules (leaked artifact secrets and env dumps, permissive Firebase/Supabase rules, raw SQL injection risk, unsafe webhook signature comparisons, committed private key material, public debug artifacts, …) ship in the oxlint plugin as ordinarydefineRulemodules that declare a project-levelscaninstead of AST visitors and run in@react-doctor/core's environment-check phase over one bounded whole-tree walk — covering shipped bundles, dotenv/config files, SQL, and Firebase rules files that per-file linting never sees.Scan rules register metadata (id, title, severity, recommendation,
Securitycategory,security-scantag) like any other rule but carry a project-levelscaninstead of AST visitors, so their findings flow through the standard diagnostic pipeline: per-rule and per-category severity overrides, inline disables, and outputsurfacesnow apply to scan-rule diagnostics, andreact-doctor rules ignore-tag security-scan(configignore.tags) silences the whole family. They never appear in generated oxlint configs or the ESLint presets — they only execute through React Doctor's scan. A plain--diff/--stagedscan skips them like the other whole-project checks, and the gate is now diff mode itself rather than the presence of include paths, so projects configuringignore.filesget the security scan too.#744
eacdcf2Thanks @aidenybai! - Remove the--sfwdemo flag (the standalone Socket.dev supply-chain score listing that printed every direct dependency's score and exited).The Socket.dev supply-chain check is unaffected — it still runs during normal full scans (and on diff scans whose
package.jsonchanged) and its scores still appear in the JSON report. Only the standalone listing is gone, along with its demo-only internals (collectSupplyChainScores, theDependencyScoretype, the monorepo-wide dependency collector, and the score-table renderer).Updated dependencies [
eacdcf2,eacdcf2]:v0.5.3Compare Source
Patch Changes
#804
022790bThanks @NisargIO! - Clearer Socket supply-chain diagnostics (socket/low-supply-chain-score). When Socket returns a concrete alert, the message now names it — e.g. a critical "known malware" alert, the offending file, and a one-line description — instead of only a bare score; when it doesn't (metric-driven dips like CVE-only scores), the message explains what the failing axis means. The help is now axis-aware: remove a package flagged as compromised, upgrade past known vulnerabilities (npm audit), or vet-and-raise the threshold — rather than a generic "update or replace". The headline leads with the exact failing axis and collapses the redundant "declared as X, scored at X" phrasing (a range now readspkg@floor (lowest version "^x.y.z" allows)). JSON report shape is unchanged (schemaVersion: 1).Updated dependencies []:
v0.5.2Compare Source
Patch Changes
#767
486c68fThanks @rayhanadev! - The GitHub Action'sblockinginput now defaults tonone(advisory) instead oferror. Every PR still gets the full React Doctor report — the sticky summary comment, inline review comments, and a commit status with the health score — but the check no longer fails on findings, so a brand-new install can't red-X a teammate's PR on day one (trust-before-gate). To turn the gate back on, setblocking: warning(fail on any finding) orblocking: error(fail on error-severity findings) on the action. The generatedreact-doctor.ymldocuments this inline.Note: this changes behavior for existing
millionco/react-doctor@v2workflows that never setblocking— they were gating on error-severity findings and will now run advisory. Addblocking: errorto the action'swith:block to keep the previous behavior.The CLI / config default is unchanged:
react-doctor(and--blocking/ theblockingconfig key) still defaults toerror, so local runs, pre-commit hooks, and non-action CI keep failing on error-severity findings.#766
94f9f4fThanks @devin-ai-integration! - Bumpengines.nodeto^20.19.0 || >=22.13.0so the declared support range matches transitive dependencies (eslint-scope@9,eslint-visitor-keys@5require^22.13.0), preventing EBADENGINE warnings on npm and hard install failures on Yarn 1 under Node 22.12.x.#731
1ca6f0eThanks @aidenybai! - Bundle Effect into the published CLI sonpx react-doctor@latestno longer installs Effect'sini@7dependency and avoids the Node 22.19 engine warning.#791
22268f7Thanks @rayhanadev! - Cap theoxlintdependency to>=1.66.0 <1.67.0. oxlint 1.67.0 added an optional peer dependency onvite-plus, which in pnpm workspaces that installvite-plusat the root forces a second peer-resolution context for the Vite+ toolchain. That split installs a duplicate copy of the Vitest fork (@voidzero-dev/vite-plus-test), and test runs fail at collection withVitest failed to find the current suitebecause hooks register in one copy while suites live in the other (#699). Pinning below 1.67 keeps react-doctor's oxlint free of thevite-pluspeer edge, so pnpm dedupes the toolchain back to a single instance.#793
9cc6555Thanks @devin-ai-integration! - Carry the React Compiler bail-out reason in the primary diagnostic message.react-hooks-js/*diagnostics previously all rendered the same generic "This component misses React Compiler's automatic memoization…" message, with the specific reason relegated tohelp. The message now includes the first line of the compiler's reason (e.g.useMemo() callbacks may not be async or generator functions) so contexts that only show the message explain why the compiler bailed; the reason's remaining lines stay inhelp, so the rendered message + suggestion never repeat the same sentence.tododiagnostics keep the generic message — their reasons are compiler-internal work notes, not user-facing copy. Because diagnostics dedupe on their full message, two different bail-out reasons anchored at the same source location now survive as two diagnostics instead of collapsing into one, so counts can rise slightly on affected projects.#800
3de9106Thanks @devin-ai-integration! - Loaddoctor.config.tsfiles that importdefineConfigfromreact-doctor/apieven when the scanned repo has no installed node_modules (e.g. the GitHub Action runs the CLI vianpm execwithout installing the repo's dependencies). The config loader now retries the load withreact-doctor/apialiased to the running package's own copy instead of silently falling back to default config.#769
2f26228Thanks @rayhanadev! - Consolidate the scan-scope controls into one--scopeflag (andscopeconfig option) with four values, shared verbatim by the CLI and the GitHub Action:full(default) — the whole project, every issue. Whole-project checks (dead-code, environment, supply-chain) run only here.files— only the files changed vs the base, with all issues in them (no compare-to-main). What--stagedand an uncommitted--diffdid.changed— only issues the change introduced vs the base (the baseline delta). What--diff <base>and the action'sscope: changeddid.lines— only issues on the lines the change actually touched. New: previously this scoping existed only inside the GitHub Action's inline-review-comment step; it now lives in the engine, so the CI gate, score display, summary, and inline comments all honor one scope.--base <ref>sets the comparison base forfiles/changed/lines(auto-detected when omitted). Behavior is unchanged by default: the CLI--scopedefaults tofulland the actionscopeinput still defaults tochanged.--diff/config.diffkeep working as a deprecated alias (--diff <base>→--scope changed --base <base>,--diff false→--scope full) and emit a one-time deprecation warning;--stagedis retained as the source selector and composes with--scope files/--scope lines.#795
04e72a4Thanks @devin-ai-integration! - Diagnostics in test, spec, fixture, and Storybook files are now labeled with their file context. The terminal report and the per-rule text dumps tag those sites as(test file)/(story file)so a finding in a spec doesn't read as a production problem, and each diagnostic in the JSON report carries an optionalfileContextfield ("test"/"story"; omitted for production files). The classification reuses the same path heuristics that already drive test-noise auto-suppression, so the label and the suppression can never disagree.#784
038aaf7Thanks @rayhanadev! - Fix a false positive innextjs-missing-metadata(#775): an App Router page is no longer flagged as "missing metadata for search previews" when it inheritsmetadata/generateMetadatafrom a co-located or ancestorlayout.*. Next.js merges metadata down the segment chain, so a page covered by a parent layout's title/description already has search-preview metadata. The rule now walks up the App Router directory tree (bounded, stopping atapp/) and stays quiet when an ancestor layout supplies metadata; pages with no metadata anywhere in the chain are still flagged.#768
a64093cThanks @rayhanadev! - CI onboarding now resolves the repository's actual default branch instead of assumingmain. The pull request opened during setup asks GitHub (gh repo view) for the default branch — falling back toorigin/HEAD, thenmain/master— and uses it as the PR base, and the installed workflow's push trigger scans that same branch (master,develop, …) so the health-score trend works on repos whose default branch isn'tmain.#783
a48fb06Thanks @devin-ai-integration! - Add a--output-dir <dir>flag that writes the full diagnostics dump (diagnostics.json + one .txt per rule) to a directory of your choice instead of a random temp folder, prints the written path whenever the flag is set (previously--verbose-only), and makes the agent handoff reuse that directory instead of writing a second temp copy. Without the flag, behavior is unchanged.#792
19d99eeThanks @devin-ai-integration! - Titlereact-hooks-js/tododiagnostics "React Compiler doesn't support this syntax" instead of the generic "React Compiler can't optimize this" headline. Thetodorule fires when the compiler bails out on syntax it doesn't handle yet, so the headline now says what actually happened.#801
0f91fa3Thanks @devin-ai-integration! - Addrn-no-metro-babel-runtime-version— warns when a babel config usesmodule:@​react-native/babel-presetwithout anenableBabelRuntimeversion. Without a version the preset can duplicate Babel runtime helpers across files instead of importing them once from@babel/runtime, increasing the JS bundle (facebook/react-native#57123). It fires as awarning(a bundle-size optimization, not a broken build, so it never blocks CI on the default React Native config), only when the preset is referenced as a real string literal (Expo'sbabel-preset-expoand comment mentions are unaffected), and treatsenableBabelRuntime: true/falseas still missing a version.#790
f52bd07Thanks @devin-ai-integration! - Fix false positives inrn-no-raw-text(#788) for custom components that forward their children into a<Text>: the in-file wrapper detection now recognizes components that render{children}(or{props.children}) inside a nested<Text>(the<View><Text>{children}</Text></View>shape), not just components whose returned root is a<Text>. Detection also handles parenthesizedreturn (...)bodies,memo/forwardRef-wrapped components, fragment roots, conditional and logical returns, early returns insideifbranches, renamed destructured children ({ children: content }), the<Text children={children} />prop form, wrappers that forward through another in-file wrapper, children aliased to a variable or destructured from props in the body, props spreads that carry children (<Text {...props} />,<Text {...rest} />,<Text {...this.props} />), class components, andstyled(Text)/styled.Textfactories. The rule is also taggedtest-noise, so it no longer fires in test/story files — raw text rendered through React Native Testing Library never ships to users, and cross-file wrappers (an imported<Chip>Test Chip</Chip>in a.test.tsx) were the main source of unfixable noise there.#780
f5f539aThanks @rayhanadev! - The Socket supply-chain check now gates on the security axes (supply chain, vulnerability) instead of Socket'soverallscore, and the diagnostic names the exact axis that failed. Socket'soverallis its lowest axis, so a package with perfect security scores could fail the Security gate purely on quality/maintenance —@types/bunwas reported as having a "supply-chain score of 48" while socket.dev showed Supply Chain 100 (issue #770). Known-bad packages (event-stream@3.3.6, vulnerableminimist/lodashreleases) are still flagged via their vulnerability axis, and the reported number now always matches the axis named on the socket.dev package page.Updated dependencies [
94f9f4f,038aaf7,fee3fc4,c4f0e60,f52bd07,7c88165]:v0.5.1Compare Source
Patch Changes
77a70ab]:v0.5.0Compare Source
Minor Changes
#756
93d4eecThanks @NisargIO! - React Doctor now runs on repositories that don't depend on React. Previously a scan hard-failed withNo React project found/No React dependency, even though many checks (security, bundle size, JS performance, architecture, and the Zod rules) are framework-agnostic and apply to any TypeScript / JavaScript codebase.A project is now analyzable when it has source files, with or without React. A bare directory of TypeScript files — including a monorepo's
packages/subfolder that has nopackage.jsonof its own — is scanned by inheriting dependency/framework detection from the enclosing workspace root.React-flavoured rules stay off without React. A new
reactcapability (set only when React or Preact is present) gates every React-runtime rule family (hooks, JSX, accessibility, render performance, React state) plus any rule taggedreact-jsx-only, so hook/component-name heuristics likerules-of-hooks,no-legacy-class-lifecycles, andno-nested-component-definitioncan't false-fire on ordinary TypeScript. Once React (or Preact) is detected, every rule behaves exactly as before.#747
a254414Thanks @NisargIO! - Add a--sfwdemo flag that prints the Socket.dev supply-chain score (0–100) of every direct dependency — across every workspacepackage.jsonin a monorepo, de-duplicated byname@version— color-coded and sorted worst-first, then exits without running a scan. Scores come from Socket's free, keyless PURL endpoint (the same one the supply-chain check uses).#747
a254414Thanks @NisargIO! - Add a Socket.dev supply-chain score check. Every direct dependency inpackage.jsonis scored against Socket's free, keyless PURL endpoint (the same lookup Socket Firewall's free tier uses) and any dependency whose Socket score falls belowsupplyChain.minScore(default50, 0–100 scale) produces aSecuritydiagnostic anchored at the offendingpackage.jsonentry. At the defaultseverity: "error"a low score fails the scan at the standardblockinggate.The check runs by default; opt out with
supplyChain: { enabled: false }. It is fail-open (per-package timeouts / network failures are skipped, never sinking the scan). A plain--diff/--stagedscan skips it like the other whole-project checks, but a diff that edits apackage.json(including any workspace's in a monorepo) still scores that project's dependencies — so a PR that adds or bumps a dependency is covered.nextis excluded (its framework-specific risks are already covered by the Next.js / server-components rules).Patch Changes
#739
829655cThanks @NisargIO! - CI setup: collapsed the multi-line inline comments in the generated.github/workflows/react-doctor.ymlto a single explanatory sentence per trigger and one line for the concurrency block, and dropped the permissions comment (the four well-named keys are self-explanatory). The resulting workflow still configures the same triggers, permissions, and action ref — just with less scrolling for new users.#729
25cc69bThanks @aidenybai! - Fold the standalonedoctor-explainskill into thereact-doctorskill asreferences/explain.md.Rule-explanation and config-tuning guidance now ships as an on-demand reference inside the primary skill (per the agentskills.io
references/convention) instead of a separate sibling skill.react-doctor installinstalls a single skill, and the dead bundled-sibling-skill install machinery is removed.#752
5b06a86Thanks @rayhanadev! - Name every unused dependency in the verbose warning tail.Unused-dependency warnings all report at the same line-less location (
package.json:0), so the dim location header collapsed every finding into one line and dropped the package names — leaving only a genericdeslop/unused-dependency ×Nline (#690).react-doctor --verbosenow lists eachdeslop/unused-dependencyanddeslop/unused-dev-dependencyby name, with the shared "why" explanation shown once instead of repeated per package. Errors and code-frame rendering are unchanged.Updated dependencies [
b4b79ad,af98f83,93d4eec]:v0.4.2Compare Source
Patch Changes
#721
d17dc87Thanks @aidenybai! - Add adefineConfighelper for authoring a typeddoctor.config.{ts,js,mjs,cjs}and readreact-doctor.config.jsonas a deprecated fallback.defineConfigis exported fromreact-doctor/api(and@react-doctor/api/@react-doctor/core) as an identity helper that gives editor autocomplete and type-checking without an explicitsatisfies ReactDoctorConfigannotation:The pre-migration
react-doctor.config.jsonfilename is now read as the lowest-priority fallback (afterdoctor.config.*andpackage.json#reactDoctor) instead of being ignored, so an un-migrated config keeps applying. It still emits a deprecation warning nudging a rename, and interactive runs continue to auto-migrate it todoctor.config.ts. A present-but-broken legacy file stops config resolution (it won't silently inherit an ancestor repo's config), andreact-doctor rules <...>migrates a legacy file todoctor.config.jsonon write rather than editing it in place.Note: a
react-doctor.config.jsonthat was previously ignored in non-interactive runs (CI, coding agents,--json/--score/--staged) is now honored again, which can change which rules fire, the score, and PR gating for projects that still have one. Rename it todoctor.config.json(or delete it) to avoid surprises.Updated dependencies []:
v0.4.1Compare Source
Patch Changes
#711
36ecd05Thanks @devin-ai-integration! - Fix false positive inrequire-reduced-motion: the check now searches untracked files so newly created source (e.g. aproviders.tsxwith<MotionConfig reducedMotion="user">not yet committed) is detected.#706
15bd9d8Thanks @rayhanadev! - CI setup now offers a one-time, per-repo prompt to upgrade an existing React Doctor GitHub Actions workflow from@v1to@v2— accepting opens a PR with the bump, declining is remembered so it never asks again. The generated / "Add to CI" workflow now pinsmillionco/react-doctor@v2and grantsstatuses: write, so the action can publish the score as a commit status (and surface results on pushes to the default branch).Updated dependencies [
dc35070,b1a22ef,73dcb20,64667da,ee9ab33,fe5f3de,831cf3f]:v0.4.0Compare Source
Minor Changes
#663
9a8ad6eThanks @rayhanadev! - Rework CI reporting: a renamedblockinggate, PR-introduced-issues-only baselines, inline PR review comments, and a simpler CLI flag surface.CI gate
fail-onis renamed toblocking(CLI--blocking <level>, configblocking, GitHub Actionblockinginput). Sameerror | warning | nonevalues, defaulterror: a scan fails CI when anerror-severity diagnostic reaches theciFailuresurface;warningblocks on any diagnostic;nonestays advisory (always exits 0).--fail-on/failOnstill work as a deprecated, warned alias hidden from--help.--blocking warningnow wins over--no-warnings(it previously silently no-op'd the gate — you can't block on warnings you've hidden).Baseline — report only the issues a PR introduces (Codecov-style)
--diff <base>mode, react-doctor runs a second lint pass over the changed files as they existed at the base merge-base and reports only the diagnostics the change introduced; pre-existing findings that merely shifted lines are matched out by a content fingerprint (file + rule + flagged-line hash). The head project-health score is unchanged; the gate fails on newly-introduced errors only. If the baseline can't be computed (base unreachable, or a lint pass failed), the run degrades to a plain diff — all findings stay visible and CI isn't gated on findings whose new-vs-pre-existing attribution is unknown.computeDiagnosticDelta,Git.showRefContent/Git.mergeBase,materializeSourceTree, andInspectOptions.baseline/InspectResult.baselineDelta.schemaVersion: 2with abaselineblock (newCount,fixedCount,baseTotalCount) andmode: "baseline";summary.scorestays the head score. v1 reports are unchanged.GitHub Action
annotationsinput was removed.fetch-depth: 0onactions/checkout. Newfixed-issuesoutput. Defaults:project: "*",node-version: 24.CLI flags (fewer flags, fewer footguns)
--explain/--why→ thereact-doctor why <file>:<line>subcommand (rules explain <rule>still explains what a rule means).--full(use--diff falseto force a full scan),--pr-comment(the Action renders its comment from--json), and the positive--respect-inline-disables(already the default; use--no-respect-inline-disablesfor audit mode). The internal--changed-files-fromis hidden from--help.--projectfilter (e.g.--project ",") is rejected.Patch Changes
#681
915745eThanks @rayhanadev! - Addreact-doctor experimental-lsp, an experimental language server that surfaces React Doctor diagnostics directly in your editor — VS Code, Cursor, Zed, Neovim, Sublime Text, Emacs, Helix, or any LSP client. It is gated behind theexperimental-prefix while its protocol, caching, and diagnostics stabilize. It scans the file you are editing live from the unsaved buffer, underlines the exact offending token via precise ranges, shows rich hovers (rule, category, recommendation, docs link), and offers quick fixes (disable-for-this-line with the correct comment style, suppress-all-in-file, explain, open docs, report false positive). It discovers every React project across workspace folders and monorepo packages, runs offline (no score lookup, no git), prioritizes open-buffer scans, supports push and pull diagnostics, and invalidates caches when config / package.json / lockfiles change. The background workspace scan is chunked so diagnostics stream in progressively (seconds to first results on large repos), parallelizes across all CPU cores, reserves a slot so edits stay responsive while it runs, and cancels in-flight work when config changes. Results are cached per file (by content metadata, invalidated on config change) and persisted to disk, so re-opening the editor or re-scanning surfaces diagnostics almost instantly — on an ~8,800-file repo a cold scan is ~27s and a warm scan ~2s.Start it with
react-doctor experimental-lsp --stdio(ornpx react-doctor@latest experimental-lsp --stdio). AscanOnTypeinitialization option toggles live-as-you-type scanning, with first-class companion extensions for VS Code/Cursor and Zed.Like the CLI, the language server reports anonymized usage analytics to Sentry — a per-workspace-scan wide event plus session/scan counters — sharing the CLI's IP-stripping and path/secret scrubbing. Opt out with
REACT_DOCTOR_NO_TELEMETRY=1(or by launching it with--no-telemetry).Updated dependencies []:
v0.3.0Compare Source
Minor Changes
#658
cbdff62Thanks @aidenybai! - Add an "Add to CI" path to the post-scan handoff and makeinstallset up CI by default.The post-scan prompt now leads with an "Add to CI" choice (the default) that installs the
react-doctordev dependency +doctorscript and writes a.github/workflows/react-doctor.ymlGitHub Actions workflow so every pull request is scanned. When you instead hand off to an agent, the generated prompt now asks the agent to offer CI setup first. Theinstallsubcommand pre-selects the workflow andinstall --yesnow writes it by default. The workflow's action is pinned to the@v1floating major (never@main, per the supply-chain guidance in issue #299).Patch Changes
#676
08e1d55Thanks @devin-ai-integration! -react-doctor --full --yesno longer errors with "Cannot combine --yes and --full; pick one."--yes(skip prompts, scan all workspace projects) and--full(force a full scan, overriding anydiffvalue) control orthogonal concerns, so combining them is a valid request — "scan every workspace project fully, without prompting." The mutual-exclusion check that rejected the pair has been removed.#674
6851a78Thanks @aidenybai! - Bump bundleddeslop-jsto^0.0.17, which stopsdeslop/unused-dev-dependencyfrom false-positiving on dependencies referenced in apackage.jsonscript as a flag argument rather than the leading command — e.g.jest --testResultsProcessor jest-sonar-reporteror--reporters=jest-junit(#653).#668
3c05fc4Thanks @aidenybai! - Update the dead-code analysis engine (deslop-js) to0.0.16.#655
d594f69Thanks @rayhanadev! - react-doctor no longer crashes when the--changed-files-fromfile can't be read.--changed-files-from <file>is user input, so an unreadable file — missing, a directory, permission-denied, or a stale pipe/process-substitution descriptor (EBADF, REACT-DOCTOR-V) — is an invocation mistake, not a bug. It now exits non-zero with a clean, single-line message telling you to pass a readable text file, instead of printing the generic "Something went wrong" block and reporting the read failure to Sentry.#660
e3b106eThanks @rayhanadev! - react-doctor now records a single anonymized per-scan "wide event" on its Sentry run span — the full run/CI/project/outcome context (scan mode, score, diagnostics by severity and category, top rule, lint/dead-code state, and, in CI, the GitHub event, an official-action marker, the forwarded action inputs, and the pull-request gate) — so usage and CI behavior can be analyzed by querying spans instead of pre-aggregated counters.It also mints a random per-run
runIdattached to the Sentry run context (never as a tag or metric dimension) to correlate the spans of a single run. Telemetry stays anonymized — no repo, owner, username, branch, or path is sent to Sentry — and--no-score/--no-telemetrystill opts out entirely. The official GitHub Action forwards its inputs (fail-on, non-blocking, comment, annotations, version) so action configuration is visible in telemetry.#658
cbdff62Thanks @aidenybai! - Polished the first-run onboarding experience — the animated welcome scene now plays on every interactive regular-mode run (not just the first) but at half the cadence for returning users (hasCompletedOnboarding()),--verboseskips the intro entirely and goes straight to the static branded header, and the closing"Let's scan your codebase..."typewriter beat was cut so the intro ends on the tagline.Restructured the scan-report layout so the top-errors detail (code frames + fixes) leads the report and the per-category breakdown moves down as a wrap-up overview directly above the score. The breakdown now has its own bold
All N issuesheader (mirroringTop N errors you should fix) with the total folded into the header text, categories sort in a fixed Security → Bugs → Performance → Accessibility → Maintainability order, and warnings no longer get boxed code frames in--verbose(errors still do) so a long warning tail stops drowning the report. The trailing--verboseCTA drops the redundant+N more rules and +N optional warningsstats (the breakdown above already carries those) and reads as a cleanRun npx react-doctor@latest --verbose to list every error and warning.Quieted the "Add to CI" handoff: it no longer runs the local dev-dep install (the
doctorpackage script and the GitHub workflow both invokenpx react-doctor@latest, so a local copy adds nothing and on pnpm with a beta channel it noisily trips the supply-chain trust guard for zero user benefit). The trust-policy skip on thereact-doctor installpath now renders as a yellow⚠warning with a tightened one-liner and a dim follow-up showing the manual install command, instead of a red✖that read like a crash next to its own "React Doctor still works" reassurance.Made the case for GitHub Actions before the handoff prompt instead of after it. The scan-report footer now closes with a
GitHub Actions: https://react.doctor/cientry (matching theShare/Docs/GitHubbold label + dim description shape) carrying the strongest reasons in two short lines:Scan every pull request: new PRs stay clean while you fix the backlog+Used by teams at PayPal, Rippling, and Alibaba. Sitting last in the footer makes it the final thing read before the handoff prompt that recommends the same action. The prompt's choice reads asAdd to GitHub Actions (recommended)(or(already configured)) with a description of what gets set up; the state tag lives in the title so the description always describes what the option does, not the project's current state. The post-pick message drops the social-proof + backlog framing (now redundant — the footer already showed it) and just confirms what changed plus the docs link.#667
4dc48d7Thanks @aidenybai! - React Compiler projects no longer reportjsx-no-constructed-context-valuesfor fresh context provider values that the compiler memoizes automatically.#654
eab6dc2Thanks @rayhanadev! - react-doctor no longer crashes when a directory can't be enumerated during project discovery.The recursive subproject crawl reads directories best-effort and already skipped ones it couldn't open for permission or missing-path reasons (
EACCES/EPERM/ENOENT/ENOTDIR). It now also skips directories the underlying filesystem rejects outright —EINVALonscandir(REACT-DOCTOR-N, seen on special/virtual mounts), plus symlink loops (ELOOP) and over-long paths (ENAMETOOLONG) — instead of throwing and reporting the environment issue to Sentry. The crawl continues past the unreadable directory.#666
5d7b36bThanks @aidenybai! - Retiresrn-animate-layout-property. ReanimateduseAnimatedStyleruns entirely on the UI thread, so layout-affecting style animations driven by helpers likewithTimingorwithSpringare valid and should not be flagged.#645
4aadaabThanks @aidenybai! - Two React Native rules no longer false-positive on Expo Universal UI (@expo/ui).@expo/uiis a native UI layer (it delegates to SwiftUI / Jetpack Compose), not React Native's core primitives, so several RN-core assumptions don't hold for its components:rn-no-raw-text: Universal UI's<ListItem>renders its raw string children inside the native headline text area, and its compound slot markers (<ListItem.Leading>,<ListItem.Supporting>,<ListItem.Trailing>) forward strings into native text too — so raw text inside them is safe, unlike React Native's core<View>. The rule now recognizes them as text-handling.rn-no-scrollview-mapped-list: Universal UI's<ScrollView>is a native scroll container; React Native's virtualized lists (FlashList/FlatList) can't compose inside its<Host>tree, and@expo/uishipsConfiguration
📅 Schedule: (UTC)
* 0-4,22-23 * * 1-5)* * * * 0,6)🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.