Skip to content

Commit c98457d

Browse files
committed
feat(napi/transformer): add runtime helper mode (#7727)
part of #7599
1 parent 85eec3c commit c98457d

5 files changed

Lines changed: 104 additions & 5 deletions

File tree

crates/oxc_transformer/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use regexp::RegExp;
5151
use typescript::TypeScript;
5252

5353
pub use crate::{
54-
common::helper_loader::HelperLoaderMode,
54+
common::helper_loader::{HelperLoaderMode, HelperLoaderOptions},
5555
compiler_assumptions::CompilerAssumptions,
5656
es2015::{ArrowFunctionsOptions, ES2015Options},
5757
jsx::{JsxOptions, JsxRuntime, ReactRefreshOptions},

napi/transform/index.d.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,34 @@ export interface Es2015Options {
3838
arrowFunction?: ArrowFunctionsOptions
3939
}
4040

41+
export declare const enum HelperMode {
42+
/**
43+
* Runtime mode (default): Helper functions are imported from a runtime package.
44+
*
45+
* Example:
46+
*
47+
* ```js
48+
* import helperName from "@babel/runtime/helpers/helperName";
49+
* helperName(...arguments);
50+
* ```
51+
*/
52+
Runtime = 'Runtime',
53+
/**
54+
* External mode: Helper functions are accessed from a global `babelHelpers` object.
55+
*
56+
* Example:
57+
*
58+
* ```js
59+
* babelHelpers.helperName(...arguments);
60+
* ```
61+
*/
62+
External = 'External'
63+
}
64+
65+
export interface Helpers {
66+
mode?: HelperMode
67+
}
68+
4169
/** TypeScript Isolated Declarations for Standalone DTS Emit */
4270
export declare function isolatedDeclaration(filename: string, sourceText: string, options?: IsolatedDeclarationsOptions | undefined | null): IsolatedDeclarationsResult
4371

@@ -247,6 +275,8 @@ export interface TransformOptions {
247275
* @see [esbuild#target](https://esbuild.github.io/api/#target)
248276
*/
249277
target?: string | Array<string>
278+
/** Behaviour for runtime helpers. */
279+
helpers?: Helpers
250280
/** Define Plugin */
251281
define?: Record<string, string>
252282
/** Inject Plugin */

napi/transform/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ if (!nativeBinding) {
361361
throw new Error(`Failed to load native binding`)
362362
}
363363

364+
module.exports.HelperMode = nativeBinding.HelperMode
364365
module.exports.isolatedDeclaration = nativeBinding.isolatedDeclaration
365366
module.exports.Severity = nativeBinding.Severity
366367
module.exports.transform = nativeBinding.transform

napi/transform/src/transformer.rs

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use oxc::{
1212
diagnostics::OxcDiagnostic,
1313
span::SourceType,
1414
transformer::{
15-
EnvOptions, InjectGlobalVariablesConfig, InjectImport, JsxRuntime,
16-
ReplaceGlobalDefinesConfig, RewriteExtensionsMode,
15+
EnvOptions, HelperLoaderMode, HelperLoaderOptions, InjectGlobalVariablesConfig,
16+
InjectImport, JsxRuntime, ReplaceGlobalDefinesConfig, RewriteExtensionsMode,
1717
},
1818
CompilerInterface,
1919
};
@@ -107,6 +107,9 @@ pub struct TransformOptions {
107107
/// @see [esbuild#target](https://esbuild.github.io/api/#target)
108108
pub target: Option<Either<String, Vec<String>>>,
109109

110+
/// Behaviour for runtime helpers.
111+
pub helpers: Option<Helpers>,
112+
110113
/// Define Plugin
111114
#[napi(ts_type = "Record<string, string>")]
112115
pub define: Option<FxHashMap<String, String>>,
@@ -134,7 +137,9 @@ impl TryFrom<TransformOptions> for oxc::transformer::TransformOptions {
134137
.unwrap_or_default(),
135138
jsx: options.jsx.map(Into::into).unwrap_or_default(),
136139
env,
137-
..Self::default()
140+
helper_loader: options
141+
.helpers
142+
.map_or_else(HelperLoaderOptions::default, HelperLoaderOptions::from),
138143
})
139144
}
140145
}
@@ -393,6 +398,53 @@ impl From<Es2015Options> for oxc::transformer::ES2015Options {
393398
}
394399
}
395400

401+
#[napi(object)]
402+
#[derive(Default)]
403+
pub struct Helpers {
404+
pub mode: Option<HelperMode>,
405+
}
406+
407+
#[derive(Default, Clone, Copy)]
408+
#[napi(string_enum)]
409+
pub enum HelperMode {
410+
/// Runtime mode (default): Helper functions are imported from a runtime package.
411+
///
412+
/// Example:
413+
///
414+
/// ```js
415+
/// import helperName from "@babel/runtime/helpers/helperName";
416+
/// helperName(...arguments);
417+
/// ```
418+
#[default]
419+
Runtime,
420+
/// External mode: Helper functions are accessed from a global `babelHelpers` object.
421+
///
422+
/// Example:
423+
///
424+
/// ```js
425+
/// babelHelpers.helperName(...arguments);
426+
/// ```
427+
External,
428+
}
429+
430+
impl From<Helpers> for HelperLoaderOptions {
431+
fn from(value: Helpers) -> Self {
432+
Self {
433+
mode: value.mode.map(HelperLoaderMode::from).unwrap_or_default(),
434+
..HelperLoaderOptions::default()
435+
}
436+
}
437+
}
438+
439+
impl From<HelperMode> for HelperLoaderMode {
440+
fn from(value: HelperMode) -> Self {
441+
match value {
442+
HelperMode::Runtime => Self::Runtime,
443+
HelperMode::External => Self::External,
444+
}
445+
}
446+
}
447+
396448
#[derive(Default)]
397449
struct Compiler {
398450
transform_options: oxc::transformer::TransformOptions,

napi/transform/test/transform.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { assert, describe, it, test } from 'vitest';
22

3-
import { transform } from '../index';
3+
import { HelperMode, transform } from '../index';
44

55
describe('simple', () => {
66
const code = 'export class A<T> {}';
@@ -92,6 +92,22 @@ describe('target', () => {
9292
});
9393
});
9494

95+
describe('helpers', () => {
96+
const data: Array<[HelperMode, string]> = [
97+
[HelperMode.External, 'babelHelpers.objectSpread2({}, x);\n'],
98+
[HelperMode.Runtime, 'import _objectSpread from "@babel/runtime/helpers/objectSpread2";\n_objectSpread({}, x);\n'],
99+
];
100+
101+
test.each(data)('%s', (mode, expected) => {
102+
const code = `({ ...x })`;
103+
const ret = transform('test.js', code, {
104+
target: 'es2015',
105+
helpers: { mode },
106+
});
107+
assert.equal(ret.code, expected);
108+
});
109+
});
110+
95111
describe('modules', () => {
96112
it('should transform export = and import ', () => {
97113
const code = `

0 commit comments

Comments
 (0)