swc_ecma_transforms_proposal/
export_default_from.rs

1use 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
6/// `@babel/plugin-proposal-export-default-from`
7pub 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}