diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js index c814c352948..dca85562f76 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js @@ -432,6 +432,151 @@ export default (codegenNativeComponent( ): NativeComponent); `; +const PROP_MIXED_ENUM = ` +/** + * 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 ModuleProps = $ReadOnly<{| + ...ViewProps, + + someProp?: WithDefault<'foo' | 1, 1> +|}>; + +export default (codegenNativeComponent( + 'Module', +): NativeComponent); +`; + +const PROP_ENUM_BOOLEAN = ` +/** + * 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 ModuleProps = $ReadOnly<{| + ...ViewProps, + + someProp?: WithDefault +|}>; + +export default (codegenNativeComponent( + 'Module', +): NativeComponent); +`; + +const PROP_ARRAY_MIXED_ENUM = ` +/** + * 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 ModuleProps = $ReadOnly<{| + ...ViewProps, + + someProp?: WithDefault<$ReadOnlyArray<'foo' | 1>, 1> +|}>; + +export default (codegenNativeComponent( + 'Module', +): NativeComponent); +`; + +const PROP_ARRAY_ENUM_BOOLEAN = ` +/** + * 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 ModuleProps = $ReadOnly<{| + ...ViewProps, + + someProp?: WithDefault<$ReadOnlyArray, false> +|}>; + +export default (codegenNativeComponent( + 'Module', +): NativeComponent); +`; + +const PROP_ARRAY_ENUM_INT = ` +/** + * 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 ModuleProps = $ReadOnly<{| + ...ViewProps, + + someProp?: WithDefault<$ReadOnlyArray<0 | 1>, 0> +|}>; + +export default (codegenNativeComponent( + 'Module', +): NativeComponent); +`; + module.exports = { COMMANDS_DEFINED_INLINE, COMMANDS_DEFINED_MULTIPLE_TIMES, @@ -445,4 +590,9 @@ module.exports = { PROPS_CONFLICT_WITH_SPREAD_PROPS, PROPS_SPREAD_CONFLICTS_WITH_PROPS, PROP_NUMBER_TYPE, + PROP_MIXED_ENUM, + PROP_ENUM_BOOLEAN, + PROP_ARRAY_MIXED_ENUM, + PROP_ARRAY_ENUM_BOOLEAN, + PROP_ARRAY_ENUM_INT, }; diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js index 01de8d9ac97..0f474255698 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js @@ -242,6 +242,9 @@ type ModuleProps = $ReadOnly<{| enum_optional_key?: WithDefault<'small' | 'large', 'small'>, enum_optional_both?: WithDefault<'small' | 'large', 'small'>, + // Int enum props + int_enum_optional_key?: WithDefault<0 | 1, 0>, + // Object props object_optional_key?: $ReadOnly<{| prop: string |}>, object_optional_both?: ?$ReadOnly<{| prop: string |}>, diff --git a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap index db7d5026afa..dc76406266f 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap @@ -16,6 +16,16 @@ exports[`RN Codegen Flow Parser Fails with error message NON_OPTIONAL_KEY_WITH_D exports[`RN Codegen Flow Parser Fails with error message NULLABLE_WITH_DEFAULT 1`] = `"WithDefault<> is optional and does not need to be marked as optional. Please remove the ? annotation in front of it."`; +exports[`RN Codegen Flow Parser Fails with error message PROP_ARRAY_ENUM_BOOLEAN 1`] = `"Unsupported union type for \\"someProp\\", recieved \\"BooleanLiteralTypeAnnotation\\""`; + +exports[`RN Codegen Flow Parser Fails with error message PROP_ARRAY_ENUM_INT 1`] = `"Arrays of int enums are not supported (see: \\"someProp\\")"`; + +exports[`RN Codegen Flow Parser Fails with error message PROP_ARRAY_MIXED_ENUM 1`] = `"Mixed types are not supported (see \\"someProp\\")"`; + +exports[`RN Codegen Flow Parser Fails with error message PROP_ENUM_BOOLEAN 1`] = `"Unsupported union type for \\"someProp\\", received \\"BooleanLiteralTypeAnnotation\\""`; + +exports[`RN Codegen Flow Parser Fails with error message PROP_MIXED_ENUM 1`] = `"Mixed types are not supported (see \\"someProp\\")"`; + exports[`RN Codegen Flow Parser Fails with error message PROP_NUMBER_TYPE 1`] = `"Cannot use \\"NumberTypeAnnotation\\" type annotation for \\"someProp\\": must use a specific numeric type like Int32, Double, or Float"`; exports[`RN Codegen Flow Parser Fails with error message PROPS_CONFLICT_NAMES 1`] = `"A prop was already defined with the name isEnabled"`; @@ -247,6 +257,22 @@ Object { "type": "StringEnumTypeAnnotation", }, }, + Object { + "name": "int_enum_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": 0, + "options": Array [ + Object { + "value": 0, + }, + Object { + "value": 1, + }, + ], + "type": "Int32EnumTypeAnnotation", + }, + }, Object { "name": "object_optional_key", "optional": true, diff --git a/packages/react-native-codegen/src/parsers/flow/components/props.js b/packages/react-native-codegen/src/parsers/flow/components/props.js index 0d13e710783..20ede46ef05 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/props.js +++ b/packages/react-native-codegen/src/parsers/flow/components/props.js @@ -106,16 +106,33 @@ function getTypeAnnotationForArray(name, typeAnnotation, defaultValue, types) { type: 'StringTypeAnnotation', }; case 'UnionTypeAnnotation': - if (defaultValue == null) { - throw new Error(`A default array enum value is required for "${name}"`); + typeAnnotation.types.reduce((lastType, currType) => { + if (lastType && currType.type !== lastType.type) { + throw new Error(`Mixed types are not supported (see "${name}")`); + } + return currType; + }); + + if (defaultValue === null) { + throw new Error(`A default enum value is required for "${name}"`); + } + + const unionType = typeAnnotation.types[0].type; + if (unionType === 'StringLiteralTypeAnnotation') { + return { + type: 'StringEnumTypeAnnotation', + default: (defaultValue: string), + options: typeAnnotation.types.map(option => ({name: option.value})), + }; + } else if (unionType === 'NumberLiteralTypeAnnotation') { + throw new Error( + `Arrays of int enums are not supported (see: "${name}")`, + ); + } else { + throw new Error( + `Unsupported union type for "${name}", recieved "${unionType}"`, + ); } - return { - type: 'StringEnumTypeAnnotation', - default: defaultValue, - options: extractedTypeAnnotation.types.map(option => ({ - name: option.value, - })), - }; default: (type: empty); throw new Error(`Unknown prop type for "${name}": ${type}`); @@ -221,14 +238,35 @@ function getTypeAnnotation(name, annotation, defaultValue, types) { } throw new Error(`A default string (or null) is required for "${name}"`); case 'UnionTypeAnnotation': - if (defaultValue !== null) { + typeAnnotation.types.reduce((lastType, currType) => { + if (lastType && currType.type !== lastType.type) { + throw new Error(`Mixed types are not supported (see "${name}")`); + } + return currType; + }); + + if (defaultValue === null) { + throw new Error(`A default enum value is required for "${name}"`); + } + + const unionType = typeAnnotation.types[0].type; + if (unionType === 'StringLiteralTypeAnnotation') { return { type: 'StringEnumTypeAnnotation', default: (defaultValue: string), options: typeAnnotation.types.map(option => ({name: option.value})), }; + } else if (unionType === 'NumberLiteralTypeAnnotation') { + return { + type: 'Int32EnumTypeAnnotation', + default: (defaultValue: number), + options: typeAnnotation.types.map(option => ({value: option.value})), + }; + } else { + throw new Error( + `Unsupported union type for "${name}", received "${unionType}"`, + ); } - throw new Error(`A default enum value is required for "${name}"`); case 'NumberTypeAnnotation': throw new Error( `Cannot use "${type}" type annotation for "${name}": must use a specific numeric type like Int32, Double, or Float`,