diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 8776caaa923..8ffc0061254 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -295,6 +295,16 @@ export type NativeModulePromiseTypeAnnotation = $ReadOnly<{ type: 'PromiseTypeAnnotation', }>; +export type UnionTypeAnnotationMemberType = + | 'NumberTypeAnnotation' + | 'ObjectTypeAnnotation' + | 'StringTypeAnnotation'; + +export type NativeModuleUnionTypeAnnotation = $ReadOnly<{ + type: 'UnionTypeAnnotation', + memberType: UnionTypeAnnotationMemberType, +}>; + export type NativeModuleMixedTypeAnnotation = $ReadOnly<{ type: 'MixedTypeAnnotation', }>; @@ -311,6 +321,7 @@ export type NativeModuleBaseTypeAnnotation = | NativeModuleTypeAliasTypeAnnotation | NativeModuleArrayTypeAnnotation> | NativeModuleObjectTypeAnnotation + | NativeModuleUnionTypeAnnotation | NativeModuleMixedTypeAnnotation; export type NativeModuleParamTypeAnnotation = diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js index 046e86b1c65..d49ed925315 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js @@ -167,6 +167,19 @@ function serializeArg( return wrap(val => `${val}.asObject(rt).asFunction(rt)`); case 'GenericObjectTypeAnnotation': return wrap(val => `${val}.asObject(rt)`); + case 'UnionTypeAnnotation': + switch (typeAnnotation.memberType) { + case 'NumberTypeAnnotation': + return wrap(val => `${val}.asNumber()`); + case 'ObjectTypeAnnotation': + return wrap(val => `${val}.asObject(rt)`); + case 'StringTypeAnnotation': + return wrap(val => `${val}.asString(rt)`); + default: + throw new Error( + `Unsupported union member type for param "${arg.name}, found: ${realTypeAnnotation.memberType}"`, + ); + } case 'ObjectTypeAnnotation': return wrap(val => `${val}.asObject(rt)`); case 'MixedTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index 1f518d3f47e..6e5f97a8551 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -148,6 +148,17 @@ function translatePrimitiveJSTypeToCpp( return wrap('bool'); case 'GenericObjectTypeAnnotation': return wrap('jsi::Object'); + case 'UnionTypeAnnotation': + switch (typeAnnotation.memberType) { + case 'NumberTypeAnnotation': + return wrap('double'); + case 'ObjectTypeAnnotation': + return wrap('jsi::Object'); + case 'StringTypeAnnotation': + return wrap('jsi::String'); + default: + throw new Error(createErrorMessage(realTypeAnnotation.type)); + } case 'ObjectTypeAnnotation': return wrap('jsi::Object'); case 'ArrayTypeAnnotation': diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index 538371a7c49..aa833afbba3 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -156,7 +156,7 @@ function translateFunctionParamToJavaType( imports.add('com.facebook.react.bridge.Callback'); return 'Callback'; default: - (realTypeAnnotation.type: 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -220,7 +220,7 @@ function translateFunctionReturnTypeToJavaType( imports.add('com.facebook.react.bridge.WritableArray'); return wrapIntoNullableIfNeeded('WritableArray'); default: - (realTypeAnnotation.type: 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -272,7 +272,7 @@ function getFalsyReturnStatementFromReturnType( case 'ArrayTypeAnnotation': return 'return null;'; default: - (realTypeAnnotation.type: 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index 4adb37c943c..bca66c4f992 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -171,7 +171,7 @@ function translateReturnTypeToKind( case 'ArrayTypeAnnotation': return 'ArrayKind'; default: - (realTypeAnnotation.type: 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error( `Unknown prop type for returning value, found: ${realTypeAnnotation.type}"`, ); @@ -226,7 +226,7 @@ function translateParamTypeToJniType( case 'FunctionTypeAnnotation': return 'Lcom/facebook/react/bridge/Callback;'; default: - (realTypeAnnotation.type: 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error( `Unknown prop type for method arg, found: ${realTypeAnnotation.type}"`, ); @@ -278,7 +278,7 @@ function translateReturnTypeToJniType( case 'ArrayTypeAnnotation': return 'Lcom/facebook/react/bridge/WritableArray;'; default: - (realTypeAnnotation.type: 'MixedTypeAnnotation'); + (realTypeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error( `Unknown prop type for method return type, found: ${realTypeAnnotation.type}"`, ); diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js index e942ff3c978..82e8d5bc245 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -114,6 +114,8 @@ class StructCollector { } case 'MixedTypeAnnotation': throw new Error('Mixed types are unsupported in structs'); + case 'UnionTypeAnnotation': + throw new Error('Union types are unsupported in structs'); default: { return wrapNullable(nullable, typeAnnotation); } diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js index a74367dcb87..d7f33cecb7a 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -338,7 +338,7 @@ function getReturnObjCType( case 'GenericObjectTypeAnnotation': return wrapIntoNullableIfNeeded('NSDictionary *'); default: - (typeAnnotation.type: 'MixedTypeAnnotation'); + (typeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error( `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, ); @@ -378,7 +378,7 @@ function getReturnJSType( case 'GenericObjectTypeAnnotation': return 'ObjectKind'; default: - (typeAnnotation.type: 'MixedTypeAnnotation'); + (typeAnnotation.type: 'MixedTypeAnnotation' | 'UnionTypeAnnotation'); throw new Error( `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, ); diff --git a/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js index 16f6bd517ba..590d3e939de 100644 --- a/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js @@ -1567,6 +1567,51 @@ const CXX_ONLY_NATIVE_MODULES: SchemaType = { ], }, }, + { + name: 'getUnion', + optional: false, + typeAnnotation: { + type: 'FunctionTypeAnnotation', + returnTypeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'ObjectTypeAnnotation', + }, + params: [ + { + name: 'chooseInt', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'NumberTypeAnnotation', + }, + }, + { + name: 'chooseFloat', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'NumberTypeAnnotation', + }, + }, + { + name: 'chooseObject', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'ObjectTypeAnnotation', + }, + }, + { + name: 'chooseString', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'StringTypeAnnotation', + }, + }, + ], + }, + }, ], }, moduleNames: ['SampleTurboModuleCxx'], diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap index 93a57fc91bc..741eb73ee23 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap @@ -115,11 +115,15 @@ static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getNullableNu auto result = static_cast(&turboModule)->getNullableNumberFromNullableAlias(rt, args[0].isNull() || args[0].isUndefined() ? std::nullopt : std::make_optional(args[0].asObject(rt))); return result ? jsi::Value(std::move(*result)) : jsi::Value::null(); } +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getUnion(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getUnion(rt, args[0].asNumber(), args[1].asNumber(), args[2].asObject(rt), args[3].asString(rt)); +} NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule(\\"SampleTurboModuleCxx\\", jsInvoker) { methodMap_[\\"getMixed\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getMixed}; methodMap_[\\"getNullableNumberFromNullableAlias\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getNullableNumberFromNullableAlias}; + methodMap_[\\"getUnion\\"] = MethodMetadata {4, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getUnion}; } diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap index 7fce7ea9310..8cf7d8ee7f5 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap @@ -209,6 +209,7 @@ protected: public: virtual jsi::Value getMixed(jsi::Runtime &rt, jsi::Value arg) = 0; virtual std::optional getNullableNumberFromNullableAlias(jsi::Runtime &rt, std::optional a) = 0; + virtual jsi::Object getUnion(jsi::Runtime &rt, double chooseInt, double chooseFloat, jsi::Object chooseObject, jsi::String chooseString) = 0; }; @@ -246,6 +247,14 @@ private: return bridging::callFromJs>( rt, &T::getNullableNumberFromNullableAlias, jsInvoker_, instance_, std::move(a)); } + jsi::Object getUnion(jsi::Runtime &rt, double chooseInt, double chooseFloat, jsi::Object chooseObject, jsi::String chooseString) override { + static_assert( + bridging::getParameterCount(&T::getUnion) == 5, + \\"Expected getUnion(...) to have 5 parameters\\"); + + return bridging::callFromJs( + rt, &T::getUnion, jsInvoker_, instance_, std::move(chooseInt), std::move(chooseFloat), std::move(chooseObject), std::move(chooseString)); + } private: T *instance_; diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js index cbbc156c29f..f9f84ee20ac 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js @@ -593,9 +593,15 @@ const CXX_ONLY_NATIVE_MODULE = ` import type {TurboModule} from '../RCTExport'; import * as TurboModuleRegistry from '../TurboModuleRegistry'; +export type ChooseInt = 1 | 2 | 3; +export type ChooseFloat = 1.44 | 2.88 | 5.76; +export type ChooseObject = {} | {low: string}; +export type ChooseString = 'One' | 'Two' | 'Three'; + export interface Spec extends TurboModule { +getCallback: () => () => void; +getMixed: (arg: mixed) => mixed; + +getUnion: (chooseInt: ChooseInt, chooseFloat: ChooseFloat, chooseObject: ChooseObject, chooseString: ChooseString) => ChooseObject; } export default TurboModuleRegistry.getEnforcing('SampleTurboModuleCxx'); 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 aef18a0ef6c..abe2c393988 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 @@ -77,6 +77,51 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] } ] } + }, + { + 'name': 'getUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + }, + 'params': [ + { + 'name': 'chooseInt', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + } + }, + { + 'name': 'chooseFloat', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + } + }, + { + 'name': 'chooseObject', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + } + }, + { + 'name': 'chooseString', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'StringTypeAnnotation' + } + } + ] + } } ] }, diff --git a/packages/react-native-codegen/src/parsers/flow/modules/errors.js b/packages/react-native-codegen/src/parsers/flow/modules/errors.js index c8bb4253885..03bc6d63be7 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/errors.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/errors.js @@ -227,6 +227,30 @@ class UnsupportedFunctionReturnTypeAnnotationParserError extends ParserError { } } +/** + * Union parsing errors + */ + +class UnsupportedUnionTypeAnnotationParserError extends ParserError { + constructor( + hasteModuleName: string, + arrayElementTypeAST: $FlowFixMe, + types: string[], + ) { + super( + hasteModuleName, + arrayElementTypeAST, + `Union members must be of the same type, but multiple types were found ${types.join( + ', ', + )}'.`, + ); + } +} + +/** + * Module parsing errors + */ + class UnusedModuleFlowInterfaceParserError extends ParserError { constructor(hasteModuleName: string, flowInterface: $FlowFixMe) { super( @@ -323,6 +347,7 @@ module.exports = { UnsupportedFlowTypeAnnotationParserError, UnsupportedFunctionParamTypeAnnotationParserError, UnsupportedFunctionReturnTypeAnnotationParserError, + UnsupportedUnionTypeAnnotationParserError, UnsupportedModulePropertyParserError, UnsupportedObjectPropertyTypeAnnotationParserError, UnsupportedObjectPropertyValueTypeAnnotationParserError, 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 38ce80db4e7..528813922cf 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -44,6 +44,7 @@ const { UnsupportedFlowTypeAnnotationParserError, UnsupportedFunctionParamTypeAnnotationParserError, UnsupportedFunctionReturnTypeAnnotationParserError, + UnsupportedUnionTypeAnnotationParserError, UnsupportedModulePropertyParserError, UnsupportedObjectPropertyTypeAnnotationParserError, UnsupportedObjectPropertyValueTypeAnnotationParserError, @@ -367,6 +368,33 @@ function translateTypeAnnotation( ), ); } + case 'UnionTypeAnnotation': { + if (cxxOnly) { + // Remap literal names + const unionTypes = typeAnnotation.types + .map( + item => + item.type + .replace('NumberLiteralTypeAnnotation', 'NumberTypeAnnotation') + .replace('StringLiteralTypeAnnotation', 'StringTypeAnnotation'), + // ObjectAnnotation is already 'correct' + ) + .filter((value, index, self) => self.indexOf(value) === index); + // Only support unionTypes of the same kind + if (unionTypes.length > 1) { + throw new UnsupportedUnionTypeAnnotationParserError( + hasteModuleName, + typeAnnotation, + unionTypes, + ); + } + return wrapNullable(nullable, { + type: 'UnionTypeAnnotation', + memberType: unionTypes[0], + }); + } + // Fallthrough + } case 'MixedTypeAnnotation': { if (cxxOnly) { return wrapNullable(nullable, { diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js index 39956142c70..f776e26ae3c 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js @@ -608,9 +608,15 @@ const CXX_ONLY_NATIVE_MODULE = ` import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; +export type ChooseInt = 1 | 2 | 3; +export type ChooseFloat = 1.44 | 2.88 | 5.76; +export type ChooseObject = {} | {low: string}; +export type ChooseString = 'One' | 'Two' | 'Three'; + export interface Spec extends TurboModule { readonly getCallback: () => () => void; readonly getMixed: (arg: unknown) => unknown; + readonly getUnion: (chooseInt: ChooseInt, chooseFloat: ChooseFloat, chooseObject: ChooseObject, chooseString: ChooseString) => ChooseObject; } export default TurboModuleRegistry.getEnforcing( diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap index 20420a83361..e56dfc7871c 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap @@ -75,6 +75,51 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL } ] } + }, + { + 'name': 'getUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + }, + 'params': [ + { + 'name': 'chooseInt', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + } + }, + { + 'name': 'chooseFloat', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + } + }, + { + 'name': 'chooseObject', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + } + }, + { + 'name': 'chooseString', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'StringTypeAnnotation' + } + } + ] + } } ] }, @@ -369,6 +414,43 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR }" `; +exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliases': {}, + 'spec': { + 'properties': [ + { + 'name': 'getArray', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'ArrayTypeAnnotation' + }, + 'params': [ + { + 'name': 'arg', + 'optional': false, + 'typeAnnotation': { + 'type': 'ArrayTypeAnnotation' + } + } + ] + } + } + ] + }, + 'moduleNames': [ + 'SampleTurboModule' + ] + } + } +}" +`; + exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY2_WITH_ALIAS 1`] = ` "{ 'modules': { @@ -412,43 +494,6 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_AR }" `; -exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE 1`] = ` -"{ - 'modules': { - 'NativeSampleTurboModule': { - 'type': 'NativeModule', - 'aliases': {}, - 'spec': { - 'properties': [ - { - 'name': 'getArray', - 'optional': false, - 'typeAnnotation': { - 'type': 'FunctionTypeAnnotation', - 'returnTypeAnnotation': { - 'type': 'ArrayTypeAnnotation' - }, - 'params': [ - { - 'name': 'arg', - 'optional': false, - 'typeAnnotation': { - 'type': 'ArrayTypeAnnotation' - } - } - ] - } - } - ] - }, - 'moduleNames': [ - 'SampleTurboModule' - ] - } - } -}" -`; - exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_ARRAY2_WITH_UNION_AND_TOUPLE 1`] = ` "{ 'modules': { diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/errors.js b/packages/react-native-codegen/src/parsers/typescript/modules/errors.js index 357135d7875..76064b5f056 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/errors.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/errors.js @@ -223,6 +223,30 @@ class UnsupportedFunctionReturnTypeAnnotationParserError extends ParserError { } } +/** + * Union parsing errors + */ + +class UnsupportedTypeScriptUnionTypeAnnotationParserError extends ParserError { + constructor( + hasteModuleName: string, + arrayElementTypeAST: $FlowFixMe, + types: string[], + ) { + super( + hasteModuleName, + arrayElementTypeAST, + `Union members must be of the same type, but multiple types were found ${types.join( + ', ', + )}'.`, + ); + } +} + +/** + * Module parsing errors + */ + class UnusedModuleTypeScriptInterfaceParserError extends ParserError { constructor(hasteModuleName: string, flowInterface: $FlowFixMe) { super( @@ -319,6 +343,7 @@ module.exports = { UnsupportedTypeScriptTypeAnnotationParserError, UnsupportedFunctionParamTypeAnnotationParserError, UnsupportedFunctionReturnTypeAnnotationParserError, + UnsupportedTypeScriptUnionTypeAnnotationParserError, UnsupportedModulePropertyParserError, UnsupportedObjectPropertyTypeAnnotationParserError, UnsupportedObjectPropertyValueTypeAnnotationParserError, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index d0e395e31ac..5db27cc5f95 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -44,6 +44,7 @@ const { UnsupportedTypeScriptTypeAnnotationParserError, UnsupportedFunctionParamTypeAnnotationParserError, UnsupportedFunctionReturnTypeAnnotationParserError, + UnsupportedTypeScriptUnionTypeAnnotationParserError, UnsupportedModulePropertyParserError, UnsupportedObjectPropertyTypeAnnotationParserError, UnsupportedObjectPropertyValueTypeAnnotationParserError, @@ -419,6 +420,33 @@ function translateTypeAnnotation( ), ); } + case 'TSUnionType': { + if (cxxOnly) { + // Remap literal names + const unionTypes = typeAnnotation.types + .map(item => + item.literal + ? item.literal.type + .replace('NumericLiteral', 'NumberTypeAnnotation') + .replace('StringLiteral', 'StringTypeAnnotation') + : 'ObjectTypeAnnotation', + ) + .filter((value, index, self) => self.indexOf(value) === index); + // Only support unionTypes of the same kind + if (unionTypes.length > 1) { + throw new UnsupportedTypeScriptUnionTypeAnnotationParserError( + hasteModuleName, + typeAnnotation, + unionTypes, + ); + } + return wrapNullable(nullable, { + type: 'UnionTypeAnnotation', + memberType: unionTypes[0], + }); + } + // Fallthrough + } case 'TSUnknownKeyword': { if (cxxOnly) { return wrapNullable(nullable, {