1use serde_json::Value;
2use swc_core::{
3 atoms::Wtf8Atom,
4 common::{errors::HANDLER, Spanned, DUMMY_SP},
5 ecma::{
6 ast::*,
7 visit::{noop_visit_type, Visit},
8 },
9};
10
11pub struct FontImportsGenerator<'a> {
12 pub state: &'a mut super::State,
13 pub relative_path: &'a str,
14}
15
16impl FontImportsGenerator<'_> {
17 fn check_call_expr(
18 &mut self,
19 call_expr: &CallExpr,
20 variable_name: &Result<Ident, &Pat>,
21 ) -> Option<ImportDecl> {
22 if let Callee::Expr(callee_expr) = &call_expr.callee {
23 if let Expr::Ident(ident) = &**callee_expr {
24 if let Some(font_function) = self.state.font_functions.get(&ident.to_id()) {
25 self.state
26 .font_functions_in_allowed_scope
27 .insert(ident.span.lo);
28
29 let json: Result<Vec<Value>, ()> = call_expr
30 .args
31 .iter()
32 .map(|expr_or_spread| {
33 if let Some(span) = expr_or_spread.spread {
34 HANDLER.with(|handler| {
35 handler
36 .struct_span_err(span, "Font loaders don't accept spreads")
37 .emit()
38 });
39 }
40
41 expr_to_json(&expr_or_spread.expr)
42 })
43 .collect();
44
45 if let Ok(json) = json {
46 let function_name = match &font_function.function_name {
47 Some(function) => String::from(&**function),
48 None => String::new(),
49 };
50 let mut query_json_values = serde_json::Map::new();
51 query_json_values.insert(
52 String::from("path"),
53 Value::String(self.relative_path.to_string()),
54 );
55 query_json_values
56 .insert(String::from("import"), Value::String(function_name));
57 query_json_values.insert(String::from("arguments"), Value::Array(json));
58 if let Ok(ident) = variable_name {
59 query_json_values.insert(
60 String::from("variableName"),
61 Value::String(ident.sym.to_string()),
62 );
63 }
64
65 let query_json = Value::Object(query_json_values);
66
67 return Some(ImportDecl {
68 src: Box::new(Str {
69 value: Wtf8Atom::from(format!(
70 "{}/target.css?{}",
71 font_function.loader.to_string_lossy(),
72 query_json
73 )),
74 raw: None,
75 span: DUMMY_SP,
76 }),
77 specifiers: vec![],
78 type_only: false,
79 with: None,
80 span: DUMMY_SP,
81 phase: Default::default(),
82 });
83 }
84 }
85 }
86 }
87
88 None
89 }
90
91 fn check_var_decl(&mut self, var_decl: &VarDecl) -> Option<Ident> {
92 if let Some(decl) = var_decl.decls.first() {
93 let ident = match &decl.name {
94 Pat::Ident(ident) => Ok(ident.id.clone()),
95 pattern => Err(pattern),
96 };
97 if let Some(expr) = &decl.init {
98 if let Expr::Call(call_expr) = &**expr {
99 let import_decl = self.check_call_expr(call_expr, &ident);
100
101 if let Some(mut import_decl) = import_decl {
102 match var_decl.kind {
103 VarDeclKind::Const => {}
104 _ => {
105 HANDLER.with(|handler| {
106 handler
107 .struct_span_err(
108 var_decl.span,
109 "Font loader calls must be assigned to a const",
110 )
111 .emit()
112 });
113 }
114 }
115
116 match ident {
117 Ok(ident) => {
118 import_decl.specifiers =
119 vec![ImportSpecifier::Default(ImportDefaultSpecifier {
120 span: DUMMY_SP,
121 local: ident.clone(),
122 })];
123
124 self.state
125 .font_imports
126 .push(ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)));
127
128 return Some(ident);
129 }
130 Err(pattern) => {
131 HANDLER.with(|handler| {
132 handler
133 .struct_span_err(
134 pattern.span(),
135 "Font loader calls must be assigned to an identifier",
136 )
137 .emit()
138 });
139 }
140 }
141 }
142 }
143 }
144 }
145 None
146 }
147}
148
149impl Visit for FontImportsGenerator<'_> {
…lines 150–153 unchanged (4 lines)
154 ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))) => {
155 if self.check_var_decl(var_decl).is_some() {
156 self.state.removable_module_items.insert(var_decl.span.lo);
157 }
158 }
159 ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
160 if let Decl::Var(var_decl) = &export_decl.decl {
161 if let Some(ident) = self.check_var_decl(var_decl) {
162 self.state
163 .removable_module_items
164 .insert(export_decl.span.lo);
165
166 self.state.font_exports.push(ModuleItem::ModuleDecl(
167 ModuleDecl::ExportNamed(NamedExport {
168 span: DUMMY_SP,
169 specifiers: vec![ExportSpecifier::Named(ExportNamedSpecifier {
170 orig: ModuleExportName::Ident(ident),
171 span: DUMMY_SP,
172 exported: None,
173 is_type_only: false,
174 })],
175 src: None,
176 type_only: false,
177 with: None,
178 }),
179 ));
180 }
181 }
182 }
183 _ => {}
184 }
185 }
186}
187
…lines 188–275 unchanged (88 lines)