diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 7e35b52207a..a341f1757d3 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -258,13 +258,7 @@ export type SchemaType = $ReadOnly<{| /** * NativeModule Types - * - * TODO(T71923114): Remove nullable from NativeModule type annotations. - * This is necessary for us to start unifying the notion of a "type - * annotation" across the codegen schema as a whole. */ -export type Required = $ReadOnly<{...T, nullable: false}>; - export type NativeModuleSchema = $ReadOnly<{| // We only support aliases to Objects aliases: NativeModuleAliasMap, @@ -272,26 +266,36 @@ export type NativeModuleSchema = $ReadOnly<{| |}>; export type NativeModuleAliasMap = $ReadOnly<{| - [aliasName: string]: Required, + [aliasName: string]: NativeModuleObjectTypeAnnotation, |}>; export type NativeModulePropertySchema = $ReadOnly<{| name: string, optional: boolean, - typeAnnotation: NativeModuleFunctionTypeAnnotation, + typeAnnotation: Nullable, +|}>; + +export type Nullable<+T: NativeModuleTypeAnnotation> = + | NullableTypeAnnotation + | T; + +export type NullableTypeAnnotation< + +T: NativeModuleTypeAnnotation, +> = $ReadOnly<{| + type: 'NullableTypeAnnotation', + typeAnnotation: T, |}>; export type NativeModuleFunctionTypeAnnotation = $ReadOnly<{| type: 'FunctionTypeAnnotation', params: $ReadOnlyArray, - returnTypeAnnotation: NativeModuleReturnTypeAnnotation, - nullable: boolean, + returnTypeAnnotation: Nullable, |}>; export type NativeModuleMethodParamSchema = $ReadOnly<{| name: string, optional: boolean, - typeAnnotation: NativeModuleParamTypeAnnotation, + typeAnnotation: Nullable, |}>; export type NativeModuleObjectTypeAnnotation = $ReadOnly<{| @@ -300,14 +304,13 @@ export type NativeModuleObjectTypeAnnotation = $ReadOnly<{| $ReadOnly<{| name: string, optional: boolean, - typeAnnotation: NativeModuleBaseTypeAnnotation, + typeAnnotation: Nullable, |}>, >, - nullable: boolean, |}>; export type NativeModuleArrayTypeAnnotation< - T = NativeModuleBaseTypeAnnotation, + +T: Nullable, > = $ReadOnly<{| type: 'ArrayTypeAnnotation', /** @@ -315,64 +318,52 @@ export type NativeModuleArrayTypeAnnotation< * invalid Array ElementTypes. Then, make the elementType required. */ elementType?: T, - nullable: boolean, |}>; export type NativeModuleStringTypeAnnotation = $ReadOnly<{| type: 'StringTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleNumberTypeAnnotation = $ReadOnly<{| type: 'NumberTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleInt32TypeAnnotation = $ReadOnly<{| type: 'Int32TypeAnnotation', - nullable: boolean, |}>; export type NativeModuleDoubleTypeAnnotation = $ReadOnly<{| type: 'DoubleTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleFloatTypeAnnotation = $ReadOnly<{| type: 'FloatTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleBooleanTypeAnnotation = $ReadOnly<{| type: 'BooleanTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleGenericObjectTypeAnnotation = $ReadOnly<{| type: 'GenericObjectTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleReservedFunctionValueTypeAnnotation = $ReadOnly<{| type: 'ReservedFunctionValueTypeAnnotation', name: ReservedFunctionValueTypeName, - nullable: boolean, |}>; export type NativeModuleTypeAliasTypeAnnotation = $ReadOnly<{| type: 'TypeAliasTypeAnnotation', name: string, - nullable: boolean, |}>; export type NativeModulePromiseTypeAnnotation = $ReadOnly<{| type: 'PromiseTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleVoidTypeAnnotation = $ReadOnly<{| type: 'VoidTypeAnnotation', - nullable: boolean, |}>; export type NativeModuleBaseTypeAnnotation = @@ -385,7 +376,7 @@ export type NativeModuleBaseTypeAnnotation = | NativeModuleGenericObjectTypeAnnotation | NativeModuleReservedFunctionValueTypeAnnotation | NativeModuleTypeAliasTypeAnnotation - | NativeModuleArrayTypeAnnotation<> + | NativeModuleArrayTypeAnnotation> | NativeModuleObjectTypeAnnotation; export type NativeModuleParamTypeAnnotation = diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap index 64b677c38d8..f5ec83220a0 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap @@ -34,28 +34,27 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES SampleTurboModule: { aliases: { ObjectAlias: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'x', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } }, { name: 'y', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } }, { name: 'label', optional: false, - typeAnnotation: { nullable: false, type: 'StringTypeAnnotation' } + typeAnnotation: { type: 'StringTypeAnnotation' } }, { name: 'truthy', optional: false, - typeAnnotation: { nullable: false, type: 'BooleanTypeAnnotation' } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -66,15 +65,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } } - ], - nullable: false + ] } }, { @@ -82,9 +80,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, - params: [], - nullable: false + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, + params: [] } }, { @@ -93,13 +90,12 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'a', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } } ] }, @@ -108,13 +104,11 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES name: 'a', optional: false, typeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'NumberTypeAnnotation' } + elementType: { type: 'NumberTypeAnnotation' } } } - ], - nullable: false + ] } }, { @@ -122,19 +116,17 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ALIASES optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'StringTypeAnnotation' }, + returnTypeAnnotation: { type: 'StringTypeAnnotation' }, params: [ { name: 'a', optional: false, typeAnnotation: { - nullable: false, type: 'TypeAliasTypeAnnotation', name: 'ObjectAlias' } } - ], - nullable: false + ] } } ] @@ -159,22 +151,19 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WI typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } }, params: [ { name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } } } - ], - nullable: false + ] } } ] @@ -198,15 +187,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WI optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'ArrayTypeAnnotation' }, + returnTypeAnnotation: { type: 'ArrayTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'ArrayTypeAnnotation' } + typeAnnotation: { type: 'ArrayTypeAnnotation' } } - ], - nullable: false + ] } } ] @@ -231,22 +219,19 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_AR typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } }, params: [ { name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } } } - ], - nullable: false + ] } }, { @@ -255,22 +240,19 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_AR typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } }, params: [ { name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } } } - ], - nullable: false + ] } } ] @@ -294,15 +276,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PA optional: true, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'BooleanTypeAnnotation' } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } - ], - nullable: false + ] } }, { @@ -310,15 +291,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PA optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } } - ], - nullable: false + ] } }, { @@ -326,15 +306,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PA optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'StringTypeAnnotation' } + typeAnnotation: { type: 'StringTypeAnnotation' } } - ], - nullable: false + ] } }, { @@ -342,15 +321,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_BASIC_PA optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'StringTypeAnnotation' } + typeAnnotation: { type: 'StringTypeAnnotation' } } - ], - nullable: false + ] } } ] @@ -374,45 +352,35 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_CALLBACK optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'callback', optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'value', optional: false, - typeAnnotation: { - nullable: false, - type: 'StringTypeAnnotation' - } + typeAnnotation: { type: 'StringTypeAnnotation' } }, { name: 'arr', optional: false, typeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { - nullable: false, - type: 'StringTypeAnnotation' - } + elementType: { type: 'StringTypeAnnotation' } } } } - ], - nullable: false + ] } } - ], - nullable: false + ] } } ] @@ -437,15 +405,12 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { nullable: false, type: 'StringTypeAnnotation' } + elementType: { type: 'StringTypeAnnotation' } } } }, @@ -454,32 +419,23 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ArrayTypeAnnotation', - elementType: { - nullable: false, - type: 'StringTypeAnnotation' - } + elementType: { type: 'StringTypeAnnotation' } } } } } } } - ], - nullable: false + ] } } ] @@ -504,23 +460,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -532,23 +483,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -556,8 +502,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ ] } } - ], - nullable: false + ] } }, { @@ -566,23 +511,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -594,23 +534,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -618,8 +553,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ ] } } - ], - nullable: false + ] } }, { @@ -627,31 +561,23 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { - nullable: false, - type: 'GenericObjectTypeAnnotation' - }, + returnTypeAnnotation: { type: 'GenericObjectTypeAnnotation' }, params: [ { name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'a', optional: false, - typeAnnotation: { - nullable: false, - type: 'StringTypeAnnotation' - } + typeAnnotation: { type: 'StringTypeAnnotation' } } ] } } - ], - nullable: false + ] } }, { @@ -660,26 +586,20 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ArrayTypeAnnotation', elementType: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -692,23 +612,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ name: 'arg', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'const1', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } } ] } @@ -716,8 +631,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ ] } } - ], - nullable: false + ] } } ] @@ -742,54 +656,40 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'isTesting', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } }, { name: 'reactNativeVersion', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'major', optional: false, - typeAnnotation: { - nullable: false, - type: 'NumberTypeAnnotation' - } + typeAnnotation: { type: 'NumberTypeAnnotation' } }, { name: 'minor', optional: false, - typeAnnotation: { - nullable: false, - type: 'NumberTypeAnnotation' - } + typeAnnotation: { type: 'NumberTypeAnnotation' } }, { name: 'patch', optional: true, - typeAnnotation: { - nullable: false, - type: 'NumberTypeAnnotation' - } + typeAnnotation: { type: 'NumberTypeAnnotation' } }, { name: 'prerelease', optional: false, typeAnnotation: { - nullable: true, - type: 'NumberTypeAnnotation' + type: 'NullableTypeAnnotation', + typeAnnotation: { type: 'NumberTypeAnnotation' } } } ] @@ -798,30 +698,26 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_ { name: 'forceTouchAvailable', optional: false, - typeAnnotation: { - nullable: false, - type: 'BooleanTypeAnnotation' - } + typeAnnotation: { type: 'BooleanTypeAnnotation' } }, { name: 'osVersion', optional: false, - typeAnnotation: { nullable: false, type: 'StringTypeAnnotation' } + typeAnnotation: { type: 'StringTypeAnnotation' } }, { name: 'systemName', optional: false, - typeAnnotation: { nullable: false, type: 'StringTypeAnnotation' } + typeAnnotation: { type: 'StringTypeAnnotation' } }, { name: 'interfaceIdiom', optional: false, - typeAnnotation: { nullable: false, type: 'StringTypeAnnotation' } + typeAnnotation: { type: 'StringTypeAnnotation' } } ] }, - params: [], - nullable: false + params: [] } } ] @@ -845,15 +741,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_FLOAT_AN optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'Int32TypeAnnotation' }, + returnTypeAnnotation: { type: 'Int32TypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'Int32TypeAnnotation' } + typeAnnotation: { type: 'Int32TypeAnnotation' } } - ], - nullable: false + ] } }, { @@ -861,15 +756,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_FLOAT_AN optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'FloatTypeAnnotation' }, + returnTypeAnnotation: { type: 'FloatTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: false, type: 'FloatTypeAnnotation' } + typeAnnotation: { type: 'FloatTypeAnnotation' } } - ], - nullable: false + ] } } ] @@ -888,37 +782,27 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NESTED_A SampleTurboModule: { aliases: { Bar: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'z', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } } ] }, Foo: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'bar1', optional: false, - typeAnnotation: { - nullable: false, - type: 'TypeAliasTypeAnnotation', - name: 'Bar' - } + typeAnnotation: { type: 'TypeAliasTypeAnnotation', name: 'Bar' } }, { name: 'bar2', optional: false, - typeAnnotation: { - nullable: false, - type: 'TypeAliasTypeAnnotation', - name: 'Bar' - } + typeAnnotation: { type: 'TypeAliasTypeAnnotation', name: 'Bar' } } ] } @@ -929,23 +813,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NESTED_A optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { - nullable: false, - type: 'TypeAliasTypeAnnotation', - name: 'Foo' - }, + returnTypeAnnotation: { type: 'TypeAliasTypeAnnotation', name: 'Foo' }, params: [ { name: 'x', optional: false, - typeAnnotation: { - nullable: false, - type: 'TypeAliasTypeAnnotation', - name: 'Foo' - } + typeAnnotation: { type: 'TypeAliasTypeAnnotation', name: 'Foo' } } - ], - nullable: false + ] } }, { @@ -953,19 +828,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NESTED_A optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'x', optional: false, - typeAnnotation: { - nullable: false, - type: 'TypeAliasTypeAnnotation', - name: 'Foo' - } + typeAnnotation: { type: 'TypeAliasTypeAnnotation', name: 'Foo' } } - ], - nullable: false + ] } } ] @@ -989,15 +859,17 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_NULLABLE optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'VoidTypeAnnotation' }, + returnTypeAnnotation: { type: 'VoidTypeAnnotation' }, params: [ { name: 'arg', optional: false, - typeAnnotation: { nullable: true, type: 'StringTypeAnnotation' } + typeAnnotation: { + type: 'NullableTypeAnnotation', + typeAnnotation: { type: 'StringTypeAnnotation' } + } } - ], - nullable: false + ] } } ] @@ -1016,13 +888,12 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W SampleTurboModule: { aliases: { DisplayMetricsAndroid: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'width', optional: false, - typeAnnotation: { nullable: false, type: 'NumberTypeAnnotation' } + typeAnnotation: { type: 'NumberTypeAnnotation' } } ] } @@ -1034,21 +905,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'Dimensions', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'windowPhysicalPixels', optional: false, typeAnnotation: { - nullable: false, type: 'TypeAliasTypeAnnotation', name: 'DisplayMetricsAndroid' } @@ -1058,8 +926,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W } ] }, - params: [], - nullable: false + params: [] } }, { @@ -1068,21 +935,18 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'Dimensions', optional: false, typeAnnotation: { - nullable: false, type: 'ObjectTypeAnnotation', properties: [ { name: 'windowPhysicalPixels', optional: false, typeAnnotation: { - nullable: false, type: 'TypeAliasTypeAnnotation', name: 'DisplayMetricsAndroid' } @@ -1092,8 +956,7 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_OBJECT_W } ] }, - params: [], - nullable: false + params: [] } } ] @@ -1117,9 +980,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'PromiseTypeAnnotation' }, - params: [], - nullable: false + returnTypeAnnotation: { type: 'PromiseTypeAnnotation' }, + params: [] } }, { @@ -1127,9 +989,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'PromiseTypeAnnotation' }, - params: [], - nullable: false + returnTypeAnnotation: { type: 'PromiseTypeAnnotation' }, + params: [] } }, { @@ -1137,9 +998,8 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_PROMISE optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { nullable: false, type: 'PromiseTypeAnnotation' }, - params: [], - nullable: false + returnTypeAnnotation: { type: 'PromiseTypeAnnotation' }, + params: [] } } ] @@ -1164,7 +1024,6 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ROOT_TAG typeAnnotation: { type: 'FunctionTypeAnnotation', returnTypeAnnotation: { - nullable: false, type: 'ReservedFunctionValueTypeAnnotation', name: 'RootTag' }, @@ -1173,13 +1032,11 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_ROOT_TAG name: 'rootTag', optional: false, typeAnnotation: { - nullable: false, type: 'ReservedFunctionValueTypeAnnotation', name: 'RootTag' } } - ], - nullable: false + ] } } ] @@ -1203,21 +1060,14 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_SIMPLE_O optional: false, typeAnnotation: { type: 'FunctionTypeAnnotation', - returnTypeAnnotation: { - nullable: false, - type: 'GenericObjectTypeAnnotation' - }, + returnTypeAnnotation: { type: 'GenericObjectTypeAnnotation' }, params: [ { name: 'o', optional: false, - typeAnnotation: { - nullable: false, - type: 'GenericObjectTypeAnnotation' - } + typeAnnotation: { type: 'GenericObjectTypeAnnotation' } } - ], - nullable: false + ] } } ] diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js index b48f155accf..602efd71759 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/module-parser-e2e-test.js @@ -10,9 +10,13 @@ import type { ReservedFunctionValueTypeName, + NativeModuleReturnTypeAnnotation, + NativeModuleBaseTypeAnnotation, NativeModuleSchema, + NativeModuleParamTypeAnnotation, } from '../../../../CodegenSchema'; const {parseString} = require('../../index.js'); +const {unwrapNullable} = require('../utils'); const { FlowGenericNotTypeParameterizedParserError, UnrecognizedFlowTypeAnnotationParserError, @@ -58,14 +62,16 @@ function expectAnimalTypeAliasToExist(module: NativeModuleSchema) { expect(animalAlias).not.toBe(null); invariant(animalAlias != null, ''); expect(animalAlias.type).toBe('ObjectTypeAnnotation'); - expect(animalAlias.nullable).toBe(false); expect(animalAlias.properties.length).toBe(1); expect(animalAlias.properties[0].name).toBe('name'); expect(animalAlias.properties[0].optional).toBe(false); - expect(animalAlias.properties[0].typeAnnotation.type).toBe( - 'StringTypeAnnotation', + + const [typeAnnotation, nullable] = unwrapNullable( + animalAlias.properties[0].typeAnnotation, ); - expect(animalAlias.properties[0].typeAnnotation.nullable).toBe(false); + + expect(typeAnnotation.type).toBe('StringTypeAnnotation'); + expect(nullable).toBe(false); } describe('Flow Module Parser', () => { @@ -133,7 +139,10 @@ describe('Flow Module Parser', () => { return `${paramName}: ${paramType}`; } - function parseParamType(paramName: string, paramType: string) { + function parseParamType( + paramName: string, + paramType: string, + ): [NativeModuleParamTypeAnnotation, NativeModuleSchema] { const module = parseModule(` import type {TurboModule} from 'RCTExport'; import * as TurboModuleRegistry from 'TurboModuleRegistry'; @@ -147,13 +156,18 @@ describe('Flow Module Parser', () => { `); expect(module.properties[0]).not.toBe(null); - const param = module.properties[0].typeAnnotation.params[0]; + const param = unwrapNullable(module.properties[0].typeAnnotation)[0] + .params[0]; expect(param).not.toBe(null); expect(param.name).toBe(paramName); expect(param.optional).toBe(optional); - expect(param.typeAnnotation.nullable).toBe(nullable); + const [ + paramTypeAnnotation, + isParamTypeAnnotationNullable, + ] = unwrapNullable(param.typeAnnotation); + expect(isParamTypeAnnotationNullable).toBe(nullable); - return [param, module]; + return [paramTypeAnnotation, module]; } describe( @@ -174,15 +188,15 @@ describe('Flow Module Parser', () => { describe('Primitive types', () => { PRIMITIVES.forEach(([FLOW_TYPE, PARSED_TYPE_NAME]) => { it(`should parse methods that have ${PARAM_TYPE_DESCRIPTION} primitive parameter of type '${FLOW_TYPE}'`, () => { - const [param] = parseParamType('arg', FLOW_TYPE); - expect(param.typeAnnotation.type).toBe(PARSED_TYPE_NAME); + const [paramTypeAnnotation] = parseParamType('arg', FLOW_TYPE); + expect(paramTypeAnnotation.type).toBe(PARSED_TYPE_NAME); }); }); }); it(`should parse methods that have ${PARAM_TYPE_DESCRIPTION} parameter of type 'Object'`, () => { - const [param] = parseParamType('arg', 'Object'); - expect(param.typeAnnotation.type).toBe( + const [paramTypeAnnotation] = parseParamType('arg', 'Object'); + expect(paramTypeAnnotation.type).toBe( 'GenericObjectTypeAnnotation', ); }); @@ -190,18 +204,18 @@ describe('Flow Module Parser', () => { describe('Reserved Types', () => { RESERVED_FUNCTION_VALUE_TYPE_NAME.forEach(FLOW_TYPE => { it(`should parse methods that have ${PARAM_TYPE_DESCRIPTION} parameter of reserved type '${FLOW_TYPE}'`, () => { - const [param] = parseParamType('arg', FLOW_TYPE); + const [paramTypeAnnotation] = parseParamType('arg', FLOW_TYPE); - expect(param.typeAnnotation.type).toBe( + expect(paramTypeAnnotation.type).toBe( 'ReservedFunctionValueTypeAnnotation', ); invariant( - param.typeAnnotation.type === + paramTypeAnnotation.type === 'ReservedFunctionValueTypeAnnotation', 'Param must be a Reserved type', ); - expect(param.typeAnnotation.name).toBe(FLOW_TYPE); + expect(paramTypeAnnotation.name).toBe(FLOW_TYPE); }); }); }); @@ -219,21 +233,25 @@ describe('Flow Module Parser', () => { function parseParamArrayElementType( paramName: string, paramType: string, - ) { - const [param, module] = parseParamType( + ): [NativeModuleBaseTypeAnnotation, NativeModuleSchema] { + const [paramTypeAnnotation, module] = parseParamType( paramName, `Array<${paramType}>`, ); - expect(param.typeAnnotation.type).toBe('ArrayTypeAnnotation'); - invariant( - param.typeAnnotation.type === 'ArrayTypeAnnotation', - '', - ); + expect(paramTypeAnnotation.type).toBe('ArrayTypeAnnotation'); + invariant(paramTypeAnnotation.type === 'ArrayTypeAnnotation', ''); - expect(param.typeAnnotation.elementType).not.toBe(null); - invariant(param.typeAnnotation.elementType != null, ''); - return [param.typeAnnotation.elementType, module]; + expect(paramTypeAnnotation.elementType).not.toBe(null); + invariant(paramTypeAnnotation.elementType != null, ''); + const [ + elementType, + isElementTypeNullable, + ] = unwrapNullable( + paramTypeAnnotation.elementType, + ); + expect(isElementTypeNullable).toBe(false); + return [elementType, module]; } // TODO: Do we support nullable element types? @@ -304,35 +322,44 @@ describe('Flow Module Parser', () => { expect(properties[0]).not.toBe(null); expect(properties[0].name).toBe('foo'); expect(properties[0].typeAnnotation).not.toBe(null); - expect(properties[0].typeAnnotation?.type).toBe( - 'StringTypeAnnotation', + + const [typeAnnotation, isPropertyNullable] = unwrapNullable( + properties[0].typeAnnotation, ); - expect(properties[0].typeAnnotation?.nullable).toBe(true); + + expect(typeAnnotation.type).toBe('StringTypeAnnotation'); + expect(isPropertyNullable).toBe(true); expect(properties[0].optional).toBe(false); }); }); it(`should parse methods that have ${PARAM_TYPE_DESCRIPTION} parameter type of some type alias`, () => { - const [param, module] = parseParamType('arg', 'Animal'); - expect(param.typeAnnotation.type).toBe('TypeAliasTypeAnnotation'); + const [paramTypeAnnotation, module] = parseParamType( + 'arg', + 'Animal', + ); + expect(paramTypeAnnotation.type).toBe('TypeAliasTypeAnnotation'); invariant( - param.typeAnnotation.type === 'TypeAliasTypeAnnotation', + paramTypeAnnotation.type === 'TypeAliasTypeAnnotation', '', ); - expect(param.typeAnnotation.name).toBe('Animal'); + expect(paramTypeAnnotation.name).toBe('Animal'); expectAnimalTypeAliasToExist(module); }); it(`should parse methods that have ${PARAM_TYPE_DESCRIPTION} parameter type of some type alias that points to another type alias`, () => { - const [param, module] = parseParamType('arg', 'AnimalPointer'); - expect(param.typeAnnotation.type).toBe('TypeAliasTypeAnnotation'); + const [paramTypeAnnotation, module] = parseParamType( + 'arg', + 'AnimalPointer', + ); + expect(paramTypeAnnotation.type).toBe('TypeAliasTypeAnnotation'); invariant( - param.typeAnnotation.type === 'TypeAliasTypeAnnotation', + paramTypeAnnotation.type === 'TypeAliasTypeAnnotation', '', ); - expect(param.typeAnnotation.name).toBe('Animal'); + expect(paramTypeAnnotation.name).toBe('Animal'); expectAnimalTypeAliasToExist(module); }); @@ -354,18 +381,23 @@ describe('Flow Module Parser', () => { `); expect(module.properties[0]).not.toBe(null); - const param = module.properties[0].typeAnnotation.params[0]; + const param = unwrapNullable(module.properties[0].typeAnnotation)[0] + .params[0]; expect(param.name).toBe('arg'); expect(param.optional).toBe(optional); // The TypeAliasAnnotation is called Animal, and is nullable - expect(param.typeAnnotation.type).toBe('TypeAliasTypeAnnotation'); + const [ + paramTypeAnnotation, + isParamTypeAnnotationNullable, + ] = unwrapNullable(param.typeAnnotation); + expect(paramTypeAnnotation.type).toBe('TypeAliasTypeAnnotation'); invariant( - param.typeAnnotation.type === 'TypeAliasTypeAnnotation', + paramTypeAnnotation.type === 'TypeAliasTypeAnnotation', '', ); - expect(param.typeAnnotation.name).toBe('Animal'); - expect(param.typeAnnotation.nullable).toBe(true); + expect(paramTypeAnnotation.name).toBe('Animal'); + expect(isParamTypeAnnotationNullable).toBe(true); // The Animal type alias RHS is valid, and non-null expectAnimalTypeAliasToExist(module); @@ -402,19 +434,26 @@ describe('Flow Module Parser', () => { function parseParamTypeObjectLiteralProp( propName: string, propType: string, - ) { - const [param, module] = parseParamType( + ): [ + $ReadOnly<{ + name: string, + optional: boolean, + typeAnnotation: NativeModuleBaseTypeAnnotation, + }>, + NativeModuleSchema, + ] { + const [paramTypeAnnotation, module] = parseParamType( 'arg', `{|${annotateProp(propName, propType)}|}`, ); - expect(param.typeAnnotation.type).toBe('ObjectTypeAnnotation'); + expect(paramTypeAnnotation.type).toBe('ObjectTypeAnnotation'); invariant( - param.typeAnnotation.type === 'ObjectTypeAnnotation', + paramTypeAnnotation.type === 'ObjectTypeAnnotation', '', ); - const {properties} = param.typeAnnotation; + const {properties} = paramTypeAnnotation; expect(properties).not.toBe(null); invariant(properties != null, ''); @@ -422,16 +461,19 @@ describe('Flow Module Parser', () => { expect(properties.length).toBe(1); expect(properties[0].name).toBe(propName); expect(properties[0].optional).toBe(isPropOptional); - expect(properties[0].typeAnnotation).not.toBe(null); - expect(properties[0].typeAnnotation.nullable).toBe( - isPropNullable, - ); - invariant(properties[0].typeAnnotation != null, ''); + + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(properties[0].typeAnnotation); + + expect(propertyTypeAnnotation).not.toBe(null); + expect(isPropertyTypeAnnotationNullable).toBe(isPropNullable); return [ { ...properties[0], - typeAnnotation: properties[0].typeAnnotation, + typeAnnotation: propertyTypeAnnotation, }, module, ]; @@ -504,7 +546,7 @@ describe('Flow Module Parser', () => { function parseArrayElementType( propName: string, arrayElementType: string, - ) { + ): [NativeModuleBaseTypeAnnotation, NativeModuleSchema] { const [property, module] = parseParamTypeObjectLiteralProp( 'propName', `Array<${arrayElementType}>`, @@ -517,9 +559,21 @@ describe('Flow Module Parser', () => { '', ); - const {elementType} = property.typeAnnotation; - expect(elementType).not.toBe(null); - invariant(elementType != null, ''); + const { + elementType: nullableElementType, + } = property.typeAnnotation; + expect(nullableElementType).not.toBe(null); + invariant(nullableElementType != null, ''); + + const [ + elementType, + isElementTypeNullable, + ] = unwrapNullable( + nullableElementType, + ); + + expect(isElementTypeNullable).toBe(false); + return [elementType, module]; } @@ -595,10 +649,16 @@ describe('Flow Module Parser', () => { expect(properties[0]).not.toBe(null); expect(properties[0].name).toBe('foo'); expect(properties[0].typeAnnotation).not.toBe(null); - expect(properties[0].typeAnnotation?.type).toBe( + + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(properties[0].typeAnnotation); + + expect(propertyTypeAnnotation.type).toBe( 'StringTypeAnnotation', ); - expect(properties[0].typeAnnotation?.nullable).toBe(true); + expect(isPropertyTypeAnnotationNullable).toBe(true); expect(properties[0].optional).toBe(false); }); }); @@ -623,11 +683,16 @@ describe('Flow Module Parser', () => { expect(properties[0]).not.toBe(null); expect(properties[0].name).toBe('foo'); - expect(properties[0].typeAnnotation).not.toBe(null); - expect(properties[0].typeAnnotation?.type).toBe( + + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(properties[0].typeAnnotation); + + expect(propertyTypeAnnotation.type).toBe( 'StringTypeAnnotation', ); - expect(properties[0].typeAnnotation?.nullable).toBe(true); + expect(isPropertyTypeAnnotationNullable).toBe(true); expect(properties[0].optional).toBe(false); }); @@ -668,10 +733,19 @@ describe('Flow Module Parser', () => { `); expect(module.properties[0]).not.toBe(null); - const {returnTypeAnnotation} = module.properties[0].typeAnnotation; - expect(returnTypeAnnotation).not.toBe(null); + + const [ + functionTypeAnnotation, + isFunctionTypeAnnotationNullable, + ] = unwrapNullable(module.properties[0].typeAnnotation); + expect(isFunctionTypeAnnotationNullable).toBe(false); + + const [ + returnTypeAnnotation, + isReturnTypeAnnotationNullable, + ] = unwrapNullable(functionTypeAnnotation.returnTypeAnnotation); expect(returnTypeAnnotation.type).toBe('VoidTypeAnnotation'); - expect(returnTypeAnnotation.nullable).toBe(false); + expect(isReturnTypeAnnotationNullable).toBe(false); }); [true, false].forEach(IS_RETURN_TYPE_NULLABLE => { @@ -681,7 +755,9 @@ describe('Flow Module Parser', () => { const annotateRet = retType => IS_RETURN_TYPE_NULLABLE ? `?${retType}` : retType; - function parseReturnType(flowType: string) { + function parseReturnType( + flowType: string, + ): [NativeModuleReturnTypeAnnotation, NativeModuleSchema] { const module = parseModule(` import type {TurboModule} from 'RCTExport'; import * as TurboModuleRegistry from 'TurboModuleRegistry'; @@ -695,9 +771,18 @@ describe('Flow Module Parser', () => { `); expect(module.properties[0]).not.toBe(null); - const {returnTypeAnnotation} = module.properties[0].typeAnnotation; - expect(returnTypeAnnotation).not.toBe(null); - expect(returnTypeAnnotation.nullable).toBe(IS_RETURN_TYPE_NULLABLE); + const [ + functionTypeAnnotation, + isFunctionTypeAnnotationNullable, + ] = unwrapNullable(module.properties[0].typeAnnotation); + expect(isFunctionTypeAnnotationNullable).toBe(false); + + const [ + returnTypeAnnotation, + isReturnTypeAnnotationNullable, + ] = unwrapNullable(functionTypeAnnotation.returnTypeAnnotation); + expect(isReturnTypeAnnotationNullable).toBe(IS_RETURN_TYPE_NULLABLE); + return [returnTypeAnnotation, module]; } @@ -749,7 +834,9 @@ describe('Flow Module Parser', () => { ); }); - function parseArrayElementReturnType(flowType: string) { + function parseArrayElementReturnType( + flowType: string, + ): [NativeModuleBaseTypeAnnotation, NativeModuleSchema] { const [returnTypeAnnotation, module] = parseReturnType( 'Array' + (flowType != null ? `<${flowType}>` : ''), ); @@ -759,10 +846,19 @@ describe('Flow Module Parser', () => { '', ); - const {elementType} = returnTypeAnnotation; + const arrayTypeAnnotation = returnTypeAnnotation; + + const {elementType} = arrayTypeAnnotation; expect(elementType).not.toBe(null); invariant(elementType != null, ''); - return [elementType, module]; + + const [ + elementTypeAnnotation, + isElementTypeAnnotation, + ] = unwrapNullable(elementType); + expect(isElementTypeAnnotation).toBe(false); + + return [elementTypeAnnotation, module]; } // TODO: Do we support nullable element types? @@ -824,10 +920,14 @@ describe('Flow Module Parser', () => { expect(properties[0]).not.toBe(null); expect(properties[0].name).toBe('foo'); expect(properties[0].typeAnnotation).not.toBe(null); - expect(properties[0].typeAnnotation?.type).toBe( - 'StringTypeAnnotation', - ); - expect(properties[0].typeAnnotation?.nullable).toBe(true); + + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(properties[0].typeAnnotation); + + expect(propertyTypeAnnotation.type).toBe('StringTypeAnnotation'); + expect(isPropertyTypeAnnotationNullable).toBe(true); expect(properties[0].optional).toBe(false); }); }); @@ -903,7 +1003,14 @@ describe('Flow Module Parser', () => { function parseObjectLiteralReturnTypeProp( propName: string, propType: string, - ) { + ): [ + $ReadOnly<{ + name: string, + optional: boolean, + typeAnnotation: NativeModuleBaseTypeAnnotation, + }>, + NativeModuleSchema, + ] { const [returnTypeAnnotation, module] = parseReturnType( `{|${annotateProp(propName, propType)}|}`, ); @@ -923,13 +1030,18 @@ describe('Flow Module Parser', () => { const property = properties[0]; expect(property.name).toBe(propName); expect(property.optional).toBe(optional); - expect(property.typeAnnotation).not.toBe(null); - expect(property.typeAnnotation?.nullable).toBe(nullable); - invariant(property.typeAnnotation != null, ''); + + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(property.typeAnnotation); + + expect(propertyTypeAnnotation).not.toBe(null); + expect(isPropertyTypeAnnotationNullable).toBe(nullable); return [ { ...property, - typeAnnotation: property.typeAnnotation, + typeAnnotation: propertyTypeAnnotation, }, module, ]; @@ -1010,7 +1122,7 @@ describe('Flow Module Parser', () => { function parseArrayElementType( propName: string, arrayElementType: string, - ) { + ): [NativeModuleBaseTypeAnnotation, NativeModuleSchema] { const [ property, module, @@ -1027,9 +1139,20 @@ describe('Flow Module Parser', () => { '', ); - const {elementType} = property.typeAnnotation; - expect(elementType).not.toBe(null); - invariant(elementType != null, ''); + const { + elementType: nullableElementType, + } = property.typeAnnotation; + expect(nullableElementType).not.toBe(null); + invariant(nullableElementType != null, ''); + + const [ + elementType, + isElementTypeNullable, + ] = unwrapNullable( + nullableElementType, + ); + expect(isElementTypeNullable).toBe(false); + return [elementType, module]; } @@ -1105,13 +1228,15 @@ describe('Flow Module Parser', () => { expect(properties[0].name).toBe('foo'); expect(properties[0].optional).toBe(false); - expect(properties[0].typeAnnotation).not.toBe(null); - invariant(properties[0].typeAnnotation != null, ''); + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(properties[0].typeAnnotation); - expect(properties[0].typeAnnotation.type).toBe( + expect(propertyTypeAnnotation.type).toBe( 'StringTypeAnnotation', ); - expect(properties[0].typeAnnotation.nullable).toBe(true); + expect(isPropertyTypeAnnotationNullable).toBe(true); }); }); @@ -1138,13 +1263,15 @@ describe('Flow Module Parser', () => { expect(properties[0].name).toBe('foo'); expect(properties[0].optional).toBe(false); - expect(properties[0].typeAnnotation).not.toBe(null); - invariant(properties[0].typeAnnotation != null, ''); + const [ + propertyTypeAnnotation, + isPropertyTypeAnnotationNullable, + ] = unwrapNullable(properties[0].typeAnnotation); - expect(properties[0].typeAnnotation.type).toBe( + expect(propertyTypeAnnotation.type).toBe( 'StringTypeAnnotation', ); - expect(properties[0].typeAnnotation.nullable).toBe(true); + expect(isPropertyTypeAnnotationNullable).toBe(true); }); it(`should parse methods that have ${RETURN_TYPE_DESCRIPTION} return type of an object literal with ${PROP_TYPE_DESCRIPTION} prop of some type alias`, () => { diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index a1da76184fb..8f936530a79 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -16,10 +16,14 @@ import type { NativeModuleAliasMap, NativeModuleSchema, NativeModuleFunctionTypeAnnotation, + NativeModuleArrayTypeAnnotation, + NativeModuleBaseTypeAnnotation, + Nullable, } from '../../../CodegenSchema.js'; import type {TypeDeclarationMap} from '../utils.js'; const {resolveTypeAnnotation} = require('../utils.js'); +const {unwrapNullable, wrapNullable} = require('./utils'); const { FlowGenericNotTypeParameterizedParserError, FlowGenericTypeParameterCountMismatchParserError, @@ -39,7 +43,7 @@ function translateTypeAnnotation( flowTypeAnnotation: $FlowFixMe, types: TypeDeclarationMap, aliasMap: {...NativeModuleAliasMap}, -): NativeModuleTypeAnnotation { +): Nullable { const { nullable, typeAnnotation, @@ -49,21 +53,21 @@ function translateTypeAnnotation( switch (typeAnnotation.type) { case 'GenericTypeAnnotation': { switch (typeAnnotation.id.name) { - case 'RootTag': - return { - nullable, + case 'RootTag': { + return wrapNullable(nullable, { type: 'ReservedFunctionValueTypeAnnotation', name: 'RootTag', - }; + }); + } case 'Promise': { assertGenericTypeAnnotationHasExactlyOneTypeParameter( moduleName, typeAnnotation, ); - return { - nullable, + + return wrapNullable(nullable, { type: 'PromiseTypeAnnotation', - }; + }); } case 'Array': case '$ReadOnlyArray': { @@ -78,11 +82,14 @@ function translateTypeAnnotation( * invalid Array ElementTypes. Then, make the elementType a required * parameter. */ - const elementType = translateTypeAnnotation( - moduleName, - typeAnnotation.typeParameters.params[0], - types, - aliasMap, + + const [elementType, isElementTypeNullable] = unwrapNullable( + translateTypeAnnotation( + moduleName, + typeAnnotation.typeParameters.params[0], + types, + aliasMap, + ), ); invariant( @@ -99,16 +106,18 @@ function translateTypeAnnotation( `${typeAnnotation.id.name} element type cannot be a function.`, ); - return { - nullable, + const finalTypeAnnotation: NativeModuleArrayTypeAnnotation< + Nullable, + > = { type: 'ArrayTypeAnnotation', - elementType: elementType, + elementType: wrapNullable(isElementTypeNullable, elementType), }; + + return wrapNullable(nullable, finalTypeAnnotation); } catch (ex) { - return { - nullable, + return wrapNullable(nullable, { type: 'ArrayTypeAnnotation', - }; + }); } } case '$ReadOnly': { @@ -124,34 +133,29 @@ function translateTypeAnnotation( ); } case 'Stringish': { - return { - nullable, + return wrapNullable(nullable, { type: 'StringTypeAnnotation', - }; + }); } case 'Int32': { - return { - nullable, + return wrapNullable(nullable, { type: 'Int32TypeAnnotation', - }; + }); } case 'Double': { - return { - nullable, + return wrapNullable(nullable, { type: 'DoubleTypeAnnotation', - }; + }); } case 'Float': { - return { - nullable, + return wrapNullable(nullable, { type: 'FloatTypeAnnotation', - }; + }); } case 'Object': { - return { - nullable, + return wrapNullable(nullable, { type: 'GenericObjectTypeAnnotation', - }; + }); } default: { throw new UnrecognizedFlowGenericParserError( @@ -162,7 +166,7 @@ function translateTypeAnnotation( } } case 'ObjectTypeAnnotation': { - const objectTypeAnnotationPartial = { + const objectTypeAnnotation = { type: 'ObjectTypeAnnotation', properties: typeAnnotation.properties.map(property => { const {optional} = property; @@ -180,19 +184,13 @@ function translateTypeAnnotation( }; if (!typeAliasResolutionStatus.successful) { - return { - nullable, - ...objectTypeAnnotationPartial, - }; + return wrapNullable(nullable, objectTypeAnnotation); } /** * All aliases RHS are required. */ - aliasMap[typeAliasResolutionStatus.aliasName] = { - nullable: false, - ...objectTypeAnnotationPartial, - }; + aliasMap[typeAliasResolutionStatus.aliasName] = objectTypeAnnotation; /** * Nullability of type aliases is transitive. @@ -223,43 +221,40 @@ function translateTypeAnnotation( * Hence, it's better to manage nullability within the actual TypeAliasTypeAnnotation nodes, and not the * associated ObjectTypeAnnotations. */ - return { - nullable: nullable, + return wrapNullable(nullable, { type: 'TypeAliasTypeAnnotation', name: typeAliasResolutionStatus.aliasName, - }; + }); } case 'BooleanTypeAnnotation': { - return { - nullable, + return wrapNullable(nullable, { type: 'BooleanTypeAnnotation', - }; + }); } case 'NumberTypeAnnotation': { - return { - nullable, + return wrapNullable(nullable, { type: 'NumberTypeAnnotation', - }; + }); } case 'VoidTypeAnnotation': { - return { - nullable, + return wrapNullable(nullable, { type: 'VoidTypeAnnotation', - }; + }); } case 'StringTypeAnnotation': { - return { - nullable, + return wrapNullable(nullable, { type: 'StringTypeAnnotation', - }; + }); } case 'FunctionTypeAnnotation': { - return translateFunctionTypeAnnotation( - moduleName, - typeAnnotation, - types, + return wrapNullable( nullable, - aliasMap, + translateFunctionTypeAnnotation( + moduleName, + typeAnnotation, + types, + aliasMap, + ), ); } default: { @@ -305,7 +300,6 @@ function translateFunctionTypeAnnotation( // TODO(T71778680): This is a FunctionTypeAnnotation. Type this. flowFunctionTypeAnnotation: $FlowFixMe, types: TypeDeclarationMap, - nullable: boolean, aliasMap: {...NativeModuleAliasMap}, ): NativeModuleFunctionTypeAnnotation { const params: Array = []; @@ -315,11 +309,13 @@ function translateFunctionTypeAnnotation( } const paramName = flowParam.name.name; - const paramTypeAnnotation = translateTypeAnnotation( - moduleName, - flowParam.typeAnnotation, - types, - aliasMap, + const [paramTypeAnnotation, isParamTypeAnnotationNullable] = unwrapNullable( + translateTypeAnnotation( + moduleName, + flowParam.typeAnnotation, + types, + aliasMap, + ), ); invariant( @@ -335,15 +331,20 @@ function translateFunctionTypeAnnotation( params.push({ name: flowParam.name.name, optional: flowParam.optional, - typeAnnotation: paramTypeAnnotation, + typeAnnotation: wrapNullable( + isParamTypeAnnotationNullable, + paramTypeAnnotation, + ), }); } - const returnTypeAnnotation = translateTypeAnnotation( - moduleName, - flowFunctionTypeAnnotation.returnType, - types, - aliasMap, + const [returnTypeAnnotation, isReturnTypeAnnotationNullable] = unwrapNullable( + translateTypeAnnotation( + moduleName, + flowFunctionTypeAnnotation.returnType, + types, + aliasMap, + ), ); invariant( @@ -353,9 +354,11 @@ function translateFunctionTypeAnnotation( return { type: 'FunctionTypeAnnotation', - returnTypeAnnotation, + returnTypeAnnotation: wrapNullable( + isReturnTypeAnnotationNullable, + returnTypeAnnotation, + ), params, - nullable, }; } @@ -385,12 +388,9 @@ function buildPropertySchema( return { name: methodName, optional: property.optional, - typeAnnotation: translateFunctionTypeAnnotation( - moduleName, - value, - types, + typeAnnotation: wrapNullable( nullable, - aliasMap, + translateFunctionTypeAnnotation(moduleName, value, types, aliasMap), ), }; } diff --git a/packages/react-native-codegen/src/parsers/flow/modules/utils.js b/packages/react-native-codegen/src/parsers/flow/modules/utils.js new file mode 100644 index 00000000000..8b8aa0b0648 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/modules/utils.js @@ -0,0 +1,45 @@ +/** + * 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. + * + * @flow strict + * @format + */ + +'use strict'; + +import type { + NativeModuleTypeAnnotation, + Nullable, +} from '../../../CodegenSchema.js'; + +function unwrapNullable<+T: NativeModuleTypeAnnotation>( + x: Nullable, +): [T, boolean] { + if (x.type === 'NullableTypeAnnotation') { + return [x.typeAnnotation, true]; + } + + return [x, false]; +} + +function wrapNullable<+T: NativeModuleTypeAnnotation>( + nullable: boolean, + typeAnnotation: T, +): Nullable { + if (!nullable) { + return typeAnnotation; + } + + return { + type: 'NullableTypeAnnotation', + typeAnnotation, + }; +} + +module.exports = { + unwrapNullable, + wrapNullable, +};