terser 5.7.0 → 5.9.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 +38 -0
- package/README.md +23 -4
- package/dist/bundle.min.js +4706 -3723
- package/lib/ast.js +1 -7
- package/lib/cli.js +0 -2
- package/lib/compress/common.js +296 -0
- package/lib/compress/compressor-flags.js +63 -0
- package/lib/compress/drop-side-effect-free.js +350 -0
- package/lib/compress/evaluate.js +461 -0
- package/lib/compress/index.js +489 -3603
- package/lib/compress/inference.js +948 -0
- package/lib/compress/native-objects.js +183 -0
- package/lib/compress/reduce-vars.js +675 -0
- package/lib/compress/tighten-body.js +1461 -0
- package/lib/equivalent-to.js +5 -0
- package/lib/minify.js +3 -1
- package/lib/output.js +20 -7
- package/lib/parse.js +4 -2
- package/lib/propmangle.js +57 -34
- package/lib/scope.js +49 -24
- package/lib/transform.js +2 -2
- package/lib/utils/index.js +2 -4
- package/package.json +10 -10
- package/tools/terser.d.ts +37 -0
- package/bin/terser.mjs +0 -21
package/lib/equivalent-to.js
CHANGED
@@ -18,6 +18,7 @@ import {
|
|
18
18
|
AST_Directive,
|
19
19
|
AST_Do,
|
20
20
|
AST_Dot,
|
21
|
+
AST_DotHash,
|
21
22
|
AST_EmptyStatement,
|
22
23
|
AST_Expansion,
|
23
24
|
AST_Export,
|
@@ -233,6 +234,10 @@ AST_Dot.prototype.shallow_cmp = mkshallow({
|
|
233
234
|
property: "eq"
|
234
235
|
});
|
235
236
|
|
237
|
+
AST_DotHash.prototype.shallow_cmp = mkshallow({
|
238
|
+
property: "eq"
|
239
|
+
});
|
240
|
+
|
236
241
|
AST_Unary.prototype.shallow_cmp = mkshallow({
|
237
242
|
operator: "eq"
|
238
243
|
});
|
package/lib/minify.js
CHANGED
@@ -15,6 +15,7 @@ import { base54 } from "./scope.js";
|
|
15
15
|
import { SourceMap } from "./sourcemap.js";
|
16
16
|
import {
|
17
17
|
mangle_properties,
|
18
|
+
mangle_private_properties,
|
18
19
|
reserve_quoted_keys,
|
19
20
|
} from "./propmangle.js";
|
20
21
|
|
@@ -113,6 +114,7 @@ async function minify(files, options) {
|
|
113
114
|
keep_classnames: false,
|
114
115
|
keep_fnames: false,
|
115
116
|
module: false,
|
117
|
+
nth_identifier: base54,
|
116
118
|
properties: false,
|
117
119
|
reserved: [],
|
118
120
|
safari10: false,
|
@@ -203,9 +205,9 @@ async function minify(files, options) {
|
|
203
205
|
if (options.mangle) toplevel.figure_out_scope(options.mangle);
|
204
206
|
if (timings) timings.mangle = Date.now();
|
205
207
|
if (options.mangle) {
|
206
|
-
base54.reset();
|
207
208
|
toplevel.compute_char_frequency(options.mangle);
|
208
209
|
toplevel.mangle_names(options.mangle);
|
210
|
+
toplevel = mangle_private_properties(toplevel, options.mangle);
|
209
211
|
}
|
210
212
|
if (timings) timings.properties = Date.now();
|
211
213
|
if (options.mangle && options.mangle.properties) {
|
package/lib/output.js
CHANGED
@@ -159,7 +159,7 @@ import {
|
|
159
159
|
is_basic_identifier_string,
|
160
160
|
is_identifier_string,
|
161
161
|
PRECEDENCE,
|
162
|
-
|
162
|
+
ALL_RESERVED_WORDS,
|
163
163
|
} from "./parse.js";
|
164
164
|
|
165
165
|
const EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
@@ -349,11 +349,17 @@ function OutputStream(options) {
|
|
349
349
|
var do_add_mapping = mappings ? function() {
|
350
350
|
mappings.forEach(function(mapping) {
|
351
351
|
try {
|
352
|
+
let { name, token } = mapping;
|
353
|
+
if (token.type == "name" || token.type === "privatename") {
|
354
|
+
name = token.value;
|
355
|
+
} else if (name instanceof AST_Symbol) {
|
356
|
+
name = token.type === "string" ? token.value : name.name;
|
357
|
+
}
|
352
358
|
options.source_map.add(
|
353
359
|
mapping.token.file,
|
354
360
|
mapping.line, mapping.col,
|
355
361
|
mapping.token.line, mapping.token.col,
|
356
|
-
|
362
|
+
is_basic_identifier_string(name) ? name : undefined
|
357
363
|
);
|
358
364
|
} catch(ex) {
|
359
365
|
// Ignore bad mapping
|
@@ -1713,7 +1719,11 @@ function OutputStream(options) {
|
|
1713
1719
|
// https://github.com/mishoo/UglifyJS2/issues/60
|
1714
1720
|
if (noin) {
|
1715
1721
|
parens = walk(node, node => {
|
1716
|
-
|
1722
|
+
// Don't go into scopes -- except arrow functions:
|
1723
|
+
// https://github.com/terser/terser/issues/1019#issuecomment-877642607
|
1724
|
+
if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
|
1725
|
+
return true;
|
1726
|
+
}
|
1717
1727
|
if (node instanceof AST_Binary && node.operator == "in") {
|
1718
1728
|
return walk_abort; // makes walk() return true
|
1719
1729
|
}
|
@@ -1783,7 +1793,7 @@ function OutputStream(options) {
|
|
1783
1793
|
var expr = self.expression;
|
1784
1794
|
expr.print(output);
|
1785
1795
|
var prop = self.property;
|
1786
|
-
var print_computed =
|
1796
|
+
var print_computed = ALL_RESERVED_WORDS.has(prop)
|
1787
1797
|
? output.option("ie8")
|
1788
1798
|
: !is_identifier_string(
|
1789
1799
|
prop,
|
@@ -1816,6 +1826,7 @@ function OutputStream(options) {
|
|
1816
1826
|
|
1817
1827
|
if (self.optional) output.print("?");
|
1818
1828
|
output.print(".#");
|
1829
|
+
output.add_mapping(self.end);
|
1819
1830
|
output.print_name(prop);
|
1820
1831
|
});
|
1821
1832
|
DEFPRINT(AST_Sub, function(self, output) {
|
@@ -1964,7 +1975,7 @@ function OutputStream(options) {
|
|
1964
1975
|
}
|
1965
1976
|
return output.print(make_num(key));
|
1966
1977
|
}
|
1967
|
-
var print_string =
|
1978
|
+
var print_string = ALL_RESERVED_WORDS.has(key)
|
1968
1979
|
? output.option("ie8")
|
1969
1980
|
: (
|
1970
1981
|
output.option("ecma") < 2015 || output.option("safari10")
|
@@ -1991,7 +2002,7 @@ function OutputStream(options) {
|
|
1991
2002
|
output.option("ecma") >= 2015 || output.option("safari10")
|
1992
2003
|
) &&
|
1993
2004
|
get_name(self.value) === self.key &&
|
1994
|
-
!
|
2005
|
+
!ALL_RESERVED_WORDS.has(self.key)
|
1995
2006
|
) {
|
1996
2007
|
print_property_name(self.key, self.quote, output);
|
1997
2008
|
|
@@ -2269,8 +2280,10 @@ function OutputStream(options) {
|
|
2269
2280
|
DEFMAP([
|
2270
2281
|
AST_ObjectGetter,
|
2271
2282
|
AST_ObjectSetter,
|
2283
|
+
AST_PrivateGetter,
|
2284
|
+
AST_PrivateSetter,
|
2272
2285
|
], function(output) {
|
2273
|
-
output.add_mapping(this.
|
2286
|
+
output.add_mapping(this.key.end, this.key.name);
|
2274
2287
|
});
|
2275
2288
|
|
2276
2289
|
DEFMAP([ AST_ObjectProperty ], function(output) {
|
package/lib/parse.js
CHANGED
@@ -166,13 +166,15 @@ var LATEST_TEMPLATE_END = true;
|
|
166
166
|
|
167
167
|
var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with";
|
168
168
|
var KEYWORDS_ATOM = "false null true";
|
169
|
-
var RESERVED_WORDS = "enum
|
169
|
+
var RESERVED_WORDS = "enum import super this " + KEYWORDS_ATOM + " " + KEYWORDS;
|
170
|
+
var ALL_RESERVED_WORDS = "implements interface package private protected public static " + RESERVED_WORDS;
|
170
171
|
var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case yield await";
|
171
172
|
|
172
173
|
KEYWORDS = makePredicate(KEYWORDS);
|
173
174
|
RESERVED_WORDS = makePredicate(RESERVED_WORDS);
|
174
175
|
KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
|
175
176
|
KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
|
177
|
+
ALL_RESERVED_WORDS = makePredicate(ALL_RESERVED_WORDS);
|
176
178
|
|
177
179
|
var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
|
178
180
|
|
@@ -3339,6 +3341,6 @@ export {
|
|
3339
3341
|
JS_Parse_Error,
|
3340
3342
|
parse,
|
3341
3343
|
PRECEDENCE,
|
3342
|
-
|
3344
|
+
ALL_RESERVED_WORDS,
|
3343
3345
|
tokenizer,
|
3344
3346
|
};
|
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
@@ -107,7 +107,7 @@ import {
|
|
107
107
|
walk
|
108
108
|
} from "./ast.js";
|
109
109
|
import {
|
110
|
-
|
110
|
+
ALL_RESERVED_WORDS,
|
111
111
|
js_error,
|
112
112
|
} from "./parse.js";
|
113
113
|
|
@@ -299,7 +299,14 @@ AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = null,
|
|
299
299
|
// scope when we encounter the AST_Defun node (which is
|
300
300
|
// instanceof AST_Scope) but we get to the symbol a bit
|
301
301
|
// later.
|
302
|
-
|
302
|
+
const closest_scope = defun.parent_scope;
|
303
|
+
|
304
|
+
// In strict mode, function definitions are block-scoped
|
305
|
+
node.scope = tw.directives["use strict"]
|
306
|
+
? closest_scope
|
307
|
+
: closest_scope.get_defun_scope();
|
308
|
+
|
309
|
+
mark_export(node.scope.def_function(node, defun), 1);
|
303
310
|
} else if (node instanceof AST_SymbolClass) {
|
304
311
|
mark_export(defun.def_variable(node, defun), 1);
|
305
312
|
} else if (node instanceof AST_SymbolImport) {
|
@@ -478,7 +485,6 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
|
478
485
|
|
479
486
|
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
480
487
|
this.variables = new Map(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
481
|
-
this.functions = new Map(); // map name to AST_SymbolDefun (functions defined in this scope)
|
482
488
|
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
483
489
|
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
484
490
|
this.parent_scope = parent_scope; // the parent scope
|
@@ -641,7 +647,6 @@ AST_Scope.DEFMETHOD("find_variable", function(name) {
|
|
641
647
|
AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
|
642
648
|
var def = this.def_variable(symbol, init);
|
643
649
|
if (!def.init || def.init instanceof AST_Defun) def.init = init;
|
644
|
-
this.functions.set(symbol.name, def);
|
645
650
|
return def;
|
646
651
|
});
|
647
652
|
|
@@ -662,9 +667,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
|
662
667
|
|
663
668
|
function next_mangled(scope, options) {
|
664
669
|
var ext = scope.enclosed;
|
670
|
+
var nth_identifier = options.nth_identifier;
|
665
671
|
out: while (true) {
|
666
|
-
var m =
|
667
|
-
if (
|
672
|
+
var m = nth_identifier.get(++scope.cname);
|
673
|
+
if (ALL_RESERVED_WORDS.has(m)) continue; // skip over "do"
|
668
674
|
|
669
675
|
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
670
676
|
// shadow a name reserved from mangling.
|
@@ -739,6 +745,7 @@ AST_Symbol.DEFMETHOD("global", function() {
|
|
739
745
|
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
|
740
746
|
options = defaults(options, {
|
741
747
|
eval : false,
|
748
|
+
nth_identifier : base54,
|
742
749
|
ie8 : false,
|
743
750
|
keep_classnames: false,
|
744
751
|
keep_fnames : false,
|
@@ -760,6 +767,7 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
|
|
760
767
|
|
761
768
|
AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
762
769
|
options = this._default_mangler_options(options);
|
770
|
+
var nth_identifier = options.nth_identifier;
|
763
771
|
|
764
772
|
// We only need to mangle declaration nodes. Special logic wired
|
765
773
|
// into the code generator will display the mangled name if it's
|
@@ -811,8 +819,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|
811
819
|
if (node instanceof AST_Label) {
|
812
820
|
let name;
|
813
821
|
do {
|
814
|
-
name =
|
815
|
-
} while (
|
822
|
+
name = nth_identifier.get(++lname);
|
823
|
+
} while (ALL_RESERVED_WORDS.has(name));
|
816
824
|
node.mangled_name = name;
|
817
825
|
return true;
|
818
826
|
}
|
@@ -873,9 +881,12 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
|
873
881
|
});
|
874
882
|
|
875
883
|
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
876
|
-
base54.reset();
|
877
|
-
base54.sort();
|
878
884
|
options = this._default_mangler_options(options);
|
885
|
+
var nth_identifier = options.nth_identifier;
|
886
|
+
if (nth_identifier.reset && nth_identifier.sort) {
|
887
|
+
nth_identifier.reset();
|
888
|
+
nth_identifier.sort();
|
889
|
+
}
|
879
890
|
var avoid = this.find_colliding_names(options);
|
880
891
|
var cname = 0;
|
881
892
|
this.globals.forEach(rename);
|
@@ -887,8 +898,8 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|
887
898
|
function next_name() {
|
888
899
|
var name;
|
889
900
|
do {
|
890
|
-
name =
|
891
|
-
} while (avoid.has(name) ||
|
901
|
+
name = nth_identifier.get(cname++);
|
902
|
+
} while (avoid.has(name) || ALL_RESERVED_WORDS.has(name));
|
892
903
|
return name;
|
893
904
|
}
|
894
905
|
|
@@ -914,30 +925,37 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
|
|
914
925
|
|
915
926
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
916
927
|
options = this._default_mangler_options(options);
|
928
|
+
var nth_identifier = options.nth_identifier;
|
929
|
+
if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) {
|
930
|
+
// If the identifier mangler is invariant, skip computing character frequency.
|
931
|
+
return;
|
932
|
+
}
|
933
|
+
nth_identifier.reset();
|
934
|
+
|
917
935
|
try {
|
918
936
|
AST_Node.prototype.print = function(stream, force_parens) {
|
919
937
|
this._print(stream, force_parens);
|
920
938
|
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
921
|
-
|
939
|
+
nth_identifier.consider(this.name, -1);
|
922
940
|
} else if (options.properties) {
|
923
941
|
if (this instanceof AST_DotHash) {
|
924
|
-
|
942
|
+
nth_identifier.consider("#" + this.property, -1);
|
925
943
|
} else if (this instanceof AST_Dot) {
|
926
|
-
|
944
|
+
nth_identifier.consider(this.property, -1);
|
927
945
|
} else if (this instanceof AST_Sub) {
|
928
946
|
skip_string(this.property);
|
929
947
|
}
|
930
948
|
}
|
931
949
|
};
|
932
|
-
|
950
|
+
nth_identifier.consider(this.print_to_string(), 1);
|
933
951
|
} finally {
|
934
952
|
AST_Node.prototype.print = AST_Node.prototype._print;
|
935
953
|
}
|
936
|
-
|
954
|
+
nth_identifier.sort();
|
937
955
|
|
938
956
|
function skip_string(node) {
|
939
957
|
if (node instanceof AST_String) {
|
940
|
-
|
958
|
+
nth_identifier.consider(node.value, -1);
|
941
959
|
} else if (node instanceof AST_Conditional) {
|
942
960
|
skip_string(node.consequent);
|
943
961
|
skip_string(node.alternative);
|
@@ -961,19 +979,20 @@ const base54 = (() => {
|
|
961
979
|
frequency.set(ch, 0);
|
962
980
|
});
|
963
981
|
}
|
964
|
-
|
982
|
+
function consider(str, delta) {
|
965
983
|
for (var i = str.length; --i >= 0;) {
|
966
984
|
frequency.set(str[i], frequency.get(str[i]) + delta);
|
967
985
|
}
|
968
|
-
}
|
986
|
+
}
|
969
987
|
function compare(a, b) {
|
970
988
|
return frequency.get(b) - frequency.get(a);
|
971
989
|
}
|
972
|
-
|
990
|
+
function sort() {
|
973
991
|
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
974
|
-
}
|
975
|
-
|
992
|
+
}
|
993
|
+
// Ensure this is in a usable initial state.
|
976
994
|
reset();
|
995
|
+
sort();
|
977
996
|
function base54(num) {
|
978
997
|
var ret = "", base = 54;
|
979
998
|
num++;
|
@@ -985,7 +1004,13 @@ const base54 = (() => {
|
|
985
1004
|
} while (num > 0);
|
986
1005
|
return ret;
|
987
1006
|
}
|
988
|
-
|
1007
|
+
|
1008
|
+
return {
|
1009
|
+
get: base54,
|
1010
|
+
consider,
|
1011
|
+
reset,
|
1012
|
+
sort
|
1013
|
+
};
|
989
1014
|
})();
|
990
1015
|
|
991
1016
|
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/lib/utils/index.js
CHANGED
@@ -64,10 +64,8 @@ class DefaultsError extends Error {
|
|
64
64
|
function defaults(args, defs, croak) {
|
65
65
|
if (args === true) {
|
66
66
|
args = {};
|
67
|
-
}
|
68
|
-
|
69
|
-
if (args != null && typeof args === "object") {
|
70
|
-
args = Object.assign({}, args);
|
67
|
+
} else if (args != null && typeof args === "object") {
|
68
|
+
args = {...args};
|
71
69
|
}
|
72
70
|
|
73
71
|
const ret = args || {};
|
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.9.0",
|
8
8
|
"engines": {
|
9
9
|
"node": ">=10"
|
10
10
|
},
|
@@ -45,19 +45,19 @@
|
|
45
45
|
"dependencies": {
|
46
46
|
"commander": "^2.20.0",
|
47
47
|
"source-map": "~0.7.2",
|
48
|
-
"source-map-support": "~0.5.
|
48
|
+
"source-map-support": "~0.5.20"
|
49
49
|
},
|
50
50
|
"devDependencies": {
|
51
|
-
"@ls-lint/ls-lint": "^1.
|
52
|
-
"acorn": "^8.0
|
53
|
-
"astring": "^1.
|
54
|
-
"eslint": "^7.
|
55
|
-
"eslump": "^
|
51
|
+
"@ls-lint/ls-lint": "^1.10.0",
|
52
|
+
"acorn": "^8.5.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.1.1",
|
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": {
|
@@ -93,7 +93,7 @@
|
|
93
93
|
"eslintConfig": {
|
94
94
|
"parserOptions": {
|
95
95
|
"sourceType": "module",
|
96
|
-
"ecmaVersion":
|
96
|
+
"ecmaVersion": 2020
|
97
97
|
},
|
98
98
|
"env": {
|
99
99
|
"node": true,
|
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
|
}
|
@@ -138,6 +174,7 @@ export enum OutputQuoteStyle {
|
|
138
174
|
export interface MinifyOptions {
|
139
175
|
compress?: boolean | CompressOptions;
|
140
176
|
ecma?: ECMA;
|
177
|
+
enclose?: boolean | string;
|
141
178
|
ie8?: boolean;
|
142
179
|
keep_classnames?: boolean | RegExp;
|
143
180
|
keep_fnames?: boolean | RegExp;
|