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/CHANGELOG.md
CHANGED
@@ -1,13 +1,32 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v5.0.0
|
4
|
+
|
5
|
+
- `in` operator now taken into account during property mangle.
|
6
|
+
- Fixed infinite loop in face of a reference loop in some situations.
|
7
|
+
- Kept exports and imports around even if there's something which will throw before them.
|
8
|
+
- The main exported bundle for commonjs, dist/bundle.min.js is no longer minified.
|
9
|
+
|
3
10
|
## v5.0.0-beta.0
|
4
11
|
|
5
|
-
- `minify()` is now async and rejects a promise instead of returning an error.
|
6
|
-
- Internal AST is no longer exposed, so that it can be improved without releasing breaking changes.
|
7
|
-
- Lowest supported node version is 10
|
12
|
+
- BREAKING: `minify()` is now async and rejects a promise instead of returning an error.
|
13
|
+
- BREAKING: Internal AST is no longer exposed, so that it can be improved without releasing breaking changes.
|
14
|
+
- BREAKING: Lowest supported node version is 10
|
8
15
|
- Module is now distributed as a dual package - You can `import` and `require()` too.
|
9
16
|
- Inline improvements were made
|
10
17
|
|
18
|
+
## v4.8.0
|
19
|
+
|
20
|
+
- Support for numeric separators (`million = 1_000_000`) was added.
|
21
|
+
- Assigning properties to a class is now assumed to be pure.
|
22
|
+
- Fixed bug where `yield` wasn't considered a valid property key in generators.
|
23
|
+
|
24
|
+
## v4.7.0
|
25
|
+
|
26
|
+
- A bug was fixed where an arrow function would have the wrong size
|
27
|
+
- `arguments` object is now considered safe to retrieve properties from (useful for `length`, or `0`) even when `pure_getters` is not set.
|
28
|
+
- Fixed erroneous `const` declarations without value (which is invalid) in some corner cases when using `collapse_vars`.
|
29
|
+
|
11
30
|
## v4.6.13
|
12
31
|
|
13
32
|
- Fixed issue where ES5 object properties were being turned into ES6 object properties due to more lax unicode rules.
|
package/README.md
CHANGED
@@ -1251,6 +1251,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|
1251
1251
|
`Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
|
1252
1252
|
`Object.preventExtensions()` or `Object.seal()`).
|
1253
1253
|
- `document.all` is not `== null`
|
1254
|
+
- Assigning properties to a class doesn't have side effects and does not throw.
|
1254
1255
|
|
1255
1256
|
### Build Tools and Adaptors using Terser
|
1256
1257
|
|
package/dist/bundle.min.js
CHANGED
@@ -672,12 +672,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|
672
672
|
}
|
673
673
|
|
674
674
|
function read_num(prefix) {
|
675
|
-
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false;
|
675
|
+
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false, numeric_separator = false;
|
676
676
|
var num = read_while(function(ch, i) {
|
677
677
|
if (is_big_int) return false;
|
678
678
|
|
679
679
|
var code = ch.charCodeAt(0);
|
680
680
|
switch (code) {
|
681
|
+
case 95: // _
|
682
|
+
return (numeric_separator = true);
|
681
683
|
case 98: case 66: // bB
|
682
684
|
return (has_x = true); // Can occur in hex sequence, don't return false yet
|
683
685
|
case 111: case 79: // oO
|
@@ -705,6 +707,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|
705
707
|
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
706
708
|
parse_error("Legacy octal literals are not allowed in strict mode");
|
707
709
|
}
|
710
|
+
if (numeric_separator) {
|
711
|
+
if (num.endsWith("_")) {
|
712
|
+
parse_error("Numeric separators are not allowed at the end of numeric literals");
|
713
|
+
} else if (num.includes("__")) {
|
714
|
+
parse_error("Only one underscore is allowed as numeric separator");
|
715
|
+
}
|
716
|
+
num = num.replace(/_/g, "");
|
717
|
+
}
|
708
718
|
if (num.endsWith("n")) {
|
709
719
|
const without_n = num.slice(0, -1);
|
710
720
|
const allow_e = RE_HEX_NUMBER.test(without_n);
|
@@ -2967,15 +2977,6 @@ function parse($TEXT, options) {
|
|
2967
2977
|
}
|
2968
2978
|
/* falls through */
|
2969
2979
|
case "name":
|
2970
|
-
if (tmp.value == "yield") {
|
2971
|
-
if (is_in_generator()) {
|
2972
|
-
token_error(tmp, "Yield cannot be used as identifier inside generators");
|
2973
|
-
} else if (!is_token(peek(), "punc", ":")
|
2974
|
-
&& !is_token(peek(), "punc", "(")
|
2975
|
-
&& S.input.has_directive("use strict")) {
|
2976
|
-
token_error(tmp, "Unexpected yield identifier inside strict mode");
|
2977
|
-
}
|
2978
|
-
}
|
2979
2980
|
case "string":
|
2980
2981
|
case "num":
|
2981
2982
|
case "big_int":
|
@@ -9780,7 +9781,7 @@ AST_Arrow.prototype._size = function () {
|
|
9780
9781
|
args_and_arrow += 2;
|
9781
9782
|
}
|
9782
9783
|
|
9783
|
-
return lambda_modifiers(this) + args_and_arrow + Array.isArray(this.body) ? list_overhead(this.body) : this.body._size();
|
9784
|
+
return lambda_modifiers(this) + args_and_arrow + (Array.isArray(this.body) ? list_overhead(this.body) : this.body._size());
|
9784
9785
|
};
|
9785
9786
|
|
9786
9787
|
AST_Destructuring.prototype._size = () => 2;
|
@@ -11546,8 +11547,7 @@ function tighten_body(statements, compressor) {
|
|
11546
11547
|
extract_candidates(expr.condition);
|
11547
11548
|
extract_candidates(expr.consequent);
|
11548
11549
|
extract_candidates(expr.alternative);
|
11549
|
-
} else if (expr instanceof AST_Definitions
|
11550
|
-
&& (compressor.option("unused") || !(expr instanceof AST_Const))) {
|
11550
|
+
} else if (expr instanceof AST_Definitions) {
|
11551
11551
|
var len = expr.definitions.length;
|
11552
11552
|
// limit number of trailing variable definitions for consideration
|
11553
11553
|
var i = len - 200;
|
@@ -11715,7 +11715,9 @@ function tighten_body(statements, compressor) {
|
|
11715
11715
|
if (node === expr || node.body === expr) {
|
11716
11716
|
found = true;
|
11717
11717
|
if (node instanceof AST_VarDef) {
|
11718
|
-
node.value =
|
11718
|
+
node.value = node.name instanceof AST_SymbolConst
|
11719
|
+
? make_node(AST_Undefined, node.value) // `const` always needs value.
|
11720
|
+
: null;
|
11719
11721
|
return node;
|
11720
11722
|
}
|
11721
11723
|
return in_list ? MAP.skip : null;
|
@@ -12031,7 +12033,7 @@ function tighten_body(statements, compressor) {
|
|
12031
12033
|
statements.length = n;
|
12032
12034
|
CHANGED = n != len;
|
12033
12035
|
if (has_quit) has_quit.forEach(function(stat) {
|
12034
|
-
|
12036
|
+
trim_unreachable_code(compressor, stat, statements);
|
12035
12037
|
});
|
12036
12038
|
}
|
12037
12039
|
|
@@ -12289,7 +12291,7 @@ function tighten_body(statements, compressor) {
|
|
12289
12291
|
}
|
12290
12292
|
}
|
12291
12293
|
|
12292
|
-
function
|
12294
|
+
function trim_unreachable_code(compressor, stat, target) {
|
12293
12295
|
walk(stat, node => {
|
12294
12296
|
if (node instanceof AST_Var) {
|
12295
12297
|
node.remove_initializers();
|
@@ -12310,6 +12312,10 @@ function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
|
12310
12312
|
}));
|
12311
12313
|
return true;
|
12312
12314
|
}
|
12315
|
+
if (node instanceof AST_Export || node instanceof AST_Import) {
|
12316
|
+
target.push(node);
|
12317
|
+
return true;
|
12318
|
+
}
|
12313
12319
|
if (node instanceof AST_Scope) {
|
12314
12320
|
return true;
|
12315
12321
|
}
|
@@ -12361,6 +12367,10 @@ function is_undefined(node, compressor) {
|
|
12361
12367
|
if (this.properties[i]._dot_throw(compressor)) return true;
|
12362
12368
|
return false;
|
12363
12369
|
});
|
12370
|
+
// Do not be as strict with classes as we are with objects.
|
12371
|
+
// Hopefully the community is not going to abuse static getters and setters.
|
12372
|
+
// https://github.com/terser/terser/issues/724#issuecomment-643655656
|
12373
|
+
def_may_throw_on_access(AST_Class, return_false);
|
12364
12374
|
def_may_throw_on_access(AST_ObjectProperty, return_false);
|
12365
12375
|
def_may_throw_on_access(AST_ObjectGetter, return_true);
|
12366
12376
|
def_may_throw_on_access(AST_Expansion, function(compressor) {
|
@@ -12393,7 +12403,8 @@ function is_undefined(node, compressor) {
|
|
12393
12403
|
return this.tail_node()._dot_throw(compressor);
|
12394
12404
|
});
|
12395
12405
|
def_may_throw_on_access(AST_SymbolRef, function(compressor) {
|
12396
|
-
if (
|
12406
|
+
if (this.name === "arguments") return false;
|
12407
|
+
if (has_flag(this, UNDEFINED)) return true;
|
12397
12408
|
if (!is_strict(compressor)) return false;
|
12398
12409
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
12399
12410
|
if (this.is_immutable()) return false;
|
@@ -12795,13 +12806,33 @@ var static_fns = convert_to_predicate({
|
|
12795
12806
|
return this;
|
12796
12807
|
});
|
12797
12808
|
var non_converting_binary = makePredicate("&& || ?? === !==");
|
12809
|
+
const identity_comparison = makePredicate("== != === !==");
|
12810
|
+
const has_identity = value =>
|
12811
|
+
typeof value === "object"
|
12812
|
+
|| typeof value === "function"
|
12813
|
+
|| typeof value === "symbol";
|
12814
|
+
|
12798
12815
|
def_eval(AST_Binary, function(compressor, depth) {
|
12799
12816
|
if (!non_converting_binary.has(this.operator)) depth++;
|
12817
|
+
|
12800
12818
|
var left = this.left._eval(compressor, depth);
|
12801
12819
|
if (left === this.left) return this;
|
12802
12820
|
var right = this.right._eval(compressor, depth);
|
12803
12821
|
if (right === this.right) return this;
|
12804
12822
|
var result;
|
12823
|
+
|
12824
|
+
if (
|
12825
|
+
left != null
|
12826
|
+
&& right != null
|
12827
|
+
&& identity_comparison.has(this.operator)
|
12828
|
+
&& has_identity(left)
|
12829
|
+
&& has_identity(right)
|
12830
|
+
&& typeof left === typeof right
|
12831
|
+
) {
|
12832
|
+
// Do not compare by reference
|
12833
|
+
return this;
|
12834
|
+
}
|
12835
|
+
|
12805
12836
|
switch (this.operator) {
|
12806
12837
|
case "&&" : result = left && right; break;
|
12807
12838
|
case "||" : result = left || right; break;
|
@@ -12842,20 +12873,24 @@ var static_fns = convert_to_predicate({
|
|
12842
12873
|
var value = node._eval(compressor, depth);
|
12843
12874
|
return value === node ? this : value;
|
12844
12875
|
});
|
12876
|
+
|
12877
|
+
// Set of AST_SymbolRef which are currently being evaluated.
|
12878
|
+
// Avoids infinite recursion of ._eval()
|
12879
|
+
const reentrant_ref_eval = new Set();
|
12845
12880
|
def_eval(AST_SymbolRef, function(compressor, depth) {
|
12881
|
+
if (reentrant_ref_eval.has(this)) return this;
|
12882
|
+
|
12846
12883
|
var fixed = this.fixed_value();
|
12847
12884
|
if (!fixed) return this;
|
12848
12885
|
var value;
|
12849
12886
|
if (HOP(fixed, "_eval")) {
|
12850
12887
|
value = fixed._eval();
|
12851
12888
|
} else {
|
12852
|
-
this
|
12889
|
+
reentrant_ref_eval.add(this);
|
12853
12890
|
value = fixed._eval(compressor, depth);
|
12854
|
-
delete
|
12891
|
+
reentrant_ref_eval.delete(this);
|
12892
|
+
|
12855
12893
|
if (value === fixed) return this;
|
12856
|
-
fixed._eval = function() {
|
12857
|
-
return value;
|
12858
|
-
};
|
12859
12894
|
}
|
12860
12895
|
if (value && typeof value == "object") {
|
12861
12896
|
var escaped = this.definition().escaped;
|
@@ -12863,13 +12898,7 @@ var static_fns = convert_to_predicate({
|
|
12863
12898
|
}
|
12864
12899
|
return value;
|
12865
12900
|
});
|
12866
|
-
var global_objs = {
|
12867
|
-
Array: Array,
|
12868
|
-
Math: Math,
|
12869
|
-
Number: Number,
|
12870
|
-
Object: Object,
|
12871
|
-
String: String,
|
12872
|
-
};
|
12901
|
+
var global_objs = { Array, Math, Number, Object, String };
|
12873
12902
|
var static_values = convert_to_predicate({
|
12874
12903
|
Math: [
|
12875
12904
|
"E",
|
@@ -14395,7 +14424,7 @@ function if_break_in_loop(self, compressor) {
|
|
14395
14424
|
body: self.condition
|
14396
14425
|
}));
|
14397
14426
|
}
|
14398
|
-
|
14427
|
+
trim_unreachable_code(compressor, self.body, body);
|
14399
14428
|
return make_node(AST_BlockStatement, self, {
|
14400
14429
|
body: body
|
14401
14430
|
});
|
@@ -14466,7 +14495,7 @@ def_optimize(AST_For, function(self, compressor) {
|
|
14466
14495
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
14467
14496
|
if (!cond) {
|
14468
14497
|
var body = [];
|
14469
|
-
|
14498
|
+
trim_unreachable_code(compressor, self.body, body);
|
14470
14499
|
if (self.init instanceof AST_Statement) {
|
14471
14500
|
body.push(self.init);
|
14472
14501
|
} else if (self.init) {
|
@@ -14502,7 +14531,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
14502
14531
|
if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
|
14503
14532
|
if (!cond) {
|
14504
14533
|
var body = [];
|
14505
|
-
|
14534
|
+
trim_unreachable_code(compressor, self.body, body);
|
14506
14535
|
body.push(make_node(AST_SimpleStatement, self.condition, {
|
14507
14536
|
body: self.condition
|
14508
14537
|
}));
|
@@ -14515,7 +14544,7 @@ def_optimize(AST_If, function(self, compressor) {
|
|
14515
14544
|
}));
|
14516
14545
|
body.push(self.body);
|
14517
14546
|
if (self.alternative) {
|
14518
|
-
|
14547
|
+
trim_unreachable_code(compressor, self.alternative, body);
|
14519
14548
|
}
|
14520
14549
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
14521
14550
|
}
|
@@ -14727,7 +14756,7 @@ def_optimize(AST_Switch, function(self, compressor) {
|
|
14727
14756
|
if (prev && !aborts(prev)) {
|
14728
14757
|
prev.body = prev.body.concat(branch.body);
|
14729
14758
|
} else {
|
14730
|
-
|
14759
|
+
trim_unreachable_code(compressor, branch, decl);
|
14731
14760
|
}
|
14732
14761
|
}
|
14733
14762
|
});
|
@@ -14738,7 +14767,7 @@ def_optimize(AST_Try, function(self, compressor) {
|
|
14738
14767
|
if (compressor.option("dead_code") && self.body.every(is_empty)) {
|
14739
14768
|
var body = [];
|
14740
14769
|
if (self.bcatch) {
|
14741
|
-
|
14770
|
+
trim_unreachable_code(compressor, self.bcatch, body);
|
14742
14771
|
}
|
14743
14772
|
if (self.bfinally) body.push(...self.bfinally.body);
|
14744
14773
|
return make_node(AST_BlockStatement, self, {
|
@@ -17267,7 +17296,7 @@ function lift_key(self, compressor) {
|
|
17267
17296
|
if (!compressor.option("computed_props")) return self;
|
17268
17297
|
// save a comparison in the typical case
|
17269
17298
|
if (!(self.key instanceof AST_Constant)) return self;
|
17270
|
-
//
|
17299
|
+
// allow certain acceptable props as not all AST_Constants are true constants
|
17271
17300
|
if (self.key instanceof AST_String || self.key instanceof AST_Number) {
|
17272
17301
|
if (self.key.value === "__proto__") return self;
|
17273
17302
|
if (self.key.value == "constructor"
|
@@ -23301,6 +23330,8 @@ function mangle_properties(ast, options) {
|
|
23301
23330
|
} else if (node instanceof AST_Call
|
23302
23331
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
23303
23332
|
addStrings(node.args[1], add);
|
23333
|
+
} else if (node instanceof AST_Binary && node.operator === "in") {
|
23334
|
+
addStrings(node.left, add);
|
23304
23335
|
}
|
23305
23336
|
}));
|
23306
23337
|
|
@@ -23325,6 +23356,8 @@ function mangle_properties(ast, options) {
|
|
23325
23356
|
} else if (node instanceof AST_Call
|
23326
23357
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
23327
23358
|
node.args[1] = mangleStrings(node.args[1]);
|
23359
|
+
} else if (node instanceof AST_Binary && node.operator === "in") {
|
23360
|
+
node.left = mangleStrings(node.left);
|
23328
23361
|
}
|
23329
23362
|
}));
|
23330
23363
|
|
@@ -23704,6 +23737,7 @@ async function run_cli({ program, packageJson, fs, path }) {
|
|
23704
23737
|
options[name] = program[name];
|
23705
23738
|
}
|
23706
23739
|
});
|
23740
|
+
|
23707
23741
|
if ("ecma" in program) {
|
23708
23742
|
if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
|
23709
23743
|
const ecma = program.ecma | 0;
|
@@ -23933,7 +23967,7 @@ async function run_cli({ program, packageJson, fs, path }) {
|
|
23933
23967
|
}
|
23934
23968
|
} else if (program.output) {
|
23935
23969
|
fs.writeFileSync(program.output, result.code);
|
23936
|
-
if (options.sourceMap.url !== "inline" && result.map) {
|
23970
|
+
if (options.sourceMap && options.sourceMap.url !== "inline" && result.map) {
|
23937
23971
|
fs.writeFileSync(program.output + ".map", result.map);
|
23938
23972
|
}
|
23939
23973
|
} else {
|