terser 5.17.2 → 5.17.4

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,15 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.17.4
4
+
5
+ - Fix crash when trying to negate a class (`!class{}`)
6
+ - Avoid outputting comments between `yield`/`await` and its argument
7
+ - Fix detection of left-hand-side of assignment, to avoid optimizing it like any other expression in some edge cases
8
+
9
+ ## v5.17.3
10
+
11
+ - Fix issue with trimming a static class property's contents accessing the class as `this`.
12
+
3
13
  ## v5.17.2
4
14
  - Be less conservative when detecting use-before-definition of `var` in hoisted functions.
5
15
  - Support unusual (but perfectly valid) initializers of for-in and for-of loops.
@@ -9345,14 +9345,17 @@ function OutputStream(options) {
9345
9345
  if (!start) return;
9346
9346
  var printed_comments = self.printed_comments;
9347
9347
 
9348
- // There cannot be a newline between return and its value.
9349
- const return_with_value = node instanceof AST_Exit && node.value;
9348
+ // There cannot be a newline between return/yield and its value.
9349
+ const keyword_with_value =
9350
+ node instanceof AST_Exit && node.value
9351
+ || (node instanceof AST_Await || node instanceof AST_Yield)
9352
+ && node.expression;
9350
9353
 
9351
9354
  if (
9352
9355
  start.comments_before
9353
9356
  && printed_comments.has(start.comments_before)
9354
9357
  ) {
9355
- if (return_with_value) {
9358
+ if (keyword_with_value) {
9356
9359
  start.comments_before = [];
9357
9360
  } else {
9358
9361
  return;
@@ -9365,10 +9368,12 @@ function OutputStream(options) {
9365
9368
  }
9366
9369
  printed_comments.add(comments);
9367
9370
 
9368
- if (return_with_value) {
9371
+ if (keyword_with_value) {
9369
9372
  var tw = new TreeWalker(function(node) {
9370
9373
  var parent = tw.parent();
9371
9374
  if (parent instanceof AST_Exit
9375
+ || parent instanceof AST_Await
9376
+ || parent instanceof AST_Yield
9372
9377
  || parent instanceof AST_Binary && parent.left === node
9373
9378
  || parent.TYPE == "Call" && parent.expression === node
9374
9379
  || parent instanceof AST_Conditional && parent.condition === node
@@ -9387,7 +9392,7 @@ function OutputStream(options) {
9387
9392
  }
9388
9393
  });
9389
9394
  tw.push(node);
9390
- node.value.walk(tw);
9395
+ keyword_with_value.walk(tw);
9391
9396
  }
9392
9397
 
9393
9398
  if (current_pos == 0) {
@@ -14022,6 +14027,9 @@ function is_lhs(node, parent) {
14022
14027
  def_negate(AST_Function, function() {
14023
14028
  return basic_negation(this);
14024
14029
  });
14030
+ def_negate(AST_Class, function() {
14031
+ return basic_negation(this);
14032
+ });
14025
14033
  def_negate(AST_Arrow, function() {
14026
14034
  return basic_negation(this);
14027
14035
  });
@@ -14155,6 +14163,19 @@ const aborts = (thing) => thing && thing.aborts();
14155
14163
  node.DEFMETHOD("aborts", func);
14156
14164
  });
14157
14165
 
14166
+ AST_Node.DEFMETHOD("contains_this", function() {
14167
+ return walk(this, node => {
14168
+ if (node instanceof AST_This) return walk_abort;
14169
+ if (
14170
+ node !== this
14171
+ && node instanceof AST_Scope
14172
+ && !(node instanceof AST_Arrow)
14173
+ ) {
14174
+ return true;
14175
+ }
14176
+ });
14177
+ });
14178
+
14158
14179
  function is_modified(compressor, tw, node, value, level, immutable) {
14159
14180
  var parent = tw.parent(level);
14160
14181
  var lhs = is_lhs(node, parent);
@@ -14760,6 +14781,15 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
14760
14781
  }
14761
14782
  }
14762
14783
 
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;
14791
+ }
14792
+
14763
14793
  const trimmed_prop = prop.drop_side_effect_free(compressor);
14764
14794
  if (trimmed_prop)
14765
14795
  with_effects.push(trimmed_prop);
@@ -18313,6 +18343,13 @@ class Compressor extends TreeWalker {
18313
18343
  if (opt === node) set_flag(opt, SQUEEZED);
18314
18344
  return opt;
18315
18345
  }
18346
+
18347
+ /** Alternative to plain is_lhs() which doesn't work within .optimize() */
18348
+ is_lhs() {
18349
+ const self = this.stack[this.stack.length - 1];
18350
+ const parent = this.stack[this.stack.length - 2];
18351
+ return is_lhs(self, parent);
18352
+ }
18316
18353
  }
18317
18354
 
18318
18355
  function def_optimize(node, optimizer) {
@@ -20470,8 +20507,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
20470
20507
  }
20471
20508
  }
20472
20509
 
20473
- const parent = compressor.parent();
20474
- if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
20510
+ if (compressor.option("reduce_vars") && !compressor.is_lhs()) {
20475
20511
  return inline_into_symbolref(self, compressor);
20476
20512
  } else {
20477
20513
  return self;
@@ -20495,7 +20531,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
20495
20531
  return ref;
20496
20532
  }
20497
20533
  }
20498
- var lhs = is_lhs(compressor.self(), compressor.parent());
20534
+ var lhs = compressor.is_lhs();
20499
20535
  if (lhs && is_atomic(lhs, self)) return self;
20500
20536
  return make_node(AST_UnaryPrefix, self, {
20501
20537
  operator: "void",
@@ -20506,7 +20542,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
20506
20542
  });
20507
20543
 
20508
20544
  def_optimize(AST_Infinity, function(self, compressor) {
20509
- var lhs = is_lhs(compressor.self(), compressor.parent());
20545
+ var lhs = compressor.is_lhs();
20510
20546
  if (lhs && is_atomic(lhs, self)) return self;
20511
20547
  if (
20512
20548
  compressor.option("keep_infinity")
@@ -20527,7 +20563,7 @@ def_optimize(AST_Infinity, function(self, compressor) {
20527
20563
  });
20528
20564
 
20529
20565
  def_optimize(AST_NaN, function(self, compressor) {
20530
- var lhs = is_lhs(compressor.self(), compressor.parent());
20566
+ var lhs = compressor.is_lhs();
20531
20567
  if (lhs && !is_atomic(lhs, self)
20532
20568
  || find_variable(compressor, "NaN")) {
20533
20569
  return make_node(AST_Binary, self, {
@@ -21103,7 +21139,10 @@ def_optimize(AST_Sub, function(self, compressor) {
21103
21139
  }
21104
21140
  }
21105
21141
  }
21106
- prop = self.property = best_of_expression(prop, make_node_from_constant(key, prop).transform(compressor));
21142
+ prop = self.property = best_of_expression(
21143
+ prop,
21144
+ make_node_from_constant(key, prop).transform(compressor)
21145
+ );
21107
21146
  var property = "" + key;
21108
21147
  if (is_basic_identifier_string(property)
21109
21148
  && property.length <= prop.size() + 1) {
@@ -21161,7 +21200,7 @@ def_optimize(AST_Sub, function(self, compressor) {
21161
21200
  return sym;
21162
21201
  }
21163
21202
  }
21164
- if (is_lhs(self, compressor.parent())) return self;
21203
+ if (compressor.is_lhs()) return self;
21165
21204
  if (key !== prop) {
21166
21205
  var sub = self.flatten_object(property, compressor);
21167
21206
  if (sub) {
@@ -21229,22 +21268,9 @@ def_optimize(AST_Chain, function (self, compressor) {
21229
21268
  return self;
21230
21269
  });
21231
21270
 
21232
- AST_Lambda.DEFMETHOD("contains_this", function() {
21233
- return walk(this, node => {
21234
- if (node instanceof AST_This) return walk_abort;
21235
- if (
21236
- node !== this
21237
- && node instanceof AST_Scope
21238
- && !(node instanceof AST_Arrow)
21239
- ) {
21240
- return true;
21241
- }
21242
- });
21243
- });
21244
-
21245
21271
  def_optimize(AST_Dot, function(self, compressor) {
21246
21272
  const parent = compressor.parent();
21247
- if (is_lhs(self, parent)) return self;
21273
+ if (compressor.is_lhs()) return self;
21248
21274
  if (compressor.option("unsafe_proto")
21249
21275
  && self.expression instanceof AST_Dot
21250
21276
  && self.expression.property == "prototype") {
@@ -165,6 +165,15 @@ def_drop_side_effect_free(AST_Class, function (compressor) {
165
165
  }
166
166
  }
167
167
 
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;
175
+ }
176
+
168
177
  const trimmed_prop = prop.drop_side_effect_free(compressor);
169
178
  if (trimmed_prop)
170
179
  with_effects.push(trimmed_prop);
@@ -442,6 +442,13 @@ class Compressor extends TreeWalker {
442
442
  if (opt === node) set_flag(opt, SQUEEZED);
443
443
  return opt;
444
444
  }
445
+
446
+ /** Alternative to plain is_lhs() which doesn't work within .optimize() */
447
+ is_lhs() {
448
+ const self = this.stack[this.stack.length - 1];
449
+ const parent = this.stack[this.stack.length - 2];
450
+ return is_lhs(self, parent);
451
+ }
445
452
  }
446
453
 
447
454
  function def_optimize(node, optimizer) {
@@ -2599,8 +2606,7 @@ def_optimize(AST_SymbolRef, function(self, compressor) {
2599
2606
  }
2600
2607
  }
2601
2608
 
2602
- const parent = compressor.parent();
2603
- if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
2609
+ if (compressor.option("reduce_vars") && !compressor.is_lhs()) {
2604
2610
  return inline_into_symbolref(self, compressor);
2605
2611
  } else {
2606
2612
  return self;
@@ -2624,7 +2630,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
2624
2630
  return ref;
2625
2631
  }
2626
2632
  }
2627
- var lhs = is_lhs(compressor.self(), compressor.parent());
2633
+ var lhs = compressor.is_lhs();
2628
2634
  if (lhs && is_atomic(lhs, self)) return self;
2629
2635
  return make_node(AST_UnaryPrefix, self, {
2630
2636
  operator: "void",
@@ -2635,7 +2641,7 @@ def_optimize(AST_Undefined, function(self, compressor) {
2635
2641
  });
2636
2642
 
2637
2643
  def_optimize(AST_Infinity, function(self, compressor) {
2638
- var lhs = is_lhs(compressor.self(), compressor.parent());
2644
+ var lhs = compressor.is_lhs();
2639
2645
  if (lhs && is_atomic(lhs, self)) return self;
2640
2646
  if (
2641
2647
  compressor.option("keep_infinity")
@@ -2656,7 +2662,7 @@ def_optimize(AST_Infinity, function(self, compressor) {
2656
2662
  });
2657
2663
 
2658
2664
  def_optimize(AST_NaN, function(self, compressor) {
2659
- var lhs = is_lhs(compressor.self(), compressor.parent());
2665
+ var lhs = compressor.is_lhs();
2660
2666
  if (lhs && !is_atomic(lhs, self)
2661
2667
  || find_variable(compressor, "NaN")) {
2662
2668
  return make_node(AST_Binary, self, {
@@ -3232,7 +3238,10 @@ def_optimize(AST_Sub, function(self, compressor) {
3232
3238
  }
3233
3239
  }
3234
3240
  }
3235
- prop = self.property = best_of_expression(prop, make_node_from_constant(key, prop).transform(compressor));
3241
+ prop = self.property = best_of_expression(
3242
+ prop,
3243
+ make_node_from_constant(key, prop).transform(compressor)
3244
+ );
3236
3245
  var property = "" + key;
3237
3246
  if (is_basic_identifier_string(property)
3238
3247
  && property.length <= prop.size() + 1) {
@@ -3290,7 +3299,7 @@ def_optimize(AST_Sub, function(self, compressor) {
3290
3299
  return sym;
3291
3300
  }
3292
3301
  }
3293
- if (is_lhs(self, compressor.parent())) return self;
3302
+ if (compressor.is_lhs()) return self;
3294
3303
  if (key !== prop) {
3295
3304
  var sub = self.flatten_object(property, compressor);
3296
3305
  if (sub) {
@@ -3358,22 +3367,9 @@ def_optimize(AST_Chain, function (self, compressor) {
3358
3367
  return self;
3359
3368
  });
3360
3369
 
3361
- AST_Lambda.DEFMETHOD("contains_this", function() {
3362
- return walk(this, node => {
3363
- if (node instanceof AST_This) return walk_abort;
3364
- if (
3365
- node !== this
3366
- && node instanceof AST_Scope
3367
- && !(node instanceof AST_Arrow)
3368
- ) {
3369
- return true;
3370
- }
3371
- });
3372
- });
3373
-
3374
3370
  def_optimize(AST_Dot, function(self, compressor) {
3375
3371
  const parent = compressor.parent();
3376
- if (is_lhs(self, parent)) return self;
3372
+ if (compressor.is_lhs()) return self;
3377
3373
  if (compressor.option("unsafe_proto")
3378
3374
  && self.expression instanceof AST_Dot
3379
3375
  && self.expression.property == "prototype") {
@@ -84,6 +84,7 @@ import {
84
84
  AST_PropAccess,
85
85
  AST_RegExp,
86
86
  AST_Return,
87
+ AST_Scope,
87
88
  AST_Sequence,
88
89
  AST_SimpleStatement,
89
90
  AST_Statement,
@@ -817,6 +818,9 @@ export function is_lhs(node, parent) {
817
818
  def_negate(AST_Function, function() {
818
819
  return basic_negation(this);
819
820
  });
821
+ def_negate(AST_Class, function() {
822
+ return basic_negation(this);
823
+ });
820
824
  def_negate(AST_Arrow, function() {
821
825
  return basic_negation(this);
822
826
  });
@@ -950,6 +954,19 @@ export const aborts = (thing) => thing && thing.aborts();
950
954
  node.DEFMETHOD("aborts", func);
951
955
  });
952
956
 
957
+ AST_Node.DEFMETHOD("contains_this", function() {
958
+ return walk(this, node => {
959
+ if (node instanceof AST_This) return walk_abort;
960
+ if (
961
+ node !== this
962
+ && node instanceof AST_Scope
963
+ && !(node instanceof AST_Arrow)
964
+ ) {
965
+ return true;
966
+ }
967
+ });
968
+ });
969
+
953
970
  export function is_modified(compressor, tw, node, value, level, immutable) {
954
971
  var parent = tw.parent(level);
955
972
  var lhs = is_lhs(node, parent);
package/lib/output.js CHANGED
@@ -662,14 +662,17 @@ function OutputStream(options) {
662
662
  if (!start) return;
663
663
  var printed_comments = self.printed_comments;
664
664
 
665
- // There cannot be a newline between return and its value.
666
- const return_with_value = node instanceof AST_Exit && node.value;
665
+ // There cannot be a newline between return/yield and its value.
666
+ const keyword_with_value =
667
+ node instanceof AST_Exit && node.value
668
+ || (node instanceof AST_Await || node instanceof AST_Yield)
669
+ && node.expression;
667
670
 
668
671
  if (
669
672
  start.comments_before
670
673
  && printed_comments.has(start.comments_before)
671
674
  ) {
672
- if (return_with_value) {
675
+ if (keyword_with_value) {
673
676
  start.comments_before = [];
674
677
  } else {
675
678
  return;
@@ -682,10 +685,12 @@ function OutputStream(options) {
682
685
  }
683
686
  printed_comments.add(comments);
684
687
 
685
- if (return_with_value) {
688
+ if (keyword_with_value) {
686
689
  var tw = new TreeWalker(function(node) {
687
690
  var parent = tw.parent();
688
691
  if (parent instanceof AST_Exit
692
+ || parent instanceof AST_Await
693
+ || parent instanceof AST_Yield
689
694
  || parent instanceof AST_Binary && parent.left === node
690
695
  || parent.TYPE == "Call" && parent.expression === node
691
696
  || parent instanceof AST_Conditional && parent.condition === node
@@ -704,7 +709,7 @@ function OutputStream(options) {
704
709
  }
705
710
  });
706
711
  tw.push(node);
707
- node.value.walk(tw);
712
+ keyword_with_value.walk(tw);
708
713
  }
709
714
 
710
715
  if (current_pos == 0) {
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.2",
7
+ "version": "5.17.4",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },