terser 5.15.1 → 5.16.1

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
@@ -2250,6 +2250,29 @@ var AST_ClassPrivateProperty = DEFNODE("ClassPrivateProperty", "", function AST_
2250
2250
  $documentation: "A class property for a private property",
2251
2251
  }, AST_ClassProperty);
2252
2252
 
2253
+ var AST_PrivateIn = DEFNODE("PrivateIn", "key value", function AST_PrivateIn(props) {
2254
+ if (props) {
2255
+ this.key = props.key;
2256
+ this.value = props.value;
2257
+ this.start = props.start;
2258
+ this.end = props.end;
2259
+ }
2260
+
2261
+ this.flags = 0;
2262
+ }, {
2263
+ $documentation: "An `in` binop when the key is private, eg #x in this",
2264
+ _walk: function(visitor) {
2265
+ return visitor._visit(this, function() {
2266
+ this.key._walk(visitor);
2267
+ this.value._walk(visitor);
2268
+ });
2269
+ },
2270
+ _children_backwards(push) {
2271
+ push(this.value);
2272
+ push(this.key);
2273
+ },
2274
+ });
2275
+
2253
2276
  var AST_DefClass = DEFNODE("DefClass", null, function AST_DefClass(props) {
2254
2277
  if (props) {
2255
2278
  this.name = props.name;
@@ -2653,6 +2676,20 @@ var AST_LabelRef = DEFNODE("LabelRef", null, function AST_LabelRef(props) {
2653
2676
  $documentation: "Reference to a label symbol",
2654
2677
  }, AST_Symbol);
2655
2678
 
2679
+ var AST_SymbolPrivateProperty = DEFNODE("SymbolPrivateProperty", null, function AST_SymbolPrivateProperty(props) {
2680
+ if (props) {
2681
+ this.scope = props.scope;
2682
+ this.name = props.name;
2683
+ this.thedef = props.thedef;
2684
+ this.start = props.start;
2685
+ this.end = props.end;
2686
+ }
2687
+
2688
+ this.flags = 0;
2689
+ }, {
2690
+ $documentation: "A symbol that refers to a private property",
2691
+ }, AST_Symbol);
2692
+
2656
2693
  var AST_This = DEFNODE("This", null, function AST_This(props) {
2657
2694
  if (props) {
2658
2695
  this.scope = props.scope;
@@ -3024,8 +3061,9 @@ class TreeWalker {
3024
3061
  }
3025
3062
 
3026
3063
  find_scope() {
3027
- for (let i = 0;;i++) {
3028
- const p = this.parent(i);
3064
+ var stack = this.stack;
3065
+ for (var i = stack.length; --i >= 0;) {
3066
+ const p = stack[i];
3029
3067
  if (p instanceof AST_Toplevel) return p;
3030
3068
  if (p instanceof AST_Lambda) return p;
3031
3069
  if (p.block_scope) return p.block_scope;
@@ -3093,6 +3131,7 @@ export {
3093
3131
  AST_Class,
3094
3132
  AST_ClassExpression,
3095
3133
  AST_ClassPrivateProperty,
3134
+ AST_PrivateIn,
3096
3135
  AST_ClassProperty,
3097
3136
  AST_ClassStaticBlock,
3098
3137
  AST_ConciseMethod,
@@ -3185,6 +3224,7 @@ export {
3185
3224
  AST_SymbolVar,
3186
3225
  AST_TemplateSegment,
3187
3226
  AST_TemplateString,
3227
+ AST_SymbolPrivateProperty,
3188
3228
  AST_This,
3189
3229
  AST_Throw,
3190
3230
  AST_Token,
@@ -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