swc_ecma_transforms_proposal/
export_default_from.rs1use swc_common::DUMMY_SP;
2use swc_ecma_ast::*;
3use swc_ecma_utils::quote_ident;
4use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut};
5
6pub fn export_default_from() -> impl Pass {
8 visit_mut_pass(ExportDefaultFrom)
9}
10
11struct ExportDefaultFrom;
12
13impl VisitMut for ExportDefaultFrom {
14 noop_visit_mut_type!();
15
16 fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
17 let count = items
18 .iter()
19 .filter(|m| {
20 matches!(m, ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
21 specifiers,
22 src: Some(..),
23 type_only: false,
24 ..
25 })) if specifiers.iter().any(|s| s.is_default()))
26 })
27 .count();
28
29 if count == 0 {
30 return;
31 }
32
33 let mut stmts = Vec::<ModuleItem>::with_capacity(items.len() + count);
34
35 for item in items.drain(..) {
36 match item {
37 ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
38 span,
39 specifiers,
40 src: Some(src),
41 type_only: false,
42 with,
43 })) if specifiers.iter().any(|s| s.is_default()) => {
44 let mut origin_specifiers = Vec::new();
45
46 let mut export_specifiers = Vec::new();
47
48 let mut has_namespace = false;
49
50 for s in specifiers.into_iter() {
51 match s {
52 ExportSpecifier::Default(ExportDefaultSpecifier { exported }) => {
53 export_specifiers.push(ExportSpecifier::Named(
54 ExportNamedSpecifier {
55 span: DUMMY_SP,
56 orig: quote_ident!(exported.ctxt, exported.span, "default")
57 .into(),
58 exported: Some(exported.into()),
59 is_type_only: false,
60 },
61 ));
62 }
63 ExportSpecifier::Namespace(..) => {
64 has_namespace = true;
65 origin_specifiers.push(s);
66 }
67 ExportSpecifier::Named(..) => {
68 if has_namespace {
69 origin_specifiers.push(s);
70 } else {
71 export_specifiers.push(s);
72 }
73 }
74 }
75 }
76
77 stmts.push(
78 NamedExport {
79 span,
80 specifiers: export_specifiers,
81 src: Some(src.clone()),
82 type_only: false,
83 with: None,
84 }
85 .into(),
86 );
87
88 if !origin_specifiers.is_empty() {
89 stmts.push(
90 NamedExport {
91 span,
92 specifiers: origin_specifiers,
93 src: Some(src),
94 type_only: false,
95 with,
96 }
97 .into(),
98 );
99 }
100 }
101 _ => {
102 stmts.push(item);
103 }
104 }
105 }
106
107 *items = stmts;
108 }
109}