From bec456ca87eae545df03fe949427053e85a8f127 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Sun, 29 Sep 2024 15:14:22 +0800 Subject: [PATCH] feat(transformer): support helper loader --- .../src/common/helper_loader/mod.rs | 156 ++++++++++++++++++ .../src/common/helper_loader/options.rs | 31 ++++ crates/oxc_transformer/src/common/mod.rs | 5 + crates/oxc_transformer/src/context.rs | 7 +- crates/oxc_transformer/src/es2018/mod.rs | 13 +- .../src/es2018/object_rest_spread/mod.rs | 14 +- .../object_rest_spread/object_spread.rs | 39 ++--- .../oxc_transformer/src/helpers/loader/mod.rs | 136 +++++++++++++++ crates/oxc_transformer/src/lib.rs | 4 +- crates/oxc_transformer/src/options/babel.rs | 6 + .../src/options/transformer.rs | 11 ++ 11 files changed, 382 insertions(+), 40 deletions(-) create mode 100644 crates/oxc_transformer/src/common/helper_loader/mod.rs create mode 100644 crates/oxc_transformer/src/common/helper_loader/options.rs create mode 100644 crates/oxc_transformer/src/helpers/loader/mod.rs diff --git a/crates/oxc_transformer/src/common/helper_loader/mod.rs b/crates/oxc_transformer/src/common/helper_loader/mod.rs new file mode 100644 index 00000000000000..a7cb2366c80f8f --- /dev/null +++ b/crates/oxc_transformer/src/common/helper_loader/mod.rs @@ -0,0 +1,156 @@ +//! Utility import / inline / external helper function transform. +//! +//! TODO: add more details +pub mod options; + +use std::{ + borrow::Cow, + cell::{Cell, RefCell}, + rc::Rc, +}; + +use options::{HelperLoaderMode, HelperLoaderOptions}; +use oxc_allocator::Vec; +use oxc_ast::ast::{Argument, CallExpression, Expression, Program, TSTypeParameterInstantiation}; +use oxc_semantic::{ReferenceFlags, SymbolFlags, SymbolId}; +use oxc_span::{Atom, SPAN}; +use oxc_traverse::{BoundIdentifier, Traverse, TraverseCtx}; +use rustc_hash::FxHashMap; + +use super::module_imports::ImportKind; +use crate::TransformCtx; + +pub struct HelperLoader<'a, 'ctx> { + ctx: &'ctx TransformCtx<'a>, +} + +impl<'a, 'ctx> Traverse<'a> for HelperLoader<'a, 'ctx> { + fn exit_program(&mut self, _program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) { + self.insert_into_program(); + } +} + +impl<'a, 'ctx> HelperLoader<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { ctx } + } + + fn insert_into_program(&self) { + self.ctx.helper_loader.loaded_helpers.borrow_mut().drain().for_each( + |(_, (source, import))| { + self.ctx.module_imports.add_import( + source, + ImportKind::new_default(import.name, import.symbol_id), + false, + ); + }, + ); + } +} + +// (helper_name, (path, bound_ident)) +type LoadedHelper<'a> = FxHashMap, (Atom<'a>, BoundIdentifier<'a>)>; + +pub struct HelperLoaderStore<'a> { + mode: HelperLoaderMode, + module_name: Cow<'static, str>, + babel_helper_symbol_id: Rc>>, + loaded_helpers: Rc>>, +} + +impl<'a> HelperLoaderStore<'a> { + pub fn new(options: &HelperLoaderOptions) -> Self { + Self { + mode: options.mode, + module_name: options.module_name.clone(), + loaded_helpers: Rc::new(RefCell::new(FxHashMap::default())), + babel_helper_symbol_id: Rc::new(Cell::new(None)), + } + } + + fn add_default_import(&self, helper_name: Atom<'a>, ctx: &mut TraverseCtx<'a>) { + let source = ctx.ast.atom(&format!("{}/helpers/{helper_name}", self.module_name)); + let bound_ident = ctx.generate_uid_in_root_scope(&helper_name, SymbolFlags::Import); + self.loaded_helpers.borrow_mut().insert(helper_name, (source, bound_ident)); + } + + fn transform_for_runtime_helper( + &self, + helper_name: &Atom<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + if !self.loaded_helpers.borrow().contains_key(helper_name) { + self.add_default_import(helper_name.clone(), ctx); + } + let bound_ident = self.loaded_helpers.borrow_mut()[helper_name].1.clone(); + let ident = bound_ident.create_read_reference(ctx); + ctx.ast.expression_from_identifier_reference(ident) + } + + fn transform_for_external_helper( + &self, + helper_name: Atom<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let symbol_id = self.babel_helper_symbol_id.get().or_else(|| { + let symbol_id = ctx.scopes().get_root_binding("babelHelpers"); + self.babel_helper_symbol_id.set(symbol_id); + symbol_id + }); + + let ident = ctx.create_reference_id( + SPAN, + Atom::from("babelHelpers"), + symbol_id, + ReferenceFlags::Read, + ); + + let object = ctx.ast.expression_from_identifier_reference(ident); + let property = ctx.ast.identifier_name(SPAN, helper_name); + Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) + } + + #[allow(dead_code)] + pub fn call( + &mut self, + helper_name: Atom<'a>, + arguments: Vec<'a, Argument<'a>>, + ctx: &mut TraverseCtx<'a>, + ) -> CallExpression<'a> { + let callee = self.get_callee(helper_name, ctx); + ctx.ast.call_expression( + SPAN, + callee, + None::>, + arguments, + false, + ) + } + + #[allow(dead_code)] + pub fn call_expr( + &mut self, + helper_name: Atom<'a>, + arguments: Vec<'a, Argument<'a>>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let callee = self.get_callee(helper_name, ctx); + ctx.ast.expression_call( + SPAN, + callee, + None::>, + arguments, + false, + ) + } + + pub fn get_callee(&self, helper_name: Atom<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { + match self.mode { + HelperLoaderMode::Runtime => self.transform_for_runtime_helper(&helper_name, ctx), + HelperLoaderMode::External => self.transform_for_external_helper(helper_name, ctx), + HelperLoaderMode::Inline => { + panic!("Inline helpers are not supported yet"); + } + } + } +} diff --git a/crates/oxc_transformer/src/common/helper_loader/options.rs b/crates/oxc_transformer/src/common/helper_loader/options.rs new file mode 100644 index 00000000000000..e1c17fe6ca5b62 --- /dev/null +++ b/crates/oxc_transformer/src/common/helper_loader/options.rs @@ -0,0 +1,31 @@ +use std::borrow::Cow; + +use serde::Deserialize; + +#[derive(Default, Clone, Copy, Debug, Deserialize)] +pub enum HelperLoaderMode { + /// Babel default mode + Inline, + /// Babel test default mode + External, + /// Like @babel/plugin-transform-runtime does + #[default] + Runtime, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct HelperLoaderOptions { + #[serde(default = "default_as_module_name")] + pub module_name: Cow<'static, str>, + pub mode: HelperLoaderMode, +} + +impl Default for HelperLoaderOptions { + fn default() -> Self { + Self { module_name: default_as_module_name(), mode: HelperLoaderMode::default() } + } +} + +fn default_as_module_name() -> Cow<'static, str> { + Cow::Borrowed("@babel/runtime") +} diff --git a/crates/oxc_transformer/src/common/mod.rs b/crates/oxc_transformer/src/common/mod.rs index ed3465d0c57e23..207112d806ca0f 100644 --- a/crates/oxc_transformer/src/common/mod.rs +++ b/crates/oxc_transformer/src/common/mod.rs @@ -1,11 +1,13 @@ //! Utility transforms which are in common between other transforms. +use helper_loader::HelperLoader; use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_traverse::{Traverse, TraverseCtx}; use crate::TransformCtx; +pub mod helper_loader; pub mod module_imports; pub mod top_level_statements; pub mod var_declarations; @@ -18,6 +20,7 @@ pub struct Common<'a, 'ctx> { module_imports: ModuleImports<'a, 'ctx>, var_declarations: VarDeclarations<'a, 'ctx>, top_level_statements: TopLevelStatements<'a, 'ctx>, + helper_loader: HelperLoader<'a, 'ctx>, } impl<'a, 'ctx> Common<'a, 'ctx> { @@ -26,12 +29,14 @@ impl<'a, 'ctx> Common<'a, 'ctx> { module_imports: ModuleImports::new(ctx), var_declarations: VarDeclarations::new(ctx), top_level_statements: TopLevelStatements::new(ctx), + helper_loader: HelperLoader::new(ctx), } } } impl<'a, 'ctx> Traverse<'a> for Common<'a, 'ctx> { fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { + self.helper_loader.exit_program(program, ctx); self.module_imports.exit_program(program, ctx); self.var_declarations.exit_program(program, ctx); self.top_level_statements.exit_program(program, ctx); diff --git a/crates/oxc_transformer/src/context.rs b/crates/oxc_transformer/src/context.rs index 3f0b166a011b6c..d7910e1c8cf8c2 100644 --- a/crates/oxc_transformer/src/context.rs +++ b/crates/oxc_transformer/src/context.rs @@ -10,8 +10,8 @@ use oxc_span::SourceType; use crate::{ common::{ - module_imports::ModuleImportsStore, top_level_statements::TopLevelStatementsStore, - var_declarations::VarDeclarationsStore, + helper_loader::HelperLoaderStore, module_imports::ModuleImportsStore, + top_level_statements::TopLevelStatementsStore, var_declarations::VarDeclarationsStore, }, TransformOptions, }; @@ -38,6 +38,8 @@ pub struct TransformCtx<'a> { pub var_declarations: VarDeclarationsStore<'a>, /// Manage inserting statements at top of program globally pub top_level_statements: TopLevelStatementsStore<'a>, + /// Manage helper loading + pub helper_loader: HelperLoaderStore<'a>, } impl<'a> TransformCtx<'a> { @@ -65,6 +67,7 @@ impl<'a> TransformCtx<'a> { module_imports: ModuleImportsStore::new(), var_declarations: VarDeclarationsStore::new(), top_level_statements: TopLevelStatementsStore::new(), + helper_loader: HelperLoaderStore::new(&options.helper_loader), } } diff --git a/crates/oxc_transformer/src/es2018/mod.rs b/crates/oxc_transformer/src/es2018/mod.rs index 512894b946091c..4f50ef198e1a34 100644 --- a/crates/oxc_transformer/src/es2018/mod.rs +++ b/crates/oxc_transformer/src/es2018/mod.rs @@ -6,25 +6,28 @@ pub use options::ES2018Options; use oxc_ast::ast::*; use oxc_traverse::{Traverse, TraverseCtx}; -pub struct ES2018 { +use crate::context::TransformCtx; + +pub struct ES2018<'a, 'ctx> { options: ES2018Options, // Plugins - object_rest_spread: ObjectRestSpread, + object_rest_spread: ObjectRestSpread<'a, 'ctx>, } -impl ES2018 { - pub fn new(options: ES2018Options) -> Self { +impl<'a, 'ctx> ES2018<'a, 'ctx> { + pub fn new(options: ES2018Options, ctx: &'ctx TransformCtx<'a>) -> Self { Self { object_rest_spread: ObjectRestSpread::new( options.object_rest_spread.unwrap_or_default(), + ctx, ), options, } } } -impl<'a> Traverse<'a> for ES2018 { +impl<'a, 'ctx> Traverse<'a> for ES2018<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if self.options.object_rest_spread.is_some() { self.object_rest_spread.enter_expression(expr, ctx); diff --git a/crates/oxc_transformer/src/es2018/object_rest_spread/mod.rs b/crates/oxc_transformer/src/es2018/object_rest_spread/mod.rs index c8bd93765eaed0..10a59281f2538d 100644 --- a/crates/oxc_transformer/src/es2018/object_rest_spread/mod.rs +++ b/crates/oxc_transformer/src/es2018/object_rest_spread/mod.rs @@ -32,6 +32,8 @@ use oxc_ast::ast::*; use oxc_traverse::{Traverse, TraverseCtx}; use serde::Deserialize; +use crate::context::TransformCtx; + mod object_rest; mod object_spread; @@ -43,27 +45,27 @@ pub struct ObjectRestSpreadOptions { pub(crate) use_built_ins: bool, } -pub struct ObjectRestSpread { +pub struct ObjectRestSpread<'a, 'ctx> { #[allow(dead_code)] options: ObjectRestSpreadOptions, // Plugins - object_spread: ObjectSpread, + object_spread: ObjectSpread<'a, 'ctx>, #[allow(dead_code)] object_rest: ObjectRest, } -impl ObjectRestSpread { - pub fn new(options: ObjectRestSpreadOptions) -> Self { +impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { + pub fn new(options: ObjectRestSpreadOptions, ctx: &'ctx TransformCtx<'a>) -> Self { Self { - object_spread: ObjectSpread::new(options), + object_spread: ObjectSpread::new(options, ctx), object_rest: ObjectRest::new(options), options, } } } -impl<'a> Traverse<'a> for ObjectRestSpread { +impl<'a, 'ctx> Traverse<'a> for ObjectRestSpread<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { self.object_spread.enter_expression(expr, ctx); } diff --git a/crates/oxc_transformer/src/es2018/object_rest_spread/object_spread.rs b/crates/oxc_transformer/src/es2018/object_rest_spread/object_spread.rs index bd05c13b308d18..ba2a2a4c36b885 100644 --- a/crates/oxc_transformer/src/es2018/object_rest_spread/object_spread.rs +++ b/crates/oxc_transformer/src/es2018/object_rest_spread/object_spread.rs @@ -31,18 +31,21 @@ use oxc_semantic::{ReferenceFlags, SymbolId}; use oxc_span::SPAN; use oxc_traverse::{Traverse, TraverseCtx}; +use crate::context::TransformCtx; + use super::ObjectRestSpreadOptions; -pub struct ObjectSpread { +pub struct ObjectSpread<'a, 'ctx> { options: ObjectRestSpreadOptions, + ctx: &'ctx TransformCtx<'a>, } -impl ObjectSpread { - pub fn new(options: ObjectRestSpreadOptions) -> Self { - Self { options } +impl<'a, 'ctx> ObjectSpread<'a, 'ctx> { + pub fn new(options: ObjectRestSpreadOptions, ctx: &'ctx TransformCtx<'a>) -> Self { + Self { options, ctx } } } -impl<'a> Traverse<'a> for ObjectSpread { +impl<'a, 'ctx> Traverse<'a> for ObjectSpread<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { let Expression::ObjectExpression(obj_expr) = expr else { return; @@ -77,9 +80,8 @@ impl<'a> Traverse<'a> for ObjectSpread { arguments.push(Argument::from(ctx.ast.move_expression(&mut spread_prop.argument))); let object_id = ctx.scopes().find_binding(ctx.current_scope_id(), "Object"); - let babel_helpers_id = ctx.scopes().find_binding(ctx.current_scope_id(), "babelHelpers"); - let callee = self.get_extend_object_callee(object_id, babel_helpers_id, ctx); + let callee = self.get_extend_object_callee(object_id, ctx); // ({ ...x }) => _objectSpread({}, x) *expr = ctx.ast.expression_call(SPAN, callee, NONE, arguments, false); @@ -91,14 +93,14 @@ impl<'a> Traverse<'a> for ObjectSpread { arguments.push(Argument::from(ctx.ast.move_expression(expr))); arguments.push(Argument::from(ctx.ast.expression_object(SPAN, obj_prop_list, None))); - let callee = self.get_extend_object_callee(object_id, babel_helpers_id, ctx); + let callee = self.get_extend_object_callee(object_id, ctx); *expr = ctx.ast.expression_call(SPAN, callee, NONE, arguments, false); } } } -impl<'a> ObjectSpread { +impl<'a, 'ctx> ObjectSpread<'a, 'ctx> { fn object_assign(symbol_id: Option, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { let ident = ctx.create_reference_id(SPAN, Atom::from("Object"), symbol_id, ReferenceFlags::Read); @@ -108,32 +110,19 @@ impl<'a> ObjectSpread { Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) } - fn babel_external_helper( - symbol_id: Option, - ctx: &mut TraverseCtx<'a>, - ) -> Expression<'a> { - let ident = ctx.create_reference_id( - SPAN, - Atom::from("babelHelpers"), - symbol_id, - ReferenceFlags::Read, - ); - let object = ctx.ast.expression_from_identifier_reference(ident); - let property = ctx.ast.identifier_name(SPAN, Atom::from("objectSpread2")); - - Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) + fn babel_external_helper(&self, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { + self.ctx.helper_loader.get_callee(Atom::from("objectSpread2"), ctx) } fn get_extend_object_callee( &mut self, object_id: Option, - babel_helpers_id: Option, ctx: &mut TraverseCtx<'a>, ) -> Expression<'a> { if self.options.set_spread_properties { Self::object_assign(object_id, ctx) } else { - Self::babel_external_helper(babel_helpers_id, ctx) + self.babel_external_helper(ctx) } } } diff --git a/crates/oxc_transformer/src/helpers/loader/mod.rs b/crates/oxc_transformer/src/helpers/loader/mod.rs new file mode 100644 index 00000000000000..d98b9aeb5f9bb2 --- /dev/null +++ b/crates/oxc_transformer/src/helpers/loader/mod.rs @@ -0,0 +1,136 @@ +pub mod options; + +use std::{cell::RefCell, rc::Rc}; + +use options::{HelperLoaderMode, HelperLoaderOptions}; +use oxc_allocator::{Allocator, Vec}; +use oxc_ast::{ + ast::{Argument, CallExpression, Expression, TSTypeParameterInstantiation}, + AstBuilder, +}; +use oxc_semantic::{ReferenceFlags, SymbolFlags, SymbolId}; +use oxc_span::{Atom, SPAN}; +use oxc_traverse::TraverseCtx; +use rustc_hash::FxHashMap; + +use super::module_imports::{ImportSpecifier, ModuleImports}; + +pub struct HelperLoader<'a> { + ast: AstBuilder<'a>, + mode: HelperLoaderMode, + module_name: Atom<'a>, + /// (helper_name, (import_name, symbol_id)) + loaded_helper: FxHashMap, (Atom<'a>, Option)>, + module_imports: Rc>>, +} + +impl<'a> HelperLoader<'a> { + pub fn new( + options: &HelperLoaderOptions, + allocator: &'a Allocator, + module_imports: &Rc>>, + ) -> Self { + let ast = AstBuilder::new(allocator); + let module_name = ast.atom(&options.module_name); + Self { + ast, + mode: options.mode, + module_name, + loaded_helper: FxHashMap::default(), + module_imports: Rc::clone(module_imports), + } + } + + fn add_default_import(&self, helper_name: &str, ctx: &mut TraverseCtx<'a>) -> SymbolId { + let source = ctx.ast.atom(&format!("{}/helpers/{helper_name}", self.module_name)); + let symbol_id = ctx.generate_uid_in_root_scope(helper_name, SymbolFlags::Import); + let name = self.ast.atom(&ctx.symbols().names[symbol_id]); + self.module_imports + .borrow_mut() + .add_default(source, ImportSpecifier::new(name, None, symbol_id)); + symbol_id + } + + fn transform_for_runtime_helper( + &mut self, + helper_name: &str, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + if !self.loaded_helper.contains_key(helper_name) { + let symbol_id = self.add_default_import(helper_name, ctx); + let name = self.ast.atom(&ctx.symbols().names[symbol_id]); + self.loaded_helper.insert(ctx.ast.atom(helper_name), (name, Some(symbol_id))); + } + + let (name, symbol_id) = self.loaded_helper[helper_name].clone(); + let ident = ctx.create_reference_id(SPAN, name, symbol_id, ReferenceFlags::Read); + ctx.ast.expression_from_identifier_reference(ident) + } + + fn transform_for_external_helper( + &mut self, + helper_name: Atom<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + // TODO: Whether to use find_binding instead of get_root_binding + if !self.loaded_helper.contains_key(&helper_name) { + let symbol_id = ctx.scopes().get_root_binding("babelHelpers"); + let name = self.ast.atom("babelHelpers"); + self.loaded_helper.insert(helper_name.clone(), (name, symbol_id)); + } + + let (name, symbol_id) = self.loaded_helper[&helper_name].clone(); + let ident = ctx.create_reference_id(SPAN, name, symbol_id, ReferenceFlags::Read); + let object = ctx.ast.expression_from_identifier_reference(ident); + let property = ctx.ast.identifier_name(SPAN, helper_name); + Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) + } + + #[allow(dead_code)] + pub fn call( + &mut self, + helper_name: Atom<'a>, + arguments: Vec<'a, Argument<'a>>, + ctx: &mut TraverseCtx<'a>, + ) -> CallExpression<'a> { + let callee = self.get_callee(helper_name, ctx); + ctx.ast.call_expression( + SPAN, + callee, + None::>, + arguments, + false, + ) + } + + #[allow(dead_code)] + pub fn call_expr( + &mut self, + helper_name: Atom<'a>, + arguments: Vec<'a, Argument<'a>>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let callee = self.get_callee(helper_name, ctx); + ctx.ast.expression_call( + SPAN, + callee, + None::>, + arguments, + false, + ) + } + + pub fn get_callee( + &mut self, + helper_name: Atom<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + match self.mode { + HelperLoaderMode::Runtime => self.transform_for_runtime_helper(&helper_name, ctx), + HelperLoaderMode::External => self.transform_for_external_helper(helper_name, ctx), + HelperLoaderMode::Inline => { + panic!("Inline helpers are not supported yet"); + } + } + } +} diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index a9f502ebb47af0..5de00b119f061f 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -98,7 +98,7 @@ impl<'a> Transformer<'a> { x2_es2021: ES2021::new(self.options.es2021, &self.ctx), x2_es2020: ES2020::new(self.options.es2020, &self.ctx), x2_es2019: ES2019::new(self.options.es2019), - x2_es2018: ES2018::new(self.options.es2018), + x2_es2018: ES2018::new(self.options.es2018, &self.ctx), x2_es2016: ES2016::new(self.options.es2016, &self.ctx), x3_es2015: ES2015::new(self.options.es2015), x4_regexp: RegExp::new(self.options.regexp, &self.ctx), @@ -117,7 +117,7 @@ struct TransformerImpl<'a, 'ctx> { x2_es2021: ES2021<'a, 'ctx>, x2_es2020: ES2020<'a, 'ctx>, x2_es2019: ES2019, - x2_es2018: ES2018, + x2_es2018: ES2018<'a, 'ctx>, x2_es2016: ES2016<'a, 'ctx>, x3_es2015: ES2015<'a>, x4_regexp: RegExp<'a, 'ctx>, diff --git a/crates/oxc_transformer/src/options/babel.rs b/crates/oxc_transformer/src/options/babel.rs index ce66fd62edf522..d93df01aedb831 100644 --- a/crates/oxc_transformer/src/options/babel.rs +++ b/crates/oxc_transformer/src/options/babel.rs @@ -28,6 +28,8 @@ pub struct BabelOptions { pub allow_await_outside_function: bool, #[serde(default)] pub allow_undeclared_exports: bool, + #[serde(default = "default_as_true")] + pub external_helpers: bool, } #[derive(Debug, Clone, Deserialize)] @@ -45,6 +47,10 @@ impl TestOs { } } +fn default_as_true() -> bool { + true +} + impl BabelOptions { /// Read options.json and merge them with options.json from ancestors directories. /// # Panics diff --git a/crates/oxc_transformer/src/options/transformer.rs b/crates/oxc_transformer/src/options/transformer.rs index fc559ea55c722a..b4a0016738df8b 100644 --- a/crates/oxc_transformer/src/options/transformer.rs +++ b/crates/oxc_transformer/src/options/transformer.rs @@ -4,6 +4,7 @@ use oxc_diagnostics::{Error, OxcDiagnostic}; use serde_json::{from_value, json, Value}; use crate::{ + common::helper_loader::options::{HelperLoaderMode, HelperLoaderOptions}, compiler_assumptions::CompilerAssumptions, env::{can_enable_plugin, EnvOptions, Versions}, es2015::{ArrowFunctionsOptions, ES2015Options}, @@ -53,6 +54,8 @@ pub struct TransformOptions { pub es2020: ES2020Options, pub es2021: ES2021Options, + + pub helper_loader: HelperLoaderOptions, } impl TransformOptions { @@ -86,6 +89,10 @@ impl TransformOptions { es2019: ES2019Options { optional_catch_binding: true }, es2020: ES2020Options { nullish_coalescing_operator: true }, es2021: ES2021Options { logical_assignment_operators: true }, + helper_loader: HelperLoaderOptions { + mode: HelperLoaderMode::Runtime, + ..Default::default() + }, } } @@ -288,6 +295,10 @@ impl TransformOptions { } }; + if options.external_helpers { + transformer_options.helper_loader.mode = HelperLoaderMode::External; + } + transformer_options.cwd = options.cwd.clone().unwrap_or_default(); if !errors.is_empty() {