terser 5.16.1 → 5.16.3

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
  }
@@ -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
  }
@@ -92,7 +92,6 @@ import "../size.js";
92
92
  import "./evaluate.js";
93
93
  import "./drop-side-effect-free.js";
94
94
  import "./reduce-vars.js";
95
- import { is_lhs } from "./inference.js";
96
95
  import {
97
96
  SQUEEZED,
98
97
  INLINED,
@@ -114,6 +113,13 @@ import {
114
113
  retain_top_func,
115
114
  } from "./common.js";
116
115
 
116
+ /**
117
+ * Module that contains the inlining logic.
118
+ *
119
+ * @module
120
+ *
121
+ * The stars of the show are `inline_into_symbolref` and `inline_into_call`.
122
+ */
117
123
 
118
124
  function within_array_or_object_literal(compressor) {
119
125
  var node, level = 0;
@@ -144,136 +150,135 @@ function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
144
150
 
145
151
  export function inline_into_symbolref(self, compressor) {
146
152
  const parent = compressor.parent();
147
- if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
148
- const def = self.definition();
149
- const nearest_scope = compressor.find_scope();
150
- if (compressor.top_retain && def.global && compressor.top_retain(def)) {
151
- def.fixed = false;
152
- def.single_use = false;
153
- return self;
154
- }
155
153
 
156
- let fixed = self.fixed_value();
157
- let single_use = def.single_use
158
- && !(parent instanceof AST_Call
159
- && (parent.is_callee_pure(compressor))
160
- || has_annotation(parent, _NOINLINE))
161
- && !(parent instanceof AST_Export
162
- && fixed instanceof AST_Lambda
163
- && fixed.name);
164
-
165
- if (single_use && fixed instanceof AST_Node) {
166
- single_use =
167
- !fixed.has_side_effects(compressor)
168
- && !fixed.may_throw(compressor);
169
- }
154
+ const def = self.definition();
155
+ const nearest_scope = compressor.find_scope();
156
+ if (compressor.top_retain && def.global && compressor.top_retain(def)) {
157
+ def.fixed = false;
158
+ def.single_use = false;
159
+ return self;
160
+ }
170
161
 
171
- if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
172
- if (retain_top_func(fixed, compressor)) {
173
- single_use = false;
174
- } else if (def.scope !== self.scope
175
- && (def.escaped == 1
176
- || has_flag(fixed, INLINED)
177
- || within_array_or_object_literal(compressor)
178
- || !compressor.option("reduce_funcs"))) {
179
- single_use = false;
180
- } else if (is_recursive_ref(compressor, def)) {
181
- single_use = false;
182
- } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
183
- single_use = fixed.is_constant_expression(self.scope);
184
- if (single_use == "f") {
185
- var scope = self.scope;
186
- do {
187
- if (scope instanceof AST_Defun || is_func_expr(scope)) {
188
- set_flag(scope, INLINED);
189
- }
190
- } while (scope = scope.parent_scope);
191
- }
162
+ let fixed = self.fixed_value();
163
+ let single_use = def.single_use
164
+ && !(parent instanceof AST_Call
165
+ && (parent.is_callee_pure(compressor))
166
+ || has_annotation(parent, _NOINLINE))
167
+ && !(parent instanceof AST_Export
168
+ && fixed instanceof AST_Lambda
169
+ && fixed.name);
170
+
171
+ if (single_use && fixed instanceof AST_Node) {
172
+ single_use =
173
+ !fixed.has_side_effects(compressor)
174
+ && !fixed.may_throw(compressor);
175
+ }
176
+
177
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
178
+ if (retain_top_func(fixed, compressor)) {
179
+ single_use = false;
180
+ } else if (def.scope !== self.scope
181
+ && (def.escaped == 1
182
+ || has_flag(fixed, INLINED)
183
+ || within_array_or_object_literal(compressor)
184
+ || !compressor.option("reduce_funcs"))) {
185
+ single_use = false;
186
+ } else if (is_recursive_ref(compressor, def)) {
187
+ single_use = false;
188
+ } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
189
+ single_use = fixed.is_constant_expression(self.scope);
190
+ if (single_use == "f") {
191
+ var scope = self.scope;
192
+ do {
193
+ if (scope instanceof AST_Defun || is_func_expr(scope)) {
194
+ set_flag(scope, INLINED);
195
+ }
196
+ } while (scope = scope.parent_scope);
192
197
  }
193
198
  }
199
+ }
194
200
 
195
- if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
196
- single_use =
197
- def.scope === self.scope
198
- && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
199
- || parent instanceof AST_Call
200
- && parent.expression === self
201
- && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
202
- && !(fixed.name && fixed.name.definition().recursive_refs > 0);
203
- }
201
+ if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
202
+ single_use =
203
+ def.scope === self.scope
204
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
205
+ || parent instanceof AST_Call
206
+ && parent.expression === self
207
+ && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
208
+ && !(fixed.name && fixed.name.definition().recursive_refs > 0);
209
+ }
204
210
 
