From c984219e066917db76b05eb21b7164bc84ad591d Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Tue, 3 Sep 2024 18:26:20 +0000 Subject: [PATCH] refactor(transformer/typescript): move all entry points to implementation of Traverse trait (#5422) --- crates/oxc_transformer/src/lib.rs | 97 ++++--- .../src/typescript/annotations.rs | 204 +++++++------- crates/oxc_transformer/src/typescript/enum.rs | 8 +- crates/oxc_transformer/src/typescript/mod.rs | 254 ++++++++++-------- .../oxc_transformer/src/typescript/module.rs | 69 ++--- .../src/typescript/namespace.rs | 31 ++- 6 files changed, 363 insertions(+), 300 deletions(-) diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 749ca37b8222f..2e2a540d7d094 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -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); } } diff --git a/crates/oxc_transformer/src/typescript/annotations.rs b/crates/oxc_transformer/src/typescript/annotations.rs index d2b61d03af1b9..7aaf1f09e2216 100644 --- a/crates/oxc_transformer/src/typescript/annotations.rs +++ b/crates/oxc_transformer/src/typescript/annotations.rs @@ -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,22 +475,7 @@ impl<'a> TypeScriptAnnotations<'a> { } } - fn create_block_with_statement( - stmt: Statement<'a>, - span: Span, - ctx: &mut TraverseCtx<'a>, - ) -> Statement<'a> { - let scope_id = ctx.insert_scope_below_statement(&stmt, ScopeFlags::empty()); - let block = - BlockStatement { span, body: ctx.ast.vec1(stmt), scope_id: Cell::new(Some(scope_id)) }; - Statement::BlockStatement(ctx.ast.alloc(block)) - } - - pub fn transform_for_statement( - &mut self, - stmt: &mut ForStatement<'a>, - ctx: &mut TraverseCtx<'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, @@ -478,11 +483,7 @@ impl<'a> TypeScriptAnnotations<'a> { ); } - pub fn transform_for_in_statement( - &mut self, - stmt: &mut ForInStatement<'a>, - ctx: &mut TraverseCtx<'a>, - ) { + 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, @@ -490,11 +491,7 @@ impl<'a> TypeScriptAnnotations<'a> { ); } - pub fn transform_for_of_statement( - &mut self, - stmt: &mut ForOfStatement<'a>, - ctx: &mut TraverseCtx<'a>, - ) { + 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, @@ -502,15 +499,11 @@ impl<'a> TypeScriptAnnotations<'a> { ); } - pub fn transform_while_statement( - &mut self, - stmt: &mut WhileStatement<'a>, - ctx: &mut TraverseCtx<'a>, - ) { + 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); } - pub fn transform_do_while_statement( + fn enter_do_while_statement( &mut self, stmt: &mut DoWhileStatement<'a>, ctx: &mut TraverseCtx<'a>, @@ -518,6 +511,53 @@ impl<'a> TypeScriptAnnotations<'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, + ctx: &mut TraverseCtx<'a>, + ) -> Statement<'a> { + let scope_id = ctx.insert_scope_below_statement(&stmt, ScopeFlags::empty()); + let block = + BlockStatement { span, body: ctx.ast.vec1(stmt), scope_id: Cell::new(Some(scope_id)) }; + Statement::BlockStatement(ctx.ast.alloc(block)) + } + fn replace_for_statement_body_with_empty_block_if_ts( body: &mut Statement<'a>, scope_id: &Cell>, @@ -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 diff --git a/crates/oxc_transformer/src/typescript/enum.rs b/crates/oxc_transformer/src/typescript/enum.rs index 1799ccf7127fd..a8a2d93a8160f 100644 --- a/crates/oxc_transformer/src/typescript/enum.rs +++ b/crates/oxc_transformer/src/typescript/enum.rs @@ -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, diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index b66e04b0f1a64..dab29e7e619a0 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -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,206 +71,224 @@ impl<'a> TypeScript<'a> { } impl<'a> Traverse<'a> for TypeScript<'a> { - fn enter_import_declaration( - &mut self, - node: &mut ImportDeclaration<'a>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.rewrite_import_extensions.is_some() { - self.rewrite_extensions.enter_import_declaration(node, ctx); - } - } - - fn enter_export_all_declaration( - &mut self, - node: &mut ExportAllDeclaration<'a>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.rewrite_import_extensions.is_some() { - self.rewrite_extensions.enter_export_all_declaration(node, ctx); - } - } - - fn enter_export_named_declaration( - &mut self, - node: &mut ExportNamedDeclaration<'a>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.rewrite_import_extensions.is_some() { - 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) { + 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.transform_program_for_namespace(program, ctx); + self.namespace.enter_program(program, ctx); } } - pub fn transform_program_on_exit( + 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, - program: &mut Program<'a>, + expr: &mut ArrowFunctionExpression<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_program_on_exit(program, ctx); + self.annotations.enter_arrow_function_expression(expr, ctx); } - pub fn transform_arrow_expression(&mut self, expr: &mut ArrowFunctionExpression<'a>) { - self.annotations.transform_arrow_expression(expr); + fn enter_binding_pattern(&mut self, pat: &mut BindingPattern<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_binding_pattern(pat, ctx); } - pub fn transform_binding_pattern(&mut self, pat: &mut BindingPattern<'a>) { - self.annotations.transform_binding_pattern(pat); + fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_call_expression(expr, ctx); } - pub fn transform_call_expression(&mut self, expr: &mut CallExpression<'a>) { - self.annotations.transform_call_expression(expr); + fn enter_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_class(class, ctx); } - pub fn transform_class(&mut self, class: &mut Class<'a>) { - self.annotations.transform_class(class); + fn enter_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_class_body(body, ctx); } - pub fn transform_class_body(&mut self, body: &mut ClassBody<'a>) { - self.annotations.transform_class_body(body); + fn enter_ts_module_declaration( + &mut self, + decl: &mut TSModuleDeclaration<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.annotations.enter_ts_module_declaration(decl, ctx); } - pub fn transform_ts_module_declaration(&mut self, decl: &mut TSModuleDeclaration<'a>) { - self.annotations.transform_ts_module_declaration(decl); + fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_expression(expr, ctx); } - pub fn transform_expression(&mut self, expr: &mut Expression<'a>) { - self.annotations.transform_expression(expr); + fn enter_simple_assignment_target( + &mut self, + target: &mut SimpleAssignmentTarget<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.annotations.enter_simple_assignment_target(target, ctx); } - pub fn transform_simple_assignment_target(&mut self, target: &mut SimpleAssignmentTarget<'a>) { - self.annotations.transform_simple_assignment_target(target); + fn enter_assignment_target( + &mut self, + target: &mut AssignmentTarget<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.annotations.enter_assignment_target(target, ctx); } - pub fn transform_assignment_target(&mut self, target: &mut AssignmentTarget<'a>) { - self.annotations.transform_assignment_target(target); + fn enter_formal_parameter( + &mut self, + param: &mut FormalParameter<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.annotations.enter_formal_parameter(param, ctx); } - pub fn transform_formal_parameter(&mut self, param: &mut FormalParameter<'a>) { - self.annotations.transform_formal_parameter(param); + fn exit_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.exit_function(func, ctx); } - pub fn transform_function(&mut self, func: &mut Function<'a>) { - self.annotations.transform_function(func); + fn enter_jsx_opening_element( + &mut self, + elem: &mut JSXOpeningElement<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.annotations.enter_jsx_opening_element(elem, ctx); } - pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) { - self.annotations.transform_jsx_opening_element(elem); + 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); } - pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) { - self.annotations.transform_method_definition(def); + fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_new_expression(expr, ctx); } - pub fn transform_method_definition_on_exit( + fn enter_property_definition( &mut self, - def: &mut MethodDefinition<'a>, + def: &mut PropertyDefinition<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_method_definition_on_exit(def, ctx); + self.annotations.enter_property_definition(def, ctx); } - pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) { - self.annotations.transform_new_expression(expr); + fn enter_accessor_property( + &mut self, + def: &mut AccessorProperty<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.annotations.enter_accessor_property(def, ctx); } - pub fn transform_property_definition(&mut self, def: &mut PropertyDefinition<'a>) { - self.annotations.transform_property_definition(def); + fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_statements(stmts, ctx); } - pub fn transform_accessor_property(&mut self, def: &mut AccessorProperty<'a>) { - self.annotations.transform_accessor_property(def); + fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.annotations.exit_statements(stmts, ctx); } - pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) { - self.annotations.transform_statements(stmts); + fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) { + self.r#enum.enter_statement(stmt, ctx); } - 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); + fn enter_if_statement(&mut self, stmt: &mut IfStatement<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_if_statement(stmt, ctx); } - pub fn transform_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) { - self.r#enum.transform_statement(stmt, ctx); + fn enter_while_statement(&mut self, stmt: &mut WhileStatement<'a>, ctx: &mut TraverseCtx<'a>) { + self.annotations.enter_while_statement(stmt, ctx); } - pub fn transform_if_statement( + fn enter_do_while_statement( &mut self, - stmt: &mut IfStatement<'a>, + stmt: &mut DoWhileStatement<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_if_statement(stmt, ctx); + self.annotations.enter_do_while_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); + 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); } - pub fn transform_do_while_statement( + 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, - stmt: &mut DoWhileStatement<'a>, + expr: &mut TaggedTemplateExpression<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_do_while_statement(stmt, ctx); + 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); } - pub fn transform_for_statement( + 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, - stmt: &mut ForStatement<'a>, + node: &mut ImportDeclaration<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_for_statement(stmt, ctx); + if self.options.rewrite_import_extensions.is_some() { + self.rewrite_extensions.enter_import_declaration(node, ctx); + } } - pub fn transform_for_in_statement( + fn enter_export_all_declaration( &mut self, - stmt: &mut ForInStatement<'a>, + node: &mut ExportAllDeclaration<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_for_in_statement(stmt, ctx); + if self.options.rewrite_import_extensions.is_some() { + self.rewrite_extensions.enter_export_all_declaration(node, ctx); + } } - pub fn transform_for_of_statement( + fn enter_export_named_declaration( &mut self, - stmt: &mut ForOfStatement<'a>, + node: &mut ExportNamedDeclaration<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.annotations.transform_for_of_statement(stmt, ctx); + if self.options.rewrite_import_extensions.is_some() { + self.rewrite_extensions.enter_export_named_declaration(node, ctx); + } } - pub fn transform_tagged_template_expression( + fn enter_ts_export_assignment( &mut self, - expr: &mut TaggedTemplateExpression<'a>, + node: &mut TSExportAssignment<'a>, + ctx: &mut TraverseCtx<'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); } } diff --git a/crates/oxc_transformer/src/typescript/module.rs b/crates/oxc_transformer/src/typescript/module.rs index e965afe3dd918..6a07b8283b57a 100644 --- a/crates/oxc_transformer/src/typescript/module.rs +++ b/crates/oxc_transformer/src/typescript/module.rs @@ -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::::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::::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)); - } - } } diff --git a/crates/oxc_transformer/src/typescript/namespace.rs b/crates/oxc_transformer/src/typescript/namespace.rs index 66315cb42b72f..c2ee4a676b476 100644 --- a/crates/oxc_transformer/src/typescript/namespace.rs +++ b/crates/oxc_transformer/src/typescript/namespace.rs @@ -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: -impl<'a> TypeScript<'a> { +pub struct TypeScriptNamespace<'a> { + ctx: Ctx<'a>, + options: Rc, +} + +impl<'a> TypeScriptNamespace<'a> { + pub fn new(options: Rc, 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>,