terser 5.17.4 → 5.17.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.17.6
4
+ - Fixes to mozilla AST input and output, for class properties, private properties and static blocks
5
+ - Fix outputting a shorthand property in quotes when safari10 and ecma=2015 options are enabled
6
+ - `configurable` and `enumerable`, used in Object.defineProperty, added to domprops (#1393)
7
+
8
+ ## v5.17.5
9
+ - Take into account the non-deferred bits of a class, such as static properties, while dropping unused code.
10
+
3
11
  ## v5.17.4
4
12
 
5
13
  - Fix crash when trying to negate a class (`!class{}`)
@@ -5840,6 +5840,40 @@ var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(p
5840
5840
  if (this.extends) push(this.extends);
5841
5841
  if (this.name) push(this.name);
5842
5842
  },
5843
+ /** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */
5844
+ visit_nondeferred_class_parts(visitor) {
5845
+ if (this.extends) {
5846
+ this.extends._walk(visitor);
5847
+ }
5848
+ this.properties.forEach((prop) => {
5849
+ if (prop instanceof AST_ClassStaticBlock) {
5850
+ prop._walk(visitor);
5851
+ return;
5852
+ }
5853
+ if (prop.computed_key()) {
5854
+ visitor.push(prop);
5855
+ prop.key._walk(visitor);
5856
+ visitor.pop();
5857
+ }
5858
+ if ((prop instanceof AST_ClassPrivateProperty || prop instanceof AST_ClassProperty) && prop.static && prop.value) {
5859
+ visitor.push(prop);
5860
+ prop.value._walk(visitor);
5861
+ visitor.pop();
5862
+ }
5863
+ });
5864
+ },
5865
+ /** go through the bits that are executed later, when the class is `new`'d or a static method is called */
5866
+ visit_deferred_class_parts(visitor) {
5867
+ this.properties.forEach((prop) => {
5868
+ if (prop instanceof AST_ConciseMethod) {
5869
+ prop.walk(visitor);
5870
+ } else if (prop instanceof AST_ClassProperty && !prop.static && prop.value) {
5871
+ visitor.push(prop);
5872
+ prop.value._walk(visitor);
5873
+ visitor.pop();
5874
+ }
5875
+ });
5876
+ },
5843
5877
  }, AST_Scope /* TODO a class might have a scope but it's not a scope */);
5844
5878
 
5845
5879
  var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) {
@@ -5956,6 +5990,7 @@ var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", funct
5956
5990
  while (i--) push(this.body[i]);
5957
5991
  },
5958
5992
  clone: clone_block_scope,
5993
+ computed_key: () => false
5959
5994
  }, AST_Scope);
5960
5995
 
5961
5996
  var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) {
@@ -7303,22 +7338,25 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7303
7338
  },
7304
7339
 
7305
7340
  MethodDefinition: function(M) {
7341
+ const is_private = M.key.type === "PrivateIdentifier";
7342
+ const key = M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || M.key.value });
7343
+
7306
7344
  var args = {
7307
7345
  start : my_start_token(M),
7308
7346
  end : my_end_token(M),
7309
- key : M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || M.key.value }),
7347
+ key,
7310
7348
  value : from_moz(M.value),
7311
7349
  static : M.static,
7312
7350
  };
7313
7351
  if (M.kind == "get") {
7314
- return new AST_ObjectGetter(args);
7352
+ return new (is_private ? AST_PrivateGetter : AST_ObjectGetter)(args);
7315
7353
  }
7316
7354
  if (M.kind == "set") {
7317
- return new AST_ObjectSetter(args);
7355
+ return new (is_private ? AST_PrivateSetter : AST_ObjectSetter)(args);
7318
7356
  }
7319
7357
  args.is_generator = M.value.generator;
7320
7358
  args.async = M.value.async;
7321
- return new AST_ConciseMethod(args);
7359
+ return new (is_private ? AST_PrivateMethod : AST_ConciseMethod)(args);
7322
7360
  },
7323
7361
 
