terser 5.0.0-beta.2 → 5.0.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 +22 -3
- package/README.md +1 -0
- package/dist/bundle.min.js +71 -37
- package/dist/bundle.min.js.map +1 -1
- package/lib/cli.js +2 -1
- package/lib/compress/index.js +53 -25
- package/lib/parse.js +11 -10
- package/lib/propmangle.js +5 -0
- package/lib/size.js +1 -1
- package/package.json +4 -1
package/lib/cli.js
CHANGED
@@ -84,6 +84,7 @@ export async function run_cli({ program, packageJson, fs, path }) {
|
|
84
84
|
options[name] = program[name];
|
85
85
|
}
|
86
86
|
});
|
87
|
+
|
87
88
|
if ("ecma" in program) {
|
88
89
|
if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
|
89
90
|
const ecma = program.ecma | 0;
|
@@ -313,7 +314,7 @@ export async function run_cli({ program, packageJson, fs, path }) {
|
|
313
314
|
}
|
314
315
|
} else if (program.output) {
|
315
316
|
fs.writeFileSync(program.output, result.code);
|
316
|
-
if (options.sourceMap.url !== "inline" && result.map) {
|
317
|
+
if (options.sourceMap && options.sourceMap.url !== "inline" && result.map) {
|
317
318
|
fs.writeFileSync(program.output + ".map", result.map);
|
318
319
|
}
|
319
320
|
} else {
|
package/lib/compress/index.js
CHANGED
@@ -1628,8 +1628,7 @@ function tighten_body(statements, compressor) {
|
|
1628
1628
|
extract_candidates(expr.condition);
|
1629
1629
|
extract_candidates(expr.consequent);
|
1630
1630
|
extract_candidates(expr.alternative);
|
1631
|
-
} else if (expr instanceof AST_Definitions
|
1632
|
-
&& (compressor.option("unused") || !(expr instanceof AST_Const))) {
|
1631
|
+
} else if (expr instanceof AST_Definitions) {
|
1633
1632
|
var len = expr.definitions.length;
|
1634
1633
|
// limit number of trailing variable definitions for consideration
|
1635
1634
|
var i = len - 200;
|
@@ -1797,7 +1796,9 @@ function tighten_body(statements, compressor) {
|
|
1797
1796
|
if (node === expr || node.body === expr) {
|
1798
1797
|
found = true;
|
1799
1798
|
if (node instanceof AST_VarDef) {
|
1800
|
-
node.value =
|
1799
|
+
node.value = node.name instanceof AST_SymbolConst
|
1800
|
+
? make_node(AST_Undefined, node.value) // `const` always needs value.
|
1801
|
+
: null;
|
1801
1802
|
return node;
|
1802
1803
|
}
|
1803
1804
|
return in_list ? MAP.skip : null;
|
@@ -2113,7 +2114,7 @@ function tighten_body(statements, compressor) {
|
|
2113
2114
|
statements.length = n;
|
2114
2115
|
CHANGED = n != len;
|
2115
2116
|
if (has_quit) has_quit.forEach(function(stat) {
|
2116
|
-
|
2117
|
+
trim_unreachable_code(compressor, stat, statements);
|
2117
2118
|
});
|
2118
2119
|
}
|
2119
2120
|
|
@@ -2371,7 +2372,7 @@ function tighten_body(statements, compressor) {
|
|
2371
2372
|
}
|
2372
2373
|
}
|
2373
2374
|
|
2374
|
-
function
|
2375
|
+
function trim_unreachable_code(compressor, stat, target) {
|
2375
2376
|
walk(stat, node => {
|
2376
2377
|
if (node instanceof AST_Var) {
|
2377
2378
|
node.remove_initializers();
|
@@ -2392,6 +2393,10 @@ function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
|
2392
2393
|
}));
|
2393
2394
|
return true;
|
2394
2395
|
}
|
2396
|
+
if (node instanceof AST_Export || node instanceof AST_Import) {
|
2397
|
+
target.push(node);
|
2398
|
+
return true;
|
2399
|
+
}
|
2395
2400
|
if (node instanceof AST_Scope) {
|
2396
2401
|
return true;
|
2397
2402
|
}
|
@@ -2443,6 +2448,10 @@ function is_undefined(node, compressor) {
|
|
2443
2448
|
if (this.properties[i]._dot_throw(compressor)) return true;
|
2444
2449
|
return false;
|
2445
2450
|
});
|
2451
|
+
// Do not be as strict with classes as we are with objects.
|
2452
|
+
// Hopefully the community is not going to abuse static getters and setters.
|
2453
|
+
// https://github.com/terser/terser/issues/724#issuecomment-643655656
|
2454
|
+
def_may_throw_on_access(AST_Class, return_false);
|
2446
2455
|
def_may_throw_on_access(AST_ObjectProperty, return_false);
|
2447
2456
|
def_may_throw_on_access(AST_ObjectGetter, return_true);
|
2448
2457
|
def_may_throw_on_access(AST_Expansion, function(compressor) {
|
@@ -2475,7 +2484,8 @@ function is_undefined(node, compressor) {
|
|
2475
2484
|
return this.tail_node()._dot_throw(compressor);
|
2476
2485
|
});
|
2477
2486
|
def_may_throw_on_access(AST_SymbolRef, function(compressor) {
|
2478
|
-
if (
|
2487
|
+
if (this.name === "arguments") return false;
|
2488
|
+
if (has_flag(this, UNDEFINED)) return true;
|
2479
2489
|
if (!is_strict(compressor)) return false;
|
2480
2490
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
2481
2491
|
if (this.is_immutable()) return false;
|
@@ -2877,13 +2887,33 @@ var static_fns = convert_to_predicate({
|
|
2877
2887
|
return this;
|
2878
2888
|
});
|
2879
2889
|
var non_converting_binary = makePredicate("&& || ?? === !==");
|
2890
|
+
const identity_comparison = makePredicate("== != === !==");
|
2891
|
+
const has_identity = value =>
|
2892
|
+
typeof value === "object"
|
2893
|
+
|| typeof value === "function"
|
2894
|
+
|| typeof value === "symbol";
|
2895
|
+
|
2880
2896
|
def_eval(AST_Binary, function(compressor, depth) {
|
2881
2897
|
if (!non_converting_binary.has(this.operator)) depth++;
|
2898
|
+
|
2882
2899
|
var left = this.left._eval(compressor, depth);
|
2883
2900
|
if (left === this.left) return this;
|
2884
2901
|
var right = this.right._eval(compressor, depth);
|
2885
2902
|
if (right === this.right) return this;
|
2886
2903
|
var result;
|
2904
|
+
|
2905
|
+
if (
|
2906
|
+
left != null
|
2907
|
+
&& right != null
|
2908
|
+
&& identity_comparison.has(this.operator)
|
2909
|
+
&& has_identity(left)
|
2910
|
+
&& has_identity(right)
|
2911
|
+
&& typeof left === typeof right
|
2912
|
+
) {
|
2913
|
+
// Do not compare by reference
|
2914
|
+
return this;
|
2915
|
+
}
|
2916
|
+
|
2887
2917
|
switch (this.operator) {
|
2888
2918
|
case "&&" : result = left && right; break;
|
2889
2919
|
case "||" : result = left || right; break;
|
@@ -2924,20 +2954,24 @@ var static_fns = convert_to_predicate({
|
|
2924
2954
|
var value = node._eval(compressor, depth);
|
2925
2955
|
return value === node ? this : value;
|
2926
2956
|
});
|
2957
|
+
|
2958
|
+
// Set of AST_SymbolRef which are currently being evaluated.
|
2959
|
+
// Avoids infinite recursion of ._eval()
|
2960
|
+
const reentrant_ref_eval = new Set();
|
2927
2961
|
def_eval(AST_SymbolRef, function(compressor, depth) {
|
2962
|
+
if (reentrant_ref_eval.has(this)) return this;
|
2963
|
+
|
2928
2964
|
var fixed = this.fixed_value();
|
2929
2965
|
if (!fixed) return this;
|
2930
2966
|
var value;
|
2931
2967
|
if (HOP(fixed, "_eval")) {
|
2932
2968
|
value = fixed._eval();
|
2933
2969
|
} else {
|
2934
|
-
this
|
2970
|
+
reentrant_ref_eval.add(this);
|
2935
2971
|
value = fixed._eval(compressor, depth);
|
2936
|
-
delete
|
2972
|
+
reentrant_ref_eval.delete(this);
|
2973
|
+
|
2937
2974
|
if (value === fixed) return this;
|
2938
|
-
fixed._eval = function() {
|
2939
|
-
return value;
|
2940
|
-
};
|
2941
2975
|
}
|
2942
2976
|
if (value && typeof value == "object") {
|
2943
2977
|
var escaped = this.definition().escaped;
|
@@ -2945,13 +2979,7 @@ var static_fns = convert_to_predicate({
|
|
2945
2979
|
}
|
2946
2980
|
return value;
|
2947
2981
|
});
|
2948
|
-
var global_objs = {
|
2949
|
-
Array: Array,
|
2950
|
-
Math: Math,
|
2951
|
-
Number: Number,
|
2952
|
-
Object: Object,
|
2953
|
-
String: String,
|
2954
|
-
};
|
2982
|
+
var global_objs = { Array, Math, Number, Object, String };
|
2955
2983
|
var static_values = convert_to_predicate({
|
2956
2984
|
Math: [
|
2957
2985
|
"E",
|
@@ -4477,7 +4505,7 @@ function if_break_in_loop(self, compressor) {
|
|
4477
4505
|
body: self.condition
|
4478
4506
|
}));
|
4479
4507
|
}
|
4480
|
-
|
4508
|
+
trim_unreachable_code(compressor, self.body, body);
|
4481
4509
|
return make_node(AST_BlockStatement, self, {
|
4482
4510
|
body: body
|
4483
4511
|
});
|
@@ -4548,7 +4576,7 @@ def_optimize(AST_For, function(self, compressor) {
|
|
4548
4576
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
4549
4577
|
if (!cond) {
|
4550
4578
|
var body = [];
|
4551
|
-
|
4579
|
+
trim_unreachable_code(compressor, self.body, body);
|
4552
4580
|
if (self.init instanceof AST_Statement) {
|
4553
4581
|
body.push(self.init);
|
4554
4582
|
} else if (self.init) {
|
@@ -4584,7 +4612,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
4584
4612
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
4585
4613
|
if (!cond) {
|
4586
4614
|
var body = [];
|
4587
|
-
|
4615
|
+
trim_unreachable_code(compressor, self.body, body);
|
4588
4616
|
body.push(make_node(AST_SimpleStatement, self.condition, {
|
4589
4617
|
body: self.condition
|
4590
4618
|
}));
|
@@ -4597,7 +4625,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
4597
4625
|
}));
|
4598
4626
|
body.push(self.body);
|
4599
4627
|
if (self.alternative) {
|
4600
|
-
|
4628
|
+
trim_unreachable_code(compressor, self.alternative, body);
|
4601
4629
|
}
|
4602
4630
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
4603
4631
|
}
|
@@ -4809,7 +4837,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
4809
4837
|
if (prev && !aborts(prev)) {
|
4810
4838
|
prev.body = prev.body.concat(branch.body);
|
4811
4839
|
} else {
|
4812
|
-
|
4840
|
+
trim_unreachable_code(compressor, branch, decl);
|
4813
4841
|
}
|
4814
4842
|
}
|
4815
4843
|
});
|
@@ -4820,7 +4848,7 @@ def_optimize(AST_Try, function(self, compressor) {
|
|
4820
4848
|
if (compressor.option("dead_code") && self.body.every(is_empty)) {
|
4821
4849
|
var body = [];
|
4822
4850
|
if (self.bcatch) {
|
4823
|
-
|
4851
|
+
trim_unreachable_code(compressor, self.bcatch, body);
|
4824
4852
|
}
|
4825
4853
|
if (self.bfinally) body.push(...self.bfinally.body);
|
4826
4854
|
return make_node(AST_BlockStatement, self, {
|
@@ -7349,7 +7377,7 @@ function lift_key(self, compressor) {
|
|
7349
7377
|
if (!compressor.option("computed_props")) return self;
|
7350
7378
|
// save a comparison in the typical case
|
7351
7379
|
if (!(self.key instanceof AST_Constant)) return self;
|
7352
|
-
//
|
7380
|
+
// allow certain acceptable props as not all AST_Constants are true constants
|
7353
7381
|
if (self.key instanceof AST_String || self.key instanceof AST_Number) {
|
7354
7382
|
if (self.key.value === "__proto__") return self;
|
7355
7383
|
if (self.key.value == "constructor"
|
package/lib/parse.js
CHANGED
@@ -503,12 +503,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|
503
503
|
}
|
504
504
|
|
505
505
|
function read_num(prefix) {
|
506
|
-
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false;
|
506
|
+
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false, numeric_separator = false;
|
507
507
|
var num = read_while(function(ch, i) {
|
508
508
|
if (is_big_int) return false;
|
509
509
|
|
510
510
|
var code = ch.charCodeAt(0);
|
511
511
|
switch (code) {
|
512
|
+
case 95: // _
|
513
|
+
return (numeric_separator = true);
|
512
514
|
case 98: case 66: // bB
|
513
515
|
return (has_x = true); // Can occur in hex sequence, don't return false yet
|
514
516
|
case 111: case 79: // oO
|
@@ -536,6 +538,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|
536
538
|
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
537
539
|
parse_error("Legacy octal literals are not allowed in strict mode");
|
538
540
|
}
|
541
|
+
if (numeric_separator) {
|
542
|
+
if (num.endsWith("_")) {
|
543
|
+
parse_error("Numeric separators are not allowed at the end of numeric literals");
|
544
|
+
} else if (num.includes("__")) {
|
545
|
+
parse_error("Only one underscore is allowed as numeric separator");
|
546
|
+
}
|
547
|
+
num = num.replace(/_/g, "");
|
548
|
+
}
|
539
549
|
if (num.endsWith("n")) {
|
540
550
|
const without_n = num.slice(0, -1);
|
541
551
|
const allow_e = RE_HEX_NUMBER.test(without_n);
|
@@ -2798,15 +2808,6 @@ function parse($TEXT, options) {
|
|
2798
2808
|
}
|
2799
2809
|
/* falls through */
|
2800
2810
|
case "name":
|
2801
|
-
if (tmp.value == "yield") {
|
2802
|
-
if (is_in_generator()) {
|
2803
|
-
token_error(tmp, "Yield cannot be used as identifier inside generators");
|
2804
|
-
} else if (!is_token(peek(), "punc", ":")
|
2805
|
-
&& !is_token(peek(), "punc", "(")
|
2806
|
-
&& S.input.has_directive("use strict")) {
|
2807
|
-
token_error(tmp, "Unexpected yield identifier inside strict mode");
|
2808
|
-
}
|
2809
|
-
}
|
2810
2811
|
case "string":
|
2811
2812
|
case "num":
|
2812
2813
|
case "big_int":
|
package/lib/propmangle.js
CHANGED
@@ -50,6 +50,7 @@ import {
|
|
50
50
|
} from "./utils/index.js";
|
51
51
|
import { base54 } from "./scope.js";
|
52
52
|
import {
|
53
|
+
AST_Binary,
|
53
54
|
AST_Call,
|
54
55
|
AST_Conditional,
|
55
56
|
AST_Dot,
|
@@ -212,6 +213,8 @@ function mangle_properties(ast, options) {
|
|
212
213
|
} else if (node instanceof AST_Call
|
213
214
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
214
215
|
addStrings(node.args[1], add);
|
216
|
+
} else if (node instanceof AST_Binary && node.operator === "in") {
|
217
|
+
addStrings(node.left, add);
|
215
218
|
}
|
216
219
|
}));
|
217
220
|
|
@@ -236,6 +239,8 @@ function mangle_properties(ast, options) {
|
|
236
239
|
} else if (node instanceof AST_Call
|
237
240
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
238
241
|
node.args[1] = mangleStrings(node.args[1]);
|
242
|
+
} else if (node instanceof AST_Binary && node.operator === "in") {
|
243
|
+
node.left = mangleStrings(node.left);
|
239
244
|
}
|
240
245
|
}));
|
241
246
|
|
package/lib/size.js
CHANGED
@@ -159,7 +159,7 @@ AST_Arrow.prototype._size = function () {
|
|
159
159
|
args_and_arrow += 2;
|
160
160
|
}
|
161
161
|
|
162
|
-
return lambda_modifiers(this) + args_and_arrow + Array.isArray(this.body) ? list_overhead(this.body) : this.body._size();
|
162
|
+
return lambda_modifiers(this) + args_and_arrow + (Array.isArray(this.body) ? list_overhead(this.body) : this.body._size());
|
163
163
|
};
|
164
164
|
|
165
165
|
AST_Destructuring.prototype._size = () => 2;
|
package/package.json
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
"homepage": "https://terser.org",
|
5
5
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
6
6
|
"license": "BSD-2-Clause",
|
7
|
-
"version": "5.0.0
|
7
|
+
"version": "5.0.0",
|
8
8
|
"engines": {
|
9
9
|
"node": ">=6.0.0"
|
10
10
|
},
|
@@ -47,6 +47,7 @@
|
|
47
47
|
"source-map-support": "~0.5.12"
|
48
48
|
},
|
49
49
|
"devDependencies": {
|
50
|
+
"@ls-lint/ls-lint": "^1.9.2",
|
50
51
|
"acorn": "^7.1.1",
|
51
52
|
"astring": "^1.4.1",
|
52
53
|
"eslint": "^7.0.0",
|
@@ -64,6 +65,7 @@
|
|
64
65
|
"test:mocha": "mocha test/mocha",
|
65
66
|
"lint": "eslint lib",
|
66
67
|
"lint-fix": "eslint --fix lib",
|
68
|
+
"ls-lint": "ls-lint",
|
67
69
|
"build": "rimraf dist/bundle* && rollup --config --silent",
|
68
70
|
"prepare": "npm run build",
|
69
71
|
"postversion": "echo 'Remember to update the changelog!'"
|
@@ -140,6 +142,7 @@
|
|
140
142
|
},
|
141
143
|
"pre-commit": [
|
142
144
|
"lint-fix",
|
145
|
+
"ls-lint",
|
143
146
|
"test"
|
144
147
|
]
|
145
148
|
}
|