espolar 0.2.1 → 0.3.0
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.d.ts +4 -6
- package/dist/index.js +285 -133
- package/package.json +1 -1
- package/src/api.ts +5 -6
- package/src/printer.ts +35 -18
- package/src/printers.ts +490 -158
package/src/printers.ts
CHANGED
|
@@ -1,90 +1,179 @@
|
|
|
1
1
|
import type { PrinterContext, Printers } from "./api.ts";
|
|
2
|
-
import type { AST, Comment } from "./types.ts";
|
|
2
|
+
import type { AST, AST_NODE_TYPES, Comment } from "./types.ts";
|
|
3
3
|
|
|
4
|
-
const EXPRESSIONS_PRECEDENCE
|
|
4
|
+
const EXPRESSIONS_PRECEDENCE = {
|
|
5
|
+
// LHS of =, must NOT parenthesized
|
|
5
6
|
ArrayPattern: 20,
|
|
6
7
|
ObjectPattern: 20,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Super:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
MetaProperty: 19,
|
|
16
|
-
CallExpression: 19,
|
|
17
|
-
ChainExpression: 19,
|
|
18
|
-
ImportExpression: 19,
|
|
19
|
-
NewExpression: 19,
|
|
8
|
+
|
|
9
|
+
// PrimaryExpression
|
|
10
|
+
// @ts-expect-error acorn-typescript compat
|
|
11
|
+
ParenthesizedExpression: 18,
|
|
12
|
+
ThisExpression: 18,
|
|
13
|
+
Super: 18, // like ThisExpression
|
|
14
|
+
Identifier: 18,
|
|
15
|
+
PrivateIdentifier: 18, // LHS of in
|
|
20
16
|
Literal: 18,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
ClassExpression: 18,
|
|
18
|
+
FunctionExpression: 18,
|
|
19
|
+
ObjectExpression: 18,
|
|
20
|
+
ArrayExpression: 18,
|
|
21
|
+
TemplateLiteral: 18,
|
|
22
|
+
// https://react.github.io/jsx/
|
|
23
|
+
JSXElement: 18,
|
|
24
|
+
JSXFragment: 18,
|
|
25
|
+
|
|
26
|
+
MetaProperty: 17,
|
|
27
|
+
MemberExpression: 17,
|
|
28
|
+
// Same precedence as MemberExpression, e.g. foo!.bar
|
|
29
|
+
TSNonNullExpression: 17,
|
|
30
|
+
ChainExpression: 17,
|
|
31
|
+
NewExpression: 17, // only with argument list, 16 if not (we don't print this form)
|
|
32
|
+
CallExpression: 17,
|
|
33
|
+
TaggedTemplateExpression: 17,
|
|
34
|
+
ImportExpression: 17,
|
|
35
|
+
// Between MemberExpression and NewExpression w/o arguments, e.g.
|
|
36
|
+
// f<T>.x // Error
|
|
37
|
+
// (f<T>).x // OK
|
|
38
|
+
// new f<T> // OK
|
|
39
|
+
TSInstantiationExpression: 16.5,
|
|
40
|
+
|
|
41
|
+
// postfix operators
|
|
42
|
+
UpdateExpression: 15,
|
|
43
|
+
// prefix operators
|
|
44
|
+
UnaryExpression: 14,
|
|
45
|
+
AwaitExpression: 14,
|
|
46
|
+
// behaves like postfix operators (e.g. cannot be part of LHS of **)
|
|
47
|
+
TSTypeAssertion: 14,
|
|
48
|
+
|
|
49
|
+
// ranges from 13-5 depending on operator
|
|
50
|
+
BinaryExpression: 13,
|
|
51
|
+
// as/satisfies have same precedence as relational operators
|
|
52
|
+
TSAsExpression: 9,
|
|
53
|
+
TSSatisfiesExpression: 9,
|
|
54
|
+
// ranges from 4-3 depending on operator
|
|
55
|
+
LogicalExpression: 4,
|
|
56
|
+
|
|
57
|
+
AssignmentExpression: 2,
|
|
58
|
+
ConditionalExpression: 2,
|
|
37
59
|
YieldExpression: 2,
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
ArrowFunctionExpression: 2,
|
|
61
|
+
SpreadElement: 2,
|
|
40
62
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
63
|
+
SequenceExpression: 1,
|
|
64
|
+
} as const satisfies Partial<Record<AST.Expression["type"], number>>;
|
|
65
|
+
|
|
66
|
+
const OPERATOR_PRECEDENCE = {
|
|
67
|
+
"**": 13,
|
|
68
|
+
"*": 12,
|
|
69
|
+
"%": 12,
|
|
70
|
+
"/": 12,
|
|
71
|
+
"+": 11,
|
|
72
|
+
"-": 11,
|
|
73
|
+
"<<": 10,
|
|
74
|
+
">>": 10,
|
|
75
|
+
">>>": 10,
|
|
52
76
|
"<": 9,
|
|
53
77
|
">": 9,
|
|
54
78
|
"<=": 9,
|
|
55
79
|
">=": 9,
|
|
56
80
|
in: 9,
|
|
57
81
|
instanceof: 9,
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
82
|
+
"==": 8,
|
|
83
|
+
"!=": 8,
|
|
84
|
+
"===": 8,
|
|
85
|
+
"!==": 8,
|
|
86
|
+
"&": 7,
|
|
87
|
+
"^": 6,
|
|
88
|
+
"|": 5,
|
|
89
|
+
"&&": 4,
|
|
90
|
+
"??": 3,
|
|
91
|
+
"||": 3,
|
|
92
|
+
} as const satisfies Record<
|
|
93
|
+
(AST.BinaryExpression | AST.LogicalExpression)["operator"],
|
|
94
|
+
number
|
|
95
|
+
>;
|
|
96
|
+
|
|
97
|
+
const ASSOCIATIVE: Record<number, "left" | "right"> = {
|
|
98
|
+
[EXPRESSIONS_PRECEDENCE.MemberExpression]: "left",
|
|
99
|
+
[EXPRESSIONS_PRECEDENCE.UpdateExpression]: "left",
|
|
100
|
+
[EXPRESSIONS_PRECEDENCE.UnaryExpression]: "right",
|
|
101
|
+
[OPERATOR_PRECEDENCE["**"]]: "right",
|
|
102
|
+
[OPERATOR_PRECEDENCE["*"]]: "left",
|
|
103
|
+
[OPERATOR_PRECEDENCE["+"]]: "left",
|
|
104
|
+
[OPERATOR_PRECEDENCE["<"]]: "left",
|
|
105
|
+
[OPERATOR_PRECEDENCE["==="]]: "left",
|
|
106
|
+
[OPERATOR_PRECEDENCE["&"]]: "left",
|
|
107
|
+
[OPERATOR_PRECEDENCE["^"]]: "left",
|
|
108
|
+
[OPERATOR_PRECEDENCE["|"]]: "left",
|
|
109
|
+
[OPERATOR_PRECEDENCE["&&"]]: "left",
|
|
110
|
+
[OPERATOR_PRECEDENCE["||"]]: "left",
|
|
111
|
+
[EXPRESSIONS_PRECEDENCE.AssignmentExpression]: "right",
|
|
67
112
|
};
|
|
68
113
|
|
|
69
|
-
function
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
114
|
+
function getPrecedence(node: AST.Expression | AST.PrivateIdentifier): number {
|
|
115
|
+
if (node.type === "BinaryExpression" || node.type === "LogicalExpression") {
|
|
116
|
+
return (
|
|
117
|
+
OPERATOR_PRECEDENCE[node.operator] ?? EXPRESSIONS_PRECEDENCE[node.type]
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return EXPRESSIONS_PRECEDENCE[node.type] ?? 20;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
type ExpressionWithPrecedence = keyof typeof EXPRESSIONS_PRECEDENCE;
|
|
124
|
+
type ExpressionTypeWithPrecedenceAs<T extends number> = {
|
|
125
|
+
[K in AST_NODE_TYPES]: K extends ExpressionWithPrecedence
|
|
126
|
+
? (typeof EXPRESSIONS_PRECEDENCE)[K] extends T
|
|
127
|
+
? K
|
|
128
|
+
: never
|
|
129
|
+
: never;
|
|
130
|
+
}[AST_NODE_TYPES];
|
|
131
|
+
|
|
132
|
+
// Expression with same precedence as MemberExpression
|
|
133
|
+
type MemberLikeExpression = Extract<
|
|
134
|
+
AST.Expression,
|
|
135
|
+
{
|
|
136
|
+
type: ExpressionTypeWithPrecedenceAs<
|
|
137
|
+
typeof EXPRESSIONS_PRECEDENCE.MemberExpression
|
|
138
|
+
>;
|
|
139
|
+
}
|
|
140
|
+
>;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check whether the operand of a Binary/Logical/AssignmentExpression needs parentheses.
|
|
144
|
+
* @param node
|
|
145
|
+
* @param parent
|
|
146
|
+
* @param where
|
|
147
|
+
* @returns
|
|
148
|
+
*/
|
|
149
|
+
function operandOfBinaryExprNeedsParens(
|
|
75
150
|
node: AST.Expression | AST.PrivateIdentifier,
|
|
76
151
|
parent:
|
|
152
|
+
| AST.MemberExpression
|
|
153
|
+
| AST.CallExpression
|
|
154
|
+
| AST.NewExpression
|
|
155
|
+
| AST.TaggedTemplateExpression
|
|
156
|
+
| AST.TSInstantiationExpression
|
|
157
|
+
| AST.TSNonNullExpression
|
|
158
|
+
| AST.TSAsExpression
|
|
159
|
+
| AST.TSSatisfiesExpression
|
|
77
160
|
| AST.BinaryExpression
|
|
78
161
|
| AST.LogicalExpression
|
|
79
|
-
| AST.AssignmentExpression
|
|
80
|
-
|
|
162
|
+
| AST.AssignmentExpression
|
|
163
|
+
| AST.ConditionalExpression,
|
|
164
|
+
where: "left" | "right",
|
|
81
165
|
): boolean {
|
|
166
|
+
// In a BinaryExpression where LHS have a TS postfix, e.g.:
|
|
167
|
+
// (0 as number) & 1;
|
|
168
|
+
// (0 as number) | 1;
|
|
169
|
+
// If op is & or |, then LHS should be parenthesized to disambiguate;
|
|
170
|
+
// otherwise, no need to parenthesize.
|
|
82
171
|
if (
|
|
83
|
-
|
|
84
|
-
node.type === "
|
|
85
|
-
|
|
172
|
+
where === "left" &&
|
|
173
|
+
(node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") &&
|
|
174
|
+
parent.type === "BinaryExpression"
|
|
86
175
|
) {
|
|
87
|
-
return
|
|
176
|
+
return parent.operator === "&" || parent.operator === "|";
|
|
88
177
|
}
|
|
89
178
|
|
|
90
179
|
// LogicalExpression mixed with ?? requires parens
|
|
@@ -96,36 +185,98 @@ function needsParens(
|
|
|
96
185
|
return true;
|
|
97
186
|
}
|
|
98
187
|
|
|
99
|
-
const precedence =
|
|
100
|
-
const parentPrecedence =
|
|
188
|
+
const precedence = getPrecedence(node);
|
|
189
|
+
const parentPrecedence = getPrecedence(parent);
|
|
190
|
+
|
|
191
|
+
if (
|
|
192
|
+
parent.type === "BinaryExpression" &&
|
|
193
|
+
parent.operator === "**" &&
|
|
194
|
+
precedence === EXPRESSIONS_PRECEDENCE.UnaryExpression
|
|
195
|
+
) {
|
|
196
|
+
// LHS of ** cannot have prefix operators, according to ES spec.
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
101
199
|
|
|
102
200
|
if (precedence !== parentPrecedence) {
|
|
103
|
-
// ** is right-to-left associative: `a ** b ** c` => `a ** (b ** c)`
|
|
104
|
-
if (
|
|
105
|
-
!isRight &&
|
|
106
|
-
precedence === 15 &&
|
|
107
|
-
parentPrecedence === 14 &&
|
|
108
|
-
parent.operator === "**"
|
|
109
|
-
) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
201
|
return precedence < parentPrecedence;
|
|
113
202
|
}
|
|
114
203
|
|
|
115
|
-
|
|
116
|
-
|
|
204
|
+
// optional chain cannot appeared as LHS of MemberExpression-like
|
|
205
|
+
if (
|
|
206
|
+
precedence === EXPRESSIONS_PRECEDENCE.MemberExpression &&
|
|
207
|
+
node.type === "ChainExpression"
|
|
208
|
+
) {
|
|
209
|
+
return true;
|
|
117
210
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
211
|
+
if (
|
|
212
|
+
parent.type === "NewExpression" &&
|
|
213
|
+
!validUnparenthesizedNewOperand(node as MemberLikeExpression)
|
|
214
|
+
) {
|
|
215
|
+
// new X(), X cannot contain CallExpression
|
|
216
|
+
return true;
|
|
123
217
|
}
|
|
124
218
|
|
|
125
|
-
|
|
126
|
-
|
|
219
|
+
const associative = ASSOCIATIVE[precedence] ?? "left";
|
|
220
|
+
return associative !== where;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* A valid unparenthesized `new` operand must be a member chain
|
|
225
|
+
* which not contains a CallExpression
|
|
226
|
+
*/
|
|
227
|
+
function validUnparenthesizedNewOperand(node: MemberLikeExpression): boolean {
|
|
228
|
+
let cur: AST.Expression = node;
|
|
229
|
+
while (true) {
|
|
230
|
+
if (cur.type === "CallExpression") {
|
|
231
|
+
return false;
|
|
232
|
+
} else if (cur.type === "TSNonNullExpression") {
|
|
233
|
+
cur = cur.expression;
|
|
234
|
+
} else if (cur.type === "MemberExpression") {
|
|
235
|
+
cur = cur.object;
|
|
236
|
+
} else if (cur.type === "TaggedTemplateExpression") {
|
|
237
|
+
cur = cur.tag;
|
|
238
|
+
} else if (
|
|
239
|
+
cur.type === "MetaProperty" ||
|
|
240
|
+
cur.type === "NewExpression" ||
|
|
241
|
+
cur.type === "ImportExpression"
|
|
242
|
+
) {
|
|
243
|
+
return true;
|
|
244
|
+
} else {
|
|
245
|
+
// The operand is either:
|
|
246
|
+
// - an expression with higher precedence, no need to check further
|
|
247
|
+
// - an expression with lower precedence, will be inner-parenthesized later
|
|
248
|
+
// - a ChainExpression, will be inner-parenthesized later
|
|
249
|
+
return cur !== node;
|
|
250
|
+
}
|
|
127
251
|
}
|
|
128
|
-
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function operandOfUnaryExprNeedsParens(node: AST.Expression): boolean {
|
|
255
|
+
return (
|
|
256
|
+
EXPRESSIONS_PRECEDENCE[node.type] < EXPRESSIONS_PRECEDENCE.UnaryExpression
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function expectAssignmentExprNeedsParen(
|
|
261
|
+
node: AST.Expression | AST.SpreadElement,
|
|
262
|
+
): boolean {
|
|
263
|
+
return (
|
|
264
|
+
EXPRESSIONS_PRECEDENCE[node.type] <
|
|
265
|
+
EXPRESSIONS_PRECEDENCE.AssignmentExpression
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function expectLHSExprNeedsParen(
|
|
270
|
+
node: AST.Expression | AST.SpreadElement,
|
|
271
|
+
): boolean {
|
|
272
|
+
return (
|
|
273
|
+
EXPRESSIONS_PRECEDENCE[node.type] < EXPRESSIONS_PRECEDENCE.MemberExpression
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function commentNeedsNewline(comment: Comment): boolean {
|
|
278
|
+
if (comment.type === "Line") return true;
|
|
279
|
+
return comment.value.includes("\n");
|
|
129
280
|
}
|
|
130
281
|
|
|
131
282
|
function arrowConciseBodyNeedsWrap(
|
|
@@ -306,7 +457,54 @@ export const defaultPrinters = {
|
|
|
306
457
|
// JS – Statements
|
|
307
458
|
|
|
308
459
|
function printProgram(program: AST.Program, context: PrinterContext): void {
|
|
309
|
-
context.
|
|
460
|
+
context.writeNodeListWithNewLineSep(program.body);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function canStartExpressionStatement(
|
|
464
|
+
node: AST.Expression | AST.PrivateIdentifier,
|
|
465
|
+
): boolean {
|
|
466
|
+
let lhs: AST.Expression | AST.PrivateIdentifier;
|
|
467
|
+
switch (node.type) {
|
|
468
|
+
default:
|
|
469
|
+
return true;
|
|
470
|
+
case "ObjectExpression":
|
|
471
|
+
case "FunctionExpression":
|
|
472
|
+
case "ClassExpression":
|
|
473
|
+
case "ObjectPattern":
|
|
474
|
+
return false;
|
|
475
|
+
case "AssignmentExpression":
|
|
476
|
+
case "LogicalExpression":
|
|
477
|
+
case "BinaryExpression":
|
|
478
|
+
lhs = node.left;
|
|
479
|
+
break;
|
|
480
|
+
case "TSAsExpression":
|
|
481
|
+
case "TSSatisfiesExpression":
|
|
482
|
+
case "TSNonNullExpression":
|
|
483
|
+
lhs = node.expression;
|
|
484
|
+
break;
|
|
485
|
+
case "CallExpression":
|
|
486
|
+
lhs = node.callee;
|
|
487
|
+
break;
|
|
488
|
+
case "MemberExpression":
|
|
489
|
+
lhs = node.object;
|
|
490
|
+
break;
|
|
491
|
+
case "TaggedTemplateExpression":
|
|
492
|
+
lhs = node.tag;
|
|
493
|
+
break;
|
|
494
|
+
case "ConditionalExpression":
|
|
495
|
+
lhs = node.test;
|
|
496
|
+
break;
|
|
497
|
+
case "SequenceExpression":
|
|
498
|
+
return canStartExpressionStatement(node.expressions[0]);
|
|
499
|
+
case "UpdateExpression":
|
|
500
|
+
return canStartExpressionStatement(node.argument);
|
|
501
|
+
case "ChainExpression":
|
|
502
|
+
return canStartExpressionStatement(node.expression);
|
|
503
|
+
}
|
|
504
|
+
return (
|
|
505
|
+
operandOfBinaryExprNeedsParens(lhs, node, "left") ||
|
|
506
|
+
canStartExpressionStatement(lhs)
|
|
507
|
+
);
|
|
310
508
|
}
|
|
311
509
|
|
|
312
510
|
function printExpressionStatement(
|
|
@@ -314,11 +512,7 @@ function printExpressionStatement(
|
|
|
314
512
|
context: PrinterContext,
|
|
315
513
|
): void {
|
|
316
514
|
const expr = statement.expression;
|
|
317
|
-
if (
|
|
318
|
-
expr.type === "ObjectExpression" ||
|
|
319
|
-
expr.type === "FunctionExpression" ||
|
|
320
|
-
(expr.type === "AssignmentExpression" && expr.left.type === "ObjectPattern")
|
|
321
|
-
) {
|
|
515
|
+
if (!canStartExpressionStatement(expr)) {
|
|
322
516
|
context.write("(");
|
|
323
517
|
context.writeNode(expr);
|
|
324
518
|
context.write(");");
|
|
@@ -358,7 +552,14 @@ function printVariableDeclarator(
|
|
|
358
552
|
}
|
|
359
553
|
if (declarator.init) {
|
|
360
554
|
context.write(" = ");
|
|
361
|
-
|
|
555
|
+
const needsParens = expectAssignmentExprNeedsParen(declarator.init);
|
|
556
|
+
if (needsParens) {
|
|
557
|
+
context.write("(");
|
|
558
|
+
context.writeNode(declarator.init);
|
|
559
|
+
context.write(")");
|
|
560
|
+
} else {
|
|
561
|
+
context.writeNode(declarator.init);
|
|
562
|
+
}
|
|
362
563
|
}
|
|
363
564
|
}
|
|
364
565
|
|
|
@@ -370,7 +571,7 @@ function printBlockStatement(
|
|
|
370
571
|
context.write("{");
|
|
371
572
|
if (body.length > 0) {
|
|
372
573
|
context.write("\n");
|
|
373
|
-
context.
|
|
574
|
+
context.writeNodeListWithNewLineSep(body);
|
|
374
575
|
context.write("\n");
|
|
375
576
|
}
|
|
376
577
|
context.write("}");
|
|
@@ -660,12 +861,21 @@ function printUnaryExpression(
|
|
|
660
861
|
if (expr.operator.length > 1) {
|
|
661
862
|
context.write(" ");
|
|
662
863
|
}
|
|
663
|
-
const
|
|
664
|
-
if (
|
|
864
|
+
const needsParen = operandOfUnaryExprNeedsParens(expr.argument);
|
|
865
|
+
if (needsParen) {
|
|
665
866
|
context.write("(");
|
|
666
867
|
context.writeNode(expr.argument);
|
|
667
868
|
context.write(")");
|
|
668
869
|
} else {
|
|
870
|
+
if (
|
|
871
|
+
expr.operator.length === 1 &&
|
|
872
|
+
(expr.argument.type === "UnaryExpression" ||
|
|
873
|
+
expr.argument.type === "UpdateExpression") &&
|
|
874
|
+
expr.argument.operator.startsWith(expr.operator)
|
|
875
|
+
) {
|
|
876
|
+
// `- -x` or `+ ++x` should not be printed as `--x` or `+++x`
|
|
877
|
+
context.write(" ");
|
|
878
|
+
}
|
|
669
879
|
context.writeNode(expr.argument);
|
|
670
880
|
}
|
|
671
881
|
}
|
|
@@ -704,7 +914,7 @@ function printBinaryExpression(
|
|
|
704
914
|
const left = expression.left;
|
|
705
915
|
const right = expression.right;
|
|
706
916
|
|
|
707
|
-
if (
|
|
917
|
+
if (operandOfBinaryExprNeedsParens(left, expression, "left")) {
|
|
708
918
|
context.write("(");
|
|
709
919
|
context.writeNode(left);
|
|
710
920
|
context.write(")");
|
|
@@ -716,7 +926,7 @@ function printBinaryExpression(
|
|
|
716
926
|
context.write(String(expression.operator));
|
|
717
927
|
context.write(" ");
|
|
718
928
|
|
|
719
|
-
if (
|
|
929
|
+
if (operandOfBinaryExprNeedsParens(right, expression, "right")) {
|
|
720
930
|
context.write("(");
|
|
721
931
|
context.writeNode(right);
|
|
722
932
|
context.write(")");
|
|
@@ -729,8 +939,7 @@ function printConditionalExpression(
|
|
|
729
939
|
expr: AST.ConditionalExpression,
|
|
730
940
|
context: PrinterContext,
|
|
731
941
|
): void {
|
|
732
|
-
|
|
733
|
-
if (testPrec <= EXPRESSIONS_PRECEDENCE.ConditionalExpression) {
|
|
942
|
+
if (operandOfBinaryExprNeedsParens(expr.test, expr, "left")) {
|
|
734
943
|
context.write("(");
|
|
735
944
|
context.writeNode(expr.test);
|
|
736
945
|
context.write(")");
|
|
@@ -740,7 +949,13 @@ function printConditionalExpression(
|
|
|
740
949
|
context.write(" ? ");
|
|
741
950
|
context.writeNode(expr.consequent);
|
|
742
951
|
context.write(" : ");
|
|
743
|
-
|
|
952
|
+
if (operandOfBinaryExprNeedsParens(expr.alternate, expr, "right")) {
|
|
953
|
+
context.write("(");
|
|
954
|
+
context.writeNode(expr.alternate);
|
|
955
|
+
context.write(")");
|
|
956
|
+
} else {
|
|
957
|
+
context.writeNode(expr.alternate);
|
|
958
|
+
}
|
|
744
959
|
}
|
|
745
960
|
|
|
746
961
|
function printYieldExpression(
|
|
@@ -753,12 +968,14 @@ function printYieldExpression(
|
|
|
753
968
|
const leadingComments = context.options.getLeadingComments?.(expr.argument);
|
|
754
969
|
const needsParensASi =
|
|
755
970
|
leadingComments?.some((c) => commentNeedsNewline(c)) ?? false;
|
|
756
|
-
|
|
971
|
+
const needsParens =
|
|
972
|
+
needsParensASi || expectAssignmentExprNeedsParen(expr.argument);
|
|
973
|
+
if (needsParens) {
|
|
757
974
|
context.write("(");
|
|
758
|
-
|
|
759
|
-
context.writeNode(expr.argument);
|
|
760
|
-
if (needsParensASi) {
|
|
975
|
+
context.writeNode(expr.argument);
|
|
761
976
|
context.write(")");
|
|
977
|
+
} else {
|
|
978
|
+
context.writeNode(expr.argument);
|
|
762
979
|
}
|
|
763
980
|
}
|
|
764
981
|
}
|
|
@@ -769,8 +986,8 @@ function printAwaitExpression(
|
|
|
769
986
|
): void {
|
|
770
987
|
context.write("await");
|
|
771
988
|
if (expr.argument) {
|
|
772
|
-
const
|
|
773
|
-
if (
|
|
989
|
+
const needsParens = operandOfUnaryExprNeedsParens(expr.argument);
|
|
990
|
+
if (needsParens) {
|
|
774
991
|
context.write(" (");
|
|
775
992
|
context.writeNode(expr.argument);
|
|
776
993
|
context.write(")");
|
|
@@ -785,17 +1002,19 @@ function printSequenceExpression(
|
|
|
785
1002
|
expr: AST.SequenceExpression,
|
|
786
1003
|
context: PrinterContext,
|
|
787
1004
|
): void {
|
|
788
|
-
context.write("(");
|
|
789
1005
|
context.writeNodeList(expr.expressions, ", ");
|
|
790
|
-
context.write(")");
|
|
791
1006
|
}
|
|
792
1007
|
|
|
793
1008
|
function printCallExpression(
|
|
794
1009
|
expression: AST.CallExpression,
|
|
795
1010
|
context: PrinterContext,
|
|
796
1011
|
): void {
|
|
797
|
-
const
|
|
798
|
-
|
|
1012
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
1013
|
+
expression.callee,
|
|
1014
|
+
expression,
|
|
1015
|
+
"left",
|
|
1016
|
+
);
|
|
1017
|
+
if (needsParens) {
|
|
799
1018
|
context.write("(");
|
|
800
1019
|
context.writeNode(expression.callee);
|
|
801
1020
|
context.write(")");
|
|
@@ -815,7 +1034,7 @@ function printCallExpression(
|
|
|
815
1034
|
} else {
|
|
816
1035
|
context.write("(");
|
|
817
1036
|
}
|
|
818
|
-
context.
|
|
1037
|
+
context.writeExpressionListWithCommaSep(expression.arguments);
|
|
819
1038
|
context.write(")");
|
|
820
1039
|
}
|
|
821
1040
|
|
|
@@ -824,11 +1043,12 @@ function printNewExpression(
|
|
|
824
1043
|
context: PrinterContext,
|
|
825
1044
|
): void {
|
|
826
1045
|
context.write("new ");
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
)
|
|
1046
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
1047
|
+
expression.callee,
|
|
1048
|
+
expression,
|
|
1049
|
+
"left",
|
|
1050
|
+
);
|
|
1051
|
+
if (needsParens) {
|
|
832
1052
|
context.write("(");
|
|
833
1053
|
context.writeNode(expression.callee);
|
|
834
1054
|
context.write(")");
|
|
@@ -845,23 +1065,10 @@ function printNewExpression(
|
|
|
845
1065
|
} else {
|
|
846
1066
|
context.write("(");
|
|
847
1067
|
}
|
|
848
|
-
context.
|
|
1068
|
+
context.writeExpressionListWithCommaSep(expression.arguments);
|
|
849
1069
|
context.write(")");
|
|
850
1070
|
}
|
|
851
1071
|
|
|
852
|
-
function hasCallExpression(node: AST.Expression): boolean {
|
|
853
|
-
let cur: AST.Expression | undefined = node;
|
|
854
|
-
while (cur) {
|
|
855
|
-
if (cur.type === "CallExpression") return true;
|
|
856
|
-
if (cur.type === "MemberExpression") {
|
|
857
|
-
cur = cur.object;
|
|
858
|
-
} else {
|
|
859
|
-
return false;
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
return false;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
1072
|
function printChainExpression(
|
|
866
1073
|
expression: AST.ChainExpression,
|
|
867
1074
|
context: PrinterContext,
|
|
@@ -873,8 +1080,12 @@ function printMemberExpression(
|
|
|
873
1080
|
expression: AST.MemberExpression,
|
|
874
1081
|
context: PrinterContext,
|
|
875
1082
|
): void {
|
|
876
|
-
const
|
|
877
|
-
|
|
1083
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
1084
|
+
expression.object,
|
|
1085
|
+
expression,
|
|
1086
|
+
"left",
|
|
1087
|
+
);
|
|
1088
|
+
if (needsParens) {
|
|
878
1089
|
context.write("(");
|
|
879
1090
|
context.writeNode(expression.object);
|
|
880
1091
|
context.write(")");
|
|
@@ -915,7 +1126,7 @@ function printArrayExpression(
|
|
|
915
1126
|
context: PrinterContext,
|
|
916
1127
|
): void {
|
|
917
1128
|
context.write("[");
|
|
918
|
-
context.
|
|
1129
|
+
context.writeExpressionListWithCommaSep(array.elements);
|
|
919
1130
|
context.write("]");
|
|
920
1131
|
}
|
|
921
1132
|
|
|
@@ -996,7 +1207,14 @@ function printSpreadElement(
|
|
|
996
1207
|
context: PrinterContext,
|
|
997
1208
|
): void {
|
|
998
1209
|
context.write("...");
|
|
999
|
-
|
|
1210
|
+
const needsParens = expectAssignmentExprNeedsParen(spread.argument);
|
|
1211
|
+
if (needsParens) {
|
|
1212
|
+
context.write("(");
|
|
1213
|
+
context.writeNode(spread.argument);
|
|
1214
|
+
context.write(")");
|
|
1215
|
+
} else {
|
|
1216
|
+
context.writeNode(spread.argument);
|
|
1217
|
+
}
|
|
1000
1218
|
}
|
|
1001
1219
|
|
|
1002
1220
|
function printRestElement(
|
|
@@ -1037,7 +1255,17 @@ function printTaggedTemplateExpression(
|
|
|
1037
1255
|
node: AST.TaggedTemplateExpression,
|
|
1038
1256
|
context: PrinterContext,
|
|
1039
1257
|
): void {
|
|
1040
|
-
|
|
1258
|
+
const needsParens = operandOfBinaryExprNeedsParens(node.tag, node, "left");
|
|
1259
|
+
if (needsParens) {
|
|
1260
|
+
context.write("(");
|
|
1261
|
+
context.writeNode(node.tag);
|
|
1262
|
+
context.write(")");
|
|
1263
|
+
} else {
|
|
1264
|
+
context.writeNode(node.tag);
|
|
1265
|
+
}
|
|
1266
|
+
if (node.typeArguments) {
|
|
1267
|
+
context.writeNode(node.typeArguments);
|
|
1268
|
+
}
|
|
1041
1269
|
context.writeNode(node.quasi);
|
|
1042
1270
|
}
|
|
1043
1271
|
|
|
@@ -1175,7 +1403,14 @@ function printClass(
|
|
|
1175
1403
|
}
|
|
1176
1404
|
if (node.superClass) {
|
|
1177
1405
|
context.write("extends ");
|
|
1178
|
-
|
|
1406
|
+
const needsParens = expectLHSExprNeedsParen(node.superClass);
|
|
1407
|
+
if (needsParens) {
|
|
1408
|
+
context.write("(");
|
|
1409
|
+
context.writeNode(node.superClass);
|
|
1410
|
+
context.write(")");
|
|
1411
|
+
} else {
|
|
1412
|
+
context.writeNode(node.superClass);
|
|
1413
|
+
}
|
|
1179
1414
|
if (node.superTypeArguments) {
|
|
1180
1415
|
context.writeNode(node.superTypeArguments);
|
|
1181
1416
|
} else if (node.superTypeParameters) {
|
|
@@ -1197,7 +1432,7 @@ function printClassBody(node: AST.ClassBody, context: PrinterContext): void {
|
|
|
1197
1432
|
const body = node.body;
|
|
1198
1433
|
if (body.length > 0) {
|
|
1199
1434
|
context.write("\n");
|
|
1200
|
-
context.
|
|
1435
|
+
context.writeNodeListWithNewLineSep(body);
|
|
1201
1436
|
context.write("\n");
|
|
1202
1437
|
}
|
|
1203
1438
|
context.write("}");
|
|
@@ -1211,15 +1446,43 @@ function printStaticBlock(
|
|
|
1211
1446
|
const body = node.body;
|
|
1212
1447
|
if (body.length > 0) {
|
|
1213
1448
|
context.write("\n");
|
|
1214
|
-
context.
|
|
1449
|
+
context.writeNodeListWithNewLineSep(body);
|
|
1215
1450
|
context.write("\n");
|
|
1216
1451
|
}
|
|
1217
1452
|
context.write("}");
|
|
1218
1453
|
}
|
|
1219
1454
|
|
|
1455
|
+
function validUnparenthesizedDecorator(node: AST.Expression): boolean {
|
|
1456
|
+
let current: AST.Expression = node;
|
|
1457
|
+
if (current.type === "CallExpression") {
|
|
1458
|
+
current = current.callee;
|
|
1459
|
+
}
|
|
1460
|
+
if (current.type === "TSInstantiationExpression") {
|
|
1461
|
+
current = current.expression;
|
|
1462
|
+
}
|
|
1463
|
+
while (true) {
|
|
1464
|
+
if (current.type === "Identifier") {
|
|
1465
|
+
return true;
|
|
1466
|
+
} else if (current.type === "MemberExpression") {
|
|
1467
|
+
if (current.computed) {
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1470
|
+
current = current.object;
|
|
1471
|
+
} else {
|
|
1472
|
+
return false;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1220
1477
|
function printDecorator(node: AST.Decorator, context: PrinterContext): void {
|
|
1221
1478
|
context.write("@");
|
|
1222
|
-
|
|
1479
|
+
if (!validUnparenthesizedDecorator(node.expression)) {
|
|
1480
|
+
context.write("(");
|
|
1481
|
+
context.writeNode(node.expression);
|
|
1482
|
+
context.write(")");
|
|
1483
|
+
} else {
|
|
1484
|
+
context.writeNode(node.expression);
|
|
1485
|
+
}
|
|
1223
1486
|
context.write("\n");
|
|
1224
1487
|
}
|
|
1225
1488
|
|
|
@@ -1375,13 +1638,17 @@ function printImportDeclaration(
|
|
|
1375
1638
|
}
|
|
1376
1639
|
|
|
1377
1640
|
if (namespaceSpec) {
|
|
1378
|
-
if (wroteDefault)
|
|
1641
|
+
if (wroteDefault) {
|
|
1642
|
+
context.write(", ");
|
|
1643
|
+
}
|
|
1379
1644
|
context.write("* as ");
|
|
1380
1645
|
context.writeNode(namespaceSpec.local);
|
|
1381
1646
|
}
|
|
1382
1647
|
|
|
1383
1648
|
if (namedSpecs.length > 0) {
|
|
1384
|
-
if (wroteDefault || namespaceSpec)
|
|
1649
|
+
if (wroteDefault || namespaceSpec) {
|
|
1650
|
+
context.write(", ");
|
|
1651
|
+
}
|
|
1385
1652
|
context.write("{ ");
|
|
1386
1653
|
context.writeNodeList(namedSpecs, ", ");
|
|
1387
1654
|
context.write(" }");
|
|
@@ -1546,8 +1813,12 @@ function printTSAsExpression(
|
|
|
1546
1813
|
expression: AST.TSAsExpression,
|
|
1547
1814
|
context: PrinterContext,
|
|
1548
1815
|
): void {
|
|
1549
|
-
const
|
|
1550
|
-
|
|
1816
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
1817
|
+
expression.expression,
|
|
1818
|
+
expression,
|
|
1819
|
+
"left",
|
|
1820
|
+
);
|
|
1821
|
+
if (needsParens) {
|
|
1551
1822
|
context.write("(");
|
|
1552
1823
|
context.writeNode(expression.expression);
|
|
1553
1824
|
context.write(")");
|
|
@@ -1562,8 +1833,12 @@ function printTSSatisfiesExpression(
|
|
|
1562
1833
|
expression: AST.TSSatisfiesExpression,
|
|
1563
1834
|
context: PrinterContext,
|
|
1564
1835
|
): void {
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1836
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
1837
|
+
expression.expression,
|
|
1838
|
+
expression,
|
|
1839
|
+
"left",
|
|
1840
|
+
);
|
|
1841
|
+
if (needsParens) {
|
|
1567
1842
|
context.write("(");
|
|
1568
1843
|
context.writeNode(expression.expression);
|
|
1569
1844
|
context.write(")");
|
|
@@ -1581,8 +1856,8 @@ function printTSTypeAssertion(
|
|
|
1581
1856
|
context.write("<");
|
|
1582
1857
|
context.writeNode(expression.typeAnnotation);
|
|
1583
1858
|
context.write(">");
|
|
1584
|
-
const
|
|
1585
|
-
if (
|
|
1859
|
+
const needsParens = operandOfUnaryExprNeedsParens(expression.expression);
|
|
1860
|
+
if (needsParens) {
|
|
1586
1861
|
context.write("(");
|
|
1587
1862
|
context.writeNode(expression.expression);
|
|
1588
1863
|
context.write(")");
|
|
@@ -1595,7 +1870,18 @@ function printTSNonNullExpression(
|
|
|
1595
1870
|
expression: AST.TSNonNullExpression,
|
|
1596
1871
|
context: PrinterContext,
|
|
1597
1872
|
): void {
|
|
1598
|
-
|
|
1873
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
1874
|
+
expression.expression,
|
|
1875
|
+
expression,
|
|
1876
|
+
"left",
|
|
1877
|
+
);
|
|
1878
|
+
if (needsParens) {
|
|
1879
|
+
context.write("(");
|
|
1880
|
+
context.writeNode(expression.expression);
|
|
1881
|
+
context.write(")");
|
|
1882
|
+
} else {
|
|
1883
|
+
context.writeNode(expression.expression);
|
|
1884
|
+
}
|
|
1599
1885
|
context.write("!");
|
|
1600
1886
|
}
|
|
1601
1887
|
|
|
@@ -1991,7 +2277,14 @@ function printTSMappedType(
|
|
|
1991
2277
|
node: AST.TSMappedType,
|
|
1992
2278
|
context: PrinterContext,
|
|
1993
2279
|
): void {
|
|
1994
|
-
context.write("{
|
|
2280
|
+
context.write("{ ");
|
|
2281
|
+
if (node.readonly) {
|
|
2282
|
+
if (typeof node.readonly === "string") {
|
|
2283
|
+
context.write(node.readonly);
|
|
2284
|
+
}
|
|
2285
|
+
context.write("readonly ");
|
|
2286
|
+
}
|
|
2287
|
+
context.write("[");
|
|
1995
2288
|
const legacyTp = node.typeParameter;
|
|
1996
2289
|
const key = node.key ?? legacyTp?.name;
|
|
1997
2290
|
const constraint = node.constraint ?? legacyTp?.constraint;
|
|
@@ -2007,7 +2300,17 @@ function printTSMappedType(
|
|
|
2007
2300
|
context.write(" in ");
|
|
2008
2301
|
context.writeNode(constraint);
|
|
2009
2302
|
}
|
|
2303
|
+
if (node.nameType) {
|
|
2304
|
+
context.write(" as ");
|
|
2305
|
+
context.writeNode(node.nameType);
|
|
2306
|
+
}
|
|
2010
2307
|
context.write("]");
|
|
2308
|
+
if (node.optional) {
|
|
2309
|
+
if (typeof node.optional === "string") {
|
|
2310
|
+
context.write(node.optional);
|
|
2311
|
+
}
|
|
2312
|
+
context.write("?");
|
|
2313
|
+
}
|
|
2011
2314
|
if (node.typeAnnotation) {
|
|
2012
2315
|
context.write(": ");
|
|
2013
2316
|
context.writeNode(node.typeAnnotation);
|
|
@@ -2164,11 +2467,18 @@ function printTSModuleDeclaration(
|
|
|
2164
2467
|
context.write(String(kind) + " ");
|
|
2165
2468
|
context.writeNode(node.id);
|
|
2166
2469
|
}
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2470
|
+
let body = node.body as
|
|
2471
|
+
| AST.TSModuleDeclaration
|
|
2472
|
+
| AST.TSModuleBlock
|
|
2473
|
+
| undefined;
|
|
2474
|
+
while (body?.type === "TSModuleDeclaration") {
|
|
2475
|
+
context.write(".");
|
|
2476
|
+
context.writeNode(body.id);
|
|
2477
|
+
body = body.body;
|
|
2478
|
+
}
|
|
2479
|
+
if (body) {
|
|
2480
|
+
context.write(" ");
|
|
2481
|
+
context.writeNode(body);
|
|
2172
2482
|
}
|
|
2173
2483
|
}
|
|
2174
2484
|
|
|
@@ -2177,7 +2487,7 @@ function printTSModuleBlock(
|
|
|
2177
2487
|
context: PrinterContext,
|
|
2178
2488
|
): void {
|
|
2179
2489
|
context.write("{\n");
|
|
2180
|
-
context.
|
|
2490
|
+
context.writeNodeListWithNewLineSep(node.body);
|
|
2181
2491
|
context.write("\n}");
|
|
2182
2492
|
}
|
|
2183
2493
|
|
|
@@ -2239,10 +2549,21 @@ function printTSNamespaceExportDeclaration(
|
|
|
2239
2549
|
}
|
|
2240
2550
|
|
|
2241
2551
|
function printTSInstantiationExpression(
|
|
2242
|
-
node:
|
|
2552
|
+
node: AST.TSInstantiationExpression,
|
|
2243
2553
|
context: PrinterContext,
|
|
2244
2554
|
): void {
|
|
2245
|
-
|
|
2555
|
+
const needsParens = operandOfBinaryExprNeedsParens(
|
|
2556
|
+
node.expression,
|
|
2557
|
+
node,
|
|
2558
|
+
"left",
|
|
2559
|
+
);
|
|
2560
|
+
if (needsParens) {
|
|
2561
|
+
context.write("(");
|
|
2562
|
+
context.writeNode(node.expression);
|
|
2563
|
+
context.write(")");
|
|
2564
|
+
} else {
|
|
2565
|
+
context.writeNode(node.expression);
|
|
2566
|
+
}
|
|
2246
2567
|
context.writeNode(node.typeArguments);
|
|
2247
2568
|
}
|
|
2248
2569
|
|
|
@@ -2274,3 +2595,14 @@ function writeOptionalTypeAnnotation(
|
|
|
2274
2595
|
context.writeNode(node.typeAnnotation);
|
|
2275
2596
|
}
|
|
2276
2597
|
}
|
|
2598
|
+
|
|
2599
|
+
export function writeComment(comment: Comment, context: PrinterContext): void {
|
|
2600
|
+
if (comment.type === "Line") {
|
|
2601
|
+
context.write("//" + comment.value + "\n");
|
|
2602
|
+
} else {
|
|
2603
|
+
context.write("/*" + comment.value + "*/");
|
|
2604
|
+
if (comment.value.includes("\n")) {
|
|
2605
|
+
context.write("\n");
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
}
|