terser 5.6.0 → 5.7.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.
@@ -0,0 +1,934 @@
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_Array,
46
+ AST_Arrow,
47
+ AST_Assign,
48
+ AST_Binary,
49
+ AST_Block,
50
+ AST_BlockStatement,
51
+ AST_Call,
52
+ AST_Case,
53
+ AST_Chain,
54
+ AST_Class,
55
+ AST_ClassProperty,
56
+ AST_ConciseMethod,
57
+ AST_Conditional,
58
+ AST_Constant,
59
+ AST_Definitions,
60
+ AST_Dot,
61
+ AST_EmptyStatement,
62
+ AST_Expansion,
63
+ AST_False,
64
+ AST_Function,
65
+ AST_If,
66
+ AST_Import,
67
+ AST_Jump,
68
+ AST_LabeledStatement,
69
+ AST_Lambda,
70
+ AST_New,
71
+ AST_Node,
72
+ AST_Null,
73
+ AST_Number,
74
+ AST_Object,
75
+ AST_ObjectGetter,
76
+ AST_ObjectKeyVal,
77
+ AST_ObjectProperty,
78
+ AST_ObjectSetter,
79
+ AST_PropAccess,
80
+ AST_RegExp,
81
+ AST_Return,
82
+ AST_Sequence,
83
+ AST_SimpleStatement,
84
+ AST_Statement,
85
+ AST_String,
86
+ AST_Sub,
87
+ AST_Switch,
88
+ AST_SwitchBranch,
89
+ AST_SymbolClassProperty,
90
+ AST_SymbolDeclaration,
91
+ AST_SymbolRef,
92
+ AST_TemplateSegment,
93
+ AST_TemplateString,
94
+ AST_This,
95
+ AST_Toplevel,
96
+ AST_True,
97
+ AST_Try,
98
+ AST_Unary,
99
+ AST_UnaryPostfix,
100
+ AST_UnaryPrefix,
101
+ AST_Undefined,
102
+ AST_VarDef,
103
+
104
+ TreeTransformer,
105
+ walk,
106
+ walk_abort,
107
+
108
+ _PURE
109
+ } from "../ast.js";
110
+ import {
111
+ makePredicate,
112
+ return_true,
113
+ return_false,
114
+ return_null,
115
+ return_this,
116
+ make_node,
117
+ member,
118
+ noop,
119
+ has_annotation,
120
+ HOP
121
+ } from "../utils/index.js";
122
+ import { make_node_from_constant, make_sequence, best_of_expression, read_property } from "./common.js";
123
+
124
+ import { INLINED, UNDEFINED, has_flag } from "./compressor-flags.js";
125
+ import { pure_prop_access_globals, is_pure_native_fn, is_pure_native_method } from "./native-objects.js";
126
+
127
+ // Functions and methods to infer certain facts about expressions
128
+ // It's not always possible to be 100% sure about something just by static analysis,
129
+ // so `true` means yes, and `false` means maybe
130
+
131
+ export const is_undeclared_ref = (node) =>
132
+ node instanceof AST_SymbolRef && node.definition().undeclared;
133
+
134
+ export const lazy_op = makePredicate("&& || ??");
135
+ export const unary_side_effects = makePredicate("delete ++ --");
136
+
137
+ // methods to determine whether an expression has a boolean result type
138
+ (function(def_is_boolean) {
139
+ const unary_bool = makePredicate("! delete");
140
+ const binary_bool = makePredicate("in instanceof == != === !== < <= >= >");
141
+ def_is_boolean(AST_Node, return_false);
142
+ def_is_boolean(AST_UnaryPrefix, function() {
143
+ return unary_bool.has(this.operator);
144
+ });
145
+ def_is_boolean(AST_Binary, function() {
146
+ return binary_bool.has(this.operator)
147
+ || lazy_op.has(this.operator)
148
+ && this.left.is_boolean()
149
+ && this.right.is_boolean();
150
+ });
151
+ def_is_boolean(AST_Conditional, function() {
152
+ return this.consequent.is_boolean() && this.alternative.is_boolean();
153
+ });
154
+ def_is_boolean(AST_Assign, function() {
155
+ return this.operator == "=" && this.right.is_boolean();
156
+ });
157
+ def_is_boolean(AST_Sequence, function() {
158
+ return this.tail_node().is_boolean();
159
+ });
160
+ def_is_boolean(AST_True, return_true);
161
+ def_is_boolean(AST_False, return_true);
162
+ })(function(node, func) {
163
+ node.DEFMETHOD("is_boolean", func);
164
+ });
165
+
166
+ // methods to determine if an expression has a numeric result type
167
+ (function(def_is_number) {
168
+ def_is_number(AST_Node, return_false);
169
+ def_is_number(AST_Number, return_true);
170
+ const unary = makePredicate("+ - ~ ++ --");
171
+ def_is_number(AST_Unary, function() {
172
+ return unary.has(this.operator);
173
+ });
174
+ const numeric_ops = makePredicate("- * / % & | ^ << >> >>>");
175
+ def_is_number(AST_Binary, function(compressor) {
176
+ return numeric_ops.has(this.operator) || this.operator == "+"
177
+ && this.left.is_number(compressor)
178
+ && this.right.is_number(compressor);
179
+ });
180
+ def_is_number(AST_Assign, function(compressor) {
181
+ return numeric_ops.has(this.operator.slice(0, -1))
182
+ || this.operator == "=" && this.right.is_number(compressor);
183
+ });
184
+ def_is_number(AST_Sequence, function(compressor) {
185
+ return this.tail_node().is_number(compressor);
186
+ });
187
+ def_is_number(AST_Conditional, function(compressor) {
188
+ return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
189
+ });
190
+ })(function(node, func) {
191
+ node.DEFMETHOD("is_number", func);
192
+ });
193
+
194
+ // methods to determine if an expression has a string result type
195
+ (function(def_is_string) {
196
+ def_is_string(AST_Node, return_false);
197
+ def_is_string(AST_String, return_true);
198
+ def_is_string(AST_TemplateString, return_true);
199
+ def_is_string(AST_UnaryPrefix, function() {
200
+ return this.operator == "typeof";
201
+ });
202
+ def_is_string(AST_Binary, function(compressor) {
203
+ return this.operator == "+" &&
204
+ (this.left.is_string(compressor) || this.right.is_string(compressor));
205
+ });
206
+ def_is_string(AST_Assign, function(compressor) {
207
+ return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
208
+ });
209
+ def_is_string(AST_Sequence, function(compressor) {
210
+ return this.tail_node().is_string(compressor);
211
+ });
212
+ def_is_string(AST_Conditional, function(compressor) {
213
+ return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
214
+ });
215
+ })(function(node, func) {
216
+ node.DEFMETHOD("is_string", func);
217
+ });
218
+
219
+ export function is_undefined(node, compressor) {
220
+ return (
221
+ has_flag(node, UNDEFINED)
222
+ || node instanceof AST_Undefined
223
+ || node instanceof AST_UnaryPrefix
224
+ && node.operator == "void"
225
+ && !node.expression.has_side_effects(compressor)
226
+ );
227
+ }
228
+
229
+ // Find out if something is == null
230
+ // Used to optimize ?. and ??
231
+ export function is_nullish(node, compressor) {
232
+ let fixed;
233
+ return (
234
+ node instanceof AST_Null
235
+ || is_undefined(node, compressor)
236
+ || (
237
+ node instanceof AST_SymbolRef
238
+ && (fixed = node.definition().fixed) instanceof AST_Node
239
+ && is_nullish(fixed, compressor)
240
+ )
241
+ // Recurse into those optional chains!
242
+ || node instanceof AST_PropAccess && node.optional && is_nullish(node.expression, compressor)
243
+ || node instanceof AST_Call && node.optional && is_nullish(node.expression, compressor)
244
+ || node instanceof AST_Chain && is_nullish(node.expression, compressor)
245
+ );
246
+ }
247
+
248
+ // Determine if expression might cause side effects
249
+ // If there's a possibility that a node may change something when it's executed, this returns true
250
+ (function(def_has_side_effects) {
251
+ def_has_side_effects(AST_Node, return_true);
252
+
253
+ def_has_side_effects(AST_EmptyStatement, return_false);
254
+ def_has_side_effects(AST_Constant, return_false);
255
+ def_has_side_effects(AST_This, return_false);
256
+
257
+ function any(list, compressor) {
258
+ for (var i = list.length; --i >= 0;)
259
+ if (list[i].has_side_effects(compressor))
260
+ return true;
261
+ return false;
262
+ }
263
+
264
+ def_has_side_effects(AST_Block, function(compressor) {
265
+ return any(this.body, compressor);
266
+ });
267
+ def_has_side_effects(AST_Call, function(compressor) {
268
+ if (
269
+ !this.is_callee_pure(compressor)
270
+ && (!this.expression.is_call_pure(compressor)
271
+ || this.expression.has_side_effects(compressor))
272
+ ) {
273
+ return true;
274
+ }
275
+ return any(this.args, compressor);
276
+ });
277
+ def_has_side_effects(AST_Switch, function(compressor) {
278
+ return this.expression.has_side_effects(compressor)
279
+ || any(this.body, compressor);
280
+ });
281
+ def_has_side_effects(AST_Case, function(compressor) {
282
+ return this.expression.has_side_effects(compressor)
283
+ || any(this.body, compressor);
284
+ });
285
+ def_has_side_effects(AST_Try, function(compressor) {
286
+ return any(this.body, compressor)
287
+ || this.bcatch && this.bcatch.has_side_effects(compressor)
288
+ || this.bfinally && this.bfinally.has_side_effects(compressor);
289
+ });
290
+ def_has_side_effects(AST_If, function(compressor) {
291
+ return this.condition.has_side_effects(compressor)
292
+ || this.body && this.body.has_side_effects(compressor)
293
+ || this.alternative && this.alternative.has_side_effects(compressor);
294
+ });
295
+ def_has_side_effects(AST_LabeledStatement, function(compressor) {
296
+ return this.body.has_side_effects(compressor);
297
+ });
298
+ def_has_side_effects(AST_SimpleStatement, function(compressor) {
299
+ return this.body.has_side_effects(compressor);
300
+ });
301
+ def_has_side_effects(AST_Lambda, return_false);
302
+ def_has_side_effects(AST_Class, function (compressor) {
303
+ if (this.extends && this.extends.has_side_effects(compressor)) {
304
+ return true;
305
+ }
306
+ return any(this.properties, compressor);
307
+ });
308
+ def_has_side_effects(AST_Binary, function(compressor) {
309
+ return this.left.has_side_effects(compressor)
310
+ || this.right.has_side_effects(compressor);
311
+ });
312
+ def_has_side_effects(AST_Assign, return_true);
313
+ def_has_side_effects(AST_Conditional, function(compressor) {
314
+ return this.condition.has_side_effects(compressor)
315
+ || this.consequent.has_side_effects(compressor)
316
+ || this.alternative.has_side_effects(compressor);
317
+ });
318
+ def_has_side_effects(AST_Unary, function(compressor) {
319
+ return unary_side_effects.has(this.operator)
320
+ || this.expression.has_side_effects(compressor);
321
+ });
322
+ def_has_side_effects(AST_SymbolRef, function(compressor) {
323
+ return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
324
+ });
325
+ def_has_side_effects(AST_SymbolClassProperty, return_false);
326
+ def_has_side_effects(AST_SymbolDeclaration, return_false);
327
+ def_has_side_effects(AST_Object, function(compressor) {
328
+ return any(this.properties, compressor);
329
+ });
330
+ def_has_side_effects(AST_ObjectProperty, function(compressor) {
331
+ return (
332
+ this.computed_key() && this.key.has_side_effects(compressor)
333
+ || this.value && this.value.has_side_effects(compressor)
334
+ );
335
+ });
336
+ def_has_side_effects(AST_ClassProperty, function(compressor) {
337
+ return (
338
+ this.computed_key() && this.key.has_side_effects(compressor)
339
+ || this.static && this.value && this.value.has_side_effects(compressor)
340
+ );
341
+ });
342
+ def_has_side_effects(AST_ConciseMethod, function(compressor) {
343
+ return this.computed_key() && this.key.has_side_effects(compressor);
344
+ });
345
+ def_has_side_effects(AST_ObjectGetter, function(compressor) {
346
+ return this.computed_key() && this.key.has_side_effects(compressor);
347
+ });
348
+ def_has_side_effects(AST_ObjectSetter, function(compressor) {
349
+ return this.computed_key() && this.key.has_side_effects(compressor);
350
+ });
351
+ def_has_side_effects(AST_Array, function(compressor) {
352
+ return any(this.elements, compressor);
353
+ });
354
+ def_has_side_effects(AST_Dot, function(compressor) {
355
+ return !this.optional && this.expression.may_throw_on_access(compressor)
356
+ || this.expression.has_side_effects(compressor);
357
+ });
358
+ def_has_side_effects(AST_Sub, function(compressor) {
359
+ if (this.optional && is_nullish(this.expression, compressor)) {
360
+ return false;
361
+ }
362
+
363
+ return !this.optional && this.expression.may_throw_on_access(compressor)
364
+ || this.expression.has_side_effects(compressor)
365
+ || this.property.has_side_effects(compressor);
366
+ });
367
+ def_has_side_effects(AST_Chain, function (compressor) {
368
+ return this.expression.has_side_effects(compressor);
369
+ });
370
+ def_has_side_effects(AST_Sequence, function(compressor) {
371
+ return any(this.expressions, compressor);
372
+ });
373
+ def_has_side_effects(AST_Definitions, function(compressor) {
374
+ return any(this.definitions, compressor);
375
+ });
376
+ def_has_side_effects(AST_VarDef, function() {
377
+ return this.value;
378
+ });
379
+ def_has_side_effects(AST_TemplateSegment, return_false);
380
+ def_has_side_effects(AST_TemplateString, function(compressor) {
381
+ return any(this.segments, compressor);
382
+ });
383
+ })(function(node, func) {
384
+ node.DEFMETHOD("has_side_effects", func);
385
+ });
386
+
387
+ // determine if expression may throw
388
+ (function(def_may_throw) {
389
+ def_may_throw(AST_Node, return_true);
390
+
391
+ def_may_throw(AST_Constant, return_false);
392
+ def_may_throw(AST_EmptyStatement, return_false);
393
+ def_may_throw(AST_Lambda, return_false);
394
+ def_may_throw(AST_SymbolDeclaration, return_false);
395
+ def_may_throw(AST_This, return_false);
396
+
397
+ function any(list, compressor) {
398
+ for (var i = list.length; --i >= 0;)
399
+ if (list[i].may_throw(compressor))
400
+ return true;
401
+ return false;
402
+ }
403
+
404
+ def_may_throw(AST_Class, function(compressor) {
405
+ if (this.extends && this.extends.may_throw(compressor)) return true;
406
+ return any(this.properties, compressor);
407
+ });
408
+
409
+ def_may_throw(AST_Array, function(compressor) {
410
+ return any(this.elements, compressor);
411
+ });
412
+ def_may_throw(AST_Assign, function(compressor) {
413
+ if (this.right.may_throw(compressor)) return true;
414
+ if (!compressor.has_directive("use strict")
415
+ && this.operator == "="
416
+ && this.left instanceof AST_SymbolRef) {
417
+ return false;
418
+ }
419
+ return this.left.may_throw(compressor);
420
+ });
421
+ def_may_throw(AST_Binary, function(compressor) {
422
+ return this.left.may_throw(compressor)
423
+ || this.right.may_throw(compressor);
424
+ });
425
+ def_may_throw(AST_Block, function(compressor) {
426
+ return any(this.body, compressor);
427
+ });
428
+ def_may_throw(AST_Call, function(compressor) {
429
+ if (this.optional && is_nullish(this.expression, compressor)) return false;
430
+ if (any(this.args, compressor)) return true;
431
+ if (this.is_callee_pure(compressor)) return false;
432
+ if (this.expression.may_throw(compressor)) return true;
433
+ return !(this.expression instanceof AST_Lambda)
434
+ || any(this.expression.body, compressor);
435
+ });
436
+ def_may_throw(AST_Case, function(compressor) {
437
+ return this.expression.may_throw(compressor)
438
+ || any(this.body, compressor);
439
+ });
440
+ def_may_throw(AST_Conditional, function(compressor) {
441
+ return this.condition.may_throw(compressor)
442
+ || this.consequent.may_throw(compressor)
443
+ || this.alternative.may_throw(compressor);
444
+ });
445
+ def_may_throw(AST_Definitions, function(compressor) {
446
+ return any(this.definitions, compressor);
447
+ });
448
+ def_may_throw(AST_If, function(compressor) {
449
+ return this.condition.may_throw(compressor)
450
+ || this.body && this.body.may_throw(compressor)
451
+ || this.alternative && this.alternative.may_throw(compressor);
452
+ });
453
+ def_may_throw(AST_LabeledStatement, function(compressor) {
454
+ return this.body.may_throw(compressor);
455
+ });
456
+ def_may_throw(AST_Object, function(compressor) {
457
+ return any(this.properties, compressor);
458
+ });
459
+ def_may_throw(AST_ObjectProperty, function(compressor) {
460
+ // TODO key may throw too
461
+ return this.value ? this.value.may_throw(compressor) : false;
462
+ });
463
+ def_may_throw(AST_ClassProperty, function(compressor) {
464
+ return (
465
+ this.computed_key() && this.key.may_throw(compressor)
466
+ || this.static && this.value && this.value.may_throw(compressor)
467
+ );
468
+ });
469
+ def_may_throw(AST_ConciseMethod, function(compressor) {
470
+ return this.computed_key() && this.key.may_throw(compressor);
471
+ });
472
+ def_may_throw(AST_ObjectGetter, function(compressor) {
473
+ return this.computed_key() && this.key.may_throw(compressor);
474
+ });
475
+ def_may_throw(AST_ObjectSetter, function(compressor) {
476
+ return this.computed_key() && this.key.may_throw(compressor);
477
+ });
478
+ def_may_throw(AST_Return, function(compressor) {
479
+ return this.value && this.value.may_throw(compressor);
480
+ });
481
+ def_may_throw(AST_Sequence, function(compressor) {
482
+ return any(this.expressions, compressor);
483
+ });
484
+ def_may_throw(AST_SimpleStatement, function(compressor) {
485
+ return this.body.may_throw(compressor);
486
+ });
487
+ def_may_throw(AST_Dot, function(compressor) {
488
+ return !this.optional && this.expression.may_throw_on_access(compressor)
489
+ || this.expression.may_throw(compressor);
490
+ });
491
+ def_may_throw(AST_Sub, function(compressor) {
492
+ if (this.optional && is_nullish(this.expression, compressor)) return false;
493
+
494
+ return !this.optional && this.expression.may_throw_on_access(compressor)
495
+ || this.expression.may_throw(compressor)
496
+ || this.property.may_throw(compressor);
497
+ });
498
+ def_may_throw(AST_Chain, function(compressor) {
499
+ return this.expression.may_throw(compressor);
500
+ });
501
+ def_may_throw(AST_Switch, function(compressor) {
502
+ return this.expression.may_throw(compressor)
503
+ || any(this.body, compressor);
504
+ });
505
+ def_may_throw(AST_SymbolRef, function(compressor) {
506
+ return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
507
+ });
508
+ def_may_throw(AST_SymbolClassProperty, return_false);
509
+ def_may_throw(AST_Try, function(compressor) {
510
+ return this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor)
511
+ || this.bfinally && this.bfinally.may_throw(compressor);
512
+ });
513
+ def_may_throw(AST_Unary, function(compressor) {
514
+ if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
515
+ return false;
516
+ return this.expression.may_throw(compressor);
517
+ });
518
+ def_may_throw(AST_VarDef, function(compressor) {
519
+ if (!this.value) return false;
520
+ return this.value.may_throw(compressor);
521
+ });
522
+ })(function(node, func) {
523
+ node.DEFMETHOD("may_throw", func);
524
+ });
525
+
526
+ // determine if expression is constant
527
+ (function(def_is_constant_expression) {
528
+ function all_refs_local(scope) {
529
+ let result = true;
530
+ walk(this, node => {
531
+ if (node instanceof AST_SymbolRef) {
532
+ if (has_flag(this, INLINED)) {
533
+ result = false;
534
+ return walk_abort;
535
+ }
536
+ var def = node.definition();
537
+ if (
538
+ member(def, this.enclosed)
539
+ && !this.variables.has(def.name)
540
+ ) {
541
+ if (scope) {
542
+ var scope_def = scope.find_variable(node);
543
+ if (def.undeclared ? !scope_def : scope_def === def) {
544
+ result = "f";
545
+ return true;
546
+ }
547
+ }
548
+ result = false;
549
+ return walk_abort;
550
+ }
551
+ return true;
552
+ }
553
+ if (node instanceof AST_This && this instanceof AST_Arrow) {
554
+ // TODO check arguments too!
555
+ result = false;
556
+ return walk_abort;
557
+ }
558
+ });
559
+ return result;
560
+ }
561
+
562
+ def_is_constant_expression(AST_Node, return_false);
563
+ def_is_constant_expression(AST_Constant, return_true);
564
+ def_is_constant_expression(AST_Class, function(scope) {
565
+ if (this.extends && !this.extends.is_constant_expression(scope)) {
566
+ return false;
567
+ }
568
+
569
+ for (const prop of this.properties) {
570
+ if (prop.computed_key() && !prop.key.is_constant_expression(scope)) {
571
+ return false;
572
+ }
573
+ if (prop.static && prop.value && !prop.value.is_constant_expression(scope)) {
574
+ return false;
575
+ }
576
+ }
577
+
578
+ return all_refs_local.call(this, scope);
579
+ });
580
+ def_is_constant_expression(AST_Lambda, all_refs_local);
581
+ def_is_constant_expression(AST_Unary, function() {
582
+ return this.expression.is_constant_expression();
583
+ });
584
+ def_is_constant_expression(AST_Binary, function() {
585
+ return this.left.is_constant_expression()
586
+ && this.right.is_constant_expression();
587
+ });
588
+ def_is_constant_expression(AST_Array, function() {
589
+ return this.elements.every((l) => l.is_constant_expression());
590
+ });
591
+ def_is_constant_expression(AST_Object, function() {
592
+ return this.properties.every((l) => l.is_constant_expression());
593
+ });
594
+ def_is_constant_expression(AST_ObjectProperty, function() {
595
+ return !!(!(this.key instanceof AST_Node) && this.value && this.value.is_constant_expression());
596
+ });
597
+ })(function(node, func) {
598
+ node.DEFMETHOD("is_constant_expression", func);
599
+ });
600
+
601
+
602
+ // may_throw_on_access()
603
+ // returns true if this node may be null, undefined or contain `AST_Accessor`
604
+ (function(def_may_throw_on_access) {
605
+ AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
606
+ return !compressor.option("pure_getters")
607
+ || this._dot_throw(compressor);
608
+ });
609
+
610
+ function is_strict(compressor) {
611
+ return /strict/.test(compressor.option("pure_getters"));
612
+ }
613
+
614
+ def_may_throw_on_access(AST_Node, is_strict);
615
+ def_may_throw_on_access(AST_Null, return_true);
616
+ def_may_throw_on_access(AST_Undefined, return_true);
617
+ def_may_throw_on_access(AST_Constant, return_false);
618
+ def_may_throw_on_access(AST_Array, return_false);
619
+ def_may_throw_on_access(AST_Object, function(compressor) {
620
+ if (!is_strict(compressor)) return false;
621
+ for (var i = this.properties.length; --i >=0;)
622
+ if (this.properties[i]._dot_throw(compressor)) return true;
623
+ return false;
624
+ });
625
+ // Do not be as strict with classes as we are with objects.
626
+ // Hopefully the community is not going to abuse static getters and setters.
627
+ // https://github.com/terser/terser/issues/724#issuecomment-643655656
628
+ def_may_throw_on_access(AST_Class, return_false);
629
+ def_may_throw_on_access(AST_ObjectProperty, return_false);
630
+ def_may_throw_on_access(AST_ObjectGetter, return_true);
631
+ def_may_throw_on_access(AST_Expansion, function(compressor) {
632
+ return this.expression._dot_throw(compressor);
633
+ });
634
+ def_may_throw_on_access(AST_Function, return_false);
635
+ def_may_throw_on_access(AST_Arrow, return_false);
636
+ def_may_throw_on_access(AST_UnaryPostfix, return_false);
637
+ def_may_throw_on_access(AST_UnaryPrefix, function() {
638
+ return this.operator == "void";
639
+ });
640
+ def_may_throw_on_access(AST_Binary, function(compressor) {
641
+ return (this.operator == "&&" || this.operator == "||" || this.operator == "??")
642
+ && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
643
+ });
644
+ def_may_throw_on_access(AST_Assign, function(compressor) {
645
+ if (this.logical) return true;
646
+
647
+ return this.operator == "="
648
+ && this.right._dot_throw(compressor);
649
+ });
650
+ def_may_throw_on_access(AST_Conditional, function(compressor) {
651
+ return this.consequent._dot_throw(compressor)
652
+ || this.alternative._dot_throw(compressor);
653
+ });
654
+ def_may_throw_on_access(AST_Dot, function(compressor) {
655
+ if (!is_strict(compressor)) return false;
656
+
657
+ if (this.property == "prototype") {
658
+ return !(
659
+ this.expression instanceof AST_Function
660
+ || this.expression instanceof AST_Class
661
+ );
662
+ }
663
+ return true;
664
+ });
665
+ def_may_throw_on_access(AST_Chain, function(compressor) {
666
+ return this.expression._dot_throw(compressor);
667
+ });
668
+ def_may_throw_on_access(AST_Sequence, function(compressor) {
669
+ return this.tail_node()._dot_throw(compressor);
670
+ });
671
+ def_may_throw_on_access(AST_SymbolRef, function(compressor) {
672
+ if (this.name === "arguments") return false;
673
+ if (has_flag(this, UNDEFINED)) return true;
674
+ if (!is_strict(compressor)) return false;
675
+ if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
676
+ if (this.is_immutable()) return false;
677
+ var fixed = this.fixed_value();
678
+ return !fixed || fixed._dot_throw(compressor);
679
+ });
680
+ })(function(node, func) {
681
+ node.DEFMETHOD("_dot_throw", func);
682
+ });
683
+
684
+ export function is_lhs(node, parent) {
685
+ if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
686
+ if (parent instanceof AST_Assign && parent.left === node) return node;
687
+ }
688
+
689
+ (function(def_find_defs) {
690
+ function to_node(value, orig) {
691
+ if (value instanceof AST_Node) {
692
+ if (!(value instanceof AST_Constant)) {
693
+ // Value may be a function, an array including functions and even a complex assign / block expression,
694
+ // so it should never be shared in different places.
695
+ // Otherwise wrong information may be used in the compression phase
696
+ value = value.clone(true);
697
+ }
698
+ return make_node(value.CTOR, orig, value);
699
+ }
700
+ if (Array.isArray(value)) return make_node(AST_Array, orig, {
701
+ elements: value.map(function(value) {
702
+ return to_node(value, orig);
703
+ })
704
+ });
705
+ if (value && typeof value == "object") {
706
+ var props = [];
707
+ for (var key in value) if (HOP(value, key)) {
708
+ props.push(make_node(AST_ObjectKeyVal, orig, {
709
+ key: key,
710
+ value: to_node(value[key], orig)
711
+ }));
712
+ }
713
+ return make_node(AST_Object, orig, {
714
+ properties: props
715
+ });
716
+ }
717
+ return make_node_from_constant(value, orig);
718
+ }
719
+
720
+ AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) {
721
+ if (!compressor.option("global_defs")) return this;
722
+ this.figure_out_scope({ ie8: compressor.option("ie8") });
723
+ return this.transform(new TreeTransformer(function(node) {
724
+ var def = node._find_defs(compressor, "");
725
+ if (!def) return;
726
+ var level = 0, child = node, parent;
727
+ while (parent = this.parent(level++)) {
728
+ if (!(parent instanceof AST_PropAccess)) break;
729
+ if (parent.expression !== child) break;
730
+ child = parent;
731
+ }
732
+ if (is_lhs(child, parent)) {
733
+ return;
734
+ }
735
+ return def;
736
+ }));
737
+ });
738
+ def_find_defs(AST_Node, noop);
739
+ def_find_defs(AST_Chain, function(compressor, suffix) {
740
+ return this.expression._find_defs(compressor, suffix);
741
+ });
742
+ def_find_defs(AST_Dot, function(compressor, suffix) {
743
+ return this.expression._find_defs(compressor, "." + this.property + suffix);
744
+ });
745
+ def_find_defs(AST_SymbolDeclaration, function() {
746
+ if (!this.global()) return;
747
+ });
748
+ def_find_defs(AST_SymbolRef, function(compressor, suffix) {
749
+ if (!this.global()) return;
750
+ var defines = compressor.option("global_defs");
751
+ var name = this.name + suffix;
752
+ if (HOP(defines, name)) return to_node(defines[name], this);
753
+ });
754
+ })(function(node, func) {
755
+ node.DEFMETHOD("_find_defs", func);
756
+ });
757
+
758
+ // method to negate an expression
759
+ (function(def_negate) {
760
+ function basic_negation(exp) {
761
+ return make_node(AST_UnaryPrefix, exp, {
762
+ operator: "!",
763
+ expression: exp
764
+ });
765
+ }
766
+ function best(orig, alt, first_in_statement) {
767
+ var negated = basic_negation(orig);
768
+ if (first_in_statement) {
769
+ var stat = make_node(AST_SimpleStatement, alt, {
770
+ body: alt
771
+ });
772
+ return best_of_expression(negated, stat) === stat ? alt : negated;
773
+ }
774
+ return best_of_expression(negated, alt);
775
+ }
776
+ def_negate(AST_Node, function() {
777
+ return basic_negation(this);
778
+ });
779
+ def_negate(AST_Statement, function() {
780
+ throw new Error("Cannot negate a statement");
781
+ });
782
+ def_negate(AST_Function, function() {
783
+ return basic_negation(this);
784
+ });
785
+ def_negate(AST_Arrow, function() {
786
+ return basic_negation(this);
787
+ });
788
+ def_negate(AST_UnaryPrefix, function() {
789
+ if (this.operator == "!")
790
+ return this.expression;
791
+ return basic_negation(this);
792
+ });
793
+ def_negate(AST_Sequence, function(compressor) {
794
+ var expressions = this.expressions.slice();
795
+ expressions.push(expressions.pop().negate(compressor));
796
+ return make_sequence(this, expressions);
797
+ });
798
+ def_negate(AST_Conditional, function(compressor, first_in_statement) {
799
+ var self = this.clone();
800
+ self.consequent = self.consequent.negate(compressor);
801
+ self.alternative = self.alternative.negate(compressor);
802
+ return best(this, self, first_in_statement);
803
+ });
804
+ def_negate(AST_Binary, function(compressor, first_in_statement) {
805
+ var self = this.clone(), op = this.operator;
806
+ if (compressor.option("unsafe_comps")) {
807
+ switch (op) {
808
+ case "<=" : self.operator = ">" ; return self;
809
+ case "<" : self.operator = ">=" ; return self;
810
+ case ">=" : self.operator = "<" ; return self;
811
+ case ">" : self.operator = "<=" ; return self;
812
+ }
813
+ }
814
+ switch (op) {
815
+ case "==" : self.operator = "!="; return self;
816
+ case "!=" : self.operator = "=="; return self;
817
+ case "===": self.operator = "!=="; return self;
818
+ case "!==": self.operator = "==="; return self;
819
+ case "&&":
820
+ self.operator = "||";
821
+ self.left = self.left.negate(compressor, first_in_statement);
822
+ self.right = self.right.negate(compressor);
823
+ return best(this, self, first_in_statement);
824
+ case "||":
825
+ self.operator = "&&";
826
+ self.left = self.left.negate(compressor, first_in_statement);
827
+ self.right = self.right.negate(compressor);
828
+ return best(this, self, first_in_statement);
829
+ }
830
+ return basic_negation(this);
831
+ });
832
+ })(function(node, func) {
833
+ node.DEFMETHOD("negate", function(compressor, first_in_statement) {
834
+ return func.call(this, compressor, first_in_statement);
835
+ });
836
+ });
837
+
838
+ // Is the callee of this function pure?
839
+ var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
840
+ AST_Call.DEFMETHOD("is_callee_pure", function(compressor) {
841
+ if (compressor.option("unsafe")) {
842
+ var expr = this.expression;
843
+ var first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor));
844
+ if (
845
+ expr.expression && expr.expression.name === "hasOwnProperty" &&
846
+ (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)
847
+ ) {
848
+ return false;
849
+ }
850
+ if (is_undeclared_ref(expr) && global_pure_fns.has(expr.name)) return true;
851
+ if (
852
+ expr instanceof AST_Dot
853
+ && is_undeclared_ref(expr.expression)
854
+ && is_pure_native_fn(expr.expression.name, expr.property)
855
+ ) {
856
+ return true;
857
+ }
858
+ }
859
+ return !!has_annotation(this, _PURE) || !compressor.pure_funcs(this);
860
+ });
861
+
862
+ // If I call this, is it a pure function?
863
+ AST_Node.DEFMETHOD("is_call_pure", return_false);
864
+ AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
865
+ if (!compressor.option("unsafe")) return;
866
+ const expr = this.expression;
867
+
868
+ let native_obj;
869
+ if (expr instanceof AST_Array) {
870
+ native_obj = "Array";
871
+ } else if (expr.is_boolean()) {
872
+ native_obj = "Boolean";
873
+ } else if (expr.is_number(compressor)) {
874
+ native_obj = "Number";
875
+ } else if (expr instanceof AST_RegExp) {
876
+ native_obj = "RegExp";
877
+ } else if (expr.is_string(compressor)) {
878
+ native_obj = "String";
879
+ } else if (!this.may_throw_on_access(compressor)) {
880
+ native_obj = "Object";
881
+ }
882
+ return native_obj != null && is_pure_native_method(native_obj, this.property);
883
+ });
884
+
885
+ // tell me if a statement aborts
886
+ export const aborts = (thing) => thing && thing.aborts();
887
+
888
+ (function(def_aborts) {
889
+ def_aborts(AST_Statement, return_null);
890
+ def_aborts(AST_Jump, return_this);
891
+ function block_aborts() {
892
+ for (var i = 0; i < this.body.length; i++) {
893
+ if (aborts(this.body[i])) {
894
+ return this.body[i];
895
+ }
896
+ }
897
+ return null;
898
+ }
899
+ def_aborts(AST_Import, function() { return null; });
900
+ def_aborts(AST_BlockStatement, block_aborts);
901
+ def_aborts(AST_SwitchBranch, block_aborts);
902
+ def_aborts(AST_If, function() {
903
+ return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
904
+ });
905
+ })(function(node, func) {
906
+ node.DEFMETHOD("aborts", func);
907
+ });
908
+
909
+ export function is_modified(compressor, tw, node, value, level, immutable) {
910
+ var parent = tw.parent(level);
911
+ var lhs = is_lhs(node, parent);
912
+ if (lhs) return lhs;
913
+ if (!immutable
914
+ && parent instanceof AST_Call
915
+ && parent.expression === node
916
+ && !(value instanceof AST_Arrow)
917
+ && !(value instanceof AST_Class)
918
+ && !parent.is_callee_pure(compressor)
919
+ && (!(value instanceof AST_Function)
920
+ || !(parent instanceof AST_New) && value.contains_this())) {
921
+ return true;
922
+ }
923
+ if (parent instanceof AST_Array) {
924
+ return is_modified(compressor, tw, parent, parent, level + 1);
925
+ }
926
+ if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
927
+ var obj = tw.parent(level + 1);
928
+ return is_modified(compressor, tw, obj, obj, level + 2);
929
+ }
930
+ if (parent instanceof AST_PropAccess && parent.expression === node) {
931
+ var prop = read_property(value, parent.property);
932
+ return !immutable && is_modified(compressor, tw, parent, prop, level + 1);
933
+ }
934
+ }