flow-api-translator 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flowDefToTSDef.js +941 -564
- package/dist/flowDefToTSDef.js.flow +1065 -609
- package/dist/flowToFlowDef.js +2 -1
- package/dist/flowToFlowDef.js.flow +1 -0
- package/dist/index.js +4 -2
- package/dist/index.js.flow +4 -2
- package/dist/utils/ErrorUtils.js +3 -2
- package/dist/utils/ErrorUtils.js.flow +5 -4
- package/package.json +1 -1
|
@@ -13,25 +13,44 @@
|
|
|
13
13
|
import type {ObjectWithLoc} from 'hermes-estree';
|
|
14
14
|
import * as FlowESTree from 'hermes-estree';
|
|
15
15
|
import type {ScopeManager} from 'hermes-eslint';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
cloneJSDocCommentsToNewNode as cloneJSDocCommentsToNewNodeOriginal,
|
|
18
|
+
makeCommentOwnLine as makeCommentOwnLineOriginal,
|
|
19
|
+
} from 'hermes-transform';
|
|
17
20
|
import * as TSESTree from './utils/ts-estree-ast-types';
|
|
18
21
|
import {
|
|
22
|
+
buildCodeFrame,
|
|
19
23
|
translationError as translationErrorBase,
|
|
20
24
|
unexpectedTranslationError as unexpectedTranslationErrorBase,
|
|
21
25
|
} from './utils/ErrorUtils';
|
|
22
26
|
import {removeAtFlowFromDocblock} from './utils/DocblockUtils';
|
|
27
|
+
import type {TranslationOptions} from './utils/TranslationUtils';
|
|
28
|
+
import {EOL} from 'os';
|
|
29
|
+
|
|
30
|
+
type DeclarationOrUnsupported<T> = T | TSESTree.TSTypeAliasDeclaration;
|
|
23
31
|
|
|
24
32
|
const cloneJSDocCommentsToNewNode =
|
|
25
33
|
// $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
|
|
26
34
|
(cloneJSDocCommentsToNewNodeOriginal: (mixed, mixed) => void);
|
|
27
35
|
|
|
36
|
+
const makeCommentOwnLine =
|
|
37
|
+
// $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
|
|
38
|
+
(makeCommentOwnLineOriginal: (string, mixed) => string);
|
|
39
|
+
|
|
28
40
|
const VALID_REACT_IMPORTS = new Set<string>(['React', 'react']);
|
|
29
41
|
|
|
42
|
+
function isValidReactImportOrGlobal(id: FlowESTree.Identifier): boolean {
|
|
43
|
+
return VALID_REACT_IMPORTS.has(id.name) || id.name.startsWith('React$');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let shouldAddReactImport: boolean | null = null;
|
|
47
|
+
|
|
30
48
|
export function flowDefToTSDef(
|
|
31
49
|
originalCode: string,
|
|
32
50
|
ast: FlowESTree.Program,
|
|
33
51
|
scopeManager: ScopeManager,
|
|
34
|
-
|
|
52
|
+
opts: TranslationOptions,
|
|
53
|
+
): [TSESTree.Program, string] {
|
|
35
54
|
const tsBody: Array<TSESTree.ProgramStatement> = [];
|
|
36
55
|
const tsProgram: TSESTree.Program = {
|
|
37
56
|
type: 'Program',
|
|
@@ -41,7 +60,9 @@ export function flowDefToTSDef(
|
|
|
41
60
|
ast.docblock == null ? null : removeAtFlowFromDocblock(ast.docblock),
|
|
42
61
|
};
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
shouldAddReactImport = null;
|
|
64
|
+
|
|
65
|
+
const [transform, code] = getTransforms(originalCode, scopeManager, opts);
|
|
45
66
|
|
|
46
67
|
for (const node of ast.body) {
|
|
47
68
|
if (node.type in transform) {
|
|
@@ -58,26 +79,117 @@ export function flowDefToTSDef(
|
|
|
58
79
|
throw unexpectedTranslationErrorBase(
|
|
59
80
|
node,
|
|
60
81
|
`Unexpected node type ${node.type}`,
|
|
61
|
-
{code
|
|
82
|
+
{code},
|
|
62
83
|
);
|
|
63
84
|
}
|
|
64
85
|
}
|
|
65
86
|
|
|
66
|
-
|
|
87
|
+
if (shouldAddReactImport === true) {
|
|
88
|
+
tsBody.unshift({
|
|
89
|
+
type: 'ImportDeclaration',
|
|
90
|
+
assertions: [],
|
|
91
|
+
source: {
|
|
92
|
+
type: 'Literal',
|
|
93
|
+
value: 'react',
|
|
94
|
+
raw: "'react'",
|
|
95
|
+
},
|
|
96
|
+
specifiers: [
|
|
97
|
+
{
|
|
98
|
+
type: 'ImportNamespaceSpecifier',
|
|
99
|
+
local: {
|
|
100
|
+
type: 'Identifier',
|
|
101
|
+
name: 'React',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
importKind: 'value',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return [tsProgram, code];
|
|
67
110
|
}
|
|
68
111
|
|
|
69
|
-
const getTransforms = (
|
|
112
|
+
const getTransforms = (
|
|
113
|
+
originalCode: string,
|
|
114
|
+
scopeManager: ScopeManager,
|
|
115
|
+
opts: TranslationOptions,
|
|
116
|
+
) => {
|
|
117
|
+
let code = originalCode;
|
|
70
118
|
function translationError(node: ObjectWithLoc, message: string) {
|
|
71
119
|
return translationErrorBase(node, message, {code});
|
|
72
120
|
}
|
|
73
121
|
function unexpectedTranslationError(node: ObjectWithLoc, message: string) {
|
|
74
122
|
return unexpectedTranslationErrorBase(node, message, {code});
|
|
75
123
|
}
|
|
76
|
-
function
|
|
77
|
-
return
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
124
|
+
function unsupportedFeatureMessage(thing: string) {
|
|
125
|
+
return `Unsupported feature: Translating "${thing}" is currently not supported.`;
|
|
126
|
+
}
|
|
127
|
+
function buildCodeFrameForComment(node: ObjectWithLoc, message: string) {
|
|
128
|
+
return buildCodeFrame(node, message, code, false);
|
|
129
|
+
}
|
|
130
|
+
function addErrorComment(node: TSESTree.Node, message: string): void {
|
|
131
|
+
const comment = {
|
|
132
|
+
type: 'Block',
|
|
133
|
+
value: `*${EOL} * ${message.replace(
|
|
134
|
+
new RegExp(EOL, 'g'),
|
|
135
|
+
`${EOL} * `,
|
|
136
|
+
)}${EOL}*`,
|
|
137
|
+
leading: true,
|
|
138
|
+
printed: false,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
code = makeCommentOwnLine(code, comment);
|
|
142
|
+
|
|
143
|
+
// $FlowExpectedError[prop-missing]
|
|
144
|
+
// $FlowExpectedError[cannot-write]
|
|
145
|
+
node.comments ??= [];
|
|
146
|
+
// $FlowExpectedError[prop-missing]
|
|
147
|
+
// $FlowExpectedError[incompatible-cast]
|
|
148
|
+
(node.comments: Array<TSESTree.Comment>).push(comment);
|
|
149
|
+
}
|
|
150
|
+
function unsupportedAnnotation(
|
|
151
|
+
node: ObjectWithLoc,
|
|
152
|
+
thing: string,
|
|
153
|
+
): TSESTree.TSAnyKeyword {
|
|
154
|
+
const message = unsupportedFeatureMessage(thing);
|
|
155
|
+
if (opts.recoverFromErrors) {
|
|
156
|
+
const codeFrame = buildCodeFrameForComment(node, message);
|
|
157
|
+
const newNode = {
|
|
158
|
+
type: 'TSAnyKeyword',
|
|
159
|
+
};
|
|
160
|
+
addErrorComment(newNode, codeFrame);
|
|
161
|
+
return newNode;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
throw translationError(node, message);
|
|
165
|
+
}
|
|
166
|
+
function unsupportedDeclaration(
|
|
167
|
+
node: ObjectWithLoc,
|
|
168
|
+
thing: string,
|
|
169
|
+
id: FlowESTree.Identifier,
|
|
170
|
+
declare: boolean = false,
|
|
171
|
+
typeParameters: FlowESTree.TypeParameterDeclaration | null = null,
|
|
172
|
+
): TSESTree.TSTypeAliasDeclaration {
|
|
173
|
+
const message = unsupportedFeatureMessage(thing);
|
|
174
|
+
if (opts.recoverFromErrors) {
|
|
175
|
+
const codeFrame = buildCodeFrameForComment(node, message);
|
|
176
|
+
const newNode = {
|
|
177
|
+
type: 'TSTypeAliasDeclaration',
|
|
178
|
+
declare,
|
|
179
|
+
id: transform.Identifier(id, false),
|
|
180
|
+
typeAnnotation: {
|
|
181
|
+
type: 'TSAnyKeyword',
|
|
182
|
+
},
|
|
183
|
+
typeParameters:
|
|
184
|
+
typeParameters == null
|
|
185
|
+
? undefined
|
|
186
|
+
: transform.TypeParameterDeclaration(typeParameters),
|
|
187
|
+
};
|
|
188
|
+
addErrorComment(newNode, codeFrame);
|
|
189
|
+
return newNode;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
throw translationError(node, message);
|
|
81
193
|
}
|
|
82
194
|
|
|
83
195
|
const topScope = (() => {
|
|
@@ -92,7 +204,20 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
92
204
|
})();
|
|
93
205
|
|
|
94
206
|
function isReactImport(id: FlowESTree.Identifier): boolean {
|
|
95
|
-
let currentScope =
|
|
207
|
+
let currentScope = (() => {
|
|
208
|
+
let scope = null;
|
|
209
|
+
let node: FlowESTree.ESNode = id;
|
|
210
|
+
while (!scope && node) {
|
|
211
|
+
scope = scopeManager.acquire(node, true);
|
|
212
|
+
node = node.parent;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return scope;
|
|
216
|
+
})();
|
|
217
|
+
|
|
218
|
+
if (currentScope == null) {
|
|
219
|
+
throw new Error('unable to resolve scope');
|
|
220
|
+
}
|
|
96
221
|
|
|
97
222
|
const variableDef = (() => {
|
|
98
223
|
while (currentScope != null) {
|
|
@@ -105,9 +230,10 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
105
230
|
}
|
|
106
231
|
})();
|
|
107
232
|
|
|
108
|
-
// No variable found, it
|
|
233
|
+
// No variable found, it is not imported.
|
|
234
|
+
// It could be a global though if isValidReactImportOrGlobal returns true.
|
|
109
235
|
if (variableDef == null) {
|
|
110
|
-
return
|
|
236
|
+
return false;
|
|
111
237
|
}
|
|
112
238
|
|
|
113
239
|
const def = variableDef.defs[0];
|
|
@@ -138,6 +264,407 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
138
264
|
return false;
|
|
139
265
|
}
|
|
140
266
|
|
|
267
|
+
function EnumImpl(
|
|
268
|
+
node: FlowESTree.EnumDeclaration | FlowESTree.DeclareEnum,
|
|
269
|
+
): DeclarationOrUnsupported<
|
|
270
|
+
[TSESTree.TSEnumDeclaration, TSESTree.TSModuleDeclaration],
|
|
271
|
+
> {
|
|
272
|
+
const body = node.body;
|
|
273
|
+
if (body.type === 'EnumSymbolBody') {
|
|
274
|
+
/*
|
|
275
|
+
There's unfortunately no way for us to support this in a clean way.
|
|
276
|
+
We can get really close using this code:
|
|
277
|
+
```
|
|
278
|
+
declare namespace SymbolEnum {
|
|
279
|
+
export const member1: unique symbol;
|
|
280
|
+
export type member1 = typeof member1;
|
|
281
|
+
|
|
282
|
+
export const member2: unique symbol;
|
|
283
|
+
export type member2 = typeof member2;
|
|
284
|
+
}
|
|
285
|
+
type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
However as explained in https://github.com/microsoft/TypeScript/issues/43657:
|
|
289
|
+
"A unique symbol type is never transferred from one declaration to another through inference."
|
|
290
|
+
This intended behaviour in TS means that the usage of the fake-enum would look like this:
|
|
291
|
+
```
|
|
292
|
+
const value: SymbolEnum.member1 = SymbolEnum.member1;
|
|
293
|
+
// ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
|
|
294
|
+
```
|
|
295
|
+
Which is really clunky and shitty. It definitely works, but ofc it's not good.
|
|
296
|
+
We can go with this design if users are okay with it!
|
|
297
|
+
|
|
298
|
+
Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
|
|
299
|
+
*/
|
|
300
|
+
return unsupportedDeclaration(
|
|
301
|
+
node,
|
|
302
|
+
'symbol enums',
|
|
303
|
+
node.id,
|
|
304
|
+
FlowESTree.isDeclareEnum(node),
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
if (body.type === 'EnumBooleanBody') {
|
|
308
|
+
/*
|
|
309
|
+
TODO - TS enums only allow strings or numbers as their values - not booleans.
|
|
310
|
+
This means we need a non-ts-enum representation of the enum.
|
|
311
|
+
We can support boolean enums using a construct like this:
|
|
312
|
+
```ts
|
|
313
|
+
declare namespace BooleanEnum {
|
|
314
|
+
export const member1: true;
|
|
315
|
+
export type member1 = typeof member1;
|
|
316
|
+
|
|
317
|
+
export const member2: false;
|
|
318
|
+
export type member2 = typeof member1;
|
|
319
|
+
}
|
|
320
|
+
declare type BooleanEnum = boolean;
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
But it's pretty clunky and ugly.
|
|
324
|
+
Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
|
|
325
|
+
*/
|
|
326
|
+
return unsupportedDeclaration(
|
|
327
|
+
node,
|
|
328
|
+
'boolean enums',
|
|
329
|
+
node.id,
|
|
330
|
+
FlowESTree.isDeclareEnum(node),
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const members: Array<TSESTree.TSEnumMemberNonComputedName> = [];
|
|
335
|
+
for (const member of body.members) {
|
|
336
|
+
switch (member.type) {
|
|
337
|
+
case 'EnumDefaultedMember': {
|
|
338
|
+
if (body.type === 'EnumNumberBody') {
|
|
339
|
+
// this should be impossible!
|
|
340
|
+
throw unexpectedTranslationError(
|
|
341
|
+
member,
|
|
342
|
+
'Unexpected defaulted number enum member',
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
members.push({
|
|
346
|
+
type: 'TSEnumMember',
|
|
347
|
+
computed: false,
|
|
348
|
+
id: transform.Identifier(member.id, false),
|
|
349
|
+
initializer: ({
|
|
350
|
+
type: 'Literal',
|
|
351
|
+
raw: `"${member.id.name}"`,
|
|
352
|
+
value: member.id.name,
|
|
353
|
+
}: TSESTree.StringLiteral),
|
|
354
|
+
});
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
case 'EnumNumberMember':
|
|
359
|
+
case 'EnumStringMember':
|
|
360
|
+
members.push({
|
|
361
|
+
type: 'TSEnumMember',
|
|
362
|
+
computed: false,
|
|
363
|
+
id: transform.Identifier(member.id, false),
|
|
364
|
+
initializer:
|
|
365
|
+
member.init.literalType === 'string'
|
|
366
|
+
? transform.StringLiteral(member.init)
|
|
367
|
+
: transform.NumericLiteral(member.init),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const bodyRepresentationType =
|
|
373
|
+
body.type === 'EnumNumberBody'
|
|
374
|
+
? {type: 'TSNumberKeyword'}
|
|
375
|
+
: {type: 'TSStringKeyword'};
|
|
376
|
+
|
|
377
|
+
const enumName = transform.Identifier(node.id, false);
|
|
378
|
+
return [
|
|
379
|
+
{
|
|
380
|
+
type: 'TSEnumDeclaration',
|
|
381
|
+
const: false,
|
|
382
|
+
declare: true,
|
|
383
|
+
id: enumName,
|
|
384
|
+
members,
|
|
385
|
+
},
|
|
386
|
+
// flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
|
|
387
|
+
// we can use declaration merging to declare these functions on the enum:
|
|
388
|
+
/*
|
|
389
|
+
declare enum Foo {
|
|
390
|
+
A = 1,
|
|
391
|
+
B = 2,
|
|
392
|
+
}
|
|
393
|
+
declare namespace Foo {
|
|
394
|
+
export function cast(value: number | null | undefined): Foo;
|
|
395
|
+
export function isValid(value: number | null | undefined): value is Foo;
|
|
396
|
+
export function members(): IterableIterator<Foo>;
|
|
397
|
+
export function getName(value: Foo): string;
|
|
398
|
+
}
|
|
399
|
+
*/
|
|
400
|
+
{
|
|
401
|
+
type: 'TSModuleDeclaration',
|
|
402
|
+
declare: true,
|
|
403
|
+
id: enumName,
|
|
404
|
+
body: {
|
|
405
|
+
type: 'TSModuleBlock',
|
|
406
|
+
body: [
|
|
407
|
+
// export function cast(value: number | null | undefined): Foo
|
|
408
|
+
{
|
|
409
|
+
type: 'ExportNamedDeclaration',
|
|
410
|
+
declaration: {
|
|
411
|
+
type: 'TSDeclareFunction',
|
|
412
|
+
id: {
|
|
413
|
+
type: 'Identifier',
|
|
414
|
+
name: 'cast',
|
|
415
|
+
},
|
|
416
|
+
generator: false,
|
|
417
|
+
expression: false,
|
|
418
|
+
async: false,
|
|
419
|
+
params: [
|
|
420
|
+
{
|
|
421
|
+
type: 'Identifier',
|
|
422
|
+
name: 'value',
|
|
423
|
+
typeAnnotation: {
|
|
424
|
+
type: 'TSTypeAnnotation',
|
|
425
|
+
typeAnnotation: {
|
|
426
|
+
type: 'TSUnionType',
|
|
427
|
+
types: [
|
|
428
|
+
bodyRepresentationType,
|
|
429
|
+
{
|
|
430
|
+
type: 'TSNullKeyword',
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
type: 'TSUndefinedKeyword',
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
],
|
|
440
|
+
returnType: {
|
|
441
|
+
type: 'TSTypeAnnotation',
|
|
442
|
+
typeAnnotation: {
|
|
443
|
+
type: 'TSTypeReference',
|
|
444
|
+
typeName: enumName,
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
specifiers: [],
|
|
449
|
+
source: null,
|
|
450
|
+
exportKind: 'value',
|
|
451
|
+
assertions: [],
|
|
452
|
+
},
|
|
453
|
+
// export function isValid(value: number | null | undefined): value is Foo;
|
|
454
|
+
{
|
|
455
|
+
type: 'ExportNamedDeclaration',
|
|
456
|
+
declaration: {
|
|
457
|
+
type: 'TSDeclareFunction',
|
|
458
|
+
id: {
|
|
459
|
+
type: 'Identifier',
|
|
460
|
+
name: 'isValid',
|
|
461
|
+
},
|
|
462
|
+
generator: false,
|
|
463
|
+
expression: false,
|
|
464
|
+
async: false,
|
|
465
|
+
params: [
|
|
466
|
+
{
|
|
467
|
+
type: 'Identifier',
|
|
468
|
+
name: 'value',
|
|
469
|
+
typeAnnotation: {
|
|
470
|
+
type: 'TSTypeAnnotation',
|
|
471
|
+
typeAnnotation: {
|
|
472
|
+
type: 'TSUnionType',
|
|
473
|
+
types: [
|
|
474
|
+
bodyRepresentationType,
|
|
475
|
+
{
|
|
476
|
+
type: 'TSNullKeyword',
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
type: 'TSUndefinedKeyword',
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
returnType: {
|
|
487
|
+
type: 'TSTypeAnnotation',
|
|
488
|
+
typeAnnotation: {
|
|
489
|
+
type: 'TSTypePredicate',
|
|
490
|
+
asserts: false,
|
|
491
|
+
parameterName: {
|
|
492
|
+
type: 'Identifier',
|
|
493
|
+
name: 'value',
|
|
494
|
+
},
|
|
495
|
+
typeAnnotation: {
|
|
496
|
+
type: 'TSTypeAnnotation',
|
|
497
|
+
typeAnnotation: {
|
|
498
|
+
type: 'TSTypeReference',
|
|
499
|
+
typeName: enumName,
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
specifiers: [],
|
|
506
|
+
source: null,
|
|
507
|
+
exportKind: 'value',
|
|
508
|
+
assertions: [],
|
|
509
|
+
},
|
|
510
|
+
// export function members(): IterableIterator<Foo>;
|
|
511
|
+
{
|
|
512
|
+
type: 'ExportNamedDeclaration',
|
|
513
|
+
declaration: {
|
|
514
|
+
type: 'TSDeclareFunction',
|
|
515
|
+
id: {
|
|
516
|
+
type: 'Identifier',
|
|
517
|
+
name: 'members',
|
|
518
|
+
},
|
|
519
|
+
generator: false,
|
|
520
|
+
expression: false,
|
|
521
|
+
async: false,
|
|
522
|
+
params: [],
|
|
523
|
+
returnType: {
|
|
524
|
+
type: 'TSTypeAnnotation',
|
|
525
|
+
typeAnnotation: {
|
|
526
|
+
type: 'TSTypeReference',
|
|
527
|
+
typeName: {
|
|
528
|
+
type: 'Identifier',
|
|
529
|
+
name: 'IterableIterator',
|
|
530
|
+
},
|
|
531
|
+
typeParameters: {
|
|
532
|
+
type: 'TSTypeParameterInstantiation',
|
|
533
|
+
params: [
|
|
534
|
+
{
|
|
535
|
+
type: 'TSTypeReference',
|
|
536
|
+
typeName: enumName,
|
|
537
|
+
},
|
|
538
|
+
],
|
|
539
|
+
},
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
specifiers: [],
|
|
544
|
+
source: null,
|
|
545
|
+
exportKind: 'value',
|
|
546
|
+
assertions: [],
|
|
547
|
+
},
|
|
548
|
+
// export function getName(value: Foo): string;
|
|
549
|
+
{
|
|
550
|
+
type: 'ExportNamedDeclaration',
|
|
551
|
+
declaration: {
|
|
552
|
+
type: 'TSDeclareFunction',
|
|
553
|
+
id: {
|
|
554
|
+
type: 'Identifier',
|
|
555
|
+
name: 'getName',
|
|
556
|
+
},
|
|
557
|
+
generator: false,
|
|
558
|
+
expression: false,
|
|
559
|
+
async: false,
|
|
560
|
+
params: [
|
|
561
|
+
{
|
|
562
|
+
type: 'Identifier',
|
|
563
|
+
name: 'value',
|
|
564
|
+
typeAnnotation: {
|
|
565
|
+
type: 'TSTypeAnnotation',
|
|
566
|
+
typeAnnotation: {
|
|
567
|
+
type: 'TSTypeReference',
|
|
568
|
+
typeName: enumName,
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
],
|
|
573
|
+
returnType: {
|
|
574
|
+
type: 'TSTypeAnnotation',
|
|
575
|
+
typeAnnotation: {
|
|
576
|
+
type: 'TSStringKeyword',
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
specifiers: [],
|
|
581
|
+
source: null,
|
|
582
|
+
exportKind: 'value',
|
|
583
|
+
assertions: [],
|
|
584
|
+
},
|
|
585
|
+
],
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
];
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const getPlaceholderNameForTypeofImport: () => string = (() => {
|
|
592
|
+
let typeof_import_count = 0;
|
|
593
|
+
return () => `$$IMPORT_TYPEOF_${++typeof_import_count}$$`;
|
|
594
|
+
})();
|
|
595
|
+
|
|
596
|
+
const transformTypeAnnotationType = (
|
|
597
|
+
node: FlowESTree.TypeAnnotationType,
|
|
598
|
+
): TSESTree.TypeNode => {
|
|
599
|
+
switch (node.type) {
|
|
600
|
+
case 'AnyTypeAnnotation':
|
|
601
|
+
return transform.AnyTypeAnnotation(node);
|
|
602
|
+
case 'ArrayTypeAnnotation':
|
|
603
|
+
return transform.ArrayTypeAnnotation(node);
|
|
604
|
+
case 'BigIntLiteralTypeAnnotation':
|
|
605
|
+
return transform.BigIntLiteralTypeAnnotation(node);
|
|
606
|
+
case 'BigIntTypeAnnotation':
|
|
607
|
+
return transform.BigIntTypeAnnotation(node);
|
|
608
|
+
case 'BooleanLiteralTypeAnnotation':
|
|
609
|
+
return transform.BooleanLiteralTypeAnnotation(node);
|
|
610
|
+
case 'BooleanTypeAnnotation':
|
|
611
|
+
return transform.BooleanTypeAnnotation(node);
|
|
612
|
+
case 'EmptyTypeAnnotation':
|
|
613
|
+
return transform.EmptyTypeAnnotation(node);
|
|
614
|
+
case 'ExistsTypeAnnotation':
|
|
615
|
+
return transform.ExistsTypeAnnotation(node);
|
|
616
|
+
case 'FunctionTypeAnnotation':
|
|
617
|
+
return transform.FunctionTypeAnnotation(node);
|
|
618
|
+
case 'GenericTypeAnnotation':
|
|
619
|
+
return transform.GenericTypeAnnotation(node);
|
|
620
|
+
case 'IndexedAccessType':
|
|
621
|
+
return transform.IndexedAccessType(node);
|
|
622
|
+
case 'InterfaceTypeAnnotation':
|
|
623
|
+
return transform.InterfaceTypeAnnotation(node);
|
|
624
|
+
case 'IntersectionTypeAnnotation':
|
|
625
|
+
return transform.IntersectionTypeAnnotation(node);
|
|
626
|
+
case 'MixedTypeAnnotation':
|
|
627
|
+
return transform.MixedTypeAnnotation(node);
|
|
628
|
+
case 'NullLiteralTypeAnnotation':
|
|
629
|
+
return transform.NullLiteralTypeAnnotation(node);
|
|
630
|
+
case 'NullableTypeAnnotation':
|
|
631
|
+
return transform.NullableTypeAnnotation(node);
|
|
632
|
+
case 'NumberLiteralTypeAnnotation':
|
|
633
|
+
return transform.NumberLiteralTypeAnnotation(node);
|
|
634
|
+
case 'NumberTypeAnnotation':
|
|
635
|
+
return transform.NumberTypeAnnotation(node);
|
|
636
|
+
case 'ObjectTypeAnnotation':
|
|
637
|
+
return transform.ObjectTypeAnnotation(node);
|
|
638
|
+
case 'OptionalIndexedAccessType':
|
|
639
|
+
return transform.OptionalIndexedAccessType(node);
|
|
640
|
+
case 'QualifiedTypeIdentifier':
|
|
641
|
+
return transform.QualifiedTypeIdentifier(node);
|
|
642
|
+
case 'StringLiteralTypeAnnotation':
|
|
643
|
+
return transform.StringLiteralTypeAnnotation(node);
|
|
644
|
+
case 'StringTypeAnnotation':
|
|
645
|
+
return transform.StringTypeAnnotation(node);
|
|
646
|
+
case 'SymbolTypeAnnotation':
|
|
647
|
+
return transform.SymbolTypeAnnotation(node);
|
|
648
|
+
case 'ThisTypeAnnotation':
|
|
649
|
+
return transform.ThisTypeAnnotation(node);
|
|
650
|
+
case 'TupleTypeAnnotation':
|
|
651
|
+
return transform.TupleTypeAnnotation(node);
|
|
652
|
+
case 'TupleTypeLabeledElement':
|
|
653
|
+
case 'TupleTypeSpreadElement':
|
|
654
|
+
return unsupportedAnnotation(node, node.type);
|
|
655
|
+
case 'TypeofTypeAnnotation':
|
|
656
|
+
return transform.TypeofTypeAnnotation(node);
|
|
657
|
+
case 'UnionTypeAnnotation':
|
|
658
|
+
return transform.UnionTypeAnnotation(node);
|
|
659
|
+
case 'VoidTypeAnnotation':
|
|
660
|
+
return transform.VoidTypeAnnotation(node);
|
|
661
|
+
case 'TypePredicate':
|
|
662
|
+
return unsupportedAnnotation(node, node.type);
|
|
663
|
+
default:
|
|
664
|
+
throw unexpectedTranslationError(node, `Unhandled type ${node.type}`);
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
|
|
141
668
|
const transform = {
|
|
142
669
|
AnyTypeAnnotation(
|
|
143
670
|
_node: FlowESTree.AnyTypeAnnotation,
|
|
@@ -151,7 +678,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
151
678
|
): TSESTree.TSArrayType {
|
|
152
679
|
return {
|
|
153
680
|
type: 'TSArrayType',
|
|
154
|
-
elementType:
|
|
681
|
+
elementType: transformTypeAnnotationType(node.elementType),
|
|
155
682
|
};
|
|
156
683
|
},
|
|
157
684
|
BigIntLiteral(node: FlowESTree.BigIntLiteral): TSESTree.BigIntLiteral {
|
|
@@ -233,13 +760,16 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
233
760
|
},
|
|
234
761
|
DeclareClass(
|
|
235
762
|
node: FlowESTree.DeclareClass,
|
|
236
|
-
): TSESTree.ClassDeclarationWithName {
|
|
763
|
+
): DeclarationOrUnsupported<TSESTree.ClassDeclarationWithName> {
|
|
237
764
|
const classMembers: Array<TSESTree.ClassElement> = [];
|
|
238
765
|
const transformedBody = transform.ObjectTypeAnnotation(node.body);
|
|
239
766
|
if (transformedBody.type !== 'TSTypeLiteral') {
|
|
240
|
-
|
|
767
|
+
return unsupportedDeclaration(
|
|
241
768
|
node.body,
|
|
242
769
|
'Spreads in declare class are not allowed',
|
|
770
|
+
node.id,
|
|
771
|
+
true,
|
|
772
|
+
node.typeParameters,
|
|
243
773
|
);
|
|
244
774
|
}
|
|
245
775
|
for (const member of transformedBody.members) {
|
|
@@ -359,9 +889,12 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
359
889
|
```
|
|
360
890
|
Let's put a pin in it for now and deal with it later if the need arises.
|
|
361
891
|
*/
|
|
362
|
-
|
|
892
|
+
return unsupportedDeclaration(
|
|
363
893
|
node.body.callProperties[0] ?? node.body,
|
|
364
894
|
'call signatures on classes',
|
|
895
|
+
node.id,
|
|
896
|
+
true,
|
|
897
|
+
node.typeParameters,
|
|
365
898
|
);
|
|
366
899
|
}
|
|
367
900
|
|
|
@@ -406,12 +939,14 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
406
939
|
node: FlowESTree.DeclareExportDeclaration,
|
|
407
940
|
):
|
|
408
941
|
| TSESTree.ExportNamedDeclaration
|
|
942
|
+
| Array<TSESTree.ExportNamedDeclaration>
|
|
409
943
|
| TSESTree.ExportDefaultDeclaration
|
|
410
944
|
| [
|
|
411
945
|
(
|
|
412
946
|
| TSESTree.VariableDeclaration
|
|
413
947
|
| TSESTree.ClassDeclaration
|
|
414
948
|
| TSESTree.TSDeclareFunction
|
|
949
|
+
| TSESTree.TSTypeAliasDeclaration
|
|
415
950
|
),
|
|
416
951
|
TSESTree.ExportDefaultDeclaration,
|
|
417
952
|
] {
|
|
@@ -543,7 +1078,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
543
1078
|
typeAnnotation: {
|
|
544
1079
|
type: 'TSTypeAnnotation',
|
|
545
1080
|
typeAnnotation:
|
|
546
|
-
|
|
1081
|
+
transformTypeAnnotationType(declaration),
|
|
547
1082
|
},
|
|
548
1083
|
},
|
|
549
1084
|
init: null,
|
|
@@ -580,45 +1115,73 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
580
1115
|
}: TSESTree.ExportNamedDeclarationWithoutSourceWithMultiple);
|
|
581
1116
|
}
|
|
582
1117
|
|
|
583
|
-
const
|
|
1118
|
+
const declarations = (() => {
|
|
584
1119
|
switch (node.declaration.type) {
|
|
585
1120
|
case 'DeclareClass':
|
|
586
|
-
return
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
1121
|
+
return [
|
|
1122
|
+
{
|
|
1123
|
+
declaration: transform.DeclareClass(node.declaration),
|
|
1124
|
+
exportKind: 'value',
|
|
1125
|
+
},
|
|
1126
|
+
];
|
|
590
1127
|
case 'DeclareFunction':
|
|
591
|
-
return
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
1128
|
+
return [
|
|
1129
|
+
{
|
|
1130
|
+
declaration: transform.DeclareFunction(node.declaration),
|
|
1131
|
+
exportKind: 'value',
|
|
1132
|
+
},
|
|
1133
|
+
];
|
|
595
1134
|
case 'DeclareInterface':
|
|
596
|
-
return
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
1135
|
+
return [
|
|
1136
|
+
{
|
|
1137
|
+
declaration: transform.DeclareInterface(node.declaration),
|
|
1138
|
+
exportKind: 'type',
|
|
1139
|
+
},
|
|
1140
|
+
];
|
|
600
1141
|
case 'DeclareOpaqueType':
|
|
601
|
-
return
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
1142
|
+
return [
|
|
1143
|
+
{
|
|
1144
|
+
declaration: transform.DeclareOpaqueType(node.declaration),
|
|
1145
|
+
exportKind: 'type',
|
|
1146
|
+
},
|
|
1147
|
+
];
|
|
605
1148
|
case 'DeclareVariable':
|
|
606
|
-
return
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
1149
|
+
return [
|
|
1150
|
+
{
|
|
1151
|
+
declaration: transform.DeclareVariable(node.declaration),
|
|
1152
|
+
exportKind: 'value',
|
|
1153
|
+
},
|
|
1154
|
+
];
|
|
1155
|
+
case 'DeclareEnum': {
|
|
1156
|
+
const result = transform.DeclareEnum(node.declaration);
|
|
1157
|
+
return Array.isArray(result)
|
|
1158
|
+
? [
|
|
1159
|
+
{
|
|
1160
|
+
declaration: result[0],
|
|
1161
|
+
exportKind: 'type',
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
declaration: result[1],
|
|
1165
|
+
exportKind: 'type',
|
|
1166
|
+
},
|
|
1167
|
+
]
|
|
1168
|
+
: [{declaration: result, exportKind: 'type'}];
|
|
1169
|
+
}
|
|
610
1170
|
}
|
|
611
1171
|
})();
|
|
612
1172
|
|
|
613
|
-
return (
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
1173
|
+
return declarations.map(
|
|
1174
|
+
({declaration, exportKind}) =>
|
|
1175
|
+
({
|
|
1176
|
+
type: 'ExportNamedDeclaration',
|
|
1177
|
+
// flow does not currently support assertions
|
|
1178
|
+
assertions: [],
|
|
1179
|
+
declaration,
|
|
1180
|
+
exportKind,
|
|
1181
|
+
source: null,
|
|
1182
|
+
specifiers: [],
|
|
1183
|
+
}: TSESTree.ExportNamedDeclarationWithoutSourceWithSingle),
|
|
1184
|
+
);
|
|
622
1185
|
} else {
|
|
623
1186
|
return ({
|
|
624
1187
|
type: 'ExportNamedDeclaration',
|
|
@@ -691,7 +1254,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
691
1254
|
type: 'TSTypeAliasDeclaration',
|
|
692
1255
|
declare: node.type === 'DeclareTypeAlias',
|
|
693
1256
|
id: transform.Identifier(node.id, false),
|
|
694
|
-
typeAnnotation:
|
|
1257
|
+
typeAnnotation: transformTypeAnnotationType(node.right),
|
|
695
1258
|
typeParameters:
|
|
696
1259
|
node.typeParameters == null
|
|
697
1260
|
? undefined
|
|
@@ -710,353 +1273,56 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
710
1273
|
declare: true,
|
|
711
1274
|
id: transform.Identifier(node.id, false),
|
|
712
1275
|
typeAnnotation:
|
|
713
|
-
node.supertype == null
|
|
714
|
-
? {
|
|
715
|
-
type: 'TSUnknownKeyword',
|
|
716
|
-
}
|
|
717
|
-
:
|
|
718
|
-
typeParameters:
|
|
719
|
-
node.typeParameters == null
|
|
720
|
-
? undefined
|
|
721
|
-
: transform.TypeParameterDeclaration(node.typeParameters),
|
|
722
|
-
};
|
|
723
|
-
},
|
|
724
|
-
DeclareVariable(
|
|
725
|
-
node: FlowESTree.DeclareVariable,
|
|
726
|
-
): TSESTree.VariableDeclaration {
|
|
727
|
-
return {
|
|
728
|
-
type: 'VariableDeclaration',
|
|
729
|
-
declare: true,
|
|
730
|
-
declarations: [
|
|
731
|
-
{
|
|
732
|
-
type: 'VariableDeclarator',
|
|
733
|
-
declare: true,
|
|
734
|
-
id: transform.Identifier(node.id, true),
|
|
735
|
-
init: null,
|
|
736
|
-
},
|
|
737
|
-
],
|
|
738
|
-
kind: 'var',
|
|
739
|
-
};
|
|
740
|
-
},
|
|
741
|
-
EmptyTypeAnnotation(
|
|
742
|
-
node: FlowESTree.EmptyTypeAnnotation,
|
|
743
|
-
): TSESTree.TypeNode {
|
|
744
|
-
// Flow's `empty` type doesn't map well to any types in TS.
|
|
745
|
-
// The closest is `never`, but `never` has a number of different semantics
|
|
746
|
-
// In reality no human code should ever directly use the `empty` type in flow
|
|
747
|
-
// So let's put a pin in it for now
|
|
748
|
-
throw unsupportedTranslationError(node, 'empty type');
|
|
749
|
-
},
|
|
750
|
-
EnumDeclaration(
|
|
751
|
-
node: FlowESTree.EnumDeclaration,
|
|
752
|
-
): [TSESTree.TSEnumDeclaration, TSESTree.TSModuleDeclaration] {
|
|
753
|
-
const body = node.body;
|
|
754
|
-
if (body.type === 'EnumSymbolBody') {
|
|
755
|
-
/*
|
|
756
|
-
There's unfortunately no way for us to support this in a clean way.
|
|
757
|
-
We can get really close using this code:
|
|
758
|
-
```
|
|
759
|
-
declare namespace SymbolEnum {
|
|
760
|
-
export const member1: unique symbol;
|
|
761
|
-
export type member1 = typeof member1;
|
|
762
|
-
|
|
763
|
-
export const member2: unique symbol;
|
|
764
|
-
export type member2 = typeof member2;
|
|
765
|
-
}
|
|
766
|
-
type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
|
|
767
|
-
```
|
|
768
|
-
|
|
769
|
-
However as explained in https://github.com/microsoft/TypeScript/issues/43657:
|
|
770
|
-
"A unique symbol type is never transferred from one declaration to another through inference."
|
|
771
|
-
This intended behaviour in TS means that the usage of the fake-enum would look like this:
|
|
772
|
-
```
|
|
773
|
-
const value: SymbolEnum.member1 = SymbolEnum.member1;
|
|
774
|
-
// ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
|
|
775
|
-
```
|
|
776
|
-
Which is really clunky and shitty. It definitely works, but ofc it's not good.
|
|
777
|
-
We can go with this design if users are okay with it!
|
|
778
|
-
|
|
779
|
-
Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
|
|
780
|
-
*/
|
|
781
|
-
throw unsupportedTranslationError(node, 'symbol enums');
|
|
782
|
-
}
|
|
783
|
-
if (body.type === 'EnumBooleanBody') {
|
|
784
|
-
/*
|
|
785
|
-
TODO - TS enums only allow strings or numbers as their values - not booleans.
|
|
786
|
-
This means we need a non-ts-enum representation of the enum.
|
|
787
|
-
We can support boolean enums using a construct like this:
|
|
788
|
-
```ts
|
|
789
|
-
declare namespace BooleanEnum {
|
|
790
|
-
export const member1: true;
|
|
791
|
-
export type member1 = typeof member1;
|
|
792
|
-
|
|
793
|
-
export const member2: false;
|
|
794
|
-
export type member2 = typeof member1;
|
|
795
|
-
}
|
|
796
|
-
declare type BooleanEnum = boolean;
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
But it's pretty clunky and ugly.
|
|
800
|
-
Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
|
|
801
|
-
*/
|
|
802
|
-
throw unsupportedTranslationError(node, 'boolean enums');
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
const members: Array<TSESTree.TSEnumMemberNonComputedName> = [];
|
|
806
|
-
for (const member of body.members) {
|
|
807
|
-
switch (member.type) {
|
|
808
|
-
case 'EnumDefaultedMember': {
|
|
809
|
-
if (body.type === 'EnumNumberBody') {
|
|
810
|
-
// this should be impossible!
|
|
811
|
-
throw unexpectedTranslationError(
|
|
812
|
-
member,
|
|
813
|
-
'Unexpected defaulted number enum member',
|
|
814
|
-
);
|
|
815
|
-
}
|
|
816
|
-
members.push({
|
|
817
|
-
type: 'TSEnumMember',
|
|
818
|
-
computed: false,
|
|
819
|
-
id: transform.Identifier(member.id, false),
|
|
820
|
-
initializer: ({
|
|
821
|
-
type: 'Literal',
|
|
822
|
-
raw: `"${member.id.name}"`,
|
|
823
|
-
value: member.id.name,
|
|
824
|
-
}: TSESTree.StringLiteral),
|
|
825
|
-
});
|
|
826
|
-
break;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
case 'EnumNumberMember':
|
|
830
|
-
case 'EnumStringMember':
|
|
831
|
-
members.push({
|
|
832
|
-
type: 'TSEnumMember',
|
|
833
|
-
computed: false,
|
|
834
|
-
id: transform.Identifier(member.id, false),
|
|
835
|
-
initializer:
|
|
836
|
-
member.init.literalType === 'string'
|
|
837
|
-
? transform.StringLiteral(member.init)
|
|
838
|
-
: transform.NumericLiteral(member.init),
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
const bodyRepresentationType =
|
|
844
|
-
body.type === 'EnumNumberBody'
|
|
845
|
-
? {type: 'TSNumberKeyword'}
|
|
846
|
-
: {type: 'TSStringKeyword'};
|
|
847
|
-
|
|
848
|
-
const enumName = transform.Identifier(node.id, false);
|
|
849
|
-
return [
|
|
850
|
-
{
|
|
851
|
-
type: 'TSEnumDeclaration',
|
|
852
|
-
const: false,
|
|
853
|
-
declare: true,
|
|
854
|
-
id: enumName,
|
|
855
|
-
members,
|
|
856
|
-
},
|
|
857
|
-
// flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
|
|
858
|
-
// we can use declaration merging to declare these functions on the enum:
|
|
859
|
-
/*
|
|
860
|
-
declare enum Foo {
|
|
861
|
-
A = 1,
|
|
862
|
-
B = 2,
|
|
863
|
-
}
|
|
864
|
-
declare namespace Foo {
|
|
865
|
-
export function cast(value: number | null | undefined): Foo;
|
|
866
|
-
export function isValid(value: number | null | undefined): value is Foo;
|
|
867
|
-
export function members(): IterableIterator<Foo>;
|
|
868
|
-
export function getName(value: Foo): string;
|
|
869
|
-
}
|
|
870
|
-
*/
|
|
871
|
-
{
|
|
872
|
-
type: 'TSModuleDeclaration',
|
|
873
|
-
declare: true,
|
|
874
|
-
id: enumName,
|
|
875
|
-
body: {
|
|
876
|
-
type: 'TSModuleBlock',
|
|
877
|
-
body: [
|
|
878
|
-
// export function cast(value: number | null | undefined): Foo
|
|
879
|
-
{
|
|
880
|
-
type: 'ExportNamedDeclaration',
|
|
881
|
-
declaration: {
|
|
882
|
-
type: 'TSDeclareFunction',
|
|
883
|
-
id: {
|
|
884
|
-
type: 'Identifier',
|
|
885
|
-
name: 'cast',
|
|
886
|
-
},
|
|
887
|
-
generator: false,
|
|
888
|
-
expression: false,
|
|
889
|
-
async: false,
|
|
890
|
-
params: [
|
|
891
|
-
{
|
|
892
|
-
type: 'Identifier',
|
|
893
|
-
name: 'value',
|
|
894
|
-
typeAnnotation: {
|
|
895
|
-
type: 'TSTypeAnnotation',
|
|
896
|
-
typeAnnotation: {
|
|
897
|
-
type: 'TSUnionType',
|
|
898
|
-
types: [
|
|
899
|
-
bodyRepresentationType,
|
|
900
|
-
{
|
|
901
|
-
type: 'TSNullKeyword',
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
type: 'TSUndefinedKeyword',
|
|
905
|
-
},
|
|
906
|
-
],
|
|
907
|
-
},
|
|
908
|
-
},
|
|
909
|
-
},
|
|
910
|
-
],
|
|
911
|
-
returnType: {
|
|
912
|
-
type: 'TSTypeAnnotation',
|
|
913
|
-
typeAnnotation: {
|
|
914
|
-
type: 'TSTypeReference',
|
|
915
|
-
typeName: enumName,
|
|
916
|
-
},
|
|
917
|
-
},
|
|
918
|
-
},
|
|
919
|
-
specifiers: [],
|
|
920
|
-
source: null,
|
|
921
|
-
exportKind: 'value',
|
|
922
|
-
assertions: [],
|
|
923
|
-
},
|
|
924
|
-
// export function isValid(value: number | null | undefined): value is Foo;
|
|
925
|
-
{
|
|
926
|
-
type: 'ExportNamedDeclaration',
|
|
927
|
-
declaration: {
|
|
928
|
-
type: 'TSDeclareFunction',
|
|
929
|
-
id: {
|
|
930
|
-
type: 'Identifier',
|
|
931
|
-
name: 'isValid',
|
|
932
|
-
},
|
|
933
|
-
generator: false,
|
|
934
|
-
expression: false,
|
|
935
|
-
async: false,
|
|
936
|
-
params: [
|
|
937
|
-
{
|
|
938
|
-
type: 'Identifier',
|
|
939
|
-
name: 'value',
|
|
940
|
-
typeAnnotation: {
|
|
941
|
-
type: 'TSTypeAnnotation',
|
|
942
|
-
typeAnnotation: {
|
|
943
|
-
type: 'TSUnionType',
|
|
944
|
-
types: [
|
|
945
|
-
bodyRepresentationType,
|
|
946
|
-
{
|
|
947
|
-
type: 'TSNullKeyword',
|
|
948
|
-
},
|
|
949
|
-
{
|
|
950
|
-
type: 'TSUndefinedKeyword',
|
|
951
|
-
},
|
|
952
|
-
],
|
|
953
|
-
},
|
|
954
|
-
},
|
|
955
|
-
},
|
|
956
|
-
],
|
|
957
|
-
returnType: {
|
|
958
|
-
type: 'TSTypeAnnotation',
|
|
959
|
-
typeAnnotation: {
|
|
960
|
-
type: 'TSTypePredicate',
|
|
961
|
-
asserts: false,
|
|
962
|
-
parameterName: {
|
|
963
|
-
type: 'Identifier',
|
|
964
|
-
name: 'value',
|
|
965
|
-
},
|
|
966
|
-
typeAnnotation: {
|
|
967
|
-
type: 'TSTypeAnnotation',
|
|
968
|
-
typeAnnotation: {
|
|
969
|
-
type: 'TSTypeReference',
|
|
970
|
-
typeName: enumName,
|
|
971
|
-
},
|
|
972
|
-
},
|
|
973
|
-
},
|
|
974
|
-
},
|
|
975
|
-
},
|
|
976
|
-
specifiers: [],
|
|
977
|
-
source: null,
|
|
978
|
-
exportKind: 'value',
|
|
979
|
-
assertions: [],
|
|
980
|
-
},
|
|
981
|
-
// export function members(): IterableIterator<Foo>;
|
|
982
|
-
{
|
|
983
|
-
type: 'ExportNamedDeclaration',
|
|
984
|
-
declaration: {
|
|
985
|
-
type: 'TSDeclareFunction',
|
|
986
|
-
id: {
|
|
987
|
-
type: 'Identifier',
|
|
988
|
-
name: 'members',
|
|
989
|
-
},
|
|
990
|
-
generator: false,
|
|
991
|
-
expression: false,
|
|
992
|
-
async: false,
|
|
993
|
-
params: [],
|
|
994
|
-
returnType: {
|
|
995
|
-
type: 'TSTypeAnnotation',
|
|
996
|
-
typeAnnotation: {
|
|
997
|
-
type: 'TSTypeReference',
|
|
998
|
-
typeName: {
|
|
999
|
-
type: 'Identifier',
|
|
1000
|
-
name: 'IterableIterator',
|
|
1001
|
-
},
|
|
1002
|
-
typeParameters: {
|
|
1003
|
-
type: 'TSTypeParameterInstantiation',
|
|
1004
|
-
params: [
|
|
1005
|
-
{
|
|
1006
|
-
type: 'TSTypeReference',
|
|
1007
|
-
typeName: enumName,
|
|
1008
|
-
},
|
|
1009
|
-
],
|
|
1010
|
-
},
|
|
1011
|
-
},
|
|
1012
|
-
},
|
|
1013
|
-
},
|
|
1014
|
-
specifiers: [],
|
|
1015
|
-
source: null,
|
|
1016
|
-
exportKind: 'value',
|
|
1017
|
-
assertions: [],
|
|
1018
|
-
},
|
|
1019
|
-
// export function getName(value: Foo): string;
|
|
1020
|
-
{
|
|
1021
|
-
type: 'ExportNamedDeclaration',
|
|
1022
|
-
declaration: {
|
|
1023
|
-
type: 'TSDeclareFunction',
|
|
1024
|
-
id: {
|
|
1025
|
-
type: 'Identifier',
|
|
1026
|
-
name: 'getName',
|
|
1027
|
-
},
|
|
1028
|
-
generator: false,
|
|
1029
|
-
expression: false,
|
|
1030
|
-
async: false,
|
|
1031
|
-
params: [
|
|
1032
|
-
{
|
|
1033
|
-
type: 'Identifier',
|
|
1034
|
-
name: 'value',
|
|
1035
|
-
typeAnnotation: {
|
|
1036
|
-
type: 'TSTypeAnnotation',
|
|
1037
|
-
typeAnnotation: {
|
|
1038
|
-
type: 'TSTypeReference',
|
|
1039
|
-
typeName: enumName,
|
|
1040
|
-
},
|
|
1041
|
-
},
|
|
1042
|
-
},
|
|
1043
|
-
],
|
|
1044
|
-
returnType: {
|
|
1045
|
-
type: 'TSTypeAnnotation',
|
|
1046
|
-
typeAnnotation: {
|
|
1047
|
-
type: 'TSStringKeyword',
|
|
1048
|
-
},
|
|
1049
|
-
},
|
|
1050
|
-
},
|
|
1051
|
-
specifiers: [],
|
|
1052
|
-
source: null,
|
|
1053
|
-
exportKind: 'value',
|
|
1054
|
-
assertions: [],
|
|
1055
|
-
},
|
|
1056
|
-
],
|
|
1276
|
+
node.supertype == null
|
|
1277
|
+
? {
|
|
1278
|
+
type: 'TSUnknownKeyword',
|
|
1279
|
+
}
|
|
1280
|
+
: transformTypeAnnotationType(node.supertype),
|
|
1281
|
+
typeParameters:
|
|
1282
|
+
node.typeParameters == null
|
|
1283
|
+
? undefined
|
|
1284
|
+
: transform.TypeParameterDeclaration(node.typeParameters),
|
|
1285
|
+
};
|
|
1286
|
+
},
|
|
1287
|
+
DeclareVariable(
|
|
1288
|
+
node: FlowESTree.DeclareVariable,
|
|
1289
|
+
): TSESTree.VariableDeclaration {
|
|
1290
|
+
return {
|
|
1291
|
+
type: 'VariableDeclaration',
|
|
1292
|
+
declare: true,
|
|
1293
|
+
declarations: [
|
|
1294
|
+
{
|
|
1295
|
+
type: 'VariableDeclarator',
|
|
1296
|
+
declare: true,
|
|
1297
|
+
id: transform.Identifier(node.id, true),
|
|
1298
|
+
init: null,
|
|
1057
1299
|
},
|
|
1058
|
-
|
|
1059
|
-
|
|
1300
|
+
],
|
|
1301
|
+
kind: node.kind,
|
|
1302
|
+
};
|
|
1303
|
+
},
|
|
1304
|
+
DeclareEnum(
|
|
1305
|
+
node: FlowESTree.DeclareEnum,
|
|
1306
|
+
): DeclarationOrUnsupported<
|
|
1307
|
+
[TSESTree.TSEnumDeclaration, TSESTree.TSModuleDeclaration],
|
|
1308
|
+
> {
|
|
1309
|
+
return EnumImpl(node);
|
|
1310
|
+
},
|
|
1311
|
+
EmptyTypeAnnotation(
|
|
1312
|
+
node: FlowESTree.EmptyTypeAnnotation,
|
|
1313
|
+
): TSESTree.TypeNode {
|
|
1314
|
+
// Flow's `empty` type doesn't map well to any types in TS.
|
|
1315
|
+
// The closest is `never`, but `never` has a number of different semantics
|
|
1316
|
+
// In reality no human code should ever directly use the `empty` type in flow
|
|
1317
|
+
// So let's put a pin in it for now
|
|
1318
|
+
return unsupportedAnnotation(node, 'empty type');
|
|
1319
|
+
},
|
|
1320
|
+
EnumDeclaration(
|
|
1321
|
+
node: FlowESTree.EnumDeclaration,
|
|
1322
|
+
): DeclarationOrUnsupported<
|
|
1323
|
+
[TSESTree.TSEnumDeclaration, TSESTree.TSModuleDeclaration],
|
|
1324
|
+
> {
|
|
1325
|
+
return EnumImpl(node);
|
|
1060
1326
|
},
|
|
1061
1327
|
DeclareModuleExports(
|
|
1062
1328
|
node: FlowESTree.DeclareModuleExports,
|
|
@@ -1068,7 +1334,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1068
1334
|
): TSESTree.TypeNode {
|
|
1069
1335
|
// The existential type does not map to any types in TS
|
|
1070
1336
|
// It's also super deprecated - so let's not ever worry
|
|
1071
|
-
|
|
1337
|
+
return unsupportedAnnotation(node, 'existential type');
|
|
1072
1338
|
},
|
|
1073
1339
|
ExportNamedDeclaration(
|
|
1074
1340
|
node: FlowESTree.ExportNamedDeclaration,
|
|
@@ -1091,11 +1357,12 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1091
1357
|
|
|
1092
1358
|
const [exportedDeclaration, mergedDeclaration] = (() => {
|
|
1093
1359
|
if (node.declaration == null) {
|
|
1094
|
-
return [null];
|
|
1360
|
+
return [null, null];
|
|
1095
1361
|
}
|
|
1096
1362
|
|
|
1097
1363
|
switch (node.declaration.type) {
|
|
1098
1364
|
case 'ClassDeclaration':
|
|
1365
|
+
case 'ComponentDeclaration':
|
|
1099
1366
|
case 'FunctionDeclaration':
|
|
1100
1367
|
case 'VariableDeclaration':
|
|
1101
1368
|
// These cases shouldn't happen in flow defs because they have their own special
|
|
@@ -1105,8 +1372,10 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1105
1372
|
`Unexpected named declaration found ${node.declaration.type}`,
|
|
1106
1373
|
);
|
|
1107
1374
|
|
|
1108
|
-
case 'EnumDeclaration':
|
|
1109
|
-
|
|
1375
|
+
case 'EnumDeclaration': {
|
|
1376
|
+
const result = transform.EnumDeclaration(node.declaration);
|
|
1377
|
+
return Array.isArray(result) ? result : [result, null];
|
|
1378
|
+
}
|
|
1110
1379
|
case 'InterfaceDeclaration':
|
|
1111
1380
|
return [transform.InterfaceDeclaration(node.declaration), null];
|
|
1112
1381
|
case 'OpaqueType':
|
|
@@ -1163,7 +1432,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1163
1432
|
name: 'this',
|
|
1164
1433
|
typeAnnotation: {
|
|
1165
1434
|
type: 'TSTypeAnnotation',
|
|
1166
|
-
typeAnnotation:
|
|
1435
|
+
typeAnnotation: transformTypeAnnotationType(
|
|
1167
1436
|
node.this.typeAnnotation,
|
|
1168
1437
|
),
|
|
1169
1438
|
},
|
|
@@ -1182,7 +1451,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1182
1451
|
: transform.Identifier(rest.name, false),
|
|
1183
1452
|
typeAnnotation: {
|
|
1184
1453
|
type: 'TSTypeAnnotation',
|
|
1185
|
-
typeAnnotation:
|
|
1454
|
+
typeAnnotation: transformTypeAnnotationType(rest.typeAnnotation),
|
|
1186
1455
|
},
|
|
1187
1456
|
});
|
|
1188
1457
|
}
|
|
@@ -1192,7 +1461,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1192
1461
|
params,
|
|
1193
1462
|
returnType: {
|
|
1194
1463
|
type: 'TSTypeAnnotation',
|
|
1195
|
-
typeAnnotation:
|
|
1464
|
+
typeAnnotation: transformTypeAnnotationType(node.returnType),
|
|
1196
1465
|
},
|
|
1197
1466
|
typeParameters:
|
|
1198
1467
|
node.typeParameters == null
|
|
@@ -1209,7 +1478,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1209
1478
|
name: node.name == null ? `$$PARAM_${idx}$$` : node.name.name,
|
|
1210
1479
|
typeAnnotation: {
|
|
1211
1480
|
type: 'TSTypeAnnotation',
|
|
1212
|
-
typeAnnotation:
|
|
1481
|
+
typeAnnotation: transformTypeAnnotationType(node.typeAnnotation),
|
|
1213
1482
|
},
|
|
1214
1483
|
optional: node.optional,
|
|
1215
1484
|
};
|
|
@@ -1256,7 +1525,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1256
1525
|
|
|
1257
1526
|
const res = [];
|
|
1258
1527
|
for (const param of node.typeParameters.params) {
|
|
1259
|
-
res.push(
|
|
1528
|
+
res.push(transformTypeAnnotationType(param));
|
|
1260
1529
|
}
|
|
1261
1530
|
return res;
|
|
1262
1531
|
}
|
|
@@ -1299,7 +1568,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1299
1568
|
type PropType = ReturnType<ExtractPropType<Obj>>; // number
|
|
1300
1569
|
```
|
|
1301
1570
|
*/
|
|
1302
|
-
|
|
1571
|
+
return unsupportedAnnotation(node, fullTypeName);
|
|
1303
1572
|
}
|
|
1304
1573
|
|
|
1305
1574
|
case '$Diff':
|
|
@@ -1547,20 +1816,95 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1547
1816
|
}
|
|
1548
1817
|
|
|
1549
1818
|
// React special conversion:
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1819
|
+
const validReactImportOrGlobal = isValidReactImportOrGlobal(baseId);
|
|
1820
|
+
const reactImport = isReactImport(baseId);
|
|
1821
|
+
if (validReactImportOrGlobal || reactImport) {
|
|
1822
|
+
// Returns appropriate Identifier for `React` import.
|
|
1823
|
+
// If a global is in use, set a flag to indicate that we should add the import.
|
|
1824
|
+
const getReactIdentifier = () => {
|
|
1825
|
+
if (shouldAddReactImport !== false) {
|
|
1826
|
+
shouldAddReactImport = !reactImport;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
return {
|
|
1830
|
+
type: 'Identifier',
|
|
1831
|
+
name: `React`,
|
|
1832
|
+
};
|
|
1554
1833
|
};
|
|
1555
1834
|
|
|
1556
1835
|
switch (fullTypeName) {
|
|
1836
|
+
// TODO: In flow this is `ChildrenArray<T> = T | $ReadOnlyArray<ChildrenArray<T>>`.
|
|
1837
|
+
// The recursive nature of it is rarely needed, so we're simplifying this for now
|
|
1838
|
+
// but omitting that aspect. Once we're able to provide utility types for our translations,
|
|
1839
|
+
// we should update this.
|
|
1840
|
+
// React.ChildrenArray<T> -> T | ReadonlyArray<T>
|
|
1841
|
+
// React$ChildrenArray<T> -> T | ReadonlyArray<T>
|
|
1842
|
+
case 'React.ChildrenArray':
|
|
1843
|
+
case 'React$ChildrenArray': {
|
|
1844
|
+
const [param] = assertHasExactlyNTypeParameters(1);
|
|
1845
|
+
return {
|
|
1846
|
+
type: 'TSUnionType',
|
|
1847
|
+
types: [
|
|
1848
|
+
param,
|
|
1849
|
+
{
|
|
1850
|
+
type: 'TSTypeReference',
|
|
1851
|
+
typeName: {
|
|
1852
|
+
type: 'Identifier',
|
|
1853
|
+
name: 'ReadonlyArray',
|
|
1854
|
+
},
|
|
1855
|
+
typeParameters: {
|
|
1856
|
+
type: 'TSTypeParameterInstantiation',
|
|
1857
|
+
params: [param],
|
|
1858
|
+
},
|
|
1859
|
+
},
|
|
1860
|
+
],
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
// React.Component<A,B> -> React.Component<A,B>
|
|
1864
|
+
// React$Component<A,B> -> React.Component<A,B>
|
|
1865
|
+
case 'React.Component':
|
|
1866
|
+
case 'React$Component': {
|
|
1867
|
+
const typeParameters = node.typeParameters;
|
|
1868
|
+
if (typeParameters == null || typeParameters.params.length === 0) {
|
|
1869
|
+
throw translationError(
|
|
1870
|
+
node,
|
|
1871
|
+
`Expected at least 1 type parameter with \`${fullTypeName}\``,
|
|
1872
|
+
);
|
|
1873
|
+
}
|
|
1874
|
+
const params = typeParameters.params;
|
|
1875
|
+
if (params.length > 2) {
|
|
1876
|
+
throw translationError(
|
|
1877
|
+
node,
|
|
1878
|
+
`Expected at no more than 2 type parameters with \`${fullTypeName}\``,
|
|
1879
|
+
);
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
return {
|
|
1883
|
+
type: 'TSTypeReference',
|
|
1884
|
+
typeName: {
|
|
1885
|
+
type: 'TSQualifiedName',
|
|
1886
|
+
left: getReactIdentifier(),
|
|
1887
|
+
right: {
|
|
1888
|
+
type: 'Identifier',
|
|
1889
|
+
name: 'Component',
|
|
1890
|
+
},
|
|
1891
|
+
},
|
|
1892
|
+
typeParameters: {
|
|
1893
|
+
type: 'TSTypeParameterInstantiation',
|
|
1894
|
+
params: params.map(param => transformTypeAnnotationType(param)),
|
|
1895
|
+
},
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
// React.Context<A> -> React.Context<A>
|
|
1900
|
+
// React$Context<A> -> React.Context<A>
|
|
1557
1901
|
case 'React$Context':
|
|
1558
1902
|
case 'React.Context':
|
|
1559
1903
|
return {
|
|
1560
1904
|
type: 'TSTypeReference',
|
|
1561
1905
|
typeName: {
|
|
1562
1906
|
type: 'TSQualifiedName',
|
|
1563
|
-
left:
|
|
1907
|
+
left: getReactIdentifier(),
|
|
1564
1908
|
right: {
|
|
1565
1909
|
type: 'Identifier',
|
|
1566
1910
|
name: `Context`,
|
|
@@ -1571,6 +1915,40 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1571
1915
|
params: assertHasExactlyNTypeParameters(1),
|
|
1572
1916
|
},
|
|
1573
1917
|
};
|
|
1918
|
+
// React.Key -> React.Key
|
|
1919
|
+
// React$Key -> React.Key
|
|
1920
|
+
case 'React.Key':
|
|
1921
|
+
case 'React$Key':
|
|
1922
|
+
assertHasExactlyNTypeParameters(0);
|
|
1923
|
+
return {
|
|
1924
|
+
type: 'TSTypeReference',
|
|
1925
|
+
typeName: {
|
|
1926
|
+
type: 'TSQualifiedName',
|
|
1927
|
+
left: getReactIdentifier(),
|
|
1928
|
+
right: {
|
|
1929
|
+
type: 'Identifier',
|
|
1930
|
+
name: 'Key',
|
|
1931
|
+
},
|
|
1932
|
+
},
|
|
1933
|
+
};
|
|
1934
|
+
// React.ElementType -> React.ElementType
|
|
1935
|
+
// React$ElementType -> React.ElementType
|
|
1936
|
+
case 'React$ElementType':
|
|
1937
|
+
case 'React.ElementType': {
|
|
1938
|
+
assertHasExactlyNTypeParameters(0);
|
|
1939
|
+
return {
|
|
1940
|
+
type: 'TSTypeReference',
|
|
1941
|
+
typeName: {
|
|
1942
|
+
type: 'TSQualifiedName',
|
|
1943
|
+
left: getReactIdentifier(),
|
|
1944
|
+
right: {
|
|
1945
|
+
type: 'Identifier',
|
|
1946
|
+
name: `ElementType`,
|
|
1947
|
+
},
|
|
1948
|
+
},
|
|
1949
|
+
typeParameters: undefined,
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1574
1952
|
// React.Node -> React.ReactNode
|
|
1575
1953
|
case 'React$Node':
|
|
1576
1954
|
case 'React.Node': {
|
|
@@ -1579,7 +1957,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1579
1957
|
type: 'TSTypeReference',
|
|
1580
1958
|
typeName: {
|
|
1581
1959
|
type: 'TSQualifiedName',
|
|
1582
|
-
left:
|
|
1960
|
+
left: getReactIdentifier(),
|
|
1583
1961
|
right: {
|
|
1584
1962
|
type: 'Identifier',
|
|
1585
1963
|
name: `ReactNode`,
|
|
@@ -1595,7 +1973,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1595
1973
|
type: 'TSTypeReference',
|
|
1596
1974
|
typeName: {
|
|
1597
1975
|
type: 'TSQualifiedName',
|
|
1598
|
-
left:
|
|
1976
|
+
left: getReactIdentifier(),
|
|
1599
1977
|
right: {
|
|
1600
1978
|
type: 'Identifier',
|
|
1601
1979
|
name: `ReactElement`,
|
|
@@ -1615,7 +1993,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1615
1993
|
type: 'TSTypeReference',
|
|
1616
1994
|
typeName: {
|
|
1617
1995
|
type: 'TSQualifiedName',
|
|
1618
|
-
left:
|
|
1996
|
+
left: getReactIdentifier(),
|
|
1619
1997
|
right: {
|
|
1620
1998
|
type: 'Identifier',
|
|
1621
1999
|
name: `ElementRef`,
|
|
@@ -1635,7 +2013,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1635
2013
|
type: 'TSTypeReference',
|
|
1636
2014
|
typeName: {
|
|
1637
2015
|
type: 'TSQualifiedName',
|
|
1638
|
-
left:
|
|
2016
|
+
left: getReactIdentifier(),
|
|
1639
2017
|
right: {
|
|
1640
2018
|
type: 'Identifier',
|
|
1641
2019
|
name: `Fragment`,
|
|
@@ -1662,15 +2040,32 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1662
2040
|
typeParameters: undefined,
|
|
1663
2041
|
};
|
|
1664
2042
|
}
|
|
1665
|
-
// React.
|
|
1666
|
-
// React
|
|
1667
|
-
// React$AbstractComponent<Config, Instance> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<Instance>>
|
|
1668
|
-
// React.ComponentType<Config> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<unknown>>
|
|
1669
|
-
// React$ComponentType<Config> -> React.ForwardRefExoticComponent<Config & React.RefAttributes<unknown>>
|
|
1670
|
-
case 'React.AbstractComponent':
|
|
1671
|
-
case 'React$AbstractComponent':
|
|
2043
|
+
// React.ComponentType<Config> -> React.ComponentType<Config>
|
|
2044
|
+
// React$ComponentType<Config> -> React.ComponentType<Config>
|
|
1672
2045
|
case 'React.ComponentType':
|
|
1673
2046
|
case 'React$ComponentType': {
|
|
2047
|
+
return {
|
|
2048
|
+
type: 'TSTypeReference',
|
|
2049
|
+
typeName: {
|
|
2050
|
+
type: 'TSQualifiedName',
|
|
2051
|
+
left: getReactIdentifier(),
|
|
2052
|
+
right: {
|
|
2053
|
+
type: 'Identifier',
|
|
2054
|
+
name: 'ComponentType',
|
|
2055
|
+
},
|
|
2056
|
+
},
|
|
2057
|
+
typeParameters: {
|
|
2058
|
+
type: 'TSTypeParameterInstantiation',
|
|
2059
|
+
params: assertHasExactlyNTypeParameters(1),
|
|
2060
|
+
},
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2063
|
+
// React.AbstractComponent<Config> -> React.ComponentType<Config>
|
|
2064
|
+
// React$AbstractComponent<Config> -> React.ComponentType<Config>
|
|
2065
|
+
// React.AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
|
|
2066
|
+
// React$AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
|
|
2067
|
+
case 'React.AbstractComponent':
|
|
2068
|
+
case 'React$AbstractComponent': {
|
|
1674
2069
|
const typeParameters = node.typeParameters;
|
|
1675
2070
|
if (typeParameters == null || typeParameters.params.length === 0) {
|
|
1676
2071
|
throw translationError(
|
|
@@ -1686,56 +2081,142 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1686
2081
|
);
|
|
1687
2082
|
}
|
|
1688
2083
|
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
2084
|
+
const newParams = (() => {
|
|
2085
|
+
if (params.length === 1) {
|
|
2086
|
+
return assertHasExactlyNTypeParameters(1);
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
const [props, ref] = assertHasExactlyNTypeParameters(2);
|
|
2090
|
+
|
|
2091
|
+
return [
|
|
1694
2092
|
{
|
|
1695
|
-
type: '
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
type: '
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
2093
|
+
type: 'TSIntersectionType',
|
|
2094
|
+
types: [
|
|
2095
|
+
props,
|
|
2096
|
+
{
|
|
2097
|
+
type: 'TSTypeReference',
|
|
2098
|
+
typeName: {
|
|
2099
|
+
type: 'TSQualifiedName',
|
|
2100
|
+
left: {
|
|
2101
|
+
type: 'Identifier',
|
|
2102
|
+
name: 'React',
|
|
2103
|
+
},
|
|
2104
|
+
right: {
|
|
2105
|
+
type: 'Identifier',
|
|
2106
|
+
name: 'RefAttributes',
|
|
2107
|
+
},
|
|
2108
|
+
},
|
|
2109
|
+
typeParameters: {
|
|
2110
|
+
type: 'TSTypeParameterInstantiation',
|
|
2111
|
+
params: [ref],
|
|
2112
|
+
},
|
|
1705
2113
|
},
|
|
1706
|
-
|
|
1707
|
-
typeParameters: {
|
|
1708
|
-
type: 'TSTypeParameterInstantiation',
|
|
1709
|
-
params: [
|
|
1710
|
-
params[1]
|
|
1711
|
-
? transform.TypeAnnotationType(params[1])
|
|
1712
|
-
: {
|
|
1713
|
-
type: 'TSUnknownKeyword',
|
|
1714
|
-
},
|
|
1715
|
-
],
|
|
1716
|
-
},
|
|
2114
|
+
],
|
|
1717
2115
|
},
|
|
1718
|
-
]
|
|
1719
|
-
};
|
|
2116
|
+
];
|
|
2117
|
+
})();
|
|
1720
2118
|
|
|
1721
2119
|
return {
|
|
1722
2120
|
type: 'TSTypeReference',
|
|
1723
2121
|
typeName: {
|
|
1724
2122
|
type: 'TSQualifiedName',
|
|
1725
|
-
left:
|
|
2123
|
+
left: getReactIdentifier(),
|
|
2124
|
+
right: {
|
|
2125
|
+
type: 'Identifier',
|
|
2126
|
+
name: 'ComponentType',
|
|
2127
|
+
},
|
|
2128
|
+
},
|
|
2129
|
+
typeParameters: {
|
|
2130
|
+
type: 'TSTypeParameterInstantiation',
|
|
2131
|
+
params: newParams,
|
|
2132
|
+
},
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
// React.ElementConfig<A> -> JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
|
|
2136
|
+
// React$ElementConfig<A> -> JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
|
|
2137
|
+
case 'React.ElementConfig':
|
|
2138
|
+
case 'React$ElementConfig': {
|
|
2139
|
+
const [param] = assertHasExactlyNTypeParameters(1);
|
|
2140
|
+
return {
|
|
2141
|
+
type: 'TSTypeReference',
|
|
2142
|
+
typeName: {
|
|
2143
|
+
type: 'TSQualifiedName',
|
|
2144
|
+
left: {
|
|
2145
|
+
type: 'Identifier',
|
|
2146
|
+
name: 'JSX',
|
|
2147
|
+
},
|
|
1726
2148
|
right: {
|
|
1727
2149
|
type: 'Identifier',
|
|
1728
|
-
name:
|
|
2150
|
+
name: 'LibraryManagedAttributes',
|
|
1729
2151
|
},
|
|
1730
2152
|
},
|
|
1731
2153
|
typeParameters: {
|
|
1732
2154
|
type: 'TSTypeParameterInstantiation',
|
|
1733
|
-
params: [
|
|
2155
|
+
params: [
|
|
2156
|
+
param,
|
|
2157
|
+
{
|
|
2158
|
+
type: 'TSTypeReference',
|
|
2159
|
+
typeName: {
|
|
2160
|
+
type: 'TSQualifiedName',
|
|
2161
|
+
left: getReactIdentifier(),
|
|
2162
|
+
right: {
|
|
2163
|
+
type: 'Identifier',
|
|
2164
|
+
name: `ComponentProps`,
|
|
2165
|
+
},
|
|
2166
|
+
},
|
|
2167
|
+
typeParameters: {
|
|
2168
|
+
type: 'TSTypeParameterInstantiation',
|
|
2169
|
+
params: [param],
|
|
2170
|
+
},
|
|
2171
|
+
},
|
|
2172
|
+
],
|
|
1734
2173
|
},
|
|
1735
2174
|
};
|
|
1736
2175
|
}
|
|
2176
|
+
// React.Ref<C> -> NonNullable<React.Ref<C> | string | number>
|
|
2177
|
+
// React$Ref<C> -> NonNullable<React.Ref<C> | string | number>
|
|
2178
|
+
case 'React.Ref':
|
|
2179
|
+
case 'React$Ref':
|
|
2180
|
+
return {
|
|
2181
|
+
type: 'TSTypeReference',
|
|
2182
|
+
typeName: {
|
|
2183
|
+
type: 'Identifier',
|
|
2184
|
+
name: 'NonNullable',
|
|
2185
|
+
},
|
|
2186
|
+
typeParameters: {
|
|
2187
|
+
type: 'TSTypeParameterInstantiation',
|
|
2188
|
+
params: [
|
|
2189
|
+
{
|
|
2190
|
+
type: 'TSUnionType',
|
|
2191
|
+
types: [
|
|
2192
|
+
{
|
|
2193
|
+
type: 'TSTypeReference',
|
|
2194
|
+
typeName: {
|
|
2195
|
+
type: 'TSQualifiedName',
|
|
2196
|
+
left: getReactIdentifier(),
|
|
2197
|
+
right: {
|
|
2198
|
+
type: 'Identifier',
|
|
2199
|
+
name: 'Ref',
|
|
2200
|
+
},
|
|
2201
|
+
},
|
|
2202
|
+
typeParameters: {
|
|
2203
|
+
type: 'TSTypeParameterInstantiation',
|
|
2204
|
+
params: assertHasExactlyNTypeParameters(1),
|
|
2205
|
+
},
|
|
2206
|
+
},
|
|
2207
|
+
{
|
|
2208
|
+
type: 'TSStringKeyword',
|
|
2209
|
+
},
|
|
2210
|
+
{
|
|
2211
|
+
type: 'TSNumberKeyword',
|
|
2212
|
+
},
|
|
2213
|
+
],
|
|
2214
|
+
},
|
|
2215
|
+
],
|
|
2216
|
+
},
|
|
2217
|
+
};
|
|
1737
2218
|
default:
|
|
1738
|
-
|
|
2219
|
+
return unsupportedAnnotation(node, fullTypeName);
|
|
1739
2220
|
}
|
|
1740
2221
|
}
|
|
1741
2222
|
|
|
@@ -1770,8 +2251,8 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1770
2251
|
): TSESTree.TSIndexedAccessType {
|
|
1771
2252
|
return {
|
|
1772
2253
|
type: 'TSIndexedAccessType',
|
|
1773
|
-
objectType:
|
|
1774
|
-
indexType:
|
|
2254
|
+
objectType: transformTypeAnnotationType(node.objectType),
|
|
2255
|
+
indexType: transformTypeAnnotationType(node.indexType),
|
|
1775
2256
|
};
|
|
1776
2257
|
},
|
|
1777
2258
|
InterfaceDeclaration(
|
|
@@ -1793,67 +2274,77 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1793
2274
|
},
|
|
1794
2275
|
ImportDeclaration(
|
|
1795
2276
|
node: FlowESTree.ImportDeclaration,
|
|
1796
|
-
): TSESTree.ImportDeclaration {
|
|
1797
|
-
|
|
1798
|
-
/*
|
|
1799
|
-
TODO - this is a complicated change to support because TS
|
|
1800
|
-
does not have typeof imports.
|
|
1801
|
-
Making it a `type` import would change the meaning!
|
|
1802
|
-
The only way to truly support this is to prefix all **usages** with `typeof T`.
|
|
1803
|
-
eg:
|
|
2277
|
+
): Array<DeclarationOrUnsupported<TSESTree.ImportDeclaration>> {
|
|
2278
|
+
const importKind = node.importKind;
|
|
1804
2279
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
2280
|
+
const specifiers = [];
|
|
2281
|
+
const unsupportedSpecifiers = [];
|
|
2282
|
+
node.specifiers.forEach(spec => {
|
|
2283
|
+
let id = (() => {
|
|
2284
|
+
if (node.importKind === 'typeof' || spec.importKind === 'typeof') {
|
|
2285
|
+
const id = {
|
|
2286
|
+
type: 'Identifier',
|
|
2287
|
+
name: getPlaceholderNameForTypeofImport(),
|
|
2288
|
+
};
|
|
1809
2289
|
|
|
1810
|
-
|
|
2290
|
+
unsupportedSpecifiers.push({
|
|
2291
|
+
type: 'TSTypeAliasDeclaration',
|
|
2292
|
+
id: transform.Identifier(spec.local, false),
|
|
2293
|
+
typeAnnotation: {
|
|
2294
|
+
type: 'TSTypeQuery',
|
|
2295
|
+
exprName: id,
|
|
2296
|
+
},
|
|
2297
|
+
});
|
|
1811
2298
|
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
type T = typeof Foo;
|
|
1815
|
-
```
|
|
2299
|
+
return id;
|
|
2300
|
+
}
|
|
1816
2301
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
*/
|
|
1820
|
-
throw unsupportedTranslationError(node, 'typeof imports');
|
|
1821
|
-
}
|
|
1822
|
-
const importKind = node.importKind;
|
|
2302
|
+
return transform.Identifier(spec.local, false);
|
|
2303
|
+
})();
|
|
1823
2304
|
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
case 'ImportDefaultSpecifier':
|
|
1832
|
-
return {
|
|
1833
|
-
type: 'ImportDefaultSpecifier',
|
|
1834
|
-
local: transform.Identifier(spec.local, false),
|
|
1835
|
-
};
|
|
2305
|
+
switch (spec.type) {
|
|
2306
|
+
case 'ImportDefaultSpecifier':
|
|
2307
|
+
specifiers.push({
|
|
2308
|
+
type: 'ImportDefaultSpecifier',
|
|
2309
|
+
local: id,
|
|
2310
|
+
});
|
|
2311
|
+
return;
|
|
1836
2312
|
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2313
|
+
case 'ImportNamespaceSpecifier':
|
|
2314
|
+
specifiers.push({
|
|
2315
|
+
type: 'ImportNamespaceSpecifier',
|
|
2316
|
+
local: id,
|
|
2317
|
+
});
|
|
2318
|
+
return;
|
|
2319
|
+
|
|
2320
|
+
case 'ImportSpecifier':
|
|
2321
|
+
specifiers.push({
|
|
2322
|
+
type: 'ImportSpecifier',
|
|
2323
|
+
importKind:
|
|
2324
|
+
spec.importKind === 'typeof' || spec.importKind === 'type'
|
|
2325
|
+
? 'type'
|
|
2326
|
+
: null,
|
|
2327
|
+
imported: transform.Identifier(spec.imported, false),
|
|
2328
|
+
local: id,
|
|
2329
|
+
});
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
});
|
|
2333
|
+
|
|
2334
|
+
const out = specifiers.length
|
|
2335
|
+
? [
|
|
2336
|
+
{
|
|
2337
|
+
type: 'ImportDeclaration',
|
|
2338
|
+
assertions: node.assertions.map(transform.ImportAttribute),
|
|
2339
|
+
importKind:
|
|
2340
|
+
importKind === 'typeof' ? 'type' : importKind ?? 'value',
|
|
2341
|
+
source: transform.StringLiteral(node.source),
|
|
2342
|
+
specifiers,
|
|
2343
|
+
},
|
|
2344
|
+
]
|
|
2345
|
+
: [];
|
|
1842
2346
|
|
|
1843
|
-
|
|
1844
|
-
if (spec.importKind === 'typeof') {
|
|
1845
|
-
// see above
|
|
1846
|
-
throw unsupportedTranslationError(node, 'typeof imports');
|
|
1847
|
-
}
|
|
1848
|
-
return {
|
|
1849
|
-
type: 'ImportSpecifier',
|
|
1850
|
-
importKind: spec.importKind === 'type' ? 'type' : null,
|
|
1851
|
-
imported: transform.Identifier(spec.imported, false),
|
|
1852
|
-
local: transform.Identifier(spec.local, false),
|
|
1853
|
-
};
|
|
1854
|
-
}
|
|
1855
|
-
}),
|
|
1856
|
-
};
|
|
2347
|
+
return [...out, ...unsupportedSpecifiers];
|
|
1857
2348
|
},
|
|
1858
2349
|
InterfaceExtends(
|
|
1859
2350
|
node: FlowESTree.InterfaceExtends,
|
|
@@ -1897,7 +2388,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1897
2388
|
): TSESTree.TSIntersectionType {
|
|
1898
2389
|
return {
|
|
1899
2390
|
type: 'TSIntersectionType',
|
|
1900
|
-
types: node.types.map(
|
|
2391
|
+
types: node.types.map(transformTypeAnnotationType),
|
|
1901
2392
|
};
|
|
1902
2393
|
},
|
|
1903
2394
|
Literal(node: FlowESTree.Literal): TSESTree.Literal {
|
|
@@ -1951,7 +2442,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1951
2442
|
{
|
|
1952
2443
|
type: 'TSUndefinedKeyword',
|
|
1953
2444
|
},
|
|
1954
|
-
|
|
2445
|
+
transformTypeAnnotationType(node.typeAnnotation),
|
|
1955
2446
|
],
|
|
1956
2447
|
};
|
|
1957
2448
|
},
|
|
@@ -1983,7 +2474,10 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
1983
2474
|
},
|
|
1984
2475
|
ObjectTypeAnnotation(
|
|
1985
2476
|
node: FlowESTree.ObjectTypeAnnotation,
|
|
1986
|
-
):
|
|
2477
|
+
):
|
|
2478
|
+
| TSESTree.TSTypeLiteral
|
|
2479
|
+
| TSESTree.TSIntersectionType
|
|
2480
|
+
| TSESTree.TSAnyKeyword {
|
|
1987
2481
|
// we want to preserve the source order of the members
|
|
1988
2482
|
// unfortunately flow has unordered properties storing things
|
|
1989
2483
|
// so store all elements with their start index and sort the
|
|
@@ -2010,10 +2504,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2010
2504
|
They're really rarely used (if ever) - so let's just ignore them for now
|
|
2011
2505
|
*/
|
|
2012
2506
|
if (node.internalSlots.length > 0) {
|
|
2013
|
-
|
|
2014
|
-
node.internalSlots[0],
|
|
2015
|
-
'internal slots',
|
|
2016
|
-
);
|
|
2507
|
+
return unsupportedAnnotation(node.internalSlots[0], 'internal slots');
|
|
2017
2508
|
}
|
|
2018
2509
|
|
|
2019
2510
|
if (!node.properties.find(FlowESTree.isObjectTypeSpreadProperty)) {
|
|
@@ -2024,6 +2515,14 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2024
2515
|
throw unexpectedTranslationError(property, 'Impossible state');
|
|
2025
2516
|
}
|
|
2026
2517
|
|
|
2518
|
+
if (property.type === 'ObjectTypeMappedTypeProperty') {
|
|
2519
|
+
// TODO - Support mapped types
|
|
2520
|
+
return unsupportedAnnotation(
|
|
2521
|
+
property,
|
|
2522
|
+
'object type with mapped type property',
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2027
2526
|
members.push({
|
|
2028
2527
|
start: property.range[0],
|
|
2029
2528
|
node: transform.ObjectTypeProperty(property),
|
|
@@ -2110,7 +2609,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2110
2609
|
*/
|
|
2111
2610
|
|
|
2112
2611
|
if (members.length > 0) {
|
|
2113
|
-
|
|
2612
|
+
return unsupportedAnnotation(
|
|
2114
2613
|
node,
|
|
2115
2614
|
'object types with spreads, indexers and/or call properties at the same time',
|
|
2116
2615
|
);
|
|
@@ -2120,21 +2619,27 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2120
2619
|
for (const property of node.properties) {
|
|
2121
2620
|
if (property.type === 'ObjectTypeSpreadProperty') {
|
|
2122
2621
|
if (members.length > 0) {
|
|
2123
|
-
|
|
2622
|
+
return unsupportedAnnotation(
|
|
2124
2623
|
property,
|
|
2125
2624
|
'object types with spreads in the middle or at the end',
|
|
2126
2625
|
);
|
|
2127
2626
|
}
|
|
2128
2627
|
|
|
2129
|
-
const spreadType =
|
|
2628
|
+
const spreadType = transformTypeAnnotationType(property.argument);
|
|
2130
2629
|
if (spreadType.type !== 'TSTypeReference') {
|
|
2131
|
-
|
|
2630
|
+
return unsupportedAnnotation(
|
|
2132
2631
|
property,
|
|
2133
2632
|
'object types with complex spreads',
|
|
2134
2633
|
);
|
|
2135
2634
|
}
|
|
2136
2635
|
|
|
2137
2636
|
typesToIntersect.push(spreadType);
|
|
2637
|
+
} else if (property.type === 'ObjectTypeMappedTypeProperty') {
|
|
2638
|
+
// TODO - Support mapped types
|
|
2639
|
+
return unsupportedAnnotation(
|
|
2640
|
+
property,
|
|
2641
|
+
'object type with mapped type property',
|
|
2642
|
+
);
|
|
2138
2643
|
} else {
|
|
2139
2644
|
members.push({
|
|
2140
2645
|
start: property.range[0],
|
|
@@ -2208,7 +2713,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2208
2713
|
name: node.id == null ? '$$Key$$' : node.id.name,
|
|
2209
2714
|
typeAnnotation: {
|
|
2210
2715
|
type: 'TSTypeAnnotation',
|
|
2211
|
-
typeAnnotation:
|
|
2716
|
+
typeAnnotation: transformTypeAnnotationType(node.key),
|
|
2212
2717
|
},
|
|
2213
2718
|
},
|
|
2214
2719
|
],
|
|
@@ -2216,7 +2721,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2216
2721
|
static: node.static,
|
|
2217
2722
|
typeAnnotation: {
|
|
2218
2723
|
type: 'TSTypeAnnotation',
|
|
2219
|
-
typeAnnotation:
|
|
2724
|
+
typeAnnotation: transformTypeAnnotationType(node.value),
|
|
2220
2725
|
},
|
|
2221
2726
|
};
|
|
2222
2727
|
},
|
|
@@ -2273,7 +2778,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2273
2778
|
static: node.static,
|
|
2274
2779
|
typeAnnotation: {
|
|
2275
2780
|
type: 'TSTypeAnnotation',
|
|
2276
|
-
typeAnnotation:
|
|
2781
|
+
typeAnnotation: transformTypeAnnotationType(node.value),
|
|
2277
2782
|
},
|
|
2278
2783
|
};
|
|
2279
2784
|
},
|
|
@@ -2302,10 +2807,10 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2302
2807
|
},
|
|
2303
2808
|
typeParameters: {
|
|
2304
2809
|
type: 'TSTypeParameterInstantiation',
|
|
2305
|
-
params: [
|
|
2810
|
+
params: [transformTypeAnnotationType(node.objectType)],
|
|
2306
2811
|
},
|
|
2307
2812
|
},
|
|
2308
|
-
indexType:
|
|
2813
|
+
indexType: transformTypeAnnotationType(node.indexType),
|
|
2309
2814
|
};
|
|
2310
2815
|
},
|
|
2311
2816
|
QualifiedTypeIdentifier(
|
|
@@ -2322,6 +2827,20 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2322
2827
|
right: transform.Identifier(node.id, false),
|
|
2323
2828
|
};
|
|
2324
2829
|
},
|
|
2830
|
+
QualifiedTypeofIdentifier(
|
|
2831
|
+
node: FlowESTree.QualifiedTypeofIdentifier,
|
|
2832
|
+
): TSESTree.TSQualifiedName {
|
|
2833
|
+
const qual = node.qualification;
|
|
2834
|
+
|
|
2835
|
+
return {
|
|
2836
|
+
type: 'TSQualifiedName',
|
|
2837
|
+
left:
|
|
2838
|
+
qual.type === 'Identifier'
|
|
2839
|
+
? transform.Identifier(qual, false)
|
|
2840
|
+
: transform.QualifiedTypeofIdentifier(qual),
|
|
2841
|
+
right: transform.Identifier(node.id, false),
|
|
2842
|
+
};
|
|
2843
|
+
},
|
|
2325
2844
|
RegExpLiteral(node: FlowESTree.RegExpLiteral): TSESTree.RegExpLiteral {
|
|
2326
2845
|
return {
|
|
2327
2846
|
type: 'Literal',
|
|
@@ -2378,7 +2897,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2378
2897
|
): TSESTree.TSTupleType {
|
|
2379
2898
|
return {
|
|
2380
2899
|
type: 'TSTupleType',
|
|
2381
|
-
elementTypes: node.types.map(
|
|
2900
|
+
elementTypes: node.types.map(transformTypeAnnotationType),
|
|
2382
2901
|
};
|
|
2383
2902
|
},
|
|
2384
2903
|
TypeAlias(node: FlowESTree.TypeAlias): TSESTree.TSTypeAliasDeclaration {
|
|
@@ -2387,89 +2906,26 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2387
2906
|
TypeAnnotation(node: FlowESTree.TypeAnnotation): TSESTree.TSTypeAnnotation {
|
|
2388
2907
|
return {
|
|
2389
2908
|
type: 'TSTypeAnnotation',
|
|
2390
|
-
typeAnnotation:
|
|
2909
|
+
typeAnnotation: transformTypeAnnotationType(node.typeAnnotation),
|
|
2391
2910
|
};
|
|
2392
2911
|
},
|
|
2393
|
-
TypeAnnotationType(node: FlowESTree.TypeAnnotationType): TSESTree.TypeNode {
|
|
2394
|
-
switch (node.type) {
|
|
2395
|
-
case 'AnyTypeAnnotation':
|
|
2396
|
-
return transform.AnyTypeAnnotation(node);
|
|
2397
|
-
case 'ArrayTypeAnnotation':
|
|
2398
|
-
return transform.ArrayTypeAnnotation(node);
|
|
2399
|
-
case 'BigIntLiteralTypeAnnotation':
|
|
2400
|
-
return transform.BigIntLiteralTypeAnnotation(node);
|
|
2401
|
-
case 'BigIntTypeAnnotation':
|
|
2402
|
-
return transform.BigIntTypeAnnotation(node);
|
|
2403
|
-
case 'BooleanLiteralTypeAnnotation':
|
|
2404
|
-
return transform.BooleanLiteralTypeAnnotation(node);
|
|
2405
|
-
case 'BooleanTypeAnnotation':
|
|
2406
|
-
return transform.BooleanTypeAnnotation(node);
|
|
2407
|
-
case 'EmptyTypeAnnotation':
|
|
2408
|
-
return transform.EmptyTypeAnnotation(node);
|
|
2409
|
-
case 'ExistsTypeAnnotation':
|
|
2410
|
-
return transform.ExistsTypeAnnotation(node);
|
|
2411
|
-
case 'FunctionTypeAnnotation':
|
|
2412
|
-
return transform.FunctionTypeAnnotation(node);
|
|
2413
|
-
case 'GenericTypeAnnotation':
|
|
2414
|
-
return transform.GenericTypeAnnotation(node);
|
|
2415
|
-
case 'IndexedAccessType':
|
|
2416
|
-
return transform.IndexedAccessType(node);
|
|
2417
|
-
case 'InterfaceTypeAnnotation':
|
|
2418
|
-
return transform.InterfaceTypeAnnotation(node);
|
|
2419
|
-
case 'IntersectionTypeAnnotation':
|
|
2420
|
-
return transform.IntersectionTypeAnnotation(node);
|
|
2421
|
-
case 'MixedTypeAnnotation':
|
|
2422
|
-
return transform.MixedTypeAnnotation(node);
|
|
2423
|
-
case 'NullLiteralTypeAnnotation':
|
|
2424
|
-
return transform.NullLiteralTypeAnnotation(node);
|
|
2425
|
-
case 'NullableTypeAnnotation':
|
|
2426
|
-
return transform.NullableTypeAnnotation(node);
|
|
2427
|
-
case 'NumberLiteralTypeAnnotation':
|
|
2428
|
-
return transform.NumberLiteralTypeAnnotation(node);
|
|
2429
|
-
case 'NumberTypeAnnotation':
|
|
2430
|
-
return transform.NumberTypeAnnotation(node);
|
|
2431
|
-
case 'ObjectTypeAnnotation':
|
|
2432
|
-
return transform.ObjectTypeAnnotation(node);
|
|
2433
|
-
case 'OptionalIndexedAccessType':
|
|
2434
|
-
return transform.OptionalIndexedAccessType(node);
|
|
2435
|
-
case 'QualifiedTypeIdentifier':
|
|
2436
|
-
return transform.QualifiedTypeIdentifier(node);
|
|
2437
|
-
case 'StringLiteralTypeAnnotation':
|
|
2438
|
-
return transform.StringLiteralTypeAnnotation(node);
|
|
2439
|
-
case 'StringTypeAnnotation':
|
|
2440
|
-
return transform.StringTypeAnnotation(node);
|
|
2441
|
-
case 'SymbolTypeAnnotation':
|
|
2442
|
-
return transform.SymbolTypeAnnotation(node);
|
|
2443
|
-
case 'ThisTypeAnnotation':
|
|
2444
|
-
return transform.ThisTypeAnnotation(node);
|
|
2445
|
-
case 'TupleTypeAnnotation':
|
|
2446
|
-
return transform.TupleTypeAnnotation(node);
|
|
2447
|
-
case 'TypeofTypeAnnotation':
|
|
2448
|
-
return transform.TypeofTypeAnnotation(node);
|
|
2449
|
-
case 'UnionTypeAnnotation':
|
|
2450
|
-
return transform.UnionTypeAnnotation(node);
|
|
2451
|
-
case 'VoidTypeAnnotation':
|
|
2452
|
-
return transform.VoidTypeAnnotation(node);
|
|
2453
|
-
default:
|
|
2454
|
-
throw unexpectedTranslationError(node, `Unhandled type ${node.type}`);
|
|
2455
|
-
}
|
|
2456
|
-
},
|
|
2457
2912
|
TypeofTypeAnnotation(
|
|
2458
2913
|
node: FlowESTree.TypeofTypeAnnotation,
|
|
2459
2914
|
): TSESTree.TSTypeQuery {
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2915
|
+
switch (node.argument.type) {
|
|
2916
|
+
case 'Identifier':
|
|
2917
|
+
return {
|
|
2918
|
+
type: 'TSTypeQuery',
|
|
2919
|
+
exprName: transform.Identifier(node.argument),
|
|
2920
|
+
typeParameters: undefined,
|
|
2921
|
+
};
|
|
2922
|
+
case 'QualifiedTypeofIdentifier':
|
|
2923
|
+
return {
|
|
2924
|
+
type: 'TSTypeQuery',
|
|
2925
|
+
exprName: transform.QualifiedTypeofIdentifier(node.argument),
|
|
2926
|
+
typeParameters: undefined,
|
|
2927
|
+
};
|
|
2466
2928
|
}
|
|
2467
|
-
|
|
2468
|
-
return {
|
|
2469
|
-
type: 'TSTypeQuery',
|
|
2470
|
-
exprName: argument.typeName,
|
|
2471
|
-
typeParameters: argument.typeParameters,
|
|
2472
|
-
};
|
|
2473
2929
|
},
|
|
2474
2930
|
TypeParameter(node: FlowESTree.TypeParameter): TSESTree.TSTypeParameter {
|
|
2475
2931
|
/*
|
|
@@ -2502,11 +2958,11 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2502
2958
|
constraint:
|
|
2503
2959
|
node.bound == null
|
|
2504
2960
|
? undefined
|
|
2505
|
-
:
|
|
2961
|
+
: transformTypeAnnotationType(node.bound.typeAnnotation),
|
|
2506
2962
|
default:
|
|
2507
2963
|
node.default == null
|
|
2508
2964
|
? undefined
|
|
2509
|
-
:
|
|
2965
|
+
: transformTypeAnnotationType(node.default),
|
|
2510
2966
|
in: false,
|
|
2511
2967
|
out: false,
|
|
2512
2968
|
// in: variance.has('in'),
|
|
@@ -2526,7 +2982,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2526
2982
|
): TSESTree.TSTypeParameterInstantiation {
|
|
2527
2983
|
return {
|
|
2528
2984
|
type: 'TSTypeParameterInstantiation',
|
|
2529
|
-
params: node.params.map(
|
|
2985
|
+
params: node.params.map(transformTypeAnnotationType),
|
|
2530
2986
|
};
|
|
2531
2987
|
},
|
|
2532
2988
|
UnionTypeAnnotation(
|
|
@@ -2534,7 +2990,7 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2534
2990
|
): TSESTree.TSUnionType {
|
|
2535
2991
|
return {
|
|
2536
2992
|
type: 'TSUnionType',
|
|
2537
|
-
types: node.types.map(
|
|
2993
|
+
types: node.types.map(transformTypeAnnotationType),
|
|
2538
2994
|
};
|
|
2539
2995
|
},
|
|
2540
2996
|
VoidTypeAnnotation(
|
|
@@ -2563,5 +3019,5 @@ const getTransforms = (code: string, scopeManager: ScopeManager) => {
|
|
|
2563
3019
|
};
|
|
2564
3020
|
}
|
|
2565
3021
|
|
|
2566
|
-
return transform;
|
|
3022
|
+
return [transform, code];
|
|
2567
3023
|
};
|