Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
buildSchema,
parseModuleName,
createComponentConfig,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
Expand Down Expand Up @@ -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([]);
});
});
});
47 changes: 18 additions & 29 deletions packages/react-native-codegen/src/parsers/flow/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -23,6 +21,7 @@ const {throwIfMoreThanOneCodegenNativecommands} = require('../../error-utils');
const {
createComponentConfig,
findNativeComponentType,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
Expand Down Expand Up @@ -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];

Expand All @@ -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(
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native-codegen/src/parsers/flow/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
7 changes: 7 additions & 0 deletions packages/react-native-codegen/src/parsers/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
}
4 changes: 4 additions & 0 deletions packages/react-native-codegen/src/parsers/parserMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
10 changes: 9 additions & 1 deletion packages/react-native-codegen/src/parsers/parsers-commons.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@ function getOptions(optionsExpression: OptionsAST): ?OptionsShape {
'Failed to parse codegen options, cannot use both paperComponentName and paperComponentNameDeprecated',
);
}

return foundOptions;
}

Expand Down Expand Up @@ -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,
Expand All @@ -825,6 +832,7 @@ module.exports = {
parseModuleName,
buildModuleSchema,
findNativeComponentType,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -24,6 +22,7 @@ const {throwIfMoreThanOneCodegenNativecommands} = require('../../error-utils');
const {
createComponentConfig,
findNativeComponentType,
propertyNames,
getCommandOptions,
getOptions,
getCommandTypeNameAndOptionsExpression,
Expand Down Expand Up @@ -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') {
Expand All @@ -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',
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down