farmfe_plugin_polyfill/
lib.rs1use std::path::PathBuf;
2
3use farmfe_core::{
4 config::{
5 config_regex::ConfigRegex,
6 preset_env::{PresetEnvConfig, PresetEnvConfigObj},
7 Config,
8 },
9 plugin::Plugin,
10 serde_json,
11 swc_common::{comments::SingleThreadedComments, Mark},
12};
13use farmfe_toolkit::{
14 common::{create_swc_source_map, Source},
15 preset_env_base::query::Query,
16 script::swc_try_with::try_with,
17 swc_ecma_preset_env::{self, preset_env, Mode, Targets},
18 swc_ecma_transforms::Assumptions,
19 swc_ecma_transforms_base::{feature::FeatureFlag, helpers::inject_helpers},
20 swc_ecma_visit::{FoldWith, VisitMutWith},
21};
22
23pub struct FarmPluginPolyfill {
24 config: swc_ecma_preset_env::Config,
25 include: Vec<ConfigRegex>,
26 exclude: Vec<ConfigRegex>,
27 enforce_exclude: Vec<ConfigRegex>,
28 assumptions: Assumptions,
29}
30
31impl FarmPluginPolyfill {
32 pub fn new(config: &Config) -> Self {
33 let (config, include, exclude, assumptions) = match &*config.preset_env {
34 PresetEnvConfig::Bool(_) => {
35 let PresetEnvConfigObj {
36 include,
37 exclude,
38 options: _,
39 assumptions: _,
40 } = PresetEnvConfigObj::default();
41
42 (
43 swc_ecma_preset_env::Config {
44 mode: Some(Mode::Usage),
45 targets: Some(Targets::Query(Query::Single("ie >= 9".to_string()))),
46 ..Default::default()
47 },
48 include,
49 exclude,
50 Default::default(),
51 )
52 }
53 PresetEnvConfig::Obj(obj) => {
54 let options = &obj.options;
55 let mut user_config: swc_ecma_preset_env::Config =
56 serde_json::from_value(*options.clone()).unwrap();
57 user_config.mode = user_config.mode.or(Some(Mode::Usage));
58 user_config.targets = user_config
59 .targets
60 .or(Some(Targets::Query(Query::Single("ie >= 9".to_string()))));
61 let user_assumption: Assumptions =
62 serde_json::from_value(*obj.assumptions.clone()).unwrap();
63 (
64 user_config,
65 obj.include.clone(),
66 obj.exclude.clone(),
67 user_assumption,
68 )
69 }
70 };
71
72 Self {
73 config,
74 include,
75 exclude,
76 assumptions,
77 enforce_exclude: vec![ConfigRegex::new("node_modules/core-js")],
78 }
79 }
80}
81
82impl Plugin for FarmPluginPolyfill {
83 fn name(&self) -> &str {
84 "FarmPluginPolyfill"
85 }
86 fn priority(&self) -> i32 {
88 i32::MIN
89 }
90
91 fn process_module(
92 &self,
93 param: &mut farmfe_core::plugin::PluginProcessModuleHookParam,
94 context: &std::sync::Arc<farmfe_core::context::CompilationContext>,
95 ) -> farmfe_core::error::Result<Option<()>> {
96 if !param.module_type.is_script() {
97 return Ok(None);
98 }
99
100 let relative_path = param.module_id.relative_path();
102
103 if !self.include.iter().any(|r| r.is_match(relative_path))
104 && self.exclude.iter().any(|r| r.is_match(relative_path))
105 {
106 return Ok(None);
107 }
108
109 if self
110 .enforce_exclude
111 .iter()
112 .any(|r| r.is_match(relative_path))
113 {
114 return Ok(None);
115 }
116
117 let (cm, _) = create_swc_source_map(Source {
118 path: PathBuf::from(¶m.module_id.to_string()),
119 content: param.content.clone(),
120 });
121 try_with(cm, &context.meta.script.globals, || {
122 let unresolved_mark = Mark::from_u32(param.meta.as_script().unresolved_mark);
123 let mut ast = param.meta.as_script_mut().take_ast();
124
125 let mut feature_flag = FeatureFlag::empty();
126 let comments: SingleThreadedComments = param.meta.as_script().comments.clone().into();
127 ast = ast.fold_with(&mut preset_env(
128 unresolved_mark,
129 Some(&comments),
130 self.config.clone(),
131 self.assumptions,
132 &mut feature_flag,
133 ));
134 ast.visit_mut_with(&mut inject_helpers(unresolved_mark));
135
136 param.meta.as_script_mut().set_ast(ast);
137 })?;
138
139 Ok(Some(()))
140 }
141}