7324
7362
  FieldDefinition: function(M) {
@@ -7342,8 +7380,16 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7342
7380
  let key;
7343
7381
  if (M.computed) {
7344
7382
  key = from_moz(M.key);
7383
+ } else if (M.key.type === "PrivateIdentifier") {
7384
+ return new AST_ClassPrivateProperty({
7385
+ start : my_start_token(M),
7386
+ end : my_end_token(M),
7387
+ key : from_moz(M.key),
7388
+ value : from_moz(M.value),
7389
+ static : M.static,
7390
+ });
7345
7391
  } else {
7346
- if (M.key.type !== "Identifier" && M.key.type !== "PrivateIdentifier") {
7392
+ if (M.key.type !== "Identifier") {
7347
7393
  throw new Error("Non-Identifier key in PropertyDefinition");
7348
7394
  }
7349
7395
  key = from_moz(M.key);
@@ -7358,6 +7404,14 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7358
7404
  });
7359
7405
  },
7360
7406
 
7407
+ PrivateIdentifier: function (M) {
7408
+ return new AST_SymbolPrivateProperty({
7409
+ start: my_start_token(M),
7410
+ end: my_end_token(M),
7411
+ name: M.name
7412
+ });
7413
+ },
7414
+
7361
7415
  StaticBlock: function(M) {
7362
7416
  return new AST_ClassStaticBlock({
7363
7417
  start : my_start_token(M),
@@ -7399,6 +7453,15 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
7399
7453
  },
7400
7454
 
7401
7455
  MemberExpression: function(M) {
7456
+ if (M.property.type === "PrivateIdentifier") {
7457
+ return new AST_DotHash({
7458
+ start : my_start_token(M),
7459
+ end : my_end_token(M),
7460
+ property : M.property.name,
7461
+ expression : from_moz(M.object),
7462
+ optional : M.optional || false
7463
+ });
7464
+ }
7402
7465
  return new (M.computed ? AST_Sub : AST_Dot)({
7403
7466
  start : my_start_token(M),
7404
7467
  end : my_end_token(M),
@@ -10600,7 +10663,7 @@ function OutputStream(options) {
10600
10663
  ? output.option("ie8")
10601
10664
  : !is_identifier_string(
10602
10665
  prop,
10603
- output.option("ecma") >= 2015 || output.option("safari10")
10666
+ output.option("ecma") >= 2015 && !output.option("safari10")
10604
10667
  );
10605
10668
 
10606
10669
  if (self.optional) output.print("?.");
@@ -10768,15 +10831,19 @@ function OutputStream(options) {
10768
10831
  output.print("new.target");
10769
10832
  });
10770
10833
 
10834
+ /** Prints a prop name. Returns whether it can be used as a shorthand. */
10771
10835
  function print_property_name(key, quote, output) {
10772
10836
  if (output.option("quote_keys")) {
10773
- return output.print_string(key);
10837
+ output.print_string(key);
10838
+ return false;
10774
10839
  }
10775
10840
  if ("" + +key == key && key >= 0) {
10776
10841
  if (output.option("keep_numbers")) {
10777
- return output.print(key);
10842
+ output.print(key);
10843
+ return false;
10778
10844
  }
10779
- return output.print(make_num(key));
10845
+ output.print(make_num(key));
10846
+ return false;
10780
10847
  }
10781
10848
  var print_string = ALL_RESERVED_WORDS.has(key)
10782
10849
  ? output.option("ie8")
@@ -10786,9 +10853,11 @@ function OutputStream(options) {
10786
10853
  : !is_identifier_string(key, true)
10787
10854
  );
10788
10855
  if (print_string || (quote && output.option("keep_quoted_props"))) {
10789
- return output.print_string(key, quote);
10856
+ output.print_string(key, quote);
10857
+ return false;
10790
10858
  }
10791
- return output.print_name(key);
10859
+ output.print_name(key);
10860
+ return true;
10792
10861
  }
10793
10862
 
10794
10863
  DEFPRINT(AST_ObjectKeyVal, function(self, output) {
@@ -10797,28 +10866,29 @@ function OutputStream(options) {
10797
10866
  return def ? def.mangled_name || def.name : self.name;
10798
10867
  }
10799
10868
 
10800
- var allowShortHand = output.option("shorthand");
10801
- if (allowShortHand &&
10802
- self.value instanceof AST_Symbol &&
10803
- is_identifier_string(
10804
- self.key,
10805
- output.option("ecma") >= 2015 || output.option("safari10")
10806
- ) &&
10807
- get_name(self.value) === self.key &&
10808
- !ALL_RESERVED_WORDS.has(self.key)
10869
+ const try_shorthand = output.option("shorthand") && !(self.key instanceof AST_Node);
10870
+ if (
10871
+ try_shorthand
10872
+ && self.value instanceof AST_Symbol
10873
+ && get_name(self.value) === self.key
10874
+ && !ALL_RESERVED_WORDS.has(self.key)
10809
10875
  ) {
10810
- print_property_name(self.key, self.quote, output);
10811
-
10812
- } else if (allowShortHand &&
10813
- self.value instanceof AST_DefaultAssign &&
10814
- self.value.left instanceof AST_Symbol &&
10815
- is_identifier_string(
10816
- self.key,
10817
- output.option("ecma") >= 2015 || output.option("safari10")
10818
- ) &&
10819
- get_name(self.value.left) === self.key
10876
+ const was_shorthand = print_property_name(self.key, self.quote, output);
10877
+ if (!was_shorthand) {
10878
+ output.colon();
10879
+ self.value.print(output);
10880
+ }
10881
+ } else if (
10882
+ try_shorthand
10883
+ && self.value instanceof AST_DefaultAssign
10884
+ && self.value.left instanceof AST_Symbol
10885
+ && get_name(self.value.left) === self.key
10820
10886
  ) {
10821
- print_property_name(self.key, self.quote, output);
10887
+ const was_shorthand = print_property_name(self.key, self.quote, output);
10888
+ if (!was_shorthand) {
10889
+ output.colon();
10890
+ self.value.left.print(output);
10891
+ }
10822
10892
  output.space();
10823
10893
  output.print("=");
10824
10894
  output.space();
@@ -14772,31 +14842,43 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
14772
14842
  const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
14773
14843
  if (trimmed_extends)
14774
14844
  with_effects.push(trimmed_extends);
14845
+
14775
14846
  for (const prop of this.properties) {
14776
14847
  if (prop instanceof AST_ClassStaticBlock) {
14777
- if (prop.body.some(stat => stat.has_side_effects(compressor))) {
14778
- return this;
14779
- } else {
14780
- continue;
14848
+ if (prop.has_side_effects(compressor)) {
14849
+ return this; // Be cautious about these
14781
14850
  }
14782
- }
14851
+ } else {
14852
+ const trimmed_prop = prop.drop_side_effect_free(compressor);
14853
+ if (trimmed_prop) {
14854
+ if (trimmed_prop.contains_this()) return this;
14783
14855
 
14784
- if (
14785
- prop instanceof AST_ClassProperty
14786
- && prop.static
14787
- && prop.value.has_side_effects(compressor)
14788
- && prop.contains_this()
14789
- ) {
14790
- return this;
14856
+ with_effects.push(trimmed_prop);
14857
+ }
14791
14858
  }
14792
-
14793
- const trimmed_prop = prop.drop_side_effect_free(compressor);
14794
- if (trimmed_prop)
14795
- with_effects.push(trimmed_prop);
14796
14859
  }
14860
+
14797
14861
  if (!with_effects.length)
14798
14862
  return null;
14799
- return make_sequence(this, with_effects);
14863
+
14864
+ const exprs = make_sequence(this, with_effects);
14865
+ if (this instanceof AST_DefClass) {
14866
+ // We want a statement
14867
+ return make_node(AST_SimpleStatement, this, { body: exprs });
14868
+ } else {
14869
+ return exprs;
14870
+ }
14871
+ });
14872
+
14873
+ def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
14874
+ const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
14875
+
14876
+ const value = this.static && this.value
14877
+ && this.value.drop_side_effect_free(compressor);
14878
+
14879
+ if (key && value)
14880
+ return make_sequence(this, [key, value]);
14881
+ return key || value || null;
14800
14882
  });
14801
14883
 
14802
14884
  def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
@@ -14902,17 +14984,6 @@ def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_sta
14902
14984
  return key || value;
14903
14985
  });
14904
14986
 
14905
- def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
14906
- const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
14907
-
14908
- const value = this.static && this.value
14909
- && this.value.drop_side_effect_free(compressor);
14910
-
14911
- if (key && value)
14912
- return make_sequence(this, [key, value]);
14913
- return key || value || null;
14914
- });
14915
-
14916
14987
  def_drop_side_effect_free(AST_ConciseMethod, function () {
14917
14988
  return this.computed_key() ? this.key : null;
14918
14989
  });
@@ -15072,6 +15143,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15072
15143
  });
