espolar 0.2.1 → 0.3.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.
package/dist/index.js CHANGED
@@ -2,98 +2,134 @@
2
2
  const EXPRESSIONS_PRECEDENCE = {
3
3
  ArrayPattern: 20,
4
4
  ObjectPattern: 20,
5
- ArrayExpression: 20,
6
- TaggedTemplateExpression: 20,
7
- ThisExpression: 20,
8
- Identifier: 20,
9
- TemplateLiteral: 20,
10
- Super: 20,
11
- SequenceExpression: 20,
12
- MemberExpression: 19,
13
- MetaProperty: 19,
14
- CallExpression: 19,
15
- ChainExpression: 19,
16
- ImportExpression: 19,
17
- NewExpression: 19,
5
+ ParenthesizedExpression: 18,
6
+ ThisExpression: 18,
7
+ Super: 18,
8
+ Identifier: 18,
9
+ PrivateIdentifier: 18,
18
10
  Literal: 18,
19
- TSSatisfiesExpression: 18,
20
- TSInstantiationExpression: 18,
21
- TSNonNullExpression: 18,
22
- TSTypeAssertion: 18,
23
- AwaitExpression: 17,
24
- ClassExpression: 17,
25
- FunctionExpression: 17,
26
- ObjectExpression: 17,
27
- UnaryExpression: 16,
28
- UpdateExpression: 16,
29
- TSAsExpression: 15,
30
- BinaryExpression: 14,
31
- LogicalExpression: 13,
32
- ConditionalExpression: 4,
33
- ArrowFunctionExpression: 3,
34
- AssignmentExpression: 3,
11
+ ClassExpression: 18,
12
+ FunctionExpression: 18,
13
+ ObjectExpression: 18,
14
+ ArrayExpression: 18,
15
+ TemplateLiteral: 18,
16
+ JSXElement: 18,
17
+ JSXFragment: 18,
18
+ MetaProperty: 17,
19
+ MemberExpression: 17,
20
+ TSNonNullExpression: 17,
21
+ ChainExpression: 17,
22
+ NewExpression: 17,
23
+ CallExpression: 17,
24
+ TaggedTemplateExpression: 17,
25
+ ImportExpression: 17,
26
+ TSInstantiationExpression: 16.5,
27
+ UpdateExpression: 15,
28
+ UnaryExpression: 14,
29
+ AwaitExpression: 14,
30
+ TSTypeAssertion: 14,
31
+ BinaryExpression: 13,
32
+ TSAsExpression: 9,
33
+ TSSatisfiesExpression: 9,
34
+ LogicalExpression: 4,
35
+ AssignmentExpression: 2,
36
+ ConditionalExpression: 2,
35
37
  YieldExpression: 2,
36
- RestElement: 1
38
+ ArrowFunctionExpression: 2,
39
+ SpreadElement: 2,
40
+ SequenceExpression: 1
37
41
  };
38
42
  const OPERATOR_PRECEDENCE = {
39
- "||": 2,
40
- "&&": 3,
41
- "??": 4,
42
- "|": 5,
43
- "^": 6,
44
- "&": 7,
45
- "==": 8,
46
- "!=": 8,
47
- "===": 8,
48
- "!==": 8,
43
+ "**": 13,
44
+ "*": 12,
45
+ "%": 12,
46
+ "/": 12,
47
+ "+": 11,
48
+ "-": 11,
49
+ "<<": 10,
50
+ ">>": 10,
51
+ ">>>": 10,
49
52
  "<": 9,
50
53
  ">": 9,
51
54
  "<=": 9,
52
55
  ">=": 9,
53
56
  in: 9,
54
57
  instanceof: 9,
55
- "<<": 10,
56
- ">>": 10,
57
- ">>>": 10,
58
- "+": 11,
59
- "-": 11,
60
- "*": 12,
61
- "%": 12,
62
- "/": 12,
63
- "**": 13
58
+ "==": 8,
59
+ "!=": 8,
60
+ "===": 8,
61
+ "!==": 8,
62
+ "&": 7,
63
+ "^": 6,
64
+ "|": 5,
65
+ "&&": 4,
66
+ "??": 3,
67
+ "||": 3
68
+ };
69
+ const ASSOCIATIVE = {
70
+ [EXPRESSIONS_PRECEDENCE.MemberExpression]: "left",
71
+ [EXPRESSIONS_PRECEDENCE.UpdateExpression]: "left",
72
+ [EXPRESSIONS_PRECEDENCE.UnaryExpression]: "right",
73
+ [OPERATOR_PRECEDENCE["**"]]: "right",
74
+ [OPERATOR_PRECEDENCE["*"]]: "left",
75
+ [OPERATOR_PRECEDENCE["+"]]: "left",
76
+ [OPERATOR_PRECEDENCE["<"]]: "left",
77
+ [OPERATOR_PRECEDENCE["==="]]: "left",
78
+ [OPERATOR_PRECEDENCE["&"]]: "left",
79
+ [OPERATOR_PRECEDENCE["^"]]: "left",
80
+ [OPERATOR_PRECEDENCE["|"]]: "left",
81
+ [OPERATOR_PRECEDENCE["&&"]]: "left",
82
+ [OPERATOR_PRECEDENCE["||"]]: "left",
83
+ [EXPRESSIONS_PRECEDENCE.AssignmentExpression]: "right"
64
84
  };
