Code view:

A painting is a person's account of this edit as text, recorded independently of the node mapping - a rendering often has several equally defensible answers where the mapping has one. Deletions and insertions carry no position on the opposite side in a painting, so that panel draws no caret for them.

Before

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)

After

1use serde_json::Value;
2use swc_core::{
3 atoms::Wtf8Atom,
4 common::{DUMMY_SP, Spanned, errors::HANDLER},
5 ecma::{
6 ast::*,
7 visit::{Visit, noop_visit_type},
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 && let Expr::Ident(ident) = &**callee_expr
24 && let Some(font_function) = self.state.font_functions.get(&ident.to_id())
25 {
26 self.state
27 .font_functions_in_allowed_scope
28 .insert(ident.span.lo);
29
30 let json: Result<Vec<Value>, ()> = call_expr
31 .args
32 .iter()
33 .map(|expr_or_spread| {
34 if let Some(span) = expr_or_spread.spread {
35 HANDLER.with(|handler| {
36 handler
37 .struct_span_err(span, "Font loaders don't accept spreads")
38 .emit()
39 });
40 }
41
42 expr_to_json(&expr_or_spread.expr)
43 })
44 .collect();
45
46 if let Ok(json) = json {
47 let function_name = match &font_function.function_name {
48 Some(function) => String::from(&**function),
49 None => String::new(),
50 };
51 let mut query_json_values = serde_json::Map::new();
52 query_json_values.insert(
53 String::from("path"),
54 Value::String(self.relative_path.to_string()),
55 );
56 query_json_values.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 None
87 }
88
89 fn check_var_decl(&mut self, var_decl: &VarDecl) -> Option<Ident> {
90 if let Some(decl) = var_decl.decls.first() {
91 let ident = match &decl.name {
92 Pat::Ident(ident) => Ok(ident.id.clone()),
93 pattern => Err(pattern),
94 };
95 if let Some(expr) = &decl.init
96 && let Expr::Call(call_expr) = &**expr
97 {
98 let import_decl = self.check_call_expr(call_expr, &ident);
99
100 if let Some(mut import_decl) = import_decl {
101 match var_decl.kind {
102 VarDeclKind::Const => {}
103 _ => {
104 HANDLER.with(|handler| {
105 handler
106 .struct_span_err(
107 var_decl.span,
108 "Font loader calls must be assigned to a const",
109 )
110 .emit()
111 });
112 }
113 }
114
115 match ident {
116 Ok(ident) => {
117 import_decl.specifiers =
118 vec![ImportSpecifier::Default(ImportDefaultSpecifier {
119 span: DUMMY_SP,
120 local: ident.clone(),
121 })];
122
123 self.state
124 .font_imports
125 .push(ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)));
126
127 return Some(ident);
128 }
129 Err(pattern) => {
130 HANDLER.with(|handler| {
131 handler
132 .struct_span_err(
133 pattern.span(),
134 "Font loader calls must be assigned to an identifier",
135 )
136 .emit()
137 });
138 }
139 }
140 }
141 }
142 }
143 None
144 }
145}
146
147impl Visit for FontImportsGenerator<'_> {
…lines 148–152 unchanged (5 lines)
153 if self.check_var_decl(var_decl).is_some() {
154 self.state.removable_module_items.insert(var_decl.span.lo);
155 }
156 }
157 ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
158 if let Decl::Var(var_decl) = &export_decl.decl
159 && let Some(ident) = self.check_var_decl(var_decl)
160 {
161 self.state
162 .removable_module_items
163 .insert(export_decl.span.lo);
164
165 self.state
166 .font_exports
167 .push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
168 NamedExport {
169 span: DUMMY_SP,
170 specifiers: vec![ExportSpecifier::Named(ExportNamedSpecifier {
171 orig: ModuleExportName::Ident(ident),
172 span: DUMMY_SP,
173 exported: None,
174 is_type_only: false,
175 })],
176 src: None,
177 type_only: false,
178 with: None,
179 },
180 )));
181 }
182 }
183 _ => {}
184 }
185 }
186}
187
…lines 188–275 unchanged (88 lines)