15073
15144
  }
15074
15145
  if (node === self) return;
15146
+ if (node instanceof AST_Class) {
15147
+ if (node.has_side_effects(compressor)) {
15148
+ node.visit_nondeferred_class_parts(tw);
15149
+ }
15150
+ }
15075
15151
  if (node instanceof AST_Defun || node instanceof AST_DefClass) {
15076
15152
  var node_def = node.name.definition();
15077
15153
  const in_export = tw.parent() instanceof AST_Export;
@@ -15080,23 +15156,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15080
15156
  in_use_ids.set(node_def.id, node_def);
15081
15157
  }
15082
15158
  }
15083
- if (node instanceof AST_DefClass) {
15084
- if (
15085
- node.extends
15086
- && (node.extends.has_side_effects(compressor)
15087
- || node.extends.may_throw(compressor))
15088
- ) {
15089
- node.extends.walk(tw);
15090
- }
15091
- for (const prop of node.properties) {
15092
- if (
15093
- prop.has_side_effects(compressor) ||
15094
- prop.may_throw(compressor)
15095
- ) {
15096
- prop.walk(tw);
15097
- }
15098
- }
15099
- }
15159
+
15100
15160
  map_add(initializations, node_def.id, node);
15101
15161
  return true; // don't go in nested scopes
