Make buildModuleSchema and buildComponentSchema operate on Program AST nodes

Summary:
## Why
We want to reuse these functions inside the ESLint rule. Therefore, it's better to make them accept the AST node object, as opposed to a custom type defined in codegen.

Changelog: [Internal]

Reviewed By: fkgozali

Differential Revision: D24379512

fbshipit-source-id: 9f7378fc6c5f48cce34da109f5a7c017332b302a
This commit is contained in:
Ramanpreet Nara
2020-10-19 21:59:29 -07:00
committed by Facebook GitHub Bot
parent 33789ba0ea
commit 2f438b03d7
4 changed files with 59 additions and 40 deletions
@@ -16,6 +16,7 @@ const {getEvents} = require('./events');
const {getProps, getPropProperties} = require('./props');
const {getCommandOptions, getOptions} = require('./options');
const {getExtendsProps, removeKnownExtends} = require('./extends');
const {getTypes} = require('../utils');
function findComponentConfig(ast) {
const foundConfigs = [];
@@ -167,7 +168,7 @@ function getCommandProperties(commandTypeName, types, commandOptions) {
}
// $FlowFixMe there's no flowtype for AST
function buildComponentSchema(ast, types): ComponentSchemaBuilderConfig {
function buildComponentSchema(ast): ComponentSchemaBuilderConfig {
const {
componentName,
propsTypeName,
@@ -176,6 +177,8 @@ function buildComponentSchema(ast, types): ComponentSchemaBuilderConfig {
optionsExpression,
} = findComponentConfig(ast);
const types = getTypes(ast);
const propProperties = getPropProperties(propsTypeName, types);
const commandOptions = getCommandOptions(commandOptionsExpression);
+29 -37
View File
@@ -21,27 +21,6 @@ const {buildModuleSchema} = require('./modules');
const {wrapModuleSchema} = require('./modules/schema');
const invariant = require('invariant');
import type {TypeDeclarationMap} from './utils';
function getTypes(ast): TypeDeclarationMap {
return ast.body.reduce((types, node) => {
if (node.type === 'ExportNamedDeclaration' && node.exportKind === 'type') {
if (
node.declaration.type === 'TypeAlias' ||
node.declaration.type === 'InterfaceDeclaration'
) {
types[node.declaration.id.name] = node.declaration;
}
} else if (
node.type === 'TypeAlias' ||
node.type === 'InterfaceDeclaration'
) {
types[node.id.name] = node;
}
return types;
}, {});
}
function isComponent(ast) {
const defaultExports = ast.body.filter(
node => node.type === 'ExportDefaultDeclaration',
@@ -68,27 +47,39 @@ function isComponent(ast) {
);
}
function isModule(types: TypeDeclarationMap) {
const declaredModuleNames: Array<string> = Object.keys(types).filter(
(typeName: string) => {
const declaration = types[typeName];
function isModule(
// TODO(T71778680): Flow-type this node.
ast: $FlowFixMe,
) {
const moduleInterfaces = ast.body
.map(node => {
if (
node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'type' &&
node.declaration.type === 'InterfaceDeclaration'
) {
return node.declaration;
}
return node;
})
.filter(declaration => {
return (
declaration.type === 'InterfaceDeclaration' &&
declaration.extends.length === 1 &&
declaration.extends[0].type === 'InterfaceExtends' &&
declaration.extends[0].id.name === 'TurboModule'
);
},
);
})
.map(declaration => declaration.id.name);
if (declaredModuleNames.length === 0) {
if (moduleInterfaces.length === 0) {
return false;
}
if (declaredModuleNames.length > 1) {
if (moduleInterfaces.length > 1) {
throw new Error(
'File contains declarations of more than one module: ' +
declaredModuleNames.join(', ') +
moduleInterfaces.join(', ') +
'. Please declare exactly one module in this file.',
);
}
@@ -96,9 +87,12 @@ function isModule(types: TypeDeclarationMap) {
return true;
}
function getConfigType(ast, types: TypeDeclarationMap): 'module' | 'component' {
function getConfigType(
// TODO(T71778680): Flow-type this node.
ast: $FlowFixMe,
): 'module' | 'component' {
const isConfigAComponent = isComponent(ast);
const isConfigAModule = isModule(types);
const isConfigAModule = isModule(ast);
if (isConfigAModule && isConfigAComponent) {
throw new Error(
@@ -142,12 +136,10 @@ const TURBO_MODULE_REGISTRY_REQUIRE_REGEX_STRING = withSpace(
function buildSchema(contents: string, filename: ?string): SchemaType {
const ast = flowParser.parse(contents);
const types = getTypes(ast);
const configType = getConfigType(ast, types);
const configType = getConfigType(ast);
if (configType === 'component') {
return wrapComponentSchema(buildComponentSchema(ast, types));
return wrapComponentSchema(buildComponentSchema(ast));
} else {
if (filename === undefined || filename === null) {
throw new Error('Filepath expected while parasing a module');
@@ -180,7 +172,7 @@ function buildSchema(contents: string, filename: ?string): SchemaType {
}
return wrapModuleSchema(
buildModuleSchema(hasteModuleName, moduleNames, types),
buildModuleSchema(hasteModuleName, moduleNames, ast),
hasteModuleName,
);
}
@@ -22,7 +22,7 @@ import type {
} from '../../../CodegenSchema.js';
import type {TypeDeclarationMap} from '../utils.js';
const {resolveTypeAnnotation} = require('../utils.js');
const {resolveTypeAnnotation, getTypes} = require('../utils.js');
const {unwrapNullable, wrapNullable} = require('./utils');
const {
FlowGenericNotTypeParameterizedParserError,
@@ -398,8 +398,12 @@ function buildPropertySchema(
function buildModuleSchema(
hasteModuleName: string,
moduleNames: $ReadOnlyArray<string>,
types: TypeDeclarationMap,
/**
* TODO(T71778680): Flow-type this node.
*/
ast: $FlowFixMe,
): NativeModuleSchema {
const types = getTypes(ast);
const moduleInterfaceNames = (Object.keys(
types,
): $ReadOnlyArray<string>).filter((typeName: string) => {
+20
View File
@@ -20,6 +20,25 @@
*/
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'
) {
types[node.declaration.id.name] = node.declaration;
}
} else if (
node.type === 'TypeAlias' ||
node.type === 'InterfaceDeclaration'
) {
types[node.id.name] = node;
}
return types;
}, {});
}
// $FlowFixMe there's no flowtype for ASTs
export type ASTNode = Object;
@@ -95,4 +114,5 @@ function getValueFromTypes(value: ASTNode, types: TypeDeclarationMap): ASTNode {
module.exports = {
getValueFromTypes,
resolveTypeAnnotation,
getTypes,
};