swc_ecma_minifier/pass/
merge_exports.rs

1use swc_common::{util::take::Take, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
4
5use crate::maybe_par;
6
7///
8/// - merge exports
9pub(crate) fn merge_exports() -> impl VisitMut {
10    Merger::default()
11}
12
13#[derive(Default)]
14struct Merger {
15    specifiers: Vec<ExportSpecifier>,
16}
17
18impl VisitMut for Merger {
19    noop_visit_mut_type!(fail);
20
21    fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
22        let was_module = maybe_par!(
23            stmts
24                .iter()
25                .any(|s| matches!(s, ModuleItem::ModuleDecl(..))),
26            *crate::LIGHT_TASK_PARALLELS
27        );
28
29        // Fast-path
30        if !was_module {
31            return;
32        }
33
34        stmts.visit_mut_children_with(self);
35
36        // Merge exports
37        stmts.retain(|s| {
38            !matches!(
39                s,
40                ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport { src: None, .. }))
41            )
42        });
43
44        if !self.specifiers.is_empty() {
45            stmts.push(
46                NamedExport {
47                    src: None,
48                    specifiers: self.specifiers.take(),
49                    span: DUMMY_SP,
50                    type_only: Default::default(),
51                    with: Default::default(),
52                }
53                .into(),
54            );
55        }
56
57        // export {}, to preserve module semantics
58        if stmts.iter().all(|s| matches!(s, ModuleItem::Stmt(..))) {
59            debug_assert!(was_module);
60            stmts.push(
61                NamedExport {
62                    src: None,
63                    specifiers: Default::default(),
64                    span: DUMMY_SP,
65                    type_only: Default::default(),
66                    with: Default::default(),
67                }
68                .into(),
69            );
70        }
71    }
72
73    fn visit_mut_named_export(&mut self, e: &mut NamedExport) {
74        if e.src.is_some() {
75            return;
76        }
77
78        self.specifiers.append(&mut e.specifiers);
79    }
80}