Skip to content

Commit

Permalink
Support spreading locally defined types
Browse files Browse the repository at this point in the history
Summary: We want to be able to spread types that are defined in the same file.

Reviewed By: JoshuaGross

Differential Revision: D16812171

fbshipit-source-id: 7cda9869ea25f0357b3f8a3b28443407b219f04b
  • Loading branch information
elicwhite authored and facebook-github-bot committed Aug 14, 2019
1 parent a02176e commit 0a39674
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,39 @@ export default (codegenNativeComponent<ModuleProps>(
): NativeComponent<ModuleProps>);
`;

const PROPS_ALIASED_LOCALLY = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
import type {ViewProps} from 'ViewPropTypes';
import type {NativeComponent} from 'codegenNativeComponent';
const codegenNativeComponent = require('codegenNativeComponent');
export type PropsInFile = $ReadOnly<{|
isEnabled: boolean,
|}>;
export type ModuleProps = $ReadOnly<{|
...ViewProps,
...PropsInFile
|}>;
export default (codegenNativeComponent<ModuleProps>(
'Module',
): NativeComponent<ModuleProps>);
`;

const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = `
/**
* Copyright (c) Facebook, Inc. and its affiliates.
Expand Down Expand Up @@ -807,6 +840,7 @@ module.exports = {
ALL_PROP_TYPES_NO_EVENTS,
ARRAY_PROP_TYPES_NO_EVENTS,
OBJECT_PROP_TYPES_NO_EVENTS,
PROPS_ALIASED_LOCALLY,
ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS,
ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS_NO_CAST,
NO_PROPS_EVENTS_ONLY_DEPRECATED_VIEW_CONFIG_NAME_OPTION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4903,6 +4903,37 @@ Object {
}
`;

exports[`RN Codegen Flow Parser can generate fixture PROPS_ALIASED_LOCALLY 1`] = `
Object {
"modules": Object {
"Module": Object {
"components": Object {
"Module": Object {
"commands": Array [],
"events": Array [],
"extendsProps": Array [
Object {
"knownTypeName": "ReactNativeCoreViewProps",
"type": "ReactNativeBuiltInType",
},
],
"props": Array [
Object {
"name": "isEnabled",
"optional": false,
"typeAnnotation": Object {
"default": false,
"type": "BooleanTypeAnnotation",
},
},
],
},
},
},
},
}
`;

exports[`RN Codegen Flow Parser can generate fixture PROPS_AND_EVENTS_TYPES_EXPORTED 1`] = `
Object {
"modules": Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,19 @@
'use strict';

import type {ExtendsPropsShape} from '../../../CodegenSchema.js';
import type {TypeMap} from '../utils.js';

function extendsForProp(prop) {
function extendsForProp(prop: PropsAST, types: TypeMap) {
if (!prop.argument) {
console.log('null', prop);
}
const name = prop.argument.id.name;

if (types[name] != null) {
// This type is locally defined in the file
return null;
}

switch (name) {
case 'ViewProps':
return {
Expand All @@ -26,17 +36,31 @@ function extendsForProp(prop) {
}
}

function removeKnownExtends(
typeDefinition: $ReadOnlyArray<PropsAST>,
types: TypeMap,
): $ReadOnlyArray<PropsAST> {
return typeDefinition.filter(
prop =>
prop.type !== 'ObjectTypeSpreadProperty' ||
extendsForProp(prop, types) === null,
);
}

// $FlowFixMe there's no flowtype for ASTs
type PropsAST = Object;

function getExtendsProps(
typeDefinition: $ReadOnlyArray<PropsAST>,
types: TypeMap,
): $ReadOnlyArray<ExtendsPropsShape> {
return typeDefinition
.filter(prop => prop.type === 'ObjectTypeSpreadProperty')
.map(extendsForProp);
.map(prop => extendsForProp(prop, types))
.filter(Boolean);
}

module.exports = {
getExtendsProps,
removeKnownExtends,
};
20 changes: 5 additions & 15 deletions packages/react-native-codegen/src/parsers/flow/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
import type {ComponentSchemaBuilderConfig} from './schema.js';
const {getCommands} = require('./commands');
const {getEvents} = require('./events');
const {getProps} = require('./props');
const {getProps, getPropProperties} = require('./props');
const {getCommandOptions, getOptions} = require('./options');
const {getExtendsProps} = require('./extends');
const {getExtendsProps, removeKnownExtends} = require('./extends');

function findComponentConfig(ast) {
const foundConfigs = [];
Expand Down Expand Up @@ -118,17 +118,6 @@ function findComponentConfig(ast) {
};
}

function getPropProperties(propsTypeName, types) {
const typeAlias = types[propsTypeName];
try {
return typeAlias.right.typeParameters.params[0].properties;
} catch (e) {
throw new Error(
`Failed to find type definition for "${propsTypeName}", please check that you have a valid codegen flow file`,
);
}
}

function getCommandProperties(commandTypeName, types, commandOptions) {
if (commandTypeName == null) {
return [];
Expand Down Expand Up @@ -198,10 +187,11 @@ function processComponent(ast, types): ComponentSchemaBuilderConfig {
commandOptions,
);

const extendsProps = getExtendsProps(propProperties);
const extendsProps = getExtendsProps(propProperties, types);
const options = getOptions(optionsExpression);

const props = getProps(propProperties, types);
const nonExtendsProps = removeKnownExtends(propProperties, types);
const props = getProps(nonExtendsProps, types);
const events = getEvents(propProperties, types);
const commands = getCommands(commandProperties, types);

Expand Down
32 changes: 30 additions & 2 deletions packages/react-native-codegen/src/parsers/flow/components/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ import type {TypeMap} from '../utils.js';

const {getValueFromTypes} = require('../utils.js');

function getPropProperties(propsTypeName: string, types: TypeMap) {
const typeAlias = types[propsTypeName];
try {
return typeAlias.right.typeParameters.params[0].properties;
} catch (e) {
throw new Error(
`Failed to find type definition for "${propsTypeName}", please check that you have a valid codegen flow file`,
);
}
}

function getTypeAnnotationForArray(name, typeAnnotation, defaultValue, types) {
const extractedTypeAnnotation = getValueFromTypes(typeAnnotation, types);
if (extractedTypeAnnotation.type === 'NullableTypeAnnotation') {
Expand Down Expand Up @@ -293,11 +304,28 @@ function getProps(
types: TypeMap,
): $ReadOnlyArray<PropTypeShape> {
return typeDefinition
.filter(property => property.type === 'ObjectTypeProperty')
.map(property => buildPropSchema(property, types))
.map(property => {
if (property.type === 'ObjectTypeProperty') {
return buildPropSchema(property, types);
} else if (property.type === 'ObjectTypeSpreadProperty') {
return getProps(
getPropProperties(property.argument.id.name, types),
types[property.argument.id.name],
);
}
})
.reduce((acc, item) => {
if (Array.isArray(item)) {
return acc.concat(item);
} else {
acc.push(item);
return acc;
}
}, [])
.filter(Boolean);
}

module.exports = {
getProps,
getPropProperties,
};

0 comments on commit 0a39674

Please sign in to comment.