terser 5.17.3 → 5.17.5
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 +122 -73
- package/lib/ast.js +35 -0
- package/lib/compress/drop-side-effect-free.js +31 -28
- package/lib/compress/drop-unused.js +29 -30
- package/lib/compress/index.js +17 -10
- package/lib/compress/inference.js +3 -0
- package/lib/output.js +10 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v5.17.5
|
4
|
+
- Take into account the non-deferred bits of a class, such as static properties, while dropping unused code.
|
5
|
+
|
6
|
+
## v5.17.4
|
7
|
+
|
8
|
+
- Fix crash when trying to negate a class (`!class{}`)
|
9
|
+
- Avoid outputting comments between `yield`/`await` and its argument
|
10
|
+
- Fix detection of left-hand-side of assignment, to avoid optimizing it like any other expression in some edge cases
|
11
|
+
|
3
12
|
## v5.17.3
|
4
13
|
|
5
14
|
- Fix issue with trimming a static class property's contents accessing the class as `this`.
|
package/dist/bundle.min.js
CHANGED
@@ -5840,6 +5840,40 @@ var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(p
|
|
5840
5840
|
if (this.extends) push(this.extends);
|
5841
5841
|
if (this.name) push(this.name);
|
5842
5842
|
},
|
5843
|
+
/** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */
|
5844
|
+
visit_nondeferred_class_parts(visitor) {
|
5845
|
+
if (this.extends) {
|
5846
|
+
this.extends._walk(visitor);
|
5847
|
+
}
|
5848
|
+
this.properties.forEach((prop) => {
|
5849
|
+
if (prop instanceof AST_ClassStaticBlock) {
|
5850
|
+
prop._walk(visitor);
|
5851
|
+
return;
|
5852
|
+
}
|
5853
|
+
if (prop.computed_key()) {
|
5854
|
+
visitor.push(prop);
|
5855
|
+
prop.key._walk(visitor);
|
5856
|
+
visitor.pop();
|
5857
|
+
}
|
5858
|
+
if ((prop instanceof AST_ClassPrivateProperty || prop instanceof AST_ClassProperty) && prop.static && prop.value) {
|
5859
|
+
visitor.push(prop);
|
5860
|
+
prop.value._walk(visitor);
|
5861
|
+
visitor.pop();
|
5862
|
+
}
|
5863
|
+
});
|
5864
|
+
},
|
5865
|
+
/** go through the bits that are executed later, when the class is `new`'d or a static method is called */
|
5866
|
+
visit_deferred_class_parts(visitor) {
|
5867
|
+
this.properties.forEach((prop) => {
|
5868
|
+
if (prop instanceof AST_ConciseMethod) {
|
5869
|
+
prop.walk(visitor);
|
5870
|
+
} else if (prop instanceof AST_ClassProperty && !prop.static && prop.value) {
|
5871
|
+
visitor.push(prop);
|
5872
|
+
prop.value._walk(visitor);
|
5873
|
+
visitor.pop();
|
5874
|
+
}
|
5875
|
+
});
|
5876
|
+
},
|
5843
5877
|
}, AST_Scope /* TODO a class might have a scope but it's not a scope */);
|
5844
5878
|
|
5845
5879
|
var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) {
|
@@ -5956,6 +5990,7 @@ var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", funct
|
|
5956
5990
|
while (i--) push(this.body[i]);
|
5957
5991
|
},
|
5958
5992
|
clone: clone_block_scope,
|
5993
|
+
computed_key: () => false
|
5959
5994
|
}, AST_Scope);
|
5960
5995
|
|
5961
5996
|
var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) {
|
@@ -9345,14 +9380,17 @@ function OutputStream(options) {
|
|
9345
9380
|
if (!start) return;
|
9346
9381
|
var printed_comments = self.printed_comments;
|
9347
9382
|
|
9348
|
-
// There cannot be a newline between return and its value.
|
9349
|
-
const
|
9383
|
+
// There cannot be a newline between return/yield and its value.
|
9384
|
+
const keyword_with_value =
|
9385
|
+
node instanceof AST_Exit && node.value
|
9386
|
+
|| (node instanceof AST_Await || node instanceof AST_Yield)
|
9387
|
+
&& node.expression;
|
9350
9388
|
|
9351
9389
|
if (
|
9352
9390
|
start.comments_before
|
9353
9391
|
&& printed_comments.has(start.comments_before)
|
9354
9392
|
) {
|
9355
|
-
if (
|
9393
|
+
if (keyword_with_value) {
|
9356
9394
|
start.comments_before = [];
|
9357
9395
|
} else {
|
9358
9396
|
return;
|
@@ -9365,10 +9403,12 @@ function OutputStream(options) {
|
|
9365
9403
|
}
|
9366
9404
|
printed_comments.add(comments);
|
9367
9405
|
|
9368
|
-
if (
|
9406
|
+
if (keyword_with_value) {
|
9369
9407
|
var tw = new TreeWalker(function(node) {
|
9370
9408
|
var parent = tw.parent();
|
9371
9409
|
if (parent instanceof AST_Exit
|
9410
|
+
|| parent instanceof AST_Await
|
9411
|
+
|| parent instanceof AST_Yield
|
9372
9412
|
|| parent instanceof AST_Binary && parent.left === node
|
9373
9413
|
|| parent.TYPE == "Call" && parent.expression === node
|
9374
9414
|
|| parent instanceof AST_Conditional && parent.condition === node
|
@@ -9387,7 +9427,7 @@ function OutputStream(options) {
|
|
9387
9427
|
}
|
9388
9428
|
});
|
9389
9429
|
tw.push(node);
|
9390
|
-
|
9430
|
+
keyword_with_value.walk(tw);
|
9391
9431
|
}
|
9392
9432
|
|
9393
9433
|
if (current_pos == 0) {
|
@@ -14022,6 +14062,9 @@ function is_lhs(node, parent) {
|
|
14022
14062
|
def_negate(AST_Function, function() {
|
14023
14063
|
return basic_negation(this);
|
14024
14064
|
});
|
14065
|
+
def_negate(AST_Class, function() {
|
14066
|
+
return basic_negation(this);
|
14067
|
+
});
|
14025
14068
|
def_negate(AST_Arrow, function() {
|
14026
14069
|
return basic_negation(this);
|
14027
14070
|
});
|
@@ -14764,31 +14807,43 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
|
|
14764
14807
|
const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
|
14765
14808
|
if (trimmed_extends)
|
14766
14809
|
with_effects.push(trimmed_extends);
|
14810
|
+
|
14767
14811
|
for (const prop of this.properties) {
|
14768
14812
|
if (prop instanceof AST_ClassStaticBlock) {
|
14769
|
-
if (prop.
|
14770
|
-
return this;
|
14771
|
-
} else {
|
14772
|
-
continue;
|
14813
|
+
if (prop.has_side_effects(compressor)) {
|
14814
|
+
return this; // Be cautious about these
|
14773
14815
|
}
|
14774
|
-
}
|
14816
|
+
} else {
|
14817
|
+
const trimmed_prop = prop.drop_side_effect_free(compressor);
|
14818
|
+
if (trimmed_prop) {
|
14819
|
+
if (trimmed_prop.contains_this()) return this;
|
14775
14820
|
|
14776
|
-
|
14777
|
-
|
14778
|
-
&& prop.static
|
14779
|
-
&& prop.value.has_side_effects(compressor)
|
14780
|
-
&& prop.contains_this()
|
14781
|
-
) {
|
14782
|
-
return this;
|
14821
|
+
with_effects.push(trimmed_prop);
|
14822
|
+
}
|
14783
14823
|
}
|
14784
|
-
|
14785
|
-
const trimmed_prop = prop.drop_side_effect_free(compressor);
|
14786
|
-
if (trimmed_prop)
|
14787
|
-
with_effects.push(trimmed_prop);
|
14788
14824
|
}
|
14825
|
+
|
14789
14826
|
if (!with_effects.length)
|
14790
14827
|
return null;
|
14791
|
-
|
14828
|
+
|
14829
|
+
const exprs = make_sequence(this, with_effects);
|
14830
|
+
if (this instanceof AST_DefClass) {
|
14831
|
+
// We want a statement
|
14832
|
+
return make_node(AST_SimpleStatement, this, { body: exprs });
|
14833
|
+
} else {
|
14834
|
+
return exprs;
|
14835
|
+
}
|
14836
|
+
});
|
14837
|
+
|
14838
|
+
def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
|
14839
|
+
const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
|
14840
|
+
|
14841
|
+
const value = this.static && this.value
|
14842
|
+
&& this.value.drop_side_effect_free(compressor);
|
14843
|
+
|
14844
|
+
if (key && value)
|
14845
|
+
return make_sequence(this, [key, value]);
|
14846
|
+
return key || value || null;
|
14792
14847
|
});
|
14793
14848
|
|
14794
14849
|
def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
|
@@ -14894,17 +14949,6 @@ def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_sta
|
|
14894
14949
|
return key || value;
|
14895
14950
|
});
|
14896
14951
|
|
14897
|
-
def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
|
14898
|
-
const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
|
14899
|
-
|
14900
|
-
const value = this.static && this.value
|
14901
|
-
&& this.value.drop_side_effect_free(compressor);
|
14902
|
-
|
14903
|
-
if (key && value)
|
14904
|
-
return make_sequence(this, [key, value]);
|
14905
|
-
return key || value || null;
|
14906
|
-
});
|
14907
|
-
|
14908
14952
|
def_drop_side_effect_free(AST_ConciseMethod, function () {
|
14909
14953
|
return this.computed_key() ? this.key : null;
|
14910
14954
|
});
|
@@ -15064,6 +15108,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15064
15108
|
});
|
15065
15109
|
}
|
15066
15110
|
if (node === self) return;
|
15111
|
+
if (node instanceof AST_Class) {
|
15112
|
+
if (node.has_side_effects(compressor)) {
|
15113
|
+
node.visit_nondeferred_class_parts(tw);
|
15114
|
+
}
|
15115
|
+
}
|
15067
15116
|
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
15068
15117
|
var node_def = node.name.definition();
|
15069
15118
|
const in_export = tw.parent() instanceof AST_Export;
|
@@ -15072,23 +15121,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15072
15121
|
in_use_ids.set(node_def.id, node_def);
|
15073
15122
|
}
|
15074
15123
|
}
|
15075
|
-
|
15076
|
-
if (
|
15077
|
-
node.extends
|
15078
|
-
&& (node.extends.has_side_effects(compressor)
|
15079
|
-
|| node.extends.may_throw(compressor))
|
15080
|
-
) {
|
15081
|
-
node.extends.walk(tw);
|
15082
|
-
}
|
15083
|
-
for (const prop of node.properties) {
|
15084
|
-
if (
|
15085
|
-
prop.has_side_effects(compressor) ||
|
15086
|
-
prop.may_throw(compressor)
|
15087
|
-
) {
|
15088
|
-
prop.walk(tw);
|
15089
|
-
}
|
15090
|
-
}
|
15091
|
-
}
|
15124
|
+
|
15092
15125
|
map_add(initializations, node_def.id, node);
|
15093
15126
|
return true; // don't go in nested scopes
|
15094
15127
|
}
|
@@ -15153,9 +15186,9 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15153
15186
|
if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
|
15154
15187
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
15155
15188
|
}
|
15156
|
-
} else if (!in_use)
|
15157
|
-
value: 0
|
15158
|
-
}
|
15189
|
+
} else if (!in_use) {
|
15190
|
+
return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
|
15191
|
+
}
|
15159
15192
|
}
|
15160
15193
|
}
|
15161
15194
|
if (scope !== self) return;
|
@@ -15198,11 +15231,18 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15198
15231
|
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
15199
15232
|
const def = node.name.definition();
|
15200
15233
|
const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
|
15201
|
-
|
15202
|
-
|
15203
|
-
|
15204
|
-
|
15205
|
-
|
15234
|
+
if (!keep) {
|
15235
|
+
// Class "extends" and static blocks may have side effects
|
15236
|
+
if (node instanceof AST_Class) {
|
15237
|
+
const kept = node.drop_side_effect_free(compressor);
|
15238
|
+
if (kept !== node) {
|
15239
|
+
def.eliminated++;
|
15240
|
+
if (kept) return kept;
|
15241
|
+
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
15242
|
+
} else {
|
15243
|
+
return kept;
|
15244
|
+
}
|
15245
|
+
}
|
15206
15246
|
def.eliminated++;
|
15207
15247
|
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
15208
15248
|
}
|
@@ -15298,9 +15338,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15298
15338
|
case 1:
|
15299
15339
|
return body[0];
|
15300
15340
|
default:
|
15301
|
-
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
|
15302
|
-
body: body
|
15303
|
-
});
|
15341
|
+
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { body });
|
15304
15342
|
}
|
15305
15343
|
}
|
15306
15344
|
// certain combination of unused name + side effect leads to:
|
@@ -15343,7 +15381,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15343
15381
|
}
|
15344
15382
|
return node;
|
15345
15383
|
}
|
15346
|
-
if (node instanceof AST_Scope) {
|
15384
|
+
if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
|
15347
15385
|
const save_scope = scope;
|
15348
15386
|
scope = node;
|
15349
15387
|
descend(node, this);
|
@@ -15382,7 +15420,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
15382
15420
|
}
|
15383
15421
|
return true;
|
15384
15422
|
}
|
15385
|
-
if (node instanceof
|
15423
|
+
if (node instanceof AST_Class) {
|
15424
|
+
descend();
|
15425
|
+
return true;
|
15426
|
+
}
|
15427
|
+
if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
|
15386
15428
|
var save_scope = scope;
|
15387
15429
|
scope = node;
|
15388
15430
|
descend();
|
@@ -18335,6 +18377,13 @@ class Compressor extends TreeWalker {
|
|
18335
18377
|
if (opt === node) set_flag(opt, SQUEEZED);
|
18336
18378
|
return opt;
|
18337
18379
|
}
|
18380
|
+
|
18381
|
+
/** Alternative to plain is_lhs() which doesn't work within .optimize() */
|
18382
|
+
is_lhs() {
|
18383
|
+
const self = this.stack[this.stack.length - 1];
|
18384
|
+
const parent = this.stack[this.stack.length - 2];
|
18385
|
+
return is_lhs(self, parent);
|
18386
|
+
}
|
18338
18387
|
}
|
18339
18388
|
|
18340
18389
|
function def_optimize(node, optimizer) {
|
@@ -18541,8 +18590,6 @@ def_optimize(AST_Lambda, opt_AST_Lambda);
|
|
18541
18590
|
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
|
18542
18591
|
var self = this;
|
18543
18592
|
if (compressor.has_directive("use asm")) return self;
|
18544
|
-
// Hoisting makes no sense in an arrow func
|
18545
|
-
if (!Array.isArray(self.body)) return self;
|
18546
18593
|
|
18547
18594
|
var hoist_funs = compressor.option("hoist_funs");
|
18548
18595
|
var hoist_vars = compressor.option("hoist_vars");
|
@@ -20492,8 +20539,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
|
|
20492
20539
|
}
|
20493
20540
|
}
|
20494
20541
|
|
20495
|
-
|
20496
|
-
if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
|
20542
|
+
if (compressor.option("reduce_vars") && !compressor.is_lhs()) {
|
20497
20543
|
return inline_into_symbolref(self, compressor);
|
20498
20544
|
} else {
|
20499
20545
|
return self;
|
@@ -20517,7 +20563,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
|
|
20517
20563
|
return ref;
|
20518
20564
|
}
|
20519
20565
|
}
|
20520
|
-
var lhs =
|
20566
|
+
var lhs = compressor.is_lhs();
|
20521
20567
|
if (lhs && is_atomic(lhs, self)) return self;
|
20522
20568
|
return make_node(AST_UnaryPrefix, self, {
|
20523
20569
|
operator: "void",
|
@@ -20528,7 +20574,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
|
|
20528
20574
|
});
|
20529
20575
|
|
20530
20576
|
def_optimize(AST_Infinity, function(self, compressor) {
|
20531
|
-
var lhs =
|
20577
|
+
var lhs = compressor.is_lhs();
|
20532
20578
|
if (lhs && is_atomic(lhs, self)) return self;
|
20533
20579
|
if (
|
20534
20580
|
compressor.option("keep_infinity")
|
@@ -20549,7 +20595,7 @@ def_optimize(AST_Infinity, function(self, compressor) {
|
|
20549
20595
|
});
|
20550
20596
|
|
20551
20597
|
def_optimize(AST_NaN, function(self, compressor) {
|
20552
|
-
var lhs =
|
20598
|
+
var lhs = compressor.is_lhs();
|
20553
20599
|
if (lhs && !is_atomic(lhs, self)
|
20554
20600
|
|| find_variable(compressor, "NaN")) {
|
20555
20601
|
return make_node(AST_Binary, self, {
|
@@ -21125,7 +21171,10 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
21125
21171
|
}
|
21126
21172
|
}
|
21127
21173
|
}
|
21128
|
-
prop = self.property = best_of_expression(
|
21174
|
+
prop = self.property = best_of_expression(
|
21175
|
+
prop,
|
21176
|
+
make_node_from_constant(key, prop).transform(compressor)
|
21177
|
+
);
|
21129
21178
|
var property = "" + key;
|
21130
21179
|
if (is_basic_identifier_string(property)
|
21131
21180
|
&& property.length <= prop.size() + 1) {
|
@@ -21183,7 +21232,7 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
21183
21232
|
return sym;
|
21184
21233
|
}
|
21185
21234
|
}
|
21186
|
-
if (
|
21235
|
+
if (compressor.is_lhs()) return self;
|
21187
21236
|
if (key !== prop) {
|
21188
21237
|
var sub = self.flatten_object(property, compressor);
|
21189
21238
|
if (sub) {
|
@@ -21253,7 +21302,7 @@ def_optimize(AST_Chain, function (self, compressor) {
|
|
21253
21302
|
|
21254
21303
|
def_optimize(AST_Dot, function(self, compressor) {
|
21255
21304
|
const parent = compressor.parent();
|
21256
|
-
if (is_lhs(
|
21305
|
+
if (compressor.is_lhs()) return self;
|
21257
21306
|
if (compressor.option("unsafe_proto")
|
21258
21307
|
&& self.expression instanceof AST_Dot
|
21259
21308
|
&& self.expression.property == "prototype") {
|
package/lib/ast.js
CHANGED
@@ -2230,6 +2230,40 @@ var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(p
|
|
2230
2230
|
if (this.extends) push(this.extends);
|
2231
2231
|
if (this.name) push(this.name);
|
2232
2232
|
},
|
2233
|
+
/** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */
|
2234
|
+
visit_nondeferred_class_parts(visitor) {
|
2235
|
+
if (this.extends) {
|
2236
|
+
this.extends._walk(visitor);
|
2237
|
+
}
|
2238
|
+
this.properties.forEach((prop) => {
|
2239
|
+
if (prop instanceof AST_ClassStaticBlock) {
|
2240
|
+
prop._walk(visitor);
|
2241
|
+
return;
|
2242
|
+
}
|
2243
|
+
if (prop.computed_key()) {
|
2244
|
+
visitor.push(prop);
|
2245
|
+
prop.key._walk(visitor);
|
2246
|
+
visitor.pop();
|
2247
|
+
}
|
2248
|
+
if ((prop instanceof AST_ClassPrivateProperty || prop instanceof AST_ClassProperty) && prop.static && prop.value) {
|
2249
|
+
visitor.push(prop);
|
2250
|
+
prop.value._walk(visitor);
|
2251
|
+
visitor.pop();
|
2252
|
+
}
|
2253
|
+
});
|
2254
|
+
},
|
2255
|
+
/** go through the bits that are executed later, when the class is `new`'d or a static method is called */
|
2256
|
+
visit_deferred_class_parts(visitor) {
|
2257
|
+
this.properties.forEach((prop) => {
|
2258
|
+
if (prop instanceof AST_ConciseMethod) {
|
2259
|
+
prop.walk(visitor);
|
2260
|
+
} else if (prop instanceof AST_ClassProperty && !prop.static && prop.value) {
|
2261
|
+
visitor.push(prop);
|
2262
|
+
prop.value._walk(visitor);
|
2263
|
+
visitor.pop();
|
2264
|
+
}
|
2265
|
+
});
|
2266
|
+
},
|
2233
2267
|
}, AST_Scope /* TODO a class might have a scope but it's not a scope */);
|
2234
2268
|
|
2235
2269
|
var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) {
|
@@ -2346,6 +2380,7 @@ var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", funct
|
|
2346
2380
|
while (i--) push(this.body[i]);
|
2347
2381
|
},
|
2348
2382
|
clone: clone_block_scope,
|
2383
|
+
computed_key: () => false
|
2349
2384
|
}, AST_Scope);
|
2350
2385
|
|
2351
2386
|
var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) {
|
@@ -55,6 +55,7 @@ import {
|
|
55
55
|
AST_ConciseMethod,
|
56
56
|
AST_Conditional,
|
57
57
|
AST_Constant,
|
58
|
+
AST_DefClass,
|
58
59
|
AST_Dot,
|
59
60
|
AST_Expansion,
|
60
61
|
AST_Function,
|
@@ -68,6 +69,7 @@ import {
|
|
68
69
|
AST_PropAccess,
|
69
70
|
AST_Scope,
|
70
71
|
AST_Sequence,
|
72
|
+
AST_SimpleStatement,
|
71
73
|
AST_Sub,
|
72
74
|
AST_SymbolRef,
|
73
75
|
AST_TemplateSegment,
|
@@ -156,31 +158,43 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
|
|
156
158
|
const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
|
157
159
|
if (trimmed_extends)
|
158
160
|
with_effects.push(trimmed_extends);
|
161
|
+
|
159
162
|
for (const prop of this.properties) {
|
160
163
|
if (prop instanceof AST_ClassStaticBlock) {
|
161
|
-
if (prop.
|
162
|
-
return this;
|
163
|
-
} else {
|
164
|
-
continue;
|
164
|
+
if (prop.has_side_effects(compressor)) {
|
165
|
+
return this; // Be cautious about these
|
165
166
|
}
|
166
|
-
}
|
167
|
+
} else {
|
168
|
+
const trimmed_prop = prop.drop_side_effect_free(compressor);
|
169
|
+
if (trimmed_prop) {
|
170
|
+
if (trimmed_prop.contains_this()) return this;
|
167
171
|
|
168
|
-
|
169
|
-
|
170
|
-
&& prop.static
|
171
|
-
&& prop.value.has_side_effects(compressor)
|
172
|
-
&& prop.contains_this()
|
173
|
-
) {
|
174
|
-
return this;
|
172
|
+
with_effects.push(trimmed_prop);
|
173
|
+
}
|
175
174
|
}
|
176
|
-
|
177
|
-
const trimmed_prop = prop.drop_side_effect_free(compressor);
|
178
|
-
if (trimmed_prop)
|
179
|
-
with_effects.push(trimmed_prop);
|
180
175
|
}
|
176
|
+
|
181
177
|
if (!with_effects.length)
|
182
178
|
return null;
|
183
|
-
|
179
|
+
|
180
|
+
const exprs = make_sequence(this, with_effects);
|
181
|
+
if (this instanceof AST_DefClass) {
|
182
|
+
// We want a statement
|
183
|
+
return make_node(AST_SimpleStatement, this, { body: exprs });
|
184
|
+
} else {
|
185
|
+
return exprs;
|
186
|
+
}
|
187
|
+
});
|
188
|
+
|
189
|
+
def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
|
190
|
+
const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
|
191
|
+
|
192
|
+
const value = this.static && this.value
|
193
|
+
&& this.value.drop_side_effect_free(compressor);
|
194
|
+
|
195
|
+
if (key && value)
|
196
|
+
return make_sequence(this, [key, value]);
|
197
|
+
return key || value || null;
|
184
198
|
});
|
185
199
|
|
186
200
|
def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
|
@@ -286,17 +300,6 @@ def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_sta
|
|
286
300
|
return key || value;
|
287
301
|
});
|
288
302
|
|
289
|
-
def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
|
290
|
-
const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
|
291
|
-
|
292
|
-
const value = this.static && this.value
|
293
|
-
&& this.value.drop_side_effect_free(compressor);
|
294
|
-
|
295
|
-
if (key && value)
|
296
|
-
return make_sequence(this, [key, value]);
|
297
|
-
return key || value || null;
|
298
|
-
});
|
299
|
-
|
300
303
|
def_drop_side_effect_free(AST_ConciseMethod, function () {
|
301
304
|
return this.computed_key() ? this.key : null;
|
302
305
|
});
|
@@ -47,6 +47,7 @@ import {
|
|
47
47
|
AST_BlockStatement,
|
48
48
|
AST_Class,
|
49
49
|
AST_ClassExpression,
|
50
|
+
AST_ClassStaticBlock,
|
50
51
|
AST_DefaultAssign,
|
51
52
|
AST_DefClass,
|
52
53
|
AST_Definitions,
|
@@ -152,6 +153,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
152
153
|
});
|
153
154
|
}
|
154
155
|
if (node === self) return;
|
156
|
+
if (node instanceof AST_Class) {
|
157
|
+
if (node.has_side_effects(compressor)) {
|
158
|
+
node.visit_nondeferred_class_parts(tw);
|
159
|
+
}
|
160
|
+
}
|
155
161
|
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
156
162
|
var node_def = node.name.definition();
|
157
163
|
const in_export = tw.parent() instanceof AST_Export;
|
@@ -160,23 +166,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
160
166
|
in_use_ids.set(node_def.id, node_def);
|
161
167
|
}
|
162
168
|
}
|
163
|
-
|
164
|
-
if (
|
165
|
-
node.extends
|
166
|
-
&& (node.extends.has_side_effects(compressor)
|
167
|
-
|| node.extends.may_throw(compressor))
|
168
|
-
) {
|
169
|
-
node.extends.walk(tw);
|
170
|
-
}
|
171
|
-
for (const prop of node.properties) {
|
172
|
-
if (
|
173
|
-
prop.has_side_effects(compressor) ||
|
174
|
-
prop.may_throw(compressor)
|
175
|
-
) {
|
176
|
-
prop.walk(tw);
|
177
|
-
}
|
178
|
-
}
|
179
|
-
}
|
169
|
+
|
180
170
|
map_add(initializations, node_def.id, node);
|
181
171
|
return true; // don't go in nested scopes
|
182
172
|
}
|
@@ -241,9 +231,9 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
241
231
|
if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
|
242
232
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
243
233
|
}
|
244
|
-
} else if (!in_use)
|
245
|
-
value: 0
|
246
|
-
}
|
234
|
+
} else if (!in_use) {
|
235
|
+
return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
|
236
|
+
}
|
247
237
|
}
|
248
238
|
}
|
249
239
|
if (scope !== self) return;
|
@@ -286,11 +276,18 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
286
276
|
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
287
277
|
const def = node.name.definition();
|
288
278
|
const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
279
|
+
if (!keep) {
|
280
|
+
// Class "extends" and static blocks may have side effects
|
281
|
+
if (node instanceof AST_Class) {
|
282
|
+
const kept = node.drop_side_effect_free(compressor);
|
283
|
+
if (kept !== node) {
|
284
|
+
def.eliminated++;
|
285
|
+
if (kept) return kept;
|
286
|
+
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
287
|
+
} else {
|
288
|
+
return kept;
|
289
|
+
}
|
290
|
+
}
|
294
291
|
def.eliminated++;
|
295
292
|
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
296
293
|
}
|
@@ -386,9 +383,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
386
383
|
case 1:
|
387
384
|
return body[0];
|
388
385
|
default:
|
389
|
-
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
|
390
|
-
body: body
|
391
|
-
});
|
386
|
+
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { body });
|
392
387
|
}
|
393
388
|
}
|
394
389
|
// certain combination of unused name + side effect leads to:
|
@@ -431,7 +426,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
431
426
|
}
|
432
427
|
return node;
|
433
428
|
}
|
434
|
-
if (node instanceof AST_Scope) {
|
429
|
+
if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
|
435
430
|
const save_scope = scope;
|
436
431
|
scope = node;
|
437
432
|
descend(node, this);
|
@@ -470,7 +465,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
|
|
470
465
|
}
|
471
466
|
return true;
|
472
467
|
}
|
473
|
-
if (node instanceof
|
468
|
+
if (node instanceof AST_Class) {
|
469
|
+
descend();
|
470
|
+
return true;
|
471
|
+
}
|
472
|
+
if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
|
474
473
|
var save_scope = scope;
|
475
474
|
scope = node;
|
476
475
|
descend();
|
package/lib/compress/index.js
CHANGED
@@ -442,6 +442,13 @@ class Compressor extends TreeWalker {
|
|
442
442
|
if (opt === node) set_flag(opt, SQUEEZED);
|
443
443
|
return opt;
|
444
444
|
}
|
445
|
+
|
446
|
+
/** Alternative to plain is_lhs() which doesn't work within .optimize() */
|
447
|
+
is_lhs() {
|
448
|
+
const self = this.stack[this.stack.length - 1];
|
449
|
+
const parent = this.stack[this.stack.length - 2];
|
450
|
+
return is_lhs(self, parent);
|
451
|
+
}
|
445
452
|
}
|
446
453
|
|
447
454
|
function def_optimize(node, optimizer) {
|
@@ -648,8 +655,6 @@ def_optimize(AST_Lambda, opt_AST_Lambda);
|
|
648
655
|
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
|
649
656
|
var self = this;
|
650
657
|
if (compressor.has_directive("use asm")) return self;
|
651
|
-
// Hoisting makes no sense in an arrow func
|
652
|
-
if (!Array.isArray(self.body)) return self;
|
653
658
|
|
654
659
|
var hoist_funs = compressor.option("hoist_funs");
|
655
660
|
var hoist_vars = compressor.option("hoist_vars");
|
@@ -2599,8 +2604,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
|
|
2599
2604
|
}
|
2600
2605
|
}
|
2601
2606
|
|
2602
|
-
|
2603
|
-
if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
|
2607
|
+
if (compressor.option("reduce_vars") && !compressor.is_lhs()) {
|
2604
2608
|
return inline_into_symbolref(self, compressor);
|
2605
2609
|
} else {
|
2606
2610
|
return self;
|
@@ -2624,7 +2628,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
|
|
2624
2628
|
return ref;
|
2625
2629
|
}
|
2626
2630
|
}
|
2627
|
-
var lhs =
|
2631
|
+
var lhs = compressor.is_lhs();
|
2628
2632
|
if (lhs && is_atomic(lhs, self)) return self;
|
2629
2633
|
return make_node(AST_UnaryPrefix, self, {
|
2630
2634
|
operator: "void",
|
@@ -2635,7 +2639,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
|
|
2635
2639
|
});
|
2636
2640
|
|
2637
2641
|
def_optimize(AST_Infinity, function(self, compressor) {
|
2638
|
-
var lhs =
|
2642
|
+
var lhs = compressor.is_lhs();
|
2639
2643
|
if (lhs && is_atomic(lhs, self)) return self;
|
2640
2644
|
if (
|
2641
2645
|
compressor.option("keep_infinity")
|
@@ -2656,7 +2660,7 @@ def_optimize(AST_Infinity, function(self, compressor) {
|
|
2656
2660
|
});
|
2657
2661
|
|
2658
2662
|
def_optimize(AST_NaN, function(self, compressor) {
|
2659
|
-
var lhs =
|
2663
|
+
var lhs = compressor.is_lhs();
|
2660
2664
|
if (lhs && !is_atomic(lhs, self)
|
2661
2665
|
|| find_variable(compressor, "NaN")) {
|
2662
2666
|
return make_node(AST_Binary, self, {
|
@@ -3232,7 +3236,10 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
3232
3236
|
}
|
3233
3237
|
}
|
3234
3238
|
}
|
3235
|
-
prop = self.property = best_of_expression(
|
3239
|
+
prop = self.property = best_of_expression(
|
3240
|
+
prop,
|
3241
|
+
make_node_from_constant(key, prop).transform(compressor)
|
3242
|
+
);
|
3236
3243
|
var property = "" + key;
|
3237
3244
|
if (is_basic_identifier_string(property)
|
3238
3245
|
&& property.length <= prop.size() + 1) {
|
@@ -3290,7 +3297,7 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
3290
3297
|
return sym;
|
3291
3298
|
}
|
3292
3299
|
}
|
3293
|
-
if (
|
3300
|
+
if (compressor.is_lhs()) return self;
|
3294
3301
|
if (key !== prop) {
|
3295
3302
|
var sub = self.flatten_object(property, compressor);
|
3296
3303
|
if (sub) {
|
@@ -3360,7 +3367,7 @@ def_optimize(AST_Chain, function (self, compressor) {
|
|
3360
3367
|
|
3361
3368
|
def_optimize(AST_Dot, function(self, compressor) {
|
3362
3369
|
const parent = compressor.parent();
|
3363
|
-
if (is_lhs(
|
3370
|
+
if (compressor.is_lhs()) return self;
|
3364
3371
|
if (compressor.option("unsafe_proto")
|
3365
3372
|
&& self.expression instanceof AST_Dot
|
3366
3373
|
&& self.expression.property == "prototype") {
|
@@ -818,6 +818,9 @@ export function is_lhs(node, parent) {
|
|
818
818
|
def_negate(AST_Function, function() {
|
819
819
|
return basic_negation(this);
|
820
820
|
});
|
821
|
+
def_negate(AST_Class, function() {
|
822
|
+
return basic_negation(this);
|
823
|
+
});
|
821
824
|
def_negate(AST_Arrow, function() {
|
822
825
|
return basic_negation(this);
|
823
826
|
});
|
package/lib/output.js
CHANGED
@@ -662,14 +662,17 @@ function OutputStream(options) {
|
|
662
662
|
if (!start) return;
|
663
663
|
var printed_comments = self.printed_comments;
|
664
664
|
|
665
|
-
// There cannot be a newline between return and its value.
|
666
|
-
const
|
665
|
+
// There cannot be a newline between return/yield and its value.
|
666
|
+
const keyword_with_value =
|
667
|
+
node instanceof AST_Exit && node.value
|
668
|
+
|| (node instanceof AST_Await || node instanceof AST_Yield)
|
669
|
+
&& node.expression;
|
667
670
|
|
668
671
|
if (
|
669
672
|
start.comments_before
|
670
673
|
&& printed_comments.has(start.comments_before)
|
671
674
|
) {
|
672
|
-
if (
|
675
|
+
if (keyword_with_value) {
|
673
676
|
start.comments_before = [];
|
674
677
|
} else {
|
675
678
|
return;
|
@@ -682,10 +685,12 @@ function OutputStream(options) {
|
|
682
685
|
}
|
683
686
|
printed_comments.add(comments);
|
684
687
|
|
685
|
-
if (
|
688
|
+
if (keyword_with_value) {
|
686
689
|
var tw = new TreeWalker(function(node) {
|
687
690
|
var parent = tw.parent();
|
688
691
|
if (parent instanceof AST_Exit
|
692
|
+
|| parent instanceof AST_Await
|
693
|
+
|| parent instanceof AST_Yield
|
689
694
|
|| parent instanceof AST_Binary && parent.left === node
|
690
695
|
|| parent.TYPE == "Call" && parent.expression === node
|
691
696
|
|| parent instanceof AST_Conditional && parent.condition === node
|
@@ -704,7 +709,7 @@ function OutputStream(options) {
|
|
704
709
|
}
|
705
710
|
});
|
706
711
|
tw.push(node);
|
707
|
-
|
712
|
+
keyword_with_value.walk(tw);
|
708
713
|
}
|
709
714
|
|
710
715
|
if (current_pos == 0) {
|