Skip to content

Commit c7380ba

Browse files
appdenfacebook-github-bot
authored andcommitted
Support function return types
Summary: This adds the option for a TurboModule spec to use a "Cxx" suffix to unblock additional capabilities. This extends the pattern where TurboModules can have an "Android" or "IOS" suffix to exclude codegen for the other platform. When in `cxxOnly` mode, the parser will allow function return types (and additional features will be added over time). Changelog: [General][Added] C++ TurboModule methods can return functions Reviewed By: christophpurrer Differential Revision: D35364346 fbshipit-source-id: 768eb0ec2a1cbe3e458466064247d7e7f01135ff
1 parent 6f26a92 commit c7380ba

File tree

6 files changed

+154
-2
lines changed

6 files changed

+154
-2
lines changed

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

+25
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,30 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModuleIOS');
573573
574574
`;
575575

576+
const CXX_ONLY_NATIVE_MODULE = `
577+
/**
578+
* Copyright (c) Meta Platforms, Inc. and affiliates.
579+
*
580+
* This source code is licensed under the MIT license found in the
581+
* LICENSE file in the root directory of this source tree.
582+
*
583+
* @flow strict-local
584+
* @format
585+
*/
586+
587+
'use strict';
588+
589+
import type {TurboModule} from '../RCTExport';
590+
import * as TurboModuleRegistry from '../TurboModuleRegistry';
591+
592+
export interface Spec extends TurboModule {
593+
+getCallback: () => () => void;
594+
}
595+
596+
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModuleCxx');
597+
598+
`;
599+
576600
module.exports = {
577601
NATIVE_MODULE_WITH_OBJECT_WITH_OBJECT_DEFINED_IN_FILE_AS_PROPERTY,
578602
NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE,
@@ -594,4 +618,5 @@ module.exports = {
594618
EMPTY_NATIVE_MODULE,
595619
ANDROID_ONLY_NATIVE_MODULE,
596620
IOS_ONLY_NATIVE_MODULE,
621+
CXX_ONLY_NATIVE_MODULE,
597622
};

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

+37
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,43 @@ exports[`RN Codegen Flow Parser can generate fixture ANDROID_ONLY_NATIVE_MODULE
3636
}"
3737
`;
3838

39+
exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] = `
40+
"{
41+
'modules': {
42+
'NativeSampleTurboModule': {
43+
'type': 'NativeModule',
44+
'aliases': {},
45+
'spec': {
46+
'properties': [
47+
{
48+
'name': 'getCallback',
49+
'optional': false,
50+
'typeAnnotation': {
51+
'type': 'FunctionTypeAnnotation',
52+
'returnTypeAnnotation': {
53+
'type': 'FunctionTypeAnnotation',
54+
'returnTypeAnnotation': {
55+
'type': 'VoidTypeAnnotation'
56+
},
57+
'params': []
58+
},
59+
'params': []
60+
}
61+
}
62+
]
63+
},
64+
'moduleNames': [
65+
'SampleTurboModuleCxx'
66+
],
67+
'excludedPlatforms': [
68+
'iOS',
69+
'android'
70+
]
71+
}
72+
}
73+
}"
74+
`;
75+
3976
exports[`RN Codegen Flow Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = `
4077
"{
4178
'modules': {

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ function translateTypeAnnotation(
7070
types: TypeDeclarationMap,
7171
aliasMap: {...NativeModuleAliasMap},
7272
tryParse: ParserErrorCapturer,
73+
cxxOnly: boolean,
7374
): Nullable<NativeModuleTypeAnnotation> {
7475
const {nullable, typeAnnotation, typeAliasResolutionStatus} =
7576
resolveTypeAnnotation(flowTypeAnnotation, types);
@@ -121,6 +122,7 @@ function translateTypeAnnotation(
121122
* to be parseable.
122123
*/
123124
nullGuard,
125+
cxxOnly,
124126
),
125127
);
126128

@@ -177,6 +179,7 @@ function translateTypeAnnotation(
177179
types,
178180
aliasMap,
179181
tryParse,
182+
cxxOnly,
180183
);
181184
}
182185
case 'Stringish': {
@@ -239,6 +242,7 @@ function translateTypeAnnotation(
239242
types,
240243
aliasMap,
241244
tryParse,
245+
cxxOnly,
242246
),
243247
);
244248

@@ -355,6 +359,7 @@ function translateTypeAnnotation(
355359
types,
356360
aliasMap,
357361
tryParse,
362+
cxxOnly,
358363
),
359364
);
360365
}
@@ -401,6 +406,7 @@ function translateFunctionTypeAnnotation(
401406
types: TypeDeclarationMap,
402407
aliasMap: {...NativeModuleAliasMap},
403408
tryParse: ParserErrorCapturer,
409+
cxxOnly: boolean,
404410
): NativeModuleFunctionTypeAnnotation {
405411
type Param = NamedShape<Nullable<NativeModuleParamTypeAnnotation>>;
406412
const params: Array<Param> = [];
@@ -420,6 +426,7 @@ function translateFunctionTypeAnnotation(
420426
types,
421427
aliasMap,
422428
tryParse,
429+
cxxOnly,
423430
),
424431
);
425432

@@ -463,10 +470,11 @@ function translateFunctionTypeAnnotation(
463470
types,
464471
aliasMap,
465472
tryParse,
473+
cxxOnly,
466474
),
467475
);
468476

469-
if (returnTypeAnnotation.type === 'FunctionTypeAnnotation') {
477+
if (!cxxOnly && returnTypeAnnotation.type === 'FunctionTypeAnnotation') {
470478
throw new UnsupportedFunctionReturnTypeAnnotationParserError(
471479
hasteModuleName,
472480
flowFunctionTypeAnnotation.returnType,
@@ -494,6 +502,7 @@ function buildPropertySchema(
494502
types: TypeDeclarationMap,
495503
aliasMap: {...NativeModuleAliasMap},
496504
tryParse: ParserErrorCapturer,
505+
cxxOnly: boolean,
497506
): NativeModulePropertyShape {
498507
let nullable = false;
499508
let {key, value} = property;
@@ -522,6 +531,7 @@ function buildPropertySchema(
522531
types,
523532
aliasMap,
524533
tryParse,
534+
cxxOnly,
525535
),
526536
),
527537
};
@@ -653,13 +663,17 @@ function buildModuleSchema(
653663
// Eventually this should be made explicit in the Flow type itself.
654664
// Also check the hasteModuleName for platform suffix.
655665
// Note: this shape is consistent with ComponentSchema.
666+
let cxxOnly = false;
656667
const excludedPlatforms = [];
657668
const namesToValidate = [...moduleNames, hasteModuleName];
658669
namesToValidate.forEach(name => {
659670
if (name.endsWith('Android')) {
660671
excludedPlatforms.push('iOS');
661672
} else if (name.endsWith('IOS')) {
662673
excludedPlatforms.push('android');
674+
} else if (name.endsWith('Cxx')) {
675+
cxxOnly = true;
676+
excludedPlatforms.push('iOS', 'android');
663677
}
664678
});
665679

@@ -680,6 +694,7 @@ function buildModuleSchema(
680694
types,
681695
aliasMap,
682696
tryParse,
697+
cxxOnly,
683698
),
684699
}));
685700
})

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

+23
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,28 @@ export default TurboModuleRegistry.getEnforcing<Spec>(
504504
);
505505
`;
506506

