terser 5.30.1 → 5.30.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.30.3
4
+ - Fix precedence of `#private in ...` operator
5
+
6
+ ## v5.30.2
7
+ - Avoid optimizations inside computed keys, because they can cause js-engine-specific bugs.
8
+
3
9
  ## v5.30.1
4
10
  - Removed useless `\` escapes for non-ascii characters
5
11
  - Make modern identifier characters quoted for older environments (#1512)
@@ -1172,9 +1172,8 @@ var LOGICAL_ASSIGNMENT = makePredicate([ "??=", "&&=", "||=" ]);
1172
1172
 
1173
1173
  var PRECEDENCE = (function(a, ret) {
1174
1174
  for (var i = 0; i < a.length; ++i) {
1175
- var b = a[i];
1176
- for (var j = 0; j < b.length; ++j) {
1177
- ret[b[j]] = i + 1;
1175
+ for (const op of a[i]) {
1176
+ ret[op] = i + 1;
1178
1177
  }
1179
1178
  }
1180
1179
  return ret;
@@ -2526,29 +2525,6 @@ function parse($TEXT, options) {
2526
2525
  if (is("template_head")) {
2527
2526
  return subscripts(template_string(), allow_calls);
2528
2527
  }
2529
- if (is("privatename")) {
2530
- if(!S.in_class) {
2531
- croak("Private field must be used in an enclosing class");
2532
- }
2533
-
2534
- const start = S.token;
2535
- const key = new AST_SymbolPrivateProperty({
2536
- start,
2537
- name: start.value,
2538
- end: start
2539
- });
2540
- next();
2541
- expect_token("operator", "in");
2542
-
2543
- const private_in = new AST_PrivateIn({
2544
- start,
2545
- key,
2546
- value: subscripts(as_atom_node(), allow_calls),
2547
- end: prev()
2548
- });
2549
-
2550
- return subscripts(private_in, allow_calls);
2551
- }
2552
2528
  if (ATOMIC_START_TOKEN.has(S.token.type)) {
2553
2529
  return subscripts(as_atom_node(), allow_calls);
2554
2530
  }
@@ -3461,7 +3437,32 @@ function parse($TEXT, options) {
3461
3437
  };
3462
3438
 
3463
3439
  function expr_ops(no_in) {
3464
- return expr_op(maybe_unary(true, true), 0, no_in);
3440
+ // maybe_unary won't return us a AST_SymbolPrivateProperty
3441
+ if (!no_in && is("privatename")) {
3442
+ if(!S.in_class) {
3443
+ croak("Private field must be used in an enclosing class");
3444
+ }
3445
+
3446
+ const start = S.token;
3447
+ const key = new AST_SymbolPrivateProperty({
3448
+ start,
3449
+ name: start.value,
3450
+ end: start
3451
+ });
3452
+ next();
3453
+ expect_token("operator", "in");
3454
+
3455
+ const private_in = new AST_PrivateIn({
3456
+ start,
3457
+ key,
3458
+ value: expr_op(maybe_unary(true), PRECEDENCE["in"], no_in),
3459
+ end: prev()
3460
+ });
3461
+
3462
+ return expr_op(private_in, 0, no_in);
3463
+ } else {
3464
+ return expr_op(maybe_unary(true, true), 0, no_in);
3465
+ }
3465
3466
  }
3466
3467
 
3467
3468
  var maybe_conditional = function(no_in) {
@@ -9846,25 +9847,66 @@ function OutputStream(options) {
9846
9847
  return true;
9847
9848
  // this deals with precedence: 3 * (2 + 1)
9848
9849
  if (p instanceof AST_Binary) {
9849
- const po = p.operator;
9850
- const so = this.operator;
9850
+ const parent_op = p.operator;
9851
+ const op = this.operator;
9851
9852
 
9852
- if (so === "??" && (po === "||" || po === "&&")) {
9853
+ // It is forbidden for ?? to be used with || or && without parens.
9854
+ if (op === "??" && (parent_op === "||" || parent_op === "&&")) {
9855
+ return true;
9856
+ }
9857
+ if (parent_op === "??" && (op === "||" || op === "&&")) {
9853
9858
  return true;
9854
9859
  }
9855
9860
 
9856
- if (po === "??" && (so === "||" || so === "&&")) {
9861
+ const pp = PRECEDENCE[parent_op];
9862
+ const sp = PRECEDENCE[op];
9863
+ if (pp > sp
9864
+ || (pp == sp
9865
+ && (this === p.right || parent_op == "**"))) {
9857
9866
  return true;
9858
9867
  }
9868
+ }
9869
+ if (p instanceof AST_PrivateIn) {
9870
+ const op = this.operator;
9859
9871
 
9860
- const pp = PRECEDENCE[po];
9861
- const sp = PRECEDENCE[so];
9872
+ const pp = PRECEDENCE["in"];
9873
+ const sp = PRECEDENCE[op];
9874
+ if (pp > sp || (pp == sp && this === p.value)) {
9875
+ return true;
9876
+ }
9877
+ }
9878
+ });
9879
+
9880
+ PARENS(AST_PrivateIn, function(output) {
9881
+ var p = output.parent();
9882
+ // (#x in this)()
9883
+ if (p instanceof AST_Call && p.expression === this) {
9884
+ return true;
9885
+ }
9886
+ // typeof (#x in this)
9887
+ if (p instanceof AST_Unary) {
9888
+ return true;
9889
+ }
9890
+ // (#x in this)["prop"], (#x in this).prop
9891
+ if (p instanceof AST_PropAccess && p.expression === this) {
9892
+ return true;
9893
+ }
9894
+ // same precedence as regular in operator
9895
+ if (p instanceof AST_Binary) {
9896
+ const parent_op = p.operator;
9897
+
9898
+ const pp = PRECEDENCE[parent_op];
9899
+ const sp = PRECEDENCE["in"];
9862
9900
  if (pp > sp
9863
9901
  || (pp == sp
9864
- && (this === p.right || po == "**"))) {
9902
+ && (this === p.right || parent_op == "**"))) {
9865
9903
  return true;
9866
9904
  }
9867
9905
  }
9906
+ // rules are the same as binary in, but the class differs
9907
+ if (p instanceof AST_PrivateIn && this === p.value) {
9908
+ return true;
9909
+ }
9868
9910
  });
9869
9911
 
9870
9912
  PARENS(AST_Yield, function(output) {
@@ -16560,6 +16602,7 @@ function tighten_body(statements, compressor) {
16560
16602
  || node instanceof AST_SymbolRef
16561
16603
  && parent instanceof AST_Call
16562
16604
  && has_annotation(parent, _NOINLINE)
16605
+ || node instanceof AST_ObjectProperty && node.key instanceof AST_Node
16563
16606
  ) {
16564
16607
  abort = true;
16565
16608
  return node;
@@ -17842,6 +17885,8 @@ function is_const_symbol_short_than_init_value(def, fixed_value) {
17842
17885
  }
17843
17886
 
17844
17887
  function inline_into_symbolref(self, compressor) {
17888
+ if (compressor.in_computed_key()) return self;
17889
+
17845
17890
  const parent = compressor.parent();
17846
17891
  const def = self.definition();
17847
17892
  const nearest_scope = compressor.find_scope();
@@ -17991,6 +18036,8 @@ function inline_into_symbolref(self, compressor) {
17991
18036
  }
17992
18037
 
17993
18038
  function inline_into_call(self, compressor) {
18039
+ if (compressor.in_computed_key()) return self;
18040
+
17994
18041
  var exp = self.expression;
17995
18042
  var fn = exp;
17996
18043
  var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion));
@@ -18646,6 +18693,17 @@ class Compressor extends TreeWalker {
18646
18693
  }
18647
18694
  }
18648
18695
 
18696
+ in_computed_key() {
18697
+ if (!this.option("evaluate")) return false;
18698
+ var self = this.self();
18699
+ for (var i = 0, p; p = this.parent(i); i++) {
18700
+ if (p instanceof AST_ObjectProperty && p.key === self) {
18701
+ return true;
18702
+ }
18703
+ }
18704
+ return false;
18705
+ }
18706
+
18649
18707
  get_toplevel() {
18650
18708
  return this._toplevel;
18651
18709
  }
@@ -401,6 +401,17 @@ class Compressor extends TreeWalker {
401
401
  }
402
402
  }
403
403
 
404
+ in_computed_key() {
405
+ if (!this.option("evaluate")) return false;
406
+ var self = this.self();
407
+ for (var i = 0, p; p = this.parent(i); i++) {
408
+ if (p instanceof AST_ObjectProperty && p.key === self) {
409
+ return true;
410
+ }
411
+ }
412
+ return false;
413
+ }
414
+
404
415
  get_toplevel() {
405
416
  return this._toplevel;
406
417
  }
@@ -167,6 +167,8 @@ function is_const_symbol_short_than_init_value(def, fixed_value) {
167
167
  }
168
168
 
169
169
  export function inline_into_symbolref(self, compressor) {
170
+ if (compressor.in_computed_key()) return self;
171
+
170
172
  const parent = compressor.parent();
171
173
  const def = self.definition();
172
174
  const nearest_scope = compressor.find_scope();
@@ -316,6 +318,8 @@ export function inline_into_symbolref(self, compressor) {
316
318
  }
317
319
 
318
320
  export function inline_into_call(self, compressor) {
321
+ if (compressor.in_computed_key()) return self;
322
+
319
323
  var exp = self.expression;
320
324
  var fn = exp;
321
325
  var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion));
@@ -82,6 +82,7 @@ import {
82
82
  AST_Number,
83
83
  AST_Object,
84
84
  AST_ObjectKeyVal,
85
+ AST_ObjectProperty,
85
86
  AST_PropAccess,
86
87
  AST_RegExp,
87
88
  AST_Return,
@@ -116,7 +117,7 @@ import {
116
117
  walk,
117
118
  walk_abort,
118
119
 
119
- _NOINLINE
120
+ _NOINLINE,
120
121
  } from "../ast.js";
121
122
  import {
122
123
  make_node,
@@ -328,6 +329,7 @@ export function tighten_body(statements, compressor) {
328
329
  || node instanceof AST_SymbolRef
329
330
  && parent instanceof AST_Call
330
331
  && has_annotation(parent, _NOINLINE)
332
+ || node instanceof AST_ObjectProperty && node.key instanceof AST_Node
331
333
  ) {
332
334
  abort = true;
333
335
  return node;
package/lib/output.js CHANGED
@@ -1072,25 +1072,66 @@ function OutputStream(options) {
1072
1072
  return true;
1073
1073
  // this deals with precedence: 3 * (2 + 1)
1074
1074
  if (p instanceof AST_Binary) {
1075
- const po = p.operator;
1076
- const so = this.operator;
1075
+ const parent_op = p.operator;
1076
+ const op = this.operator;
1077
1077
 
1078
- if (so === "??" && (po === "||" || po === "&&")) {
1078
+ // It is forbidden for ?? to be used with || or && without parens.
1079
+ if (op === "??" && (parent_op === "||" || parent_op === "&&")) {
1080
+ return true;
1081
+ }
1082
+ if (parent_op === "??" && (op === "||" || op === "&&")) {
1079
1083
  return true;
1080
1084
  }
1081
1085
 
1082
- if (po === "??" && (so === "||" || so === "&&")) {
1086
+ const pp = PRECEDENCE[parent_op];
1087
+ const sp = PRECEDENCE[op];
1088
+ if (pp > sp
1089
+ || (pp == sp
1090
+ && (this === p.right || parent_op == "**"))) {
1083
1091
  return true;
1084
1092
  }
1093
+ }
1094
+ if (p instanceof AST_PrivateIn) {
1095
+ const op = this.operator;
1096
+
1097
+ const pp = PRECEDENCE["in"];
1098
+ const sp = PRECEDENCE[op];
1099
+ if (pp > sp || (pp == sp && this === p.value)) {
1100
+ return true;
1101
+ }
1102
+ }
1103
+ });
1104
+
1105
+ PARENS(AST_PrivateIn, function(output) {
1106
+ var p = output.parent();
1107
+ // (#x in this)()
1108
+ if (p instanceof AST_Call && p.expression === this) {
1109
+ return true;
1110
+ }
1111
+ // typeof (#x in this)
1112
+ if (p instanceof AST_Unary) {
1113
+ return true;
1114
+ }
1115
+ // (#x in this)["prop"], (#x in this).prop
1116
+ if (p instanceof AST_PropAccess && p.expression === this) {
1117
+ return true;
1118
+ }
1119
+ // same precedence as regular in operator
1120
+ if (p instanceof AST_Binary) {
1121
+ const parent_op = p.operator;
1085
1122
 
1086
- const pp = PRECEDENCE[po];
1087
- const sp = PRECEDENCE[so];
1123
+ const pp = PRECEDENCE[parent_op];
1124
+ const sp = PRECEDENCE["in"];
1088
1125
  if (pp > sp
1089
1126
  || (pp == sp
1090
- && (this === p.right || po == "**"))) {
1127
+ && (this === p.right || parent_op == "**"))) {
1091
1128
  return true;
1092
1129
  }
1093
1130
  }
1131
+ // rules are the same as binary in, but the class differs
1132
+ if (p instanceof AST_PrivateIn && this === p.value) {
1133
+ return true;
1134
+ }
1094
1135
  });
1095
1136
 
1096
1137
  PARENS(AST_Yield, function(output) {
package/lib/parse.js CHANGED
@@ -1027,9 +1027,8 @@ var LOGICAL_ASSIGNMENT = makePredicate([ "??=", "&&=", "||=" ]);
1027
1027
 
1028
1028
  var PRECEDENCE = (function(a, ret) {
1029
1029
  for (var i = 0; i < a.length; ++i) {
1030
- var b = a[i];
1031
- for (var j = 0; j < b.length; ++j) {
1032
- ret[b[j]] = i + 1;
1030
+ for (const op of a[i]) {
1031
+ ret[op] = i + 1;
1033
1032
  }
1034
1033
  }
1035
1034
  return ret;
@@ -2381,29 +2380,6 @@ function parse($TEXT, options) {
2381
2380
  if (is("template_head")) {
2382
2381
  return subscripts(template_string(), allow_calls);
2383
2382
  }
2384
- if (is("privatename")) {
2385
- if(!S.in_class) {
2386
- croak("Private field must be used in an enclosing class");
2387
- }
2388
-
2389
- const start = S.token;
2390
- const key = new AST_SymbolPrivateProperty({
2391
- start,
2392
- name: start.value,
2393
- end: start
2394
- });
2395
- next();
2396
- expect_token("operator", "in");
2397
-
2398
- const private_in = new AST_PrivateIn({
2399
- start,
2400
- key,
2401
- value: subscripts(as_atom_node(), allow_calls),
2402
- end: prev()
2403
- });
2404
-
2405
- return subscripts(private_in, allow_calls);
2406
- }
2407
2383
  if (ATOMIC_START_TOKEN.has(S.token.type)) {
2408
2384
  return subscripts(as_atom_node(), allow_calls);
2409
2385
  }
@@ -3316,7 +3292,32 @@ function parse($TEXT, options) {
3316
3292
  };
3317
3293
 
3318
3294
  function expr_ops(no_in) {
3319
- return expr_op(maybe_unary(true, true), 0, no_in);
3295
+ // maybe_unary won't return us a AST_SymbolPrivateProperty
3296
+ if (!no_in && is("privatename")) {
3297
+ if(!S.in_class) {
3298
+ croak("Private field must be used in an enclosing class");
3299
+ }
3300
+
3301
+ const start = S.token;
3302
+ const key = new AST_SymbolPrivateProperty({
3303
+ start,
3304
+ name: start.value,
3305
+ end: start
3306
+ });
3307
+ next();
3308
+ expect_token("operator", "in");
3309
+
3310
+ const private_in = new AST_PrivateIn({
3311
+ start,
3312
+ key,
3313
+ value: expr_op(maybe_unary(true), PRECEDENCE["in"], no_in),
3314
+ end: prev()
3315
+ });
3316
+
3317
+ return expr_op(private_in, 0, no_in);
3318
+ } else {
3319
+ return expr_op(maybe_unary(true, true), 0, no_in);
3320
+ }
3320
3321
  }
3321
3322
 
3322
3323
  var maybe_conditional = function(no_in) {
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.30.1",
7
+ "version": "5.30.3",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },