esrap 1.4.9 → 2.0.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/src/handlers.js DELETED
@@ -1,1688 +0,0 @@
1
- /** @import { TSESTree } from '@typescript-eslint/types' */
2
- /** @import { Command, Dedent, Handlers, Location, Indent, Newline, NodeWithComments, State, TypeAnnotationNodes } from './types' */
3
-
4
- /** @type {Newline} */
5
- const newline = { type: 'Newline' };
6
-
7
- /** @type {Indent} */
8
- const indent = { type: 'Indent' };
9
-
10
- /** @type {Dedent} */
11
- const dedent = { type: 'Dedent' };
12
-
13
- /**
14
- * @returns {Command[]}
15
- */
16
- function create_sequence() {
17
- return [];
18
- }
19
-
20
- /**
21
- * Rough estimate of the combined width of a group of commands
22
- * @param {Command[]} commands
23
- * @param {number} from
24
- * @param {number} to
25
- */
26
- function measure(commands, from, to = commands.length) {
27
- let total = 0;
28
- for (let i = from; i < to; i += 1) {
29
- const command = commands[i];
30
- if (typeof command === 'string') {
31
- total += command.length;
32
- } else if (Array.isArray(command)) {
33
- total +=
34
- command.length === 0
35
- ? 2 // assume this is ', '
36
- : measure(command, 0);
37
- }
38
- }
39
-
40
- return total;
41
- }
42
-
43
- /**
44
- * @param {TSESTree.Node} node
45
- * @param {State} state
46
- */
47
- export function handle(node, state) {
48
- const node_with_comments = /** @type {NodeWithComments} */ (node);
49
-
50
- const handler = handlers[node.type];
51
-
52
- if (!handler) {
53
- throw new Error(`Not implemented ${node.type}`);
54
- }
55
-
56
- if (node_with_comments.leadingComments) {
57
- prepend_comments(node_with_comments.leadingComments, state, false);
58
- }
59
-
60
- // @ts-expect-error
61
- handler(node, state);
62
-
63
- if (node_with_comments.trailingComments) {
64
- state.comments.push(node_with_comments.trailingComments[0]); // there is only ever one
65
- }
66
- }
67
-
68
- /**
69
- * @param {number} line
70
- * @param {number} column
71
- * @returns {Location}
72
- */
73
- function l(line, column) {
74
- return {
75
- type: 'Location',
76
- line,
77
- column
78
- };
79
- }
80
-
81
- /**
82
- * @param {string} content
83
- * @param {TSESTree.Node} node
84
- * @returns {string | Command[]}
85
- */
86
- function c(content, node) {
87
- return node.loc
88
- ? [
89
- l(node.loc.start.line, node.loc.start.column),
90
- content,
91
- l(node.loc.end.line, node.loc.end.column)
92
- ]
93
- : content;
94
- }
95
-
96
- /**
97
- * @param {TSESTree.Comment[]} comments
98
- * @param {State} state
99
- * @param {boolean} newlines
100
- */
101
- function prepend_comments(comments, state, newlines) {
102
- for (const comment of comments) {
103
- state.commands.push({ type: 'Comment', comment });
104
-
105
- if (newlines || comment.type === 'Line' || /\n/.test(comment.value)) {
106
- state.commands.push(newline);
107
- } else {
108
- state.commands.push(' ');
109
- }
110
- }
111
- }
112
-
113
- /**
114
- * @param {string} string
115
- * @param {'\'' | '"'} char
116
- */
117
- function quote(string, char) {
118
- let out = char;
119
-
120
- for (const c of string) {
121
- if (c === '\\') {
122
- out += '\\\\';
123
- } else if (c === char) {
124
- out += '\\' + c;
125
- } else if (c === '\n') {
126
- out += '\\n';
127
- } else if (c === '\r') {
128
- out += '\\r';
129
- } else {
130
- out += c;
131
- }
132
- }
133
-
134
- return out + char;
135
- }
136
-
137
- const OPERATOR_PRECEDENCE = {
138
- '||': 2,
139
- '&&': 3,
140
- '??': 4,
141
- '|': 5,
142
- '^': 6,
143
- '&': 7,
144
- '==': 8,
145
- '!=': 8,
146
- '===': 8,
147
- '!==': 8,
148
- '<': 9,
149
- '>': 9,
150
- '<=': 9,
151
- '>=': 9,
152
- in: 9,
153
- instanceof: 9,
154
- '<<': 10,
155
- '>>': 10,
156
- '>>>': 10,
157
- '+': 11,
158
- '-': 11,
159
- '*': 12,
160
- '%': 12,
161
- '/': 12,
162
- '**': 13
163
- };
164
-
165
- /** @type {Record<TSESTree.Expression['type'] | 'Super' | 'RestElement', number>} */
166
- const EXPRESSIONS_PRECEDENCE = {
167
- JSXFragment: 20,
168
- JSXElement: 20,
169
- ArrayPattern: 20,
170
- ObjectPattern: 20,
171
- ArrayExpression: 20,
172
- TaggedTemplateExpression: 20,
173
- ThisExpression: 20,
174
- Identifier: 20,
175
- TemplateLiteral: 20,
176
- Super: 20,
177
- SequenceExpression: 20,
178
- MemberExpression: 19,
179
- MetaProperty: 19,
180
- CallExpression: 19,
181
- ChainExpression: 19,
182
- ImportExpression: 19,
183
- NewExpression: 19,
184
- Literal: 18,
185
- TSSatisfiesExpression: 18,
186
- TSInstantiationExpression: 18,
187
- TSNonNullExpression: 18,
188
- TSTypeAssertion: 18,
189
- AwaitExpression: 17,
190
- ClassExpression: 17,
191
- FunctionExpression: 17,
192
- ObjectExpression: 17,
193
- TSAsExpression: 16,
194
- UpdateExpression: 16,
195
- UnaryExpression: 15,
196
- BinaryExpression: 14,
197
- LogicalExpression: 13,
198
- ConditionalExpression: 4,
199
- ArrowFunctionExpression: 3,
200
- AssignmentExpression: 3,
201
- YieldExpression: 2,
202
- RestElement: 1
203
- };
204
-
205
- /**
206
- *
207
- * @param {TSESTree.Expression | TSESTree.PrivateIdentifier} node
208
- * @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} parent
209
- * @param {boolean} is_right
210
- * @returns
211
- */
212
- function needs_parens(node, parent, is_right) {
213
- if (node.type === 'PrivateIdentifier') return false;
214
-
215
- // special case where logical expressions and coalesce expressions cannot be mixed,
216
- // either of them need to be wrapped with parentheses
217
- if (
218
- node.type === 'LogicalExpression' &&
219
- parent.type === 'LogicalExpression' &&
220
- ((parent.operator === '??' && node.operator !== '??') ||
221
- (parent.operator !== '??' && node.operator === '??'))
222
- ) {
223
- return true;
224
- }
225
-
226
- const precedence = EXPRESSIONS_PRECEDENCE[node.type];
227
- const parent_precedence = EXPRESSIONS_PRECEDENCE[parent.type];
228
-
229
- if (precedence !== parent_precedence) {
230
- // Different node types
231
- return (
232
- (!is_right && precedence === 15 && parent_precedence === 14 && parent.operator === '**') ||
233
- precedence < parent_precedence
234
- );
235
- }
236
-
237
- if (precedence !== 13 && precedence !== 14) {
238
- // Not a `LogicalExpression` or `BinaryExpression`
239
- return false;
240
- }
241
-
242
- if (
243
- /** @type {TSESTree.BinaryExpression} */ (node).operator === '**' &&
244
- parent.operator === '**'
245
- ) {
246
- // Exponentiation operator has right-to-left associativity
247
- return !is_right;
248
- }
249
-
250
- if (is_right) {
251
- // Parenthesis are used if both operators have the same precedence
252
- return (
253
- OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] <=
254
- OPERATOR_PRECEDENCE[parent.operator]
255
- );
256
- }
257
-
258
- return (
259
- OPERATOR_PRECEDENCE[/** @type {TSESTree.BinaryExpression} */ (node).operator] <
260
- OPERATOR_PRECEDENCE[parent.operator]
261
- );
262
- }
263
-
264
- /** @param {TSESTree.Node} node */
265
- function has_call_expression(node) {
266
- while (node) {
267
- if (node.type === 'CallExpression') {
268
- return true;
269
- } else if (node.type === 'MemberExpression') {
270
- node = node.object;
271
- } else {
272
- return false;
273
- }
274
- }
275
- }
276
-
277
- const grouped_expression_types = [
278
- 'ImportDeclaration',
279
- 'VariableDeclaration',
280
- 'ExportDefaultDeclaration',
281
- 'ExportNamedDeclaration'
282
- ];
283
-
284
- /**
285
- * @param {TSESTree.Node[]} nodes
286
- * @param {State} state
287
- */
288
- const handle_body = (nodes, state) => {
289
- let last_statement = /** @type {TSESTree.Node} */ ({
290
- type: 'EmptyStatement'
291
- });
292
- let first = true;
293
- let needs_margin = false;
294
-
295
- for (const statement of nodes) {
296
- if (statement.type === 'EmptyStatement') continue;
297
-
298
- const margin = create_sequence();
299
-
300
- if (!first) state.commands.push(margin, newline);
301
- first = false;
302
-
303
- const statement_with_comments = /** @type {NodeWithComments} */ (statement);
304
- const leading_comments = statement_with_comments.leadingComments;
305
- delete statement_with_comments.leadingComments;
306
-
307
- if (leading_comments && leading_comments.length > 0) {
308
- prepend_comments(leading_comments, state, true);
309
- }
310
-
311
- const child_state = { ...state, multiline: false };
312
- handle(statement, child_state);
313
-
314
- if (
315
- child_state.multiline ||
316
- needs_margin ||
317
- ((grouped_expression_types.includes(statement.type) ||
318
- grouped_expression_types.includes(last_statement.type)) &&
319
- last_statement.type !== statement.type)
320
- ) {
321
- margin.push('\n');
322
- }
323
-
324
- let add_newline = false;
325
-
326
- while (state.comments.length) {
327
- const comment = /** @type {TSESTree.Comment} */ (state.comments.shift());
328
-
329
- state.commands.push(add_newline ? newline : ' ', { type: 'Comment', comment });
330
- add_newline = comment.type === 'Line';
331
- }
332
-
333
- needs_margin = child_state.multiline;
334
- last_statement = statement;
335
- }
336
- };
337
-
338
- /**
339
- * @param {TSESTree.VariableDeclaration} node
340
- * @param {State} state
341
- */
342
- const handle_var_declaration = (node, state) => {
343
- const index = state.commands.length;
344
-
345
- const open = create_sequence();
346
- const join = create_sequence();
347
- const child_state = { ...state, multiline: false };
348
-
349
- state.commands.push(`${node.kind} `, open);
350
-
351
- let first = true;
352
-
353
- for (const d of node.declarations) {
354
- if (!first) state.commands.push(join);
355
- first = false;
356
-
357
- handle(d, child_state);
358
- }
359
-
360
- const multiline =
361
- child_state.multiline || (node.declarations.length > 1 && measure(state.commands, index) > 50);
362
-
363
- if (multiline) {
364
- state.multiline = true;
365
- if (node.declarations.length > 1) open.push(indent);
366
- join.push(',', newline);
367
- if (node.declarations.length > 1) state.commands.push(dedent);
368
- } else {
369
- join.push(', ');
370
- }
371
- };
372
-
373
- /**
374
- * @template {TSESTree.Node} T
375
- * @param {Array<T | null>} nodes
376
- * @param {State} state
377
- * @param {boolean} spaces
378
- * @param {(node: T, state: State) => void} fn
379
- */
380
- function sequence(nodes, state, spaces, fn, separator = ',') {
381
- if (nodes.length === 0) return;
382
-
383
- const index = state.commands.length;
384
-
385
- const open = create_sequence();
386
- const join = create_sequence();
387
- const close = create_sequence();
388
-
389
- state.commands.push(open);
390
-
391
- const child_state = { ...state, multiline: false };
392
-
393
- let prev;
394
-
395
- for (let i = 0; i < nodes.length; i += 1) {
396
- const node = nodes[i];
397
- const is_first = i === 0;
398
- const is_last = i === nodes.length - 1;
399
-
400
- if (node) {
401
- if (!is_first && !prev) {
402
- state.commands.push(join);
403
- }
404
-
405
- fn(node, child_state);
406
-
407
- if (!is_last) {
408
- state.commands.push(separator);
409
- }
410
-
411
- if (state.comments.length > 0) {
412
- state.commands.push(' ');
413
-
414
- while (state.comments.length) {
415
- const comment = /** @type {TSESTree.Comment} */ (state.comments.shift());
416
- state.commands.push({ type: 'Comment', comment });
417
- if (!is_last) state.commands.push(join);
418
- }
419
-
420
- child_state.multiline = true;
421
- } else {
422
- if (!is_last) state.commands.push(join);
423
- }
424
- } else {
425
- // This is only used for ArrayPattern and ArrayExpression, but
426
- // it makes more sense to have the logic here than there, because
427
- // otherwise we'd duplicate a lot more stuff
428
- state.commands.push(separator);
429
- }
430
-
431
- prev = node;
432
- }
433
-
434
- state.commands.push(close);
435
-
436
- const multiline = child_state.multiline || measure(state.commands, index) > 50;
437
-
438
- if (multiline) {
439
- state.multiline = true;
440
-
441
- open.push(indent, newline);
442
- join.push(newline);
443
- close.push(dedent, newline);
444
- } else {
445
- if (spaces) open.push(' ');
446
- join.push(' ');
447
- if (spaces) close.push(' ');
448
- }
449
- }
450
-
451
- /**
452
- * @param {TypeAnnotationNodes} node
453
- * @param {State} state
454
- */
455
- function handle_type_annotation(node, state) {
456
- switch (node.type) {
457
- case 'TSNumberKeyword':
458
- state.commands.push('number');
459
- break;
460
- case 'TSStringKeyword':
461
- state.commands.push('string');
462
- break;
463
- case 'TSBooleanKeyword':
464
- state.commands.push('boolean');
465
- break;
466
- case 'TSAnyKeyword':
467
- state.commands.push('any');
468
- break;
469
- case 'TSVoidKeyword':
470
- state.commands.push('void');
471
- break;
472
- case 'TSUnknownKeyword':
473
- state.commands.push('unknown');
474
- break;
475
- case 'TSNeverKeyword':
476
- state.commands.push('never');
477
- break;
478
- case 'TSSymbolKeyword':
479
- state.commands.push('symbol');
480
- break;
481
- case 'TSNullKeyword':
482
- state.commands.push('null');
483
- break;
484
- case 'TSUndefinedKeyword':
485
- state.commands.push('undefined');
486
- break;
487
- case 'TSArrayType':
488
- handle_type_annotation(node.elementType, state);
489
- state.commands.push('[]');
490
- break;
491
- case 'TSTypeAnnotation':
492
- state.commands.push(': ');
493
- handle_type_annotation(node.typeAnnotation, state);
494
- break;
495
- case 'TSTypeLiteral':
496
- state.commands.push('{ ');
497
- sequence(node.members, state, false, handle_type_annotation, ';');
498
- state.commands.push(' }');
499
- break;
500
- case 'TSPropertySignature':
501
- handle(node.key, state);
502
- if (node.optional) state.commands.push('?');
503
- if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state);
504
- break;
505
- case 'TSTypeReference':
506
- handle(node.typeName, state);
507
-
508
- if (node.typeArguments) {
509
- handle_type_annotation(node.typeArguments, state);
510
- }
511
- break;
512
- case 'TSTypeParameterInstantiation':
513
- case 'TSTypeParameterDeclaration':
514
- state.commands.push('<');
515
- for (let i = 0; i < node.params.length; i++) {
516
- handle_type_annotation(node.params[i], state);
517
- if (i != node.params.length - 1) state.commands.push(', ');
518
- }
519
- state.commands.push('>');
520
- break;
521
- case 'TSTypeParameter':
522
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
523
- state.commands.push(node.name);
524
-
525
- if (node.constraint) {
526
- state.commands.push(' extends ');
527
- handle_type_annotation(node.constraint, state);
528
- }
529
- break;
530
- case 'TSTypeQuery':
531
- state.commands.push('typeof ');
532
- handle(node.exprName, state);
533
- break;
534
- case 'TSEnumMember':
535
- handle(node.id, state);
536
- if (node.initializer) {
537
- state.commands.push(' = ');
538
- handle(node.initializer, state);
539
- }
540
- break;
541
- case 'TSFunctionType':
542
- if (node.typeParameters) handle_type_annotation(node.typeParameters, state);
543
-
544
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
545
- const parameters = node.parameters;
546
- state.commands.push('(');
547
- sequence(parameters, state, false, handle);
548
-
549
- state.commands.push(') => ');
550
-
551
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
552
- handle_type_annotation(node.typeAnnotation.typeAnnotation, state);
553
- break;
554
- case 'TSIndexSignature':
555
- const indexParameters = node.parameters;
556
- state.commands.push('[');
557
- sequence(indexParameters, state, false, handle);
558
- state.commands.push(']');
559
-
560
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
561
- handle_type_annotation(node.typeAnnotation, state);
562
- break;
563
- case 'TSMethodSignature':
564
- handle(node.key, state);
565
-
566
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
567
- const parametersSignature = node.parameters;
568
- state.commands.push('(');
569
- sequence(parametersSignature, state, false, handle);
570
- state.commands.push(')');
571
-
572
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
573
- handle_type_annotation(node.typeAnnotation, state);
574
- break;
575
- case 'TSExpressionWithTypeArguments':
576
- handle(node.expression, state);
577
- break;
578
- case 'TSTupleType':
579
- state.commands.push('[');
580
- sequence(node.elementTypes, state, false, handle_type_annotation);
581
- state.commands.push(']');
582
- break;
583
- case 'TSNamedTupleMember':
584
- handle(node.label, state);
585
- state.commands.push(': ');
586
- handle_type_annotation(node.elementType, state);
587
-
588
- break;
589
- case 'TSUnionType':
590
- sequence(node.types, state, false, handle_type_annotation, ' |');
591
- break;
592
- case 'TSIntersectionType':
593
- sequence(node.types, state, false, handle_type_annotation, ' &');
594
- break;
595
- case 'TSLiteralType':
596
- handle(node.literal, state);
597
- break;
598
- case 'TSConditionalType':
599
- handle_type_annotation(node.checkType, state);
600
- state.commands.push(' extends ');
601
- handle_type_annotation(node.extendsType, state);
602
- state.commands.push(' ? ');
603
- handle_type_annotation(node.trueType, state);
604
- state.commands.push(' : ');
605
- handle_type_annotation(node.falseType, state);
606
- break;
607
- case 'TSIndexedAccessType':
608
- handle_type_annotation(node.objectType, state);
609
- state.commands.push('[');
610
- handle_type_annotation(node.indexType, state);
611
- state.commands.push(']');
612
- break;
613
- case 'TSImportType':
614
- state.commands.push('import(');
615
- handle(node.argument, state);
616
- state.commands.push(')');
617
-
618
- if (node.qualifier) {
619
- state.commands.push('.');
620
- handle(node.qualifier, state);
621
- }
622
- break;
623
- default:
624
- throw new Error(`Not implemented type annotation ${node.type}`);
625
- }
626
- }
627
-
628
- /** @satisfies {Record<string, (node: any, state: State) => undefined>} */
629
- const shared = {
630
- /**
631
- * @param {TSESTree.ArrayExpression | TSESTree.ArrayPattern} node
632
- * @param {State} state
633
- */
634
- 'ArrayExpression|ArrayPattern': (node, state) => {
635
- state.commands.push('[');
636
- sequence(/** @type {TSESTree.Node[]} */ (node.elements), state, false, handle);
637
- state.commands.push(']');
638
- },
639
-
640
- /**
641
- * @param {TSESTree.BinaryExpression | TSESTree.LogicalExpression} node
642
- * @param {State} state
643
- */
644
- 'BinaryExpression|LogicalExpression': (node, state) => {
645
- // TODO
646
- // const is_in = node.operator === 'in';
647
- // if (is_in) {
648
- // // Avoids confusion in `for` loops initializers
649
- // chunks.push(c('('));
650
- // }
651
-
652
- if (needs_parens(node.left, node, false)) {
653
- state.commands.push('(');
654
- handle(node.left, state);
655
- state.commands.push(')');
656
- } else {
657
- handle(node.left, state);
658
- }
659
-
660
- state.commands.push(` ${node.operator} `);
661
-
662
- if (needs_parens(node.right, node, true)) {
663
- state.commands.push('(');
664
- handle(node.right, state);
665
- state.commands.push(')');
666
- } else {
667
- handle(node.right, state);
668
- }
669
- },
670
-
671
- /**
672
- * @param {TSESTree.BlockStatement | TSESTree.ClassBody} node
673
- * @param {State} state
674
- */
675
- 'BlockStatement|ClassBody': (node, state) => {
676
- if (node.loc) {
677
- const { line, column } = node.loc.start;
678
- state.commands.push(l(line, column), '{', l(line, column + 1));
679
- } else {
680
- state.commands.push('{');
681
- }
682
-
683
- if (node.body.length > 0) {
684
- state.multiline = true;
685
- state.commands.push(indent, newline);
686
- handle_body(node.body, state);
687
- state.commands.push(dedent, newline);
688
- }
689
-
690
- if (node.loc) {
691
- const { line, column } = node.loc.end;
692
- state.commands.push(l(line, column - 1), '}', l(line, column));
693
- } else {
694
- state.commands.push('}');
695
- }
696
- },
697
-
698
- /**
699
- * @param {TSESTree.CallExpression | TSESTree.NewExpression} node
700
- * @param {State} state
701
- */
702
- 'CallExpression|NewExpression': (node, state) => {
703
- if (node.type === 'NewExpression') {
704
- state.commands.push('new ');
705
- }
706
-
707
- const needs_parens =
708
- EXPRESSIONS_PRECEDENCE[node.callee.type] < EXPRESSIONS_PRECEDENCE.CallExpression ||
709
- (node.type === 'NewExpression' && has_call_expression(node.callee));
710
-
711
- if (needs_parens) {
712
- state.commands.push('(');
713
- handle(node.callee, state);
714
- state.commands.push(')');
715
- } else {
716
- handle(node.callee, state);
717
- }
718
-
719
- if (/** @type {TSESTree.CallExpression} */ (node).optional) {
720
- state.commands.push('?.');
721
- }
722
-
723
- if (node.typeArguments) handle_type_annotation(node.typeArguments, state);
724
-
725
- const open = create_sequence();
726
- const join = create_sequence();
727
- const close = create_sequence();
728
-
729
- state.commands.push('(', open);
730
-
731
- // if the final argument is multiline, it doesn't need to force all the
732
- // other arguments to also be multiline
733
- const child_state = { ...state, multiline: false };
734
- const final_state = { ...state, multiline: false };
735
-
736
- for (let i = 0; i < node.arguments.length; i += 1) {
737
- if (i > 0) {
738
- if (state.comments.length > 0) {
739
- state.commands.push(', ');
740
-
741
- while (state.comments.length) {
742
- const comment = /** @type {TSESTree.Comment} */ (state.comments.shift());
743
-
744
- state.commands.push({ type: 'Comment', comment });
745
-
746
- if (comment.type === 'Line') {
747
- child_state.multiline = true;
748
- state.commands.push(newline);
749
- } else {
750
- state.commands.push(' ');
751
- }
752
- }
753
- } else {
754
- state.commands.push(join);
755
- }
756
- }
757
-
758
- const p = node.arguments[i];
759
-
760
- handle(p, i === node.arguments.length - 1 ? final_state : child_state);
761
- }
762
-
763
- state.commands.push(close, ')');
764
-
765
- const multiline = child_state.multiline;
766
-
767
- if (multiline || final_state.multiline) {
768
- state.multiline = true;
769
- }
770
-
771
- if (multiline) {
772
- open.push(indent, newline);
773
- join.push(',', newline);
774
- close.push(dedent, newline);
775
- } else {
776
- join.push(', ');
777
- }
778
- },
779
-
780
- /**
781
- * @param {TSESTree.ClassDeclaration | TSESTree.ClassExpression} node
782
- * @param {State} state
783
- */
784
- 'ClassDeclaration|ClassExpression': (node, state) => {
785
- state.commands.push('class ');
786
-
787
- if (node.id) {
788
- handle(node.id, state);
789
- state.commands.push(' ');
790
- }
791
-
792
- if (node.superClass) {
793
- state.commands.push('extends ');
794
- handle(node.superClass, state);
795
- state.commands.push(' ');
796
- }
797
-
798
- if (node.implements) {
799
- state.commands.push('implements ');
800
- sequence(node.implements, state, false, handle_type_annotation);
801
- }
802
-
803
- handle(node.body, state);
804
- },
805
-
806
- /**
807
- * @param {TSESTree.ForInStatement | TSESTree.ForOfStatement} node
808
- * @param {State} state
809
- */
810
- 'ForInStatement|ForOfStatement': (node, state) => {
811
- state.commands.push('for ');
812
- if (node.type === 'ForOfStatement' && node.await) state.commands.push('await ');
813
- state.commands.push('(');
814
-
815
- if (node.left.type === 'VariableDeclaration') {
816
- handle_var_declaration(node.left, state);
817
- } else {
818
- handle(node.left, state);
819
- }
820
-
821
- state.commands.push(node.type === 'ForInStatement' ? ` in ` : ` of `);
822
- handle(node.right, state);
823
- state.commands.push(') ');
824
- handle(node.body, state);
825
- },
826
-
827
- /**
828
- * @param {TSESTree.FunctionDeclaration | TSESTree.FunctionExpression} node
829
- * @param {State} state
830
- */
831
- 'FunctionDeclaration|FunctionExpression': (node, state) => {
832
- if (node.async) state.commands.push('async ');
833
- state.commands.push(node.generator ? 'function* ' : 'function ');
834
- if (node.id) handle(node.id, state);
835
-
836
- if (node.typeParameters) {
837
- handle_type_annotation(node.typeParameters, state);
838
- }
839
-
840
- state.commands.push('(');
841
- sequence(node.params, state, false, handle);
842
- state.commands.push(')');
843
-
844
- if (node.returnType) handle_type_annotation(node.returnType, state);
845
-
846
- state.commands.push(' ');
847
-
848
- handle(node.body, state);
849
- },
850
-
851
- /**
852
- * @param {TSESTree.RestElement | TSESTree.SpreadElement} node
853
- * @param {State} state
854
- */
855
- 'RestElement|SpreadElement': (node, state) => {
856
- state.commands.push('...');
857
- handle(node.argument, state);
858
-
859
- // @ts-expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
860
- if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state);
861
- }
862
- };
863
-
864
- /** @type {Handlers} */
865
- const handlers = {
866
- ArrayExpression: shared['ArrayExpression|ArrayPattern'],
867
-
868
- ArrayPattern: shared['ArrayExpression|ArrayPattern'],
869
-
870
- ArrowFunctionExpression: (node, state) => {
871
- if (node.async) state.commands.push('async ');
872
-
873
- state.commands.push('(');
874
- sequence(node.params, state, false, handle);
875
- state.commands.push(') => ');
876
-
877
- if (
878
- node.body.type === 'ObjectExpression' ||
879
- (node.body.type === 'AssignmentExpression' && node.body.left.type === 'ObjectPattern') ||
880
- (node.body.type === 'LogicalExpression' && node.body.left.type === 'ObjectExpression') ||
881
- (node.body.type === 'ConditionalExpression' && node.body.test.type === 'ObjectExpression')
882
- ) {
883
- state.commands.push('(');
884
- handle(node.body, state);
885
- state.commands.push(')');
886
- } else {
887
- handle(node.body, state);
888
- }
889
- },
890
-
891
- AssignmentExpression(node, state) {
892
- handle(node.left, state);
893
- state.commands.push(` ${node.operator} `);
894
- handle(node.right, state);
895
- },
896
-
897
- AssignmentPattern(node, state) {
898
- handle(node.left, state);
899
- state.commands.push(' = ');
900
- handle(node.right, state);
901
- },
902
-
903
- AwaitExpression(node, state) {
904
- if (node.argument) {
905
- const precedence = EXPRESSIONS_PRECEDENCE[node.argument.type];
906
-
907
- if (precedence && precedence < EXPRESSIONS_PRECEDENCE.AwaitExpression) {
908
- state.commands.push('await (');
909
- handle(node.argument, state);
910
- state.commands.push(')');
911
- } else {
912
- state.commands.push('await ');
913
- handle(node.argument, state);
914
- }
915
- } else {
916
- state.commands.push('await');
917
- }
918
- },
919
-
920
- BinaryExpression: shared['BinaryExpression|LogicalExpression'],
921
-
922
- BlockStatement: shared['BlockStatement|ClassBody'],
923
-
924
- BreakStatement(node, state) {
925
- if (node.label) {
926
- state.commands.push('break ');
927
- handle(node.label, state);
928
- state.commands.push(';');
929
- } else {
930
- state.commands.push('break;');
931
- }
932
- },
933
-
934
- CallExpression: shared['CallExpression|NewExpression'],
935
-
936
- ChainExpression(node, state) {
937
- handle(node.expression, state);
938
- },
939
-
940
- ClassBody: shared['BlockStatement|ClassBody'],
941
-
942
- ClassDeclaration: shared['ClassDeclaration|ClassExpression'],
943
-
944
- ClassExpression: shared['ClassDeclaration|ClassExpression'],
945
-
946
- ConditionalExpression(node, state) {
947
- if (EXPRESSIONS_PRECEDENCE[node.test.type] > EXPRESSIONS_PRECEDENCE.ConditionalExpression) {
948
- handle(node.test, state);
949
- } else {
950
- state.commands.push('(');
951
- handle(node.test, state);
952
- state.commands.push(')');
953
- }
954
-
955
- const if_true = create_sequence();
956
- const if_false = create_sequence();
957
-
958
- const child_state = { ...state, multiline: false };
959
-
960
- state.commands.push(if_true);
961
- handle(node.consequent, child_state);
962
- state.commands.push(if_false);
963
- handle(node.alternate, child_state);
964
-
965
- const multiline = child_state.multiline;
966
-
967
- if (multiline) {
968
- if_true.push(indent, newline, '? ');
969
- if_false.push(newline, ': ');
970
- state.commands.push(dedent);
971
- } else {
972
- if_true.push(' ? ');
973
- if_false.push(' : ');
974
- }
975
- },
976
-
977
- ContinueStatement(node, state) {
978
- if (node.label) {
979
- state.commands.push('continue ');
980
- handle(node.label, state);
981
- state.commands.push(';');
982
- } else {
983
- state.commands.push('continue;');
984
- }
985
- },
986
-
987
- DebuggerStatement(node, state) {
988
- state.commands.push(c('debugger', node), ';');
989
- },
990
-
991
- Decorator(node, state) {
992
- state.commands.push('@');
993
- handle(node.expression, state);
994
- state.commands.push(newline);
995
- },
996
-
997
- DoWhileStatement(node, state) {
998
- state.commands.push('do ');
999
- handle(node.body, state);
1000
- state.commands.push(' while (');
1001
- handle(node.test, state);
1002
- state.commands.push(');');
1003
- },
1004
-
1005
- EmptyStatement(node, state) {
1006
- state.commands.push(';');
1007
- },
1008
-
1009
- ExportAllDeclaration(node, state) {
1010
- state.commands.push('export * ');
1011
- if (node.exported) {
1012
- state.commands.push('as ');
1013
- handle(node.exported, state);
1014
- }
1015
- state.commands.push(' from ');
1016
- handle(node.source, state);
1017
- state.commands.push(';');
1018
- },
1019
-
1020
- ExportDefaultDeclaration(node, state) {
1021
- state.commands.push('export default ');
1022
-
1023
- handle(node.declaration, state);
1024
-
1025
- if (node.declaration.type !== 'FunctionDeclaration') {
1026
- state.commands.push(';');
1027
- }
1028
- },
1029
-
1030
- ExportNamedDeclaration(node, state) {
1031
- state.commands.push('export ');
1032
-
1033
- if (node.declaration) {
1034
- handle(node.declaration, state);
1035
- return;
1036
- }
1037
-
1038
- state.commands.push('{');
1039
- sequence(node.specifiers, state, true, (s, state) => {
1040
- handle(s.local, state);
1041
-
1042
- if (s.local.name !== s.exported.name) {
1043
- state.commands.push(' as ');
1044
- handle(s.exported, state);
1045
- }
1046
- });
1047
- state.commands.push('}');
1048
-
1049
- if (node.source) {
1050
- state.commands.push(' from ');
1051
- handle(node.source, state);
1052
- }
1053
-
1054
- state.commands.push(';');
1055
- },
1056
-
1057
- ExpressionStatement(node, state) {
1058
- if (
1059
- node.expression.type === 'ObjectExpression' ||
1060
- (node.expression.type === 'AssignmentExpression' &&
1061
- node.expression.left.type === 'ObjectPattern') ||
1062
- node.expression.type === 'FunctionExpression'
1063
- ) {
1064
- // is an AssignmentExpression to an ObjectPattern
1065
- state.commands.push('(');
1066
- handle(node.expression, state);
1067
- state.commands.push(');');
1068
- return;
1069
- }
1070
-
1071
- handle(node.expression, state);
1072
- state.commands.push(';');
1073
- },
1074
-
1075
- ForStatement: (node, state) => {
1076
- state.commands.push('for (');
1077
-
1078
- if (node.init) {
1079
- if (node.init.type === 'VariableDeclaration') {
1080
- handle_var_declaration(node.init, state);
1081
- } else {
1082
- handle(node.init, state);
1083
- }
1084
- }
1085
-
1086
- state.commands.push('; ');
1087
- if (node.test) handle(node.test, state);
1088
- state.commands.push('; ');
1089
- if (node.update) handle(node.update, state);
1090
-
1091
- state.commands.push(') ');
1092
- handle(node.body, state);
1093
- },
1094
-
1095
- ForInStatement: shared['ForInStatement|ForOfStatement'],
1096
-
1097
- ForOfStatement: shared['ForInStatement|ForOfStatement'],
1098
-
1099
- FunctionDeclaration: shared['FunctionDeclaration|FunctionExpression'],
1100
-
1101
- FunctionExpression: shared['FunctionDeclaration|FunctionExpression'],
1102
-
1103
- Identifier(node, state) {
1104
- let name = node.name;
1105
- state.commands.push(c(name, node));
1106
-
1107
- if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state);
1108
- },
1109
-
1110
- IfStatement(node, state) {
1111
- state.commands.push('if (');
1112
- handle(node.test, state);
1113
- state.commands.push(') ');
1114
- handle(node.consequent, state);
1115
-
1116
- if (node.alternate) {
1117
- state.commands.push(' else ');
1118
- handle(node.alternate, state);
1119
- }
1120
- },
1121
-
1122
- ImportDeclaration(node, state) {
1123
- if (node.specifiers.length === 0) {
1124
- state.commands.push('import ');
1125
- handle(node.source, state);
1126
- state.commands.push(';');
1127
- return;
1128
- }
1129
-
1130
- /** @type {TSESTree.ImportNamespaceSpecifier | null} */
1131
- let namespace_specifier = null;
1132
-
1133
- /** @type {TSESTree.ImportDefaultSpecifier | null} */
1134
- let default_specifier = null;
1135
-
1136
- /** @type {TSESTree.ImportSpecifier[]} */
1137
- const named_specifiers = [];
1138
-
1139
- for (const s of node.specifiers) {
1140
- if (s.type === 'ImportNamespaceSpecifier') {
1141
- namespace_specifier = s;
1142
- } else if (s.type === 'ImportDefaultSpecifier') {
1143
- default_specifier = s;
1144
- } else {
1145
- named_specifiers.push(s);
1146
- }
1147
- }
1148
-
1149
- state.commands.push('import ');
1150
- if (node.importKind == 'type') state.commands.push('type ');
1151
-
1152
- if (default_specifier) {
1153
- state.commands.push(c(default_specifier.local.name, default_specifier));
1154
- if (namespace_specifier || named_specifiers.length > 0) state.commands.push(', ');
1155
- }
1156
-
1157
- if (namespace_specifier) {
1158
- state.commands.push(c('* as ' + namespace_specifier.local.name, namespace_specifier));
1159
- }
1160
-
1161
- if (named_specifiers.length > 0) {
1162
- state.commands.push('{');
1163
- sequence(named_specifiers, state, true, (s, state) => {
1164
- if (s.local.name !== s.imported.name) {
1165
- handle(s.imported, state);
1166
- state.commands.push(' as ');
1167
- }
1168
-
1169
- if (s.importKind == 'type') state.commands.push('type ');
1170
- handle(s.local, state);
1171
- });
1172
- state.commands.push('}');
1173
- }
1174
-
1175
- state.commands.push(' from ');
1176
- handle(node.source, state);
1177
- if (node.attributes && node.attributes.length > 0) {
1178
- state.commands.push(' with { ');
1179
- for (let index = 0; index < node.attributes.length; index++) {
1180
- const { key, value } = node.attributes[index];
1181
- handle(key, state);
1182
- state.commands.push(': ');
1183
- handle(value, state);
1184
- if (index + 1 !== node.attributes.length) {
1185
- state.commands.push(', ');
1186
- }
1187
- }
1188
- state.commands.push(' }');
1189
- }
1190
- state.commands.push(';');
1191
- },
1192
-
1193
- ImportExpression(node, state) {
1194
- state.commands.push('import(');
1195
- handle(node.source, state);
1196
- //@ts-expect-error for some reason the types haven't been updated
1197
- if (node.arguments) {
1198
- //@ts-expect-error
1199
- for (let index = 0; index < node.arguments.length; index++) {
1200
- state.commands.push(', ');
1201
- //@ts-expect-error
1202
- handle(node.arguments[index], state);
1203
- }
1204
- }
1205
- state.commands.push(')');
1206
- },
1207
-
1208
- LabeledStatement(node, state) {
1209
- handle(node.label, state);
1210
- state.commands.push(': ');
1211
- handle(node.body, state);
1212
- },
1213
-
1214
- Literal(node, state) {
1215
- // TODO do we need to handle weird unicode characters somehow?
1216
- // str.replace(/\\u(\d{4})/g, (m, n) => String.fromCharCode(+n))
1217
-
1218
- const value =
1219
- node.raw ||
1220
- (typeof node.value === 'string' ? quote(node.value, state.quote) : String(node.value));
1221
-
1222
- state.commands.push(c(value, node));
1223
- },
1224
-
1225
- LogicalExpression: shared['BinaryExpression|LogicalExpression'],
1226
-
1227
- MemberExpression(node, state) {
1228
- if (EXPRESSIONS_PRECEDENCE[node.object.type] < EXPRESSIONS_PRECEDENCE.MemberExpression) {
1229
- state.commands.push('(');
1230
- handle(node.object, state);
1231
- state.commands.push(')');
1232
- } else {
1233
- handle(node.object, state);
1234
- }
1235
-
1236
- if (node.computed) {
1237
- if (node.optional) {
1238
- state.commands.push('?.');
1239
- }
1240
- state.commands.push('[');
1241
- handle(node.property, state);
1242
- state.commands.push(']');
1243
- } else {
1244
- state.commands.push(node.optional ? '?.' : '.');
1245
- handle(node.property, state);
1246
- }
1247
- },
1248
-
1249
- MetaProperty(node, state) {
1250
- handle(node.meta, state);
1251
- state.commands.push('.');
1252
- handle(node.property, state);
1253
- },
1254
-
1255
- MethodDefinition(node, state) {
1256
- if (node.decorators) {
1257
- for (const decorator of node.decorators) {
1258
- handle(decorator, state);
1259
- }
1260
- }
1261
-
1262
- if (node.static) {
1263
- state.commands.push('static ');
1264
- }
1265
-
1266
- if (node.kind === 'get' || node.kind === 'set') {
1267
- // Getter or setter
1268
- state.commands.push(node.kind + ' ');
1269
- }
1270
-
1271
- if (node.value.async) {
1272
- state.commands.push('async ');
1273
- }
1274
-
1275
- if (node.value.generator) {
1276
- state.commands.push('*');
1277
- }
1278
-
1279
- if (node.computed) state.commands.push('[');
1280
- handle(node.key, state);
1281
- if (node.computed) state.commands.push(']');
1282
-
1283
- state.commands.push('(');
1284
- sequence(node.value.params, state, false, handle);
1285
- state.commands.push(')');
1286
-
1287
- if (node.value.returnType) handle_type_annotation(node.value.returnType, state);
1288
-
1289
- state.commands.push(' ');
1290
-
1291
- if (node.value.body) handle(node.value.body, state);
1292
- },
1293
-
1294
- NewExpression: shared['CallExpression|NewExpression'],
1295
-
1296
- ObjectExpression(node, state) {
1297
- state.commands.push('{');
1298
- sequence(node.properties, state, true, (p, state) => {
1299
- if (p.type === 'Property' && p.value.type === 'FunctionExpression') {
1300
- const fn = /** @type {TSESTree.FunctionExpression} */ (p.value);
1301
-
1302
- if (p.kind === 'get' || p.kind === 'set') {
1303
- state.commands.push(p.kind + ' ');
1304
- } else {
1305
- if (fn.async) state.commands.push('async ');
1306
- if (fn.generator) state.commands.push('*');
1307
- }
1308
-
1309
- if (p.computed) state.commands.push('[');
1310
- handle(p.key, state);
1311
- if (p.computed) state.commands.push(']');
1312
-
1313
- state.commands.push('(');
1314
- sequence(fn.params, state, false, handle);
1315
- state.commands.push(') ');
1316
-
1317
- handle(fn.body, state);
1318
- } else {
1319
- handle(p, state);
1320
- }
1321
- });
1322
- state.commands.push('}');
1323
- },
1324
-
1325
- ObjectPattern(node, state) {
1326
- state.commands.push('{');
1327
- sequence(node.properties, state, true, handle);
1328
- state.commands.push('}');
1329
-
1330
- if (node.typeAnnotation) handle_type_annotation(node.typeAnnotation, state);
1331
- },
1332
-
1333
- // @ts-expect-error this isn't a real node type, but Acorn produces it
1334
- ParenthesizedExpression(node, state) {
1335
- return handle(node.expression, state);
1336
- },
1337
-
1338
- PrivateIdentifier(node, state) {
1339
- state.commands.push('#', c(node.name, node));
1340
- },
1341
-
1342
- Program(node, state) {
1343
- handle_body(node.body, state);
1344
- },
1345
-
1346
- Property(node, state) {
1347
- const value = node.value.type === 'AssignmentPattern' ? node.value.left : node.value;
1348
-
1349
- const shorthand =
1350
- !node.computed &&
1351
- node.kind === 'init' &&
1352
- node.key.type === 'Identifier' &&
1353
- value.type === 'Identifier' &&
1354
- node.key.name === value.name;
1355
-
1356
- if (shorthand) {
1357
- handle(node.value, state);
1358
- return;
1359
- }
1360
-
1361
- if (node.computed) state.commands.push('[');
1362
- handle(node.key, state);
1363
- state.commands.push(node.computed ? ']: ' : ': ');
1364
- handle(node.value, state);
1365
- },
1366
-
1367
- PropertyDefinition(node, state) {
1368
- if (node.decorators) {
1369
- for (const decorator of node.decorators) {
1370
- handle(decorator, state);
1371
- }
1372
- }
1373
-
1374
- if (node.accessibility) {
1375
- state.commands.push(node.accessibility, ' ');
1376
- }
1377
-
1378
- if (node.static) {
1379
- state.commands.push('static ');
1380
- }
1381
-
1382
- if (node.computed) {
1383
- state.commands.push('[');
1384
- handle(node.key, state);
1385
- state.commands.push(']');
1386
- } else {
1387
- handle(node.key, state);
1388
- }
1389
-
1390
- if (node.typeAnnotation) {
1391
- state.commands.push(': ');
1392
- handle_type_annotation(node.typeAnnotation.typeAnnotation, state);
1393
- }
1394
-
1395
- if (node.value) {
1396
- state.commands.push(' = ');
1397
-
1398
- handle(node.value, state);
1399
- }
1400
-
1401
- state.commands.push(';');
1402
- },
1403
-
1404
- RestElement: shared['RestElement|SpreadElement'],
1405
-
1406
- ReturnStatement(node, state) {
1407
- if (node.argument) {
1408
- const argumentWithComment = /** @type {NodeWithComments} */ (node.argument);
1409
- const contains_comment =
1410
- argumentWithComment.leadingComments &&
1411
- argumentWithComment.leadingComments.some((comment) => comment.type === 'Line');
1412
-
1413
- state.commands.push(contains_comment ? 'return (' : 'return ');
1414
- handle(node.argument, state);
1415
- state.commands.push(contains_comment ? ');' : ';');
1416
- } else {
1417
- state.commands.push('return;');
1418
- }
1419
- },
1420
-
1421
- SequenceExpression(node, state) {
1422
- state.commands.push('(');
1423
- sequence(node.expressions, state, false, handle);
1424
- state.commands.push(')');
1425
- },
1426
-
1427
- SpreadElement: shared['RestElement|SpreadElement'],
1428
-
1429
- StaticBlock(node, state) {
1430
- state.commands.push(indent, 'static {', newline);
1431
-
1432
- handle_body(node.body, state);
1433
-
1434
- state.commands.push(dedent, newline, '}');
1435
- },
1436
-
1437
- Super(node, state) {
1438
- state.commands.push(c('super', node));
1439
- },
1440
-
1441
- SwitchStatement(node, state) {
1442
- state.commands.push('switch (');
1443
- handle(node.discriminant, state);
1444
- state.commands.push(') {', indent);
1445
-
1446
- let first = true;
1447
-
1448
- for (const block of node.cases) {
1449
- if (!first) state.commands.push('\n');
1450
- first = false;
1451
-
1452
- if (block.test) {
1453
- state.commands.push(newline, `case `);
1454
- handle(block.test, state);
1455
- state.commands.push(':');
1456
- } else {
1457
- state.commands.push(newline, `default:`);
1458
- }
1459
-
1460
- state.commands.push(indent);
1461
-
1462
- for (const statement of block.consequent) {
1463
- state.commands.push(newline);
1464
- handle(statement, state);
1465
- }
1466
-
1467
- state.commands.push(dedent);
1468
- }
1469
-
1470
- state.commands.push(dedent, newline, `}`);
1471
- },
1472
-
1473
- TaggedTemplateExpression(node, state) {
1474
- handle(node.tag, state);
1475
- handle(node.quasi, state);
1476
- },
1477
-
1478
- TemplateLiteral(node, state) {
1479
- state.commands.push('`');
1480
-
1481
- const { quasis, expressions } = node;
1482
-
1483
- for (let i = 0; i < expressions.length; i++) {
1484
- const raw = quasis[i].value.raw;
1485
-
1486
- state.commands.push(raw, '${');
1487
- handle(expressions[i], state);
1488
- state.commands.push('}');
1489
-
1490
- if (/\n/.test(raw)) state.multiline = true;
1491
- }
1492
-
1493
- const raw = quasis[quasis.length - 1].value.raw;
1494
-
1495
- state.commands.push(raw, '`');
1496
- if (/\n/.test(raw)) state.multiline = true;
1497
- },
1498
-
1499
- ThisExpression(node, state) {
1500
- state.commands.push(c('this', node));
1501
- },
1502
-
1503
- ThrowStatement(node, state) {
1504
- state.commands.push('throw ');
1505
- if (node.argument) handle(node.argument, state);
1506
- state.commands.push(';');
1507
- },
1508
-
1509
- TryStatement(node, state) {
1510
- state.commands.push('try ');
1511
- handle(node.block, state);
1512
-
1513
- if (node.handler) {
1514
- if (node.handler.param) {
1515
- state.commands.push(' catch(');
1516
- handle(node.handler.param, state);
1517
- state.commands.push(') ');
1518
- } else {
1519
- state.commands.push(' catch ');
1520
- }
1521
-
1522
- handle(node.handler.body, state);
1523
- }
1524
-
1525
- if (node.finalizer) {
1526
- state.commands.push(' finally ');
1527
- handle(node.finalizer, state);
1528
- }
1529
- },
1530
-
1531
- TSAsExpression(node, state) {
1532
- if (node.expression) {
1533
- const needs_parens =
1534
- EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSAsExpression;
1535
-
1536
- if (needs_parens) {
1537
- state.commands.push('(');
1538
- handle(node.expression, state);
1539
- state.commands.push(')');
1540
- } else {
1541
- handle(node.expression, state);
1542
- }
1543
- }
1544
- state.commands.push(' as ');
1545
- handle_type_annotation(node.typeAnnotation, state);
1546
- },
1547
-
1548
- TSEnumDeclaration(node, state) {
1549
- state.commands.push('enum ');
1550
- handle(node.id, state);
1551
- state.commands.push(' {', indent, newline);
1552
- sequence(node.members, state, false, handle_type_annotation);
1553
- state.commands.push(dedent, newline, '}', newline);
1554
- },
1555
-
1556
- TSModuleBlock(node, state) {
1557
- state.commands.push(' {', indent, newline);
1558
- handle_body(node.body, state);
1559
- state.commands.push(dedent, newline, '}');
1560
- },
1561
-
1562
- TSModuleDeclaration(node, state) {
1563
- if (node.declare) state.commands.push('declare ');
1564
- else state.commands.push('namespace ');
1565
-
1566
- handle(node.id, state);
1567
-
1568
- if (!node.body) return;
1569
- handle(node.body, state);
1570
- },
1571
-
1572
- TSNonNullExpression(node, state) {
1573
- handle(node.expression, state);
1574
- state.commands.push('!');
1575
- },
1576
-
1577
- TSInterfaceBody(node, state) {
1578
- sequence(node.body, state, true, handle_type_annotation, ';');
1579
- },
1580
-
1581
- TSInterfaceDeclaration(node, state) {
1582
- state.commands.push('interface ');
1583
- handle(node.id, state);
1584
- if (node.typeParameters) handle_type_annotation(node.typeParameters, state);
1585
- if (node.extends) {
1586
- state.commands.push(' extends ');
1587
- sequence(node.extends, state, false, handle_type_annotation);
1588
- }
1589
- state.commands.push(' {');
1590
- handle(node.body, state);
1591
- state.commands.push('}');
1592
- },
1593
-
1594
- TSSatisfiesExpression(node, state) {
1595
- if (node.expression) {
1596
- const needs_parens =
1597
- EXPRESSIONS_PRECEDENCE[node.expression.type] < EXPRESSIONS_PRECEDENCE.TSSatisfiesExpression;
1598
-
1599
- if (needs_parens) {
1600
- state.commands.push('(');
1601
- handle(node.expression, state);
1602
- state.commands.push(')');
1603
- } else {
1604
- handle(node.expression, state);
1605
- }
1606
- }
1607
- state.commands.push(' satisfies ');
1608
- handle_type_annotation(node.typeAnnotation, state);
1609
- },
1610
-
1611
- TSTypeAliasDeclaration(node, state) {
1612
- state.commands.push('type ');
1613
- handle(node.id, state);
1614
- if (node.typeParameters) handle_type_annotation(node.typeParameters, state);
1615
- state.commands.push(' = ');
1616
- handle_type_annotation(node.typeAnnotation, state);
1617
- state.commands.push(';');
1618
- },
1619
-
1620
- TSQualifiedName(node, state) {
1621
- handle(node.left, state);
1622
- state.commands.push('.');
1623
- handle(node.right, state);
1624
- },
1625
-
1626
- UnaryExpression(node, state) {
1627
- state.commands.push(node.operator);
1628
-
1629
- if (node.operator.length > 1) {
1630
- state.commands.push(' ');
1631
- }
1632
-
1633
- if (EXPRESSIONS_PRECEDENCE[node.argument.type] < EXPRESSIONS_PRECEDENCE.UnaryExpression) {
1634
- state.commands.push('(');
1635
- handle(node.argument, state);
1636
- state.commands.push(')');
1637
- } else {
1638
- handle(node.argument, state);
1639
- }
1640
- },
1641
-
1642
- UpdateExpression(node, state) {
1643
- if (node.prefix) {
1644
- state.commands.push(node.operator);
1645
- handle(node.argument, state);
1646
- } else {
1647
- handle(node.argument, state);
1648
- state.commands.push(node.operator);
1649
- }
1650
- },
1651
-
1652
- VariableDeclaration(node, state) {
1653
- handle_var_declaration(node, state);
1654
- state.commands.push(';');
1655
- },
1656
-
1657
- VariableDeclarator(node, state) {
1658
- handle(node.id, state);
1659
-
1660
- if (node.init) {
1661
- state.commands.push(' = ');
1662
- handle(node.init, state);
1663
- }
1664
- },
1665
-
1666
- WhileStatement(node, state) {
1667
- state.commands.push('while (');
1668
- handle(node.test, state);
1669
- state.commands.push(') ');
1670
- handle(node.body, state);
1671
- },
1672
-
1673
- WithStatement(node, state) {
1674
- state.commands.push('with (');
1675
- handle(node.object, state);
1676
- state.commands.push(') ');
1677
- handle(node.body, state);
1678
- },
1679
-
1680
- YieldExpression(node, state) {
1681
- if (node.argument) {
1682
- state.commands.push(node.delegate ? `yield* ` : `yield `);
1683
- handle(node.argument, state);
1684
- } else {
1685
- state.commands.push(node.delegate ? `yield*` : `yield`);
1686
- }
1687
- }
1688
- };