terser 5.30.2 → 5.30.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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.30.4
4
+ - Fix parsing `#private in ...` when next to other operators
5
+
6
+ ## v5.30.3
7
+ - Fix precedence of `#private in ...` operator
8
+
3
9
  ## v5.30.2
4
10
  - Avoid optimizations inside computed keys, because they can cause js-engine-specific bugs.
5
11
 
@@ -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
  }
@@ -3448,7 +3424,7 @@ function parse($TEXT, options) {
3448
3424
  var prec = op != null ? PRECEDENCE[op] : null;
3449
3425
  if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) {
3450
3426
  next();
3451
- var right = expr_op(maybe_unary(true), prec, no_in);
3427
+ var right = expr_ops(no_in, prec, true);
3452
3428
  return expr_op(new AST_Binary({
3453
3429
  start : left.start,
3454
3430
  left : left,
@@ -3460,13 +3436,38 @@ function parse($TEXT, options) {
3460
3436
  return left;
3461
3437
  };
3462
3438
 
3463
- function expr_ops(no_in) {
3464
- return expr_op(maybe_unary(true, true), 0, no_in);
3439
+ function expr_ops(no_in, min_prec, allow_calls, allow_arrows) {
3440
+ // maybe_unary won't return us a AST_SymbolPrivateProperty
3441
+ if (!no_in && min_prec < PRECEDENCE["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_ops(no_in, PRECEDENCE["in"], true),
3459
+ end: prev()
3460
+ });
3461
+
3462
+ return expr_op(private_in, 0, no_in);
3463
+ } else {
3464
+ return expr_op(maybe_unary(allow_calls, allow_arrows), min_prec, no_in);
3465
+ }
3465
3466
  }
3466
3467
 
3467
3468
  var maybe_conditional = function(no_in) {
3468
3469
  var start = S.token;
3469
- var expr = expr_ops(no_in);
3470
+ var expr = expr_ops(no_in, 0, true, true);
3470
3471
  if (is("operator", "?")) {
3471
3472
  next();
3472
3473
  var yes = expression(false);
@@ -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) {
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
  }
@@ -3303,7 +3279,7 @@ function parse($TEXT, options) {
3303
3279
  var prec = op != null ? PRECEDENCE[op] : null;
3304
3280
  if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) {
3305
3281
  next();
3306
- var right = expr_op(maybe_unary(true), prec, no_in);
3282
+ var right = expr_ops(no_in, prec, true);
3307
3283
  return expr_op(new AST_Binary({
3308
3284
  start : left.start,
3309
3285
  left : left,
@@ -3315,13 +3291,38 @@ function parse($TEXT, options) {
3315
3291
  return left;
3316
3292
  };
3317
3293
 
3318
- function expr_ops(no_in) {
3319
- return expr_op(maybe_unary(true, true), 0, no_in);
3294
+ function expr_ops(no_in, min_prec, allow_calls, allow_arrows) {
3295
+ // maybe_unary won't return us a AST_SymbolPrivateProperty
3296
+ if (!no_in && min_prec < PRECEDENCE["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_ops(no_in, PRECEDENCE["in"], true),
3314
+ end: prev()
3315
+ });
3316
+
3317
+ return expr_op(private_in, 0, no_in);
3318
+ } else {
3319
+ return expr_op(maybe_unary(allow_calls, allow_arrows), min_prec, no_in);
3320
+ }
3320
3321
  }
3321
3322
 
3322
3323
  var maybe_conditional = function(no_in) {
3323
3324
  var start = S.token;
3324
- var expr = expr_ops(no_in);
3325
+ var expr = expr_ops(no_in, 0, true, true);
3325
3326
  if (is("operator", "?")) {
3326
3327
  next();
3327
3328
  var yes = expression(false);
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.2",
7
+ "version": "5.30.4",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },