diff --git a/crates/oxc_transformer/src/typescript/namespace.rs b/crates/oxc_transformer/src/typescript/namespace.rs index 35959717ebfffd..7e993928c71ec2 100644 --- a/crates/oxc_transformer/src/typescript/namespace.rs +++ b/crates/oxc_transformer/src/typescript/namespace.rs @@ -1,3 +1,4 @@ +use oxc_semantic::Reference; use rustc_hash::FxHashSet; use oxc_allocator::{Box as ArenaBox, Vec as ArenaVec}; @@ -23,11 +24,16 @@ pub struct TypeScriptNamespace<'a, 'ctx> { // Options allow_namespaces: bool, + only_remove_type_imports: bool, } impl<'a, 'ctx> TypeScriptNamespace<'a, 'ctx> { pub fn new(options: &TypeScriptOptions, ctx: &'ctx TransformCtx<'a>) -> Self { - Self { ctx, allow_namespaces: options.allow_namespaces } + Self { + ctx, + allow_namespaces: options.allow_namespaces, + only_remove_type_imports: options.only_remove_type_imports, + } } } @@ -274,9 +280,20 @@ impl<'a> TypeScriptNamespace<'a, '_> { | Statement::TSEnumDeclaration(_) => { names.insert(stmt.to_declaration().id().as_ref().unwrap().name.clone()); } - Statement::TSTypeAliasDeclaration(_) - | Statement::TSInterfaceDeclaration(_) - | Statement::TSImportEqualsDeclaration(_) => continue, + // Retain when `only_remove_type_imports` is true or there are value references + // The behavior is the same as `TypeScriptModule::transform_ts_import_equals` + Statement::TSImportEqualsDeclaration(decl) + if !self.only_remove_type_imports + && ctx + .symbols() + .get_resolved_references(decl.id.symbol_id()) + .all(Reference::is_type) => + { + continue; + } + Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => { + continue + } _ => {} } new_stmts.push(stmt); diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 5dc1cb57665e59..44675a8c634267 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 126/145 +Passed: 126/147 # All Passed: * babel-plugin-transform-class-static-block @@ -47,7 +47,7 @@ after transform: SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), R rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), ReferenceId(10)] -# babel-plugin-transform-typescript (2/11) +# babel-plugin-transform-typescript (2/13) * class-property-definition/input.ts Unresolved references mismatch: after transform: ["const"] @@ -159,6 +159,65 @@ Scope children mismatch: after transform: ScopeId(0): [ScopeId(1)] rebuilt : ScopeId(0): [] +* namespace/import-=/input.ts +Missing SymbolId: "N1" +Missing SymbolId: "_N" +Missing ReferenceId: "N1" +Missing ReferenceId: "N1" +Missing SymbolId: "N2" +Missing SymbolId: "_N2" +Missing SymbolId: "X" +Missing ReferenceId: "N2" +Missing ReferenceId: "N2" +Binding symbols mismatch: +after transform: ScopeId(0): [SymbolId(0), SymbolId(1), SymbolId(4)] +rebuilt : ScopeId(0): [SymbolId(0), SymbolId(1), SymbolId(4)] +Bindings mismatch: +after transform: ScopeId(1): ["V", "X", "_N"] +rebuilt : ScopeId(1): ["V", "_N"] +Scope flags mismatch: +after transform: ScopeId(1): ScopeFlags(StrictMode | Function) +rebuilt : ScopeId(1): ScopeFlags(Function) +Binding symbols mismatch: +after transform: ScopeId(2): [SymbolId(5), SymbolId(6), SymbolId(8)] +rebuilt : ScopeId(2): [SymbolId(5), SymbolId(6), SymbolId(7)] +Scope flags mismatch: +after transform: ScopeId(2): ScopeFlags(StrictMode | Function) +rebuilt : ScopeId(2): ScopeFlags(Function) +Symbol reference IDs mismatch for "A": +after transform: SymbolId(0): [ReferenceId(0), ReferenceId(1)] +rebuilt : SymbolId(0): [ReferenceId(2)] +Reference symbol mismatch for "X": +after transform: SymbolId(5) "X" +rebuilt : SymbolId(6) "X" + +* namespace/preserve-import-=/input.ts +Missing SymbolId: "N1" +Missing SymbolId: "_N" +Missing SymbolId: "Foo" +Missing ReferenceId: "N1" +Missing ReferenceId: "N1" +Missing SymbolId: "N2" +Missing SymbolId: "_N2" +Missing SymbolId: "Foo" +Missing ReferenceId: "N2" +Missing ReferenceId: "N2" +Binding symbols mismatch: +after transform: ScopeId(0): [SymbolId(0), SymbolId(1), SymbolId(4)] +rebuilt : ScopeId(0): [SymbolId(0), SymbolId(1), SymbolId(5)] +Binding symbols mismatch: +after transform: ScopeId(1): [SymbolId(2), SymbolId(3), SymbolId(7)] +rebuilt : ScopeId(1): [SymbolId(2), SymbolId(3), SymbolId(4)] +Scope flags mismatch: +after transform: ScopeId(1): ScopeFlags(StrictMode | Function) +rebuilt : ScopeId(1): ScopeFlags(Function) +Binding symbols mismatch: +after transform: ScopeId(2): [SymbolId(5), SymbolId(6), SymbolId(8)] +rebuilt : ScopeId(2): [SymbolId(6), SymbolId(7), SymbolId(8)] +Scope flags mismatch: +after transform: ScopeId(2): ScopeFlags(StrictMode | Function) +rebuilt : ScopeId(2): ScopeFlags(Function) + * preserve-import-=/input.js Missing SymbolId: "Foo" Binding symbols mismatch: diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/import-=/input.ts b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/import-=/input.ts new file mode 100644 index 00000000000000..4f01e2d5b6dae1 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/import-=/input.ts @@ -0,0 +1,13 @@ +import A from 'mod'; +namespace N1 { + // Remove because `X` has not been referenced + import X = A.B; + const V = 0; +} + +namespace N2 { + // Retain because `X` has been referenced + import X = A.B; + const V = X; +} + diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/import-=/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/import-=/output.js new file mode 100644 index 00000000000000..5d5976174136f9 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/import-=/output.js @@ -0,0 +1,11 @@ +import A from 'mod'; +let N1; +(function (_N) { + const V = 0; +})(N1 || (N1 = {})); +let N2; +(function (_N2) { + // Retain because `X` has been referenced + var X = A.B; + const V = X; +})(N2 || (N2 = {})); diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/input.ts b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/input.ts new file mode 100644 index 00000000000000..a70f3279017ba2 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/input.ts @@ -0,0 +1,13 @@ +import nsa from "mod"; + +namespace N1 { + // Retain because `onlyRemoveTypeImports` is true + import Foo = nsa.bar; + const foo = 0; +} + +namespace N2 { + // Retain because `onlyRemoveTypeImports` is true + import Foo = nsa.bar; + const foo: Foo = 0; +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/options.json b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/options.json new file mode 100644 index 00000000000000..0ec61d2b5e55bc --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + [ + "transform-typescript", + { + "onlyRemoveTypeImports": true + } + ] + ] +} diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/output.js new file mode 100644 index 00000000000000..569a232c36be0d --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-typescript/test/fixtures/namespace/preserve-import-=/output.js @@ -0,0 +1,15 @@ +import nsa from "mod"; + +let N1; +(function(_N) { + // Retain because `onlyRemoveTypeImports` is true + var Foo = nsa.bar; + const foo = 0; +})(N1 || (N1 = {})); + +let N2; +(function(_N2) { + // Retain because `onlyRemoveTypeImports` is true + var Foo = nsa.bar; + const foo = 0; +})(N2 || (N2 = {}));