terser 5.16.8 → 5.17.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 +11 -1
- package/README.md +15 -1
- package/dist/bundle.min.js +87 -10
- package/lib/ast.js +3 -0
- package/lib/compress/common.js +3 -1
- package/lib/compress/evaluate.js +28 -1
- package/lib/compress/index.js +32 -8
- package/lib/output.js +6 -0
- package/lib/parse.js +7 -1
- package/lib/propmangle.js +11 -0
- package/lib/utils/index.js +6 -1
- package/package.json +1 -1
- package/bin/terser.mjs +0 -21
package/CHANGELOG.md
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v5.17.0
|
4
|
+
- Drop vestigial `= undefined` default argument in IIFE calls (#1366)
|
5
|
+
- Evaluate known arrays' `.length` property when statically determinable
|
6
|
+
- Add `@__KEY__` annotation to mangle string literals (#1365)
|
7
|
+
|
8
|
+
## v5.16.9
|
9
|
+
- Fix parentheses in output of optional chains (`a?.b`) (#1374)
|
10
|
+
- More documentation on source maps (#1368)
|
11
|
+
- New `lhs_constants` option, allowing to stop Terser from swapping comparison operands (#1361)
|
12
|
+
|
3
13
|
## v5.16.8
|
4
14
|
|
5
15
|
- Become even less conservative around function definitions for `reduce_vars`
|
6
16
|
- Fix parsing context of `import.meta` expressions such that method calls are allowed
|
7
17
|
|
8
|
-
## v5.16.
|
18
|
+
## v5.16.6
|
9
19
|
|
10
20
|
- Become less conservative with analyzing function definitions for `reduce_vars`
|
11
21
|
- Parse `import.meta` as a real AST node and not an `object.property`
|
package/README.md
CHANGED
@@ -708,7 +708,8 @@ If you happen to need the source map as a raw object, set `sourceMap.asObject` t
|
|
708
708
|
|
709
709
|
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes,
|
710
710
|
e.g. `!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
|
711
|
-
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
|
711
|
+
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc. Note: `comparisons`
|
712
|
+
works best with `lhs_constants` enabled.
|
712
713
|
|
713
714
|
- `computed_props` (default: `true`) -- Transforms constant computed properties
|
714
715
|
into regular ones: `{["computed"]: 1}` is converted to `{computed: 1}`.
|
@@ -775,6 +776,9 @@ If you happen to need the source map as a raw object, set `sourceMap.asObject` t
|
|
775
776
|
- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
|
776
777
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
777
778
|
|
779
|
+
- `lhs_constants` (default: `true`) -- Moves constant values to the left-hand side
|
780
|
+
of binary nodes. `foo == 42 → 42 == foo`
|
781
|
+
|
778
782
|
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
|
779
783
|
when we can statically determine the condition.
|
780
784
|
|
@@ -1184,6 +1188,7 @@ Annotations in Terser are a way to tell it to treat a certain function call diff
|
|
1184
1188
|
* `/*@__INLINE__*/` - forces a function to be inlined somewhere.
|
1185
1189
|
* `/*@__NOINLINE__*/` - Makes sure the called function is not inlined into the call site.
|
1186
1190
|
* `/*@__PURE__*/` - Marks a function call as pure. That means, it can safely be dropped.
|
1191
|
+
* `/*@__KEY__*/` - Marks a string literal as a property to also mangle it when mangling properties.
|
1187
1192
|
|
1188
1193
|
You can use either a `@` sign at the start, or a `#`.
|
1189
1194
|
|
@@ -1197,6 +1202,9 @@ function_always_inlined_here()
|
|
1197
1202
|
function_cant_be_inlined_into_here()
|
1198
1203
|
|
1199
1204
|
const x = /*#__PURE__*/i_am_dropped_if_x_is_not_used()
|
1205
|
+
|
1206
|
+
function lookup(object, key) { return object[key]; }
|
1207
|
+
lookup({ i_will_be_mangled_too: "bar" }, /*@__KEY__*/ "i_will_be_mangled_too");
|
1200
1208
|
```
|
1201
1209
|
|
1202
1210
|
### ESTree / SpiderMonkey AST
|
@@ -1267,6 +1275,12 @@ expected as code is optimized and mappings are often simply not possible as
|
|
1267
1275
|
some code no longer exists. For highest fidelity in source map debugging
|
1268
1276
|
disable the `compress` option and just use `mangle`.
|
1269
1277
|
|
1278
|
+
When debugging, make sure you enable the **"map scopes"** feature to map mangled variable names back to their original names.
|
1279
|
+
Without this, all variable values will be `undefined`. See https://github.com/terser/terser/issues/1367 for more details.
|
1280
|
+
<br/><br/>
|
1281
|
+
|
1282
|
+

|
1283
|
+
|
1270
1284
|
### Compiler assumptions
|
1271
1285
|
|
1272
1286
|
To allow for better optimizations, the compiler makes various assumptions:
|
package/dist/bundle.min.js
CHANGED
@@ -264,6 +264,10 @@ function set_annotation(node, annotation) {
|
|
264
264
|
node._annotations |= annotation;
|
265
265
|
}
|
266
266
|
|
267
|
+
function clear_annotation(node, annotation) {
|
268
|
+
node._annotations &= ~annotation;
|
269
|
+
}
|
270
|
+
|
267
271
|
/***********************************************************************
|
268
272
|
|
269
273
|
A JavaScript tokenizer / parser / beautifier / compressor.
|
@@ -2368,6 +2372,7 @@ function parse($TEXT, options) {
|
|
2368
2372
|
value : tok.value,
|
2369
2373
|
quote : tok.quote
|
2370
2374
|
});
|
2375
|
+
annotate(ret);
|
2371
2376
|
break;
|
2372
2377
|
case "regexp":
|
2373
2378
|
const [_, source, flags] = tok.value.match(/^\/(.*)\/(\w*)$/);
|
@@ -3254,6 +3259,10 @@ function parse($TEXT, options) {
|
|
3254
3259
|
set_annotation(node, _NOINLINE);
|
3255
3260
|
break;
|
3256
3261
|
}
|
3262
|
+
if (/[@#]__KEY__/.test(comment.value)) {
|
3263
|
+
set_annotation(node, _KEY);
|
3264
|
+
break;
|
3265
|
+
}
|
3257
3266
|
}
|
3258
3267
|
}
|
3259
3268
|
}
|
@@ -6363,6 +6372,7 @@ var AST_String = DEFNODE("String", "value quote", function AST_String(props) {
|
|
6363
6372
|
this.quote = props.quote;
|
6364
6373
|
this.start = props.start;
|
6365
6374
|
this.end = props.end;
|
6375
|
+
this._annotations = props._annotations;
|
6366
6376
|
}
|
6367
6377
|
|
6368
6378
|
this.flags = 0;
|
@@ -6735,6 +6745,7 @@ class TreeTransformer extends TreeWalker {
|
|
6735
6745
|
const _PURE = 0b00000001;
|
6736
6746
|
const _INLINE = 0b00000010;
|
6737
6747
|
const _NOINLINE = 0b00000100;
|
6748
|
+
const _KEY = 0b00001000;
|
6738
6749
|
|
6739
6750
|
/***********************************************************************
|
6740
6751
|
|
@@ -9742,6 +9753,12 @@ function OutputStream(options) {
|
|
9742
9753
|
return true;
|
9743
9754
|
});
|
9744
9755
|
|
9756
|
+
PARENS(AST_Chain, function(output) {
|
9757
|
+
var p = output.parent();
|
9758
|
+
if (!(p instanceof AST_Call || p instanceof AST_PropAccess)) return false;
|
9759
|
+
return p.expression === this;
|
9760
|
+
});
|
9761
|
+
|
9745
9762
|
PARENS(AST_PropAccess, function(output) {
|
9746
9763
|
var p = output.parent();
|
9747
9764
|
if (p instanceof AST_New && p.expression === this) {
|
@@ -12939,7 +12956,8 @@ function maintain_this_binding(parent, orig, val) {
|
|
12939
12956
|
parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
12940
12957
|
|| parent instanceof AST_Call && parent.expression === orig
|
12941
12958
|
&& (
|
12942
|
-
val instanceof
|
12959
|
+
val instanceof AST_Chain
|
12960
|
+
|| val instanceof AST_PropAccess
|
12943
12961
|
|| val instanceof AST_SymbolRef && val.name == "eval"
|
12944
12962
|
)
|
12945
12963
|
) {
|
@@ -14471,6 +14489,33 @@ const regexp_flags = new Set([
|
|
14471
14489
|
def_eval(AST_PropAccess, function (compressor, depth) {
|
14472
14490
|
let obj = this.expression._eval(compressor, depth + 1);
|
14473
14491
|
if (obj === nullish || (this.optional && obj == null)) return nullish;
|
14492
|
+
|
14493
|
+
// `.length` of strings and arrays is always safe
|
14494
|
+
if (this.property === "length") {
|
14495
|
+
if (typeof obj === "string") {
|
14496
|
+
return obj.length;
|
14497
|
+
}
|
14498
|
+
|
14499
|
+
const is_spreadless_array = obj =>
|
14500
|
+
obj instanceof AST_Array
|
14501
|
+
&& obj.elements.every(el => !(el instanceof AST_Expansion));
|
14502
|
+
|
14503
|
+
if (
|
14504
|
+
is_spreadless_array(obj)
|
14505
|
+
&& obj.elements.every(el => !el.has_side_effects(compressor))
|
14506
|
+
) {
|
14507
|
+
return obj.elements.length;
|
14508
|
+
}
|
14509
|
+
|
14510
|
+
let fixed;
|
14511
|
+
if (
|
14512
|
+
obj instanceof AST_SymbolRef
|
14513
|
+
&& is_spreadless_array((fixed = obj.definition().fixed_value()))
|
14514
|
+
) {
|
14515
|
+
return fixed.elements.length;
|
14516
|
+
}
|
14517
|
+
}
|
14518
|
+
|
14474
14519
|
if (compressor.option("unsafe")) {
|
14475
14520
|
var key = this.property;
|
14476
14521
|
if (key instanceof AST_Node) {
|
@@ -14478,9 +14523,9 @@ def_eval(AST_PropAccess, function (compressor, depth) {
|
|
14478
14523
|
if (key === this.property)
|
14479
14524
|
return this;
|
14480
14525
|
}
|
14526
|
+
|
14481
14527
|
var exp = this.expression;
|
14482
14528
|
if (is_undeclared_ref(exp)) {
|
14483
|
-
|
14484
14529
|
var aa;
|
14485
14530
|
var first_arg = exp.name === "hasOwnProperty"
|
14486
14531
|
&& key === "call"
|
@@ -18028,6 +18073,7 @@ class Compressor extends TreeWalker {
|
|
18028
18073
|
keep_fargs : true,
|
18029
18074
|
keep_fnames : false,
|
18030
18075
|
keep_infinity : false,
|
18076
|
+
lhs_constants : !false_by_default,
|
18031
18077
|
loops : !false_by_default,
|
18032
18078
|
module : false,
|
18033
18079
|
negate_iife : !false_by_default,
|
@@ -19914,7 +19960,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
19914
19960
|
self.right = tmp;
|
19915
19961
|
}
|
19916
19962
|
}
|
19917
|
-
if (commutativeOperators.has(self.operator)) {
|
19963
|
+
if (compressor.option("lhs_constants") && commutativeOperators.has(self.operator)) {
|
19918
19964
|
if (self.right.is_constant()
|
19919
19965
|
&& !self.left.is_constant()) {
|
19920
19966
|
// if right is a constant, whatever side effects the
|
@@ -19944,6 +19990,9 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
19944
19990
|
// void 0 == x => null == x
|
19945
19991
|
if (!is_strict_comparison && is_undefined(self.left, compressor)) {
|
19946
19992
|
self.left = make_node(AST_Null, self.left);
|
19993
|
+
// x == void 0 => x == null
|
19994
|
+
} else if (!is_strict_comparison && is_undefined(self.right, compressor)) {
|
19995
|
+
self.right = make_node(AST_Null, self.right);
|
19947
19996
|
} else if (compressor.option("typeofs")
|
19948
19997
|
// "undefined" == typeof x => undefined === x
|
19949
19998
|
&& self.left instanceof AST_String
|
@@ -19957,6 +20006,19 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
19957
20006
|
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
|
19958
20007
|
if (self.operator.length == 2) self.operator += "=";
|
19959
20008
|
}
|
20009
|
+
} else if (compressor.option("typeofs")
|
20010
|
+
// typeof x === "undefined" => x === undefined
|
20011
|
+
&& self.left instanceof AST_UnaryPrefix
|
20012
|
+
&& self.left.operator == "typeof"
|
20013
|
+
&& self.right instanceof AST_String
|
20014
|
+
&& self.right.value == "undefined") {
|
20015
|
+
var expr = self.left.expression;
|
20016
|
+
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
20017
|
+
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
20018
|
+
self.left = expr;
|
20019
|
+
self.right = make_node(AST_Undefined, self.right).optimize(compressor);
|
20020
|
+
if (self.operator.length == 2) self.operator += "=";
|
20021
|
+
}
|
19960
20022
|
} else if (self.left instanceof AST_SymbolRef
|
19961
20023
|
// obj !== obj => false
|
19962
20024
|
&& self.right instanceof AST_SymbolRef
|
@@ -20548,13 +20610,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
|
|
20548
20610
|
|
20549
20611
|
// `[x = undefined] = foo` ---> `[x] = foo`
|
20550
20612
|
// `(arg = undefined) => ...` ---> `(arg) => ...` (unless `keep_fargs`)
|
20551
|
-
|
20552
|
-
|
20553
|
-
|
20554
|
-
|
20555
|
-
|
20556
|
-
|
20557
|
-
|
20613
|
+
// `((arg = undefined) => ...)()` ---> `((arg) => ...)()`
|
20614
|
+
let lambda, iife;
|
20615
|
+
if (evaluateRight === undefined) {
|
20616
|
+
if (
|
20617
|
+
(lambda = compressor.parent()) instanceof AST_Lambda
|
20618
|
+
? (
|
20619
|
+
compressor.option("keep_fargs") === false
|
20620
|
+
|| (iife = compressor.parent(1)).TYPE === "Call"
|
20621
|
+
&& iife.expression === lambda
|
20622
|
+
)
|
20623
|
+
: true
|
20624
|
+
) {
|
20625
|
+
self = self.left;
|
20626
|
+
}
|
20558
20627
|
} else if (evaluateRight !== self.right) {
|
20559
20628
|
evaluateRight = make_node_from_constant(evaluateRight, self.right);
|
20560
20629
|
self.right = best_of_expression(evaluateRight, self.right);
|
@@ -29707,6 +29776,8 @@ function mangle_properties(ast, options) {
|
|
29707
29776
|
addStrings(node.args[1], add);
|
29708
29777
|
} else if (node instanceof AST_Binary && node.operator === "in") {
|
29709
29778
|
addStrings(node.left, add);
|
29779
|
+
} else if (node instanceof AST_String && has_annotation(node, _KEY)) {
|
29780
|
+
add(node.value);
|
29710
29781
|
}
|
29711
29782
|
}));
|
29712
29783
|
|
@@ -29738,6 +29809,10 @@ function mangle_properties(ast, options) {
|
|
29738
29809
|
node.args[1] = mangleStrings(node.args[1]);
|
29739
29810
|
} else if (node instanceof AST_Binary && node.operator === "in") {
|
29740
29811
|
node.left = mangleStrings(node.left);
|
29812
|
+
} else if (node instanceof AST_String && has_annotation(node, _KEY)) {
|
29813
|
+
// Clear _KEY annotation to prevent double mangling
|
29814
|
+
clear_annotation(node, _KEY);
|
29815
|
+
node.value = mangle(node.value);
|
29741
29816
|
}
|
29742
29817
|
}));
|
29743
29818
|
|
@@ -29803,6 +29878,8 @@ function mangle_properties(ast, options) {
|
|
29803
29878
|
var last = node.expressions.length - 1;
|
29804
29879
|
node.expressions[last] = mangleStrings(node.expressions[last]);
|
29805
29880
|
} else if (node instanceof AST_String) {
|
29881
|
+
// Clear _KEY annotation to prevent double mangling
|
29882
|
+
clear_annotation(node, _KEY);
|
29806
29883
|
node.value = mangle(node.value);
|
29807
29884
|
} else if (node instanceof AST_Conditional) {
|
29808
29885
|
node.consequent = mangleStrings(node.consequent);
|
package/lib/ast.js
CHANGED
@@ -2762,6 +2762,7 @@ var AST_String = DEFNODE("String", "value quote", function AST_String(props) {
|
|
2762
2762
|
this.quote = props.quote;
|
2763
2763
|
this.start = props.start;
|
2764
2764
|
this.end = props.end;
|
2765
|
+
this._annotations = props._annotations;
|
2765
2766
|
}
|
2766
2767
|
|
2767
2768
|
this.flags = 0;
|
@@ -3134,6 +3135,7 @@ class TreeTransformer extends TreeWalker {
|
|
3134
3135
|
const _PURE = 0b00000001;
|
3135
3136
|
const _INLINE = 0b00000010;
|
3136
3137
|
const _NOINLINE = 0b00000100;
|
3138
|
+
const _KEY = 0b00001000;
|
3137
3139
|
|
3138
3140
|
export {
|
3139
3141
|
AST_Accessor,
|
@@ -3278,4 +3280,5 @@ export {
|
|
3278
3280
|
_INLINE,
|
3279
3281
|
_NOINLINE,
|
3280
3282
|
_PURE,
|
3283
|
+
_KEY,
|
3281
3284
|
};
|
package/lib/compress/common.js
CHANGED
@@ -46,6 +46,7 @@ import {
|
|
46
46
|
AST_Arrow,
|
47
47
|
AST_BlockStatement,
|
48
48
|
AST_Call,
|
49
|
+
AST_Chain,
|
49
50
|
AST_Class,
|
50
51
|
AST_Const,
|
51
52
|
AST_Constant,
|
@@ -226,7 +227,8 @@ export function maintain_this_binding(parent, orig, val) {
|
|
226
227
|
parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
227
228
|
|| parent instanceof AST_Call && parent.expression === orig
|
228
229
|
&& (
|
229
|
-
val instanceof
|
230
|
+
val instanceof AST_Chain
|
231
|
+
|| val instanceof AST_PropAccess
|
230
232
|
|| val instanceof AST_SymbolRef && val.name == "eval"
|
231
233
|
)
|
232
234
|
) {
|
package/lib/compress/evaluate.js
CHANGED
@@ -352,6 +352,33 @@ const regexp_flags = new Set([
|
|
352
352
|
def_eval(AST_PropAccess, function (compressor, depth) {
|
353
353
|
let obj = this.expression._eval(compressor, depth + 1);
|
354
354
|
if (obj === nullish || (this.optional && obj == null)) return nullish;
|
355
|
+
|
356
|
+
// `.length` of strings and arrays is always safe
|
357
|
+
if (this.property === "length") {
|
358
|
+
if (typeof obj === "string") {
|
359
|
+
return obj.length;
|
360
|
+
}
|
361
|
+
|
362
|
+
const is_spreadless_array = obj =>
|
363
|
+
obj instanceof AST_Array
|
364
|
+
&& obj.elements.every(el => !(el instanceof AST_Expansion));
|
365
|
+
|
366
|
+
if (
|
367
|
+
is_spreadless_array(obj)
|
368
|
+
&& obj.elements.every(el => !el.has_side_effects(compressor))
|
369
|
+
) {
|
370
|
+
return obj.elements.length;
|
371
|
+
}
|
372
|
+
|
373
|
+
let fixed;
|
374
|
+
if (
|
375
|
+
obj instanceof AST_SymbolRef
|
376
|
+
&& is_spreadless_array((fixed = obj.definition().fixed_value()))
|
377
|
+
) {
|
378
|
+
return fixed.elements.length;
|
379
|
+
}
|
380
|
+
}
|
381
|
+
|
355
382
|
if (compressor.option("unsafe")) {
|
356
383
|
var key = this.property;
|
357
384
|
if (key instanceof AST_Node) {
|
@@ -359,9 +386,9 @@ def_eval(AST_PropAccess, function (compressor, depth) {
|
|
359
386
|
if (key === this.property)
|
360
387
|
return this;
|
361
388
|
}
|
389
|
+
|
362
390
|
var exp = this.expression;
|
363
391
|
if (is_undeclared_ref(exp)) {
|
364
|
-
|
365
392
|
var aa;
|
366
393
|
var first_arg = exp.name === "hasOwnProperty"
|
367
394
|
&& key === "call"
|
package/lib/compress/index.js
CHANGED
@@ -245,6 +245,7 @@ class Compressor extends TreeWalker {
|
|
245
245
|
keep_fargs : true,
|
246
246
|
keep_fnames : false,
|
247
247
|
keep_infinity : false,
|
248
|
+
lhs_constants : !false_by_default,
|
248
249
|
loops : !false_by_default,
|
249
250
|
module : false,
|
250
251
|
negate_iife : !false_by_default,
|
@@ -2131,7 +2132,7 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
2131
2132
|
self.right = tmp;
|
2132
2133
|
}
|
2133
2134
|
}
|
2134
|
-
if (commutativeOperators.has(self.operator)) {
|
2135
|
+
if (compressor.option("lhs_constants") && commutativeOperators.has(self.operator)) {
|
2135
2136
|
if (self.right.is_constant()
|
2136
2137
|
&& !self.left.is_constant()) {
|
2137
2138
|
// if right is a constant, whatever side effects the
|
@@ -2161,6 +2162,9 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
2161
2162
|
// void 0 == x => null == x
|
2162
2163
|
if (!is_strict_comparison && is_undefined(self.left, compressor)) {
|
2163
2164
|
self.left = make_node(AST_Null, self.left);
|
2165
|
+
// x == void 0 => x == null
|
2166
|
+
} else if (!is_strict_comparison && is_undefined(self.right, compressor)) {
|
2167
|
+
self.right = make_node(AST_Null, self.right);
|
2164
2168
|
} else if (compressor.option("typeofs")
|
2165
2169
|
// "undefined" == typeof x => undefined === x
|
2166
2170
|
&& self.left instanceof AST_String
|
@@ -2174,6 +2178,19 @@ def_optimize(AST_Binary, function(self, compressor) {
|
|
2174
2178
|
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
|
2175
2179
|
if (self.operator.length == 2) self.operator += "=";
|
2176
2180
|
}
|
2181
|
+
} else if (compressor.option("typeofs")
|
2182
|
+
// typeof x === "undefined" => x === undefined
|
2183
|
+
&& self.left instanceof AST_UnaryPrefix
|
2184
|
+
&& self.left.operator == "typeof"
|
2185
|
+
&& self.right instanceof AST_String
|
2186
|
+
&& self.right.value == "undefined") {
|
2187
|
+
var expr = self.left.expression;
|
2188
|
+
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
2189
|
+
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
2190
|
+
self.left = expr;
|
2191
|
+
self.right = make_node(AST_Undefined, self.right).optimize(compressor);
|
2192
|
+
if (self.operator.length == 2) self.operator += "=";
|
2193
|
+
}
|
2177
2194
|
} else if (self.left instanceof AST_SymbolRef
|
2178
2195
|
// obj !== obj => false
|
2179
2196
|
&& self.right instanceof AST_SymbolRef
|
@@ -2765,13 +2782,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
|
|
2765
2782
|
|
2766
2783
|
// `[x = undefined] = foo` ---> `[x] = foo`
|
2767
2784
|
// `(arg = undefined) => ...` ---> `(arg) => ...` (unless `keep_fargs`)
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2774
|
-
|
2785
|
+
// `((arg = undefined) => ...)()` ---> `((arg) => ...)()`
|
2786
|
+
let lambda, iife;
|
2787
|
+
if (evaluateRight === undefined) {
|
2788
|
+
if (
|
2789
|
+
(lambda = compressor.parent()) instanceof AST_Lambda
|
2790
|
+
? (
|
2791
|
+
compressor.option("keep_fargs") === false
|
2792
|
+
|| (iife = compressor.parent(1)).TYPE === "Call"
|
2793
|
+
&& iife.expression === lambda
|
2794
|
+
)
|
2795
|
+
: true
|
2796
|
+
) {
|
2797
|
+
self = self.left;
|
2798
|
+
}
|
2775
2799
|
} else if (evaluateRight !== self.right) {
|
2776
2800
|
evaluateRight = make_node_from_constant(evaluateRight, self.right);
|
2777
2801
|
self.right = best_of_expression(evaluateRight, self.right);
|
package/lib/output.js
CHANGED
@@ -1080,6 +1080,12 @@ function OutputStream(options) {
|
|
1080
1080
|
return true;
|
1081
1081
|
});
|
1082
1082
|
|
1083
|
+
PARENS(AST_Chain, function(output) {
|
1084
|
+
var p = output.parent();
|
1085
|
+
if (!(p instanceof AST_Call || p instanceof AST_PropAccess)) return false;
|
1086
|
+
return p.expression === this;
|
1087
|
+
});
|
1088
|
+
|
1083
1089
|
PARENS(AST_PropAccess, function(output) {
|
1084
1090
|
var p = output.parent();
|
1085
1091
|
if (p instanceof AST_New && p.expression === this) {
|
package/lib/parse.js
CHANGED
@@ -162,7 +162,8 @@ import {
|
|
162
162
|
AST_Yield,
|
163
163
|
_INLINE,
|
164
164
|
_NOINLINE,
|
165
|
-
_PURE
|
165
|
+
_PURE,
|
166
|
+
_KEY
|
166
167
|
} from "./ast.js";
|
167
168
|
|
168
169
|
var LATEST_RAW = ""; // Only used for numbers and template strings
|
@@ -2225,6 +2226,7 @@ function parse($TEXT, options) {
|
|
2225
2226
|
value : tok.value,
|
2226
2227
|
quote : tok.quote
|
2227
2228
|
});
|
2229
|
+
annotate(ret);
|
2228
2230
|
break;
|
2229
2231
|
case "regexp":
|
2230
2232
|
const [_, source, flags] = tok.value.match(/^\/(.*)\/(\w*)$/);
|
@@ -3111,6 +3113,10 @@ function parse($TEXT, options) {
|
|
3111
3113
|
set_annotation(node, _NOINLINE);
|
3112
3114
|
break;
|
3113
3115
|
}
|
3116
|
+
if (/[@#]__KEY__/.test(comment.value)) {
|
3117
|
+
set_annotation(node, _KEY);
|
3118
|
+
break;
|
3119
|
+
}
|
3114
3120
|
}
|
3115
3121
|
}
|
3116
3122
|
}
|
package/lib/propmangle.js
CHANGED
@@ -47,6 +47,8 @@
|
|
47
47
|
import {
|
48
48
|
defaults,
|
49
49
|
push_uniq,
|
50
|
+
has_annotation,
|
51
|
+
clear_annotation,
|
50
52
|
} from "./utils/index.js";
|
51
53
|
import { base54 } from "./scope.js";
|
52
54
|
import {
|
@@ -67,6 +69,7 @@ import {
|
|
67
69
|
AST_Sub,
|
68
70
|
TreeTransformer,
|
69
71
|
TreeWalker,
|
72
|
+
_KEY,
|
70
73
|
} from "./ast.js";
|
71
74
|
import { domprops } from "../tools/domprops.js";
|
72
75
|
|
@@ -263,6 +266,8 @@ function mangle_properties(ast, options) {
|
|
263
266
|
addStrings(node.args[1], add);
|
264
267
|
} else if (node instanceof AST_Binary && node.operator === "in") {
|
265
268
|
addStrings(node.left, add);
|
269
|
+
} else if (node instanceof AST_String && has_annotation(node, _KEY)) {
|
270
|
+
add(node.value);
|
266
271
|
}
|
267
272
|
}));
|
268
273
|
|
@@ -296,6 +301,10 @@ function mangle_properties(ast, options) {
|
|
296
301
|
node.args[1] = mangleStrings(node.args[1]);
|
297
302
|
} else if (node instanceof AST_Binary && node.operator === "in") {
|
298
303
|
node.left = mangleStrings(node.left);
|
304
|
+
} else if (node instanceof AST_String && has_annotation(node, _KEY)) {
|
305
|
+
// Clear _KEY annotation to prevent double mangling
|
306
|
+
clear_annotation(node, _KEY);
|
307
|
+
node.value = mangle(node.value);
|
299
308
|
}
|
300
309
|
}));
|
301
310
|
|
@@ -361,6 +370,8 @@ function mangle_properties(ast, options) {
|
|
361
370
|
var last = node.expressions.length - 1;
|
362
371
|
node.expressions[last] = mangleStrings(node.expressions[last]);
|
363
372
|
} else if (node instanceof AST_String) {
|
373
|
+
// Clear _KEY annotation to prevent double mangling
|
374
|
+
clear_annotation(node, _KEY);
|
364
375
|
node.value = mangle(node.value);
|
365
376
|
} else if (node instanceof AST_Conditional) {
|
366
377
|
node.consequent = mangleStrings(node.consequent);
|
package/lib/utils/index.js
CHANGED
@@ -262,6 +262,10 @@ function set_annotation(node, annotation) {
|
|
262
262
|
node._annotations |= annotation;
|
263
263
|
}
|
264
264
|
|
265
|
+
function clear_annotation(node, annotation) {
|
266
|
+
node._annotations &= ~annotation;
|
267
|
+
}
|
268
|
+
|
265
269
|
export {
|
266
270
|
characters,
|
267
271
|
defaults,
|
@@ -286,5 +290,6 @@ export {
|
|
286
290
|
sort_regexp_flags,
|
287
291
|
string_template,
|
288
292
|
has_annotation,
|
289
|
-
set_annotation
|
293
|
+
set_annotation,
|
294
|
+
clear_annotation,
|
290
295
|
};
|
package/package.json
CHANGED
package/bin/terser.mjs
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
"use strict";
|
4
|
-
|
5
|
-
import "../tools/exit.cjs";
|
6
|
-
|
7
|
-
import fs from "fs";
|
8
|
-
import path from "path";
|
9
|
-
import program from "commander";
|
10
|
-
|
11
|
-
import { run_cli } from "../lib/cli.js";
|
12
|
-
|
13
|
-
const packageJson = {
|
14
|
-
name: "terser",
|
15
|
-
version: "experimental module CLI"
|
16
|
-
};
|
17
|
-
|
18
|
-
run_cli({ program, packageJson, fs, path }).catch((error) => {
|
19
|
-
console.error(error);
|
20
|
-
process.exitCode = 1;
|
21
|
-
});
|