Skip to content

chore: version packages - #827

Merged
rayhanadev merged 1 commit into
mainfrom
changeset-release/main
Jun 19, 2026
Merged

chore: version packages#827
rayhanadev merged 1 commit into
mainfrom
changeset-release/main

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

Releases

eslint-plugin-react-doctor@0.5.7

Patch Changes

oxlint-plugin-react-doctor@0.5.7

Patch Changes

  • #847 424d8f9 Thanks @rayhanadev! - Fix agent-tool-capability-risk (and its sibling mcp-tool-capability-risk) false positives when a capability keyword appears only in prose (#838).

    The rules already blanked comments before their keyword scan but still matched the dangerous-capability pattern inside string literals. A tool whose description happened to contain a capability word as prose — e.g. description: "...ALWAYS fetch the underlying numbers first" — fired even though no shell/fs/network primitive was wired to the handler. The keyword scan now blanks string-literal interiors (preserving offsets, so reported lines/columns stay correct), via a new opt-in ignoreStringLiterals flag on the shared scanByPattern helper.

    Genuine signals still fire: a real call site outside the quotes (exec(command), fetch(url)), a capability inside a template interpolation (`${fetch(url)}`${…} is treated as code, not blanked), and a dangerous module specifier (import { execFile } from "node:child_process", require("axios")) are all preserved.

  • #845 81bbfcc Thanks @rayhanadev! - Fix artifact-baas-authority-surface false positives on next-sanity / @sanity/client studio bundles (#840).

    The rule's "BaaS client config present" gate paired the generic createClient token with Firebase's projectId field. But that pairing is the Sanity client signature — createClient({ projectId, dataset, apiVersion }) — not a Firebase or Supabase one, so every Sanity Studio browser chunk tripped the gate and then matched the second factor on a shipped roles/administrator string. createClient now only counts as a BaaS signal next to a Supabase marker (supabase / SUPABASE_URL); Firebase is still detected by its own verbs (initializeApp, firebase, firestore), so genuine Firebase/Supabase authority maps keep firing.

  • #861 937a7ca Thanks @rayhanadev! - Stop no-inline-exhaustive-style from flagging Satori (next/og, @vercel/og) OG-image components.

    OG components style everything inline because Satori rasterizes the JSX to a static image and supports no other styling channel — so the rule's "rebuilds every render" premise never applies, and an exhaustive style={{…}} is the only way to lay them out. The rule now shares the same isGeneratedImageRenderContext guard the sibling image rules already use (alt-text, nextjs-no-img-element, no-unknown-property): it short-circuits in Next.js metadata image routes (opengraph-image.tsx, twitter-image.tsx, icon.tsx, …) and skips JSX that flows into an ImageResponse(...)/satori(...) call, including a helper component resolved to that call. The expensive per-node generated-image lookup runs only once a style is large enough to report, so ordinary files pay nothing. Exhaustive inline styles in regular components are still flagged.

  • #862 b8170f8 Thanks @rayhanadev! - Stop jsx-key from flagging element collections handed to a non-children prop (e.g. <Tabs items={[<Tab />, <Tab />]} />).

    The rule decided whether an element needed a key purely from its structural position — "is this JSX inside an array literal or a .map/.flatMap/Array.from callback?" — and never looked at where the resulting collection was consumed. React's dev-mode key validation only iterates props.children (jsxWithValidationvalidateChildKeys(props.children, type)), so an element array passed to any other prop is never key-validated at the call site; the receiving component owns keying (the cloneElement / Children.map / Children.toArray idiom). Flagging the producer site was a false positive — the same "data handoff, not a sibling render" reasoning the rule already applies to object-Property values.

    The fix exempts collections that are the value of a non-children JSX attribute, for both array literals and iterator callbacks — including when the value is wrapped in optional chaining, &&/||/??, a ternary branch, or a TS as / satisfies / ! assertion (items={ready && xs.map(...)}), since none of those change whether React validates it.

    Genuine missing keys still fire: array literals and .map results in children position (<Menu>{data.map(...)}</Menu>, <ul>{[<li/>, <li/>]}</ul>), and the explicit children={[...]} attribute — which is props.children and which React does validate.

  • #865 3f7d0e7 Thanks @rayhanadev! - Ship no-danger default-off so it no longer blanket-flags safe dangerouslySetInnerHTML.

    no-danger is the absolutist oxc port — it flags every dangerouslySetInnerHTML with zero content awareness, so it fired Security warnings on the canonical-safe idioms that React Doctor's own content-aware detectors deliberately exempt: escaped JSON-LD, theme-init <script> templates, CSS-variable <style> injection, and sanitized / safe-named values. Two default-on Security rules judged the same prop and disagreed.

    The content-aware rules are now the canonical default-on detectors for dangerouslySetInnerHTML: dangerous-html-sink (dynamic/tainted markup, with the style-tag / static-template / sanitizer exemptions) and unsafe-json-in-html (the unescaped-JSON.stringify breakout case). no-danger remains available opt-in ("react-doctor/no-danger": "warn") for teams that want the stricter "never use dangerouslySetInnerHTML at all" policy (oxc / eslint-plugin-react parity).

    Score impact: repos using these safe idioms will see fewer Security findings and a correspondingly higher score. A CI gate pinned to a fixed threshold may pass where it previously failed. Re-enable no-danger in config to restore the old behavior.

  • #846 6b8e756 Thanks @rayhanadev! - Fix server-sequential-independent-await false positive on awaits whose dependency flows through nested destructuring (#839).

    The rule's binding collector only saw top-level Identifier bindings and shallow object/array pattern elements, so names bound through a nested pattern — e.g. const [{ slug }, { isEnabled }] = await Promise.all([...]) — were invisible. A follow-up await client.fetch(BlogPostQuery, { slug }, isEnabled ? ... : ...) that genuinely depended on those names was wrongly flagged as an independent waterfall. The collector now reuses the recursive collectPatternNames utility, so nested array/object patterns, defaulted bindings, and rest elements all count as a real dependency.

  • #831 03301fc Thanks @aidenybai! - Fix server-auth-actions false positives on custom auth guards (#829).

    The rule only recognized a fixed list of auth function names, so a server action protected by a project's own guard — e.g. await requireAdmin() or await getAdminSession() — was wrongly flagged as callable by anyone. It now recognizes auth checks by naming convention as well: an assertive verb plus an auth noun (requireAdmin, ensureSignedIn, checkPermission, assertUser, isAdmin, hasRole), a getter plus a strong auth noun (getServerAuthSession, getAdminSession), and current/my/own qualifiers (getCurrentUser). Genuinely ambiguous names like getUser and getToken still require an auth-related receiver, so analytics.getUser() keeps firing the rule.

  • #859 44db3e0 Thanks @rayhanadev! - Fix server-fetch-without-revalidate false positive on mutating fetches. Next.js only caches GET requests, so a fetch(url, { method: "POST" | "PUT" | "PATCH" | "DELETE" }) in a Server Component or route handler can never serve stale cached data — the rule no longer flags it.

  • #843 5b742fa Thanks @rayhanadev! - Fix url-prefilled-privileged-action false positive when a validating helper
    wraps a read behind a receiver chain. The validator-suppression lookbehind only
    recognized validator(searchParams.get(...)) or validator(new URLSearchParams(...))
    directly — real code reads through a receiver (sanitizeNext(url.searchParams.get(...)),
    validateNext(request.nextUrl.searchParams.get(...))), and that intervening url.
    broke the match so validated reads kept firing. The lookbehind now allows an optional
    receiver member-chain between the helper's ( and the read.

  • #826 8908f98 Thanks @aidenybai! - Add 7 new rules mined from React, web-platform, security, and accessibility best practices:

    • no-call-component-as-function (Bugs): calling a component like Foo(props) instead of <Foo /> runs it outside React and breaks hooks, state, and memoization. Shadow-safe via scope resolution.
    • no-create-ref-in-function-component (Bugs): createRef() in a function component or hook allocates a fresh ref every render; use useRef().
    • no-async-effect-callback (Bugs): an async useEffect/useLayoutEffect callback returns a Promise that React treats as cleanup, causing unmount races.
    • no-json-parse-stringify-clone (Performance): JSON.parse(JSON.stringify(x)) is a slow, lossy deep clone; use structuredClone(x).
    • no-img-lazy-with-high-fetchpriority (Performance): loading="lazy" and fetchPriority="high" are contradictory directives on the same image.
    • dialog-has-accessible-name (Accessibility): a <dialog> / role="dialog" with no aria-label/aria-labelledby is announced only as "dialog".
    • auth-token-in-web-storage (Security): persisting auth tokens in localStorage/sessionStorage exposes them to XSS exfiltration.
  • #828 451beeb Thanks @aidenybai! - Add 3 new rules (mining batch 2), each validated with an OSS noise sweep (0 false positives across ~2,800 diagnostics in react-use, radix-ui/primitives, excalidraw, mantine):

    • no-document-write (Performance): document.write()/document.writeln() blocks parsing and is ignored or wipes the page after load.
    • no-sync-xhr (Performance): a synchronous XMLHttpRequest (.open(method, url, false)) freezes the main thread until the request finishes.
    • no-string-false-on-boolean-attribute (Bugs): disabled="false" and friends pass the string "false", which is truthy, so the boolean attribute is applied even when you wrote "false". Targets a curated set of true HTML boolean attributes on intrinsic elements; excludes enumerated attrs (aria-*, contentEditable, draggable, spellCheck) and custom components.