15102
15162
  }
@@ -15161,9 +15221,9 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15161
15221
  if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
15162
15222
  return maintain_this_binding(parent, node, node.right.transform(tt));
15163
15223
  }
15164
- } else if (!in_use) return in_list ? MAP.skip : make_node(AST_Number, node, {
15165
- value: 0
15166
- });
15224
+ } else if (!in_use) {
15225
+ return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
15226
+ }
15167
15227
  }
15168
15228
  }
15169
15229
  if (scope !== self) return;
@@ -15206,11 +15266,18 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15206
15266
  if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
15207
15267
  const def = node.name.definition();
15208
15268
  const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
15209
- // Class "extends" and static blocks may have side effects
15210
- const has_side_effects = !keep
15211
- && node instanceof AST_Class
15212
- && node.has_side_effects(compressor);
15213
- if (!keep && !has_side_effects) {
15269
+ if (!keep) {
15270
+ // Class "extends" and static blocks may have side effects
15271
+ if (node instanceof AST_Class) {
15272
+ const kept = node.drop_side_effect_free(compressor);
15273
+ if (kept !== node) {
15274
+ def.eliminated++;
15275
+ if (kept) return kept;
15276
+ return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
15277
+ } else {
15278
+ return kept;
15279
+ }
15280
+ }
15214
15281
  def.eliminated++;
15215
15282
  return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
15216
15283
  }
@@ -15306,9 +15373,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15306
15373
  case 1:
15307
15374
  return body[0];
15308
15375
  default:
15309
- return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
15310
- body: body
15311
- });
15376
+ return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { body });
15312
15377
  }
15313
15378
  }
15314
15379
  // certain combination of unused name + side effect leads to:
@@ -15351,7 +15416,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15351
15416
  }
15352
15417
  return node;
15353
15418
  }
15354
- if (node instanceof AST_Scope) {
15419
+ if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
15355
15420
  const save_scope = scope;
15356
15421
  scope = node;
15357
15422
  descend(node, this);
@@ -15390,7 +15455,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
15390
15455
  }
15391
15456
  return true;
15392
15457
  }
