terser 5.16.0 → 5.16.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/lib/ast.js CHANGED
@@ -994,6 +994,7 @@ var AST_Jump = DEFNODE("Jump", null, function AST_Jump(props) {
994
994
  $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
995
995
  }, AST_Statement);
996
996
 
997
+ /** Base class for “exits” (`return` and `throw`) */
997
998
  var AST_Exit = DEFNODE("Exit", "value", function AST_Exit(props) {
998
999
  if (props) {
999
1000
  this.value = props.value;
@@ -2588,6 +2589,7 @@ var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, function AST_
2588
2589
  this.scope = props.scope;
2589
2590
  this.name = props.name;
2590
2591
  this.thedef = props.thedef;
2592
+ this.quote = props.quote;
2591
2593
  this.start = props.start;
2592
2594
  this.end = props.end;
2593
2595
  }
@@ -2639,6 +2641,7 @@ var AST_SymbolExport = DEFNODE("SymbolExport", null, function AST_SymbolExport(p
2639
2641
  this.scope = props.scope;
2640
2642
  this.name = props.name;
2641
2643
  this.thedef = props.thedef;
2644
+ this.quote = props.quote;
2642
2645
  this.start = props.start;
2643
2646
  this.end = props.end;
2644
2647
  }
@@ -2653,6 +2656,7 @@ var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, function AST_
2653
2656
  this.scope = props.scope;
2654
2657
  this.name = props.name;
2655
2658
  this.thedef = props.thedef;
2659
+ this.quote = props.quote;
2656
2660
  this.start = props.start;
2657
2661
  this.end = props.end;
2658
2662
  }
@@ -3061,8 +3065,9 @@ class TreeWalker {
3061
3065
  }
3062
3066
 
3063
3067
  find_scope() {
3064
- for (let i = 0;;i++) {
3065
- const p = this.parent(i);
3068
+ var stack = this.stack;
3069
+ for (var i = stack.length; --i >= 0;) {
3070
+ const p = stack[i];
3066
3071
  if (p instanceof AST_Toplevel) return p;
3067
3072
  if (p instanceof AST_Lambda) return p;
3068
3073
  if (p.block_scope) return p.block_scope;
@@ -241,9 +241,10 @@ export function is_func_expr(node) {
241
241
  return node instanceof AST_Arrow || node instanceof AST_Function;
242
242
  }
243
243
 
244
+ /**
245
+ * Used to determine whether the node can benefit from negation.
246
+ * Not the case with arrow functions (you need an extra set of parens). */
244
247
  export function is_iife_call(node) {
245
- // Used to determine whether the node can benefit from negation.
246
- // Not the case with arrow functions (you need an extra set of parens).
247
248
  if (node.TYPE != "Call") return false;
248
249
  return node.expression instanceof AST_Function || is_iife_call(node.expression);
249
250
  }
@@ -0,0 +1,482 @@
1
+ /***********************************************************************
2
+
3
+ A JavaScript tokenizer / parser / beautifier / compressor.
4
+ https://github.com/mishoo/UglifyJS2
5
+
6
+ -------------------------------- (C) ---------------------------------
7
+
8
+ Author: Mihai Bazon
9
+ <mihai.bazon@gmail.com>
10
+ http://mihai.bazon.net/blog
11
+
12
+ Distributed under the BSD license:
13
+
14
+ Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
+
16
+ Redistribution and use in source and binary forms, with or without
17
+ modification, are permitted provided that the following conditions
18
+ are met:
19
+
20
+ * Redistributions of source code must retain the above
21
+ copyright notice, this list of conditions and the following
22
+ disclaimer.
23
+
24
+ * Redistributions in binary form must reproduce the above
25
+ copyright notice, this list of conditions and the following
26
+ disclaimer in the documentation and/or other materials
27
+ provided with the distribution.
28
+
29
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40
+ SUCH DAMAGE.
41
+
42
+ ***********************************************************************/
43
+
44
+ import {
45
+ AST_Accessor,
46
+ AST_Assign,
47
+ AST_BlockStatement,
48
+ AST_Class,
49
+ AST_ClassExpression,
50
+ AST_DefaultAssign,
51
+ AST_DefClass,
52
+ AST_Definitions,
53
+ AST_Defun,
54
+ AST_Destructuring,
55
+ AST_EmptyStatement,
56
+ AST_Expansion,
57
+ AST_Export,
58
+ AST_For,
59
+ AST_ForIn,
60
+ AST_Function,
61
+ AST_LabeledStatement,
62
+ AST_Lambda,
63
+ AST_Number,
64
+ AST_Scope,
65
+ AST_SimpleStatement,
66
+ AST_SymbolBlockDeclaration,
67
+ AST_SymbolCatch,
68
+ AST_SymbolDeclaration,
69
+ AST_SymbolFunarg,
70
+ AST_SymbolRef,
71
+ AST_SymbolVar,
72
+ AST_Toplevel,
73
+ AST_Unary,
74
+ AST_Var,
75
+
76
+ TreeTransformer,
77
+ TreeWalker,
78
+ walk,
79
+
80
+ _INLINE,
81
+ _NOINLINE,
82
+ _PURE
83
+ } from "../ast.js";
84
+ import {
85
+ keep_name,
86
+ make_node,
87
+ map_add,
88
+ MAP,
89
+ remove,
90
+ return_false,
91
+ } from "../utils/index.js";
92
+ import { SymbolDef } from "../scope.js";
93
+
94
+ import {
95
+ WRITE_ONLY,
96
+ UNUSED,
97
+
98
+ has_flag,
99
+ set_flag,
100
+ } from "./compressor-flags.js";
101
+ import {
102
+ make_sequence,
103
+ maintain_this_binding,
104
+ is_empty,
105
+ is_ref_of,
106
+ can_be_evicted_from_block,
107
+ } from "./common.js";
108
+
109
+ const r_keep_assign = /keep_assign/;
110
+
111
+ /** Drop unused variables from this scope */
112
+ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
113
+ if (!compressor.option("unused")) return;
114
+ if (compressor.has_directive("use asm")) return;
115
+ var self = this;
116
+ if (self.pinned()) return;
117
+ var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
118
+ var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
119
+ const assign_as_unused = r_keep_assign.test(compressor.option("unused")) ? return_false : function(node) {
120
+ if (node instanceof AST_Assign
121
+ && !node.logical
122
+ && (has_flag(node, WRITE_ONLY) || node.operator == "=")
123
+ ) {
124
+ return node.left;
125
+ }
126
+ if (node instanceof AST_Unary && has_flag(node, WRITE_ONLY)) {
127
+ return node.expression;
128
+ }
129
+ };
130
+ var in_use_ids = new Map();
131
+ var fixed_ids = new Map();
132
+ if (self instanceof AST_Toplevel && compressor.top_retain) {
133
+ self.variables.forEach(function(def) {
134
+ if (compressor.top_retain(def) && !in_use_ids.has(def.id)) {
135
+ in_use_ids.set(def.id, def);
136
+ }
137
+ });
138
+ }
139
+ var var_defs_by_id = new Map();
140
+ var initializations = new Map();
141
+ // pass 1: find out which symbols are directly used in
142
+ // this scope (not in nested scopes).
143
+ var scope = this;
144
+ var tw = new TreeWalker(function(node, descend) {
145
+ if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) {
146
+ node.argnames.forEach(function(argname) {
147
+ if (!(argname instanceof AST_SymbolDeclaration)) return;
148
+ var def = argname.definition();
149
+ if (!in_use_ids.has(def.id)) {
150
+ in_use_ids.set(def.id, def);
151
+ }
152
+ });
153
+ }
154
+ if (node === self) return;
155
+ if (node instanceof AST_Defun || node instanceof AST_DefClass) {
156
+ var node_def = node.name.definition();
157
+ const in_export = tw.parent() instanceof AST_Export;
158
+ if (in_export || !drop_funcs && scope === self) {
159
+ if (node_def.global && !in_use_ids.has(node_def.id)) {
160
+ in_use_ids.set(node_def.id, node_def);
161
+ }
162
+ }
163
+ if (node instanceof AST_DefClass) {
164
+ if (
165
+ node.extends
166
+ && (node.extends.has_side_effects(compressor)
167
+ || node.extends.may_throw(compressor))
168
+ ) {
169
+ node.extends.walk(tw);
170
+ }
171
+ for (const prop of node.properties) {
172
+ if (
173
+ prop.has_side_effects(compressor) ||
174
+ prop.may_throw(compressor)
175
+ ) {
176
+ prop.walk(tw);
177
+ }
178
+ }
179
+ }
180
+ map_add(initializations, node_def.id, node);
181
+ return true; // don't go in nested scopes
182
+ }
183
+ if (node instanceof AST_SymbolFunarg && scope === self) {
184
+ map_add(var_defs_by_id, node.definition().id, node);
185
+ }
186
+ if (node instanceof AST_Definitions && scope === self) {
187
+ const in_export = tw.parent() instanceof AST_Export;
188
+ node.definitions.forEach(function(def) {
189
+ if (def.name instanceof AST_SymbolVar) {
190
+ map_add(var_defs_by_id, def.name.definition().id, def);
191
+ }
192
+ if (in_export || !drop_vars) {
193
+ walk(def.name, node => {
194
+ if (node instanceof AST_SymbolDeclaration) {
195
+ const def = node.definition();
196
+ if (def.global && !in_use_ids.has(def.id)) {
197
+ in_use_ids.set(def.id, def);
198
+ }
199
+ }
200
+ });
201
+ }
202
+ if (def.name instanceof AST_Destructuring) {
203
+ def.walk(tw);
204
+ }
205
+ if (def.name instanceof AST_SymbolDeclaration && def.value) {
206
+ var node_def = def.name.definition();
207
+ map_add(initializations, node_def.id, def.value);
208
+ if (!node_def.chained && def.name.fixed_value() === def.value) {
209
+ fixed_ids.set(node_def.id, def);
210
+ }
211
+ if (def.value.has_side_effects(compressor)) {
212
+ def.value.walk(tw);
213
+ }
214
+ }
215
+ });
216
+ return true;
217
+ }
218
+ return scan_ref_scoped(node, descend);
219
+ });
220
+ self.walk(tw);
221
+ // pass 2: for every used symbol we need to walk its
222
+ // initialization code to figure out if it uses other
223
+ // symbols (that may not be in_use).
224
+ tw = new TreeWalker(scan_ref_scoped);
225
+ in_use_ids.forEach(function (def) {
226
+ var init = initializations.get(def.id);
227
+ if (init) init.forEach(function(init) {
228
+ init.walk(tw);
229
+ });
230
+ });
231
+ // pass 3: we should drop declarations not in_use
232
+ var tt = new TreeTransformer(
233
+ function before(node, descend, in_list) {
234
+ var parent = tt.parent();
235
+ if (drop_vars) {
236
+ const sym = assign_as_unused(node);
237
+ if (sym instanceof AST_SymbolRef) {
238
+ var def = sym.definition();
239
+ var in_use = in_use_ids.has(def.id);
240
+ if (node instanceof AST_Assign) {
241
+ if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
242
+ return maintain_this_binding(parent, node, node.right.transform(tt));
243
+ }
244
+ } else if (!in_use) return in_list ? MAP.skip : make_node(AST_Number, node, {
245
+ value: 0
246
+ });
247
+ }
248
+ }
249
+ if (scope !== self) return;
250
+ var def;
251
+ if (node.name
252
+ && (node instanceof AST_ClassExpression
253
+ && !keep_name(compressor.option("keep_classnames"), (def = node.name.definition()).name)
254
+ || node instanceof AST_Function
255
+ && !keep_name(compressor.option("keep_fnames"), (def = node.name.definition()).name))) {
256
+ // any declarations with same name will overshadow
257
+ // name of this anonymous function and can therefore
258
+ // never be used anywhere
259
+ if (!in_use_ids.has(def.id) || def.orig.length > 1) node.name = null;
260
+ }
261
+ if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
262
+ var trim = !compressor.option("keep_fargs");
263
+ for (var a = node.argnames, i = a.length; --i >= 0;) {
264
+ var sym = a[i];
265
+ if (sym instanceof AST_Expansion) {
266
+ sym = sym.expression;
267
+ }
268
+ if (sym instanceof AST_DefaultAssign) {
269
+ sym = sym.left;
270
+ }
271
+ // Do not drop destructuring arguments.
272
+ // They constitute a type assertion of sorts
273
+ if (
274
+ !(sym instanceof AST_Destructuring)
275
+ && !in_use_ids.has(sym.definition().id)
276
+ ) {
277
+ set_flag(sym, UNUSED);
278
+ if (trim) {
279
+ a.pop();
280
+ }
281
+ } else {
282
+ trim = false;
283
+ }
284
+ }
285
+ }
286
+ if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
287
+ const def = node.name.definition();
288
+ const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
289
+ // Class "extends" and static blocks may have side effects
290
+ const has_side_effects = !keep
291
+ && node instanceof AST_Class
292
+ && node.has_side_effects(compressor);
293
+ if (!keep && !has_side_effects) {
294
+ def.eliminated++;
295
+ return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
296
+ }
297
+ }
298
+ if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
299
+ var drop_block = !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var);
300
+ // place uninitialized names at the start
301
+ var body = [], head = [], tail = [];
302
+ // for unused names whose initialization has
303
+ // side effects, we can cascade the init. code
304
+ // into the next one, or next statement.
305
+ var side_effects = [];
306
+ node.definitions.forEach(function(def) {
307
+ if (def.value) def.value = def.value.transform(tt);
308
+ var is_destructure = def.name instanceof AST_Destructuring;
309
+ var sym = is_destructure
310
+ ? new SymbolDef(null, { name: "<destructure>" }) /* fake SymbolDef */
311
+ : def.name.definition();
312
+ if (drop_block && sym.global) return tail.push(def);
313
+ if (!(drop_vars || drop_block)
314
+ || is_destructure
315
+ && (def.name.names.length
316
+ || def.name.is_array
317
+ || compressor.option("pure_getters") != true)
318
+ || in_use_ids.has(sym.id)
319
+ ) {
320
+ if (def.value && fixed_ids.has(sym.id) && fixed_ids.get(sym.id) !== def) {
321
+ def.value = def.value.drop_side_effect_free(compressor);
322
+ }
323
+ if (def.name instanceof AST_SymbolVar) {
324
+ var var_defs = var_defs_by_id.get(sym.id);
325
+ if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
326
+ if (def.value) {
327
+ var ref = make_node(AST_SymbolRef, def.name, def.name);
328
+ sym.references.push(ref);
329
+ var assign = make_node(AST_Assign, def, {
330
+ operator: "=",
331
+ logical: false,
332
+ left: ref,
333
+ right: def.value
334
+ });
335
+ if (fixed_ids.get(sym.id) === def) {
336
+ fixed_ids.set(sym.id, assign);
337
+ }
338
+ side_effects.push(assign.transform(tt));
339
+ }
340
+ remove(var_defs, def);
341
+ sym.eliminated++;
342
+ return;
343
+ }
344
+ }
345
+ if (def.value) {
346
+ if (side_effects.length > 0) {
347
+ if (tail.length > 0) {
348
+ side_effects.push(def.value);
349
+ def.value = make_sequence(def.value, side_effects);
350
+ } else {
351
+ body.push(make_node(AST_SimpleStatement, node, {
352
+ body: make_sequence(node, side_effects)
353
+ }));
354
+ }
355
+ side_effects = [];
356
+ }
357
+ tail.push(def);
358
+ } else {
359
+ head.push(def);
360
+ }
361
+ } else if (sym.orig[0] instanceof AST_SymbolCatch) {
362
+ var value = def.value && def.value.drop_side_effect_free(compressor);
363
+ if (value) side_effects.push(value);
364
+ def.value = null;
365
+ head.push(def);
366
+ } else {
367
+ var value = def.value && def.value.drop_side_effect_free(compressor);
368
+ if (value) {
369
+ side_effects.push(value);
370
+ }
371
+ sym.eliminated++;
372
+ }
373
+ });
374
+ if (head.length > 0 || tail.length > 0) {
375
+ node.definitions = head.concat(tail);
376
+ body.push(node);
377
+ }
378
+ if (side_effects.length > 0) {
379
+ body.push(make_node(AST_SimpleStatement, node, {
380
+ body: make_sequence(node, side_effects)
381
+ }));
382
+ }
383
+ switch (body.length) {
384
+ case 0:
385
+ return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
386
+ case 1:
387
+ return body[0];
388
+ default:
389
+ return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
390
+ body: body
391
+ });
392
+ }
393
+ }
394
+ // certain combination of unused name + side effect leads to:
395
+ // https://github.com/mishoo/UglifyJS2/issues/44
396
+ // https://github.com/mishoo/UglifyJS2/issues/1830
397
+ // https://github.com/mishoo/UglifyJS2/issues/1838
398
+ // that's an invalid AST.
399
+ // We fix it at this stage by moving the `var` outside the `for`.
400
+ if (node instanceof AST_For) {
401
+ descend(node, this);
402
+ var block;
403
+ if (node.init instanceof AST_BlockStatement) {
404
+ block = node.init;
405
+ node.init = block.body.pop();
406
+ block.body.push(node);
407
+ }
408
+ if (node.init instanceof AST_SimpleStatement) {
409
+ node.init = node.init.body;
410
+ } else if (is_empty(node.init)) {
411
+ node.init = null;
412
+ }
413
+ return !block ? node : in_list ? MAP.splice(block.body) : block;
414
+ }
415
+ if (node instanceof AST_LabeledStatement
416
+ && node.body instanceof AST_For
417
+ ) {
418
+ descend(node, this);
419
+ if (node.body instanceof AST_BlockStatement) {
420
+ var block = node.body;
421
+ node.body = block.body.pop();
422
+ block.body.push(node);
423
+ return in_list ? MAP.splice(block.body) : block;
424
+ }
425
+ return node;
426
+ }
427
+ if (node instanceof AST_BlockStatement) {
428
+ descend(node, this);
429
+ if (in_list && node.body.every(can_be_evicted_from_block)) {
430
+ return MAP.splice(node.body);
431
+ }
432
+ return node;
433
+ }
434
+ if (node instanceof AST_Scope) {
435
+ const save_scope = scope;
436
+ scope = node;
437
+ descend(node, this);
438
+ scope = save_scope;
439
+ return node;
440
+ }
441
+ }
442
+ );
443
+
444
+ self.transform(tt);
445
+
446
+ function scan_ref_scoped(node, descend) {
447
+ var node_def;
448
+ const sym = assign_as_unused(node);
449
+ if (sym instanceof AST_SymbolRef
450
+ && !is_ref_of(node.left, AST_SymbolBlockDeclaration)
451
+ && self.variables.get(sym.name) === (node_def = sym.definition())
452
+ ) {
453
+ if (node instanceof AST_Assign) {
454
+ node.right.walk(tw);
455
+ if (!node_def.chained && node.left.fixed_value() === node.right) {
456
+ fixed_ids.set(node_def.id, node);
457
+ }
458
+ }
459
+ return true;
460
+ }
461
+ if (node instanceof AST_SymbolRef) {
462
+ node_def = node.definition();
463
+ if (!in_use_ids.has(node_def.id)) {
464
+ in_use_ids.set(node_def.id, node_def);
465
+ if (node_def.orig[0] instanceof AST_SymbolCatch) {
466
+ const redef = node_def.scope.is_block_scope()
467
+ && node_def.scope.get_defun_scope().variables.get(node_def.name);
468
+ if (redef) in_use_ids.set(redef.id, redef);
469
+ }
470
+ }
471
+ return true;
472
+ }
473
+ if (node instanceof AST_Scope) {
474
+ var save_scope = scope;
475
+ scope = node;
476
+ descend();
477
+ scope = save_scope;
478
+ return true;
479
+ }
480
+ }
481
+ });
482
+
@@ -99,6 +99,13 @@ AST_Node.DEFMETHOD("evaluate", function (compressor) {
99
99
  return val;
100
100
  if (typeof val == "function" || typeof val == "object" || val == nullish)
101
101
  return this;
102
+
103
+ // Evaluated strings can be larger than the original expression
104
+ if (typeof val === "string") {
105
+ const unevaluated_size = this.size(compressor);
106
+ if (val.length + 2 > unevaluated_size) return this;
107
+ }
108
+
102
109
  return val;
103
110
  });
104
111