Replace getTypes functions with parser specific methods (#36225)

Summary:
This PR is task 74 from https://github.com/facebook/react-native/issues/34872:
> Move getTypes functions from utils.js to specific Parsers. Right now we have two Parser classes that takes care of the language specific details and two utils files that contains similar logic. We would like to move everything under the Parsers classes for better OOP architecture and to encourage code-reuse.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[Internal] [Changed] - Replace getTypes functions with parser specific methods

Pull Request resolved: https://github.com/facebook/react-native/pull/36225

Test Plan: I tested using Jest and Flow commands.

Reviewed By: rshest

Differential Revision: D43453454

Pulled By: cipolleschi

fbshipit-source-id: 0eebcb55e1af3319e2c35bb462980046329a2c09
This commit is contained in:
Antoine Doubovetzky authored and Facebook GitHub Bot committed 2023-03-01 06:13:57 -08:00
1 parent a1f6b4d0ef
commit f23f7f4c0f
12 files changed
+113 -91

No files matched your search

@@ -33,9 +33,12 @@ const {
} = require('../errors');
import {MockedParser} from '../parserMock';
import {FlowParser} from '../flow/parser';
const parser = new MockedParser();
const flowParser = new FlowParser();
const flowTranslateTypeAnnotation = require('../flow/modules/index');
const typeScriptTranslateTypeAnnotation = require('../typescript/modules/index');
@@ -384,7 +387,9 @@ describe('buildSchemaFromConfigType', () => {
};
const wrapComponentSchemaMock = jest.fn();
const buildComponentSchemaMock = jest.fn(_ => componentSchemaMock);
const buildComponentSchemaMock = jest.fn(
(_ast, _parser) => componentSchemaMock,
);
const buildModuleSchemaMock = jest.fn((_0, _1, _2, _3) => moduleSchemaMock);
const buildSchemaFromConfigTypeHelper = (
@@ -414,7 +419,7 @@ describe('buildSchemaFromConfigType', () => {
buildSchemaFromConfigTypeHelper('component');
expect(buildComponentSchemaMock).toHaveBeenCalledTimes(1);
expect(buildComponentSchemaMock).toHaveBeenCalledWith(astMock);
expect(buildComponentSchemaMock).toHaveBeenCalledWith(astMock, parser);
expect(wrapComponentSchemaMock).toHaveBeenCalledTimes(1);
expect(wrapComponentSchemaMock).toHaveBeenCalledWith(componentSchemaMock);
@@ -681,7 +686,7 @@ describe('buildSchema', () => {
buildComponentSchema,
buildModuleSchema,
Visitor,
parser,
flowParser,
);
expect(getConfigTypeSpy).toHaveBeenCalledTimes(1);
@@ -734,7 +739,7 @@ describe('buildSchema', () => {
buildComponentSchema,
buildModuleSchema,
Visitor,
parser,
flowParser,
);
expect(getConfigTypeSpy).toHaveBeenCalledTimes(1);
@@ -9,11 +9,11 @@
*/
'use strict';
import type {Parser} from '../../parser';
import type {TypeDeclarationMap} from '../../utils';
import type {CommandOptions} from './options';
import type {ComponentSchemaBuilderConfig} from '../../schema.js';
const {getTypes} = require('../utils');
const {getCommands} = require('./commands');
const {getEvents} = require('./events');
const {getExtendsProps, removeKnownExtends} = require('./extends');
@@ -180,9 +180,10 @@ function getCommandProperties(
}
// $FlowFixMe[signature-verification-failure] there's no flowtype for AST
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
* LTI update could not be added via codemod */
function buildComponentSchema(ast): ComponentSchemaBuilderConfig {
function buildComponentSchema(
ast: $FlowFixMe,
parser: Parser,
): ComponentSchemaBuilderConfig {
const {
componentName,
propsTypeName,
@@ -191,7 +192,7 @@ function buildComponentSchema(ast): ComponentSchemaBuilderConfig {
optionsExpression,
} = findComponentConfig(ast);
const types = getTypes(ast);
const types = parser.getTypes(ast);
const propProperties = getProperties(propsTypeName, types);
const commandOptions = getCommandOptions(commandOptionsExpression);
@@ -25,7 +25,7 @@ import type {Parser} from '../../parser';
import type {ParserErrorCapturer, TypeDeclarationMap} from '../../utils';
const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils');
const {resolveTypeAnnotation, getTypes} = require('../utils');
const {resolveTypeAnnotation} = require('../utils');
const {
unwrapNullable,
wrapNullable,
@@ -339,7 +339,7 @@ function buildModuleSchema(
tryParse: ParserErrorCapturer,
parser: Parser,
): NativeModuleSchema {
const types = getTypes(ast);
const types = parser.getTypes(ast);
const moduleSpecs = (Object.values(types): $ReadOnlyArray<$FlowFixMe>).filter(
t => parser.isModuleInterface(t),
);
@@ -213,6 +213,46 @@ class FlowParser implements Parser {
): $FlowFixMe {
return types[typeAnnotation.typeParameters.params[0].id.name];
}
/**
* 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
*/
getTypes(ast: $FlowFixMe): TypeDeclarationMap {
return ast.body.reduce((types, node) => {
if (
node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'type'
) {
if (
node.declaration != null &&
(node.declaration.type === 'TypeAlias' ||
node.declaration.type === 'InterfaceDeclaration')
) {
types[node.declaration.id.name] = node.declaration;
}
} else if (
node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'value' &&
node.declaration &&
node.declaration.type === 'EnumDeclaration'
) {
types[node.declaration.id.name] = node.declaration;
} else if (
node.type === 'TypeAlias' ||
node.type === 'InterfaceDeclaration' ||
node.type === 'EnumDeclaration'
) {
types[node.id.name] = node;
}
return types;
}, {});
}
}
module.exports = {
-38
View File
@@ -12,43 +12,6 @@
import type {TypeResolutionStatus, TypeDeclarationMap} from '../utils';
/**
* 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
*/
function getTypes(ast: $FlowFixMe): TypeDeclarationMap {
return ast.body.reduce((types, node) => {
if (node.type === 'ExportNamedDeclaration' && node.exportKind === 'type') {
if (
node.declaration != null &&
(node.declaration.type === 'TypeAlias' ||
node.declaration.type === 'InterfaceDeclaration')
) {
types[node.declaration.id.name] = node.declaration;
}
} else if (
node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'value' &&
node.declaration &&
node.declaration.type === 'EnumDeclaration'
) {
types[node.declaration.id.name] = node.declaration;
} else if (
node.type === 'TypeAlias' ||
node.type === 'InterfaceDeclaration' ||
node.type === 'EnumDeclaration'
) {
types[node.id.name] = node;
}
return types;
}, {});
}
// $FlowFixMe[unclear-type] there's no flowtype for ASTs
export type ASTNode = Object;
@@ -134,5 +97,4 @@ function getValueFromTypes(value: ASTNode, types: TypeDeclarationMap): ASTNode {
module.exports = {
getValueFromTypes,
resolveTypeAnnotation,
getTypes,
};
+5
View File
@@ -169,4 +169,9 @@ export interface Parser {
typeAnnotation: $FlowFixMe,
types: TypeDeclarationMap,
): $FlowFixMe;
/**
* Given the AST, returns the TypeDeclarationMap
*/
getTypes(ast: $FlowFixMe): TypeDeclarationMap;
}
+4 -1
View File
@@ -21,7 +21,6 @@ import type {
NativeModuleEnumMemberType,
NativeModuleEnumMembers,
} from '../CodegenSchema';
import type {TypeDeclarationMap} from './utils';
// $FlowFixMe[untyped-import] there's no flowtype flow-parser
@@ -177,4 +176,8 @@ export class MockedParser implements Parser {
): $FlowFixMe {
return types[typeAnnotation.typeParameters.params[0].id.name];
}
getTypes(ast: $FlowFixMe): TypeDeclarationMap {
return {};
}
}
@@ -345,7 +345,10 @@ function buildSchemaFromConfigType(
filename: ?string,
ast: $FlowFixMe,
wrapComponentSchema: (config: ComponentSchemaBuilderConfig) => SchemaType,
buildComponentSchema: (ast: $FlowFixMe) => ComponentSchemaBuilderConfig,
buildComponentSchema: (
ast: $FlowFixMe,
parser: Parser,
) => ComponentSchemaBuilderConfig,
buildModuleSchema: (
hasteModuleName: string,
ast: $FlowFixMe,
@@ -356,7 +359,7 @@ function buildSchemaFromConfigType(
): SchemaType {
switch (configType) {
case 'component': {
return wrapComponentSchema(buildComponentSchema(ast));
return wrapComponentSchema(buildComponentSchema(ast, parser));
}
case 'module': {
if (filename === undefined || filename === null) {
@@ -398,7 +401,10 @@ function buildSchema(
contents: string,
filename: ?string,
wrapComponentSchema: (config: ComponentSchemaBuilderConfig) => SchemaType,
buildComponentSchema: (ast: $FlowFixMe) => ComponentSchemaBuilderConfig,
buildComponentSchema: (
ast: $FlowFixMe,
parser: Parser,
) => ComponentSchemaBuilderConfig,
buildModuleSchema: (
hasteModuleName: string,
ast: $FlowFixMe,
@@ -10,11 +10,11 @@
'use strict';
import type {ExtendsPropsShape} from '../../../CodegenSchema.js';
import type {Parser} from '../../parser';
import type {TypeDeclarationMap} from '../../utils';
import type {CommandOptions} from './options';
import type {ComponentSchemaBuilderConfig} from '../../schema.js';
const {getTypes} = require('../utils');
const {getCommands} = require('./commands');
const {getEvents} = require('./events');
const {categorizeProps} = require('./extends');
@@ -185,9 +185,10 @@ function getCommandProperties(
type PropsAST = Object;
// $FlowFixMe[signature-verification-failure] TODO(T108222691): Use flow-types for @babel/parser
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
* LTI update could not be added via codemod */
function buildComponentSchema(ast): ComponentSchemaBuilderConfig {
function buildComponentSchema(
ast: $FlowFixMe,
parser: Parser,
): ComponentSchemaBuilderConfig {
const {
componentName,
propsTypeName,
@@ -196,7 +197,7 @@ function buildComponentSchema(ast): ComponentSchemaBuilderConfig {
optionsExpression,
} = findComponentConfig(ast);
const types = getTypes(ast);
const types = parser.getTypes(ast);
const propProperties = getProperties(propsTypeName, types);
const commandOptions = getCommandOptions(commandOptionsExpression);
@@ -31,7 +31,7 @@ const {flattenIntersectionType} = require('../parseTopLevelType');
const {flattenProperties} = require('../components/componentsUtils');
const {visit, isModuleRegistryCall, verifyPlatforms} = require('../../utils');
const {resolveTypeAnnotation, getTypes} = require('../utils');
const {resolveTypeAnnotation} = require('../utils');
const {
parseObjectProperty,
@@ -445,7 +445,7 @@ function buildModuleSchema(
tryParse: ParserErrorCapturer,
parser: Parser,
): NativeModuleSchema {
const types = getTypes(ast);
const types = parser.getTypes(ast);
const moduleSpecs = (Object.values(types): $ReadOnlyArray<$FlowFixMe>).filter(
t => parser.isModuleInterface(t),
);
@@ -209,6 +209,36 @@ class TypeScriptParser implements Parser {
): $FlowFixMe {
return types[typeAnnotation.typeParameters.params[0].typeName.name];
}
/**
* TODO(T108222691): Use flow-types for @babel/parser
*/
getTypes(ast: $FlowFixMe): TypeDeclarationMap {
return ast.body.reduce((types, node) => {
switch (node.type) {
case 'ExportNamedDeclaration': {
if (node.declaration) {
switch (node.declaration.type) {
case 'TSTypeAliasDeclaration':
case 'TSInterfaceDeclaration':
case 'TSEnumDeclaration': {
types[node.declaration.id.name] = node.declaration;
break;
}
}
}
break;
}
case 'TSTypeAliasDeclaration':
case 'TSInterfaceDeclaration':
case 'TSEnumDeclaration': {
types[node.id.name] = node;
break;
}
}
return types;
}, {});
}
}
module.exports = {
TypeScriptParser,
@@ -14,36 +14,6 @@ import type {TypeResolutionStatus, TypeDeclarationMap} from '../utils';
const {parseTopLevelType} = require('./parseTopLevelType');
/**
* TODO(T108222691): Use flow-types for @babel/parser
*/
function getTypes(ast: $FlowFixMe): TypeDeclarationMap {
return ast.body.reduce((types, node) => {
switch (node.type) {
case 'ExportNamedDeclaration': {
if (node.declaration) {
switch (node.declaration.type) {
case 'TSTypeAliasDeclaration':
case 'TSInterfaceDeclaration':
case 'TSEnumDeclaration': {
types[node.declaration.id.name] = node.declaration;
break;
}
}
}
break;
}
case 'TSTypeAliasDeclaration':
case 'TSInterfaceDeclaration':
case 'TSEnumDeclaration': {
types[node.id.name] = node;
break;
}
}
return types;
}, {});
}
// $FlowFixMe[unclear-type] Use flow-types for @babel/parser
export type ASTNode = Object;
@@ -131,5 +101,4 @@ function resolveTypeAnnotation(
module.exports = {
resolveTypeAnnotation,
getTypes,
};