Skip to content

Commit 2eccd59

Browse files
react-native-code-gen Add Union Type support for Java/ObjC TurboModules (#35312)
Summary: Pull Request resolved: #35312 Changelog: [General][Added] react-native-code-gen Add Union Type support for Java/ObjC TurboModules Reviewed By: javache Differential Revision: D41216605 fbshipit-source-id: d411abed66c694d855ede40725667cbc7067538f
1 parent 72d3da1 commit 2eccd59

File tree

9 files changed

+323
-56
lines changed

9 files changed

+323
-56
lines changed

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

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ function translateFunctionParamToJavaType(
148148
default:
149149
throw new Error(createErrorMessage(realTypeAnnotation.type));
150150
}
151+
case 'UnionTypeAnnotation':
152+
switch (typeAnnotation.memberType) {
153+
case 'NumberTypeAnnotation':
154+
return wrapNullable('double', 'Double');
155+
case 'ObjectTypeAnnotation':
156+
imports.add('com.facebook.react.bridge.ReadableMap');
157+
return wrapNullable('ReadableMap');
158+
case 'StringTypeAnnotation':
159+
return wrapNullable('String');
160+
default:
161+
throw new Error(
162+
`Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`,
163+
);
164+
}
151165
case 'ObjectTypeAnnotation':
152166
imports.add('com.facebook.react.bridge.ReadableMap');
153167
return wrapNullable('ReadableMap');
@@ -162,10 +176,7 @@ function translateFunctionParamToJavaType(
162176
imports.add('com.facebook.react.bridge.Callback');
163177
return wrapNullable('Callback');
164178
default:
165-
(realTypeAnnotation.type:
166-
| 'EnumDeclaration'
167-
| 'MixedTypeAnnotation'
168-
| 'UnionTypeAnnotation');
179+
(realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
169180
throw new Error(createErrorMessage(realTypeAnnotation.type));
170181
}
171182
}
@@ -229,6 +240,20 @@ function translateFunctionReturnTypeToJavaType(
229240
default:
230241
throw new Error(createErrorMessage(realTypeAnnotation.type));
231242
}
243+
case 'UnionTypeAnnotation':
244+
switch (realTypeAnnotation.memberType) {
245+
case 'NumberTypeAnnotation':
246+
return wrapNullable('double', 'Double');
247+
case 'ObjectTypeAnnotation':
248+
imports.add('com.facebook.react.bridge.WritableMap');
249+
return wrapNullable('WritableMap');
250+
case 'StringTypeAnnotation':
251+
return wrapNullable('String');
252+
default:
253+
throw new Error(
254+
`Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`,
255+
);
256+
}
232257
case 'ObjectTypeAnnotation':
233258
imports.add('com.facebook.react.bridge.WritableMap');
234259
return wrapNullable('WritableMap');
@@ -239,10 +264,7 @@ function translateFunctionReturnTypeToJavaType(
239264
imports.add('com.facebook.react.bridge.WritableArray');
240265
return wrapNullable('WritableArray');
241266
default:
242-
(realTypeAnnotation.type:
243-
| 'EnumDeclaration'
244-
| 'MixedTypeAnnotation'
245-
| 'UnionTypeAnnotation');
267+
(realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
246268
throw new Error(createErrorMessage(realTypeAnnotation.type));
247269
}
248270
}
@@ -294,6 +316,19 @@ function getFalsyReturnStatementFromReturnType(
294316
default:
295317
throw new Error(createErrorMessage(realTypeAnnotation.type));
296318
}
319+
case 'UnionTypeAnnotation':
320+
switch (realTypeAnnotation.memberType) {
321+
case 'NumberTypeAnnotation':
322+
return nullable ? 'return null;' : 'return 0;';
323+
case 'ObjectTypeAnnotation':
324+
return 'return null;';
325+
case 'StringTypeAnnotation':
326+
return nullable ? 'return null;' : 'return "";';
327+
default:
328+
throw new Error(
329+
`Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`,
330+
);
331+
}
297332
case 'StringTypeAnnotation':
298333
return nullable ? 'return null;' : 'return "";';
299334
case 'ObjectTypeAnnotation':
@@ -303,10 +338,7 @@ function getFalsyReturnStatementFromReturnType(
303338
case 'ArrayTypeAnnotation':
304339
return 'return null;';
305340
default:
306-
(realTypeAnnotation.type:
307-
| 'EnumDeclaration'
308-
| 'MixedTypeAnnotation'
309-
| 'UnionTypeAnnotation');
341+
(realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
310342
throw new Error(createErrorMessage(realTypeAnnotation.type));
311343
}
312344
}

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

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ function translateReturnTypeToKind(
165165
`Unknown enum prop type for returning value, found: ${realTypeAnnotation.type}"`,
166166
);
167167
}
168+
case 'UnionTypeAnnotation':
169+
switch (typeAnnotation.memberType) {
170+
case 'NumberTypeAnnotation':
171+
return 'NumberKind';
172+
case 'ObjectTypeAnnotation':
173+
return 'ObjectKind';
174+
case 'StringTypeAnnotation':
175+
return 'StringKind';
176+
default:
177+
throw new Error(
178+
`Unsupported union member returning value, found: ${realTypeAnnotation.memberType}"`,
179+
);
180+
}
168181
case 'NumberTypeAnnotation':
169182
return 'NumberKind';
170183
case 'DoubleTypeAnnotation':
@@ -182,10 +195,7 @@ function translateReturnTypeToKind(
182195
case 'ArrayTypeAnnotation':
183196
return 'ArrayKind';
184197
default:
185-
(realTypeAnnotation.type:
186-
| 'EnumDeclaration'
187-
| 'MixedTypeAnnotation'
188-
| 'UnionTypeAnnotation');
198+
(realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
189199
throw new Error(
190200
`Unknown prop type for returning value, found: ${realTypeAnnotation.type}"`,
191201
);
@@ -234,6 +244,19 @@ function translateParamTypeToJniType(
234244
`Unknown enum prop type for method arg, found: ${realTypeAnnotation.type}"`,
235245
);
236246
}
247+
case 'UnionTypeAnnotation':
248+
switch (typeAnnotation.memberType) {
249+
case 'NumberTypeAnnotation':
250+
return !isRequired ? 'Ljava/lang/Double;' : 'D';
251+
case 'ObjectTypeAnnotation':
252+
return 'Lcom/facebook/react/bridge/ReadableMap;';
253+
case 'StringTypeAnnotation':
254+
return 'Ljava/lang/String;';
255+
default:
256+
throw new Error(
257+
`Unsupported union prop value, found: ${realTypeAnnotation.memberType}"`,
258+
);
259+
}
237260
case 'NumberTypeAnnotation':
238261
return !isRequired ? 'Ljava/lang/Double;' : 'D';
239262
case 'DoubleTypeAnnotation':
@@ -251,10 +274,7 @@ function translateParamTypeToJniType(
251274
case 'FunctionTypeAnnotation':
252275
return 'Lcom/facebook/react/bridge/Callback;';
253276
default:
254-
(realTypeAnnotation.type:
255-
| 'EnumDeclaration'
256-
| 'MixedTypeAnnotation'
257-
| 'UnionTypeAnnotation');
277+
(realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
258278
throw new Error(
259279
`Unknown prop type for method arg, found: ${realTypeAnnotation.type}"`,
260280
);
@@ -300,6 +320,19 @@ function translateReturnTypeToJniType(
300320
`Unknown enum prop type for method return type, found: ${realTypeAnnotation.type}"`,
301321
);
302322
}
323+
case 'UnionTypeAnnotation':
324+
switch (typeAnnotation.memberType) {
325+
case 'NumberTypeAnnotation':
326+
return nullable ? 'Ljava/lang/Double;' : 'D';
327+
case 'ObjectTypeAnnotation':
328+
return 'Lcom/facebook/react/bridge/WritableMap;';
329+
case 'StringTypeAnnotation':
330+
return 'Ljava/lang/String;';
331+
default:
332+
throw new Error(
333+
`Unsupported union member type, found: ${realTypeAnnotation.memberType}"`,
334+
);
335+
}
303336
case 'NumberTypeAnnotation':
304337
return nullable ? 'Ljava/lang/Double;' : 'D';
305338
case 'DoubleTypeAnnotation':
@@ -317,10 +350,7 @@ function translateReturnTypeToJniType(
317350
case 'ArrayTypeAnnotation':
318351
return 'Lcom/facebook/react/bridge/WritableArray;';
319352
default:
320-
(realTypeAnnotation.type:
321-
| 'EnumDeclaration'
322-
| 'MixedTypeAnnotation'
323-
| 'UnionTypeAnnotation');
353+
(realTypeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
324354
throw new Error(
325355
`Unknown prop type for method return type, found: ${realTypeAnnotation.type}"`,
326356
);

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

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,25 @@ function getReturnObjCType(
357357
`Unsupported enum return type for ${methodName}. Found: ${typeAnnotation.type}`,
358358
);
359359
}
360+
case 'UnionTypeAnnotation':
361+
switch (typeAnnotation.memberType) {
362+
case 'NumberTypeAnnotation':
363+
return wrapIntoNullableIfNeeded('NSNumber *');
364+
case 'ObjectTypeAnnotation':
365+
return wrapIntoNullableIfNeeded('NSDictionary *');
366+
case 'StringTypeAnnotation':
367+
// TODO: Can NSString * returns not be _Nullable?
368+
// In the legacy codegen, we don't surround NSSTring * with _Nullable
369+
return wrapIntoNullableIfNeeded('NSString *');
370+
default:
371+
throw new Error(
372+
`Unsupported union return type for ${methodName}, found: ${typeAnnotation.memberType}"`,
373+
);
374+
}
360375
case 'GenericObjectTypeAnnotation':
361376
return wrapIntoNullableIfNeeded('NSDictionary *');
362377
default:
363-
(typeAnnotation.type:
364-
| 'EnumDeclaration'
365-
| 'MixedTypeAnnotation'
366-
| 'UnionTypeAnnotation');
378+
(typeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
367379
throw new Error(
368380
`Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`,
369381
);
@@ -413,11 +425,21 @@ function getReturnJSType(
413425
`Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`,
414426
);
415427
}
428+
case 'UnionTypeAnnotation':
429+
switch (typeAnnotation.memberType) {
430+
case 'NumberTypeAnnotation':
431+
return 'NumberKind';
432+
case 'ObjectTypeAnnotation':
433+
return 'ObjectKind';
434+
case 'StringTypeAnnotation':
435+
return 'StringKind';
436+
default:
437+
throw new Error(
438+
`Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`,
439+
);
440+
}
416441
default:
417-
(typeAnnotation.type:
418-
| 'EnumDeclaration'
419-
| 'MixedTypeAnnotation'
420-
| 'UnionTypeAnnotation');
442+
(typeAnnotation.type: 'EnumDeclaration' | 'MixedTypeAnnotation');
421443
throw new Error(
422444
`Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`,
423445
);

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,35 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
529529
530530
`;
531531

532+
const NATIVE_MODULE_WITH_UNION = `
533+
/**
534+
* Copyright (c) Meta Platforms, Inc. and affiliates.
535+
*
536+
* This source code is licensed under the MIT license found in the
537+
* LICENSE file in the root directory of this source tree.
538+
*
539+
* @flow strict-local
540+
* @format
541+
*/
542+
543+
'use strict';
544+
545+
import type {TurboModule} from '../RCTExport';
546+
import * as TurboModuleRegistry from '../TurboModuleRegistry';
547+
548+
export type ChooseInt = 1 | 2 | 3;
549+
export type ChooseFloat = 1.44 | 2.88 | 5.76;
550+
export type ChooseObject = {} | {low: string};
551+
export type ChooseString = 'One' | 'Two' | 'Three';
552+
553+
export interface Spec extends TurboModule {
554+
+getUnion: (chooseInt: ChooseInt, chooseFloat: ChooseFloat, chooseObject: ChooseObject, chooseString: ChooseString) => ChooseObject;
555+
}
556+
557+
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
558+
559+
`;
560+
532561
const ANDROID_ONLY_NATIVE_MODULE = `
533562
/**
534563
* Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -671,6 +700,7 @@ module.exports = {
671700
NATIVE_MODULE_WITH_ARRAY_WITH_ALIAS,
672701
NATIVE_MODULE_WITH_BASIC_PARAM_TYPES,
673702
NATIVE_MODULE_WITH_CALLBACK,
703+
NATIVE_MODULE_WITH_UNION,
674704
EMPTY_NATIVE_MODULE,
675705
ANDROID_ONLY_NATIVE_MODULE,
676706
IOS_ONLY_NATIVE_MODULE,

packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,69 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_SIMPLE_O
16281628
}"
16291629
`;
16301630

1631+
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNION 1`] = `
1632+
"{
1633+
'modules': {
1634+
'NativeSampleTurboModule': {
1635+
'type': 'NativeModule',
1636+
'aliases': {},
1637+
'spec': {
1638+
'properties': [
1639+
{
1640+
'name': 'getUnion',
1641+
'optional': false,
1642+
'typeAnnotation': {
1643+
'type': 'FunctionTypeAnnotation',
1644+
'returnTypeAnnotation': {
1645+
'type': 'UnionTypeAnnotation',
1646+
'memberType': 'ObjectTypeAnnotation'
1647+
},
1648+
'params': [
1649+
{
1650+
'name': 'chooseInt',
1651+
'optional': false,
1652+
'typeAnnotation': {
1653+
'type': 'UnionTypeAnnotation',
1654+
'memberType': 'NumberTypeAnnotation'
1655+
}
1656+
},
1657+
{
1658+
'name': 'chooseFloat',
1659+
'optional': false,
1660+
'typeAnnotation': {
1661+
'type': 'UnionTypeAnnotation',
1662+
'memberType': 'NumberTypeAnnotation'
1663+
}
1664+
},
1665+
{
1666+
'name': 'chooseObject',
1667+
'optional': false,
1668+
'typeAnnotation': {
1669+
'type': 'UnionTypeAnnotation',
1670+
'memberType': 'ObjectTypeAnnotation'
1671+
}
1672+
},
1673+
{
1674+
'name': 'chooseString',
1675+
'optional': false,
1676+
'typeAnnotation': {
1677+
'type': 'UnionTypeAnnotation',
1678+
'memberType': 'StringTypeAnnotation'
1679+
}
1680+
}
1681+
]
1682+
}
1683+
}
1684+
]
1685+
},
1686+
'moduleNames': [
1687+
'SampleTurboModule'
1688+
]
1689+
}
1690+
}
1691+
}"
1692+
`;
1693+
16311694
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNSAFE_OBJECT 1`] = `
16321695
"{
16331696
'modules': {

0 commit comments

Comments
 (0)