15393
- if (node instanceof AST_Scope) {
15458
+ if (node instanceof AST_Class) {
15459
+ descend();
15460
+ return true;
15461
+ }
15462
+ if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
15394
15463
  var save_scope = scope;
15395
15464
  scope = node;
15396
15465
  descend();
@@ -18556,8 +18625,6 @@ def_optimize(AST_Lambda, opt_AST_Lambda);
18556
18625
  AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
18557
18626
  var self = this;
18558
18627
  if (compressor.has_directive("use asm")) return self;
18559
- // Hoisting makes no sense in an arrow func
18560
- if (!Array.isArray(self.body)) return self;
18561
18628
 
18562
18629
  var hoist_funs = compressor.option("hoist_funs");
18563
18630
  var hoist_vars = compressor.option("hoist_vars");
@@ -25381,6 +25448,7 @@ var domprops = [
25381
25448
  "coneInnerAngle",
25382
25449
  "coneOuterAngle",
25383
25450
  "coneOuterGain",
25451
+ "configurable",
25384
25452
  "configuration",
25385
25453
  "configurationName",
25386
25454
  "configurationValue",
@@ -25890,6 +25958,7 @@ var domprops = [
25890
25958
  "entities",
25891
25959
  "entries",
25892
25960
  "entryType",
25961
+ "enumerable",
25893
25962
  "enumerate",
25894
25963
  "enumerateDevices",
25895
25964
  "enumerateEditable",
package/lib/ast.js CHANGED
@@ -2230,6 +2230,40 @@ var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(p
2230
2230
  if (this.extends) push(this.extends);
2231
2231
  if (this.name) push(this.name);
2232
2232
  },
2233
+ /** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */
2234
+ visit_nondeferred_class_parts(visitor) {
2235
+ if (this.extends) {
2236
+ this.extends._walk(visitor);
2237
+ }
2238
+ this.properties.forEach((prop) => {
2239
+ if (prop instanceof AST_ClassStaticBlock) {
2240
+ prop._walk(visitor);
2241
+ return;
2242
+ }
2243
+ if (prop.computed_key()) {
2244
+ visitor.push(prop);
2245
+ prop.key._walk(visitor);
2246
+ visitor.pop();
2247
+ }
2248
+ if ((prop instanceof AST_ClassPrivateProperty || prop instanceof AST_ClassProperty) && prop.static && prop.value) {
2249
+ visitor.push(prop);
2250
+ prop.value._walk(visitor);
2251
+ visitor.pop();
2252
+ }
2253
+ });
2254
+ },
2255
+ /** go through the bits that are executed later, when the class is `new`'d or a static method is called */
2256
+ visit_deferred_class_parts(visitor) {
2257
+ this.properties.forEach((prop) => {
2258
+ if (prop instanceof AST_ConciseMethod) {
2259
+ prop.walk(visitor);
2260
+ } else if (prop instanceof AST_ClassProperty && !prop.static && prop.value) {
2261
+ visitor.push(prop);
2262
+ prop.value._walk(visitor);
2263
+ visitor.pop();
2264
+ }
2265
+ });
2266
+ },
2233
2267
  }, AST_Scope /* TODO a class might have a scope but it's not a scope */);
2234
2268
 
2235
2269
  var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) {
@@ -2346,6 +2380,7 @@ var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", funct
2346
2380
  while (i--) push(this.body[i]);
2347
2381
  },
2348
2382
  clone: clone_block_scope,
2383
+ computed_key: () => false
2349
2384
  }, AST_Scope);
2350
2385
 
2351
2386
  var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) {
@@ -55,6 +55,7 @@ import {
55
55
  AST_ConciseMethod,
56
56
  AST_Conditional,
57
57
  AST_Constant,
58
+ AST_DefClass,
58
59
  AST_Dot,
59
60
  AST_Expansion,
60
61
  AST_Function,
@@ -68,6 +69,7 @@ import {
68
69
  AST_PropAccess,
69
70
  AST_Scope,
70
71
  AST_Sequence,
72
+ AST_SimpleStatement,
71
73
  AST_Sub,
72
74
  AST_SymbolRef,
73
75
  AST_TemplateSegment,
@@ -156,31 +158,43 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
156
158
  const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
157
159
  if (trimmed_extends)
158
160
  with_effects.push(trimmed_extends);
161
+
159
162
  for (const prop of this.properties) {
160
163
  if (prop instanceof AST_ClassStaticBlock) {
161
- if (prop.body.some(stat => stat.has_side_effects(compressor))) {
162
- return this;
163
- } else {
164
- continue;
164
+ if (prop.has_side_effects(compressor)) {
165
+ return this; // Be cautious about these
165
166
  }
166
- }
167
+ } else {
168
+ const trimmed_prop = prop.drop_side_effect_free(compressor);
169
+ if (trimmed_prop) {
170
+ if (trimmed_prop.contains_this()) return this;
167
171
 
168
- if (
169
- prop instanceof AST_ClassProperty
170
- && prop.static
171
- && prop.value.has_side_effects(compressor)
172
- && prop.contains_this()
173
- ) {
174
- return this;
172
+ with_effects.push(trimmed_prop);
173
+ }
175
174
  }
176
-
177
- const trimmed_prop = prop.drop_side_effect_free(compressor);
178
- if (trimmed_prop)
179
- with_effects.push(trimmed_prop);
180
175
  }
176
+
181
177
  if (!with_effects.length)
182
178
  return null;
183
- return make_sequence(this, with_effects);
179
+
180
+ const exprs = make_sequence(this, with_effects);
181
+ if (this instanceof AST_DefClass) {
182
+ // We want a statement
183
+ return make_node(AST_SimpleStatement, this, { body: exprs });
184
+ } else {
185
+ return exprs;
186
+ }
187
+ });
188
+
189
+ def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
190
+ const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
191
+
192
+ const value = this.static && this.value
193
+ && this.value.drop_side_effect_free(compressor);
194
+
195
+ if (key && value)
196
+ return make_sequence(this, [key, value]);
197
+ return key || value || null;
184
198
  });
