From ad3df84668f1624e830396364c331783c6f99948 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Mon, 1 Jul 2024 14:42:46 -0700 Subject: [PATCH] Add EventEmitter Code-gen support for Java and ObjC Turbo Modules (#45119) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45119 ## Changelog: [iOS][Added] - Add EventEmitter Code-gen support for Java and ObjC Turbo Modules Reviewed By: RSNara Differential Revision: D58929417 fbshipit-source-id: 5208ba5ecb5882d47c3827c2aa8e3a54a3d7f2b6 --- .../GenerateModuleObjCpp-test.js.snap | 352 ++++++++++++++++-- .../modules/GenerateModuleJavaSpec.js | 56 ++- .../modules/GenerateModuleJniCpp.js | 22 +- .../modules/GenerateModuleObjCpp/index.js | 15 +- .../serializeEventEmitter.js | 70 ++++ .../source/serializeModule.js | 35 +- .../modules/__test_fixtures__/fixtures.js | 124 ++++++ .../GenerateModuleCpp-test.js.snap | 33 ++ .../GenerateModuleH-test.js.snap | 172 +++++++++ .../GenerateModuleHObjCpp-test.js.snap | 142 ++++++- .../GenerateModuleJavaSpec-test.js.snap | 69 ++++ .../GenerateModuleJniCpp-test.js.snap | 45 +++ .../GenerateModuleJniH-test.js.snap | 86 +++++ .../GenerateModuleMm-test.js.snap | 131 +++++++ 14 files changed, 1305 insertions(+), 47 deletions(-) create mode 100644 packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js diff --git a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap index 0f545d88d4a096..e71b84d55960de 100644 --- a/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap +++ b/packages/react-native-codegen/e2e/__tests__/modules/__snapshots__/GenerateModuleObjCpp-test.js.snap @@ -43,7 +43,13 @@ exports[`GenerateModuleObjCpp can generate a header file NativeModule specs 1`] @end -@interface NativeArrayTurboModuleSpecBase : NSObject +@interface NativeArrayTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -63,7 +69,13 @@ namespace facebook::react { @end -@interface NativeBooleanTurboModuleSpecBase : NSObject +@interface NativeBooleanTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -83,7 +95,13 @@ namespace facebook::react { @end -@interface NativeCallbackTurboModuleSpecBase : NSObject +@interface NativeCallbackTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -143,7 +161,13 @@ namespace JS { @end -@interface NativeEnumTurboModuleSpecBase : NSObject +@interface NativeEnumTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -168,7 +192,13 @@ namespace facebook::react { @end -@interface NativeNullableTurboModuleSpecBase : NSObject +@interface NativeNullableTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -188,7 +218,13 @@ namespace facebook::react { @end -@interface NativeNumberTurboModuleSpecBase : NSObject +@interface NativeNumberTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -361,7 +397,13 @@ namespace JS { @end -@interface NativeObjectTurboModuleSpecBase : NSObject +@interface NativeObjectTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -497,7 +539,13 @@ namespace JS { @end -@interface NativeOptionalObjectTurboModuleSpecBase : NSObject +@interface NativeOptionalObjectTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -567,7 +615,13 @@ namespace JS { @end -@interface NativePartialAnnotationTurboModuleSpecBase : NSObject +@interface NativePartialAnnotationTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -591,7 +645,13 @@ namespace facebook::react { @end -@interface NativePromiseTurboModuleSpecBase : NSObject +@interface NativePromiseTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -685,7 +745,13 @@ getValuegetValuegetValuegetValuegetValuey:(NSString *)getValuegetValuegetValuege @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -777,7 +843,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleArraysSpecBase : NSObject +@interface NativeSampleTurboModuleArraysSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -871,7 +943,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleNullableSpecBase : NSObject +@interface NativeSampleTurboModuleNullableSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -965,7 +1043,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleNullableAndOptionalSpecBase : NSObject +@interface NativeSampleTurboModuleNullableAndOptionalSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1059,7 +1143,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleOptionalSpecBase : NSObject +@interface NativeSampleTurboModuleOptionalSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1079,7 +1169,13 @@ namespace facebook::react { @end -@interface NativeStringTurboModuleSpecBase : NSObject +@interface NativeStringTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1459,7 +1555,13 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface NativeArrayTurboModuleSpecBase : NSObject +@interface NativeArrayTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1479,7 +1581,13 @@ namespace facebook::react { @end -@interface NativeBooleanTurboModuleSpecBase : NSObject +@interface NativeBooleanTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1499,7 +1607,13 @@ namespace facebook::react { @end -@interface NativeCallbackTurboModuleSpecBase : NSObject +@interface NativeCallbackTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1559,7 +1673,13 @@ namespace JS { @end -@interface NativeEnumTurboModuleSpecBase : NSObject +@interface NativeEnumTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1584,7 +1704,13 @@ namespace facebook::react { @end -@interface NativeNullableTurboModuleSpecBase : NSObject +@interface NativeNullableTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1604,7 +1730,13 @@ namespace facebook::react { @end -@interface NativeNumberTurboModuleSpecBase : NSObject +@interface NativeNumberTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1777,7 +1909,13 @@ namespace JS { @end -@interface NativeObjectTurboModuleSpecBase : NSObject +@interface NativeObjectTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1913,7 +2051,13 @@ namespace JS { @end -@interface NativeOptionalObjectTurboModuleSpecBase : NSObject +@interface NativeOptionalObjectTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1983,7 +2127,13 @@ namespace JS { @end -@interface NativePartialAnnotationTurboModuleSpecBase : NSObject +@interface NativePartialAnnotationTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2007,7 +2157,13 @@ namespace facebook::react { @end -@interface NativePromiseTurboModuleSpecBase : NSObject +@interface NativePromiseTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2101,7 +2257,13 @@ getValuegetValuegetValuegetValuegetValuey:(NSString *)getValuegetValuegetValuege @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2193,7 +2355,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleArraysSpecBase : NSObject +@interface NativeSampleTurboModuleArraysSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2287,7 +2455,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleNullableSpecBase : NSObject +@interface NativeSampleTurboModuleNullableSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2381,7 +2555,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleNullableAndOptionalSpecBase : NSObject +@interface NativeSampleTurboModuleNullableAndOptionalSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2475,7 +2655,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleOptionalSpecBase : NSObject +@interface NativeSampleTurboModuleOptionalSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2495,7 +2681,13 @@ namespace facebook::react { @end -@interface NativeStringTurboModuleSpecBase : NSObject +@interface NativeStringTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -2849,6 +3041,12 @@ exports[`GenerateModuleObjCpp can generate an implementation file NativeModule s @implementation NativeArrayTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -2881,6 +3079,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeBooleanTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -2906,6 +3110,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeCallbackTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -2931,6 +3141,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeEnumTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeEnumTurboModule_StateType) @@ -2995,6 +3211,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeNullableTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -3048,6 +3270,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeNumberTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -3073,6 +3301,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeObjectTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeObjectTurboModule_SpecDifficultObjectAE) @@ -3130,6 +3364,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeOptionalObjectTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -3148,6 +3388,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativePartialAnnotationTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativePartialAnnotationTurboModule_SpecGetSomeObjFromPartialSomeObjValue) @@ -3205,6 +3451,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativePromiseTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -3230,6 +3482,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeSampleTurboModule_SpecGetObjectShapeArg) @@ -3343,6 +3601,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeSampleTurboModuleArraysSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -3445,6 +3709,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeSampleTurboModuleNullableSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeSampleTurboModuleNullable_SpecGetObjectShapeArg) @@ -3558,6 +3828,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeSampleTurboModuleNullableAndOptionalSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeSampleTurboModuleNullableAndOptional_SpecGetObjectShapeArg) @@ -3671,6 +3947,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeSampleTurboModuleOptionalSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeSampleTurboModuleOptional_SpecGetObjectShapeArg) @@ -3784,6 +4066,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeStringTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index ee3237d5d8c0cf..86f94fbcee40cc 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -12,6 +12,7 @@ import type { NamedShape, + NativeModuleEventEmitterShape, NativeModuleFunctionTypeAnnotation, NativeModuleParamTypeAnnotation, NativeModulePropertyShape, @@ -23,6 +24,7 @@ import type {AliasResolver} from './Utils'; const {unwrapNullable} = require('../../parsers/parsers-commons'); const {wrapOptional} = require('../TypeUtils/Java'); +const {toPascalCase} = require('../Utils'); const {createAliasResolver, getModules} = require('./Utils'); type FilesOutput = Map; @@ -32,11 +34,13 @@ function FileTemplate( packageName: string, className: string, jsName: string, + eventEmitters: string, methods: string, imports: string, }>, ): string { - const {packageName, className, jsName, methods, imports} = config; + const {packageName, className, jsName, eventEmitters, methods, imports} = + config; return ` /** * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). @@ -65,11 +69,28 @@ public abstract class ${className} extends ReactContextBaseJavaModule implements return NAME; } -${methods} +${eventEmitters}${eventEmitters.length > 0 ? '\n\n' : ''}${methods} } `; } +function EventEmitterTemplate( + eventEmitter: NativeModuleEventEmitterShape, + imports: Set, +): string { + return ` protected final void emit${toPascalCase(eventEmitter.name)}(${ + eventEmitter.typeAnnotation.typeAnnotation.type !== 'VoidTypeAnnotation' + ? `${translateEventEmitterTypeToJavaType(eventEmitter, imports)} value` + : '' + }) { + mEventEmitterCallback.invoke("${eventEmitter.name}"${ + eventEmitter.typeAnnotation.typeAnnotation.type !== 'VoidTypeAnnotation' + ? ', value' + : '' + }); + }`; +} + function MethodTemplate( config: $ReadOnly<{ abstract: boolean, @@ -102,6 +123,34 @@ function MethodTemplate( type Param = NamedShape>; +function translateEventEmitterTypeToJavaType( + eventEmitter: NativeModuleEventEmitterShape, + imports: Set, +): string { + switch (eventEmitter.typeAnnotation.typeAnnotation.type) { + case 'StringTypeAnnotation': + return 'String'; + case 'NumberTypeAnnotation': + case 'FloatTypeAnnotation': + case 'DoubleTypeAnnotation': + case 'Int32TypeAnnotation': + return 'double'; + case 'BooleanTypeAnnotation': + return 'boolean'; + case 'ObjectTypeAnnotation': + case 'TypeAliasTypeAnnotation': + imports.add('com.facebook.react.bridge.ReadableMap'); + return 'ReadableMap'; + case 'ArrayTypeAnnotation': + imports.add('com.facebook.react.bridge.ReadableArray'); + return 'ReadableArray'; + default: + throw new Error( + `Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`, + ); + } +} + function translateFunctionParamToJavaType( param: Param, createErrorMessage: (typeName: string) => string, @@ -533,6 +582,9 @@ module.exports = { packageName: normalizedPackageName, className, jsName: moduleName, + eventEmitters: spec.eventEmitters + .map(eventEmitter => EventEmitterTemplate(eventEmitter, imports)) + .join('\n\n'), methods: methods.filter(Boolean).join('\n\n'), imports: Array.from(imports) .sort() diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index 2930ab1be9a0be..92e642118d1b01 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -12,6 +12,7 @@ import type { NamedShape, + NativeModuleEventEmitterShape, NativeModuleFunctionTypeAnnotation, NativeModuleParamTypeAnnotation, NativeModulePropertyShape, @@ -54,9 +55,11 @@ const HostFunctionTemplate = ({ const ModuleClassConstructorTemplate = ({ hasteModuleName, + eventEmitters, methods, }: $ReadOnly<{ hasteModuleName: string, + eventEmitters: $ReadOnlyArray, methods: $ReadOnlyArray<{ propertyName: string, argCount: number, @@ -69,7 +72,21 @@ ${methods .map(({propertyName, argCount}) => { return ` methodMap_["${propertyName}"] = MethodMetadata {${argCount}, __hostFunction_${hasteModuleName}SpecJSI_${propertyName}};`; }) - .join('\n')} + .join('\n')}${ + eventEmitters.length > 0 + ? eventEmitters + .map(eventEmitter => { + return ` + eventEmitterMap_["${eventEmitter.name}"] = std::make_shared>();`; + }) + .join('') + : '' + }${ + eventEmitters.length > 0 + ? ` + setEventEmitterCallback(params.instance);` + : '' + } }`.trim(); }; @@ -438,7 +455,7 @@ module.exports = { .map(hasteModuleName => { const { aliasMap, - spec: {methods}, + spec: {eventEmitters, methods}, } = nativeModules[hasteModuleName]; const resolveAlias = createAliasResolver(aliasMap); @@ -457,6 +474,7 @@ module.exports = { '\n\n' + ModuleClassConstructorTemplate({ hasteModuleName, + eventEmitters, methods: methods .map(({name: propertyName, typeAnnotation}) => { const [{returnTypeAnnotation, params}] = diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js index e1a8d02cf36f17..defe5722f29a03 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/index.js @@ -15,6 +15,7 @@ import type {MethodSerializationOutput} from './serializeMethod'; const {createAliasResolver, getModules} = require('../Utils'); const {serializeStruct} = require('./header/serializeStruct'); +const {EventEmitterHeaderTemplate} = require('./serializeEventEmitter'); const {serializeMethod} = require('./serializeMethod'); const {serializeModuleSource} = require('./source/serializeModule'); const {StructCollector} = require('./StructCollector'); @@ -24,10 +25,12 @@ type FilesOutput = Map; const ModuleDeclarationTemplate = ({ hasteModuleName, structDeclarations, + eventEmitters, protocolMethods, }: $ReadOnly<{ hasteModuleName: string, structDeclarations: string, + eventEmitters: string, protocolMethods: string, }>) => `${structDeclarations} @protocol ${hasteModuleName}Spec @@ -36,7 +39,13 @@ ${protocolMethods} @end -@interface ${hasteModuleName}SpecBase : NSObject +@interface ${hasteModuleName}SpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + +${eventEmitters} @end namespace facebook::react { @@ -191,6 +200,9 @@ module.exports = { ModuleDeclarationTemplate({ hasteModuleName: hasteModuleName, structDeclarations: structStrs.join('\n'), + eventEmitters: spec.eventEmitters + .map(eventEmitter => EventEmitterHeaderTemplate(eventEmitter)) + .join('\n'), protocolMethods: methodSerializations .map(({protocolMethod}) => protocolMethod) .join('\n'), @@ -204,6 +216,7 @@ module.exports = { hasteModuleName, generatedStructs, hasteModuleName, + spec.eventEmitters, methodSerializations.filter( ({selector}) => selector !== '@selector(constantsToExport)', ), diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js new file mode 100644 index 00000000000000..aa8e2bb752681d --- /dev/null +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeEventEmitter.js @@ -0,0 +1,70 @@ +/** + * Copyright (c) Meta Platforms, Inc. and 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 + */ + +import type {NativeModuleEventEmitterShape} from '../../../CodegenSchema'; + +const {toPascalCase} = require('../../Utils'); + +function getEventEmitterTypeObjCType( + eventEmitter: NativeModuleEventEmitterShape, +): string { + switch (eventEmitter.typeAnnotation.typeAnnotation.type) { + case 'StringTypeAnnotation': + return 'NSString *_Nonnull'; + case 'NumberTypeAnnotation': + return 'NSNumber *_Nonnull'; + case 'BooleanTypeAnnotation': + return 'BOOL'; + case 'ObjectTypeAnnotation': + case 'TypeAliasTypeAnnotation': + return 'NSDictionary *'; + case 'ArrayTypeAnnotation': + return 'NSArray> *'; + default: + throw new Error( + `Unsupported eventType for ${eventEmitter.name}. Found: ${eventEmitter.typeAnnotation.typeAnnotation.type}`, + ); + } +} + +function EventEmitterHeaderTemplate( + eventEmitter: NativeModuleEventEmitterShape, +): string { + return `- (void)emit${toPascalCase(eventEmitter.name)}${ + eventEmitter.typeAnnotation.typeAnnotation.type !== 'VoidTypeAnnotation' + ? `:(${getEventEmitterTypeObjCType(eventEmitter)})value` + : '' + };`; +} + +function EventEmitterImplementationTemplate( + eventEmitter: NativeModuleEventEmitterShape, +): string { + return `- (void)emit${toPascalCase(eventEmitter.name)}${ + eventEmitter.typeAnnotation.typeAnnotation.type !== 'VoidTypeAnnotation' + ? `:(${getEventEmitterTypeObjCType(eventEmitter)})value` + : '' + } +{ + _eventEmitterCallback("${eventEmitter.name}", ${ + eventEmitter.typeAnnotation.typeAnnotation.type !== 'VoidTypeAnnotation' + ? eventEmitter.typeAnnotation.typeAnnotation.type !== + 'BooleanTypeAnnotation' + ? 'value' + : '[NSNumber numberWithBool:value]' + : 'nil' + }); +}`; +} + +module.exports = { + EventEmitterHeaderTemplate, + EventEmitterImplementationTemplate, +}; diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/source/serializeModule.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/source/serializeModule.js index f4760f2f7f3cb6..10e3c2eeec9c6c 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/source/serializeModule.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/source/serializeModule.js @@ -10,24 +10,39 @@ 'use strict'; +import type {NativeModuleEventEmitterShape} from '../../../../CodegenSchema'; import type { MethodSerializationOutput, StructParameterRecord, } from '../serializeMethod'; import type {Struct} from '../StructCollector'; +const { + EventEmitterImplementationTemplate, +} = require('./../serializeEventEmitter'); + const ModuleTemplate = ({ hasteModuleName, structs, moduleName, + eventEmitters, methodSerializationOutputs, }: $ReadOnly<{ hasteModuleName: string, structs: $ReadOnlyArray, moduleName: string, + eventEmitters: $ReadOnlyArray, methodSerializationOutputs: $ReadOnlyArray, }>) => ` @implementation ${hasteModuleName}SpecBase +${eventEmitters + .map(eventEmitter => EventEmitterImplementationTemplate(eventEmitter)) + .join('\n')} + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end ${structs @@ -58,7 +73,23 @@ namespace facebook::react { argCount, }), ) - .join('\n' + ' '.repeat(8))} + .join('\n' + ' '.repeat(8))}${ + eventEmitters.length > 0 + ? eventEmitters + .map(eventEmitter => { + return ` + eventEmitterMap_["${eventEmitter.name}"] = std::make_shared>();`; + }) + .join('') + : '' +}${ + eventEmitters.length > 0 + ? ` + setEventEmitterCallback([&](const std::string &name, id value) { + static_cast &>(*eventEmitterMap_[name]).emit(value); + });` + : '' +} } } // namespace facebook::react`; @@ -112,12 +143,14 @@ function serializeModuleSource( hasteModuleName: string, structs: $ReadOnlyArray, moduleName: string, + eventEmitters: $ReadOnlyArray, methodSerializationOutputs: $ReadOnlyArray, ): string { return ModuleTemplate({ hasteModuleName, structs: structs.filter(({context}) => context !== 'CONSTANTS'), moduleName, + eventEmitters, methodSerializationOutputs, }); } 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 aea2ffbcfbaccd..adbc596c38a84b 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 @@ -27,6 +27,129 @@ const EMPTY_NATIVE_MODULES: SchemaType = { }, }; +const EVENT_EMITTER_MODULES: SchemaType = { + modules: { + NativeSampleTurboModule: { + type: 'NativeModule', + aliasMap: { + ObjectStruct: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'a', + optional: false, + typeAnnotation: { + type: 'NumberTypeAnnotation', + }, + }, + { + name: 'b', + optional: false, + typeAnnotation: { + type: 'StringTypeAnnotation', + }, + }, + { + name: 'c', + optional: true, + typeAnnotation: { + type: 'NullableTypeAnnotation', + typeAnnotation: { + type: 'StringTypeAnnotation', + }, + }, + }, + ], + }, + }, + enumMap: {}, + spec: { + eventEmitters: [ + { + name: 'onEvent1', + optional: false, + typeAnnotation: { + type: 'EventEmitterTypeAnnotation', + typeAnnotation: { + type: 'VoidTypeAnnotation', + }, + }, + }, + { + name: 'onEvent2', + optional: false, + typeAnnotation: { + type: 'EventEmitterTypeAnnotation', + typeAnnotation: { + type: 'StringTypeAnnotation', + }, + }, + }, + { + name: 'onEvent3', + optional: false, + typeAnnotation: { + type: 'EventEmitterTypeAnnotation', + typeAnnotation: { + type: 'NumberTypeAnnotation', + }, + }, + }, + { + name: 'onEvent4', + optional: false, + typeAnnotation: { + type: 'EventEmitterTypeAnnotation', + typeAnnotation: { + type: 'BooleanTypeAnnotation', + }, + }, + }, + { + name: 'onEvent5', + optional: false, + typeAnnotation: { + type: 'EventEmitterTypeAnnotation', + typeAnnotation: { + type: 'TypeAliasTypeAnnotation', + name: 'ObjectStruct', + }, + }, + }, + { + name: 'onEvent6', + optional: false, + typeAnnotation: { + type: 'EventEmitterTypeAnnotation', + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'TypeAliasTypeAnnotation', + name: 'ObjectStruct', + }, + }, + }, + }, + ], + methods: [ + { + name: 'voidFunc', + optional: false, + typeAnnotation: { + type: 'FunctionTypeAnnotation', + returnTypeAnnotation: { + type: 'VoidTypeAnnotation', + }, + params: [], + }, + }, + ], + }, + moduleName: 'SampleTurboModule', + }, + }, +}; + const SIMPLE_NATIVE_MODULES: SchemaType = { modules: { NativeSampleTurboModule: { @@ -2435,6 +2558,7 @@ module.exports = { complex_objects: COMPLEX_OBJECTS, two_modules_different_files: TWO_MODULES_DIFFERENT_FILES, empty_native_modules: EMPTY_NATIVE_MODULES, + event_emitter_module: EVENT_EMITTER_MODULES, simple_native_modules: SIMPLE_NATIVE_MODULES, native_modules_with_type_aliases: NATIVE_MODULES_WITH_TYPE_ALIASES, real_module_example: REAL_MODULE_EXAMPLE, 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 dcfbcaa3e16023..8e0045608a7ed4 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 @@ -352,6 +352,39 @@ NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared } +} // namespace facebook::react +", +} +`; + +exports[`GenerateModuleCpp can generate fixture event_emitter_module 1`] = ` +Map { + "event_emitter_moduleJSI-generated.cpp" => "/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleCpp.js + */ + +#include \\"event_emitter_moduleJSI.h\\" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_voidFunc(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + static_cast(&turboModule)->voidFunc( + rt + ); + return jsi::Value::undefined(); +} + +NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_voidFunc}; +} + + } // namespace facebook::react ", } 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 ad2183e4e3d30a..b5d82e4b7754ef 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 @@ -1019,6 +1019,178 @@ private: } `; +exports[`GenerateModuleH can generate fixture event_emitter_module 1`] = ` +Map { + "event_emitter_moduleJSI.h" => "/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleH.js + */ + +#pragma once + +#include +#include + +namespace facebook::react { + + + +#pragma mark - NativeSampleTurboModuleObjectStruct + +template +struct NativeSampleTurboModuleObjectStruct { + P0 a; + P1 b; + P2 c; + bool operator==(const NativeSampleTurboModuleObjectStruct &other) const { + return a == other.a && b == other.b && c == other.c; + } +}; + +template +struct NativeSampleTurboModuleObjectStructBridging { + static T types; + + static T fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + T result{ + bridging::fromJs(rt, value.getProperty(rt, \\"a\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"b\\"), jsInvoker), + bridging::fromJs(rt, value.getProperty(rt, \\"c\\"), jsInvoker)}; + return result; + } + +#ifdef DEBUG + static double aToJs(jsi::Runtime &rt, decltype(types.a) value) { + return bridging::toJs(rt, value); + } + + static jsi::String bToJs(jsi::Runtime &rt, decltype(types.b) value) { + return bridging::toJs(rt, value); + } + + static std::optional cToJs(jsi::Runtime &rt, decltype(types.c) value) { + return bridging::toJs(rt, value); + } +#endif + + static jsi::Object toJs( + jsi::Runtime &rt, + const T &value, + const std::shared_ptr &jsInvoker) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, \\"a\\", bridging::toJs(rt, value.a, jsInvoker)); + result.setProperty(rt, \\"b\\", bridging::toJs(rt, value.b, jsInvoker)); + if (value.c) { + result.setProperty(rt, \\"c\\", bridging::toJs(rt, value.c.value(), jsInvoker)); + } + return result; + } +}; + +class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual void voidFunc(jsi::Runtime &rt) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.get(rt, propName); + } + + static constexpr std::string_view kModuleName = \\"SampleTurboModule\\"; + +protected: + NativeSampleTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeSampleTurboModuleCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + void emitOnEvent1() { + static_cast&>(*delegate_.eventEmitterMap_[\\"onEvent1\\"]).emit(); + } + + template void emitOnEvent2(OnEvent2Type value) { + static_assert(bridging::supportsFromJs, \\"value cannnot be converted to jsi::String\\"); + static_cast&>(*delegate_.eventEmitterMap_[\\"onEvent2\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value { + return bridging::toJs(rt, eventValue, jsInvoker); + }); + } + + template void emitOnEvent3(OnEvent3Type value) { + static_assert(bridging::supportsFromJs, \\"value cannnot be converted to double\\"); + static_cast&>(*delegate_.eventEmitterMap_[\\"onEvent3\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value { + return bridging::toJs(rt, eventValue, jsInvoker); + }); + } + + template void emitOnEvent4(OnEvent4Type value) { + static_assert(bridging::supportsFromJs, \\"value cannnot be converted to bool\\"); + static_cast&>(*delegate_.eventEmitterMap_[\\"onEvent4\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value { + return bridging::toJs(rt, eventValue, jsInvoker); + }); + } + + template void emitOnEvent5(OnEvent5Type value) { + static_assert(bridging::supportsFromJs, \\"value cannnot be converted to jsi::Object\\"); + static_cast&>(*delegate_.eventEmitterMap_[\\"onEvent5\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value { + return bridging::toJs(rt, eventValue, jsInvoker); + }); + } + + template void emitOnEvent6(std::vector value) { + static_assert(bridging::supportsFromJs, jsi::Array>, \\"value cannnot be converted to jsi::Array\\"); + static_cast&>(*delegate_.eventEmitterMap_[\\"onEvent6\\"]).emit([jsInvoker = jsInvoker_, eventValue = value](jsi::Runtime& rt) -> jsi::Value { + return bridging::toJs(rt, eventValue, jsInvoker); + }); + } + +private: + class Delegate : public NativeSampleTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + eventEmitterMap_[\\"onEvent1\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent2\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent3\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent4\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent5\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent6\\"] = std::make_shared>(); + } + + void voidFunc(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::voidFunc) == 1, + \\"Expected voidFunc(...) to have 1 parameters\\"); + + return bridging::callFromJs( + rt, &T::voidFunc, jsInvoker_, instance_); + } + + private: + friend class NativeSampleTurboModuleCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react +", +} +`; + exports[`GenerateModuleH can generate fixture native_modules_with_type_aliases 1`] = ` Map { "native_modules_with_type_aliasesJSI.h" => "/** diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap index 994c04389b79fb..3fafff6f52f24b 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleHObjCpp-test.js.snap @@ -41,7 +41,13 @@ Map { @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -211,7 +217,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -410,7 +422,13 @@ Map { @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -428,6 +446,76 @@ namespace facebook::react { } `; +exports[`GenerateModuleHObjCpp can generate fixture event_emitter_module 1`] = ` +Map { + "event_emitter_module.h" => "/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#ifndef __cplusplus +#error This file must be compiled as Obj-C++. If you are importing it, you must change your file extension to .mm. +#endif + +// Avoid multiple includes of event_emitter_module symbols +#ifndef event_emitter_module_H +#define event_emitter_module_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +@protocol NativeSampleTurboModuleSpec + +- (void)voidFunc; + +@end + +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + +- (void)emitOnEvent1; +- (void)emitOnEvent2:(NSString *_Nonnull)value; +- (void)emitOnEvent3:(NSNumber *_Nonnull)value; +- (void)emitOnEvent4:(BOOL)value; +- (void)emitOnEvent5:(NSDictionary *)value; +- (void)emitOnEvent6:(NSArray> *)value; +@end + +namespace facebook::react { + /** + * ObjC++ class for module 'NativeSampleTurboModule' + */ + class JSI_EXPORT NativeSampleTurboModuleSpecJSI : public ObjCTurboModule { + public: + NativeSampleTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms); + }; +} // namespace facebook::react + +#endif // event_emitter_module_H +", +} +`; + exports[`GenerateModuleHObjCpp can generate fixture native_modules_with_type_aliases 1`] = ` Map { "native_modules_with_type_aliases.h" => "/** @@ -535,7 +623,13 @@ namespace JS { @end -@interface AliasTurboModuleSpecBase : NSObject +@interface AliasTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -677,7 +771,13 @@ namespace JS { @end -@interface NativeCameraRollManagerSpecBase : NSObject +@interface NativeCameraRollManagerSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -746,7 +846,13 @@ namespace JS { @end -@interface NativeExceptionsManagerSpecBase : NSObject +@interface NativeExceptionsManagerSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -954,7 +1060,13 @@ namespace JS { @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1025,7 +1137,13 @@ Map { @end -@interface NativeSampleTurboModuleSpecBase : NSObject +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { @@ -1044,7 +1162,13 @@ namespace facebook::react { @end -@interface NativeSampleTurboModule2SpecBase : NSObject +@interface NativeSampleTurboModule2SpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + @end namespace facebook::react { diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap index 875476d45acaae..4da79695dade85 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJavaSpec-test.js.snap @@ -157,6 +157,75 @@ public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaMo } `; +exports[`GenerateModuleJavaSpec can generate fixture event_emitter_module 1`] = ` +Map { + "java/com/facebook/fbreact/specs/NativeSampleTurboModuleSpec.java" => " +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; + +public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaModule implements TurboModule { + public static final String NAME = \\"SampleTurboModule\\"; + + public NativeSampleTurboModuleSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + protected final void emitOnEvent1() { + mEventEmitterCallback.invoke(\\"onEvent1\\"); + } + + protected final void emitOnEvent2(String value) { + mEventEmitterCallback.invoke(\\"onEvent2\\", value); + } + + protected final void emitOnEvent3(double value) { + mEventEmitterCallback.invoke(\\"onEvent3\\", value); + } + + protected final void emitOnEvent4(boolean value) { + mEventEmitterCallback.invoke(\\"onEvent4\\", value); + } + + protected final void emitOnEvent5(ReadableMap value) { + mEventEmitterCallback.invoke(\\"onEvent5\\", value); + } + + protected final void emitOnEvent6(ReadableArray value) { + mEventEmitterCallback.invoke(\\"onEvent6\\", value); + } + + @ReactMethod + @DoNotStrip + public abstract void voidFunc(); +} +", +} +`; + exports[`GenerateModuleJavaSpec can generate fixture native_modules_with_type_aliases 1`] = ` Map { "java/com/facebook/fbreact/specs/AliasTurboModuleSpec.java" => " diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap index 27f98851161d91..c929bfd55c57b7 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniCpp-test.js.snap @@ -172,6 +172,51 @@ std::shared_ptr empty_native_modules_ModuleProvider(const std::stri } `; +exports[`GenerateModuleJniCpp can generate fixture event_emitter_module 1`] = ` +Map { + "jni/event_emitter_module-generated.cpp" => " +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniCpp.js + */ + +#include \\"event_emitter_module.h\\" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, VoidKind, \\"voidFunc\\", \\"()V\\", args, count, cachedMethodId); +} + +NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc}; + eventEmitterMap_[\\"onEvent1\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent2\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent3\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent4\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent5\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent6\\"] = std::make_shared>(); + setEventEmitterCallback(params.instance); +} + +std::shared_ptr event_emitter_module_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == \\"SampleTurboModule\\") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react +", +} +`; + exports[`GenerateModuleJniCpp can generate fixture native_modules_with_type_aliases 1`] = ` Map { "jni/native_modules_with_type_aliases-generated.cpp" => " diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap index 72877187166bd8..c2df3b016bc167 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleJniH-test.js.snap @@ -341,6 +341,92 @@ target_compile_options( } `; +exports[`GenerateModuleJniH can generate fixture event_emitter_module 1`] = ` +Map { + "jni/event_emitter_module.h" => " +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleJniH.js + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +/** + * JNI C++ class for module 'NativeSampleTurboModule' + */ +class JSI_EXPORT NativeSampleTurboModuleSpecJSI : public JavaTurboModule { +public: + NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms); +}; + + +JSI_EXPORT +std::shared_ptr event_emitter_module_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace facebook::react +", + "jni/CMakeLists.txt" => "# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_VERBOSE_MAKEFILE on) + +file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/event_emitter_module/*.cpp) + +add_library( + react_codegen_event_emitter_module + SHARED + \${react_codegen_SRCS} +) + +target_include_directories(react_codegen_event_emitter_module PUBLIC . react/renderer/components/event_emitter_module) + +target_link_libraries( + react_codegen_event_emitter_module + fbjni + folly_runtime + glog + jsi + react_codegen_rncore + react_debug + react_nativemodule_core + react_render_componentregistry + react_render_core + react_render_debug + react_render_graphics + react_render_imagemanager + react_render_mapbuffer + react_utils + rrc_image + rrc_view + yoga +) + +target_compile_options( + react_codegen_event_emitter_module + PRIVATE + -DLOG_TAG=\\\\\\"ReactNative\\\\\\" + -fexceptions + -frtti + -std=c++20 + -Wall +) +", +} +`; + exports[`GenerateModuleJniH can generate fixture native_modules_with_type_aliases 1`] = ` Map { "jni/native_modules_with_type_aliases.h" => " diff --git a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap index cce63ca537aaf3..13be394c79d815 100644 --- a/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap +++ b/packages/react-native-codegen/src/generators/modules/__tests__/__snapshots__/GenerateModuleMm-test.js.snap @@ -19,6 +19,12 @@ Map { @implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -53,6 +59,12 @@ Map { @implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeSampleTurboModule_SpecDifficultAE) @@ -191,6 +203,12 @@ Map { @implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -206,6 +224,83 @@ namespace facebook::react { } `; +exports[`GenerateModuleMm can generate fixture event_emitter_module 1`] = ` +Map { + "event_emitter_module-generated.mm" => "/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateModuleObjCpp + * + * We create an umbrella header (and corresponding implementation) here since + * Cxx compilation in BUCK has a limitation: source-code producing genrule()s + * must have a single output. More files => more genrule()s => slower builds. + */ + +#import \\"event_emitter_module.h\\" + + +@implementation NativeSampleTurboModuleSpecBase +- (void)emitOnEvent1 +{ + _eventEmitterCallback(\\"onEvent1\\", nil); +} +- (void)emitOnEvent2:(NSString *_Nonnull)value +{ + _eventEmitterCallback(\\"onEvent2\\", value); +} +- (void)emitOnEvent3:(NSNumber *_Nonnull)value +{ + _eventEmitterCallback(\\"onEvent3\\", value); +} +- (void)emitOnEvent4:(BOOL)value +{ + _eventEmitterCallback(\\"onEvent4\\", [NSNumber numberWithBool:value]); +} +- (void)emitOnEvent5:(NSDictionary *)value +{ + _eventEmitterCallback(\\"onEvent5\\", value); +} +- (void)emitOnEvent6:(NSArray> *)value +{ + _eventEmitterCallback(\\"onEvent6\\", value); +} + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, \\"voidFunc\\", @selector(voidFunc), args, count); + } + + NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_[\\"voidFunc\\"] = MethodMetadata {0, __hostFunction_NativeSampleTurboModuleSpecJSI_voidFunc}; + + eventEmitterMap_[\\"onEvent1\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent2\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent3\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent4\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent5\\"] = std::make_shared>(); + eventEmitterMap_[\\"onEvent6\\"] = std::make_shared>(); + setEventEmitterCallback([&](const std::string &name, id value) { + static_cast &>(*eventEmitterMap_[name]).emit(value); + }); + } +} // namespace facebook::react +", +} +`; + exports[`GenerateModuleMm can generate fixture native_modules_with_type_aliases 1`] = ` Map { "native_modules_with_type_aliases-generated.mm" => "/** @@ -225,6 +320,12 @@ Map { @implementation AliasTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (AliasTurboModule_OptionsOffset) @@ -287,6 +388,12 @@ Map { @implementation NativeCameraRollManagerSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeCameraRollManager_GetPhotosParams) @@ -324,6 +431,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeExceptionsManagerSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @implementation RCTCxxConvert (NativeExceptionsManager_StackFrame) @@ -402,6 +515,12 @@ Map { @implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -532,6 +651,12 @@ Map { @implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end @@ -550,6 +675,12 @@ namespace facebook::react { } // namespace facebook::react @implementation NativeSampleTurboModule2SpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} @end