Skip to content

feat(lint/js): add useReactCompiler - #10710

Merged
dyc3 merged 22 commits into
mainfrom
dyc3/react-compiler-service
Aug 5, 2026
Merged

dyc3 merged 22 commits into
mainfrom
dyc3/react-compiler-service

Conversation

@dyc3

@dyc3 dyc3 commented Jun 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The goal of this PR is to integrate the React Compiler as a new lint rule. I believe this is in a good enough state to ship, but IMO we should probably keep it in nursery for a while.

Long term:

  • I think we'll have to vendor the react compiler in here, or deal with having a git dependency (which would prevent us from publishing crates).
  • The most brittle part about this is the string comparisons we have to do in order to emit diagnostics that meet our standards. It would be better to expose a different API surface if we vendor the compiler.
  • We'll likely skip the Biome CST -> Babel AST -> React compiler HIR and just have Biome CST -> React compiler HIR at some point in the future, but for now that is out of scope of this PR.

This is practically done entirely by the clankers gpt 5.5/opus 4.8/fable.

Review guide

The vast majority of this PR is plumbing (biome_react_compiler). Assume the signals the diagnostics provide is correct. It's using the react compiler, we don't implement the business logic. There's also some unavoidable string cloning and string comparisons because of the react compiler's API surface.

The rest of the code is the usual lint rule boilerplate, and a new analyzer service to hold the react compiler (crates/biome_js_analyze/src/services/react_compiler.rs).

The parts I think need attention:

  • Are the diagnostic messages right? I don't have tons of context on React, so I don't know if the wording is right.
  • Do our tests cover common cases that people expect the react compiler to catch?

I've filed #10974 for the remaining work.

Test Plan

  • Previous versions of this PR included a conformance suite (checks if we flag all the things that the react compiler flags in their tests), removed in 02560f4, see commit message for context
    • Status of conformance when removed: only 6 tests were failing, all were extreme edge cases, and may be caused by bugs/missing features in our semantic model.
  • plus some of our own snapshot tests

Docs

@changeset-bot

changeset-bot Bot commented Jun 19, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ef56ebf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

✅ Organic activity

No automation signals detected in the analyzed events.

View full analysis →

This is an automated analysis by AgentScan

@github-actions github-actions Bot added A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Jun 19, 2026
mateicanavra added a commit to mateicanavra/civ7-modding-tools that referenced this pull request Jun 30, 2026
…oks, exhaustive-deps, jsx-key)

Add the React linting that applies to the controller-hook decomposition, kept
entirely on Biome — the repo's single hygiene/lint owner. ESLint stays
quarantined to @nx/enforce-module-boundaries (one-owner-per-layer principle), so
no ESLint rules are added here.

  correctness.useHookAtTopLevel        = "error"  (rules-of-hooks)
  correctness.useJsxKeyInIterable      = "error"  (jsx-key; 0 violations)
  correctness.useExhaustiveDependencies = "warn"  (exhaustive-deps)

Hand-picked, NOT the whole `react` domain. Two reasons: (1) the domain's
recommended set drags in rules with unrelated pre-existing violations (e.g.
noChildrenProp x2 in .design-sync/previews) that would break `biome ci`; (2) it
matches the repo's deliberate `recommended:false` + explicit-allowlist
philosophy. The explicit rules activate fine without enabling the domain.

FORWARD PLAN (per maintainer): once the habitat-toolkit infra settles and the
base is cleaned up, the repo will turn on ALL recommended Biome rules wholesale
per domain — at which point these explicit React entries fold into the domain
recommended set. This enablement is the targeted interim subset for the hook
decomposition, not the end state.

Severities:
- useHookAtTopLevel = error: 0 violations after the SchemaConfigForm fix below
  this commit (the rule caught a real null->resolved hook-count crash there).
- useExhaustiveDependencies = warn (non-blocking): surfaces ~20 deliberately-
  curated dependency arrays (54 warnings) from the decomposition whose deps were
  preserved byte-for-byte for behavioral parity; auto-injecting deps would change
  behavior. Verified warnings do NOT fail `biome ci` (a warn-only file exits 0),
  so the habitat biome:ci gate stays green.

Rationale lives in this message, not an inline biome.json comment: Biome 2.4.16
silently falls back to default (recommended) rules when biome.json carries a
JSONC `//` comment (observed: a warn-only file flipped to 3 errors), so the
config is kept pure JSON.

Deferred (tracked): the official eslint-plugin-react-hooks React Compiler /
Rules-of-React family (purity, set-state-in-render, ref-stability, manual-
memoization) has no Biome equivalent and GritQL plugins cannot express it.
Deferred to stay on one linter and honor the ESLint-quarantine principle.
Revisit when Biome ships React Compiler support — tracking biomejs/biome#10710
(checkback ~2026-07-13).

Verify: biome lint . = 0 errors + 54 warnings (exhaustive-deps only); biome ci
on studio sources exit 0; biome ci biome.json exit 0; tsc 0; studio suite 441
passed / 6 pre-existing, 0 new.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mateicanavra added a commit to mateicanavra/civ7-modding-tools that referenced this pull request Jun 30, 2026
…Compiler rules, in-memory)

Add the official React Compiler / Rules-of-React lint rules that Biome has no
equivalent for, as an opt-in developer command — WITHOUT a standing ESLint
config. apps/mapgen-studio/scripts/lint-react-compiler.mjs runs
eslint-plugin-react-hooks v7 through the ESLint Node API with
`overrideConfigFile: true` + an inline config, so it is fully in-memory: no
discoverable eslint.config enters the tree and it is intentionally NOT wired
into any CI/nx target. Biome stays the single standing linter; ESLint stays
quarantined to @nx/enforce-module-boundaries (one-owner-per-layer) — this
command never runs in the enforced lint lanes.

  bun run --cwd apps/mapgen-studio lint:react-compiler          # studio src
  node apps/mapgen-studio/scripts/lint-react-compiler.mjs <paths>
  ... --strict                                                  # exit 1 on errors

It drops rules-of-hooks + exhaustive-deps (Biome owns those via
useHookAtTopLevel / useExhaustiveDependencies) and runs the rest of v7
recommended-latest: the compiler-grade family Biome cannot express (purity,
set-state-in-render, set-state-in-effect, refs, immutability,
preserve-manual-memoization, static-components, …). Advisory by default
(exit 0) so it can be run freely.

First run surfaces 12 errors + 1 warning across the studio (e.g.
set-state-in-effect at ExplorePanel.tsx:224 and RecipePanel.tsx:160) — real
Rules-of-React findings left for separate, deliberate follow-up. This commit
makes the linter AVAILABLE; it does not fix those findings.

