terser 5.7.2 → 5.11.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 +36 -0
- package/README.md +21 -2
- package/dist/bundle.min.js +705 -213
- package/lib/ast.js +6 -4
- package/lib/compress/drop-side-effect-free.js +9 -12
- package/lib/compress/evaluate.js +15 -12
- package/lib/compress/index.js +368 -66
- package/lib/compress/inference.js +27 -13
- package/lib/compress/native-objects.js +1 -0
- package/lib/compress/tighten-body.js +29 -7
- package/lib/minify.js +3 -1
- package/lib/mozilla-ast.js +48 -6
- package/lib/output.js +81 -26
- package/lib/parse.js +24 -8
- package/lib/propmangle.js +57 -34
- package/lib/scope.js +42 -21
- package/lib/transform.js +2 -2
- package/package.json +9 -9
- package/tools/terser.d.ts +36 -0
package/lib/propmangle.js
CHANGED
@@ -59,6 +59,8 @@ import {
|
|
59
59
|
AST_ObjectKeyVal,
|
60
60
|
AST_ObjectProperty,
|
61
61
|
AST_PrivateMethod,
|
62
|
+
AST_PrivateGetter,
|
63
|
+
AST_PrivateSetter,
|
62
64
|
AST_Sequence,
|
63
65
|
AST_String,
|
64
66
|
AST_Sub,
|
@@ -140,33 +142,61 @@ function addStrings(node, add) {
|
|
140
142
|
}));
|
141
143
|
}
|
142
144
|
|
145
|
+
function mangle_private_properties(ast, options) {
|
146
|
+
var cprivate = -1;
|
147
|
+
var private_cache = new Map();
|
148
|
+
var nth_identifier = options.nth_identifier || base54;
|
149
|
+
|
150
|
+
ast = ast.transform(new TreeTransformer(function(node) {
|
151
|
+
if (
|
152
|
+
node instanceof AST_ClassPrivateProperty
|
153
|
+
|| node instanceof AST_PrivateMethod
|
154
|
+
|| node instanceof AST_PrivateGetter
|
155
|
+
|| node instanceof AST_PrivateSetter
|
156
|
+
) {
|
157
|
+
node.key.name = mangle_private(node.key.name);
|
158
|
+
} else if (node instanceof AST_DotHash) {
|
159
|
+
node.property = mangle_private(node.property);
|
160
|
+
}
|
161
|
+
}));
|
162
|
+
return ast;
|
163
|
+
|
164
|
+
function mangle_private(name) {
|
165
|
+
let mangled = private_cache.get(name);
|
166
|
+
if (!mangled) {
|
167
|
+
mangled = nth_identifier.get(++cprivate);
|
168
|
+
private_cache.set(name, mangled);
|
169
|
+
}
|
170
|
+
|
171
|
+
return mangled;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
143
175
|
function mangle_properties(ast, options) {
|
144
176
|
options = defaults(options, {
|
145
177
|
builtins: false,
|
146
178
|
cache: null,
|
147
179
|
debug: false,
|
148
180
|
keep_quoted: false,
|
181
|
+
nth_identifier: base54,
|
149
182
|
only_cache: false,
|
150
183
|
regex: null,
|
151
184
|
reserved: null,
|
152
185
|
undeclared: false,
|
153
186
|
}, true);
|
154
187
|
|
188
|
+
var nth_identifier = options.nth_identifier;
|
189
|
+
|
155
190
|
var reserved_option = options.reserved;
|
156
191
|
if (!Array.isArray(reserved_option)) reserved_option = [reserved_option];
|
157
192
|
var reserved = new Set(reserved_option);
|
158
193
|
if (!options.builtins) find_builtins(reserved);
|
159
194
|
|
160
195
|
var cname = -1;
|
161
|
-
var cprivate = -1;
|
162
196
|
|
163
197
|
var cache;
|
164
|
-
var private_cache = new Map();
|
165
198
|
if (options.cache) {
|
166
199
|
cache = options.cache.props;
|
167
|
-
cache.forEach(function(mangled_name) {
|
168
|
-
reserved.add(mangled_name);
|
169
|
-
});
|
170
200
|
} else {
|
171
201
|
cache = new Map();
|
172
202
|
}
|
@@ -184,27 +214,29 @@ function mangle_properties(ast, options) {
|
|
184
214
|
|
185
215
|
var names_to_mangle = new Set();
|
186
216
|
var unmangleable = new Set();
|
187
|
-
|
217
|
+
// Track each already-mangled name to prevent nth_identifier from generating
|
218
|
+
// the same name.
|
219
|
+
cache.forEach((mangled_name) => unmangleable.add(mangled_name));
|
188
220
|
|
189
|
-
var
|
221
|
+
var keep_quoted = !!options.keep_quoted;
|
190
222
|
|
191
223
|
// step 1: find candidates to mangle
|
192
224
|
ast.walk(new TreeWalker(function(node) {
|
193
225
|
if (
|
194
226
|
node instanceof AST_ClassPrivateProperty
|
195
227
|
|| node instanceof AST_PrivateMethod
|
228
|
+
|| node instanceof AST_PrivateGetter
|
229
|
+
|| node instanceof AST_PrivateSetter
|
230
|
+
|| node instanceof AST_DotHash
|
196
231
|
) {
|
197
|
-
|
198
|
-
} else if (node instanceof AST_DotHash) {
|
199
|
-
private_properties.add(node.property);
|
232
|
+
// handled by mangle_private_properties
|
200
233
|
} else if (node instanceof AST_ObjectKeyVal) {
|
201
|
-
if (typeof node.key == "string" &&
|
202
|
-
(!keep_quoted_strict || !node.quote)) {
|
234
|
+
if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
|
203
235
|
add(node.key);
|
204
236
|
}
|
205
237
|
} else if (node instanceof AST_ObjectProperty) {
|
206
238
|
// setter or getter, since KeyVal is handled above
|
207
|
-
if (!
|
239
|
+
if (!keep_quoted || !node.quote) {
|
208
240
|
add(node.key.name);
|
209
241
|
}
|
210
242
|
} else if (node instanceof AST_Dot) {
|
@@ -217,11 +249,11 @@ function mangle_properties(ast, options) {
|
|
217
249
|
declared = !(root.thedef && root.thedef.undeclared);
|
218
250
|
}
|
219
251
|
if (declared &&
|
220
|
-
(!
|
252
|
+
(!keep_quoted || !node.quote)) {
|
221
253
|
add(node.property);
|
222
254
|
}
|
223
255
|
} else if (node instanceof AST_Sub) {
|
224
|
-
if (!
|
256
|
+
if (!keep_quoted) {
|
225
257
|
addStrings(node.property, add);
|
226
258
|
}
|
227
259
|
} else if (node instanceof AST_Call
|
@@ -237,25 +269,25 @@ function mangle_properties(ast, options) {
|
|
237
269
|
if (
|
238
270
|
node instanceof AST_ClassPrivateProperty
|
239
271
|
|| node instanceof AST_PrivateMethod
|
272
|
+
|| node instanceof AST_PrivateGetter
|
273
|
+
|| node instanceof AST_PrivateSetter
|
274
|
+
|| node instanceof AST_DotHash
|
240
275
|
) {
|
241
|
-
|
242
|
-
} else if (node instanceof AST_DotHash) {
|
243
|
-
node.property = mangle_private(node.property);
|
276
|
+
// handled by mangle_private_properties
|
244
277
|
} else if (node instanceof AST_ObjectKeyVal) {
|
245
|
-
if (typeof node.key == "string" &&
|
246
|
-
(!keep_quoted_strict || !node.quote)) {
|
278
|
+
if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
|
247
279
|
node.key = mangle(node.key);
|
248
280
|
}
|
249
281
|
} else if (node instanceof AST_ObjectProperty) {
|
250
282
|
// setter, getter, method or class field
|
251
|
-
if (!
|
283
|
+
if (!keep_quoted || !node.quote) {
|
252
284
|
node.key.name = mangle(node.key.name);
|
253
285
|
}
|
254
286
|
} else if (node instanceof AST_Dot) {
|
255
|
-
if (!
|
287
|
+
if (!keep_quoted || !node.quote) {
|
256
288
|
node.property = mangle(node.property);
|
257
289
|
}
|
258
|
-
} else if (!
|
290
|
+
} else if (!keep_quoted && node instanceof AST_Sub) {
|
259
291
|
node.property = mangleStrings(node.property);
|
260
292
|
} else if (node instanceof AST_Call
|
261
293
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
@@ -312,7 +344,7 @@ function mangle_properties(ast, options) {
|
|
312
344
|
// either debug mode is off, or it is on and we could not use the mangled name
|
313
345
|
if (!mangled) {
|
314
346
|
do {
|
315
|
-
mangled =
|
347
|
+
mangled = nth_identifier.get(++cname);
|
316
348
|
} while (!can_mangle(mangled));
|
317
349
|
}
|
318
350
|
|
@@ -321,16 +353,6 @@ function mangle_properties(ast, options) {
|
|
321
353
|
return mangled;
|
322
354
|
}
|
323
355
|
|
324
|
-
function mangle_private(name) {
|
325
|
-
let mangled = private_cache.get(name);
|
326
|
-
if (!mangled) {
|
327
|
-
mangled = base54(++cprivate);
|
328
|
-
private_cache.set(name, mangled);
|
329
|
-
}
|
330
|
-
|
331
|
-
return mangled;
|
332
|
-
}
|
333
|
-
|
334
356
|
function mangleStrings(node) {
|
335
357
|
return node.transform(new TreeTransformer(function(node) {
|
336
358
|
if (node instanceof AST_Sequence) {
|
@@ -350,4 +372,5 @@ function mangle_properties(ast, options) {
|
|
350
372
|
export {
|
351
373
|
reserve_quoted_keys,
|
352
374
|
mangle_properties,
|
375
|
+
mangle_private_properties,
|
353
376
|
};
|
package/lib/scope.js
CHANGED
@@ -667,8 +667,9 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
|
667
667
|
|
668
668
|
function next_mangled(scope, options) {
|
669
669
|
var ext = scope.enclosed;
|
670
|
+
var nth_identifier = options.nth_identifier;
|
670
671
|
out: while (true) {
|
671
|
-
var m =
|
672
|
+
var m = nth_identifier.get(++scope.cname);
|
672
673
|
if (ALL_RESERVED_WORDS.has(m)) continue; // skip over "do"
|
673
674
|
|
674
675
|
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
@@ -744,6 +745,7 @@ AST_Symbol.DEFMETHOD("global", function() {
|
|
744
745
|
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
|
745
746
|
options = defaults(options, {
|
746
747
|
eval : false,
|
748
|
+
nth_identifier : base54,
|
747
749
|
ie8 : false,
|
748
750
|
keep_classnames: false,
|
749
751
|
keep_fnames : false,
|
@@ -765,6 +767,7 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
|
|
765
767
|
|
766
768
|
AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
767
769
|
options = this._default_mangler_options(options);
|
770
|
+
var nth_identifier = options.nth_identifier;
|
768
771
|
|
769
772
|
// We only need to mangle declaration nodes. Special logic wired
|
770
773
|
// into the code generator will display the mangled name if it's
|
@@ -778,6 +781,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|
778
781
|
}
|
779
782
|
|
780
783
|
const mangled_names = this.mangled_names = new Set();
|
784
|
+
unmangleable_names = new Set();
|
785
|
+
|
781
786
|
if (options.cache) {
|
782
787
|
this.globals.forEach(collect);
|
783
788
|
if (options.cache.props) {
|
@@ -816,7 +821,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|
816
821
|
if (node instanceof AST_Label) {
|
817
822
|
let name;
|
818
823
|
do {
|
819
|
-
name =
|
824
|
+
name = nth_identifier.get(++lname);
|
820
825
|
} while (ALL_RESERVED_WORDS.has(name));
|
821
826
|
node.mangled_name = name;
|
822
827
|
return true;
|
@@ -830,7 +835,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|
830
835
|
this.walk(tw);
|
831
836
|
|
832
837
|
if (options.keep_fnames || options.keep_classnames) {
|
833
|
-
unmangleable_names = new Set();
|
834
838
|
// Collect a set of short names which are unmangleable,
|
835
839
|
// for use in avoiding collisions in next_mangled.
|
836
840
|
to_mangle.forEach(def => {
|
@@ -846,9 +850,9 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|
846
850
|
unmangleable_names = null;
|
847
851
|
|
848
852
|
function collect(symbol) {
|
849
|
-
|
850
|
-
|
851
|
-
if (
|
853
|
+
if (symbol.export & MASK_EXPORT_DONT_MANGLE) {
|
854
|
+
unmangleable_names.add(symbol.name);
|
855
|
+
} else if (!options.reserved.has(symbol.name)) {
|
852
856
|
to_mangle.push(symbol);
|
853
857
|
}
|
854
858
|
}
|
@@ -878,9 +882,12 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
|
878
882
|
});
|
879
883
|
|
880
884
|
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
881
|
-
base54.reset();
|
882
|
-
base54.sort();
|
883
885
|
options = this._default_mangler_options(options);
|
886
|
+
var nth_identifier = options.nth_identifier;
|
887
|
+
if (nth_identifier.reset && nth_identifier.sort) {
|
888
|
+
nth_identifier.reset();
|
889
|
+
nth_identifier.sort();
|
890
|
+
}
|
884
891
|
var avoid = this.find_colliding_names(options);
|
885
892
|
var cname = 0;
|
886
893
|
this.globals.forEach(rename);
|
@@ -892,7 +899,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|
892
899
|
function next_name() {
|
893
900
|
var name;
|
894
901
|
do {
|
895
|
-
name =
|
902
|
+
name = nth_identifier.get(cname++);
|
896
903
|
} while (avoid.has(name) || ALL_RESERVED_WORDS.has(name));
|
897
904
|
return name;
|
898
905
|
}
|
@@ -919,30 +926,37 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
|
|
919
926
|
|
920
927
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
921
928
|
options = this._default_mangler_options(options);
|
929
|
+
var nth_identifier = options.nth_identifier;
|
930
|
+
if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) {
|
931
|
+
// If the identifier mangler is invariant, skip computing character frequency.
|
932
|
+
return;
|
933
|
+
}
|
934
|
+
nth_identifier.reset();
|
935
|
+
|
922
936
|
try {
|
923
937
|
AST_Node.prototype.print = function(stream, force_parens) {
|
924
938
|
this._print(stream, force_parens);
|
925
939
|
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
926
|
-
|
940
|
+
nth_identifier.consider(this.name, -1);
|
927
941
|
} else if (options.properties) {
|
928
942
|
if (this instanceof AST_DotHash) {
|
929
|
-
|
943
|
+
nth_identifier.consider("#" + this.property, -1);
|
930
944
|
} else if (this instanceof AST_Dot) {
|
931
|
-
|
945
|
+
nth_identifier.consider(this.property, -1);
|
932
946
|
} else if (this instanceof AST_Sub) {
|
933
947
|
skip_string(this.property);
|
934
948
|
}
|
935
949
|
}
|
936
950
|
};
|
937
|
-
|
951
|
+
nth_identifier.consider(this.print_to_string(), 1);
|
938
952
|
} finally {
|
939
953
|
AST_Node.prototype.print = AST_Node.prototype._print;
|
940
954
|
}
|
941
|
-
|
955
|
+
nth_identifier.sort();
|
942
956
|
|
943
957
|
function skip_string(node) {
|
944
958
|
if (node instanceof AST_String) {
|
945
|
-
|
959
|
+
nth_identifier.consider(node.value, -1);
|
946
960
|
} else if (node instanceof AST_Conditional) {
|
947
961
|
skip_string(node.consequent);
|
948
962
|
skip_string(node.alternative);
|
@@ -966,19 +980,20 @@ const base54 = (() => {
|
|
966
980
|
frequency.set(ch, 0);
|
967
981
|
});
|
968
982
|
}
|
969
|
-
|
983
|
+
function consider(str, delta) {
|
970
984
|
for (var i = str.length; --i >= 0;) {
|
971
985
|
frequency.set(str[i], frequency.get(str[i]) + delta);
|
972
986
|
}
|
973
|
-
}
|
987
|
+
}
|
974
988
|
function compare(a, b) {
|
975
989
|
return frequency.get(b) - frequency.get(a);
|
976
990
|
}
|
977
|
-
|
991
|
+
function sort() {
|
978
992
|
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
979
|
-
}
|
980
|
-
|
993
|
+
}
|
994
|
+
// Ensure this is in a usable initial state.
|
981
995
|
reset();
|
996
|
+
sort();
|
982
997
|
function base54(num) {
|
983
998
|
var ret = "", base = 54;
|
984
999
|
num++;
|
@@ -990,7 +1005,13 @@ const base54 = (() => {
|
|
990
1005
|
} while (num > 0);
|
991
1006
|
return ret;
|
992
1007
|
}
|
993
|
-
|
1008
|
+
|
1009
|
+
return {
|
1010
|
+
get: base54,
|
1011
|
+
consider,
|
1012
|
+
reset,
|
1013
|
+
sort
|
1014
|
+
};
|
994
1015
|
})();
|
995
1016
|
|
996
1017
|
export {
|
package/lib/transform.js
CHANGED
@@ -57,7 +57,6 @@ import {
|
|
57
57
|
AST_Definitions,
|
58
58
|
AST_Destructuring,
|
59
59
|
AST_Do,
|
60
|
-
AST_Dot,
|
61
60
|
AST_Exit,
|
62
61
|
AST_Expansion,
|
63
62
|
AST_Export,
|
@@ -74,6 +73,7 @@ import {
|
|
74
73
|
AST_Object,
|
75
74
|
AST_ObjectProperty,
|
76
75
|
AST_PrefixedTemplateString,
|
76
|
+
AST_PropAccess,
|
77
77
|
AST_Sequence,
|
78
78
|
AST_SimpleStatement,
|
79
79
|
AST_Sub,
|
@@ -228,7 +228,7 @@ def_transform(AST_Sequence, function(self, tw) {
|
|
228
228
|
: [new AST_Number({ value: 0 })];
|
229
229
|
});
|
230
230
|
|
231
|
-
def_transform(
|
231
|
+
def_transform(AST_PropAccess, function(self, tw) {
|
232
232
|
self.expression = self.expression.transform(tw);
|
233
233
|
});
|
234
234
|
|
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.
|
7
|
+
"version": "5.11.0",
|
8
8
|
"engines": {
|
9
9
|
"node": ">=10"
|
10
10
|
},
|
@@ -43,21 +43,21 @@
|
|
43
43
|
"main.js"
|
44
44
|
],
|
45
45
|
"dependencies": {
|
46
|
+
"acorn": "^8.5.0",
|
46
47
|
"commander": "^2.20.0",
|
47
48
|
"source-map": "~0.7.2",
|
48
|
-
"source-map-support": "~0.5.
|
49
|
+
"source-map-support": "~0.5.20"
|
49
50
|
},
|
50
51
|
"devDependencies": {
|
51
|
-
"@ls-lint/ls-lint": "^1.
|
52
|
-
"
|
53
|
-
"
|
54
|
-
"
|
55
|
-
"eslump": "^2.0.0",
|
52
|
+
"@ls-lint/ls-lint": "^1.10.0",
|
53
|
+
"astring": "^1.7.5",
|
54
|
+
"eslint": "^7.32.0",
|
55
|
+
"eslump": "^3.0.0",
|
56
56
|
"esm": "^3.2.25",
|
57
|
-
"mocha": "^
|
57
|
+
"mocha": "^9.2.0",
|
58
58
|
"pre-commit": "^1.2.2",
|
59
59
|
"rimraf": "^3.0.2",
|
60
|
-
"rollup": "2.
|
60
|
+
"rollup": "2.56.3",
|
61
61
|
"semver": "^7.3.4"
|
62
62
|
},
|
63
63
|
"scripts": {
|
package/tools/terser.d.ts
CHANGED
@@ -80,16 +80,52 @@ export interface MangleOptions {
|
|
80
80
|
keep_classnames?: boolean | RegExp;
|
81
81
|
keep_fnames?: boolean | RegExp;
|
82
82
|
module?: boolean;
|
83
|
+
nth_identifier?: SimpleIdentifierMangler | WeightedIdentifierMangler;
|
83
84
|
properties?: boolean | ManglePropertiesOptions;
|
84
85
|
reserved?: string[];
|
85
86
|
safari10?: boolean;
|
86
87
|
toplevel?: boolean;
|
87
88
|
}
|
88
89
|
|
90
|
+
/**
|
91
|
+
* An identifier mangler for which the output is invariant with respect to the source code.
|
92
|
+
*/
|
93
|
+
export interface SimpleIdentifierMangler {
|
94
|
+
/**
|
95
|
+
* Obtains the nth most favored (usually shortest) identifier to rename a variable to.
|
96
|
+
* The mangler will increment n and retry until the return value is not in use in scope, and is not a reserved word.
|
97
|
+
* This function is expected to be stable; Evaluating get(n) === get(n) should always return true.
|
98
|
+
* @param n The ordinal of the identifier.
|
99
|
+
*/
|
100
|
+
get(n: number): string;
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* An identifier mangler that leverages character frequency analysis to determine identifier precedence.
|
105
|
+
*/
|
106
|
+
export interface WeightedIdentifierMangler extends SimpleIdentifierMangler {
|
107
|
+
/**
|
108
|
+
* Modifies the internal weighting of the input characters by the specified delta.
|
109
|
+
* Will be invoked on the entire printed AST, and then deduct mangleable identifiers.
|
110
|
+
* @param chars The characters to modify the weighting of.
|
111
|
+
* @param delta The numeric weight to add to the characters.
|
112
|
+
*/
|
113
|
+
consider(chars: string, delta: number): number;
|
114
|
+
/**
|
115
|
+
* Resets character weights.
|
116
|
+
*/
|
117
|
+
reset(): void;
|
118
|
+
/**
|
119
|
+
* Sorts identifiers by character frequency, in preparation for calls to get(n).
|
120
|
+
*/
|
121
|
+
sort(): void;
|
122
|
+
}
|
123
|
+
|
89
124
|
export interface ManglePropertiesOptions {
|
90
125
|
builtins?: boolean;
|
91
126
|
debug?: boolean;
|
92
127
|
keep_quoted?: boolean | 'strict';
|
128
|
+
nth_identifier?: SimpleIdentifierMangler | WeightedIdentifierMangler;
|
93
129
|
regex?: RegExp | string;
|
94
130
|
reserved?: string[];
|
95
131
|
}
|