Skip to content

Commit

Permalink
fix: strip export type
Browse files Browse the repository at this point in the history
  • Loading branch information
magic-akari committed May 18, 2023
1 parent 35772ab commit 0f5c32e
Showing 1 changed file with 84 additions and 26 deletions.
110 changes: 84 additions & 26 deletions crates/swc_ecma_transforms_typescript/src/strip_import_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -100,47 +106,46 @@ fn get_module_ident(ts_entity_name: &TsEntityName) -> &Ident {

#[derive(Debug, Default)]
struct DeclareCollect {
id_declare: AHashSet<Id>,
id_type: AHashSet<Id>,
id_value: AHashSet<Id>,
}

// 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) {
match &n.decl {
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());
}
_ => {}
};
}

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) {
Expand All @@ -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
}
Expand All @@ -162,21 +197,24 @@ 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.
pub(crate) struct StripImportExport;

impl VisitMut for StripImportExport {
fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
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 {
Expand All @@ -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())
}
});

Expand All @@ -204,20 +244,38 @@ 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
}
});

!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,
});
}
Expand Down

0 comments on commit 0f5c32e

Please sign in to comment.