swc_ecma_preset_env/corejs2/
entry.rs

1use std::sync::Arc;
2
3use indexmap::IndexSet;
4use preset_env_base::{version::should_enable, Versions};
5use rustc_hash::FxBuildHasher;
6use swc_atoms::atom;
7use swc_common::DUMMY_SP;
8use swc_ecma_ast::*;
9use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
10
11use super::builtin::BUILTINS;
12
13#[derive(Debug)]
14pub struct Entry {
15    is_any_target: bool,
16    target: Arc<Versions>,
17    pub imports: IndexSet<&'static str, FxBuildHasher>,
18}
19
20impl Entry {
21    pub fn new(target: Arc<Versions>, regenerator: bool) -> Self {
22        let is_any_target = target.is_any_target();
23        let is_web_target = target.into_iter().any(|(k, v)| {
24            if k == "node" {
25                return false;
26            }
27
28            v.is_some()
29        });
30
31        let mut v = Entry {
32            is_any_target: target.is_any_target(),
33            target,
34            imports: Default::default(),
35        };
36        if is_any_target || is_web_target {
37            v.imports.insert("web.timers");
38            v.imports.insert("web.immediate");
39            v.imports.insert("web.dom.iterable");
40        }
41
42        if regenerator {
43            v.imports.insert("regenerator-runtime/runtime.js");
44        }
45
46        v
47    }
48
49    /// Add imports.
50    /// Returns true if it's replaced.
51    fn add_all(&mut self, src: &str) -> bool {
52        if src != "@babel/polyfill" && src != "@swc/polyfill" && src != "core-js" {
53            return false;
54        }
55
56        for (feature, version) in BUILTINS.iter() {
57            self.add_inner(feature, version);
58        }
59
60        true
61    }
62
63    fn add_inner(&mut self, feature: &'static str, version: &Versions) {
64        if self.is_any_target || should_enable(&self.target, version, true) {
65            self.imports.insert(feature);
66        }
67    }
68}
69
70impl VisitMut for Entry {
71    noop_visit_mut_type!(fail);
72
73    fn visit_mut_import_decl(&mut self, i: &mut ImportDecl) {
74        let remove = i.specifiers.is_empty() && self.add_all(&i.src.value.to_string_lossy());
75
76        if remove {
77            i.src.value = atom!("").into();
78            i.src.span = DUMMY_SP;
79        }
80    }
81
82    fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
83        items.retain_mut(|item| {
84            item.visit_mut_children_with(self);
85            if let ModuleItem::Stmt(Stmt::Expr(ExprStmt { expr, .. })) = &item {
86                if let Expr::Call(CallExpr {
87                    callee: Callee::Expr(callee),
88                    ref args,
89                    ..
90                }) = &**expr
91                {
92                    if callee.is_ident_ref_to("require")
93                        && args.len() == 1
94                        && if let ExprOrSpread { spread: None, expr } = &args[0] {
95                            if let Expr::Lit(Lit::Str(s)) = &**expr {
96                                s.value == *"core-js"
97                                    || s.value == *"@swc/polyfill"
98                                    || s.value == *"@babel/polyfill"
99                            } else {
100                                false
101                            }
102                        } else {
103                            false
104                        }
105                        && self.add_all("@swc/polyfill")
106                    {
107                        return false;
108                    }
109                }
110            }
111            true
112        })
113    }
114}