diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 3ee4879818c..113fd95f582 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -45,7 +45,7 @@ type PropTypeTypeAnnotation = |}> | $ReadOnly<{| type: 'StringTypeAnnotation', - default: string, + default: string | null, |}> | $ReadOnly<{| type: 'FloatTypeAnnotation', diff --git a/packages/react-native-codegen/src/generators/GeneratePropsH.js b/packages/react-native-codegen/src/generators/GeneratePropsH.js index 2e95c2c5435..73308ced6ad 100644 --- a/packages/react-native-codegen/src/generators/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/GeneratePropsH.js @@ -140,6 +140,9 @@ function convertDefaultTypeToString(componentName: string, prop): string { case 'BooleanTypeAnnotation': return String(typeAnnotation.default); case 'StringTypeAnnotation': + if (typeAnnotation.default == null) { + return ''; + } return `"${typeAnnotation.default}"`; case 'Int32TypeAnnotation': return String(typeAnnotation.default); diff --git a/packages/react-native-codegen/src/generators/GenerateTests.js b/packages/react-native-codegen/src/generators/GenerateTests.js index 16ecefe5d44..3596cde9527 100644 --- a/packages/react-native-codegen/src/generators/GenerateTests.js +++ b/packages/react-native-codegen/src/generators/GenerateTests.js @@ -14,9 +14,11 @@ import type {SchemaType} from '../CodegenSchema'; const {getImports, toSafeCppString} = require('./CppHelpers'); type FilesOutput = Map; +type PropValueType = string | number | boolean; + type TestCase = $ReadOnly<{| propName: string, - propValue: string | number | boolean, + propValue: ?PropValueType, testName?: string, raw?: boolean, |}>; @@ -59,7 +61,10 @@ function getTestCasesForProp(propName, typeAnnotation) { } else if (typeAnnotation.type === 'StringTypeAnnotation') { cases.push({ propName, - propValue: typeAnnotation.default || 'foo', + propValue: + typeAnnotation.default != null && typeAnnotation.default !== '' + ? typeAnnotation.default + : 'foo', }); } else if (typeAnnotation.type === 'BooleanTypeAnnotation') { cases.push({ diff --git a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js index 8e95a41bede..2a3288580c4 100644 --- a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js @@ -110,6 +110,14 @@ const STRING_PROP: SchemaType = { default: '', }, }, + { + name: 'accessibilityRole', + optional: true, + typeAnnotation: { + type: 'StringTypeAnnotation', + default: null, + }, + }, ], }, }, diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap index 9f3f61ebb8a..75ba45c640a 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap @@ -387,7 +387,8 @@ StringPropComponentProps::StringPropComponentProps( const StringPropComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, accessibilityHint)) + accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, accessibilityHint)), + accessibilityRole(convertRawProp(rawProps, \\"accessibilityRole\\", sourceProps.accessibilityRole, accessibilityRole)) {} } // namespace react diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap index 17bf1608eeb..ea486647acf 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -452,6 +452,7 @@ class StringPropComponentProps final : public ViewProps { #pragma mark - Props const std::string accessibilityHint{\\"\\"}; + const std::string accessibilityRole{}; }; } // namespace react diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateTests-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateTests-test.js.snap index 9103023cbf9..3636fe89690 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateTests-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateTests-test.js.snap @@ -457,6 +457,13 @@ TEST(StringPropComponentProps_accessibilityHint, etc) { auto const &sourceProps = StringPropComponentProps(); auto const &rawProps = RawProps(folly::dynamic::object(\\"accessibilityHint\\", \\"foo\\")); + StringPropComponentProps(sourceProps, rawProps); +} + +TEST(StringPropComponentProps_accessibilityRole, etc) { + auto const &sourceProps = StringPropComponentProps(); + auto const &rawProps = RawProps(folly::dynamic::object(\\"accessibilityRole\\", \\"foo\\")); + StringPropComponentProps(sourceProps, rawProps); }", } 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 95c783e1acc..ee9fb31e9d6 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 @@ -478,6 +478,7 @@ const StringPropComponentViewConfig = { validAttributes: { accessibilityHint: true, + accessibilityRole: 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 a54aa2bb62b..b4e85b54f1a 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 @@ -137,6 +137,12 @@ type ModuleProps = $ReadOnly<{| string_optional_value: ?WithDefault, string_optional_both?: ?WithDefault, + // String props, null default + string_null_required: WithDefault, + string_null_optional_key?: WithDefault, + string_null_optional_value: ?WithDefault, + string_null_optional_both?: ?WithDefault, + // Float props float_required: WithDefault, float_optional_key?: WithDefault, 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 8feeb11c71c..327efc73bc7 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 @@ -78,6 +78,38 @@ Object { "type": "StringTypeAnnotation", }, }, + Object { + "name": "string_null_required", + "optional": false, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "string_null_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "string_null_optional_value", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "string_null_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, Object { "name": "float_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 222b2ca014b..135d4b824eb 100644 --- a/packages/react-native-codegen/src/parsers/flow/props.js +++ b/packages/react-native-codegen/src/parsers/flow/props.js @@ -119,7 +119,7 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { name: 'PointPrimitive', }; case 'Int32': - if (defaultValue !== null) { + if (defaultValue != null) { return { type: 'Int32TypeAnnotation', default: (defaultValue: number), @@ -127,7 +127,7 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { } throw new Error(`A default int is required for "${name}"`); case 'Float': - if (defaultValue !== null) { + if (defaultValue != null) { return { type: 'FloatTypeAnnotation', default: (defaultValue: number), @@ -135,7 +135,7 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { } throw new Error(`A default float is required for "${name}"`); case 'BooleanTypeAnnotation': - if (defaultValue !== null) { + if (defaultValue != null) { return { type: 'BooleanTypeAnnotation', default: (defaultValue: boolean), @@ -143,13 +143,13 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { } throw new Error(`A default boolean is required for "${name}"`); case 'StringTypeAnnotation': - if (defaultValue !== null) { + if (typeof defaultValue !== 'undefined') { return { type: 'StringTypeAnnotation', - default: (defaultValue: string), + default: (defaultValue: string | null), }; } - throw new Error(`A default string is required for "${name}"`); + throw new Error(`A default string (or null) is required for "${name}"`); case 'UnionTypeAnnotation': if (defaultValue !== null) { return { @@ -199,6 +199,18 @@ function buildPropSchema(property): ?PropTypeShape { } type = typeAnnotation.typeParameters.params[0].type; defaultValue = typeAnnotation.typeParameters.params[1].value; + const defaultValueType = typeAnnotation.typeParameters.params[1].type; + + if (defaultValueType === 'NullLiteralTypeAnnotation') { + if (type !== 'StringTypeAnnotation') { + throw new Error( + `WithDefault can only provide a 'null' default value for string types (see ${name})`, + ); + } + + defaultValue = null; + } + typeAnnotation = typeAnnotation.typeParameters.params[0]; }