diff --git a/.changeset/wicked-lizards-smoke.md b/.changeset/wicked-lizards-smoke.md new file mode 100644 index 000000000000..903ad056e9ef --- /dev/null +++ b/.changeset/wicked-lizards-smoke.md @@ -0,0 +1,5 @@ +--- +swc_ecma_transforms_typescript: patch +--- + +fix(es/typescript): Analyze import chain diff --git a/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.1.normal.js b/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.1.normal.js index 1b2eef9d1863..eb9f3745fec6 100644 --- a/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.1.normal.js +++ b/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.1.normal.js @@ -38,9 +38,8 @@ define([ //// [foo_1.ts] define([ "require", - "exports", - "./foo_0" -], function(require, exports, _foo_0) { + "exports" +], function(require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true diff --git a/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.2.minified.js b/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.2.minified.js index 8ff118e13278..3ffcd4cf0324 100644 --- a/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.2.minified.js +++ b/crates/swc/tests/tsc-references/amdImportNotAsPrimaryExpression.2.minified.js @@ -27,9 +27,8 @@ define([ //// [foo_1.ts] define([ "require", - "exports", - "./foo_0" -], function(require, exports, _foo_0) { + "exports" +], function(require, exports) { Object.defineProperty(exports, "__esModule", { value: !0 }); diff --git a/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.1.normal.js b/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.1.normal.js index bbce10fcee7c..44d87fb2e67c 100644 --- a/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.1.normal.js +++ b/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.1.normal.js @@ -35,7 +35,6 @@ var E1; Object.defineProperty(exports, "__esModule", { value: true }); -var foo = require("./foo_0"); var i; var x = {}; var y = false; diff --git a/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.2.minified.js b/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.2.minified.js index c18d2b9820d4..3f12bb103c2b 100644 --- a/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.2.minified.js +++ b/crates/swc/tests/tsc-references/commonJSImportNotAsPrimaryExpression.2.minified.js @@ -21,4 +21,4 @@ C1.s1 = !0, (E1 = E11 || (E11 = {}))[E1.A = 0] = "A", E1[E1.B = 1] = "B", E1[E1. //// [foo_1.ts] Object.defineProperty(exports, "__esModule", { value: !0 -}), require("./foo_0"); +}); diff --git a/crates/swc/tests/tsc-references/importStatementsInterfaces.1.normal.js b/crates/swc/tests/tsc-references/importStatementsInterfaces.1.normal.js index 1ee46bc5ff32..99284a9839d2 100644 --- a/crates/swc/tests/tsc-references/importStatementsInterfaces.1.normal.js +++ b/crates/swc/tests/tsc-references/importStatementsInterfaces.1.normal.js @@ -2,7 +2,6 @@ var C; // no code gen expected (function(C) { - var a = A; var m; var p; var p = { diff --git a/crates/swc/tests/tsc-references/importStatementsInterfaces.2.minified.js b/crates/swc/tests/tsc-references/importStatementsInterfaces.2.minified.js index e5f6534008e4..4334d5daa9d8 100644 --- a/crates/swc/tests/tsc-references/importStatementsInterfaces.2.minified.js +++ b/crates/swc/tests/tsc-references/importStatementsInterfaces.2.minified.js @@ -1,5 +1,5 @@ //// [importStatementsInterfaces.ts] var C, D, E; -C || (C = {}), A, D || (D = {}), (E || (E = {})).xDist = function(x) { +C || (C = {}), D || (D = {}), (E || (E = {})).xDist = function(x) { return 0 - x.x; }; diff --git a/crates/swc_ecma_transforms_typescript/src/strip_import_export.rs b/crates/swc_ecma_transforms_typescript/src/strip_import_export.rs index f3952f07f18f..ab4eda550ae4 100644 --- a/crates/swc_ecma_transforms_typescript/src/strip_import_export.rs +++ b/crates/swc_ecma_transforms_typescript/src/strip_import_export.rs @@ -1,6 +1,6 @@ use std::mem; -use swc_common::collections::AHashSet; +use swc_common::collections::{AHashMap, AHashSet}; use swc_ecma_ast::*; use swc_ecma_utils::stack_size::maybe_grow_default; use swc_ecma_visit::{noop_visit_type, Visit, VisitMut, VisitMutWith, VisitWith}; @@ -10,11 +10,15 @@ use crate::{strip_type::IsConcrete, ImportsNotUsedAsValues}; #[derive(Debug, Default)] struct UsageCollect { id_usage: AHashSet, + import_chain: AHashMap, } impl From> for UsageCollect { fn from(id_usage: AHashSet) -> Self { - Self { id_usage } + Self { + id_usage, + import_chain: Default::default(), + } } } @@ -68,7 +72,15 @@ impl Visit for UsageCollect { return; }; - get_module_ident(ts_entity_name).visit_with(self); + let id = get_module_ident(ts_entity_name); + + if n.is_export { + id.visit_with(self); + n.id.visit_with(self); + return; + } + + self.import_chain.insert(n.id.to_id(), id.to_id()); } fn visit_export_named_specifier(&mut self, n: &ExportNamedSpecifier) { @@ -101,6 +113,26 @@ impl UsageCollect { fn has_usage(&self, id: &Id) -> bool { self.id_usage.contains(id) } + + fn analyze_import_chain(&mut self) { + if self.import_chain.is_empty() { + return; + } + + let mut new_usage = AHashSet::default(); + for id in &self.id_usage { + let mut entry = self.import_chain.remove_entry(id); + while let Some((id, next)) = entry { + new_usage.insert(next); + entry = self.import_chain.remove_entry(&id); + } + if self.import_chain.is_empty() { + break; + } + } + self.import_chain.clear(); + self.id_usage.extend(new_usage); + } } fn get_module_ident(ts_entity_name: &TsEntityName) -> &Ident { @@ -264,6 +296,8 @@ impl VisitMut for StripImportExport { n.visit_with(&mut usage_info); n.visit_with(&mut declare_info); + usage_info.analyze_import_chain(); + let mut strip_ts_import_equals = StripTsImportEquals; n.retain_mut(|module_item| match module_item { diff --git a/crates/swc_ecma_transforms_typescript/tests/__swc_snapshots__/tests/strip.rs/deno_12395_import_equals_2.js b/crates/swc_ecma_transforms_typescript/tests/__swc_snapshots__/tests/strip.rs/deno_12395_import_equals_2.js index 4a0913877086..c9be2f4ec727 100644 --- a/crates/swc_ecma_transforms_typescript/tests/__swc_snapshots__/tests/strip.rs/deno_12395_import_equals_2.js +++ b/crates/swc_ecma_transforms_typescript/tests/__swc_snapshots__/tests/strip.rs/deno_12395_import_equals_2.js @@ -1,2 +1 @@ -import * as mongo from 'https://deno.land/x/mongo@v0.27.0/mod.ts'; const mongoClient = {}; diff --git a/crates/swc_ecma_transforms_typescript/tests/fixture/issue-9368/input.ts b/crates/swc_ecma_transforms_typescript/tests/fixture/issue-9368/input.ts new file mode 100644 index 000000000000..30dbafb1bb4f --- /dev/null +++ b/crates/swc_ecma_transforms_typescript/tests/fixture/issue-9368/input.ts @@ -0,0 +1,16 @@ +import { Schemas } from './types.d'; +import AddressResource = Schemas.AddressResource; + +// type usage +const x: AddressResource = {}; + + +import { foo, bar } from "mod"; + +// value usage +import y = foo.y; + +// type usage +import z = bar.z; + +console.log(y as z); diff --git a/crates/swc_ecma_transforms_typescript/tests/fixture/issue-9368/output.js b/crates/swc_ecma_transforms_typescript/tests/fixture/issue-9368/output.js new file mode 100644 index 000000000000..bea8219de834 --- /dev/null +++ b/crates/swc_ecma_transforms_typescript/tests/fixture/issue-9368/output.js @@ -0,0 +1,6 @@ +// type usage +const x = {}; +import { foo } from "mod"; +// value usage +const y = foo.y; +console.log(y);