Skip to content

Commit

Permalink
fix(webpack/ast): Fix span of null literals (#2925)
Browse files Browse the repository at this point in the history
swc_webpack_ast:
 - Preserve original spans for injected `null` literals
  • Loading branch information
kdy1 authored Dec 1, 2021
1 parent 86d2ceb commit 18d9fd9
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 13 deletions.
29 changes: 16 additions & 13 deletions crates/swc_webpack_ast/src/reducer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use swc_common::{
collections::AHashSet,
pass::{Repeat, Repeated},
util::take::Take,
Mark, SyntaxContext, DUMMY_SP,
Mark, Span, SyntaxContext, DUMMY_SP,
};
use swc_ecma_ast::*;
use swc_ecma_utils::{ident::IdentLike, Id, IsEmpty, StmtLike, StmtOrModuleItem};
Expand Down Expand Up @@ -509,7 +509,7 @@ impl VisitMut for ReduceAst {
match e {
Expr::Seq(seq) => {
if seq.exprs.is_empty() {
*e = null_expr();
*e = null_expr(seq.span);
return;
}

Expand All @@ -530,7 +530,8 @@ impl VisitMut for ReduceAst {
return;
}

*e = null_expr();
*e = null_expr(i.span);
return;
}

Expr::Member(MemberExpr {
Expand Down Expand Up @@ -559,7 +560,7 @@ impl VisitMut for ReduceAst {
if let Some(arg) = expr.arg.take() {
*e = *arg;
} else {
*e = null_expr();
*e = null_expr(expr.span);
return;
}
}
Expand Down Expand Up @@ -747,7 +748,7 @@ impl VisitMut for ReduceAst {
}

if el.opening.attrs.is_empty() && el.children.is_empty() {
*e = null_expr();
*e = null_expr(el.span);
return;
}
}
Expand Down Expand Up @@ -780,19 +781,20 @@ impl VisitMut for ReduceAst {
&& function.params.is_empty()
&& function.body.is_empty()
{
*e = null_expr();
*e = null_expr(function.span);
self.changed = true;
return;
}
}

Expr::Arrow(ArrowExpr {
span,
params,
body: BlockStmtOrExpr::BlockStmt(body),
..
}) => {
if !self.preserve_fn && params.is_empty() && body.is_empty() {
*e = null_expr();
*e = null_expr(*span);
self.changed = true;
return;
}
Expand All @@ -812,14 +814,15 @@ impl VisitMut for ReduceAst {
}

Expr::Call(CallExpr {
span,
callee: ExprOrSuper::Super(..),
args,
..
}) => {
self.changed = true;
let exprs: Vec<_> = args.take().into_iter().map(|arg| arg.expr).collect();
if exprs.is_empty() {
*e = null_expr();
*e = null_expr(*span);
return;
}
let seq = Expr::Seq(SeqExpr {
Expand Down Expand Up @@ -942,7 +945,7 @@ impl VisitMut for ReduceAst {

self.ignore_expr(&mut s.test);
if s.test.is_invalid() {
s.test = Box::new(null_expr());
s.test = Box::new(null_expr(s.span));
}
}

Expand Down Expand Up @@ -1665,7 +1668,7 @@ impl VisitMut for ReduceAst {
self.ignore_expr(&mut ap.right);

if ap.right.is_invalid() {
ap.right = Box::new(null_expr());
ap.right = Box::new(null_expr(ap.span));
}
}
}
Expand Down Expand Up @@ -1693,7 +1696,7 @@ impl VisitMut for ReduceAst {
}

if had_init && v.init.is_none() && matches!(self.var_decl_kind, Some(VarDeclKind::Const)) {
v.init = Some(Box::new(null_expr()));
v.init = Some(Box::new(null_expr(v.span)));
}
}
}
Expand Down Expand Up @@ -1766,8 +1769,8 @@ fn left_most(e: &Expr) -> Option<Ident> {
}
}

fn null_expr() -> Expr {
Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))
fn null_expr(span: Span) -> Expr {
Expr::Lit(Lit::Null(Null { span }))
}

fn can_remove(e: &Expr) -> bool {
Expand Down
106 changes: 106 additions & 0 deletions crates/swc_webpack_ast/tests/fixture/css-escape/1/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
; (function (root, factory) {
// https://github.com/umdjs/umd/blob/master/returnExports.js
if (typeof exports == 'object') {
// For Node.js.
module.exports = factory(root);
} else if (typeof define == 'function' && define.amd) {
// For AMD. Register as an anonymous module.
define([], factory.bind(root, root));
} else {
// For browser globals (not exposing the function separately).
factory(root);
}
}(typeof global != 'undefined' ? global : this, function (root) {

if (root.CSS && root.CSS.escape) {
return root.CSS.escape;
}

// https://drafts.csswg.org/cssom/#serialize-an-identifier
var cssEscape = function (value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: there’s no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.

// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}

if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}

if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
index == 0 &&
length == 1 &&
codeUnit == 0x002D
) {
result += '\\' + string.charAt(index);
continue;
}

// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}

// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);

}
return result;
};

if (!root.CSS) {
root.CSS = {};
}

root.CSS.escape = cssEscape;
return cssEscape;

}));
2 changes: 2 additions & 0 deletions crates/swc_webpack_ast/tests/fixture/css-escape/1/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if (null) module.exports;
else if (define, define.amd) define(null, null);

1 comment on commit 18d9fd9

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 18d9fd9 Previous: 563c63c Ratio
base_tr_fixer 30105 ns/iter (± 5204) 22857 ns/iter (± 351) 1.32
base_tr_resolver_and_hygiene 173993 ns/iter (± 60784) 131173 ns/iter (± 26278) 1.33
codegen_es2015 61546 ns/iter (± 14946) 51346 ns/iter (± 1186) 1.20
codegen_es2016 62359 ns/iter (± 11305) 51610 ns/iter (± 333) 1.21
codegen_es2017 61304 ns/iter (± 9930) 51492 ns/iter (± 397) 1.19
codegen_es2018 63365 ns/iter (± 10790) 51879 ns/iter (± 400) 1.22
codegen_es2019 59751 ns/iter (± 8190) 51591 ns/iter (± 440) 1.16
codegen_es2020 61291 ns/iter (± 14027) 51719 ns/iter (± 508) 1.19
codegen_es3 59460 ns/iter (± 9237) 51613 ns/iter (± 537) 1.15
codegen_es5 60442 ns/iter (± 14540) 51768 ns/iter (± 351) 1.17
full_es2015 220860392 ns/iter (± 49756034) 185479122 ns/iter (± 8126862) 1.19
full_es2016 167947647 ns/iter (± 17015222) 149843528 ns/iter (± 8696274) 1.12
full_es2017 181840738 ns/iter (± 16519428) 164892517 ns/iter (± 12101773) 1.10
full_es2018 179723806 ns/iter (± 17790761) 160422201 ns/iter (± 9464018) 1.12
full_es2019 181594482 ns/iter (± 21107369) 156670700 ns/iter (± 9787924) 1.16
full_es2020 180593390 ns/iter (± 16258526) 156392062 ns/iter (± 8160785) 1.15
full_es3 256105802 ns/iter (± 23775278) 224933143 ns/iter (± 10878500) 1.14
full_es5 233754318 ns/iter (± 22125785) 205231151 ns/iter (± 10320572) 1.14
parser 885039 ns/iter (± 203829) 698345 ns/iter (± 24731) 1.27
ser_ast_node 177 ns/iter (± 53) 151 ns/iter (± 3) 1.17
ser_serde 166 ns/iter (± 29) 150 ns/iter (± 2) 1.11
emit_colors 12224066 ns/iter (± 7482329) 18858168 ns/iter (± 25047941) 0.65
emit_large 116267004 ns/iter (± 179693379) 119687318 ns/iter (± 177198232) 0.97
base_clone 2821773 ns/iter (± 623243) 2568496 ns/iter (± 141306) 1.10
fold_span 4767813 ns/iter (± 1104260) 4167106 ns/iter (± 188993) 1.14
fold_span_panic 5103649 ns/iter (± 1419462) 4397477 ns/iter (± 409179) 1.16
visit_mut_span 3507945 ns/iter (± 633470) 3175127 ns/iter (± 289324) 1.10
visit_mut_span_panic 3391416 ns/iter (± 808712) 3343531 ns/iter (± 278916) 1.01
ast_clone 23347 ns/iter (± 4526) 17522 ns/iter (± 106) 1.33
ast_clone_to_stable 72943 ns/iter (± 13694) 52041 ns/iter (± 459) 1.40
ast_clone_to_stable_then_to_unstable 134162 ns/iter (± 28090) 95196 ns/iter (± 582) 1.41
json_deserialize 2496438 ns/iter (± 614026) 1911439 ns/iter (± 19386) 1.31
json_serialize 104377 ns/iter (± 22954) 92469 ns/iter (± 823) 1.13
boxing_boxed 143 ns/iter (± 28) 125 ns/iter (± 1) 1.14
boxing_boxed_clone 74 ns/iter (± 13) 67 ns/iter (± 0) 1.10
boxing_unboxed 132 ns/iter (± 33) 110 ns/iter (± 0) 1.20
boxing_unboxed_clone 71 ns/iter (± 15) 62 ns/iter (± 0) 1.15
time_10 353 ns/iter (± 80) 316 ns/iter (± 2) 1.12
time_15 771 ns/iter (± 142) 669 ns/iter (± 3) 1.15
time_20 1383 ns/iter (± 226) 1284 ns/iter (± 3) 1.08
time_40 5159 ns/iter (± 822) 6564 ns/iter (± 38) 0.79
time_5 109 ns/iter (± 16) 100 ns/iter (± 0) 1.09
time_60 11100 ns/iter (± 1963) 15089 ns/iter (± 247) 0.74

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.