Enrich getCommandProperties with the parser object (#36500)

Summary:
> [Codegen 101] The code of getCommandProperties is almost identical in [Flow](https://github.com/facebook/react-native/blob/main/packages/react-native-codegen/src/parsers/flow/components/index.js#L128) and [TS](https://github.com/facebook/react-native/blob/main/packages/react-native-codegen/src/parsers/typescript/components/index.js#L129). There are small differences between flow/ts, so we need for it to accept a Parser object. Enrich the parser object with the required methods if necessary.

## Changelog:

[Internal] [Changed] - Enrich getCommandProperties with the parser object

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

Test Plan: `yarn test react-native-codegen`

Reviewed By: cortinico

Differential Revision: D44415265

Pulled By: cipolleschi

fbshipit-source-id: ed13b553a6f782beb0f1aec79bd17d865a96fac9
This commit is contained in:
Kyaw Thura
2023-03-29 09:28:00 -07:00
committed by Facebook GitHub Bot
parent 3ac7a5ef4e
commit 969a8d0799
8 changed files with 82 additions and 59 deletions
@@ -21,6 +21,7 @@ import {
buildSchema,
parseModuleName,
createComponentConfig,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
@@ -1536,4 +1537,23 @@ describe('getCommandTypeNameAndOptionsExpression', () => {
commandOptionsExpression,
});
});
describe('propertyNames', () => {
it('returns propertyNames with valid properties', () => {
const properties = [
{key: {name: 'testName'}},
{key: {name: 'testName2'}},
];
const expected = ['testName', 'testName2'];
expect(propertyNames(properties)).toEqual(expected);
});
it('returns empty propertyNames with incorrect properties', () => {
const properties = [
{key: {invalid: 'testName'}},
{key: {invalid: 'testName2'}},
];
expect(propertyNames(properties)).toEqual([]);
});
});
});
@@ -10,8 +10,6 @@
'use strict';
import type {Parser} from '../../parser';
import type {TypeDeclarationMap} from '../../utils';
import type {CommandOptions} from '../../parsers-commons';
import type {ComponentSchemaBuilderConfig} from '../../schema.js';
const {getCommands} = require('./commands');
@@ -23,6 +21,7 @@ const {throwIfMoreThanOneCodegenNativecommands} = require('../../error-utils');
const {
createComponentConfig,
findNativeComponentType,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
@@ -62,16 +61,16 @@ function findComponentConfig(ast: $FlowFixMe, parser: Parser) {
return createComponentConfig(foundConfig, commandsTypeNames);
}
function getCommandProperties(
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
* LTI update could not be added via codemod */
commandTypeName,
types: TypeDeclarationMap,
commandOptions: ?CommandOptions,
) {
function getCommandProperties(ast: $FlowFixMe, parser: Parser) {
const {commandTypeName, commandOptionsExpression} = findComponentConfig(
ast,
parser,
);
if (commandTypeName == null) {
return [];
}
const types = parser.getTypes(ast);
const typeAlias = types[commandTypeName];
@@ -81,18 +80,16 @@ function getCommandProperties(
);
}
let properties;
try {
properties = typeAlias.body.properties;
} catch (e) {
const properties = parser.bodyProperties(typeAlias);
if (!properties) {
throw new Error(
`Failed to find type definition for "${commandTypeName}", please check that you have a valid codegen flow file`,
);
}
const flowPropertyNames = properties
.map(property => property && property.key && property.key.name)
.filter(Boolean);
const flowPropertyNames = propertyNames(properties);
const commandOptions = getCommandOptions(commandOptionsExpression);
if (commandOptions == null || commandOptions.supportedCommands == null) {
throw new Error(
@@ -121,24 +118,16 @@ function buildComponentSchema(
ast: $FlowFixMe,
parser: Parser,
): ComponentSchemaBuilderConfig {
const {
componentName,
propsTypeName,
commandTypeName,
commandOptionsExpression,
optionsExpression,
} = findComponentConfig(ast, parser);
const {componentName, propsTypeName, optionsExpression} = findComponentConfig(
ast,
parser,
);
const types = parser.getTypes(ast);
const propProperties = getProperties(propsTypeName, types);
const commandOptions = getCommandOptions(commandOptionsExpression);
const commandProperties = getCommandProperties(
commandTypeName,
types,
commandOptions,
);
const commandProperties = getCommandProperties(ast, parser);
const extendsProps = getExtendsProps(propProperties, types);
const options = getOptions(optionsExpression);
@@ -321,6 +321,10 @@ class FlowParser implements Parser {
getAnnotatedElementProperties(annotatedElement: $FlowFixMe): $FlowFixMe {
return annotatedElement.right.properties;
}
bodyProperties(typeAlias: $FlowFixMe): $ReadOnlyArray<$FlowFixMe> {
return typeAlias.body.properties;
}
}
module.exports = {
+7
View File
@@ -241,4 +241,11 @@ export interface Parser {
* @returns: the properties of annotated element.
*/
getAnnotatedElementProperties(annotatedElement: $FlowFixMe): $FlowFixMe;
/**
* Given a typeAlias, it returns an array of properties.
* @parameter typeAlias: the type alias.
* @returns: an array of properties.
*/
bodyProperties(typeAlias: $FlowFixMe): $ReadOnlyArray<$FlowFixMe>;
}
@@ -235,4 +235,8 @@ export class MockedParser implements Parser {
getAnnotatedElementProperties(annotatedElement: $FlowFixMe): $FlowFixMe {
return annotatedElement.right.properties;
}
bodyProperties(typeAlias: $FlowFixMe): $ReadOnlyArray<$FlowFixMe> {
return typeAlias.body.properties;
}
}
@@ -765,7 +765,6 @@ function getOptions(optionsExpression: OptionsAST): ?OptionsShape {
'Failed to parse codegen options, cannot use both paperComponentName and paperComponentNameDeprecated',
);
}
return foundOptions;
}
@@ -810,6 +809,14 @@ function getCommandTypeNameAndOptionsExpression(
};
}
function propertyNames(
properties: $ReadOnlyArray<$FlowFixMe>,
): $ReadOnlyArray<$FlowFixMe> {
return properties
.map(property => property && property.key && property.key.name)
.filter(Boolean);
}
module.exports = {
wrapModuleSchema,
unwrapNullable,
@@ -825,6 +832,7 @@ module.exports = {
parseModuleName,
buildModuleSchema,
findNativeComponentType,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
@@ -11,8 +11,6 @@
'use strict';
import type {ExtendsPropsShape} from '../../../CodegenSchema.js';
import type {Parser} from '../../parser';
import type {TypeDeclarationMap} from '../../utils';
import type {CommandOptions} from '../../parsers-commons';
import type {ComponentSchemaBuilderConfig} from '../../schema.js';
const {getCommands} = require('./commands');
@@ -24,6 +22,7 @@ const {throwIfMoreThanOneCodegenNativecommands} = require('../../error-utils');
const {
createComponentConfig,
findNativeComponentType,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
@@ -63,17 +62,16 @@ function findComponentConfig(ast: $FlowFixMe, parser: Parser) {
return createComponentConfig(foundConfig, commandsTypeNames);
}
function getCommandProperties(
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
* LTI update could not be added via codemod */
commandTypeName,
types: TypeDeclarationMap,
commandOptions: ?CommandOptions,
) {
function getCommandProperties(ast: $FlowFixMe, parser: Parser) {
const {commandTypeName, commandOptionsExpression} = findComponentConfig(
ast,
parser,
);
if (commandTypeName == null) {
return [];
}
const types = parser.getTypes(ast);
const typeAlias = types[commandTypeName];
if (typeAlias.type !== 'TSInterfaceDeclaration') {
@@ -82,19 +80,16 @@ function getCommandProperties(
);
}
let properties;
try {
properties = typeAlias.body.body;
} catch (e) {
const properties = parser.bodyProperties(typeAlias);
if (!properties) {
throw new Error(
`Failed to find type definition for "${commandTypeName}", please check that you have a valid codegen typescript file`,
);
}
const typeScriptPropertyNames = properties
.map(property => property && property.key && property.key.name)
.filter(Boolean);
const typeScriptPropertyNames = propertyNames(properties);
const commandOptions = getCommandOptions(commandOptionsExpression);
if (commandOptions == null || commandOptions.supportedCommands == null) {
throw new Error(
'codegenNativeCommands must be given an options object with supportedCommands array',
@@ -126,24 +121,16 @@ function buildComponentSchema(
ast: $FlowFixMe,
parser: Parser,
): ComponentSchemaBuilderConfig {
const {
componentName,
propsTypeName,
commandTypeName,
commandOptionsExpression,
optionsExpression,
} = findComponentConfig(ast, parser);
const {componentName, propsTypeName, optionsExpression} = findComponentConfig(
ast,
parser,
);
const types = parser.getTypes(ast);
const propProperties = getProperties(propsTypeName, types);
const commandOptions = getCommandOptions(commandOptionsExpression);
const commandProperties = getCommandProperties(
commandTypeName,
types,
commandOptions,
);
const commandProperties = getCommandProperties(ast, parser);
const options = getOptions(optionsExpression);
@@ -307,6 +307,10 @@ class TypeScriptParser implements Parser {
getAnnotatedElementProperties(annotatedElement: $FlowFixMe): $FlowFixMe {
return annotatedElement.typeAnnotation.members;
}
bodyProperties(typeAlias: TypeDeclarationMap): $ReadOnlyArray<$FlowFixMe> {
return typeAlias.body.body;
}
}
module.exports = {