185
199
 
186
200
  def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
@@ -286,17 +300,6 @@ def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_sta
286
300
  return key || value;
287
301
  });
288
302
 
289
- def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
290
- const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
291
-
292
- const value = this.static && this.value
293
- && this.value.drop_side_effect_free(compressor);
294
-
295
- if (key && value)
296
- return make_sequence(this, [key, value]);
297
- return key || value || null;
298
- });
299
-
300
303
  def_drop_side_effect_free(AST_ConciseMethod, function () {
301
304
  return this.computed_key() ? this.key : null;
302
305
  });
@@ -47,6 +47,7 @@ import {
47
47
  AST_BlockStatement,
48
48
  AST_Class,
49
49
  AST_ClassExpression,
50
+ AST_ClassStaticBlock,
50
51
  AST_DefaultAssign,
51
52
  AST_DefClass,
52
53
  AST_Definitions,
@@ -152,6 +153,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
152
153
  });
153
154
  }
154
155
  if (node === self) return;
156
+ if (node instanceof AST_Class) {
157
+ if (node.has_side_effects(compressor)) {
158
+ node.visit_nondeferred_class_parts(tw);
159
+ }
160
+ }
155
161
  if (node instanceof AST_Defun || node instanceof AST_DefClass) {
156
162
  var node_def = node.name.definition();
157
163
  const in_export = tw.parent() instanceof AST_Export;
@@ -160,23 +166,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
160
166
  in_use_ids.set(node_def.id, node_def);
161
167
  }
162
168
  }
163
- if (node instanceof AST_DefClass) {
164
- if (
165
- node.extends
166
- && (node.extends.has_side_effects(compressor)
167
- || node.extends.may_throw(compressor))
168
- ) {
169
- node.extends.walk(tw);
170
- }
171
- for (const prop of node.properties) {
172
- if (
173
- prop.has_side_effects(compressor) ||
174
- prop.may_throw(compressor)
175
- ) {
176
- prop.walk(tw);
177
- }
178
- }
179
- }
169
+
180
170
  map_add(initializations, node_def.id, node);
181
171
  return true; // don't go in nested scopes
182
172
  }
@@ -241,9 +231,9 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
241
231
  if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
242
232
  return maintain_this_binding(parent, node, node.right.transform(tt));
243
233
  }
244
- } else if (!in_use) return in_list ? MAP.skip : make_node(AST_Number, node, {
245
- value: 0
246
- });
234
+ } else if (!in_use) {
235
+ return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
236
+ }
247
237
  }
248
238
  }
249
239
  if (scope !== self) return;
@@ -286,11 +276,18 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
286
276
  if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
287
277
  const def = node.name.definition();
288
278
  const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
289
- // Class "extends" and static blocks may have side effects
290
- const has_side_effects = !keep
291
- && node instanceof AST_Class
292
- && node.has_side_effects(compressor);
293
- if (!keep && !has_side_effects) {
279
+ if (!keep) {
280
+ // Class "extends" and static blocks may have side effects
281
+ if (node instanceof AST_Class) {
282
+ const kept = node.drop_side_effect_free(compressor);
283
+ if (kept !== node) {
284
+ def.eliminated++;
285
+ if (kept) return kept;
286
+ return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
287
+ } else {
288
+ return kept;
289
+ }
290
+ }
294
291
  def.eliminated++;
295
292
  return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
296
293
  }
@@ -386,9 +383,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
386
383
  case 1:
387
384
  return body[0];
388
385
  default:
389
- return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
390
- body: body
391
- });
386
+ return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { body });
392
387
  }
393
388
  }
394
389
  // certain combination of unused name + side effect leads to:
@@ -431,7 +426,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
431
426
  }
432
427
  return node;
433
428
  }
434
- if (node instanceof AST_Scope) {
429
+ if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
435
430
  const save_scope = scope;
436
431
  scope = node;
437
432
  descend(node, this);
@@ -470,7 +465,11 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
470
465
  }
471
466
  return true;
472
467
  }
