refactor(transformer/typescript): move all entry points to implementation of Traverse trait (#5422)

This commit is contained in:
Dunqing 2024-09-03 18:26:20 +00:00
parent 0617249716
commit c984219e06
6 changed files with 436 additions and 373 deletions

View file

@ -120,13 +120,13 @@ impl<'a> Transformer<'a> {
impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_program(program, ctx);
self.x0_typescript.enter_program(program, ctx);
self.x1_react.transform_program(program, ctx);
}
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.x1_react.transform_program_on_exit(program, ctx);
self.x0_typescript.transform_program_on_exit(program, ctx);
self.x0_typescript.exit_program(program, ctx);
self.x3_es2015.exit_program(program, ctx);
}
@ -135,22 +135,22 @@ impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_arrow_function_expression(
&mut self,
expr: &mut ArrowFunctionExpression<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_arrow_expression(expr);
self.x0_typescript.enter_arrow_function_expression(expr, ctx);
}
fn enter_binding_pattern(&mut self, pat: &mut BindingPattern<'a>, _ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_binding_pattern(pat);
fn enter_binding_pattern(&mut self, pat: &mut BindingPattern<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_binding_pattern(pat, ctx);
}
fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_call_expression(expr);
self.x0_typescript.enter_call_expression(expr, ctx);
self.x1_react.transform_call_expression(expr, ctx);
}
fn enter_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_class(class);
self.x0_typescript.enter_class(class, ctx);
self.x3_es2015.enter_class(class, ctx);
}
@ -158,19 +158,19 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x3_es2015.exit_class(class, ctx);
}
fn enter_class_body(&mut self, body: &mut ClassBody<'a>, _ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_class_body(body);
fn enter_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_class_body(body, ctx);
}
fn enter_ts_module_declaration(
&mut self,
decl: &mut TSModuleDeclaration<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_ts_module_declaration(decl);
self.x0_typescript.enter_ts_module_declaration(decl, ctx);
}
fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_expression(expr);
self.x0_typescript.enter_expression(expr, ctx);
self.x1_react.transform_expression(expr, ctx);
self.x2_es2021.enter_expression(expr, ctx);
self.x2_es2020.enter_expression(expr, ctx);
@ -187,44 +187,43 @@ impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_simple_assignment_target(
&mut self,
node: &mut SimpleAssignmentTarget<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_simple_assignment_target(node);
self.x0_typescript.enter_simple_assignment_target(node, ctx);
}
fn enter_assignment_target(
&mut self,
node: &mut AssignmentTarget<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_assignment_target(node);
self.x0_typescript.enter_assignment_target(node, ctx);
}
fn enter_formal_parameter(
&mut self,
param: &mut FormalParameter<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_formal_parameter(param);
self.x0_typescript.enter_formal_parameter(param, ctx);
}
fn enter_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_function(func);
self.x3_es2015.enter_function(func, ctx);
}
fn exit_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_function(func);
self.x0_typescript.exit_function(func, ctx);
self.x1_react.transform_function_on_exit(func, ctx);
self.x3_es2015.exit_function(func, ctx);
}
fn enter_jsx_element(&mut self, node: &mut JSXElement<'a>, _ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_jsx_element(node);
fn enter_jsx_element(&mut self, node: &mut JSXElement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_jsx_element(node, ctx);
}
fn enter_jsx_fragment(&mut self, node: &mut JSXFragment<'a>, _ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_jsx_fragment(node);
fn enter_jsx_fragment(&mut self, node: &mut JSXFragment<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_jsx_fragment(node, ctx);
}
fn enter_jsx_opening_element(
@ -232,7 +231,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
elem: &mut JSXOpeningElement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_jsx_opening_element(elem);
self.x0_typescript.enter_jsx_opening_element(elem, ctx);
self.x1_react.transform_jsx_opening_element(elem, ctx);
}
@ -251,9 +250,9 @@ impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_method_definition(def);
self.x0_typescript.enter_method_definition(def, ctx);
}
fn exit_method_definition(
@ -261,31 +260,31 @@ impl<'a> Traverse<'a> for Transformer<'a> {
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_method_definition_on_exit(def, ctx);
self.x0_typescript.exit_method_definition(def, ctx);
}
fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, _ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_new_expression(expr);
fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.enter_new_expression(expr, ctx);
}
fn enter_property_definition(
&mut self,
def: &mut PropertyDefinition<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_property_definition(def);
self.x0_typescript.enter_property_definition(def, ctx);
}
fn enter_accessor_property(
&mut self,
node: &mut AccessorProperty<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_accessor_property(node);
self.x0_typescript.enter_accessor_property(node, ctx);
}
fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_statements(stmts);
self.x0_typescript.enter_statements(stmts, ctx);
self.x1_react.transform_statements(stmts, ctx);
self.x2_es2021.enter_statements(stmts, ctx);
self.x2_es2020.enter_statements(stmts, ctx);
@ -315,7 +314,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
}
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_statements_on_exit(stmts, ctx);
self.x0_typescript.exit_statements(stmts, ctx);
self.x1_react.transform_statements_on_exit(stmts, ctx);
self.x2_es2021.exit_statements(stmts, ctx);
self.x2_es2020.exit_statements(stmts, ctx);
@ -325,17 +324,17 @@ impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_tagged_template_expression(
&mut self,
expr: &mut TaggedTemplateExpression<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_tagged_template_expression(expr);
self.x0_typescript.enter_tagged_template_expression(expr, ctx);
}
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_statement(stmt, ctx);
self.x0_typescript.enter_statement(stmt, ctx);
}
fn enter_declaration(&mut self, decl: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_declaration(decl, ctx);
self.x0_typescript.enter_declaration(decl, ctx);
self.x3_es2015.enter_declaration(decl, ctx);
}
@ -344,11 +343,11 @@ impl<'a> Traverse<'a> for Transformer<'a> {
}
fn enter_if_statement(&mut self, stmt: &mut IfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_if_statement(stmt, ctx);
self.x0_typescript.enter_if_statement(stmt, ctx);
}
fn enter_while_statement(&mut self, stmt: &mut WhileStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_while_statement(stmt, ctx);
self.x0_typescript.enter_while_statement(stmt, ctx);
}
fn enter_do_while_statement(
@ -356,19 +355,19 @@ impl<'a> Traverse<'a> for Transformer<'a> {
stmt: &mut DoWhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_do_while_statement(stmt, ctx);
self.x0_typescript.enter_do_while_statement(stmt, ctx);
}
fn enter_for_statement(&mut self, stmt: &mut ForStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_for_statement(stmt, ctx);
self.x0_typescript.enter_for_statement(stmt, ctx);
}
fn enter_for_of_statement(&mut self, stmt: &mut ForOfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_for_of_statement(stmt, ctx);
self.x0_typescript.enter_for_of_statement(stmt, ctx);
}
fn enter_for_in_statement(&mut self, stmt: &mut ForInStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.x0_typescript.transform_for_in_statement(stmt, ctx);
self.x0_typescript.enter_for_in_statement(stmt, ctx);
}
fn enter_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
@ -410,8 +409,8 @@ impl<'a> Traverse<'a> for Transformer<'a> {
fn enter_ts_export_assignment(
&mut self,
export_assignment: &mut TSExportAssignment<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.x0_typescript.transform_ts_export_assignment(export_assignment);
self.x0_typescript.enter_ts_export_assignment(export_assignment, ctx);
}
}

