terser 5.7.2 → 5.8.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/README.md +15 -2
- package/bin/terser.mjs +21 -0
- package/dist/bundle.min.js +422 -110
- package/lib/ast.js +1 -1
- package/lib/compress/index.js +293 -44
- package/lib/compress/tighten-body.js +29 -7
- package/lib/minify.js +2 -2
- package/lib/output.js +9 -4
- package/lib/propmangle.js +54 -31
- package/lib/scope.js +37 -17
- package/lib/transform.js +2 -2
- package/package.json +9 -9
- package/tools/terser.d.ts +36 -0
package/dist/bundle.min.js
CHANGED
@@ -1214,7 +1214,7 @@ function parse($TEXT, options) {
|
|
1214
1214
|
// Example: /* I count */ ( /* I don't */ foo() )
|
1215
1215
|
// Useful because comments_before property of call with parens outside
|
1216
1216
|
// contains both comments inside and outside these parens. Used to find the
|
1217
|
-
|
1217
|
+
|
1218
1218
|
const outer_comments_before_counts = new WeakMap();
|
1219
1219
|
|
1220
1220
|
options = defaults(options, {
|
@@ -4819,7 +4819,7 @@ var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", {
|
|
4819
4819
|
}
|
4820
4820
|
}, AST_ObjectProperty);
|
4821
4821
|
|
4822
|
-
var AST_ClassPrivateProperty = DEFNODE("
|
4822
|
+
var AST_ClassPrivateProperty = DEFNODE("ClassPrivateProperty", "", {
|
4823
4823
|
$documentation: "A class property for a private property",
|
4824
4824
|
}, AST_ClassProperty);
|
4825
4825
|
|
@@ -5521,7 +5521,7 @@ def_transform(AST_Sequence, function(self, tw) {
|
|
5521
5521
|
: [new AST_Number({ value: 0 })];
|
5522
5522
|
});
|
5523
5523
|
|
5524
|
-
def_transform(
|
5524
|
+
def_transform(AST_PropAccess, function(self, tw) {
|
5525
5525
|
self.expression = self.expression.transform(tw);
|
5526
5526
|
});
|
5527
5527
|
|
@@ -7093,9 +7093,11 @@ function OutputStream(options) {
|
|
7093
7093
|
var do_add_mapping = mappings ? function() {
|
7094
7094
|
mappings.forEach(function(mapping) {
|
7095
7095
|
try {
|
7096
|
-
let
|
7097
|
-
if (name
|
7098
|
-
name =
|
7096
|
+
let { name, token } = mapping;
|
7097
|
+
if (token.type == "name" || token.type === "privatename") {
|
7098
|
+
name = token.value;
|
7099
|
+
} else if (name instanceof AST_Symbol) {
|
7100
|
+
name = token.type === "string" ? token.value : name.name;
|
7099
7101
|
}
|
7100
7102
|
options.source_map.add(
|
7101
7103
|
mapping.token.file,
|
@@ -8568,6 +8570,7 @@ function OutputStream(options) {
|
|
8568
8570
|
|
8569
8571
|
if (self.optional) output.print("?");
|
8570
8572
|
output.print(".#");
|
8573
|
+
output.add_mapping(self.end);
|
8571
8574
|
output.print_name(prop);
|
8572
8575
|
});
|
8573
8576
|
DEFPRINT(AST_Sub, function(self, output) {
|
@@ -9021,8 +9024,10 @@ function OutputStream(options) {
|
|
9021
9024
|
DEFMAP([
|
9022
9025
|
AST_ObjectGetter,
|
9023
9026
|
AST_ObjectSetter,
|
9027
|
+
AST_PrivateGetter,
|
9028
|
+
AST_PrivateSetter,
|
9024
9029
|
], function(output) {
|
9025
|
-
output.add_mapping(this.
|
9030
|
+
output.add_mapping(this.key.end, this.key.name);
|
9026
9031
|
});
|
9027
9032
|
|
9028
9033
|
DEFMAP([ AST_ObjectProperty ], function(output) {
|
@@ -9877,8 +9882,9 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
|
9877
9882
|
|
9878
9883
|
function next_mangled(scope, options) {
|
9879
9884
|
var ext = scope.enclosed;
|
9885
|
+
var nth_identifier = options.nth_identifier;
|
9880
9886
|
out: while (true) {
|
9881
|
-
var m =
|
9887
|
+
var m = nth_identifier.get(++scope.cname);
|
9882
9888
|
if (ALL_RESERVED_WORDS.has(m)) continue; // skip over "do"
|
9883
9889
|
|
9884
9890
|
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
@@ -9954,6 +9960,7 @@ AST_Symbol.DEFMETHOD("global", function() {
|
|
9954
9960
|
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
|
9955
9961
|
options = defaults(options, {
|
9956
9962
|
eval : false,
|
9963
|
+
nth_identifier : base54,
|
9957
9964
|
ie8 : false,
|
9958
9965
|
keep_classnames: false,
|
9959
9966
|
keep_fnames : false,
|
@@ -9975,6 +9982,7 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
|
|
9975
9982
|
|
9976
9983
|
AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
9977
9984
|
options = this._default_mangler_options(options);
|
9985
|
+
var nth_identifier = options.nth_identifier;
|
9978
9986
|
|
9979
9987
|
// We only need to mangle declaration nodes. Special logic wired
|
9980
9988
|
// into the code generator will display the mangled name if it's
|
@@ -10026,7 +10034,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|
10026
10034
|
if (node instanceof AST_Label) {
|
10027
10035
|
let name;
|
10028
10036
|
do {
|
10029
|
-
name =
|
10037
|
+
name = nth_identifier.get(++lname);
|
10030
10038
|
} while (ALL_RESERVED_WORDS.has(name));
|
10031
10039
|
node.mangled_name = name;
|
10032
10040
|
return true;
|
@@ -10088,9 +10096,12 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
|
10088
10096
|
});
|
10089
10097
|
|
10090
10098
|
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
10091
|
-
base54.reset();
|
10092
|
-
base54.sort();
|
10093
10099
|
options = this._default_mangler_options(options);
|
10100
|
+
var nth_identifier = options.nth_identifier;
|
10101
|
+
if (nth_identifier.reset && nth_identifier.sort) {
|
10102
|
+
nth_identifier.reset();
|
10103
|
+
nth_identifier.sort();
|
10104
|
+
}
|
10094
10105
|
var avoid = this.find_colliding_names(options);
|
10095
10106
|
var cname = 0;
|
10096
10107
|
this.globals.forEach(rename);
|
@@ -10102,7 +10113,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|
10102
10113
|
function next_name() {
|
10103
10114
|
var name;
|
10104
10115
|
do {
|
10105
|
-
name =
|
10116
|
+
name = nth_identifier.get(cname++);
|
10106
10117
|
} while (avoid.has(name) || ALL_RESERVED_WORDS.has(name));
|
10107
10118
|
return name;
|
10108
10119
|
}
|
@@ -10129,30 +10140,37 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
|
|
10129
10140
|
|
10130
10141
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
10131
10142
|
options = this._default_mangler_options(options);
|
10143
|
+
var nth_identifier = options.nth_identifier;
|
10144
|
+
if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) {
|
10145
|
+
// If the identifier mangler is invariant, skip computing character frequency.
|
10146
|
+
return;
|
10147
|
+
}
|
10148
|
+
nth_identifier.reset();
|
10149
|
+
|
10132
10150
|
try {
|
10133
10151
|
AST_Node.prototype.print = function(stream, force_parens) {
|
10134
10152
|
this._print(stream, force_parens);
|
10135
10153
|
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
10136
|
-
|
10154
|
+
nth_identifier.consider(this.name, -1);
|
10137
10155
|
} else if (options.properties) {
|
10138
10156
|
if (this instanceof AST_DotHash) {
|
10139
|
-
|
10157
|
+
nth_identifier.consider("#" + this.property, -1);
|
10140
10158
|
} else if (this instanceof AST_Dot) {
|
10141
|
-
|
10159
|
+
nth_identifier.consider(this.property, -1);
|
10142
10160
|
} else if (this instanceof AST_Sub) {
|
10143
10161
|
skip_string(this.property);
|
10144
10162
|
}
|
10145
10163
|
}
|
10146
10164
|
};
|
10147
|
-
|
10165
|
+
nth_identifier.consider(this.print_to_string(), 1);
|
10148
10166
|
} finally {
|
10149
10167
|
AST_Node.prototype.print = AST_Node.prototype._print;
|
10150
10168
|
}
|
10151
|
-
|
10169
|
+
nth_identifier.sort();
|
10152
10170
|
|
10153
10171
|
function skip_string(node) {
|
10154
10172
|
if (node instanceof AST_String) {
|
10155
|
-
|
10173
|
+
nth_identifier.consider(node.value, -1);
|
10156
10174
|
} else if (node instanceof AST_Conditional) {
|
10157
10175
|
skip_string(node.consequent);
|
10158
10176
|
skip_string(node.alternative);
|
@@ -10176,19 +10194,20 @@ const base54 = (() => {
|
|
10176
10194
|
frequency.set(ch, 0);
|
10177
10195
|
});
|
10178
10196
|
}
|
10179
|
-
|
10197
|
+
function consider(str, delta) {
|
10180
10198
|
for (var i = str.length; --i >= 0;) {
|
10181
10199
|
frequency.set(str[i], frequency.get(str[i]) + delta);
|
10182
10200
|
}
|
10183
|
-
}
|
10201
|
+
}
|
10184
10202
|
function compare(a, b) {
|
10185
10203
|
return frequency.get(b) - frequency.get(a);
|
10186
10204
|
}
|
10187
|
-
|
10205
|
+
function sort() {
|
10188
10206
|
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
10189
|
-
}
|
10190
|
-
|
10207
|
+
}
|
10208
|
+
// Ensure this is in a usable initial state.
|
10191
10209
|
reset();
|
10210
|
+
sort();
|
10192
10211
|
function base54(num) {
|
10193
10212
|
var ret = "", base = 54;
|
10194
10213
|
num++;
|
@@ -10200,7 +10219,13 @@ const base54 = (() => {
|
|
10200
10219
|
} while (num > 0);
|
10201
10220
|
return ret;
|
10202
10221
|
}
|
10203
|
-
|
10222
|
+
|
10223
|
+
return {
|
10224
|
+
get: base54,
|
10225
|
+
consider,
|
10226
|
+
reset,
|
10227
|
+
sort
|
10228
|
+
};
|
10204
10229
|
})();
|
10205
10230
|
|
10206
10231
|
let mangle_options = undefined;
|
@@ -13527,7 +13552,9 @@ function tighten_body(statements, compressor) {
|
|
13527
13552
|
// Replace variable with assignment when found
|
13528
13553
|
if (can_replace
|
13529
13554
|
&& !(node instanceof AST_SymbolDeclaration)
|
13530
|
-
&& lhs.equivalent_to(node)
|
13555
|
+
&& lhs.equivalent_to(node)
|
13556
|
+
&& !shadows(node.scope, lvalues)
|
13557
|
+
) {
|
13531
13558
|
if (stop_if_hit) {
|
13532
13559
|
abort = true;
|
13533
13560
|
return node;
|
@@ -13575,7 +13602,7 @@ function tighten_body(statements, compressor) {
|
|
13575
13602
|
|| node instanceof AST_PropAccess
|
13576
13603
|
&& (side_effects || node.expression.may_throw_on_access(compressor))
|
13577
13604
|
|| node instanceof AST_SymbolRef
|
13578
|
-
&& (lvalues.get(node.name) || side_effects && may_modify(node))
|
13605
|
+
&& ((lvalues.has(node.name) && lvalues.get(node.name).modified) || side_effects && may_modify(node))
|
13579
13606
|
|| node instanceof AST_VarDef && node.value
|
13580
13607
|
&& (lvalues.has(node.name.name) || side_effects && may_modify(node.name))
|
13581
13608
|
|| (sym = is_lhs(node.left, node))
|
@@ -13648,8 +13675,9 @@ function tighten_body(statements, compressor) {
|
|
13648
13675
|
// Locate symbols which may execute code outside of scanning range
|
13649
13676
|
var lvalues = get_lvalues(candidate);
|
13650
13677
|
var lhs_local = is_lhs_local(lhs);
|
13651
|
-
if (lhs instanceof AST_SymbolRef)
|
13652
|
-
lvalues.set(lhs.name, false);
|
13678
|
+
if (lhs instanceof AST_SymbolRef) {
|
13679
|
+
lvalues.set(lhs.name, { def: lhs.definition(), modified: false });
|
13680
|
+
}
|
13653
13681
|
var side_effects = value_has_side_effects(candidate);
|
13654
13682
|
var replace_all = replace_all_symbols();
|
13655
13683
|
var may_throw = candidate.may_throw(compressor);
|
@@ -13715,8 +13743,9 @@ function tighten_body(statements, compressor) {
|
|
13715
13743
|
return false;
|
13716
13744
|
let cur_scope = def.scope;
|
13717
13745
|
while (cur_scope && cur_scope !== scope) {
|
13718
|
-
if (cur_scope.variables.has(def.name))
|
13746
|
+
if (cur_scope.variables.has(def.name)) {
|
13719
13747
|
return true;
|
13748
|
+
}
|
13720
13749
|
cur_scope = cur_scope.parent_scope;
|
13721
13750
|
}
|
13722
13751
|
return false;
|
@@ -13997,8 +14026,14 @@ function tighten_body(statements, compressor) {
|
|
13997
14026
|
var sym = node;
|
13998
14027
|
while (sym instanceof AST_PropAccess)
|
13999
14028
|
sym = sym.expression;
|
14000
|
-
if (sym instanceof AST_SymbolRef
|
14001
|
-
|
14029
|
+
if (sym instanceof AST_SymbolRef) {
|
14030
|
+
const prev = lvalues.get(sym.name);
|
14031
|
+
if (!prev || !prev.modified) {
|
14032
|
+
lvalues.set(sym.name, {
|
14033
|
+
def: sym.definition(),
|
14034
|
+
modified: is_modified(compressor, tw, node, node, 0)
|
14035
|
+
});
|
14036
|
+
}
|
14002
14037
|
}
|
14003
14038
|
});
|
14004
14039
|
get_rvalue(expr).walk(tw);
|
@@ -14110,6 +14145,18 @@ function tighten_body(statements, compressor) {
|
|
14110
14145
|
}
|
14111
14146
|
return false;
|
14112
14147
|
}
|
14148
|
+
|
14149
|
+
function shadows(newScope, lvalues) {
|
14150
|
+
for (const {def} of lvalues.values()) {
|
14151
|
+
let current = newScope;
|
14152
|
+
while (current && current !== def.scope) {
|
14153
|
+
let nested_def = current.variables.get(def.name);
|
14154
|
+
if (nested_def && nested_def !== def) return true;
|
14155
|
+
current = current.parent_scope;
|
14156
|
+
}
|
14157
|
+
}
|
14158
|
+
return false;
|
14159
|
+
}
|
14113
14160
|
}
|
14114
14161
|
|
14115
14162
|
function eliminate_spurious_blocks(statements) {
|
@@ -14853,7 +14900,8 @@ class Compressor extends TreeWalker {
|
|
14853
14900
|
var passes = +this.options.passes || 1;
|
14854
14901
|
var min_count = 1 / 0;
|
14855
14902
|
var stopping = false;
|
14856
|
-
var
|
14903
|
+
var nth_identifier = this.mangle_options && this.mangle_options.nth_identifier || base54;
|
14904
|
+
var mangle = { ie8: this.option("ie8"), nth_identifier: nth_identifier };
|
14857
14905
|
for (var pass = 0; pass < passes; pass++) {
|
14858
14906
|
this._toplevel.figure_out_scope(mangle);
|
14859
14907
|
if (pass === 0 && this.option("drop_console")) {
|
@@ -16055,58 +16103,251 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
16055
16103
|
}
|
16056
16104
|
}
|
16057
16105
|
}
|
16058
|
-
if (aborts(branch)) {
|
16059
|
-
var prev = body[body.length - 1];
|
16060
|
-
if (aborts(prev) && prev.body.length == branch.body.length
|
16061
|
-
&& make_node(AST_BlockStatement, prev, prev).equivalent_to(make_node(AST_BlockStatement, branch, branch))) {
|
16062
|
-
prev.body = [];
|
16063
|
-
}
|
16064
|
-
}
|
16065
16106
|
body.push(branch);
|
16066
16107
|
}
|
16067
16108
|
while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]);
|
16109
|
+
self.body = body;
|
16110
|
+
|
16111
|
+
for (let i = 0; i < body.length; i++) {
|
16112
|
+
let branch = body[i];
|
16113
|
+
if (branch.body.length === 0) continue;
|
16114
|
+
if (!aborts(branch)) continue;
|
16115
|
+
|
16116
|
+
for (let j = i + 1; j < body.length; i++, j++) {
|
16117
|
+
let next = body[j];
|
16118
|
+
if (next.body.length === 0) continue;
|
16119
|
+
if (
|
16120
|
+
branches_equivalent(next, branch, false)
|
16121
|
+
|| (j === body.length - 1 && branches_equivalent(next, branch, true))
|
16122
|
+
) {
|
16123
|
+
branch.body = [];
|
16124
|
+
branch = next;
|
16125
|
+
continue;
|
16126
|
+
}
|
16127
|
+
break;
|
16128
|
+
}
|
16129
|
+
}
|
16130
|
+
|
16131
|
+
let default_or_exact = default_branch || exact_match;
|
16132
|
+
default_branch = null;
|
16133
|
+
exact_match = null;
|
16134
|
+
|
16135
|
+
// Prune any empty branches at the end of the switch statement.
|
16136
|
+
{
|
16137
|
+
let i = body.length - 1;
|
16138
|
+
for (; i >= 0; i--) {
|
16139
|
+
let bbody = body[i].body;
|
16140
|
+
if (is_break(bbody[bbody.length - 1], compressor)) bbody.pop();
|
16141
|
+
if (!is_inert_body(body[i])) break;
|
16142
|
+
}
|
16143
|
+
// i now points to the index of a branch that contains a body. By incrementing, it's
|
16144
|
+
// pointing to the first branch that's empty.
|
16145
|
+
i++;
|
16146
|
+
if (!default_or_exact || body.indexOf(default_or_exact) >= i) {
|
16147
|
+
// The default behavior is to do nothing. We can take advantage of that to
|
16148
|
+
// remove all case expressions that are side-effect free that also do
|
16149
|
+
// nothing, since they'll default to doing nothing. But we can't remove any
|
16150
|
+
// case expressions before one that would side-effect, since they may cause
|
16151
|
+
// the side-effect to be skipped.
|
16152
|
+
for (let j = body.length - 1; j >= i; j--) {
|
16153
|
+
let branch = body[j];
|
16154
|
+
if (branch === default_or_exact) {
|
16155
|
+
default_or_exact = null;
|
16156
|
+
body.pop();
|
16157
|
+
} else if (!branch.expression.has_side_effects(compressor)) {
|
16158
|
+
body.pop();
|
16159
|
+
} else {
|
16160
|
+
break;
|
16161
|
+
}
|
16162
|
+
}
|
16163
|
+
}
|
16164
|
+
}
|
16165
|
+
|
16166
|
+
|
16167
|
+
// Prune side-effect free branches that fall into default.
|
16168
|
+
if (default_or_exact) {
|
16169
|
+
let default_index = body.indexOf(default_or_exact);
|
16170
|
+
let default_body_index = default_index;
|
16171
|
+
for (; default_body_index < body.length - 1; default_body_index++) {
|
16172
|
+
if (!is_inert_body(body[default_body_index])) break;
|
16173
|
+
}
|
16174
|
+
let side_effect_index = body.length - 1;
|
16175
|
+
for (; side_effect_index >= 0; side_effect_index--) {
|
16176
|
+
let branch = body[side_effect_index];
|
16177
|
+
if (branch === default_or_exact) continue;
|
16178
|
+
if (branch.expression.has_side_effects(compressor)) break;
|
16179
|
+
}
|
16180
|
+
// If the default behavior comes after any side-effect case expressions,
|
16181
|
+
// then we can fold all side-effect free cases into the default branch.
|
16182
|
+
// If the side-effect case is after the default, then any side-effect
|
16183
|
+
// free cases could prevent the side-effect from occurring.
|
16184
|
+
if (default_body_index > side_effect_index) {
|
16185
|
+
let prev_body_index = default_index - 1;
|
16186
|
+
for (; prev_body_index >= 0; prev_body_index--) {
|
16187
|
+
if (!is_inert_body(body[prev_body_index])) break;
|
16188
|
+
}
|
16189
|
+
let before = Math.max(side_effect_index, prev_body_index) + 1;
|
16190
|
+
let after = default_index;
|
16191
|
+
if (side_effect_index > default_index) {
|
16192
|
+
// If the default falls into the same body as a side-effect
|
16193
|
+
// case, then we need preserve that case and only prune the
|
16194
|
+
// cases after it.
|
16195
|
+
after = side_effect_index;
|
16196
|
+
body[side_effect_index].body = body[default_body_index].body;
|
16197
|
+
} else {
|
16198
|
+
// The default will be the last branch.
|
16199
|
+
default_or_exact.body = body[default_body_index].body;
|
16200
|
+
}
|
16201
|
+
|
16202
|
+
// Prune everything after the default (or last side-effect case)
|
16203
|
+
// until the next case with a body.
|
16204
|
+
body.splice(after + 1, default_body_index - after);
|
16205
|
+
// Prune everything before the default that falls into it.
|
16206
|
+
body.splice(before, default_index - before);
|
16207
|
+
}
|
16208
|
+
}
|
16209
|
+
|
16210
|
+
// See if we can remove the switch entirely if all cases (the default) fall into the same case body.
|
16211
|
+
DEFAULT: if (default_or_exact) {
|
16212
|
+
let i = body.findIndex(branch => !is_inert_body(branch));
|
16213
|
+
let caseBody;
|
16214
|
+
// `i` is equal to one of the following:
|
16215
|
+
// - `-1`, there is no body in the switch statement.
|
16216
|
+
// - `body.length - 1`, all cases fall into the same body.
|
16217
|
+
// - anything else, there are multiple bodies in the switch.
|
16218
|
+
if (i === body.length - 1) {
|
16219
|
+
// All cases fall into the case body.
|
16220
|
+
let branch = body[i];
|
16221
|
+
if (has_nested_break(self)) break DEFAULT;
|
16222
|
+
|
16223
|
+
// This is the last case body, and we've already pruned any breaks, so it's
|
16224
|
+
// safe to hoist.
|
16225
|
+
caseBody = make_node(AST_BlockStatement, branch, {
|
16226
|
+
body: branch.body
|
16227
|
+
});
|
16228
|
+
branch.body = [];
|
16229
|
+
} else if (i !== -1) {
|
16230
|
+
// If there are multiple bodies, then we cannot optimize anything.
|
16231
|
+
break DEFAULT;
|
16232
|
+
}
|
16233
|
+
|
16234
|
+
let sideEffect = body.find(branch => {
|
16235
|
+
return (
|
16236
|
+
branch !== default_or_exact
|
16237
|
+
&& branch.expression.has_side_effects(compressor)
|
16238
|
+
);
|
16239
|
+
});
|
16240
|
+
// If no cases cause a side-effect, we can eliminate the switch entirely.
|
16241
|
+
if (!sideEffect) {
|
16242
|
+
return make_node(AST_BlockStatement, self, {
|
16243
|
+
body: decl.concat(
|
16244
|
+
statement(self.expression),
|
16245
|
+
default_or_exact.expression ? statement(default_or_exact.expression) : [],
|
16246
|
+
caseBody || []
|
16247
|
+
)
|
16248
|
+
}).optimize(compressor);
|
16249
|
+
}
|
16250
|
+
|
16251
|
+
// If we're this far, either there was no body or all cases fell into the same body.
|
16252
|
+
// If there was no body, then we don't need a default branch (because the default is
|
16253
|
+
// do nothing). If there was a body, we'll extract it to after the switch, so the
|
16254
|
+
// switch's new default is to do nothing and we can still prune it.
|
16255
|
+
const default_index = body.indexOf(default_or_exact);
|
16256
|
+
body.splice(default_index, 1);
|
16257
|
+
default_or_exact = null;
|
16258
|
+
|
16259
|
+
if (caseBody) {
|
16260
|
+
// Recurse into switch statement one more time so that we can append the case body
|
16261
|
+
// outside of the switch. This recursion will only happen once since we've pruned
|
16262
|
+
// the default case.
|
16263
|
+
return make_node(AST_BlockStatement, self, {
|
16264
|
+
body: decl.concat(self, caseBody)
|
16265
|
+
}).optimize(compressor);
|
16266
|
+
}
|
16267
|
+
// If we fall here, there is a default branch somewhere, there are no case bodies,
|
16268
|
+
// and there's a side-effect somewhere. Just let the below paths take care of it.
|
16269
|
+
}
|
16270
|
+
|
16068
16271
|
if (body.length > 0) {
|
16069
16272
|
body[0].body = decl.concat(body[0].body);
|
16070
16273
|
}
|
16071
|
-
|
16072
|
-
while (branch = body[body.length - 1]) {
|
16073
|
-
var stat = branch.body[branch.body.length - 1];
|
16074
|
-
if (stat instanceof AST_Break && compressor.loopcontrol_target(stat) === self)
|
16075
|
-
branch.body.pop();
|
16076
|
-
if (branch.body.length || branch instanceof AST_Case
|
16077
|
-
&& (default_branch || branch.expression.has_side_effects(compressor))) break;
|
16078
|
-
if (body.pop() === default_branch) default_branch = null;
|
16079
|
-
}
|
16274
|
+
|
16080
16275
|
if (body.length == 0) {
|
16081
16276
|
return make_node(AST_BlockStatement, self, {
|
16082
|
-
body: decl.concat(
|
16083
|
-
body: self.expression
|
16084
|
-
}))
|
16277
|
+
body: decl.concat(statement(self.expression))
|
16085
16278
|
}).optimize(compressor);
|
16086
16279
|
}
|
16087
|
-
if (body.length == 1 && (
|
16088
|
-
|
16089
|
-
|
16090
|
-
|
16091
|
-
|
16092
|
-
|
16093
|
-
|
16094
|
-
|
16095
|
-
|
16096
|
-
|
16097
|
-
|
16098
|
-
|
16099
|
-
|
16100
|
-
|
16101
|
-
|
16102
|
-
|
16103
|
-
|
16104
|
-
|
16105
|
-
|
16106
|
-
|
16107
|
-
|
16280
|
+
if (body.length == 1 && !has_nested_break(self)) {
|
16281
|
+
// This is the last case body, and we've already pruned any breaks, so it's
|
16282
|
+
// safe to hoist.
|
16283
|
+
let branch = body[0];
|
16284
|
+
return make_node(AST_If, self, {
|
16285
|
+
condition: make_node(AST_Binary, self, {
|
16286
|
+
operator: "===",
|
16287
|
+
left: self.expression,
|
16288
|
+
right: branch.expression,
|
16289
|
+
}),
|
16290
|
+
body: make_node(AST_BlockStatement, branch, {
|
16291
|
+
body: branch.body
|
16292
|
+
}),
|
16293
|
+
alternative: null
|
16294
|
+
}).optimize(compressor);
|
16295
|
+
}
|
16296
|
+
if (body.length === 2 && default_or_exact && !has_nested_break(self)) {
|
16297
|
+
let branch = body[0] === default_or_exact ? body[1] : body[0];
|
16298
|
+
let exact_exp = default_or_exact.expression && statement(default_or_exact.expression);
|
16299
|
+
if (aborts(body[0])) {
|
16300
|
+
// Only the first branch body could have a break (at the last statement)
|
16301
|
+
let first = body[0];
|
16302
|
+
if (is_break(first.body[first.body.length - 1], compressor)) {
|
16303
|
+
first.body.pop();
|
16304
|
+
}
|
16305
|
+
return make_node(AST_If, self, {
|
16306
|
+
condition: make_node(AST_Binary, self, {
|
16307
|
+
operator: "===",
|
16308
|
+
left: self.expression,
|
16309
|
+
right: branch.expression,
|
16310
|
+
}),
|
16311
|
+
body: make_node(AST_BlockStatement, branch, {
|
16312
|
+
body: branch.body
|
16313
|
+
}),
|
16314
|
+
alternative: make_node(AST_BlockStatement, default_or_exact, {
|
16315
|
+
body: [].concat(
|
16316
|
+
exact_exp || [],
|
16317
|
+
default_or_exact.body
|
16318
|
+
)
|
16319
|
+
})
|
16108
16320
|
}).optimize(compressor);
|
16109
16321
|
}
|
16322
|
+
let operator = "===";
|
16323
|
+
let consequent = make_node(AST_BlockStatement, branch, {
|
16324
|
+
body: branch.body,
|
16325
|
+
});
|
16326
|
+
let always = make_node(AST_BlockStatement, default_or_exact, {
|
16327
|
+
body: [].concat(
|
16328
|
+
exact_exp || [],
|
16329
|
+
default_or_exact.body
|
16330
|
+
)
|
16331
|
+
});
|
16332
|
+
if (body[0] === default_or_exact) {
|
16333
|
+
operator = "!==";
|
16334
|
+
let tmp = always;
|
16335
|
+
always = consequent;
|
16336
|
+
consequent = tmp;
|
16337
|
+
}
|
16338
|
+
return make_node(AST_BlockStatement, self, {
|
16339
|
+
body: [
|
16340
|
+
make_node(AST_If, self, {
|
16341
|
+
condition: make_node(AST_Binary, self, {
|
16342
|
+
operator: operator,
|
16343
|
+
left: self.expression,
|
16344
|
+
right: branch.expression,
|
16345
|
+
}),
|
16346
|
+
body: consequent,
|
16347
|
+
alternative: null
|
16348
|
+
})
|
16349
|
+
].concat(always)
|
16350
|
+
}).optimize(compressor);
|
16110
16351
|
}
|
16111
16352
|
return self;
|
16112
16353
|
|
@@ -16117,6 +16358,50 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
16117
16358
|
trim_unreachable_code(compressor, branch, decl);
|
16118
16359
|
}
|
16119
16360
|
}
|
16361
|
+
function branches_equivalent(branch, prev, insertBreak) {
|
16362
|
+
let bbody = branch.body;
|
16363
|
+
let pbody = prev.body;
|
16364
|
+
if (insertBreak) {
|
16365
|
+
bbody = bbody.concat(make_node(AST_Break));
|
16366
|
+
}
|
16367
|
+
if (bbody.length !== pbody.length) return false;
|
16368
|
+
let bblock = make_node(AST_BlockStatement, branch, { body: bbody });
|
16369
|
+
let pblock = make_node(AST_BlockStatement, prev, { body: pbody });
|
16370
|
+
return bblock.equivalent_to(pblock);
|
16371
|
+
}
|
16372
|
+
function statement(expression) {
|
16373
|
+
return make_node(AST_SimpleStatement, expression, {
|
16374
|
+
body: expression
|
16375
|
+
});
|
16376
|
+
}
|
16377
|
+
function has_nested_break(root) {
|
16378
|
+
let has_break = false;
|
16379
|
+
let tw = new TreeWalker(node => {
|
16380
|
+
if (has_break) return true;
|
16381
|
+
if (node instanceof AST_Lambda) return true;
|
16382
|
+
if (node instanceof AST_SimpleStatement) return true;
|
16383
|
+
if (!is_break(node, tw)) return;
|
16384
|
+
let parent = tw.parent();
|
16385
|
+
if (
|
16386
|
+
parent instanceof AST_SwitchBranch
|
16387
|
+
&& parent.body[parent.body.length - 1] === node
|
16388
|
+
) {
|
16389
|
+
return;
|
16390
|
+
}
|
16391
|
+
has_break = true;
|
16392
|
+
});
|
16393
|
+
root.walk(tw);
|
16394
|
+
return has_break;
|
16395
|
+
}
|
16396
|
+
function is_break(node, stack) {
|
16397
|
+
return node instanceof AST_Break
|
16398
|
+
&& stack.loopcontrol_target(node) === self;
|
16399
|
+
}
|
16400
|
+
function is_inert_body(branch) {
|
16401
|
+
return !aborts(branch) && !make_node(AST_BlockStatement, branch, {
|
16402
|
+
body: branch.body
|
16403
|
+
}).has_side_effects(compressor);
|
16404
|
+
}
|
16120
16405
|
});
|
16121
16406
|
|
16122
16407
|
def_optimize(AST_Try, function(self, compressor) {
|
@@ -16283,6 +16568,14 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
16283
16568
|
}
|
16284
16569
|
|
16285
16570
|
if (compressor.option("unsafe")) {
|
16571
|
+
if (exp instanceof AST_Dot && exp.start.value === "Array" && exp.property === "from" && self.args.length === 1) {
|
16572
|
+
const [argument] = self.args;
|
16573
|
+
if (argument instanceof AST_Array) {
|
16574
|
+
return make_node(AST_Array, argument, {
|
16575
|
+
elements: argument.elements
|
16576
|
+
}).optimize(compressor);
|
16577
|
+
}
|
16578
|
+
}
|
16286
16579
|
if (is_undeclared_ref(exp)) switch (exp.name) {
|
16287
16580
|
case "Array":
|
16288
16581
|
if (self.args.length != 1) {
|
@@ -16488,6 +16781,7 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
16488
16781
|
argnames: [],
|
16489
16782
|
body: []
|
16490
16783
|
}).optimize(compressor);
|
16784
|
+
var nth_identifier = compressor.mangle_options && compressor.mangle_options.nth_identifier || base54;
|
16491
16785
|
if (self.args.every((x) => x instanceof AST_String)) {
|
16492
16786
|
// quite a corner-case, but we can handle it:
|
16493
16787
|
// https://github.com/mishoo/UglifyJS2/issues/203
|
@@ -16497,14 +16791,13 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
16497
16791
|
return arg.value;
|
16498
16792
|
}).join(",") + "){" + self.args[self.args.length - 1].value + "})";
|
16499
16793
|
var ast = parse(code);
|
16500
|
-
var mangle = { ie8: compressor.option("ie8") };
|
16794
|
+
var mangle = { ie8: compressor.option("ie8"), nth_identifier: nth_identifier };
|
16501
16795
|
ast.figure_out_scope(mangle);
|
16502
16796
|
var comp = new Compressor(compressor.options, {
|
16503
16797
|
mangle_options: compressor.mangle_options
|
16504
16798
|
});
|
16505
16799
|
ast = ast.transform(comp);
|
16506
16800
|
ast.figure_out_scope(mangle);
|
16507
|
-
base54.reset();
|
16508
16801
|
ast.compute_char_frequency(mangle);
|
16509
16802
|
ast.mangle_names(mangle);
|
16510
16803
|
var fun;
|
@@ -18702,12 +18995,15 @@ function lift_key(self, compressor) {
|
|
18702
18995
|
if (self.key.value == "constructor"
|
18703
18996
|
&& compressor.parent() instanceof AST_Class) return self;
|
18704
18997
|
if (self instanceof AST_ObjectKeyVal) {
|
18998
|
+
self.quote = self.key.quote;
|
18705
18999
|
self.key = self.key.value;
|
18706
19000
|
} else if (self instanceof AST_ClassProperty) {
|
19001
|
+
self.quote = self.key.quote;
|
18707
19002
|
self.key = make_node(AST_SymbolClassProperty, self.key, {
|
18708
19003
|
name: self.key.value
|
18709
19004
|
});
|
18710
19005
|
} else {
|
19006
|
+
self.quote = self.key.quote;
|
18711
19007
|
self.key = make_node(AST_SymbolMethod, self.key, {
|
18712
19008
|
name: self.key.value
|
18713
19009
|
});
|
@@ -26815,28 +27111,59 @@ function addStrings(node, add) {
|
|
26815
27111
|
}));
|
26816
27112
|
}
|
26817
27113
|
|
27114
|
+
function mangle_private_properties(ast, options) {
|
27115
|
+
var cprivate = -1;
|
27116
|
+
var private_cache = new Map();
|
27117
|
+
var nth_identifier = options.nth_identifier || base54;
|
27118
|
+
|
27119
|
+
ast = ast.transform(new TreeTransformer(function(node) {
|
27120
|
+
if (
|
27121
|
+
node instanceof AST_ClassPrivateProperty
|
27122
|
+
|| node instanceof AST_PrivateMethod
|
27123
|
+
|| node instanceof AST_PrivateGetter
|
27124
|
+
|| node instanceof AST_PrivateSetter
|
27125
|
+
) {
|
27126
|
+
node.key.name = mangle_private(node.key.name);
|
27127
|
+
} else if (node instanceof AST_DotHash) {
|
27128
|
+
node.property = mangle_private(node.property);
|
27129
|
+
}
|
27130
|
+
}));
|
27131
|
+
return ast;
|
27132
|
+
|
27133
|
+
function mangle_private(name) {
|
27134
|
+
let mangled = private_cache.get(name);
|
27135
|
+
if (!mangled) {
|
27136
|
+
mangled = nth_identifier.get(++cprivate);
|
27137
|
+
private_cache.set(name, mangled);
|
27138
|
+
}
|
27139
|
+
|
27140
|
+
return mangled;
|
27141
|
+
}
|
27142
|
+
}
|
27143
|
+
|
26818
27144
|
function mangle_properties(ast, options) {
|
26819
27145
|
options = defaults(options, {
|
26820
27146
|
builtins: false,
|
26821
27147
|
cache: null,
|
26822
27148
|
debug: false,
|
26823
27149
|
keep_quoted: false,
|
27150
|
+
nth_identifier: base54,
|
26824
27151
|
only_cache: false,
|
26825
27152
|
regex: null,
|
26826
27153
|
reserved: null,
|
26827
27154
|
undeclared: false,
|
26828
27155
|
}, true);
|
26829
27156
|
|
27157
|
+
var nth_identifier = options.nth_identifier;
|
27158
|
+
|
26830
27159
|
var reserved_option = options.reserved;
|
26831
27160
|
if (!Array.isArray(reserved_option)) reserved_option = [reserved_option];
|
26832
27161
|
var reserved = new Set(reserved_option);
|
26833
27162
|
if (!options.builtins) find_builtins(reserved);
|
26834
27163
|
|
26835
27164
|
var cname = -1;
|
26836
|
-
var cprivate = -1;
|
26837
27165
|
|
26838
27166
|
var cache;
|
26839
|
-
var private_cache = new Map();
|
26840
27167
|
if (options.cache) {
|
26841
27168
|
cache = options.cache.props;
|
26842
27169
|
cache.forEach(function(mangled_name) {
|
@@ -26859,27 +27186,24 @@ function mangle_properties(ast, options) {
|
|
26859
27186
|
|
26860
27187
|
var names_to_mangle = new Set();
|
26861
27188
|
var unmangleable = new Set();
|
26862
|
-
var private_properties = new Set();
|
26863
27189
|
|
26864
|
-
var
|
27190
|
+
var keep_quoted = !!options.keep_quoted;
|
26865
27191
|
|
26866
27192
|
// step 1: find candidates to mangle
|
26867
27193
|
ast.walk(new TreeWalker(function(node) {
|
26868
27194
|
if (
|
26869
27195
|
node instanceof AST_ClassPrivateProperty
|
26870
27196
|
|| node instanceof AST_PrivateMethod
|
26871
|
-
|
26872
|
-
|
26873
|
-
|
26874
|
-
|
26875
|
-
|
26876
|
-
if (typeof node.key == "string" &&
|
26877
|
-
(!keep_quoted_strict || !node.quote)) {
|
27197
|
+
|| node instanceof AST_PrivateGetter
|
27198
|
+
|| node instanceof AST_PrivateSetter
|
27199
|
+
|| node instanceof AST_DotHash
|
27200
|
+
) ; else if (node instanceof AST_ObjectKeyVal) {
|
27201
|
+
if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
|
26878
27202
|
add(node.key);
|
26879
27203
|
}
|
26880
27204
|
} else if (node instanceof AST_ObjectProperty) {
|
26881
27205
|
// setter or getter, since KeyVal is handled above
|
26882
|
-
if (!
|
27206
|
+
if (!keep_quoted || !node.quote) {
|
26883
27207
|
add(node.key.name);
|
26884
27208
|
}
|
26885
27209
|
} else if (node instanceof AST_Dot) {
|
@@ -26892,11 +27216,11 @@ function mangle_properties(ast, options) {
|
|
26892
27216
|
declared = !(root.thedef && root.thedef.undeclared);
|
26893
27217
|
}
|
26894
27218
|
if (declared &&
|
26895
|
-
(!
|
27219
|
+
(!keep_quoted || !node.quote)) {
|
26896
27220
|
add(node.property);
|
26897
27221
|
}
|
26898
27222
|
} else if (node instanceof AST_Sub) {
|
26899
|
-
if (!
|
27223
|
+
if (!keep_quoted) {
|
26900
27224
|
addStrings(node.property, add);
|
26901
27225
|
}
|
26902
27226
|
} else if (node instanceof AST_Call
|
@@ -26912,25 +27236,23 @@ function mangle_properties(ast, options) {
|
|
26912
27236
|
if (
|
26913
27237
|
node instanceof AST_ClassPrivateProperty
|
26914
27238
|
|| node instanceof AST_PrivateMethod
|
26915
|
-
|
26916
|
-
node
|
26917
|
-
|
26918
|
-
|
26919
|
-
|
26920
|
-
if (typeof node.key == "string" &&
|
26921
|
-
(!keep_quoted_strict || !node.quote)) {
|
27239
|
+
|| node instanceof AST_PrivateGetter
|
27240
|
+
|| node instanceof AST_PrivateSetter
|
27241
|
+
|| node instanceof AST_DotHash
|
27242
|
+
) ; else if (node instanceof AST_ObjectKeyVal) {
|
27243
|
+
if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
|
26922
27244
|
node.key = mangle(node.key);
|
26923
27245
|
}
|
26924
27246
|
} else if (node instanceof AST_ObjectProperty) {
|
26925
27247
|
// setter, getter, method or class field
|
26926
|
-
if (!
|
27248
|
+
if (!keep_quoted || !node.quote) {
|
26927
27249
|
node.key.name = mangle(node.key.name);
|
26928
27250
|
}
|
26929
27251
|
} else if (node instanceof AST_Dot) {
|
26930
|
-
if (!
|
27252
|
+
if (!keep_quoted || !node.quote) {
|
26931
27253
|
node.property = mangle(node.property);
|
26932
27254
|
}
|
26933
|
-
} else if (!
|
27255
|
+
} else if (!keep_quoted && node instanceof AST_Sub) {
|
26934
27256
|
node.property = mangleStrings(node.property);
|
26935
27257
|
} else if (node instanceof AST_Call
|
26936
27258
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
@@ -26987,7 +27309,7 @@ function mangle_properties(ast, options) {
|
|
26987
27309
|
// either debug mode is off, or it is on and we could not use the mangled name
|
26988
27310
|
if (!mangled) {
|
26989
27311
|
do {
|
26990
|
-
mangled =
|
27312
|
+
mangled = nth_identifier.get(++cname);
|
26991
27313
|
} while (!can_mangle(mangled));
|
26992
27314
|
}
|
26993
27315
|
|
@@ -26996,16 +27318,6 @@ function mangle_properties(ast, options) {
|
|
26996
27318
|
return mangled;
|
26997
27319
|
}
|
26998
27320
|
|
26999
|
-
function mangle_private(name) {
|
27000
|
-
let mangled = private_cache.get(name);
|
27001
|
-
if (!mangled) {
|
27002
|
-
mangled = base54(++cprivate);
|
27003
|
-
private_cache.set(name, mangled);
|
27004
|
-
}
|
27005
|
-
|
27006
|
-
return mangled;
|
27007
|
-
}
|
27008
|
-
|
27009
27321
|
function mangleStrings(node) {
|
27010
27322
|
return node.transform(new TreeTransformer(function(node) {
|
27011
27323
|
if (node instanceof AST_Sequence) {
|
@@ -27201,9 +27513,9 @@ async function minify(files, options) {
|
|
27201
27513
|
if (options.mangle) toplevel.figure_out_scope(options.mangle);
|
27202
27514
|
if (timings) timings.mangle = Date.now();
|
27203
27515
|
if (options.mangle) {
|
27204
|
-
base54.reset();
|
27205
27516
|
toplevel.compute_char_frequency(options.mangle);
|
27206
27517
|
toplevel.mangle_names(options.mangle);
|
27518
|
+
toplevel = mangle_private_properties(toplevel, options.mangle);
|
27207
27519
|
}
|
27208
27520
|
if (timings) timings.properties = Date.now();
|
27209
27521
|
if (options.mangle && options.mangle.properties) {
|