Stopgap until Biome ships React Compiler rule support — remove then (tracking
biomejs/biome#10710, checkback ~2026-07-13). Adds eslint-plugin-react-hooks@7.1.1
as a root devDep alongside eslint + @typescript-eslint/parser (which the script
also imports). Lockfile updated by bun (tool-managed).

Verify: script + `bun run lint:react-compiler` run (12 err/1 warn, exit 0
advisory); biome ci on root package.json + studio package.json + the script
exit 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mateicanavra added a commit to mateicanavra/civ7-modding-tools that referenced this pull request Jun 30, 2026
…plugin-react-hooks v7)` (#1982)

Add an opt-in `lint:react-compiler` script that runs React Compiler lint rules Biome cannot express

Biome is the repo's standing linter, but `eslint-plugin-react-hooks` v7 includes a family of React Compiler rules that Biome has no equivalent for — purity, set-state-in-render, ref stability, manual-memoization preservation, immutability, and static components. `rules-of-hooks` and `exhaustive-deps` are intentionally excluded since Biome already owns those.

Rather than adding a discoverable `eslint.config` to the tree, the check runs entirely in-memory via the ESLint Node API with `overrideConfigFile: true`. It is not wired into any CI or Nx target and is advisory by default (pass `--strict` to exit non-zero on errors). The script can be invoked from any directory and accepts optional path arguments to narrow the lint scope.

This is intended as a stopgap until Biome ships native React Compiler rule support (biomejs/biome#10710).
mateicanavra added a commit to mateicanavra/civ7-modding-tools that referenced this pull request Jun 30, 2026
…ction

Resolves the last react-compiler error + the lone warning, both in
useVizSelection.ts, taking lint:react-compiler --strict to 0 errors / 0 warnings.

- preserve-manual-memoization @ selection useMemo (:207) — JUSTIFIED-SUPPRESS.
  The React Compiler is NOT wired into this app's build (no
  babel-plugin-react-compiler), so this rule is advisory about future compiler
  adoption only; today the manual memo is intentional and correct. Refactoring to
  satisfy a compiler that isn't running would be speculative and risk behavior
  change for zero present benefit. Suppressed with rationale + checkback ref
  (biomejs/biome#10710).

- stale `eslint-disable react-hooks/exhaustive-deps` (:190) — CONVERTED to a
  correctly-placed `biome-ignore lint/correctness/useExhaustiveDependencies`.
  Biome now owns exhaustive-deps (and reports it at the hook call, not the deps
  array), so the old eslint-disable was inert to the real linter AND flagged as
  unused by the in-memory script. The biome-ignore documents the intentional
  one-directional resync (external selectedStepId -> viz; depending on
  viz.selectedStepId would loop) and is honored by `biome ci`. Verified it
  silences the previously-emitted Biome warn.

Runtime behavior is unchanged: the dep array stays [selectedStepId] and the
dedupe guard is untouched — only the suppression mechanism changed.

Test: useVizSelection.source.test.ts SS-4 is a SOURCE-invariant guard that was
pinned to the eslint-disable form. Updated to assert the new biome-ignore
suppression (above the effect) and to pin the [selectedStepId] deps array
directly — same invariant, current mechanism. No runtime test changed.

Verify: tsc 0; biome ci 0; studio suite 441 passed / 6 pre-existing config
failures (0 new); lint:react-compiler --strict exits 0 (0 errors, 0 warnings,
159 files). Workstream complete: all 12 errors + 1 warning resolved across the
4-branch stack (refs, set-state-derive, set-state-justified, vizselection).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added the A-CLI Area: CLI label Jul 6, 2026
@dyc3
dyc3 force-pushed the dyc3/react-compiler-service branch from 81fd80a to e1fbc8d Compare July 7, 2026 14:42
@dyc3
dyc3 marked this pull request as ready for review July 7, 2026 14:44
@codspeed

codspeed Bot commented Jul 7, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 3.74%

⚡ 8 improved benchmarks
❌ 3 regressed benchmarks
✅ 264 untouched benchmarks
🆕 3 new benchmarks
⏩ 4 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ bench_normalize_local_alias 99.2 µs 314 µs -68.41%
❌ bench_index_d_ts_salsa_invalidated[react/index.d.ts] 8.2 ms 10.3 ms -20.19%
❌ js_analyzer[index_3894593175024091846.js] 73.4 ms 86.6 ms -15.15%
⚡ tsconfig_json 626.7 µs 440.2 µs +42.37%
⚡ index_d_ts[@next/font/google/index.d.ts] 276.8 ms 235.8 ms +17.39%
⚡ index_d_ts[react/index.d.ts] 19.8 ms 16.9 ms +16.9%
⚡ bench_index_d_ts_salsa_end_to_end[@next/font/google/index.d.ts] 333.8 ms 294.1 ms +13.5%
⚡ index_d_ts[RedisCommander.d.ts] 131.9 ms 119.6 ms +10.28%
⚡ bench_index_d_ts_salsa_incremental_first_run 554.2 ms 507.8 ms +9.14%
⚡ bench_index_d_ts_salsa_end_to_end[RedisCommander.d.ts] 149.3 ms 137.3 ms +8.7%
⚡ json_analyzer[package-lock_11240515041603712709.json] 29 ms 27.4 ms +5.89%
🆕 ascii N/A 10.9 µs N/A
🆕 sanitized N/A 322 µs N/A
🆕 unicode_without_colors N/A 441.9 µs N/A

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing dyc3/react-compiler-service (ef56ebf) with main (f1f72fe)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@coderabbitai

coderabbitai Bot commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds the biome_react_compiler crate with JavaScript, TypeScript, JSX, scope, comment, diagnostic, and source-range conversion. Integrates compiler services into biome_js_analyze and adds the configurable useReactCompiler nursery rule with React 19 gating and diagnostic filtering. Adds compiler tests, lint fixtures, React version manifests, compilation-mode coverage, rule options, workspace wiring, Windows long-path support, and a release changeset.

Suggested labels: A-Core

Suggested reviewers: ematipico

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the new useReactCompiler JavaScript lint rule.
Description check ✅ Passed The description explains the React Compiler integration, nursery status, implementation scope, testing, and planned follow-up work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dyc3/react-compiler-service

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
crates/biome_react_compiler/tests/convert_ast.rs (1)

6-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hard-coded node IDs make these tests brittle to converter changes, but that's the point here.

Asserting exact node_id/start values (e.g. Some(22), Some(13)) ties the test to the current traversal order — any future conversion tweak (even unrelated ones) will need a snapshot-style update here. Acceptable for now since it's precisely what's being verified, just flagging for awareness rather than as a defect.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_react_compiler/tests/convert_ast.rs` around lines 6 - 34, The
test in converts_directive_and_function intentionally asserts exact node_id and
start values, so no code change is needed here; keep the hard-coded expectations
in this converter test as-is since they are verifying traversal output for the
current convert_file behavior.
crates/biome_react_compiler/tests/probe.rs (1)

75-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

This "test" doesn't actually test anything.