react-doctor@0.5.7

Patch Changes

  • #881 50999f4 Thanks @rayhanadev! - Add a --debug flag that prints the run's Sentry trace id at the end of a scan.

    When something looks wrong, run react-doctor --debug: it forces a Sentry performance trace for that run (even if SENTRY_TRACES_SAMPLE_RATE was turned down) and prints Sentry trace (mention this when reporting): <id> as the last line so the id can be pasted into a bug report for maintainers to pull the full trace. It prints on both outcomes — a clean run and a crash (the crash's trace is surfaced even when it happens before the scan span starts). The line goes to stderr, so --json / --score stdout stays machine-clean. Combining --debug with --no-score / --no-telemetry is rejected up front, since those flags disable the Sentry reporting --debug depends on. Telemetry also gains a low-cardinality debug run tag so adoption of the flag is visible.

  • #864 b317164 Thanks @rayhanadev! - Make file:line diagnostic locations clickable in the terminal, and record which terminal each run uses.

    Diagnostic locations are now wrapped in OSC 8 hyperlinks pointing at each file's absolute path, so supporting terminals (iTerm2, WezTerm, Kitty, Windows Terminal, VS Code, and other VTE-based emulators) turn them into click-to-open links — even in monorepo scans where the displayed path is relative to a sub-project root rather than the terminal's cwd. The visible text is unchanged (src/App.tsx:12), the link rides in escape sequences, and terminals without OSC 8 support print it exactly as before. Hyperlinks are auto-detected per terminal and can be forced on/off with the standard FORCE_HYPERLINK env var; they are off for non-TTYs, CI, and coding agents (whose output parsers shouldn't see the escapes).

    Telemetry also gains a terminalKind run tag (neovim, vscode, iterm, wezterm, kitty, windows-terminal, …) so we can see where React Doctor is actually run. It is a low-cardinality enum with no path, username, or secret.

  • #863 740211c Thanks @rayhanadev! - Add a per-project scannedFileCount to the JSON report's projects[] entries —
    the number of source files the scan's linter examined (the changed React-eligible
    files in diff mode, the whole source tree in a full scan). It's additive and
    optional, so the schemaVersion is unchanged and existing consumers are unaffected.

    This lets the GitHub Action tell "a PR that changed no React-eligible files" (the
    linter examined nothing — scannedFileCount: 0 for every project) apart from "a
    clean scan of real React changes" (scannedFileCount >= 1), which previously
    produced identical reports. The Action now treats the former as a no-op: it skips
    the sticky PR comment entirely and the commit status reads "Skipped — no React
    files changed" instead of a zero-filled score line. A clean scan of real React
    changes still posts its "no issues 🎉" comment.

  • #844 eafac9d Thanks @rayhanadev! - Stop recommending the deprecated --diff flag in agent-facing guidance (#834).

    The CLI "Agent guidance" section, the installed agent hooks, and the --help examples all advised running react-doctor --verbose --diff, which now prints a deprecation warning on every run. They now recommend the supported --scope changed (pass --base <ref> to pin the base). The website llms.txt and the react-doctor skill reference were updated to match.

  • #832 f45cb29 Thanks @devin-ai-integration! - Fix a false-positive deslop/unused-file for a file imported only by a file in ignore.files. Ignored files are now kept in the dead-code dependency graph (only their reporting is suppressed), so a module reachable solely through an ignored file is no longer flagged as unused.

  • #851 1e260c5 Thanks @rayhanadev! - Show the "Add React Doctor to CI" and "install React Doctor" pitches once per repo instead of on every scan.

    The post-scan handoff re-asked the CI question on every run, and the agent install hint re-printed every run because its opt-out store was built but never written. Both now record a per-repo answer (reusing the existing once-per-repo Conf pattern) and stay quiet afterward — the first-run experience is unchanged, only the repetition stops.

    The agent copy-prompt no longer carries the CI marketing preamble at all. The interactive handoff prompt is now the single once-per-repo pitch, so the agent is never instructed to re-ask what the user was just asked — capable agents were flagging that preamble as social-engineering and it was eroding trust in the actual diagnostics.

  • #848 431e515 Thanks @rayhanadev! - Stop a broken eslint-plugin-react-hooks install from sinking the whole lint pass, and fix the misleading error it produced (issue #833).

    When the optional react-hooks-js (React Compiler) plugin can't be imported in the user's environment, oxlint fails the entire config load — which previously dropped every curated react-doctor diagnostic too and left the scan with skippedChecks: ["lint"] and zero results. The oxlint error is also multi-line, and the 200-char error preview truncated its plugin path mid-string (often right at …/node_modules/), so it read as react-doctor passing an invalid directory rather than a plugin that failed to load.

    • Graceful degradation: the oxlint runner now detects a react-hooks-js plugin-load failure and retries once with that plugin (and its compiler rules) dropped — mirroring the existing adopted-extends fallback. The curated react-doctor rules, dead-code, and environment checks all still run; only the React Compiler rules are skipped, surfaced as a clear lint:partial note that includes oxlint's real underlying reason.
    • Readable error: the unparseable-output preview grew from 200 to 600 chars so the full plugin path and the underlying Error: line survive instead of being cut at …/node_modules/.
  • #857 17389ba Thanks @rayhanadev! - Show a syntax-highlighted source snippet in react-doctor why <file>:<line>.

    The buildCodeFrame util already powers the source frames in the scan summary, but the why command (the single-location explain path) never called it — so explaining a diagnostic printed the rule, category, help, and suppression hint with no view of the offending code. It now renders the same code frame directly under the headline, with the caret on the offending column (or the whole line span for a multi-site diagnostic). When the file can't be read or the line is minified, it falls back to the existing text-only output.

  • #882 a9d2713 Thanks @rayhanadev! - Group findings that a single fix resolves into one root-cause task.

    Several findings can share one fix — e.g. four useEffects that reset state on the same prop change all clear with a single key prop. Those findings now carry a shared fixGroupId in the JSON report and the on-disk diagnostics.json dump, so a tool that turns findings into work items counts one fix as one task instead of N. The terminal labels such a group "One fix clears all N findings", and the agent handoff frames it as a single task ("one fix · N sites") and tells the agent to group by fixGroupId.

    Grouping is presentation-only and keyed on identical (file, rule, message) for an allowlist of rules where the same message means the same fix — the state-on-prop-change family today (no-derived-state-effect, no-adjust-state-on-prop-change, no-reset-all-state-on-prop-change, and the no-derived-state / no-derived-useState rules). The score is unchanged — it already de-weights repeated same-rule findings and never reads the new field. fixGroupId is an additive optional field, so existing JSON consumers are unaffected.

  • #859 44db3e0 Thanks @rayhanadev! - Improve disable-directive handling for react-doctor rules:

    • // react-doctor-disable-line / -next-line (and ignore.rules / rule lookups) now accept a rule's bare short id, e.g. no-eval for react-doctor/no-eval — the unqualified form people reach for first.
    • When an eslint-disable / oxlint-disable directive names a react-doctor rule by an id oxlint can't bind to a plugin rule — a bare short id (no-eval) or a legacy plugin prefix (react/jsx-key), whether inline or as a file-level block disable — the diagnostic now carries a hint to use the full react-doctor/<id> key.
  • #884 869f220 Thanks @rayhanadev! - Warn before mass-fixing a migration-scale bucket. When a single rule spans dozens of files (≥ MIGRATION_SCALE_RULE_FILE_COUNT, default 40), the report now prints a "Migration-scale change: sample before you sweep" advisory. It names the rule(s), explains the review risk, and points at npx react-doctor@latest <path> to scope the work down one area at a time.

    The same guidance reaches coding agents. A new "Agent guidance" line and an inline note on any migration-scale bucket in the agent handoff prompt tell the agent to fix a representative sample, confirm the recipe holds, and get the code owner's sign-off before changing the rest, instead of mass-fixing a broad pattern in one unreviewed pass.

    A new wide-event attribute (migration.largestRuleBucketFiles, plus migration.largestRuleBucketSites and migration.largestRuleBucketRule) records the widest-blast-radius rule per scan, so the threshold can be calibrated against real runs. No change to the score, exit code, or JSON report.

  • Updated dependencies [424d8f9, 81bbfcc, 937a7ca, b8170f8, 3f7d0e7, 6b8e756, 03301fc, 44db3e0, 5b742fa, 8908f98, 451beeb]:

    • oxlint-plugin-react-doctor@0.5.7

@react-doctor/api@0.5.7

Patch Changes

  • Updated dependencies [431e515]:
    • @react-doctor/core@0.5.7

@react-doctor/core@0.5.7

Patch Changes

  • #848 431e515 Thanks @rayhanadev! - Stop a broken eslint-plugin-react-hooks install from sinking the whole lint pass, and fix the misleading error it produced (issue #833).

    When the optional react-hooks-js (React Compiler) plugin can't be imported in the user's environment, oxlint fails the entire config load — which previously dropped every curated react-doctor diagnostic too and left the scan with skippedChecks: ["lint"] and zero results. The oxlint error is also multi-line, and the 200-char error preview truncated its plugin path mid-string (often right at …/node_modules/), so it read as react-doctor passing an invalid directory rather than a plugin that failed to load.

    • Graceful degradation: the oxlint runner now detects a react-hooks-js plugin-load failure and retries once with that plugin (and its compiler rules) dropped — mirroring the existing adopted-extends fallback. The curated react-doctor rules, dead-code, and environment checks all still run; only the React Compiler rules are skipped, surfaced as a clear lint:partial note that includes oxlint's real underlying reason.
    • Readable error: the unparseable-output preview grew from 200 to 600 chars so the full plugin path and the underlying Error: line survive instead of being cut at …/node_modules/.
  • Updated dependencies [424d8f9, 81bbfcc, 937a7ca, b8170f8, 3f7d0e7, 6b8e756, 03301fc, 44db3e0, 5b742fa, 8908f98, 451beeb]:

    • oxlint-plugin-react-doctor@0.5.7

@react-doctor/language-server@0.5.7

Patch Changes

  • Updated dependencies [431e515]:
    • @react-doctor/core@0.5.7

Note

Low Risk
Release-metadata-only diff; behavioral risk is inherited from already-reviewed feature PRs, with notable user-facing deltas being new default-off no-danger (higher scores) and stricter CI semantics via scannedFileCount.

Overview
Changesets release PR that bumps the monorepo from 0.5.6 → 0.5.7 and removes the consumed .changeset/*.md entries. The diff is almost entirely package.json version fields and CHANGELOG.md prose—no application logic in this merge.

react-doctor@0.5.7 (CLI): --debug (Sentry trace id on stderr), OSC 8 clickable file:line locations + terminalKind telemetry, per-project scannedFileCount for GitHub Action no-React-files skip, fixGroupId grouping for one-fix-many-findings, migration-scale advisory, why code frames, once-per-repo CI/agent pitches, --scope changed in agent docs (drops deprecated --diff guidance), bare-rule disable hints, and oxlint react-hooks-js load fallback via @react-doctor/core.

oxlint-plugin-react-doctor@0.5.7: ten new rules (two batches), no-danger default-off (scores may rise; CI thresholds), plus FP fixes (jsx-key, Satori OG styles, Sanity BaaS gate, agent/MCP tool prose in strings, server auth guards, nested await deps, mutating fetch revalidate, URL validator chains, etc.).

eslint-plugin-react-doctor and internal @react-doctor/* packages only pick up dependency bumps and changelog mirrors.

Reviewed by Cursor Bugbot for commit cfbdcdb. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
github-actions Bot force-pushed the changeset-release/main branch 27 times, most recently from ceb9887 to d727155 Compare June 19, 2026 03:21
@github-actions
github-actions Bot force-pushed the changeset-release/main branch 2 times, most recently from 16bf0cb to 70c9624 Compare June 19, 2026 03:30
@pkg-pr-new

pkg-pr-new Bot commented Jun 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-react-doctor@827
npm i https://pkg.pr.new/oxlint-plugin-react-doctor@827
npm i https://pkg.pr.new/react-doctor@827

commit: 70c9624

@github-actions
github-actions Bot force-pushed the changeset-release/main branch 2 times, most recently from e136294 to 3edb630 Compare June 19, 2026 04:16
@github-actions
github-actions Bot force-pushed the changeset-release/main branch from 3edb630 to cfbdcdb Compare June 19, 2026 04:19
@rayhanadev
rayhanadev merged commit 96b5bb4 into main Jun 19, 2026
6 checks passed
@rayhanadev
rayhanadev deleted the changeset-release/main branch June 19, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant