swc_ecma_minifier/pass/
merge_exports.rs1use 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
7pub(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 if !was_module {
31 return;
32 }
33
34 stmts.visit_mut_children_with(self);
35
36 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 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}