probe_diagnostics never asserts on the output — it just prints diagnostic counts/errors for each case. As written it will pass regardless of what the compiler produces, silently masking regressions. As per coding guidelines, **/*.rs debugging should go through dbg!() rather than ad-hoc println!, so this reads more like leftover exploration code than a real regression test.

Consider either converting the cases into actual assertions (e.g. expected diagnostic categories/messages per case) or moving this to a dbg!()-based scratch test excluded from CI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_react_compiler/tests/probe.rs` around lines 75 - 84,
probe_diagnostics is only printing results with println! and never asserting
anything, so it cannot catch regressions; update the test in probe.rs to either
validate the compiler output with real assertions in probe_diagnostics (using
the existing result/output/diagnostics flow) or convert it into a dbg!-style
scratch/debug test that is not treated as CI coverage, and remove the ad-hoc
println! output accordingly.

Source: Coding guidelines

crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx (1)

3-7: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Heads up: this Component is a clone of immutabilityProps.jsx.

Lines 3-7 duplicate the fixture in immutabilityProps.jsx verbatim. Harmless for now, but worth checking the two fixtures still exercise distinct diagnostic paths (immutability vs. mutation) once the rule stabilizes, otherwise one is redundant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx`
around lines 3 - 7, The Component fixture currently duplicates
immutabilityProps.jsx verbatim, so update invalidPropMutation.jsx to exercise a
distinct mutation-specific path in useReactCompiler instead of mirroring the
other test. Adjust the Component/props interaction or surrounding fixture setup
so this test uniquely covers the invalid prop mutation diagnostic, and keep the
existing duplicate fixture only if both files intentionally validate different
behaviors with clearly different inputs.
crates/biome_react_compiler/src/convert_ast/expressions.rs (1)

629-657: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

cooked is set to the raw (escaped) text.

cooked mirrors raw, so escape sequences (\n, \u0041, …) are never unescaped. Harmless for most lint paths, but if the compiler ever folds cooked template strings it will see the escaped form. Fine to defer while this stays in nursery.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_react_compiler/src/convert_ast/expressions.rs` around lines 629
- 657, The TemplateElementValue in convert_ast/expressions.rs is currently
setting cooked to the escaped raw text, so template escape sequences are never
unescaped. Update the AnyJsTemplateElement::JsTemplateElement conversion and the
final tail TemplateElement push so raw stays escaped but cooked is derived from
the decoded/unescaped template contents instead of cloning pending_raw.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/biome_react_compiler/src/convert_ast/ctx.rs`:
- Around line 45-56: The Position conversion in ctx::position is using raw byte
offsets from TextRange, but react_compiler_ast::common::Position expects UTF-16
code units for both column and index. Update the offset-to-position mapping in
position() to translate the incoming byte offset into UTF-16 units before
constructing Position, while keeping the line lookup via line_offsets intact.
Use the existing position() method and line_offsets-based line_start calculation
to locate the change.

In `@crates/biome_react_compiler/src/convert_ast/identifiers.rs`:
- Around line 140-159: In convert_optional_default_pattern,
AssignmentPattern.base is currently derived only from the initializer syntax, so
the span/loc/id excludes the left-hand pattern. Update the base range
computation to cover the full default assignment expression, using both left and
init inside convert_optional_default_pattern so AssignmentPattern tracks left =
value instead of just = value.

In `@crates/biome_react_compiler/src/convert_ast/jsx.rs`:
- Around line 224-242: convert_jsx_attribute_value currently only handles
AnyJsxTag::JsxElement, so JSX attribute values that parse as self-closing
elements or fragments still hit unsupported(...). Update the match in
convert_jsx_attribute_value to cover all AnyJsxTag variants that can appear in
attribute values, using the existing convert_jsx_element / corresponding
fragment conversion paths, and keep unsupported(...) only for truly invalid
cases.

In `@crates/biome_react_compiler/src/convert_ast/literals.rs`:
- Around line 18-37: The JsNumberLiteralExpression handling in literals.rs
currently uses a generic parse that rejects valid JavaScript numeric forms.
Update the numeric literal conversion path in the match arm for
AnyJsLiteralExpression::JsNumberLiteralExpression to use parse_js_number from
biome_js_syntax::numbers instead of raw.parse(), and map its result into the
existing NumericLiteral and ReactCompilerError::InvalidLiteral flow so hex,
octal, binary, and underscore-separated literals are accepted correctly.

---

Nitpick comments:
In
`@crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx`:
- Around line 3-7: The Component fixture currently duplicates
immutabilityProps.jsx verbatim, so update invalidPropMutation.jsx to exercise a
distinct mutation-specific path in useReactCompiler instead of mirroring the
other test. Adjust the Component/props interaction or surrounding fixture setup
so this test uniquely covers the invalid prop mutation diagnostic, and keep the
existing duplicate fixture only if both files intentionally validate different
behaviors with clearly different inputs.

In `@crates/biome_react_compiler/src/convert_ast/expressions.rs`:
- Around line 629-657: The TemplateElementValue in convert_ast/expressions.rs is
currently setting cooked to the escaped raw text, so template escape sequences
are never unescaped. Update the AnyJsTemplateElement::JsTemplateElement
conversion and the final tail TemplateElement push so raw stays escaped but
cooked is derived from the decoded/unescaped template contents instead of
cloning pending_raw.

In `@crates/biome_react_compiler/tests/convert_ast.rs`:
- Around line 6-34: The test in converts_directive_and_function intentionally
asserts exact node_id and start values, so no code change is needed here; keep
the hard-coded expectations in this converter test as-is since they are
verifying traversal output for the current convert_file behavior.

In `@crates/biome_react_compiler/tests/probe.rs`:
- Around line 75-84: probe_diagnostics is only printing results with println!
and never asserting anything, so it cannot catch regressions; update the test in
probe.rs to either validate the compiler output with real assertions in
probe_diagnostics (using the existing result/output/diagnostics flow) or convert
it into a dbg!-style scratch/debug test that is not treated as CI coverage, and
remove the ad-hoc println! output accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1e6d66d5-d5d7-4214-9240-96a320f7ae5a

📥 Commits

Reviewing files that changed from the base of the PR and between b12e486 and e1fbc8d.

⛔ Files ignored due to path filters (29)
  • Cargo.lock is excluded by !**/*.lock and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/domain_selector.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/anonymousDefaultExport.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/customHookNoJsx.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookConditional.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/immutabilityProps.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookOrder.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidUseMemo.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/renderSetState.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (55)
  • .changeset/add-react-compiler-rule.md
  • Cargo.toml
  • crates/biome_js_analyze/Cargo.toml
  • crates/biome_js_analyze/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/use_react_compiler.rs
  • crates/biome_js_analyze/src/services/mod.rs
  • crates/biome_js_analyze/src/services/react_compiler.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/anonymousDefaultExport.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/customHookNoJsx.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookConditional.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/immutabilityProps.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookOrder.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidUseMemo.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/renderSetState.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.jsx
  • crates/biome_react_compiler/Cargo.toml
  • crates/biome_react_compiler/src/comments.rs
  • crates/biome_react_compiler/src/convert_ast.rs
  • crates/biome_react_compiler/src/convert_ast/ctx.rs
  • crates/biome_react_compiler/src/convert_ast/directives.rs
  • crates/biome_react_compiler/src/convert_ast/errors.rs
  • crates/biome_react_compiler/src/convert_ast/expressions.rs
  • crates/biome_react_compiler/src/convert_ast/identifiers.rs
  • crates/biome_react_compiler/src/convert_ast/jsx.rs
  • crates/biome_react_compiler/src/convert_ast/literals.rs
  • crates/biome_react_compiler/src/convert_ast/modules.rs
  • crates/biome_react_compiler/src/convert_ast/operators.rs
  • crates/biome_react_compiler/src/convert_ast/statements.rs
  • crates/biome_react_compiler/src/convert_scope.rs
  • crates/biome_react_compiler/src/error.rs
  • crates/biome_react_compiler/src/lib.rs
  • crates/biome_react_compiler/src/prefilter.rs
  • crates/biome_react_compiler/tests/compile.rs
  • crates/biome_react_compiler/tests/convert_ast.rs
  • crates/biome_react_compiler/tests/convert_scope.rs
  • crates/biome_react_compiler/tests/probe.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/use_react_compiler.rs

Comment thread crates/biome_react_compiler/src/convert_ast/ctx.rs Outdated
Comment thread crates/biome_react_compiler/src/convert_ast/identifiers.rs
Comment thread crates/biome_react_compiler/src/convert_ast/jsx.rs
Comment thread crates/biome_react_compiler/src/convert_ast/literals.rs
@dyc3
dyc3 force-pushed the dyc3/react-compiler-service branch from 7fbf2fe to 5794d26 Compare July 7, 2026 18:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/biome_react_compiler/tests/convert_ast.rs (1)

412-423: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Trait name doesn't match its impl.

TestObjectPatternPropExt is only implemented for Expression, never for ObjectPatternProperty. Name is misleading for anyone extending these helpers later — consider TestExpressionExt or similar.