View file

@ -13,7 +13,7 @@ use oxc_syntax::{
scope::{ScopeFlags, ScopeId},
symbol::SymbolId,
};
use oxc_traverse::TraverseCtx;
use oxc_traverse::{Traverse, TraverseCtx};
use rustc_hash::FxHashSet;
use crate::{context::Ctx, TypeScriptOptions};
@ -59,20 +59,9 @@ impl<'a> TypeScriptAnnotations<'a> {
type_identifier_names: FxHashSet::default(),
}
}
/// 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 {
self.has_jsx_element && name == self.jsx_element_import_name
|| self.has_jsx_fragment && name == self.jsx_fragment_import_name
}
// Remove type only imports/exports
pub fn transform_program_on_exit(
&mut self,
program: &mut Program<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
impl<'a> Traverse<'a> for TypeScriptAnnotations<'a> {
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;
@ -166,13 +155,16 @@ impl<'a> TypeScriptAnnotations<'a> {
program.body.push(self.ctx.ast.statement_module_declaration(export_decl));
}
}
pub fn transform_arrow_expression(&mut self, expr: &mut ArrowFunctionExpression<'a>) {
fn enter_arrow_function_expression(
&mut self,
expr: &mut ArrowFunctionExpression<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
expr.type_parameters = None;
expr.return_type = None;
}
pub fn transform_binding_pattern(&mut self, pat: &mut BindingPattern<'a>) {
fn enter_binding_pattern(&mut self, pat: &mut BindingPattern<'a>, _ctx: &mut TraverseCtx<'a>) {
pat.type_annotation = None;
if pat.kind.is_binding_identifier() {
@ -180,18 +172,18 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
pub fn transform_call_expression(&mut self, expr: &mut CallExpression<'a>) {
fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, _ctx: &mut TraverseCtx<'a>) {
expr.type_parameters = None;
}
pub fn transform_class(&mut self, class: &mut Class<'a>) {
fn enter_class(&mut self, class: &mut Class<'a>, _ctx: &mut TraverseCtx<'a>) {
class.type_parameters = None;
class.super_type_parameters = None;
class.implements = None;
class.r#abstract = false;
}
pub fn transform_class_body(&mut self, body: &mut ClassBody<'a>) {
fn enter_class_body(&mut self, body: &mut ClassBody<'a>, _ctx: &mut TraverseCtx<'a>) {
// Remove type only members
body.body.retain(|elem| match elem {
ClassElement::MethodDefinition(method) => {
@ -213,14 +205,18 @@ impl<'a> TypeScriptAnnotations<'a> {
});
}
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
fn enter_expression(&mut self, expr: &mut Expression<'a>, _ctx: &mut TraverseCtx<'a>) {
if expr.is_typescript_syntax() {
let inner_expr = expr.get_inner_expression_mut();
*expr = self.ctx.ast.move_expression(inner_expr);
}
}
pub fn transform_simple_assignment_target(&mut self, target: &mut SimpleAssignmentTarget<'a>) {
fn enter_simple_assignment_target(
&mut self,
target: &mut SimpleAssignmentTarget<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
if let Some(expr) = target.get_expression_mut() {
match expr.get_inner_expression_mut() {
// `foo!++` to `foo++`
@ -245,7 +241,11 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
pub fn transform_assignment_target(&mut self, target: &mut AssignmentTarget<'a>) {
fn enter_assignment_target(
&mut self,
target: &mut AssignmentTarget<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
if let Some(expr) = target.get_expression_mut() {
let inner_expr = expr.get_inner_expression_mut();
if inner_expr.is_member_expression() {
@ -256,21 +256,33 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
pub fn transform_formal_parameter(&mut self, param: &mut FormalParameter<'a>) {
fn enter_formal_parameter(
&mut self,
param: &mut FormalParameter<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
param.accessibility = None;
}
pub fn transform_function(&mut self, func: &mut Function<'a>) {
fn exit_function(&mut self, func: &mut Function<'a>, _ctx: &mut TraverseCtx<'a>) {
func.this_param = None;
func.type_parameters = None;
func.return_type = None;
}
pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) {
fn enter_jsx_opening_element(
&mut self,
elem: &mut JSXOpeningElement<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
elem.type_parameters = None;
}
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
fn enter_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
// Collects parameter properties so that we can add an assignment
// for each of them in the constructor body.
if def.kind == MethodDefinitionKind::Constructor {
@ -296,7 +308,7 @@ impl<'a> TypeScriptAnnotations<'a> {
def.r#override = false;
}
pub fn transform_method_definition_on_exit(
fn exit_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
@ -327,11 +339,15 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, _ctx: &mut TraverseCtx<'a>) {
expr.type_parameters = None;
}
pub fn transform_property_definition(&mut self, def: &mut PropertyDefinition<'a>) {
fn enter_property_definition(
&mut self,
def: &mut PropertyDefinition<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
assert!(
!(def.declare && def.value.is_some()),
"Fields with the 'declare' modifier cannot be initialized here, but only in the constructor"
@ -351,13 +367,21 @@ impl<'a> TypeScriptAnnotations<'a> {
def.type_annotation = None;
}
pub fn transform_accessor_property(&mut self, def: &mut AccessorProperty<'a>) {
fn enter_accessor_property(
&mut self,
def: &mut AccessorProperty<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
def.accessibility = None;
def.definite = false;
def.type_annotation = None;
}
pub fn transform_statements(&mut self, stmts: &mut ArenaVec<'a, Statement<'a>>) {
fn enter_statements(
&mut self,
stmts: &mut ArenaVec<'a, Statement<'a>>,
_ctx: &mut TraverseCtx<'a>,
) {
// Remove declare declaration
stmts.retain(
|stmt| {
@ -370,7 +394,7 @@ impl<'a> TypeScriptAnnotations<'a> {
);
}
pub fn transform_statements_on_exit(
fn exit_statements(
&mut self,
stmts: &mut ArenaVec<'a, Statement<'a>>,
ctx: &mut TraverseCtx<'a>,
@ -415,11 +439,7 @@ impl<'a> TypeScriptAnnotations<'a> {
/// // to
/// if (true) { super() } else { super() }
/// ```
pub fn transform_if_statement(
&mut self,
stmt: &mut IfStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
fn enter_if_statement(&mut self, stmt: &mut IfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
if !self.assignments.is_empty() {
let consequent_span = match &stmt.consequent {
Statement::ExpressionStatement(expr)
@ -455,6 +475,78 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
fn enter_for_statement(&mut self, stmt: &mut ForStatement<'a>, ctx: &mut TraverseCtx<'a>) {
Self::replace_for_statement_body_with_empty_block_if_ts(
&mut stmt.body,
&stmt.scope_id,
ctx,
);
}
fn enter_for_in_statement(&mut self, stmt: &mut ForInStatement<'a>, ctx: &mut TraverseCtx<'a>) {
Self::replace_for_statement_body_with_empty_block_if_ts(
&mut stmt.body,
&stmt.scope_id,
ctx,
);
}
fn enter_for_of_statement(&mut self, stmt: &mut ForOfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
Self::replace_for_statement_body_with_empty_block_if_ts(
&mut stmt.body,
&stmt.scope_id,
ctx,
);
}
fn enter_while_statement(&mut self, stmt: &mut WhileStatement<'a>, ctx: &mut TraverseCtx<'a>) {
Self::replace_with_empty_block_if_ts(&mut stmt.body, ctx.current_scope_id(), ctx);
}
fn enter_do_while_statement(
&mut self,
stmt: &mut DoWhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
Self::replace_with_empty_block_if_ts(&mut stmt.body, ctx.current_scope_id(), ctx);
}
fn enter_tagged_template_expression(
&mut self,
expr: &mut TaggedTemplateExpression<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
expr.type_parameters = None;
}
fn enter_jsx_element(&mut self, _elem: &mut JSXElement<'a>, _ctx: &mut TraverseCtx<'a>) {
self.has_jsx_element = true;
}
fn enter_jsx_fragment(&mut self, _elem: &mut JSXFragment<'a>, _ctx: &mut TraverseCtx<'a>) {
self.has_jsx_fragment = true;
}
fn enter_ts_module_declaration(
&mut self,
decl: &mut TSModuleDeclaration<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
// NB: Namespace transform happens in `enter_program` visitor, and replaces retained
// namespaces with functions. This visitor is called after, by which time any remaining
// namespaces need to be deleted.
self.type_identifier_names.insert(decl.id.name().clone());
}
}
impl<'a> TypeScriptAnnotations<'a> {
/// 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 {
self.has_jsx_element && name == self.jsx_element_import_name
|| self.has_jsx_fragment && name == self.jsx_fragment_import_name
}
fn create_block_with_statement(
stmt: Statement<'a>,
span: Span,
@ -466,58 +558,6 @@ impl<'a> TypeScriptAnnotations<'a> {
Statement::BlockStatement(ctx.ast.alloc(block))
}
pub fn transform_for_statement(
&mut self,
stmt: &mut ForStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
Self::replace_for_statement_body_with_empty_block_if_ts(
&mut stmt.body,
&stmt.scope_id,
ctx,
);
}
pub fn transform_for_in_statement(
&mut self,
stmt: &mut ForInStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
Self::replace_for_statement_body_with_empty_block_if_ts(
&mut stmt.body,
&stmt.scope_id,
ctx,
);
}
pub fn transform_for_of_statement(
&mut self,
stmt: &mut ForOfStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
Self::replace_for_statement_body_with_empty_block_if_ts(
&mut stmt.body,
&stmt.scope_id,
ctx,
);
}
pub fn transform_while_statement(
&mut self,
stmt: &mut WhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
Self::replace_with_empty_block_if_ts(&mut stmt.body, ctx.current_scope_id(), ctx);
}
pub fn transform_do_while_statement(
&mut self,
stmt: &mut DoWhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
Self::replace_with_empty_block_if_ts(&mut stmt.body, ctx.current_scope_id(), ctx);
}
fn replace_for_statement_body_with_empty_block_if_ts(
body: &mut Statement<'a>,
scope_id: &Cell<Option<ScopeId>>,
@ -543,28 +583,6 @@ impl<'a> TypeScriptAnnotations<'a> {
}
}
pub fn transform_tagged_template_expression(
&mut self,
expr: &mut TaggedTemplateExpression<'a>,
) {
expr.type_parameters = None;
}
pub fn transform_jsx_element(&mut self, _elem: &mut JSXElement<'a>) {
self.has_jsx_element = true;
}
pub fn transform_jsx_fragment(&mut self, _elem: &mut JSXFragment<'a>) {
self.has_jsx_fragment = true;
}
pub fn transform_ts_module_declaration(&mut self, decl: &mut TSModuleDeclaration<'a>) {
// NB: Namespace transform happens in `enter_program` visitor, and replaces retained
// namespaces with functions. This visitor is called after, by which time any remaining
// namespaces need to be deleted.
self.type_identifier_names.insert(decl.id.name().clone());
}
pub fn has_value_reference(&self, name: &str, ctx: &TraverseCtx<'a>) -> bool {
if let Some(symbol_id) = ctx.scopes().get_root_binding(name) {
// `import T from 'mod'; const T = 1;` The T has a value redeclaration

View file

@ -10,7 +10,7 @@ use oxc_syntax::{
reference::ReferenceFlags,
symbol::SymbolFlags,
};
use oxc_traverse::TraverseCtx;
use oxc_traverse::{Traverse, TraverseCtx};
use rustc_hash::FxHashMap;
use crate::context::Ctx;
@ -24,8 +24,10 @@ impl<'a> TypeScriptEnum<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
Self { ctx, enums: FxHashMap::default() }
}
}
pub fn transform_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
impl<'a> Traverse<'a> for TypeScriptEnum<'a> {
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
let new_stmt = match stmt {
Statement::TSEnumDeclaration(ts_enum_decl) => {
self.transform_ts_enum(ts_enum_decl, None, ctx)
@ -45,7 +47,9 @@ impl<'a> TypeScriptEnum<'a> {
*stmt = new_stmt;
}
}
}
impl<'a> TypeScriptEnum<'a> {
/// ```TypeScript
/// enum Foo {
/// X = 1,

View file

@ -8,6 +8,8 @@ mod rewrite_extensions;
use std::rc::Rc;
use module::TypeScriptModule;
use namespace::TypeScriptNamespace;
use oxc_allocator::Vec;
use oxc_ast::ast::*;
use oxc_traverse::{Traverse, TraverseCtx};
@ -45,6 +47,8 @@ pub struct TypeScript<'a> {
annotations: TypeScriptAnnotations<'a>,
r#enum: TypeScriptEnum<'a>,
namespace: TypeScriptNamespace<'a>,
module: TypeScriptModule<'a>,
rewrite_extensions: TypeScriptRewriteExtensions,
}
@ -58,6 +62,8 @@ impl<'a> TypeScript<'a> {
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)),
options,
ctx,
}
@ -65,6 +71,189 @@ impl<'a> TypeScript<'a> {
}
impl<'a> Traverse<'a> for TypeScript<'a> {
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
program.directives.clear();
program.hashbang = None;
program.body.clear();
} else {
self.namespace.enter_program(program, ctx);
}
}
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.exit_program(program, ctx);
}
fn enter_arrow_function_expression(
&mut self,
expr: &mut ArrowFunctionExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_arrow_function_expression(expr, ctx);
}
fn enter_binding_pattern(&mut self, pat: &mut BindingPattern<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_binding_pattern(pat, ctx);
}
fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_call_expression(expr, ctx);
}
fn enter_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_class(class, ctx);
}
fn enter_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_class_body(body, ctx);
}
fn enter_ts_module_declaration(
&mut self,
decl: &mut TSModuleDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_ts_module_declaration(decl, ctx);
}
fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_expression(expr, ctx);
}
fn enter_simple_assignment_target(
&mut self,
target: &mut SimpleAssignmentTarget<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_simple_assignment_target(target, ctx);
}
fn enter_assignment_target(
&mut self,
target: &mut AssignmentTarget<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_assignment_target(target, ctx);
}
fn enter_formal_parameter(
&mut self,
param: &mut FormalParameter<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_formal_parameter(param, ctx);
}
fn exit_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.exit_function(func, ctx);
}
fn enter_jsx_opening_element(
&mut self,
elem: &mut JSXOpeningElement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_jsx_opening_element(elem, ctx);
}
fn enter_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_method_definition(def, ctx);
}
fn exit_method_definition(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.exit_method_definition(def, ctx);
}
fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_new_expression(expr, ctx);
}
fn enter_property_definition(
&mut self,
def: &mut PropertyDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_property_definition(def, ctx);
}
fn enter_accessor_property(
&mut self,
def: &mut AccessorProperty<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_accessor_property(def, ctx);
}
fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_statements(stmts, ctx);
}
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
self.annotations.exit_statements(stmts, ctx);
}
fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.r#enum.enter_statement(stmt, ctx);
}
fn enter_if_statement(&mut self, stmt: &mut IfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_if_statement(stmt, ctx);
}
fn enter_while_statement(&mut self, stmt: &mut WhileStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_while_statement(stmt, ctx);
}
fn enter_do_while_statement(
&mut self,
stmt: &mut DoWhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_do_while_statement(stmt, ctx);
}
fn enter_for_statement(&mut self, stmt: &mut ForStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_for_statement(stmt, ctx);
}
fn enter_for_in_statement(&mut self, stmt: &mut ForInStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_for_in_statement(stmt, ctx);
}
fn enter_for_of_statement(&mut self, stmt: &mut ForOfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_for_of_statement(stmt, ctx);
}
fn enter_tagged_template_expression(
&mut self,
expr: &mut TaggedTemplateExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.enter_tagged_template_expression(expr, ctx);
}
fn enter_jsx_element(&mut self, elem: &mut JSXElement<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_jsx_element(elem, ctx);
}
fn enter_jsx_fragment(&mut self, elem: &mut JSXFragment<'a>, ctx: &mut TraverseCtx<'a>) {
self.annotations.enter_jsx_fragment(elem, ctx);
}
fn enter_declaration(&mut self, node: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) {
self.module.enter_declaration(node, ctx);
}
fn enter_import_declaration(
&mut self,
node: &mut ImportDeclaration<'a>,
@ -94,177 +283,12 @@ impl<'a> Traverse<'a> for TypeScript<'a> {
self.rewrite_extensions.enter_export_named_declaration(node, ctx);
}
}
}
// Transforms
impl<'a> TypeScript<'a> {
pub fn transform_program(&self, program: &mut Program<'a>, ctx: &mut TraverseCtx) {
if self.ctx.source_type.is_typescript_definition() {
// Output empty file for TS definitions
program.directives.clear();
program.hashbang = None;
program.body.clear();
} else {
self.transform_program_for_namespace(program, ctx);
}
}
pub fn transform_program_on_exit(
fn enter_ts_export_assignment(
&mut self,
program: &mut Program<'a>,
node: &mut TSExportAssignment<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_program_on_exit(program, ctx);
}
pub fn transform_arrow_expression(&mut self, expr: &mut ArrowFunctionExpression<'a>) {
self.annotations.transform_arrow_expression(expr);
}
pub fn transform_binding_pattern(&mut self, pat: &mut BindingPattern<'a>) {
self.annotations.transform_binding_pattern(pat);
}
pub fn transform_call_expression(&mut self, expr: &mut CallExpression<'a>) {
self.annotations.transform_call_expression(expr);
}
pub fn transform_class(&mut self, class: &mut Class<'a>) {
self.annotations.transform_class(class);
}
pub fn transform_class_body(&mut self, body: &mut ClassBody<'a>) {
self.annotations.transform_class_body(body);
}
pub fn transform_ts_module_declaration(&mut self, decl: &mut TSModuleDeclaration<'a>) {
self.annotations.transform_ts_module_declaration(decl);
}
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
self.annotations.transform_expression(expr);
}
pub fn transform_simple_assignment_target(&mut self, target: &mut SimpleAssignmentTarget<'a>) {
self.annotations.transform_simple_assignment_target(target);
}
pub fn transform_assignment_target(&mut self, target: &mut AssignmentTarget<'a>) {
self.annotations.transform_assignment_target(target);
}
pub fn transform_formal_parameter(&mut self, param: &mut FormalParameter<'a>) {
self.annotations.transform_formal_parameter(param);
}
pub fn transform_function(&mut self, func: &mut Function<'a>) {
self.annotations.transform_function(func);
}
pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) {
self.annotations.transform_jsx_opening_element(elem);
}
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
self.annotations.transform_method_definition(def);
}
pub fn transform_method_definition_on_exit(
&mut self,
def: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_method_definition_on_exit(def, ctx);
}
pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
self.annotations.transform_new_expression(expr);
}
pub fn transform_property_definition(&mut self, def: &mut PropertyDefinition<'a>) {
self.annotations.transform_property_definition(def);
}
pub fn transform_accessor_property(&mut self, def: &mut AccessorProperty<'a>) {
self.annotations.transform_accessor_property(def);
}
pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
self.annotations.transform_statements(stmts);
}
pub fn transform_statements_on_exit(
&mut self,
stmts: &mut Vec<'a, Statement<'a>>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_statements_on_exit(stmts, ctx);
}
pub fn transform_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
self.r#enum.transform_statement(stmt, ctx);
}
pub fn transform_if_statement(
&mut self,
stmt: &mut IfStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_if_statement(stmt, ctx);
}
pub fn transform_while_statement(
&mut self,
stmt: &mut WhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_while_statement(stmt, ctx);
}
pub fn transform_do_while_statement(
&mut self,
stmt: &mut DoWhileStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_do_while_statement(stmt, ctx);
}
pub fn transform_for_statement(
&mut self,
stmt: &mut ForStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_for_statement(stmt, ctx);
}
pub fn transform_for_in_statement(
&mut self,
stmt: &mut ForInStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_for_in_statement(stmt, ctx);
}
pub fn transform_for_of_statement(
&mut self,
stmt: &mut ForOfStatement<'a>,
ctx: &mut TraverseCtx<'a>,
) {
self.annotations.transform_for_of_statement(stmt, ctx);
}
pub fn transform_tagged_template_expression(
&mut self,
expr: &mut TaggedTemplateExpression<'a>,
) {
self.annotations.transform_tagged_template_expression(expr);
}
pub fn transform_jsx_element(&mut self, elem: &mut JSXElement<'a>) {
self.annotations.transform_jsx_element(elem);
}
pub fn transform_jsx_fragment(&mut self, elem: &mut JSXFragment<'a>) {
self.annotations.transform_jsx_fragment(elem);
self.module.enter_ts_export_assignment(node, ctx);
}
}

View file

@ -2,11 +2,21 @@ use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_span::SPAN;
use oxc_syntax::reference::ReferenceFlags;
use oxc_traverse::TraverseCtx;
use oxc_traverse::{Traverse, TraverseCtx};
use super::TypeScript;
use crate::context::Ctx;
impl<'a> TypeScript<'a> {
pub struct TypeScriptModule<'a> {
ctx: Ctx<'a>,
}
impl<'a> TypeScriptModule<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
Self { ctx }
}
}
impl<'a> Traverse<'a> for TypeScriptModule<'a> {
/// ```TypeScript
/// import b = babel;
/// import AliasModule = LongNameModule;
@ -15,7 +25,7 @@ impl<'a> TypeScript<'a> {
/// var b = babel;
/// var AliasModule = LongNameModule;
/// ```
pub fn transform_declaration(&mut self, decl: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) {
fn enter_declaration(&mut self, decl: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) {
match decl {
Declaration::TSImportEqualsDeclaration(ts_import_equals)
if ts_import_equals.import_kind.is_value() =>
@ -26,6 +36,19 @@ impl<'a> TypeScript<'a> {
}
}
fn enter_ts_export_assignment(
&mut self,
export_assignment: &mut TSExportAssignment<'a>,
_ctx: &mut TraverseCtx<'a>,
) {
if self.ctx.source_type.is_module() {
self.ctx
.error(super::diagnostics::export_assignment_unsupported(export_assignment.span));
}
}
}
impl<'a> TypeScriptModule<'a> {
fn transform_ts_import_equals(
&self,
decl: &mut Box<'a, TSImportEqualsDeclaration<'a>>,
@ -34,8 +57,8 @@ impl<'a> TypeScript<'a> {
let kind = VariableDeclarationKind::Var;
let decls = {
let binding_pattern_kind =
self.ctx.ast.binding_pattern_kind_binding_identifier(SPAN, &decl.id.name);
let binding = self.ctx.ast.binding_pattern(
ctx.ast.binding_pattern_kind_binding_identifier(SPAN, &decl.id.name);
let binding = ctx.ast.binding_pattern(
binding_pattern_kind,
Option::<TSTypeAnnotation>::None,
false,
@ -53,11 +76,11 @@ impl<'a> TypeScript<'a> {
));
}
let callee = self.ctx.ast.expression_identifier_reference(SPAN, "require");
let arguments = self.ctx.ast.vec1(Argument::from(
self.ctx.ast.expression_from_string_literal(reference.expression.clone()),
let callee = ctx.ast.expression_identifier_reference(SPAN, "require");
let arguments = ctx.ast.vec1(Argument::from(
ctx.ast.expression_from_string_literal(reference.expression.clone()),
));
self.ctx.ast.expression_call(
ctx.ast.expression_call(
SPAN,
callee,
Option::<TSTypeParameterInstantiation>::None,
@ -66,18 +89,13 @@ impl<'a> TypeScript<'a> {
)
}
};
self.ctx.ast.vec1(self.ctx.ast.variable_declarator(
SPAN,
kind,
binding,
Some(init),
false,
))
ctx.ast.vec1(ctx.ast.variable_declarator(SPAN, kind, binding, Some(init), false))
};
self.ctx.ast.declaration_variable(SPAN, kind, decls, false)
ctx.ast.declaration_variable(SPAN, kind, decls, false)
}
#[allow(clippy::only_used_in_recursion)]
fn transform_ts_type_name(
&self,
type_name: &mut TSTypeName<'a>,
@ -89,10 +107,9 @@ impl<'a> TypeScript<'a> {
let reference_id = ident.reference_id.get().unwrap();
let reference = ctx.symbols_mut().get_reference_mut(reference_id);
*reference.flags_mut() = ReferenceFlags::Read;
self.ctx.ast.expression_from_identifier_reference(ident)
ctx.ast.expression_from_identifier_reference(ident)
}
TSTypeName::QualifiedName(qualified_name) => self
.ctx
TSTypeName::QualifiedName(qualified_name) => ctx
.ast
.member_expression_static(
SPAN,
@ -103,14 +120,4 @@ impl<'a> TypeScript<'a> {
.into(),
}
}
pub fn transform_ts_export_assignment(
&mut self,
export_assignment: &mut TSExportAssignment<'a>,
) {
if self.ctx.source_type.is_module() {
self.ctx
.error(super::diagnostics::export_assignment_unsupported(export_assignment.span));
}
}
}

View file

@ -1,3 +1,5 @@
use std::rc::Rc;
use oxc_allocator::{Box, Vec};
use oxc_ast::{ast::*, syntax_directed_operations::BoundNames};
use oxc_span::{Atom, CompactStr, SPAN};
@ -6,23 +8,30 @@ use oxc_syntax::{
scope::{ScopeFlags, ScopeId},
symbol::SymbolFlags,
};
use oxc_traverse::TraverseCtx;
use oxc_traverse::{Traverse, TraverseCtx};
use rustc_hash::FxHashSet;
use crate::context::Ctx;
use super::{
diagnostics::{ambient_module_nested, namespace_exporting_non_const, namespace_not_supported},
TypeScript,
TypeScriptOptions,
};
// TODO:
// 1. register scope for the newly created function: <https://github.com/babel/babel/blob/08b0472069cd207f043dd40a4d157addfdd36011/packages/babel-plugin-transform-typescript/src/namespace.ts#L38>
impl<'a> TypeScript<'a> {
pub struct TypeScriptNamespace<'a> {
ctx: Ctx<'a>,
options: Rc<TypeScriptOptions>,
}
impl<'a> TypeScriptNamespace<'a> {
pub fn new(options: Rc<TypeScriptOptions>, ctx: Ctx<'a>) -> Self {
Self { ctx, options }
}
}
impl<'a> Traverse<'a> for TypeScriptNamespace<'a> {
// `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
pub(super) fn transform_program_for_namespace(
&self,
program: &mut Program<'a>,
ctx: &mut TraverseCtx,
) {
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
// namespace declaration is only allowed at the top level
if !has_namespace(program.body.as_slice()) {
@ -129,7 +138,9 @@ impl<'a> TypeScript<'a> {
program.body = new_stmts;
}
}
impl<'a> TypeScriptNamespace<'a> {
fn handle_nested(
&self,
decl: TSModuleDeclaration<'a>,