## Summary
Removes React Compiler from the `oxc-transform` napi binding entirely.
It was previously exposed as a `reactCompiler` transform option (added
in #22942, shipped in 0.135.0 / 0.136.0).
**Why not feature-gate it instead?** Gating React Compiler in the
binding can't produce a consistent `index.d.ts`:
- Keep the option types unconditionally → the published `.d.ts`
advertises a `reactCompiler` option that a default (feature-off) build
silently ignores.
- Gate the type surface too → CI's `build-test` (which would enable the
feature) regenerates a `.d.ts` that no longer matches the checked-in
lean one, breaking `git diff --exit-code`.
Removing it from the binding sidesteps both. React Compiler stays
available to the Rust `oxc_transformer` crate behind its own
`react_compiler` feature — only the napi binding loses it.
## Changes
- Drop the `reactCompiler` option and the `ReactCompilerOptions` /
`ReactCompilerGating` / `ReactCompilerDynamicGating` types.
- Remove the `oxc_react_compiler` dependency and stop enabling `oxc`'s
`react_compiler` feature.
- Delete `src/react_compiler.rs` and `test/reactCompiler.test.ts`.
- Regenerate `index.d.ts` (drops the three interfaces + the field;
`index.js` is unchanged — they were type-only).
## Breaking change
`oxc-transform` no longer accepts the `reactCompiler` option. It shipped
in 0.135.0 and 0.136.0.
## Verification
- `cargo check` + `cargo clippy --all-targets`: clean.
- `cargo shear`: no issues; `Cargo.lock` drops only the
`oxc_transform_napi → oxc_react_compiler` edge.
- No remaining `reactCompiler` / `ReactCompilerOptions` references
anywhere else in the repo.
- `pnpm build-test` + `pnpm test`: 53/53 pass (the React Compiler test
is removed).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Reorders the option struct fields in `oxc_transformer` and the napi transform binding to match the order their transforms are evaluated, and documents that order on each struct. Behavior-neutral; the only externally visible change is field order and docs in the generated `index.d.ts`.
- **`TransformOptions`** (`oxc_transformer`): `react_compiler` (separate pass before the traversal) → `typescript` → `decorator` → `plugins` → `jsx` → `env`, with `helper_loader` last (not a transform). Previously `plugins` sat after `env` and `react_compiler` was last despite running first.
- **`EnvOptions`**: was ascending `es2015`→`es2026`; now `module` (consumed by the TypeScript transform), then `es2026` down to `es2015`, then `regexp` last.
- **`ES2020Options`**: `optional_chaining` moved next to `nullish_coalescing_operator`, matching their `enter_expression` order.
- **napi `TransformOptions`**: follows the full compiler pipeline — `lang`/`sourceType` (parse) → `assumptions` → `reactCompiler` → `typescript` → `decorator` → `plugins` → `jsx` → `target` → `helpers` → `inject` → `define` → `sourcemap` (codegen). Two things this surfaced: `inject` runs **before** `define` (the struct listed them reversed), and `sourcemap` is a codegen option so it belongs at the end. `index.d.ts` regenerated.
The canonical order is `TransformerImpl`'s field order in `lib.rs` (and `CompilerInterface::compile` for the napi pipeline stages); a note on `TransformerImpl` now reminds maintainers to keep `TransformOptions` in sync.
Verified: `cargo check`/`clippy --all-features --all-targets` (CI profile), `cargo test -p oxc_transformer`, napi vitest 62/62, transform conformance with zero snapshot diffs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Exposes the React Compiler from `oxc_transformer` behind a Cargo feature so callers no longer need a separate `oxc_react_compiler::transform` + scoping-rebuild step before transforming.
- **`oxc_transformer`**: new `react_compiler` Cargo feature (off by default) + `TransformOptions::react_compiler` field. When set, `Transformer::build_with_scoping` runs the React Compiler first (via a private `run_react_compiler` method), replacing the program and rebuilding scoping for the downstream transforms.
- **Opt-in**: the feature is **not** enabled by `oxc_transformer`'s defaults, nor by `oxc`'s `transformer`/`full` features — enabling the transformer does not pull the heavy `oxc_react_compiler` dependency. It is a separate `react_compiler` feature on `oxc` (which implies `transformer`); the napi transform binding opts in explicitly.
- **Dedupe**: removes the inline React-Compiler orchestration (and the `react_compiler_options()` hook) from `oxc`'s `CompilerInterface` and the napi transform binding; both now drive it through `TransformOptions::react_compiler`.
- **Diagnostics**: the compiler's errors and warnings are merged into `TransformerReturn::errors` (each keeps its severity; downstream filters). `compile()` reports them but no longer aborts codegen — the transformer always leaves a valid program, matching the documented "code may still be available even if there are errors" behaviour.
- **Links**: updates the React Compiler references to the merged upstream location (`react/react/tree/main/compiler`).
## Notes
Transform/codegen output is unchanged when the feature is off (the field defaults to `None` everywhere). The diagnostics behaviour change (no codegen abort) is conformance-safe — the transform-conformance harness keys off reported diagnostics, not printed output.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
Closes#13398.
The styled-components transform's `transpileTemplateLiterals` option rewrites tagged template literals into the array-call form:
```js
// in
styled.div`width: 100%;`
// out — transpileTemplateLiterals: true
styled.div(["width: 100%;"])
```
This form is only more compact when template literals are *also* down-levelled to ES5 — which is why `babel-plugin-styled-components` enables it by default, to pre-empt Babel's verbose `_taggedTemplateLiteral` output. Oxc does not down-level template literals below ES6, so the array-call form is strictly *larger* than leaving the tagged template untouched.
This PR flips the default to `false`, as agreed with @Dunqing in #13398.
## Changes
- `StyledComponentsOptions::transpile_template_literals` now defaults to `false` (both the `serde` field default and the `Default` impl), with docs explaining why.
- napi: `transpileTemplateLiterals` is documented `@default false` (`transformer.rs` + `index.d.ts`), and the styled-components napi test snapshot now reflects the non-transpiled default output.
- Conformance fixtures that relied on the old default and whose reference output is transpiled now pin `transpileTemplateLiterals: true`, so they keep matching `babel-plugin-styled-components`' reference output. The conformance snapshot is unchanged — `plugin-styled-components` stays at 25/40.
## Breaking change
`transpileTemplateLiterals` now defaults to `false`. Pass `transpileTemplateLiterals: true` to restore the previous behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Closes https://github.com/oxc-project/oxc/issues/10048
Integrates the Rust port of the React Compiler ([facebook/react#36173](https://github.com/facebook/react/pull/36173)) into oxc.
## Notes (resolved)
- Published crates can't reference Git URLs, so using this from Rolldown needs the React Compiler crates on crates.io. ✅ Published as a fork at https://crates.io/crates/forked_react_compiler; this PR depends on those `forked_react_compiler*` crates so people can get earlier access.
- The React Compiler crates had no license field. ✅ The published fork carries `license = "MIT"` (per the React repo's MIT license), so Cargo Deny and Security Analysis pass.
## Benchmark
**Wall-clock overhead vs plain transform** (release `transformSync`, same `jsx: automatic`, toggling only `reactCompiler`):
| fixture | without | with | overhead |
| --- | --- | --- | --- |
| RadixUIAdoptionSection.jsx (2.5 KiB) | 0.03 ms | 1.81 ms | +1.8 ms |
| excalidraw `App.tsx` (406 KiB) | 4.09 ms | 14.49 ms | +10.4 ms (3.5×) |
So roughly a fixed ~1.8 ms floor per file plus a per-size cost — about **3.5× the transform time** on a large real-world component.
## Binary size
Linking the React Compiler pulls the whole compiler pipeline (HIR, lowering, inference, SSA, optimization, reactive scopes, validation) plus the oxc⇄Babel AST conversion into the binding. Release build of the napi transform addon (`transform.darwin-arm64.node`, `--release`, stripped), darwin-arm64:
| build | size |
| --- | --- |
| baseline (`main`) | 3.51 MiB |
| with React Compiler | 8.66 MiB |
| **delta** | **+5.14 MiB (+146%, 2.46×)** |
## Summary
Adds a `strictNullChecks` field to `DecoratorOptions` (default `true`)
that
controls whether `null` and `undefined` are elided from union
`design:type`
metadata. The default preserves tsc strict semantics (`T | null` →
`Object`);
setting `strictNullChecks: false` matches
babel-plugin-transform-typescript-metadata
and tsc with `--strictNullChecks=false`, emitting the underlying
primitive
(`T | null` → `String` when `T = string`).
Originally this PR unconditionally elided null/undefined. Per @Dunqing's
review, it's now opt-in so the default-strict behaviour is preserved.
## Motivation
When `strictNullChecks` is off, tsc emits the constructor of the
underlying
primitive. babel-plugin-transform-typescript-metadata always elides null
and
undefined regardless of tsconfig. Downstream consumers (NestJS Swagger,
class-validator, TypeORM, AutoMapper) treat `Object` as "no metadata"
and
silently drop fields, so users with `strictNullChecks: false` (common in
older codebases) get worse behaviour under OXC than under tsc/babel.
## Implementation
```rust
pub struct DecoratorOptions {
pub legacy: bool,
pub emit_decorator_metadata: bool,
#[serde(default = "default_as_true")]
pub strict_null_checks: bool, // default true
}
```
Threaded through `Decorator::new(options) →
LegacyDecorator::new(&options) →
LegacyDecoratorMetadata::new(&options)` (matching the established
`TypeScript::new(&TypeScriptOptions)` precedent), and gated in
`serialize_union_or_intersection_constituents`:
```rust
TSType::TSNullKeyword(_) | TSType::TSUndefinedKeyword(_)
if !is_intersection && !self.strict_null_checks => continue,
```
Mirrored at the napi binding (`napi/transform/src/transformer.rs`) so
direct
Node consumers can flip it the day this lands. Consumers that wire
tsconfig
(rolldown, bundlers) can forward `compilerOptions.strictNullChecks` to
it.
## Behaviour matrix
| Source | `strictNullChecks: true` (default) | `strictNullChecks:
false` |
|---|---|---|
| `string \| null` | `Object` (matches tsc strict, current behaviour) |
`String` (matches babel, tsc non-strict) |
| `number \| undefined` | `Object` | `Number` |
| `boolean \| null \| undefined` | `Object` | `Boolean` |
| `null \| undefined` | `void 0` | `void 0` |
| `string \| number` | `Object` | `Object` (distinct primitives) |
| `string & null` | `Object` | `Object` (intersection unchanged) |
## Test plan
- [x] 7 unit tests in `tests/integrations/decorator_metadata.rs`
covering
`T | null` under both `strictNullChecks: true` (emits `Object`, current
behaviour) and `strictNullChecks: false` (emits primitive), plus
`T | undefined`, `T | null | undefined`, the `null | undefined`
void-only
case, the `string | number` distinct-primitive case (still `Object`),
and
the intersection-with-null regression
- [x] New conformance fixture `oxc/metadata/nullable-union/` with its
own
`options.json` setting `strictNullChecks: false`
- [x] `cargo test -p oxc_transformer` passes (31 unit + 11 integration)
- [x] `cargo run -p oxc_transform_conformance` shows 0 regressions;
baseline
fixtures still pass plus the new `nullable-union`
- [x] `cargo fmt -p oxc_transformer -p oxc_transform_napi` and
`cargo clippy --tests --no-deps` clean
AI assistance was used in writing this patch and tests; the contributor
has
reviewed and tested locally.
---------
Co-authored-by: Dunqing <dengqing0821@gmail.com>
Surface the TypeScript transformer's `optimize_const_enums` and
`optimize_enums` options through the napi bindings so JavaScript
consumers can opt into const enum inlining and regular (non-const)
enum inlining. Previously both were hardcoded to `false` in the
`From<TypeScriptOptions>` conversion, making them unreachable from JS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
#18089 added support in parser for `commonjs` source type.
Extend this support to the NAPI packages - accept `sourceType: 'commonjs'` in options for `oxc-parser` and `oxc-transform`.
Follow-on after #16383 and #16403.
While working on those I discovered an option NAPI-RS has to represent `Option::None` as `null`, instead of omitting the field entirely.
Use that option on the structs used for transferring errors and module record over to JS.
I think this is likely more performant because:
1. NAPI-RS can create all properties of the objects using only the faster `node_api_create_object_with_properties` API.
2. It produces consistent object shapes, so JS engine can better optimize code using these objects.
It also brings the shape of the data perfectly into line between standard transfer and raw transfer, and is consistent with how empty fields in the AST are represented as `null`.
I would have used this option before if I'd known it existed.
### Breaking change
I've marked this as a breaking change because code consuming these objects would now need to check for empty fields with `value === null` instead of `value === undefined`.
However in practice, most people probably use `!value` or `value ?? ...`, so it's unlikely to affect many users. This only affects module record and errors anyway, not the AST itself, as we transfer that as JSON, not via NAPI.
Implement a transformation plugin for tagged template expressions containing </script> tags to prevent script tag issues in browser environments.
This plugin transforms tagged template literals containing `</script` (case-insensitive) to use a helper function call with template caching, matching esbuild's behavior.
### Example
Transforms tagged templates to use cached template objects with a helper function:
Input:
```js
foo`</script>`
bar`<script>${content}</script>`
```
Output:
```js
var _templateObject, _templateObject2;
foo(_templateObject || (_templateObject = babelHelpers.taggedTemplateLiteral(["<\/script>"])));
bar(_templateObject2 || (_templateObject2 = babelHelpers.taggedTemplateLiteral(["<script>", "<\/script>"])), content);
```
Closes#15306
## Summary
This PR adds an async transform function to the NAPI transform package, following the same pattern used in the parser package for consistency.
Closes#10900
## Changes
- Added `transformAsync` function that returns a Promise
- Implemented `TransformTask` struct with `napi::Task` trait
- Reuses existing transform logic from the synchronous version
- Added comprehensive tests to verify async behavior
## Test Plan
Added tests in `test/transform.test.ts` that verify:
- Async function works correctly
- Produces identical results to sync version
- Properly handles errors
All existing tests continue to pass.
🤖 Generated with [Claude Code](https://claude.ai/code)
closes#10980
Previously final source type was only computed when `lang` is not set.
It is changed to:
* compute source type from `lang`, use filename extension if `lang` is
not set
* reset the computed source type with 'script` or `module` if provided
Expose a `moduleRunnerTransform` function that `Vite` can directly use it to speed-up ssr transform. In this way, `Vitest` also benefits without having to wait for `rolldown-vite`.
part of #6274 and #6156
```
/// Treat the source text as `js`, `jsx`, `ts`, or `tsx`.
#[napi(ts_type = "'js' | 'jsx' | 'ts' | 'tsx'")]
pub lang: Option<String>,
```