Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions napi/transform/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ export interface CompilerAssumptions {
setPublicClassFields?: boolean
}

export interface DecoratorOptions {
/**
* Enables experimental support for decorators, which is a version of decorators that predates the TC39 standardization process.
*
* Decorators are a language feature which hasn’t yet been fully ratified into the JavaScript specification.
* This means that the implementation version in TypeScript may differ from the implementation in JavaScript when it it decided by TC39.
*
* @see https://www.typescriptlang.org/tsconfig/#experimentalDecorators
* @default false
*/
legacy?: boolean
}

export interface ErrorLabel {
message?: string
start: number
Expand Down Expand Up @@ -270,6 +283,8 @@ export interface TransformOptions {
define?: Record<string, string>
/** Inject Plugin */
inject?: Record<string, string | [string, string]>
/** Decorator plugin */
decorator?: DecoratorOptions
}

export interface TransformResult {
Expand Down
32 changes: 28 additions & 4 deletions napi/transform/src/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ use oxc::{
diagnostics::OxcDiagnostic,
span::SourceType,
transformer::{
DecoratorOptions, EnvOptions, HelperLoaderMode, HelperLoaderOptions,
InjectGlobalVariablesConfig, InjectImport, JsxRuntime, ReplaceGlobalDefinesConfig,
RewriteExtensionsMode,
EnvOptions, HelperLoaderMode, HelperLoaderOptions, InjectGlobalVariablesConfig,
InjectImport, JsxRuntime, ReplaceGlobalDefinesConfig, RewriteExtensionsMode,
},
CompilerInterface,
};
Expand Down Expand Up @@ -134,6 +133,9 @@ pub struct TransformOptions {
/// Inject Plugin
#[napi(ts_type = "Record<string, string | [string, string]>")]
pub inject: Option<FxHashMap<String, Either<String, Vec<String>>>>,

/// Decorator plugin
pub decorator: Option<DecoratorOptions>,
}

impl TryFrom<TransformOptions> for oxc::transformer::TransformOptions {
Expand All @@ -152,7 +154,10 @@ impl TryFrom<TransformOptions> for oxc::transformer::TransformOptions {
.typescript
.map(oxc::transformer::TypeScriptOptions::from)
.unwrap_or_default(),
decorator: DecoratorOptions::default(),
decorator: options
.decorator
.map(oxc::transformer::DecoratorOptions::from)
.unwrap_or_default(),
jsx: match options.jsx {
Some(Either::A(s)) => {
if s == "preserve" {
Expand Down Expand Up @@ -262,6 +267,25 @@ impl From<TypeScriptOptions> for oxc::transformer::TypeScriptOptions {
}
}

#[napi(object)]
#[derive(Default)]
pub struct DecoratorOptions {
/// Enables experimental support for decorators, which is a version of decorators that predates the TC39 standardization process.
///
/// Decorators are a language feature which hasn’t yet been fully ratified into the JavaScript specification.
/// This means that the implementation version in TypeScript may differ from the implementation in JavaScript when it it decided by TC39.
///
/// @see https://www.typescriptlang.org/tsconfig/#experimentalDecorators
/// @default false
pub legacy: Option<bool>,
}

impl From<DecoratorOptions> for oxc::transformer::DecoratorOptions {
fn from(options: DecoratorOptions) -> Self {
oxc::transformer::DecoratorOptions { legacy: options.legacy.unwrap_or_default() }
}
}

/// Configure how TSX and JSX are transformed.
///
/// @see {@link https://babeljs.io/docs/babel-plugin-transform-react-jsx#options}
Expand Down
30 changes: 30 additions & 0 deletions napi/transform/test/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,33 @@ describe('inject plugin', () => {
expect(ret.code).toEqual('import $inject_Object_assign from "foo";\nlet _ = $inject_Object_assign;\n');
});
});

describe('legacy decorator', () => {
it('matches output', () => {
const code = `
export default @dce class C {
@dce
prop = 0;
method(@dce param) {}
}
`;
const ret = transform('test.tsx', code, {
decorator: {
legacy: true,
},
});
expect(ret.code).toMatchInlineSnapshot(`
"import _decorate from "@babel/runtime/helpers/decorate";
import _decorateParam from "@babel/runtime/helpers/decorateParam";
let C = class C {
prop = 0;
method(param) {}
};
_decorate([dce], C.prototype, "prop", void 0);
_decorate([_decorateParam(0, dce)], C.prototype, "method", null);
C = _decorate([dce], C);
export default C;
"
`);
});
});
Loading