diff --git a/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js b/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js index 2d8d96175e8..1117c1819ce 100644 --- a/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js +++ b/packages/react-native-codegen/src/parsers/__tests__/parsers-commons-test.js @@ -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); diff --git a/packages/react-native-codegen/src/parsers/flow/components/index.js b/packages/react-native-codegen/src/parsers/flow/components/index.js index 35106bcab38..e209ce4671f 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/index.js +++ b/packages/react-native-codegen/src/parsers/flow/components/index.js @@ -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); diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index 29c825ee633..b6d6c53028e 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -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), ); diff --git a/packages/react-native-codegen/src/parsers/flow/parser.js b/packages/react-native-codegen/src/parsers/flow/parser.js index 4d6e84836a3..5ae36dbd134 100644 --- a/packages/react-native-codegen/src/parsers/flow/parser.js +++ b/packages/react-native-codegen/src/parsers/flow/parser.js @@ -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 = { diff --git a/packages/react-native-codegen/src/parsers/flow/utils.js b/packages/react-native-codegen/src/parsers/flow/utils.js index d8939913389..3692cf16f89 100644 --- a/packages/react-native-codegen/src/parsers/flow/utils.js +++ b/packages/react-native-codegen/src/parsers/flow/utils.js @@ -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, }; diff --git a/packages/react-native-codegen/src/parsers/parser.js b/packages/react-native-codegen/src/parsers/parser.js index 54e9605dafd..4126b1ca5ee 100644 --- a/packages/react-native-codegen/src/parsers/parser.js +++ b/packages/react-native-codegen/src/parsers/parser.js @@ -169,4 +169,9 @@ export interface Parser { typeAnnotation: $FlowFixMe, types: TypeDeclarationMap, ): $FlowFixMe; + + /** + * Given the AST, returns the TypeDeclarationMap + */ + getTypes(ast: $FlowFixMe): TypeDeclarationMap; } diff --git a/packages/react-native-codegen/src/parsers/parserMock.js b/packages/react-native-codegen/src/parsers/parserMock.js index 75874a0b85e..b0e6545b2a0 100644 --- a/packages/react-native-codegen/src/parsers/parserMock.js +++ b/packages/react-native-codegen/src/parsers/parserMock.js @@ -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 {}; + } } diff --git a/packages/react-native-codegen/src/parsers/parsers-commons.js b/packages/react-native-codegen/src/parsers/parsers-commons.js index 0a674eb85f4..4c633eb07b9 100644 --- a/packages/react-native-codegen/src/parsers/parsers-commons.js +++ b/packages/react-native-codegen/src/parsers/parsers-commons.js @@ -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, diff --git a/packages/react-native-codegen/src/parsers/typescript/components/index.js b/packages/react-native-codegen/src/parsers/typescript/components/index.js index 41b5c0e41c2..2adaddeceeb 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/index.js @@ -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); diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index 5a511b51a31..a37dd4cbbca 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -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), ); diff --git a/packages/react-native-codegen/src/parsers/typescript/parser.js b/packages/react-native-codegen/src/parsers/typescript/parser.js index b050c9a87ac..3a6cca42664 100644 --- a/packages/react-native-codegen/src/parsers/typescript/parser.js +++ b/packages/react-native-codegen/src/parsers/typescript/parser.js @@ -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, diff --git a/packages/react-native-codegen/src/parsers/typescript/utils.js b/packages/react-native-codegen/src/parsers/typescript/utils.js index ae72b030f64..ffb7145d620 100644 --- a/packages/react-native-codegen/src/parsers/typescript/utils.js +++ b/packages/react-native-codegen/src/parsers/typescript/utils.js @@ -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, };