swc_ecma_preset_env/corejs3/
entry.rs

1use std::{ops::Range, sync::Arc};
2
3use indexmap::IndexSet;
4use preset_env_base::{
5    version::{should_enable, Version},
6    Versions,
7};
8use rustc_hash::FxBuildHasher;
9use swc_atoms::atom;
10use swc_common::DUMMY_SP;
11use swc_ecma_ast::*;
12use swc_ecma_visit::VisitMut;
13
14use super::{compat::DATA as CORE_JS_COMPAT_DATA, data};
15use crate::util::{PooledStr, SwcFold};
16
17include!(concat!(env!("OUT_DIR"), "/corejs3_entries/lib.rs"));
18
19pub struct FeatureSet(Range<u32>);
20
21pub fn entries_get(name: &str) -> Option<FeatureSet> {
22    let index = ENTRY_INDEX.get(name)?;
23    ENTRY_VALUES_LIST.get(index).cloned().map(FeatureSet)
24}
25
26impl FeatureSet {
27    pub fn iter(&self) -> impl ExactSizeIterator<Item = &'static str> {
28        use precomputed_map::store::AccessSeq;
29
30        use crate::util::PooledStr;
31
32        self.0
33            .clone()
34            .map(|idx| EntryValuesStringId::index(idx as usize).unwrap())
35            .map(|id| PooledStr(id).as_str())
36    }
37}
38
39#[derive(Debug)]
40pub struct Entry {
41    is_any_target: bool,
42    target: Arc<Versions>,
43    corejs_version: Version,
44    pub imports: IndexSet<&'static str, FxBuildHasher>,
45    remove_regenerator: bool,
46}
47
48impl Entry {
49    pub fn new(target: Arc<Versions>, corejs_version: Version, remove_regenerator: bool) -> Self {
50        assert_eq!(corejs_version.major, 3);
51
52        Entry {
53            is_any_target: target.is_any_target(),
54            target,
55            corejs_version,
56            imports: Default::default(),
57            remove_regenerator,
58        }
59    }
60
61    /// Add imports.
62    /// Returns true if it's replaced.
63    fn add(&mut self, src: &str) -> bool {
64        let Entry {
65            is_any_target,
66            target,
67            corejs_version,
68            remove_regenerator,
69            ..
70        } = self;
71
72        if *remove_regenerator && src == "regenerator-runtime/runtime.js" {
73            return true;
74        }
75
76        if let Some(features) = entries_get(src) {
77            self.imports.extend(features.iter().filter(|f| {
78                let feature = CORE_JS_COMPAT_DATA.get(*f);
79
80                if !*is_any_target {
81                    if let Some(feature) = feature {
82                        if !should_enable(target, feature, true) {
83                            return false;
84                        }
85                    }
86                }
87
88                if let Some(version) = data::modules_by_version(f) {
89                    return version <= *corejs_version;
90                }
91
92                true
93            }));
94
95            true
96        } else {
97            false
98        }
99    }
100}
101
102impl VisitMut for Entry {
103    fn visit_mut_import_decl(&mut self, i: &mut ImportDecl) {
104        let remove = i.specifiers.is_empty() && self.add(&i.src.value.to_string_lossy());
105
106        if remove {
107            i.src.span = DUMMY_SP;
108            i.src.value = atom!("").into();
109        }
110    }
111}