## 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)
Summary:
- Upgrade oxc_sourcemap to 8.0.1.
- Return borrowed SourceMap from CodegenReturn.
- Support no-sourcemap feature builds used by benchmarks.
AI-assisted: yes
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
Introduces `oxc_diagnostics::Diagnostics` — a `Vec<OxcDiagnostic>` newtype that knows the difference between errors and warnings — and makes it the standard diagnostics return value across oxc.
- **New type**: `Diagnostics` with `has_errors()`, `has_warnings()`, `errors()`, `warnings()`, plus `Vec`-like ergonomics (Deref, `IntoIterator`, `Extend`, `From`/`Into<Vec>`) so most call sites are unchanged.
- **Return types**: `ParserReturn`, `SemanticBuilderReturn`, `IsolatedDeclarationsReturn`, the React Compiler `TransformResult`/`LintResult`, and `TransformerReturn` now expose `diagnostics: Diagnostics` instead of `errors: Vec<OxcDiagnostic>` (the React Compiler's separate `errors`/`warnings` are merged into one severity-tagged list).
- **Behaviour**: a React Compiler **error** now stops the transform (no output), while **warnings** flow through and the transform continues. `compile()` aborts codegen only when `diagnostics.has_errors()` — warnings alone no longer abort (previously any diagnostic did).
## Breaking change
Consumers reading `*.errors` on these return values must read `*.diagnostics`. React Compiler consumers that read `.errors`/`.warnings` separately should use `diagnostics.has_errors()` / `diagnostics.errors()` / `diagnostics.warnings()`.
Parser/semantic/isolated-declarations fatality is otherwise unchanged. Builds on the React Compiler transform feature (#23201).
🤖 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 two named constructor presets to `SemanticBuilder` that bake in the options each use case needs, so the configuration lives in one place instead of being repeated at call sites:
- **`SemanticBuilder::new_compiler()`** — compiler pipeline. Enables syntax-error checking; leaves linter-only analyses (control flow graph, class table) off.
- **`SemanticBuilder::new_linter()`** — linter. Enables syntax-error checking, the control flow graph, and the class table.
The presets are applied at the real pipeline entry points:
- `new_linter()` → the linter service build.
- `new_compiler()` → `oxc::Compiler`, and the napi parser/transform bindings.
Everywhere else keeps `SemanticBuilder::new()` and turns on only the features it needs (mangler, minifier, formatter, transformer plugins, examples, tests, ...). Individual options can still be overridden after a preset (e.g. the linter service overrides `check_syntax_error` with its runtime flag).
Behavior is preserved at every migrated site. Node-store access is intentionally untouched in this PR.
## Verified
- Builds across the affected crates + napi; clippy clean; `oxc_linter` tests pass; full `cargo coverage` with no snapshot changes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## 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>
This is required in Rolldown to align with `esbuild`, which could inline a regular enum as long as all its enum members can be evaluated. See https://github.com/rolldown/rolldown/pull/8796
## Summary
Depends on #20508.
- Add `optimize_enums` option to `TypeScriptOptions` that treats regular enums with all-evaluable members the same as const enums: inlines member accesses and removes non-exported declarations
- Regular enums are only removed when no runtime value references remain (e.g., `typeof Foo`, passing as argument)
- Includes 14 conformance test fixtures covering basic, string values, binary expressions, cross-member/cross-enum references, merged enums, exported (kept), non-evaluable (kept), template literals, unary expressions, typeof/value-usage/passed-as-argument (kept), and re-exported (kept)
## Test plan
- [x] 14 new conformance test fixtures under `optimize-enums/`
- [x] `cargo run -p oxc_transform_conformance` passes
- [x] `cargo test -p oxc_transformer` passes
## Summary
- Disable mimalloc as the global allocator on Windows for all NAPI packages (`oxc-parser`, `oxc-minify`, `oxc-transform`)
- On Windows, packages now use the system allocator instead
Fixes#15518
## Root Cause
mimalloc has known issues with DLL unloading on Windows when the DLL is loaded by the main thread but unloaded by a worker thread ([mimalloc issue #288](https://github.com/microsoft/mimalloc/issues/288)). The cleanup code has `_mi_is_main_thread()` checks that prevent proper memory cleanup when called from a non-main thread, causing `STATUS_ACCESS_VIOLATION` crashes.
## Platforms with mimalloc enabled
| Platform | mimalloc |
|----------|----------|
| macOS | ✅ |
| Linux x86_64 | ✅ |
| Linux aarch64 | ✅ |
| Windows | ❌ (disabled) |
| FreeBSD | ❌ |
| ARM 32-bit | ❌ |
| WASM | ❌ |
🤖 Generated with [Claude Code](https://claude.ai/code)
#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`.
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)
close: #11876
This plugin adds comprehensive support for styled-components with server-side rendering, style minification, and enhanced debugging capabilities. The implementation is ported from the [official Babel plugin](https://github.com/styled-components/babel-plugin-styled-components) to ensure compatibility and feature parity.
## Current Limitations
⚠️ **Import Support**: This plugin currently only supports styled-components imported via ES modules (`import` statements). CommonJS imports using `require("styled-components")` are not yet supported.
## Feature Support
### Options:
**✅ Fully Supported:**
- `displayName`: Adds display names for debugging
- `fileName`: Controls filename prefixing in display names
- `ssr`: Adds unique component IDs for server-side rendering
- `transpileTemplateLiterals`: Converts template literals to function calls
- `minify`: Minifies CSS content in template literals
- `namespace`: Adds namespace prefixes to component IDs
- `meaninglessFileNames`: Controls which filenames are considered meaningless
**⚠️ Partially Supported:**
- `pure`: Only supports call expressions, not tagged template expressions (bundler limitation)
**❌ Not Yet Implemented:**
- `cssProp`: JSX css prop transformation
- `topLevelImportPaths`: Custom import path handling
## Testing
The test suite is adapted from the [official Babel plugin tests](https://github.com/styled-components/babel-plugin-styled-components) with modifications to integrate with our testing infrastructure.
**Note**: Some test outputs differ from the original due to our different hashing algorithm for component IDs. This is intentional and follows the same approach used by SWC's implementation.
Control printing of comments more precisely via more options:
The logic change here is that jsdoc is no longer part of annotation
comments.
```rust
pub struct CommentOptions {
/// Print normal comments that do not have special meanings.
///
/// At present only statement level comments are printed.
///
/// Default is `true`.
pub normal: bool,
/// Print jsdoc comments.
///
/// * jsdoc: `/** jsdoc */`
///
/// Default is `true`.
pub jsdoc: bool,
/// Print annotation comments.
///
/// * pure: `/* #__PURE__ */` and `/* #__NO_SIDE_EFFECTS__ */`
/// * webpack: `/* webpackChunkName */`
/// * vite: `/* @vite-ignore */`
/// * coverage: `v8 ignore`, `c8 ignore`, `node:coverage`, `istanbul ignore`
///
/// Default is `true`.
pub annotation: bool,
/// Print legal comments.
///
/// * starts with `//!` or `/*!`.
/// * contains `/* @license */` or `/* @preserve */`
///
/// Default is [LegalComment::Inline].
pub legal: LegalComment,
}
```
closes#12030
related https://github.com/rolldown/tsdown/issues/357
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
I found that the import source can be repeated, so it seems like removing the duplicate `deps` and `dynamicDeps` would be better, but I am not sure it is worth doing it.
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`.
close: #9186
## Implementation
The Implementation port from [TypeScript]( https://github.com/microsoft/TypeScript/blob/d85767abfd83880cea17cea70f9913e9c4496dcc/src/compiler/transformers/ts.ts#L1119-L1136)
## Example
Input:
```ts
class Demo {
@LogMethod
public foo(bar: number) {}
@Prop
prop: string = "hello";
}
```
Output:
```js
class Demo {
foo(bar) {}
prop = "hello";
}
babelHelpers.decorate([
LogMethod,
babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:type", Function)),
babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:paramtypes", [Number])),
babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:returntype", void 0))
], Demo.prototype, "foo", null);
babelHelpers.decorate([Prop, babelHelpers.decorateMetadata("design:type", String)], Demo.prototype, "prop", void 0);
```
## Limitations
### Compared to TypeScript
We lack a type inference ability that TypeScript has, so we cannot determine the exact type of the TyepReference refers to. See [`LegacyDecoratorMetadata::serialize_type_reference_node`] does.
For example:
Input:
```ts
type Foo = string;
class Cls {
@dec
p: Foo = ""
}
```
TypeScript Output:
```js
class Cls {
constructor() {
this.p = "";
}
}
__decorate([
dec,
__metadata("design:type", String) // Infer the type of `Foo` is `String`
], Cls.prototype, "p", void 0);
```
OXC Output:
```js
var _ref;
class Cls {
p = "";
}
babelHelpers.decorate([
dec,
babelHelpers.decorateMetadata("design:type", typeof (_ref = typeof Foo === "undefined" && Foo) === "function" ? _ref : Object)
],
Cls.prototype, "p", void 0);
```
### Compared to SWC
SWC also has the above limitation, considering that SWC has been adopted in [NestJS](https://docs.nestjs.com/recipes/swc#jest--swc), so the limitation may not be a problem. In addition, SWC provides additional support for inferring enum members, which we currently do not have. We haven't dived into how NestJS uses it, so we don't know if it matters, thus we may leave it until we receive feedback.
related: #4047
related: https://github.com/rolldown/rolldown/issues/2296
This is also known as "Experimental Decorator" in `TypeScript` by [experimentalDecorators](https://www.typescriptlang.org/tsconfig/#experimentalDecorators) enabling.
### Testing
- Six tests fail due to [emitDecoratorMetadata](https://www.typescriptlang.org/tsconfig/#emitDecoratorMetadata), as we haven't supported it yet. I found `esbuild` doesn't support it as well.
- A few tests fail due to different unique binding generator
- ...
Replace `#[allow]` with `#[expect]` through the whole codebase.
This also surfaced many places where the `#[allow]` attributes were outdated/pointless and could be removed entirely.
Only places `#[allow]` remains are:
1. In generated code and macros, where lint errors may or may not be triggered depending on the generated code.
2. A few places where clippy malfunctions. These use e.g. `#[allow(unused, clippy::allow_attributes)]`.