flow-api-translator 0.20.1 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2030 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
+ * @format
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ import type {ObjectWithLoc} from 'hermes-estree';
14
+ import type {TranslationOptions} from './utils/TranslationUtils';
15
+
16
+ import * as FlowESTree from 'hermes-estree';
17
+ import * as TSESTree from './utils/ts-estree-ast-types';
18
+ import {makeCommentOwnLine as makeCommentOwnLineOriginal} from 'hermes-transform';
19
+ import {
20
+ buildCodeFrame,
21
+ translationError as translationErrorBase,
22
+ unexpectedTranslationError as unexpectedTranslationErrorBase,
23
+ } from './utils/ErrorUtils';
24
+ import {EOL} from 'os';
25
+
26
+ const DUMMY_LOC: FlowESTree.SourceLocation = (null: $FlowFixMe);
27
+ const DUMMY_RANGE: [number, number] = [0, 0];
28
+ const DUMMY_PARENT: $FlowFixMe = null;
29
+ const DUMMY_COMMON = {
30
+ loc: DUMMY_LOC,
31
+ range: DUMMY_RANGE,
32
+ parent: DUMMY_PARENT,
33
+ };
34
+
35
+ function constructFlowNode<T: FlowESTree.BaseNode>(
36
+ node: $Diff<T, FlowESTree.BaseNode>,
37
+ ): T {
38
+ return {
39
+ ...node,
40
+ ...DUMMY_COMMON,
41
+ };
42
+ }
43
+
44
+ const makeCommentOwnLine =
45
+ // $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
46
+ (makeCommentOwnLineOriginal: (string, mixed) => string);
47
+
48
+ export function TSDefToFlowDef(
49
+ originalCode: string,
50
+ ast: TSESTree.Program,
51
+ opts: TranslationOptions,
52
+ ): [FlowESTree.Program, string] {
53
+ const flowBody: Array<FlowESTree.Statement | FlowESTree.ModuleDeclaration> =
54
+ [];
55
+ const flowProgram: FlowESTree.Program = {
56
+ ...DUMMY_COMMON,
57
+ type: 'Program',
58
+ body: flowBody,
59
+ comments: [],
60
+ sourceType: ast.sourceType,
61
+ interpreter: null,
62
+ tokens: [],
63
+ loc: ast.loc,
64
+ docblock: {
65
+ comment: {...DUMMY_COMMON, type: 'Block', value: ''},
66
+ directives: {flow: []},
67
+ },
68
+ };
69
+
70
+ const [transform, code] = getTransforms(originalCode, opts);
71
+
72
+ for (const node of ast.body) {
73
+ const result = transform.AllStatement(node);
74
+ flowBody.push(...(Array.isArray(result) ? result : [result]));
75
+ }
76
+
77
+ return [flowProgram, code];
78
+ }
79
+
80
+ // Note: The implementation here is still in early stage. If something is not supported, it doesn't
81
+ // necessarily mean that it cannot be. It might just mean that it's not priortized yet. If something
82
+ // is translated in way that is wrong, then it's likely wrong.
83
+ const getTransforms = (originalCode: string, opts: TranslationOptions) => {
84
+ let code = originalCode;
85
+ function translationError(node: ObjectWithLoc, message: string) {
86
+ return translationErrorBase(node, message, {code});
87
+ }
88
+ function unexpectedTranslationError(node: ObjectWithLoc, message: string) {
89
+ return unexpectedTranslationErrorBase(node, message, {code});
90
+ }
91
+ function unsupportedFeatureMessage(thing: string) {
92
+ return `Unsupported feature: Translating "${thing}" is currently not supported.`;
93
+ }
94
+ function buildCodeFrameForComment(node: ObjectWithLoc, message: string) {
95
+ return buildCodeFrame(node, message, code, false);
96
+ }
97
+ function addErrorComment(node: FlowESTree.ESNode, message: string): void {
98
+ const comment = {
99
+ type: 'Block',
100
+ loc: DUMMY_LOC,
101
+ value: `*${EOL} * ${message.replace(
102
+ new RegExp(EOL, 'g'),
103
+ `${EOL} * `,
104
+ )}${EOL}*`,
105
+ leading: true,
106
+ printed: false,
107
+ };
108
+
109
+ code = makeCommentOwnLine(code, comment);
110
+
111
+ // $FlowExpectedError[prop-missing]
112
+ // $FlowExpectedError[cannot-write]
113
+ node.comments ??= [];
114
+ // $FlowExpectedError[incompatible-cast]
115
+ (node.comments: Array<TSESTree.Comment>).push(comment);
116
+ }
117
+ function unsupportedAnnotation(
118
+ node: ObjectWithLoc,
119
+ thing: string,
120
+ ): FlowESTree.AnyTypeAnnotation {
121
+ const message = unsupportedFeatureMessage(thing);
122
+ if (opts.recoverFromErrors) {
123
+ const codeFrame = buildCodeFrameForComment(node, message);
124
+ const newNode: FlowESTree.AnyTypeAnnotation = {
125
+ ...DUMMY_COMMON,
126
+ type: 'AnyTypeAnnotation',
127
+ };
128
+ addErrorComment(newNode, codeFrame);
129
+ return newNode;
130
+ }
131
+
132
+ throw translationError(node, message);
133
+ }
134
+ function unsupportedDeclaration(
135
+ node: ObjectWithLoc,
136
+ thing: string,
137
+ id: TSESTree.Identifier,
138
+ typeParameters: TSESTree.TSTypeParameterDeclaration | null = null,
139
+ ): FlowESTree.TypeAlias {
140
+ const message = unsupportedFeatureMessage(thing);
141
+ if (opts.recoverFromErrors) {
142
+ const codeFrame = buildCodeFrameForComment(node, message);
143
+ const newNode: FlowESTree.TypeAlias = {
144
+ ...DUMMY_COMMON,
145
+ type: 'TypeAlias',
146
+ id: Transform.Identifier(id, false),
147
+ right: {
148
+ ...DUMMY_COMMON,
149
+ type: 'AnyTypeAnnotation',
150
+ },
151
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(typeParameters),
152
+ };
153
+ addErrorComment(newNode, codeFrame);
154
+ return newNode;
155
+ }
156
+
157
+ throw translationError(node, message);
158
+ }
159
+
160
+ class Transform {
161
+ static BlockStatement(
162
+ node: TSESTree.BlockStatement,
163
+ ): FlowESTree.BlockStatement {
164
+ return constructFlowNode<FlowESTree.BlockStatement>({
165
+ type: 'BlockStatement',
166
+ body: node.body.flatMap(node => Transform.Statement(node)),
167
+ });
168
+ }
169
+
170
+ static ClassDeclarationWithName(
171
+ node: TSESTree.ClassDeclarationWithName,
172
+ ): FlowESTree.DeclareClass {
173
+ return constructFlowNode<FlowESTree.DeclareClass>({
174
+ type: 'DeclareClass',
175
+ id: Transform.Identifier(node.id),
176
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(
177
+ node.typeParameters,
178
+ ),
179
+ implements: (node.implements || []).map(impl =>
180
+ Transform.ClassImplements(impl),
181
+ ),
182
+ extends: Transform.ClassDeclarationSuperClass(
183
+ node.superClass,
184
+ node.superTypeParameters,
185
+ ),
186
+ mixins: [],
187
+ body: Transform.ClassDeclarationBody(node.body),
188
+ });
189
+ }
190
+
191
+ static ClassDeclarationBody({
192
+ body,
193
+ }: TSESTree.ClassBody): FlowESTree.ObjectTypeAnnotation {
194
+ const properties: Array<FlowESTree.ObjectTypeProperty> = [];
195
+ const indexers: Array<FlowESTree.ObjectTypeIndexer> = [];
196
+ for (const classItem of body) {
197
+ switch (classItem.type) {
198
+ case 'StaticBlock':
199
+ break;
200
+ case 'TSIndexSignature':
201
+ break;
202
+ case 'TSAbstractPropertyDefinition':
203
+ case 'PropertyDefinition':
204
+ // $FlowFixMe[incompatible-call] ambiguous node
205
+ Transform._translateIntoObjectProp(classItem, properties, indexers);
206
+ break;
207
+ case 'MethodDefinition':
208
+ case 'TSAbstractMethodDefinition':
209
+ // $FlowFixMe[incompatible-call] ambiguous node
210
+ Transform._translateIntoObjectMethod(classItem, properties);
211
+ break;
212
+ }
213
+ }
214
+ return constructFlowNode<FlowESTree.ObjectTypeAnnotation>({
215
+ type: 'ObjectTypeAnnotation',
216
+ properties,
217
+ indexers,
218
+ callProperties: [],
219
+ internalSlots: [],
220
+ exact: false,
221
+ inexact: false,
222
+ });
223
+ }
224
+
225
+ static ClassDeclarationSuperClass(
226
+ superClass: ?TSESTree.LeftHandSideExpression,
227
+ superTypeParameters: ?TSESTree.TSTypeParameterInstantiation,
228
+ ): [FlowESTree.InterfaceExtends] | [] {
229
+ if (superClass == null) {
230
+ return [];
231
+ }
232
+ const id = Transform._expressionToIdOrQualifiedTypeId(
233
+ superClass,
234
+ 'superClass',
235
+ );
236
+ return [
237
+ constructFlowNode<FlowESTree.InterfaceExtends>({
238
+ type: 'InterfaceExtends',
239
+ id,
240
+ typeParameters:
241
+ Transform.TSTypeParameterInstantiationOpt(superTypeParameters),
242
+ }),
243
+ ];
244
+ }
245
+
246
+ static ClassImplements(
247
+ node: TSESTree.TSClassImplements,
248
+ ): FlowESTree.ClassImplements {
249
+ if (node.expression.type !== 'Identifier') {
250
+ throw unexpectedTranslationError(
251
+ node,
252
+ 'Expected expression to be an Identifier',
253
+ );
254
+ }
255
+ return constructFlowNode<FlowESTree.ClassImplements>({
256
+ type: 'ClassImplements',
257
+ id: Transform.Identifier(node.expression),
258
+ typeParameters: Transform.TSTypeParameterInstantiationOpt(
259
+ node.typeParameters,
260
+ ),
261
+ });
262
+ }
263
+
264
+ static DebuggerStatement(): FlowESTree.DebuggerStatement {
265
+ return constructFlowNode<FlowESTree.DebuggerStatement>({
266
+ type: 'DebuggerStatement',
267
+ });
268
+ }
269
+
270
+ static EntityNameToTypeIdentifier(
271
+ node: TSESTree.EntityName,
272
+ ): FlowESTree.Identifier | FlowESTree.QualifiedTypeIdentifier {
273
+ switch (node.type) {
274
+ case 'Identifier':
275
+ return Transform.Identifier(node);
276
+ case 'TSQualifiedName':
277
+ return Transform.TSQualifiedNameToQualifiedTypeIdentifier(node);
278
+ case 'ThisExpression':
279
+ return constructFlowNode<FlowESTree.Identifier>({
280
+ type: 'Identifier',
281
+ name: 'this',
282
+ typeAnnotation: null,
283
+ optional: false,
284
+ });
285
+ }
286
+ }
287
+
288
+ static EntityNameToTypeofIdentifier(
289
+ node: TSESTree.EntityName,
290
+ ): FlowESTree.Identifier | FlowESTree.QualifiedTypeofIdentifier {
291
+ switch (node.type) {
292
+ case 'Identifier':
293
+ return Transform.Identifier(node);
294
+ case 'TSQualifiedName':
295
+ return Transform.TSQualifiedNameToQualifiedTypeofIdentifier(node);
296
+ case 'ThisExpression':
297
+ return constructFlowNode<FlowESTree.Identifier>({
298
+ type: 'Identifier',
299
+ name: 'this',
300
+ typeAnnotation: null,
301
+ optional: false,
302
+ });
303
+ }
304
+ }
305
+
306
+ static ExportAllDeclaration(
307
+ node: TSESTree.ExportAllDeclaration,
308
+ ): FlowESTree.ExportAllDeclaration {
309
+ return constructFlowNode<FlowESTree.ExportAllDeclaration>({
310
+ type: 'ExportAllDeclaration',
311
+ source: constructFlowNode<FlowESTree.StringLiteral>({
312
+ type: 'Literal',
313
+ literalType: 'string',
314
+ value: node.source.value,
315
+ raw: node.source.raw,
316
+ }),
317
+ assertions: [],
318
+ exportKind: node.exportKind,
319
+ exported:
320
+ node.exported != null ? Transform.Identifier(node.exported) : null,
321
+ });
322
+ }
323
+
324
+ static ExportDefaultDeclaration(
325
+ node: TSESTree.ExportDefaultDeclaration,
326
+ ): FlowESTree.DeclareExportDefaultDeclaration {
327
+ let declaration: FlowESTree.DeclareExportDefaultDeclaration['declaration'];
328
+ switch (node.declaration.type) {
329
+ case 'ClassDeclaration':
330
+ declaration = Transform.ClassDeclarationWithName(
331
+ // possibly missing id
332
+ (node.declaration: $FlowFixMe),
333
+ );
334
+ break;
335
+ case 'FunctionDeclaration':
336
+ declaration = Transform.FunctionDeclarationWithName(
337
+ // possibly missing id
338
+ (node.declaration: $FlowFixMe),
339
+ );
340
+ break;
341
+ case 'TSDeclareFunction':
342
+ declaration = Transform.TSDeclareFunction(node.declaration);
343
+ break;
344
+ case 'Identifier':
345
+ declaration = constructFlowNode<FlowESTree.TypeofTypeAnnotation>({
346
+ type: 'TypeofTypeAnnotation',
347
+ argument: Transform.Identifier(node.declaration),
348
+ });
349
+ break;
350
+ default:
351
+ throw translationError(
352
+ node.declaration,
353
+ `Unsupported export declaration: ${node.declaration.type}`,
354
+ );
355
+ }
356
+ return constructFlowNode<FlowESTree.DeclareExportDefaultDeclaration>({
357
+ type: 'DeclareExportDeclaration',
358
+ declaration,
359
+ default: true,
360
+ source: null,
361
+ specifiers: [],
362
+ });
363
+ }
364
+
365
+ static ExportNamedDeclaration(
366
+ node: TSESTree.ExportNamedDeclaration,
367
+ ):
368
+ | FlowESTree.ExportNamedDeclaration
369
+ | FlowESTree.DeclareExportDeclarationNamedWithDeclaration
370
+ | FlowESTree.DeclareExportDeclarationNamedWithSpecifiers
371
+ | $ReadOnlyArray<
372
+ | FlowESTree.DeclareExportDeclarationNamedWithDeclaration
373
+ | FlowESTree.TypeAlias
374
+ | FlowESTree.DeclareNamespace
375
+ | FlowESTree.DeclareModule
376
+ | FlowESTree.ExportNamedDeclaration,
377
+ > {
378
+ if (node.declaration == null) {
379
+ const source: FlowESTree.StringLiteral =
380
+ node.source == null
381
+ ? (null: $FlowFixMe)
382
+ : constructFlowNode<FlowESTree.StringLiteral>({
383
+ type: 'Literal',
384
+ literalType: 'string',
385
+ value: node.source.value,
386
+ raw: node.source.raw,
387
+ });
388
+ const specifiers = node.specifiers.map(specifier =>
389
+ constructFlowNode<FlowESTree.ExportSpecifier>({
390
+ type: 'ExportSpecifier',
391
+ local: Transform.Identifier(specifier.local),
392
+ exported: Transform.Identifier(specifier.exported),
393
+ }),
394
+ );
395
+ return constructFlowNode<FlowESTree.DeclareExportDeclarationNamedWithSpecifiers>(
396
+ {
397
+ type: 'DeclareExportDeclaration',
398
+ declaration: null,
399
+ default: false,
400
+ source,
401
+ specifiers,
402
+ },
403
+ );
404
+ }
405
+ switch (node.declaration.type) {
406
+ case 'ClassDeclaration':
407
+ return constructFlowNode<FlowESTree.DeclareExportDeclarationNamedWithDeclaration>(
408
+ {
409
+ type: 'DeclareExportDeclaration',
410
+ declaration: Transform.ClassDeclarationWithName(
411
+ // possibly missing id
412
+ (node.declaration: $FlowFixMe),
413
+ ),
414
+ default: false,
415
+ source: null,
416
+ specifiers: [],
417
+ },
418
+ );
419
+ case 'FunctionDeclaration':
420
+ return constructFlowNode<FlowESTree.DeclareExportDeclarationNamedWithDeclaration>(
421
+ {
422
+ type: 'DeclareExportDeclaration',
423
+ declaration: Transform.FunctionDeclarationWithName(
424
+ // possibly missing id
425
+ (node.declaration: $FlowFixMe),
426
+ ),
427
+ default: false,
428
+ source: null,
429
+ specifiers: [],
430
+ },
431
+ );
432
+ case 'TSDeclareFunction':
433
+ return constructFlowNode<FlowESTree.DeclareExportDeclarationNamedWithDeclaration>(
434
+ {
435
+ type: 'DeclareExportDeclaration',
436
+ declaration: Transform.TSDeclareFunction(node.declaration),
437
+ default: false,
438
+ source: null,
439
+ specifiers: [],
440
+ },
441
+ );
442
+ case 'TSEnumDeclaration':
443
+ throw translationError(
444
+ node.declaration,
445
+ `Unsupported export declaration: ${node.declaration.type}`,
446
+ );
447
+ case 'TSModuleDeclaration': {
448
+ const decl = Transform.TSModuleDeclaration(node.declaration);
449
+ if (decl.id.type !== 'Identifier') {
450
+ throw translationError(
451
+ decl.id,
452
+ `Unsupported module declaration id`,
453
+ );
454
+ }
455
+ return [
456
+ decl,
457
+ constructFlowNode<FlowESTree.ExportNamedDeclaration>({
458
+ type: 'ExportNamedDeclaration',
459
+ declaration: null,
460
+ source: null,
461
+ exportKind: 'value',
462
+ specifiers: [
463
+ constructFlowNode<FlowESTree.ExportSpecifier>({
464
+ type: 'ExportSpecifier',
465
+ local: decl.id,
466
+ exported: decl.id,
467
+ }),
468
+ ],
469
+ }),
470
+ ];
471
+ }
472
+ case 'TSInterfaceDeclaration': {
473
+ const decl = Transform.TSInterfaceDeclaration(node.declaration);
474
+ return constructFlowNode<FlowESTree.DeclareExportDeclarationNamedWithDeclaration>(
475
+ {
476
+ type: 'DeclareExportDeclaration',
477
+ declaration: constructFlowNode<FlowESTree.DeclareInterface>({
478
+ type: 'DeclareInterface',
479
+ id: decl.id,
480
+ typeParameters: decl.typeParameters,
481
+ body: decl.body,
482
+ extends: decl.extends,
483
+ }),
484
+ default: false,
485
+ source: null,
486
+ specifiers: [],
487
+ },
488
+ );
489
+ }
490
+ case 'TSTypeAliasDeclaration': {
491
+ const decl = Transform.TSTypeAliasDeclaration(node.declaration);
492
+ return constructFlowNode<FlowESTree.ExportNamedDeclaration>({
493
+ type: 'ExportNamedDeclaration',
494
+ declaration: decl,
495
+ source: null,
496
+ exportKind: 'type',
497
+ specifiers: [],
498
+ });
499
+ }
500
+ case 'VariableDeclaration': {
501
+ return Transform.VariableDeclaration(node.declaration).map(
502
+ declaration =>
503
+ constructFlowNode<FlowESTree.DeclareExportDeclarationNamedWithDeclaration>(
504
+ {
505
+ type: 'DeclareExportDeclaration',
506
+ declaration,
507
+ default: false,
508
+ source: null,
509
+ specifiers: [],
510
+ },
511
+ ),
512
+ );
513
+ }
514
+ }
515
+ }
516
+
517
+ static FunctionDeclarationWithName(
518
+ node: TSESTree.FunctionDeclarationWithName,
519
+ ): FlowESTree.DeclareFunction {
520
+ const {thisParam, restParam, params} =
521
+ Transform._partitionAndTranslateTSFunctionParams(node.params);
522
+ const fnAnnot = constructFlowNode<FlowESTree.FunctionTypeAnnotation>({
523
+ type: 'FunctionTypeAnnotation',
524
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(
525
+ node.typeParameters,
526
+ ),
527
+ params,
528
+ rest: restParam,
529
+ returnType:
530
+ node.returnType?.typeAnnotation == null
531
+ ? unsupportedAnnotation(node, 'missing return type')
532
+ : Transform.TSTypeAnnotation(node.returnType.typeAnnotation),
533
+ this: thisParam,
534
+ });
535
+ return constructFlowNode<FlowESTree.DeclareFunction>({
536
+ type: 'DeclareFunction',
537
+ id: {
538
+ ...DUMMY_COMMON,
539
+ type: 'Identifier',
540
+ name: node.id.name,
541
+ typeAnnotation: {
542
+ ...DUMMY_COMMON,
543
+ type: 'TypeAnnotation',
544
+ typeAnnotation: fnAnnot,
545
+ },
546
+ optional: false,
547
+ },
548
+ predicate: null,
549
+ });
550
+ }
551
+
552
+ static Identifier(
553
+ node: TSESTree.Identifier,
554
+ optional?: boolean,
555
+ ): FlowESTree.Identifier {
556
+ return constructFlowNode<FlowESTree.Identifier>({
557
+ type: 'Identifier',
558
+ name: node.name,
559
+ typeAnnotation:
560
+ node.typeAnnotation != null
561
+ ? Transform.TSTypeAnnotationNode(node.typeAnnotation)
562
+ : null,
563
+ optional: Boolean(optional ?? node.optional),
564
+ });
565
+ }
566
+
567
+ static ImportDeclaration(
568
+ node: TSESTree.ImportDeclaration,
569
+ ): FlowESTree.ImportDeclaration {
570
+ const specifiers = node.specifiers.map(specifier => {
571
+ switch (specifier.type) {
572
+ case 'ImportNamespaceSpecifier':
573
+ return constructFlowNode<FlowESTree.ImportNamespaceSpecifier>({
574
+ type: 'ImportNamespaceSpecifier',
575
+ local: Transform.Identifier(specifier.local),
576
+ });
577
+ case 'ImportDefaultSpecifier':
578
+ return constructFlowNode<FlowESTree.ImportDefaultSpecifier>({
579
+ type: 'ImportDefaultSpecifier',
580
+ local: Transform.Identifier(specifier.local),
581
+ });
582
+ case 'ImportSpecifier':
583
+ return constructFlowNode<FlowESTree.ImportSpecifier>({
584
+ type: 'ImportSpecifier',
585
+ local: Transform.Identifier(specifier.local),
586
+ imported: Transform.Identifier(specifier.imported),
587
+ importKind:
588
+ specifier.importKind === 'value'
589
+ ? null
590
+ : specifier.importKind ?? null,
591
+ });
592
+ }
593
+ });
594
+ return constructFlowNode<FlowESTree.ImportDeclaration>({
595
+ type: 'ImportDeclaration',
596
+ source: constructFlowNode<FlowESTree.StringLiteral>({
597
+ type: 'Literal',
598
+ literalType: 'string',
599
+ value: node.source.value,
600
+ raw: node.source.raw,
601
+ }),
602
+ importKind:
603
+ // `import type React from 'react'` in TS means `import typeof React from react` in Flow
604
+ specifiers.some(s => s.type === 'ImportDefaultSpecifier') &&
605
+ node.importKind === 'type'
606
+ ? 'typeof'
607
+ : node.importKind,
608
+ assertions: [],
609
+ specifiers,
610
+ });
611
+ }
612
+
613
+ static LabeledStatement(
614
+ node: TSESTree.LabeledStatement,
615
+ ): FlowESTree.LabeledStatement {
616
+ const body = Transform.Statement(node.body);
617
+ if (Array.isArray(body)) {
618
+ throw translationError(node.body, 'Unexpected array of statements');
619
+ }
620
+ return constructFlowNode<FlowESTree.LabeledStatement>({
621
+ type: 'LabeledStatement',
622
+ label: Transform.Identifier(node.label),
623
+ body,
624
+ });
625
+ }
626
+
627
+ static Literal(node: TSESTree.Literal): FlowESTree.Literal {
628
+ if (typeof node.value === 'number') {
629
+ return constructFlowNode<FlowESTree.NumericLiteral>({
630
+ type: 'Literal',
631
+ literalType: 'numeric',
632
+ value: Number(node.raw),
633
+ raw: node.raw,
634
+ });
635
+ } else if (typeof node.value === 'string') {
636
+ return constructFlowNode<FlowESTree.StringLiteral>({
637
+ type: 'Literal',
638
+ literalType: 'string',
639
+ value: node.value,
640
+ raw: node.raw,
641
+ });
642
+ } else if (typeof node.value === 'boolean') {
643
+ return constructFlowNode<FlowESTree.BooleanLiteral>({
644
+ type: 'Literal',
645
+ literalType: 'boolean',
646
+ value: node.value,
647
+ raw: node.value ? 'true' : 'false',
648
+ });
649
+ } else if (typeof node.value === 'bigint') {
650
+ return constructFlowNode<FlowESTree.BigIntLiteral>({
651
+ type: 'Literal',
652
+ literalType: 'bigint',
653
+ value: node.value,
654
+ raw: node.raw,
655
+ bigint: node.raw,
656
+ });
657
+ } else if (node.value instanceof RegExp) {
658
+ return constructFlowNode<FlowESTree.RegExpLiteral>({
659
+ type: 'Literal',
660
+ literalType: 'regexp',
661
+ value: node.value,
662
+ regex: (null: $FlowFixMe),
663
+ raw: node.raw,
664
+ });
665
+ } else if (node.value == null) {
666
+ return constructFlowNode<FlowESTree.NullLiteral>({
667
+ type: 'Literal',
668
+ literalType: 'null',
669
+ value: node.value,
670
+ raw: 'null',
671
+ });
672
+ } else {
673
+ throw translationError(
674
+ node,
675
+ `Unsupported literal type ${typeof node.value}`,
676
+ );
677
+ }
678
+ }
679
+
680
+ static LiteralType(node: TSESTree.Literal): FlowESTree.TypeAnnotationType {
681
+ const literal = Transform.Literal(node);
682
+ switch (literal.literalType) {
683
+ case 'boolean':
684
+ return constructFlowNode<FlowESTree.BooleanLiteralTypeAnnotation>({
685
+ type: 'BooleanLiteralTypeAnnotation',
686
+ value: literal.value,
687
+ raw: literal.raw,
688
+ });
689
+ case 'numeric':
690
+ return constructFlowNode<FlowESTree.NumberLiteralTypeAnnotation>({
691
+ type: 'NumberLiteralTypeAnnotation',
692
+ value: literal.value,
693
+ raw: literal.raw,
694
+ });
695
+ case 'string':
696
+ return constructFlowNode<FlowESTree.StringLiteralTypeAnnotation>({
697
+ type: 'StringLiteralTypeAnnotation',
698
+ value: literal.value,
699
+ raw: literal.raw,
700
+ });
701
+ case 'bigint':
702
+ return constructFlowNode<FlowESTree.BigIntLiteralTypeAnnotation>({
703
+ type: 'BigIntLiteralTypeAnnotation',
704
+ value: literal.value,
705
+ bigint: literal.bigint,
706
+ raw: literal.raw,
707
+ });
708
+ case 'null':
709
+ return constructFlowNode<FlowESTree.NullLiteralTypeAnnotation>({
710
+ type: 'NullLiteralTypeAnnotation',
711
+ value: literal.value,
712
+ raw: literal.raw,
713
+ });
714
+ case 'regexp':
715
+ return unsupportedAnnotation(node, 'regexp literal type');
716
+ default:
717
+ (literal: empty);
718
+ throw 'unreachable';
719
+ }
720
+ }
721
+
722
+ static AllStatement(
723
+ node: TSESTree.Statement,
724
+ ):
725
+ | FlowESTree.Statement
726
+ | FlowESTree.ModuleDeclaration
727
+ | $ReadOnlyArray<FlowESTree.Statement | FlowESTree.ModuleDeclaration> {
728
+ switch (node.type) {
729
+ case 'BlockStatement':
730
+ return Transform.BlockStatement(node);
731
+ case 'ClassDeclaration':
732
+ return Transform.ClassDeclarationWithName(node);
733
+ case 'DebuggerStatement':
734
+ return Transform.DebuggerStatement();
735
+ case 'ExportAllDeclaration':
736
+ return Transform.ExportAllDeclaration(node);
737
+ case 'ExportDefaultDeclaration':
738
+ return Transform.ExportDefaultDeclaration(node);
739
+ case 'ExportNamedDeclaration':
740
+ return Transform.ExportNamedDeclaration(node);
741
+ case 'FunctionDeclaration':
742
+ return Transform.FunctionDeclarationWithName(node);
743
+ case 'ImportDeclaration':
744
+ return Transform.ImportDeclaration(node);
745
+ case 'LabeledStatement':
746
+ return Transform.LabeledStatement(node);
747
+ case 'TSDeclareFunction':
748
+ return Transform.TSDeclareFunction(node);
749
+ case 'TSEnumDeclaration':
750
+ return Transform.TSEnumDeclaration(node);
751
+ case 'TSExportAssignment':
752
+ return Transform.TSExportAssignment(node);
753
+ case 'TSImportEqualsDeclaration':
754
+ return Transform.TSImportEqualsDeclaration(node);
755
+ case 'TSInterfaceDeclaration':
756
+ return Transform.TSInterfaceDeclaration(node);
757
+ case 'TSModuleDeclaration':
758
+ return Transform.TSModuleDeclaration(node);
759
+ case 'TSNamespaceExportDeclaration':
760
+ // Flow will never support `export as namespace` since we can't allow a normal file to
761
+ // introduce a global out of nowhere, and because it's only useful for legacy module
762
+ // system However, it's very reasonable to completely ignore it under some mode, so that
763
+ // people using these libdefs won't have a lot of pain.
764
+ return [];
765
+ case 'TSTypeAliasDeclaration':
766
+ return Transform.TSTypeAliasDeclaration(node);
767
+ case 'VariableDeclaration':
768
+ return Transform.VariableDeclaration(node);
769
+ case 'ExpressionStatement':
770
+ throw translationError(node, 'Unsupported expression statement');
771
+ case 'WithStatement':
772
+ throw translationError(node, 'Unsupported with statement');
773
+ case 'BreakStatement':
774
+ case 'ContinueStatement':
775
+ case 'DoWhileStatement':
776
+ case 'ForInStatement':
777
+ case 'ForOfStatement':
778
+ case 'ForStatement':
779
+ case 'IfStatement':
780
+ case 'ReturnStatement':
781
+ case 'SwitchStatement':
782
+ case 'ThrowStatement':
783
+ case 'TryStatement':
784
+ case 'WhileStatement':
785
+ throw translationError(node, 'Unsupported control flow statement');
786
+ }
787
+ }
788
+
789
+ static Statement(
790
+ node: TSESTree.Statement,
791
+ ): FlowESTree.Statement | $ReadOnlyArray<FlowESTree.Statement> {
792
+ return (Transform.AllStatement(node): $FlowFixMe);
793
+ }
794
+
795
+ static TSAnyType(): FlowESTree.AnyTypeAnnotation {
796
+ return constructFlowNode<FlowESTree.AnyTypeAnnotation>({
797
+ type: 'AnyTypeAnnotation',
798
+ });
799
+ }
800
+
801
+ static TSArrayType(
802
+ node: TSESTree.TSArrayType,
803
+ ): FlowESTree.ArrayTypeAnnotation {
804
+ return constructFlowNode<FlowESTree.ArrayTypeAnnotation>({
805
+ type: 'ArrayTypeAnnotation',
806
+ elementType: Transform.TSTypeAnnotation(node.elementType),
807
+ });
808
+ }
809
+
810
+ static TSBigIntType(): FlowESTree.BigIntTypeAnnotation {
811
+ return constructFlowNode<FlowESTree.BigIntTypeAnnotation>({
812
+ type: 'BigIntTypeAnnotation',
813
+ });
814
+ }
815
+
816
+ static TSBooleanType(): FlowESTree.BooleanTypeAnnotation {
817
+ return constructFlowNode<FlowESTree.BooleanTypeAnnotation>({
818
+ type: 'BooleanTypeAnnotation',
819
+ });
820
+ }
821
+
822
+ static TSConditionalType(
823
+ node: TSESTree.TSConditionalType,
824
+ ): FlowESTree.ConditionalTypeAnnotation {
825
+ return constructFlowNode<FlowESTree.ConditionalTypeAnnotation>({
826
+ type: 'ConditionalTypeAnnotation',
827
+ checkType: Transform.TSTypeAnnotation(node.checkType),
828
+ extendsType: Transform.TSTypeAnnotation(node.extendsType),
829
+ trueType: Transform.TSTypeAnnotation(node.trueType),
830
+ falseType: Transform.TSTypeAnnotation(node.falseType),
831
+ });
832
+ }
833
+
834
+ static TSConstructorType(
835
+ node: TSESTree.TSConstructorType,
836
+ ): FlowESTree.AnyTypeAnnotation {
837
+ return unsupportedAnnotation(node, 'constructor types');
838
+ }
839
+
840
+ static TSDeclareFunction(
841
+ node: TSESTree.TSDeclareFunction,
842
+ ): FlowESTree.DeclareFunction {
843
+ if (node.id == null) {
844
+ throw translationError(node, 'Missing function name');
845
+ }
846
+ const name = node.id.name;
847
+ const {thisParam, restParam, params} =
848
+ Transform._partitionAndTranslateTSFunctionParams(node.params);
849
+ const fnAnnot = constructFlowNode<FlowESTree.FunctionTypeAnnotation>({
850
+ type: 'FunctionTypeAnnotation',
851
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(
852
+ node.typeParameters,
853
+ ),
854
+ params,
855
+ rest: restParam,
856
+ returnType:
857
+ node.returnType?.typeAnnotation == null
858
+ ? unsupportedAnnotation(node, 'missing return type')
859
+ : Transform.TSTypeAnnotation(node.returnType.typeAnnotation),
860
+ this: thisParam,
861
+ });
862
+ return constructFlowNode<FlowESTree.DeclareFunction>({
863
+ type: 'DeclareFunction',
864
+ id: {
865
+ ...DUMMY_COMMON,
866
+ type: 'Identifier',
867
+ name,
868
+ typeAnnotation: {
869
+ ...DUMMY_COMMON,
870
+ type: 'TypeAnnotation',
871
+ typeAnnotation: fnAnnot,
872
+ },
873
+ optional: false,
874
+ },
875
+ predicate: null,
876
+ });
877
+ }
878
+
879
+ static TSEnumDeclaration(
880
+ node: TSESTree.TSEnumDeclaration,
881
+ ): FlowESTree.TypeAlias {
882
+ return unsupportedDeclaration(node, 'enums', node.id);
883
+ }
884
+
885
+ static TSExportAssignment(
886
+ node: TSESTree.TSExportAssignment,
887
+ ): FlowESTree.DeclareModuleExports {
888
+ let typeAnnotation: FlowESTree.TypeAnnotationType;
889
+ if (node.expression.type === 'Identifier') {
890
+ typeAnnotation = constructFlowNode<FlowESTree.TypeofTypeAnnotation>({
891
+ type: 'TypeofTypeAnnotation',
892
+ argument: Transform.Identifier(node.expression),
893
+ });
894
+ } else if (node.expression.type === 'Literal') {
895
+ typeAnnotation = Transform.LiteralType(node.expression);
896
+ } else {
897
+ throw translationError(
898
+ node,
899
+ `Unsupported export assignment expression ${node.expression.type}`,
900
+ );
901
+ }
902
+ return constructFlowNode<FlowESTree.DeclareModuleExports>({
903
+ type: 'DeclareModuleExports',
904
+ typeAnnotation: constructFlowNode<FlowESTree.TypeAnnotation>({
905
+ type: 'TypeAnnotation',
906
+ typeAnnotation,
907
+ }),
908
+ });
909
+ }
910
+
911
+ static TSFunctionType(
912
+ node: TSESTree.TSFunctionType,
913
+ allowMissingReturn: boolean = false,
914
+ ): FlowESTree.FunctionTypeAnnotation {
915
+ const {thisParam, restParam, params} =
916
+ Transform._partitionAndTranslateTSFunctionParams(node.params);
917
+ return constructFlowNode<FlowESTree.FunctionTypeAnnotation>({
918
+ type: 'FunctionTypeAnnotation',
919
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(
920
+ node.typeParameters,
921
+ ),
922
+ params: params,
923
+ rest: restParam,
924
+ returnType:
925
+ node.returnType?.typeAnnotation == null
926
+ ? allowMissingReturn
927
+ ? constructFlowNode<FlowESTree.VoidTypeAnnotation>({
928
+ type: 'VoidTypeAnnotation',
929
+ })
930
+ : unsupportedAnnotation(node, 'missing return type')
931
+ : Transform.TSTypeAnnotation(node.returnType.typeAnnotation),
932
+ this: thisParam,
933
+ });
934
+ }
935
+
936
+ static _partitionAndTranslateTSFunctionParams(
937
+ tsParams: $ReadOnlyArray<TSESTree.Parameter>,
938
+ ): {
939
+ thisParam: FlowESTree.FunctionTypeParam | null,
940
+ restParam: FlowESTree.FunctionTypeParam | null,
941
+ params: Array<FlowESTree.FunctionTypeParam>,
942
+ } {
943
+ const params = [...tsParams];
944
+ const firstParam = params[0];
945
+ let thisParam: FlowESTree.FunctionTypeParam | null = null;
946
+ let restParam: FlowESTree.FunctionTypeParam | null = null;
947
+ if (
948
+ firstParam != null &&
949
+ firstParam.type === 'Identifier' &&
950
+ firstParam.name === 'this'
951
+ ) {
952
+ thisParam = constructFlowNode<FlowESTree.FunctionTypeParam>({
953
+ type: 'FunctionTypeParam',
954
+ name: constructFlowNode<FlowESTree.Identifier>({
955
+ type: 'Identifier',
956
+ name: 'this',
957
+ optional: false,
958
+ typeAnnotation: null,
959
+ }),
960
+ optional: false,
961
+ typeAnnotation: Transform.TSTypeAnnotationOpt(
962
+ firstParam.typeAnnotation?.typeAnnotation,
963
+ ),
964
+ });
965
+ params.shift();
966
+ }
967
+ const lastParam = params[params.length - 1];
968
+ if (lastParam != null && lastParam.type === 'RestElement') {
969
+ restParam = constructFlowNode<FlowESTree.FunctionTypeParam>({
970
+ type: 'FunctionTypeParam',
971
+ name: constructFlowNode<FlowESTree.Identifier>({
972
+ type: 'Identifier',
973
+ name: '$$rest$$',
974
+ optional: false,
975
+ typeAnnotation: null,
976
+ }),
977
+ optional: false,
978
+ typeAnnotation: Transform.TSTypeAnnotationOpt(
979
+ lastParam.typeAnnotation?.typeAnnotation,
980
+ ),
981
+ });
982
+ params.pop();
983
+ }
984
+ return {
985
+ thisParam,
986
+ restParam,
987
+ params: params.map((param, i) => {
988
+ if (param.type === 'Identifier') {
989
+ return constructFlowNode<FlowESTree.FunctionTypeParam>({
990
+ type: 'FunctionTypeParam',
991
+ name: constructFlowNode<FlowESTree.Identifier>({
992
+ type: 'Identifier',
993
+ name: param.name,
994
+ optional: false,
995
+ typeAnnotation: null,
996
+ }),
997
+ optional: Boolean(param.optional),
998
+ typeAnnotation: Transform.TSTypeAnnotationOpt(
999
+ param.typeAnnotation?.typeAnnotation,
1000
+ ),
1001
+ });
1002
+ } else if (
1003
+ param.type === 'ArrayPattern' ||
1004
+ param.type === 'ObjectPattern'
1005
+ ) {
1006
+ return constructFlowNode<FlowESTree.FunctionTypeParam>({
1007
+ type: 'FunctionTypeParam',
1008
+ name: constructFlowNode<FlowESTree.Identifier>({
1009
+ type: 'Identifier',
1010
+ name: `$$param${i}$`,
1011
+ optional: false,
1012
+ typeAnnotation: null,
1013
+ }),
1014
+ optional: Boolean(param.optional),
1015
+ typeAnnotation: Transform.TSTypeAnnotationOpt(
1016
+ param.typeAnnotation?.typeAnnotation,
1017
+ ),
1018
+ });
1019
+ } else {
1020
+ throw new Error(`Unexpected function parameter ${param.type}`);
1021
+ }
1022
+ }),
1023
+ };
1024
+ }
1025
+
1026
+ static TSImportType(
1027
+ node: TSESTree.TSImportType,
1028
+ ): FlowESTree.TypeAnnotationType {
1029
+ let base: FlowESTree.TypeAnnotationType =
1030
+ constructFlowNode<FlowESTree.GenericTypeAnnotation>({
1031
+ type: 'GenericTypeAnnotation',
1032
+ id: constructFlowNode<FlowESTree.Identifier>({
1033
+ type: 'Identifier',
1034
+ name: '$Exports',
1035
+ optional: false,
1036
+ typeAnnotation: null,
1037
+ }),
1038
+ typeParameters:
1039
+ constructFlowNode<FlowESTree.TypeParameterInstantiation>({
1040
+ type: 'TypeParameterInstantiation',
1041
+ params: [Transform.TSTypeAnnotation(node.argument)],
1042
+ }),
1043
+ });
1044
+ if (node.qualifier == null) {
1045
+ return base;
1046
+ }
1047
+ if (node.typeParameters != null) {
1048
+ return unsupportedAnnotation(node, 'import types with type parameters');
1049
+ }
1050
+ let qualifier = Transform.EntityNameToTypeIdentifier(node.qualifier);
1051
+ const namesRev: Array<string> = [];
1052
+ while (qualifier.type !== 'Identifier') {
1053
+ namesRev.push(qualifier.id.name);
1054
+ qualifier = qualifier.qualification;
1055
+ }
1056
+ namesRev.push(qualifier.name);
1057
+ while (namesRev.length > 0) {
1058
+ const name = namesRev.pop();
1059
+ base = constructFlowNode<FlowESTree.IndexedAccessType>({
1060
+ type: 'IndexedAccessType',
1061
+ objectType: base,
1062
+ indexType: constructFlowNode<FlowESTree.StringLiteralTypeAnnotation>({
1063
+ type: 'StringLiteralTypeAnnotation',
1064
+ value: name,
1065
+ raw: `'${name}'`,
1066
+ }),
1067
+ });
1068
+ }
1069
+ return base;
1070
+ }
1071
+
1072
+ static TSImportEqualsDeclaration(
1073
+ node: TSESTree.TSImportEqualsDeclaration,
1074
+ ): FlowESTree.VariableDeclaration | FlowESTree.TypeAlias {
1075
+ if (
1076
+ node.moduleReference.type === 'ThisExpression' ||
1077
+ node.moduleReference.type === 'TSQualifiedName'
1078
+ ) {
1079
+ return unsupportedDeclaration(
1080
+ node,
1081
+ 'import equals declaration with weird module reference',
1082
+ node.id,
1083
+ );
1084
+ }
1085
+ let moduleName: string;
1086
+ if (node.moduleReference.type === 'TSExternalModuleReference') {
1087
+ if (node.moduleReference.expression.type === 'Literal') {
1088
+ moduleName = String(node.moduleReference.expression.value);
1089
+ } else {
1090
+ return unsupportedDeclaration(
1091
+ node,
1092
+ 'import equals declaration with weird module reference',
1093
+ node.id,
1094
+ );
1095
+ }
1096
+ } else {
1097
+ moduleName = node.moduleReference.name;
1098
+ }
1099
+ return constructFlowNode<FlowESTree.VariableDeclaration>({
1100
+ type: 'VariableDeclaration',
1101
+ kind: 'const',
1102
+ declarations: [
1103
+ constructFlowNode<FlowESTree.VariableDeclarator>({
1104
+ type: 'VariableDeclarator',
1105
+ id: constructFlowNode<FlowESTree.Identifier>({
1106
+ type: 'Identifier',
1107
+ name: node.id.name,
1108
+ optional: false,
1109
+ typeAnnotation: null,
1110
+ }),
1111
+ init: constructFlowNode<FlowESTree.CallExpression>({
1112
+ type: 'CallExpression',
1113
+ callee: constructFlowNode<FlowESTree.Identifier>({
1114
+ type: 'Identifier',
1115
+ name: 'require',
1116
+ optional: false,
1117
+ typeAnnotation: null,
1118
+ }),
1119
+ arguments: [
1120
+ constructFlowNode<FlowESTree.StringLiteral>({
1121
+ type: 'Literal',
1122
+ literalType: 'string',
1123
+ value: moduleName,
1124
+ raw: `"${moduleName}"`,
1125
+ }),
1126
+ ],
1127
+ optional: false,
1128
+ typeArguments: null,
1129
+ }),
1130
+ }),
1131
+ ],
1132
+ });
1133
+ }
1134
+
1135
+ static TSIndexedAccessType(
1136
+ node: TSESTree.TSIndexedAccessType,
1137
+ ): FlowESTree.IndexedAccessType {
1138
+ return constructFlowNode<FlowESTree.IndexedAccessType>({
1139
+ type: 'IndexedAccessType',
1140
+ objectType: Transform.TSTypeAnnotation(node.objectType),
1141
+ indexType: Transform.TSTypeAnnotation(node.indexType),
1142
+ });
1143
+ }
1144
+
1145
+ static TSInferType(
1146
+ node: TSESTree.TSInferType,
1147
+ ): FlowESTree.InferTypeAnnotation {
1148
+ return constructFlowNode<FlowESTree.InferTypeAnnotation>({
1149
+ type: 'InferTypeAnnotation',
1150
+ typeParameter: Transform.TSTypeParameter(node.typeParameter),
1151
+ });
1152
+ }
1153
+
1154
+ static TSInterfaceDeclaration(
1155
+ node: TSESTree.TSInterfaceDeclaration,
1156
+ ): FlowESTree.InterfaceDeclaration {
1157
+ const body = Transform.TSTypeLiteralOrInterfaceBody(node.body);
1158
+ // $FlowFixMe[cannot-write]
1159
+ body.inexact = false;
1160
+ return constructFlowNode<FlowESTree.InterfaceDeclaration>({
1161
+ type: 'InterfaceDeclaration',
1162
+ id: Transform.Identifier(node.id),
1163
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(
1164
+ node.typeParameters,
1165
+ ),
1166
+ body,
1167
+ extends: (node.extends || []).map(e =>
1168
+ Transform.TSInterfaceHeritage(e),
1169
+ ),
1170
+ });
1171
+ }
1172
+
1173
+ static TSInterfaceHeritage(
1174
+ node: TSESTree.TSInterfaceHeritage,
1175
+ ): FlowESTree.InterfaceExtends {
1176
+ return constructFlowNode<FlowESTree.InterfaceExtends>({
1177
+ type: 'InterfaceExtends',
1178
+ id: Transform._expressionToIdOrQualifiedTypeId(
1179
+ node.expression,
1180
+ 'interface extends',
1181
+ ),
1182
+ typeParameters: Transform.TSTypeParameterInstantiationOpt(
1183
+ node.typeParameters,
1184
+ ),
1185
+ });
1186
+ }
1187
+
1188
+ static _expressionToIdOrQualifiedTypeId(
1189
+ node: TSESTree.Expression,
1190
+ kind: string,
1191
+ ): FlowESTree.Identifier | FlowESTree.QualifiedTypeIdentifier {
1192
+ if (node.type === 'Identifier') {
1193
+ return Transform.Identifier(node);
1194
+ } else if (
1195
+ node.type === 'MemberExpression' &&
1196
+ node.property.type === 'Identifier'
1197
+ ) {
1198
+ const id = Transform.Identifier(node.property);
1199
+ return constructFlowNode<FlowESTree.QualifiedTypeIdentifier>({
1200
+ type: 'QualifiedTypeIdentifier',
1201
+ qualification: Transform._expressionToIdOrQualifiedTypeId(
1202
+ node.object,
1203
+ kind,
1204
+ ),
1205
+ id,
1206
+ });
1207
+ } else {
1208
+ throw unexpectedTranslationError(
1209
+ node,
1210
+ `Expected ${kind} to be an Identifier or Member`,
1211
+ );
1212
+ }
1213
+ }
1214
+
1215
+ static TSIntersectionType(
1216
+ node: TSESTree.TSIntersectionType,
1217
+ ): FlowESTree.IntersectionTypeAnnotation {
1218
+ return constructFlowNode<FlowESTree.IntersectionTypeAnnotation>({
1219
+ type: 'IntersectionTypeAnnotation',
1220
+ types: node.types.map(node => Transform.TSTypeAnnotation(node)),
1221
+ });
1222
+ }
1223
+
1224
+ static TSLiteralType(
1225
+ node: TSESTree.TSLiteralType,
1226
+ ): FlowESTree.TypeAnnotationType {
1227
+ switch (node.literal.type) {
1228
+ case 'TemplateLiteral':
1229
+ return unsupportedAnnotation(node, 'template literals');
1230
+ case 'Literal':
1231
+ return Transform.LiteralType(node.literal);
1232
+ case 'UnaryExpression':
1233
+ return unsupportedAnnotation(node, 'UnaryExpression literal type');
1234
+ case 'UpdateExpression':
1235
+ return unsupportedAnnotation(node, 'UpdateExpression literal type');
1236
+ }
1237
+ }
1238
+
1239
+ static TSMappedType(
1240
+ node: TSESTree.TSMappedType,
1241
+ ): FlowESTree.ObjectTypeAnnotation {
1242
+ const keyTparam = Transform.TSTypeParameter(node.typeParameter);
1243
+ const sourceType: FlowESTree.TypeAnnotationType = (keyTparam.bound
1244
+ ?.typeAnnotation: $FlowFixMe);
1245
+ // $FlowFixMe[cannot-write]
1246
+ keyTparam.bound = null;
1247
+ const prop = constructFlowNode<FlowESTree.ObjectTypeMappedTypeProperty>({
1248
+ type: 'ObjectTypeMappedTypeProperty',
1249
+ keyTparam,
1250
+ propType: Transform.TSTypeAnnotationOpt(node.typeAnnotation),
1251
+ sourceType,
1252
+ variance:
1253
+ node.readonly === '+' || Boolean(node.readonly)
1254
+ ? constructFlowNode<FlowESTree.Variance>({
1255
+ type: 'Variance',
1256
+ kind: 'plus',
1257
+ })
1258
+ : null,
1259
+ optional:
1260
+ node.optional === '+'
1261
+ ? 'PlusOptional'
1262
+ : node.optional === '-'
1263
+ ? 'MinusOptional'
1264
+ : // eslint-disable-next-line no-extra-boolean-cast
1265
+ Boolean(node.optional)
1266
+ ? 'Optional'
1267
+ : null,
1268
+ });
1269
+ return constructFlowNode<FlowESTree.ObjectTypeAnnotation>({
1270
+ type: 'ObjectTypeAnnotation',
1271
+ properties: [prop],
1272
+ indexers: [],
1273
+ callProperties: [],
1274
+ internalSlots: [],
1275
+ exact: false,
1276
+ inexact: false,
1277
+ });
1278
+ }
1279
+
1280
+ static TSModuleDeclaration(
1281
+ node: TSESTree.TSModuleDeclaration,
1282
+ ):
1283
+ | FlowESTree.TypeAlias
1284
+ | FlowESTree.DeclareNamespace
1285
+ | FlowESTree.DeclareModule {
1286
+ const body =
1287
+ node.body == null
1288
+ ? constructFlowNode<FlowESTree.BlockStatement>({
1289
+ type: 'BlockStatement',
1290
+ body: [],
1291
+ })
1292
+ : node.body.type === 'TSModuleDeclaration'
1293
+ ? (() => {
1294
+ throw translationError(node, 'nested module declarations');
1295
+ })()
1296
+ : constructFlowNode<FlowESTree.BlockStatement>({
1297
+ type: 'BlockStatement',
1298
+ body: node.body.body.flatMap(s => Transform.Statement(s)),
1299
+ });
1300
+ if (node.id.type === 'Literal') {
1301
+ return constructFlowNode<FlowESTree.DeclareModule>({
1302
+ type: 'DeclareModule',
1303
+ id: (Transform.Literal(node.id): $FlowFixMe),
1304
+ body,
1305
+ });
1306
+ }
1307
+ if (node.global ?? false) {
1308
+ return unsupportedDeclaration(node, 'global declaration', node.id);
1309
+ }
1310
+ return constructFlowNode<FlowESTree.DeclareNamespace>({
1311
+ type: 'DeclareNamespace',
1312
+ id: Transform.Identifier(node.id),
1313
+ body,
1314
+ });
1315
+ }
1316
+
1317
+ static TSNamedTupleMember(
1318
+ node: TSESTree.TSNamedTupleMember,
1319
+ ): FlowESTree.TupleTypeLabeledElement | FlowESTree.TupleTypeSpreadElement {
1320
+ let optional = false;
1321
+ let elementType: FlowESTree.TypeAnnotationType;
1322
+ if (node.elementType.type === 'TSRestType') {
1323
+ const child = node.elementType;
1324
+ return constructFlowNode<FlowESTree.TupleTypeSpreadElement>({
1325
+ type: 'TupleTypeSpreadElement',
1326
+ label: Transform.Identifier(node.label),
1327
+ typeAnnotation: Transform.TSTypeAnnotation(child.typeAnnotation),
1328
+ optional: false,
1329
+ variance: null,
1330
+ });
1331
+ } else if (node.elementType.type === 'TSOptionalType') {
1332
+ optional = true;
1333
+ elementType = Transform.TSTypeAnnotation(
1334
+ node.elementType.typeAnnotation,
1335
+ );
1336
+ } else {
1337
+ elementType = Transform.TSTypeAnnotation(node.elementType);
1338
+ }
1339
+ return constructFlowNode<FlowESTree.TupleTypeLabeledElement>({
1340
+ type: 'TupleTypeLabeledElement',
1341
+ label: Transform.Identifier(node.label),
1342
+ elementType,
1343
+ optional,
1344
+ variance: null,
1345
+ });
1346
+ }
1347
+
1348
+ static TSNeverType(): FlowESTree.EmptyTypeAnnotation {
1349
+ return constructFlowNode<FlowESTree.EmptyTypeAnnotation>({
1350
+ type: 'EmptyTypeAnnotation',
1351
+ });
1352
+ }
1353
+
1354
+ static TSNullType(): FlowESTree.NullLiteralTypeAnnotation {
1355
+ return constructFlowNode<FlowESTree.NullLiteralTypeAnnotation>({
1356
+ type: 'NullLiteralTypeAnnotation',
1357
+ });
1358
+ }
1359
+
1360
+ static TSNumberType(): FlowESTree.NumberTypeAnnotation {
1361
+ return constructFlowNode<FlowESTree.NumberTypeAnnotation>({
1362
+ type: 'NumberTypeAnnotation',
1363
+ });
1364
+ }
1365
+
1366
+ static TSObjectType(): FlowESTree.InterfaceTypeAnnotation {
1367
+ return constructFlowNode<FlowESTree.InterfaceTypeAnnotation>({
1368
+ type: 'InterfaceTypeAnnotation',
1369
+ body: constructFlowNode<FlowESTree.ObjectTypeAnnotation>({
1370
+ type: 'ObjectTypeAnnotation',
1371
+ inexact: false,
1372
+ exact: false,
1373
+ properties: [],
1374
+ indexers: [],
1375
+ callProperties: [],
1376
+ internalSlots: [],
1377
+ }),
1378
+ extends: [],
1379
+ });
1380
+ }
1381
+
1382
+ static TSQualifiedNameToQualifiedTypeIdentifier(
1383
+ node: TSESTree.TSQualifiedName,
1384
+ ): FlowESTree.QualifiedTypeIdentifier {
1385
+ return constructFlowNode<FlowESTree.QualifiedTypeIdentifier>({
1386
+ type: 'QualifiedTypeIdentifier',
1387
+ qualification: Transform.EntityNameToTypeIdentifier(node.left),
1388
+ id: Transform.Identifier(node.right),
1389
+ });
1390
+ }
1391
+
1392
+ static TSQualifiedNameToQualifiedTypeofIdentifier(
1393
+ node: TSESTree.TSQualifiedName,
1394
+ ): FlowESTree.QualifiedTypeofIdentifier {
1395
+ return constructFlowNode<FlowESTree.QualifiedTypeofIdentifier>({
1396
+ type: 'QualifiedTypeofIdentifier',
1397
+ qualification: Transform.EntityNameToTypeofIdentifier(node.left),
1398
+ id: Transform.Identifier(node.right),
1399
+ });
1400
+ }
1401
+
1402
+ static TSStringType(): FlowESTree.StringTypeAnnotation {
1403
+ return constructFlowNode<FlowESTree.StringTypeAnnotation>({
1404
+ type: 'StringTypeAnnotation',
1405
+ });
1406
+ }
1407
+
1408
+ static TSSymbolType(): FlowESTree.SymbolTypeAnnotation {
1409
+ return constructFlowNode<FlowESTree.SymbolTypeAnnotation>({
1410
+ type: 'SymbolTypeAnnotation',
1411
+ });
1412
+ }
1413
+
1414
+ static TSTemplateLiteralType(
1415
+ node: TSESTree.TSTemplateLiteralType,
1416
+ ): FlowESTree.AnyTypeAnnotation {
1417
+ return unsupportedAnnotation(node, 'constructor types');
1418
+ }
1419
+
1420
+ static TSThisType(
1421
+ _node: TSESTree.TSThisType,
1422
+ ): FlowESTree.GenericTypeAnnotation {
1423
+ return constructFlowNode<FlowESTree.GenericTypeAnnotation>({
1424
+ type: 'GenericTypeAnnotation',
1425
+ id: constructFlowNode<FlowESTree.Identifier>({
1426
+ type: 'Identifier',
1427
+ name: 'this',
1428
+ typeAnnotation: null,
1429
+ optional: false,
1430
+ }),
1431
+ typeParameters: null,
1432
+ });
1433
+ }
1434
+
1435
+ static TSTupleType(
1436
+ node: TSESTree.TSTupleType,
1437
+ ): FlowESTree.TupleTypeAnnotation {
1438
+ return constructFlowNode<FlowESTree.TupleTypeAnnotation>({
1439
+ type: 'TupleTypeAnnotation',
1440
+ types: node.elementTypes.map(node => Transform.TSTypeAnnotation(node)),
1441
+ inexact: false,
1442
+ });
1443
+ }
1444
+
1445
+ static TSTypeAliasDeclaration(
1446
+ node: TSESTree.TSTypeAliasDeclaration,
1447
+ ): FlowESTree.TypeAlias {
1448
+ return constructFlowNode<FlowESTree.TypeAlias>({
1449
+ type: 'TypeAlias',
1450
+ id: Transform.Identifier(node.id),
1451
+ typeParameters: Transform.TSTypeParameterDeclarationOpt(
1452
+ node.typeParameters,
1453
+ ),
1454
+ right: Transform.TSTypeAnnotation(node.typeAnnotation),
1455
+ });
1456
+ }
1457
+
1458
+ static TSTypeAnnotation(
1459
+ node: TSESTree.TypeNode,
1460
+ ): FlowESTree.TypeAnnotationType {
1461
+ switch (node.type) {
1462
+ case 'TSOptionalType':
1463
+ case 'TSQualifiedName':
1464
+ case 'TSRestType':
1465
+ return unsupportedAnnotation(
1466
+ node,
1467
+ 'unexpected toplevel ' + node.type,
1468
+ );
1469
+ case 'TSAbstractKeyword':
1470
+ case 'TSAsyncKeyword':
1471
+ case 'TSDeclareKeyword':
1472
+ case 'TSExportKeyword':
1473
+ case 'TSPrivateKeyword':
1474
+ case 'TSProtectedKeyword':
1475
+ case 'TSPublicKeyword':
1476
+ case 'TSReadonlyKeyword':
1477
+ case 'TSStaticKeyword':
1478
+ return unsupportedAnnotation(node, 'wat keyword ' + node.type);
1479
+ case 'TSAnyKeyword':
1480
+ return Transform.TSAnyType();
1481
+ case 'TSArrayType':
1482
+ return Transform.TSArrayType(node);
1483
+ case 'TSBigIntKeyword':
1484
+ return Transform.TSBigIntType();
1485
+ case 'TSBooleanKeyword':
1486
+ return Transform.TSBooleanType();
1487
+ case 'TSConditionalType':
1488
+ return Transform.TSConditionalType(node);
1489
+ case 'TSConstructorType':
1490
+ return Transform.TSConstructorType(node);
1491
+ case 'TSFunctionType':
1492
+ return Transform.TSFunctionType(node);
1493
+ case 'TSImportType':
1494
+ return Transform.TSImportType(node);
1495
+ case 'TSIndexedAccessType':
1496
+ return Transform.TSIndexedAccessType(node);
1497
+ case 'TSInferType':
1498
+ return Transform.TSInferType(node);
1499
+ case 'TSIntersectionType':
1500
+ return Transform.TSIntersectionType(node);
1501
+ case 'TSIntrinsicKeyword':
1502
+ return unsupportedAnnotation(node, 'intrinsic keyword');
1503
+ case 'TSLiteralType':
1504
+ return Transform.TSLiteralType(node);
1505
+ case 'TSMappedType':
1506
+ return Transform.TSMappedType(node);
1507
+ case 'TSNamedTupleMember':
1508
+ return Transform.TSNamedTupleMember(node);
1509
+ case 'TSNeverKeyword':
1510
+ return Transform.TSNeverType();
1511
+ case 'TSNullKeyword':
1512
+ return Transform.TSNullType();
1513
+ case 'TSNumberKeyword':
1514
+ return Transform.TSNumberType();
1515
+ case 'TSObjectKeyword':
1516
+ return Transform.TSObjectType();
1517
+ case 'TSStringKeyword':
1518
+ return Transform.TSStringType();
1519
+ case 'TSSymbolKeyword':
1520
+ return Transform.TSSymbolType();
1521
+ case 'TSTemplateLiteralType':
1522
+ return Transform.TSTemplateLiteralType(node);
1523
+ case 'TSThisType':
1524
+ return Transform.TSThisType(node);
1525
+ case 'TSTupleType':
1526
+ return Transform.TSTupleType(node);
1527
+ case 'TSTypeLiteral':
1528
+ return Transform.TSTypeLiteralOrInterfaceBody(node);
1529
+ case 'TSTypeOperator':
1530
+ return Transform.TSTypeOperator(node);
1531
+ case 'TSTypePredicate':
1532
+ return Transform.TSTypePredicate(node);
1533
+ case 'TSTypeQuery':
1534
+ return Transform.TSTypeQuery(node);
1535
+ case 'TSTypeReference':
1536
+ return Transform.TSTypeReference(node);
1537
+ case 'TSUndefinedKeyword':
1538
+ case 'TSVoidKeyword':
1539
+ return Transform.TSUndefinedOrVoidType();
1540
+ case 'TSUnionType':
1541
+ return Transform.TSUnionType(node);
1542
+ case 'TSUnknownKeyword':
1543
+ return Transform.TSUnknownType();
1544
+ }
1545
+ }
1546
+
1547
+ static TSTypeAnnotationOpt(
1548
+ node: ?TSESTree.TypeNode,
1549
+ ): FlowESTree.TypeAnnotationType {
1550
+ return node == null
1551
+ ? constructFlowNode<FlowESTree.AnyTypeAnnotation>({
1552
+ type: 'AnyTypeAnnotation',
1553
+ })
1554
+ : Transform.TSTypeAnnotation(node);
1555
+ }
1556
+
1557
+ static TSTypeAnnotationNode(
1558
+ node: TSESTree.TSTypeAnnotation,
1559
+ ): FlowESTree.TypeAnnotation {
1560
+ return constructFlowNode<FlowESTree.TypeAnnotation>({
1561
+ type: 'TypeAnnotation',
1562
+ typeAnnotation: Transform.TSTypeAnnotation(node.typeAnnotation),
1563
+ });
1564
+ }
1565
+
1566
+ /** A very confusingly named object type */
1567
+ static TSTypeLiteralOrInterfaceBody(
1568
+ node: TSESTree.TSTypeLiteral | TSESTree.TSInterfaceBody,
1569
+ ): FlowESTree.ObjectTypeAnnotation {
1570
+ const properties: Array<FlowESTree.ObjectTypeProperty> = [];
1571
+ const indexers: Array<FlowESTree.ObjectTypeIndexer> = [];
1572
+ const callProperties: Array<FlowESTree.ObjectTypeCallProperty> = [];
1573
+ for (const prop of node.type === 'TSTypeLiteral'
1574
+ ? node.members
1575
+ : node.body) {
1576
+ switch (prop.type) {
1577
+ case 'TSPropertySignature': {
1578
+ Transform._translateIntoObjectProp(prop, properties, indexers);
1579
+ break;
1580
+ }
1581
+ case 'TSMethodSignature': {
1582
+ Transform._translateIntoObjectMethod(prop, properties);
1583
+ break;
1584
+ }
1585
+ case 'TSCallSignatureDeclaration':
1586
+ callProperties.push(
1587
+ constructFlowNode<FlowESTree.ObjectTypeCallProperty>({
1588
+ type: 'ObjectTypeCallProperty',
1589
+ method: false,
1590
+ optional: false,
1591
+ static: false,
1592
+ proto: false,
1593
+ variance: null,
1594
+ value: Transform.TSFunctionType({
1595
+ type: 'TSFunctionType',
1596
+ loc: prop.loc,
1597
+ params: prop.params,
1598
+ returnType: prop.returnType,
1599
+ typeParameters: prop.typeParameters,
1600
+ }),
1601
+ }),
1602
+ );
1603
+ break;
1604
+ case 'TSIndexSignature': {
1605
+ // eslint-disable-next-line no-extra-boolean-cast
1606
+ const variance = Boolean(prop.readonly)
1607
+ ? constructFlowNode<FlowESTree.Variance>({
1608
+ type: 'Variance',
1609
+ kind: 'plus',
1610
+ })
1611
+ : null;
1612
+ indexers.push(
1613
+ constructFlowNode<FlowESTree.ObjectTypeIndexer>({
1614
+ type: 'ObjectTypeIndexer',
1615
+ kind: 'init',
1616
+ method: false,
1617
+ optional: false,
1618
+ static: Boolean(prop.static),
1619
+ proto: false,
1620
+ variance,
1621
+ id: null,
1622
+ key: constructFlowNode<FlowESTree.StringTypeAnnotation>({
1623
+ type: 'StringTypeAnnotation',
1624
+ }),
1625
+ value: Transform.TSTypeAnnotationOpt(
1626
+ prop.typeAnnotation?.typeAnnotation,
1627
+ ),
1628
+ }),
1629
+ );
1630
+ break;
1631
+ }
1632
+ case 'TSConstructSignatureDeclaration':
1633
+ properties.push(
1634
+ constructFlowNode<FlowESTree.ObjectTypeMethodSignature>({
1635
+ type: 'ObjectTypeProperty',
1636
+ kind: 'init',
1637
+ method: true,
1638
+ optional: false,
1639
+ static: false,
1640
+ proto: false,
1641
+ variance: null,
1642
+ key: constructFlowNode<FlowESTree.Identifier>({
1643
+ type: 'Identifier',
1644
+ name: 'constructor',
1645
+ optional: false,
1646
+ typeAnnotation: null,
1647
+ }),
1648
+ value: Transform.TSFunctionType(
1649
+ {
1650
+ type: 'TSFunctionType',
1651
+ loc: prop.loc,
1652
+ params: prop.params,
1653
+ returnType: prop.returnType,
1654
+ typeParameters: prop.typeParameters,
1655
+ },
1656
+ true,
1657
+ ),
1658
+ }),
1659
+ );
1660
+ break;
1661
+ }
1662
+ }
1663
+ return constructFlowNode<FlowESTree.ObjectTypeAnnotation>({
1664
+ type: 'ObjectTypeAnnotation',
1665
+ properties,
1666
+ indexers,
1667
+ callProperties,
1668
+ internalSlots: [],
1669
+ exact: false,
1670
+ inexact: true,
1671
+ });
1672
+ }
1673
+
1674
+ static _translateIntoObjectProp(
1675
+ prop:
1676
+ | TSESTree.TSPropertySignatureComputedName
1677
+ | TSESTree.TSPropertySignatureNonComputedName
1678
+ | TSESTree.TSAbstractPropertyDefinitionComputedName
1679
+ | TSESTree.TSAbstractPropertyDefinitionNonComputedName
1680
+ | TSESTree.PropertyDefinitionComputedName
1681
+ | TSESTree.PropertyDefinitionNonComputedName,
1682
+ properties: Array<FlowESTree.ObjectTypeProperty>,
1683
+ indexers: Array<FlowESTree.ObjectTypeIndexer>,
1684
+ ): void {
1685
+ // eslint-disable-next-line no-extra-boolean-cast
1686
+ const variance = Boolean(prop.readonly)
1687
+ ? constructFlowNode<FlowESTree.Variance>({
1688
+ type: 'Variance',
1689
+ kind: 'plus',
1690
+ })
1691
+ : null;
1692
+ if (prop.computed === false) {
1693
+ const key = prop.key;
1694
+ properties.push(
1695
+ constructFlowNode<FlowESTree.ObjectTypePropertySignature>({
1696
+ type: 'ObjectTypeProperty',
1697
+ kind: 'init',
1698
+ method: false,
1699
+ optional: Boolean(prop.optional),
1700
+ static: false,
1701
+ proto: false,
1702
+ variance,
1703
+ key:
1704
+ key.type === 'Identifier'
1705
+ ? Transform.Identifier(key, false)
1706
+ : key.type === 'PrivateIdentifier'
1707
+ ? (constructFlowNode<FlowESTree.PrivateIdentifier>({
1708
+ type: 'PrivateIdentifier',
1709
+ name: key.name,
1710
+ }): $FlowFixMe)
1711
+ : constructFlowNode<FlowESTree.StringLiteral>({
1712
+ type: 'Literal',
1713
+ literalType: 'string',
1714
+ value: String(key.value),
1715
+ raw: JSON.stringify(String(key.value)),
1716
+ }),
1717
+ value: Transform.TSTypeAnnotationOpt(
1718
+ prop.typeAnnotation?.typeAnnotation,
1719
+ ),
1720
+ }),
1721
+ );
1722
+ } else {
1723
+ indexers.push(
1724
+ constructFlowNode<FlowESTree.ObjectTypeIndexer>({
1725
+ type: 'ObjectTypeIndexer',
1726
+ kind: 'init',
1727
+ method: false,
1728
+ optional: Boolean(prop.optional),
1729
+ static: false,
1730
+ proto: false,
1731
+ variance,
1732
+ id: null,
1733
+ key: constructFlowNode<FlowESTree.StringTypeAnnotation>({
1734
+ type: 'StringTypeAnnotation',
1735
+ }),
1736
+ value: Transform.TSTypeAnnotationOpt(
1737
+ prop.typeAnnotation?.typeAnnotation,
1738
+ ),
1739
+ }),
1740
+ );
1741
+ }
1742
+ }
1743
+
1744
+ static _translateIntoObjectMethod(
1745
+ prop:
1746
+ | TSESTree.TSMethodSignatureComputedName
1747
+ | TSESTree.TSMethodSignatureNonComputedName
1748
+ | TSESTree.MethodDefinitionComputedName
1749
+ | TSESTree.MethodDefinitionNonComputedName
1750
+ | TSESTree.TSAbstractMethodDefinitionComputedName
1751
+ | TSESTree.TSAbstractMethodDefinitionNonComputedName,
1752
+ properties: Array<FlowESTree.ObjectTypeProperty>,
1753
+ ): void {
1754
+ if (prop.computed === true) {
1755
+ throw translationError(prop, 'computed method signature');
1756
+ }
1757
+ const originalKey = prop.key;
1758
+ const key: FlowESTree.Identifier | FlowESTree.StringLiteral =
1759
+ originalKey.type === 'Identifier'
1760
+ ? Transform.Identifier(originalKey, false)
1761
+ : originalKey.type === 'PrivateIdentifier'
1762
+ ? (constructFlowNode<FlowESTree.PrivateIdentifier>({
1763
+ type: 'PrivateIdentifier',
1764
+ name: originalKey.name,
1765
+ }): $FlowFixMe)
1766
+ : constructFlowNode<FlowESTree.StringLiteral>({
1767
+ type: 'Literal',
1768
+ literalType: 'string',
1769
+ value: String(originalKey.value),
1770
+ raw: JSON.stringify(String(originalKey.value)),
1771
+ });
1772
+ const value = Transform.TSFunctionType(
1773
+ {
1774
+ type: 'TSFunctionType',
1775
+ loc: prop.loc,
1776
+ params:
1777
+ prop.type === 'MethodDefinition' ||
1778
+ prop.type === 'TSAbstractMethodDefinition'
1779
+ ? prop.value.params
1780
+ : prop.params,
1781
+ returnType:
1782
+ prop.type === 'MethodDefinition' ||
1783
+ prop.type === 'TSAbstractMethodDefinition'
1784
+ ? prop.value.returnType
1785
+ : prop.returnType,
1786
+ typeParameters: prop.typeParameters,
1787
+ },
1788
+ true,
1789
+ );
1790
+ if (prop.kind === 'method' || prop.kind === 'constructor') {
1791
+ properties.push(
1792
+ constructFlowNode<FlowESTree.ObjectTypeMethodSignature>({
1793
+ type: 'ObjectTypeProperty',
1794
+ kind: 'init',
1795
+ method: true,
1796
+ optional: false,
1797
+ static: false,
1798
+ proto: false,
1799
+ variance: null,
1800
+ key,
1801
+ value,
1802
+ }),
1803
+ );
1804
+ } else {
1805
+ properties.push(
1806
+ constructFlowNode<FlowESTree.ObjectTypeAccessorSignature>({
1807
+ type: 'ObjectTypeProperty',
1808
+ kind: prop.kind,
1809
+ method: false,
1810
+ optional: false,
1811
+ static: false,
1812
+ proto: false,
1813
+ variance: null,
1814
+ key,
1815
+ value,
1816
+ }),
1817
+ );
1818
+ }
1819
+ }
1820
+
1821
+ static TSTypeOperator(
1822
+ node: TSESTree.TSTypeOperator,
1823
+ ): FlowESTree.TypeAnnotationType {
1824
+ switch (node.operator) {
1825
+ case 'unique':
1826
+ return unsupportedAnnotation(node, 'unique operator');
1827
+ case 'keyof':
1828
+ return constructFlowNode<FlowESTree.KeyofTypeAnnotation>({
1829
+ type: 'KeyofTypeAnnotation',
1830
+ argument: Transform.TSTypeAnnotationOpt(node.typeAnnotation),
1831
+ });
1832
+ case 'readonly': {
1833
+ const child = node.typeAnnotation;
1834
+ switch (child?.type) {
1835
+ case 'TSArrayType':
1836
+ return constructFlowNode<FlowESTree.GenericTypeAnnotation>({
1837
+ type: 'GenericTypeAnnotation',
1838
+ id: constructFlowNode<FlowESTree.Identifier>({
1839
+ type: 'Identifier',
1840
+ name: '$ReadOnlyArray',
1841
+ optional: false,
1842
+ typeAnnotation: null,
1843
+ }),
1844
+ typeParameters:
1845
+ constructFlowNode<FlowESTree.TypeParameterInstantiation>({
1846
+ type: 'TypeParameterInstantiation',
1847
+ params: [Transform.TSTypeAnnotation(child.elementType)],
1848
+ }),
1849
+ });
1850
+ case 'TSTupleType':
1851
+ return constructFlowNode<FlowESTree.GenericTypeAnnotation>({
1852
+ type: 'GenericTypeAnnotation',
1853
+ id: constructFlowNode<FlowESTree.Identifier>({
1854
+ type: 'Identifier',
1855
+ name: '$ReadOnly',
1856
+ optional: false,
1857
+ typeAnnotation: null,
1858
+ }),
1859
+ typeParameters:
1860
+ constructFlowNode<FlowESTree.TypeParameterInstantiation>({
1861
+ type: 'TypeParameterInstantiation',
1862
+ params: [Transform.TSTypeAnnotation(child)],
1863
+ }),
1864
+ });
1865
+ default:
1866
+ return unsupportedAnnotation(
1867
+ node,
1868
+ 'readonly operator with inner type: ' + (child?.type || 'null'),
1869
+ );
1870
+ }
1871
+ }
1872
+ }
1873
+ }
1874
+
1875
+ static TSTypeParameter(
1876
+ node: TSESTree.TSTypeParameter,
1877
+ ): FlowESTree.TypeParameter {
1878
+ return constructFlowNode<FlowESTree.TypeParameter>({
1879
+ type: 'TypeParameter',
1880
+ name: node.name.name,
1881
+ bound:
1882
+ node.constraint == null
1883
+ ? null
1884
+ : constructFlowNode<FlowESTree.TypeAnnotation>({
1885
+ type: 'TypeAnnotation',
1886
+ typeAnnotation: Transform.TSTypeAnnotation(node.constraint),
1887
+ }),
1888
+ default:
1889
+ node.default == null
1890
+ ? null
1891
+ : Transform.TSTypeAnnotation(node.default),
1892
+ usesExtendsBound: false,
1893
+ variance:
1894
+ (node.in && node.out) || (!node.in && !node.out)
1895
+ ? null
1896
+ : constructFlowNode<FlowESTree.Variance>({
1897
+ type: 'Variance',
1898
+ kind: node.out ? 'plus' : 'minus',
1899
+ }),
1900
+ });
1901
+ }
1902
+
1903
+ static TSTypeParameterDeclaration(
1904
+ node: TSESTree.TSTypeParameterDeclaration,
1905
+ ): FlowESTree.TypeParameterDeclaration {
1906
+ return constructFlowNode<FlowESTree.TypeParameterDeclaration>({
1907
+ type: 'TypeParameterDeclaration',
1908
+ params: node.params.map(node => Transform.TSTypeParameter(node)),
1909
+ });
1910
+ }
1911
+
1912
+ static TSTypeParameterDeclarationOpt(
1913
+ node: ?TSESTree.TSTypeParameterDeclaration,
1914
+ ): FlowESTree.TypeParameterDeclaration | null {
1915
+ return node != null ? Transform.TSTypeParameterDeclaration(node) : null;
1916
+ }
1917
+
1918
+ static TSTypeParameterInstantiation(
1919
+ node: TSESTree.TSTypeParameterInstantiation,
1920
+ ): FlowESTree.TypeParameterInstantiation {
1921
+ return constructFlowNode<FlowESTree.TypeParameterInstantiation>({
1922
+ type: 'TypeParameterInstantiation',
1923
+ params: node.params.map(node => Transform.TSTypeAnnotation(node)),
1924
+ });
1925
+ }
1926
+
1927
+ static TSTypeParameterInstantiationOpt(
1928
+ node: ?TSESTree.TSTypeParameterInstantiation,
1929
+ ): FlowESTree.TypeParameterInstantiation | null {
1930
+ return node != null ? Transform.TSTypeParameterInstantiation(node) : null;
1931
+ }
1932
+
1933
+ static TSTypePredicate(
1934
+ node: TSESTree.TSTypePredicate,
1935
+ ): FlowESTree.TypePredicate {
1936
+ return constructFlowNode<FlowESTree.TypePredicate>({
1937
+ type: 'TypePredicate',
1938
+ parameterName:
1939
+ node.parameterName.type === 'TSThisType'
1940
+ ? constructFlowNode<FlowESTree.Identifier>({
1941
+ type: 'Identifier',
1942
+ name: 'this',
1943
+ optional: false,
1944
+ typeAnnotation: null,
1945
+ })
1946
+ : Transform.Identifier(node.parameterName, false),
1947
+ kind: node.asserts ? 'asserts' : null,
1948
+ typeAnnotation:
1949
+ node.typeAnnotation == null
1950
+ ? null
1951
+ : Transform.TSTypeAnnotation(node.typeAnnotation.typeAnnotation),
1952
+ });
1953
+ }
1954
+
1955
+ static TSTypeQuery(
1956
+ node: TSESTree.TSTypeQuery,
1957
+ ): FlowESTree.TypeofTypeAnnotation {
1958
+ return constructFlowNode<FlowESTree.TypeofTypeAnnotation>({
1959
+ type: 'TypeofTypeAnnotation',
1960
+ argument: Transform.EntityNameToTypeofIdentifier(node.exprName),
1961
+ typeArguments:
1962
+ Transform.TSTypeParameterInstantiationOpt(node.typeParameters) ??
1963
+ undefined,
1964
+ });
1965
+ }
1966
+
1967
+ static TSTypeReference(
1968
+ node: TSESTree.TSTypeReference,
1969
+ ): FlowESTree.GenericTypeAnnotation {
1970
+ return constructFlowNode<FlowESTree.GenericTypeAnnotation>({
1971
+ type: 'GenericTypeAnnotation',
1972
+ id: Transform.EntityNameToTypeIdentifier(node.typeName),
1973
+ typeParameters: Transform.TSTypeParameterInstantiationOpt(
1974
+ node.typeParameters,
1975
+ ),
1976
+ });
1977
+ }
1978
+
1979
+ static TSUndefinedOrVoidType(): FlowESTree.VoidTypeAnnotation {
1980
+ return constructFlowNode<FlowESTree.VoidTypeAnnotation>({
1981
+ type: 'VoidTypeAnnotation',
1982
+ });
1983
+ }
1984
+
1985
+ static TSUnionType(
1986
+ node: TSESTree.TSUnionType,
1987
+ ): FlowESTree.UnionTypeAnnotation {
1988
+ return constructFlowNode<FlowESTree.UnionTypeAnnotation>({
1989
+ type: 'UnionTypeAnnotation',
1990
+ types: node.types.map(node => Transform.TSTypeAnnotation(node)),
1991
+ });
1992
+ }
1993
+
1994
+ static TSUnknownType(): FlowESTree.MixedTypeAnnotation {
1995
+ return constructFlowNode<FlowESTree.MixedTypeAnnotation>({
1996
+ type: 'MixedTypeAnnotation',
1997
+ });
1998
+ }
1999
+
2000
+ static VariableDeclaration(
2001
+ node: TSESTree.VariableDeclaration,
2002
+ ): $ReadOnlyArray<FlowESTree.DeclareVariable> {
2003
+ return node.declarations.map(decl => {
2004
+ if (decl.id.type !== 'Identifier') {
2005
+ throw translationError(
2006
+ decl.id,
2007
+ 'Non-identifier variable declaration',
2008
+ );
2009
+ }
2010
+ const id = Transform.Identifier(decl.id);
2011
+ if (id.typeAnnotation == null) {
2012
+ // $FlowExpectedError[cannot-write]
2013
+ id.typeAnnotation = constructFlowNode<FlowESTree.TypeAnnotation>({
2014
+ type: 'TypeAnnotation',
2015
+ typeAnnotation: constructFlowNode<FlowESTree.AnyTypeAnnotation>({
2016
+ type: 'AnyTypeAnnotation',
2017
+ }),
2018
+ });
2019
+ }
2020
+ return constructFlowNode<FlowESTree.DeclareVariable>({
2021
+ type: 'DeclareVariable',
2022
+ id,
2023
+ kind: node.kind,
2024
+ });
2025
+ });
2026
+ }
2027
+ }
2028
+
2029
+ return [Transform, code];
2030
+ };