From ebb8caa4df2b6559ae9ed7cc532c7ff5a6c17e8d Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 3 Jun 2019 07:15:13 -0700 Subject: [PATCH] Add handling for ColorArray Summary: This diff adds support for ColorArrayValue in the flow parser Reviewed By: cpojer Differential Revision: D15502923 fbshipit-source-id: 6a906b6d609168378fabeb49d0080de011a34d78 --- .../getNativeComponentAttributes.js | 5 +- Libraries/StyleSheet/StyleSheetTypes.js | 1 + Libraries/StyleSheet/processColorArray.js | 19 ++ .../src/generators/GenerateViewConfigJs.js | 168 ++++++++++-------- .../GenerateViewConfigJs-test.js.snap | 2 +- .../flow/__test_fixtures__/fixtures.js | 8 +- .../__snapshots__/parser-test.js.snap | 44 +++++ .../src/parsers/flow/props.js | 8 + 8 files changed, 176 insertions(+), 79 deletions(-) create mode 100644 Libraries/StyleSheet/processColorArray.js diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 85a347bea1f..9dba82c4750 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -17,6 +17,7 @@ const insetsDiffer = require('../Utilities/differ/insetsDiffer'); const matricesDiffer = require('../Utilities/differ/matricesDiffer'); const pointsDiffer = require('../Utilities/differ/pointsDiffer'); const processColor = require('../StyleSheet/processColor'); +const processColorArray = require('../StyleSheet/processColorArray'); const resolveAssetSource = require('../Image/resolveAssetSource'); const sizesDiffer = require('../Utilities/differ/sizesDiffer'); const invariant = require('invariant'); @@ -182,8 +183,4 @@ function getProcessorForType(typeName: string): ?(nextProp: any) => any { return null; } -function processColorArray(colors: ?Array): ?Array { - return colors == null ? null : colors.map(processColor); -} - module.exports = getNativeComponentAttributes; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 39819d5e6b4..9da10526c23 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -13,6 +13,7 @@ const AnimatedNode = require('../Animated/src/nodes/AnimatedNode'); export type ColorValue = null | string; +export type ColorArrayValue = null | $ReadOnlyArray; export type PointValue = {| x: number, y: number, diff --git a/Libraries/StyleSheet/processColorArray.js b/Libraries/StyleSheet/processColorArray.js new file mode 100644 index 00000000000..711dc32aee5 --- /dev/null +++ b/Libraries/StyleSheet/processColorArray.js @@ -0,0 +1,19 @@ +/** + * 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 strict-local + */ + +'use strict'; + +const processColor = require('./processColor'); + +function processColorArray(colors: ?Array): ?Array { + return colors == null ? null : colors.map(processColor); +} + +module.exports = processColorArray; diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index 3315d1a29d1..d5e1583ea2b 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -34,15 +34,12 @@ const template = ` ::_COMPONENT_CONFIG_:: `; -function getReactDiffProcessValue(prop) { - const typeAnnotation = prop.typeAnnotation; - +function getReactDiffProcessValue(typeAnnotation) { switch (typeAnnotation.type) { case 'BooleanTypeAnnotation': case 'StringTypeAnnotation': case 'Int32TypeAnnotation': case 'FloatTypeAnnotation': - case 'ArrayTypeAnnotation': case 'StringEnumTypeAnnotation': return j.literal(true); case 'NativePrimitiveTypeAnnotation': @@ -60,6 +57,25 @@ function getReactDiffProcessValue(prop) { `Received unknown native typeAnnotation: "${typeAnnotation.name}"`, ); } + case 'ArrayTypeAnnotation': + if (typeAnnotation.elementType.type === 'NativePrimitiveTypeAnnotation') { + switch (typeAnnotation.elementType.name) { + case 'ColorPrimitive': + return j.template + .expression`{ process: require('processColorArray') }`; + case 'ImageSourcePrimitive': + return j.literal(true); + case 'PointPrimitive': + return j.literal(true); + default: + throw new Error( + `Received unknown array native typeAnnotation: "${ + typeAnnotation.elementType.name + }"`, + ); + } + } + return j.literal(true); default: (typeAnnotation: empty); throw new Error( @@ -194,7 +210,7 @@ function buildViewConfig( return j.property( 'init', j.identifier(schemaProp.name), - getReactDiffProcessValue(schemaProp), + getReactDiffProcessValue(schemaProp.typeAnnotation), ); }), ...getValidAttributesForEvents(componentEvents), @@ -253,76 +269,82 @@ function buildViewConfig( module.exports = { generate(libraryName: string, schema: SchemaType): FilesOutput { - const fileName = `${libraryName}NativeViewConfig.js`; - const imports: Set = new Set(); + try { + const fileName = `${libraryName}NativeViewConfig.js`; + const imports: Set = new Set(); - imports.add( - "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", - ); - imports.add( - "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", - ); - - const moduleResults = Object.keys(schema.modules) - .map(moduleName => { - const components = schema.modules[moduleName].components; - // No components in this module - if (components == null) { - return null; - } - - return Object.keys(components) - .map(componentName => { - const component = components[componentName]; - - const compatabilityComponentName = `${ - component.isDeprecatedPaperComponentNameRCT ? 'RCT' : '' - }${componentName}`; - - const replacedTemplate = componentTemplate - .replace(/::_COMPONENT_NAME_::/g, componentName) - .replace( - /::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::/g, - compatabilityComponentName, - ) - .replace( - /::_COMPAT_COMMENT_::/g, - component.isDeprecatedPaperComponentNameRCT - ? ' // RCT prefix present for paper support' - : '', - ); - - const replacedSource: string = j - .withParser('flow')(replacedTemplate) - .find(j.Identifier, { - name: 'VIEW_CONFIG', - }) - .replaceWith( - buildViewConfig( - schema, - compatabilityComponentName, - component, - imports, - ), - ) - .toSource({quote: 'single', trailingComma: true}); - - return replacedSource; - }) - .join('\n\n'); - }) - .filter(Boolean) - .join('\n\n'); - - const replacedTemplate = template - .replace(/::_COMPONENT_CONFIG_::/g, moduleResults) - .replace( - '::_IMPORTS_::', - Array.from(imports) - .sort() - .join('\n'), + imports.add( + "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", + ); + imports.add( + "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", ); - return new Map([[fileName, replacedTemplate]]); + const moduleResults = Object.keys(schema.modules) + .map(moduleName => { + const components = schema.modules[moduleName].components; + // No components in this module + if (components == null) { + return null; + } + + return Object.keys(components) + .map(componentName => { + const component = components[componentName]; + + const compatabilityComponentName = `${ + component.isDeprecatedPaperComponentNameRCT ? 'RCT' : '' + }${componentName}`; + + const replacedTemplate = componentTemplate + .replace(/::_COMPONENT_NAME_::/g, componentName) + .replace( + /::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::/g, + compatabilityComponentName, + ) + .replace( + /::_COMPAT_COMMENT_::/g, + component.isDeprecatedPaperComponentNameRCT + ? ' // RCT prefix present for paper support' + : '', + ); + + const replacedSource: string = j + .withParser('flow')(replacedTemplate) + .find(j.Identifier, { + name: 'VIEW_CONFIG', + }) + .replaceWith( + buildViewConfig( + schema, + compatabilityComponentName, + component, + imports, + ), + ) + .toSource({quote: 'single', trailingComma: true}); + + return replacedSource; + }) + .join('\n\n'); + }) + .filter(Boolean) + .join('\n\n'); + + const replacedTemplate = template + .replace(/::_COMPONENT_CONFIG_::/g, moduleResults) + .replace( + '::_IMPORTS_::', + Array.from(imports) + .sort() + .join('\n'), + ); + + return new Map([[fileName, replacedTemplate]]); + } catch (error) { + console.error(`\nError parsing schema for ${libraryName}\n`); + console.error(JSON.stringify(schema)); + throw error; + } }, }; diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 8e7ec6e5fb5..729bfac1050 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -36,7 +36,7 @@ const ArrayPropsNativeComponentViewConfig = { disableds: true, progress: true, radii: true, - colors: true, + colors: { process: require('processColorArray') }, srcs: true, points: true, }, diff --git a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js index 5fbef12ed35..d971d6dba4e 100644 --- a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js @@ -122,7 +122,7 @@ import type { CodegenNativeComponent, } from 'CodegenFlowtypes'; -import type {ColorValue, PointValue} from 'StyleSheetTypes'; +import type {ColorValue, ColorArrayValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; import type {ViewProps} from 'ViewPropTypes'; @@ -171,6 +171,12 @@ type ModuleProps = $ReadOnly<{| color_optional_value: ?ColorValue, color_optional_both?: ?ColorValue, + // ColorArrayValue props + color_array_required: ColorArrayValue, + color_array_optional_key?: ColorArrayValue, + color_array_optional_value: ?ColorArrayValue, + color_array_optional_both?: ?ColorArrayValue, + // PointValue props point_required: PointValue, point_optional_key?: PointValue, diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap index 527f9edd44c..8feeb11c71c 100644 --- a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap @@ -262,6 +262,50 @@ Object { "type": "NativePrimitiveTypeAnnotation", }, }, + Object { + "name": "color_array_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, Object { "name": "point_required", "optional": false, diff --git a/packages/react-native-codegen/src/parsers/flow/props.js b/packages/react-native-codegen/src/parsers/flow/props.js index e7d5e16d7da..222b2ca014b 100644 --- a/packages/react-native-codegen/src/parsers/flow/props.js +++ b/packages/react-native-codegen/src/parsers/flow/props.js @@ -105,6 +105,14 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { type: 'NativePrimitiveTypeAnnotation', name: 'ColorPrimitive', }; + case 'ColorArrayValue': + return { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive', + }, + }; case 'PointValue': return { type: 'NativePrimitiveTypeAnnotation',