507+
const CXX_ONLY_NATIVE_MODULE = `
508+
/**
509+
* Copyright (c) Meta Platforms, Inc. and affiliates.
510+
*
511+
* This source code is licensed under the MIT license found in the
512+
* LICENSE file in the root directory of this source tree.
513+
*
514+
* @format
515+
*/
516+
517+
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
518+
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
519+
520+
export interface Spec extends TurboModule {
521+
readonly getCallback: () => () => void;
522+
}
523+
524+
export default TurboModuleRegistry.getEnforcing<Spec>(
525+
'SampleTurboModuleCxx',
526+
);
527+
`;
528+
507529
module.exports = {
508530
NATIVE_MODULE_WITH_OBJECT_WITH_OBJECT_DEFINED_IN_FILE_AS_PROPERTY,
509531
NATIVE_MODULE_WITH_ARRAY_WITH_UNION_AND_TOUPLE,
@@ -525,4 +547,5 @@ module.exports = {
525547
EMPTY_NATIVE_MODULE,
526548
ANDROID_ONLY_NATIVE_MODULE,
527549
IOS_ONLY_NATIVE_MODULE,
550+
CXX_ONLY_NATIVE_MODULE,
528551
};

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

+37
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,43 @@ exports[`RN Codegen TypeScript Parser can generate fixture ANDROID_ONLY_NATIVE_M
3434
}"
3535
`;
3636

37+
exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] = `
38+
"{
39+
'modules': {
40+
'NativeSampleTurboModule': {
41+
'type': 'NativeModule',
42+
'aliases': {},
43+
'spec': {
44+
'properties': [
45+
{
46+
'name': 'getCallback',
47+
'optional': false,
48+
'typeAnnotation': {
49+
'type': 'FunctionTypeAnnotation',
50+
'returnTypeAnnotation': {
51+
'type': 'FunctionTypeAnnotation',
52+
'returnTypeAnnotation': {
53+
'type': 'VoidTypeAnnotation'
54+
},
55+
'params': []
56+
},
57+
'params': []
58+
}
59+
}
60+
]
61+
},
62+
'moduleNames': [
63+
'SampleTurboModuleCxx'
64+
],
65+
'excludedPlatforms': [
66+
'iOS',
67+
'android'
68+
]
69+
}
70+
}
71+
}"
72+
`;
73+
3774
exports[`RN Codegen TypeScript Parser can generate fixture EMPTY_NATIVE_MODULE 1`] = `
3875
"{
3976
'modules': {

packages/react-native-codegen/src/parsers/typescript/modules/index.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ function translateTypeAnnotation(
7070
types: TypeDeclarationMap,
7171
aliasMap: {...NativeModuleAliasMap},
7272
tryParse: ParserErrorCapturer,
73+
cxxOnly: boolean,
7374
): Nullable<NativeModuleTypeAnnotation> {
7475
const {nullable, typeAnnotation, typeAliasResolutionStatus} =
7576
resolveTypeAnnotation(typeScriptTypeAnnotation, types);
@@ -121,6 +122,7 @@ function translateTypeAnnotation(
121122
* to be parseable.
122123
*/
123124
nullGuard,
125+
cxxOnly,
124126
),
125127
);
126128

@@ -177,6 +179,7 @@ function translateTypeAnnotation(
177179
types,
178180
aliasMap,
179181
tryParse,
182+
cxxOnly,
180183
);
181184
}
182185
case 'Stringish': {
@@ -239,6 +242,7 @@ function translateTypeAnnotation(
239242
types,
240243
aliasMap,
241244
tryParse,
245+
cxxOnly,
242246
),
243247
);
244248

@@ -355,6 +359,7 @@ function translateTypeAnnotation(
355359
types,
356360
aliasMap,
357361
tryParse,
362+
cxxOnly,
358363
),
359364
);
360365
}
@@ -401,6 +406,7 @@ function translateFunctionTypeAnnotation(
401406
types: TypeDeclarationMap,
402407
aliasMap: {...NativeModuleAliasMap},
403408
tryParse: ParserErrorCapturer,
409+
cxxOnly: boolean,
404410
): NativeModuleFunctionTypeAnnotation {
405411
type Param = NamedShape<Nullable<NativeModuleParamTypeAnnotation>>;
406412
const params: Array<Param> = [];
@@ -423,6 +429,7 @@ function translateFunctionTypeAnnotation(
423429
types,
424430
aliasMap,
425431
tryParse,
432+
cxxOnly,
426433
),
427434
);
428435

@@ -466,10 +473,11 @@ function translateFunctionTypeAnnotation(
466473
types,
467474
aliasMap,
468475
tryParse,
476+
cxxOnly,
469477
),
470478
);
471479

472-
if (returnTypeAnnotation.type === 'FunctionTypeAnnotation') {
480+
if (!cxxOnly && returnTypeAnnotation.type === 'FunctionTypeAnnotation') {
473481
throw new UnsupportedFunctionReturnTypeAnnotationParserError(
474482
hasteModuleName,
475483
typescriptFunctionTypeAnnotation.returnType,
@@ -494,6 +502,7 @@ function buildPropertySchema(
494502
types: TypeDeclarationMap,
495503
aliasMap: {...NativeModuleAliasMap},
496504
tryParse: ParserErrorCapturer,
505+
cxxOnly: boolean,
497506
): NativeModulePropertyShape {
498507
let nullable = false;
499508
let {key} = property;
@@ -524,6 +533,7 @@ function buildPropertySchema(
524533
types,
525534
aliasMap,
526535
tryParse,
536+
cxxOnly,
527537
),
528538
),
529539
};
@@ -658,13 +668,17 @@ function buildModuleSchema(
658668
// Eventually this should be made explicit in the Flow type itself.
659669
// Also check the hasteModuleName for platform suffix.
660670
// Note: this shape is consistent with ComponentSchema.
671+
let cxxOnly = false;
661672
const excludedPlatforms = [];
662673
const namesToValidate = [...moduleNames, hasteModuleName];
663674
namesToValidate.forEach(name => {
664675
if (name.endsWith('Android')) {
665676
excludedPlatforms.push('iOS');
666677
} else if (name.endsWith('IOS')) {
667678
excludedPlatforms.push('android');
679+
} else if (name.endsWith('Cxx')) {
680+
cxxOnly = true;
681+
excludedPlatforms.push('iOS', 'android');
668682
}
669683
});
670684

@@ -689,6 +703,7 @@ function buildModuleSchema(
689703
types,
690704
aliasMap,
691705
tryParse,
706+
cxxOnly,
692707
),
693708
}));
694709
})

0 commit comments

Comments
 (0)