mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
5771982655
## Root cause
The `oxc_react_compiler` snapshot harness (`tests/snapshot.rs`) rendered a clean no-op compile as the literal `No changes.` marker:
```rust
if result.changed {
out.push_str(&Codegen::new().build(&program).code);
} else {
out.push_str("No changes.");
}
```
Upstream's `snap` runner instead **always** re-emits the program as `## Code`, and only replaces it with `## Error` on a hard error. So for every fixture where oxc "bails" with `No changes.`, the fork's golden shows the reprinted source — a permanent, opaque diff.
Investigating the **rules-of-hooks** batch showed this is purely a harness-representation gap, not a compiler bug:
- All 17 "bailing" rules-of-hooks fixtures carry `@expectNothingCompiled` (e.g. top-level statements, classes, or `@compilationMode:"infer"` functions that aren't components/hooks). oxc correctly compiles nothing — matching the fork, which also compiles nothing and just reprints the source.
- Every rules-of-hooks **error** fixture already matches the fork on category, message text, and source location (Rules-of-Hooks validation is a complete port).
- Every rules-of-hooks **compiling** fixture already matches the fork structurally; residual diffs are pure codegen formatting (trailing commas, JSX paren-wrapping) which are out of scope.
## Fix
Test-only change. On a clean no-op (no parse errors **and** no compile diagnostics), codegen the unchanged program instead of the marker, mirroring the upstream runner. The marker is kept when an error was reported, since upstream emits `## Error` with no code there — and reprinting a parse-recovered AST would be misleading.
```rust
let clean = parsed.diagnostics.is_empty() && result.diagnostics.as_slice().is_empty();
if result.changed || clean {
out.push_str(&Codegen::new().build(&program).code);
} else {
out.push_str("No changes.");
}
```
No compiler source is touched, so there is no risk to the compiler, napi bindings, or other consumers. The snapshot test still catches any future behavior change.
## Fixtures changed
54 snapshots that previously said `No changes.` now render the reprinted source:
- **17 rules-of-hooks** (this batch) — all `@expectNothingCompiled`; now match the fork's `## Code` modulo whitespace.
- **37 elsewhere** (guarded corpus-wide no-ops: `infer-*`, `use-no-forget-*`, `use-no-memo-*`, `gating/*`, `effect-derived-computations/*`, `valid-setState-*`, etc.).
52 of the 54 match the fork's `## Code` modulo formatting. The 11 parse-error fixtures (`error.todo-*`) keep the marker as intended.
## Remaining work
Two of the changed snapshots move **closer** to the fork but retain **pre-existing, out-of-batch** compiler gaps (unchanged by this PR, now just more visible):
- `ignore-use-no-forget.js` — oxc doesn't implement the `@ignoreUseNoForget` plugin option, so it honors the `'use no forget'` opt-out and skips; the fork ignores the opt-out and fully compiles.
- `valid-setState-in-effect-from-ref-function-call.js` — in `@outputMode:"lint"` the fork reprints with an SSA-renamed shadowed param (`ref` → `ref_0`); oxc leaves the source unchanged.
Both are separate from Rules-of-Hooks and left to their respective batches.
26 lines
575 B
Plaintext
26 lines
575 B
Plaintext
---
|
|
source: crates/oxc_react_compiler/tests/snapshot.rs
|
|
input_file: crates/oxc_react_compiler/fixtures/valid-setState-in-effect-from-ref-array-index.js
|
|
---
|
|
// @validateNoSetStateInEffects @enableAllowSetStateFromRefsInEffects @outputMode:"lint"
|
|
import { useState, useRef, useEffect } from "react";
|
|
function Component() {
|
|
const ref = useRef([
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5
|
|
]);
|
|
const [value, setValue] = useState(0);
|
|
useEffect(() => {
|
|
const index = 2;
|
|
setValue(ref.current[index]);
|
|
}, []);
|
|
return value;
|
|
}
|
|
export const FIXTURE_ENTRYPOINT = {
|
|
fn: Component,
|
|
params: []
|
|
};
|