Before

source_file
use_declaration
use "use"
scoped_identifier
identifier "serde_json"
:: "::"
identifier "Value"
; ";"
use_declaration
use "use"
scoped_use_list
identifier "swc_core"
:: "::"
use_list
{ "{"
scoped_identifier
identifier "atoms"
:: "::"
identifier "Wtf8Atom"
, ","
scoped_use_list
identifier "common"
:: "::"
use_list
{ "{"
scoped_identifier
identifier "errors"
:: "::"
identifier "HANDLER"
, ","
identifier "Spanned"
, ","
identifier "DUMMY_SP"
} "}"
, ","
scoped_use_list
identifier "ecma"
:: "::"
use_list
{ "{"
use_wildcard
identifier "ast"
:: "::"
* "*"
, ","
scoped_use_list
identifier "visit"
:: "::"
use_list
{ "{"
identifier "noop_visit_type"
, ","
identifier "Visit"
} "}"
, ","
} "}"
, ","
} "}"
; ";"
struct_item (+43 nodes collapsed)
impl_item
impl "impl"
generic_type
type_identifier "FontImportsGenerator"
type_arguments
< "<"
lifetime
' "'"
identifier "_"
> ">"
declaration_list
{ "{"
function_item
fn "fn"
identifier "check_call_expr"
parameters (+31 nodes collapsed)
-> "->"
generic_type
type_identifier "Option"
type_arguments
< "<"
type_identifier "ImportDecl"
> ">"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Callee"
:: "::"
identifier "Expr"
( "("
identifier "callee_expr"
) ")"
= "="
reference_expression
& "&"
field_expression
identifier "call_expr"
. "."
field_identifier "callee"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Expr"
:: "::"
identifier "Ident"
( "("
identifier "ident"
) ")"
= "="
reference_expression
& "&"
unary_expression
* "*"
unary_expression
* "*"
identifier "callee_expr"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition (+32 nodes collapsed)
block (+524 nodes collapsed)
} "}"
} "}"
identifier "None"
} "}"
function_item
fn "fn"
identifier "check_var_decl"
parameters
( "("
self_parameter
& "&"
mutable_specifier "mut"
self "self"
, ","
parameter
identifier "var_decl"
: ":"
reference_type
& "&"
type_identifier "VarDecl"
) ")"
-> "->"
generic_type
type_identifier "Option"
type_arguments
< "<"
type_identifier "Ident"
> ">"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
identifier "Some"
( "("
identifier "decl"
) ")"
= "="
call_expression
field_expression
field_expression
identifier "var_decl"
. "."
field_identifier "decls"
. "."
field_identifier "first"
arguments
( "("
) ")"
block
{ "{"
let_declaration (+55 nodes collapsed)
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
identifier "Some"
( "("
identifier "expr"
) ")"
= "="
reference_expression
& "&"
field_expression
identifier "decl"
. "."
field_identifier "init"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Expr"
:: "::"
identifier "Call"
( "("
identifier "call_expr"
) ")"
= "="
reference_expression
& "&"
unary_expression
* "*"
unary_expression
* "*"
identifier "expr"
block (+264 nodes collapsed)
} "}"
} "}"
identifier "None"
} "}"
} "}"
impl_item
impl "impl"
type_identifier "Visit"
for "for"
generic_type
type_identifier "FontImportsGenerator"
type_arguments
< "<"
lifetime
' "'"
identifier "_"
> ">"
declaration_list
{ "{"
macro_invocation
identifier "noop_visit_type"
! "!"
token_tree
( "("
) ")"
empty_statement
; ";"
function_item
fn "fn"
identifier "visit_module_item"
parameters
( "("
self_parameter
& "&"
mutable_specifier "mut"
self "self"
, ","
parameter
identifier "item"
: ":"
reference_type
& "&"
type_identifier "ModuleItem"
) ")"
block
{ "{"
expression_statement
match_expression
match "match"
identifier "item"
match_block
{ "{"
match_arm (+73 nodes collapsed)
match_arm
match_pattern
tuple_struct_pattern
scoped_identifier
identifier "ModuleItem"
:: "::"
identifier "ModuleDecl"
( "("
tuple_struct_pattern
scoped_identifier
identifier "ModuleDecl"
:: "::"
identifier "ExportDecl"
( "("
identifier "export_decl"
) ")"
) ")"
=> "=>"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Decl"
:: "::"
identifier "Var"
( "("
identifier "var_decl"
) ")"
= "="
reference_expression
& "&"
field_expression
identifier "export_decl"
. "."
field_identifier "decl"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
identifier "Some"
( "("
identifier "ident"
) ")"
= "="
call_expression
field_expression
self "self"
. "."
field_identifier "check_var_decl"
arguments
( "("
identifier "var_decl"
) ")"
block
{ "{"
expression_statement (+23 nodes collapsed)
expression_statement
call_expression
field_expression
field_expression
field_expression
self "self"
. "."
field_identifier "state"
. "."
field_identifier "font_exports"
. "."
field_identifier "push"
arguments
( "("
call_expression
scoped_identifier
identifier "ModuleItem"
:: "::"
identifier "ModuleDecl"
arguments
( "("
call_expression
scoped_identifier
identifier "ModuleDecl"
:: "::"
identifier "ExportNamed"
arguments
( "("
struct_expression (+69 nodes collapsed)
) ")"
, ","
) ")"
) ")"
; ";"
} "}"
} "}"
} "}"
match_arm
match_pattern
_ "_"
=> "=>"
block
{ "{"
} "}"
} "}"
} "}"
} "}"
function_item (+375 nodes collapsed)
function_item (+513 nodes collapsed)