85
+ function getPrecedence(node) {
86
+ if (node.type === "BinaryExpression" || node.type === "LogicalExpression") return OPERATOR_PRECEDENCE[node.operator] ?? EXPRESSIONS_PRECEDENCE[node.type];
87
+ return EXPRESSIONS_PRECEDENCE[node.type] ?? 20;
88
+ }
89
+ /**
90
+ * Check whether the operand of a Binary/Logical/AssignmentExpression needs parentheses.
91
+ * @param node
92
+ * @param parent
93
+ * @param where
94
+ * @returns
95
+ */
96
+ function operandOfBinaryExprNeedsParens(node, parent, where) {
97
+ if (where === "left" && (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") && parent.type === "BinaryExpression") return parent.operator === "&" || parent.operator === "|";
98
+ if (node.type === "LogicalExpression" && parent.type === "LogicalExpression" && parent.operator === "??" !== (node.operator === "??")) return true;
99
+ const precedence = getPrecedence(node);
100
+ const parentPrecedence = getPrecedence(parent);
101
+ if (parent.type === "BinaryExpression" && parent.operator === "**" && precedence === EXPRESSIONS_PRECEDENCE.UnaryExpression) return true;
102
+ if (precedence !== parentPrecedence) return precedence < parentPrecedence;
103
+ if (precedence === EXPRESSIONS_PRECEDENCE.MemberExpression && node.type === "ChainExpression") return true;
104
+ if (parent.type === "NewExpression" && !validUnparenthesizedNewOperand(node)) return true;
105
+ return (ASSOCIATIVE[precedence] ?? "left") !== where;
106
+ }
107
+ /**
108
+ * A valid unparenthesized `new` operand must be a member chain
109
+ * which not contains a CallExpression
110
+ */
111
+ function validUnparenthesizedNewOperand(node) {
112
+ if (node.type === "ChainExpression" || node.type === "ImportExpression") return false;
113
+ let cur = node;
114
+ while (true) if (cur.type === "CallExpression") return false;
115
+ else if (cur.type === "TSNonNullExpression") cur = cur.expression;
116
+ else if (cur.type === "MemberExpression") cur = cur.object;
117
+ else if (cur.type === "TaggedTemplateExpression") cur = cur.tag;
118
+ else return true;
119
+ }
120
+ function operandOfUnaryExprNeedsParens(node) {
121
+ return EXPRESSIONS_PRECEDENCE[node.type] < EXPRESSIONS_PRECEDENCE.UnaryExpression;
122
+ }
123
+ function expectAssignmentExprNeedsParen(node) {
124
+ return EXPRESSIONS_PRECEDENCE[node.type] < EXPRESSIONS_PRECEDENCE.AssignmentExpression;
125
+ }
126
+ function expectLHSExprNeedsParen(node) {
127
+ return EXPRESSIONS_PRECEDENCE[node.type] < EXPRESSIONS_PRECEDENCE.MemberExpression;
128
+ }
65
129
  function commentNeedsNewline(comment) {
66
130
  if (comment.type === "Line") return true;
67
131
  return comment.value.includes("\n");
68
132
  }
69
- function needsParens(node, parent, isRight) {
70
- if (node.type === "PrivateIdentifier" || node.type === "Identifier" || node.type === "Super") return false;
71
- if (node.type === "LogicalExpression" && parent.type === "LogicalExpression" && parent.operator === "??" !== (node.operator === "??")) return true;
72
- const precedence = EXPRESSIONS_PRECEDENCE[node.type] ?? 20;
73
- const parentPrecedence = EXPRESSIONS_PRECEDENCE[parent.type] ?? 20;
74
- if (precedence !== parentPrecedence) {
75
- if (!isRight && precedence === 15 && parentPrecedence === 14 && parent.operator === "**") return false;
76
- return precedence < parentPrecedence;
77
- }
78
- if (precedence !== 13 && precedence !== 14) return false;
79
- const nodeOp = node.operator;
80
- if (nodeOp === "**" && parent.operator === "**") return !isRight;
81
- if (isRight) return OPERATOR_PRECEDENCE[nodeOp] <= OPERATOR_PRECEDENCE[parent.operator];
82
- return OPERATOR_PRECEDENCE[nodeOp] < OPERATOR_PRECEDENCE[parent.operator];
83
- }
84
- function arrowConciseBodyNeedsWrap(body) {
85
- if (body.type === "BlockStatement") return false;
86
- switch (body.type) {
87
- case "ObjectExpression": return true;
88
- case "AssignmentExpression": return body.left.type === "ObjectPattern";
89
- case "LogicalExpression": return body.left.type === "ObjectExpression";
90
- case "ConditionalExpression": return body.test.type === "ObjectExpression";
91
- case "TSAsExpression":
92
- case "TSSatisfiesExpression":
93
- case "TSNonNullExpression": return body.expression ? arrowConciseBodyNeedsWrap(body.expression) : false;
94
- default: return false;
95
- }
96
- }
97
133
  const defaultPrinters = {
98
134
  Program: printProgram,
99
135
  Identifier: printIdentifier,
@@ -238,11 +274,48 @@ const defaultPrinters = {
238
274
  TSIntrinsicKeyword: printKeywordType
239
275
  };
240
276
  function printProgram(program, context) {
241
- context.writeNodeListWithSourceGaps(program.body, "\n");
277
+ context.writeNodeListWithNewLineSep(program.body);
278
+ }
279
+ function canStartExpressionStatement(node) {
280
+ let lhs;
281
+ switch (node.type) {
282
+ default: return true;
283
+ case "ObjectExpression":
284
+ case "FunctionExpression":
285
+ case "ClassExpression":
286
+ case "ObjectPattern": return false;
287
+ case "AssignmentExpression":
288
+ case "LogicalExpression":
289
+ case "BinaryExpression":
290
+ lhs = node.left;
291
+ break;
292
+ case "TSAsExpression":
293
+ case "TSSatisfiesExpression":
294
+ case "TSNonNullExpression":
295
+ lhs = node.expression;
296
+ break;
297
+ case "CallExpression":
298
+ lhs = node.callee;
299
+ break;
300
+ case "MemberExpression":
301
+ lhs = node.object;
302
+ if (node.computed && lhs.type === "Identifier" && lhs.name === "let") return false;
303
+ break;
304
+ case "TaggedTemplateExpression":
305
+ lhs = node.tag;
306
+ break;
307
+ case "ConditionalExpression":
308
+ lhs = node.test;
309
+ break;
310
+ case "SequenceExpression": return canStartExpressionStatement(node.expressions[0]);
311
+ case "UpdateExpression": return canStartExpressionStatement(node.argument);
312
+ case "ChainExpression": return canStartExpressionStatement(node.expression);
313
+ }
314
+ return operandOfBinaryExprNeedsParens(lhs, node, "left") || canStartExpressionStatement(lhs);
242
315
  }
243
316
  function printExpressionStatement(statement, context) {
244
317
  const expr = statement.expression;
245
- if (expr.type === "ObjectExpression" || expr.type === "FunctionExpression" || expr.type === "AssignmentExpression" && expr.left.type === "ObjectPattern") {
318
+ if (!canStartExpressionStatement(expr)) {
246
319
  context.write("(");
247
320
  context.writeNode(expr);
248
321
  context.write(");");
@@ -266,7 +339,11 @@ function printVariableDeclarator(declarator, context) {
266
339
  if (declarator.definite === true) context.write("!");
267
340
  if (declarator.init) {
268
341
  context.write(" = ");
269
- context.writeNode(declarator.init);
342
+ if (expectAssignmentExprNeedsParen(declarator.init)) {
343
+ context.write("(");
344
+ context.writeNode(declarator.init);
345
+ context.write(")");
346
+ } else context.writeNode(declarator.init);
270
347
  }
271
348
  }
272
349
  function printBlockStatement(block, context) {
@@ -274,7 +351,7 @@ function printBlockStatement(block, context) {
274
351
  context.write("{");
275
352
  if (body.length > 0) {
276
353
  context.write("\n");
277
- context.writeNodeListWithSourceGaps(body, "\n");
354
+ context.writeNodeListWithNewLineSep(body);
278
355
  context.write("\n");
279
356
  }
280
357
  context.write("}");
@@ -443,12 +520,14 @@ function printLiteral(literal, context) {
443
520
  function printUnaryExpression(expr, context) {
444
521
  context.write(expr.operator);
445
522
  if (expr.operator.length > 1) context.write(" ");
446
- const argPrec = EXPRESSIONS_PRECEDENCE[expr.argument.type];
447
- if (argPrec != null && argPrec < EXPRESSIONS_PRECEDENCE.UnaryExpression) {
523
+ if (operandOfUnaryExprNeedsParens(expr.argument)) {
448
524
  context.write("(");
449
525
  context.writeNode(expr.argument);
450
526
  context.write(")");
451
- } else context.writeNode(expr.argument);
527
+ } else {
528
+ if (expr.operator.length === 1 && (expr.argument.type === "UnaryExpression" || expr.argument.type === "UpdateExpression") && expr.argument.operator.startsWith(expr.operator)) context.write(" ");
529
+ context.writeNode(expr.argument);
530
+ }
452
531
  }
453
532
  function printUpdateExpression(expr, context) {
454
533
  if (expr.prefix === true) {
@@ -465,7 +544,7 @@ function printUpdateExpression(expr, context) {
465
544
  function printBinaryExpression(expression, context) {
466
545
  const left = expression.left;
467
546
  const right = expression.right;
468
- if (needsParens(left, expression, false)) {
547
+ if (operandOfBinaryExprNeedsParens(left, expression, "left")) {
469
548
  context.write("(");
470
549
  context.writeNode(left);
471
550
  context.write(")");
@@ -473,14 +552,14 @@ function printBinaryExpression(expression, context) {
473
552
  context.write(" ");
474
553
  context.write(String(expression.operator));
475
554
  context.write(" ");
476
- if (needsParens(right, expression, true)) {
555
+ if (operandOfBinaryExprNeedsParens(right, expression, "right")) {
477
556
  context.write("(");
478
557
  context.writeNode(right);
479
558
  context.write(")");
480
559
  } else context.writeNode(right);
481
560
  }
482
561
  function printConditionalExpression(expr, context) {
483
- if ((EXPRESSIONS_PRECEDENCE[expr.test.type] ?? 20) <= EXPRESSIONS_PRECEDENCE.ConditionalExpression) {
562
+ if (operandOfBinaryExprNeedsParens(expr.test, expr, "left")) {
484
563
  context.write("(");
485
564
  context.writeNode(expr.test);
486
565
  context.write(")");
@@ -488,39 +567,39 @@ function printConditionalExpression(expr, context) {
488
567
  context.write(" ? ");
489
568
  context.writeNode(expr.consequent);
490
569
  context.write(" : ");
491
- context.writeNode(expr.alternate);
570
+ if (operandOfBinaryExprNeedsParens(expr.alternate, expr, "right")) {
571
+ context.write("(");
572
+ context.writeNode(expr.alternate);
573
+ context.write(")");
574
+ } else context.writeNode(expr.alternate);
492
575
  }
493
576
  function printYieldExpression(expr, context) {
494
577
  context.write(expr.delegate === true ? "yield*" : "yield");
495
578
  if (expr.argument) {
496
579
  context.write(" ");
497
- const needsParensASi = (context.options.getLeadingComments?.(expr.argument))?.some((c) => commentNeedsNewline(c)) ?? false;
498
- if (needsParensASi) context.write("(");
499
- context.writeNode(expr.argument);
500
- if (needsParensASi) context.write(")");
580
+ if (((context.options.getLeadingComments?.(expr.argument))?.some((c) => commentNeedsNewline(c)) ?? false) || expectAssignmentExprNeedsParen(expr.argument)) {
581
+ context.write("(");
582
+ context.writeNode(expr.argument);
583
+ context.write(")");
584
+ } else context.writeNode(expr.argument);
501
585
  }
502
586
  }
503
587
  function printAwaitExpression(expr, context) {
504
588
  context.write("await");
505
- if (expr.argument) {
506
- const argPrec = EXPRESSIONS_PRECEDENCE[expr.argument.type];
507
- if (argPrec != null && argPrec < EXPRESSIONS_PRECEDENCE.AwaitExpression) {
508
- context.write(" (");
509
- context.writeNode(expr.argument);
510
- context.write(")");
511
- } else {
512
- context.write(" ");
513
- context.writeNode(expr.argument);
514
- }
589
+ if (expr.argument) if (operandOfUnaryExprNeedsParens(expr.argument)) {
590
+ context.write(" (");
591
+ context.writeNode(expr.argument);
592
+ context.write(")");
593
+ } else {
594
+ context.write(" ");
595
+ context.writeNode(expr.argument);
515
596
  }
516
597
  }
517
598
  function printSequenceExpression(expr, context) {
518
- context.write("(");
519
599
  context.writeNodeList(expr.expressions, ", ");
520
- context.write(")");
521
600
  }
522
601
  function printCallExpression(expression, context) {
523
- if ((EXPRESSIONS_PRECEDENCE[expression.callee.type] ?? 20) < EXPRESSIONS_PRECEDENCE.CallExpression) {
602
+ if (operandOfBinaryExprNeedsParens(expression.callee, expression, "left")) {
524
603
  context.write("(");
525
604
  context.writeNode(expression.callee);
526
605
  context.write(")");
@@ -530,12 +609,12 @@ function printCallExpression(expression, context) {
530
609
  const parenRange = context.options.experimentalGetLeftParenSourceRange?.(expression);
531
610
  if (parenRange) context.writeMapped("(", parenRange.start, parenRange.end);
532
611
  else context.write("(");
533
- context.writeNodeList(expression.arguments, ", ");
612
+ context.writeExpressionListWithCommaSep(expression.arguments);
534
613
  context.write(")");
535
614
  }
536
615
  function printNewExpression(expression, context) {
537
616
  context.write("new ");
538
- if ((EXPRESSIONS_PRECEDENCE[expression.callee.type] ?? 20) < EXPRESSIONS_PRECEDENCE.NewExpression || hasCallExpression(expression.callee)) {
617
+ if (operandOfBinaryExprNeedsParens(expression.callee, expression, "left")) {
539
618
  context.write("(");
540
619
  context.writeNode(expression.callee);
541
620
  context.write(")");
@@ -544,23 +623,14 @@ function printNewExpression(expression, context) {
544
623
  const parenRange = context.options.experimentalGetLeftParenSourceRange?.(expression);
545
624
  if (parenRange) context.writeMapped("(", parenRange.start, parenRange.end);
546
625
  else context.write("(");
547
- context.writeNodeList(expression.arguments, ", ");
626
+ context.writeExpressionListWithCommaSep(expression.arguments);
548
627
  context.write(")");
549
628
  }
550
- function hasCallExpression(node) {
551
- let cur = node;
552
- while (cur) {
553
- if (cur.type === "CallExpression") return true;
554
- if (cur.type === "MemberExpression") cur = cur.object;
555
- else return false;
556
- }
557
- return false;
558
- }
559
629
  function printChainExpression(expression, context) {
560
630
  context.writeNode(expression.expression);
561
631
  }
562
632
  function printMemberExpression(expression, context) {
563
- if ((EXPRESSIONS_PRECEDENCE[expression.object.type] ?? 20) < EXPRESSIONS_PRECEDENCE.MemberExpression) {
633
+ if (operandOfBinaryExprNeedsParens(expression.object, expression, "left")) {
564
634
  context.write("(");
565
635
  context.writeNode(expression.object);
566
636
  context.write(")");
@@ -587,7 +657,7 @@ function printObjectPattern(pattern, context) {
587
657
  }
588
658
  function printArrayExpression(array, context) {
589
659
  context.write("[");
590
- context.writeNodeList(array.elements, ", ");
660
+ context.writeExpressionListWithCommaSep(array.elements);
591
661
  context.write("]");
592
662
  }
593
663
  function printArrayPattern(pattern, context) {
@@ -604,7 +674,7 @@ function printProperty(property, context) {
604
674
  context.writeNode(value);
605
675
  return;
606
676
  }
607
- if (value.type === "FunctionExpression") {
677
+ if (value.type === "FunctionExpression" && (property.method || property.kind !== "init")) {
608
678
  if (property.kind !== "init") context.write(property.kind + " ");
609
679
  if (value.async === true) context.write("async ");
610
680
  if (value.generator === true) context.write("*");
@@ -626,7 +696,6 @@ function printProperty(property, context) {
626
696
  context.writeNode(property.key);
627
697
  context.write("]: ");
628
698
  } else {
629
- if (property.kind === "get" || property.kind === "set") context.write(property.kind + " ");
630
699
  context.writeNode(property.key);
631
700
  context.write(": ");
632
701
  }
@@ -635,7 +704,11 @@ function printProperty(property, context) {
635
704
  }
636
705
  function printSpreadElement(spread, context) {
637
706
  context.write("...");
638
- context.writeNode(spread.argument);
707
+ if (expectAssignmentExprNeedsParen(spread.argument)) {
708
+ context.write("(");
709
+ context.writeNode(spread.argument);
710
+ context.write(")");
711
+ } else context.writeNode(spread.argument);
639
712
  }
640
713
  function printRestElement(rest, context) {
641
714
  context.write("...");
@@ -660,7 +733,12 @@ function printTemplateLiteral(node, context) {
660
733
  context.write("`");
661
734
  }
662
735
  function printTaggedTemplateExpression(node, context) {
663
- context.writeNode(node.tag);
736
+ if (operandOfBinaryExprNeedsParens(node.tag, node, "left")) {
737
+ context.write("(");
738
+ context.writeNode(node.tag);
739
+ context.write(")");
740
+ } else context.writeNode(node.tag);
741
+ if (node.typeArguments) context.writeNode(node.typeArguments);
664
742
  context.writeNode(node.quasi);
665
743
  }
666
744
  function printThisExpression(_node, context) {
@@ -703,6 +781,44 @@ function printFunction(fn, context) {
703
781
  context.writeNode(fn.body);
704
782
  }
705
783
  }
784
+ function canStartConciseBody(body) {
785
+ if (body.type === "BlockStatement" || body.type === "PrivateIdentifier") return true;
786
+ if (expectAssignmentExprNeedsParen(body)) return false;
787
+ let lhs;
788
+ switch (body.type) {
789
+ default: return true;
790
+ case "ObjectExpression":
791
+ case "FunctionExpression":
792
+ case "ClassExpression":
793
+ case "ObjectPattern": return false;
794
+ case "AssignmentExpression":
795
+ case "LogicalExpression":
796
+ case "BinaryExpression":
797
+ lhs = body.left;
798
+ break;
799
+ case "TSAsExpression":
800
+ case "TSSatisfiesExpression":
801
+ case "TSNonNullExpression":
802
+ lhs = body.expression;
803
+ break;
804
+ case "CallExpression":
805
+ lhs = body.callee;
806
+ break;
807
+ case "MemberExpression":
808
+ lhs = body.object;
809
+ if (body.computed && lhs.type === "Identifier" && lhs.name === "let") return false;
810
+ break;
811
+ case "TaggedTemplateExpression":
812
+ lhs = body.tag;
813
+ break;
814
+ case "ConditionalExpression":
815
+ lhs = body.test;
816
+ break;
817
+ case "UpdateExpression": return canStartConciseBody(body.argument);
818
+ case "ChainExpression": return canStartConciseBody(body.expression);
819
+ }
820
+ return operandOfBinaryExprNeedsParens(lhs, body, "left") || canStartConciseBody(lhs);
821
+ }
706
822
  function printArrowFunctionExpression(fn, context) {
707
823
  if (fn.async === true) context.write("async ");
708
824
  if (fn.typeParameters) context.writeNode(fn.typeParameters);
@@ -712,7 +828,7 @@ function printArrowFunctionExpression(fn, context) {
712
828
  writeReturnType(fn, context);
713
829
  context.write(" => ");
714
830
  const body = fn.body;
715
- if (arrowConciseBodyNeedsWrap(body)) {
831
+ if (!canStartConciseBody(body)) {
716
832
  context.write("(");
717
833
  context.writeNode(body);
718
834
  context.write(")");
@@ -735,7 +851,11 @@ function printClass(node, context) {
735
851
  }
736
852
  if (node.superClass) {
737
853
  context.write("extends ");
738
- context.writeNode(node.superClass);
854
+ if (expectLHSExprNeedsParen(node.superClass)) {
855
+ context.write("(");
856
+ context.writeNode(node.superClass);
857
+ context.write(")");
858
+ } else context.writeNode(node.superClass);
739
859
  if (node.superTypeArguments) context.writeNode(node.superTypeArguments);
740
860
  else if (node.superTypeParameters) context.writeNode(node.superTypeParameters);
741
861
  }
@@ -751,7 +871,7 @@ function printClassBody(node, context) {
751
871
  const body = node.body;
752
872
  if (body.length > 0) {
753
873
  context.write("\n");
754
- context.writeNodeListWithSourceGaps(body, "\n");
874
+ context.writeNodeListWithNewLineSep(body);
755
875
  context.write("\n");
756
876
  }
757
877
  context.write("}");
@@ -761,14 +881,28 @@ function printStaticBlock(node, context) {
761
881
  const body = node.body;
762
882
  if (body.length > 0) {
763
883
  context.write("\n");
764
- context.writeNodeListWithSourceGaps(body, "\n");
884
+ context.writeNodeListWithNewLineSep(body);
765
885
  context.write("\n");
766
886
  }
767
887
  context.write("}");
768
888
  }
889
+ function validUnparenthesizedDecorator(node) {
890
+ let current = node;
891
+ if (current.type === "CallExpression") current = current.callee;
892
+ if (current.type === "TSInstantiationExpression") current = current.expression;
893
+ while (true) if (current.type === "Identifier") return true;
894
+ else if (current.type === "MemberExpression") {
895
+ if (current.computed) return false;
896
+ current = current.object;
897
+ } else return false;
898
+ }
769
899
  function printDecorator(node, context) {
770
900
  context.write("@");
771
- context.writeNode(node.expression);
901
+ if (!validUnparenthesizedDecorator(node.expression)) {
902
+ context.write("(");
903
+ context.writeNode(node.expression);
904
+ context.write(")");
905
+ } else context.writeNode(node.expression);
772
906
  context.write("\n");
773
907
  }
774
908
  function printPropertyDefinition(node, context) {
@@ -933,7 +1067,7 @@ function printExportSpecifier(node, context) {
933
1067
  }
934
1068
  }
935
1069
  function printTSAsExpression(expression, context) {
936
- if ((EXPRESSIONS_PRECEDENCE[expression.expression.type] ?? 20) < EXPRESSIONS_PRECEDENCE.TSAsExpression) {
1070
+ if (operandOfBinaryExprNeedsParens(expression.expression, expression, "left")) {
937
1071
  context.write("(");
938
1072
  context.writeNode(expression.expression);
939
1073
  context.write(")");
@@ -942,7 +1076,7 @@ function printTSAsExpression(expression, context) {
942
1076
  context.writeNode(expression.typeAnnotation);
943
1077
  }
944
1078
  function printTSSatisfiesExpression(expression, context) {
945
- if ((EXPRESSIONS_PRECEDENCE[expression.expression.type] ?? 20) < EXPRESSIONS_PRECEDENCE.TSSatisfiesExpression) {
1079
+ if (operandOfBinaryExprNeedsParens(expression.expression, expression, "left")) {
946
1080
  context.write("(");
947
1081
  context.writeNode(expression.expression);
948
1082
  context.write(")");
@@ -954,14 +1088,18 @@ function printTSTypeAssertion(expression, context) {
954
1088
  context.write("<");
955
1089
  context.writeNode(expression.typeAnnotation);
956
1090
  context.write(">");
957
- if ((EXPRESSIONS_PRECEDENCE[expression.expression.type] ?? 20) < EXPRESSIONS_PRECEDENCE.TSTypeAssertion) {
1091
+ if (operandOfUnaryExprNeedsParens(expression.expression)) {
958
1092
  context.write("(");
959
1093
  context.writeNode(expression.expression);
960
1094
  context.write(")");
961
1095
  } else context.writeNode(expression.expression);
962
1096
  }
963
1097
  function printTSNonNullExpression(expression, context) {
964
- context.writeNode(expression.expression);
1098
+ if (operandOfBinaryExprNeedsParens(expression.expression, expression, "left")) {
1099
+ context.write("(");
1100
+ context.writeNode(expression.expression);
1101
+ context.write(")");
1102
+ } else context.writeNode(expression.expression);
965
1103
  context.write("!");
966
1104
  }
967
1105
  function printTSTypeAnnotation(annotation, context) {
@@ -1155,7 +1293,12 @@ function printTSTypeQuery(node, context) {
1155
1293
  context.writeNode(node.exprName);
1156
1294
  }
1157
1295
  function printTSMappedType(node, context) {
1158
- context.write("{ [");
1296
+ context.write("{ ");
1297
+ if (node.readonly) {
1298
+ if (typeof node.readonly === "string") context.write(node.readonly);
1299
+ context.write("readonly ");
1300
+ }
1301
+ context.write("[");
1159
1302
  const legacyTp = node.typeParameter;
1160
1303
  const key = node.key ?? legacyTp?.name;
1161
1304
  const constraint = node.constraint ?? legacyTp?.constraint;
@@ -1165,7 +1308,15 @@ function printTSMappedType(node, context) {
1165
1308
  context.write(" in ");
1166
1309
  context.writeNode(constraint);
1167
1310
  }
1311
+ if (node.nameType) {
1312
+ context.write(" as ");
1313
+ context.writeNode(node.nameType);
1314
+ }
1168
1315
  context.write("]");
1316
+ if (node.optional) {
1317
+ if (typeof node.optional === "string") context.write(node.optional);
1318
+ context.write("?");
1319
+ }
1169
1320
  if (node.typeAnnotation) {
1170
1321
  context.write(": ");
1171
1322
  context.writeNode(node.typeAnnotation);
@@ -1262,14 +1413,20 @@ function printTSModuleDeclaration(node, context) {
1262
1413
  context.write(String(kind) + " ");
1263
1414
  context.writeNode(node.id);
1264
1415
  }
1265
- if (node.body) {
1266
- if (node.body.type === "TSModuleBlock") context.write(" ");
1267
- context.writeNode(node.body);
1416
+ let body = node.body;
1417
+ while (body?.type === "TSModuleDeclaration") {
1418
+ context.write(".");
1419
+ context.writeNode(body.id);
1420
+ body = body.body;
1421
+ }
1422
+ if (body) {
1423
+ context.write(" ");
1424
+ context.writeNode(body);
1268
1425
  }
1269
1426
  }
1270
1427
  function printTSModuleBlock(node, context) {
1271
1428
  context.write("{\n");
1272
- context.writeNodeListWithSourceGaps(node.body, "\n");
1429
+ context.writeNodeListWithNewLineSep(node.body);
1273
1430
  context.write("\n}");
1274
1431
  }
1275
1432
  function printTSDeclareFunction(node, context) {
@@ -1304,7 +1461,11 @@ function printTSNamespaceExportDeclaration(node, context) {
1304
1461
  context.write(";");
1305
1462
  }
1306
1463
  function printTSInstantiationExpression(node, context) {
1307
- context.writeNode(node.expression);
1464
+ if (operandOfBinaryExprNeedsParens(node.expression, node, "left")) {
1465
+ context.write("(");
1466
+ context.writeNode(node.expression);
1467
+ context.write(")");
1468
+ } else context.writeNode(node.expression);
1308
1469
  context.writeNode(node.typeArguments);
1309
1470
  }
1310
1471
  function printTSParenthesizedType(node, context) {
@@ -1320,6 +1481,13 @@ function writeOptionalTypeAnnotation(node, context) {
1320
1481
  if (node.optional === true) context.write("?");
1321
1482
  if (node.typeAnnotation) context.writeNode(node.typeAnnotation);
1322
1483
  }
1484
+ function writeComment(comment, context) {
1485
+ if (comment.type === "Line") context.write("//" + comment.value + "\n");
1486
+ else {
1487
+ context.write("/*" + comment.value + "*/");
1488
+ if (comment.value.includes("\n")) context.write("\n");
1489
+ }
1490
+ }
1323
1491
  //#endregion
1324
1492
  //#region src/mappings.ts
1325
1493
  function getNodeRange(node) {
@@ -1368,13 +1536,6 @@ function toVolarMapping(mapping) {
1368
1536
  }
1369
1537
  //#endregion
1370
1538
  //#region src/printer.ts
1371
- function writeComment(context, comment) {
1372
- if (comment.type === "Line") context.write("//" + comment.value + "\n");
1373
- else {
1374
- context.write("/*" + comment.value + "*/");
1375
- if (comment.value.includes("\n")) context.write("\n");
1376
- }
1377
- }
1378
1539
  function print(node, options) {
1379
1540
  const context = createPrinterContext(options);
1380
1541
  context.writeNode(node);
@@ -1441,12 +1602,12 @@ function createPrinterContext(options) {
1441
1602
  const printer = printers[node.type];
1442
1603
  if (!printer) throw new Error(`No printer registered for node type ${node.type}`);
1443
1604
  const leadingComments = options.getLeadingComments?.(node);
1444
- if (leadingComments) for (const c of leadingComments) writeComment(context, c);
1605
+ if (leadingComments) for (const comment of leadingComments) writeComment(comment, context);
1445
1606
  const generatedStart = generatedOffset;
1446
1607
  printer(node, context);
1447
1608
  const generatedEnd = generatedOffset;
1448
1609
  const trailingComments = options.getTrailingComments?.(node);
1449
- if (trailingComments) for (const c of trailingComments) writeComment(context, c);
1610
+ if (trailingComments) for (const comment of trailingComments) writeComment(comment, context);
1450
1611
  const lastMappingGeneratedEnd = mappings.at(-1)?.generatedEnd ?? 0;
1451
1612
  if (range && lastMappingGeneratedEnd <= generatedStart) appendMapping(range, generatedStart, generatedEnd, getMappingData(node));
1452
1613
  },
@@ -1462,14 +1623,30 @@ function createPrinterContext(options) {
1462
1623
  needsSeparator = true;
1463
1624
  }
1464
1625
  },
1465
- writeNodeListWithSourceGaps(nodes, fallbackSeparator) {
1626
+ writeExpressionListWithCommaSep(nodes) {
1627
+ let needsSeparator = false;
1628
+ for (const node of nodes) {
1629
+ if (!node) {
1630
+ if (needsSeparator) context.write(", ");
1631
+ continue;
1632
+ }
1633
+ if (needsSeparator) context.write(", ");
1634
+ if (expectAssignmentExprNeedsParen(node)) {
1635
+ context.write("(");
1636
+ context.writeNode(node);
1637
+ context.write(")");
1638
+ } else context.writeNode(node);
1639
+ needsSeparator = true;
1640
+ }
1641
+ },
1642
+ writeNodeListWithNewLineSep(nodes) {
1466
1643
  let lastRangeEnd;
1467
1644
  let wroteNode = false;
1468
1645
  for (const node of nodes) {
1469
1646
  if (!node) continue;
1470
1647
  const range = getNodeRange(node);
1471
1648
  if (wroteNode) if (lastRangeEnd !== void 0 && range && range.start >= lastRangeEnd) context.writeSource(lastRangeEnd, range.start, getMappingData(null));
1472
- else context.write(fallbackSeparator);
1649
+ else context.write("\n");
1473
1650
  context.writeNode(node);
1474
1651
  wroteNode = true;
1475
1652
  if (range) lastRangeEnd = range.end;