Skip to content

Commit

Permalink
feat(napi/transformer): add runtime helper mode (#7727)
Browse files Browse the repository at this point in the history
part of #7599
  • Loading branch information
Boshen committed Dec 8, 2024
1 parent 85eec3c commit c98457d
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 5 deletions.
2 changes: 1 addition & 1 deletion crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use regexp::RegExp;
use typescript::TypeScript;

pub use crate::{
common::helper_loader::HelperLoaderMode,
common::helper_loader::{HelperLoaderMode, HelperLoaderOptions},
compiler_assumptions::CompilerAssumptions,
es2015::{ArrowFunctionsOptions, ES2015Options},
jsx::{JsxOptions, JsxRuntime, ReactRefreshOptions},
Expand Down
30 changes: 30 additions & 0 deletions napi/transform/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,34 @@ export interface Es2015Options {
arrowFunction?: ArrowFunctionsOptions
}

export declare const enum HelperMode {
/**
* Runtime mode (default): Helper functions are imported from a runtime package.
*
* Example:
*
* ```js
* import helperName from "@babel/runtime/helpers/helperName";
* helperName(...arguments);
* ```
*/
Runtime = 'Runtime',
/**
* External mode: Helper functions are accessed from a global `babelHelpers` object.
*
* Example:
*
* ```js
* babelHelpers.helperName(...arguments);
* ```
*/
External = 'External'
}

export interface Helpers {
mode?: HelperMode
}

/** TypeScript Isolated Declarations for Standalone DTS Emit */
export declare function isolatedDeclaration(filename: string, sourceText: string, options?: IsolatedDeclarationsOptions | undefined | null): IsolatedDeclarationsResult

Expand Down Expand Up @@ -247,6 +275,8 @@ export interface TransformOptions {
* @see [esbuild#target](https://esbuild.github.io/api/#target)
*/
target?: string | Array<string>
/** Behaviour for runtime helpers. */
helpers?: Helpers
/** Define Plugin */
define?: Record<string, string>
/** Inject Plugin */
Expand Down
1 change: 1 addition & 0 deletions napi/transform/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}

module.exports.HelperMode = nativeBinding.HelperMode
module.exports.isolatedDeclaration = nativeBinding.isolatedDeclaration
module.exports.Severity = nativeBinding.Severity
module.exports.transform = nativeBinding.transform
58 changes: 55 additions & 3 deletions napi/transform/src/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use oxc::{
diagnostics::OxcDiagnostic,
span::SourceType,
transformer::{
EnvOptions, InjectGlobalVariablesConfig, InjectImport, JsxRuntime,
ReplaceGlobalDefinesConfig, RewriteExtensionsMode,
EnvOptions, HelperLoaderMode, HelperLoaderOptions, InjectGlobalVariablesConfig,
InjectImport, JsxRuntime, ReplaceGlobalDefinesConfig, RewriteExtensionsMode,
},
CompilerInterface,
};
Expand Down Expand Up @@ -107,6 +107,9 @@ pub struct TransformOptions {
/// @see [esbuild#target](https://esbuild.github.io/api/#target)
pub target: Option<Either<String, Vec<String>>>,

/// Behaviour for runtime helpers.
pub helpers: Option<Helpers>,

/// Define Plugin
#[napi(ts_type = "Record<string, string>")]
pub define: Option<FxHashMap<String, String>>,
Expand Down Expand Up @@ -134,7 +137,9 @@ impl TryFrom<TransformOptions> for oxc::transformer::TransformOptions {
.unwrap_or_default(),
jsx: options.jsx.map(Into::into).unwrap_or_default(),
env,
..Self::default()
helper_loader: options
.helpers
.map_or_else(HelperLoaderOptions::default, HelperLoaderOptions::from),
})
}
}
Expand Down Expand Up @@ -393,6 +398,53 @@ impl From<Es2015Options> for oxc::transformer::ES2015Options {
}
}

#[napi(object)]
#[derive(Default)]
pub struct Helpers {
pub mode: Option<HelperMode>,
}

#[derive(Default, Clone, Copy)]
#[napi(string_enum)]
pub enum HelperMode {
/// Runtime mode (default): Helper functions are imported from a runtime package.
///
/// Example:
///
/// ```js
/// import helperName from "@babel/runtime/helpers/helperName";
/// helperName(...arguments);
/// ```
#[default]
Runtime,
/// External mode: Helper functions are accessed from a global `babelHelpers` object.
///
/// Example:
///
/// ```js
/// babelHelpers.helperName(...arguments);
/// ```
External,
}

impl From<Helpers> for HelperLoaderOptions {
fn from(value: Helpers) -> Self {
Self {
mode: value.mode.map(HelperLoaderMode::from).unwrap_or_default(),
..HelperLoaderOptions::default()
}
}
}

impl From<HelperMode> for HelperLoaderMode {
fn from(value: HelperMode) -> Self {
match value {
HelperMode::Runtime => Self::Runtime,
HelperMode::External => Self::External,
}
}
}

#[derive(Default)]
struct Compiler {
transform_options: oxc::transformer::TransformOptions,
Expand Down
18 changes: 17 additions & 1 deletion napi/transform/test/transform.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assert, describe, it, test } from 'vitest';

import { transform } from '../index';
import { HelperMode, transform } from '../index';

describe('simple', () => {
const code = 'export class A<T> {}';
Expand Down Expand Up @@ -92,6 +92,22 @@ describe('target', () => {
});
});

describe('helpers', () => {
const data: Array<[HelperMode, string]> = [
[HelperMode.External, 'babelHelpers.objectSpread2({}, x);\n'],
[HelperMode.Runtime, 'import _objectSpread from "@babel/runtime/helpers/objectSpread2";\n_objectSpread({}, x);\n'],
];

test.each(data)('%s', (mode, expected) => {
const code = `({ ...x })`;
const ret = transform('test.js', code, {
target: 'es2015',
helpers: { mode },
});
assert.equal(ret.code, expected);
});
});

describe('modules', () => {
it('should transform export = and import ', () => {
const code = `
Expand Down

0 comments on commit c98457d

Please sign in to comment.