flow-api-translator 0.10.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/LICENSE +21 -0
- package/README.md +44 -0
- package/dist/flowDefToTSDef.js +2325 -0
- package/dist/flowDefToTSDef.js.flow +2507 -0
- package/dist/flowImportTo.js +73 -0
- package/dist/flowImportTo.js.flow +73 -0
- package/dist/flowToFlowDef.js +932 -0
- package/dist/flowToFlowDef.js.flow +1303 -0
- package/dist/flowToJS.js +188 -0
- package/dist/flowToJS.js.flow +166 -0
- package/dist/index.js +78 -0
- package/dist/index.js.flow +84 -0
- package/dist/utils/DocblockUtils.js +33 -0
- package/dist/utils/DocblockUtils.js.flow +36 -0
- package/dist/utils/ErrorUtils.js +102 -0
- package/dist/utils/ErrorUtils.js.flow +100 -0
- package/dist/utils/FlowAnalyze.js +55 -0
- package/dist/utils/FlowAnalyze.js.flow +47 -0
- package/dist/utils/TranslationUtils.js +42 -0
- package/dist/utils/TranslationUtils.js.flow +44 -0
- package/dist/utils/ts-estree-ast-types.js +30 -0
- package/dist/utils/ts-estree-ast-types.js.flow +2052 -0
- package/package.json +27 -0
|
@@ -0,0 +1,1303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
AFunction,
|
|
15
|
+
BindingName,
|
|
16
|
+
ClassBody,
|
|
17
|
+
ClassDeclaration,
|
|
18
|
+
ClassMember,
|
|
19
|
+
ClassPropertyNameComputed,
|
|
20
|
+
ClassPropertyNameNonComputed,
|
|
21
|
+
DeclareClass,
|
|
22
|
+
DeclareFunction,
|
|
23
|
+
DeclareOpaqueType,
|
|
24
|
+
DeclareVariable,
|
|
25
|
+
ESNode,
|
|
26
|
+
ExportDefaultDeclaration,
|
|
27
|
+
ExportNamedDeclaration,
|
|
28
|
+
ExportSpecifier,
|
|
29
|
+
Expression,
|
|
30
|
+
FunctionDeclaration,
|
|
31
|
+
FunctionParameter,
|
|
32
|
+
FunctionTypeAnnotation,
|
|
33
|
+
FunctionTypeParam,
|
|
34
|
+
Identifier,
|
|
35
|
+
ImportDeclaration,
|
|
36
|
+
InterfaceDeclaration,
|
|
37
|
+
InterfaceExtends,
|
|
38
|
+
Literal,
|
|
39
|
+
ModuleDeclaration,
|
|
40
|
+
NumericLiteral,
|
|
41
|
+
ObjectExpression,
|
|
42
|
+
ObjectTypeAnnotation,
|
|
43
|
+
ObjectTypeProperty,
|
|
44
|
+
OpaqueType,
|
|
45
|
+
Program,
|
|
46
|
+
Statement,
|
|
47
|
+
StringLiteral,
|
|
48
|
+
TypeAlias,
|
|
49
|
+
TypeAnnotation,
|
|
50
|
+
TypeAnnotationType,
|
|
51
|
+
TypeCastExpression,
|
|
52
|
+
TypeParameterDeclaration,
|
|
53
|
+
TypeParameterInstantiation,
|
|
54
|
+
VariableDeclaration,
|
|
55
|
+
} from 'hermes-estree';
|
|
56
|
+
import type {ScopeManager} from 'hermes-eslint';
|
|
57
|
+
import type {DetachedNode} from 'hermes-transform';
|
|
58
|
+
import type {
|
|
59
|
+
Dep,
|
|
60
|
+
TranslationContext,
|
|
61
|
+
TranslationOptions,
|
|
62
|
+
} from './utils/TranslationUtils';
|
|
63
|
+
|
|
64
|
+
import {t} from 'hermes-transform';
|
|
65
|
+
import {
|
|
66
|
+
analyzeFunctionReturn,
|
|
67
|
+
analyzeTypeDependencies,
|
|
68
|
+
} from './utils/FlowAnalyze';
|
|
69
|
+
import {createTranslationContext} from './utils/TranslationUtils';
|
|
70
|
+
import {asDetachedNode} from 'hermes-transform';
|
|
71
|
+
import {translationError, flowFixMeOrError} from './utils/ErrorUtils';
|
|
72
|
+
import {isExpression} from 'hermes-estree';
|
|
73
|
+
|
|
74
|
+
const EMPTY_TRANSLATION_RESULT = [null, []];
|
|
75
|
+
|
|
76
|
+
type TranslatedDeps = $ReadOnlyArray<Dep>;
|
|
77
|
+
type TranslatedResultOrNull<T> = [DetachedNode<T> | null, TranslatedDeps];
|
|
78
|
+
type TranslatedResultArray<T> = [
|
|
79
|
+
$ReadOnlyArray<DetachedNode<T>>,
|
|
80
|
+
TranslatedDeps,
|
|
81
|
+
];
|
|
82
|
+
type TranslatedResult<T> = [DetachedNode<T>, TranslatedDeps];
|
|
83
|
+
|
|
84
|
+
type ProgramStatement = Statement | ModuleDeclaration;
|
|
85
|
+
|
|
86
|
+
function convertArray<TIn, TOut>(
|
|
87
|
+
items: $ReadOnlyArray<TIn>,
|
|
88
|
+
convert: TIn => TranslatedResultOrNull<TOut>,
|
|
89
|
+
): TranslatedResultArray<TOut> {
|
|
90
|
+
const resultItems: Array<DetachedNode<TOut>> = [];
|
|
91
|
+
const deps: Array<Dep> = [];
|
|
92
|
+
for (const item of items) {
|
|
93
|
+
const [resultItem, itemDeps] = convert(item);
|
|
94
|
+
if (resultItem != null) {
|
|
95
|
+
resultItems.push(resultItem);
|
|
96
|
+
|
|
97
|
+
deps.push(...itemDeps);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return [resultItems, deps];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getTopLevelStatement(
|
|
104
|
+
node: ESNode,
|
|
105
|
+
context: TranslationContext,
|
|
106
|
+
): ProgramStatement {
|
|
107
|
+
let currentNode: ?ESNode = node;
|
|
108
|
+
while (currentNode != null) {
|
|
109
|
+
if (currentNode.parent?.type === 'Program') {
|
|
110
|
+
// $FlowFixMe[incompatible-return]
|
|
111
|
+
return currentNode;
|
|
112
|
+
}
|
|
113
|
+
currentNode = currentNode.parent;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
throw translationError(
|
|
117
|
+
node,
|
|
118
|
+
`getTopLevelStatement: Detached node of type "${node.type}" passed`,
|
|
119
|
+
context,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function transferProgramStatementProperties(
|
|
124
|
+
stmt: DetachedNode<ProgramStatement>,
|
|
125
|
+
orgStmt: ProgramStatement,
|
|
126
|
+
): void {
|
|
127
|
+
// $FlowExpectedError[prop-missing]
|
|
128
|
+
// $FlowExpectedError[incompatible-use]
|
|
129
|
+
stmt.comments = orgStmt.comments;
|
|
130
|
+
// $FlowExpectedError[incompatible-use]
|
|
131
|
+
stmt.range = orgStmt.range;
|
|
132
|
+
// $FlowExpectedError[incompatible-use]
|
|
133
|
+
stmt.loc = orgStmt.loc;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Consume an abribray Flow AST and convert it into a Type defintion file.
|
|
138
|
+
*
|
|
139
|
+
* To do this all runtime logic will be stripped and only Type that describe the module boundary will remain.
|
|
140
|
+
*/
|
|
141
|
+
export default function flowToFlowDef(
|
|
142
|
+
ast: Program,
|
|
143
|
+
code: string,
|
|
144
|
+
scopeManager: ScopeManager,
|
|
145
|
+
opts: TranslationOptions,
|
|
146
|
+
): [DetachedNode<Program>, string] {
|
|
147
|
+
const context = createTranslationContext(code, scopeManager, opts);
|
|
148
|
+
|
|
149
|
+
const translatedStatements = new Map<
|
|
150
|
+
ProgramStatement,
|
|
151
|
+
DetachedNode<ProgramStatement>,
|
|
152
|
+
>();
|
|
153
|
+
function storeTranslatedStatement(
|
|
154
|
+
stmt: DetachedNode<ProgramStatement>,
|
|
155
|
+
orgStmt: ProgramStatement,
|
|
156
|
+
): void {
|
|
157
|
+
translatedStatements.set(orgStmt, stmt);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const seenDeps = new Set<Dep>();
|
|
161
|
+
const processedStatements = new Set<ProgramStatement>();
|
|
162
|
+
const pendingStatements = new Set<ProgramStatement>();
|
|
163
|
+
function updatePendingStatements(deps: TranslatedDeps): void {
|
|
164
|
+
for (const dep of deps) {
|
|
165
|
+
if (seenDeps.has(dep)) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
seenDeps.add(dep);
|
|
169
|
+
const variable = context.variableMap.get(dep);
|
|
170
|
+
if (variable == null) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`updatePendingStatements: Variable for dependency "${dep}" not found`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
for (const def of variable.defs) {
|
|
176
|
+
const stmt = def.node;
|
|
177
|
+
if (stmt == null) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`updatePendingStatements: Variable parent of "${dep}" not found`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const topLevelStmt = getTopLevelStatement(stmt, context);
|
|
183
|
+
if (processedStatements.has(topLevelStmt)) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
pendingStatements.add(topLevelStmt);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function updateProcessedStatement(stmt: ProgramStatement): void {
|
|
191
|
+
processedStatements.add(stmt);
|
|
192
|
+
pendingStatements.delete(stmt);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Process all export statements
|
|
196
|
+
for (const stmt of ast.body) {
|
|
197
|
+
const resultExport = convertExport(stmt, context);
|
|
198
|
+
if (resultExport != null) {
|
|
199
|
+
updateProcessedStatement(stmt);
|
|
200
|
+
const [resultExportedStmt, deps] = resultExport;
|
|
201
|
+
storeTranslatedStatement(resultExportedStmt, stmt);
|
|
202
|
+
updatePendingStatements(deps);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
while (pendingStatements.size > 0) {
|
|
207
|
+
const stmt = pendingStatements.values().next().value;
|
|
208
|
+
if (stmt == null) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`flowToFlowDef: Invalid state, "pendingStatements" cannot be empty`,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
updateProcessedStatement(stmt);
|
|
214
|
+
const [resultStmt, deps] = convertStatement(stmt, context);
|
|
215
|
+
storeTranslatedStatement(resultStmt, stmt);
|
|
216
|
+
updatePendingStatements(deps);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const translatedBody: Array<DetachedNode<ProgramStatement>> = [];
|
|
220
|
+
for (const stmt of ast.body) {
|
|
221
|
+
const translatedStatement = translatedStatements.get(stmt);
|
|
222
|
+
if (translatedStatement != null) {
|
|
223
|
+
const optimizedStatement = stripUnusedDefs(
|
|
224
|
+
translatedStatement,
|
|
225
|
+
seenDeps,
|
|
226
|
+
context,
|
|
227
|
+
);
|
|
228
|
+
transferProgramStatementProperties(optimizedStatement, stmt);
|
|
229
|
+
translatedBody.push(optimizedStatement);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return [
|
|
234
|
+
t.Program({
|
|
235
|
+
body: translatedBody,
|
|
236
|
+
sourceType: ast.sourceType,
|
|
237
|
+
interpreter: ast.interpreter?.value ?? null,
|
|
238
|
+
comments: ast.comments,
|
|
239
|
+
tokens: ast.tokens,
|
|
240
|
+
docblock: ast.docblock,
|
|
241
|
+
}),
|
|
242
|
+
code,
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function convertExport(
|
|
247
|
+
stmt: ProgramStatement,
|
|
248
|
+
context: TranslationContext,
|
|
249
|
+
): ?TranslatedResult<ProgramStatement> {
|
|
250
|
+
switch (stmt.type) {
|
|
251
|
+
case 'ExportNamedDeclaration': {
|
|
252
|
+
return convertExportNamedDeclaration(stmt, context);
|
|
253
|
+
}
|
|
254
|
+
case 'ExportDefaultDeclaration': {
|
|
255
|
+
return convertExportDefaultDeclaration(stmt, context);
|
|
256
|
+
}
|
|
257
|
+
case 'ExportAllDeclaration':
|
|
258
|
+
case 'DeclareExportAllDeclaration': {
|
|
259
|
+
return [asDetachedNode(stmt), []];
|
|
260
|
+
}
|
|
261
|
+
case 'DeclareExportDeclaration':
|
|
262
|
+
case 'DeclareModuleExports': {
|
|
263
|
+
return [asDetachedNode(stmt), analyzeTypeDependencies(stmt, context)];
|
|
264
|
+
}
|
|
265
|
+
case 'ExpressionStatement': {
|
|
266
|
+
const expr = stmt.expression;
|
|
267
|
+
if (
|
|
268
|
+
expr.type === 'AssignmentExpression' &&
|
|
269
|
+
expr.left.type === 'MemberExpression'
|
|
270
|
+
) {
|
|
271
|
+
const member = expr.left;
|
|
272
|
+
if (
|
|
273
|
+
// exports.A = 1;
|
|
274
|
+
(member.object.type === 'Identifier' &&
|
|
275
|
+
member.object.name === 'exports') ||
|
|
276
|
+
// module.exports.A = 1;
|
|
277
|
+
(member.object.type === 'MemberExpression' &&
|
|
278
|
+
member.object.object.type === 'Identifier' &&
|
|
279
|
+
member.object.object.name === 'module' &&
|
|
280
|
+
member.object.property.type === 'Identifier' &&
|
|
281
|
+
member.object.property.name === 'exports')
|
|
282
|
+
) {
|
|
283
|
+
throw translationError(
|
|
284
|
+
stmt,
|
|
285
|
+
`convertExport: Named CommonJS exports not supported. Use either \`module.exports = {...}\` or ES6 exports.`,
|
|
286
|
+
context,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (
|
|
291
|
+
// exports.A = 1;
|
|
292
|
+
member.object.type === 'Identifier' &&
|
|
293
|
+
member.object.name === 'module' &&
|
|
294
|
+
member.property.type === 'Identifier' &&
|
|
295
|
+
member.property.name === 'exports'
|
|
296
|
+
) {
|
|
297
|
+
const [typeAnnotation, deps] = convertExpressionToTypeAnnotation(
|
|
298
|
+
expr.right,
|
|
299
|
+
context,
|
|
300
|
+
);
|
|
301
|
+
return [
|
|
302
|
+
t.DeclareModuleExports({
|
|
303
|
+
typeAnnotation: t.TypeAnnotation({typeAnnotation}),
|
|
304
|
+
}),
|
|
305
|
+
deps,
|
|
306
|
+
];
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
default: {
|
|
313
|
+
// Skip non exported functions
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function stripUnusedDefs(
|
|
320
|
+
detachedStmt: DetachedNode<ProgramStatement>,
|
|
321
|
+
usedDeps: Set<Dep>,
|
|
322
|
+
context: TranslationContext,
|
|
323
|
+
): DetachedNode<ProgramStatement> {
|
|
324
|
+
// $FlowExpectedError[incompatible-type]
|
|
325
|
+
const stmt: ProgramStatement = detachedStmt;
|
|
326
|
+
switch (stmt.type) {
|
|
327
|
+
case 'ImportDeclaration': {
|
|
328
|
+
const resultSpecfiers = stmt.specifiers.filter(spec =>
|
|
329
|
+
usedDeps.has(spec.local.name),
|
|
330
|
+
);
|
|
331
|
+
if (resultSpecfiers.length === 0) {
|
|
332
|
+
throw translationError(
|
|
333
|
+
stmt,
|
|
334
|
+
`stripUnusedDefs ImportDeclaration: No specifiers remaining`,
|
|
335
|
+
context,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
if (resultSpecfiers.length !== stmt.specifiers.length) {
|
|
339
|
+
return t.ImportDeclaration({
|
|
340
|
+
specifiers: resultSpecfiers,
|
|
341
|
+
importKind: stmt.importKind,
|
|
342
|
+
source: stmt.source,
|
|
343
|
+
assertions: stmt.assertions,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
return detachedStmt;
|
|
347
|
+
}
|
|
348
|
+
default: {
|
|
349
|
+
return detachedStmt;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function convertStatement(
|
|
355
|
+
stmt: ProgramStatement,
|
|
356
|
+
context: TranslationContext,
|
|
357
|
+
): TranslatedResult<ProgramStatement> {
|
|
358
|
+
switch (stmt.type) {
|
|
359
|
+
case 'FunctionDeclaration': {
|
|
360
|
+
const [result, deps] = convertFunctionDeclation(stmt, context);
|
|
361
|
+
return [result, deps];
|
|
362
|
+
}
|
|
363
|
+
case 'ClassDeclaration': {
|
|
364
|
+
const [result, deps] = convertClassDeclaration(stmt, context);
|
|
365
|
+
return [result, deps];
|
|
366
|
+
}
|
|
367
|
+
case 'InterfaceDeclaration': {
|
|
368
|
+
const [result, deps] = convertInterfaceDeclaration(stmt, context);
|
|
369
|
+
return [result, deps];
|
|
370
|
+
}
|
|
371
|
+
case 'TypeAlias': {
|
|
372
|
+
const [result, deps] = convertTypeAlias(stmt, context);
|
|
373
|
+
return [result, deps];
|
|
374
|
+
}
|
|
375
|
+
case 'OpaqueType': {
|
|
376
|
+
const [result, deps] = convertOpaqueType(stmt, context);
|
|
377
|
+
return [result, deps];
|
|
378
|
+
}
|
|
379
|
+
case 'ImportDeclaration': {
|
|
380
|
+
const [result, deps] = convertImportDeclaration(stmt, context);
|
|
381
|
+
return [result, deps];
|
|
382
|
+
}
|
|
383
|
+
case 'VariableDeclaration': {
|
|
384
|
+
const [result, deps] = convertVariableDeclaration(stmt, context);
|
|
385
|
+
return [result, deps];
|
|
386
|
+
}
|
|
387
|
+
case 'DeclareClass':
|
|
388
|
+
case 'DeclareVariable':
|
|
389
|
+
case 'DeclareFunction':
|
|
390
|
+
case 'DeclareModule':
|
|
391
|
+
case 'DeclareInterface':
|
|
392
|
+
case 'DeclareTypeAlias':
|
|
393
|
+
case 'DeclareOpaqueType':
|
|
394
|
+
case 'EnumDeclaration': {
|
|
395
|
+
return [asDetachedNode(stmt), analyzeTypeDependencies(stmt, context)];
|
|
396
|
+
}
|
|
397
|
+
default: {
|
|
398
|
+
throw translationError(
|
|
399
|
+
stmt,
|
|
400
|
+
`Statement: Unsupported statement type of "${stmt.type}"`,
|
|
401
|
+
context,
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function convertExpressionToTypeAnnotation(
|
|
408
|
+
expr: Expression,
|
|
409
|
+
context: TranslationContext,
|
|
410
|
+
): TranslatedResult<TypeAnnotationType> {
|
|
411
|
+
switch (expr.type) {
|
|
412
|
+
case 'TypeCastExpression': {
|
|
413
|
+
const [resultExpr, deps] = convertTypeCastExpression(expr, context);
|
|
414
|
+
return [resultExpr, deps];
|
|
415
|
+
}
|
|
416
|
+
case 'Identifier': {
|
|
417
|
+
return [
|
|
418
|
+
t.GenericTypeAnnotation({id: t.Identifier({name: expr.name})}),
|
|
419
|
+
analyzeTypeDependencies(expr, context),
|
|
420
|
+
];
|
|
421
|
+
}
|
|
422
|
+
case 'Literal': {
|
|
423
|
+
const [resultExpr, deps] = convertLiteral(expr, context);
|
|
424
|
+
return [resultExpr, deps];
|
|
425
|
+
}
|
|
426
|
+
case 'ObjectExpression': {
|
|
427
|
+
const [resultExpr, deps] = convertObjectExpression(expr, context);
|
|
428
|
+
return [resultExpr, deps];
|
|
429
|
+
}
|
|
430
|
+
case 'ArrowFunctionExpression':
|
|
431
|
+
case 'FunctionExpression': {
|
|
432
|
+
const [resultExpr, deps] = convertAFunction(expr, context);
|
|
433
|
+
return [resultExpr, deps];
|
|
434
|
+
}
|
|
435
|
+
default: {
|
|
436
|
+
return [
|
|
437
|
+
flowFixMeOrError(
|
|
438
|
+
expr,
|
|
439
|
+
`convertExpressionToTypeAnnotation: Unsupported expression of type "${expr.type}", a type annotation is required.`,
|
|
440
|
+
context,
|
|
441
|
+
),
|
|
442
|
+
[],
|
|
443
|
+
];
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function convertObjectExpression(
|
|
449
|
+
expr: ObjectExpression,
|
|
450
|
+
context: TranslationContext,
|
|
451
|
+
): TranslatedResult<TypeAnnotationType> {
|
|
452
|
+
const [resultProperties, deps] = convertArray(expr.properties, prop => {
|
|
453
|
+
switch (prop.type) {
|
|
454
|
+
case 'SpreadElement': {
|
|
455
|
+
const [resultExpr, deps] = convertExpressionToTypeAnnotation(
|
|
456
|
+
prop.argument,
|
|
457
|
+
context,
|
|
458
|
+
);
|
|
459
|
+
return [t.ObjectTypeSpreadProperty({argument: resultExpr}), deps];
|
|
460
|
+
}
|
|
461
|
+
case 'Property': {
|
|
462
|
+
if (
|
|
463
|
+
prop.key.type !== 'Identifier' &&
|
|
464
|
+
prop.key.type !== 'StringLiteral'
|
|
465
|
+
) {
|
|
466
|
+
throw translationError(
|
|
467
|
+
prop.key,
|
|
468
|
+
`ObjectExpression Property: Unsupported key type of "${prop.key.type}"`,
|
|
469
|
+
context,
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (prop.method === true) {
|
|
474
|
+
if (
|
|
475
|
+
prop.value.type !== 'ArrowFunctionExpression' &&
|
|
476
|
+
prop.value.type !== 'FunctionExpression'
|
|
477
|
+
) {
|
|
478
|
+
throw translationError(
|
|
479
|
+
prop.key,
|
|
480
|
+
`ObjectExpression Property: Expected method to have a function value, but got ${prop.value.type}`,
|
|
481
|
+
context,
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const [resultExpr, deps] = convertAFunction(prop.value, context);
|
|
486
|
+
return [
|
|
487
|
+
t.ObjectTypeMethodSignature({
|
|
488
|
+
// $FlowFixMe[incompatible-call]
|
|
489
|
+
key: asDetachedNode<
|
|
490
|
+
Identifier | NumericLiteral | StringLiteral | Expression,
|
|
491
|
+
>(prop.key),
|
|
492
|
+
value: resultExpr,
|
|
493
|
+
}),
|
|
494
|
+
deps,
|
|
495
|
+
];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (prop.kind === 'get' || prop.kind === 'set') {
|
|
499
|
+
if (
|
|
500
|
+
prop.value.type !== 'ArrowFunctionExpression' &&
|
|
501
|
+
prop.value.type !== 'FunctionExpression'
|
|
502
|
+
) {
|
|
503
|
+
throw translationError(
|
|
504
|
+
prop.key,
|
|
505
|
+
`ObjectExpression Property: Expected accessor to have a function value, but got ${prop.value.type}`,
|
|
506
|
+
context,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const kind = prop.kind;
|
|
511
|
+
const [resultExpr, deps] = convertAFunction(prop.value, context);
|
|
512
|
+
return [
|
|
513
|
+
t.ObjectTypeAccessorSignature({
|
|
514
|
+
// $FlowFixMe[incompatible-call]
|
|
515
|
+
key: asDetachedNode<
|
|
516
|
+
Identifier | NumericLiteral | StringLiteral | Expression,
|
|
517
|
+
>(prop.key),
|
|
518
|
+
kind,
|
|
519
|
+
value: resultExpr,
|
|
520
|
+
}),
|
|
521
|
+
deps,
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const [resultExpr, deps] = convertExpressionToTypeAnnotation(
|
|
526
|
+
prop.value,
|
|
527
|
+
context,
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
return [
|
|
531
|
+
t.ObjectTypePropertySignature({
|
|
532
|
+
// $FlowFixMe[incompatible-call]
|
|
533
|
+
key: asDetachedNode<
|
|
534
|
+
Identifier | NumericLiteral | StringLiteral | Expression,
|
|
535
|
+
>(prop.key),
|
|
536
|
+
value: resultExpr,
|
|
537
|
+
optional: false,
|
|
538
|
+
variance: null,
|
|
539
|
+
}),
|
|
540
|
+
deps,
|
|
541
|
+
];
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
return [
|
|
546
|
+
t.ObjectTypeAnnotation({
|
|
547
|
+
inexact: false,
|
|
548
|
+
exact: false,
|
|
549
|
+
properties: resultProperties,
|
|
550
|
+
indexers: [],
|
|
551
|
+
callProperties: [],
|
|
552
|
+
internalSlots: [],
|
|
553
|
+
}),
|
|
554
|
+
deps,
|
|
555
|
+
];
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function convertLiteral(
|
|
559
|
+
expr: Literal,
|
|
560
|
+
context: TranslationContext,
|
|
561
|
+
): TranslatedResult<TypeAnnotationType> {
|
|
562
|
+
switch (expr.literalType) {
|
|
563
|
+
case 'bigint': {
|
|
564
|
+
return [t.BigIntLiteralTypeAnnotation({raw: expr.raw}), []];
|
|
565
|
+
}
|
|
566
|
+
case 'boolean': {
|
|
567
|
+
return [
|
|
568
|
+
t.BooleanLiteralTypeAnnotation({raw: expr.raw, value: expr.value}),
|
|
569
|
+
[],
|
|
570
|
+
];
|
|
571
|
+
}
|
|
572
|
+
case 'null': {
|
|
573
|
+
return [t.NullLiteralTypeAnnotation({}), []];
|
|
574
|
+
}
|
|
575
|
+
case 'numeric': {
|
|
576
|
+
return [
|
|
577
|
+
t.NumberLiteralTypeAnnotation({raw: expr.raw, value: expr.value}),
|
|
578
|
+
[],
|
|
579
|
+
];
|
|
580
|
+
}
|
|
581
|
+
case 'string': {
|
|
582
|
+
return [
|
|
583
|
+
t.StringLiteralTypeAnnotation({raw: expr.raw, value: expr.value}),
|
|
584
|
+
[],
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
case 'regexp': {
|
|
588
|
+
return [
|
|
589
|
+
t.GenericTypeAnnotation({id: t.Identifier({name: 'RegExp'})}),
|
|
590
|
+
[],
|
|
591
|
+
];
|
|
592
|
+
}
|
|
593
|
+
default: {
|
|
594
|
+
throw translationError(
|
|
595
|
+
expr,
|
|
596
|
+
'convertLiteral: Unsupported literal type.',
|
|
597
|
+
context,
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function convertExportDeclaration(
|
|
604
|
+
decl:
|
|
605
|
+
| ExportDefaultDeclaration['declaration']
|
|
606
|
+
| $NonMaybeType<ExportNamedDeclaration['declaration']>,
|
|
607
|
+
opts: {default: boolean},
|
|
608
|
+
context: TranslationContext,
|
|
609
|
+
): TranslatedResult<ProgramStatement> {
|
|
610
|
+
switch (decl.type) {
|
|
611
|
+
case 'FunctionDeclaration': {
|
|
612
|
+
const [declDecl, deps] = convertFunctionDeclation(decl, context);
|
|
613
|
+
return [
|
|
614
|
+
opts.default
|
|
615
|
+
? t.DeclareExportDefaultDeclaration({
|
|
616
|
+
declaration: declDecl,
|
|
617
|
+
})
|
|
618
|
+
: t.DeclareExportDeclarationNamedWithDeclaration({
|
|
619
|
+
declaration: declDecl,
|
|
620
|
+
}),
|
|
621
|
+
deps,
|
|
622
|
+
];
|
|
623
|
+
}
|
|
624
|
+
case 'ClassDeclaration': {
|
|
625
|
+
const [declDecl, deps] = convertClassDeclaration(decl, context);
|
|
626
|
+
return [
|
|
627
|
+
opts.default
|
|
628
|
+
? t.DeclareExportDefaultDeclaration({
|
|
629
|
+
declaration: declDecl,
|
|
630
|
+
})
|
|
631
|
+
: t.DeclareExportDeclarationNamedWithDeclaration({
|
|
632
|
+
declaration: declDecl,
|
|
633
|
+
}),
|
|
634
|
+
deps,
|
|
635
|
+
];
|
|
636
|
+
}
|
|
637
|
+
case 'InterfaceDeclaration': {
|
|
638
|
+
if (opts.default) {
|
|
639
|
+
throw translationError(
|
|
640
|
+
decl,
|
|
641
|
+
'ExportDeclaration: Default interface found, invalid AST.',
|
|
642
|
+
context,
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const [declDecl, deps] = convertInterfaceDeclaration(decl, context);
|
|
647
|
+
return [
|
|
648
|
+
t.ExportNamedDeclarationWithDeclaration({
|
|
649
|
+
exportKind: 'type',
|
|
650
|
+
declaration: declDecl,
|
|
651
|
+
}),
|
|
652
|
+
deps,
|
|
653
|
+
];
|
|
654
|
+
}
|
|
655
|
+
case 'TypeAlias': {
|
|
656
|
+
if (opts.default) {
|
|
657
|
+
throw translationError(
|
|
658
|
+
decl,
|
|
659
|
+
'ExportDeclaration: Default type alias found, invalid AST.',
|
|
660
|
+
context,
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const [declDecl, deps] = convertTypeAlias(decl, context);
|
|
665
|
+
return [
|
|
666
|
+
t.ExportNamedDeclarationWithDeclaration({
|
|
667
|
+
exportKind: 'type',
|
|
668
|
+
declaration: declDecl,
|
|
669
|
+
}),
|
|
670
|
+
deps,
|
|
671
|
+
];
|
|
672
|
+
}
|
|
673
|
+
case 'OpaqueType': {
|
|
674
|
+
if (opts.default) {
|
|
675
|
+
throw translationError(
|
|
676
|
+
decl,
|
|
677
|
+
'ExportDeclaration: Default opaque type found, invalid AST.',
|
|
678
|
+
context,
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
const [declDecl, deps] = convertOpaqueType(decl, context);
|
|
682
|
+
return [
|
|
683
|
+
t.DeclareExportDeclarationNamedWithDeclaration({
|
|
684
|
+
declaration: declDecl,
|
|
685
|
+
}),
|
|
686
|
+
deps,
|
|
687
|
+
];
|
|
688
|
+
}
|
|
689
|
+
case 'VariableDeclaration': {
|
|
690
|
+
if (opts.default) {
|
|
691
|
+
throw translationError(
|
|
692
|
+
decl,
|
|
693
|
+
'ExportDeclaration: Default VariableDeclaration found, invalid AST.',
|
|
694
|
+
context,
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
const [declDecl, deps] = convertVariableDeclaration(decl, context);
|
|
698
|
+
return [
|
|
699
|
+
t.DeclareExportDeclarationNamedWithDeclaration({
|
|
700
|
+
declaration: declDecl,
|
|
701
|
+
}),
|
|
702
|
+
deps,
|
|
703
|
+
];
|
|
704
|
+
}
|
|
705
|
+
case 'EnumDeclaration': {
|
|
706
|
+
return [
|
|
707
|
+
t.ExportNamedDeclarationWithDeclaration({
|
|
708
|
+
exportKind: 'value',
|
|
709
|
+
declaration: asDetachedNode(decl),
|
|
710
|
+
}),
|
|
711
|
+
[],
|
|
712
|
+
];
|
|
713
|
+
}
|
|
714
|
+
default: {
|
|
715
|
+
if (isExpression(decl)) {
|
|
716
|
+
if (!opts.default) {
|
|
717
|
+
throw translationError(
|
|
718
|
+
decl,
|
|
719
|
+
'ExportDeclaration: Non default expression found, invalid AST.',
|
|
720
|
+
context,
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
const [declDecl, deps] = convertExpressionToTypeAnnotation(
|
|
724
|
+
decl,
|
|
725
|
+
context,
|
|
726
|
+
);
|
|
727
|
+
return [
|
|
728
|
+
t.DeclareExportDefaultDeclaration({
|
|
729
|
+
declaration: declDecl,
|
|
730
|
+
}),
|
|
731
|
+
deps,
|
|
732
|
+
];
|
|
733
|
+
}
|
|
734
|
+
throw translationError(
|
|
735
|
+
decl,
|
|
736
|
+
`ExportDeclaration: Unsupported declaration of type "${decl.type}".`,
|
|
737
|
+
context,
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function convertExportDefaultDeclaration(
|
|
744
|
+
stmt: ExportDefaultDeclaration,
|
|
745
|
+
context: TranslationContext,
|
|
746
|
+
): TranslatedResult<ProgramStatement> {
|
|
747
|
+
return convertExportDeclaration(stmt.declaration, {default: true}, context);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function convertExportNamedDeclaration(
|
|
751
|
+
stmt: ExportNamedDeclaration,
|
|
752
|
+
context: TranslationContext,
|
|
753
|
+
): TranslatedResult<ProgramStatement> {
|
|
754
|
+
const decl = stmt.declaration;
|
|
755
|
+
if (decl != null) {
|
|
756
|
+
return convertExportDeclaration(decl, {default: false}, context);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const resultSpecfiers = stmt.specifiers.map(spec =>
|
|
760
|
+
asDetachedNode<ExportSpecifier>(spec),
|
|
761
|
+
);
|
|
762
|
+
const specifiersDeps: Array<Dep> =
|
|
763
|
+
stmt.source != null
|
|
764
|
+
? []
|
|
765
|
+
: stmt.specifiers.flatMap(({local}) =>
|
|
766
|
+
analyzeTypeDependencies(local, context),
|
|
767
|
+
);
|
|
768
|
+
return [
|
|
769
|
+
t.ExportNamedDeclarationWithSpecifiers({
|
|
770
|
+
exportKind: stmt.exportKind,
|
|
771
|
+
source: asDetachedNode(stmt.source),
|
|
772
|
+
specifiers: resultSpecfiers,
|
|
773
|
+
}),
|
|
774
|
+
specifiersDeps,
|
|
775
|
+
];
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function convertVariableDeclaration(
|
|
779
|
+
stmt: VariableDeclaration,
|
|
780
|
+
context: TranslationContext,
|
|
781
|
+
): TranslatedResult<DeclareVariable> {
|
|
782
|
+
const [first, ...rest] = stmt.declarations;
|
|
783
|
+
if (rest.length > 0) {
|
|
784
|
+
throw translationError(
|
|
785
|
+
stmt,
|
|
786
|
+
`VariableDeclaration: more than one VariableDeclarators found`,
|
|
787
|
+
context,
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const id = first.id;
|
|
792
|
+
if (id.type !== 'Identifier') {
|
|
793
|
+
throw translationError(
|
|
794
|
+
id,
|
|
795
|
+
`VariableDeclaration: unsupported destructing`,
|
|
796
|
+
context,
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const [resultTypeAnnotation, annotDeps] = (() => {
|
|
801
|
+
if (id.typeAnnotation != null) {
|
|
802
|
+
return convertTypeAnnotation(id.typeAnnotation, id, context);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const init = first.init;
|
|
806
|
+
if (init == null) {
|
|
807
|
+
return [
|
|
808
|
+
flowFixMeOrError(
|
|
809
|
+
first,
|
|
810
|
+
`VariableDeclaration: Type annotation missing`,
|
|
811
|
+
context,
|
|
812
|
+
),
|
|
813
|
+
[],
|
|
814
|
+
];
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return convertExpressionToTypeAnnotation(init, context);
|
|
818
|
+
})();
|
|
819
|
+
|
|
820
|
+
return [
|
|
821
|
+
t.DeclareVariable({
|
|
822
|
+
id: t.Identifier({
|
|
823
|
+
name: id.name,
|
|
824
|
+
typeAnnotation: t.TypeAnnotation({
|
|
825
|
+
typeAnnotation: resultTypeAnnotation,
|
|
826
|
+
}),
|
|
827
|
+
optional: false,
|
|
828
|
+
}),
|
|
829
|
+
}),
|
|
830
|
+
annotDeps,
|
|
831
|
+
];
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
function convertImportDeclaration(
|
|
835
|
+
stmt: ImportDeclaration,
|
|
836
|
+
context: TranslationContext,
|
|
837
|
+
): TranslatedResult<ImportDeclaration> {
|
|
838
|
+
if (stmt.assertions.length > 0) {
|
|
839
|
+
throw translationError(
|
|
840
|
+
stmt,
|
|
841
|
+
'ImportDeclaration: assertions not supported',
|
|
842
|
+
context,
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
return [
|
|
847
|
+
t.ImportDeclaration({
|
|
848
|
+
specifiers: stmt.specifiers,
|
|
849
|
+
importKind: stmt.importKind,
|
|
850
|
+
source: stmt.source,
|
|
851
|
+
assertions: [],
|
|
852
|
+
}),
|
|
853
|
+
[],
|
|
854
|
+
];
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function convertInterfaceDeclaration(
|
|
858
|
+
interface_: InterfaceDeclaration,
|
|
859
|
+
context: TranslationContext,
|
|
860
|
+
): TranslatedResult<InterfaceDeclaration> {
|
|
861
|
+
return [
|
|
862
|
+
asDetachedNode(interface_),
|
|
863
|
+
analyzeTypeDependencies(interface_, context),
|
|
864
|
+
];
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
function convertClassDeclaration(
|
|
868
|
+
class_: ClassDeclaration,
|
|
869
|
+
context: TranslationContext,
|
|
870
|
+
): TranslatedResult<DeclareClass> {
|
|
871
|
+
const [resultTypeParams, typeParamsDeps] =
|
|
872
|
+
convertTypeParameterDeclarationOrNull(class_.typeParameters, context);
|
|
873
|
+
const implementsDeps = class_.implements.flatMap(impl =>
|
|
874
|
+
analyzeTypeDependencies(impl, context),
|
|
875
|
+
);
|
|
876
|
+
const [resultSuperClass, superClassDeps] = convertSuperClass(
|
|
877
|
+
class_.superClass,
|
|
878
|
+
class_.superTypeParameters,
|
|
879
|
+
context,
|
|
880
|
+
);
|
|
881
|
+
const [resultClassBody, bodyDeps] = convertClassBody(class_.body, context);
|
|
882
|
+
|
|
883
|
+
if (class_.decorators.length > 0) {
|
|
884
|
+
throw translationError(
|
|
885
|
+
class_,
|
|
886
|
+
'ClassDeclaration: decorators not supported',
|
|
887
|
+
context,
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
return [
|
|
891
|
+
t.DeclareClass({
|
|
892
|
+
// $FlowFixMe[incompatible-call]
|
|
893
|
+
id: asDetachedNode<Identifier | null>(class_.id),
|
|
894
|
+
typeParameters: resultTypeParams,
|
|
895
|
+
implements: class_.implements.map(impl => asDetachedNode(impl)),
|
|
896
|
+
extends: resultSuperClass == null ? [] : [resultSuperClass],
|
|
897
|
+
mixins: [],
|
|
898
|
+
body: resultClassBody,
|
|
899
|
+
}),
|
|
900
|
+
[...typeParamsDeps, ...implementsDeps, ...superClassDeps, ...bodyDeps],
|
|
901
|
+
];
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
function convertSuperClass(
|
|
905
|
+
superClass: ?Expression,
|
|
906
|
+
superTypeParameters: ?TypeParameterInstantiation,
|
|
907
|
+
context: TranslationContext,
|
|
908
|
+
): TranslatedResultOrNull<InterfaceExtends> {
|
|
909
|
+
if (superClass == null) {
|
|
910
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (superClass.type !== 'Identifier') {
|
|
914
|
+
throw translationError(
|
|
915
|
+
superClass,
|
|
916
|
+
`SuperClass: Non identifier super type of "${superClass.type}" not supported`,
|
|
917
|
+
context,
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
const [resultTypeParams, typeParamsDeps] =
|
|
921
|
+
convertTypeParameterInstantiationOrNull(superTypeParameters, context);
|
|
922
|
+
const superDeps = analyzeTypeDependencies(superClass, context);
|
|
923
|
+
return [
|
|
924
|
+
t.InterfaceExtends({
|
|
925
|
+
id: asDetachedNode(superClass),
|
|
926
|
+
typeParameters: resultTypeParams,
|
|
927
|
+
}),
|
|
928
|
+
[...typeParamsDeps, ...superDeps],
|
|
929
|
+
];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
function convertClassBody(
|
|
933
|
+
body: ClassBody,
|
|
934
|
+
context: TranslationContext,
|
|
935
|
+
): TranslatedResult<ObjectTypeAnnotation> {
|
|
936
|
+
const [resultProperties, deps] = convertArray(body.body, member =>
|
|
937
|
+
convertClassMember(member, context),
|
|
938
|
+
);
|
|
939
|
+
|
|
940
|
+
return [
|
|
941
|
+
t.ObjectTypeAnnotation({
|
|
942
|
+
inexact: false,
|
|
943
|
+
exact: false,
|
|
944
|
+
properties: resultProperties,
|
|
945
|
+
indexers: [],
|
|
946
|
+
callProperties: [],
|
|
947
|
+
internalSlots: [],
|
|
948
|
+
}),
|
|
949
|
+
deps,
|
|
950
|
+
];
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
function convertClassMember(
|
|
954
|
+
member: ClassMember,
|
|
955
|
+
context: TranslationContext,
|
|
956
|
+
): TranslatedResultOrNull<ObjectTypeProperty> {
|
|
957
|
+
switch (member.type) {
|
|
958
|
+
case 'PropertyDefinition': {
|
|
959
|
+
// PrivateIdentifier's are not exposed so can be stripped.
|
|
960
|
+
if (member.key.type === 'PrivateIdentifier') {
|
|
961
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
962
|
+
}
|
|
963
|
+
if (
|
|
964
|
+
member.key.type !== 'Identifier' &&
|
|
965
|
+
member.key.type !== 'StringLiteral'
|
|
966
|
+
) {
|
|
967
|
+
throw translationError(
|
|
968
|
+
member.key,
|
|
969
|
+
`ClassMember PropertyDefinition: Unsupported key type of "${member.key.type}"`,
|
|
970
|
+
context,
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const [resultTypeAnnotation, deps] = convertTypeAnnotation(
|
|
975
|
+
member.typeAnnotation,
|
|
976
|
+
member,
|
|
977
|
+
context,
|
|
978
|
+
);
|
|
979
|
+
|
|
980
|
+
return [
|
|
981
|
+
t.ObjectTypePropertySignature({
|
|
982
|
+
// $FlowFixMe[incompatible-call]
|
|
983
|
+
key: asDetachedNode<
|
|
984
|
+
ClassPropertyNameComputed | ClassPropertyNameNonComputed,
|
|
985
|
+
>(member.key),
|
|
986
|
+
value: resultTypeAnnotation,
|
|
987
|
+
optional: member.optional,
|
|
988
|
+
static: member.static,
|
|
989
|
+
variance: member.variance,
|
|
990
|
+
}),
|
|
991
|
+
deps,
|
|
992
|
+
];
|
|
993
|
+
}
|
|
994
|
+
case 'MethodDefinition': {
|
|
995
|
+
// PrivateIdentifier's are not exposed so can be stripped.
|
|
996
|
+
if (member.key.type === 'PrivateIdentifier') {
|
|
997
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
998
|
+
}
|
|
999
|
+
if (
|
|
1000
|
+
member.key.type !== 'Identifier' &&
|
|
1001
|
+
member.key.type !== 'StringLiteral'
|
|
1002
|
+
) {
|
|
1003
|
+
throw translationError(
|
|
1004
|
+
member.key,
|
|
1005
|
+
`ClassMember PropertyDefinition: Unsupported key type of "${member.key.type}"`,
|
|
1006
|
+
context,
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
const [resultValue, deps] = convertAFunction(member.value, context);
|
|
1011
|
+
|
|
1012
|
+
if (member.kind === 'get' || member.kind === 'set') {
|
|
1013
|
+
// accessors are methods - but flow accessor signatures are properties
|
|
1014
|
+
const kind = member.kind;
|
|
1015
|
+
return [
|
|
1016
|
+
t.ObjectTypeAccessorSignature({
|
|
1017
|
+
// $FlowFixMe[incompatible-call]
|
|
1018
|
+
key: asDetachedNode<
|
|
1019
|
+
ClassPropertyNameComputed | ClassPropertyNameNonComputed,
|
|
1020
|
+
>(member.key),
|
|
1021
|
+
value: resultValue,
|
|
1022
|
+
static: member.static,
|
|
1023
|
+
kind,
|
|
1024
|
+
}),
|
|
1025
|
+
deps,
|
|
1026
|
+
];
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return [
|
|
1030
|
+
t.ObjectTypeMethodSignature({
|
|
1031
|
+
// $FlowFixMe[incompatible-call]
|
|
1032
|
+
key: asDetachedNode<
|
|
1033
|
+
ClassPropertyNameComputed | ClassPropertyNameNonComputed,
|
|
1034
|
+
>(member.key),
|
|
1035
|
+
value: resultValue,
|
|
1036
|
+
static: member.static,
|
|
1037
|
+
}),
|
|
1038
|
+
deps,
|
|
1039
|
+
];
|
|
1040
|
+
}
|
|
1041
|
+
default: {
|
|
1042
|
+
throw translationError(
|
|
1043
|
+
member,
|
|
1044
|
+
`ClassMember: Unsupported member type of "${member.type}"`,
|
|
1045
|
+
context,
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
function convertFunctionDeclation(
|
|
1052
|
+
func: FunctionDeclaration,
|
|
1053
|
+
context: TranslationContext,
|
|
1054
|
+
): TranslatedResult<DeclareFunction> {
|
|
1055
|
+
const id = func.id;
|
|
1056
|
+
if (id == null) {
|
|
1057
|
+
throw translationError(func, `FunctionDeclaration: Missing name`, context);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
const [resultFunc, funcDeps] = convertAFunction(func, context);
|
|
1061
|
+
|
|
1062
|
+
const [resultPredicate, predicateDeps] = (() => {
|
|
1063
|
+
if (func.predicate == null) {
|
|
1064
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
1065
|
+
}
|
|
1066
|
+
const body = func.body.body;
|
|
1067
|
+
const predicateExpr =
|
|
1068
|
+
body.length === 1 &&
|
|
1069
|
+
body[0].type === 'ReturnStatement' &&
|
|
1070
|
+
body[0].argument != null
|
|
1071
|
+
? body[0].argument
|
|
1072
|
+
: null;
|
|
1073
|
+
if (predicateExpr == null) {
|
|
1074
|
+
throw translationError(
|
|
1075
|
+
func,
|
|
1076
|
+
'FunctionDeclation: Invalid predicate function.',
|
|
1077
|
+
context,
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
return [
|
|
1081
|
+
t.DeclaredPredicate({value: asDetachedNode(predicateExpr)}),
|
|
1082
|
+
analyzeTypeDependencies(predicateExpr, context),
|
|
1083
|
+
];
|
|
1084
|
+
})();
|
|
1085
|
+
|
|
1086
|
+
return [
|
|
1087
|
+
t.DeclareFunction({
|
|
1088
|
+
name: id.name,
|
|
1089
|
+
functionType: resultFunc,
|
|
1090
|
+
predicate: resultPredicate,
|
|
1091
|
+
}),
|
|
1092
|
+
[...funcDeps, ...predicateDeps],
|
|
1093
|
+
];
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
function convertAFunction(
|
|
1097
|
+
func: AFunction,
|
|
1098
|
+
context: TranslationContext,
|
|
1099
|
+
): TranslatedResult<FunctionTypeAnnotation> {
|
|
1100
|
+
const returnType = analyzeFunctionReturn(func);
|
|
1101
|
+
const [resultReturnType, returnDeps] = convertTypeAnnotation(
|
|
1102
|
+
returnType,
|
|
1103
|
+
func,
|
|
1104
|
+
context,
|
|
1105
|
+
);
|
|
1106
|
+
|
|
1107
|
+
const [resultParams, restParam, paramsDeps] = convertFunctionParameters(
|
|
1108
|
+
func.params,
|
|
1109
|
+
context,
|
|
1110
|
+
);
|
|
1111
|
+
|
|
1112
|
+
const [resultTypeParams, typeParamsDeps] =
|
|
1113
|
+
convertTypeParameterDeclarationOrNull(func.typeParameters, context);
|
|
1114
|
+
|
|
1115
|
+
return [
|
|
1116
|
+
t.FunctionTypeAnnotation({
|
|
1117
|
+
params: resultParams,
|
|
1118
|
+
returnType: resultReturnType,
|
|
1119
|
+
rest: restParam,
|
|
1120
|
+
typeParameters: resultTypeParams,
|
|
1121
|
+
}),
|
|
1122
|
+
[...paramsDeps, ...returnDeps, ...typeParamsDeps],
|
|
1123
|
+
];
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
type TranslatedFunctionParametersResults = [
|
|
1127
|
+
$ReadOnlyArray<DetachedNode<FunctionTypeParam>>,
|
|
1128
|
+
?DetachedNode<FunctionTypeParam>,
|
|
1129
|
+
TranslatedDeps,
|
|
1130
|
+
];
|
|
1131
|
+
function convertFunctionParameters(
|
|
1132
|
+
params: $ReadOnlyArray<FunctionParameter>,
|
|
1133
|
+
context: TranslationContext,
|
|
1134
|
+
): TranslatedFunctionParametersResults {
|
|
1135
|
+
return params.reduce<TranslatedFunctionParametersResults>(
|
|
1136
|
+
([resultParams, restParam, paramsDeps], param) => {
|
|
1137
|
+
switch (param.type) {
|
|
1138
|
+
case 'Identifier':
|
|
1139
|
+
case 'ArrayPattern':
|
|
1140
|
+
case 'ObjectPattern': {
|
|
1141
|
+
const [resultParam, deps] = convertBindingNameToFunctionTypeParam(
|
|
1142
|
+
param,
|
|
1143
|
+
context,
|
|
1144
|
+
);
|
|
1145
|
+
return [
|
|
1146
|
+
[...resultParams, resultParam],
|
|
1147
|
+
restParam,
|
|
1148
|
+
[...paramsDeps, ...deps],
|
|
1149
|
+
];
|
|
1150
|
+
}
|
|
1151
|
+
case 'AssignmentPattern': {
|
|
1152
|
+
const [resultParam, deps] = convertBindingNameToFunctionTypeParam(
|
|
1153
|
+
param.left,
|
|
1154
|
+
context,
|
|
1155
|
+
);
|
|
1156
|
+
return [
|
|
1157
|
+
[...resultParams, resultParam],
|
|
1158
|
+
restParam,
|
|
1159
|
+
[...paramsDeps, ...deps],
|
|
1160
|
+
];
|
|
1161
|
+
}
|
|
1162
|
+
case 'RestElement': {
|
|
1163
|
+
if (restParam != null) {
|
|
1164
|
+
throw translationError(
|
|
1165
|
+
param,
|
|
1166
|
+
`FunctionParameter: Multiple rest elements found`,
|
|
1167
|
+
context,
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
const [resultParam, deps] = convertBindingNameToFunctionTypeParam(
|
|
1171
|
+
// $FlowFixMe[incompatible-call] I dont think these other cases are possible
|
|
1172
|
+
param.argument,
|
|
1173
|
+
context,
|
|
1174
|
+
);
|
|
1175
|
+
return [resultParams, resultParam, [...paramsDeps, ...deps]];
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
},
|
|
1179
|
+
[[], null, []],
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
function convertBindingNameToFunctionTypeParam(
|
|
1184
|
+
pat: BindingName,
|
|
1185
|
+
context: TranslationContext,
|
|
1186
|
+
): TranslatedResult<FunctionTypeParam> {
|
|
1187
|
+
const name = pat.type === 'Identifier' ? pat.name : null;
|
|
1188
|
+
const [resultParamTypeAnnotation, paramDeps] = convertTypeAnnotation(
|
|
1189
|
+
pat.typeAnnotation,
|
|
1190
|
+
pat,
|
|
1191
|
+
context,
|
|
1192
|
+
);
|
|
1193
|
+
return [
|
|
1194
|
+
t.FunctionTypeParam({
|
|
1195
|
+
name: name != null ? t.Identifier({name}) : null,
|
|
1196
|
+
typeAnnotation: resultParamTypeAnnotation,
|
|
1197
|
+
optional: pat.type === 'Identifier' ? pat.optional : false,
|
|
1198
|
+
}),
|
|
1199
|
+
paramDeps,
|
|
1200
|
+
];
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
function convertTypeAlias(
|
|
1204
|
+
typeAlias: TypeAlias,
|
|
1205
|
+
context: TranslationContext,
|
|
1206
|
+
): TranslatedResult<TypeAlias> {
|
|
1207
|
+
const [typeAnnotationType, rightDeps] = convertTypeAnnotationType(
|
|
1208
|
+
typeAlias.right,
|
|
1209
|
+
typeAlias,
|
|
1210
|
+
context,
|
|
1211
|
+
);
|
|
1212
|
+
const [typeParameters, typeParamsDeps] =
|
|
1213
|
+
convertTypeParameterDeclarationOrNull(typeAlias.typeParameters, context);
|
|
1214
|
+
return [
|
|
1215
|
+
t.TypeAlias({
|
|
1216
|
+
right: typeAnnotationType,
|
|
1217
|
+
id: asDetachedNode(typeAlias.id),
|
|
1218
|
+
typeParameters,
|
|
1219
|
+
}),
|
|
1220
|
+
[...rightDeps, ...typeParamsDeps],
|
|
1221
|
+
];
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
function convertOpaqueType(
|
|
1225
|
+
opaqueType: OpaqueType,
|
|
1226
|
+
context: TranslationContext,
|
|
1227
|
+
): TranslatedResult<DeclareOpaqueType> {
|
|
1228
|
+
const [resultSupertype, supertypeDeps] = convertTypeAnnotationTypeOrNull(
|
|
1229
|
+
opaqueType.supertype,
|
|
1230
|
+
context,
|
|
1231
|
+
);
|
|
1232
|
+
const [typeParameters, typeParamsDeps] =
|
|
1233
|
+
convertTypeParameterDeclarationOrNull(opaqueType.typeParameters, context);
|
|
1234
|
+
return [
|
|
1235
|
+
t.DeclareOpaqueType({
|
|
1236
|
+
id: asDetachedNode(opaqueType.id),
|
|
1237
|
+
typeParameters,
|
|
1238
|
+
supertype: resultSupertype,
|
|
1239
|
+
}),
|
|
1240
|
+
[...typeParamsDeps, ...supertypeDeps],
|
|
1241
|
+
];
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
function convertTypeCastExpression(
|
|
1245
|
+
typeCast: TypeCastExpression,
|
|
1246
|
+
context: TranslationContext,
|
|
1247
|
+
): TranslatedResult<TypeAnnotationType> {
|
|
1248
|
+
return convertTypeAnnotation(typeCast.typeAnnotation, typeCast, context);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
function convertTypeAnnotation(
|
|
1252
|
+
annot: ?TypeAnnotation,
|
|
1253
|
+
container: ESNode,
|
|
1254
|
+
context: TranslationContext,
|
|
1255
|
+
): TranslatedResult<TypeAnnotationType> {
|
|
1256
|
+
return convertTypeAnnotationType(annot?.typeAnnotation, container, context);
|
|
1257
|
+
}
|
|
1258
|
+
function convertTypeAnnotationType(
|
|
1259
|
+
annot: ?TypeAnnotationType,
|
|
1260
|
+
container: ESNode,
|
|
1261
|
+
context: TranslationContext,
|
|
1262
|
+
): TranslatedResult<TypeAnnotationType> {
|
|
1263
|
+
if (annot == null) {
|
|
1264
|
+
return [
|
|
1265
|
+
flowFixMeOrError(
|
|
1266
|
+
container,
|
|
1267
|
+
`TypeAnnotationType: Type annotation missing`,
|
|
1268
|
+
context,
|
|
1269
|
+
),
|
|
1270
|
+
[],
|
|
1271
|
+
];
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
return [asDetachedNode(annot), analyzeTypeDependencies(annot, context)];
|
|
1275
|
+
}
|
|
1276
|
+
function convertTypeAnnotationTypeOrNull(
|
|
1277
|
+
annot: ?TypeAnnotationType,
|
|
1278
|
+
context: TranslationContext,
|
|
1279
|
+
): TranslatedResultOrNull<TypeAnnotationType> {
|
|
1280
|
+
if (annot == null) {
|
|
1281
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
return [asDetachedNode(annot), analyzeTypeDependencies(annot, context)];
|
|
1285
|
+
}
|
|
1286
|
+
function convertTypeParameterDeclarationOrNull(
|
|
1287
|
+
decl: ?TypeParameterDeclaration,
|
|
1288
|
+
context: TranslationContext,
|
|
1289
|
+
): TranslatedResultOrNull<TypeParameterDeclaration> {
|
|
1290
|
+
if (decl == null) {
|
|
1291
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
1292
|
+
}
|
|
1293
|
+
return [asDetachedNode(decl), analyzeTypeDependencies(decl, context)];
|
|
1294
|
+
}
|
|
1295
|
+
function convertTypeParameterInstantiationOrNull(
|
|
1296
|
+
inst: ?TypeParameterInstantiation,
|
|
1297
|
+
context: TranslationContext,
|
|
1298
|
+
): TranslatedResultOrNull<TypeParameterInstantiation> {
|
|
1299
|
+
if (inst == null) {
|
|
1300
|
+
return EMPTY_TRANSLATION_RESULT;
|
|
1301
|
+
}
|
|
1302
|
+
return [asDetachedNode(inst), analyzeTypeDependencies(inst, context)];
|
|
1303
|
+
}
|