Summary:
These are utility functions that the TypeScript parser uses and are copied from and follows the same logic as the flow parser with some TypeScript specific changes.  Also added dependency of `babel/parser` as the parsing engine we're using for TypeScript.

Changelog:
[General][Add] - Add foundation for WIP TypeScript parser for Codegen

Reviewed By: RSNara

Differential Revision: D33080527

fbshipit-source-id: d4bd515af549a41f07a2e3ee1a16b5ed678180b2
This commit is contained in:
Charles Dudley 2021-12-20 14:15:57 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 165dfbcc87
Коммит 114d5a8a17
3 изменённых файлов: 48 добавлений и 25 удалений

Просмотреть файл

@ -18,6 +18,7 @@
"lib"
],
"dependencies": {
"@babel/parser": "^7.14.0",
"flow-parser": "^0.121.0",
"jscodeshift": "^0.11.0",
"nullthrows": "^1.1.1"

Просмотреть файл

@ -197,6 +197,11 @@ function isModuleRegistryCall(node: $FlowFixMe): boolean {
) {
return false;
}
if (memberExpression.computed) {
return false;
}
return true;
}

Просмотреть файл

@ -13,12 +13,7 @@
const {ParserError} = require('./errors');
/**
* This FlowFixMe is supposed to refer to an InterfaceDeclaration or TypeAlias
* declaration type. Unfortunately, we don't have those types, because flow-parser
* generates them, and flow-parser is not type-safe. In the future, we should find
* a way to get these types from our flow parser library.
*
* TODO(T71778680): Flow type AST Nodes
* TODO(T108222691): Use flow-types for @babel/parser
*/
export type TypeDeclarationMap = {[declarationName: string]: $FlowFixMe};
@ -26,22 +21,23 @@ function getTypes(ast: $FlowFixMe): TypeDeclarationMap {
return ast.body.reduce((types, node) => {
if (node.type === 'ExportNamedDeclaration' && node.exportKind === 'type') {
if (
node.declaration.type === 'TypeAlias' ||
node.declaration.type === 'InterfaceDeclaration'
node.declaration.type === 'TSTypeAliasDeclaration' ||
node.declaration.type === 'TSInterfaceDeclaration'
) {
types[node.declaration.id.name] = node.declaration;
}
} else if (
node.type === 'TypeAlias' ||
node.type === 'InterfaceDeclaration'
node.type === 'TSTypeAliasDeclaration' ||
node.type === 'TSInterfaceDeclaration'
) {
types[node.id.name] = node;
}
return types;
}, {});
}
// $FlowFixMe[unclear-type] there's no flowtype for ASTs
// $FlowFixMe[unclear-type] Use flow-types for @babel/parser
export type ASTNode = Object;
const invariant = require('invariant');
@ -56,7 +52,7 @@ type TypeAliasResolutionStatus =
}>;
function resolveTypeAnnotation(
// TODO(T71778680): This is an Flow TypeAnnotation. Flow-type this
// TODO(T108222691): Use flow-types for @babel/parser
typeAnnotation: $FlowFixMe,
types: TypeDeclarationMap,
): {
@ -69,32 +65,43 @@ function resolveTypeAnnotation(
'resolveTypeAnnotation(): typeAnnotation cannot be null',
);
let node = typeAnnotation;
let node =
typeAnnotation.type === 'TSTypeAnnotation'
? typeAnnotation.typeAnnotation
: typeAnnotation;
let nullable = false;
let typeAliasResolutionStatus: TypeAliasResolutionStatus = {
successful: false,
};
for (;;) {
if (node.type === 'NullableTypeAnnotation') {
// Check for optional type in union e.g. T | null | void
if (
node.type === 'TSUnionType' &&
node.types.some(
t => t.type === 'TSNullKeyword' || t.type === 'TSVoidKeyword',
)
) {
node = node.types.filter(
t => t.type !== 'TSNullKeyword' && t.type !== 'TSVoidKeyword',
)[0];
nullable = true;
node = node.typeAnnotation;
} else if (node.type === 'GenericTypeAnnotation') {
} else if (node.type === 'TSTypeReference') {
typeAliasResolutionStatus = {
successful: true,
aliasName: node.id.name,
aliasName: node.typeName.name,
};
const resolvedTypeAnnotation = types[node.id.name];
const resolvedTypeAnnotation = types[node.typeName.name];
if (resolvedTypeAnnotation == null) {
break;
}
invariant(
resolvedTypeAnnotation.type === 'TypeAlias',
`GenericTypeAnnotation '${node.id.name}' must resolve to a TypeAlias. Instead, it resolved to a '${resolvedTypeAnnotation.type}'`,
resolvedTypeAnnotation.type === 'TSTypeAliasDeclaration',
`GenericTypeAnnotation '${node.typeName.name}' must resolve to a TSTypeAliasDeclaration. Instead, it resolved to a '${resolvedTypeAnnotation.type}'`,
);
node = resolvedTypeAnnotation.right;
node = resolvedTypeAnnotation.typeAnnotation;
} else {
break;
}
@ -108,9 +115,14 @@ function resolveTypeAnnotation(
}
function getValueFromTypes(value: ASTNode, types: TypeDeclarationMap): ASTNode {
if (value.type === 'GenericTypeAnnotation' && types[value.id.name]) {
return getValueFromTypes(types[value.id.name].right, types);
if (value.type === 'TSTypeReference' && types[value.typeName.name]) {
return getValueFromTypes(types[value.typeName.name], types);
}
if (value.type === 'TSTypeAliasDeclaration') {
return value.typeAnnotation;
}
return value;
}
@ -137,7 +149,7 @@ function createParserErrorCapturer(): [
return [errors, guard];
}
// TODO(T71778680): Flow-type ASTNodes.
// TODO(T108222691): Use flow-types for @babel/parser
function visit(
astNode: $FlowFixMe,
visitor: {
@ -166,7 +178,7 @@ function visit(
}
}
// TODO(T71778680): Flow-type ASTNodes.
// TODO(T108222691): Use flow-types for @babel/parser
function isModuleRegistryCall(node: $FlowFixMe): boolean {
if (node.type !== 'CallExpression') {
return false;
@ -197,6 +209,11 @@ function isModuleRegistryCall(node: $FlowFixMe): boolean {
) {
return false;
}
if (memberExpression.computed) {
return false;
}
return true;
}