terser 5.44.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/bundle.min.js +74 -52
- package/lib/compress/common.js +2 -2
- package/lib/compress/index.js +49 -36
- package/lib/compress/inline.js +8 -9
- package/lib/compress/reduce-vars.js +3 -4
- package/lib/compress/tighten-body.js +9 -8
- package/lib/utils/index.js +11 -1
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v5.45.0
|
|
4
|
+
|
|
5
|
+
- Produce `void 0` instead of `undefined`, which is more safe
|
|
6
|
+
|
|
7
|
+
## v5.44.1
|
|
8
|
+
|
|
9
|
+
- fix bitwise optimization changing the result of `&&`, `||`
|
|
10
|
+
- switches: make sure `var` is extracted from a deleted default case
|
|
11
|
+
|
|
3
12
|
## v5.44.0
|
|
4
13
|
|
|
5
14
|
- Support `using` and `await using` declarations (#1635)
|
package/dist/bundle.min.js
CHANGED
|
@@ -132,6 +132,15 @@ function make_node(ctor, orig, props) {
|
|
|
132
132
|
return new ctor(props);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/** Makes a `void 0` expression. Use instead of AST_Undefined which may conflict
|
|
136
|
+
* with an existing variable called `undefined` */
|
|
137
|
+
function make_void_0(orig) {
|
|
138
|
+
return make_node(AST_UnaryPrefix, orig, {
|
|
139
|
+
operator: "void",
|
|
140
|
+
expression: make_node(AST_Number, orig, { value: 0 })
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
135
144
|
function push_uniq(array, el) {
|
|
136
145
|
if (!array.includes(el))
|
|
137
146
|
array.push(el);
|
|
@@ -13558,7 +13567,7 @@ function make_node_from_constant(val, orig) {
|
|
|
13558
13567
|
case "boolean":
|
|
13559
13568
|
return make_node(val ? AST_True : AST_False, orig);
|
|
13560
13569
|
case "undefined":
|
|
13561
|
-
return
|
|
13570
|
+
return make_void_0(orig);
|
|
13562
13571
|
default:
|
|
13563
13572
|
if (val === null) {
|
|
13564
13573
|
return make_node(AST_Null, orig, { value: null });
|
|
@@ -16408,7 +16417,7 @@ function safe_to_read(tw, def) {
|
|
|
16408
16417
|
if (def.fixed == null) {
|
|
16409
16418
|
var orig = def.orig[0];
|
|
16410
16419
|
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
|
16411
|
-
def.fixed =
|
|
16420
|
+
def.fixed = make_void_0(orig);
|
|
16412
16421
|
}
|
|
16413
16422
|
return true;
|
|
16414
16423
|
}
|
|
@@ -16706,7 +16715,7 @@ function mark_lambda(tw, descend, compressor) {
|
|
|
16706
16715
|
if (d.orig.length > 1) return;
|
|
16707
16716
|
if (d.fixed === undefined && (!this.uses_arguments || tw.has_directive("use strict"))) {
|
|
16708
16717
|
d.fixed = function() {
|
|
16709
|
-
return iife.args[i] ||
|
|
16718
|
+
return iife.args[i] || make_void_0(iife);
|
|
16710
16719
|
};
|
|
16711
16720
|
tw.loop_ids.set(d.id, tw.in_loop);
|
|
16712
16721
|
mark(tw, d, true);
|
|
@@ -17186,8 +17195,8 @@ function remove_initializers(var_statement) {
|
|
|
17186
17195
|
return decls.length ? make_node(AST_Var, var_statement, { definitions: decls }) : null;
|
|
17187
17196
|
}
|
|
17188
17197
|
|
|
17189
|
-
/** Called on code which
|
|
17190
|
-
function
|
|
17198
|
+
/** Called on code which won't be executed but has an effect outside of itself: `var`, `function` statements, `export`, `import`. */
|
|
17199
|
+
function extract_from_unreachable_code(compressor, stat, target) {
|
|
17191
17200
|
walk(stat, node => {
|
|
17192
17201
|
if (node instanceof AST_Var) {
|
|
17193
17202
|
const no_initializers = remove_initializers(node);
|
|
@@ -17212,7 +17221,8 @@ function trim_unreachable_code(compressor, stat, target) {
|
|
|
17212
17221
|
target.push(node);
|
|
17213
17222
|
return true;
|
|
17214
17223
|
}
|
|
17215
|
-
if (node instanceof AST_Scope) {
|
|
17224
|
+
if (node instanceof AST_Scope || node instanceof AST_Class) {
|
|
17225
|
+
// Do not go into nested scopes
|
|
17216
17226
|
return true;
|
|
17217
17227
|
}
|
|
17218
17228
|
});
|
|
@@ -17629,7 +17639,7 @@ function tighten_body(statements, compressor) {
|
|
|
17629
17639
|
}
|
|
17630
17640
|
} else {
|
|
17631
17641
|
if (!arg) {
|
|
17632
|
-
arg =
|
|
17642
|
+
arg = make_void_0(sym).transform(compressor);
|
|
17633
17643
|
} else if (arg instanceof AST_Lambda && arg.pinned()
|
|
17634
17644
|
|| has_overlapping_symbol(fn, arg, fn_strict)) {
|
|
17635
17645
|
arg = null;
|
|
@@ -17869,7 +17879,7 @@ function tighten_body(statements, compressor) {
|
|
|
17869
17879
|
found = true;
|
|
17870
17880
|
if (node instanceof AST_VarDef) {
|
|
17871
17881
|
node.value = node.name instanceof AST_SymbolConst
|
|
17872
|
-
?
|
|
17882
|
+
? make_void_0(node.value) // `const` always needs value.
|
|
17873
17883
|
: null;
|
|
17874
17884
|
return node;
|
|
17875
17885
|
}
|
|
@@ -18236,7 +18246,7 @@ function tighten_body(statements, compressor) {
|
|
|
18236
18246
|
CHANGED = n != len;
|
|
18237
18247
|
if (has_quit)
|
|
18238
18248
|
has_quit.forEach(function (stat) {
|
|
18239
|
-
|
|
18249
|
+
extract_from_unreachable_code(compressor, stat, statements);
|
|
18240
18250
|
});
|
|
18241
18251
|
}
|
|
18242
18252
|
|
|
@@ -18308,7 +18318,7 @@ function tighten_body(statements, compressor) {
|
|
|
18308
18318
|
var stat = statements[i];
|
|
18309
18319
|
if (prev) {
|
|
18310
18320
|
if (stat instanceof AST_Exit) {
|
|
18311
|
-
stat.value = cons_seq(stat.value ||
|
|
18321
|
+
stat.value = cons_seq(stat.value || make_void_0(stat).transform(compressor));
|
|
18312
18322
|
} else if (stat instanceof AST_For) {
|
|
18313
18323
|
if (!(stat.init instanceof AST_DefinitionsLike)) {
|
|
18314
18324
|
const abort = walk(prev.body, node => {
|
|
@@ -18812,7 +18822,7 @@ function inline_into_call(self, compressor) {
|
|
|
18812
18822
|
if (returned) {
|
|
18813
18823
|
returned = returned.clone(true);
|
|
18814
18824
|
} else {
|
|
18815
|
-
returned =
|
|
18825
|
+
returned = make_void_0(self);
|
|
18816
18826
|
}
|
|
18817
18827
|
const args = self.args.concat(returned);
|
|
18818
18828
|
return make_sequence(self, args).optimize(compressor);
|
|
@@ -18828,7 +18838,7 @@ function inline_into_call(self, compressor) {
|
|
|
18828
18838
|
&& returned.name === fn.argnames[0].name
|
|
18829
18839
|
) {
|
|
18830
18840
|
const replacement =
|
|
18831
|
-
(self.args[0] ||
|
|
18841
|
+
(self.args[0] || make_void_0()).optimize(compressor);
|
|
18832
18842
|
|
|
18833
18843
|
let parent;
|
|
18834
18844
|
if (
|
|
@@ -18910,7 +18920,7 @@ function inline_into_call(self, compressor) {
|
|
|
18910
18920
|
|
|
18911
18921
|
const can_drop_this_call = is_regular_func && compressor.option("side_effects") && fn.body.every(is_empty);
|
|
18912
18922
|
if (can_drop_this_call) {
|
|
18913
|
-
var args = self.args.concat(
|
|
18923
|
+
var args = self.args.concat(make_void_0(self));
|
|
18914
18924
|
return make_sequence(self, args).optimize(compressor);
|
|
18915
18925
|
}
|
|
18916
18926
|
|
|
@@ -18929,9 +18939,9 @@ function inline_into_call(self, compressor) {
|
|
|
18929
18939
|
return self;
|
|
18930
18940
|
|
|
18931
18941
|
function return_value(stat) {
|
|
18932
|
-
if (!stat) return
|
|
18942
|
+
if (!stat) return make_void_0(self);
|
|
18933
18943
|
if (stat instanceof AST_Return) {
|
|
18934
|
-
if (!stat.value) return
|
|
18944
|
+
if (!stat.value) return make_void_0(self);
|
|
18935
18945
|
return stat.value.clone(true);
|
|
18936
18946
|
}
|
|
18937
18947
|
if (stat instanceof AST_SimpleStatement) {
|
|
@@ -19077,7 +19087,7 @@ function inline_into_call(self, compressor) {
|
|
|
19077
19087
|
} else {
|
|
19078
19088
|
var symbol = make_node(AST_SymbolVar, name, name);
|
|
19079
19089
|
name.definition().orig.push(symbol);
|
|
19080
|
-
if (!value && in_loop) value =
|
|
19090
|
+
if (!value && in_loop) value = make_void_0(self);
|
|
19081
19091
|
append_var(decls, expressions, symbol, value);
|
|
19082
19092
|
}
|
|
19083
19093
|
}
|
|
@@ -19104,7 +19114,7 @@ function inline_into_call(self, compressor) {
|
|
|
19104
19114
|
operator: "=",
|
|
19105
19115
|
logical: false,
|
|
19106
19116
|
left: sym,
|
|
19107
|
-
right:
|
|
19117
|
+
right: make_void_0(name),
|
|
19108
19118
|
}));
|
|
19109
19119
|
}
|
|
19110
19120
|
}
|
|
@@ -19417,6 +19427,11 @@ class Compressor extends TreeWalker {
|
|
|
19417
19427
|
}
|
|
19418
19428
|
}
|
|
19419
19429
|
|
|
19430
|
+
/** True if compressor.self()'s result will be turned into a 32-bit integer.
|
|
19431
|
+
* ex:
|
|
19432
|
+
* ~{expr}
|
|
19433
|
+
* (1, 2, {expr}) | 0
|
|
19434
|
+
**/
|
|
19420
19435
|
in_32_bit_context(other_operand_must_be_number) {
|
|
19421
19436
|
if (!this.option("evaluate")) return false;
|
|
19422
19437
|
var self = this.self();
|
|
@@ -19434,9 +19449,10 @@ class Compressor extends TreeWalker {
|
|
|
19434
19449
|
if (
|
|
19435
19450
|
p instanceof AST_Binary
|
|
19436
19451
|
&& (
|
|
19437
|
-
p.
|
|
19438
|
-
|
|
19439
|
-
|| p.operator == "
|
|
19452
|
+
// Don't talk about p.left. Can change branch taken
|
|
19453
|
+
p.operator == "&&" && p.right === self
|
|
19454
|
+
|| p.operator == "||" && p.right === self
|
|
19455
|
+
|| p.operator == "??" && p.right === self
|
|
19440
19456
|
)
|
|
19441
19457
|
|| p instanceof AST_Conditional && p.condition !== self
|
|
19442
19458
|
|| p.tail_node() === self
|
|
@@ -19595,7 +19611,7 @@ AST_Toplevel.DEFMETHOD("drop_console", function(options) {
|
|
|
19595
19611
|
set_flag(exp.expression, SQUEEZED);
|
|
19596
19612
|
self.args = [];
|
|
19597
19613
|
} else {
|
|
19598
|
-
return
|
|
19614
|
+
return make_void_0(self);
|
|
19599
19615
|
}
|
|
19600
19616
|
}
|
|
19601
19617
|
});
|
|
@@ -19623,12 +19639,7 @@ AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) {
|
|
|
19623
19639
|
: make_node(AST_EmptyStatement, node);
|
|
19624
19640
|
}
|
|
19625
19641
|
return make_node(AST_SimpleStatement, node, {
|
|
19626
|
-
body: node.value ||
|
|
19627
|
-
operator: "void",
|
|
19628
|
-
expression: make_node(AST_Number, node, {
|
|
19629
|
-
value: 0
|
|
19630
|
-
})
|
|
19631
|
-
})
|
|
19642
|
+
body: node.value || make_void_0(node)
|
|
19632
19643
|
});
|
|
19633
19644
|
}
|
|
19634
19645
|
if (node instanceof AST_Class || node instanceof AST_Lambda && node !== self) {
|
|
@@ -20039,7 +20050,7 @@ function if_break_in_loop(self, compressor) {
|
|
|
20039
20050
|
body: self.condition
|
|
20040
20051
|
}));
|
|
20041
20052
|
}
|
|
20042
|
-
|
|
20053
|
+
extract_from_unreachable_code(compressor, self.body, body);
|
|
20043
20054
|
return make_node(AST_BlockStatement, self, {
|
|
20044
20055
|
body: body
|
|
20045
20056
|
});
|
|
@@ -20110,7 +20121,7 @@ def_optimize(AST_For, function(self, compressor) {
|
|
|
20110
20121
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
|
20111
20122
|
if (!cond) {
|
|
20112
20123
|
var body = [];
|
|
20113
|
-
|
|
20124
|
+
extract_from_unreachable_code(compressor, self.body, body);
|
|
20114
20125
|
if (self.init instanceof AST_Statement) {
|
|
20115
20126
|
body.push(self.init);
|
|
20116
20127
|
} else if (self.init) {
|
|
@@ -20146,7 +20157,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
|
20146
20157
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
|
20147
20158
|
if (!cond) {
|
|
20148
20159
|
var body = [];
|
|
20149
|
-
|
|
20160
|
+
extract_from_unreachable_code(compressor, self.body, body);
|
|
20150
20161
|
body.push(make_node(AST_SimpleStatement, self.condition, {
|
|
20151
20162
|
body: self.condition
|
|
20152
20163
|
}));
|
|
@@ -20159,7 +20170,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
|
20159
20170
|
}));
|
|
20160
20171
|
body.push(self.body);
|
|
20161
20172
|
if (self.alternative) {
|
|
20162
|
-
|
|
20173
|
+
extract_from_unreachable_code(compressor, self.alternative, body);
|
|
20163
20174
|
}
|
|
20164
20175
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
|
20165
20176
|
}
|
|
@@ -20231,8 +20242,8 @@ def_optimize(AST_If, function(self, compressor) {
|
|
|
20231
20242
|
return make_node(self.body.CTOR, self, {
|
|
20232
20243
|
value: make_node(AST_Conditional, self, {
|
|
20233
20244
|
condition : self.condition,
|
|
20234
|
-
consequent : self.body.value ||
|
|
20235
|
-
alternative : self.alternative.value ||
|
|
20245
|
+
consequent : self.body.value || make_void_0(self.body),
|
|
20246
|
+
alternative : self.alternative.value || make_void_0(self.alternative),
|
|
20236
20247
|
}).transform(compressor)
|
|
20237
20248
|
}).optimize(compressor);
|
|
20238
20249
|
}
|
|
@@ -20287,6 +20298,9 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
20287
20298
|
var body = [];
|
|
20288
20299
|
var default_branch;
|
|
20289
20300
|
var exact_match;
|
|
20301
|
+
// - compress self.body into `body`
|
|
20302
|
+
// - find and deduplicate default branch
|
|
20303
|
+
// - find the exact match (`case 1234` inside `switch(1234)`)
|
|
20290
20304
|
for (var i = 0, len = self.body.length; i < len && !exact_match; i++) {
|
|
20291
20305
|
branch = self.body[i];
|
|
20292
20306
|
if (branch instanceof AST_Default) {
|
|
@@ -20316,6 +20330,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
20316
20330
|
}
|
|
20317
20331
|
body.push(branch);
|
|
20318
20332
|
}
|
|
20333
|
+
// i < len if we found an exact_match. eliminate the rest
|
|
20319
20334
|
while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]);
|
|
20320
20335
|
self.body = body;
|
|
20321
20336
|
|
|
@@ -20387,7 +20402,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
20387
20402
|
let i = body.length - 1;
|
|
20388
20403
|
for (; i >= 0; i--) {
|
|
20389
20404
|
let bbody = body[i].body;
|
|
20390
|
-
|
|
20405
|
+
while (is_break(bbody[bbody.length - 1], compressor)) bbody.pop();
|
|
20391
20406
|
if (!is_inert_body(body[i])) break;
|
|
20392
20407
|
}
|
|
20393
20408
|
// i now points to the index of a branch that contains a body. By incrementing, it's
|
|
@@ -20403,9 +20418,9 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
20403
20418
|
let branch = body[j];
|
|
20404
20419
|
if (branch === default_or_exact) {
|
|
20405
20420
|
default_or_exact = null;
|
|
20406
|
-
body.pop();
|
|
20421
|
+
eliminate_branch(body.pop());
|
|
20407
20422
|
} else if (!branch.expression.has_side_effects(compressor)) {
|
|
20408
|
-
body.pop();
|
|
20423
|
+
eliminate_branch(body.pop());
|
|
20409
20424
|
} else {
|
|
20410
20425
|
break;
|
|
20411
20426
|
}
|
|
@@ -20519,15 +20534,16 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
20519
20534
|
// and there's a side-effect somewhere. Just let the below paths take care of it.
|
|
20520
20535
|
}
|
|
20521
20536
|
|
|
20537
|
+
// Reintegrate `decl` (var statements)
|
|
20522
20538
|
if (body.length > 0) {
|
|
20523
20539
|
body[0].body = decl.concat(body[0].body);
|
|
20524
20540
|
}
|
|
20525
|
-
|
|
20526
20541
|
if (body.length == 0) {
|
|
20527
20542
|
return make_node(AST_BlockStatement, self, {
|
|
20528
20543
|
body: decl.concat(statement(self.expression))
|
|
20529
20544
|
}).optimize(compressor);
|
|
20530
20545
|
}
|
|
20546
|
+
|
|
20531
20547
|
if (body.length == 1 && !has_nested_break(self)) {
|
|
20532
20548
|
// This is the last case body, and we've already pruned any breaks, so it's
|
|
20533
20549
|
// safe to hoist.
|
|
@@ -20607,7 +20623,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
20607
20623
|
if (prev && !aborts(prev)) {
|
|
20608
20624
|
prev.body = prev.body.concat(branch.body);
|
|
20609
20625
|
} else {
|
|
20610
|
-
|
|
20626
|
+
extract_from_unreachable_code(compressor, branch, decl);
|
|
20611
20627
|
}
|
|
20612
20628
|
}
|
|
20613
20629
|
function branches_equivalent(branch, prev, insertBreak) {
|
|
@@ -20661,7 +20677,7 @@ def_optimize(AST_Try, function(self, compressor) {
|
|
|
20661
20677
|
if (compressor.option("dead_code") && self.body.body.every(is_empty)) {
|
|
20662
20678
|
var body = [];
|
|
20663
20679
|
if (self.bcatch) {
|
|
20664
|
-
|
|
20680
|
+
extract_from_unreachable_code(compressor, self.bcatch, body);
|
|
20665
20681
|
}
|
|
20666
20682
|
if (self.bfinally) body.push(...self.bfinally.body);
|
|
20667
20683
|
return make_node(AST_BlockStatement, self, {
|
|
@@ -20780,7 +20796,7 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
|
20780
20796
|
const value = condition.evaluate(compressor);
|
|
20781
20797
|
|
|
20782
20798
|
if (value === 1 || value === true) {
|
|
20783
|
-
return
|
|
20799
|
+
return make_void_0(self).optimize(compressor);
|
|
20784
20800
|
}
|
|
20785
20801
|
}
|
|
20786
20802
|
}
|
|
@@ -21142,6 +21158,10 @@ def_optimize(AST_UnaryPrefix, function(self, compressor) {
|
|
|
21142
21158
|
) {
|
|
21143
21159
|
return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor);
|
|
21144
21160
|
}
|
|
21161
|
+
// Short-circuit common `void 0`
|
|
21162
|
+
if (self.operator === "void" && e instanceof AST_Number && e.value === 0) {
|
|
21163
|
+
return unsafe_undefined_ref(self, compressor) || self;
|
|
21164
|
+
}
|
|
21145
21165
|
var seq = self.lift_sequences(compressor);
|
|
21146
21166
|
if (seq !== self) {
|
|
21147
21167
|
return seq;
|
|
@@ -21152,7 +21172,7 @@ def_optimize(AST_UnaryPrefix, function(self, compressor) {
|
|
|
21152
21172
|
self.expression = e;
|
|
21153
21173
|
return self;
|
|
21154
21174
|
} else {
|
|
21155
|
-
return
|
|
21175
|
+
return make_void_0(self).optimize(compressor);
|
|
21156
21176
|
}
|
|
21157
21177
|
}
|
|
21158
21178
|
if (compressor.in_boolean_context()) {
|
|
@@ -21338,7 +21358,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
|
21338
21358
|
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
|
21339
21359
|
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
|
21340
21360
|
self.right = expr;
|
|
21341
|
-
self.left =
|
|
21361
|
+
self.left = make_void_0(self.left).optimize(compressor);
|
|
21342
21362
|
if (self.operator.length == 2) self.operator += "=";
|
|
21343
21363
|
}
|
|
21344
21364
|
} else if (compressor.option("typeofs")
|
|
@@ -21351,7 +21371,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
|
21351
21371
|
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
|
21352
21372
|
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
|
21353
21373
|
self.left = expr;
|
|
21354
|
-
self.right =
|
|
21374
|
+
self.right = make_void_0(self.right).optimize(compressor);
|
|
21355
21375
|
if (self.operator.length == 2) self.operator += "=";
|
|
21356
21376
|
}
|
|
21357
21377
|
} else if (self.left instanceof AST_SymbolRef
|
|
@@ -21992,7 +22012,8 @@ function is_atomic(lhs, self) {
|
|
|
21992
22012
|
return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
|
|
21993
22013
|
}
|
|
21994
22014
|
|
|
21995
|
-
|
|
22015
|
+
/** Apply the `unsafe_undefined` option: find a variable called `undefined` and turn `self` into a reference to it. */
|
|
22016
|
+
function unsafe_undefined_ref(self, compressor) {
|
|
21996
22017
|
if (compressor.option("unsafe_undefined")) {
|
|
21997
22018
|
var undef = find_variable(compressor, "undefined");
|
|
21998
22019
|
if (undef) {
|
|
@@ -22005,14 +22026,15 @@ def_optimize(AST_Undefined, function(self, compressor) {
|
|
|
22005
22026
|
return ref;
|
|
22006
22027
|
}
|
|
22007
22028
|
}
|
|
22029
|
+
return null;
|
|
22030
|
+
}
|
|
22031
|
+
|
|
22032
|
+
def_optimize(AST_Undefined, function(self, compressor) {
|
|
22033
|
+
var symbolref = unsafe_undefined_ref(self, compressor);
|
|
22034
|
+
if (symbolref) return symbolref;
|
|
22008
22035
|
var lhs = compressor.is_lhs();
|
|
22009
22036
|
if (lhs && is_atomic(lhs, self)) return self;
|
|
22010
|
-
return
|
|
22011
|
-
operator: "void",
|
|
22012
|
-
expression: make_node(AST_Number, self, {
|
|
22013
|
-
value: 0
|
|
22014
|
-
})
|
|
22015
|
-
});
|
|
22037
|
+
return make_void_0(self);
|
|
22016
22038
|
});
|
|
22017
22039
|
|
|
22018
22040
|
def_optimize(AST_Infinity, function(self, compressor) {
|
|
@@ -22699,7 +22721,7 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
|
22699
22721
|
}
|
|
22700
22722
|
}
|
|
22701
22723
|
if (retValue instanceof AST_Expansion) break FLATTEN;
|
|
22702
|
-
retValue = retValue instanceof AST_Hole ?
|
|
22724
|
+
retValue = retValue instanceof AST_Hole ? make_void_0(retValue) : retValue;
|
|
22703
22725
|
if (!flatten) values.unshift(retValue);
|
|
22704
22726
|
while (--i >= 0) {
|
|
22705
22727
|
var value = elements[i];
|
|
@@ -22738,7 +22760,7 @@ def_optimize(AST_Chain, function (self, compressor) {
|
|
|
22738
22760
|
if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") {
|
|
22739
22761
|
return make_node_from_constant(0, self);
|
|
22740
22762
|
}
|
|
22741
|
-
return
|
|
22763
|
+
return make_void_0(self).optimize(compressor);
|
|
22742
22764
|
}
|
|
22743
22765
|
if (
|
|
22744
22766
|
self.expression instanceof AST_PropAccess
|
package/lib/compress/common.js
CHANGED
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
walk_abort,
|
|
88
88
|
walk_parent,
|
|
89
89
|
} from "../ast.js";
|
|
90
|
-
import { make_node, regexp_source_fix, string_template, makePredicate } from "../utils/index.js";
|
|
90
|
+
import { make_node, make_void_0, regexp_source_fix, string_template, makePredicate } from "../utils/index.js";
|
|
91
91
|
import { first_in_statement } from "../utils/first_in_statement.js";
|
|
92
92
|
import { has_flag, TOP } from "./compressor-flags.js";
|
|
93
93
|
|
|
@@ -148,7 +148,7 @@ export function make_node_from_constant(val, orig) {
|
|
|
148
148
|
case "boolean":
|
|
149
149
|
return make_node(val ? AST_True : AST_False, orig);
|
|
150
150
|
case "undefined":
|
|
151
|
-
return
|
|
151
|
+
return make_void_0(orig);
|
|
152
152
|
default:
|
|
153
153
|
if (val === null) {
|
|
154
154
|
return make_node(AST_Null, orig, { value: null });
|
package/lib/compress/index.js
CHANGED
|
@@ -146,6 +146,7 @@ import {
|
|
|
146
146
|
defaults,
|
|
147
147
|
HOP,
|
|
148
148
|
make_node,
|
|
149
|
+
make_void_0,
|
|
149
150
|
makePredicate,
|
|
150
151
|
MAP,
|
|
151
152
|
remove,
|
|
@@ -211,7 +212,7 @@ import {
|
|
|
211
212
|
as_statement_array,
|
|
212
213
|
is_func_expr,
|
|
213
214
|
} from "./common.js";
|
|
214
|
-
import { tighten_body,
|
|
215
|
+
import { tighten_body, extract_from_unreachable_code } from "./tighten-body.js";
|
|
215
216
|
import { inline_into_symbolref, inline_into_call } from "./inline.js";
|
|
216
217
|
import "./global-defs.js";
|
|
217
218
|
|
|
@@ -378,6 +379,11 @@ class Compressor extends TreeWalker {
|
|
|
378
379
|
}
|
|
379
380
|
}
|
|
380
381
|
|
|
382
|
+
/** True if compressor.self()'s result will be turned into a 32-bit integer.
|
|
383
|
+
* ex:
|
|
384
|
+
* ~{expr}
|
|
385
|
+
* (1, 2, {expr}) | 0
|
|
386
|
+
**/
|
|
381
387
|
in_32_bit_context(other_operand_must_be_number) {
|
|
382
388
|
if (!this.option("evaluate")) return false;
|
|
383
389
|
var self = this.self();
|
|
@@ -395,9 +401,10 @@ class Compressor extends TreeWalker {
|
|
|
395
401
|
if (
|
|
396
402
|
p instanceof AST_Binary
|
|
397
403
|
&& (
|
|
398
|
-
p.
|
|
399
|
-
|
|
400
|
-
|| p.operator == "
|
|
404
|
+
// Don't talk about p.left. Can change branch taken
|
|
405
|
+
p.operator == "&&" && p.right === self
|
|
406
|
+
|| p.operator == "||" && p.right === self
|
|
407
|
+
|| p.operator == "??" && p.right === self
|
|
401
408
|
)
|
|
402
409
|
|| p instanceof AST_Conditional && p.condition !== self
|
|
403
410
|
|| p.tail_node() === self
|
|
@@ -556,7 +563,7 @@ AST_Toplevel.DEFMETHOD("drop_console", function(options) {
|
|
|
556
563
|
set_flag(exp.expression, SQUEEZED);
|
|
557
564
|
self.args = [];
|
|
558
565
|
} else {
|
|
559
|
-
return
|
|
566
|
+
return make_void_0(self);
|
|
560
567
|
}
|
|
561
568
|
}
|
|
562
569
|
});
|
|
@@ -584,12 +591,7 @@ AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) {
|
|
|
584
591
|
: make_node(AST_EmptyStatement, node);
|
|
585
592
|
}
|
|
586
593
|
return make_node(AST_SimpleStatement, node, {
|
|
587
|
-
body: node.value ||
|
|
588
|
-
operator: "void",
|
|
589
|
-
expression: make_node(AST_Number, node, {
|
|
590
|
-
value: 0
|
|
591
|
-
})
|
|
592
|
-
})
|
|
594
|
+
body: node.value || make_void_0(node)
|
|
593
595
|
});
|
|
594
596
|
}
|
|
595
597
|
if (node instanceof AST_Class || node instanceof AST_Lambda && node !== self) {
|
|
@@ -1000,7 +1002,7 @@ function if_break_in_loop(self, compressor) {
|
|
|
1000
1002
|
body: self.condition
|
|
1001
1003
|
}));
|
|
1002
1004
|
}
|
|
1003
|
-
|
|
1005
|
+
extract_from_unreachable_code(compressor, self.body, body);
|
|
1004
1006
|
return make_node(AST_BlockStatement, self, {
|
|
1005
1007
|
body: body
|
|
1006
1008
|
});
|
|
@@ -1071,7 +1073,7 @@ def_optimize(AST_For, function(self, compressor) {
|
|
|
1071
1073
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
|
1072
1074
|
if (!cond) {
|
|
1073
1075
|
var body = [];
|
|
1074
|
-
|
|
1076
|
+
extract_from_unreachable_code(compressor, self.body, body);
|
|
1075
1077
|
if (self.init instanceof AST_Statement) {
|
|
1076
1078
|
body.push(self.init);
|
|
1077
1079
|
} else if (self.init) {
|
|
@@ -1107,7 +1109,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
|
1107
1109
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
|
1108
1110
|
if (!cond) {
|
|
1109
1111
|
var body = [];
|
|
1110
|
-
|
|
1112
|
+
extract_from_unreachable_code(compressor, self.body, body);
|
|
1111
1113
|
body.push(make_node(AST_SimpleStatement, self.condition, {
|
|
1112
1114
|
body: self.condition
|
|
1113
1115
|
}));
|
|
@@ -1120,7 +1122,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
|
1120
1122
|
}));
|
|
1121
1123
|
body.push(self.body);
|
|
1122
1124
|
if (self.alternative) {
|
|
1123
|
-
|
|
1125
|
+
extract_from_unreachable_code(compressor, self.alternative, body);
|
|
1124
1126
|
}
|
|
1125
1127
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
|
1126
1128
|
}
|
|
@@ -1192,8 +1194,8 @@ def_optimize(AST_If, function(self, compressor) {
|
|
|
1192
1194
|
return make_node(self.body.CTOR, self, {
|
|
1193
1195
|
value: make_node(AST_Conditional, self, {
|
|
1194
1196
|
condition : self.condition,
|
|
1195
|
-
consequent : self.body.value ||
|
|
1196
|
-
alternative : self.alternative.value ||
|
|
1197
|
+
consequent : self.body.value || make_void_0(self.body),
|
|
1198
|
+
alternative : self.alternative.value || make_void_0(self.alternative),
|
|
1197
1199
|
}).transform(compressor)
|
|
1198
1200
|
}).optimize(compressor);
|
|
1199
1201
|
}
|
|
@@ -1248,6 +1250,9 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
1248
1250
|
var body = [];
|
|
1249
1251
|
var default_branch;
|
|
1250
1252
|
var exact_match;
|
|
1253
|
+
// - compress self.body into `body`
|
|
1254
|
+
// - find and deduplicate default branch
|
|
1255
|
+
// - find the exact match (`case 1234` inside `switch(1234)`)
|
|
1251
1256
|
for (var i = 0, len = self.body.length; i < len && !exact_match; i++) {
|
|
1252
1257
|
branch = self.body[i];
|
|
1253
1258
|
if (branch instanceof AST_Default) {
|
|
@@ -1277,6 +1282,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
1277
1282
|
}
|
|
1278
1283
|
body.push(branch);
|
|
1279
1284
|
}
|
|
1285
|
+
// i < len if we found an exact_match. eliminate the rest
|
|
1280
1286
|
while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]);
|
|
1281
1287
|
self.body = body;
|
|
1282
1288
|
|
|
@@ -1348,7 +1354,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
1348
1354
|
let i = body.length - 1;
|
|
1349
1355
|
for (; i >= 0; i--) {
|
|
1350
1356
|
let bbody = body[i].body;
|
|
1351
|
-
|
|
1357
|
+
while (is_break(bbody[bbody.length - 1], compressor)) bbody.pop();
|
|
1352
1358
|
if (!is_inert_body(body[i])) break;
|
|
1353
1359
|
}
|
|
1354
1360
|
// i now points to the index of a branch that contains a body. By incrementing, it's
|
|
@@ -1364,9 +1370,9 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
1364
1370
|
let branch = body[j];
|
|
1365
1371
|
if (branch === default_or_exact) {
|
|
1366
1372
|
default_or_exact = null;
|
|
1367
|
-
body.pop();
|
|
1373
|
+
eliminate_branch(body.pop());
|
|
1368
1374
|
} else if (!branch.expression.has_side_effects(compressor)) {
|
|
1369
|
-
body.pop();
|
|
1375
|
+
eliminate_branch(body.pop());
|
|
1370
1376
|
} else {
|
|
1371
1377
|
break;
|
|
1372
1378
|
}
|
|
@@ -1480,15 +1486,16 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
1480
1486
|
// and there's a side-effect somewhere. Just let the below paths take care of it.
|
|
1481
1487
|
}
|
|
1482
1488
|
|
|
1489
|
+
// Reintegrate `decl` (var statements)
|
|
1483
1490
|
if (body.length > 0) {
|
|
1484
1491
|
body[0].body = decl.concat(body[0].body);
|
|
1485
1492
|
}
|
|
1486
|
-
|
|
1487
1493
|
if (body.length == 0) {
|
|
1488
1494
|
return make_node(AST_BlockStatement, self, {
|
|
1489
1495
|
body: decl.concat(statement(self.expression))
|
|
1490
1496
|
}).optimize(compressor);
|
|
1491
1497
|
}
|
|
1498
|
+
|
|
1492
1499
|
if (body.length == 1 && !has_nested_break(self)) {
|
|
1493
1500
|
// This is the last case body, and we've already pruned any breaks, so it's
|
|
1494
1501
|
// safe to hoist.
|
|
@@ -1568,7 +1575,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
|
1568
1575
|
if (prev && !aborts(prev)) {
|
|
1569
1576
|
prev.body = prev.body.concat(branch.body);
|
|
1570
1577
|
} else {
|
|
1571
|
-
|
|
1578
|
+
extract_from_unreachable_code(compressor, branch, decl);
|
|
1572
1579
|
}
|
|
1573
1580
|
}
|
|
1574
1581
|
function branches_equivalent(branch, prev, insertBreak) {
|
|
@@ -1622,7 +1629,7 @@ def_optimize(AST_Try, function(self, compressor) {
|
|
|
1622
1629
|
if (compressor.option("dead_code") && self.body.body.every(is_empty)) {
|
|
1623
1630
|
var body = [];
|
|
1624
1631
|
if (self.bcatch) {
|
|
1625
|
-
|
|
1632
|
+
extract_from_unreachable_code(compressor, self.bcatch, body);
|
|
1626
1633
|
}
|
|
1627
1634
|
if (self.bfinally) body.push(...self.bfinally.body);
|
|
1628
1635
|
return make_node(AST_BlockStatement, self, {
|
|
@@ -1741,7 +1748,7 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
|
1741
1748
|
const value = condition.evaluate(compressor);
|
|
1742
1749
|
|
|
1743
1750
|
if (value === 1 || value === true) {
|
|
1744
|
-
return
|
|
1751
|
+
return make_void_0(self).optimize(compressor);
|
|
1745
1752
|
}
|
|
1746
1753
|
}
|
|
1747
1754
|
}
|
|
@@ -2103,6 +2110,10 @@ def_optimize(AST_UnaryPrefix, function(self, compressor) {
|
|
|
2103
2110
|
) {
|
|
2104
2111
|
return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor);
|
|
2105
2112
|
}
|
|
2113
|
+
// Short-circuit common `void 0`
|
|
2114
|
+
if (self.operator === "void" && e instanceof AST_Number && e.value === 0) {
|
|
2115
|
+
return unsafe_undefined_ref(self, compressor) || self;
|
|
2116
|
+
}
|
|
2106
2117
|
var seq = self.lift_sequences(compressor);
|
|
2107
2118
|
if (seq !== self) {
|
|
2108
2119
|
return seq;
|
|
@@ -2113,7 +2124,7 @@ def_optimize(AST_UnaryPrefix, function(self, compressor) {
|
|
|
2113
2124
|
self.expression = e;
|
|
2114
2125
|
return self;
|
|
2115
2126
|
} else {
|
|
2116
|
-
return
|
|
2127
|
+
return make_void_0(self).optimize(compressor);
|
|
2117
2128
|
}
|
|
2118
2129
|
}
|
|
2119
2130
|
if (compressor.in_boolean_context()) {
|
|
@@ -2299,7 +2310,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
|
2299
2310
|
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
|
2300
2311
|
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
|
2301
2312
|
self.right = expr;
|
|
2302
|
-
self.left =
|
|
2313
|
+
self.left = make_void_0(self.left).optimize(compressor);
|
|
2303
2314
|
if (self.operator.length == 2) self.operator += "=";
|
|
2304
2315
|
}
|
|
2305
2316
|
} else if (compressor.option("typeofs")
|
|
@@ -2312,7 +2323,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
|
2312
2323
|
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
|
2313
2324
|
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
|
2314
2325
|
self.left = expr;
|
|
2315
|
-
self.right =
|
|
2326
|
+
self.right = make_void_0(self.right).optimize(compressor);
|
|
2316
2327
|
if (self.operator.length == 2) self.operator += "=";
|
|
2317
2328
|
}
|
|
2318
2329
|
} else if (self.left instanceof AST_SymbolRef
|
|
@@ -2953,7 +2964,8 @@ function is_atomic(lhs, self) {
|
|
|
2953
2964
|
return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
|
|
2954
2965
|
}
|
|
2955
2966
|
|
|
2956
|
-
|
|
2967
|
+
/** Apply the `unsafe_undefined` option: find a variable called `undefined` and turn `self` into a reference to it. */
|
|
2968
|
+
function unsafe_undefined_ref(self, compressor) {
|
|
2957
2969
|
if (compressor.option("unsafe_undefined")) {
|
|
2958
2970
|
var undef = find_variable(compressor, "undefined");
|
|
2959
2971
|
if (undef) {
|
|
@@ -2966,14 +2978,15 @@ def_optimize(AST_Undefined, function(self, compressor) {
|
|
|
2966
2978
|
return ref;
|
|
2967
2979
|
}
|
|
2968
2980
|
}
|
|
2981
|
+
return null;
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
def_optimize(AST_Undefined, function(self, compressor) {
|
|
2985
|
+
var symbolref = unsafe_undefined_ref(self, compressor);
|
|
2986
|
+
if (symbolref) return symbolref;
|
|
2969
2987
|
var lhs = compressor.is_lhs();
|
|
2970
2988
|
if (lhs && is_atomic(lhs, self)) return self;
|
|
2971
|
-
return
|
|
2972
|
-
operator: "void",
|
|
2973
|
-
expression: make_node(AST_Number, self, {
|
|
2974
|
-
value: 0
|
|
2975
|
-
})
|
|
2976
|
-
});
|
|
2989
|
+
return make_void_0(self);
|
|
2977
2990
|
});
|
|
2978
2991
|
|
|
2979
2992
|
def_optimize(AST_Infinity, function(self, compressor) {
|
|
@@ -3660,7 +3673,7 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
|
3660
3673
|
}
|
|
3661
3674
|
}
|
|
3662
3675
|
if (retValue instanceof AST_Expansion) break FLATTEN;
|
|
3663
|
-
retValue = retValue instanceof AST_Hole ?
|
|
3676
|
+
retValue = retValue instanceof AST_Hole ? make_void_0(retValue) : retValue;
|
|
3664
3677
|
if (!flatten) values.unshift(retValue);
|
|
3665
3678
|
while (--i >= 0) {
|
|
3666
3679
|
var value = elements[i];
|
|
@@ -3699,7 +3712,7 @@ def_optimize(AST_Chain, function (self, compressor) {
|
|
|
3699
3712
|
if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") {
|
|
3700
3713
|
return make_node_from_constant(0, self);
|
|
3701
3714
|
}
|
|
3702
|
-
return
|
|
3715
|
+
return make_void_0(self).optimize(compressor);
|
|
3703
3716
|
}
|
|
3704
3717
|
if (
|
|
3705
3718
|
self.expression instanceof AST_PropAccess
|
package/lib/compress/inline.js
CHANGED
|
@@ -76,7 +76,6 @@ import {
|
|
|
76
76
|
AST_This,
|
|
77
77
|
AST_Toplevel,
|
|
78
78
|
AST_UnaryPrefix,
|
|
79
|
-
AST_Undefined,
|
|
80
79
|
AST_Var,
|
|
81
80
|
AST_VarDef,
|
|
82
81
|
|
|
@@ -86,7 +85,7 @@ import {
|
|
|
86
85
|
_NOINLINE,
|
|
87
86
|
_PURE,
|
|
88
87
|
} from "../ast.js";
|
|
89
|
-
import { make_node, has_annotation } from "../utils/index.js";
|
|
88
|
+
import { make_node, make_void_0, has_annotation } from "../utils/index.js";
|
|
90
89
|
import "../size.js";
|
|
91
90
|
|
|
92
91
|
import "./evaluate.js";
|
|
@@ -358,7 +357,7 @@ export function inline_into_call(self, compressor) {
|
|
|
358
357
|
if (returned) {
|
|
359
358
|
returned = returned.clone(true);
|
|
360
359
|
} else {
|
|
361
|
-
returned =
|
|
360
|
+
returned = make_void_0(self);
|
|
362
361
|
}
|
|
363
362
|
const args = self.args.concat(returned);
|
|
364
363
|
return make_sequence(self, args).optimize(compressor);
|
|
@@ -374,7 +373,7 @@ export function inline_into_call(self, compressor) {
|
|
|
374
373
|
&& returned.name === fn.argnames[0].name
|
|
375
374
|
) {
|
|
376
375
|
const replacement =
|
|
377
|
-
(self.args[0] ||
|
|
376
|
+
(self.args[0] || make_void_0()).optimize(compressor);
|
|
378
377
|
|
|
379
378
|
let parent;
|
|
380
379
|
if (
|
|
@@ -456,7 +455,7 @@ export function inline_into_call(self, compressor) {
|
|
|
456
455
|
|
|
457
456
|
const can_drop_this_call = is_regular_func && compressor.option("side_effects") && fn.body.every(is_empty);
|
|
458
457
|
if (can_drop_this_call) {
|
|
459
|
-
var args = self.args.concat(
|
|
458
|
+
var args = self.args.concat(make_void_0(self));
|
|
460
459
|
return make_sequence(self, args).optimize(compressor);
|
|
461
460
|
}
|
|
462
461
|
|
|
@@ -475,9 +474,9 @@ export function inline_into_call(self, compressor) {
|
|
|
475
474
|
return self;
|
|
476
475
|
|
|
477
476
|
function return_value(stat) {
|
|
478
|
-
if (!stat) return
|
|
477
|
+
if (!stat) return make_void_0(self);
|
|
479
478
|
if (stat instanceof AST_Return) {
|
|
480
|
-
if (!stat.value) return
|
|
479
|
+
if (!stat.value) return make_void_0(self);
|
|
481
480
|
return stat.value.clone(true);
|
|
482
481
|
}
|
|
483
482
|
if (stat instanceof AST_SimpleStatement) {
|
|
@@ -623,7 +622,7 @@ export function inline_into_call(self, compressor) {
|
|
|
623
622
|
} else {
|
|
624
623
|
var symbol = make_node(AST_SymbolVar, name, name);
|
|
625
624
|
name.definition().orig.push(symbol);
|
|
626
|
-
if (!value && in_loop) value =
|
|
625
|
+
if (!value && in_loop) value = make_void_0(self);
|
|
627
626
|
append_var(decls, expressions, symbol, value);
|
|
628
627
|
}
|
|
629
628
|
}
|
|
@@ -650,7 +649,7 @@ export function inline_into_call(self, compressor) {
|
|
|
650
649
|
operator: "=",
|
|
651
650
|
logical: false,
|
|
652
651
|
left: sym,
|
|
653
|
-
right:
|
|
652
|
+
right: make_void_0(name),
|
|
654
653
|
}));
|
|
655
654
|
}
|
|
656
655
|
}
|
|
@@ -87,7 +87,6 @@ import {
|
|
|
87
87
|
AST_Try,
|
|
88
88
|
AST_Unary,
|
|
89
89
|
AST_UnaryPrefix,
|
|
90
|
-
AST_Undefined,
|
|
91
90
|
AST_UsingDef,
|
|
92
91
|
AST_VarDef,
|
|
93
92
|
AST_VarDefLike,
|
|
@@ -98,7 +97,7 @@ import {
|
|
|
98
97
|
walk_body,
|
|
99
98
|
walk_parent,
|
|
100
99
|
} from "../ast.js";
|
|
101
|
-
import { HOP, make_node, noop } from "../utils/index.js";
|
|
100
|
+
import { HOP, make_node, make_void_0, noop } from "../utils/index.js";
|
|
102
101
|
|
|
103
102
|
import { lazy_op, is_modified, is_lhs } from "./inference.js";
|
|
104
103
|
import { INLINED, clear_flag } from "./compressor-flags.js";
|
|
@@ -172,7 +171,7 @@ function safe_to_read(tw, def) {
|
|
|
172
171
|
if (def.fixed == null) {
|
|
173
172
|
var orig = def.orig[0];
|
|
174
173
|
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
|
175
|
-
def.fixed =
|
|
174
|
+
def.fixed = make_void_0(orig);
|
|
176
175
|
}
|
|
177
176
|
return true;
|
|
178
177
|
}
|
|
@@ -470,7 +469,7 @@ function mark_lambda(tw, descend, compressor) {
|
|
|
470
469
|
if (d.orig.length > 1) return;
|
|
471
470
|
if (d.fixed === undefined && (!this.uses_arguments || tw.has_directive("use strict"))) {
|
|
472
471
|
d.fixed = function() {
|
|
473
|
-
return iife.args[i] ||
|
|
472
|
+
return iife.args[i] || make_void_0(iife);
|
|
474
473
|
};
|
|
475
474
|
tw.loop_ids.set(d.id, tw.in_loop);
|
|
476
475
|
mark(tw, d, true);
|
|
@@ -106,7 +106,6 @@ import {
|
|
|
106
106
|
AST_Unary,
|
|
107
107
|
AST_UnaryPostfix,
|
|
108
108
|
AST_UnaryPrefix,
|
|
109
|
-
AST_Undefined,
|
|
110
109
|
AST_Using,
|
|
111
110
|
AST_Var,
|
|
112
111
|
AST_VarDef,
|
|
@@ -122,6 +121,7 @@ import {
|
|
|
122
121
|
} from "../ast.js";
|
|
123
122
|
import {
|
|
124
123
|
make_node,
|
|
124
|
+
make_void_0,
|
|
125
125
|
MAP,
|
|
126
126
|
member,
|
|
127
127
|
remove,
|
|
@@ -191,8 +191,8 @@ function remove_initializers(var_statement) {
|
|
|
191
191
|
return decls.length ? make_node(AST_Var, var_statement, { definitions: decls }) : null;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
/** Called on code which
|
|
195
|
-
export function
|
|
194
|
+
/** Called on code which won't be executed but has an effect outside of itself: `var`, `function` statements, `export`, `import`. */
|
|
195
|
+
export function extract_from_unreachable_code(compressor, stat, target) {
|
|
196
196
|
walk(stat, node => {
|
|
197
197
|
if (node instanceof AST_Var) {
|
|
198
198
|
const no_initializers = remove_initializers(node);
|
|
@@ -217,7 +217,8 @@ export function trim_unreachable_code(compressor, stat, target) {
|
|
|
217
217
|
target.push(node);
|
|
218
218
|
return true;
|
|
219
219
|
}
|
|
220
|
-
if (node instanceof AST_Scope) {
|
|
220
|
+
if (node instanceof AST_Scope || node instanceof AST_Class) {
|
|
221
|
+
// Do not go into nested scopes
|
|
221
222
|
return true;
|
|
222
223
|
}
|
|
223
224
|
});
|
|
@@ -634,7 +635,7 @@ export function tighten_body(statements, compressor) {
|
|
|
634
635
|
}
|
|
635
636
|
} else {
|
|
636
637
|
if (!arg) {
|
|
637
|
-
arg =
|
|
638
|
+
arg = make_void_0(sym).transform(compressor);
|
|
638
639
|
} else if (arg instanceof AST_Lambda && arg.pinned()
|
|
639
640
|
|| has_overlapping_symbol(fn, arg, fn_strict)) {
|
|
640
641
|
arg = null;
|
|
@@ -874,7 +875,7 @@ export function tighten_body(statements, compressor) {
|
|
|
874
875
|
found = true;
|
|
875
876
|
if (node instanceof AST_VarDef) {
|
|
876
877
|
node.value = node.name instanceof AST_SymbolConst
|
|
877
|
-
?
|
|
878
|
+
? make_void_0(node.value) // `const` always needs value.
|
|
878
879
|
: null;
|
|
879
880
|
return node;
|
|
880
881
|
}
|
|
@@ -1241,7 +1242,7 @@ export function tighten_body(statements, compressor) {
|
|
|
1241
1242
|
CHANGED = n != len;
|
|
1242
1243
|
if (has_quit)
|
|
1243
1244
|
has_quit.forEach(function (stat) {
|
|
1244
|
-
|
|
1245
|
+
extract_from_unreachable_code(compressor, stat, statements);
|
|
1245
1246
|
});
|
|
1246
1247
|
}
|
|
1247
1248
|
|
|
@@ -1313,7 +1314,7 @@ export function tighten_body(statements, compressor) {
|
|
|
1313
1314
|
var stat = statements[i];
|
|
1314
1315
|
if (prev) {
|
|
1315
1316
|
if (stat instanceof AST_Exit) {
|
|
1316
|
-
stat.value = cons_seq(stat.value ||
|
|
1317
|
+
stat.value = cons_seq(stat.value || make_void_0(stat).transform(compressor));
|
|
1317
1318
|
} else if (stat instanceof AST_For) {
|
|
1318
1319
|
if (!(stat.init instanceof AST_DefinitionsLike)) {
|
|
1319
1320
|
const abort = walk(prev.body, node => {
|
package/lib/utils/index.js
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
"use strict";
|
|
45
45
|
|
|
46
|
-
import { AST_Node } from "../ast.js";
|
|
46
|
+
import { AST_Node, AST_Number, AST_UnaryPrefix } from "../ast.js";
|
|
47
47
|
|
|
48
48
|
function characters(str) {
|
|
49
49
|
return str.split("");
|
|
@@ -130,6 +130,15 @@ function make_node(ctor, orig, props) {
|
|
|
130
130
|
return new ctor(props);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/** Makes a `void 0` expression. Use instead of AST_Undefined which may conflict
|
|
134
|
+
* with an existing variable called `undefined` */
|
|
135
|
+
function make_void_0(orig) {
|
|
136
|
+
return make_node(AST_UnaryPrefix, orig, {
|
|
137
|
+
operator: "void",
|
|
138
|
+
expression: make_node(AST_Number, orig, { value: 0 })
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
133
142
|
function push_uniq(array, el) {
|
|
134
143
|
if (!array.includes(el))
|
|
135
144
|
array.push(el);
|
|
@@ -272,6 +281,7 @@ export {
|
|
|
272
281
|
HOP,
|
|
273
282
|
keep_name,
|
|
274
283
|
make_node,
|
|
284
|
+
make_void_0,
|
|
275
285
|
makePredicate,
|
|
276
286
|
map_add,
|
|
277
287
|
map_from_object,
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"homepage": "https://terser.org",
|
|
5
5
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
|
6
6
|
"license": "BSD-2-Clause",
|
|
7
|
-
"version": "5.
|
|
7
|
+
"version": "5.45.0",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=10"
|
|
10
10
|
},
|
|
@@ -61,6 +61,10 @@
|
|
|
61
61
|
"semver": "^7.5.1",
|
|
62
62
|
"source-map": "~0.8.0-beta.0"
|
|
63
63
|
},
|
|
64
|
+
"overrides": {
|
|
65
|
+
"serialize-javascript": "6.0.2",
|
|
66
|
+
"js-yaml": "4.1.1"
|
|
67
|
+
},
|
|
64
68
|
"scripts": {
|
|
65
69
|
"test": "node test/compress.js && mocha test/mocha",
|
|
66
70
|
"test:compress": "node test/compress.js",
|