Skip to content

Commit 745f3ee

Browse files
react-native-code-gen Add Enum Type support for iOS/Android TurboModules
Summary: Adding enum support to Android/iOS generated code Changelog: [General][Added] - react-native-code-gen Add Enum Type support for iOS/Android TurboModules Reviewed By: javache Differential Revision: D38967241 fbshipit-source-id: d8bb3019dab198e16905a6422e877cd751119122
1 parent e9b89b5 commit 745f3ee

19 files changed

+347
-7
lines changed

packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js

+27
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ function translateFunctionParamToJavaType(
138138
return !isRequired ? 'Double' : 'double';
139139
case 'BooleanTypeAnnotation':
140140
return !isRequired ? 'Boolean' : 'boolean';
141+
case 'EnumDeclaration':
142+
switch (realTypeAnnotation.memberType) {
143+
case 'NumberTypeAnnotation':
144+
return !isRequired ? 'Double' : 'double';
145+
case 'StringTypeAnnotation':
146+
return wrapIntoNullableIfNeeded('String');
147+
default:
148+
throw new Error(createErrorMessage(realTypeAnnotation.type));
149+
}
141150
case 'ObjectTypeAnnotation':
142151
imports.add('com.facebook.react.bridge.ReadableMap');
143152
if (typeAnnotation.type === 'TypeAliasTypeAnnotation') {
@@ -213,6 +222,15 @@ function translateFunctionReturnTypeToJavaType(
213222
return nullable ? 'Double' : 'double';
214223
case 'BooleanTypeAnnotation':
215224
return nullable ? 'Boolean' : 'boolean';
225+
case 'EnumDeclaration':
226+
switch (realTypeAnnotation.memberType) {
227+
case 'NumberTypeAnnotation':
228+
return nullable ? 'Double' : 'double';
229+
case 'StringTypeAnnotation':
230+
return wrapIntoNullableIfNeeded('String');
231+
default:
232+
throw new Error(createErrorMessage(realTypeAnnotation.type));
233+
}
216234
case 'ObjectTypeAnnotation':
217235
imports.add('com.facebook.react.bridge.WritableMap');
218236
return wrapIntoNullableIfNeeded('WritableMap');
@@ -269,6 +287,15 @@ function getFalsyReturnStatementFromReturnType(
269287
return nullable ? 'return null;' : 'return 0;';
270288
case 'BooleanTypeAnnotation':
271289
return nullable ? 'return null;' : 'return false;';
290+
case 'EnumDeclaration':
291+
switch (realTypeAnnotation.memberType) {
292+
case 'NumberTypeAnnotation':
293+
return nullable ? 'return null;' : 'return 0;';
294+
case 'StringTypeAnnotation':
295+
return nullable ? 'return null;' : 'return "";';
296+
default:
297+
throw new Error(createErrorMessage(realTypeAnnotation.type));
298+
}
272299
case 'StringTypeAnnotation':
273300
return nullable ? 'return null;' : 'return "";';
274301
case 'ObjectTypeAnnotation':

packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js

+33
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ function translateReturnTypeToKind(
154154
return 'StringKind';
155155
case 'BooleanTypeAnnotation':
156156
return 'BooleanKind';
157+
case 'EnumDeclaration':
158+
switch (typeAnnotation.memberType) {
159+
case 'NumberTypeAnnotation':
160+
return 'NumberKind';
161+
case 'StringTypeAnnotation':
162+
return 'StringKind';
163+
default:
164+
throw new Error(
165+
`Unknown enum prop type for returning value, found: ${realTypeAnnotation.type}"`,
166+
);
167+
}
157168
case 'NumberTypeAnnotation':
158169
return 'NumberKind';
159170
case 'DoubleTypeAnnotation':
@@ -212,6 +223,17 @@ function translateParamTypeToJniType(
212223
return 'Ljava/lang/String;';
213224
case 'BooleanTypeAnnotation':
214225
return !isRequired ? 'Ljava/lang/Boolean;' : 'Z';
226+
case 'EnumDeclaration':
227+
switch (typeAnnotation.memberType) {
228+
case 'NumberTypeAnnotation':
229+
return !isRequired ? 'Ljava/lang/Double;' : 'D';
230+
case 'StringTypeAnnotation':
231+
return 'Ljava/lang/String;';
232+
default:
233+
throw new Error(
234+
`Unknown enum prop type for method arg, found: ${realTypeAnnotation.type}"`,
235+
);
236+
}
215237
case 'NumberTypeAnnotation':
216238
return !isRequired ? 'Ljava/lang/Double;' : 'D';
217239
case 'DoubleTypeAnnotation':
@@ -267,6 +289,17 @@ function translateReturnTypeToJniType(
267289
return 'Ljava/lang/String;';
268290
case 'BooleanTypeAnnotation':
269291
return nullable ? 'Ljava/lang/Boolean;' : 'Z';
292+
case 'EnumDeclaration':
293+
switch (typeAnnotation.memberType) {
294+
case 'NumberTypeAnnotation':
295+
return nullable ? 'Ljava/lang/Double;' : 'D';
296+
case 'StringTypeAnnotation':
297+
return 'Ljava/lang/String;';
298+
default:
299+
throw new Error(
300+
`Unknown enum prop type for method return type, found: ${realTypeAnnotation.type}"`,
301+
);
302+
}
270303
case 'NumberTypeAnnotation':
271304
return nullable ? 'Ljava/lang/Double;' : 'D';
272305
case 'DoubleTypeAnnotation':

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
NativeModuleDoubleTypeAnnotation,
2020
NativeModuleFloatTypeAnnotation,
2121
NativeModuleBooleanTypeAnnotation,
22+
NativeModuleEnumDeclaration,
2223
NativeModuleGenericObjectTypeAnnotation,
2324
ReservedTypeAnnotation,
2425
NativeModuleTypeAliasTypeAnnotation,
@@ -63,6 +64,7 @@ export type StructTypeAnnotation =
6364
| NativeModuleDoubleTypeAnnotation
6465
| NativeModuleFloatTypeAnnotation
6566
| NativeModuleBooleanTypeAnnotation
67+
| NativeModuleEnumDeclaration
6668
| NativeModuleGenericObjectTypeAnnotation
6769
| ReservedTypeAnnotation
6870
| NativeModuleTypeAliasTypeAnnotation
@@ -113,7 +115,7 @@ class StructCollector {
113115
return wrapNullable(nullable, typeAnnotation);
114116
}
115117
case 'EnumDeclaration':
116-
throw new Error('Enum types are unsupported in structs');
118+
return wrapNullable(nullable, typeAnnotation);
117119
case 'MixedTypeAnnotation':
118120
throw new Error('Mixed types are unsupported in structs');
119121
case 'UnionTypeAnnotation':

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeConstantsStruct.js

+22
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@ function toObjCType(
104104
return wrapOptional('double');
105105
case 'BooleanTypeAnnotation':
106106
return wrapOptional('bool');
107+
case 'EnumDeclaration':
108+
switch (typeAnnotation.memberType) {
109+
case 'NumberTypeAnnotation':
110+
return wrapOptional('double');
111+
case 'StringTypeAnnotation':
112+
return 'NSString *';
113+
default:
114+
throw new Error(
115+
`Couldn't convert enum into ObjC type: ${typeAnnotation.type}"`,
116+
);
117+
}
107118
case 'GenericObjectTypeAnnotation':
108119
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable ';
109120
case 'ArrayTypeAnnotation':
@@ -171,6 +182,17 @@ function toObjCValue(
171182
return wrapPrimitive('double');
172183
case 'BooleanTypeAnnotation':
173184
return wrapPrimitive('BOOL');
185+
case 'EnumDeclaration':
186+
switch (typeAnnotation.memberType) {
187+
case 'NumberTypeAnnotation':
188+
return wrapPrimitive('double');
189+
case 'StringTypeAnnotation':
190+
return value;
191+
default:
192+
throw new Error(
193+
`Couldn't convert enum into ObjC value: ${typeAnnotation.type}"`,
194+
);
195+
}
174196
case 'GenericObjectTypeAnnotation':
175197
return value;
176198
case 'ArrayTypeAnnotation':

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/header/serializeRegularStruct.js

+22
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ function toObjCType(
9595
return wrapOptional('double');
9696
case 'BooleanTypeAnnotation':
9797
return wrapOptional('bool');
98+
case 'EnumDeclaration':
99+
switch (typeAnnotation.memberType) {
100+
case 'NumberTypeAnnotation':
101+
return wrapOptional('double');
102+
case 'StringTypeAnnotation':
103+
return 'NSString *';
104+
default:
105+
throw new Error(
106+
`Couldn't convert enum into ObjC type: ${typeAnnotation.type}"`,
107+
);
108+
}
98109
case 'GenericObjectTypeAnnotation':
99110
return isRequired ? 'id<NSObject> ' : 'id<NSObject> _Nullable';
100111
case 'ArrayTypeAnnotation':
@@ -161,6 +172,17 @@ function toObjCValue(
161172
return RCTBridgingTo('Double');
162173
case 'BooleanTypeAnnotation':
163174
return RCTBridgingTo('Bool');
175+
case 'EnumDeclaration':
176+
switch (typeAnnotation.memberType) {
177+
case 'NumberTypeAnnotation':
178+
return RCTBridgingTo('Double');
179+
case 'StringTypeAnnotation':
180+
return RCTBridgingTo('String');
181+
default:
182+
throw new Error(
183+
`Couldn't convert enum into ObjC value: ${typeAnnotation.type}"`,
184+
);
185+
}
164186
case 'GenericObjectTypeAnnotation':
165187
return value;
166188
case 'ArrayTypeAnnotation':

packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js

+33
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,17 @@ function getParamObjCType(
271271
return notStruct(notRequired ? 'NSNumber *' : 'double');
272272
case 'BooleanTypeAnnotation':
273273
return notStruct(notRequired ? 'NSNumber *' : 'BOOL');
274+
case 'EnumDeclaration':
275+
switch (typeAnnotation.memberType) {
276+
case 'NumberTypeAnnotation':
277+
return notStruct(notRequired ? 'NSNumber *' : 'double');
278+
case 'StringTypeAnnotation':
279+
return notStruct(wrapIntoNullableIfNeeded('NSString *'));
280+
default:
281+
throw new Error(
282+
`Unsupported enum type for param "${paramName}" in ${methodName}. Found: ${typeAnnotation.type}`,
283+
);
284+
}
274285
case 'GenericObjectTypeAnnotation':
275286
return notStruct(wrapIntoNullableIfNeeded('NSDictionary *'));
276287
default:
@@ -335,6 +346,17 @@ function getReturnObjCType(
335346
return wrapIntoNullableIfNeeded('NSNumber *');
336347
case 'BooleanTypeAnnotation':
337348
return wrapIntoNullableIfNeeded('NSNumber *');
349+
case 'EnumDeclaration':
350+
switch (typeAnnotation.memberType) {
351+
case 'NumberTypeAnnotation':
352+
return wrapIntoNullableIfNeeded('NSNumber *');
353+
case 'StringTypeAnnotation':
354+
return wrapIntoNullableIfNeeded('NSString *');
355+
default:
356+
throw new Error(
357+
`Unsupported enum return type for ${methodName}. Found: ${typeAnnotation.type}`,
358+
);
359+
}
338360
case 'GenericObjectTypeAnnotation':
339361
return wrapIntoNullableIfNeeded('NSDictionary *');
340362
default:
@@ -380,6 +402,17 @@ function getReturnJSType(
380402
return 'BooleanKind';
381403
case 'GenericObjectTypeAnnotation':
382404
return 'ObjectKind';
405+
case 'EnumDeclaration':
406+
switch (typeAnnotation.memberType) {
407+
case 'NumberTypeAnnotation':
408+
return 'NumberKind';
409+
case 'StringTypeAnnotation':
410+
return 'StringKind';
411+
default:
412+
throw new Error(
413+
`Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`,
414+
);
415+
}
383416
default:
384417
(typeAnnotation.type:
385418
| 'EnumDeclaration'

packages/react-native-codegen/src/generators/modules/__test_fixtures__/fixtures.js

+36
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,42 @@ const SIMPLE_NATIVE_MODULES: SchemaType = {
275275
],
276276
},
277277
},
278+
{
279+
name: 'getEnums',
280+
optional: false,
281+
typeAnnotation: {
282+
type: 'FunctionTypeAnnotation',
283+
returnTypeAnnotation: {
284+
type: 'StringTypeAnnotation',
285+
},
286+
params: [
287+
{
288+
name: 'enumInt',
289+
optional: false,
290+
typeAnnotation: {
291+
type: 'EnumDeclaration',
292+
memberType: 'NumberTypeAnnotation',
293+
},
294+
},
295+
{
296+
name: 'enumFloat',
297+
optional: false,
298+
typeAnnotation: {
299+
type: 'EnumDeclaration',
300+
memberType: 'NumberTypeAnnotation',
301+
},
302+
},
303+
{
304+
name: 'enumString',
305+
optional: false,
306+
typeAnnotation: {
307+
type: 'EnumDeclaration',
308+
memberType: 'StringTypeAnnotation',
309+
},
310+
},
311+
],
312+
},
313+
},
278314
],
279315
},
280316
moduleNames: ['SampleTurboModule'],

packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleCpp-test.js.snap

+4
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,9 @@ static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithC
337337
static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithPromise(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
338338
return static_cast<NativeSampleTurboModuleCxxSpecJSI *>(&turboModule)->getValueWithPromise(rt, args[0].asBool());
339339
}
340+
static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getEnums(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
341+
return static_cast<NativeSampleTurboModuleCxxSpecJSI *>(&turboModule)->getEnums(rt, args[0].asNumber(), args[1].asNumber(), args[2].asString(rt));
342+
}
340343
341344
NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
342345
: TurboModule(\\"SampleTurboModule\\", jsInvoker) {
@@ -351,6 +354,7 @@ NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared
351354
methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValue};
352355
methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithCallback};
353356
methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getValueWithPromise};
357+
methodMap_[\\"getEnums\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getEnums};
354358
}
355359
356360

packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleH-test.js.snap

+9
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ public:
668668
virtual jsi::Object getValue(jsi::Runtime &rt, double x, jsi::String y, jsi::Object z) = 0;
669669
virtual void getValueWithCallback(jsi::Runtime &rt, jsi::Function callback) = 0;
670670
virtual jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) = 0;
671+
virtual jsi::String getEnums(jsi::Runtime &rt, double enumInt, double enumFloat, jsi::String enumString) = 0;
671672
672673
};
673674
@@ -777,6 +778,14 @@ private:
777778
return bridging::callFromJs<jsi::Value>(
778779
rt, &T::getValueWithPromise, jsInvoker_, instance_, std::move(error));
779780
}
781+
jsi::String getEnums(jsi::Runtime &rt, double enumInt, double enumFloat, jsi::String enumString) override {
782+
static_assert(
783+
bridging::getParameterCount(&T::getEnums) == 4,
784+
\\"Expected getEnums(...) to have 4 parameters\\");
785+
786+
return bridging::callFromJs<jsi::String>(
787+
rt, &T::getEnums, jsInvoker_, instance_, std::move(enumInt), std::move(enumFloat), std::move(enumString));
788+
}
780789
781790
private:
782791
T *instance_;

packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap

+3
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,9 @@ namespace JS {
933933
- (void)getValueWithPromise:(BOOL)error
934934
resolve:(RCTPromiseResolveBlock)resolve
935935
reject:(RCTPromiseRejectBlock)reject;
936+
- (NSString *)getEnums:(double)enumInt
937+
enumFloat:(double)enumFloat
938+
enumString:(NSString *)enumString;
936939
- (facebook::react::ModuleConstants<JS::NativeSampleTurboModule::Constants::Builder>)constantsToExport;
937940
- (facebook::react::ModuleConstants<JS::NativeSampleTurboModule::Constants::Builder>)getConstants;
938941

packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap

+4
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,10 @@ public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaMo
376376
@ReactMethod
377377
@DoNotStrip
378378
public abstract void getValueWithPromise(boolean error, Promise promise);
379+
380+
@ReactMethod(isBlockingSynchronousMethod = true)
381+
@DoNotStrip
382+
public abstract String getEnums(double enumInt, double enumFloat, String enumString);
379383
}
380384
",
381385
}

packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap

+6
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,11 @@ static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getVal
384384
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, \\"getValueWithPromise\\", \\"(ZLcom/facebook/react/bridge/Promise;)V\\", args, count, cachedMethodId);
385385
}
386386
387+
static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getEnums(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
388+
static jmethodID cachedMethodId = nullptr;
389+
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, StringKind, \\"getEnums\\", \\"(DDLjava/lang/String;)Ljava/lang/String;\\", args, count, cachedMethodId);
390+
}
391+
387392
NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams &params)
388393
: JavaTurboModule(params) {
389394
methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants};
@@ -397,6 +402,7 @@ NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboMo
397402
methodMap_[\\"getValue\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleSpecJSI_getValue};
398403
methodMap_[\\"getValueWithCallback\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithCallback};
399404
methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithPromise};
405+
methodMap_[\\"getEnums\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleSpecJSI_getEnums};
400406
}
401407
402408
std::shared_ptr<TurboModule> simple_native_modules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {

packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap

+7
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ namespace facebook {
453453
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, PromiseKind, \\"getValueWithPromise\\", @selector(getValueWithPromise:resolve:reject:), args, count);
454454
}
455455
456+
static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getEnums(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
457+
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, StringKind, \\"getEnums\\", @selector(getEnums:enumFloat:enumString:), args, count);
458+
}
459+
456460
static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
457461
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getConstants\\", @selector(getConstants), args, count);
458462
}
@@ -490,6 +494,9 @@ namespace facebook {
490494
methodMap_[\\"getValueWithPromise\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleSpecJSI_getValueWithPromise};
491495
492496
497+
methodMap_[\\"getEnums\\"] = MethodMetadata {3, __hostFunction_NativeSampleTurboModuleSpecJSI_getEnums};
498+
499+
493500
methodMap_[\\"getConstants\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_getConstants};
494501
495502
}

0 commit comments

Comments
 (0)