Commit Graph

40 Commits

Author SHA1 Message Date
Boshen bb0ed44541 feat(transformer)!: disable styled-components transpileTemplateLiterals by default (#23171)
## 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)
2026-06-10 03:26:40 +00:00
Kyle Cannon ee659b6785 feat(transformer/legacy-decorator): add strictNullChecks option for nullable-union design:type (#22266)
## 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>
2026-05-25 13:42:41 +08:00
Dunqing f5deb55ea6 feat(napi/transform): expose optimizeConstEnums and optimizeEnums options (#21388)
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>
2026-04-15 03:22:14 +00:00
Boshen 66b8c022ab feat(parser): implement unambiguous module parsing for JS/TS files (#18124)
## Summary

- Implements speculative/unambiguous parsing for `.js`, `.jsx`, `.ts`, and `.tsx` files
- Instead of assuming module or script upfront, parses with `ModuleKind::Unambiguous` and upgrades to module mode when ESM syntax is detected
- ESM indicators: `import`, `export`, `import.meta` (NOT top-level await alone)
- Defers top-level await errors until module type is resolved
- Vue loader upgrades unambiguous scripts to module mode
- Updates linter tests to use explicit ESM extensions (`.mjs`/`.mts`) where needed

## Test plan

- [x] All parser tests pass
- [x] All linter tests pass
- [x] All semantic tests pass
- [x] Coverage conformance tests updated

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-17 13:40:28 +00:00
Boshen 523a30a016 style(all): apply oxfmt default options (#16091)
Embrace the defaults!

---------

Co-authored-by: Yuji Sugiura <y.sugiura.0316@gmail.com>
2025-11-25 15:56:24 +09:00
Boshen ea51b0b5c8 feat(napi)!: standardize function naming with sync suffixes (#15661)
closes #15576

## Summary

Standardizes function naming across all NAPI packages (parser, transform, minify) with a consistent pattern:
- Async functions: `verb` (no suffix)
- Sync functions: `verbSync` (with Sync suffix)

## Changes

### Breaking Changes

**napi/parser:**
- `parseAsync` → `parse` (async)
- `parseSync` remains unchanged (sync)

**napi/transform:**
- `transformAsync` → `transform` (async)
- `transform` → `transformSync` (sync)
- `isolatedDeclaration` → `isolatedDeclarationSync` (sync)
- Added new `isolatedDeclaration` function (async)
- `moduleRunnerTransform` → `moduleRunnerTransformSync` (sync)
- Added new `moduleRunnerTransform` function (async)

**napi/minify:**
- `minify` → `minifySync` (sync)
- Added new `minify` function (async)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-11-13 12:28:23 +00:00
Copilot d7daf079a2 test(transformer): add escaping tests for inject import sources with special characters (#15127)
Investigated the reported issue where import source specifiers with
special characters (like quotes) were claimed to not be escaped in the
inject global variables transformer.

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sapphi-red <49056869+sapphi-red@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-30 20:37:33 +09:00
leaysgur a8e5181ab7 chore(infra): dogfooding oxfmt (#14979)
Fixes #14803

- Added `oxfmt` and `oxfmtrc.jsonc`
- Remove `dprint` plugin and useless ignore paths
- Apply `dprint` again
- Apply `oxfmt`
2025-10-28 01:16:46 +00:00
camc314 9e540025a3 chore(napi/transform): enable oxlint (#14572) 2025-10-14 13:47:21 +00:00
Boshen 588acd55b4 feat(transformer): add ES2026 target for explicit resource management (#14330)
## Summary

fixes #12796

* Added target `ES2026`
* Moves the explicit resource management feature from proposals to ES2026, as it is now a finalized ECMAScript 2026 feature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-10-05 07:12:53 +00:00
Boshen 013e0530c5 fix(napi/transform): fix define plugin not applying DCE correctly (#14264)
DCE options was using "smallest", hence `debugger` was removed.

fixes 14260
2025-09-30 15:58:31 +00:00
Boshen 70c402b9f9 feat(napi/transform): add async transform function (#13881)
## 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)
2025-09-18 12:44:53 +00:00
Dunqing 76a9865af0 fix(transformer/legacy-decorator): metadata should be inserted after all params decorators (#13215)
* Fixes https://github.com/oxc-project/oxc/issues/13210
2025-08-19 16:08:53 +00:00
Boshen f10ac33979 fix(codegen): remove end sourcemaps for }, ], ) (#13180)
closes #13174

This should reduce sourcemap memory usage by a huge amount.

These tokens were added in esbuild for code coverage: https://github.com/evanw/esbuild/commit/c4d45e6b5766b1a1b56bf24b7dadb240de91332b

But esbuild has an optimization to not generate these tokens when `}` is not on the same line

```
if class.CloseBraceLoc.Start > class.BodyLoc.Start {
    p.addSourceMapping(class.CloseBraceLoc)
}
```

We should revisit these tokens later in the future.
2025-08-18 11:45:14 +00:00
Dunqing ccbcf3eff7 feat(transformer, minifier, syntax)!: remove ESTarget::ES5 (#12448)
* close https://github.com/oxc-project/oxc/issues/11296

Both `Transformer` and `Minifier` have a minimum ES version support of `ES2015`. However, we can set the `ESTarget` to `ES5` now, which might mislead users into thinking we already support `ES5`, so for now, let's remove the `ESTarget::ES5` option to eliminate the confusion.

Suggested by @shulaoda
2025-07-24 01:07:20 +00:00
Dunqing 986c48e2a9 fix(transformer/decorator): transformed decorators should be injected after class-properties has run (#12418)
* close https://github.com/rolldown/rolldown/issues/5374

Example:

Input:
```ts
function myPropertyDecorator() {
  return (target: any, propertyKey: number) => {
    console.log(target.constructor.modelName, propertyKey);
  };
}

class Test {
  public static modelName = 'Test';

  @myPropertyDecorator()
  public myProperty = 1;
}

const instance = new Test();

export default instance;
```

Output diff:
```diff
function myPropertyDecorator() {
        return (target, propertyKey) => {
                console.log(target.constructor.modelName, propertyKey);
        };
}
class Test {
        constructor() {
                babelHelpers.defineProperty(this, "myProperty", 1);
        }
}
-babelHelpers.decorate([myPropertyDecorator()], Test.prototype, "myProperty", void 0);
-babelHelpers.defineProperty(Test, "modelName", "Test");
+babelHelpers.defineProperty(Test, "modelName", "Test");
+babelHelpers.decorate([myPropertyDecorator()], Test.prototype, "myProperty", void 0);

const instance = new Test();
export default instance;
```

The cause is that we transform class fields and decorators in two different plugins, and the decorator plugin should be transformed first, and then run the class-properties plugin, because class-properties might erase some decorator information. However, this cause transformed decorators injected before transformed class fields.

This PR fixes this problem by collecting all transformed decorators that wait for injection, and injecting them in batch after the `class-properties` plugin has run.
2025-07-21 15:14:41 +00:00
Dunqing bfd47f89b5 fix(transformer/styled-components): should use source path to generate file hash when the path is absoulte path (#12199)
related: https://github.com/oxc-project/oxc/issues/11876#issuecomment-3058036852
2025-07-11 04:54:35 +00:00
Dunqing 75ee3a17e5 feat(napi/transform): support enabling StyledComponent plugin (#12155) 2025-07-10 01:57:47 +00:00
Dunqing 6de0bc29bd feat(transformer/typescript): support transforming class fields into this assignment (#10854)
Close https://github.com/oxc-project/oxc/issues/10649
2025-05-09 08:43:13 +00:00
Boshen 4795059eed fix(transformer_plugins): provide reference data when identifiers are replaced (#10620)
closes #10577
fixes https://github.com/rolldown/rolldown/issues/4261
2025-04-29 04:52:29 +00:00
Dunqing b8414dbfb9 feat(napi/transform): support enabling removeClassFieldsWithoutInitializer (#10581)
Support passing `removeClassFieldsWithoutInitializer` by `oxc-transform` usage
2025-04-25 01:30:21 +00:00
Dunqing 45ace4419b feat(transformer): add /* @_PURE__ */ annotation for pure calls (#9424)
close: #6072

Many tests outputs are updated because we need to print `/* @_PURE__ */` for the pure calls.
2025-03-04 06:13:21 +00:00
Dunqing b4f050cf58 fix(transformer/legacy-decorator): metadata incorrectly wrapped by decorateParam (#9490)
close: https://github.com/rolldown/rolldown/issues/3728#issuecomment-2693097569

Before, we need to make sure all metadata decorators are placed after parameter decorators. I tried to push them to the last parameter decorators. But it caused it to be incorrectly wrapped by `decorateParam`.

I re-check decorate helper implementation, I didn't see any potential runtime will caused by the decorators order. So I decide to always push to method's decorators

Before:
```js
_decorate([
  _decorateParam(0, dce),
  _decorateParam(0, _decorateMetadata("design:type", Function)),
  _decorateParam(0, _decorateMetadata("design:paramtypes", [Object])),
  _decorateParam(0, _decorateMetadata("design:returntype", void 0))
], C.prototype, "method", null);
```

After:
```js
_decorate([
  _decorateMetadata("design:type", Function),
  _decorateMetadata("design:paramtypes", [Object]),
  _decorateMetadata("design:returntype", void 0),
  _decorateParam(0, dce)
], C.prototype, "method", null);
```
2025-03-03 04:08:32 +00:00
Boshen d129055dc6 test(napi): add tests for worker threads (#9408)
There are user code which may crash under some random circumstances
that we don't understand. Prevent these crashes with a test.
2025-02-27 07:19:11 +00:00
Dunqing 8a5051eea1 feat(napi/transform): support enabling emitDecoratorMetadata (#9190) 2025-02-19 14:04:33 +00:00
Dunqing fef82ffee1 feat(transformer/helper-loader): replace @babel/runtime with @oxc-project/runtime (#9059)
Replace it with our forked package.
2025-02-13 06:14:38 +00:00
Dunqing d6daa7565d feat(napi/transform): support for enabling legacy decorator (#8927) 2025-02-10 11:57:39 +00:00
Dunqing 9a03bd23b9 fix(transformer/typescript): remove type-only import = when only_remove_type_imports is true (#8275)
close: https://github.com/oxc-project/oxc/issues/8230
close: https://github.com/rolldown/rolldown/issues/3287

Related PR in Babel: https://github.com/oxc-project/oxc/issues/8230

I have compared our output with TypeScript, and it is the same as `TypeScript`, Babel's implementation currently hasn't removed imports referenced by type-only `TSImportEqualsDeclaration`
2025-01-11 08:42:51 +00:00
Dunqing e5ee38fdf1 chore(transformer): enable class-properties plugin (#7750)
Done!
2024-12-31 12:30:58 +00:00
Boshen c16a85176d feat(napi/transform): add jsx: 'preserve' option (#7965)
closes #7958
2024-12-17 13:49:51 +00:00
Boshen 2803aec521 feat(napi/transform): return helpers information (#7737)
closes #7599
2024-12-09 14:07:40 +00:00
Boshen c254a5b12c test(napi/transform): use the expect API instead of assert (#7739) 2024-12-09 09:28:01 +00:00
Boshen c98457db5c feat(napi/transformer): add runtime helper mode (#7727)
part of #7599
2024-12-08 15:29:55 +00:00
Kevin Deng 三咲智子 245d7d922c fix(oxc_transformer): alias es2015 to es6 (#7673)
Supported in
[esbuild](https://esbuild.github.io/try/#dAAwLjI0LjAALS10YXJnZXQ9ZXM2ADEqKjI)
2024-12-05 16:26:05 +08:00
Kevin Deng 三咲智子 be2293a1b5 fix(napi/transform): respect options.sourcemap for id (#7590)
Don't pass `source_map_path` if `options.sourcemap` is undefined or
false; then, `IsolatedDeclarationsResult.map` should be undefined.

Downstream issue
https://github.com/unplugin/unplugin-isolated-decl/issues/42

---------

Co-authored-by: Boshen <boshenc@gmail.com>
2024-12-03 11:57:44 +08:00
Boshen 713e210012 chore(transformor): disable class properties transform (#7486)
The plugin is not ready.
2024-11-26 03:47:46 +00:00
Boshen 59e7e4674f feat(napi/transform): add TransformOptions::target API (#7426) 2024-11-23 15:46:33 +00:00
Boshen be819dded1 test(napi/transform): add test for not default es transform 2024-11-10 00:21:26 +08:00
Boshen b4258ee58e feat(transformer): add defaulted Module::Preserve option (#7225) 2024-11-09 12:55:13 +00:00
Boshen fc86703933 refactor(napi/transform): change test files to TypeScript (#7221) 2024-11-09 17:32:15 +08:00