swc_ecma_transforms_module/
import_analysis.rs1use rustc_hash::FxHashMap;
2use swc_atoms::Atom;
3use swc_ecma_ast::*;
4use swc_ecma_transforms_base::enable_helper;
5use swc_ecma_visit::{
6 noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitWith,
7};
8
9use crate::{module_decl_strip::LinkFlag, util::ImportInterop};
10
11pub fn import_analyzer(import_interop: ImportInterop, ignore_dynamic: bool) -> impl Pass {
12 visit_mut_pass(ImportAnalyzer {
13 import_interop,
14 ignore_dynamic,
15 flag_record: Default::default(),
16 dynamic_import_found: false,
17 })
18}
19
20pub struct ImportAnalyzer {
21 import_interop: ImportInterop,
22 ignore_dynamic: bool,
23
24 flag_record: FxHashMap<Atom, LinkFlag>,
25 dynamic_import_found: bool,
26}
27
28impl VisitMut for ImportAnalyzer {
30 noop_visit_mut_type!(fail);
31
32 fn visit_mut_module(&mut self, module: &mut Module) {
33 self.visit_module(&*module);
34 }
35}
36
37impl Visit for ImportAnalyzer {
38 noop_visit_type!(fail);
39
40 fn visit_module_items(&mut self, n: &[ModuleItem]) {
41 for item in n.iter() {
42 if item.is_module_decl() {
43 item.visit_with(self);
44 }
45 }
46
47 let flag_record = &self.flag_record;
48
49 if flag_record.values().any(|flag| flag.export_star()) {
50 enable_helper!(export_star);
51 }
52
53 if self.import_interop.is_none() {
54 return;
55 }
56
57 if self.import_interop.is_swc()
58 && flag_record
59 .values()
60 .any(|flag| flag.interop() && !flag.has_named())
61 {
62 enable_helper!(interop_require_default);
63 }
64
65 if flag_record.values().any(|flag| flag.namespace()) {
66 enable_helper!(interop_require_wildcard);
67 } else if !self.ignore_dynamic {
68 for item in n.iter() {
71 if item.is_stmt() {
72 item.visit_with(self);
73 }
74 if self.dynamic_import_found {
75 enable_helper!(interop_require_wildcard);
76 break;
77 }
78 }
79 }
80 }
81
82 fn visit_import_decl(&mut self, n: &ImportDecl) {
83 let flag = self.flag_record.entry(n.src.value.clone()).or_default();
84 for s in &n.specifiers {
85 *flag |= s.into();
86 }
87 }
88
89 fn visit_named_export(&mut self, n: &NamedExport) {
90 if let Some(src) = n.src.clone() {
91 let flag = self.flag_record.entry(src.value).or_default();
92 for s in &n.specifiers {
93 *flag |= s.into();
94 }
95 }
96 }
97
98 fn visit_export_all(&mut self, n: &ExportAll) {
99 *self.flag_record.entry(n.src.value.clone()).or_default() |= LinkFlag::EXPORT_STAR;
100 }
101
102 fn visit_import(&mut self, _: &Import) {
103 self.dynamic_import_found = true;
104 }
105}