Skip to content

Sync upstream into pinned (627f9ca4b363) - #4

Merged
gcharang merged 72 commits into
pinnedfrom
main
Jun 20, 2026
Merged

Sync upstream into pinned (627f9ca4b363)#4
gcharang merged 72 commits into
pinnedfrom
main

Conversation

@github-actions

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

Copy link
Copy Markdown

Automated upstream sync.

  • Upstream: millionco/react-doctor@main
  • main is synced up to upstream 627f9ca4b363.

Commits this PR brings onto pinned

Merge with a merge commit — do not squash or rebase. Squashing rewrites these commits
under new SHAs, so the next sync would see them as unmerged and reopen an ever-growing PR.
A merge commit keeps main's commits reachable from pinned, which is how this
workflow detects that the sync is done.

Conflicts on the harden commit's files are expected and shown in the PR UI; resolve them in the merge.

Opened by the sync-upstream workflow. Do not auto-merge.

rayhanadev and others added 30 commits June 10, 2026 17:46
…rall score (millionco#780)

Co-authored-by: Cursor <cursoragent@cursor.com>
…ionco#776) (millionco#782)

* fix(only-export-components): skip framework route/special files (millionco#776)

Recognize the route/special files of every file-routing framework
react-doctor covers (Next.js, Expo Router, TanStack Router, Remix /
React Router) via a single `isFrameworkRouteOrSpecialFilename` helper,
so the documented "co-export config/metadata next to the default
component" shape no longer triggers false-positive non-component-export
warnings. Fixes the `alt` / `size` / `contentType` / `revalidate`
exports in `opengraph-image.tsx`.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: change variable name

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: update usages as well

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… metadata (millionco#784)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
… repos (millionco#791)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… files (millionco#790)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
…ths, and config `projects` (millionco#771)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
…ts (millionco#796)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
…ase bindings (millionco#794)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
…tic message (millionco#793)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
…g enableBabelRuntime (millionco#801)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: D N <4661784+retyui@users.noreply.github.com>
…ocal node_modules (millionco#800)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
…gnostics (millionco#804)

Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
… rules (millionco#826)

* feat(rules): add 8 mined correctness, performance, a11y, and security rules

Mined from a 12-cluster pass over the design/engineering brain and
synthesized into docs/rule-candidates-backlog.md. Ships the highest-signal,
lowest-noise batch, each with adversarial + FP-regression tests:

- no-call-component-as-function (Bugs)
- no-create-ref-in-function-component (Bugs)
- no-async-effect-callback (Bugs)
- no-json-parse-stringify-clone (Performance)
- img-missing-dimensions (Performance)
- no-img-lazy-with-high-fetchpriority (Performance)
- dialog-has-accessible-name (Accessibility)
- auth-token-in-web-storage (Security)

Adds the shared has-jsx-spread-attribute util and registers the three
in-house ported-bucket rules in RULES_NOT_PORTED_FROM_EXTERNAL.

* fix(rules): drop img-missing-dimensions; make component rules shadow-safe

- Drop `img-missing-dimensions`: width/height attributes are only one of
  several valid ways to reserve space (CSS aspect-ratio, container sizing),
  and the authoritative signal lives in stylesheets a static linter can't
  see. This is a runtime check (Lighthouse `unsized-images`), so a syntax
  rule would false-positive on any CSS-sized image.
- `no-call-component-as-function`: resolve the callee through its scope
  symbol instead of by name, so a parameter/local shadowing a component
  name is no longer flagged. The component signal is the binding's
  declaration (same-file component returning JSX) or an imported binding
  also rendered as JSX.
- `no-create-ref-in-function-component`: skip a shadowing local `createRef`
  (only flag React's import / `React.createRef`).
- Adds shadow-safety regression tests for both.

* fix(rules): tag no-call-component-as-function test-noise (eval finding)

An OSS eval sweep (react-use, radix primitives, excalidraw, mantine;
~2.8k diagnostics) showed every real-world hit of this rule was a test
render-helper (`render(Wrapper({...}))` in `.test.tsx`/`.story.tsx`) —
harmless for hookless wrappers and the dominant firing surface. Tag it
`test-noise` so it skips test/story/playground files and only nags
shipped code. The sweep also confirmed dialog-has-accessible-name (2 real
a11y bugs in excalidraw) and no-create-ref-in-function-component (1 real
bug in a mantine story) as true positives with zero false positives.
aidenybai and others added 28 commits June 17, 2026 15:50
…o#857)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ory (millionco#858) (millionco#860)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…illionco#864)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lionco#861)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rops (millionco#862)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ngerouslySetInnerHTML (millionco#865)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#866)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o#881)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… React files change (millionco#863)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ionco#883)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…positive (millionco#859)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ask (millionco#882)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o#884)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bump

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rency) (millionco#885)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…CLI, root-commit diff) (millionco#888)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: skip pnpm hardening check for monorepo sub-packages

Only check pnpm hardening settings at the workspace root or standalone
pnpm projects. Sub-packages of a pnpm workspace inherit hardening from
the workspace root's pnpm-workspace.yaml, so emitting diagnostics with
synthesized file paths for each sub-package is incorrect.

Fixes millionco#878

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* chore: add changeset for pnpm hardening fix

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* chore: format test file

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* refactor: rename rootDirectory to scanDirectory in checkPnpmHardening

The parameter name was misleading - call sites pass scanDirectory,
not a root directory.

Co-authored-by: Skosh <skoshx@users.noreply.github.com>

* refactor: deslop pnpm-hardening monorepo-skip change

Defer findMonorepoRoot inside the !hasWorkspaceFile guard so the
ancestor walk only runs when its result is used, and fold the
parent-workspace check into one short-circuit condition (one fewer
nesting level, behavior unchanged). Extract expectMissingHardeningWarnings
to collapse four repeated assertion groups in the monorepo test block.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…illionco#893)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rk (millionco#907)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l changes (millionco#906)

* fix(cli): make GitHub Actions setup flow idempotent and stop bundling local changes (millionco#904)

The setup flow opened duplicate PRs and swept unrelated local changes into
the generated branch. Two root causes in `openWorkflowPullRequest`:

1. Non-idempotent: `findUniqueBranchName` only avoided a *local* branch
   collision by appending a timestamp, and nothing checked for an
   already-open setup PR. A re-run (the workflow file lives only on the prior
   PR's branch, so it's re-written each run) minted `…-<timestamp>` branches
   and opened a second PR. Now we `gh pr list` for an open PR whose head is
   under the setup prefix and surface it (`pr-exists`) instead of opening a
   duplicate.

2. Dirty-tree bundling: `git checkout -b <new> origin/<default>` carries the
   index across and the whole-index `git commit` then committed whatever the
   user had staged (modified app files, a deleted/rewritten lockfile). Now we
   bail (`working-tree-dirty`) when the tree has tracked changes other than
   the workflow file itself, falling back to staging the workflow file. The
   workflow path is excluded from the check so the v1→v2 upgrade flow (which
   modifies the tracked workflow in place) still works.

Both callers handle the new `pr-exists` status; the runner / gh-availability
probe are now injectable for hermetic tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(cli): harden setup-flow fix from adversarial review

Findings from an adversarial review+deslop pass over the millionco#904 fix:

- fix(correctness): normalize `workflowRelative` with `toForwardSlashes` so the
  `:!` exclude pathspec matches git's forward-slash repo paths on Windows.
  Without it, `path.relative` yields backslashes there, git's magic pathspec
  doesn't treat them as separators, and the upgrade flow (tracked workflow
  modified in place) would always report `working-tree-dirty` and never open
  the PR. Applied in `openWorkflowPullRequest` and `stageWorkflowFile`.
- fix(correctness): on the upgrade flow's `pr-exists` path, restore the
  original @v1 workflow content. `pr-exists` returns without touching git
  state, so the @v2 edit written before the call would otherwise linger
  uncommitted — matching the pr-opened path's "bump lives only on the PR
  branch" contract.
- chore: extract the `gh pr list` cap to `GH_PR_LIST_MAX` in constants.ts
  (AGENTS.md: no inline magic numbers).
- test: assert the dirty-tree guard skips add/commit/push (not just checkout),
  the happy path stages ONLY the workflow file (no `git add -A`/`.`), and
  branch-pushed keeps the branch (no `git branch -D`) and restores HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): trigger duplicate-PR guard on match presence, not URL truthiness

Bot review (Cursor) flagged that the idempotency short-circuit keyed on a
truthy URL: if `gh pr list` returned a matching setup head branch with a
missing/empty `url`, `findExistingSetupPullRequest` returned null and the
flow could still mint a branch and open a duplicate PR — the exact failure
the guard exists to prevent. `gh` always populates `url` for `--json url`, so
this is defensive, but the headline millionco#904 guarantee shouldn't hinge on it.

Return the matched PR object and short-circuit on its existence; use its url
only for the `pr-exists` message (empty when absent). Adds a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…in (millionco#903)

Integrates the 7 large-repo speedup PRs (millionco#894millionco#900) plus the dead-code reworks
done on top of them.

Headline (measured on Sentry, supply-chain on): full scan ~142s → ~40s (3.6x),
with dead-code findings fully intact.

- deslop: skip the analysis passes react-doctor discards — the semantic
  TS-Program pass and the code-quality detectors (duplicate-block/complexity/
  feature-flag/TS-smell/private-type-leak/re-export-cycle), gated behind a new
  `reportCodeQuality` flag (default on for deslop standalone). ~8.5x faster
  dead-code on a large repo, byte-identical consumed findings, locked by a
  parity test.
- Dead-code runs sequentially by default with a file-count-scaled timeout,
  fixing a regression where overlapping it with lint oversubscribed the cores
  and silently dropped all dead-code findings under supply-chain. Opt-in
  `REACT_DOCTOR_DEAD_CODE_OVERLAP=on` now splits the core budget instead of
  doubling it.
- Plus the merged PRs: memory-budgeted worker cap (millionco#896), bounded-phase hard
  timeouts (millionco#899), supply-chain∥lint overlap (millionco#894), per-file lint cache (millionco#900),
  deterministic diagnostics (millionco#897), module-cache dedup (millionco#895).

CI: full test matrix (macOS/Ubuntu 20–26/Windows), build, typecheck, lint, and
react-doctor smoke all green. The 1s "CodeQL" check is the pre-existing
code-scanning-alert gate (main's CodeQL analysis is green); no security-relevant
code changed.
@github-actions github-actions Bot changed the title Sync upstream into pinned (cf9e05be8ee1) Sync upstream into pinned (627f9ca4b363) Jun 20, 2026
@gcharang
gcharang merged commit e6a4a00 into pinned Jun 20, 2026
3 checks passed
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.

5 participants