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.
@@ -205,9 +205,10 @@ export function trim_unreachable_code(compressor, stat, target) {
205
205
 
206
206
  /** Tighten a bunch of statements together, and perform statement-level optimization. */
207
207
  export function tighten_body(statements, compressor) {
208
- var in_loop, in_try;
209
- var scope = compressor.find_parent(AST_Scope).get_defun_scope();
210
- find_loop_scope_try();
208
+ const nearest_scope = compressor.find_scope();
209
+ const defun_scope = nearest_scope.get_defun_scope();
210
+ const { in_loop, in_try } = find_loop_scope_try();
211
+
211
212
  var CHANGED, max_iter = 10;
212
213
  do {
213
214
  CHANGED = false;
@@ -231,19 +232,20 @@ export function tighten_body(statements, compressor) {
231
232
  } while (CHANGED && max_iter-- > 0);
232
233
 
233
234
  function find_loop_scope_try() {
234
- var node = compressor.self(), level = 0;
235
+ var node = compressor.self(), level = 0, in_loop = false, in_try = false;
235
236
  do {
236
237
  if (node instanceof AST_Catch || node instanceof AST_Finally) {
237
238
  level++;
238
239
  } else if (node instanceof AST_IterationStatement) {
239
240
  in_loop = true;
240
241
  } else if (node instanceof AST_Scope) {
241
- scope = node;
242
242
  break;
243
243
  } else if (node instanceof AST_Try) {
244
244
  in_try = true;
245
245
  }
246
246
  } while (node = compressor.parent(level++));
247
+
248
+ return { in_loop, in_try };
247
249
  }
248
250
 
249
251
  // Search from right to left for assignment-like expressions:
@@ -255,7 +257,7 @@ export function tighten_body(statements, compressor) {
255
257
  // Will not attempt to collapse assignments into or past code blocks
256
258
  // which are not sequentially executed, e.g. loops and conditionals.
257
259
  function collapse(statements, compressor) {
258
- if (scope.pinned())
260
+ if (nearest_scope.pinned() || defun_scope.pinned())
259
261
  return statements;
260
262
  var args;
261
263
  var candidates = [];
@@ -319,10 +321,11 @@ export function tighten_body(statements, compressor) {
319
321
  stop_if_hit = parent;
320
322
  }
321
323
  // Replace variable with assignment when found
322
- if (can_replace
324
+ if (
325
+ can_replace
323
326
  && !(node instanceof AST_SymbolDeclaration)
324
327
  && lhs.equivalent_to(node)
325
- && !shadows(node.scope, lvalues)
328
+ && !shadows(scanner.find_scope() || nearest_scope, lvalues)
326
329
  ) {
327
330
  if (stop_if_hit) {
328
331
  abort = true;
@@ -527,9 +530,9 @@ export function tighten_body(statements, compressor) {
527
530
  return true;
528
531
  if (node instanceof AST_SymbolRef && (fn.variables.has(node.name) || redefined_within_scope(node.definition(), fn))) {
529
532
  var s = node.definition().scope;
530
- if (s !== scope)
533
+ if (s !== defun_scope)
531
534
  while (s = s.parent_scope) {
532
- if (s === scope)
535
+ if (s === defun_scope)
533
536
  return true;
534
537
  }
535
538
  return found = true;
@@ -851,7 +854,7 @@ export function tighten_body(statements, compressor) {
851
854
  while (lhs instanceof AST_PropAccess)
852
855
  lhs = lhs.expression;
853
856
  return lhs instanceof AST_SymbolRef
854
- && lhs.definition().scope === scope
857
+ && lhs.definition().scope.get_defun_scope() === defun_scope
855
858
  && !(in_loop
856
859
  && (lvalues.has(lhs.name)
857
860
  || candidate instanceof AST_Unary
@@ -886,15 +889,11 @@ export function tighten_body(statements, compressor) {
886
889
  var def = sym.definition();
887
890
  if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun)
888
891
  return false;
889
- if (def.scope.get_defun_scope() !== scope)
892
+ if (def.scope.get_defun_scope() !== defun_scope)
890
893
  return true;
891
- return !def.references.every((ref) => {
892
- var s = ref.scope.get_defun_scope();
893
- // "block" scope within AST_Catch
894
- if (s.TYPE == "Scope")
895
- s = s.parent_scope;
896
- return s === scope;
897
- });
894
+ return def.references.some((ref) =>
895
+ ref.scope.get_defun_scope() !== defun_scope
896
+ );
898
897
  }
899
898
 
900
899
  function side_effects_external(node, lhs) {
@@ -910,18 +909,20 @@ export function tighten_body(statements, compressor) {
910
909
  if (node instanceof AST_Sub)
911
910
  return side_effects_external(node.expression, true);
912
911
  if (node instanceof AST_SymbolRef)
913
- return node.definition().scope !== scope;
912
+ return node.definition().scope.get_defun_scope() !== defun_scope;
914
913
  }
915
914
  return false;
916
915
  }
917
916
 
918
- function shadows(newScope, lvalues) {
919
- for (const {def} of lvalues.values()) {
920
- let current = newScope;
921
- while (current && current !== def.scope) {
922
- let nested_def = current.variables.get(def.name);
923
- if (nested_def && nested_def !== def) return true;
924
- current = current.parent_scope;
917
+ /**
918
+ * Will any of the pulled-in lvalues shadow a variable in newScope or parents?
919
+ * similar to scope_encloses_variables_in_this_scope */
920
+ function shadows(my_scope, lvalues) {
921
+ for (const { def } of lvalues.values()) {
922
+ const looked_up = my_scope.find_variable(def.name);
923
+ if (looked_up) {
924
+ if (looked_up === def) continue;
925
+ return true;
925
926
  }
926
927
  }
927
928
  return false;
@@ -1343,7 +1344,7 @@ export function tighten_body(statements, compressor) {
1343
1344
  break;
1344
1345
  if (def.name.name != sym.name)
1345
1346
  break;
1346
- if (!node.right.is_constant_expression(scope))
1347
+ if (!node.right.is_constant_expression(nearest_scope))
1347
1348
  break;
1348
1349
  var prop = node.left.property;
1349
1350
  if (prop instanceof AST_Node) {
@@ -113,6 +113,7 @@ import {
113
113
  AST_PrivateGetter,
114
114
  AST_PrivateMethod,
115
115
  AST_PrivateSetter,
116
+ AST_PrivateIn,
116
117
  AST_PropAccess,
117
118
  AST_RegExp,
118
119
  AST_Return,
@@ -128,6 +129,7 @@ import {
128
129
  AST_SymbolCatch,
129
130
  AST_SymbolClass,
130
131
  AST_SymbolClassProperty,
132
+ AST_SymbolPrivateProperty,
131
133
  AST_SymbolConst,
132
134
  AST_SymbolDefClass,
133
135
  AST_SymbolDefun,
@@ -432,7 +434,9 @@ import { is_basic_identifier_string } from "./parse.js";
432
434
  if (M.computed) {
433
435
  key = from_moz(M.key);
434
436
  } else {
435
- if (M.key.type !== "Identifier") throw new Error("Non-Identifier key in PropertyDefinition");
437
+ if (M.key.type !== "Identifier" && M.key.type !== "PrivateIdentifier") {
438
+ throw new Error("Non-Identifier key in PropertyDefinition");
439
+ }
436
440
  key = from_moz(M.key);
437
441
  }
438
442
 
@@ -867,6 +871,18 @@ import { is_basic_identifier_string } from "./parse.js";
867
871
  },
868
872
 
869
873
  BinaryExpression: function(M) {
874
+ if (M.left.type === "PrivateIdentifier") {
875
+ return new AST_PrivateIn({
876
+ start: my_start_token(M),
877
+ end: my_end_token(M),
878
+ key: new AST_SymbolPrivateProperty({
879
+ start: my_start_token(M.left),
880
+ end: my_end_token(M.left),
881
+ name: M.left.name
882
+ }),
883
+ value: from_moz(M.right),
884
+ });
885
+ }
870
886
  return new AST_Binary({
871
887
  start: my_start_token(M),
872
888
  end: my_end_token(M),
@@ -1451,6 +1467,15 @@ import { is_basic_identifier_string } from "./parse.js";
1451
1467
  };
1452
1468
  });
1453
1469
 
1470
+ def_to_moz(AST_PrivateIn, function To_Moz_BinaryExpression_PrivateIn(M) {
1471
+ return {
1472
+ type: "BinaryExpression",
1473
+ left: { type: "PrivateIdentifier", name: M.key.name },
1474
+ operator: "in",
1475
+ right: to_moz(M.value),
1476
+ };
1477
+ });
1478
+
1454
1479
  def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) {
1455
1480
  return {
1456
1481
  type: "ArrayExpression",
package/lib/output.js CHANGED
@@ -74,7 +74,9 @@ import {
74
74
  AST_ConciseMethod,
75
75
  AST_PrivateGetter,
76
76
  AST_PrivateMethod,
77
+ AST_SymbolPrivateProperty,
77
78
  AST_PrivateSetter,
79
+ AST_PrivateIn,
78
80
  AST_Conditional,
79
81
  AST_Const,
80
82
  AST_Constant,
@@ -1795,7 +1797,10 @@ function OutputStream(options) {
1795
1797
  if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
1796
1798
  return true;
1797
1799
  }
1798
- if (node instanceof AST_Binary && node.operator == "in") {
1800
+ if (
1801
+ node instanceof AST_Binary && node.operator == "in"
1802
+ || node instanceof AST_PrivateIn
1803
+ ) {
1799
1804
  return walk_abort; // makes walk() return true
1800
1805
  }
1801
1806
  });
@@ -2184,6 +2189,16 @@ function OutputStream(options) {
2184
2189
  }
2185
2190
  self._print_getter_setter(type, true, output);
2186
2191
  });
2192
+ DEFPRINT(AST_PrivateIn, function(self, output) {
2193
+ self.key.print(output);
2194
+ output.space();
2195
+ output.print("in");
2196
+ output.space();
2197
+ self.value.print(output);
2198
+ });
2199
+ DEFPRINT(AST_SymbolPrivateProperty, function(self, output) {
2200
+ output.print("#" + self.name);
2201
+ });
2187
2202
  DEFPRINT(AST_ConciseMethod, function(self, output) {
2188
2203
  var type;
2189
2204
  if (self.is_generator && self.async) {
package/lib/parse.js CHANGED
@@ -69,6 +69,7 @@ import {
69
69
  AST_ClassProperty,
70
70
  AST_ClassStaticBlock,
71
71
  AST_ConciseMethod,
72
+ AST_PrivateIn,
72
73
  AST_PrivateGetter,
73
74
  AST_PrivateMethod,
74
75
  AST_PrivateSetter,
@@ -145,6 +146,7 @@ import {
145
146
  AST_TemplateSegment,
146
147
  AST_TemplateString,
147
148
  AST_This,
149
+ AST_SymbolPrivateProperty,
148
150
  AST_Throw,
149
151
  AST_Token,
150
152
  AST_Toplevel,
@@ -1041,7 +1043,7 @@ var PRECEDENCE = (function(a, ret) {
1041
1043
  {}
1042
1044
  );
1043
1045
 
1044
- var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name" ]);
1046
+ var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name"]);
1045
1047
 
1046
1048
  /* -----[ Parser ]----- */
1047
1049
 
@@ -1213,6 +1215,10 @@ function parse($TEXT, options) {
1213
1215
  return simple_statement();
1214
1216
 
1215
1217
  case "name":
1218
+ case "privatename":
1219
+ if(is("privatename") && !S.in_class)
1220
+ croak("Private field must be used in an enclosing class");
1221
+
1216
1222
  if (S.token.value == "async" && is_token(peek(), "keyword", "function")) {
1217
1223
  next();
1218
1224
  next();
@@ -2357,6 +2363,29 @@ function parse($TEXT, options) {
2357
2363
  if (is("template_head")) {
2358
2364
  return subscripts(template_string(), allow_calls);
2359
2365
  }
2366
+ if (is("privatename")) {
2367
+ if(!S.in_class) {
2368
+ croak("Private field must be used in an enclosing class");
2369
+ }
2370
+
2371
+ const start = S.token;
2372
+ const key = new AST_SymbolPrivateProperty({
2373
+ start,
2374
+ name: start.value,
2375
+ end: start
2376
+ });
2377
+ next();
2378
+ expect_token("operator", "in");
2379
+
2380
+ const private_in = new AST_PrivateIn({
2381
+ start,
2382
+ key,
2383
+ value: subscripts(as_atom_node(), allow_calls),
2384
+ end: prev()
2385
+ });
2386
+
2387
+ return subscripts(private_in, allow_calls);
2388
+ }
2360
2389
  if (ATOMIC_START_TOKEN.has(S.token.type)) {
2361
2390
  return subscripts(as_atom_node(), allow_calls);
2362
2391
  }
@@ -2442,7 +2471,9 @@ function parse($TEXT, options) {
2442
2471
  }));
2443
2472
  continue;
2444
2473
  }
2445
-
2474
+ if(is("privatename")) {
2475
+ croak("private fields are not allowed in an object");
2476
+ }
2446
2477
  var name = as_property_name();
2447
2478
  var value;
2448
2479
 
@@ -2516,7 +2547,9 @@ function parse($TEXT, options) {
2516
2547
  }
2517
2548
 
2518
2549
  expect("{");
2519
-
2550
+ // mark in class feild,
2551
+ const save_in_class = S.in_class;
2552
+ S.in_class = true;
2520
2553
  while (is("punc", ";")) { next(); } // Leading semicolons are okay in class bodies.
2521
2554
  while (!is("punc", "}")) {
2522
2555
  start = S.token;
@@ -2525,6 +2558,8 @@ function parse($TEXT, options) {
2525
2558
  a.push(method);
2526
2559
  while (is("punc", ";")) { next(); }
2527
2560
  }
2561
+ // mark in class feild,
2562
+ S.in_class = save_in_class;
2528
2563
 
2529
2564
  S.input.pop_directives_stack();
2530
2565
 
@@ -3031,6 +3066,8 @@ function parse($TEXT, options) {
3031
3066
  var start = expr.start;
3032
3067
  if (is("punc", ".")) {
3033
3068
  next();
3069
+ if(is("privatename") && !S.in_class)
3070
+ croak("Private field must be used in an enclosing class");
3034
3071
  const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
3035
3072
  return subscripts(new AST_DotVariant({
3036
3073
  start : start,
@@ -3084,6 +3121,8 @@ function parse($TEXT, options) {
3084
3121
 
3085
3122
  chain_contents = subscripts(call, true, true);
3086
3123
  } else if (is("name") || is("privatename")) {
3124
+ if(is("privatename") && !S.in_class)
3125
+ croak("Private field must be used in an enclosing class");
3087
3126
  const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
3088
3127
  chain_contents = subscripts(new AST_DotVariant({
3089
3128
  start,
@@ -3129,7 +3168,6 @@ function parse($TEXT, options) {
3129
3168
  end: prev()
3130
3169
  }), allow_calls);
3131
3170
  }
3132
-
3133
3171
  return expr;
3134
3172
  };
3135
3173
 
package/lib/propmangle.js CHANGED
@@ -61,6 +61,7 @@ import {
61
61
  AST_PrivateMethod,
62
62
  AST_PrivateGetter,
63
63
  AST_PrivateSetter,
64
+ AST_PrivateIn,
64
65
  AST_Sequence,
65
66
  AST_String,
66
67
  AST_Sub,
@@ -153,6 +154,7 @@ function mangle_private_properties(ast, options) {
153
154
  || node instanceof AST_PrivateMethod
154
155
  || node instanceof AST_PrivateGetter
155
156
  || node instanceof AST_PrivateSetter
157
+ || node instanceof AST_PrivateIn
156
158
  ) {
157
159
  node.key.name = mangle_private(node.key.name);
158
160
  } else if (node instanceof AST_DotHash) {
package/lib/scope.js CHANGED
@@ -104,7 +104,8 @@ import {
104
104
  AST_VarDef,
105
105
  AST_With,
106
106
  TreeWalker,
107
- walk
107
+ walk,
108
+ walk_abort
108
109
  } from "./ast.js";
109
110
  import {
110
111
  ALL_RESERVED_WORDS,
@@ -418,7 +419,7 @@ AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = null,
418
419
  sym = toplevel.def_global(node);
419
420
  if (node instanceof AST_SymbolExport) sym.export = MASK_EXPORT_DONT_MANGLE;
420
421
  } else if (sym.scope instanceof AST_Lambda && name == "arguments") {
421
- sym.scope.uses_arguments = true;
422
+ sym.scope.get_defun_scope().uses_arguments = true;
422
423
  }
423
424
  node.thedef = sym;
424
425
  node.reference();
@@ -520,7 +521,25 @@ AST_Scope.DEFMETHOD("add_child_scope", function (scope) {
520
521
 
521
522
  scope.parent_scope = this;
522
523
 
523
- // TODO uses_with, uses_eval, etc
524
+ // Propagate to this.uses_arguments from arrow functions
525
+ if ((scope instanceof AST_Arrow) && !this.uses_arguments) {
526
+ this.uses_arguments = walk(scope, node => {
527
+ if (
528
+ node instanceof AST_SymbolRef
529
+ && node.scope instanceof AST_Lambda
530
+ && node.name === "arguments"
531
+ ) {
532
+ return walk_abort;
533
+ }
534
+
535
+ if (node instanceof AST_Lambda && !(node instanceof AST_Arrow)) {
536
+ return true;
537
+ }
538
+ });
539
+ }
540
+
541
+ this.uses_with = this.uses_with || scope.uses_with;
542
+ this.uses_eval = this.uses_eval || scope.uses_eval;
524
543
 
525
544
  const scope_ancestry = (() => {
526
545
  const ancestry = [];
@@ -756,7 +775,10 @@ AST_Symbol.DEFMETHOD("global", function() {
756
775
  return this.thedef.global;
757
776
  });
758
777
 
759
- AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
778
+ /**
779
+ * Format the mangler options (if any) into their appropriate types
780
+ */
781
+ export function format_mangler_options(options) {
760
782
  options = defaults(options, {
761
783
  eval : false,
762
784
  nth_identifier : base54,
@@ -777,10 +799,10 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
777
799
  // Never mangle arguments
778
800
  options.reserved.add("arguments");
779
801
  return options;
780
- });
802
+ }
781
803
 
782
804
  AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
783
- options = this._default_mangler_options(options);
805
+ options = format_mangler_options(options);
784
806
  var nth_identifier = options.nth_identifier;
785
807
 
786
808
  // We only need to mangle declaration nodes. Special logic wired
@@ -904,7 +926,7 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
904
926
  });
905
927
 
906
928
  AST_Toplevel.DEFMETHOD("expand_names", function(options) {
907
- options = this._default_mangler_options(options);
929
+ options = format_mangler_options(options);
908
930
  var nth_identifier = options.nth_identifier;
909
931
  if (nth_identifier.reset && nth_identifier.sort) {
910
932
  nth_identifier.reset();
@@ -947,7 +969,7 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
947
969
  });
948
970
 
949
971
  AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
950
- options = this._default_mangler_options(options);
972
+ options = format_mangler_options(options);
951
973
  var nth_identifier = options.nth_identifier;
952
974
  if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) {
953
975
  // If the identifier mangler is invariant, skip computing character frequency.
package/lib/size.js CHANGED
@@ -53,6 +53,7 @@ import {
53
53
  AST_PrivateGetter,
54
54
  AST_PrivateMethod,
55
55
  AST_PrivateSetter,
56
+ AST_PrivateIn,
56
57
  AST_RegExp,
57
58
  AST_Return,
58
59
  AST_Sequence,
@@ -395,6 +396,10 @@ AST_PrivateGetter.prototype._size = AST_PrivateSetter.prototype._size = function
395
396
  return AST_ConciseMethod.prototype._size.call(this) + 4;
396
397
  };
397
398
 
399
+ AST_PrivateIn.prototype._size = function () {
400
+ return 5; // "#", and " in "
401
+ };
402
+
398
403
  AST_Class.prototype._size = function () {
399
404
  return (
400
405
  (this.name ? 8 : 7)
@@ -420,9 +425,11 @@ AST_ClassPrivateProperty.prototype._size = function () {
420
425
  };
421
426
 
422
427
  AST_Symbol.prototype._size = function () {
423
- return !mangle_options || this.definition().unmangleable(mangle_options)
424
- ? this.name.length
425
- : 1;
428
+ if (!(mangle_options && this.thedef && !this.thedef.unmangleable(mangle_options))) {
429
+ return this.name.length;
430
+ } else {
431
+ return 1;
432
+ }
426
433
  };
427
434
 
428
435
  // TODO take propmangle into account
@@ -431,11 +438,7 @@ AST_SymbolClassProperty.prototype._size = function () {
431
438
  };
432
439
 
433
440
  AST_SymbolRef.prototype._size = AST_SymbolDeclaration.prototype._size = function () {
434
- const { name, thedef } = this;
435
-
436
- if (thedef && thedef.global) return name.length;
437
-
438
- if (name === "arguments") return 9;
441
+ if (this.name === "arguments") return 9;
439
442
 
440
443
  return AST_Symbol.prototype._size.call(this);
441
444
  };
package/lib/transform.js CHANGED
@@ -47,6 +47,7 @@ import {
47
47
  AST_Array,
48
48
  AST_Await,
49
49
  AST_Binary,
50
+ AST_PrivateIn,
50
51
  AST_Block,
51
52
  AST_Call,
52
53
  AST_Case,
@@ -259,6 +260,11 @@ def_transform(AST_Binary, function(self, tw) {
259
260
  self.right = self.right.transform(tw);
260
261
  });
261
262
 
263
+ def_transform(AST_PrivateIn, function(self, tw) {
264
+ self.key = self.key.transform(tw);
265
+ self.value = self.value.transform(tw);
266
+ });
267
+
262
268
  def_transform(AST_Conditional, function(self, tw) {
263
269
  self.condition = self.condition.transform(tw);
264
270
  self.consequent = self.consequent.transform(tw);
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "homepage": "https://terser.org",
5
5
  "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
6
6
  "license": "BSD-2-Clause",
7
- "version": "5.15.1",
7
+ "version": "5.16.1",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },