terser 5.16.9 → 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 +5 -0
- package/README.md +4 -0
- package/dist/bundle.min.js +61 -8
- package/lib/ast.js +3 -0
- package/lib/compress/evaluate.js +28 -1
- package/lib/compress/index.js +14 -7
- 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/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
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
|
+
|
3
8
|
## v5.16.9
|
4
9
|
- Fix parentheses in output of optional chains (`a?.b`) (#1374)
|
5
10
|
- More documentation on source maps (#1368)
|
package/README.md
CHANGED
@@ -1188,6 +1188,7 @@ Annotations in Terser are a way to tell it to treat a certain function call diff
|
|
1188
1188
|
* `/*@__INLINE__*/` - forces a function to be inlined somewhere.
|
1189
1189
|
* `/*@__NOINLINE__*/` - Makes sure the called function is not inlined into the call site.
|
1190
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.
|
1191
1192
|
|
1192
1193
|
You can use either a `@` sign at the start, or a `#`.
|
1193
1194
|
|
@@ -1201,6 +1202,9 @@ function_always_inlined_here()
|
|
1201
1202
|
function_cant_be_inlined_into_here()
|
1202
1203
|
|
1203
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");
|
1204
1208
|
```
|
1205
1209
|
|
1206
1210
|
### ESTree / SpiderMonkey AST
|
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
|
|
@@ -14478,6 +14489,33 @@ const regexp_flags = new Set([
|
|
14478
14489
|
def_eval(AST_PropAccess, function (compressor, depth) {
|
14479
14490
|
let obj = this.expression._eval(compressor, depth + 1);
|
14480
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
|
+
|
14481
14519
|
if (compressor.option("unsafe")) {
|
14482
14520
|
var key = this.property;
|
14483
14521
|
if (key instanceof AST_Node) {
|
@@ -14485,9 +14523,9 @@ def_eval(AST_PropAccess, function (compressor, depth) {
|
|
14485
14523
|
if (key === this.property)
|
14486
14524
|
return this;
|
14487
14525
|
}
|
14526
|
+
|
14488
14527
|
var exp = this.expression;
|
14489
14528
|
if (is_undeclared_ref(exp)) {
|
14490
|
-
|
14491
14529
|
var aa;
|
14492
14530
|
var first_arg = exp.name === "hasOwnProperty"
|
14493
14531
|
&& key === "call"
|
@@ -20572,13 +20610,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
|
|
20572
20610
|
|
20573
20611
|
// `[x = undefined] = foo` ---> `[x] = foo`
|
20574
20612
|
// `(arg = undefined) => ...` ---> `(arg) => ...` (unless `keep_fargs`)
|
20575
|
-
|
20576
|
-
|
20577
|
-
|
20578
|
-
|
20579
|
-
|
20580
|
-
|
20581
|
-
|
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
|
+
}
|
20582
20627
|
} else if (evaluateRight !== self.right) {
|
20583
20628
|
evaluateRight = make_node_from_constant(evaluateRight, self.right);
|
20584
20629
|
self.right = best_of_expression(evaluateRight, self.right);
|
@@ -29731,6 +29776,8 @@ function mangle_properties(ast, options) {
|
|
29731
29776
|
addStrings(node.args[1], add);
|
29732
29777
|
} else if (node instanceof AST_Binary && node.operator === "in") {
|
29733
29778
|
addStrings(node.left, add);
|
29779
|
+
} else if (node instanceof AST_String && has_annotation(node, _KEY)) {
|
29780
|
+
add(node.value);
|
29734
29781
|
}
|
29735
29782
|
}));
|
29736
29783
|
|
@@ -29762,6 +29809,10 @@ function mangle_properties(ast, options) {
|
|
29762
29809
|
node.args[1] = mangleStrings(node.args[1]);
|
29763
29810
|
} else if (node instanceof AST_Binary && node.operator === "in") {
|
29764
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);
|
29765
29816
|
}
|
29766
29817
|
}));
|
29767
29818
|
|
@@ -29827,6 +29878,8 @@ function mangle_properties(ast, options) {
|
|
29827
29878
|
var last = node.expressions.length - 1;
|
29828
29879
|
node.expressions[last] = mangleStrings(node.expressions[last]);
|
29829
29880
|
} else if (node instanceof AST_String) {
|
29881
|
+
// Clear _KEY annotation to prevent double mangling
|
29882
|
+
clear_annotation(node, _KEY);
|
29830
29883
|
node.value = mangle(node.value);
|
29831
29884
|
} else if (node instanceof AST_Conditional) {
|
29832
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/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
@@ -2782,13 +2782,20 @@ def_optimize(AST_DefaultAssign, function(self, compressor) {
|
|
2782
2782
|
|
2783
2783
|
// `[x = undefined] = foo` ---> `[x] = foo`
|
2784
2784
|
// `(arg = undefined) => ...` ---> `(arg) => ...` (unless `keep_fargs`)
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
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
|
+
}
|
2792
2799
|
} else if (evaluateRight !== self.right) {
|
2793
2800
|
evaluateRight = make_node_from_constant(evaluateRight, self.right);
|
2794
2801
|
self.right = best_of_expression(evaluateRight, self.right);
|
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
|
};
|