473
- if (node instanceof AST_Scope) {
468
+ if (node instanceof AST_Class) {
469
+ descend();
470
+ return true;
471
+ }
472
+ if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
474
473
  var save_scope = scope;
475
474
  scope = node;
476
475
  descend();
@@ -655,8 +655,6 @@ def_optimize(AST_Lambda, opt_AST_Lambda);
655
655
  AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
656
656
  var self = this;
657
657
  if (compressor.has_directive("use asm")) return self;
658
- // Hoisting makes no sense in an arrow func
659
- if (!Array.isArray(self.body)) return self;
660
658
 
661
659
  var hoist_funs = compressor.option("hoist_funs");
662
660
  var hoist_vars = compressor.option("hoist_vars");
@@ -395,22 +395,25 @@ import { is_basic_identifier_string } from "./parse.js";
395
395
  },
396
396
 
397
397
  MethodDefinition: function(M) {
398
+ const is_private = M.key.type === "PrivateIdentifier";
399
+ const key = M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || M.key.value });
400
+
398
401
  var args = {
399
402
  start : my_start_token(M),
400
403
  end : my_end_token(M),
401
- key : M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || M.key.value }),
404
+ key,
402
405
  value : from_moz(M.value),
403
406
  static : M.static,
404
407
  };
405
408
  if (M.kind == "get") {
406
- return new AST_ObjectGetter(args);
409
+ return new (is_private ? AST_PrivateGetter : AST_ObjectGetter)(args);
407
410
  }
408
411
  if (M.kind == "set") {
409
- return new AST_ObjectSetter(args);
412
+ return new (is_private ? AST_PrivateSetter : AST_ObjectSetter)(args);
410
413
  }
411
414
  args.is_generator = M.value.generator;
412
415
  args.async = M.value.async;
413
- return new AST_ConciseMethod(args);
416
+ return new (is_private ? AST_PrivateMethod : AST_ConciseMethod)(args);
414
417
  },
415
418
 
416
419
  FieldDefinition: function(M) {
@@ -434,8 +437,16 @@ import { is_basic_identifier_string } from "./parse.js";
434
437
  let key;
435
438
  if (M.computed) {
436
439
  key = from_moz(M.key);
440
+ } else if (M.key.type === "PrivateIdentifier") {
441
+ return new AST_ClassPrivateProperty({
442
+ start : my_start_token(M),
443
+ end : my_end_token(M),
444
+ key : from_moz(M.key),
445
+ value : from_moz(M.value),
446
+ static : M.static,
447
+ });
437
448
  } else {
438
- if (M.key.type !== "Identifier" && M.key.type !== "PrivateIdentifier") {
449
+ if (M.key.type !== "Identifier") {
439
450
  throw new Error("Non-Identifier key in PropertyDefinition");
440
451
  }
441
452
  key = from_moz(M.key);
@@ -450,6 +461,14 @@ import { is_basic_identifier_string } from "./parse.js";
450
461
  });
451
462
  },
452
463
 
