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 #[cfg(swc_ast_unknown)]
75 _ => (),
76 }
77 }
78
79 stmts.push(
80 NamedExport {
81 span,
82 specifiers: export_specifiers,
83 src: Some(src.clone()),
84 type_only: false,
85 with: None,
86 }
87 .into(),
88 );
89
90 if !origin_specifiers.is_empty() {
91 stmts.push(
92 NamedExport {
93 span,
94 specifiers: origin_specifiers,
95 src: Some(src),
96 type_only: false,
97 with,
98 }
99 .into(),
100 );
101 }
102 }
103 _ => {
104 stmts.push(item);
105 }
106 }
107 }
108
109 *items = stmts;
110 }
111}