From 0f5c32ecc00cb12cab4d3a6f72a750d3d78d7525 Mon Sep 17 00:00:00 2001 From: magic-akari Date: Thu, 18 May 2023 14:36:09 +0800 Subject: [PATCH] fix: strip export type --- .../src/strip_import_export.rs | 110 +++++++++++++----- 1 file changed, 84 insertions(+), 26 deletions(-) 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 560a95940ea01..6e47e7f49a6a1 100644 --- a/crates/swc_ecma_transforms_typescript/src/strip_import_export.rs +++ b/crates/swc_ecma_transforms_typescript/src/strip_import_export.rs @@ -89,6 +89,12 @@ impl Visit for UsageCollect { } } +impl UsageCollect { + fn has_usage(&self, id: &Id) -> bool { + self.id_usage.contains(id) + } +} + fn get_module_ident(ts_entity_name: &TsEntityName) -> &Ident { match ts_entity_name { TsEntityName::TsQualifiedName(ts_qualified_name) => { @@ -100,23 +106,22 @@ fn get_module_ident(ts_entity_name: &TsEntityName) -> &Ident { #[derive(Debug, Default)] struct DeclareCollect { - id_declare: AHashSet, + id_type: AHashSet, + id_value: AHashSet, } // Only scan the top level of the module impl Visit for DeclareCollect { - noop_visit_type!(); - fn visit_binding_ident(&mut self, n: &BindingIdent) { - self.id_declare.insert(n.to_id()); + self.id_value.insert(n.to_id()); } fn visit_fn_decl(&mut self, n: &FnDecl) { - self.id_declare.insert(n.ident.to_id()); + self.id_value.insert(n.ident.to_id()); } fn visit_class_decl(&mut self, n: &ClassDecl) { - self.id_declare.insert(n.ident.to_id()); + self.id_value.insert(n.ident.to_id()); } fn visit_export_default_decl(&mut self, n: &ExportDefaultDecl) { @@ -124,12 +129,12 @@ impl Visit for DeclareCollect { DefaultDecl::Class(ClassExpr { ident: Some(ident), .. }) => { - self.id_declare.insert(ident.to_id()); + self.id_value.insert(ident.to_id()); } DefaultDecl::Fn(FnExpr { ident: Some(ident), .. }) => { - self.id_declare.insert(ident.to_id()); + self.id_value.insert(ident.to_id()); } _ => {} }; @@ -137,10 +142,10 @@ impl Visit for DeclareCollect { fn visit_ts_import_equals_decl(&mut self, n: &TsImportEqualsDecl) { if n.is_type_only { - return; + self.id_type.insert(n.id.to_id()); + } else { + self.id_value.insert(n.id.to_id()); } - - self.id_declare.insert(n.id.to_id()); } fn visit_ts_module_decl(&mut self, n: &TsModuleDecl) { @@ -149,10 +154,40 @@ impl Visit for DeclareCollect { } if let TsModuleName::Ident(ident) = &n.id { - self.id_declare.insert(ident.to_id()); + self.id_value.insert(ident.to_id()); } } + fn visit_ts_interface_decl(&mut self, n: &TsInterfaceDecl) { + self.id_type.insert(n.id.to_id()); + } + + fn visit_ts_type_alias_decl(&mut self, n: &TsTypeAliasDecl) { + self.id_type.insert(n.id.to_id()); + } + + fn visit_import_decl(&mut self, n: &ImportDecl) { + n.specifiers + .iter() + .for_each(|import_specifier| match import_specifier { + ImportSpecifier::Named(named) => { + if n.type_only || named.is_type_only { + self.id_type.insert(named.local.to_id()); + } + } + ImportSpecifier::Default(default) => { + if n.type_only { + self.id_type.insert(default.local.to_id()); + } + } + ImportSpecifier::Namespace(namespace) => { + if n.type_only { + self.id_type.insert(namespace.local.to_id()); + } + } + }); + } + fn visit_stmts(&mut self, _: &[Stmt]) { // skip } @@ -162,6 +197,12 @@ impl Visit for DeclareCollect { } } +impl DeclareCollect { + fn has_pure_type(&self, id: &Id) -> bool { + self.id_type.contains(id) && !self.id_value.contains(id) + } +} + /// https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues /// /// The tsc drop import statements which only reference types by default. @@ -169,14 +210,11 @@ pub(crate) struct StripImportExport; impl VisitMut for StripImportExport { fn visit_mut_module_items(&mut self, n: &mut Vec) { - let mut usage_collect = UsageCollect::default(); - let mut declare_collect = DeclareCollect::default(); - - n.visit_with(&mut usage_collect); - n.visit_with(&mut declare_collect); + let mut usage_info = UsageCollect::default(); + let mut declare_info = DeclareCollect::default(); - let UsageCollect { id_usage } = usage_collect; - let DeclareCollect { id_declare } = declare_collect; + n.visit_with(&mut usage_info); + n.visit_with(&mut declare_info); n.retain_mut(|module_item| match module_item { ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { @@ -186,11 +224,13 @@ impl VisitMut for StripImportExport { })) if !specifiers.is_empty() => { specifiers.retain(|import_specifier| match import_specifier { ImportSpecifier::Named(named) => { - !named.is_type_only && id_usage.contains(&named.local.to_id()) + !named.is_type_only && usage_info.has_usage(&named.local.to_id()) + } + ImportSpecifier::Default(default) => { + usage_info.has_usage(&default.local.to_id()) } - ImportSpecifier::Default(default) => id_usage.contains(&default.local.to_id()), ImportSpecifier::Namespace(namespace) => { - id_usage.contains(&namespace.local.to_id()) + usage_info.has_usage(&namespace.local.to_id()) } }); @@ -204,13 +244,17 @@ impl VisitMut for StripImportExport { })) => { specifiers.retain(|export_specifier| match export_specifier { ExportSpecifier::Namespace(..) => true, - ExportSpecifier::Default(default) => { - id_declare.contains(&default.exported.to_id()) - } + ExportSpecifier::Default(..) => true, + ExportSpecifier::Named(ExportNamedSpecifier { orig: ModuleExportName::Ident(ident), + is_type_only: false, .. - }) => id_declare.contains(&ident.to_id()), + }) => { + let id = ident.to_id(); + + !declare_info.has_pure_type(&id) + } ExportSpecifier::Named(ExportNamedSpecifier { is_type_only, .. }) => { !is_type_only } @@ -218,6 +262,20 @@ impl VisitMut for StripImportExport { !specifiers.is_empty() } + ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport { + ref type_only, .. + })) => !type_only, + ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(ExportDefaultExpr { + ref expr, + .. + })) => expr + .as_ident() + .map(|ident| { + let id = ident.to_id(); + + !declare_info.has_pure_type(&id) + }) + .unwrap_or(true), _ => true, }); }