11use oxc_allocator:: { Box as ArenaBox , TakeIn , Vec as ArenaVec } ;
22use oxc_ast:: { NONE , ast:: * } ;
33use oxc_ecmascript:: BoundNames ;
4- use oxc_semantic:: Reference ;
54use oxc_span:: SPAN ;
65use oxc_syntax:: {
76 operator:: { AssignmentOperator , LogicalOperator } ,
@@ -22,24 +21,18 @@ pub struct TypeScriptNamespace<'a, 'ctx> {
2221
2322 // Options
2423 allow_namespaces : bool ,
25- only_remove_type_imports : bool ,
2624}
2725
2826impl < ' a , ' ctx > TypeScriptNamespace < ' a , ' ctx > {
2927 pub fn new ( options : & TypeScriptOptions , ctx : & ' ctx TransformCtx < ' a > ) -> Self {
30- Self {
31- ctx,
32- allow_namespaces : options. allow_namespaces ,
33- only_remove_type_imports : options. only_remove_type_imports ,
34- }
28+ Self { ctx, allow_namespaces : options. allow_namespaces }
3529 }
3630}
3731
3832impl < ' a > Traverse < ' a > for TypeScriptNamespace < ' a , ' _ > {
3933 // `namespace Foo { }` -> `let Foo; (function (_Foo) { })(Foo || (Foo = {}));`
4034 fn enter_program ( & mut self , program : & mut Program < ' a > , ctx : & mut TraverseCtx < ' a > ) {
4135 // namespace declaration is only allowed at the top level
42-
4336 if !has_namespace ( program. body . as_slice ( ) ) {
4437 return ;
4538 }
@@ -59,14 +52,12 @@ impl<'a> Traverse<'a> for TypeScriptNamespace<'a, '_> {
5952 self . handle_nested ( decl, /* is_export */ false , & mut new_stmts, None , ctx) ;
6053 continue ;
6154 }
62- Statement :: ExportNamedDeclaration ( export_decl) => {
63- if export_decl. declaration . as_ref ( ) . is_none_or ( |decl| {
64- decl. declare ( ) || !matches ! ( decl, Declaration :: TSModuleDeclaration ( _) )
65- } ) {
66- new_stmts. push ( Statement :: ExportNamedDeclaration ( export_decl) ) ;
67- continue ;
68- }
69-
55+ Statement :: ExportNamedDeclaration ( export_decl)
56+ if export_decl. declaration . as_ref ( ) . is_some_and ( |declaration| {
57+ !declaration. declare ( )
58+ && matches ! ( declaration, Declaration :: TSModuleDeclaration ( _) )
59+ } ) =>
60+ {
7061 let Some ( Declaration :: TSModuleDeclaration ( decl) ) =
7162 export_decl. unbox ( ) . declaration
7263 else {
@@ -111,6 +102,11 @@ impl<'a> TypeScriptNamespace<'a, '_> {
111102 return ;
112103 } ;
113104
105+ // Empty namespace or only have type declarations.
106+ if ctx. scoping ( ) . symbol_flags ( ident. symbol_id ( ) ) . is_namespace ( ) {
107+ return ;
108+ }
109+
114110 let Some ( body) = body else {
115111 return ;
116112 } ;
@@ -151,7 +147,6 @@ impl<'a> TypeScriptNamespace<'a, '_> {
151147 match stmt {
152148 Statement :: TSModuleDeclaration ( decl) => {
153149 self . handle_nested ( decl, /* is_export */ false , & mut new_stmts, None , ctx) ;
154- continue ;
155150 }
156151 Statement :: ExportNamedDeclaration ( export_decl) => {
157152 // NB: `ExportNamedDeclaration` with no declaration (e.g. `export {x}`) is not
@@ -214,33 +209,9 @@ impl<'a> TypeScriptNamespace<'a, '_> {
214209 _ => { }
215210 }
216211 }
217- continue ;
218212 }
219- // Retain when `only_remove_type_imports` is true or there are value references
220- // The behavior is the same as `TypeScriptModule::transform_ts_import_equals`
221- Statement :: TSImportEqualsDeclaration ( decl)
222- if !self . only_remove_type_imports
223- && ctx
224- . scoping ( )
225- . get_resolved_references ( decl. id . symbol_id ( ) )
226- . all ( Reference :: is_type) =>
227- {
228- continue ;
229- }
230- Statement :: TSTypeAliasDeclaration ( _) | Statement :: TSInterfaceDeclaration ( _) => {
231- continue ;
232- }
233- _ => { }
213+ _ => new_stmts. push ( stmt) ,
234214 }
235- new_stmts. push ( stmt) ;
236- }
237-
238- if new_stmts. is_empty ( ) {
239- // Delete the scope binding that `ctx.generate_uid` created above,
240- // as no binding is actually being created
241- ctx. scoping_mut ( ) . remove_binding ( scope_id, uid_binding. name . as_str ( ) ) ;
242-
243- return ;
244215 }
245216
246217 if !Self :: is_redeclaration_namespace ( & ident, ctx) {
0 commit comments