flow-api-translator 0.10.0 → 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 +1052 -617
- package/dist/flowDefToTSDef.js.flow +1128 -612
- 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/dist/utils/ts-estree-ast-types.js.flow +1 -1
- package/package.json +5 -4
package/dist/flowDefToTSDef.js
CHANGED
|
@@ -24,15 +24,25 @@ var _ErrorUtils = require("./utils/ErrorUtils");
|
|
|
24
24
|
|
|
25
25
|
var _DocblockUtils = require("./utils/DocblockUtils");
|
|
26
26
|
|
|
27
|
+
var _os = require("os");
|
|
28
|
+
|
|
27
29
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
28
30
|
|
|
29
31
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
30
32
|
|
|
31
33
|
const cloneJSDocCommentsToNewNode = // $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
|
|
32
34
|
_hermesTransform.cloneJSDocCommentsToNewNode;
|
|
35
|
+
const makeCommentOwnLine = // $FlowExpectedError[incompatible-cast] - trust me this re-type is 100% safe
|
|
36
|
+
_hermesTransform.makeCommentOwnLine;
|
|
33
37
|
const VALID_REACT_IMPORTS = new Set(['React', 'react']);
|
|
34
38
|
|
|
35
|
-
function
|
|
39
|
+
function isValidReactImportOrGlobal(id) {
|
|
40
|
+
return VALID_REACT_IMPORTS.has(id.name) || id.name.startsWith('React$');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let shouldAddReactImport = null;
|
|
44
|
+
|
|
45
|
+
function flowDefToTSDef(originalCode, ast, scopeManager, opts) {
|
|
36
46
|
const tsBody = [];
|
|
37
47
|
const tsProgram = {
|
|
38
48
|
type: 'Program',
|
|
@@ -40,7 +50,8 @@ function flowDefToTSDef(originalCode, ast, scopeManager) {
|
|
|
40
50
|
sourceType: ast.sourceType,
|
|
41
51
|
docblock: ast.docblock == null ? null : (0, _DocblockUtils.removeAtFlowFromDocblock)(ast.docblock)
|
|
42
52
|
};
|
|
43
|
-
|
|
53
|
+
shouldAddReactImport = null;
|
|
54
|
+
const [transform, code] = getTransforms(originalCode, scopeManager, opts);
|
|
44
55
|
|
|
45
56
|
for (const node of ast.body) {
|
|
46
57
|
if (node.type in transform) {
|
|
@@ -51,15 +62,37 @@ function flowDefToTSDef(originalCode, ast, scopeManager) {
|
|
|
51
62
|
tsBody.push(...(Array.isArray(result) ? result : [result]));
|
|
52
63
|
} else {
|
|
53
64
|
throw (0, _ErrorUtils.unexpectedTranslationError)(node, `Unexpected node type ${node.type}`, {
|
|
54
|
-
code
|
|
65
|
+
code
|
|
55
66
|
});
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
|
|
70
|
+
if (shouldAddReactImport === true) {
|
|
71
|
+
tsBody.unshift({
|
|
72
|
+
type: 'ImportDeclaration',
|
|
73
|
+
assertions: [],
|
|
74
|
+
source: {
|
|
75
|
+
type: 'Literal',
|
|
76
|
+
value: 'react',
|
|
77
|
+
raw: "'react'"
|
|
78
|
+
},
|
|
79
|
+
specifiers: [{
|
|
80
|
+
type: 'ImportNamespaceSpecifier',
|
|
81
|
+
local: {
|
|
82
|
+
type: 'Identifier',
|
|
83
|
+
name: 'React'
|
|
84
|
+
}
|
|
85
|
+
}],
|
|
86
|
+
importKind: 'value'
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return [tsProgram, code];
|
|
60
91
|
}
|
|
61
92
|
|
|
62
|
-
const getTransforms = (
|
|
93
|
+
const getTransforms = (originalCode, scopeManager, opts) => {
|
|
94
|
+
let code = originalCode;
|
|
95
|
+
|
|
63
96
|
function translationError(node, message) {
|
|
64
97
|
return (0, _ErrorUtils.translationError)(node, message, {
|
|
65
98
|
code
|
|
@@ -72,8 +105,66 @@ const getTransforms = (code, scopeManager) => {
|
|
|
72
105
|
});
|
|
73
106
|
}
|
|
74
107
|
|
|
75
|
-
function
|
|
76
|
-
return
|
|
108
|
+
function unsupportedFeatureMessage(thing) {
|
|
109
|
+
return `Unsupported feature: Translating "${thing}" is currently not supported.`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function buildCodeFrameForComment(node, message) {
|
|
113
|
+
return (0, _ErrorUtils.buildCodeFrame)(node, message, code, false);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function addErrorComment(node, message) {
|
|
117
|
+
var _node$comments;
|
|
118
|
+
|
|
119
|
+
const comment = {
|
|
120
|
+
type: 'Block',
|
|
121
|
+
value: `*${_os.EOL} * ${message.replace(new RegExp(_os.EOL, 'g'), `${_os.EOL} * `)}${_os.EOL}*`,
|
|
122
|
+
leading: true,
|
|
123
|
+
printed: false
|
|
124
|
+
};
|
|
125
|
+
code = makeCommentOwnLine(code, comment); // $FlowExpectedError[prop-missing]
|
|
126
|
+
// $FlowExpectedError[cannot-write]
|
|
127
|
+
|
|
128
|
+
(_node$comments = node.comments) != null ? _node$comments : node.comments = []; // $FlowExpectedError[prop-missing]
|
|
129
|
+
// $FlowExpectedError[incompatible-cast]
|
|
130
|
+
|
|
131
|
+
node.comments.push(comment);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function unsupportedAnnotation(node, thing) {
|
|
135
|
+
const message = unsupportedFeatureMessage(thing);
|
|
136
|
+
|
|
137
|
+
if (opts.recoverFromErrors) {
|
|
138
|
+
const codeFrame = buildCodeFrameForComment(node, message);
|
|
139
|
+
const newNode = {
|
|
140
|
+
type: 'TSAnyKeyword'
|
|
141
|
+
};
|
|
142
|
+
addErrorComment(newNode, codeFrame);
|
|
143
|
+
return newNode;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
throw translationError(node, message);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function unsupportedDeclaration(node, thing, id, declare = false, typeParameters = null) {
|
|
150
|
+
const message = unsupportedFeatureMessage(thing);
|
|
151
|
+
|
|
152
|
+
if (opts.recoverFromErrors) {
|
|
153
|
+
const codeFrame = buildCodeFrameForComment(node, message);
|
|
154
|
+
const newNode = {
|
|
155
|
+
type: 'TSTypeAliasDeclaration',
|
|
156
|
+
declare,
|
|
157
|
+
id: transform.Identifier(id, false),
|
|
158
|
+
typeAnnotation: {
|
|
159
|
+
type: 'TSAnyKeyword'
|
|
160
|
+
},
|
|
161
|
+
typeParameters: typeParameters == null ? undefined : transform.TypeParameterDeclaration(typeParameters)
|
|
162
|
+
};
|
|
163
|
+
addErrorComment(newNode, codeFrame);
|
|
164
|
+
return newNode;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
throw translationError(node, message);
|
|
77
168
|
}
|
|
78
169
|
|
|
79
170
|
const topScope = (() => {
|
|
@@ -87,7 +178,21 @@ const getTransforms = (code, scopeManager) => {
|
|
|
87
178
|
})();
|
|
88
179
|
|
|
89
180
|
function isReactImport(id) {
|
|
90
|
-
let currentScope =
|
|
181
|
+
let currentScope = (() => {
|
|
182
|
+
let scope = null;
|
|
183
|
+
let node = id;
|
|
184
|
+
|
|
185
|
+
while (!scope && node) {
|
|
186
|
+
scope = scopeManager.acquire(node, true);
|
|
187
|
+
node = node.parent;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return scope;
|
|
191
|
+
})();
|
|
192
|
+
|
|
193
|
+
if (currentScope == null) {
|
|
194
|
+
throw new Error('unable to resolve scope');
|
|
195
|
+
}
|
|
91
196
|
|
|
92
197
|
const variableDef = (() => {
|
|
93
198
|
while (currentScope != null) {
|
|
@@ -99,11 +204,12 @@ const getTransforms = (code, scopeManager) => {
|
|
|
99
204
|
|
|
100
205
|
currentScope = currentScope.upper;
|
|
101
206
|
}
|
|
102
|
-
})(); // No variable found, it
|
|
207
|
+
})(); // No variable found, it is not imported.
|
|
208
|
+
// It could be a global though if isValidReactImportOrGlobal returns true.
|
|
103
209
|
|
|
104
210
|
|
|
105
211
|
if (variableDef == null) {
|
|
106
|
-
return
|
|
212
|
+
return false;
|
|
107
213
|
}
|
|
108
214
|
|
|
109
215
|
const def = variableDef.defs[0]; // Detect:
|
|
@@ -133,6 +239,393 @@ const getTransforms = (code, scopeManager) => {
|
|
|
133
239
|
return false;
|
|
134
240
|
}
|
|
135
241
|
|
|
242
|
+
function EnumImpl(node) {
|
|
243
|
+
const body = node.body;
|
|
244
|
+
|
|
245
|
+
if (body.type === 'EnumSymbolBody') {
|
|
246
|
+
/*
|
|
247
|
+
There's unfortunately no way for us to support this in a clean way.
|
|
248
|
+
We can get really close using this code:
|
|
249
|
+
```
|
|
250
|
+
declare namespace SymbolEnum {
|
|
251
|
+
export const member1: unique symbol;
|
|
252
|
+
export type member1 = typeof member1;
|
|
253
|
+
export const member2: unique symbol;
|
|
254
|
+
export type member2 = typeof member2;
|
|
255
|
+
}
|
|
256
|
+
type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
|
|
257
|
+
```
|
|
258
|
+
However as explained in https://github.com/microsoft/TypeScript/issues/43657:
|
|
259
|
+
"A unique symbol type is never transferred from one declaration to another through inference."
|
|
260
|
+
This intended behaviour in TS means that the usage of the fake-enum would look like this:
|
|
261
|
+
```
|
|
262
|
+
const value: SymbolEnum.member1 = SymbolEnum.member1;
|
|
263
|
+
// ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
|
|
264
|
+
```
|
|
265
|
+
Which is really clunky and shitty. It definitely works, but ofc it's not good.
|
|
266
|
+
We can go with this design if users are okay with it!
|
|
267
|
+
Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
|
|
268
|
+
*/
|
|
269
|
+
return unsupportedDeclaration(node, 'symbol enums', node.id, FlowESTree.isDeclareEnum(node));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (body.type === 'EnumBooleanBody') {
|
|
273
|
+
/*
|
|
274
|
+
TODO - TS enums only allow strings or numbers as their values - not booleans.
|
|
275
|
+
This means we need a non-ts-enum representation of the enum.
|
|
276
|
+
We can support boolean enums using a construct like this:
|
|
277
|
+
```ts
|
|
278
|
+
declare namespace BooleanEnum {
|
|
279
|
+
export const member1: true;
|
|
280
|
+
export type member1 = typeof member1;
|
|
281
|
+
export const member2: false;
|
|
282
|
+
export type member2 = typeof member1;
|
|
283
|
+
}
|
|
284
|
+
declare type BooleanEnum = boolean;
|
|
285
|
+
```
|
|
286
|
+
But it's pretty clunky and ugly.
|
|
287
|
+
Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
|
|
288
|
+
*/
|
|
289
|
+
return unsupportedDeclaration(node, 'boolean enums', node.id, FlowESTree.isDeclareEnum(node));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const members = [];
|
|
293
|
+
|
|
294
|
+
for (const member of body.members) {
|
|
295
|
+
switch (member.type) {
|
|
296
|
+
case 'EnumDefaultedMember':
|
|
297
|
+
{
|
|
298
|
+
if (body.type === 'EnumNumberBody') {
|
|
299
|
+
// this should be impossible!
|
|
300
|
+
throw unexpectedTranslationError(member, 'Unexpected defaulted number enum member');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
members.push({
|
|
304
|
+
type: 'TSEnumMember',
|
|
305
|
+
computed: false,
|
|
306
|
+
id: transform.Identifier(member.id, false),
|
|
307
|
+
initializer: {
|
|
308
|
+
type: 'Literal',
|
|
309
|
+
raw: `"${member.id.name}"`,
|
|
310
|
+
value: member.id.name
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
case 'EnumNumberMember':
|
|
317
|
+
case 'EnumStringMember':
|
|
318
|
+
members.push({
|
|
319
|
+
type: 'TSEnumMember',
|
|
320
|
+
computed: false,
|
|
321
|
+
id: transform.Identifier(member.id, false),
|
|
322
|
+
initializer: member.init.literalType === 'string' ? transform.StringLiteral(member.init) : transform.NumericLiteral(member.init)
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const bodyRepresentationType = body.type === 'EnumNumberBody' ? {
|
|
328
|
+
type: 'TSNumberKeyword'
|
|
329
|
+
} : {
|
|
330
|
+
type: 'TSStringKeyword'
|
|
331
|
+
};
|
|
332
|
+
const enumName = transform.Identifier(node.id, false);
|
|
333
|
+
return [{
|
|
334
|
+
type: 'TSEnumDeclaration',
|
|
335
|
+
const: false,
|
|
336
|
+
declare: true,
|
|
337
|
+
id: enumName,
|
|
338
|
+
members
|
|
339
|
+
}, // flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
|
|
340
|
+
// we can use declaration merging to declare these functions on the enum:
|
|
341
|
+
|
|
342
|
+
/*
|
|
343
|
+
declare enum Foo {
|
|
344
|
+
A = 1,
|
|
345
|
+
B = 2,
|
|
346
|
+
}
|
|
347
|
+
declare namespace Foo {
|
|
348
|
+
export function cast(value: number | null | undefined): Foo;
|
|
349
|
+
export function isValid(value: number | null | undefined): value is Foo;
|
|
350
|
+
export function members(): IterableIterator<Foo>;
|
|
351
|
+
export function getName(value: Foo): string;
|
|
352
|
+
}
|
|
353
|
+
*/
|
|
354
|
+
{
|
|
355
|
+
type: 'TSModuleDeclaration',
|
|
356
|
+
declare: true,
|
|
357
|
+
id: enumName,
|
|
358
|
+
body: {
|
|
359
|
+
type: 'TSModuleBlock',
|
|
360
|
+
body: [// export function cast(value: number | null | undefined): Foo
|
|
361
|
+
{
|
|
362
|
+
type: 'ExportNamedDeclaration',
|
|
363
|
+
declaration: {
|
|
364
|
+
type: 'TSDeclareFunction',
|
|
365
|
+
id: {
|
|
366
|
+
type: 'Identifier',
|
|
367
|
+
name: 'cast'
|
|
368
|
+
},
|
|
369
|
+
generator: false,
|
|
370
|
+
expression: false,
|
|
371
|
+
async: false,
|
|
372
|
+
params: [{
|
|
373
|
+
type: 'Identifier',
|
|
374
|
+
name: 'value',
|
|
375
|
+
typeAnnotation: {
|
|
376
|
+
type: 'TSTypeAnnotation',
|
|
377
|
+
typeAnnotation: {
|
|
378
|
+
type: 'TSUnionType',
|
|
379
|
+
types: [bodyRepresentationType, {
|
|
380
|
+
type: 'TSNullKeyword'
|
|
381
|
+
}, {
|
|
382
|
+
type: 'TSUndefinedKeyword'
|
|
383
|
+
}]
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}],
|
|
387
|
+
returnType: {
|
|
388
|
+
type: 'TSTypeAnnotation',
|
|
389
|
+
typeAnnotation: {
|
|
390
|
+
type: 'TSTypeReference',
|
|
391
|
+
typeName: enumName
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
specifiers: [],
|
|
396
|
+
source: null,
|
|
397
|
+
exportKind: 'value',
|
|
398
|
+
assertions: []
|
|
399
|
+
}, // export function isValid(value: number | null | undefined): value is Foo;
|
|
400
|
+
{
|
|
401
|
+
type: 'ExportNamedDeclaration',
|
|
402
|
+
declaration: {
|
|
403
|
+
type: 'TSDeclareFunction',
|
|
404
|
+
id: {
|
|
405
|
+
type: 'Identifier',
|
|
406
|
+
name: 'isValid'
|
|
407
|
+
},
|
|
408
|
+
generator: false,
|
|
409
|
+
expression: false,
|
|
410
|
+
async: false,
|
|
411
|
+
params: [{
|
|
412
|
+
type: 'Identifier',
|
|
413
|
+
name: 'value',
|
|
414
|
+
typeAnnotation: {
|
|
415
|
+
type: 'TSTypeAnnotation',
|
|
416
|
+
typeAnnotation: {
|
|
417
|
+
type: 'TSUnionType',
|
|
418
|
+
types: [bodyRepresentationType, {
|
|
419
|
+
type: 'TSNullKeyword'
|
|
420
|
+
}, {
|
|
421
|
+
type: 'TSUndefinedKeyword'
|
|
422
|
+
}]
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}],
|
|
426
|
+
returnType: {
|
|
427
|
+
type: 'TSTypeAnnotation',
|
|
428
|
+
typeAnnotation: {
|
|
429
|
+
type: 'TSTypePredicate',
|
|
430
|
+
asserts: false,
|
|
431
|
+
parameterName: {
|
|
432
|
+
type: 'Identifier',
|
|
433
|
+
name: 'value'
|
|
434
|
+
},
|
|
435
|
+
typeAnnotation: {
|
|
436
|
+
type: 'TSTypeAnnotation',
|
|
437
|
+
typeAnnotation: {
|
|
438
|
+
type: 'TSTypeReference',
|
|
439
|
+
typeName: enumName
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
specifiers: [],
|
|
446
|
+
source: null,
|
|
447
|
+
exportKind: 'value',
|
|
448
|
+
assertions: []
|
|
449
|
+
}, // export function members(): IterableIterator<Foo>;
|
|
450
|
+
{
|
|
451
|
+
type: 'ExportNamedDeclaration',
|
|
452
|
+
declaration: {
|
|
453
|
+
type: 'TSDeclareFunction',
|
|
454
|
+
id: {
|
|
455
|
+
type: 'Identifier',
|
|
456
|
+
name: 'members'
|
|
457
|
+
},
|
|
458
|
+
generator: false,
|
|
459
|
+
expression: false,
|
|
460
|
+
async: false,
|
|
461
|
+
params: [],
|
|
462
|
+
returnType: {
|
|
463
|
+
type: 'TSTypeAnnotation',
|
|
464
|
+
typeAnnotation: {
|
|
465
|
+
type: 'TSTypeReference',
|
|
466
|
+
typeName: {
|
|
467
|
+
type: 'Identifier',
|
|
468
|
+
name: 'IterableIterator'
|
|
469
|
+
},
|
|
470
|
+
typeParameters: {
|
|
471
|
+
type: 'TSTypeParameterInstantiation',
|
|
472
|
+
params: [{
|
|
473
|
+
type: 'TSTypeReference',
|
|
474
|
+
typeName: enumName
|
|
475
|
+
}]
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
specifiers: [],
|
|
481
|
+
source: null,
|
|
482
|
+
exportKind: 'value',
|
|
483
|
+
assertions: []
|
|
484
|
+
}, // export function getName(value: Foo): string;
|
|
485
|
+
{
|
|
486
|
+
type: 'ExportNamedDeclaration',
|
|
487
|
+
declaration: {
|
|
488
|
+
type: 'TSDeclareFunction',
|
|
489
|
+
id: {
|
|
490
|
+
type: 'Identifier',
|
|
491
|
+
name: 'getName'
|
|
492
|
+
},
|
|
493
|
+
generator: false,
|
|
494
|
+
expression: false,
|
|
495
|
+
async: false,
|
|
496
|
+
params: [{
|
|
497
|
+
type: 'Identifier',
|
|
498
|
+
name: 'value',
|
|
499
|
+
typeAnnotation: {
|
|
500
|
+
type: 'TSTypeAnnotation',
|
|
501
|
+
typeAnnotation: {
|
|
502
|
+
type: 'TSTypeReference',
|
|
503
|
+
typeName: enumName
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}],
|
|
507
|
+
returnType: {
|
|
508
|
+
type: 'TSTypeAnnotation',
|
|
509
|
+
typeAnnotation: {
|
|
510
|
+
type: 'TSStringKeyword'
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
specifiers: [],
|
|
515
|
+
source: null,
|
|
516
|
+
exportKind: 'value',
|
|
517
|
+
assertions: []
|
|
518
|
+
}]
|
|
519
|
+
}
|
|
520
|
+
}];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const getPlaceholderNameForTypeofImport = (() => {
|
|
524
|
+
let typeof_import_count = 0;
|
|
525
|
+
return () => `$$IMPORT_TYPEOF_${++typeof_import_count}$$`;
|
|
526
|
+
})();
|
|
527
|
+
|
|
528
|
+
const transformTypeAnnotationType = node => {
|
|
529
|
+
switch (node.type) {
|
|
530
|
+
case 'AnyTypeAnnotation':
|
|
531
|
+
return transform.AnyTypeAnnotation(node);
|
|
532
|
+
|
|
533
|
+
case 'ArrayTypeAnnotation':
|
|
534
|
+
return transform.ArrayTypeAnnotation(node);
|
|
535
|
+
|
|
536
|
+
case 'BigIntLiteralTypeAnnotation':
|
|
537
|
+
return transform.BigIntLiteralTypeAnnotation(node);
|
|
538
|
+
|
|
539
|
+
case 'BigIntTypeAnnotation':
|
|
540
|
+
return transform.BigIntTypeAnnotation(node);
|
|
541
|
+
|
|
542
|
+
case 'BooleanLiteralTypeAnnotation':
|
|
543
|
+
return transform.BooleanLiteralTypeAnnotation(node);
|
|
544
|
+
|
|
545
|
+
case 'BooleanTypeAnnotation':
|
|
546
|
+
return transform.BooleanTypeAnnotation(node);
|
|
547
|
+
|
|
548
|
+
case 'EmptyTypeAnnotation':
|
|
549
|
+
return transform.EmptyTypeAnnotation(node);
|
|
550
|
+
|
|
551
|
+
case 'ExistsTypeAnnotation':
|
|
552
|
+
return transform.ExistsTypeAnnotation(node);
|
|
553
|
+
|
|
554
|
+
case 'FunctionTypeAnnotation':
|
|
555
|
+
return transform.FunctionTypeAnnotation(node);
|
|
556
|
+
|
|
557
|
+
case 'GenericTypeAnnotation':
|
|
558
|
+
return transform.GenericTypeAnnotation(node);
|
|
559
|
+
|
|
560
|
+
case 'IndexedAccessType':
|
|
561
|
+
return transform.IndexedAccessType(node);
|
|
562
|
+
|
|
563
|
+
case 'InterfaceTypeAnnotation':
|
|
564
|
+
return transform.InterfaceTypeAnnotation(node);
|
|
565
|
+
|
|
566
|
+
case 'IntersectionTypeAnnotation':
|
|
567
|
+
return transform.IntersectionTypeAnnotation(node);
|
|
568
|
+
|
|
569
|
+
case 'MixedTypeAnnotation':
|
|
570
|
+
return transform.MixedTypeAnnotation(node);
|
|
571
|
+
|
|
572
|
+
case 'NullLiteralTypeAnnotation':
|
|
573
|
+
return transform.NullLiteralTypeAnnotation(node);
|
|
574
|
+
|
|
575
|
+
case 'NullableTypeAnnotation':
|
|
576
|
+
return transform.NullableTypeAnnotation(node);
|
|
577
|
+
|
|
578
|
+
case 'NumberLiteralTypeAnnotation':
|
|
579
|
+
return transform.NumberLiteralTypeAnnotation(node);
|
|
580
|
+
|
|
581
|
+
case 'NumberTypeAnnotation':
|
|
582
|
+
return transform.NumberTypeAnnotation(node);
|
|
583
|
+
|
|
584
|
+
case 'ObjectTypeAnnotation':
|
|
585
|
+
return transform.ObjectTypeAnnotation(node);
|
|
586
|
+
|
|
587
|
+
case 'OptionalIndexedAccessType':
|
|
588
|
+
return transform.OptionalIndexedAccessType(node);
|
|
589
|
+
|
|
590
|
+
case 'QualifiedTypeIdentifier':
|
|
591
|
+
return transform.QualifiedTypeIdentifier(node);
|
|
592
|
+
|
|
593
|
+
case 'StringLiteralTypeAnnotation':
|
|
594
|
+
return transform.StringLiteralTypeAnnotation(node);
|
|
595
|
+
|
|
596
|
+
case 'StringTypeAnnotation':
|
|
597
|
+
return transform.StringTypeAnnotation(node);
|
|
598
|
+
|
|
599
|
+
case 'SymbolTypeAnnotation':
|
|
600
|
+
return transform.SymbolTypeAnnotation(node);
|
|
601
|
+
|
|
602
|
+
case 'ThisTypeAnnotation':
|
|
603
|
+
return transform.ThisTypeAnnotation(node);
|
|
604
|
+
|
|
605
|
+
case 'TupleTypeAnnotation':
|
|
606
|
+
return transform.TupleTypeAnnotation(node);
|
|
607
|
+
|
|
608
|
+
case 'TupleTypeLabeledElement':
|
|
609
|
+
case 'TupleTypeSpreadElement':
|
|
610
|
+
return unsupportedAnnotation(node, node.type);
|
|
611
|
+
|
|
612
|
+
case 'TypeofTypeAnnotation':
|
|
613
|
+
return transform.TypeofTypeAnnotation(node);
|
|
614
|
+
|
|
615
|
+
case 'UnionTypeAnnotation':
|
|
616
|
+
return transform.UnionTypeAnnotation(node);
|
|
617
|
+
|
|
618
|
+
case 'VoidTypeAnnotation':
|
|
619
|
+
return transform.VoidTypeAnnotation(node);
|
|
620
|
+
|
|
621
|
+
case 'TypePredicate':
|
|
622
|
+
return unsupportedAnnotation(node, node.type);
|
|
623
|
+
|
|
624
|
+
default:
|
|
625
|
+
throw unexpectedTranslationError(node, `Unhandled type ${node.type}`);
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
|
|
136
629
|
const transform = {
|
|
137
630
|
AnyTypeAnnotation(_node) {
|
|
138
631
|
return {
|
|
@@ -143,7 +636,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
143
636
|
ArrayTypeAnnotation(node) {
|
|
144
637
|
return {
|
|
145
638
|
type: 'TSArrayType',
|
|
146
|
-
elementType:
|
|
639
|
+
elementType: transformTypeAnnotationType(node.elementType)
|
|
147
640
|
};
|
|
148
641
|
},
|
|
149
642
|
|
|
@@ -221,7 +714,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
221
714
|
const transformedBody = transform.ObjectTypeAnnotation(node.body);
|
|
222
715
|
|
|
223
716
|
if (transformedBody.type !== 'TSTypeLiteral') {
|
|
224
|
-
|
|
717
|
+
return unsupportedDeclaration(node.body, 'Spreads in declare class are not allowed', node.id, true, node.typeParameters);
|
|
225
718
|
}
|
|
226
719
|
|
|
227
720
|
for (const member of transformedBody.members) {
|
|
@@ -348,7 +841,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
348
841
|
```
|
|
349
842
|
Let's put a pin in it for now and deal with it later if the need arises.
|
|
350
843
|
*/
|
|
351
|
-
|
|
844
|
+
return unsupportedDeclaration((_node$body$callProper = node.body.callProperties[0]) != null ? _node$body$callProper : node.body, 'call signatures on classes', node.id, true, node.typeParameters);
|
|
352
845
|
}
|
|
353
846
|
|
|
354
847
|
default:
|
|
@@ -421,50 +914,48 @@ const getTransforms = (code, scopeManager) => {
|
|
|
421
914
|
if (referencedId.type === 'Identifier') {
|
|
422
915
|
const exportedVar = topScope.set.get(referencedId.name);
|
|
423
916
|
|
|
424
|
-
if (exportedVar
|
|
425
|
-
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
const def = exportedVar.defs[0];
|
|
429
|
-
|
|
430
|
-
switch (def.type) {
|
|
431
|
-
case 'ImportBinding':
|
|
432
|
-
{
|
|
433
|
-
// `import type { Wut } from 'mod'; declare export default Wut;`
|
|
434
|
-
// `import { type Wut } from 'mod'; declare export default Wut;`
|
|
435
|
-
// these cases should be wrapped in a variable because they're exporting a type, not a value
|
|
436
|
-
const specifier = def.node;
|
|
917
|
+
if (exportedVar != null && exportedVar.defs.length === 1) {
|
|
918
|
+
const def = exportedVar.defs[0];
|
|
437
919
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
920
|
+
switch (def.type) {
|
|
921
|
+
case 'ImportBinding':
|
|
922
|
+
{
|
|
923
|
+
// `import type { Wut } from 'mod'; declare export default Wut;`
|
|
924
|
+
// `import { type Wut } from 'mod'; declare export default Wut;`
|
|
925
|
+
// these cases should be wrapped in a variable because they're exporting a type, not a value
|
|
926
|
+
const specifier = def.node;
|
|
442
927
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
case 'FunctionName':
|
|
448
|
-
case 'ImplicitGlobalVariable':
|
|
449
|
-
case 'Variable':
|
|
450
|
-
// there's already a variable defined to hold the type
|
|
451
|
-
return {
|
|
452
|
-
type: 'ExportDefaultDeclaration',
|
|
453
|
-
declaration: {
|
|
454
|
-
type: 'Identifier',
|
|
455
|
-
name: referencedId.name
|
|
456
|
-
},
|
|
457
|
-
exportKind: 'value'
|
|
458
|
-
};
|
|
928
|
+
if (specifier.importKind === 'type' || specifier.parent.importKind === 'type') {
|
|
929
|
+
// fallthrough to the "default" handling
|
|
930
|
+
break;
|
|
931
|
+
} // intentional fallthrough to the "value" handling
|
|
459
932
|
|
|
460
|
-
|
|
461
|
-
case 'Parameter':
|
|
462
|
-
case 'TypeParameter':
|
|
463
|
-
throw translationError(def.node, `Unexpected variable def type: ${def.type}`);
|
|
933
|
+
}
|
|
464
934
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
935
|
+
case 'ClassName':
|
|
936
|
+
case 'Enum':
|
|
937
|
+
case 'FunctionName':
|
|
938
|
+
case 'ImplicitGlobalVariable':
|
|
939
|
+
case 'Variable':
|
|
940
|
+
// there's already a variable defined to hold the type
|
|
941
|
+
return {
|
|
942
|
+
type: 'ExportDefaultDeclaration',
|
|
943
|
+
declaration: {
|
|
944
|
+
type: 'Identifier',
|
|
945
|
+
name: referencedId.name
|
|
946
|
+
},
|
|
947
|
+
exportKind: 'value'
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
case 'CatchClause':
|
|
951
|
+
case 'Parameter':
|
|
952
|
+
case 'TypeParameter':
|
|
953
|
+
throw translationError(def.node, `Unexpected variable def type: ${def.type}`);
|
|
954
|
+
|
|
955
|
+
case 'Type':
|
|
956
|
+
// fallthrough to the "default" handling
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
468
959
|
}
|
|
469
960
|
} // intentional fallthrough to the "default" handling
|
|
470
961
|
|
|
@@ -494,7 +985,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
494
985
|
name: SPECIFIER,
|
|
495
986
|
typeAnnotation: {
|
|
496
987
|
type: 'TSTypeAnnotation',
|
|
497
|
-
typeAnnotation:
|
|
988
|
+
typeAnnotation: transformTypeAnnotationType(declaration)
|
|
498
989
|
}
|
|
499
990
|
},
|
|
500
991
|
init: null
|
|
@@ -528,44 +1019,59 @@ const getTransforms = (code, scopeManager) => {
|
|
|
528
1019
|
};
|
|
529
1020
|
}
|
|
530
1021
|
|
|
531
|
-
const {
|
|
532
|
-
declaration,
|
|
533
|
-
exportKind
|
|
534
|
-
} = (() => {
|
|
1022
|
+
const declarations = (() => {
|
|
535
1023
|
switch (node.declaration.type) {
|
|
536
1024
|
case 'DeclareClass':
|
|
537
|
-
return {
|
|
1025
|
+
return [{
|
|
538
1026
|
declaration: transform.DeclareClass(node.declaration),
|
|
539
1027
|
exportKind: 'value'
|
|
540
|
-
};
|
|
1028
|
+
}];
|
|
541
1029
|
|
|
542
1030
|
case 'DeclareFunction':
|
|
543
|
-
return {
|
|
1031
|
+
return [{
|
|
544
1032
|
declaration: transform.DeclareFunction(node.declaration),
|
|
545
1033
|
exportKind: 'value'
|
|
546
|
-
};
|
|
1034
|
+
}];
|
|
547
1035
|
|
|
548
1036
|
case 'DeclareInterface':
|
|
549
|
-
return {
|
|
1037
|
+
return [{
|
|
550
1038
|
declaration: transform.DeclareInterface(node.declaration),
|
|
551
1039
|
exportKind: 'type'
|
|
552
|
-
};
|
|
1040
|
+
}];
|
|
553
1041
|
|
|
554
1042
|
case 'DeclareOpaqueType':
|
|
555
|
-
return {
|
|
1043
|
+
return [{
|
|
556
1044
|
declaration: transform.DeclareOpaqueType(node.declaration),
|
|
557
1045
|
exportKind: 'type'
|
|
558
|
-
};
|
|
1046
|
+
}];
|
|
559
1047
|
|
|
560
1048
|
case 'DeclareVariable':
|
|
561
|
-
return {
|
|
1049
|
+
return [{
|
|
562
1050
|
declaration: transform.DeclareVariable(node.declaration),
|
|
563
1051
|
exportKind: 'value'
|
|
564
|
-
};
|
|
1052
|
+
}];
|
|
1053
|
+
|
|
1054
|
+
case 'DeclareEnum':
|
|
1055
|
+
{
|
|
1056
|
+
const result = transform.DeclareEnum(node.declaration);
|
|
1057
|
+
return Array.isArray(result) ? [{
|
|
1058
|
+
declaration: result[0],
|
|
1059
|
+
exportKind: 'type'
|
|
1060
|
+
}, {
|
|
1061
|
+
declaration: result[1],
|
|
1062
|
+
exportKind: 'type'
|
|
1063
|
+
}] : [{
|
|
1064
|
+
declaration: result,
|
|
1065
|
+
exportKind: 'type'
|
|
1066
|
+
}];
|
|
1067
|
+
}
|
|
565
1068
|
}
|
|
566
1069
|
})();
|
|
567
1070
|
|
|
568
|
-
return {
|
|
1071
|
+
return declarations.map(({
|
|
1072
|
+
declaration,
|
|
1073
|
+
exportKind
|
|
1074
|
+
}) => ({
|
|
569
1075
|
type: 'ExportNamedDeclaration',
|
|
570
1076
|
// flow does not currently support assertions
|
|
571
1077
|
assertions: [],
|
|
@@ -573,7 +1079,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
573
1079
|
exportKind,
|
|
574
1080
|
source: null,
|
|
575
1081
|
specifiers: []
|
|
576
|
-
};
|
|
1082
|
+
}));
|
|
577
1083
|
} else {
|
|
578
1084
|
return {
|
|
579
1085
|
type: 'ExportNamedDeclaration',
|
|
@@ -635,7 +1141,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
635
1141
|
type: 'TSTypeAliasDeclaration',
|
|
636
1142
|
declare: node.type === 'DeclareTypeAlias',
|
|
637
1143
|
id: transform.Identifier(node.id, false),
|
|
638
|
-
typeAnnotation:
|
|
1144
|
+
typeAnnotation: transformTypeAnnotationType(node.right),
|
|
639
1145
|
typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
|
|
640
1146
|
};
|
|
641
1147
|
},
|
|
@@ -650,7 +1156,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
650
1156
|
id: transform.Identifier(node.id, false),
|
|
651
1157
|
typeAnnotation: node.supertype == null ? {
|
|
652
1158
|
type: 'TSUnknownKeyword'
|
|
653
|
-
} :
|
|
1159
|
+
} : transformTypeAnnotationType(node.supertype),
|
|
654
1160
|
typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
|
|
655
1161
|
};
|
|
656
1162
|
},
|
|
@@ -665,297 +1171,24 @@ const getTransforms = (code, scopeManager) => {
|
|
|
665
1171
|
id: transform.Identifier(node.id, true),
|
|
666
1172
|
init: null
|
|
667
1173
|
}],
|
|
668
|
-
kind:
|
|
1174
|
+
kind: node.kind
|
|
669
1175
|
};
|
|
670
1176
|
},
|
|
671
1177
|
|
|
1178
|
+
DeclareEnum(node) {
|
|
1179
|
+
return EnumImpl(node);
|
|
1180
|
+
},
|
|
1181
|
+
|
|
672
1182
|
EmptyTypeAnnotation(node) {
|
|
673
1183
|
// Flow's `empty` type doesn't map well to any types in TS.
|
|
674
1184
|
// The closest is `never`, but `never` has a number of different semantics
|
|
675
1185
|
// In reality no human code should ever directly use the `empty` type in flow
|
|
676
1186
|
// So let's put a pin in it for now
|
|
677
|
-
|
|
1187
|
+
return unsupportedAnnotation(node, 'empty type');
|
|
678
1188
|
},
|
|
679
1189
|
|
|
680
1190
|
EnumDeclaration(node) {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
if (body.type === 'EnumSymbolBody') {
|
|
684
|
-
/*
|
|
685
|
-
There's unfortunately no way for us to support this in a clean way.
|
|
686
|
-
We can get really close using this code:
|
|
687
|
-
```
|
|
688
|
-
declare namespace SymbolEnum {
|
|
689
|
-
export const member1: unique symbol;
|
|
690
|
-
export type member1 = typeof member1;
|
|
691
|
-
export const member2: unique symbol;
|
|
692
|
-
export type member2 = typeof member2;
|
|
693
|
-
}
|
|
694
|
-
type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
|
|
695
|
-
```
|
|
696
|
-
However as explained in https://github.com/microsoft/TypeScript/issues/43657:
|
|
697
|
-
"A unique symbol type is never transferred from one declaration to another through inference."
|
|
698
|
-
This intended behaviour in TS means that the usage of the fake-enum would look like this:
|
|
699
|
-
```
|
|
700
|
-
const value: SymbolEnum.member1 = SymbolEnum.member1;
|
|
701
|
-
// ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
|
|
702
|
-
```
|
|
703
|
-
Which is really clunky and shitty. It definitely works, but ofc it's not good.
|
|
704
|
-
We can go with this design if users are okay with it!
|
|
705
|
-
Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
|
|
706
|
-
*/
|
|
707
|
-
throw unsupportedTranslationError(node, 'symbol enums');
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
if (body.type === 'EnumBooleanBody') {
|
|
711
|
-
/*
|
|
712
|
-
TODO - TS enums only allow strings or numbers as their values - not booleans.
|
|
713
|
-
This means we need a non-ts-enum representation of the enum.
|
|
714
|
-
We can support boolean enums using a construct like this:
|
|
715
|
-
```ts
|
|
716
|
-
declare namespace BooleanEnum {
|
|
717
|
-
export const member1: true;
|
|
718
|
-
export type member1 = typeof member1;
|
|
719
|
-
export const member2: false;
|
|
720
|
-
export type member2 = typeof member1;
|
|
721
|
-
}
|
|
722
|
-
declare type BooleanEnum = boolean;
|
|
723
|
-
```
|
|
724
|
-
But it's pretty clunky and ugly.
|
|
725
|
-
Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
|
|
726
|
-
*/
|
|
727
|
-
throw unsupportedTranslationError(node, 'boolean enums');
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
const members = [];
|
|
731
|
-
|
|
732
|
-
for (const member of body.members) {
|
|
733
|
-
switch (member.type) {
|
|
734
|
-
case 'EnumDefaultedMember':
|
|
735
|
-
{
|
|
736
|
-
if (body.type === 'EnumNumberBody') {
|
|
737
|
-
// this should be impossible!
|
|
738
|
-
throw unexpectedTranslationError(member, 'Unexpected defaulted number enum member');
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
members.push({
|
|
742
|
-
type: 'TSEnumMember',
|
|
743
|
-
computed: false,
|
|
744
|
-
id: transform.Identifier(member.id, false),
|
|
745
|
-
initializer: {
|
|
746
|
-
type: 'Literal',
|
|
747
|
-
raw: `"${member.id.name}"`,
|
|
748
|
-
value: member.id.name
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
break;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
case 'EnumNumberMember':
|
|
755
|
-
case 'EnumStringMember':
|
|
756
|
-
members.push({
|
|
757
|
-
type: 'TSEnumMember',
|
|
758
|
-
computed: false,
|
|
759
|
-
id: transform.Identifier(member.id, false),
|
|
760
|
-
initializer: member.init.literalType === 'string' ? transform.StringLiteral(member.init) : transform.NumericLiteral(member.init)
|
|
761
|
-
});
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
const bodyRepresentationType = body.type === 'EnumNumberBody' ? {
|
|
766
|
-
type: 'TSNumberKeyword'
|
|
767
|
-
} : {
|
|
768
|
-
type: 'TSStringKeyword'
|
|
769
|
-
};
|
|
770
|
-
const enumName = transform.Identifier(node.id, false);
|
|
771
|
-
return [{
|
|
772
|
-
type: 'TSEnumDeclaration',
|
|
773
|
-
const: false,
|
|
774
|
-
declare: true,
|
|
775
|
-
id: enumName,
|
|
776
|
-
members
|
|
777
|
-
}, // flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
|
|
778
|
-
// we can use declaration merging to declare these functions on the enum:
|
|
779
|
-
|
|
780
|
-
/*
|
|
781
|
-
declare enum Foo {
|
|
782
|
-
A = 1,
|
|
783
|
-
B = 2,
|
|
784
|
-
}
|
|
785
|
-
declare namespace Foo {
|
|
786
|
-
export function cast(value: number | null | undefined): Foo;
|
|
787
|
-
export function isValid(value: number | null | undefined): value is Foo;
|
|
788
|
-
export function members(): IterableIterator<Foo>;
|
|
789
|
-
export function getName(value: Foo): string;
|
|
790
|
-
}
|
|
791
|
-
*/
|
|
792
|
-
{
|
|
793
|
-
type: 'TSModuleDeclaration',
|
|
794
|
-
declare: true,
|
|
795
|
-
id: enumName,
|
|
796
|
-
body: {
|
|
797
|
-
type: 'TSModuleBlock',
|
|
798
|
-
body: [// export function cast(value: number | null | undefined): Foo
|
|
799
|
-
{
|
|
800
|
-
type: 'ExportNamedDeclaration',
|
|
801
|
-
declaration: {
|
|
802
|
-
type: 'TSDeclareFunction',
|
|
803
|
-
id: {
|
|
804
|
-
type: 'Identifier',
|
|
805
|
-
name: 'cast'
|
|
806
|
-
},
|
|
807
|
-
generator: false,
|
|
808
|
-
expression: false,
|
|
809
|
-
async: false,
|
|
810
|
-
params: [{
|
|
811
|
-
type: 'Identifier',
|
|
812
|
-
name: 'value',
|
|
813
|
-
typeAnnotation: {
|
|
814
|
-
type: 'TSTypeAnnotation',
|
|
815
|
-
typeAnnotation: {
|
|
816
|
-
type: 'TSUnionType',
|
|
817
|
-
types: [bodyRepresentationType, {
|
|
818
|
-
type: 'TSNullKeyword'
|
|
819
|
-
}, {
|
|
820
|
-
type: 'TSUndefinedKeyword'
|
|
821
|
-
}]
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
}],
|
|
825
|
-
returnType: {
|
|
826
|
-
type: 'TSTypeAnnotation',
|
|
827
|
-
typeAnnotation: {
|
|
828
|
-
type: 'TSTypeReference',
|
|
829
|
-
typeName: enumName
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
},
|
|
833
|
-
specifiers: [],
|
|
834
|
-
source: null,
|
|
835
|
-
exportKind: 'value',
|
|
836
|
-
assertions: []
|
|
837
|
-
}, // export function isValid(value: number | null | undefined): value is Foo;
|
|
838
|
-
{
|
|
839
|
-
type: 'ExportNamedDeclaration',
|
|
840
|
-
declaration: {
|
|
841
|
-
type: 'TSDeclareFunction',
|
|
842
|
-
id: {
|
|
843
|
-
type: 'Identifier',
|
|
844
|
-
name: 'isValid'
|
|
845
|
-
},
|
|
846
|
-
generator: false,
|
|
847
|
-
expression: false,
|
|
848
|
-
async: false,
|
|
849
|
-
params: [{
|
|
850
|
-
type: 'Identifier',
|
|
851
|
-
name: 'value',
|
|
852
|
-
typeAnnotation: {
|
|
853
|
-
type: 'TSTypeAnnotation',
|
|
854
|
-
typeAnnotation: {
|
|
855
|
-
type: 'TSUnionType',
|
|
856
|
-
types: [bodyRepresentationType, {
|
|
857
|
-
type: 'TSNullKeyword'
|
|
858
|
-
}, {
|
|
859
|
-
type: 'TSUndefinedKeyword'
|
|
860
|
-
}]
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
}],
|
|
864
|
-
returnType: {
|
|
865
|
-
type: 'TSTypeAnnotation',
|
|
866
|
-
typeAnnotation: {
|
|
867
|
-
type: 'TSTypePredicate',
|
|
868
|
-
asserts: false,
|
|
869
|
-
parameterName: {
|
|
870
|
-
type: 'Identifier',
|
|
871
|
-
name: 'value'
|
|
872
|
-
},
|
|
873
|
-
typeAnnotation: {
|
|
874
|
-
type: 'TSTypeAnnotation',
|
|
875
|
-
typeAnnotation: {
|
|
876
|
-
type: 'TSTypeReference',
|
|
877
|
-
typeName: enumName
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
},
|
|
883
|
-
specifiers: [],
|
|
884
|
-
source: null,
|
|
885
|
-
exportKind: 'value',
|
|
886
|
-
assertions: []
|
|
887
|
-
}, // export function members(): IterableIterator<Foo>;
|
|
888
|
-
{
|
|
889
|
-
type: 'ExportNamedDeclaration',
|
|
890
|
-
declaration: {
|
|
891
|
-
type: 'TSDeclareFunction',
|
|
892
|
-
id: {
|
|
893
|
-
type: 'Identifier',
|
|
894
|
-
name: 'members'
|
|
895
|
-
},
|
|
896
|
-
generator: false,
|
|
897
|
-
expression: false,
|
|
898
|
-
async: false,
|
|
899
|
-
params: [],
|
|
900
|
-
returnType: {
|
|
901
|
-
type: 'TSTypeAnnotation',
|
|
902
|
-
typeAnnotation: {
|
|
903
|
-
type: 'TSTypeReference',
|
|
904
|
-
typeName: {
|
|
905
|
-
type: 'Identifier',
|
|
906
|
-
name: 'IterableIterator'
|
|
907
|
-
},
|
|
908
|
-
typeParameters: {
|
|
909
|
-
type: 'TSTypeParameterInstantiation',
|
|
910
|
-
params: [{
|
|
911
|
-
type: 'TSTypeReference',
|
|
912
|
-
typeName: enumName
|
|
913
|
-
}]
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
},
|
|
918
|
-
specifiers: [],
|
|
919
|
-
source: null,
|
|
920
|
-
exportKind: 'value',
|
|
921
|
-
assertions: []
|
|
922
|
-
}, // export function getName(value: Foo): string;
|
|
923
|
-
{
|
|
924
|
-
type: 'ExportNamedDeclaration',
|
|
925
|
-
declaration: {
|
|
926
|
-
type: 'TSDeclareFunction',
|
|
927
|
-
id: {
|
|
928
|
-
type: 'Identifier',
|
|
929
|
-
name: 'getName'
|
|
930
|
-
},
|
|
931
|
-
generator: false,
|
|
932
|
-
expression: false,
|
|
933
|
-
async: false,
|
|
934
|
-
params: [{
|
|
935
|
-
type: 'Identifier',
|
|
936
|
-
name: 'value',
|
|
937
|
-
typeAnnotation: {
|
|
938
|
-
type: 'TSTypeAnnotation',
|
|
939
|
-
typeAnnotation: {
|
|
940
|
-
type: 'TSTypeReference',
|
|
941
|
-
typeName: enumName
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
}],
|
|
945
|
-
returnType: {
|
|
946
|
-
type: 'TSTypeAnnotation',
|
|
947
|
-
typeAnnotation: {
|
|
948
|
-
type: 'TSStringKeyword'
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
},
|
|
952
|
-
specifiers: [],
|
|
953
|
-
source: null,
|
|
954
|
-
exportKind: 'value',
|
|
955
|
-
assertions: []
|
|
956
|
-
}]
|
|
957
|
-
}
|
|
958
|
-
}];
|
|
1191
|
+
return EnumImpl(node);
|
|
959
1192
|
},
|
|
960
1193
|
|
|
961
1194
|
DeclareModuleExports(node) {
|
|
@@ -965,7 +1198,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
965
1198
|
ExistsTypeAnnotation(node) {
|
|
966
1199
|
// The existential type does not map to any types in TS
|
|
967
1200
|
// It's also super deprecated - so let's not ever worry
|
|
968
|
-
|
|
1201
|
+
return unsupportedAnnotation(node, 'existential type');
|
|
969
1202
|
},
|
|
970
1203
|
|
|
971
1204
|
ExportNamedDeclaration(node) {
|
|
@@ -984,11 +1217,12 @@ const getTransforms = (code, scopeManager) => {
|
|
|
984
1217
|
|
|
985
1218
|
const [exportedDeclaration, mergedDeclaration] = (() => {
|
|
986
1219
|
if (node.declaration == null) {
|
|
987
|
-
return [null];
|
|
1220
|
+
return [null, null];
|
|
988
1221
|
}
|
|
989
1222
|
|
|
990
1223
|
switch (node.declaration.type) {
|
|
991
1224
|
case 'ClassDeclaration':
|
|
1225
|
+
case 'ComponentDeclaration':
|
|
992
1226
|
case 'FunctionDeclaration':
|
|
993
1227
|
case 'VariableDeclaration':
|
|
994
1228
|
// These cases shouldn't happen in flow defs because they have their own special
|
|
@@ -996,7 +1230,10 @@ const getTransforms = (code, scopeManager) => {
|
|
|
996
1230
|
throw unexpectedTranslationError(node.declaration, `Unexpected named declaration found ${node.declaration.type}`);
|
|
997
1231
|
|
|
998
1232
|
case 'EnumDeclaration':
|
|
999
|
-
|
|
1233
|
+
{
|
|
1234
|
+
const result = transform.EnumDeclaration(node.declaration);
|
|
1235
|
+
return Array.isArray(result) ? result : [result, null];
|
|
1236
|
+
}
|
|
1000
1237
|
|
|
1001
1238
|
case 'InterfaceDeclaration':
|
|
1002
1239
|
return [transform.InterfaceDeclaration(node.declaration), null];
|
|
@@ -1052,7 +1289,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1052
1289
|
name: 'this',
|
|
1053
1290
|
typeAnnotation: {
|
|
1054
1291
|
type: 'TSTypeAnnotation',
|
|
1055
|
-
typeAnnotation:
|
|
1292
|
+
typeAnnotation: transformTypeAnnotationType(node.this.typeAnnotation)
|
|
1056
1293
|
}
|
|
1057
1294
|
});
|
|
1058
1295
|
}
|
|
@@ -1067,7 +1304,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1067
1304
|
} : transform.Identifier(rest.name, false),
|
|
1068
1305
|
typeAnnotation: {
|
|
1069
1306
|
type: 'TSTypeAnnotation',
|
|
1070
|
-
typeAnnotation:
|
|
1307
|
+
typeAnnotation: transformTypeAnnotationType(rest.typeAnnotation)
|
|
1071
1308
|
}
|
|
1072
1309
|
});
|
|
1073
1310
|
}
|
|
@@ -1077,7 +1314,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1077
1314
|
params,
|
|
1078
1315
|
returnType: {
|
|
1079
1316
|
type: 'TSTypeAnnotation',
|
|
1080
|
-
typeAnnotation:
|
|
1317
|
+
typeAnnotation: transformTypeAnnotationType(node.returnType)
|
|
1081
1318
|
},
|
|
1082
1319
|
typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
|
|
1083
1320
|
};
|
|
@@ -1089,7 +1326,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1089
1326
|
name: node.name == null ? `$$PARAM_${idx}$$` : node.name.name,
|
|
1090
1327
|
typeAnnotation: {
|
|
1091
1328
|
type: 'TSTypeAnnotation',
|
|
1092
|
-
typeAnnotation:
|
|
1329
|
+
typeAnnotation: transformTypeAnnotationType(node.typeAnnotation)
|
|
1093
1330
|
},
|
|
1094
1331
|
optional: node.optional
|
|
1095
1332
|
};
|
|
@@ -1129,7 +1366,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1129
1366
|
const res = [];
|
|
1130
1367
|
|
|
1131
1368
|
for (const param of node.typeParameters.params) {
|
|
1132
|
-
res.push(
|
|
1369
|
+
res.push(transformTypeAnnotationType(param));
|
|
1133
1370
|
}
|
|
1134
1371
|
|
|
1135
1372
|
return res;
|
|
@@ -1168,7 +1405,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1168
1405
|
type PropType = ReturnType<ExtractPropType<Obj>>; // number
|
|
1169
1406
|
```
|
|
1170
1407
|
*/
|
|
1171
|
-
|
|
1408
|
+
return unsupportedAnnotation(node, fullTypeName);
|
|
1172
1409
|
}
|
|
1173
1410
|
|
|
1174
1411
|
case '$Diff':
|
|
@@ -1344,86 +1581,212 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1344
1581
|
};
|
|
1345
1582
|
}
|
|
1346
1583
|
|
|
1347
|
-
case '$Shape':
|
|
1348
|
-
case '$Partial':
|
|
1349
|
-
{
|
|
1350
|
-
// `$Partial<T>` => `Partial<T>`
|
|
1584
|
+
case '$Shape':
|
|
1585
|
+
case '$Partial':
|
|
1586
|
+
{
|
|
1587
|
+
// `$Partial<T>` => `Partial<T>`
|
|
1588
|
+
return {
|
|
1589
|
+
type: 'TSTypeReference',
|
|
1590
|
+
typeName: {
|
|
1591
|
+
type: 'Identifier',
|
|
1592
|
+
name: 'Partial'
|
|
1593
|
+
},
|
|
1594
|
+
typeParameters: {
|
|
1595
|
+
type: 'TSTypeParameterInstantiation',
|
|
1596
|
+
params: assertHasExactlyNTypeParameters(1)
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
case '$Values':
|
|
1602
|
+
{
|
|
1603
|
+
// `$Values<T>` => `T[keyof T]`
|
|
1604
|
+
const transformedType = assertHasExactlyNTypeParameters(1)[0];
|
|
1605
|
+
return {
|
|
1606
|
+
type: 'TSIndexedAccessType',
|
|
1607
|
+
objectType: transformedType,
|
|
1608
|
+
indexType: {
|
|
1609
|
+
type: 'TSTypeOperator',
|
|
1610
|
+
operator: 'keyof',
|
|
1611
|
+
typeAnnotation: transformedType
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
case 'Class':
|
|
1617
|
+
{
|
|
1618
|
+
// `Class<T>` => `new (...args: any[]) => T`
|
|
1619
|
+
const param = assertHasExactlyNTypeParameters(1)[0];
|
|
1620
|
+
|
|
1621
|
+
if (param.type !== 'TSTypeReference') {
|
|
1622
|
+
throw translationError(node, 'Expected a type reference within Class<T>');
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
return {
|
|
1626
|
+
type: 'TSConstructorType',
|
|
1627
|
+
abstract: false,
|
|
1628
|
+
params: [{
|
|
1629
|
+
type: 'RestElement',
|
|
1630
|
+
argument: {
|
|
1631
|
+
type: 'Identifier',
|
|
1632
|
+
name: 'args'
|
|
1633
|
+
},
|
|
1634
|
+
typeAnnotation: {
|
|
1635
|
+
type: 'TSTypeAnnotation',
|
|
1636
|
+
typeAnnotation: {
|
|
1637
|
+
type: 'TSArrayType',
|
|
1638
|
+
elementType: {
|
|
1639
|
+
type: 'TSAnyKeyword'
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}],
|
|
1644
|
+
returnType: {
|
|
1645
|
+
type: 'TSTypeAnnotation',
|
|
1646
|
+
typeAnnotation: param
|
|
1647
|
+
}
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
} // React special conversion:
|
|
1651
|
+
|
|
1652
|
+
|
|
1653
|
+
const validReactImportOrGlobal = isValidReactImportOrGlobal(baseId);
|
|
1654
|
+
const reactImport = isReactImport(baseId);
|
|
1655
|
+
|
|
1656
|
+
if (validReactImportOrGlobal || reactImport) {
|
|
1657
|
+
// Returns appropriate Identifier for `React` import.
|
|
1658
|
+
// If a global is in use, set a flag to indicate that we should add the import.
|
|
1659
|
+
const getReactIdentifier = () => {
|
|
1660
|
+
if (shouldAddReactImport !== false) {
|
|
1661
|
+
shouldAddReactImport = !reactImport;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
return {
|
|
1665
|
+
type: 'Identifier',
|
|
1666
|
+
name: `React`
|
|
1667
|
+
};
|
|
1668
|
+
};
|
|
1669
|
+
|
|
1670
|
+
switch (fullTypeName) {
|
|
1671
|
+
// TODO: In flow this is `ChildrenArray<T> = T | $ReadOnlyArray<ChildrenArray<T>>`.
|
|
1672
|
+
// The recursive nature of it is rarely needed, so we're simplifying this for now
|
|
1673
|
+
// but omitting that aspect. Once we're able to provide utility types for our translations,
|
|
1674
|
+
// we should update this.
|
|
1675
|
+
// React.ChildrenArray<T> -> T | ReadonlyArray<T>
|
|
1676
|
+
// React$ChildrenArray<T> -> T | ReadonlyArray<T>
|
|
1677
|
+
case 'React.ChildrenArray':
|
|
1678
|
+
case 'React$ChildrenArray':
|
|
1679
|
+
{
|
|
1680
|
+
const [param] = assertHasExactlyNTypeParameters(1);
|
|
1681
|
+
return {
|
|
1682
|
+
type: 'TSUnionType',
|
|
1683
|
+
types: [param, {
|
|
1684
|
+
type: 'TSTypeReference',
|
|
1685
|
+
typeName: {
|
|
1686
|
+
type: 'Identifier',
|
|
1687
|
+
name: 'ReadonlyArray'
|
|
1688
|
+
},
|
|
1689
|
+
typeParameters: {
|
|
1690
|
+
type: 'TSTypeParameterInstantiation',
|
|
1691
|
+
params: [param]
|
|
1692
|
+
}
|
|
1693
|
+
}]
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
// React.Component<A,B> -> React.Component<A,B>
|
|
1697
|
+
// React$Component<A,B> -> React.Component<A,B>
|
|
1698
|
+
|
|
1699
|
+
case 'React.Component':
|
|
1700
|
+
case 'React$Component':
|
|
1701
|
+
{
|
|
1702
|
+
const typeParameters = node.typeParameters;
|
|
1703
|
+
|
|
1704
|
+
if (typeParameters == null || typeParameters.params.length === 0) {
|
|
1705
|
+
throw translationError(node, `Expected at least 1 type parameter with \`${fullTypeName}\``);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
const params = typeParameters.params;
|
|
1709
|
+
|
|
1710
|
+
if (params.length > 2) {
|
|
1711
|
+
throw translationError(node, `Expected at no more than 2 type parameters with \`${fullTypeName}\``);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
return {
|
|
1715
|
+
type: 'TSTypeReference',
|
|
1716
|
+
typeName: {
|
|
1717
|
+
type: 'TSQualifiedName',
|
|
1718
|
+
left: getReactIdentifier(),
|
|
1719
|
+
right: {
|
|
1720
|
+
type: 'Identifier',
|
|
1721
|
+
name: 'Component'
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
typeParameters: {
|
|
1725
|
+
type: 'TSTypeParameterInstantiation',
|
|
1726
|
+
params: params.map(param => transformTypeAnnotationType(param))
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
// React.Context<A> -> React.Context<A>
|
|
1731
|
+
// React$Context<A> -> React.Context<A>
|
|
1732
|
+
|
|
1733
|
+
case 'React$Context':
|
|
1734
|
+
case 'React.Context':
|
|
1351
1735
|
return {
|
|
1352
1736
|
type: 'TSTypeReference',
|
|
1353
1737
|
typeName: {
|
|
1354
|
-
type: '
|
|
1355
|
-
|
|
1738
|
+
type: 'TSQualifiedName',
|
|
1739
|
+
left: getReactIdentifier(),
|
|
1740
|
+
right: {
|
|
1741
|
+
type: 'Identifier',
|
|
1742
|
+
name: `Context`
|
|
1743
|
+
}
|
|
1356
1744
|
},
|
|
1357
1745
|
typeParameters: {
|
|
1358
1746
|
type: 'TSTypeParameterInstantiation',
|
|
1359
1747
|
params: assertHasExactlyNTypeParameters(1)
|
|
1360
1748
|
}
|
|
1361
1749
|
};
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
case '$Subtype':
|
|
1365
|
-
case '$Supertype':
|
|
1366
|
-
{
|
|
1367
|
-
// These types are deprecated and shouldn't be used in any modern code
|
|
1368
|
-
// so let's not even bother trying to figure it out
|
|
1369
|
-
throw unsupportedTranslationError(node, fullTypeName);
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
case '$Values':
|
|
1373
|
-
{
|
|
1374
|
-
// `$Values<T>` => `T[keyof T]`
|
|
1375
|
-
const transformedType = assertHasExactlyNTypeParameters(1)[0];
|
|
1376
|
-
return {
|
|
1377
|
-
type: 'TSIndexedAccessType',
|
|
1378
|
-
objectType: transformedType,
|
|
1379
|
-
indexType: {
|
|
1380
|
-
type: 'TSTypeOperator',
|
|
1381
|
-
operator: 'keyof',
|
|
1382
|
-
typeAnnotation: transformedType
|
|
1383
|
-
}
|
|
1384
|
-
};
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
case 'Class':
|
|
1388
|
-
{
|
|
1389
|
-
// `Class<T>` => `new (...args: any[]) => T`
|
|
1390
|
-
const param = assertHasExactlyNTypeParameters(1)[0];
|
|
1391
|
-
|
|
1392
|
-
if (param.type !== 'TSTypeReference') {
|
|
1393
|
-
throw translationError(node, 'Expected a type reference within Class<T>');
|
|
1394
|
-
}
|
|
1750
|
+
// React.Key -> React.Key
|
|
1751
|
+
// React$Key -> React.Key
|
|
1395
1752
|
|
|
1753
|
+
case 'React.Key':
|
|
1754
|
+
case 'React$Key':
|
|
1755
|
+
assertHasExactlyNTypeParameters(0);
|
|
1396
1756
|
return {
|
|
1397
|
-
type: '
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1757
|
+
type: 'TSTypeReference',
|
|
1758
|
+
typeName: {
|
|
1759
|
+
type: 'TSQualifiedName',
|
|
1760
|
+
left: getReactIdentifier(),
|
|
1761
|
+
right: {
|
|
1402
1762
|
type: 'Identifier',
|
|
1403
|
-
name: '
|
|
1404
|
-
},
|
|
1405
|
-
typeAnnotation: {
|
|
1406
|
-
type: 'TSTypeAnnotation',
|
|
1407
|
-
typeAnnotation: {
|
|
1408
|
-
type: 'TSArrayType',
|
|
1409
|
-
elementType: {
|
|
1410
|
-
type: 'TSAnyKeyword'
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1763
|
+
name: 'Key'
|
|
1413
1764
|
}
|
|
1414
|
-
}],
|
|
1415
|
-
returnType: {
|
|
1416
|
-
type: 'TSTypeAnnotation',
|
|
1417
|
-
typeAnnotation: param
|
|
1418
1765
|
}
|
|
1419
1766
|
};
|
|
1420
|
-
|
|
1421
|
-
|
|
1767
|
+
// React.ElementType -> React.ElementType
|
|
1768
|
+
// React$ElementType -> React.ElementType
|
|
1422
1769
|
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1770
|
+
case 'React$ElementType':
|
|
1771
|
+
case 'React.ElementType':
|
|
1772
|
+
{
|
|
1773
|
+
assertHasExactlyNTypeParameters(0);
|
|
1774
|
+
return {
|
|
1775
|
+
type: 'TSTypeReference',
|
|
1776
|
+
typeName: {
|
|
1777
|
+
type: 'TSQualifiedName',
|
|
1778
|
+
left: getReactIdentifier(),
|
|
1779
|
+
right: {
|
|
1780
|
+
type: 'Identifier',
|
|
1781
|
+
name: `ElementType`
|
|
1782
|
+
}
|
|
1783
|
+
},
|
|
1784
|
+
typeParameters: undefined
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1426
1787
|
// React.Node -> React.ReactNode
|
|
1788
|
+
|
|
1789
|
+
case 'React$Node':
|
|
1427
1790
|
case 'React.Node':
|
|
1428
1791
|
{
|
|
1429
1792
|
assertHasExactlyNTypeParameters(0);
|
|
@@ -1431,7 +1794,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1431
1794
|
type: 'TSTypeReference',
|
|
1432
1795
|
typeName: {
|
|
1433
1796
|
type: 'TSQualifiedName',
|
|
1434
|
-
left:
|
|
1797
|
+
left: getReactIdentifier(),
|
|
1435
1798
|
right: {
|
|
1436
1799
|
type: 'Identifier',
|
|
1437
1800
|
name: `ReactNode`
|
|
@@ -1442,13 +1805,14 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1442
1805
|
}
|
|
1443
1806
|
// React.Element<typeof Component> -> React.ReactElement<typeof Component>
|
|
1444
1807
|
|
|
1808
|
+
case 'React$Element':
|
|
1445
1809
|
case 'React.Element':
|
|
1446
1810
|
{
|
|
1447
1811
|
return {
|
|
1448
1812
|
type: 'TSTypeReference',
|
|
1449
1813
|
typeName: {
|
|
1450
1814
|
type: 'TSQualifiedName',
|
|
1451
|
-
left:
|
|
1815
|
+
left: getReactIdentifier(),
|
|
1452
1816
|
right: {
|
|
1453
1817
|
type: 'Identifier',
|
|
1454
1818
|
name: `ReactElement`
|
|
@@ -1460,8 +1824,46 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1460
1824
|
}
|
|
1461
1825
|
};
|
|
1462
1826
|
}
|
|
1827
|
+
// React.ElementRef<typeof Component> -> React.ElementRef<typeof Component>
|
|
1828
|
+
// React$ElementRef<typeof Component> -> React.ElementRef<typeof Component>
|
|
1829
|
+
|
|
1830
|
+
case 'React$ElementRef':
|
|
1831
|
+
case 'React.ElementRef':
|
|
1832
|
+
return {
|
|
1833
|
+
type: 'TSTypeReference',
|
|
1834
|
+
typeName: {
|
|
1835
|
+
type: 'TSQualifiedName',
|
|
1836
|
+
left: getReactIdentifier(),
|
|
1837
|
+
right: {
|
|
1838
|
+
type: 'Identifier',
|
|
1839
|
+
name: `ElementRef`
|
|
1840
|
+
}
|
|
1841
|
+
},
|
|
1842
|
+
typeParameters: {
|
|
1843
|
+
type: 'TSTypeParameterInstantiation',
|
|
1844
|
+
params: assertHasExactlyNTypeParameters(1)
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
// React$Fragment -> React.Fragment
|
|
1848
|
+
// React.Fragment -> React.Fragment
|
|
1849
|
+
|
|
1850
|
+
case 'React$FragmentType':
|
|
1851
|
+
case 'React.Fragment':
|
|
1852
|
+
assertHasExactlyNTypeParameters(0);
|
|
1853
|
+
return {
|
|
1854
|
+
type: 'TSTypeReference',
|
|
1855
|
+
typeName: {
|
|
1856
|
+
type: 'TSQualifiedName',
|
|
1857
|
+
left: getReactIdentifier(),
|
|
1858
|
+
right: {
|
|
1859
|
+
type: 'Identifier',
|
|
1860
|
+
name: `Fragment`
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1463
1864
|
// React.MixedElement -> JSX.Element
|
|
1464
1865
|
|
|
1866
|
+
case 'React$MixedElement':
|
|
1465
1867
|
case 'React.MixedElement':
|
|
1466
1868
|
{
|
|
1467
1869
|
assertHasExactlyNTypeParameters(0);
|
|
@@ -1481,10 +1883,35 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1481
1883
|
typeParameters: undefined
|
|
1482
1884
|
};
|
|
1483
1885
|
}
|
|
1484
|
-
// React.
|
|
1485
|
-
// React
|
|
1886
|
+
// React.ComponentType<Config> -> React.ComponentType<Config>
|
|
1887
|
+
// React$ComponentType<Config> -> React.ComponentType<Config>
|
|
1888
|
+
|
|
1889
|
+
case 'React.ComponentType':
|
|
1890
|
+
case 'React$ComponentType':
|
|
1891
|
+
{
|
|
1892
|
+
return {
|
|
1893
|
+
type: 'TSTypeReference',
|
|
1894
|
+
typeName: {
|
|
1895
|
+
type: 'TSQualifiedName',
|
|
1896
|
+
left: getReactIdentifier(),
|
|
1897
|
+
right: {
|
|
1898
|
+
type: 'Identifier',
|
|
1899
|
+
name: 'ComponentType'
|
|
1900
|
+
}
|
|
1901
|
+
},
|
|
1902
|
+
typeParameters: {
|
|
1903
|
+
type: 'TSTypeParameterInstantiation',
|
|
1904
|
+
params: assertHasExactlyNTypeParameters(1)
|
|
1905
|
+
}
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
// React.AbstractComponent<Config> -> React.ComponentType<Config>
|
|
1909
|
+
// React$AbstractComponent<Config> -> React.ComponentType<Config>
|
|
1910
|
+
// React.AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
|
|
1911
|
+
// React$AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
|
|
1486
1912
|
|
|
1487
1913
|
case 'React.AbstractComponent':
|
|
1914
|
+
case 'React$AbstractComponent':
|
|
1488
1915
|
{
|
|
1489
1916
|
const typeParameters = node.typeParameters;
|
|
1490
1917
|
|
|
@@ -1498,12 +1925,15 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1498
1925
|
throw translationError(node, `Expected at no more than 2 type parameters with \`${fullTypeName}\``);
|
|
1499
1926
|
}
|
|
1500
1927
|
|
|
1501
|
-
|
|
1928
|
+
const newParams = (() => {
|
|
1929
|
+
if (params.length === 1) {
|
|
1930
|
+
return assertHasExactlyNTypeParameters(1);
|
|
1931
|
+
}
|
|
1502
1932
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1933
|
+
const [props, ref] = assertHasExactlyNTypeParameters(2);
|
|
1934
|
+
return [{
|
|
1505
1935
|
type: 'TSIntersectionType',
|
|
1506
|
-
types: [
|
|
1936
|
+
types: [props, {
|
|
1507
1937
|
type: 'TSTypeReference',
|
|
1508
1938
|
typeName: {
|
|
1509
1939
|
type: 'TSQualifiedName',
|
|
@@ -1518,28 +1948,108 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1518
1948
|
},
|
|
1519
1949
|
typeParameters: {
|
|
1520
1950
|
type: 'TSTypeParameterInstantiation',
|
|
1521
|
-
params: [
|
|
1951
|
+
params: [ref]
|
|
1522
1952
|
}
|
|
1523
1953
|
}]
|
|
1524
|
-
};
|
|
1525
|
-
}
|
|
1954
|
+
}];
|
|
1955
|
+
})();
|
|
1956
|
+
|
|
1957
|
+
return {
|
|
1958
|
+
type: 'TSTypeReference',
|
|
1959
|
+
typeName: {
|
|
1960
|
+
type: 'TSQualifiedName',
|
|
1961
|
+
left: getReactIdentifier(),
|
|
1962
|
+
right: {
|
|
1963
|
+
type: 'Identifier',
|
|
1964
|
+
name: 'ComponentType'
|
|
1965
|
+
}
|
|
1966
|
+
},
|
|
1967
|
+
typeParameters: {
|
|
1968
|
+
type: 'TSTypeParameterInstantiation',
|
|
1969
|
+
params: newParams
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
// React.ElementConfig<A> -> JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
|
|
1974
|
+
// React$ElementConfig<A> -> JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
|
|
1526
1975
|
|
|
1976
|
+
case 'React.ElementConfig':
|
|
1977
|
+
case 'React$ElementConfig':
|
|
1978
|
+
{
|
|
1979
|
+
const [param] = assertHasExactlyNTypeParameters(1);
|
|
1527
1980
|
return {
|
|
1528
1981
|
type: 'TSTypeReference',
|
|
1529
1982
|
typeName: {
|
|
1530
1983
|
type: 'TSQualifiedName',
|
|
1531
|
-
left:
|
|
1984
|
+
left: {
|
|
1985
|
+
type: 'Identifier',
|
|
1986
|
+
name: 'JSX'
|
|
1987
|
+
},
|
|
1532
1988
|
right: {
|
|
1533
1989
|
type: 'Identifier',
|
|
1534
|
-
name:
|
|
1990
|
+
name: 'LibraryManagedAttributes'
|
|
1535
1991
|
}
|
|
1536
1992
|
},
|
|
1537
1993
|
typeParameters: {
|
|
1538
1994
|
type: 'TSTypeParameterInstantiation',
|
|
1539
|
-
params: [
|
|
1995
|
+
params: [param, {
|
|
1996
|
+
type: 'TSTypeReference',
|
|
1997
|
+
typeName: {
|
|
1998
|
+
type: 'TSQualifiedName',
|
|
1999
|
+
left: getReactIdentifier(),
|
|
2000
|
+
right: {
|
|
2001
|
+
type: 'Identifier',
|
|
2002
|
+
name: `ComponentProps`
|
|
2003
|
+
}
|
|
2004
|
+
},
|
|
2005
|
+
typeParameters: {
|
|
2006
|
+
type: 'TSTypeParameterInstantiation',
|
|
2007
|
+
params: [param]
|
|
2008
|
+
}
|
|
2009
|
+
}]
|
|
1540
2010
|
}
|
|
1541
2011
|
};
|
|
1542
2012
|
}
|
|
2013
|
+
// React.Ref<C> -> NonNullable<React.Ref<C> | string | number>
|
|
2014
|
+
// React$Ref<C> -> NonNullable<React.Ref<C> | string | number>
|
|
2015
|
+
|
|
2016
|
+
case 'React.Ref':
|
|
2017
|
+
case 'React$Ref':
|
|
2018
|
+
return {
|
|
2019
|
+
type: 'TSTypeReference',
|
|
2020
|
+
typeName: {
|
|
2021
|
+
type: 'Identifier',
|
|
2022
|
+
name: 'NonNullable'
|
|
2023
|
+
},
|
|
2024
|
+
typeParameters: {
|
|
2025
|
+
type: 'TSTypeParameterInstantiation',
|
|
2026
|
+
params: [{
|
|
2027
|
+
type: 'TSUnionType',
|
|
2028
|
+
types: [{
|
|
2029
|
+
type: 'TSTypeReference',
|
|
2030
|
+
typeName: {
|
|
2031
|
+
type: 'TSQualifiedName',
|
|
2032
|
+
left: getReactIdentifier(),
|
|
2033
|
+
right: {
|
|
2034
|
+
type: 'Identifier',
|
|
2035
|
+
name: 'Ref'
|
|
2036
|
+
}
|
|
2037
|
+
},
|
|
2038
|
+
typeParameters: {
|
|
2039
|
+
type: 'TSTypeParameterInstantiation',
|
|
2040
|
+
params: assertHasExactlyNTypeParameters(1)
|
|
2041
|
+
}
|
|
2042
|
+
}, {
|
|
2043
|
+
type: 'TSStringKeyword'
|
|
2044
|
+
}, {
|
|
2045
|
+
type: 'TSNumberKeyword'
|
|
2046
|
+
}]
|
|
2047
|
+
}]
|
|
2048
|
+
}
|
|
2049
|
+
};
|
|
2050
|
+
|
|
2051
|
+
default:
|
|
2052
|
+
return unsupportedAnnotation(node, fullTypeName);
|
|
1543
2053
|
}
|
|
1544
2054
|
}
|
|
1545
2055
|
|
|
@@ -1563,8 +2073,8 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1563
2073
|
IndexedAccessType(node) {
|
|
1564
2074
|
return {
|
|
1565
2075
|
type: 'TSIndexedAccessType',
|
|
1566
|
-
objectType:
|
|
1567
|
-
indexType:
|
|
2076
|
+
objectType: transformTypeAnnotationType(node.objectType),
|
|
2077
|
+
indexType: transformTypeAnnotationType(node.indexType)
|
|
1568
2078
|
};
|
|
1569
2079
|
},
|
|
1570
2080
|
|
|
@@ -1581,65 +2091,63 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1581
2091
|
},
|
|
1582
2092
|
|
|
1583
2093
|
ImportDeclaration(node) {
|
|
1584
|
-
if (node.importKind === 'typeof') {
|
|
1585
|
-
/*
|
|
1586
|
-
TODO - this is a complicated change to support because TS
|
|
1587
|
-
does not have typeof imports.
|
|
1588
|
-
Making it a `type` import would change the meaning!
|
|
1589
|
-
The only way to truly support this is to prefix all **usages** with `typeof T`.
|
|
1590
|
-
eg:
|
|
1591
|
-
```
|
|
1592
|
-
import typeof Foo from 'Foo';
|
|
1593
|
-
type T = Foo;
|
|
1594
|
-
```
|
|
1595
|
-
would become:
|
|
1596
|
-
```
|
|
1597
|
-
import type Foo from 'Foo';
|
|
1598
|
-
type T = typeof Foo;
|
|
1599
|
-
```
|
|
1600
|
-
This seems simple, but will actually be super complicated for us to do with
|
|
1601
|
-
our current translation architecture
|
|
1602
|
-
*/
|
|
1603
|
-
throw unsupportedTranslationError(node, 'typeof imports');
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
2094
|
const importKind = node.importKind;
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
2095
|
+
const specifiers = [];
|
|
2096
|
+
const unsupportedSpecifiers = [];
|
|
2097
|
+
node.specifiers.forEach(spec => {
|
|
2098
|
+
let id = (() => {
|
|
2099
|
+
if (node.importKind === 'typeof' || spec.importKind === 'typeof') {
|
|
2100
|
+
const id = {
|
|
2101
|
+
type: 'Identifier',
|
|
2102
|
+
name: getPlaceholderNameForTypeofImport()
|
|
2103
|
+
};
|
|
2104
|
+
unsupportedSpecifiers.push({
|
|
2105
|
+
type: 'TSTypeAliasDeclaration',
|
|
2106
|
+
id: transform.Identifier(spec.local, false),
|
|
2107
|
+
typeAnnotation: {
|
|
2108
|
+
type: 'TSTypeQuery',
|
|
2109
|
+
exprName: id
|
|
2110
|
+
}
|
|
2111
|
+
});
|
|
2112
|
+
return id;
|
|
2113
|
+
}
|
|
1621
2114
|
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
type: 'ImportNamespaceSpecifier',
|
|
1625
|
-
local: transform.Identifier(spec.local, false)
|
|
1626
|
-
};
|
|
2115
|
+
return transform.Identifier(spec.local, false);
|
|
2116
|
+
})();
|
|
1627
2117
|
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
2118
|
+
switch (spec.type) {
|
|
2119
|
+
case 'ImportDefaultSpecifier':
|
|
2120
|
+
specifiers.push({
|
|
2121
|
+
type: 'ImportDefaultSpecifier',
|
|
2122
|
+
local: id
|
|
2123
|
+
});
|
|
2124
|
+
return;
|
|
1633
2125
|
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
2126
|
+
case 'ImportNamespaceSpecifier':
|
|
2127
|
+
specifiers.push({
|
|
2128
|
+
type: 'ImportNamespaceSpecifier',
|
|
2129
|
+
local: id
|
|
2130
|
+
});
|
|
2131
|
+
return;
|
|
2132
|
+
|
|
2133
|
+
case 'ImportSpecifier':
|
|
2134
|
+
specifiers.push({
|
|
2135
|
+
type: 'ImportSpecifier',
|
|
2136
|
+
importKind: spec.importKind === 'typeof' || spec.importKind === 'type' ? 'type' : null,
|
|
2137
|
+
imported: transform.Identifier(spec.imported, false),
|
|
2138
|
+
local: id
|
|
2139
|
+
});
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
const out = specifiers.length ? [{
|
|
2144
|
+
type: 'ImportDeclaration',
|
|
2145
|
+
assertions: node.assertions.map(transform.ImportAttribute),
|
|
2146
|
+
importKind: importKind === 'typeof' ? 'type' : importKind != null ? importKind : 'value',
|
|
2147
|
+
source: transform.StringLiteral(node.source),
|
|
2148
|
+
specifiers
|
|
2149
|
+
}] : [];
|
|
2150
|
+
return [...out, ...unsupportedSpecifiers];
|
|
1643
2151
|
},
|
|
1644
2152
|
|
|
1645
2153
|
InterfaceExtends(node) {
|
|
@@ -1671,7 +2179,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1671
2179
|
IntersectionTypeAnnotation(node) {
|
|
1672
2180
|
return {
|
|
1673
2181
|
type: 'TSIntersectionType',
|
|
1674
|
-
types: node.types.map(
|
|
2182
|
+
types: node.types.map(transformTypeAnnotationType)
|
|
1675
2183
|
};
|
|
1676
2184
|
},
|
|
1677
2185
|
|
|
@@ -1726,7 +2234,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1726
2234
|
type: 'TSNullKeyword'
|
|
1727
2235
|
}, {
|
|
1728
2236
|
type: 'TSUndefinedKeyword'
|
|
1729
|
-
},
|
|
2237
|
+
}, transformTypeAnnotationType(node.typeAnnotation)]
|
|
1730
2238
|
};
|
|
1731
2239
|
},
|
|
1732
2240
|
|
|
@@ -1783,7 +2291,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1783
2291
|
|
|
1784
2292
|
|
|
1785
2293
|
if (node.internalSlots.length > 0) {
|
|
1786
|
-
|
|
2294
|
+
return unsupportedAnnotation(node.internalSlots[0], 'internal slots');
|
|
1787
2295
|
}
|
|
1788
2296
|
|
|
1789
2297
|
if (!node.properties.find(FlowESTree.isObjectTypeSpreadProperty)) {
|
|
@@ -1794,6 +2302,11 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1794
2302
|
throw unexpectedTranslationError(property, 'Impossible state');
|
|
1795
2303
|
}
|
|
1796
2304
|
|
|
2305
|
+
if (property.type === 'ObjectTypeMappedTypeProperty') {
|
|
2306
|
+
// TODO - Support mapped types
|
|
2307
|
+
return unsupportedAnnotation(property, 'object type with mapped type property');
|
|
2308
|
+
}
|
|
2309
|
+
|
|
1797
2310
|
members.push({
|
|
1798
2311
|
start: property.range[0],
|
|
1799
2312
|
node: transform.ObjectTypeProperty(property)
|
|
@@ -1870,7 +2383,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1870
2383
|
- spreads of things that aren't "Identifiers"
|
|
1871
2384
|
*/
|
|
1872
2385
|
if (members.length > 0) {
|
|
1873
|
-
|
|
2386
|
+
return unsupportedAnnotation(node, 'object types with spreads, indexers and/or call properties at the same time');
|
|
1874
2387
|
}
|
|
1875
2388
|
|
|
1876
2389
|
const typesToIntersect = [];
|
|
@@ -1878,16 +2391,19 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1878
2391
|
for (const property of node.properties) {
|
|
1879
2392
|
if (property.type === 'ObjectTypeSpreadProperty') {
|
|
1880
2393
|
if (members.length > 0) {
|
|
1881
|
-
|
|
2394
|
+
return unsupportedAnnotation(property, 'object types with spreads in the middle or at the end');
|
|
1882
2395
|
}
|
|
1883
2396
|
|
|
1884
|
-
const spreadType =
|
|
2397
|
+
const spreadType = transformTypeAnnotationType(property.argument);
|
|
1885
2398
|
|
|
1886
2399
|
if (spreadType.type !== 'TSTypeReference') {
|
|
1887
|
-
|
|
2400
|
+
return unsupportedAnnotation(property, 'object types with complex spreads');
|
|
1888
2401
|
}
|
|
1889
2402
|
|
|
1890
2403
|
typesToIntersect.push(spreadType);
|
|
2404
|
+
} else if (property.type === 'ObjectTypeMappedTypeProperty') {
|
|
2405
|
+
// TODO - Support mapped types
|
|
2406
|
+
return unsupportedAnnotation(property, 'object type with mapped type property');
|
|
1891
2407
|
} else {
|
|
1892
2408
|
members.push({
|
|
1893
2409
|
start: property.range[0],
|
|
@@ -1957,14 +2473,14 @@ const getTransforms = (code, scopeManager) => {
|
|
|
1957
2473
|
name: node.id == null ? '$$Key$$' : node.id.name,
|
|
1958
2474
|
typeAnnotation: {
|
|
1959
2475
|
type: 'TSTypeAnnotation',
|
|
1960
|
-
typeAnnotation:
|
|
2476
|
+
typeAnnotation: transformTypeAnnotationType(node.key)
|
|
1961
2477
|
}
|
|
1962
2478
|
}],
|
|
1963
2479
|
readonly: ((_node$variance = node.variance) == null ? void 0 : _node$variance.kind) === 'plus',
|
|
1964
2480
|
static: node.static,
|
|
1965
2481
|
typeAnnotation: {
|
|
1966
2482
|
type: 'TSTypeAnnotation',
|
|
1967
|
-
typeAnnotation:
|
|
2483
|
+
typeAnnotation: transformTypeAnnotationType(node.value)
|
|
1968
2484
|
}
|
|
1969
2485
|
};
|
|
1970
2486
|
},
|
|
@@ -2019,7 +2535,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2019
2535
|
static: node.static,
|
|
2020
2536
|
typeAnnotation: {
|
|
2021
2537
|
type: 'TSTypeAnnotation',
|
|
2022
|
-
typeAnnotation:
|
|
2538
|
+
typeAnnotation: transformTypeAnnotationType(node.value)
|
|
2023
2539
|
}
|
|
2024
2540
|
};
|
|
2025
2541
|
},
|
|
@@ -2048,10 +2564,10 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2048
2564
|
},
|
|
2049
2565
|
typeParameters: {
|
|
2050
2566
|
type: 'TSTypeParameterInstantiation',
|
|
2051
|
-
params: [
|
|
2567
|
+
params: [transformTypeAnnotationType(node.objectType)]
|
|
2052
2568
|
}
|
|
2053
2569
|
},
|
|
2054
|
-
indexType:
|
|
2570
|
+
indexType: transformTypeAnnotationType(node.indexType)
|
|
2055
2571
|
};
|
|
2056
2572
|
},
|
|
2057
2573
|
|
|
@@ -2064,6 +2580,15 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2064
2580
|
};
|
|
2065
2581
|
},
|
|
2066
2582
|
|
|
2583
|
+
QualifiedTypeofIdentifier(node) {
|
|
2584
|
+
const qual = node.qualification;
|
|
2585
|
+
return {
|
|
2586
|
+
type: 'TSQualifiedName',
|
|
2587
|
+
left: qual.type === 'Identifier' ? transform.Identifier(qual, false) : transform.QualifiedTypeofIdentifier(qual),
|
|
2588
|
+
right: transform.Identifier(node.id, false)
|
|
2589
|
+
};
|
|
2590
|
+
},
|
|
2591
|
+
|
|
2067
2592
|
RegExpLiteral(node) {
|
|
2068
2593
|
return {
|
|
2069
2594
|
type: 'Literal',
|
|
@@ -2116,7 +2641,7 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2116
2641
|
TupleTypeAnnotation(node) {
|
|
2117
2642
|
return {
|
|
2118
2643
|
type: 'TSTupleType',
|
|
2119
|
-
elementTypes: node.types.map(
|
|
2644
|
+
elementTypes: node.types.map(transformTypeAnnotationType)
|
|
2120
2645
|
};
|
|
2121
2646
|
},
|
|
2122
2647
|
|
|
@@ -2127,116 +2652,26 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2127
2652
|
TypeAnnotation(node) {
|
|
2128
2653
|
return {
|
|
2129
2654
|
type: 'TSTypeAnnotation',
|
|
2130
|
-
typeAnnotation:
|
|
2655
|
+
typeAnnotation: transformTypeAnnotationType(node.typeAnnotation)
|
|
2131
2656
|
};
|
|
2132
2657
|
},
|
|
2133
2658
|
|
|
2134
|
-
TypeAnnotationType(node) {
|
|
2135
|
-
switch (node.type) {
|
|
2136
|
-
case 'AnyTypeAnnotation':
|
|
2137
|
-
return transform.AnyTypeAnnotation(node);
|
|
2138
|
-
|
|
2139
|
-
case 'ArrayTypeAnnotation':
|
|
2140
|
-
return transform.ArrayTypeAnnotation(node);
|
|
2141
|
-
|
|
2142
|
-
case 'BigIntLiteralTypeAnnotation':
|
|
2143
|
-
return transform.BigIntLiteralTypeAnnotation(node);
|
|
2144
|
-
|
|
2145
|
-
case 'BigIntTypeAnnotation':
|
|
2146
|
-
return transform.BigIntTypeAnnotation(node);
|
|
2147
|
-
|
|
2148
|
-
case 'BooleanLiteralTypeAnnotation':
|
|
2149
|
-
return transform.BooleanLiteralTypeAnnotation(node);
|
|
2150
|
-
|
|
2151
|
-
case 'BooleanTypeAnnotation':
|
|
2152
|
-
return transform.BooleanTypeAnnotation(node);
|
|
2153
|
-
|
|
2154
|
-
case 'EmptyTypeAnnotation':
|
|
2155
|
-
return transform.EmptyTypeAnnotation(node);
|
|
2156
|
-
|
|
2157
|
-
case 'ExistsTypeAnnotation':
|
|
2158
|
-
return transform.ExistsTypeAnnotation(node);
|
|
2159
|
-
|
|
2160
|
-
case 'FunctionTypeAnnotation':
|
|
2161
|
-
return transform.FunctionTypeAnnotation(node);
|
|
2162
|
-
|
|
2163
|
-
case 'GenericTypeAnnotation':
|
|
2164
|
-
return transform.GenericTypeAnnotation(node);
|
|
2165
|
-
|
|
2166
|
-
case 'IndexedAccessType':
|
|
2167
|
-
return transform.IndexedAccessType(node);
|
|
2168
|
-
|
|
2169
|
-
case 'InterfaceTypeAnnotation':
|
|
2170
|
-
return transform.InterfaceTypeAnnotation(node);
|
|
2171
|
-
|
|
2172
|
-
case 'IntersectionTypeAnnotation':
|
|
2173
|
-
return transform.IntersectionTypeAnnotation(node);
|
|
2174
|
-
|
|
2175
|
-
case 'MixedTypeAnnotation':
|
|
2176
|
-
return transform.MixedTypeAnnotation(node);
|
|
2177
|
-
|
|
2178
|
-
case 'NullLiteralTypeAnnotation':
|
|
2179
|
-
return transform.NullLiteralTypeAnnotation(node);
|
|
2180
|
-
|
|
2181
|
-
case 'NullableTypeAnnotation':
|
|
2182
|
-
return transform.NullableTypeAnnotation(node);
|
|
2183
|
-
|
|
2184
|
-
case 'NumberLiteralTypeAnnotation':
|
|
2185
|
-
return transform.NumberLiteralTypeAnnotation(node);
|
|
2186
|
-
|
|
2187
|
-
case 'NumberTypeAnnotation':
|
|
2188
|
-
return transform.NumberTypeAnnotation(node);
|
|
2189
|
-
|
|
2190
|
-
case 'ObjectTypeAnnotation':
|
|
2191
|
-
return transform.ObjectTypeAnnotation(node);
|
|
2192
|
-
|
|
2193
|
-
case 'OptionalIndexedAccessType':
|
|
2194
|
-
return transform.OptionalIndexedAccessType(node);
|
|
2195
|
-
|
|
2196
|
-
case 'QualifiedTypeIdentifier':
|
|
2197
|
-
return transform.QualifiedTypeIdentifier(node);
|
|
2198
|
-
|
|
2199
|
-
case 'StringLiteralTypeAnnotation':
|
|
2200
|
-
return transform.StringLiteralTypeAnnotation(node);
|
|
2201
|
-
|
|
2202
|
-
case 'StringTypeAnnotation':
|
|
2203
|
-
return transform.StringTypeAnnotation(node);
|
|
2204
|
-
|
|
2205
|
-
case 'SymbolTypeAnnotation':
|
|
2206
|
-
return transform.SymbolTypeAnnotation(node);
|
|
2207
|
-
|
|
2208
|
-
case 'ThisTypeAnnotation':
|
|
2209
|
-
return transform.ThisTypeAnnotation(node);
|
|
2210
|
-
|
|
2211
|
-
case 'TupleTypeAnnotation':
|
|
2212
|
-
return transform.TupleTypeAnnotation(node);
|
|
2213
|
-
|
|
2214
|
-
case 'TypeofTypeAnnotation':
|
|
2215
|
-
return transform.TypeofTypeAnnotation(node);
|
|
2216
|
-
|
|
2217
|
-
case 'UnionTypeAnnotation':
|
|
2218
|
-
return transform.UnionTypeAnnotation(node);
|
|
2219
|
-
|
|
2220
|
-
case 'VoidTypeAnnotation':
|
|
2221
|
-
return transform.VoidTypeAnnotation(node);
|
|
2222
|
-
|
|
2223
|
-
default:
|
|
2224
|
-
throw unexpectedTranslationError(node, `Unhandled type ${node.type}`);
|
|
2225
|
-
}
|
|
2226
|
-
},
|
|
2227
|
-
|
|
2228
2659
|
TypeofTypeAnnotation(node) {
|
|
2229
|
-
|
|
2660
|
+
switch (node.argument.type) {
|
|
2661
|
+
case 'Identifier':
|
|
2662
|
+
return {
|
|
2663
|
+
type: 'TSTypeQuery',
|
|
2664
|
+
exprName: transform.Identifier(node.argument),
|
|
2665
|
+
typeParameters: undefined
|
|
2666
|
+
};
|
|
2230
2667
|
|
|
2231
|
-
|
|
2232
|
-
|
|
2668
|
+
case 'QualifiedTypeofIdentifier':
|
|
2669
|
+
return {
|
|
2670
|
+
type: 'TSTypeQuery',
|
|
2671
|
+
exprName: transform.QualifiedTypeofIdentifier(node.argument),
|
|
2672
|
+
typeParameters: undefined
|
|
2673
|
+
};
|
|
2233
2674
|
}
|
|
2234
|
-
|
|
2235
|
-
return {
|
|
2236
|
-
type: 'TSTypeQuery',
|
|
2237
|
-
exprName: argument.typeName,
|
|
2238
|
-
typeParameters: argument.typeParameters
|
|
2239
|
-
};
|
|
2240
2675
|
},
|
|
2241
2676
|
|
|
2242
2677
|
TypeParameter(node) {
|
|
@@ -2265,8 +2700,8 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2265
2700
|
type: 'Identifier',
|
|
2266
2701
|
name: node.name
|
|
2267
2702
|
},
|
|
2268
|
-
constraint: node.bound == null ? undefined :
|
|
2269
|
-
default: node.default == null ? undefined :
|
|
2703
|
+
constraint: node.bound == null ? undefined : transformTypeAnnotationType(node.bound.typeAnnotation),
|
|
2704
|
+
default: node.default == null ? undefined : transformTypeAnnotationType(node.default),
|
|
2270
2705
|
in: false,
|
|
2271
2706
|
out: false // in: variance.has('in'),
|
|
2272
2707
|
// out: variance.has('out'),
|
|
@@ -2284,14 +2719,14 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2284
2719
|
TypeParameterInstantiation(node) {
|
|
2285
2720
|
return {
|
|
2286
2721
|
type: 'TSTypeParameterInstantiation',
|
|
2287
|
-
params: node.params.map(
|
|
2722
|
+
params: node.params.map(transformTypeAnnotationType)
|
|
2288
2723
|
};
|
|
2289
2724
|
},
|
|
2290
2725
|
|
|
2291
2726
|
UnionTypeAnnotation(node) {
|
|
2292
2727
|
return {
|
|
2293
2728
|
type: 'TSUnionType',
|
|
2294
|
-
types: node.types.map(
|
|
2729
|
+
types: node.types.map(transformTypeAnnotationType)
|
|
2295
2730
|
};
|
|
2296
2731
|
},
|
|
2297
2732
|
|
|
@@ -2321,5 +2756,5 @@ const getTransforms = (code, scopeManager) => {
|
|
|
2321
2756
|
};
|
|
2322
2757
|
}
|
|
2323
2758
|
|
|
2324
|
-
return transform;
|
|
2759
|
+
return [transform, code];
|
|
2325
2760
|
};
|