✏️ Suggested rename
-trait TestObjectPatternPropExt {
+trait TestExpressionExt {
     fn base(&self) -> &react_compiler_ast::common::BaseNode;
 }

-impl TestObjectPatternPropExt for Expression {
+impl TestExpressionExt for Expression {
     fn base(&self) -> &react_compiler_ast::common::BaseNode {
         match self {
             Expression::Identifier(identifier) => &identifier.base,
             _ => panic!("expected identifier key"),
         }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_react_compiler/tests/convert_ast.rs` around lines 412 - 423, The
helper trait name is misleading because TestObjectPatternPropExt is implemented
for Expression, not ObjectPatternProperty. Rename the trait and its impl to
something aligned with the actual receiver, such as TestExpressionExt, and
update any references in convert_ast.rs so the identifier clearly matches the
helper’s purpose.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/biome_react_compiler/tests/convert_ast.rs`:
- Around line 412-423: The helper trait name is misleading because
TestObjectPatternPropExt is implemented for Expression, not
ObjectPatternProperty. Rename the trait and its impl to something aligned with
the actual receiver, such as TestExpressionExt, and update any references in
convert_ast.rs so the identifier clearly matches the helper’s purpose.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b54ebda8-7f1c-431f-aa0d-394494fa4674

📥 Commits

Reviewing files that changed from the base of the PR and between e1fbc8d and 5794d26.

⛔ Files ignored due to path filters (1)
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (9)
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx
  • crates/biome_react_compiler/src/convert_ast.rs
  • crates/biome_react_compiler/src/convert_ast/ctx.rs
  • crates/biome_react_compiler/src/convert_ast/expressions.rs
  • crates/biome_react_compiler/src/convert_ast/identifiers.rs
  • crates/biome_react_compiler/src/convert_ast/jsx.rs
  • crates/biome_react_compiler/src/convert_ast/literals.rs
  • crates/biome_react_compiler/tests/convert_ast.rs
  • crates/biome_react_compiler/tests/probe.rs
🚧 Files skipped from review as they are similar to previous changes (7)
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx
  • crates/biome_react_compiler/src/convert_ast.rs
  • crates/biome_react_compiler/src/convert_ast/ctx.rs
  • crates/biome_react_compiler/src/convert_ast/literals.rs
  • crates/biome_react_compiler/src/convert_ast/identifiers.rs
  • crates/biome_react_compiler/src/convert_ast/expressions.rs
  • crates/biome_react_compiler/src/convert_ast/jsx.rs

@ematipico

Copy link
Copy Markdown
Member

Would mind expanding a bit more how to review the PR, please? Thank you

@johncarmack1984

Copy link
Copy Markdown
Contributor

I ran this branch against my own production apps shipping babel-plugin-react-compiler: 7 of them across 6 repos (5 public, 1 private), ~290 source files, the 216 JS/TS files diffed against eslint-plugin-react-hooks@7.1.1 recommended-latest on the same trees. PR head c7b47a4, debug build. This is field data for the conversation, but only partial confirmation of success: only 4 of the ~17 diagnostic classes ever fired on these codebases, so I can't speak to the rest.

Parity: 8/8 across my apps, plus a synthetic smoke file exercising rules-of-hooks, also line-exact. Every reference finding reproduced on the same line (columns differ by 0–4). Zero misses in either direction. The 4 clean repos were clean on both sides.

Classes hit:

  • set-state-in-effect (×6)
  • refs (×1)
  • incompatible-library (×1)
  • rules-of-hooks (×1, the synthetic file: hand-written conditional useState, not from my apps)

I can post the full table if it's useful. (Small bonus: Biome parsed two TanStack routeTree.gen.ts files that @typescript-eslint/parser errored on.)

One hang + diagnosis.

A 494KB minified Vite bundle under dist/assets/ never completes (killed at 60s, 90s, 300s; CPU pegged throughout). The ESLint plugin takes 1.9s on the same file. Every stack sample lands in biome_react_compiler::convert_ast, not the compiler.

The cause is ConvertCtx::position (crates/biome_react_compiler/src/convert_ast/ctx.rs:56): each lookup recomputes source[..offset].encode_utf16().count(), and every node does two lookups: O(nodes × file size). The per-line column scan below it (57–59) degenerates the same way when the whole file is one line.

And here's the good news: with no biome.json, file discovery walks dist/, and this file is under the default 1MiB files.maxSize.

The fix looks contained, since line_offsets is already there: cumulative UTF-16 code-unit counts at line starts fix the index path for multi-line files. But this repro is a one-line file, so the within-line scan stays O(offset) per lookup. It needs chunked prefix sums or a monotonic cursor cache too, or this exact bundle still hangs. Happy to send a patch.

A scope question.

Two Biome findings map to reference rules that recommended-latest ships disabled. One span in my code gets two diagnostics at the same location; the second corresponds to no-deriving-state-in-effects, and ESLint does flag that exact span once the rule is enabled. Faithful port, wider default scope. The other corresponds to exhaustive-effect-dependencies and did NOT fire in ESLint even with the rule enabled, so there Biome is stricter than the reference's own opt-in.

Upstream splits this surface into individually configurable rules (17 on by default); useReactCompiler is one severity plus compilationMode. Is the single knob the intended scope, or is per-class control part of the goal?

Perf (debug build, whole repos): 48 files/314ms, 84/154, 13/49, 57/220, 50/355, 27/211, 8/72. Nothing approached a 1000ms+ run, not even close. On real source code the double AST conversion looks like a non-issue.

Not covered: the other ~13 diagnostic classes (nothing fired for purity, immutability, globals, error boundaries, preserve-manual-memoization), modes other than the default infer, overlap with useExhaustiveDependencies / useHookAtTopLevel (cheap to measure, say the word), release-build timings, memory, IDE latency.

Let me know if you'd like me to set up a sample repo (or several) to test the remaining classes.

AI disclosure: the diff harness, per-file bisect, and stack sampling were built and run by Claude Code under my direction. Every finding above was verified against the ESLint plugin directly.

@dyc3

dyc3 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

A 494KB minified Vite bundle ... never completes

Linting these kinds of files is usually user error. In the real world, they should be excluded by the user's config. Although, I wouldn't expect it to be that bad. Can you post/link the file?

I wasn't aware that the eslint version actually separates the diagnostics into different rules when it reports them. It makes sense since they are different classes of errors, I guess. I suppose we could do the same thing, but it would make this a bit more complicated than it already is. Maybe we could make it a rule option? Regardless, it's something I'd rather defer to another PR, this one's already massive.

@johncarmack1984

Copy link
Copy Markdown
Contributor

Sure. Two ways to run it locally:

  • the exact file: git clone -b repro/react-compiler-hang https://github.com/johncarmack1984/lux.git — the bundle is committed on that branch at apps/desktop/dist/assets/index-zKcsBvvp.js (build of the public app; nothing sensitive in it)
  • or generate an equivalent from scratch:
// gen.mjs
import { writeFileSync } from "node:fs";
const n = Number(process.argv[2]);
let out = "function useSynthetic(){return 1}";
for (let i = 0; i < n; i++) out += `var a${i}=(a${i > 0 ? i - 1 : 0}||${i})+Math.min(${i},${i * 2});`;
writeFileSync(process.argv[3], out);

node gen.mjs 4000 out.js && biome lint --only=lint/nursery/useReactCompiler out.js

(The hook-named function only exists to pass the prefilter; the rest is plain var chains, so the repro is content-neutral.)

re: expectation: same... I think O(n^2) just makes .5MB feel a lot bigger than it really is. Scaling on generated files (debug build):

single-line file time
19 KB 4.2s
39 KB 16.5s
83 KB 68.5s
171 KB 285s

×4 per size doubling; extrapolating that curve, the 494KB bundle would finish in roughly 40 minutes (I stopped it after 5).

re: user error: agreed in principle; it does happen, though, and eslint did finish, so felt it was worth mentioning while this was still in nursery. Not a blocker for this PR. One note on the shape of the eventual fix: the full-prefix index recompute applies to any sufficiently large file, multi-line included — minified files just also degenerate the column scan — so the durable fix is the prefix-sum index rather than a guard on minified inputs. Happy to defer either way, and the patch offer stands.

re: separating into different rules: that makes sense to me, this PR adds capability without increasing risk as far as I can tell, no need to build Rome in a single changeset.

@dyc3 dyc3 added the D-React Domain: React label Jul 8, 2026
Comment thread crates/biome_react_compiler/src/lib.rs Outdated
Comment thread crates/biome_js_analyze/src/lint/nursery/use_react_compiler.rs
Comment thread crates/biome_js_analyze/src/services/react_compiler.rs Outdated
Comment thread crates/biome_react_compiler/src/error.rs
Comment thread crates/biome_react_compiler/src/convert_ast/ctx.rs Outdated
Comment thread crates/biome_react_compiler/src/convert_ast/ctx.rs Outdated
Comment thread crates/biome_react_compiler/src/convert_ast/ctx.rs Outdated
Comment on lines +25 to +28
/// Returns `true` if the file defines at least one function whose name looks
/// like a React component or hook.
pub fn has_react_like_functions(root: &AnyJsRoot) -> bool {
// Innermost enclosing variable declarator / assignment name, used as the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a solved problem internally, we don't need to re-invent the wheel. We have a react module in the JS analyser that contains utilities for working with React components and hooks. We already use those for the existing react lint rules. If there are cases we missed, we should improve what we have.

@dyc3 dyc3 Jul 9, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah I remember this part being weird. IIRC, the react compiler's heuristics are more permissive than ours, and it was causing problems with comformance. I'll look into it again

@dyc3 dyc3 Jul 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My clanker had some thoughts about it:

  1. The predicates genuinely diverge. Biome's is_react_hook_name requires use + an uppercase letter; the compiler's is_hook_name also accepts a digit (use3rdParty). And the compiler's is_react_like_name treats any capitalized function as a potential component, while Biome's component detection (ReactComponentInfo) is deliberately more precise. The prefilter must over-approximate exactly what the compiler's infer mode selects — a stricter predicate silently drops diagnostics for files the compiler would have analyzed, which is what you saw in conformance.
  2. There's a dependency cycle. The react helpers are pub(crate) inside biome_js_analyze, and biome_js_analyze depends on biome_react_compiler — this crate can't reach them without extracting the react module into a shared crate or moving the prefilter up a layer, and neither fixes point 1.

Tbh, I'd rather defer this because it seems like our heuristics have bugs that are separate from the rule impl in this PR, and it would be a bigger refactor because of the dependency cycle.

pub fn has_react_like_functions(root: &AnyJsRoot) -> bool {
// Innermost enclosing variable declarator / assignment name, used as the
// inferred name for anonymous function and arrow expressions.
let mut name_stack: Vec<(JsSyntaxNode, Option<TokenText>)> = Vec::new();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not an hashmap?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because it wouldn't help. The lookup of the name uses last() to do it.

@mdevils

mdevils commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

I would like to look into this and review it in details, but can only do it next week.

@ematipico

Copy link
Copy Markdown
Member

Take your time @mdevils , you're more than welcome to review it even after it's merged.

@dyc3 once you have time, could you open an issue to track the work of the rule, and add said issue to the metadata? It will be useful to track the work, and users can leave feedback there :)

@dyc3
dyc3 force-pushed the dyc3/react-compiler-service branch from c7b47a4 to 549c52f Compare July 17, 2026 17:45
@johncarmack1984

Copy link
Copy Markdown
Contributor

Verified at 549c52f, same repros as before, debug builds on both sides of the table:

single-line file c7b47a4 549c52f
19 KB 4.2s 0.12s
83 KB 68.5s 0.41s
171 KB 285s 0.81s
494 KB bundle killed at 5 min (~40 min extrapolated) 1.9s

Scaling is linear now, and the bundle lands right on the eslint reference (1.9s on the same file, their release build vs this debug build). Diagnostics still fire where expected.

One note for anyone re-running the generator repro from my earlier comment: the rule now gates on the manifest, so it needs a package.json with react >= 19 next to the file. A fast clean run without one means the rule never ran.

I'll keep repro/react-compiler-hang up until this merges, then delete it.

(Runs by clanker under my direction, same harness as the earlier numbers.)

dyc3 and others added 16 commits August 5, 2026 12:47
…harness, clean up rule

Checkpoint for the react-compiler-service branch.

- Converter completeness: full coverage for arrow rest params, TS this
  params, TS type alias/interface/enum decls, new.target, JSX namespaced
  names, and TS identifier bindings. Scope adapter now merges function-body
  scopes into the parent function and classifies binding kinds, fixing
  local-vs-context-variable misclassification (~93% diagnostics parity).
- Conformance: new workspace-excluded biome_react_compiler_conformance
  crate (own Cargo.lock) running differential sweeps against the OXC
  oracle, with a checked-in skip-list regression ratchet.
- Rule cleanup: removed dead ReactCompiler<N> queryable; collapsed the
  single-variant diagnostic enum; single diagnostic gate + generic
  fallback so no compiler diagnostic is silently dropped; reworded the
  CapitalizedCalls note; boxed the large CompilerDiagnostic detail to fix
  result_large_err; thread-scoped panic filter so caught compiler panics
  no longer print to stderr.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drives corpus diagnostics parity from ~93% (113 divergences) to ~99.6% (6),
all of which are now triaged and documented.

- convert_scope previously set `import: None` on every binding, so React
  hooks imported from 'react' (`import { useEffect } from 'react'`) were
  treated as module-local custom hooks instead of resolving to their
  builtin types. That silently disabled every type-based validation —
  the effect family, setState/memo-dependency inference, and ref access —
  for imported hooks. Added `import_binding_of` to populate the binding's
  import metadata (module, kind, imported name) so the compiler resolves
  them against the React globals. Fixes 106 fixtures.
- object methods (`JS_METHOD/GETTER/SETTER_OBJECT_MEMBER`) were classified
  as block scopes rather than function scopes, breaking the function
  boundary so a method capturing a later `const` was mis-analyzed as a
  forward reference. Added them to the function arm of `scope_kind`.
- Updated 3 useReactCompiler snapshots: imported useMemo now resolves, so
  the dependency-list validations correctly fire.
- Documented the 6 residual divergences (2 are oracle under-reports where
  Biome matches Babel's canonical output, 1 is a Rust-port backend
  frontier, 3 are deep edge cases on error fixtures) and ratcheted the
  skip-list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update the React Compiler git deps from b49e0415 to e71a6393e6 and adapt
to two upstream API changes:
- StringLiteral.value is now JsString (WTF-16 aware); convert via .into().
- ScopeInfo/ScopeData maps switched to FxHashMap / IndexMap<_,_,FxBuildHasher>;
  add rustc-hash dep and build the scope maps with the Fx hasher.

Upstream removed react_compiler_oxc (#36743), which was the entire basis of
the differential conformance harness, so remove the dev-only
biome_react_compiler_conformance crate and its workspace exclude.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015M6SGJ95iwMNAfpmDZ6Mx7
Default the React Compiler lint pipeline to the compiler's infer mode so
plain utility code is no longer analyzed as if it were a component, and
add a name-based prefilter (mirroring the retired react_compiler_oxc
prefilter) that skips AST/scope conversion entirely for files without
react-like functions. The previous behavior remains available via the
new compilationMode option (infer | annotation | all).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015M6SGJ95iwMNAfpmDZ6Mx7
Rebasing onto main required adapting to three upstream changes:
- `JsFileSource` moved from `biome_js_syntax` to `biome_languages`;
  added the `biome_languages` dep and updated imports.
- `JsDeclarationKind` gained a `Function` variant (split from
  `HoistedValue`); mapped it to `BindingKind::Hoisted`.
- Regenerated `linter_options_check.rs` for alphabetical ordering.

No converter behavior change: the OXC conformance corpus sweep at the
pre-removal commit still reports MATCH 1692, Tier-1 0, ratchet 0 new /
0 stale.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015M6SGJ95iwMNAfpmDZ6Mx7
Snapshots were stale after 2e80095 added the issue number to the rule
metadata.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the hand-rolled line offset table in the AST converter with
biome_line_index::LineIndex, which handles UTF-16 columns natively and
avoids re-scanning the source for every position.

Also fixes diagnostic ranges on non-ASCII files: the compiler reports
Babel-style UTF-16 indices, but text_range_from_logger_location treated
them as byte offsets. Ranges are now mapped back through the same
LineIndex.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The workspace, the spec-test harness, and rules_check all pre-insert the
SemanticModel into the service bag, so the queryable no longer registers
its own SemanticModelBuilderVisitor and just reads the model from the
services.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generated bindings for the rule and its compilationMode option were
missing because codegen could not run earlier (disk space).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rule is gated on the nearest package.json declaring React 19, so
the expect_diagnostic doc examples need a package.json file block for
rules_check to produce the expected diagnostics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ReactCompilerError now implements biome_diagnostics::Diagnostic with a
biome_console markup message instead of std Display/Error. The
user-facing CompilerDiagnostic variant maps to the rule category; the
internal variants map to internalError/panic with the INTERNAL tag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dyc3
dyc3 force-pushed the dyc3/react-compiler-service branch from 549c52f to 30f3674 Compare August 5, 2026 17:02
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/biome_react_compiler/tests/probe.rs`:
- Line 124: Update the non_ascii fixture in the probe test to remove all emoji
characters while retaining non-ASCII UTF-8 text, using accented or otherwise
multi-byte characters so byte-offset coverage remains intact.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f5d97106-2222-4d46-859d-c1597eb50b04

📥 Commits

Reviewing files that changed from the base of the PR and between f1f72fe and 30f3674.

⛔ Files ignored due to path filters (32)
  • Cargo.lock is excluded by !**/*.lock and included by **
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/domain_selector.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_configuration/src/generated/linter_options_check.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/anonymousDefaultExport.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/customHookNoJsx.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookConditional.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/immutabilityProps.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookOrder.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidUseMemo.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/react18/invalidHookUsage.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/renderSetState.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.jsx.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.jsx.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (81)
  • .changeset/add-react-compiler-rule.md
  • Cargo.toml
  • crates/biome_js_analyze/Cargo.toml
  • crates/biome_js_analyze/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/use_react_compiler.rs
  • crates/biome_js_analyze/src/services/mod.rs
  • crates/biome_js_analyze/src/services/react_compiler.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/anonymousDefaultExport.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/anonymousDefaultExport.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/customHookNoJsx.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/customHookNoJsx.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookConditional.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookConditional.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/immutabilityProps.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/immutabilityProps.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookOrder.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookOrder.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidUseMemo.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidUseMemo.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/react18/invalidHookUsage.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/react18/invalidHookUsage.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/renderSetState.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/renderSetState.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.package.json
  • crates/biome_react_compiler/Cargo.toml
  • crates/biome_react_compiler/src/comments.rs
  • crates/biome_react_compiler/src/convert_ast.rs
  • crates/biome_react_compiler/src/convert_ast/ctx.rs
  • crates/biome_react_compiler/src/convert_ast/directives.rs
  • crates/biome_react_compiler/src/convert_ast/errors.rs
  • crates/biome_react_compiler/src/convert_ast/expressions.rs
  • crates/biome_react_compiler/src/convert_ast/identifiers.rs
  • crates/biome_react_compiler/src/convert_ast/jsx.rs
  • crates/biome_react_compiler/src/convert_ast/literals.rs
  • crates/biome_react_compiler/src/convert_ast/modules.rs
  • crates/biome_react_compiler/src/convert_ast/operators.rs
  • crates/biome_react_compiler/src/convert_ast/statements.rs
  • crates/biome_react_compiler/src/convert_scope.rs
  • crates/biome_react_compiler/src/error.rs
  • crates/biome_react_compiler/src/lib.rs
  • crates/biome_react_compiler/src/prefilter.rs
  • crates/biome_react_compiler/tests/compile.rs
  • crates/biome_react_compiler/tests/convert_ast.rs
  • crates/biome_react_compiler/tests/convert_scope.rs
  • crates/biome_react_compiler/tests/probe.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/use_react_compiler.rs
🚧 Files skipped from review as they are similar to previous changes (73)
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/react18/invalidHookUsage.package.json
  • crates/biome_js_analyze/src/services/mod.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/renderSetState.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/customHookNoJsx.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.package.json
  • crates/biome_react_compiler/src/convert_ast/errors.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/react18/invalidHookUsage.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.package.json
  • crates/biome_react_compiler/tests/convert_scope.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookDynamicReference.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidUseMemo.package.json
  • Cargo.toml
  • .changeset/add-react-compiler-rule.md
  • crates/biome_react_compiler/tests/compile.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.package.json
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookOrder.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.options.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/valid.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.package.json
  • crates/biome_js_analyze/Cargo.toml
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.package.json
  • crates/biome_react_compiler/Cargo.toml
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/jsxInTryCatch.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/staticComponent.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookConditional.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/globalsReassignment.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoMissingReturn.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoAsync.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/immutabilityProps.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoUnused.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/anonymousDefaultExport.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.package.json
  • crates/biome_js_analyze/src/services/react_compiler.rs
  • crates/biome_react_compiler/src/convert_scope.rs
  • crates/biome_js_analyze/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/hookReferencedAsValue.jsx
  • crates/biome_react_compiler/src/convert_ast.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.jsx
  • crates/biome_react_compiler/src/convert_ast/directives.rs
  • crates/biome_react_compiler/src/convert_ast/operators.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/useMemoParameters.package.json
  • crates/biome_react_compiler/src/comments.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/compilationModeAll/utilityModule.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/refsAccessInRender.jsx
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidPropMutation.jsx
  • crates/biome_react_compiler/src/convert_ast/literals.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.jsx
  • crates/biome_react_compiler/src/convert_ast/ctx.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/capitalizedCall.jsx
  • crates/biome_js_analyze/src/lint/nursery/use_react_compiler.rs
  • crates/biome_react_compiler/src/error.rs
  • crates/biome_react_compiler/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/utilityModule.js
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/invalidHookUsage.package.json
  • crates/biome_js_analyze/tests/specs/nursery/useReactCompiler/purityDateNow.jsx
  • crates/biome_rule_options/src/use_react_compiler.rs
  • crates/biome_react_compiler/src/prefilter.rs
  • crates/biome_react_compiler/src/convert_ast/statements.rs
  • crates/biome_react_compiler/tests/convert_ast.rs
  • crates/biome_react_compiler/src/convert_ast/expressions.rs
  • crates/biome_react_compiler/src/convert_ast/modules.rs
  • crates/biome_react_compiler/src/convert_ast/identifiers.rs
  • crates/biome_react_compiler/src/convert_ast/jsx.rs

}
"#;
let ascii = format!("const banner = \"sparkling hello world\";\n{body}");
let non_ascii = format!("const banner = \"✨🎉 héllo wörld ✨\";\n{body}");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove emoji characters from the UTF-8 fixture.

Line 124 adds emoji characters to Rust test source. The repository rule prohibits emojis in source code and tests. Use non-emoji multi-byte text, such as accented characters, to retain the byte-offset coverage.

As per coding guidelines, “Do not use emojis in source code, comments, rustdoc, diagnostics, tests, snapshots, commit messages, issues, PR comments, or agent output.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_react_compiler/tests/probe.rs` at line 124, Update the non_ascii
fixture in the probe test to remove all emoji characters while retaining
non-ASCII UTF-8 text, using accented or otherwise multi-byte characters so
byte-offset coverage remains intact.

Source: Coding guidelines

windows ci jobs were failing
@dyc3
dyc3 force-pushed the dyc3/react-compiler-service branch from 2bf765e to baeada4 Compare August 5, 2026 17:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/pull_request.yml:
- Around line 43-45: Update the “Enable Git long paths” step condition to match
the lint matrix identifier `depot-windows-2022` used by the workflow, replacing
the mismatched `depot-windows-2022-16` value so the configuration runs before
checkout.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 985e518c-acab-45ab-a48e-cbdcc1ef7d40

📥 Commits

Reviewing files that changed from the base of the PR and between 30f3674 and baeada4.

📒 Files selected for processing (1)
  • .github/workflows/pull_request.yml

Comment thread .github/workflows/pull_request.yml
@dyc3
dyc3 merged commit 0a0fbc1 into main Aug 5, 2026
41 of 42 checks passed
@dyc3
dyc3 deleted the dyc3/react-compiler-service branch August 5, 2026 18:26
@github-actions github-actions Bot mentioned this pull request Aug 5, 2026
@dyc3 dyc3 mentioned this pull request Aug 5, 2026
OIRNOIR pushed a commit to OIRNOIR/YouTube-Helper-Client that referenced this pull request Aug 18, 2026
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
| [@biomejs/biome](https://biomejs.dev) ([source](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)) | imports | patch | [`2.5.7` -> `2.5.8`](https://renovatebot.com/diffs/npm/@biomejs%2fbiome/2.5.7/2.5.8) | `2.5.9` |

---

### Release Notes

<details>
<summary>biomejs/biome (@&#8203;biomejs/biome)</summary>

### [`v2.5.8`](https://github.com/biomejs/biome/blob/HEAD/packages/@&#8203;biomejs/biome/CHANGELOG.md#258)

[Compare Source](https://github.com/biomejs/biome/compare/@biomejs/biome@2.5.7...@biomejs/biome@2.5.8)

##### Patch Changes

- [#&#8203;10710](biomejs/biome#10710) [`0a0fbc1`](biomejs/biome@0a0fbc1) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added a new nursery rule [`useReactCompiler`](https://biomejs.dev/linter/rules/use-react-compiler/), which reports diagnostics from React Compiler lint mode.

- [#&#8203;11251](biomejs/biome#11251) [`ea9dd8a`](biomejs/biome@ea9dd8a) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Improved performance of [`noImportCycles`](https://biomejs.dev/linter/rules/no-import-cycles/).

- [#&#8203;11247](biomejs/biome#11247) [`52b44d6`](biomejs/biome@52b44d6) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the nursery rule [`noSvelteLegacyConst`](https://biomejs.dev/linter/rules/no-svelte-legacy-const/), which disallows legacy Svelte `{@const}` tags and recommends declaration tags with `$derived()`.

  Invalid:

  ```svelte
  {#each boxes as box}
    {@const area = box.width * box.height}
    <p>{area}</p>
  {/each}
  ```

  Valid:

  ```svelte
  {#each boxes as box}
    {const area = $derived(box.width * box.height)}
    <p>{area}</p>
  {/each}
  ```

- [#&#8203;11252](biomejs/biome#11252) [`d5f5704`](biomejs/biome@d5f5704) Thanks [@&#8203;Turtle-Hwan](https://github.com/Turtle-Hwan)! - Fixed [#&#8203;11250](biomejs/biome#11250): [`useAwait`](https://biomejs.dev/linter/rules/use-await/) no longer reports async functions that contain an `await using` declaration.

- [#&#8203;11143](biomejs/biome#11143) [`6be7be1`](biomejs/biome@6be7be1) Thanks [@&#8203;vznh](https://github.com/vznh)! - Fixed [#&#8203;11017](biomejs/biome#11017): [`noUselessUndefined`](https://biomejs.dev/linter/rules/no-useless-undefined/) no longer reports `return undefined` when the enclosing function has a return type annotation other than `undefined` or `void`.

- [#&#8203;11234](biomejs/biome#11234) [`caefe39`](biomejs/biome@caefe39) Thanks [@&#8203;subotac](https://github.com/subotac)! - Fixed [#&#8203;11228](biomejs/biome#11228): CSS block comments between a declaration colon and value now preserve their source indentation.

  ```diff
   :root {
     --font-stack:
  -/* comment */
  +    /* comment */
       system-ui;
   }
  ```

- [#&#8203;11285](biomejs/biome#11285) [`bca1f73`](biomejs/biome@bca1f73) Thanks [@&#8203;denbezrukov](https://github.com/denbezrukov)! - Fixed [#&#8203;11280](biomejs/biome#11280): CSS formatting keeps comments inside functional pseudo-classes and pseudo-elements instead of moving them before the function name.

  ```diff
  -:/* comment */ where(div) {}
  +:where(/* comment */ div) {}
  ```

- [#&#8203;11080](biomejs/biome#11080) [`af16a0b`](biomejs/biome@af16a0b) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - HTML `style` attribute values are now parsed as CSS. All Biome CSS lint rules are applied to the `style` attributes.

- [#&#8203;11195](biomejs/biome#11195) [`6a85588`](biomejs/biome@6a85588) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed Svelte files failing to parse when an expression begins with an object literal.

  Now the following snippet is correctly parsed:

  ```svelte
  <p>{{ a: true }}</p>
  <div class={{ active: isActive }}></div>
  ```

- [#&#8203;11173](biomejs/biome#11173) [`481d008`](biomejs/biome@481d008) Thanks [@&#8203;Austin1serb](https://github.com/Austin1serb)! - Fixed [#&#8203;10242](biomejs/biome#10242): JavaScript GritQL patterns with multiple metavariables now match snippets consistently in WebAssembly.

- [#&#8203;11187](biomejs/biome#11187) [`23c0369`](biomejs/biome@23c0369) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Added the nursery rule [`noInvalidPropertyInitValue`](https://biomejs.dev/linter/rules/no-invalid-property-init-value/), which reports an `@property` whose `initial-value` does not match its `syntax` descriptor. For example, the following declaration triggers the rule because `red` is not a `<length>`:

  ```css
  @Property --size {
    syntax: "<length>";
    inherits: false;
    initial-value: red;
  }
  ```

- [#&#8203;11272](biomejs/biome#11272) [`73896e6`](biomejs/biome@73896e6) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Improved the diagnostic emitted by [`noRootType`](https://biomejs.dev/linter/rules/no-root-type).

- [#&#8203;11240](biomejs/biome#11240) [`bd0b68d`](biomejs/biome@bd0b68d) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed [#&#8203;11223](biomejs/biome#11223): Improved the
  performance of [`noMisusedPromises`](https://biomejs.dev/linter/rules/no-misused-promises/)
  when analyzing async class methods that call other methods through `this`.

- [#&#8203;11172](biomejs/biome#11172) [`4a0bc5c`](biomejs/biome@4a0bc5c) Thanks [@&#8203;saberoueslati](https://github.com/saberoueslati)! - Fixed [#&#8203;10806](biomejs/biome#10806): [`noUselessFragments`](https://biomejs.dev/linter/rules/no-useless-fragments/) no longer causes Biome to panic when its unsafe fix removes a fragment used as a JSX attribute value.

- [#&#8203;11227](biomejs/biome#11227) [`4d603b0`](biomejs/biome@4d603b0) Thanks [@&#8203;saberoueslati](https://github.com/saberoueslati)! - Fixed [#&#8203;11178](biomejs/biome#11178): [`noUndeclaredVariables`](https://biomejs.dev/linter/rules/no-undeclared-variables/) no longer reports Vue's built-in instance properties, such as `$slots` and `$attrs`, in template expressions or `$event` in inline event-handler expressions. The instance properties are still reported inside `<script setup>`, where they are not defined.

- [#&#8203;11187](biomejs/biome#11187) [`23c0369`](biomejs/biome@23c0369) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed CSS parsing of registered custom properties: Biome now correctly validates the `syntax` descriptor of `@property` rules.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **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.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMC4zIiwidXBkYXRlZEluVmVyIjoiNDQuMzAuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Reviewed-on: https://git.oirnoir.dev/OIRNOIR/YouTube-Helper-Client/pulls/17
OIRNOIR pushed a commit to OIRNOIR/YouTube-Helper-Server that referenced this pull request Aug 18, 2026
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
| [@biomejs/biome](https://biomejs.dev) ([source](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)) | imports | patch | [`2.5.7` -> `2.5.8`](https://renovatebot.com/diffs/npm/@biomejs%2fbiome/2.5.7/2.5.8) | `2.5.9` |

---

### Release Notes

<details>
<summary>biomejs/biome (@&#8203;biomejs/biome)</summary>

### [`v2.5.8`](https://github.com/biomejs/biome/blob/HEAD/packages/@&#8203;biomejs/biome/CHANGELOG.md#258)

[Compare Source](https://github.com/biomejs/biome/compare/@biomejs/biome@2.5.7...@biomejs/biome@2.5.8)

##### Patch Changes

- [#&#8203;10710](biomejs/biome#10710) [`0a0fbc1`](biomejs/biome@0a0fbc1) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added a new nursery rule [`useReactCompiler`](https://biomejs.dev/linter/rules/use-react-compiler/), which reports diagnostics from React Compiler lint mode.

- [#&#8203;11251](biomejs/biome#11251) [`ea9dd8a`](biomejs/biome@ea9dd8a) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Improved performance of [`noImportCycles`](https://biomejs.dev/linter/rules/no-import-cycles/).

- [#&#8203;11247](biomejs/biome#11247) [`52b44d6`](biomejs/biome@52b44d6) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Added the nursery rule [`noSvelteLegacyConst`](https://biomejs.dev/linter/rules/no-svelte-legacy-const/), which disallows legacy Svelte `{@const}` tags and recommends declaration tags with `$derived()`.

  Invalid:

  ```svelte
  {#each boxes as box}
    {@const area = box.width * box.height}
    <p>{area}</p>
  {/each}
  ```

  Valid:

  ```svelte
  {#each boxes as box}
    {const area = $derived(box.width * box.height)}
    <p>{area}</p>
  {/each}
  ```

- [#&#8203;11252](biomejs/biome#11252) [`d5f5704`](biomejs/biome@d5f5704) Thanks [@&#8203;Turtle-Hwan](https://github.com/Turtle-Hwan)! - Fixed [#&#8203;11250](biomejs/biome#11250): [`useAwait`](https://biomejs.dev/linter/rules/use-await/) no longer reports async functions that contain an `await using` declaration.

- [#&#8203;11143](biomejs/biome#11143) [`6be7be1`](biomejs/biome@6be7be1) Thanks [@&#8203;vznh](https://github.com/vznh)! - Fixed [#&#8203;11017](biomejs/biome#11017): [`noUselessUndefined`](https://biomejs.dev/linter/rules/no-useless-undefined/) no longer reports `return undefined` when the enclosing function has a return type annotation other than `undefined` or `void`.

- [#&#8203;11234](biomejs/biome#11234) [`caefe39`](biomejs/biome@caefe39) Thanks [@&#8203;subotac](https://github.com/subotac)! - Fixed [#&#8203;11228](biomejs/biome#11228): CSS block comments between a declaration colon and value now preserve their source indentation.

  ```diff
   :root {
     --font-stack:
  -/* comment */
  +    /* comment */
       system-ui;
   }
  ```

- [#&#8203;11285](biomejs/biome#11285) [`bca1f73`](biomejs/biome@bca1f73) Thanks [@&#8203;denbezrukov](https://github.com/denbezrukov)! - Fixed [#&#8203;11280](biomejs/biome#11280): CSS formatting keeps comments inside functional pseudo-classes and pseudo-elements instead of moving them before the function name.

  ```diff
  -:/* comment */ where(div) {}
  +:where(/* comment */ div) {}
  ```

- [#&#8203;11080](biomejs/biome#11080) [`af16a0b`](biomejs/biome@af16a0b) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - HTML `style` attribute values are now parsed as CSS. All Biome CSS lint rules are applied to the `style` attributes.

- [#&#8203;11195](biomejs/biome#11195) [`6a85588`](biomejs/biome@6a85588) Thanks [@&#8203;dyc3](https://github.com/dyc3)! - Fixed Svelte files failing to parse when an expression begins with an object literal.

  Now the following snippet is correctly parsed:

  ```svelte
  <p>{{ a: true }}</p>
  <div class={{ active: isActive }}></div>
  ```

- [#&#8203;11173](biomejs/biome#11173) [`481d008`](biomejs/biome@481d008) Thanks [@&#8203;Austin1serb](https://github.com/Austin1serb)! - Fixed [#&#8203;10242](biomejs/biome#10242): JavaScript GritQL patterns with multiple metavariables now match snippets consistently in WebAssembly.

- [#&#8203;11187](biomejs/biome#11187) [`23c0369`](biomejs/biome@23c0369) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Added the nursery rule [`noInvalidPropertyInitValue`](https://biomejs.dev/linter/rules/no-invalid-property-init-value/), which reports an `@property` whose `initial-value` does not match its `syntax` descriptor. For example, the following declaration triggers the rule because `red` is not a `<length>`:

  ```css
  @Property --size {
    syntax: "<length>";
    inherits: false;
    initial-value: red;
  }
  ```

- [#&#8203;11272](biomejs/biome#11272) [`73896e6`](biomejs/biome@73896e6) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Improved the diagnostic emitted by [`noRootType`](https://biomejs.dev/linter/rules/no-root-type).

- [#&#8203;11240](biomejs/biome#11240) [`bd0b68d`](biomejs/biome@bd0b68d) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed [#&#8203;11223](biomejs/biome#11223): Improved the
  performance of [`noMisusedPromises`](https://biomejs.dev/linter/rules/no-misused-promises/)
  when analyzing async class methods that call other methods through `this`.

- [#&#8203;11172](biomejs/biome#11172) [`4a0bc5c`](biomejs/biome@4a0bc5c) Thanks [@&#8203;saberoueslati](https://github.com/saberoueslati)! - Fixed [#&#8203;10806](biomejs/biome#10806): [`noUselessFragments`](https://biomejs.dev/linter/rules/no-useless-fragments/) no longer causes Biome to panic when its unsafe fix removes a fragment used as a JSX attribute value.

- [#&#8203;11227](biomejs/biome#11227) [`4d603b0`](biomejs/biome@4d603b0) Thanks [@&#8203;saberoueslati](https://github.com/saberoueslati)! - Fixed [#&#8203;11178](biomejs/biome#11178): [`noUndeclaredVariables`](https://biomejs.dev/linter/rules/no-undeclared-variables/) no longer reports Vue's built-in instance properties, such as `$slots` and `$attrs`, in template expressions or `$event` in inline event-handler expressions. The instance properties are still reported inside `<script setup>`, where they are not defined.

- [#&#8203;11187](biomejs/biome#11187) [`23c0369`](biomejs/biome@23c0369) Thanks [@&#8203;ematipico](https://github.com/ematipico)! - Fixed CSS parsing of registered custom properties: Biome now correctly validates the `syntax` descriptor of `@property` rules.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **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.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMC4zIiwidXBkYXRlZEluVmVyIjoiNDQuMzAuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Reviewed-on: https://git.oirnoir.dev/OIRNOIR/YouTube-Helper-Server/pulls/36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project D-React Domain: React L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants