refactor(transformer): share TransformCtx with ref not Rc (#6118)

Many transforms share `TransformCtx`. Currently it's shared with `Rc`, which has a cost as the `Rc` has to be cloned many times, and it also makes dropping `Transformer` more expensive.

The PR changes that to share it as a normal reference `&TransformCtx` instead.

This requires adding an inner `TransformerImpl`. `Transformer` is now just a facade which creates the `TransformCtx` and stores options. `Transformer::build_with_symbols_and_scopes` constructs `TransformerImpl` and runs the visitor on it.

Unlikely to have any perf impact on larger files, but for small files where setup/teardown is a larger % of the overall workload, it may help a little.
This commit is contained in:
overlookmotel 2024-09-27 18:07:54 +00:00
parent 58fd6eb905
commit 09e41c2c26
14 changed files with 156 additions and 166 deletions

View file

@ -2,7 +2,6 @@ use std::{
cell::RefCell,
mem,
path::{Path, PathBuf},
rc::Rc,
};
use oxc_allocator::Allocator;
@ -12,8 +11,6 @@ use oxc_span::SourceType;
use crate::{helpers::module_imports::ModuleImports, TransformOptions};
pub type Ctx<'a> = Rc<TransformCtx<'a>>;
pub struct TransformCtx<'a> {
errors: RefCell<Vec<OxcDiagnostic>>,

View file

@ -30,7 +30,7 @@ mod helpers {
pub mod stack;
}
use std::{path::Path, rc::Rc};
use std::path::Path;
use es2016::ES2016;
use es2018::ES2018;
@ -53,12 +53,7 @@ pub use crate::{
react::{ReactJsxRuntime, ReactOptions, ReactRefreshOptions},
typescript::{RewriteExtensionsMode, TypeScriptOptions},
};
use crate::{
context::{Ctx, TransformCtx},
es2015::ES2015,
react::React,
typescript::TypeScript,
};
use crate::{context::TransformCtx, es2015::ES2015, react::React, typescript::TypeScript};
pub struct TransformerReturn {
pub errors: std::vec::Vec<OxcDiagnostic>,
@ -67,17 +62,8 @@ pub struct TransformerReturn {
}
pub struct Transformer<'a> {
ctx: Ctx<'a>,
// NOTE: all callbacks must run in order.
x0_typescript: TypeScript<'a>,
x1_react: React<'a>,
x2_es2021: ES2021<'a>,
x2_es2020: ES2020<'a>,
x2_es2019: ES2019,
x2_es2018: ES2018,
x2_es2016: ES2016<'a>,
x3_es2015: ES2015<'a>,
x4_regexp: RegExp<'a>,
ctx: TransformCtx<'a>,
options: TransformOptions,
}
impl<'a> Transformer<'a> {
@ -89,41 +75,50 @@ impl<'a> Transformer<'a> {
trivias: Trivias,
options: TransformOptions,
) -> Self {
let ctx = Rc::new(TransformCtx::new(
allocator,
source_path,
source_type,
source_text,
trivias,
&options,
));
Self {
ctx: Rc::clone(&ctx),
x0_typescript: TypeScript::new(options.typescript, Rc::clone(&ctx)),
x1_react: React::new(options.react, Rc::clone(&ctx)),
x2_es2021: ES2021::new(options.es2021),
x2_es2020: ES2020::new(options.es2020),
x2_es2019: ES2019::new(options.es2019),
x2_es2018: ES2018::new(options.es2018),
x2_es2016: ES2016::new(options.es2016),
x3_es2015: ES2015::new(options.es2015),
x4_regexp: RegExp::new(options.regexp, ctx),
}
let ctx =
TransformCtx::new(allocator, source_path, source_type, source_text, trivias, &options);
Self { ctx, options }
}
pub fn build_with_symbols_and_scopes(
mut self,
self,
symbols: SymbolTable,
scopes: ScopeTree,
program: &mut Program<'a>,
) -> TransformerReturn {
let allocator = self.ctx.ast.allocator;
let (symbols, scopes) = traverse_mut(&mut self, allocator, program, symbols, scopes);
let mut transformer = TransformerImpl {
x0_typescript: TypeScript::new(self.options.typescript, &self.ctx),
x1_react: React::new(self.options.react, &self.ctx),
x2_es2021: ES2021::new(self.options.es2021),
x2_es2020: ES2020::new(self.options.es2020),
x2_es2019: ES2019::new(self.options.es2019),
x2_es2018: ES2018::new(self.options.es2018),
x2_es2016: ES2016::new(self.options.es2016),
x3_es2015: ES2015::new(self.options.es2015),
x4_regexp: RegExp::new(self.options.regexp, &self.ctx),
};
let (symbols, scopes) = traverse_mut(&mut transformer, allocator, program, symbols, scopes);
TransformerReturn { errors: self.ctx.take_errors(), symbols, scopes }
}
}
impl<'a> Traverse<'a> for Transformer<'a> {
struct TransformerImpl<'a, 'ctx> {
// NOTE: all callbacks must run in order.
x0_typescript: TypeScript<'a, 'ctx>,
x1_react: React<'a, 'ctx>,
x2_es2021: ES2021<'a>,
x2_es2020: ES2020<'a>,
x2_es2019: ES2019,
x2_es2018: ES2018,
x2_es2016: ES2016<'a>,
x3_es2015: ES2015<'a>,
x4_regexp: RegExp<'a, 'ctx>,
}
impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> {
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_program(program, ctx);
self.x1_react.enter_program(program, ctx);
@ -189,6 +184,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x0_typescript.enter_ts_module_declaration(decl, ctx);
}
#[inline]
fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_expression(expr, ctx);
self.x1_react.enter_expression(expr, ctx);

View file

@ -50,19 +50,19 @@ use oxc_ast::ast::*;
use oxc_span::{Atom, SPAN};
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
use crate::context::Ctx;
use crate::TransformCtx;
pub struct ReactDisplayName<'a> {
ctx: Ctx<'a>,
pub struct ReactDisplayName<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
}
impl<'a> ReactDisplayName<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> ReactDisplayName<'a, 'ctx> {
pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self {
Self { ctx }
}
}
impl<'a> Traverse<'a> for ReactDisplayName<'a> {
impl<'a, 'ctx> Traverse<'a> for ReactDisplayName<'a, 'ctx> {
fn enter_call_expression(
&mut self,
call_expr: &mut CallExpression<'a>,
@ -129,7 +129,7 @@ impl<'a> Traverse<'a> for ReactDisplayName<'a> {
}
}
impl<'a> ReactDisplayName<'a> {
impl<'a, 'ctx> ReactDisplayName<'a, 'ctx> {
/// Get the object from `React.createClass({})` or `createReactClass({})`
fn get_object_from_create_class<'b>(
call_expr: &'b mut CallExpression<'a>,

View file

@ -88,8 +88,6 @@
//!
//! * Babel plugin implementation: <https://github.com/babel/babel/tree/main/packages/babel-helper-builder-react-jsx>
use std::rc::Rc;
use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder, NONE};
use oxc_span::{Atom, GetSpan, Span, SPAN};
@ -108,29 +106,29 @@ pub use super::{
options::{ReactJsxRuntime, ReactOptions},
};
use crate::{
context::{Ctx, TransformCtx},
helpers::{bindings::BoundIdentifier, module_imports::NamedImport},
TransformCtx,
};
pub struct ReactJsx<'a> {
pub struct ReactJsx<'a, 'ctx> {
options: ReactOptions,
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
pub(super) jsx_self: ReactJsxSelf<'a>,
pub(super) jsx_source: ReactJsxSource<'a>,
pub(super) jsx_self: ReactJsxSelf<'a, 'ctx>,
pub(super) jsx_source: ReactJsxSource<'a, 'ctx>,
// States
bindings: Bindings<'a>,
bindings: Bindings<'a, 'ctx>,
}
/// Bindings for different import options
enum Bindings<'a> {
enum Bindings<'a, 'ctx> {
Classic(ClassicBindings<'a>),
AutomaticScript(AutomaticScriptBindings<'a>),
AutomaticModule(AutomaticModuleBindings<'a>),
AutomaticScript(AutomaticScriptBindings<'a, 'ctx>),
AutomaticModule(AutomaticModuleBindings<'a, 'ctx>),
}
impl<'a> Bindings<'a> {
impl<'a, 'ctx> Bindings<'a, 'ctx> {
#[inline]
fn is_classic(&self) -> bool {
matches!(self, Self::Classic(_))
@ -142,8 +140,8 @@ struct ClassicBindings<'a> {
pragma_frag: Pragma<'a>,
}
struct AutomaticScriptBindings<'a> {
ctx: Ctx<'a>,
struct AutomaticScriptBindings<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
jsx_runtime_importer: Atom<'a>,
react_importer_len: u32,
require_create_element: Option<BoundIdentifier<'a>>,
@ -151,9 +149,9 @@ struct AutomaticScriptBindings<'a> {
is_development: bool,
}
impl<'a> AutomaticScriptBindings<'a> {
impl<'a, 'ctx> AutomaticScriptBindings<'a, 'ctx> {
fn new(
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
jsx_runtime_importer: Atom<'a>,
react_importer_len: u32,
is_development: bool,
@ -206,8 +204,8 @@ impl<'a> AutomaticScriptBindings<'a> {
}
}
struct AutomaticModuleBindings<'a> {
ctx: Ctx<'a>,
struct AutomaticModuleBindings<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
jsx_runtime_importer: Atom<'a>,
react_importer_len: u32,
import_create_element: Option<BoundIdentifier<'a>>,
@ -217,9 +215,9 @@ struct AutomaticModuleBindings<'a> {
is_development: bool,
}
impl<'a> AutomaticModuleBindings<'a> {
impl<'a, 'ctx> AutomaticModuleBindings<'a, 'ctx> {
fn new(
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
jsx_runtime_importer: Atom<'a>,
react_importer_len: u32,
is_development: bool,
@ -371,15 +369,15 @@ impl<'a> Pragma<'a> {
}
}
impl<'a> ReactJsx<'a> {
pub fn new(options: ReactOptions, ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> ReactJsx<'a, 'ctx> {
pub fn new(options: ReactOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
let bindings = match options.runtime {
ReactJsxRuntime::Classic => {
if options.import_source.is_some() {
ctx.error(diagnostics::import_source_cannot_be_set());
}
let pragma = Pragma::parse(options.pragma.as_ref(), "createElement", &ctx);
let pragma_frag = Pragma::parse(options.pragma_frag.as_ref(), "Fragment", &ctx);
let pragma = Pragma::parse(options.pragma.as_ref(), "createElement", ctx);
let pragma_frag = Pragma::parse(options.pragma_frag.as_ref(), "Fragment", ctx);
Bindings::Classic(ClassicBindings { pragma, pragma_frag })
}
ReactJsxRuntime::Automatic => {
@ -419,14 +417,14 @@ impl<'a> ReactJsx<'a> {
if ctx.source_type.is_script() {
Bindings::AutomaticScript(AutomaticScriptBindings::new(
Rc::clone(&ctx),
ctx,
jsx_runtime_importer,
source_len,
is_development,
))
} else {
Bindings::AutomaticModule(AutomaticModuleBindings::new(
Rc::clone(&ctx),
ctx,
jsx_runtime_importer,
source_len,
is_development,
@ -437,15 +435,15 @@ impl<'a> ReactJsx<'a> {
Self {
options,
ctx: Rc::clone(&ctx),
jsx_self: ReactJsxSelf::new(Rc::clone(&ctx)),
ctx,
jsx_self: ReactJsxSelf::new(ctx),
jsx_source: ReactJsxSource::new(ctx),
bindings,
}
}
}
impl<'a> Traverse<'a> for ReactJsx<'a> {
impl<'a, 'ctx> Traverse<'a> for ReactJsx<'a, 'ctx> {
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.add_runtime_imports(program, ctx);
}
@ -461,7 +459,7 @@ impl<'a> Traverse<'a> for ReactJsx<'a> {
}
}
impl<'a> ReactJsx<'a> {
impl<'a, 'ctx> ReactJsx<'a, 'ctx> {
fn is_script(&self) -> bool {
self.ctx.source_type.is_script()
}

View file

@ -33,21 +33,21 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{Span, SPAN};
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
use crate::context::Ctx;
use crate::TransformCtx;
const SELF: &str = "__self";
pub struct ReactJsxSelf<'a> {
ctx: Ctx<'a>,
pub struct ReactJsxSelf<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
}
impl<'a> ReactJsxSelf<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> ReactJsxSelf<'a, 'ctx> {
pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self {
Self { ctx }
}
}
impl<'a> Traverse<'a> for ReactJsxSelf<'a> {
impl<'a, 'ctx> Traverse<'a> for ReactJsxSelf<'a, 'ctx> {
fn enter_jsx_opening_element(
&mut self,
elem: &mut JSXOpeningElement<'a>,
@ -57,7 +57,7 @@ impl<'a> Traverse<'a> for ReactJsxSelf<'a> {
}
}
impl<'a> ReactJsxSelf<'a> {
impl<'a, 'ctx> ReactJsxSelf<'a, 'ctx> {
pub fn report_error(&self, span: Span) {
let error = OxcDiagnostic::warn("Duplicate __self prop found.").with_label(span);
self.ctx.error(error);

View file

@ -41,24 +41,24 @@ use oxc_traverse::{Traverse, TraverseCtx};
use ropey::Rope;
use super::utils::get_line_column;
use crate::{context::Ctx, helpers::bindings::BoundIdentifier};
use crate::{helpers::bindings::BoundIdentifier, TransformCtx};
const SOURCE: &str = "__source";
const FILE_NAME_VAR: &str = "jsxFileName";
pub struct ReactJsxSource<'a> {
pub struct ReactJsxSource<'a, 'ctx> {
filename_var: Option<BoundIdentifier<'a>>,
source_rope: Option<Rope>,
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
}
impl<'a> ReactJsxSource<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> ReactJsxSource<'a, 'ctx> {
pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self {
Self { filename_var: None, source_rope: None, ctx }
}
}
impl<'a> Traverse<'a> for ReactJsxSource<'a> {
impl<'a, 'ctx> Traverse<'a> for ReactJsxSource<'a, 'ctx> {
fn exit_program(&mut self, program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) {
if let Some(stmt) = self.get_var_file_name_statement() {
program.body.insert(0, stmt);
@ -74,7 +74,7 @@ impl<'a> Traverse<'a> for ReactJsxSource<'a> {
}
}
impl<'a> ReactJsxSource<'a> {
impl<'a, 'ctx> ReactJsxSource<'a, 'ctx> {
pub fn get_line_column(&mut self, offset: u32) -> (usize, usize) {
if self.source_rope.is_none() {
self.source_rope = Some(Rope::from_str(self.ctx.source_text));

View file

@ -7,8 +7,6 @@ mod options;
mod refresh;
mod utils;
use std::rc::Rc;
use oxc_allocator::Vec;
use oxc_ast::ast::*;
use oxc_traverse::{Traverse, TraverseCtx};
@ -19,7 +17,7 @@ pub use self::{
jsx::ReactJsx,
options::{ReactJsxRuntime, ReactOptions, ReactRefreshOptions},
};
use crate::context::Ctx;
use crate::TransformCtx;
/// [Preset React](https://babel.dev/docs/babel-preset-react)
///
@ -29,10 +27,10 @@ use crate::context::Ctx;
/// * [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self)
/// * [plugin-transform-react-jsx-source](https://babel.dev/docs/babel-plugin-transform-react-jsx-source)
/// * [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name)
pub struct React<'a> {
jsx: ReactJsx<'a>,
display_name: ReactDisplayName<'a>,
refresh: ReactRefresh<'a>,
pub struct React<'a, 'ctx> {
jsx: ReactJsx<'a, 'ctx>,
display_name: ReactDisplayName<'a, 'ctx>,
refresh: ReactRefresh<'a, 'ctx>,
jsx_plugin: bool,
display_name_plugin: bool,
jsx_self_plugin: bool,
@ -41,10 +39,10 @@ pub struct React<'a> {
}
// Constructors
impl<'a> React<'a> {
pub fn new(mut options: ReactOptions, ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> React<'a, 'ctx> {
pub fn new(mut options: ReactOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
if options.jsx_plugin || options.development {
options.update_with_comments(&ctx);
options.update_with_comments(ctx);
options.conform();
}
let ReactOptions {
@ -56,8 +54,8 @@ impl<'a> React<'a> {
} = options;
let refresh = options.refresh.clone();
Self {
jsx: ReactJsx::new(options, Rc::clone(&ctx)),
display_name: ReactDisplayName::new(Rc::clone(&ctx)),
jsx: ReactJsx::new(options, ctx),
display_name: ReactDisplayName::new(ctx),
jsx_plugin,
display_name_plugin,
jsx_self_plugin,
@ -68,7 +66,7 @@ impl<'a> React<'a> {
}
}
impl<'a> Traverse<'a> for React<'a> {
impl<'a, 'ctx> Traverse<'a> for React<'a, 'ctx> {
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
if self.jsx_plugin {
program.source_type = program.source_type.with_standard(true);

View file

@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
use sha1::{Digest, Sha1};
use super::options::ReactRefreshOptions;
use crate::context::Ctx;
use crate::TransformCtx;
/// Parse a string into a `RefreshIdentifierResolver` and convert it into an `Expression`
#[derive(Debug)]
@ -94,11 +94,11 @@ impl<'a> RefreshIdentifierResolver<'a> {
///
/// * <https://github.com/facebook/react/issues/16604#issuecomment-528663101>
/// * <https://github.com/facebook/react/blob/main/packages/react-refresh/src/ReactFreshBabelPlugin.js>
pub struct ReactRefresh<'a> {
pub struct ReactRefresh<'a, 'ctx> {
refresh_reg: RefreshIdentifierResolver<'a>,
refresh_sig: RefreshIdentifierResolver<'a>,
emit_full_signatures: bool,
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
// States
registrations: Vec<(SymbolId, Atom<'a>)>,
signature_declarator_items: Vec<oxc_allocator::Vec<'a, VariableDeclarator<'a>>>,
@ -111,8 +111,8 @@ pub struct ReactRefresh<'a> {
non_builtin_hooks_callee: FxHashMap<ScopeId, Vec<Option<Expression<'a>>>>,
}
impl<'a> ReactRefresh<'a> {
pub fn new(options: &ReactRefreshOptions, ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> ReactRefresh<'a, 'ctx> {
pub fn new(options: &ReactRefreshOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
Self {
refresh_reg: RefreshIdentifierResolver::parse(&options.refresh_reg, ctx.ast),
refresh_sig: RefreshIdentifierResolver::parse(&options.refresh_sig, ctx.ast),
@ -128,7 +128,7 @@ impl<'a> ReactRefresh<'a> {
}
}
impl<'a> Traverse<'a> for ReactRefresh<'a> {
impl<'a, 'ctx> Traverse<'a> for ReactRefresh<'a, 'ctx> {
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
let mut new_statements = ctx.ast.vec_with_capacity(program.body.len());
for mut statement in program.body.drain(..) {
@ -455,7 +455,7 @@ impl<'a> Traverse<'a> for ReactRefresh<'a> {
}
// Internal Methods
impl<'a> ReactRefresh<'a> {
impl<'a, 'ctx> ReactRefresh<'a, 'ctx> {
fn create_registration(
&mut self,
persistent_id: Atom<'a>,

View file

@ -55,13 +55,13 @@ use oxc_semantic::ReferenceFlags;
use oxc_span::{Atom, SPAN};
use oxc_traverse::{Traverse, TraverseCtx};
use crate::context::Ctx;
use crate::TransformCtx;
mod options;
pub use options::RegExpOptions;
pub struct RegExp<'a> {
ctx: Ctx<'a>,
pub struct RegExp<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
unsupported_flags: RegExpFlags,
some_unsupported_patterns: bool,
look_behind_assertions: bool,
@ -69,8 +69,8 @@ pub struct RegExp<'a> {
unicode_property_escapes: bool,
}
impl<'a> RegExp<'a> {
pub fn new(options: RegExpOptions, ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> RegExp<'a, 'ctx> {
pub fn new(options: RegExpOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
// Get unsupported flags
let mut unsupported_flags = RegExpFlags::empty();
if options.dot_all_flag {
@ -111,7 +111,7 @@ impl<'a> RegExp<'a> {
}
}
impl<'a> Traverse<'a> for RegExp<'a> {
impl<'a, 'ctx> Traverse<'a> for RegExp<'a, 'ctx> {
fn enter_expression(
&mut self,
expr: &mut Expression<'a>,
@ -190,7 +190,7 @@ impl<'a> Traverse<'a> for RegExp<'a> {
}
}
impl<'a> RegExp<'a> {
impl<'a, 'ctx> RegExp<'a, 'ctx> {
/// Check if the regular expression contains any unsupported syntax.
///
/// Based on parsed regular expression pattern.

View file

@ -16,12 +16,12 @@ use oxc_syntax::{
use oxc_traverse::{Traverse, TraverseCtx};
use rustc_hash::FxHashSet;
use crate::{context::Ctx, TypeScriptOptions};
use crate::{TransformCtx, TypeScriptOptions};
pub struct TypeScriptAnnotations<'a> {
pub struct TypeScriptAnnotations<'a, 'ctx> {
#[allow(dead_code)]
options: Rc<TypeScriptOptions>,
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
/// Assignments to be added to the constructor body
assignments: Vec<Assignment<'a>>,
has_super_call: bool,
@ -33,8 +33,8 @@ pub struct TypeScriptAnnotations<'a> {
type_identifier_names: FxHashSet<Atom<'a>>,
}
impl<'a> TypeScriptAnnotations<'a> {
pub fn new(options: Rc<TypeScriptOptions>, ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> TypeScriptAnnotations<'a, 'ctx> {
pub fn new(options: Rc<TypeScriptOptions>, ctx: &'ctx TransformCtx<'a>) -> Self {
let jsx_element_import_name = if options.jsx_pragma.contains('.') {
options.jsx_pragma.split('.').next().map(String::from).unwrap()
} else {
@ -60,7 +60,8 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
}
impl<'a> Traverse<'a> for TypeScriptAnnotations<'a> {
impl<'a, 'ctx> Traverse<'a> for TypeScriptAnnotations<'a, 'ctx> {
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
let mut no_modules_remaining = true;
let mut some_modules_deleted = false;
@ -548,7 +549,7 @@ impl<'a> Traverse<'a> for TypeScriptAnnotations<'a> {
}
}
impl<'a> TypeScriptAnnotations<'a> {
impl<'a, 'ctx> TypeScriptAnnotations<'a, 'ctx> {
/// Check if the given name is a JSX pragma or fragment pragma import
/// and if the file contains JSX elements or fragments
fn is_jsx_imports(&self, name: &str) -> bool {

View file

@ -11,20 +11,20 @@ use oxc_syntax::{
use oxc_traverse::{Traverse, TraverseCtx};
use rustc_hash::FxHashMap;
use crate::context::Ctx;
use crate::TransformCtx;
pub struct TypeScriptEnum<'a> {
ctx: Ctx<'a>,
pub struct TypeScriptEnum<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
enums: FxHashMap<Atom<'a>, FxHashMap<Atom<'a>, ConstantValue>>,
}
impl<'a> TypeScriptEnum<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> TypeScriptEnum<'a, 'ctx> {
pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self {
Self { ctx, enums: FxHashMap::default() }
}
}
impl<'a> Traverse<'a> for TypeScriptEnum<'a> {
impl<'a, 'ctx> Traverse<'a> for TypeScriptEnum<'a, 'ctx> {
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
let new_stmt = match stmt {
Statement::TSEnumDeclaration(ts_enum_decl) => {
@ -47,7 +47,7 @@ impl<'a> Traverse<'a> for TypeScriptEnum<'a> {
}
}
impl<'a> TypeScriptEnum<'a> {
impl<'a, 'ctx> TypeScriptEnum<'a, 'ctx> {
/// ```TypeScript
/// enum Foo {
/// X = 1,
@ -366,7 +366,7 @@ enum ConstantValue {
String(String),
}
impl<'a> TypeScriptEnum<'a> {
impl<'a, 'ctx> TypeScriptEnum<'a, 'ctx> {
/// Evaluate the expression to a constant value.
/// Refer to [babel](https://github.com/babel/babel/blob/610897a9a96c5e344e77ca9665df7613d2f88358/packages/babel-plugin-transform-typescript/src/enum.ts#L241C1-L394C2)
fn computed_constant_value(

View file

@ -17,7 +17,7 @@ use rewrite_extensions::TypeScriptRewriteExtensions;
pub use self::options::{RewriteExtensionsMode, TypeScriptOptions};
use self::{annotations::TypeScriptAnnotations, r#enum::TypeScriptEnum};
use crate::context::Ctx;
use crate::TransformCtx;
/// [Preset TypeScript](https://babeljs.io/docs/babel-preset-typescript)
///
@ -40,36 +40,36 @@ use crate::context::Ctx;
///
/// In: `const x: number = 0;`
/// Out: `const x = 0;`
pub struct TypeScript<'a> {
pub struct TypeScript<'a, 'ctx> {
options: Rc<TypeScriptOptions>,
ctx: Ctx<'a>,
ctx: &'ctx TransformCtx<'a>,
annotations: TypeScriptAnnotations<'a>,
r#enum: TypeScriptEnum<'a>,
namespace: TypeScriptNamespace<'a>,
module: TypeScriptModule<'a>,
annotations: TypeScriptAnnotations<'a, 'ctx>,
r#enum: TypeScriptEnum<'a, 'ctx>,
namespace: TypeScriptNamespace<'a, 'ctx>,
module: TypeScriptModule<'a, 'ctx>,
rewrite_extensions: TypeScriptRewriteExtensions,
}
impl<'a> TypeScript<'a> {
pub fn new(options: TypeScriptOptions, ctx: Ctx<'a>) -> Self {
let options = Rc::new(options.update_with_comments(&ctx));
impl<'a, 'ctx> TypeScript<'a, 'ctx> {
pub fn new(options: TypeScriptOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
let options = Rc::new(options.update_with_comments(ctx));
Self {
annotations: TypeScriptAnnotations::new(Rc::clone(&options), Rc::clone(&ctx)),
r#enum: TypeScriptEnum::new(Rc::clone(&ctx)),
annotations: TypeScriptAnnotations::new(Rc::clone(&options), ctx),
r#enum: TypeScriptEnum::new(ctx),
rewrite_extensions: TypeScriptRewriteExtensions::new(
options.rewrite_import_extensions.clone().unwrap_or_default(),
),
namespace: TypeScriptNamespace::new(Rc::clone(&options), Rc::clone(&ctx)),
module: TypeScriptModule::new(Rc::clone(&ctx)),
namespace: TypeScriptNamespace::new(Rc::clone(&options), ctx),
module: TypeScriptModule::new(ctx),
options,
ctx,
}
}
}
impl<'a> Traverse<'a> for TypeScript<'a> {
impl<'a, 'ctx> Traverse<'a> for TypeScript<'a, 'ctx> {
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
if self.ctx.source_type.is_typescript_definition() {
// Output empty file for TS definitions

View file

@ -4,19 +4,19 @@ use oxc_span::SPAN;
use oxc_syntax::reference::ReferenceFlags;
use oxc_traverse::{Traverse, TraverseCtx};
use crate::context::Ctx;
use crate::TransformCtx;
pub struct TypeScriptModule<'a> {
ctx: Ctx<'a>,
pub struct TypeScriptModule<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
}
impl<'a> TypeScriptModule<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> TypeScriptModule<'a, 'ctx> {
pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self {
Self { ctx }
}
}
impl<'a> Traverse<'a> for TypeScriptModule<'a> {
impl<'a, 'ctx> Traverse<'a> for TypeScriptModule<'a, 'ctx> {
/// ```TypeScript
/// import b = babel;
/// import AliasModule = LongNameModule;
@ -48,7 +48,7 @@ impl<'a> Traverse<'a> for TypeScriptModule<'a> {
}
}
impl<'a> TypeScriptModule<'a> {
impl<'a, 'ctx> TypeScriptModule<'a, 'ctx> {
fn transform_ts_import_equals(
&self,
decl: &mut Box<'a, TSImportEqualsDeclaration<'a>>,

View file

@ -15,20 +15,20 @@ use super::{
diagnostics::{ambient_module_nested, namespace_exporting_non_const, namespace_not_supported},
TypeScriptOptions,
};
use crate::context::Ctx;
use crate::TransformCtx;
pub struct TypeScriptNamespace<'a> {
ctx: Ctx<'a>,
pub struct TypeScriptNamespace<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,
options: Rc<TypeScriptOptions>,
}
impl<'a> TypeScriptNamespace<'a> {
pub fn new(options: Rc<TypeScriptOptions>, ctx: Ctx<'a>) -> Self {
impl<'a, 'ctx> TypeScriptNamespace<'a, 'ctx> {
pub fn new(options: Rc<TypeScriptOptions>, ctx: &'ctx TransformCtx<'a>) -> Self {
Self { ctx, options }
}
}
impl<'a> Traverse<'a> for TypeScriptNamespace<'a> {
impl<'a, 'ctx> Traverse<'a> for TypeScriptNamespace<'a, 'ctx> {
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
// namespace declaration is only allowed at the top level
@ -139,7 +139,7 @@ impl<'a> Traverse<'a> for TypeScriptNamespace<'a> {
}
}
impl<'a> TypeScriptNamespace<'a> {
impl<'a, 'ctx> TypeScriptNamespace<'a, 'ctx> {
fn handle_nested(
&self,
decl: TSModuleDeclaration<'a>,