After

source_file
use_declaration
use "use"
scoped_identifier
identifier "serde_json"
:: "::"
identifier "Value"
; ";"
use_declaration
use "use"
scoped_use_list
identifier "swc_core"
:: "::"
use_list
{ "{"
scoped_identifier
identifier "atoms"
:: "::"
identifier "Wtf8Atom"
, ","
scoped_use_list
identifier "common"
:: "::"
use_list
{ "{"
identifier "DUMMY_SP"
, ","
identifier "Spanned"
, ","
scoped_identifier
identifier "errors"
:: "::"
identifier "HANDLER"
} "}"
, ","
scoped_use_list
identifier "ecma"
:: "::"
use_list
{ "{"
use_wildcard
identifier "ast"
:: "::"
* "*"
, ","
scoped_use_list
identifier "visit"
:: "::"
use_list
{ "{"
identifier "Visit"
, ","
identifier "noop_visit_type"
} "}"
, ","
} "}"
, ","
} "}"
; ";"
struct_item (+43 nodes collapsed)
impl_item
impl "impl"
generic_type
type_identifier "FontImportsGenerator"
type_arguments
< "<"
lifetime
' "'"
identifier "_"
> ">"
declaration_list
{ "{"
function_item
fn "fn"
identifier "check_call_expr"
parameters (+31 nodes collapsed)
-> "->"
generic_type
type_identifier "Option"
type_arguments
< "<"
type_identifier "ImportDecl"
> ">"
block
{ "{"
expression_statement
if_expression
if "if"
let_chain
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Callee"
:: "::"
identifier "Expr"
( "("
identifier "callee_expr"
) ")"
= "="
reference_expression
& "&"
field_expression
identifier "call_expr"
. "."
field_identifier "callee"
&& "&&"
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Expr"
:: "::"
identifier "Ident"
( "("
identifier "ident"
) ")"
= "="
reference_expression
& "&"
unary_expression
* "*"
unary_expression
* "*"
identifier "callee_expr"
&& "&&"
let_condition (+32 nodes collapsed)
block (+524 nodes collapsed)
identifier "None"
} "}"
function_item
fn "fn"
identifier "check_var_decl"
parameters
( "("
self_parameter
& "&"
mutable_specifier "mut"
self "self"
, ","
parameter
identifier "var_decl"
: ":"
reference_type
& "&"
type_identifier "VarDecl"
) ")"
-> "->"
generic_type
type_identifier "Option"
type_arguments
< "<"
type_identifier "Ident"
> ">"
block
{ "{"
expression_statement
if_expression
if "if"
let_condition
let "let"
tuple_struct_pattern
identifier "Some"
( "("
identifier "decl"
) ")"
= "="
call_expression
field_expression
field_expression
identifier "var_decl"
. "."
field_identifier "decls"
. "."
field_identifier "first"
arguments
( "("
) ")"
block
{ "{"
let_declaration (+55 nodes collapsed)
expression_statement
if_expression
if "if"
let_chain
let_condition
let "let"
tuple_struct_pattern
identifier "Some"
( "("
identifier "expr"
) ")"
= "="
reference_expression
& "&"
field_expression
identifier "decl"
. "."
field_identifier "init"
&& "&&"
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Expr"
:: "::"
identifier "Call"
( "("
identifier "call_expr"
) ")"
= "="
reference_expression
& "&"
unary_expression
* "*"
unary_expression
* "*"
identifier "expr"
block (+264 nodes collapsed)
} "}"
identifier "None"
} "}"
} "}"
impl_item
impl "impl"
type_identifier "Visit"
for "for"
generic_type
type_identifier "FontImportsGenerator"
type_arguments
< "<"
lifetime
' "'"
identifier "_"
> ">"
declaration_list
{ "{"
macro_invocation
identifier "noop_visit_type"
! "!"
token_tree
( "("
) ")"
empty_statement
; ";"
function_item
fn "fn"
identifier "visit_module_item"
parameters
( "("
self_parameter
& "&"
mutable_specifier "mut"
self "self"
, ","
parameter
identifier "item"
: ":"
reference_type
& "&"
type_identifier "ModuleItem"
) ")"
block
{ "{"
expression_statement
match_expression
match "match"
identifier "item"
match_block
{ "{"
match_arm (+73 nodes collapsed)
match_arm
match_pattern
tuple_struct_pattern
scoped_identifier
identifier "ModuleItem"
:: "::"
identifier "ModuleDecl"
( "("
tuple_struct_pattern
scoped_identifier
identifier "ModuleDecl"
:: "::"
identifier "ExportDecl"
( "("
identifier "export_decl"
) ")"
) ")"
=> "=>"
block
{ "{"
expression_statement
if_expression
if "if"
let_chain
let_condition
let "let"
tuple_struct_pattern
scoped_identifier
identifier "Decl"
:: "::"
identifier "Var"
( "("
identifier "var_decl"
) ")"
= "="
reference_expression
& "&"
field_expression
identifier "export_decl"
. "."
field_identifier "decl"
&& "&&"
let_condition
let "let"
tuple_struct_pattern
identifier "Some"
( "("
identifier "ident"
) ")"
= "="
call_expression
field_expression
self "self"
. "."
field_identifier "check_var_decl"
arguments
( "("
identifier "var_decl"
) ")"
block
{ "{"
expression_statement (+23 nodes collapsed)
expression_statement
call_expression
field_expression
field_expression
field_expression
self "self"
. "."
field_identifier "state"
. "."
field_identifier "font_exports"
. "."
field_identifier "push"
arguments
( "("
call_expression
scoped_identifier
identifier "ModuleItem"
:: "::"
identifier "ModuleDecl"
arguments
( "("
call_expression
scoped_identifier
identifier "ModuleDecl"
:: "::"
identifier "ExportNamed"
arguments
( "("
struct_expression (+69 nodes collapsed)
, ","
) ")"
) ")"
) ")"
; ";"
} "}"
} "}"
match_arm
match_pattern
_ "_"
=> "=>"
block
{ "{"
} "}"
} "}"
} "}"
} "}"
function_item (+375 nodes collapsed)
function_item (+513 nodes collapsed)