464
+ PrivateIdentifier: function (M) {
465
+ return new AST_SymbolPrivateProperty({
466
+ start: my_start_token(M),
467
+ end: my_end_token(M),
468
+ name: M.name
469
+ });
470
+ },
471
+
453
472
  StaticBlock: function(M) {
454
473
  return new AST_ClassStaticBlock({
455
474
  start : my_start_token(M),
@@ -491,6 +510,15 @@ import { is_basic_identifier_string } from "./parse.js";
491
510
  },
492
511
 
493
512
  MemberExpression: function(M) {
513
+ if (M.property.type === "PrivateIdentifier") {
514
+ return new AST_DotHash({
515
+ start : my_start_token(M),
516
+ end : my_end_token(M),
517
+ property : M.property.name,
518
+ expression : from_moz(M.object),
519
+ optional : M.optional || false
520
+ });
521
+ }
494
522
  return new (M.computed ? AST_Sub : AST_Dot)({
495
523
  start : my_start_token(M),
496
524
  end : my_end_token(M),
package/lib/output.js CHANGED
@@ -1917,7 +1917,7 @@ function OutputStream(options) {
1917
1917
  ? output.option("ie8")
1918
1918
  : !is_identifier_string(
1919
1919
  prop,
1920
- output.option("ecma") >= 2015 || output.option("safari10")
1920
+ output.option("ecma") >= 2015 && !output.option("safari10")
1921
1921
  );
1922
1922
 
1923
1923
  if (self.optional) output.print("?.");
@@ -2085,15 +2085,19 @@ function OutputStream(options) {
2085
2085
  output.print("new.target");
2086
2086
  });
2087
2087
 
2088
+ /** Prints a prop name. Returns whether it can be used as a shorthand. */
2088
2089
  function print_property_name(key, quote, output) {
2089
2090
  if (output.option("quote_keys")) {
2090
- return output.print_string(key);
2091
+ output.print_string(key);
2092
+ return false;
2091
2093
  }
2092
2094
  if ("" + +key == key && key >= 0) {
2093
2095
  if (output.option("keep_numbers")) {
2094
- return output.print(key);
2096
+ output.print(key);
2097
+ return false;
2095
2098
  }
2096
- return output.print(make_num(key));
2099
+ output.print(make_num(key));
2100
+ return false;
2097
2101
  }
2098
2102
  var print_string = ALL_RESERVED_WORDS.has(key)
2099
2103
  ? output.option("ie8")
@@ -2103,9 +2107,11 @@ function OutputStream(options) {
2103
2107
  : !is_identifier_string(key, true)
2104
2108
  );
2105
2109
  if (print_string || (quote && output.option("keep_quoted_props"))) {
2106
- return output.print_string(key, quote);
2110
+ output.print_string(key, quote);
2111
+ return false;
2107
2112
  }
2108
- return output.print_name(key);
2113
+ output.print_name(key);
2114
+ return true;
2109
2115
  }
2110
2116
 
2111
2117
  DEFPRINT(AST_ObjectKeyVal, function(self, output) {
@@ -2114,28 +2120,29 @@ function OutputStream(options) {
2114
2120
  return def ? def.mangled_name || def.name : self.name;
2115
2121
  }
2116
2122
 
2117
- var allowShortHand = output.option("shorthand");
2118
- if (allowShortHand &&
2119
- self.value instanceof AST_Symbol &&
2120
- is_identifier_string(
2121
- self.key,
2122
- output.option("ecma") >= 2015 || output.option("safari10")
2123
- ) &&
2124
- get_name(self.value) === self.key &&
2125
- !ALL_RESERVED_WORDS.has(self.key)
2123
+ const try_shorthand = output.option("shorthand") && !(self.key instanceof AST_Node);
2124
+ if (
2125
+ try_shorthand
2126
+ && self.value instanceof AST_Symbol
2127
+ && get_name(self.value) === self.key
2128
+ && !ALL_RESERVED_WORDS.has(self.key)
2126
2129
  ) {
2127
- print_property_name(self.key, self.quote, output);
2128
-
2129
- } else if (allowShortHand &&
2130
- self.value instanceof AST_DefaultAssign &&
2131
- self.value.left instanceof AST_Symbol &&
2132
- is_identifier_string(
2133
- self.key,
2134
- output.option("ecma") >= 2015 || output.option("safari10")
2135
- ) &&
2136
- get_name(self.value.left) === self.key
2130
+ const was_shorthand = print_property_name(self.key, self.quote, output);
2131
+ if (!was_shorthand) {
2132
+ output.colon();
2133
+ self.value.print(output);
2134
+ }
2135
+ } else if (
2136
+ try_shorthand
2137
+ && self.value instanceof AST_DefaultAssign
2138
+ && self.value.left instanceof AST_Symbol
2139
+ && get_name(self.value.left) === self.key
2137
2140
  ) {
2138
- print_property_name(self.key, self.quote, output);
2141
+ const was_shorthand = print_property_name(self.key, self.quote, output);
2142
+ if (!was_shorthand) {
2143
+ output.colon();
2144
+ self.value.left.print(output);
2145
+ }
2139
2146
  output.space();
2140
2147
  output.print("=");
2141
2148
  output.space();
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.17.4",
7
+ "version": "5.17.6",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },
package/tools/domprops.js CHANGED
@@ -3575,6 +3575,7 @@ export var domprops = [
3575
3575
  "coneInnerAngle",
3576
3576
  "coneOuterAngle",
3577
3577
  "coneOuterGain",
3578
+ "configurable",
3578
3579
  "configuration",
3579
3580
  "configurationName",
3580
3581
  "configurationValue",
@@ -4084,6 +4085,7 @@ export var domprops = [
4084
4085
  "entities",
4085
4086
  "entries",
4086
4087
  "entryType",
4088
+ "enumerable",
4087
4089
  "enumerate",
4088
4090
  "enumerateDevices",
4089
4091
  "enumerateEditable",