swc_ecma_transforms_compat/es2020/
export_namespace_from.rsuse swc_atoms::JsWord;
use swc_ecma_ast::*;
use swc_ecma_utils::private_ident;
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut};
use swc_trace_macro::swc_trace;
#[tracing::instrument(level = "info", skip_all)]
pub fn export_namespace_from() -> impl Fold + VisitMut {
as_folder(ExportNamespaceFrom)
}
struct ExportNamespaceFrom;
#[swc_trace]
impl VisitMut for ExportNamespaceFrom {
noop_visit_mut_type!();
fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
let count = items
.iter()
.filter(|m| {
matches!(m, ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
specifiers,
src: Some(..),
type_only: false,
..
})) if specifiers.iter().any(|s| s.is_namespace()))
})
.count();
if count == 0 {
return;
}
let mut stmts = Vec::<ModuleItem>::with_capacity(items.len() + count);
for item in items.drain(..) {
match item {
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
span,
specifiers,
src: Some(src),
type_only: false,
asserts,
})) if specifiers.iter().any(|s| s.is_namespace()) => {
let mut origin_specifiers = vec![];
let mut import_specifiers = vec![];
let mut export_specifiers = vec![];
for s in specifiers.into_iter() {
match s {
ExportSpecifier::Namespace(ExportNamespaceSpecifier { span, name }) => {
let local_bridge =
private_ident!(format!("_{}", normalize_name(&name)));
import_specifiers.push(ImportSpecifier::Namespace(
ImportStarAsSpecifier {
span,
local: local_bridge.clone(),
},
));
export_specifiers.push(ExportSpecifier::Named(
ExportNamedSpecifier {
span,
orig: local_bridge.into(),
exported: Some(name),
is_type_only: false,
},
))
}
ExportSpecifier::Default(..) | ExportSpecifier::Named(..) => {
origin_specifiers.push(s);
}
}
}
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span,
specifiers: import_specifiers,
src: src.clone(),
type_only: false,
asserts: asserts.clone(),
})));
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
span,
specifiers: export_specifiers,
src: None,
type_only: false,
asserts: None,
},
)));
if !origin_specifiers.is_empty() {
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
span,
specifiers: origin_specifiers,
src: Some(src),
type_only: false,
asserts,
},
)));
}
}
_ => {
stmts.push(item);
}
}
}
*items = stmts;
}
}
fn normalize_name(module_export_name: &ModuleExportName) -> &JsWord {
match module_export_name {
ModuleExportName::Ident(Ident { sym: name, .. })
| ModuleExportName::Str(Str { value: name, .. }) => name,
}
}