mirror of
https://github.com/danbulant/oxc
synced 2026-05-21 05:08:45 +00:00
parent
065f7dcb9d
commit
2803aec521
5 changed files with 79 additions and 15 deletions
|
|
@ -156,7 +156,7 @@ pub enum Helper {
|
|||
}
|
||||
|
||||
impl Helper {
|
||||
const fn name(self) -> &'static str {
|
||||
pub const fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::AwaitAsyncGenerator => "awaitAsyncGenerator",
|
||||
Self::AsyncGeneratorDelegate => "asyncGeneratorDelegate",
|
||||
|
|
@ -184,6 +184,7 @@ pub struct HelperLoaderStore<'a> {
|
|||
mode: HelperLoaderMode,
|
||||
/// Loaded helpers, determined what helpers are loaded and what imports should be added.
|
||||
loaded_helpers: RefCell<FxHashMap<Helper, BoundIdentifier<'a>>>,
|
||||
pub(crate) used_helpers: RefCell<FxHashMap<Helper, String>>,
|
||||
}
|
||||
|
||||
impl<'a> HelperLoaderStore<'a> {
|
||||
|
|
@ -192,6 +193,7 @@ impl<'a> HelperLoaderStore<'a> {
|
|||
module_name: options.module_name.clone(),
|
||||
mode: options.mode,
|
||||
loaded_helpers: RefCell::new(FxHashMap::default()),
|
||||
used_helpers: RefCell::new(FxHashMap::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -238,9 +240,12 @@ impl<'a> TransformCtx<'a> {
|
|||
/// Load a helper function and return a callee expression.
|
||||
pub fn helper_load(&self, helper: Helper, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
|
||||
let helper_loader = &self.helper_loader;
|
||||
let source = helper_loader.get_runtime_source(helper, ctx);
|
||||
helper_loader.used_helpers.borrow_mut().entry(helper).or_insert_with(|| source.to_string());
|
||||
|
||||
match helper_loader.mode {
|
||||
HelperLoaderMode::Runtime => {
|
||||
helper_loader.transform_for_runtime_helper(helper, self, ctx)
|
||||
helper_loader.transform_for_runtime_helper(helper, source, self, ctx)
|
||||
}
|
||||
HelperLoaderMode::External => {
|
||||
HelperLoaderStore::transform_for_external_helper(helper, ctx)
|
||||
|
|
@ -257,32 +262,25 @@ impl<'a> HelperLoaderStore<'a> {
|
|||
fn transform_for_runtime_helper(
|
||||
&self,
|
||||
helper: Helper,
|
||||
source: Atom<'a>,
|
||||
transform_ctx: &TransformCtx<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Expression<'a> {
|
||||
let mut loaded_helpers = self.loaded_helpers.borrow_mut();
|
||||
let binding = loaded_helpers
|
||||
.entry(helper)
|
||||
.or_insert_with(|| self.get_runtime_helper(helper, transform_ctx, ctx));
|
||||
.or_insert_with(|| Self::get_runtime_helper(helper, source, transform_ctx, ctx));
|
||||
binding.create_read_expression(ctx)
|
||||
}
|
||||
|
||||
fn get_runtime_helper(
|
||||
&self,
|
||||
helper: Helper,
|
||||
source: Atom<'a>,
|
||||
transform_ctx: &TransformCtx<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> BoundIdentifier<'a> {
|
||||
let helper_name = helper.name();
|
||||
|
||||
// Construct string directly in arena without an intermediate temp allocation
|
||||
let len = self.module_name.len() + "/helpers/".len() + helper_name.len();
|
||||
let mut source = ArenaString::with_capacity_in(len, ctx.ast.allocator);
|
||||
source.push_str(&self.module_name);
|
||||
source.push_str("/helpers/");
|
||||
source.push_str(helper_name);
|
||||
let source = Atom::from(source.into_bump_str());
|
||||
|
||||
let flag = if transform_ctx.source_type.is_module() {
|
||||
SymbolFlags::Import
|
||||
} else {
|
||||
|
|
@ -295,6 +293,17 @@ impl<'a> HelperLoaderStore<'a> {
|
|||
binding
|
||||
}
|
||||
|
||||
// Construct string directly in arena without an intermediate temp allocation
|
||||
fn get_runtime_source(&self, helper: Helper, ctx: &mut TraverseCtx<'a>) -> Atom<'a> {
|
||||
let helper_name = helper.name();
|
||||
let len = self.module_name.len() + "/helpers/".len() + helper_name.len();
|
||||
let mut source = ArenaString::with_capacity_in(len, ctx.ast.allocator);
|
||||
source.push_str(&self.module_name);
|
||||
source.push_str("/helpers/");
|
||||
source.push_str(helper_name);
|
||||
Atom::from(source.into_bump_str())
|
||||
}
|
||||
|
||||
fn transform_for_external_helper(helper: Helper, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
|
||||
static HELPER_VAR: &str = "babelHelpers";
|
||||
|
||||
|
|
|
|||
|
|
@ -48,10 +48,11 @@ use es2021::ES2021;
|
|||
use es2022::ES2022;
|
||||
use jsx::Jsx;
|
||||
use regexp::RegExp;
|
||||
use rustc_hash::FxHashMap;
|
||||
use typescript::TypeScript;
|
||||
|
||||
pub use crate::{
|
||||
common::helper_loader::{HelperLoaderMode, HelperLoaderOptions},
|
||||
common::helper_loader::{Helper, HelperLoaderMode, HelperLoaderOptions},
|
||||
compiler_assumptions::CompilerAssumptions,
|
||||
es2015::{ArrowFunctionsOptions, ES2015Options},
|
||||
jsx::{JsxOptions, JsxRuntime, ReactRefreshOptions},
|
||||
|
|
@ -63,10 +64,14 @@ pub use crate::{
|
|||
typescript::{RewriteExtensionsMode, TypeScriptOptions},
|
||||
};
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct TransformerReturn {
|
||||
pub errors: std::vec::Vec<OxcDiagnostic>,
|
||||
pub symbols: SymbolTable,
|
||||
pub scopes: ScopeTree,
|
||||
/// Helpers used by this transform.
|
||||
#[deprecated = "Internal usage only"]
|
||||
pub helpers_used: FxHashMap<Helper, String>,
|
||||
}
|
||||
|
||||
pub struct Transformer<'a> {
|
||||
|
|
@ -128,7 +133,9 @@ impl<'a> Transformer<'a> {
|
|||
};
|
||||
|
||||
let (symbols, scopes) = traverse_mut(&mut transformer, allocator, program, symbols, scopes);
|
||||
TransformerReturn { errors: self.ctx.take_errors(), symbols, scopes }
|
||||
let helpers_used = self.ctx.helper_loader.used_helpers.borrow_mut().drain().collect();
|
||||
#[allow(deprecated)]
|
||||
TransformerReturn { errors: self.ctx.take_errors(), symbols, scopes, helpers_used }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
12
napi/transform/index.d.ts
vendored
12
napi/transform/index.d.ts
vendored
|
|
@ -313,6 +313,18 @@ export interface TransformResult {
|
|||
* {@link TransformOptions#sourcemap sourcemap} are set to `true`.
|
||||
*/
|
||||
declarationMap?: SourceMap
|
||||
/**
|
||||
* Helpers used.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```text
|
||||
* { "_objectSpread": "@babel/runtime/helpers/objectSpread2" }
|
||||
* ```
|
||||
*/
|
||||
helpersUsed: Record<string, string>
|
||||
/**
|
||||
* Parse and transformation errors.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
// NOTE: Types must be aligned with [@types/babel__core](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b5dc32740d9b45d11cff9b025896dd333c795b39/types/babel__core/index.d.ts).
|
||||
#![allow(rustdoc::bare_urls)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
ops::ControlFlow,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use napi::Either;
|
||||
use napi_derive::napi;
|
||||
|
|
@ -50,6 +53,18 @@ pub struct TransformResult {
|
|||
/// {@link TransformOptions#sourcemap sourcemap} are set to `true`.
|
||||
pub declaration_map: Option<SourceMap>,
|
||||
|
||||
/// Helpers used.
|
||||
///
|
||||
/// @internal
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// ```text
|
||||
/// { "_objectSpread": "@babel/runtime/helpers/objectSpread2" }
|
||||
/// ```
|
||||
#[napi(ts_type = "Record<string, string>")]
|
||||
pub helpers_used: FxHashMap<String, String>,
|
||||
|
||||
/// Parse and transformation errors.
|
||||
///
|
||||
/// Oxc's parser recovers from common syntax errors, meaning that
|
||||
|
|
@ -461,6 +476,7 @@ struct Compiler {
|
|||
define: Option<ReplaceGlobalDefinesConfig>,
|
||||
inject: Option<InjectGlobalVariablesConfig>,
|
||||
|
||||
helpers_used: FxHashMap<String, String>,
|
||||
errors: Vec<OxcDiagnostic>,
|
||||
}
|
||||
|
||||
|
|
@ -527,6 +543,7 @@ impl Compiler {
|
|||
declaration_map: None,
|
||||
define,
|
||||
inject,
|
||||
helpers_used: FxHashMap::default(),
|
||||
errors: vec![],
|
||||
})
|
||||
}
|
||||
|
|
@ -568,6 +585,20 @@ impl CompilerInterface for Compiler {
|
|||
self.declaration.replace(ret.code);
|
||||
self.declaration_map = ret.map.map(SourceMap::from);
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn after_transform(
|
||||
&mut self,
|
||||
_program: &mut oxc::ast::ast::Program<'_>,
|
||||
transformer_return: &mut oxc::transformer::TransformerReturn,
|
||||
) -> ControlFlow<()> {
|
||||
self.helpers_used = transformer_return
|
||||
.helpers_used
|
||||
.drain()
|
||||
.map(|(helper, source)| (helper.name().to_string(), source))
|
||||
.collect();
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Transpile a JavaScript or TypeScript into a target ECMAScript version.
|
||||
|
|
@ -629,6 +660,7 @@ pub fn transform(
|
|||
map: compiler.printed_sourcemap,
|
||||
declaration: compiler.declaration,
|
||||
declaration_map: compiler.declaration_map,
|
||||
helpers_used: compiler.helpers_used,
|
||||
errors: compiler.errors.into_iter().map(Error::from).collect(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ describe('simple', () => {
|
|||
expect(ret).toStrictEqual({
|
||||
code: 'export class A {}\n',
|
||||
errors: [],
|
||||
helpersUsed: {},
|
||||
map: {
|
||||
mappings: 'AAAA,OAAO,MAAM,EAAK,CAAE',
|
||||
names: [],
|
||||
|
|
@ -117,6 +118,9 @@ describe('helpers', () => {
|
|||
helpers: { mode },
|
||||
});
|
||||
expect(ret.code).toEqual(expected);
|
||||
expect(ret.helpersUsed).toStrictEqual({
|
||||
objectSpread2: '@babel/runtime/helpers/objectSpread2',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue