Skip to content
Open
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
afd9e16
feat(react-compiler): vendor babel-plugin-react-compiler with full te…
aidenybai May 29, 2026
fe66d52
feat(react-compiler): add HIR-based correctness verifier and CLI
aidenybai May 29, 2026
451028a
fix(react-compiler): normalize CRLF in fixture harness for Windows CI
aidenybai May 29, 2026
ff8ad8c
fix(react-compiler): normalize Windows-resolved fixture path in harness
aidenybai May 29, 2026
aa4db78
feat(react-compiler-oxc): Rust+oxc reimplementation of the React Comp…
aidenybai Jun 1, 2026
fdc2b2b
feat(react-compiler-oxc): reach honest 100% React-Compiler parity
aidenybai Jun 1, 2026
67bec6d
fix
aidenybai Jun 1, 2026
bad5a08
fix
aidenybai Jun 1, 2026
95b9add
chore: reconcile lockfile after compiler cherry-pick
aidenybai Jun 1, 2026
f943dae
feat(react-compiler-oxc): add structured lint diagnostic layer
aidenybai Jun 1, 2026
e55405a
feat(react-compiler-oxc): emit set-state-in-render lint diagnostics
aidenybai Jun 1, 2026
e0fc7c9
feat(compiler-native): add napi bindings for the lint surface
aidenybai Jun 1, 2026
be42404
feat(compiler-native): add react-hooks-js plugin over the native lint…
aidenybai Jun 1, 2026
beea13d
feat(react-compiler-oxc): emit error-boundaries lint diagnostics
aidenybai Jun 1, 2026
44fdc13
feat(react-compiler-oxc): emit set-state-in-effect diagnostics + shar…
aidenybai Jun 1, 2026
1f4569b
feat(react-compiler-oxc): emit use-memo + void-use-memo diagnostics
aidenybai Jun 1, 2026
d4eba50
test(compiler-native): cover error-boundaries + set-state-in-effect e…
aidenybai Jun 1, 2026
7cb7a4d
feat(react-compiler-oxc): emit globals/immutability/purity diagnostics
aidenybai Jun 1, 2026
10e7352
feat(react-compiler-oxc): emit static-components diagnostics
aidenybai Jun 1, 2026
7400ba4
feat(react-compiler-oxc): emit hooks diagnostics
aidenybai Jun 1, 2026
529223d
feat(react-compiler-oxc): emit refs diagnostics (ValidateNoRefAccessI…
aidenybai Jun 1, 2026
f8f275f
feat(react-compiler-oxc): emit preserve-manual-memoization diagnostics
aidenybai Jun 1, 2026
b34c074
feat(core): resolve react-hooks-js rules from native @react-doctor/co…
aidenybai Jun 1, 2026
4cb94ea
feat(react-compiler-oxc): make purity actually fire (port impure effect)
aidenybai Jun 1, 2026
76ba1c0
feat(react-compiler-oxc): emit incompatible-library diagnostics
aidenybai Jun 1, 2026
bc07f36
test(compiler-native): 1:1 parity harness vs eslint-plugin-react-hooks
aidenybai Jun 1, 2026
b14c369
ci(compiler-native): Rust tests + cross-platform prebuild matrix + JS…
aidenybai Jun 1, 2026
0aea521
test(compiler-native): broaden parity corpus + scope to verified-1:1 …
aidenybai Jun 1, 2026
3d50b98
feat(react-compiler-oxc): close todo parity (try-finally/for-await) +…
aidenybai Jun 1, 2026
6ee3f89
feat: remove eslint-plugin-react-hooks; native @react-doctor/compiler…
aidenybai Jun 1, 2026
eaa3558
fix: make @react-doctor/compiler-native an optionalDependency + add r…
aidenybai Jun 1, 2026
44f3904
fix(ci): drop unpublished platform-package optionalDependencies from …
aidenybai Jun 1, 2026
16c35c8
fix(ci): ignore react-compiler-oxc fixtures in lint + declare hermes-…
aidenybai Jun 1, 2026
af9bbc2
chore: re-trigger CI
aidenybai Jun 1, 2026
e940aa8
Merge remote-tracking branch 'origin/main' into react-doctor-oxc
aidenybai Jun 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
171 changes: 171 additions & 0 deletions .github/workflows/compiler-native.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: compiler-native

# Builds and tests @react-doctor/compiler-native (the Rust + oxc reimplementation
# of babel-plugin-react-compiler's lint analyzer) and produces the per-platform
# prebuilt `.node` addons that let react-doctor drop eslint-plugin-react-hooks.

on:
push:
branches: [main, react-doctor-oxc]
paths:
- "packages/react-compiler-oxc/**"
- "packages/react-compiler-oxc-napi/**"
- ".github/workflows/compiler-native.yml"
pull_request:
paths:
- "packages/react-compiler-oxc/**"
- "packages/react-compiler-oxc-napi/**"
- ".github/workflows/compiler-native.yml"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tag-based publish trigger will never fire

High Severity

The on.push trigger only specifies branches: [main, react-doctor-oxc] with no tags filter. When a compiler-native-v* tag is pushed, GitHub Actions fires a push event, but the branches filter excludes it because tag refs don't match branch names. The workflow never triggers for tag pushes, so the publish job's condition startsWith(github.ref, 'refs/tags/compiler-native-v') can never evaluate to true via that path. The workflow_dispatch fallback works, but the documented tag-gated release flow is broken. A tags: ['compiler-native-v*'] entry is needed alongside branches in the on.push config.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e940aa8. Configure here.


permissions:
contents: read

defaults:
run:
shell: bash

jobs:
# Rust unit tests + the full codegen corpus parity (1398 fixtures) + the
# IR-stage parity harnesses. This is the source of truth for the compiler and
# every ported lint validation.
rust-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: packages/react-compiler-oxc
- name: cargo build (0 warnings)
working-directory: packages/react-compiler-oxc
run: cargo build
- name: cargo test (unit + corpus + IR-stage parity)
working-directory: packages/react-compiler-oxc
run: cargo test -- --include-ignored

# Cross-platform prebuilt .node matrix. Each artifact is the napi addon for one
# target triple, named `react-compiler-oxc.<platform>.node` (the binaryName from
# package.json), ready to assemble into npm platform packages on release.
build:
strategy:
fail-fast: false
matrix:
include:
- host: macos-latest
target: aarch64-apple-darwin
- host: macos-latest
target: x86_64-apple-darwin
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
cross: true
- host: windows-latest
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.host }}
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: pnpm/action-setup@v5
- uses: actions/setup-node@v5
with:
node-version: "22.18.0"
cache: pnpm
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
workspaces: packages/react-compiler-oxc-napi
key: ${{ matrix.target }}
- run: pnpm install --frozen-lockfile
- name: Build addon (${{ matrix.target }})
working-directory: packages/react-compiler-oxc-napi
run: |
if [ "${{ matrix.cross }}" = "true" ]; then
pnpm exec napi build --platform --release --target ${{ matrix.target }} --use-napi-cross
else
pnpm exec napi build --platform --release --target ${{ matrix.target }}
fi
- name: List artifacts
working-directory: packages/react-compiler-oxc-napi
run: ls -la *.node
- uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.target }}
path: packages/react-compiler-oxc-napi/*.node
if-no-files-found: error

# Build the addon for the host and run the JS-side tests: the plugin shape +
# the 1:1 parity harness against eslint-plugin-react-hooks. Runs on each native
# OS so the addon is exercised where it's actually built.
js-test:
strategy:
fail-fast: false
matrix:
host: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.host }}
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: pnpm/action-setup@v5
- uses: actions/setup-node@v5
with:
node-version: "22.18.0"
cache: pnpm
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: packages/react-compiler-oxc-napi
- run: pnpm install --frozen-lockfile
- name: Build addon (host)
working-directory: packages/react-compiler-oxc-napi
run: pnpm exec napi build --platform --release
- name: Plugin + parity tests
run: pnpm exec vp test run packages/react-compiler-oxc-napi/tests

# Publish @react-doctor/compiler-native + its per-platform packages to npm.
# Gated behind a manual dispatch / `compiler-native-v*` tag so it never runs on
# ordinary pushes (and never collides with the changeset publish flow). Downloads
# every prebuilt `.node` from the `build` job, then `napi prepublish` assembles
# the platform npm dirs (matching `optionalDependencies`) and publishes them
# alongside the main package.
publish:
needs: [rust-test, build, js-test]
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/compiler-native-v') }}
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: pnpm/action-setup@v5
- uses: actions/setup-node@v5
with:
node-version: "22.18.0"
cache: pnpm
registry-url: https://registry.npmjs.org
- run: npm install -g npm@11
- run: pnpm install --frozen-lockfile
- uses: actions/download-artifact@v4
with:
path: packages/react-compiler-oxc-napi/artifacts
- name: Assemble per-platform npm packages from artifacts
working-directory: packages/react-compiler-oxc-napi
run: |
# Flatten the per-target upload-artifact subdirs into one dir, then let
# napi distribute each .node into its npm/<platform> package.
find artifacts -name '*.node' -exec mv {} . \;
pnpm exec napi artifacts --output-dir . --npm-dir npm
- name: Publish to npm
working-directory: packages/react-compiler-oxc-napi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true
run: pnpm exec napi prepublish -t npm --npm-dir npm
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Publish workflow runs prepublish but never publishes

Medium Severity

The publish job's final step runs napi prepublish which assembles platform packages and writes package.json files, but by itself does not run npm publish for the main package or the platform packages. In napi-rs v3, napi prepublish only prepares files; a separate npm publish invocation (or napi publish) is needed to actually push to the registry. The workflow will succeed without error but no packages will be published to npm.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 16c35c8. Configure here.

9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ review-*.md
*.review.md
*.tgz

# react-compiler-oxc port tooling: temporary oracle-dump scripts that the
# parity harness writes into packages/react-compiler/ (and elsewhere) at
# runtime to capture TS-compiler reference output. Never commit these.
*-oracle.mjs

# Scratch fixtures from the react-compiler-oxc CFG-outline experiments.
/example.tsx
/example-cfg.txt

# Track repository-owned agent skills, but keep other local agent state out.
/.agents/*
!/.agents/skills/
Expand Down
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,10 @@ node_modules/
# committed file stays byte-identical to its source (no formatter round-trip).
packages/website/public/schema/config.json

# Vendored React Compiler source — kept verbatim from facebook/react in
# upstream (Meta) style so it can be re-synced cleanly. Repo-owned config
# files (package.json, tsconfig.json, vite.config.ts) are still formatted.
packages/react-compiler/src/

# Lockfiles handled by their own tooling
pnpm-lock.yaml
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"scripts": {
"dev": "turbo run dev --filter=react-doctor",
"build": "turbo run build",
"test": "turbo run test --filter=react-doctor --filter=@react-doctor/core --filter=@react-doctor/api",
"test": "turbo run test --filter=react-doctor --filter=@react-doctor/core --filter=@react-doctor/api --filter=babel-plugin-react-compiler",
"test:public-react-repos": "REACT_DOCTOR_PUBLIC_REPOS=1 vp test run packages/react-doctor/tests/public-react-repos.test.ts",
"typecheck": "turbo run typecheck",
"lint": "vp lint",
Expand Down Expand Up @@ -53,7 +53,9 @@
],
"overrides": {
"oxlint": "^1.66.0",
"oxlint-tsgolint": "^0.23.0"
"oxlint-tsgolint": "^0.23.0",
"semver": "7.7.4",
"@babel/types": "7.26.3"
}
}
}
4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
"@effect/platform-node-shared": "4.0.0-beta.70",
"deslop-js": "^0.0.14",
"effect": "4.0.0-beta.70",
"eslint-plugin-react-hooks": "^7.1.1",
"oxlint": "^1.66.0",
"oxlint-plugin-react-doctor": "workspace:*",
"picomatch": "^4.0.4",
"typescript": "^6.0.3"
},
"optionalDependencies": {
"@react-doctor/compiler-native": "workspace:*"
},
"devDependencies": {
"@effect/vitest": "4.0.0-beta.70",
"@types/node": "^25.6.0",
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/runners/oxlint/plugin-resolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,28 @@ interface ResolvedReactHooksJsPlugin {

const bundledRequire = createRequire(import.meta.url);

/**
* Resolves the React-Compiler-backed `react-hooks-js/*` rules plugin: the native
* `@react-doctor/compiler-native` plugin, an in-house Rust + oxc reimplementation
* of `babel-plugin-react-compiler`'s analyzer (no `eslint-plugin-react-hooks` /
* `babel-plugin-react-compiler` runtime dependency). Returns `null` when the
* native addon can't be loaded — e.g. a platform without a prebuilt `.node` — in
* which case the React Compiler rules are simply not registered (a graceful no-op,
* the same path as when the plugin was historically absent), never a crash.
*/
export const resolveReactHooksJsPlugin = (
hasReactCompiler: boolean,
customRulesOnly: boolean,
): ResolvedReactHooksJsPlugin | null => {
if (!hasReactCompiler || customRulesOnly) return null;
let pluginSpecifier: string;
try {
pluginSpecifier = bundledRequire.resolve("eslint-plugin-react-hooks");
pluginSpecifier = bundledRequire.resolve("@react-doctor/compiler-native/plugin.js");
} catch {
return null;
}
const { ruleNames } = readPluginShape(pluginSpecifier, (spec) => bundledRequire(spec));
if (ruleNames.size === 0) return null;
return {
entry: { name: "react-hooks-js", specifier: pluginSpecifier },
availableRuleNames: ruleNames,
Expand Down
8 changes: 8 additions & 0 deletions packages/react-compiler-oxc-napi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Cargo build output.
/target

# Prebuilt native addons — produced per-platform in CI, not committed.
*.node

# rustfmt backups.
**/*.rs.bk
Loading
Loading