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.
@@ -0,0 +1,641 @@
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_Assign,
47
+ AST_Block,
48
+ AST_Call,
49
+ AST_Catch,
50
+ AST_Class,
51
+ AST_ClassExpression,
52
+ AST_DefaultAssign,
53
+ AST_DefClass,
54
+ AST_Defun,
55
+ AST_Destructuring,
56
+ AST_EmptyStatement,
57
+ AST_Expansion,
58
+ AST_Export,
59
+ AST_Function,
60
+ AST_Infinity,
61
+ AST_IterationStatement,
62
+ AST_Lambda,
63
+ AST_NaN,
64
+ AST_Node,
65
+ AST_Number,
66
+ AST_Object,
67
+ AST_ObjectKeyVal,
68
+ AST_PropAccess,
69
+ AST_Return,
70
+ AST_Scope,
71
+ AST_SimpleStatement,
72
+ AST_Statement,
73
+ AST_SymbolDefun,
74
+ AST_SymbolFunarg,
75
+ AST_SymbolLambda,
76
+ AST_SymbolRef,
77
+ AST_SymbolVar,
78
+ AST_This,
79
+ AST_Toplevel,
80
+ AST_UnaryPrefix,
81
+ AST_Undefined,
82
+ AST_Var,
83
+ AST_VarDef,
84
+ AST_With,
85
+
86
+ walk,
87
+
88
+ _INLINE,
89
+ _NOINLINE,
90
+ _PURE
91
+ } from "../ast.js";
92
+ import { make_node, has_annotation } from "../utils/index.js";
93
+ import "../size.js";
94
+
95
+ import "./evaluate.js";
96
+ import "./drop-side-effect-free.js";
97
+ import "./reduce-vars.js";
98
+ import { is_undeclared_ref, is_lhs } from "./inference.js";
99
+ import {
100
+ SQUEEZED,
101
+ INLINED,
102
+ UNUSED,
103
+
104
+ has_flag,
105
+ set_flag,
106
+ } from "./compressor-flags.js";
107
+ import {
108
+ make_sequence,
109
+ best_of,
110
+ make_node_from_constant,
111
+ identifier_atom,
112
+ is_empty,
113
+ is_func_expr,
114
+ is_iife_call,
115
+ is_reachable,
116
+ is_recursive_ref,
117
+ retain_top_func,
118
+ } from "./common.js";
119
+
120
+
121
+ function within_array_or_object_literal(compressor) {
122
+ var node, level = 0;
123
+ while (node = compressor.parent(level++)) {
124
+ if (node instanceof AST_Statement) return false;
125
+ if (node instanceof AST_Array
126
+ || node instanceof AST_ObjectKeyVal
127
+ || node instanceof AST_Object) {
128
+ return true;
129
+ }
130
+ }
131
+ return false;
132
+ }
133
+
134
+ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
135
+ for (const enclosed of pulled_scope.enclosed) {
136
+ if (pulled_scope.variables.has(enclosed.name)) {
137
+ continue;
138
+ }
139
+ const looked_up = scope.find_variable(enclosed.name);
140
+ if (looked_up) {
141
+ if (looked_up === enclosed) continue;
142
+ return true;
143
+ }
144
+ }
145
+ return false;
146
+ }
147
+
148
+ export function inline_into_symbolref(self, compressor) {
149
+ if (
150
+ !compressor.option("ie8")
151
+ && is_undeclared_ref(self)
152
+ && !compressor.find_parent(AST_With)
153
+ ) {
154
+ switch (self.name) {
155
+ case "undefined":
156
+ return make_node(AST_Undefined, self).optimize(compressor);
157
+ case "NaN":
158
+ return make_node(AST_NaN, self).optimize(compressor);
159
+ case "Infinity":
160
+ return make_node(AST_Infinity, self).optimize(compressor);
161
+ }
162
+ }
163
+
164
+ const parent = compressor.parent();
165
+ if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
166
+ const def = self.definition();
167
+ const nearest_scope = compressor.find_scope();
168
+ if (compressor.top_retain && def.global && compressor.top_retain(def)) {
169
+ def.fixed = false;
170
+ def.single_use = false;
171
+ return self;
172
+ }
173
+
174
+ let fixed = self.fixed_value();
175
+ let single_use = def.single_use
176
+ && !(parent instanceof AST_Call
177
+ && (parent.is_callee_pure(compressor))
178
+ || has_annotation(parent, _NOINLINE))
179
+ && !(parent instanceof AST_Export
180
+ && fixed instanceof AST_Lambda
181
+ && fixed.name);
182
+
183
+ if (single_use && fixed instanceof AST_Node) {
184
+ single_use =
185
+ !fixed.has_side_effects(compressor)
186
+ && !fixed.may_throw(compressor);
187
+ }
188
+
189
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
190
+ if (retain_top_func(fixed, compressor)) {
191
+ single_use = false;
192
+ } else if (def.scope !== self.scope
193
+ && (def.escaped == 1
194
+ || has_flag(fixed, INLINED)
195
+ || within_array_or_object_literal(compressor)
196
+ || !compressor.option("reduce_funcs"))) {
197
+ single_use = false;
198
+ } else if (is_recursive_ref(compressor, def)) {
199
+ single_use = false;
200
+ } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
201
+ single_use = fixed.is_constant_expression(self.scope);
202
+ if (single_use == "f") {
203
+ var scope = self.scope;
204
+ do {
205
+ if (scope instanceof AST_Defun || is_func_expr(scope)) {
206
+ set_flag(scope, INLINED);
207
+ }
208
+ } while (scope = scope.parent_scope);
209
+ }
210
+ }
211
+ }
212
+
213
+ if (single_use && fixed instanceof AST_Lambda) {
214
+ single_use =
215
+ def.scope === self.scope
216
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
217
+ || parent instanceof AST_Call
218
+ && parent.expression === self
219
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
220
+ && !(fixed.name && fixed.name.definition().recursive_refs > 0);
221
+ }
222
+
223
+ if (single_use && fixed) {
224
+ if (fixed instanceof AST_DefClass) {
225
+ set_flag(fixed, SQUEEZED);
226
+ fixed = make_node(AST_ClassExpression, fixed, fixed);
227
+ }
228
+ if (fixed instanceof AST_Defun) {
229
+ set_flag(fixed, SQUEEZED);
230
+ fixed = make_node(AST_Function, fixed, fixed);
231
+ }
232
+ if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
233
+ const defun_def = fixed.name.definition();
234
+ let lambda_def = fixed.variables.get(fixed.name.name);
235
+ let name = lambda_def && lambda_def.orig[0];
236
+ if (!(name instanceof AST_SymbolLambda)) {
237
+ name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
238
+ name.scope = fixed;
239
+ fixed.name = name;
240
+ lambda_def = fixed.def_function(name);
241
+ }
242
+ walk(fixed, node => {
243
+ if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
244
+ node.thedef = lambda_def;
245
+ lambda_def.references.push(node);
246
+ }
247
+ });
248
+ }
249
+ if (
250
+ (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
251
+ && fixed.parent_scope !== nearest_scope
252
+ ) {
253
+ fixed = fixed.clone(true, compressor.get_toplevel());
254
+
255
+ nearest_scope.add_child_scope(fixed);
256
+ }
257
+ return fixed.optimize(compressor);
258
+ }
259
+
260
+ // multiple uses
261
+ if (fixed) {
262
+ let replace;
263
+
264
+ if (fixed instanceof AST_This) {
265
+ if (!(def.orig[0] instanceof AST_SymbolFunarg)
266
+ && def.references.every((ref) =>
267
+ def.scope === ref.scope
268
+ )) {
269
+ replace = fixed;
270
+ }
271
+ } else {
272
+ var ev = fixed.evaluate(compressor);
273
+ if (
274
+ ev !== fixed
275
+ && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
276
+ ) {
277
+ replace = make_node_from_constant(ev, fixed);
278
+ }
279
+ }
280
+
281
+ if (replace) {
282
+ const name_length = self.size(compressor);
283
+ const replace_size = replace.size(compressor);
284
+
285
+ let overhead = 0;
286
+ if (compressor.option("unused") && !compressor.exposed(def)) {
287
+ overhead =
288
+ (name_length + 2 + replace_size) /
289
+ (def.references.length - def.assignments);
290
+ }
291
+
292
+ if (replace_size <= name_length + overhead) {
293
+ return replace;
294
+ }
295
+ }
296
+ }
297
+ }
298
+
299
+ return self;
300
+ }
301
+
302
+ export function inline_into_call(self, fn, compressor) {
303
+ var exp = self.expression;
304
+ var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion));
305
+
306
+ if (compressor.option("reduce_vars")
307
+ && fn instanceof AST_SymbolRef
308
+ && !has_annotation(self, _NOINLINE)
309
+ ) {
310
+ const fixed = fn.fixed_value();
311
+ if (!retain_top_func(fixed, compressor)) {
312
+ fn = fixed;
313
+ }
314
+ }
315
+
316
+ var is_func = fn instanceof AST_Lambda;
317
+
318
+ var stat = is_func && fn.body[0];
319
+ var is_regular_func = is_func && !fn.is_generator && !fn.async;
320
+ var can_inline = is_regular_func && compressor.option("inline") && !self.is_callee_pure(compressor);
321
+ if (can_inline && stat instanceof AST_Return) {
322
+ let returned = stat.value;
323
+ if (!returned || returned.is_constant_expression()) {
324
+ if (returned) {
325
+ returned = returned.clone(true);
326
+ } else {
327
+ returned = make_node(AST_Undefined, self);
328
+ }
329
+ const args = self.args.concat(returned);
330
+ return make_sequence(self, args).optimize(compressor);
331
+ }
332
+
333
+ // optimize identity function
334
+ if (
335
+ fn.argnames.length === 1
336
+ && (fn.argnames[0] instanceof AST_SymbolFunarg)
337
+ && self.args.length < 2
338
+ && returned instanceof AST_SymbolRef
339
+ && returned.name === fn.argnames[0].name
340
+ ) {
341
+ const replacement =
342
+ (self.args[0] || make_node(AST_Undefined)).optimize(compressor);
343
+
344
+ let parent;
345
+ if (
346
+ replacement instanceof AST_PropAccess
347
+ && (parent = compressor.parent()) instanceof AST_Call
348
+ && parent.expression === self
349
+ ) {
350
+ // identity function was being used to remove `this`, like in
351
+ //
352
+ // id(bag.no_this)(...)
353
+ //
354
+ // Replace with a larger but more effish (0, bag.no_this) wrapper.
355
+
356
+ return make_sequence(self, [
357
+ make_node(AST_Number, self, { value: 0 }),
358
+ replacement
359
+ ]);
360
+ }
361
+ // replace call with first argument or undefined if none passed
362
+ return replacement;
363
+ }
364
+ }
365
+
366
+ if (can_inline) {
367
+ var scope, in_loop, level = -1;
368
+ let def;
369
+ let returned_value;
370
+ let nearest_scope;
371
+ if (simple_args
372
+ && !fn.uses_arguments
373
+ && !(compressor.parent() instanceof AST_Class)
374
+ && !(fn.name && fn instanceof AST_Function)
375
+ && (returned_value = can_flatten_body(stat))
376
+ && (exp === fn
377
+ || has_annotation(self, _INLINE)
378
+ || compressor.option("unused")
379
+ && (def = exp.definition()).references.length == 1
380
+ && !is_recursive_ref(compressor, def)
381
+ && fn.is_constant_expression(exp.scope))
382
+ && !has_annotation(self, _PURE | _NOINLINE)
383
+ && !fn.contains_this()
384
+ && can_inject_symbols()
385
+ && (nearest_scope = compressor.find_scope())
386
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fn)
387
+ && !(function in_default_assign() {
388
+ // Due to the fact function parameters have their own scope
389
+ // which can't use `var something` in the function body within,
390
+ // we simply don't inline into DefaultAssign.
391
+ let i = 0;
392
+ let p;
393
+ while ((p = compressor.parent(i++))) {
394
+ if (p instanceof AST_DefaultAssign) return true;
395
+ if (p instanceof AST_Block) break;
396
+ }
397
+ return false;
398
+ })()
399
+ && !(scope instanceof AST_Class)
400
+ ) {
401
+ set_flag(fn, SQUEEZED);
402
+ nearest_scope.add_child_scope(fn);
403
+ return make_sequence(self, flatten_fn(returned_value)).optimize(compressor);
404
+ }
405
+ }
406
+
407
+ if (can_inline && has_annotation(self, _INLINE)) {
408
+ set_flag(fn, SQUEEZED);
409
+ fn = make_node(fn.CTOR === AST_Defun ? AST_Function : fn.CTOR, fn, fn);
410
+ fn = fn.clone(true);
411
+ fn.figure_out_scope({}, {
412
+ parent_scope: compressor.find_scope(),
413
+ toplevel: compressor.get_toplevel()
414
+ });
415
+
416
+ return make_node(AST_Call, self, {
417
+ expression: fn,
418
+ args: self.args,
419
+ }).optimize(compressor);
420
+ }
421
+
422
+ const can_drop_this_call = is_regular_func && compressor.option("side_effects") && fn.body.every(is_empty);
423
+ if (can_drop_this_call) {
424
+ var args = self.args.concat(make_node(AST_Undefined, self));
425
+ return make_sequence(self, args).optimize(compressor);
426
+ }
427
+
428
+ if (compressor.option("negate_iife")
429
+ && compressor.parent() instanceof AST_SimpleStatement
430
+ && is_iife_call(self)) {
431
+ return self.negate(compressor, true);
432
+ }
433
+
434
+ var ev = self.evaluate(compressor);
435
+ if (ev !== self) {
436
+ ev = make_node_from_constant(ev, self).optimize(compressor);
437
+ return best_of(compressor, ev, self);
438
+ }
439
+
440
+ return self;
441
+
442
+ function return_value(stat) {
443
+ if (!stat) return make_node(AST_Undefined, self);
444
+ if (stat instanceof AST_Return) {
445
+ if (!stat.value) return make_node(AST_Undefined, self);
446
+ return stat.value.clone(true);
447
+ }
448
+ if (stat instanceof AST_SimpleStatement) {
449
+ return make_node(AST_UnaryPrefix, stat, {
450
+ operator: "void",
451
+ expression: stat.body.clone(true)
452
+ });
453
+ }
454
+ }
455
+
456
+ function can_flatten_body(stat) {
457
+ var body = fn.body;
458
+ var len = body.length;
459
+ if (compressor.option("inline") < 3) {
460
+ return len == 1 && return_value(stat);
461
+ }
462
+ stat = null;
463
+ for (var i = 0; i < len; i++) {
464
+ var line = body[i];
465
+ if (line instanceof AST_Var) {
466
+ if (stat && !line.definitions.every((var_def) =>
467
+ !var_def.value
468
+ )) {
469
+ return false;
470
+ }
471
+ } else if (stat) {
472
+ return false;
473
+ } else if (!(line instanceof AST_EmptyStatement)) {
474
+ stat = line;
475
+ }
476
+ }
477
+ return return_value(stat);
478
+ }
479
+
480
+ function can_inject_args(block_scoped, safe_to_inject) {
481
+ for (var i = 0, len = fn.argnames.length; i < len; i++) {
482
+ var arg = fn.argnames[i];
483
+ if (arg instanceof AST_DefaultAssign) {
484
+ if (has_flag(arg.left, UNUSED)) continue;
485
+ return false;
486
+ }
487
+ if (arg instanceof AST_Destructuring) return false;
488
+ if (arg instanceof AST_Expansion) {
489
+ if (has_flag(arg.expression, UNUSED)) continue;
490
+ return false;
491
+ }
492
+ if (has_flag(arg, UNUSED)) continue;
493
+ if (!safe_to_inject
494
+ || block_scoped.has(arg.name)
495
+ || identifier_atom.has(arg.name)
496
+ || scope.conflicting_def(arg.name)) {
497
+ return false;
498
+ }
499
+ if (in_loop) in_loop.push(arg.definition());
500
+ }
501
+ return true;
502
+ }
503
+
504
+ function can_inject_vars(block_scoped, safe_to_inject) {
505
+ var len = fn.body.length;
506
+ for (var i = 0; i < len; i++) {
507
+ var stat = fn.body[i];
508
+ if (!(stat instanceof AST_Var)) continue;
509
+ if (!safe_to_inject) return false;
510
+ for (var j = stat.definitions.length; --j >= 0;) {
511
+ var name = stat.definitions[j].name;
512
+ if (name instanceof AST_Destructuring
513
+ || block_scoped.has(name.name)
514
+ || identifier_atom.has(name.name)
515
+ || scope.conflicting_def(name.name)) {
516
+ return false;
517
+ }
518
+ if (in_loop) in_loop.push(name.definition());
519
+ }
520
+ }
521
+ return true;
522
+ }
523
+
524
+ function can_inject_symbols() {
525
+ var block_scoped = new Set();
526
+ do {
527
+ scope = compressor.parent(++level);
528
+ if (scope.is_block_scope() && scope.block_scope) {
529
+ // TODO this is sometimes undefined during compression.
530
+ // But it should always have a value!
531
+ scope.block_scope.variables.forEach(function (variable) {
532
+ block_scoped.add(variable.name);
533
+ });
534
+ }
535
+ if (scope instanceof AST_Catch) {
536
+ // TODO can we delete? AST_Catch is a block scope.
537
+ if (scope.argname) {
538
+ block_scoped.add(scope.argname.name);
539
+ }
540
+ } else if (scope instanceof AST_IterationStatement) {
541
+ in_loop = [];
542
+ } else if (scope instanceof AST_SymbolRef) {
543
+ if (scope.fixed_value() instanceof AST_Scope) return false;
544
+ }
545
+ } while (!(scope instanceof AST_Scope));
546
+
547
+ var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
548
+ var inline = compressor.option("inline");
549
+ if (!can_inject_vars(block_scoped, inline >= 3 && safe_to_inject)) return false;
550
+ if (!can_inject_args(block_scoped, inline >= 2 && safe_to_inject)) return false;
551
+ return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
552
+ }
553
+
554
+ function append_var(decls, expressions, name, value) {
555
+ var def = name.definition();
556
+
557
+ // Name already exists, only when a function argument had the same name
558
+ const already_appended = scope.variables.has(name.name);
559
+ if (!already_appended) {
560
+ scope.variables.set(name.name, def);
561
+ scope.enclosed.push(def);
562
+ decls.push(make_node(AST_VarDef, name, {
563
+ name: name,
564
+ value: null
565
+ }));
566
+ }
567
+
568
+ var sym = make_node(AST_SymbolRef, name, name);
569
+ def.references.push(sym);
570
+ if (value) expressions.push(make_node(AST_Assign, self, {
571
+ operator: "=",
572
+ logical: false,
573
+ left: sym,
574
+ right: value.clone()
575
+ }));
576
+ }
577
+
578
+ function flatten_args(decls, expressions) {
579
+ var len = fn.argnames.length;
580
+ for (var i = self.args.length; --i >= len;) {
581
+ expressions.push(self.args[i]);
582
+ }
583
+ for (i = len; --i >= 0;) {
584
+ var name = fn.argnames[i];
585
+ var value = self.args[i];
586
+ if (has_flag(name, UNUSED) || !name.name || scope.conflicting_def(name.name)) {
587
+ if (value) expressions.push(value);
588
+ } else {
589
+ var symbol = make_node(AST_SymbolVar, name, name);
590
+ name.definition().orig.push(symbol);
591
+ if (!value && in_loop) value = make_node(AST_Undefined, self);
592
+ append_var(decls, expressions, symbol, value);
593
+ }
594
+ }
595
+ decls.reverse();
596
+ expressions.reverse();
597
+ }
598
+
599
+ function flatten_vars(decls, expressions) {
600
+ var pos = expressions.length;
601
+ for (var i = 0, lines = fn.body.length; i < lines; i++) {
602
+ var stat = fn.body[i];
603
+ if (!(stat instanceof AST_Var)) continue;
604
+ for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
605
+ var var_def = stat.definitions[j];
606
+ var name = var_def.name;
607
+ append_var(decls, expressions, name, var_def.value);
608
+ if (in_loop && fn.argnames.every((argname) =>
609
+ argname.name != name.name
610
+ )) {
611
+ var def = fn.variables.get(name.name);
612
+ var sym = make_node(AST_SymbolRef, name, name);
613
+ def.references.push(sym);
614
+ expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
615
+ operator: "=",
616
+ logical: false,
617
+ left: sym,
618
+ right: make_node(AST_Undefined, name)
619
+ }));
620
+ }
621
+ }
622
+ }
623
+ }
624
+
625
+ function flatten_fn(returned_value) {
626
+ var decls = [];
627
+ var expressions = [];
628
+ flatten_args(decls, expressions);
629
+ flatten_vars(decls, expressions);
630
+ expressions.push(returned_value);
631
+
632
+ if (decls.length) {
633
+ const i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
634
+ scope.body.splice(i, 0, make_node(AST_Var, fn, {
635
+ definitions: decls
636
+ }));
637
+ }
638
+
639
+ return expressions.map(exp => exp.clone(true));
640
+ }
641
+ }
@@ -154,6 +154,7 @@ export const is_pure_native_fn = make_nested_lookup({
154
154
  "isExtensible",
155
155
  "isFrozen",
156
156
  "isSealed",
157
+ "hasOwn",
157
158
  "keys",
158
159
  ],
159
160
  String: [
@@ -203,7 +203,7 @@ export function trim_unreachable_code(compressor, stat, target) {
203
203
  });
204
204
  }
205
205
 
206
- // Tighten a bunch of statements together, and perform statement-level optimization.
206
+ /** Tighten a bunch of statements together, and perform statement-level optimization. */
207
207
  export function tighten_body(statements, compressor) {
208
208
  var in_loop, in_try;
209
209
  var scope = compressor.find_parent(AST_Scope).get_defun_scope();