Skip to content

Commit

Permalink
TypeScript parser foundation
Browse files Browse the repository at this point in the history
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
  • Loading branch information
charlesbdudley authored and facebook-github-bot committed Dec 20, 2021
1 parent 165dfbc commit 114d5a8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 25 deletions.
1 change: 1 addition & 0 deletions packages/react-native-codegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"lib"
],
"dependencies": {
"@babel/parser": "^7.14.0",
"flow-parser": "^0.121.0",
"jscodeshift": "^0.11.0",
"nullthrows": "^1.1.1"
Expand Down
5 changes: 5 additions & 0 deletions packages/react-native-codegen/src/parsers/flow/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ function isModuleRegistryCall(node: $FlowFixMe): boolean {
) {
return false;
}

if (memberExpression.computed) {
return false;
}

return true;
}

Expand Down
67 changes: 42 additions & 25 deletions packages/react-native-codegen/src/parsers/typescript/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,31 @@
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};

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');
Expand All @@ -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,
): {
Expand All @@ -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;
}
Expand All @@ -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;
}

Expand All @@ -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: {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -197,6 +209,11 @@ function isModuleRegistryCall(node: $FlowFixMe): boolean {
) {
return false;
}

if (memberExpression.computed) {
return false;
}

return true;
}

Expand Down

0 comments on commit 114d5a8

Please sign in to comment.