next_custom_transforms/transforms/fonts/
mod.rs1use rustc_hash::{FxHashMap, FxHashSet};
2use serde::Deserialize;
3use swc_core::{
4 common::{BytePos, Spanned},
5 ecma::{
6 ast::{Id, ModuleItem, Pass},
7 atoms::Atom,
8 visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitWith},
9 },
10};
11
12mod find_functions_outside_module_scope;
13mod font_functions_collector;
14mod font_imports_generator;
15
16#[derive(Clone, Debug, Deserialize)]
17#[serde(deny_unknown_fields, rename_all = "camelCase")]
18pub struct Config {
19 pub font_loaders: Vec<Atom>,
20 pub relative_file_path_from_root: Atom,
21}
22
23pub fn next_font_loaders(config: Config) -> impl Pass + VisitMut {
24 visit_mut_pass(NextFontLoaders {
25 config,
26 state: State {
27 ..Default::default()
28 },
29 })
30}
31
32#[derive(Debug)]
33pub struct FontFunction {
34 loader: Atom,
35 function_name: Option<Atom>,
36}
37#[derive(Debug, Default)]
38pub struct State {
39 font_functions: FxHashMap<Id, FontFunction>,
40 removeable_module_items: FxHashSet<BytePos>,
41 font_imports: Vec<ModuleItem>,
42 font_exports: Vec<ModuleItem>,
43 font_functions_in_allowed_scope: FxHashSet<BytePos>,
44}
45
46struct NextFontLoaders {
47 config: Config,
48 state: State,
49}
50
51impl VisitMut for NextFontLoaders {
52 noop_visit_mut_type!();
53
54 fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
55 let mut functions_collector = font_functions_collector::FontFunctionsCollector {
57 font_loaders: &self.config.font_loaders,
58 state: &mut self.state,
59 };
60 items.visit_with(&mut functions_collector);
61
62 if !self.state.removeable_module_items.is_empty() {
63 let mut import_generator = font_imports_generator::FontImportsGenerator {
65 state: &mut self.state,
66 relative_path: &self.config.relative_file_path_from_root,
67 };
68 items.visit_with(&mut import_generator);
69
70 let mut wrong_scope =
72 find_functions_outside_module_scope::FindFunctionsOutsideModuleScope {
73 state: &self.state,
74 };
75 items.visit_with(&mut wrong_scope);
76
77 fn is_removable(ctx: &NextFontLoaders, item: &ModuleItem) -> bool {
78 ctx.state.removeable_module_items.contains(&item.span_lo())
79 }
80
81 let first_removable_index = items
82 .iter()
83 .position(|item| is_removable(self, item))
84 .unwrap();
85
86 items.retain(|item| !is_removable(self, item));
88
89 items.splice(
91 first_removable_index..first_removable_index,
92 std::mem::take(&mut self.state.font_imports),
93 );
94 items.append(&mut self.state.font_exports);
95 }
96 }
97}