diff --git a/packages/react-native-codegen/src/parsers/typescript/components/extends.js b/packages/react-native-codegen/src/parsers/typescript/components/extends.js index 1d4d006f5d7c..fa0ed221a957 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/extends.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/extends.js @@ -10,33 +10,8 @@ 'use strict'; -import type {ExtendsPropsShape} from '../../../CodegenSchema.js'; import type {TypeDeclarationMap} from '../../utils'; const {parseTopLevelType} = require('../parseTopLevelType'); -const {flattenProperties} = require('./componentsUtils.js'); - -function extendsForProp(prop: PropsAST, types: TypeDeclarationMap) { - if (!prop.expression) { - console.log('null', prop); - } - const name = prop.expression.name; - - if (types[name] != null) { - // This type is locally defined in the file - return null; - } - - switch (name) { - case 'ViewProps': - return { - type: 'ReactNativeBuiltInType', - knownTypeName: 'ReactNativeCoreViewProps', - }; - default: { - throw new Error(`Unable to handle prop spread: ${name}`); - } - } -} function isEvent(typeAnnotation: $FlowFixMe): boolean { if (typeAnnotation.type !== 'TSTypeReference') { @@ -46,43 +21,16 @@ function isEvent(typeAnnotation: $FlowFixMe): boolean { return eventNames.has(typeAnnotation.typeName.name); } -function isProp(name: string, typeAnnotation: $FlowFixMe): boolean { - if (typeAnnotation.type !== 'TSTypeReference') { - return true; - } - const isStyle = - name === 'style' && - typeAnnotation.type === 'GenericTypeAnnotation' && - typeAnnotation.typeName.name === 'ViewStyleProp'; - return !isStyle; -} - // $FlowFixMe[unclear-type] TODO(T108222691): Use flow-types for @babel/parser type PropsAST = Object; function categorizeProps( typeDefinition: $ReadOnlyArray, types: TypeDeclarationMap, - extendsProps: Array, - props: Array, events: Array, ): void { - const remaining: Array = []; + // find events for (const prop of typeDefinition) { - // find extends - if (prop.type === 'TSExpressionWithTypeArguments') { - const extend = extendsForProp(prop, types); - if (extend) { - extendsProps.push(extend); - continue; - } - } - - remaining.push(prop); - } - - // find events and props - for (const prop of flattenProperties(remaining, types)) { if (prop.type === 'TSPropertySignature') { const topLevelType = parseTopLevelType( prop.typeAnnotation.typeAnnotation, @@ -91,8 +39,6 @@ function categorizeProps( if (isEvent(topLevelType.type)) { events.push(prop); - } else if (isProp(prop.key.name, prop)) { - props.push(prop); } } } 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 4ebca03d6635..a42fd058cf9a 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/index.js @@ -9,7 +9,6 @@ */ 'use strict'; -import type {ExtendsPropsShape} from '../../../CodegenSchema.js'; import type {Parser} from '../../parser'; import type {ComponentSchemaBuilderConfig} from '../../schema.js'; @@ -134,17 +133,9 @@ function buildComponentSchema( const options = getOptions(optionsExpression); - const extendsProps: Array = []; - const componentPropAsts: Array = []; const componentEventAsts: Array = []; - categorizeProps( - propProperties, - types, - extendsProps, - componentPropAsts, - componentEventAsts, - ); - const props = getProps(componentPropAsts, types); + categorizeProps(propProperties, types, componentEventAsts); + const {props, extendsProps} = getProps(propProperties, types); const events = getEvents(componentEventAsts, types); const commands = getCommands(commandProperties, types); diff --git a/packages/react-native-codegen/src/parsers/typescript/components/props.js b/packages/react-native-codegen/src/parsers/typescript/components/props.js index c7a1d3b04e65..36bb16c6eeef 100644 --- a/packages/react-native-codegen/src/parsers/typescript/components/props.js +++ b/packages/react-native-codegen/src/parsers/typescript/components/props.js @@ -13,6 +13,10 @@ const {getSchemaInfo, getTypeAnnotation} = require('./componentsUtils.js'); import type {NamedShape, PropTypeAnnotation} from '../../../CodegenSchema.js'; import type {TypeDeclarationMap} from '../../utils'; +import type {ExtendsPropsShape} from '../../../CodegenSchema.js'; + +const {flattenProperties} = require('./componentsUtils.js'); +const {parseTopLevelType} = require('../parseTopLevelType'); // $FlowFixMe[unclear-type] there's no flowtype for ASTs type PropAST = Object; @@ -36,11 +40,92 @@ function buildPropSchema( }; } +function isEvent(typeAnnotation: $FlowFixMe): boolean { + if (typeAnnotation.type !== 'TSTypeReference') { + return false; + } + const eventNames = new Set(['BubblingEventHandler', 'DirectEventHandler']); + return eventNames.has(typeAnnotation.typeName.name); +} + +function isProp(name: string, typeAnnotation: $FlowFixMe): boolean { + if (typeAnnotation.type !== 'TSTypeReference') { + return true; + } + const isStyle = + name === 'style' && + typeAnnotation.type === 'GenericTypeAnnotation' && + typeAnnotation.typeName.name === 'ViewStyleProp'; + return !isStyle; +} + +function extendsForProp(prop: PropAST, types: TypeDeclarationMap) { + if (!prop.expression) { + console.log('null', prop); + } + const name = prop.expression.name; + + if (types[name] != null) { + // This type is locally defined in the file + return null; + } + + switch (name) { + case 'ViewProps': + return { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', + }; + default: { + throw new Error(`Unable to handle prop spread: ${name}`); + } + } +} + function getProps( typeDefinition: $ReadOnlyArray, types: TypeDeclarationMap, -): $ReadOnlyArray> { - return typeDefinition.map(property => buildPropSchema(property, types)); +): { + props: $ReadOnlyArray>, + extendsProps: $ReadOnlyArray, +} { + const extendsProps: Array = []; + const componentPropAsts: Array = []; + const remaining: Array = []; + + for (const prop of typeDefinition) { + // find extends + if (prop.type === 'TSExpressionWithTypeArguments') { + const extend = extendsForProp(prop, types); + if (extend) { + extendsProps.push(extend); + continue; + } + } + + remaining.push(prop); + } + + // find events and props + for (const prop of flattenProperties(remaining, types)) { + const topLevelType = parseTopLevelType( + prop.typeAnnotation.typeAnnotation, + types, + ); + + if ( + prop.type === 'TSPropertySignature' && + !isEvent(topLevelType.type) && + isProp(prop.key.name, prop) + ) { + componentPropAsts.push(prop); + } + } + + return { + props: componentPropAsts.map(property => buildPropSchema(property, types)), + extendsProps, + }; } module.exports = {