mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
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:
parent
58fd6eb905
commit
09e41c2c26
14 changed files with 156 additions and 166 deletions
|
|
@ -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>>,
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
Loading…
Reference in a new issue