espolar 0.2.0 → 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.
@@ -0,0 +1,2608 @@
1
+ import type { PrinterContext, Printers } from "./api.ts";
2
+ import type { AST, AST_NODE_TYPES, Comment } from "./types.ts";
3
+
4
+ const EXPRESSIONS_PRECEDENCE = {
5
+ // LHS of =, must NOT parenthesized
6
+ ArrayPattern: 20,
7
+ ObjectPattern: 20,
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
16
+ Literal: 18,
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,
59
+ YieldExpression: 2,
60
+ ArrowFunctionExpression: 2,
61
+ SpreadElement: 2,
62
+
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,
76
+ "<": 9,
77
+ ">": 9,
78
+ "<=": 9,
79
+ ">=": 9,
80
+ in: 9,
81
+ instanceof: 9,
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",
112
+ };
113
+
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(
150
+ node: AST.Expression | AST.PrivateIdentifier,
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
160
+ | AST.BinaryExpression
161
+ | AST.LogicalExpression
162
+ | AST.AssignmentExpression
163
+ | AST.ConditionalExpression,
164
+ where: "left" | "right",
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.
171
+ if (
172
+ where === "left" &&
173
+ (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") &&
174
+ parent.type === "BinaryExpression"
175
+ ) {
176
+ return parent.operator === "&" || parent.operator === "|";
177
+ }
178
+
179
+ // LogicalExpression mixed with ?? requires parens
180
+ if (
181
+ node.type === "LogicalExpression" &&
182
+ parent.type === "LogicalExpression" &&
183
+ (parent.operator === "??") !== (node.operator === "??")
184
+ ) {
185
+ return true;
186
+ }
187
+
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
+ }
199
+
200
+ if (precedence !== parentPrecedence) {
201
+ return precedence < parentPrecedence;
202
+ }
203
+
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;
210
+ }
211
+ if (
212
+ parent.type === "NewExpression" &&
213
+ !validUnparenthesizedNewOperand(node as MemberLikeExpression)
214
+ ) {
215
+ // new X(), X cannot contain CallExpression
216
+ return true;
217
+ }
218
+
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
+ }
251
+ }
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");
280
+ }
281
+
282
+ function arrowConciseBodyNeedsWrap(
283
+ body: AST.BlockStatement | AST.Expression,
284
+ ): boolean {
285
+ if (body.type === "BlockStatement") return false;
286
+ switch (body.type) {
287
+ case "ObjectExpression":
288
+ return true;
289
+ case "AssignmentExpression":
290
+ return body.left.type === "ObjectPattern";
291
+ case "LogicalExpression":
292
+ return body.left.type === "ObjectExpression";
293
+ case "ConditionalExpression":
294
+ return body.test.type === "ObjectExpression";
295
+ case "TSAsExpression":
296
+ case "TSSatisfiesExpression":
297
+ case "TSNonNullExpression":
298
+ return body.expression
299
+ ? arrowConciseBodyNeedsWrap(body.expression)
300
+ : false;
301
+ default:
302
+ return false;
303
+ }
304
+ }
305
+
306
+ // Printers
307
+ export const defaultPrinters = {
308
+ Program: printProgram,
309
+ Identifier: printIdentifier,
310
+ PrivateIdentifier: printPrivateIdentifier,
311
+ Literal: printLiteral,
312
+ ExpressionStatement: printExpressionStatement,
313
+ EmptyStatement: printEmptyStatement,
314
+ VariableDeclaration: printVariableDeclaration,
315
+ VariableDeclarator: printVariableDeclarator,
316
+ BlockStatement: printBlockStatement,
317
+ ReturnStatement: printReturnStatement,
318
+ ThrowStatement: printThrowStatement,
319
+ DebuggerStatement: printDebuggerStatement,
320
+ BreakStatement: printBreakStatement,
321
+ ContinueStatement: printContinueStatement,
322
+ LabeledStatement: printLabeledStatement,
323
+ WhileStatement: printWhileStatement,
324
+ DoWhileStatement: printDoWhileStatement,
325
+ IfStatement: printIfStatement,
326
+ ForStatement: printForStatement,
327
+ ForInStatement: printForInStatement,
328
+ ForOfStatement: printForOfStatement,
329
+ SwitchStatement: printSwitchStatement,
330
+ SwitchCase: printSwitchCase,
331
+ TryStatement: printTryStatement,
332
+ WithStatement: printWithStatement,
333
+ FunctionDeclaration: printFunctionDeclaration,
334
+ FunctionExpression: printFunctionExpression,
335
+ ArrowFunctionExpression: printArrowFunctionExpression,
336
+ UnaryExpression: printUnaryExpression,
337
+ UpdateExpression: printUpdateExpression,
338
+ BinaryExpression: printBinaryExpression,
339
+ LogicalExpression: printBinaryExpression,
340
+ AssignmentExpression: printBinaryExpression,
341
+ ConditionalExpression: printConditionalExpression,
342
+ YieldExpression: printYieldExpression,
343
+ AwaitExpression: printAwaitExpression,
344
+ SequenceExpression: printSequenceExpression,
345
+ CallExpression: printCallExpression,
346
+ NewExpression: printNewExpression,
347
+ ChainExpression: printChainExpression,
348
+ MemberExpression: printMemberExpression,
349
+ ObjectExpression: printObjectExpression,
350
+ ObjectPattern: printObjectPattern,
351
+ ArrayExpression: printArrayExpression,
352
+ ArrayPattern: printArrayPattern,
353
+ Property: printProperty,
354
+ SpreadElement: printSpreadElement,
355
+ RestElement: printRestElement,
356
+ AssignmentPattern: printAssignmentPattern,
357
+ TemplateLiteral: printTemplateLiteral,
358
+ TaggedTemplateExpression: printTaggedTemplateExpression,
359
+ ThisExpression: printThisExpression,
360
+ Super: printSuper,
361
+ MetaProperty: printMetaProperty,
362
+ // @ts-expect-error acorn-typescript compat (ParenthesizedExpression is not in TSESTree types)
363
+ ParenthesizedExpression: printParenthesizedExpression,
364
+ ClassDeclaration: printClassDeclaration,
365
+ ClassExpression: printClassExpression,
366
+ ClassBody: printClassBody,
367
+ StaticBlock: printStaticBlock,
368
+ PropertyDefinition: printPropertyDefinition,
369
+ AccessorProperty: printPropertyDefinition,
370
+ MethodDefinition: printMethodDefinition,
371
+ Decorator: printDecorator,
372
+
373
+ ImportDeclaration: printImportDeclaration,
374
+ ImportExpression: printImportExpression,
375
+ ImportSpecifier: printImportSpecifier,
376
+ ImportDefaultSpecifier: printImportDefaultSpecifier,
377
+ ExportNamedDeclaration: printExportNamedDeclaration,
378
+ ExportDefaultDeclaration: printExportDefaultDeclaration,
379
+ ExportAllDeclaration: printExportAllDeclaration,
380
+ ExportSpecifier: printExportSpecifier,
381
+
382
+ // TypeScript
383
+ TSAsExpression: printTSAsExpression,
384
+ TSSatisfiesExpression: printTSSatisfiesExpression,
385
+ TSTypeAssertion: printTSTypeAssertion,
386
+ TSNonNullExpression: printTSNonNullExpression,
387
+ TSTypeAnnotation: printTSTypeAnnotation,
388
+ TSTypeAliasDeclaration: printTSTypeAliasDeclaration,
389
+ TSInterfaceDeclaration: printTSInterfaceDeclaration,
390
+ // TSESTree do not have this entry
391
+ // https://github.com/sveltejs/acorn-typescript/issues/7#issuecomment-3237280163
392
+ TSExpressionWithTypeArguments: printTSExpressionWithTypeArguments,
393
+ TSClassImplements: printTSExpressionWithTypeArguments,
394
+ TSInterfaceHeritage: printTSExpressionWithTypeArguments,
395
+ TSFunctionType: printTSFunctionType,
396
+ TSConstructorType: printTSConstructorType,
397
+ TSMethodSignature: printTSMethodSignature,
398
+ TSCallSignatureDeclaration: printTSCallSignatureDeclaration,
399
+ TSConstructSignatureDeclaration: printTSConstructSignatureDeclaration,
400
+ TSIndexSignature: printTSIndexSignature,
401
+ TSPropertySignature: printTSPropertySignature,
402
+ TSTypeParameterDeclaration: printTypeParameterDeclaration,
403
+ TSTypeParameterInstantiation: printTypeParameterInstantiation,
404
+ TSTypeParameter: printTSTypeParameter,
405
+ TSTypeReference: printTSTypeReference,
406
+ TSQualifiedName: printTSQualifiedName,
407
+ TSUnionType: printJoinedTypes,
408
+ TSIntersectionType: printJoinedTypes,
409
+ TSArrayType: printTSArrayType,
410
+ TSTupleType: printTSTupleType,
411
+ TSNamedTupleMember: printTSNamedTupleMember,
412
+ TSTypeLiteral: printTSTypeLiteral,
413
+ TSTypeOperator: printTSTypeOperator,
414
+ TSTypePredicate: printTSTypePredicate,
415
+ TSTypeQuery: printTSTypeQuery,
416
+ TSMappedType: printTSMappedType,
417
+ TSConditionalType: printTSConditionalType,
418
+ TSInferType: printTSInferType,
419
+ TSIndexedAccessType: printTSIndexedAccessType,
420
+ TSOptionalType: printTSOptionalType,
421
+ TSRestType: printTSRestType,
422
+ TSThisType: printTSThisType,
423
+ TSLiteralType: printTSLiteralType,
424
+ TSTemplateLiteralType: printTSTemplateLiteralType,
425
+ TSImportType: printTSImportType,
426
+ TSImportEqualsDeclaration: printTSImportEqualsDeclaration,
427
+ TSExternalModuleReference: printTSExternalModuleReference,
428
+ TSEnumDeclaration: printTSEnumDeclaration,
429
+ TSEnumMember: printTSEnumMember,
430
+ TSModuleDeclaration: printTSModuleDeclaration,
431
+ TSModuleBlock: printTSModuleBlock,
432
+ TSDeclareFunction: printTSDeclareFunction,
433
+ TSParameterProperty: printTSParameterProperty,
434
+ TSAbstractMethodDefinition: printMethodDefinition,
435
+ TSAbstractPropertyDefinition: printPropertyDefinition,
436
+ TSAbstractAccessorProperty: printPropertyDefinition,
437
+ TSExportAssignment: printTSExportAssignment,
438
+ TSNamespaceExportDeclaration: printTSNamespaceExportDeclaration,
439
+ TSInstantiationExpression: printTSInstantiationExpression,
440
+ TSParenthesizedType: printTSParenthesizedType,
441
+ TSInterfaceBody: printTSInterfaceBody,
442
+ TSStringKeyword: printKeywordType,
443
+ TSNumberKeyword: printKeywordType,
444
+ TSBooleanKeyword: printKeywordType,
445
+ TSVoidKeyword: printKeywordType,
446
+ TSUnknownKeyword: printKeywordType,
447
+ TSAnyKeyword: printKeywordType,
448
+ TSNeverKeyword: printKeywordType,
449
+ TSNullKeyword: printKeywordType,
450
+ TSUndefinedKeyword: printKeywordType,
451
+ TSObjectKeyword: printKeywordType,
452
+ TSSymbolKeyword: printKeywordType,
453
+ TSBigIntKeyword: printKeywordType,
454
+ TSIntrinsicKeyword: printKeywordType,
455
+ } satisfies Printers<unknown>;
456
+
457
+ // JS – Statements
458
+
459
+ function printProgram(program: AST.Program, context: PrinterContext): void {
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
+ );
508
+ }
509
+
510
+ function printExpressionStatement(
511
+ statement: AST.ExpressionStatement,
512
+ context: PrinterContext,
513
+ ): void {
514
+ const expr = statement.expression;
515
+ if (!canStartExpressionStatement(expr)) {
516
+ context.write("(");
517
+ context.writeNode(expr);
518
+ context.write(");");
519
+ } else {
520
+ context.writeNode(expr);
521
+ context.write(";");
522
+ }
523
+ }
524
+
525
+ function printEmptyStatement(
526
+ _statement: AST.EmptyStatement,
527
+ context: PrinterContext,
528
+ ): void {
529
+ context.write(";");
530
+ }
531
+
532
+ function printVariableDeclaration(
533
+ declaration: AST.VariableDeclaration,
534
+ context: PrinterContext,
535
+ ): void {
536
+ if (declaration.declare === true) {
537
+ context.write("declare ");
538
+ }
539
+ context.write(String(declaration.kind));
540
+ context.write(" ");
541
+ context.writeNodeList(declaration.declarations, ", ");
542
+ context.write(";");
543
+ }
544
+
545
+ function printVariableDeclarator(
546
+ declarator: AST.VariableDeclarator,
547
+ context: PrinterContext,
548
+ ): void {
549
+ context.writeNode(declarator.id);
550
+ if (declarator.definite === true) {
551
+ context.write("!");
552
+ }
553
+ if (declarator.init) {
554
+ context.write(" = ");
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
+ }
563
+ }
564
+ }
565
+
566
+ function printBlockStatement(
567
+ block: AST.BlockStatement,
568
+ context: PrinterContext,
569
+ ): void {
570
+ const body = block.body;
571
+ context.write("{");
572
+ if (body.length > 0) {
573
+ context.write("\n");
574
+ context.writeNodeListWithNewLineSep(body);
575
+ context.write("\n");
576
+ }
577
+ context.write("}");
578
+ }
579
+
580
+ function printReturnStatement(
581
+ statement: AST.ReturnStatement,
582
+ context: PrinterContext,
583
+ ): void {
584
+ context.write("return");
585
+ if (statement.argument) {
586
+ context.write(" ");
587
+ const leadingComments = context.options.getLeadingComments?.(
588
+ statement.argument,
589
+ );
590
+ const needsParensASi =
591
+ leadingComments?.some((c) => commentNeedsNewline(c)) ?? false;
592
+ if (needsParensASi) {
593
+ context.write("(");
594
+ }
595
+ context.writeNode(statement.argument);
596
+ if (needsParensASi) {
597
+ context.write(")");
598
+ }
599
+ }
600
+ context.write(";");
601
+ }
602
+
603
+ function printThrowStatement(
604
+ statement: AST.ThrowStatement,
605
+ context: PrinterContext,
606
+ ): void {
607
+ context.write("throw ");
608
+ if (statement.argument) {
609
+ const leadingComments = context.options.getLeadingComments?.(
610
+ statement.argument,
611
+ );
612
+ const needsParensASi =
613
+ leadingComments?.some((c) => commentNeedsNewline(c)) ?? false;
614
+ if (needsParensASi) {
615
+ context.write("(");
616
+ }
617
+ context.writeNode(statement.argument);
618
+ if (needsParensASi) {
619
+ context.write(")");
620
+ }
621
+ }
622
+ context.write(";");
623
+ }
624
+
625
+ function printDebuggerStatement(
626
+ _statement: AST.DebuggerStatement,
627
+ context: PrinterContext,
628
+ ): void {
629
+ context.write("debugger;");
630
+ }
631
+
632
+ function printBreakStatement(
633
+ statement: AST.BreakStatement,
634
+ context: PrinterContext,
635
+ ): void {
636
+ context.write("break");
637
+ if (statement.label) {
638
+ context.write(" ");
639
+ context.writeNode(statement.label);
640
+ }
641
+ context.write(";");
642
+ }
643
+
644
+ function printContinueStatement(
645
+ statement: AST.ContinueStatement,
646
+ context: PrinterContext,
647
+ ): void {
648
+ context.write("continue");
649
+ if (statement.label) {
650
+ context.write(" ");
651
+ context.writeNode(statement.label);
652
+ }
653
+ context.write(";");
654
+ }
655
+
656
+ function printLabeledStatement(
657
+ statement: AST.LabeledStatement,
658
+ context: PrinterContext,
659
+ ): void {
660
+ context.writeNode(statement.label);
661
+ context.write(": ");
662
+ context.writeNode(statement.body);
663
+ }
664
+
665
+ function printWhileStatement(
666
+ statement: AST.WhileStatement,
667
+ context: PrinterContext,
668
+ ): void {
669
+ context.write("while (");
670
+ context.writeNode(statement.test);
671
+ context.write(") ");
672
+ context.writeNode(statement.body);
673
+ }
674
+
675
+ function printDoWhileStatement(
676
+ statement: AST.DoWhileStatement,
677
+ context: PrinterContext,
678
+ ): void {
679
+ context.write("do ");
680
+ context.writeNode(statement.body);
681
+ context.write(" while (");
682
+ context.writeNode(statement.test);
683
+ context.write(");");
684
+ }
685
+
686
+ function printIfStatement(
687
+ statement: AST.IfStatement,
688
+ context: PrinterContext,
689
+ ): void {
690
+ context.write("if (");
691
+ context.writeNode(statement.test);
692
+ context.write(") ");
693
+ context.writeNode(statement.consequent);
694
+ if (statement.alternate) {
695
+ context.write(" else ");
696
+ context.writeNode(statement.alternate);
697
+ }
698
+ }
699
+
700
+ function printForStatement(
701
+ statement: AST.ForStatement,
702
+ context: PrinterContext,
703
+ ): void {
704
+ context.write("for (");
705
+ if (statement.init) {
706
+ if (statement.init.type === "VariableDeclaration") {
707
+ printVariableDeclarationFor(statement.init, context);
708
+ } else {
709
+ context.writeNode(statement.init);
710
+ }
711
+ }
712
+ context.write("; ");
713
+ if (statement.test) {
714
+ context.writeNode(statement.test);
715
+ }
716
+ context.write("; ");
717
+ if (statement.update) {
718
+ context.writeNode(statement.update);
719
+ }
720
+ context.write(") ");
721
+ context.writeNode(statement.body);
722
+ }
723
+
724
+ function printForInStatement(
725
+ statement: AST.ForInStatement,
726
+ context: PrinterContext,
727
+ ): void {
728
+ context.write("for (");
729
+ if (statement.left.type === "VariableDeclaration") {
730
+ printVariableDeclarationFor(statement.left, context);
731
+ } else {
732
+ context.writeNode(statement.left);
733
+ }
734
+ context.write(" in ");
735
+ context.writeNode(statement.right);
736
+ context.write(") ");
737
+ context.writeNode(statement.body);
738
+ }
739
+
740
+ function printForOfStatement(
741
+ statement: AST.ForOfStatement,
742
+ context: PrinterContext,
743
+ ): void {
744
+ context.write("for ");
745
+ if (statement.await === true) {
746
+ context.write("await ");
747
+ }
748
+ context.write("(");
749
+ if (statement.left.type === "VariableDeclaration") {
750
+ printVariableDeclarationFor(statement.left, context);
751
+ } else {
752
+ context.writeNode(statement.left);
753
+ }
754
+ context.write(" of ");
755
+ context.writeNode(statement.right);
756
+ context.write(") ");
757
+ context.writeNode(statement.body);
758
+ }
759
+
760
+ function printVariableDeclarationFor(
761
+ declaration: AST.VariableDeclaration,
762
+ context: PrinterContext,
763
+ ): void {
764
+ context.write(String(declaration.kind));
765
+ context.write(" ");
766
+ context.writeNodeList(declaration.declarations, ", ");
767
+ }
768
+
769
+ function printSwitchStatement(
770
+ statement: AST.SwitchStatement,
771
+ context: PrinterContext,
772
+ ): void {
773
+ context.write("switch (");
774
+ context.writeNode(statement.discriminant);
775
+ context.write(") {");
776
+ for (const case_ of statement.cases) {
777
+ context.writeNode(case_);
778
+ }
779
+ context.write("}");
780
+ }
781
+
782
+ function printSwitchCase(case_: AST.SwitchCase, context: PrinterContext): void {
783
+ if (case_.test) {
784
+ context.write("\ncase ");
785
+ context.writeNode(case_.test);
786
+ context.write(":");
787
+ } else {
788
+ context.write("\ndefault:");
789
+ }
790
+ for (const stmt of case_.consequent) {
791
+ context.write("\n");
792
+ context.writeNode(stmt);
793
+ }
794
+ }
795
+
796
+ function printTryStatement(
797
+ statement: AST.TryStatement,
798
+ context: PrinterContext,
799
+ ): void {
800
+ context.write("try ");
801
+ context.writeNode(statement.block);
802
+ if (statement.handler) {
803
+ context.write(" catch");
804
+ if (statement.handler.param) {
805
+ context.write(" (");
806
+ context.writeNode(statement.handler.param);
807
+ context.write(") ");
808
+ } else {
809
+ context.write(" ");
810
+ }
811
+ context.writeNode(statement.handler.body);
812
+ }
813
+ if (statement.finalizer) {
814
+ context.write(" finally ");
815
+ context.writeNode(statement.finalizer);
816
+ }
817
+ }
818
+
819
+ function printWithStatement(
820
+ statement: AST.WithStatement,
821
+ context: PrinterContext,
822
+ ): void {
823
+ context.write("with (");
824
+ context.writeNode(statement.object);
825
+ context.write(") ");
826
+ context.writeNode(statement.body);
827
+ }
828
+
829
+ // JS – Expressions
830
+
831
+ function printIdentifier(
832
+ identifier: AST.Identifier,
833
+ context: PrinterContext,
834
+ ): void {
835
+ context.write(String(identifier.name));
836
+ writeOptionalTypeAnnotation(identifier, context);
837
+ }
838
+
839
+ function printPrivateIdentifier(
840
+ identifier: AST.PrivateIdentifier,
841
+ context: PrinterContext,
842
+ ): void {
843
+ context.write("#");
844
+ context.write(String(identifier.name));
845
+ }
846
+
847
+ function printLiteral(literal: AST.Literal, context: PrinterContext): void {
848
+ if (typeof literal.raw === "string") {
849
+ context.write(literal.raw);
850
+ return;
851
+ }
852
+ const l = literal as AST.Literal;
853
+ context.write(JSON.stringify(l.value));
854
+ }
855
+
856
+ function printUnaryExpression(
857
+ expr: AST.UnaryExpression,
858
+ context: PrinterContext,
859
+ ): void {
860
+ context.write(expr.operator);
861
+ if (expr.operator.length > 1) {
862
+ context.write(" ");
863
+ }
864
+ const needsParen = operandOfUnaryExprNeedsParens(expr.argument);
865
+ if (needsParen) {
866
+ context.write("(");
867
+ context.writeNode(expr.argument);
868
+ context.write(")");
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
+ }
879
+ context.writeNode(expr.argument);
880
+ }
881
+ }
882
+
883
+ function printUpdateExpression(
884
+ expr: AST.UpdateExpression,
885
+ context: PrinterContext,
886
+ ): void {
887
+ if (expr.prefix === true) {
888
+ context.write(expr.operator);
889
+ context.writeNode(expr.argument);
890
+ } else {
891
+ const trailingComments = context.options.getTrailingComments?.(
892
+ expr.argument,
893
+ );
894
+ const needsParensASi =
895
+ trailingComments?.some((c) => commentNeedsNewline(c)) ?? false;
896
+ if (needsParensASi) {
897
+ context.write("(");
898
+ }
899
+ context.writeNode(expr.argument);
900
+ if (needsParensASi) {
901
+ context.write(")");
902
+ }
903
+ context.write(expr.operator);
904
+ }
905
+ }
906
+
907
+ function printBinaryExpression(
908
+ expression:
909
+ | AST.AssignmentExpression
910
+ | AST.LogicalExpression
911
+ | AST.BinaryExpression,
912
+ context: PrinterContext,
913
+ ): void {
914
+ const left = expression.left;
915
+ const right = expression.right;
916
+
917
+ if (operandOfBinaryExprNeedsParens(left, expression, "left")) {
918
+ context.write("(");
919
+ context.writeNode(left);
920
+ context.write(")");
921
+ } else {
922
+ context.writeNode(left);
923
+ }
924
+
925
+ context.write(" ");
926
+ context.write(String(expression.operator));
927
+ context.write(" ");
928
+
929
+ if (operandOfBinaryExprNeedsParens(right, expression, "right")) {
930
+ context.write("(");
931
+ context.writeNode(right);
932
+ context.write(")");
933
+ } else {
934
+ context.writeNode(right);
935
+ }
936
+ }
937
+
938
+ function printConditionalExpression(
939
+ expr: AST.ConditionalExpression,
940
+ context: PrinterContext,
941
+ ): void {
942
+ if (operandOfBinaryExprNeedsParens(expr.test, expr, "left")) {
943
+ context.write("(");
944
+ context.writeNode(expr.test);
945
+ context.write(")");
946
+ } else {
947
+ context.writeNode(expr.test);
948
+ }
949
+ context.write(" ? ");
950
+ context.writeNode(expr.consequent);
951
+ context.write(" : ");
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
+ }
959
+ }
960
+
961
+ function printYieldExpression(
962
+ expr: AST.YieldExpression,
963
+ context: PrinterContext,
964
+ ): void {
965
+ context.write(expr.delegate === true ? "yield*" : "yield");
966
+ if (expr.argument) {
967
+ context.write(" ");
968
+ const leadingComments = context.options.getLeadingComments?.(expr.argument);
969
+ const needsParensASi =
970
+ leadingComments?.some((c) => commentNeedsNewline(c)) ?? false;
971
+ const needsParens =
972
+ needsParensASi || expectAssignmentExprNeedsParen(expr.argument);
973
+ if (needsParens) {
974
+ context.write("(");
975
+ context.writeNode(expr.argument);
976
+ context.write(")");
977
+ } else {
978
+ context.writeNode(expr.argument);
979
+ }
980
+ }
981
+ }
982
+
983
+ function printAwaitExpression(
984
+ expr: AST.AwaitExpression,
985
+ context: PrinterContext,
986
+ ): void {
987
+ context.write("await");
988
+ if (expr.argument) {
989
+ const needsParens = operandOfUnaryExprNeedsParens(expr.argument);
990
+ if (needsParens) {
991
+ context.write(" (");
992
+ context.writeNode(expr.argument);
993
+ context.write(")");
994
+ } else {
995
+ context.write(" ");
996
+ context.writeNode(expr.argument);
997
+ }
998
+ }
999
+ }
1000
+
1001
+ function printSequenceExpression(
1002
+ expr: AST.SequenceExpression,
1003
+ context: PrinterContext,
1004
+ ): void {
1005
+ context.writeNodeList(expr.expressions, ", ");
1006
+ }
1007
+
1008
+ function printCallExpression(
1009
+ expression: AST.CallExpression,
1010
+ context: PrinterContext,
1011
+ ): void {
1012
+ const needsParens = operandOfBinaryExprNeedsParens(
1013
+ expression.callee,
1014
+ expression,
1015
+ "left",
1016
+ );
1017
+ if (needsParens) {
1018
+ context.write("(");
1019
+ context.writeNode(expression.callee);
1020
+ context.write(")");
1021
+ } else {
1022
+ context.writeNode(expression.callee);
1023
+ }
1024
+ if (expression.typeArguments) {
1025
+ context.writeNode(expression.typeArguments);
1026
+ }
1027
+ if (expression.optional === true) {
1028
+ context.write("?.");
1029
+ }
1030
+ const parenRange =
1031
+ context.options.experimentalGetLeftParenSourceRange?.(expression);
1032
+ if (parenRange) {
1033
+ context.writeMapped("(", parenRange.start, parenRange.end);
1034
+ } else {
1035
+ context.write("(");
1036
+ }
1037
+ context.writeExpressionListWithCommaSep(expression.arguments);
1038
+ context.write(")");
1039
+ }
1040
+
1041
+ function printNewExpression(
1042
+ expression: AST.NewExpression,
1043
+ context: PrinterContext,
1044
+ ): void {
1045
+ context.write("new ");
1046
+ const needsParens = operandOfBinaryExprNeedsParens(
1047
+ expression.callee,
1048
+ expression,
1049
+ "left",
1050
+ );
1051
+ if (needsParens) {
1052
+ context.write("(");
1053
+ context.writeNode(expression.callee);
1054
+ context.write(")");
1055
+ } else {
1056
+ context.writeNode(expression.callee);
1057
+ }
1058
+ if (expression.typeArguments) {
1059
+ context.writeNode(expression.typeArguments);
1060
+ }
1061
+ const parenRange =
1062
+ context.options.experimentalGetLeftParenSourceRange?.(expression);
1063
+ if (parenRange) {
1064
+ context.writeMapped("(", parenRange.start, parenRange.end);
1065
+ } else {
1066
+ context.write("(");
1067
+ }
1068
+ context.writeExpressionListWithCommaSep(expression.arguments);
1069
+ context.write(")");
1070
+ }
1071
+
1072
+ function printChainExpression(
1073
+ expression: AST.ChainExpression,
1074
+ context: PrinterContext,
1075
+ ): void {
1076
+ context.writeNode(expression.expression);
1077
+ }
1078
+
1079
+ function printMemberExpression(
1080
+ expression: AST.MemberExpression,
1081
+ context: PrinterContext,
1082
+ ): void {
1083
+ const needsParens = operandOfBinaryExprNeedsParens(
1084
+ expression.object,
1085
+ expression,
1086
+ "left",
1087
+ );
1088
+ if (needsParens) {
1089
+ context.write("(");
1090
+ context.writeNode(expression.object);
1091
+ context.write(")");
1092
+ } else {
1093
+ context.writeNode(expression.object);
1094
+ }
1095
+ if (expression.computed === true) {
1096
+ context.write(expression.optional === true ? "?.[" : "[");
1097
+ context.writeNode(expression.property);
1098
+ context.write("]");
1099
+ } else {
1100
+ context.write(expression.optional === true ? "?." : ".");
1101
+ context.writeNode(expression.property);
1102
+ }
1103
+ }
1104
+
1105
+ function printObjectExpression(
1106
+ object: AST.ObjectExpression,
1107
+ context: PrinterContext,
1108
+ ): void {
1109
+ context.write("{ ");
1110
+ context.writeNodeList(object.properties, ", ");
1111
+ context.write(" }");
1112
+ }
1113
+
1114
+ function printObjectPattern(
1115
+ pattern: AST.ObjectPattern,
1116
+ context: PrinterContext,
1117
+ ): void {
1118
+ context.write("{ ");
1119
+ context.writeNodeList(pattern.properties, ", ");
1120
+ context.write(" }");
1121
+ writeOptionalTypeAnnotation(pattern, context);
1122
+ }
1123
+
1124
+ function printArrayExpression(
1125
+ array: AST.ArrayExpression,
1126
+ context: PrinterContext,
1127
+ ): void {
1128
+ context.write("[");
1129
+ context.writeExpressionListWithCommaSep(array.elements);
1130
+ context.write("]");
1131
+ }
1132
+
1133
+ function printArrayPattern(
1134
+ pattern: AST.ArrayPattern,
1135
+ context: PrinterContext,
1136
+ ): void {
1137
+ context.write("[");
1138
+ context.writeNodeList(pattern.elements, ", ");
1139
+ context.write("]");
1140
+ writeOptionalTypeAnnotation(pattern, context);
1141
+ }
1142
+
1143
+ function printProperty(
1144
+ property: AST.Property | AST.PropertyDefinition,
1145
+ context: PrinterContext,
1146
+ ): void {
1147
+ if (property.type === "Property") {
1148
+ const value = property.value;
1149
+ const valNode = value.type === "AssignmentPattern" ? value.left : value;
1150
+
1151
+ const shorthand =
1152
+ !property.computed &&
1153
+ property.kind === "init" &&
1154
+ property.key.type === "Identifier" &&
1155
+ valNode.type === "Identifier" &&
1156
+ property.key.name === valNode.name;
1157
+
1158
+ if (shorthand) {
1159
+ context.writeNode(value);
1160
+ return;
1161
+ }
1162
+
1163
+ // shorthand method
1164
+ if (value.type === "FunctionExpression") {
1165
+ if (property.kind !== "init") {
1166
+ context.write(property.kind + " ");
1167
+ }
1168
+ if (value.async === true) {
1169
+ context.write("async ");
1170
+ }
1171
+ if (value.generator === true) {
1172
+ context.write("*");
1173
+ }
1174
+ if (property.computed === true) {
1175
+ context.write("[");
1176
+ context.writeNode(property.key);
1177
+ context.write("]");
1178
+ } else {
1179
+ context.writeNode(property.key);
1180
+ }
1181
+ context.write("(");
1182
+ context.writeNodeList(value.params, ", ");
1183
+ context.write(")");
1184
+ writeReturnType(value, context);
1185
+ context.write(" ");
1186
+ context.writeNode(value.body!);
1187
+ return;
1188
+ }
1189
+
1190
+ if (property.computed === true) {
1191
+ context.write("[");
1192
+ context.writeNode(property.key);
1193
+ context.write("]: ");
1194
+ } else {
1195
+ if (property.kind === "get" || property.kind === "set") {
1196
+ context.write(property.kind + " ");
1197
+ }
1198
+ context.writeNode(property.key);
1199
+ context.write(": ");
1200
+ }
1201
+ context.writeNode(property.value);
1202
+ }
1203
+ }
1204
+
1205
+ function printSpreadElement(
1206
+ spread: AST.SpreadElement,
1207
+ context: PrinterContext,
1208
+ ): void {
1209
+ context.write("...");
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
+ }
1218
+ }
1219
+
1220
+ function printRestElement(
1221
+ rest: AST.RestElement,
1222
+ context: PrinterContext,
1223
+ ): void {
1224
+ context.write("...");
1225
+ context.writeNode(rest.argument);
1226
+ writeOptionalTypeAnnotation(rest, context);
1227
+ }
1228
+
1229
+ function printAssignmentPattern(
1230
+ pattern: AST.AssignmentPattern,
1231
+ context: PrinterContext,
1232
+ ): void {
1233
+ context.writeNode(pattern.left);
1234
+ context.write(" = ");
1235
+ context.writeNode(pattern.right);
1236
+ }
1237
+
1238
+ function printTemplateLiteral(
1239
+ node: AST.TemplateLiteral,
1240
+ context: PrinterContext,
1241
+ ): void {
1242
+ context.write("`");
1243
+ const { quasis, expressions } = node;
1244
+ for (let i = 0; i < expressions.length; i++) {
1245
+ context.write(quasis[i].value.raw);
1246
+ context.write("${");
1247
+ context.writeNode(expressions[i]);
1248
+ context.write("}");
1249
+ }
1250
+ context.write(quasis[quasis.length - 1].value.raw);
1251
+ context.write("`");
1252
+ }
1253
+
1254
+ function printTaggedTemplateExpression(
1255
+ node: AST.TaggedTemplateExpression,
1256
+ context: PrinterContext,
1257
+ ): void {
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
+ }
1269
+ context.writeNode(node.quasi);
1270
+ }
1271
+
1272
+ function printThisExpression(
1273
+ _node: AST.ThisExpression,
1274
+ context: PrinterContext,
1275
+ ): void {
1276
+ context.write("this");
1277
+ }
1278
+
1279
+ function printSuper(_node: AST.Super, context: PrinterContext): void {
1280
+ context.write("super");
1281
+ }
1282
+
1283
+ function printMetaProperty(
1284
+ node: AST.MetaProperty,
1285
+ context: PrinterContext,
1286
+ ): void {
1287
+ context.writeNode(node.meta);
1288
+ context.write(".");
1289
+ context.writeNode(node.property);
1290
+ }
1291
+
1292
+ function printParenthesizedExpression(
1293
+ node: { expression: AST.Node },
1294
+ context: PrinterContext,
1295
+ ): void {
1296
+ context.write("(");
1297
+ context.writeNode(node.expression);
1298
+ context.write(")");
1299
+ }
1300
+
1301
+ // JS – Functions / Classes
1302
+
1303
+ function printFunctionDeclaration(
1304
+ node: AST.FunctionDeclaration,
1305
+ context: PrinterContext,
1306
+ ): void {
1307
+ printFunction(node, context);
1308
+ }
1309
+
1310
+ function printFunctionExpression(
1311
+ node: AST.FunctionExpression,
1312
+ context: PrinterContext,
1313
+ ): void {
1314
+ printFunction(node, context);
1315
+ }
1316
+
1317
+ function printFunction(
1318
+ fn: AST.FunctionDeclaration | AST.FunctionExpression,
1319
+ context: PrinterContext,
1320
+ ): void {
1321
+ if (fn.async === true) {
1322
+ context.write("async ");
1323
+ }
1324
+ context.write("function");
1325
+ if (fn.generator === true) {
1326
+ context.write("*");
1327
+ }
1328
+ if (fn.id) {
1329
+ context.write(" ");
1330
+ context.writeNode(fn.id);
1331
+ }
1332
+ if (fn.typeParameters) {
1333
+ context.writeNode(fn.typeParameters);
1334
+ }
1335
+ context.write("(");
1336
+ context.writeNodeList(fn.params, ", ");
1337
+ context.write(")");
1338
+ writeReturnType(fn, context);
1339
+ if (fn.body) {
1340
+ context.write(" ");
1341
+ context.writeNode(fn.body);
1342
+ }
1343
+ }
1344
+
1345
+ function printArrowFunctionExpression(
1346
+ fn: AST.ArrowFunctionExpression,
1347
+ context: PrinterContext,
1348
+ ): void {
1349
+ if (fn.async === true) {
1350
+ context.write("async ");
1351
+ }
1352
+ if (fn.typeParameters) {
1353
+ context.writeNode(fn.typeParameters);
1354
+ }
1355
+ context.write("(");
1356
+ context.writeNodeList(fn.params, ", ");
1357
+ context.write(")");
1358
+ writeReturnType(fn, context);
1359
+ context.write(" => ");
1360
+ const body = fn.body;
1361
+ if (arrowConciseBodyNeedsWrap(body)) {
1362
+ context.write("(");
1363
+ context.writeNode(body);
1364
+ context.write(")");
1365
+ } else {
1366
+ context.writeNode(body);
1367
+ }
1368
+ }
1369
+
1370
+ function printClassDeclaration(
1371
+ node: AST.ClassDeclaration,
1372
+ context: PrinterContext,
1373
+ ): void {
1374
+ printClass(node, context);
1375
+ }
1376
+
1377
+ function printClassExpression(
1378
+ node: AST.ClassExpression,
1379
+ context: PrinterContext,
1380
+ ): void {
1381
+ printClass(node, context);
1382
+ }
1383
+
1384
+ function printClass(
1385
+ node: AST.ClassDeclaration | AST.ClassExpression,
1386
+ context: PrinterContext,
1387
+ ): void {
1388
+ if (node.decorators) {
1389
+ for (const d of node.decorators) {
1390
+ context.writeNode(d);
1391
+ }
1392
+ }
1393
+ if (node.declare === true) {
1394
+ context.write("declare ");
1395
+ }
1396
+ if (node.abstract === true) {
1397
+ context.write("abstract ");
1398
+ }
1399
+ context.write("class ");
1400
+ if (node.id) {
1401
+ context.writeNode(node.id);
1402
+ context.write(" ");
1403
+ }
1404
+ if (node.superClass) {
1405
+ context.write("extends ");
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
+ }
1414
+ if (node.superTypeArguments) {
1415
+ context.writeNode(node.superTypeArguments);
1416
+ } else if (node.superTypeParameters) {
1417
+ context.writeNode(node.superTypeParameters);
1418
+ }
1419
+ }
1420
+ if (node.implements && node.implements.length > 0) {
1421
+ context.write(" implements ");
1422
+ context.writeNodeList(node.implements, ", ");
1423
+ }
1424
+ if (node.superClass || (node.implements && node.implements.length > 0)) {
1425
+ context.write(" ");
1426
+ }
1427
+ context.writeNode(node.body);
1428
+ }
1429
+
1430
+ function printClassBody(node: AST.ClassBody, context: PrinterContext): void {
1431
+ context.write("{");
1432
+ const body = node.body;
1433
+ if (body.length > 0) {
1434
+ context.write("\n");
1435
+ context.writeNodeListWithNewLineSep(body);
1436
+ context.write("\n");
1437
+ }
1438
+ context.write("}");
1439
+ }
1440
+
1441
+ function printStaticBlock(
1442
+ node: AST.StaticBlock,
1443
+ context: PrinterContext,
1444
+ ): void {
1445
+ context.write("static {");
1446
+ const body = node.body;
1447
+ if (body.length > 0) {
1448
+ context.write("\n");
1449
+ context.writeNodeListWithNewLineSep(body);
1450
+ context.write("\n");
1451
+ }
1452
+ context.write("}");
1453
+ }
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
+
1477
+ function printDecorator(node: AST.Decorator, context: PrinterContext): void {
1478
+ context.write("@");
1479
+ if (!validUnparenthesizedDecorator(node.expression)) {
1480
+ context.write("(");
1481
+ context.writeNode(node.expression);
1482
+ context.write(")");
1483
+ } else {
1484
+ context.writeNode(node.expression);
1485
+ }
1486
+ context.write("\n");
1487
+ }
1488
+
1489
+ function printPropertyDefinition(
1490
+ node:
1491
+ | AST.PropertyDefinition
1492
+ | AST.AccessorProperty
1493
+ | AST.TSAbstractAccessorProperty
1494
+ | AST.TSAbstractPropertyDefinition,
1495
+ context: PrinterContext,
1496
+ ): void {
1497
+ if (node.decorators) {
1498
+ for (const d of node.decorators) {
1499
+ context.writeNode(d);
1500
+ }
1501
+ }
1502
+ if (
1503
+ node.type === "TSAbstractPropertyDefinition" ||
1504
+ ("abstract" in node && node.abstract === true)
1505
+ ) {
1506
+ context.write("abstract ");
1507
+ }
1508
+ if (node.accessibility) {
1509
+ context.write(node.accessibility + " ");
1510
+ }
1511
+ if (node.static === true) {
1512
+ context.write("static ");
1513
+ }
1514
+ if (node.override === true) {
1515
+ context.write("override ");
1516
+ }
1517
+ if (node.readonly === true) {
1518
+ context.write("readonly ");
1519
+ }
1520
+ if (
1521
+ node.type === "AccessorProperty" ||
1522
+ node.type === "TSAbstractAccessorProperty" ||
1523
+ ("accessor" in node && node.accessor === true)
1524
+ ) {
1525
+ context.write("accessor ");
1526
+ }
1527
+ if (node.computed === true) {
1528
+ context.write("[");
1529
+ context.writeNode(node.key);
1530
+ context.write("]");
1531
+ } else {
1532
+ context.writeNode(node.key);
1533
+ }
1534
+ if (node.typeAnnotation) {
1535
+ if ("accessor" in node && node.accessor === true) {
1536
+ context.writeNode(node.typeAnnotation);
1537
+ } else {
1538
+ context.write(": ");
1539
+ context.writeNode(node.typeAnnotation.typeAnnotation);
1540
+ }
1541
+ }
1542
+ if (node.value) {
1543
+ context.write(" = ");
1544
+ context.writeNode(node.value);
1545
+ }
1546
+ context.write(";");
1547
+ }
1548
+
1549
+ function printMethodDefinition(
1550
+ node: AST.MethodDefinition | AST.TSAbstractMethodDefinition,
1551
+ context: PrinterContext,
1552
+ ): void {
1553
+ const def = node;
1554
+ if (def.decorators) {
1555
+ for (const d of def.decorators) {
1556
+ context.writeNode(d);
1557
+ }
1558
+ }
1559
+ if (def.accessibility) {
1560
+ context.write(def.accessibility + " ");
1561
+ }
1562
+ if (def.static === true) {
1563
+ context.write("static ");
1564
+ }
1565
+ if (def.override === true) {
1566
+ context.write("override ");
1567
+ }
1568
+ if (
1569
+ node.type === "TSAbstractMethodDefinition" ||
1570
+ ("abstract" in def && def.abstract === true)
1571
+ ) {
1572
+ context.write("abstract ");
1573
+ }
1574
+ if (def.kind === "get" || def.kind === "set") {
1575
+ context.write(def.kind + " ");
1576
+ }
1577
+ if (def.value.async === true) {
1578
+ context.write("async ");
1579
+ }
1580
+ if (def.value.generator === true) {
1581
+ context.write("*");
1582
+ }
1583
+ if (def.computed === true) {
1584
+ context.write("[");
1585
+ context.writeNode(def.key);
1586
+ context.write("]");
1587
+ } else {
1588
+ context.writeNode(def.key);
1589
+ }
1590
+ context.write("(");
1591
+ context.writeNodeList(def.value.params, ", ");
1592
+ context.write(")");
1593
+ writeReturnType(def.value, context);
1594
+ if (def.value.body) {
1595
+ context.write(" ");
1596
+ context.writeNode(def.value.body);
1597
+ } else {
1598
+ context.write(";");
1599
+ }
1600
+ }
1601
+
1602
+ // JS – Imports / Exports
1603
+
1604
+ function printImportDeclaration(
1605
+ node: AST.ImportDeclaration,
1606
+ context: PrinterContext,
1607
+ ): void {
1608
+ context.write("import ");
1609
+ if (node.importKind === "type") {
1610
+ context.write("type ");
1611
+ }
1612
+
1613
+ const specifiers = node.specifiers;
1614
+ if (specifiers.length === 0) {
1615
+ context.writeNode(node.source);
1616
+ context.write(";");
1617
+ return;
1618
+ }
1619
+
1620
+ let wroteDefault = false;
1621
+
1622
+ for (const s of specifiers) {
1623
+ if (s.type === "ImportDefaultSpecifier") {
1624
+ context.writeNode(s);
1625
+ wroteDefault = true;
1626
+ }
1627
+ }
1628
+
1629
+ let namespaceSpec: AST.ImportNamespaceSpecifier | undefined;
1630
+ const namedSpecs: AST.ImportSpecifier[] = [];
1631
+
1632
+ for (const s of specifiers) {
1633
+ if (s.type === "ImportNamespaceSpecifier") {
1634
+ namespaceSpec = s;
1635
+ } else if (s.type === "ImportSpecifier") {
1636
+ namedSpecs.push(s);
1637
+ }
1638
+ }
1639
+
1640
+ if (namespaceSpec) {
1641
+ if (wroteDefault) {
1642
+ context.write(", ");
1643
+ }
1644
+ context.write("* as ");
1645
+ context.writeNode(namespaceSpec.local);
1646
+ }
1647
+
1648
+ if (namedSpecs.length > 0) {
1649
+ if (wroteDefault || namespaceSpec) {
1650
+ context.write(", ");
1651
+ }
1652
+ context.write("{ ");
1653
+ context.writeNodeList(namedSpecs, ", ");
1654
+ context.write(" }");
1655
+ }
1656
+
1657
+ context.write(" from ");
1658
+ context.writeNode(node.source);
1659
+
1660
+ if (node.attributes && node.attributes.length > 0) {
1661
+ context.write(" with { ");
1662
+ context.writeNodeList(node.attributes, ", ");
1663
+ context.write(" }");
1664
+ }
1665
+ context.write(";");
1666
+ }
1667
+
1668
+ function printImportExpression(
1669
+ node: AST.ImportExpression,
1670
+ context: PrinterContext,
1671
+ ): void {
1672
+ context.write("import(");
1673
+ context.writeNode(node.source);
1674
+ if (node.options) {
1675
+ context.write(", ");
1676
+ context.writeNode(node.options);
1677
+ }
1678
+ context.write(")");
1679
+ }
1680
+
1681
+ function printImportDefaultSpecifier(
1682
+ node: AST.ImportDefaultSpecifier,
1683
+ context: PrinterContext,
1684
+ ): void {
1685
+ context.writeNode(node.local);
1686
+ }
1687
+
1688
+ function printImportSpecifier(
1689
+ node: AST.ImportSpecifier,
1690
+ context: PrinterContext,
1691
+ ): void {
1692
+ if (node.importKind === "type") {
1693
+ context.write("type ");
1694
+ }
1695
+ if (
1696
+ node.local.type === "Identifier" &&
1697
+ node.imported.type === "Identifier" &&
1698
+ node.local.name !== node.imported.name
1699
+ ) {
1700
+ context.writeNode(node.imported);
1701
+ context.write(" as ");
1702
+ }
1703
+ context.writeNode(node.local);
1704
+ }
1705
+
1706
+ function printExportNamedDeclaration(
1707
+ node: AST.ExportNamedDeclaration,
1708
+ context: PrinterContext,
1709
+ ): void {
1710
+ if (node.declaration) {
1711
+ let decl = node.declaration;
1712
+ if ("decorators" in decl && decl.decorators && decl.decorators.length > 0) {
1713
+ const { decorators, ...rest } = decl;
1714
+ for (const d of decorators) {
1715
+ context.writeNode(d);
1716
+ }
1717
+ decl = rest as typeof decl;
1718
+ }
1719
+ context.write("export ");
1720
+ if (node.exportKind === "type") {
1721
+ context.write("type ");
1722
+ }
1723
+ context.writeNode(decl);
1724
+ if (
1725
+ decl.type !== "FunctionDeclaration" &&
1726
+ decl.type !== "ClassDeclaration" &&
1727
+ decl.type !== "VariableDeclaration" &&
1728
+ decl.type !== "TSModuleDeclaration" &&
1729
+ decl.type !== "TSEnumDeclaration" &&
1730
+ decl.type !== "TSTypeAliasDeclaration" &&
1731
+ decl.type !== "TSInterfaceDeclaration" &&
1732
+ decl.type !== "TSDeclareFunction"
1733
+ ) {
1734
+ context.write(";");
1735
+ }
1736
+ return;
1737
+ }
1738
+
1739
+ context.write("export ");
1740
+ if (node.exportKind === "type") {
1741
+ context.write("type ");
1742
+ }
1743
+ context.write("{ ");
1744
+ context.writeNodeList(node.specifiers, ", ");
1745
+ context.write(" }");
1746
+
1747
+ if (node.source) {
1748
+ context.write(" from ");
1749
+ context.writeNode(node.source);
1750
+ }
1751
+ context.write(";");
1752
+ }
1753
+
1754
+ function printExportDefaultDeclaration(
1755
+ node: AST.ExportDefaultDeclaration,
1756
+ context: PrinterContext,
1757
+ ): void {
1758
+ let decl = node.declaration;
1759
+ if ("decorators" in decl && decl.decorators && decl.decorators.length > 0) {
1760
+ const { decorators, ...rest } = decl;
1761
+ for (const d of decorators) {
1762
+ context.writeNode(d);
1763
+ }
1764
+ decl = rest as typeof decl;
1765
+ }
1766
+ context.write("export default ");
1767
+ context.writeNode(decl);
1768
+ if (
1769
+ decl.type !== "FunctionDeclaration" &&
1770
+ decl.type !== "ClassDeclaration" &&
1771
+ decl.type !== "ClassExpression"
1772
+ ) {
1773
+ context.write(";");
1774
+ }
1775
+ }
1776
+
1777
+ function printExportAllDeclaration(
1778
+ node: AST.ExportAllDeclaration,
1779
+ context: PrinterContext,
1780
+ ): void {
1781
+ context.write(node.exportKind === "type" ? "export type * " : "export * ");
1782
+ if (node.exported) {
1783
+ context.write("as ");
1784
+ context.writeNode(node.exported);
1785
+ context.write(" ");
1786
+ }
1787
+ context.write("from ");
1788
+ context.writeNode(node.source);
1789
+ context.write(";");
1790
+ }
1791
+
1792
+ function printExportSpecifier(
1793
+ node: AST.ExportSpecifier,
1794
+ context: PrinterContext,
1795
+ ): void {
1796
+ if (node.exportKind === "type") {
1797
+ context.write("type ");
1798
+ }
1799
+ context.writeNode(node.local);
1800
+ if (
1801
+ node.local.type === "Identifier" &&
1802
+ node.exported.type === "Identifier" &&
1803
+ node.local.name !== node.exported.name
1804
+ ) {
1805
+ context.write(" as ");
1806
+ context.writeNode(node.exported);
1807
+ }
1808
+ }
1809
+
1810
+ // TS – Expressions
1811
+
1812
+ function printTSAsExpression(
1813
+ expression: AST.TSAsExpression,
1814
+ context: PrinterContext,
1815
+ ): void {
1816
+ const needsParens = operandOfBinaryExprNeedsParens(
1817
+ expression.expression,
1818
+ expression,
1819
+ "left",
1820
+ );
1821
+ if (needsParens) {
1822
+ context.write("(");
1823
+ context.writeNode(expression.expression);
1824
+ context.write(")");
1825
+ } else {
1826
+ context.writeNode(expression.expression);
1827
+ }
1828
+ context.write(" as ");
1829
+ context.writeNode(expression.typeAnnotation);
1830
+ }
1831
+
1832
+ function printTSSatisfiesExpression(
1833
+ expression: AST.TSSatisfiesExpression,
1834
+ context: PrinterContext,
1835
+ ): void {
1836
+ const needsParens = operandOfBinaryExprNeedsParens(
1837
+ expression.expression,
1838
+ expression,
1839
+ "left",
1840
+ );
1841
+ if (needsParens) {
1842
+ context.write("(");
1843
+ context.writeNode(expression.expression);
1844
+ context.write(")");
1845
+ } else {
1846
+ context.writeNode(expression.expression);
1847
+ }
1848
+ context.write(" satisfies ");
1849
+ context.writeNode(expression.typeAnnotation);
1850
+ }
1851
+
1852
+ function printTSTypeAssertion(
1853
+ expression: AST.TSTypeAssertion,
1854
+ context: PrinterContext,
1855
+ ): void {
1856
+ context.write("<");
1857
+ context.writeNode(expression.typeAnnotation);
1858
+ context.write(">");
1859
+ const needsParens = operandOfUnaryExprNeedsParens(expression.expression);
1860
+ if (needsParens) {
1861
+ context.write("(");
1862
+ context.writeNode(expression.expression);
1863
+ context.write(")");
1864
+ } else {
1865
+ context.writeNode(expression.expression);
1866
+ }
1867
+ }
1868
+
1869
+ function printTSNonNullExpression(
1870
+ expression: AST.TSNonNullExpression,
1871
+ context: PrinterContext,
1872
+ ): void {
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
+ }
1885
+ context.write("!");
1886
+ }
1887
+
1888
+ function printTSTypeAnnotation(
1889
+ annotation: AST.TSTypeAnnotation,
1890
+ context: PrinterContext,
1891
+ ): void {
1892
+ context.write(": ");
1893
+ context.writeNode(annotation.typeAnnotation);
1894
+ }
1895
+
1896
+ function printTSTypeAliasDeclaration(
1897
+ alias: AST.TSTypeAliasDeclaration,
1898
+ context: PrinterContext,
1899
+ ): void {
1900
+ if (alias.declare === true) {
1901
+ context.write("declare ");
1902
+ }
1903
+ context.write("type ");
1904
+ context.writeNode(alias.id);
1905
+ if (alias.typeParameters) {
1906
+ context.writeNode(alias.typeParameters);
1907
+ }
1908
+ context.write(" = ");
1909
+ context.writeNode(alias.typeAnnotation);
1910
+ context.write(";");
1911
+ }
1912
+
1913
+ function printTSInterfaceDeclaration(
1914
+ node: AST.TSInterfaceDeclaration,
1915
+ context: PrinterContext,
1916
+ ): void {
1917
+ const declaration = node;
1918
+ if (declaration.declare === true) {
1919
+ context.write("declare ");
1920
+ }
1921
+ context.write("interface ");
1922
+ context.writeNode(declaration.id);
1923
+ if (declaration.typeParameters) {
1924
+ context.writeNode(declaration.typeParameters);
1925
+ }
1926
+ const heritage = declaration.extends ?? [];
1927
+ if (heritage.length > 0) {
1928
+ context.write(" extends ");
1929
+ context.writeNodeList(heritage, ", ");
1930
+ }
1931
+ context.write(" ");
1932
+ context.writeNode(declaration.body);
1933
+ }
1934
+
1935
+ function printTSExpressionWithTypeArguments(
1936
+ node: {
1937
+ expression: AST.Node;
1938
+ typeArguments?: AST.Node;
1939
+ typeParameters?: AST.Node;
1940
+ },
1941
+ context: PrinterContext,
1942
+ ): void {
1943
+ context.writeNode(node.expression);
1944
+ if (node.typeArguments) {
1945
+ context.writeNode(node.typeArguments);
1946
+ }
1947
+ if (node.typeParameters) {
1948
+ context.writeNode(node.typeParameters);
1949
+ }
1950
+ }
1951
+
1952
+ function printTSInterfaceBody(
1953
+ body: AST.TSInterfaceBody,
1954
+ context: PrinterContext,
1955
+ ): void {
1956
+ context.write("{");
1957
+ const members = body.body;
1958
+ if (members.length > 0) {
1959
+ context.write(" ");
1960
+ context.writeNodeList(members, " ");
1961
+ context.write(" ");
1962
+ }
1963
+ context.write("}");
1964
+ }
1965
+
1966
+ function printTSPropertySignature(
1967
+ signature: AST.TSPropertySignature,
1968
+ context: PrinterContext,
1969
+ ): void {
1970
+ if (signature.readonly === true) {
1971
+ context.write("readonly ");
1972
+ }
1973
+ if (signature.computed === true) {
1974
+ context.write("[");
1975
+ context.writeNode(signature.key);
1976
+ context.write("]");
1977
+ } else {
1978
+ context.writeNode(signature.key);
1979
+ }
1980
+ if (signature.optional === true) {
1981
+ context.write("?");
1982
+ }
1983
+ if (signature.typeAnnotation) {
1984
+ context.writeNode(signature.typeAnnotation);
1985
+ }
1986
+ context.write(";");
1987
+ }
1988
+
1989
+ function printTypeParameterDeclaration(
1990
+ declaration: AST.TSTypeParameterDeclaration,
1991
+ context: PrinterContext,
1992
+ ): void {
1993
+ context.write("<");
1994
+ context.writeNodeList(declaration.params, ", ");
1995
+ context.write(">");
1996
+ }
1997
+
1998
+ function printTypeParameterInstantiation(
1999
+ instantiation: AST.TSTypeParameterInstantiation,
2000
+ context: PrinterContext,
2001
+ ): void {
2002
+ context.write("<");
2003
+ context.writeNodeList(instantiation.params, ", ");
2004
+ context.write(">");
2005
+ }
2006
+
2007
+ function printTSTypeParameter(
2008
+ parameter: AST.TSTypeParameter,
2009
+ context: PrinterContext,
2010
+ ): void {
2011
+ if (parameter.const === true) {
2012
+ context.write("const ");
2013
+ }
2014
+ if (parameter.in === true) {
2015
+ context.write("in ");
2016
+ }
2017
+ if (parameter.out === true) {
2018
+ context.write("out ");
2019
+ }
2020
+ // https://github.com/sveltejs/acorn-typescript/issues/7
2021
+ // parameter.name might be a string instead of an Identifier node
2022
+ if (typeof parameter.name === "string") {
2023
+ context.write(parameter.name);
2024
+ } else {
2025
+ context.writeNode(parameter.name);
2026
+ }
2027
+ if (parameter.constraint) {
2028
+ context.write(" extends ");
2029
+ context.writeNode(parameter.constraint);
2030
+ }
2031
+ if (parameter.default) {
2032
+ context.write(" = ");
2033
+ context.writeNode(parameter.default);
2034
+ }
2035
+ }
2036
+
2037
+ function printTSFunctionType(
2038
+ type: AST.TSFunctionType,
2039
+ context: PrinterContext,
2040
+ ): void {
2041
+ if (type.typeParameters) {
2042
+ context.writeNode(type.typeParameters);
2043
+ }
2044
+ context.write("(");
2045
+ if (type.params) {
2046
+ context.writeNodeList(type.params, ", ");
2047
+ } else if (type.parameters) {
2048
+ context.writeNodeList(type.parameters, ", ");
2049
+ }
2050
+ context.write(")");
2051
+ context.write(" => ");
2052
+ writeReturnType(type, context, { tsArrowType: true });
2053
+ }
2054
+
2055
+ function printTSConstructorType(
2056
+ type: AST.TSConstructorType,
2057
+ context: PrinterContext,
2058
+ ): void {
2059
+ context.write("new ");
2060
+ if (type.typeParameters) {
2061
+ context.writeNode(type.typeParameters);
2062
+ }
2063
+ context.write("(");
2064
+ if (type.params) {
2065
+ context.writeNodeList(type.params, ", ");
2066
+ } else if (type.parameters) {
2067
+ context.writeNodeList(type.parameters, ", ");
2068
+ }
2069
+ context.write(")");
2070
+ context.write(" => ");
2071
+ writeReturnType(type, context, { tsArrowType: true });
2072
+ }
2073
+
2074
+ function printTSMethodSignature(
2075
+ signature: AST.TSMethodSignature,
2076
+ context: PrinterContext,
2077
+ ): void {
2078
+ if (signature.readonly === true) {
2079
+ context.write("readonly ");
2080
+ }
2081
+ if (signature.computed === true) {
2082
+ context.write("[");
2083
+ context.writeNode(signature.key);
2084
+ context.write("]");
2085
+ } else {
2086
+ context.writeNode(signature.key);
2087
+ }
2088
+ if (signature.optional === true) {
2089
+ context.write("?");
2090
+ }
2091
+ if (signature.typeParameters) {
2092
+ context.writeNode(signature.typeParameters);
2093
+ }
2094
+ context.write("(");
2095
+ if (signature.params) {
2096
+ context.writeNodeList(signature.params, ", ");
2097
+ } else if (signature.parameters) {
2098
+ context.writeNodeList(signature.parameters, ", ");
2099
+ }
2100
+ context.write(")");
2101
+ writeReturnType(signature, context);
2102
+ context.write(";");
2103
+ }
2104
+
2105
+ function printTSCallSignatureDeclaration(
2106
+ signature: AST.TSCallSignatureDeclaration,
2107
+ context: PrinterContext,
2108
+ ): void {
2109
+ if (signature.typeParameters) {
2110
+ context.writeNode(signature.typeParameters);
2111
+ }
2112
+ context.write("(");
2113
+ if (signature.params) {
2114
+ context.writeNodeList(signature.params, ", ");
2115
+ } else if (signature.parameters) {
2116
+ context.writeNodeList(signature.parameters, ", ");
2117
+ }
2118
+ context.write(")");
2119
+ writeReturnType(signature, context);
2120
+ context.write(";");
2121
+ }
2122
+
2123
+ function printTSConstructSignatureDeclaration(
2124
+ signature: AST.TSConstructSignatureDeclaration,
2125
+ context: PrinterContext,
2126
+ ): void {
2127
+ context.write("new ");
2128
+ if (signature.typeParameters) {
2129
+ context.writeNode(signature.typeParameters);
2130
+ }
2131
+ context.write("(");
2132
+ if (signature.params) {
2133
+ context.writeNodeList(signature.params, ", ");
2134
+ } else if (signature.parameters) {
2135
+ context.writeNodeList(signature.parameters, ", ");
2136
+ }
2137
+ context.write(")");
2138
+ writeReturnType(signature, context);
2139
+ context.write(";");
2140
+ }
2141
+
2142
+ function printTSIndexSignature(
2143
+ signature: AST.TSIndexSignature,
2144
+ context: PrinterContext,
2145
+ ): void {
2146
+ context.write("[");
2147
+ if (signature.parameters) {
2148
+ context.writeNodeList(signature.parameters, ", ");
2149
+ }
2150
+ context.write("]");
2151
+ writeReturnType(signature, context);
2152
+ context.write(";");
2153
+ }
2154
+
2155
+ function writeReturnType(
2156
+ node: {
2157
+ returnType?: AST.TSTypeAnnotation | null;
2158
+ typeAnnotation?: AST.TSTypeAnnotation | null;
2159
+ },
2160
+ context: PrinterContext,
2161
+ options?: { tsArrowType: true },
2162
+ ): void {
2163
+ let ret: AST.Node | null | undefined = node.returnType ?? node.typeAnnotation;
2164
+ if (options?.tsArrowType) {
2165
+ // TSFunctionType / TSConstructorType use `=>` syntax:
2166
+ // must unwrap the TSTypeAnnotation to get the raw type node
2167
+ ret = ret?.typeAnnotation;
2168
+ }
2169
+ if (ret) {
2170
+ context.writeNode(ret);
2171
+ }
2172
+ }
2173
+
2174
+ function printTSTypeReference(
2175
+ reference: AST.TSTypeReference,
2176
+ context: PrinterContext,
2177
+ ): void {
2178
+ context.writeNode(reference.typeName);
2179
+ if (reference.typeArguments) {
2180
+ context.writeNode(reference.typeArguments);
2181
+ }
2182
+ }
2183
+
2184
+ function printTSQualifiedName(
2185
+ name: AST.TSQualifiedName,
2186
+ context: PrinterContext,
2187
+ ): void {
2188
+ context.writeNode(name.left);
2189
+ context.write(".");
2190
+ context.writeNode(name.right);
2191
+ }
2192
+
2193
+ function printJoinedTypes(
2194
+ joined: AST.TSUnionType | AST.TSIntersectionType,
2195
+ context: PrinterContext,
2196
+ ): void {
2197
+ context.writeNodeList(
2198
+ joined.types,
2199
+ joined.type === "TSUnionType" ? " | " : " & ",
2200
+ );
2201
+ }
2202
+
2203
+ function printTSArrayType(
2204
+ array: AST.TSArrayType,
2205
+ context: PrinterContext,
2206
+ ): void {
2207
+ context.writeNode(array.elementType);
2208
+ context.write("[]");
2209
+ }
2210
+
2211
+ function printTSTupleType(
2212
+ node: AST.TSTupleType,
2213
+ context: PrinterContext,
2214
+ ): void {
2215
+ context.write("[");
2216
+ context.writeNodeList(node.elementTypes, ", ");
2217
+ context.write("]");
2218
+ }
2219
+
2220
+ function printTSNamedTupleMember(
2221
+ node: AST.TSNamedTupleMember,
2222
+ context: PrinterContext,
2223
+ ): void {
2224
+ context.writeNode(node.label);
2225
+ context.write(": ");
2226
+ context.writeNode(node.elementType);
2227
+ }
2228
+
2229
+ function printTSTypeLiteral(
2230
+ literal: AST.TSTypeLiteral,
2231
+ context: PrinterContext,
2232
+ ): void {
2233
+ context.write("{ ");
2234
+ context.writeNodeList(literal.members, " ");
2235
+ context.write(" }");
2236
+ }
2237
+
2238
+ function printTSTypeOperator(
2239
+ node: AST.TSTypeOperator,
2240
+ context: PrinterContext,
2241
+ ): void {
2242
+ context.write(node.operator + " ");
2243
+ if (node.typeAnnotation) {
2244
+ context.writeNode(node.typeAnnotation);
2245
+ }
2246
+ }
2247
+
2248
+ function printTSTypePredicate(
2249
+ node: AST.TSTypePredicate,
2250
+ context: PrinterContext,
2251
+ ): void {
2252
+ if (node.asserts === true) {
2253
+ context.write("asserts ");
2254
+ }
2255
+ if (node.parameterName) {
2256
+ context.writeNode(node.parameterName);
2257
+ } else if (node.typeAnnotation) {
2258
+ context.writeNode(node.typeAnnotation);
2259
+ }
2260
+ if (node.asserts !== true || node.typeAnnotation) {
2261
+ context.write(" is ");
2262
+ }
2263
+ if (node.typeAnnotation) {
2264
+ context.writeNode(node.typeAnnotation.typeAnnotation);
2265
+ }
2266
+ }
2267
+
2268
+ function printTSTypeQuery(
2269
+ node: AST.TSTypeQuery,
2270
+ context: PrinterContext,
2271
+ ): void {
2272
+ context.write("typeof ");
2273
+ context.writeNode(node.exprName);
2274
+ }
2275
+
2276
+ function printTSMappedType(
2277
+ node: AST.TSMappedType,
2278
+ context: PrinterContext,
2279
+ ): void {
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("[");
2288
+ const legacyTp = node.typeParameter;
2289
+ const key = node.key ?? legacyTp?.name;
2290
+ const constraint = node.constraint ?? legacyTp?.constraint;
2291
+
2292
+ if (key) {
2293
+ if (typeof key === "string") {
2294
+ context.write(key);
2295
+ } else {
2296
+ context.writeNode(key);
2297
+ }
2298
+ }
2299
+ if (constraint) {
2300
+ context.write(" in ");
2301
+ context.writeNode(constraint);
2302
+ }
2303
+ if (node.nameType) {
2304
+ context.write(" as ");
2305
+ context.writeNode(node.nameType);
2306
+ }
2307
+ context.write("]");
2308
+ if (node.optional) {
2309
+ if (typeof node.optional === "string") {
2310
+ context.write(node.optional);
2311
+ }
2312
+ context.write("?");
2313
+ }
2314
+ if (node.typeAnnotation) {
2315
+ context.write(": ");
2316
+ context.writeNode(node.typeAnnotation);
2317
+ }
2318
+ context.write(" }");
2319
+ }
2320
+
2321
+ function printTSConditionalType(
2322
+ node: AST.TSConditionalType,
2323
+ context: PrinterContext,
2324
+ ): void {
2325
+ context.writeNode(node.checkType);
2326
+ context.write(" extends ");
2327
+ context.writeNode(node.extendsType);
2328
+ context.write(" ? ");
2329
+ context.writeNode(node.trueType);
2330
+ context.write(" : ");
2331
+ context.writeNode(node.falseType);
2332
+ }
2333
+
2334
+ function printTSInferType(
2335
+ node: AST.TSInferType,
2336
+ context: PrinterContext,
2337
+ ): void {
2338
+ context.write("infer ");
2339
+ context.writeNode(node.typeParameter);
2340
+ }
2341
+
2342
+ function printTSIndexedAccessType(
2343
+ node: AST.TSIndexedAccessType,
2344
+ context: PrinterContext,
2345
+ ): void {
2346
+ context.writeNode(node.objectType);
2347
+ context.write("[");
2348
+ context.writeNode(node.indexType);
2349
+ context.write("]");
2350
+ }
2351
+
2352
+ function printTSOptionalType(
2353
+ node: AST.TSOptionalType,
2354
+ context: PrinterContext,
2355
+ ): void {
2356
+ context.writeNode(node.typeAnnotation);
2357
+ context.write("?");
2358
+ }
2359
+
2360
+ function printTSRestType(node: AST.TSRestType, context: PrinterContext): void {
2361
+ context.write("...");
2362
+ context.writeNode(node.typeAnnotation);
2363
+ }
2364
+
2365
+ function printTSThisType(_node: AST.TSThisType, context: PrinterContext): void {
2366
+ context.write("this");
2367
+ }
2368
+
2369
+ function printTSLiteralType(
2370
+ literal: AST.TSLiteralType,
2371
+ context: PrinterContext,
2372
+ ): void {
2373
+ context.writeNode(literal.literal);
2374
+ }
2375
+
2376
+ function printTSTemplateLiteralType(
2377
+ node: AST.TSTemplateLiteralType,
2378
+ context: PrinterContext,
2379
+ ): void {
2380
+ context.write("`");
2381
+ const { quasis, types } = node;
2382
+ for (let i = 0; i < types.length; i++) {
2383
+ context.write(quasis[i].value.raw);
2384
+ context.write("${");
2385
+ context.writeNode(types[i]);
2386
+ context.write("}");
2387
+ }
2388
+ context.write(quasis[quasis.length - 1].value.raw);
2389
+ context.write("`");
2390
+ }
2391
+
2392
+ function printTSImportType(
2393
+ node: AST.TSImportType,
2394
+ context: PrinterContext,
2395
+ ): void {
2396
+ context.write("import(");
2397
+ context.writeNode(node.argument);
2398
+ context.write(")");
2399
+ if (node.qualifier) {
2400
+ context.write(".");
2401
+ context.writeNode(node.qualifier);
2402
+ }
2403
+ }
2404
+
2405
+ function printTSImportEqualsDeclaration(
2406
+ node: AST.TSImportEqualsDeclaration,
2407
+ context: PrinterContext,
2408
+ ): void {
2409
+ context.write("import ");
2410
+ context.writeNode(node.id);
2411
+ context.write(" = ");
2412
+ context.writeNode(node.moduleReference);
2413
+ context.write(";");
2414
+ }
2415
+
2416
+ function printTSExternalModuleReference(
2417
+ node: AST.TSExternalModuleReference,
2418
+ context: PrinterContext,
2419
+ ): void {
2420
+ context.write("require(");
2421
+ context.writeNode(node.expression);
2422
+ context.write(")");
2423
+ }
2424
+
2425
+ function printTSEnumDeclaration(
2426
+ node: AST.TSEnumDeclaration,
2427
+ context: PrinterContext,
2428
+ ): void {
2429
+ if (node.declare === true) {
2430
+ context.write("declare ");
2431
+ }
2432
+ const isConst = node.const === true;
2433
+ if (isConst) {
2434
+ context.write("const ");
2435
+ }
2436
+ context.write("enum ");
2437
+ context.writeNode(node.id);
2438
+ context.write(" { ");
2439
+ context.writeNodeList(node.members, ", ");
2440
+ context.write(" }");
2441
+ }
2442
+
2443
+ function printTSEnumMember(
2444
+ node: AST.TSEnumMember,
2445
+ context: PrinterContext,
2446
+ ): void {
2447
+ context.writeNode(node.id);
2448
+ if (node.initializer) {
2449
+ context.write(" = ");
2450
+ context.writeNode(node.initializer);
2451
+ }
2452
+ }
2453
+
2454
+ function printTSModuleDeclaration(
2455
+ node: AST.TSModuleDeclaration,
2456
+ context: PrinterContext,
2457
+ ): void {
2458
+ if (node.declare === true) {
2459
+ context.write("declare ");
2460
+ }
2461
+ if (node.global === true) {
2462
+ context.write("global");
2463
+ } else {
2464
+ const kind =
2465
+ (node as AST.TSModuleDeclaration).kind ??
2466
+ (node.id && node.id.type === "Literal" ? "module" : "namespace");
2467
+ context.write(String(kind) + " ");
2468
+ context.writeNode(node.id);
2469
+ }
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);
2482
+ }
2483
+ }
2484
+
2485
+ function printTSModuleBlock(
2486
+ node: AST.TSModuleBlock,
2487
+ context: PrinterContext,
2488
+ ): void {
2489
+ context.write("{\n");
2490
+ context.writeNodeListWithNewLineSep(node.body);
2491
+ context.write("\n}");
2492
+ }
2493
+
2494
+ function printTSDeclareFunction(
2495
+ node: AST.TSDeclareFunction,
2496
+ context: PrinterContext,
2497
+ ): void {
2498
+ context.write("declare ");
2499
+ if (node.async === true) {
2500
+ context.write("async ");
2501
+ }
2502
+ context.write("function");
2503
+ if ((node.generator as boolean) === true) {
2504
+ context.write("*");
2505
+ }
2506
+ if (node.id) {
2507
+ context.write(" ");
2508
+ context.writeNode(node.id);
2509
+ }
2510
+ if (node.typeParameters) {
2511
+ context.writeNode(node.typeParameters);
2512
+ }
2513
+ context.write("(");
2514
+ context.writeNodeList(node.params, ", ");
2515
+ context.write(")");
2516
+ writeReturnType(node, context);
2517
+ context.write(";");
2518
+ }
2519
+
2520
+ function printTSParameterProperty(
2521
+ node: AST.TSParameterProperty,
2522
+ context: PrinterContext,
2523
+ ): void {
2524
+ if (node.accessibility) {
2525
+ context.write(node.accessibility + " ");
2526
+ }
2527
+ if (node.readonly === true) {
2528
+ context.write("readonly ");
2529
+ }
2530
+ context.writeNode(node.parameter);
2531
+ }
2532
+
2533
+ function printTSExportAssignment(
2534
+ node: AST.TSExportAssignment,
2535
+ context: PrinterContext,
2536
+ ): void {
2537
+ context.write("export = ");
2538
+ context.writeNode(node.expression);
2539
+ context.write(";");
2540
+ }
2541
+
2542
+ function printTSNamespaceExportDeclaration(
2543
+ node: AST.TSNamespaceExportDeclaration,
2544
+ context: PrinterContext,
2545
+ ): void {
2546
+ context.write("export as namespace ");
2547
+ context.writeNode(node.id);
2548
+ context.write(";");
2549
+ }
2550
+
2551
+ function printTSInstantiationExpression(
2552
+ node: AST.TSInstantiationExpression,
2553
+ context: PrinterContext,
2554
+ ): void {
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
+ }
2567
+ context.writeNode(node.typeArguments);
2568
+ }
2569
+
2570
+ function printTSParenthesizedType(
2571
+ node: { typeAnnotation: AST.Node },
2572
+ context: PrinterContext,
2573
+ ): void {
2574
+ context.write("(");
2575
+ context.writeNode(node.typeAnnotation);
2576
+ context.write(")");
2577
+ }
2578
+
2579
+ function printKeywordType(
2580
+ node: Extract<AST.Node, { type: `${string}Keyword` }>,
2581
+ context: PrinterContext,
2582
+ ): void {
2583
+ const keyword = node.type.slice(2, -"Keyword".length).toLowerCase();
2584
+ context.write(keyword);
2585
+ }
2586
+
2587
+ function writeOptionalTypeAnnotation(
2588
+ node: { optional?: boolean; typeAnnotation?: AST.Node | null },
2589
+ context: PrinterContext,
2590
+ ): void {
2591
+ if (node.optional === true) {
2592
+ context.write("?");
2593
+ }
2594
+ if (node.typeAnnotation) {
2595
+ context.writeNode(node.typeAnnotation);
2596
+ }
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
+ }