terser 5.6.0-beta → 5.7.1
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 +35 -0
- package/README.md +25 -19
- package/dist/bundle.min.js +250 -169
- package/lib/ast.js +15 -4
- package/lib/cli.js +0 -2
- package/lib/compress/index.js +102 -64
- package/lib/equivalent-to.js +5 -0
- package/lib/minify.js +26 -9
- package/lib/output.js +8 -1
- package/lib/parse.js +72 -80
- package/lib/scope.js +8 -3
- package/lib/size.js +9 -2
- package/lib/utils/index.js +6 -6
- package/package.json +4 -3
- package/tools/domprops.js +1 -0
package/lib/ast.js
CHANGED
@@ -214,8 +214,6 @@ function walk_body(node, visitor) {
|
|
214
214
|
function clone_block_scope(deep) {
|
215
215
|
var clone = this._clone(deep);
|
216
216
|
if (this.block_scope) {
|
217
|
-
// TODO this is sometimes undefined during compression.
|
218
|
-
// But it should always have a value!
|
219
217
|
clone.block_scope = this.block_scope.clone();
|
220
218
|
}
|
221
219
|
return clone;
|
@@ -399,7 +397,6 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
|
|
399
397
|
$documentation: "Base class for all statements introducing a lexical scope",
|
400
398
|
$propdoc: {
|
401
399
|
variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
402
|
-
functions: "[Map/S] like `variables`, but only lists function declarations",
|
403
400
|
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
404
401
|
uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
|
405
402
|
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
@@ -422,7 +419,6 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
|
|
422
419
|
});
|
423
420
|
} else {
|
424
421
|
if (this.variables) node.variables = new Map(this.variables);
|
425
|
-
if (this.functions) node.functions = new Map(this.functions);
|
426
422
|
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
427
423
|
if (this._block_scope) node._block_scope = this._block_scope;
|
428
424
|
}
|
@@ -522,6 +518,21 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator as
|
|
522
518
|
|
523
519
|
if (this.name) push(this.name);
|
524
520
|
},
|
521
|
+
is_braceless() {
|
522
|
+
return this.body[0] instanceof AST_Return && this.body[0].value;
|
523
|
+
},
|
524
|
+
// Default args and expansion don't count, so .argnames.length doesn't cut it
|
525
|
+
length_property() {
|
526
|
+
let length = 0;
|
527
|
+
|
528
|
+
for (const arg of this.argnames) {
|
529
|
+
if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) {
|
530
|
+
length++;
|
531
|
+
}
|
532
|
+
}
|
533
|
+
|
534
|
+
return length;
|
535
|
+
}
|
525
536
|
}, AST_Scope);
|
526
537
|
|
527
538
|
var AST_Accessor = DEFNODE("Accessor", null, {
|
package/lib/cli.js
CHANGED
@@ -264,7 +264,6 @@ export async function run_cli({ program, packageJson, fs, path }) {
|
|
264
264
|
case "enclosed":
|
265
265
|
return value.length ? value.map(symdef) : undefined;
|
266
266
|
case "variables":
|
267
|
-
case "functions":
|
268
267
|
case "globals":
|
269
268
|
return value.size ? collect_from_map(value, symdef) : undefined;
|
270
269
|
}
|
@@ -277,7 +276,6 @@ export async function run_cli({ program, packageJson, fs, path }) {
|
|
277
276
|
};
|
278
277
|
if (value.block_scope) {
|
279
278
|
result.variables = value.block_scope.variables;
|
280
|
-
result.functions = value.block_scope.functions;
|
281
279
|
result.enclosed = value.block_scope.enclosed;
|
282
280
|
}
|
283
281
|
value.CTOR.PROPS.forEach(function(prop) {
|
package/lib/compress/index.js
CHANGED
@@ -209,11 +209,8 @@ const TOP = 0b0000010000000000;
|
|
209
209
|
|
210
210
|
const CLEAR_BETWEEN_PASSES = SQUEEZED | OPTIMIZED | TOP;
|
211
211
|
|
212
|
-
/*@__INLINE__*/
|
213
212
|
const has_flag = (node, flag) => node.flags & flag;
|
214
|
-
/*@__INLINE__*/
|
215
213
|
const set_flag = (node, flag) => { node.flags |= flag; };
|
216
|
-
/*@__INLINE__*/
|
217
214
|
const clear_flag = (node, flag) => { node.flags &= ~flag; };
|
218
215
|
|
219
216
|
class Compressor extends TreeWalker {
|
@@ -256,7 +253,7 @@ class Compressor extends TreeWalker {
|
|
256
253
|
properties : !false_by_default,
|
257
254
|
pure_getters : !false_by_default && "strict",
|
258
255
|
pure_funcs : null,
|
259
|
-
reduce_funcs :
|
256
|
+
reduce_funcs : !false_by_default,
|
260
257
|
reduce_vars : !false_by_default,
|
261
258
|
sequences : !false_by_default,
|
262
259
|
side_effects : !false_by_default,
|
@@ -556,7 +553,7 @@ function is_modified(compressor, tw, node, value, level, immutable) {
|
|
556
553
|
&& parent.expression === node
|
557
554
|
&& !(value instanceof AST_Arrow)
|
558
555
|
&& !(value instanceof AST_Class)
|
559
|
-
&& !parent.
|
556
|
+
&& !parent.is_callee_pure(compressor)
|
560
557
|
&& (!(value instanceof AST_Function)
|
561
558
|
|| !(parent instanceof AST_New) && value.contains_this())) {
|
562
559
|
return true;
|
@@ -861,9 +858,6 @@ function is_modified(compressor, tw, node, value, level, immutable) {
|
|
861
858
|
return true;
|
862
859
|
});
|
863
860
|
def_reduce_vars(AST_Call, function (tw) {
|
864
|
-
// TODO this block should just be { return } but
|
865
|
-
// for some reason the _walk function of AST_Call walks the callee last
|
866
|
-
|
867
861
|
this.expression.walk(tw);
|
868
862
|
|
869
863
|
if (this.optional) {
|
@@ -1416,8 +1410,11 @@ function tighten_body(statements, compressor) {
|
|
1416
1410
|
|| node instanceof AST_Debugger
|
1417
1411
|
|| node instanceof AST_Destructuring
|
1418
1412
|
|| node instanceof AST_Expansion
|
1419
|
-
|
1420
|
-
|
1413
|
+
&& node.expression instanceof AST_Symbol
|
1414
|
+
&& (
|
1415
|
+
node.expression instanceof AST_This
|
1416
|
+
|| node.expression.definition().references.length > 1
|
1417
|
+
)
|
1421
1418
|
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
1422
1419
|
|| node instanceof AST_LoopControl
|
1423
1420
|
|| node instanceof AST_Try
|
@@ -1511,6 +1508,7 @@ function tighten_body(statements, compressor) {
|
|
1511
1508
|
if (stop_after === node) abort = true;
|
1512
1509
|
if (stop_if_hit === node) stop_if_hit = null;
|
1513
1510
|
});
|
1511
|
+
|
1514
1512
|
var multi_replacer = new TreeTransformer(function(node) {
|
1515
1513
|
if (abort) return node;
|
1516
1514
|
// Skip nodes before `candidate` as quickly as possible
|
@@ -1533,6 +1531,7 @@ function tighten_body(statements, compressor) {
|
|
1533
1531
|
// Skip (non-executed) functions and (leading) default case in switch statements
|
1534
1532
|
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
|
1535
1533
|
});
|
1534
|
+
|
1536
1535
|
while (--stat_index >= 0) {
|
1537
1536
|
// Treat parameters as collapsible in IIFE, i.e.
|
1538
1537
|
// function(a, b){ ... }(x());
|
@@ -1708,7 +1707,10 @@ function tighten_body(statements, compressor) {
|
|
1708
1707
|
function extract_candidates(expr) {
|
1709
1708
|
hit_stack.push(expr);
|
1710
1709
|
if (expr instanceof AST_Assign) {
|
1711
|
-
if (
|
1710
|
+
if (
|
1711
|
+
!expr.left.has_side_effects(compressor)
|
1712
|
+
&& !(expr.right instanceof AST_Chain)
|
1713
|
+
) {
|
1712
1714
|
candidates.push(hit_stack.slice());
|
1713
1715
|
}
|
1714
1716
|
extract_candidates(expr.right);
|
@@ -1771,7 +1773,7 @@ function tighten_body(statements, compressor) {
|
|
1771
1773
|
candidates.push(hit_stack.slice());
|
1772
1774
|
}
|
1773
1775
|
} else if (expr instanceof AST_VarDef) {
|
1774
|
-
if (expr.value) {
|
1776
|
+
if (expr.value && !(expr.value instanceof AST_Chain)) {
|
1775
1777
|
candidates.push(hit_stack.slice());
|
1776
1778
|
extract_candidates(expr.value);
|
1777
1779
|
}
|
@@ -2586,7 +2588,13 @@ function is_undefined(node, compressor) {
|
|
2586
2588
|
});
|
2587
2589
|
def_may_throw_on_access(AST_Dot, function(compressor) {
|
2588
2590
|
if (!is_strict(compressor)) return false;
|
2589
|
-
|
2591
|
+
|
2592
|
+
if (this.property == "prototype") {
|
2593
|
+
return !(
|
2594
|
+
this.expression instanceof AST_Function
|
2595
|
+
|| this.expression instanceof AST_Class
|
2596
|
+
);
|
2597
|
+
}
|
2590
2598
|
return true;
|
2591
2599
|
});
|
2592
2600
|
def_may_throw_on_access(AST_Chain, function(compressor) {
|
@@ -2928,9 +2936,7 @@ var static_fns = convert_to_predicate({
|
|
2928
2936
|
if (compressor.option("unsafe")) {
|
2929
2937
|
var fn = function() {};
|
2930
2938
|
fn.node = this;
|
2931
|
-
fn.toString =
|
2932
|
-
return this.node.print_to_string();
|
2933
|
-
};
|
2939
|
+
fn.toString = () => this.print_to_string();
|
2934
2940
|
return fn;
|
2935
2941
|
}
|
2936
2942
|
return this;
|
@@ -3111,6 +3117,14 @@ var static_fns = convert_to_predicate({
|
|
3111
3117
|
"POSITIVE_INFINITY",
|
3112
3118
|
],
|
3113
3119
|
});
|
3120
|
+
const regexp_flags = new Set([
|
3121
|
+
"dotAll",
|
3122
|
+
"global",
|
3123
|
+
"ignoreCase",
|
3124
|
+
"multiline",
|
3125
|
+
"sticky",
|
3126
|
+
"unicode",
|
3127
|
+
]);
|
3114
3128
|
def_eval(AST_PropAccess, function(compressor, depth) {
|
3115
3129
|
if (this.optional) {
|
3116
3130
|
const obj = this.expression._eval(compressor, depth);
|
@@ -3143,12 +3157,19 @@ var static_fns = convert_to_predicate({
|
|
3143
3157
|
val = global_objs[exp.name];
|
3144
3158
|
} else {
|
3145
3159
|
val = exp._eval(compressor, depth + 1);
|
3160
|
+
if (val instanceof RegExp) {
|
3161
|
+
if (key == "source") {
|
3162
|
+
return regexp_source_fix(val.source);
|
3163
|
+
} else if (key == "flags" || regexp_flags.has(key)) {
|
3164
|
+
return val[key];
|
3165
|
+
}
|
3166
|
+
}
|
3146
3167
|
if (!val || val === exp || !HOP(val, key)) return this;
|
3147
3168
|
if (typeof val == "function") switch (key) {
|
3148
3169
|
case "name":
|
3149
3170
|
return val.node.name ? val.node.name.name : "";
|
3150
3171
|
case "length":
|
3151
|
-
return val.node.
|
3172
|
+
return val.node.length_property();
|
3152
3173
|
default:
|
3153
3174
|
return this;
|
3154
3175
|
}
|
@@ -3200,6 +3221,7 @@ var static_fns = convert_to_predicate({
|
|
3200
3221
|
var arg = this.args[i];
|
3201
3222
|
var value = arg._eval(compressor, depth);
|
3202
3223
|
if (arg === value) return this;
|
3224
|
+
if (arg instanceof AST_Lambda) return this;
|
3203
3225
|
args.push(value);
|
3204
3226
|
}
|
3205
3227
|
try {
|
@@ -3299,7 +3321,7 @@ var static_fns = convert_to_predicate({
|
|
3299
3321
|
});
|
3300
3322
|
|
3301
3323
|
var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
|
3302
|
-
AST_Call.DEFMETHOD("
|
3324
|
+
AST_Call.DEFMETHOD("is_callee_pure", function(compressor) {
|
3303
3325
|
if (compressor.option("unsafe")) {
|
3304
3326
|
var expr = this.expression;
|
3305
3327
|
var first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor));
|
@@ -3369,7 +3391,7 @@ const pure_prop_access_globals = new Set([
|
|
3369
3391
|
});
|
3370
3392
|
def_has_side_effects(AST_Call, function(compressor) {
|
3371
3393
|
if (
|
3372
|
-
!this.
|
3394
|
+
!this.is_callee_pure(compressor)
|
3373
3395
|
&& (!this.expression.is_call_pure(compressor)
|
3374
3396
|
|| this.expression.has_side_effects(compressor))
|
3375
3397
|
) {
|
@@ -3459,7 +3481,7 @@ const pure_prop_access_globals = new Set([
|
|
3459
3481
|
|| this.expression.has_side_effects(compressor);
|
3460
3482
|
});
|
3461
3483
|
def_has_side_effects(AST_Sub, function(compressor) {
|
3462
|
-
if (this.optional && is_nullish(this.expression)) {
|
3484
|
+
if (this.optional && is_nullish(this.expression, compressor)) {
|
3463
3485
|
return false;
|
3464
3486
|
}
|
3465
3487
|
|
@@ -3529,9 +3551,9 @@ const pure_prop_access_globals = new Set([
|
|
3529
3551
|
return any(this.body, compressor);
|
3530
3552
|
});
|
3531
3553
|
def_may_throw(AST_Call, function(compressor) {
|
3532
|
-
if (this.optional && is_nullish(this.expression)) return false;
|
3554
|
+
if (this.optional && is_nullish(this.expression, compressor)) return false;
|
3533
3555
|
if (any(this.args, compressor)) return true;
|
3534
|
-
if (this.
|
3556
|
+
if (this.is_callee_pure(compressor)) return false;
|
3535
3557
|
if (this.expression.may_throw(compressor)) return true;
|
3536
3558
|
return !(this.expression instanceof AST_Lambda)
|
3537
3559
|
|| any(this.expression.body, compressor);
|
@@ -3592,7 +3614,7 @@ const pure_prop_access_globals = new Set([
|
|
3592
3614
|
|| this.expression.may_throw(compressor);
|
3593
3615
|
});
|
3594
3616
|
def_may_throw(AST_Sub, function(compressor) {
|
3595
|
-
if (this.optional && is_nullish(this.expression)) return false;
|
3617
|
+
if (this.optional && is_nullish(this.expression, compressor)) return false;
|
3596
3618
|
|
3597
3619
|
return !this.optional && this.expression.may_throw_on_access(compressor)
|
3598
3620
|
|| this.expression.may_throw(compressor)
|
@@ -4405,11 +4427,11 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
|
|
4405
4427
|
def_drop_side_effect_free(AST_Constant, return_null);
|
4406
4428
|
def_drop_side_effect_free(AST_This, return_null);
|
4407
4429
|
def_drop_side_effect_free(AST_Call, function(compressor, first_in_statement) {
|
4408
|
-
if (this.optional && is_nullish(this.expression)) {
|
4430
|
+
if (this.optional && is_nullish(this.expression, compressor)) {
|
4409
4431
|
return make_node(AST_Undefined, this);
|
4410
4432
|
}
|
4411
4433
|
|
4412
|
-
if (!this.
|
4434
|
+
if (!this.is_callee_pure(compressor)) {
|
4413
4435
|
if (this.expression.is_call_pure(compressor)) {
|
4414
4436
|
var exprs = this.args.slice();
|
4415
4437
|
exprs.unshift(this.expression.expression);
|
@@ -4552,7 +4574,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
|
|
4552
4574
|
});
|
4553
4575
|
def_drop_side_effect_free(AST_Dot, function(compressor, first_in_statement) {
|
4554
4576
|
if (this.optional) {
|
4555
|
-
return is_nullish(this.expression) ? make_node(AST_Undefined, this) : this;
|
4577
|
+
return is_nullish(this.expression, compressor) ? make_node(AST_Undefined, this) : this;
|
4556
4578
|
}
|
4557
4579
|
if (this.expression.may_throw_on_access(compressor)) return this;
|
4558
4580
|
|
@@ -4560,7 +4582,7 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
|
|
4560
4582
|
});
|
4561
4583
|
def_drop_side_effect_free(AST_Sub, function(compressor, first_in_statement) {
|
4562
4584
|
if (this.optional) {
|
4563
|
-
return is_nullish(this.expression) ? make_node(AST_Undefined, this): this;
|
4585
|
+
return is_nullish(this.expression, compressor) ? make_node(AST_Undefined, this): this;
|
4564
4586
|
}
|
4565
4587
|
if (this.expression.may_throw_on_access(compressor)) return this;
|
4566
4588
|
|
@@ -5085,11 +5107,11 @@ def_optimize(AST_Definitions, function(self) {
|
|
5085
5107
|
return self;
|
5086
5108
|
});
|
5087
5109
|
|
5088
|
-
def_optimize(AST_VarDef, function(self) {
|
5110
|
+
def_optimize(AST_VarDef, function(self, compressor) {
|
5089
5111
|
if (
|
5090
5112
|
self.name instanceof AST_SymbolLet
|
5091
5113
|
&& self.value != null
|
5092
|
-
&& is_undefined(self.value)
|
5114
|
+
&& is_undefined(self.value, compressor)
|
5093
5115
|
) {
|
5094
5116
|
self.value = null;
|
5095
5117
|
}
|
@@ -5127,7 +5149,7 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
5127
5149
|
}
|
5128
5150
|
}
|
5129
5151
|
|
5130
|
-
if (self.optional && is_nullish(fn)) {
|
5152
|
+
if (self.optional && is_nullish(fn, compressor)) {
|
5131
5153
|
return make_node(AST_Undefined, self);
|
5132
5154
|
}
|
5133
5155
|
|
@@ -5429,7 +5451,7 @@ def_optimize(AST_Call, function(self, compressor) {
|
|
5429
5451
|
|
5430
5452
|
var stat = is_func && fn.body[0];
|
5431
5453
|
var is_regular_func = is_func && !fn.is_generator && !fn.async;
|
5432
|
-
var can_inline = is_regular_func && compressor.option("inline") && !self.
|
5454
|
+
var can_inline = is_regular_func && compressor.option("inline") && !self.is_callee_pure(compressor);
|
5433
5455
|
if (can_inline && stat instanceof AST_Return) {
|
5434
5456
|
let returned = stat.value;
|
5435
5457
|
if (!returned || returned.is_constant_expression()) {
|
@@ -6153,7 +6175,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
6153
6175
|
}
|
6154
6176
|
break;
|
6155
6177
|
case "??":
|
6156
|
-
if (is_nullish(self.left)) {
|
6178
|
+
if (is_nullish(self.left, compressor)) {
|
6157
6179
|
return self.right;
|
6158
6180
|
}
|
6159
6181
|
|
@@ -6455,19 +6477,26 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
|
|
6455
6477
|
let fixed = self.fixed_value();
|
6456
6478
|
let single_use = def.single_use
|
6457
6479
|
&& !(parent instanceof AST_Call
|
6458
|
-
&& (parent.
|
6480
|
+
&& (parent.is_callee_pure(compressor))
|
6459
6481
|
|| has_annotation(parent, _NOINLINE))
|
6460
6482
|
&& !(parent instanceof AST_Export
|
6461
6483
|
&& fixed instanceof AST_Lambda
|
6462
6484
|
&& fixed.name);
|
6463
6485
|
|
6486
|
+
if (single_use && fixed instanceof AST_Node) {
|
6487
|
+
single_use =
|
6488
|
+
!fixed.has_side_effects(compressor)
|
6489
|
+
&& !fixed.may_throw(compressor);
|
6490
|
+
}
|
6491
|
+
|
6464
6492
|
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
|
6465
6493
|
if (retain_top_func(fixed, compressor)) {
|
6466
6494
|
single_use = false;
|
6467
6495
|
} else if (def.scope !== self.scope
|
6468
6496
|
&& (def.escaped == 1
|
6469
6497
|
|| has_flag(fixed, INLINED)
|
6470
|
-
|| within_array_or_object_literal(compressor)
|
6498
|
+
|| within_array_or_object_literal(compressor)
|
6499
|
+
|| !compressor.option("reduce_funcs"))) {
|
6471
6500
|
single_use = false;
|
6472
6501
|
} else if (recursive_ref(compressor, def)) {
|
6473
6502
|
single_use = false;
|
@@ -6483,6 +6512,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
|
|
6483
6512
|
}
|
6484
6513
|
}
|
6485
6514
|
}
|
6515
|
+
|
6486
6516
|
if (single_use && fixed instanceof AST_Lambda) {
|
6487
6517
|
single_use =
|
6488
6518
|
def.scope === self.scope
|
@@ -6492,15 +6522,6 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
|
|
6492
6522
|
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
|
6493
6523
|
&& !(fixed.name && fixed.name.definition().recursive_refs > 0);
|
6494
6524
|
}
|
6495
|
-
if (single_use && fixed instanceof AST_Class) {
|
6496
|
-
const extends_inert = !fixed.extends
|
6497
|
-
|| !fixed.extends.may_throw(compressor)
|
6498
|
-
&& !fixed.extends.has_side_effects(compressor);
|
6499
|
-
single_use = extends_inert
|
6500
|
-
&& !fixed.properties.some(prop =>
|
6501
|
-
prop.may_throw(compressor) || prop.has_side_effects(compressor)
|
6502
|
-
);
|
6503
|
-
}
|
6504
6525
|
|
6505
6526
|
if (single_use && fixed) {
|
6506
6527
|
if (fixed instanceof AST_DefClass) {
|
@@ -6577,6 +6598,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
|
|
6577
6598
|
}
|
6578
6599
|
}
|
6579
6600
|
}
|
6601
|
+
|
6580
6602
|
return self;
|
6581
6603
|
});
|
6582
6604
|
|
@@ -6761,20 +6783,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
|
|
6761
6783
|
return self;
|
6762
6784
|
});
|
6763
6785
|
|
6764
|
-
function is_nullish(node) {
|
6786
|
+
function is_nullish(node, compressor) {
|
6765
6787
|
let fixed;
|
6766
6788
|
return (
|
6767
6789
|
node instanceof AST_Null
|
6768
|
-
|| is_undefined(node)
|
6790
|
+
|| is_undefined(node, compressor)
|
6769
6791
|
|| (
|
6770
6792
|
node instanceof AST_SymbolRef
|
6771
6793
|
&& (fixed = node.definition().fixed) instanceof AST_Node
|
6772
|
-
&& is_nullish(fixed)
|
6794
|
+
&& is_nullish(fixed, compressor)
|
6773
6795
|
)
|
6774
6796
|
// Recurse into those optional chains!
|
6775
|
-
|| node instanceof AST_PropAccess && node.optional && is_nullish(node.expression)
|
6776
|
-
|| node instanceof AST_Call && node.optional && is_nullish(node.expression)
|
6777
|
-
|| node instanceof AST_Chain && is_nullish(node.expression)
|
6797
|
+
|| node instanceof AST_PropAccess && node.optional && is_nullish(node.expression, compressor)
|
6798
|
+
|| node instanceof AST_Call && node.optional && is_nullish(node.expression, compressor)
|
6799
|
+
|| node instanceof AST_Chain && is_nullish(node.expression, compressor)
|
6778
6800
|
);
|
6779
6801
|
}
|
6780
6802
|
|
@@ -6789,8 +6811,8 @@ function is_nullish_check(check, check_subject, compressor) {
|
|
6789
6811
|
&& check.operator === "=="
|
6790
6812
|
// which side is nullish?
|
6791
6813
|
&& (
|
6792
|
-
(nullish_side = is_nullish(check.left) && check.left)
|
6793
|
-
|| (nullish_side = is_nullish(check.right) && check.right)
|
6814
|
+
(nullish_side = is_nullish(check.left, compressor) && check.left)
|
6815
|
+
|| (nullish_side = is_nullish(check.right, compressor) && check.right)
|
6794
6816
|
)
|
6795
6817
|
// is the other side the same as the check_subject
|
6796
6818
|
&& (
|
@@ -6828,12 +6850,12 @@ function is_nullish_check(check, check_subject, compressor) {
|
|
6828
6850
|
null_cmp = cmp;
|
6829
6851
|
defined_side = cmp.left;
|
6830
6852
|
}
|
6831
|
-
if (is_undefined(cmp.left)) {
|
6853
|
+
if (is_undefined(cmp.left, compressor)) {
|
6832
6854
|
found++;
|
6833
6855
|
undefined_cmp = cmp;
|
6834
6856
|
defined_side = cmp.right;
|
6835
6857
|
}
|
6836
|
-
if (is_undefined(cmp.right)) {
|
6858
|
+
if (is_undefined(cmp.right, compressor)) {
|
6837
6859
|
found++;
|
6838
6860
|
undefined_cmp = cmp;
|
6839
6861
|
defined_side = cmp.left;
|
@@ -7163,27 +7185,40 @@ function safe_to_flatten(value, compressor) {
|
|
7163
7185
|
|
7164
7186
|
AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
|
7165
7187
|
if (!compressor.option("properties")) return;
|
7188
|
+
if (key === "__proto__") return;
|
7189
|
+
|
7166
7190
|
var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015;
|
7167
7191
|
var expr = this.expression;
|
7168
7192
|
if (expr instanceof AST_Object) {
|
7169
7193
|
var props = expr.properties;
|
7194
|
+
|
7170
7195
|
for (var i = props.length; --i >= 0;) {
|
7171
7196
|
var prop = props[i];
|
7197
|
+
|
7172
7198
|
if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) {
|
7173
|
-
|
7174
|
-
|
7175
|
-
|| arrows &&
|
7176
|
-
|
7177
|
-
|
7199
|
+
const all_props_flattenable = props.every((p) =>
|
7200
|
+
(p instanceof AST_ObjectKeyVal
|
7201
|
+
|| arrows && p instanceof AST_ConciseMethod && !p.is_generator
|
7202
|
+
)
|
7203
|
+
&& !p.computed_key()
|
7204
|
+
);
|
7205
|
+
|
7206
|
+
if (!all_props_flattenable) return;
|
7207
|
+
if (!safe_to_flatten(prop.value, compressor)) return;
|
7208
|
+
|
7178
7209
|
return make_node(AST_Sub, this, {
|
7179
7210
|
expression: make_node(AST_Array, expr, {
|
7180
7211
|
elements: props.map(function(prop) {
|
7181
7212
|
var v = prop.value;
|
7182
|
-
if (v instanceof AST_Accessor)
|
7213
|
+
if (v instanceof AST_Accessor) {
|
7214
|
+
v = make_node(AST_Function, v, v);
|
7215
|
+
}
|
7216
|
+
|
7183
7217
|
var k = prop.key;
|
7184
7218
|
if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) {
|
7185
7219
|
return make_sequence(prop, [ k, v ]);
|
7186
7220
|
}
|
7221
|
+
|
7187
7222
|
return v;
|
7188
7223
|
})
|
7189
7224
|
}),
|
@@ -7321,7 +7356,7 @@ def_optimize(AST_Sub, function(self, compressor) {
|
|
7321
7356
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
7322
7357
|
return best_of(compressor, ev, self);
|
7323
7358
|
}
|
7324
|
-
if (self.optional && is_nullish(self.expression)) {
|
7359
|
+
if (self.optional && is_nullish(self.expression, compressor)) {
|
7325
7360
|
return make_node(AST_Undefined, self);
|
7326
7361
|
}
|
7327
7362
|
return self;
|
@@ -7395,7 +7430,7 @@ def_optimize(AST_Dot, function(self, compressor) {
|
|
7395
7430
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
7396
7431
|
return best_of(compressor, ev, self);
|
7397
7432
|
}
|
7398
|
-
if (self.optional && is_nullish(self.expression)) {
|
7433
|
+
if (self.optional && is_nullish(self.expression, compressor)) {
|
7399
7434
|
return make_node(AST_Undefined, self);
|
7400
7435
|
}
|
7401
7436
|
return self;
|
@@ -7439,7 +7474,7 @@ def_optimize(AST_Array, function(self, compressor) {
|
|
7439
7474
|
return self;
|
7440
7475
|
});
|
7441
7476
|
|
7442
|
-
function inline_object_prop_spread(props) {
|
7477
|
+
function inline_object_prop_spread(props, compressor) {
|
7443
7478
|
for (var i = 0; i < props.length; i++) {
|
7444
7479
|
var prop = props[i];
|
7445
7480
|
if (prop instanceof AST_Expansion) {
|
@@ -7457,6 +7492,9 @@ function inline_object_prop_spread(props) {
|
|
7457
7492
|
// non-iterable value silently does nothing; it is thus safe
|
7458
7493
|
// to remove. AST_String is the only iterable AST_Constant.
|
7459
7494
|
props.splice(i, 1);
|
7495
|
+
} else if (is_nullish(expr, compressor)) {
|
7496
|
+
// Likewise, null and undefined can be silently removed.
|
7497
|
+
props.splice(i, 1);
|
7460
7498
|
}
|
7461
7499
|
}
|
7462
7500
|
}
|
@@ -7467,7 +7505,7 @@ def_optimize(AST_Object, function(self, compressor) {
|
|
7467
7505
|
if (optimized !== self) {
|
7468
7506
|
return optimized;
|
7469
7507
|
}
|
7470
|
-
inline_object_prop_spread(self.properties);
|
7508
|
+
inline_object_prop_spread(self.properties, compressor);
|
7471
7509
|
return self;
|
7472
7510
|
});
|
7473
7511
|
|
@@ -7560,7 +7598,7 @@ def_optimize(AST_TemplateString, function(self, compressor) {
|
|
7560
7598
|
&& (
|
7561
7599
|
segments[1].is_string(compressor)
|
7562
7600
|
|| segments[1].is_number(compressor)
|
7563
|
-
|| is_nullish(segments[1])
|
7601
|
+
|| is_nullish(segments[1], compressor)
|
7564
7602
|
|| compressor.option("unsafe")
|
7565
7603
|
)
|
7566
7604
|
) {
|
package/lib/equivalent-to.js
CHANGED
@@ -18,6 +18,7 @@ import {
|
|
18
18
|
AST_Directive,
|
19
19
|
AST_Do,
|
20
20
|
AST_Dot,
|
21
|
+
AST_DotHash,
|
21
22
|
AST_EmptyStatement,
|
22
23
|
AST_Expansion,
|
23
24
|
AST_Export,
|
@@ -233,6 +234,10 @@ AST_Dot.prototype.shallow_cmp = mkshallow({
|
|
233
234
|
property: "eq"
|
234
235
|
});
|
235
236
|
|
237
|
+
AST_DotHash.prototype.shallow_cmp = mkshallow({
|
238
|
+
property: "eq"
|
239
|
+
});
|
240
|
+
|
236
241
|
AST_Unary.prototype.shallow_cmp = mkshallow({
|
237
242
|
operator: "eq"
|
238
243
|
});
|
package/lib/minify.js
CHANGED
@@ -7,7 +7,7 @@ import {
|
|
7
7
|
map_to_object,
|
8
8
|
HOP,
|
9
9
|
} from "./utils/index.js";
|
10
|
-
import { AST_Toplevel } from "./ast.js";
|
10
|
+
import { AST_Toplevel, AST_Node } from "./ast.js";
|
11
11
|
import { parse } from "./parse.js";
|
12
12
|
import { OutputStream } from "./output.js";
|
13
13
|
import { Compressor } from "./compress/index.js";
|
@@ -77,6 +77,7 @@ async function minify(files, options) {
|
|
77
77
|
rename: undefined,
|
78
78
|
safari10: false,
|
79
79
|
sourceMap: false,
|
80
|
+
spidermonkey: false,
|
80
81
|
timings: false,
|
81
82
|
toplevel: false,
|
82
83
|
warnings: false,
|
@@ -148,20 +149,32 @@ async function minify(files, options) {
|
|
148
149
|
if (files instanceof AST_Toplevel) {
|
149
150
|
toplevel = files;
|
150
151
|
} else {
|
151
|
-
if (typeof files == "string") {
|
152
|
+
if (typeof files == "string" || (options.parse.spidermonkey && !Array.isArray(files))) {
|
152
153
|
files = [ files ];
|
153
154
|
}
|
154
155
|
options.parse = options.parse || {};
|
155
156
|
options.parse.toplevel = null;
|
156
|
-
|
157
|
-
|
158
|
-
options.parse.toplevel =
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
157
|
+
|
158
|
+
if (options.parse.spidermonkey) {
|
159
|
+
options.parse.toplevel = AST_Node.from_mozilla_ast(Object.keys(files).reduce(function(toplevel, name) {
|
160
|
+
if (!toplevel) return files[name];
|
161
|
+
toplevel.body = toplevel.body.concat(files[name].body);
|
162
|
+
return toplevel;
|
163
|
+
}, null));
|
164
|
+
} else {
|
165
|
+
delete options.parse.spidermonkey;
|
166
|
+
|
167
|
+
for (var name in files) if (HOP(files, name)) {
|
168
|
+
options.parse.filename = name;
|
169
|
+
options.parse.toplevel = parse(files[name], options.parse);
|
170
|
+
if (options.sourceMap && options.sourceMap.content == "inline") {
|
171
|
+
if (Object.keys(files).length > 1)
|
172
|
+
throw new Error("inline source map only works with singular input");
|
173
|
+
options.sourceMap.content = read_source_map(files[name]);
|
174
|
+
}
|
163
175
|
}
|
164
176
|
}
|
177
|
+
|
165
178
|
toplevel = options.parse.toplevel;
|
166
179
|
}
|
167
180
|
if (quoted_props && options.mangle.properties.keep_quoted !== "strict") {
|
@@ -203,6 +216,9 @@ async function minify(files, options) {
|
|
203
216
|
if (options.format.ast) {
|
204
217
|
result.ast = toplevel;
|
205
218
|
}
|
219
|
+
if (options.format.spidermonkey) {
|
220
|
+
result.ast = toplevel.to_mozilla_ast();
|
221
|
+
}
|
206
222
|
if (!HOP(options.format, "code") || options.format.code) {
|
207
223
|
if (options.sourceMap) {
|
208
224
|
options.format.source_map = await SourceMap({
|
@@ -220,6 +236,7 @@ async function minify(files, options) {
|
|
220
236
|
}
|
221
237
|
delete options.format.ast;
|
222
238
|
delete options.format.code;
|
239
|
+
delete options.format.spidermonkey;
|
223
240
|
var stream = OutputStream(options.format);
|
224
241
|
toplevel.print(stream);
|
225
242
|
result.code = stream.get();
|
package/lib/output.js
CHANGED
@@ -349,11 +349,15 @@ function OutputStream(options) {
|
|
349
349
|
var do_add_mapping = mappings ? function() {
|
350
350
|
mappings.forEach(function(mapping) {
|
351
351
|
try {
|
352
|
+
let name = !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name;
|
353
|
+
if (name instanceof AST_Symbol) {
|
354
|
+
name = name.name;
|
355
|
+
}
|
352
356
|
options.source_map.add(
|
353
357
|
mapping.token.file,
|
354
358
|
mapping.line, mapping.col,
|
355
359
|
mapping.token.line, mapping.token.col,
|
356
|
-
|
360
|
+
is_basic_identifier_string(name) ? name : undefined
|
357
361
|
);
|
358
362
|
} catch(ex) {
|
359
363
|
// Ignore bad mapping
|
@@ -933,6 +937,7 @@ function OutputStream(options) {
|
|
933
937
|
var p = output.parent();
|
934
938
|
return p instanceof AST_PropAccess && p.expression === this
|
935
939
|
|| p instanceof AST_Call && p.expression === this
|
940
|
+
|| p instanceof AST_Binary && p.operator === "**" && p.left === this
|
936
941
|
|| output.option("safari10") && p instanceof AST_UnaryPrefix;
|
937
942
|
});
|
938
943
|
|
@@ -2150,7 +2155,9 @@ function OutputStream(options) {
|
|
2150
2155
|
source = regexp_source_fix(source);
|
2151
2156
|
flags = flags ? sort_regexp_flags(flags) : "";
|
2152
2157
|
source = source.replace(r_slash_script, slash_script_replace);
|
2158
|
+
|
2153
2159
|
output.print(output.to_utf8(`/${source}/${flags}`));
|
2160
|
+
|
2154
2161
|
const parent = output.parent();
|
2155
2162
|
if (
|
2156
2163
|
parent instanceof AST_Binary
|