205
- if (single_use && fixed) {
206
- if (fixed instanceof AST_DefClass) {
207
- set_flag(fixed, SQUEEZED);
208
- fixed = make_node(AST_ClassExpression, fixed, fixed);
209
- }
210
- if (fixed instanceof AST_Defun) {
211
- set_flag(fixed, SQUEEZED);
212
- fixed = make_node(AST_Function, fixed, fixed);
211
+ if (single_use && fixed) {
212
+ if (fixed instanceof AST_DefClass) {
213
+ set_flag(fixed, SQUEEZED);
214
+ fixed = make_node(AST_ClassExpression, fixed, fixed);
215
+ }
216
+ if (fixed instanceof AST_Defun) {
217
+ set_flag(fixed, SQUEEZED);
218
+ fixed = make_node(AST_Function, fixed, fixed);
219
+ }
220
+ if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
221
+ const defun_def = fixed.name.definition();
222
+ let lambda_def = fixed.variables.get(fixed.name.name);
223
+ let name = lambda_def && lambda_def.orig[0];
224
+ if (!(name instanceof AST_SymbolLambda)) {
225
+ name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
226
+ name.scope = fixed;
227
+ fixed.name = name;
228
+ lambda_def = fixed.def_function(name);
213
229
  }
214
- if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
215
- const defun_def = fixed.name.definition();
216
- let lambda_def = fixed.variables.get(fixed.name.name);
217
- let name = lambda_def && lambda_def.orig[0];
218
- if (!(name instanceof AST_SymbolLambda)) {
219
- name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
220
- name.scope = fixed;
221
- fixed.name = name;
222
- lambda_def = fixed.def_function(name);
230
+ walk(fixed, node => {
231
+ if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
232
+ node.thedef = lambda_def;
233
+ lambda_def.references.push(node);
223
234
  }
224
- walk(fixed, node => {
225
- if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
226
- node.thedef = lambda_def;
227
- lambda_def.references.push(node);
228
- }
229
- });
235
+ });
236
+ }
237
+ if (
238
+ (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
239
+ && fixed.parent_scope !== nearest_scope
240
+ ) {
241
+ fixed = fixed.clone(true, compressor.get_toplevel());
242
+
243
+ nearest_scope.add_child_scope(fixed);
244
+ }
245
+ return fixed.optimize(compressor);
246
+ }
247
+
248
+ // multiple uses
249
+ if (fixed) {
250
+ let replace;
251
+
252
+ if (fixed instanceof AST_This) {
253
+ if (!(def.orig[0] instanceof AST_SymbolFunarg)
254
+ && def.references.every((ref) =>
255
+ def.scope === ref.scope
256
+ )) {
257
+ replace = fixed;
230
258
  }
259
+ } else {
260
+ var ev = fixed.evaluate(compressor);
231
261
  if (
232
- (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
233
- && fixed.parent_scope !== nearest_scope
262
+ ev !== fixed
263
+ && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
234
264
  ) {
235
- fixed = fixed.clone(true, compressor.get_toplevel());
236
-
237
- nearest_scope.add_child_scope(fixed);
265
+ replace = make_node_from_constant(ev, fixed);
238
266
  }
239
- return fixed.optimize(compressor);
240
267
  }
241
268
 
242
- // multiple uses
243
- if (fixed) {
244
- let replace;
269
+ if (replace) {
270
+ const name_length = self.size(compressor);
271
+ const replace_size = replace.size(compressor);
245
272
 
246
- if (fixed instanceof AST_This) {
247
- if (!(def.orig[0] instanceof AST_SymbolFunarg)
248
- && def.references.every((ref) =>
249
- def.scope === ref.scope
250
- )) {
251
- replace = fixed;
252
- }
253
- } else {
254
- var ev = fixed.evaluate(compressor);
255
- if (
256
- ev !== fixed
257
- && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
258
- ) {
259
- replace = make_node_from_constant(ev, fixed);
260
- }
273
+ let overhead = 0;
274
+ if (compressor.option("unused") && !compressor.exposed(def)) {
275
+ overhead =
276
+ (name_length + 2 + replace_size) /
277
+ (def.references.length - def.assignments);
261
278
  }
262
279
 
263
- if (replace) {
264
- const name_length = self.size(compressor);
265
- const replace_size = replace.size(compressor);
266
-
267
- let overhead = 0;
268
- if (compressor.option("unused") && !compressor.exposed(def)) {
269
- overhead =
270
- (name_length + 2 + replace_size) /
271
- (def.references.length - def.assignments);
272
- }
273
-
274
- if (replace_size <= name_length + overhead) {
275
- return replace;
276
- }
280
+ if (replace_size <= name_length + overhead) {
281
+ return replace;
277
282
  }
278
283
  }
279
284
  }
@@ -79,6 +79,9 @@ const object_methods = [
79
79
 
80
80
  export const is_pure_native_method = make_nested_lookup({
81
81
  Array: [
82
+ "at",
83
+ "flat",
84
+ "includes",
82
85
  "indexOf",
83
86
  "join",
84
87
  "lastIndexOf",
@@ -99,22 +102,41 @@ export const is_pure_native_method = make_nested_lookup({
99
102
  ...object_methods,
100
103
  ],
101
104
  String: [
105
+ "at",
102
106
  "charAt",
103
107
  "charCodeAt",
108
+ "charPointAt",
104
109
  "concat",
110
+ "endsWith",
111
+ "fromCharCode",
112
+ "fromCodePoint",
113
+ "includes",
105
114
  "indexOf",
106
115
  "italics",
107
116
  "lastIndexOf",
117
+ "localeCompare",
108
118
  "match",
119
+ "matchAll",
120
+ "normalize",
121
+ "padStart",
122
+ "padEnd",
123
+ "repeat",
109
124
  "replace",
125
+ "replaceAll",
110
126
  "search",
111
127
  "slice",
112
128
  "split",
129
+ "startsWith",
113
130
  "substr",
114
131
  "substring",
132
+ "repeat",
133
+ "toLocaleLowerCase",
134
+ "toLocaleUpperCase",
115
135
  "toLowerCase",
116
136
  "toUpperCase",
117
137
  "trim",
138
+ "trimEnd",
139
+ "trimStart",
118
140
  ...object_methods,
119
141
  ],
120
142
  });
@@ -103,15 +103,17 @@ import { lazy_op, is_modified } from "./inference.js";
103
103
  import { INLINED, clear_flag } from "./compressor-flags.js";
104
104
  import { read_property, has_break_or_continue, is_recursive_ref } from "./common.js";
105
105
 
106
- // Define the method AST_Node#reduce_vars, which goes through the AST in
107
- // execution order to perform basic flow analysis
108
-
106
+ /**
107
+ * Define the method AST_Node#reduce_vars, which goes through the AST in
108
+ * execution order to perform basic flow analysis
109
+ */
109
110
  function def_reduce_vars(node, func) {
110
111
  node.DEFMETHOD("reduce_vars", func);
111
112
  }
112
113
 
113
114
  def_reduce_vars(AST_Node, noop);
114
115
 
116
+ /** Clear definition properties */
115
117
  function reset_def(compressor, def) {
116
118
  def.assignments = 0;
117
119
  def.chained = false;
@@ -120,7 +122,10 @@ function reset_def(compressor, def) {
120
122
  def.recursive_refs = 0;
121
123
  def.references = [];
122
124
  def.single_use = undefined;
123
- if (def.scope.pinned()) {
125
+ if (
126
+ def.scope.pinned()
127
+ || (def.orig[0] instanceof AST_SymbolFunarg && def.scope.uses_arguments)
128
+ ) {
124
129
  def.fixed = false;
125
130
  } else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
126
131
  def.fixed = def.init;
@@ -442,15 +447,23 @@ def_reduce_vars(AST_Default, function(tw, descend) {
442
447
 
443
448
  function mark_lambda(tw, descend, compressor) {
444
449
  clear_flag(this, INLINED);
445
- push(tw);
446
- reset_variables(tw, compressor, this);
447
- if (this.uses_arguments) {
448
- descend();
449
- pop(tw);
450
- return;
450
+
451
+ // Sometimes we detach the lambda for safety, and instead of push()
452
+ // we go to an entirely fresh lineage of safe_ids.
453
+ let previous_safe_ids;
454
+ if (this instanceof AST_Defun || this.uses_arguments || this.pinned()) {
455
+ previous_safe_ids = tw.safe_ids;
456
+ tw.safe_ids = Object.create(null);
457
+ } else {
458
+ push(tw);
451
459
  }
460
+
461
+ reset_variables(tw, compressor, this);
462
+
452
463
  var iife;
453
464
  if (!this.name
465
+ && !this.uses_arguments
466
+ && !this.pinned()
454
467
  && (iife = tw.parent()) instanceof AST_Call
455
468
  && iife.expression === this
456
469
  && !iife.args.some(arg => arg instanceof AST_Expansion)
@@ -476,7 +489,13 @@ function mark_lambda(tw, descend, compressor) {
476
489
  });
477
490
  }
478
491
  descend();
479
- pop(tw);
492
+
493
+ if (previous_safe_ids) {
494
+ tw.safe_ids = previous_safe_ids;
495
+ } else {
496
+ pop(tw);
497
+ }
498
+
480
499
  return true;
481
500
  }
482
501
 
@@ -1404,14 +1404,21 @@ export function tighten_body(statements, compressor) {
1404
1404
  CHANGED = true;
1405
1405
  stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
1406
1406
  statements[++j] = stat;
1407
- } else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
1407
+ } else if (
1408
+ prev instanceof AST_Var
1409
+ && (!stat.init || stat.init.TYPE == prev.TYPE)
1410
+ ) {
1408
1411
  if (stat.init) {
1409
1412
  prev.definitions = prev.definitions.concat(stat.init.definitions);
1410
1413
  }
1411
1414
  stat.init = prev;
1412
1415
  statements[j] = stat;
1413
1416
  CHANGED = true;
1414
- } else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
1417
+ } else if (
1418
+ defs instanceof AST_Var
1419
+ && stat.init instanceof AST_Var
1420
+ && declarations_only(stat.init)
1421
+ ) {
1415
1422
  defs.definitions = defs.definitions.concat(stat.init.definitions);
1416
1423
  stat.init = null;
1417
1424
  statements[++j] = stat;
package/lib/minify.js CHANGED
@@ -19,12 +19,15 @@ import {
19
19
  reserve_quoted_keys,
20
20
  } from "./propmangle.js";
21
21
 
22
- var to_ascii = typeof atob == "undefined" ? function(b64) {
23
- return Buffer.from(b64, "base64").toString();
24
- } : atob;
25
- var to_base64 = typeof btoa == "undefined" ? function(str) {
26
- return Buffer.from(str).toString("base64");
27
- } : btoa;
22
+ // to/from base64 functions
23
+ // Prefer built-in Buffer, if available, then use hack
24
+ // https://developer.mozilla.org/en-US/docs/Glossary/Base64#The_Unicode_Problem
25
+ var to_ascii = typeof Buffer !== "undefined"
26
+ ? (b64) => Buffer.from(b64, "base64").toString()
27
+ : (b64) => decodeURIComponent(escape(atob(b64)));
28
+ var to_base64 = typeof Buffer !== "undefined"
29
+ ? (str) => Buffer.from(str).toString("base64")
30
+ : (str) => btoa(unescape(encodeURIComponent(str)));
28
31
 
29
32
  function read_source_map(code) {
30
33
  var match = /(?:^|[^.])\/\/# sourceMappingURL=data:application\/json(;[\w=-]*)?;base64,([+/0-9A-Za-z]*=*)\s*$/.exec(code);