terser 5.9.0 → 5.14.2
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 +63 -0
- package/README.md +30 -8
- package/dist/bundle.min.js +5407 -3433
- package/lib/ast.js +1685 -348
- package/lib/cli.js +13 -9
- package/lib/compress/common.js +48 -0
- package/lib/compress/evaluate.js +18 -17
- package/lib/compress/index.js +57 -551
- package/lib/compress/inline.js +641 -0
- package/lib/compress/native-objects.js +1 -0
- package/lib/compress/tighten-body.js +1 -1
- package/lib/equivalent-to.js +81 -107
- package/lib/minify.js +96 -15
- package/lib/mozilla-ast.js +522 -87
- package/lib/output.js +94 -24
- package/lib/parse.js +91 -72
- package/lib/propmangle.js +1 -1
- package/lib/scope.js +27 -4
- package/lib/size.js +6 -8
- package/lib/sourcemap.js +60 -26
- package/lib/utils/index.js +9 -1
- package/package.json +9 -5
- package/tools/domprops.js +12 -0
- package/tools/terser.d.ts +6 -3
package/lib/cli.js
CHANGED
@@ -224,7 +224,7 @@ export async function run_cli({ program, packageJson, fs, path }) {
|
|
224
224
|
|
225
225
|
let result;
|
226
226
|
try {
|
227
|
-
result = await minify(files, options);
|
227
|
+
result = await minify(files, options, fs);
|
228
228
|
} catch (ex) {
|
229
229
|
if (ex.name == "SyntaxError") {
|
230
230
|
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
|
@@ -287,14 +287,18 @@ export async function run_cli({ program, packageJson, fs, path }) {
|
|
287
287
|
}, 2));
|
288
288
|
} else if (program.output == "spidermonkey") {
|
289
289
|
try {
|
290
|
-
const minified = await minify(
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
290
|
+
const minified = await minify(
|
291
|
+
result.code,
|
292
|
+
{
|
293
|
+
compress: false,
|
294
|
+
mangle: false,
|
295
|
+
format: {
|
296
|
+
ast: true,
|
297
|
+
code: false
|
298
|
+
}
|
299
|
+
},
|
300
|
+
fs
|
301
|
+
);
|
298
302
|
console.log(JSON.stringify(minified.ast.to_mozilla_ast(), null, 2));
|
299
303
|
} catch (ex) {
|
300
304
|
fatal(ex);
|
package/lib/compress/common.js
CHANGED
@@ -80,9 +80,13 @@ import {
|
|
80
80
|
AST_Undefined,
|
81
81
|
|
82
82
|
TreeWalker,
|
83
|
+
walk,
|
84
|
+
walk_abort,
|
85
|
+
walk_parent,
|
83
86
|
} from "../ast.js";
|
84
87
|
import { make_node, regexp_source_fix, string_template, makePredicate } from "../utils/index.js";
|
85
88
|
import { first_in_statement } from "../utils/first_in_statement.js";
|
89
|
+
import { has_flag, TOP } from "./compressor-flags.js";
|
86
90
|
|
87
91
|
export function merge_sequence(array, node) {
|
88
92
|
if (node instanceof AST_Sequence) {
|
@@ -244,6 +248,13 @@ export function is_iife_call(node) {
|
|
244
248
|
return node.expression instanceof AST_Function || is_iife_call(node.expression);
|
245
249
|
}
|
246
250
|
|
251
|
+
export function is_empty(thing) {
|
252
|
+
if (thing === null) return true;
|
253
|
+
if (thing instanceof AST_EmptyStatement) return true;
|
254
|
+
if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
|
255
|
+
return false;
|
256
|
+
}
|
257
|
+
|
247
258
|
export const identifier_atom = makePredicate("Infinity NaN undefined");
|
248
259
|
export function is_identifier_atom(node) {
|
249
260
|
return node instanceof AST_Infinity
|
@@ -281,6 +292,34 @@ export function as_statement_array(thing) {
|
|
281
292
|
throw new Error("Can't convert thing to statement array");
|
282
293
|
}
|
283
294
|
|
295
|
+
export function is_reachable(scope_node, defs) {
|
296
|
+
const find_ref = node => {
|
297
|
+
if (node instanceof AST_SymbolRef && defs.includes(node.definition())) {
|
298
|
+
return walk_abort;
|
299
|
+
}
|
300
|
+
};
|
301
|
+
|
302
|
+
return walk_parent(scope_node, (node, info) => {
|
303
|
+
if (node instanceof AST_Scope && node !== scope_node) {
|
304
|
+
var parent = info.parent();
|
305
|
+
|
306
|
+
if (
|
307
|
+
parent instanceof AST_Call
|
308
|
+
&& parent.expression === node
|
309
|
+
// Async/Generators aren't guaranteed to sync evaluate all of
|
310
|
+
// their body steps, so it's possible they close over the variable.
|
311
|
+
&& !(node.async || node.is_generator)
|
312
|
+
) {
|
313
|
+
return;
|
314
|
+
}
|
315
|
+
|
316
|
+
if (walk(node, find_ref)) return walk_abort;
|
317
|
+
|
318
|
+
return true;
|
319
|
+
}
|
320
|
+
});
|
321
|
+
}
|
322
|
+
|
284
323
|
/** Check if a ref refers to the name of a function/class it's defined within */
|
285
324
|
export function is_recursive_ref(compressor, def) {
|
286
325
|
var node;
|
@@ -294,3 +333,12 @@ export function is_recursive_ref(compressor, def) {
|
|
294
333
|
}
|
295
334
|
return false;
|
296
335
|
}
|
336
|
+
|
337
|
+
// TODO this only works with AST_Defun, shouldn't it work for other ways of defining functions?
|
338
|
+
export function retain_top_func(fn, compressor) {
|
339
|
+
return compressor.top_retain
|
340
|
+
&& fn instanceof AST_Defun
|
341
|
+
&& has_flag(fn, TOP)
|
342
|
+
&& fn.name
|
343
|
+
&& compressor.top_retain(fn.name);
|
344
|
+
}
|
package/lib/compress/evaluate.js
CHANGED
@@ -46,7 +46,8 @@ import {
|
|
46
46
|
makePredicate,
|
47
47
|
return_this,
|
48
48
|
string_template,
|
49
|
-
regexp_source_fix
|
49
|
+
regexp_source_fix,
|
50
|
+
regexp_is_safe,
|
50
51
|
} from "../utils/index.js";
|
51
52
|
import {
|
52
53
|
AST_Array,
|
@@ -128,14 +129,15 @@ def_eval(AST_Constant, function () {
|
|
128
129
|
def_eval(AST_BigInt, return_this);
|
129
130
|
|
130
131
|
def_eval(AST_RegExp, function (compressor) {
|
131
|
-
let evaluated = compressor.evaluated_regexps.get(this);
|
132
|
-
if (evaluated === undefined) {
|
132
|
+
let evaluated = compressor.evaluated_regexps.get(this.value);
|
133
|
+
if (evaluated === undefined && regexp_is_safe(this.value.source)) {
|
133
134
|
try {
|
134
|
-
|
135
|
+
const { source, flags } = this.value;
|
136
|
+
evaluated = new RegExp(source, flags);
|
135
137
|
} catch (e) {
|
136
138
|
evaluated = null;
|
137
139
|
}
|
138
|
-
compressor.evaluated_regexps.set(this, evaluated);
|
140
|
+
compressor.evaluated_regexps.set(this.value, evaluated);
|
139
141
|
}
|
140
142
|
return evaluated || this;
|
141
143
|
});
|
@@ -341,7 +343,7 @@ const regexp_flags = new Set([
|
|
341
343
|
]);
|
342
344
|
|
343
345
|
def_eval(AST_PropAccess, function (compressor, depth) {
|
344
|
-
|
346
|
+
let obj = this.expression._eval(compressor, depth + 1);
|
345
347
|
if (obj === nullish || (this.optional && obj == null)) return nullish;
|
346
348
|
if (compressor.option("unsafe")) {
|
347
349
|
var key = this.property;
|
@@ -351,7 +353,6 @@ def_eval(AST_PropAccess, function (compressor, depth) {
|
|
351
353
|
return this;
|
352
354
|
}
|
353
355
|
var exp = this.expression;
|
354
|
-
var val;
|
355
356
|
if (is_undeclared_ref(exp)) {
|
356
357
|
|
357
358
|
var aa;
|
@@ -368,29 +369,29 @@ def_eval(AST_PropAccess, function (compressor, depth) {
|
|
368
369
|
}
|
369
370
|
if (!is_pure_native_value(exp.name, key))
|
370
371
|
return this;
|
371
|
-
|
372
|
+
obj = global_objs[exp.name];
|
372
373
|
} else {
|
373
|
-
|
374
|
-
if (val instanceof RegExp) {
|
374
|
+
if (obj instanceof RegExp) {
|
375
375
|
if (key == "source") {
|
376
|
-
return regexp_source_fix(
|
376
|
+
return regexp_source_fix(obj.source);
|
377
377
|
} else if (key == "flags" || regexp_flags.has(key)) {
|
378
|
-
return
|
378
|
+
return obj[key];
|
379
379
|
}
|
380
380
|
}
|
381
|
-
if (!
|
381
|
+
if (!obj || obj === exp || !HOP(obj, key))
|
382
382
|
return this;
|
383
|
-
|
383
|
+
|
384
|
+
if (typeof obj == "function")
|
384
385
|
switch (key) {
|
385
386
|
case "name":
|
386
|
-
return
|
387
|
+
return obj.node.name ? obj.node.name.name : "";
|
387
388
|
case "length":
|
388
|
-
return
|
389
|
+
return obj.node.length_property();
|
389
390
|
default:
|
390
391
|
return this;
|
391
392
|
}
|
392
393
|
}
|
393
|
-
return
|
394
|
+
return obj[key];
|
394
395
|
}
|
395
396
|
return this;
|
396
397
|
});
|