From 3af126b562cf7e0828906a4fe0ac79a886b557e6 Mon Sep 17 00:00:00 2001 From: Eli White Date: Fri, 4 Oct 2024 12:08:51 -0700 Subject: [PATCH] Add support for basic unions for native modules (#46747) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46747 You can now use unions in native modules. Support for this pretty much existed, but one callsite was throwing for non-cpp modules which meant nobody could use this. Previously, StructCollector would throw that this was not supported because it couldn't generate it for objc. Instead of generating something smart in the native code for each option, it just tells native to treat them like the base type (number, string, object). Changelog: [General][Added] Codegen now supports Union Types in NativeModules Reviewed By: GijsWeterings Differential Revision: D63664505 fbshipit-source-id: 73278ed9cd64452173c5170aba44ced71181510f --- .../GenerateModuleObjCpp/StructCollector.js | 23 +++- .../modules/__test_fixtures__/fixtures.js | 62 ++++++++++ .../GenerateModuleCpp-test.js.snap | 36 ++++++ .../GenerateModuleH-test.js.snap | 77 ++++++++++++ .../GenerateModuleHObjCpp-test.js.snap | 68 +++++++++++ .../GenerateModuleJavaSpec-test.js.snap | 45 +++++++ .../GenerateModuleJniCpp-test.js.snap | 38 ++++++ .../GenerateModuleJniH-test.js.snap | 74 ++++++++++++ .../GenerateModuleMm-test.js.snap | 45 +++++++ .../modules/__test_fixtures__/fixtures.js | 29 +++++ .../module-parser-snapshot-test.js.snap | 114 ++++++++++++++++++ .../modules/__test_fixtures__/fixtures.js | 28 +++++ ...script-module-parser-snapshot-test.js.snap | 114 ++++++++++++++++++ 13 files changed, 752 insertions(+), 1 deletion(-) diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js index 69a59a45389..101b9137c3e 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -121,7 +121,28 @@ class StructCollector { case 'MixedTypeAnnotation': throw new Error('Mixed types are unsupported in structs'); case 'UnionTypeAnnotation': - throw new Error('Union types are unsupported in structs'); + switch (typeAnnotation.memberType) { + case 'StringTypeAnnotation': + return wrapNullable(nullable, { + type: 'StringTypeAnnotation', + }); + case 'NumberTypeAnnotation': + return wrapNullable(nullable, { + type: 'NumberTypeAnnotation', + }); + case 'ObjectTypeAnnotation': + // This isn't smart enough to actually know how to generate the + // options on the native side. So we just treat it as an unknown object type + return wrapNullable(nullable, { + type: 'GenericObjectTypeAnnotation', + }); + default: + (typeAnnotation.memberType: empty); + throw new Error( + 'Union types are unsupported in structs' + + JSON.stringify(typeAnnotation), + ); + } default: { return wrapNullable(nullable, typeAnnotation); } 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 ac9cf2189c7..409ff9cca7b 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 @@ -2575,6 +2575,67 @@ const SAMPLE_WITH_UPPERCASE_NAME: SchemaType = { }, }; +const UNION_MODULE: SchemaType = { + modules: { + NativeSampleTurboModule: { + type: 'NativeModule', + aliasMap: {}, + enumMap: {}, + spec: { + eventEmitters: [], + methods: [ + { + name: 'getUnion', + optional: false, + typeAnnotation: { + type: 'FunctionTypeAnnotation', + returnTypeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'ObjectTypeAnnotation', + }, + params: [ + { + name: 'chooseInt', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'NumberTypeAnnotation', + }, + }, + { + name: 'chooseFloat', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'NumberTypeAnnotation', + }, + }, + { + name: 'chooseObject', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'ObjectTypeAnnotation', + }, + }, + { + name: 'chooseString', + optional: false, + typeAnnotation: { + type: 'UnionTypeAnnotation', + memberType: 'StringTypeAnnotation', + }, + }, + ], + }, + }, + ], + }, + moduleName: 'SampleTurboModule', + }, + }, +}; + module.exports = { complex_objects: COMPLEX_OBJECTS, two_modules_different_files: TWO_MODULES_DIFFERENT_FILES, @@ -2585,4 +2646,5 @@ module.exports = { real_module_example: REAL_MODULE_EXAMPLE, cxx_only_native_modules: CXX_ONLY_NATIVE_MODULES, SampleWithUppercaseName: SAMPLE_WITH_UPPERCASE_NAME, + union_module: UNION_MODULE, }; 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 8e0045608a7..cefc9c3956a 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 @@ -705,6 +705,42 @@ NativeSampleTurboModule2CxxSpecJSI::NativeSampleTurboModule2CxxSpecJSI(std::shar } +} // namespace facebook::react +", +} +`; + +exports[`GenerateModuleCpp can generate fixture union_module 1`] = ` +Map { + "union_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 \\"union_moduleJSI.h\\" + +namespace facebook::react { + +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getUnion(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getUnion( + rt, + count <= 0 ? throw jsi::JSError(rt, \\"Expected argument in position 0 to be passed\\") : args[0].asNumber(), + count <= 1 ? throw jsi::JSError(rt, \\"Expected argument in position 1 to be passed\\") : args[1].asNumber(), + count <= 2 ? throw jsi::JSError(rt, \\"Expected argument in position 2 to be passed\\") : args[2].asObject(rt), + count <= 3 ? throw jsi::JSError(rt, \\"Expected argument in position 3 to be passed\\") : args[3].asString(rt) + ); +} + +NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModule\\", jsInvoker) { + methodMap_[\\"getUnion\\"] = MethodMetadata {4, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getUnion}; +} + + } // 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 c297d405592..3c559f125a5 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 @@ -2412,3 +2412,80 @@ private: ", } `; + +exports[`GenerateModuleH can generate fixture union_module 1`] = ` +Map { + "union_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 { + + + class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Object getUnion(jsi::Runtime &rt, double chooseInt, double chooseFloat, jsi::Object chooseObject, jsi::String chooseString) = 0; + +}; + +template +class JSI_EXPORT NativeSampleTurboModuleCxxSpec : public TurboModule { +public: + jsi::Value create(jsi::Runtime &rt, const jsi::PropNameID &propName) override { + return delegate_.create(rt, propName); + } + + std::vector getPropertyNames(jsi::Runtime& runtime) override { + return delegate_.getPropertyNames(runtime); + } + + static constexpr std::string_view kModuleName = \\"SampleTurboModule\\"; + +protected: + NativeSampleTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(std::string{NativeSampleTurboModuleCxxSpec::kModuleName}, jsInvoker), + delegate_(reinterpret_cast(this), jsInvoker) {} + + +private: + class Delegate : public NativeSampleTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) { + + } + + jsi::Object getUnion(jsi::Runtime &rt, double chooseInt, double chooseFloat, jsi::Object chooseObject, jsi::String chooseString) override { + static_assert( + bridging::getParameterCount(&T::getUnion) == 5, + \\"Expected getUnion(...) to have 5 parameters\\"); + + return bridging::callFromJs( + rt, &T::getUnion, jsInvoker_, instance_, std::move(chooseInt), std::move(chooseFloat), std::move(chooseObject), std::move(chooseString)); + } + + private: + friend class NativeSampleTurboModuleCxxSpec; + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace facebook::react +", +} +`; 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 3fafff6f52f..2b68008dc63 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 @@ -1186,3 +1186,71 @@ namespace facebook::react { ", } `; + +exports[`GenerateModuleHObjCpp can generate fixture union_module 1`] = ` +Map { + "union_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 union_module symbols +#ifndef union_module_H +#define union_module_H + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + +@protocol NativeSampleTurboModuleSpec + +- (NSDictionary *)getUnion:(double)chooseInt + chooseFloat:(double)chooseFloat + chooseObject:(NSDictionary *)chooseObject + chooseString:(NSString *)chooseString; + +@end + +@interface NativeSampleTurboModuleSpecBase : NSObject { +@protected +facebook::react::EventEmitterCallback _eventEmitterCallback; +} +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper; + + +@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 // union_module_H +", +} +`; 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 4da79695dad..e90a1b00f8f 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 @@ -591,3 +591,48 @@ public abstract class NativeSampleTurboModule2Spec extends ReactContextBaseJavaM ", } `; + +exports[`GenerateModuleJavaSpec can generate fixture union_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.ReadableMap; +import com.facebook.react.bridge.WritableMap; +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; + } + + @ReactMethod(isBlockingSynchronousMethod = true) + @DoNotStrip + public abstract WritableMap getUnion(double chooseInt, double chooseFloat, ReadableMap chooseObject, String chooseString); +} +", +} +`; 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 c929bfd55c5..7990033c5ca 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 @@ -512,3 +512,41 @@ std::shared_ptr two_modules_different_files_ModuleProvider(const st ", } `; + +exports[`GenerateModuleJniCpp can generate fixture union_module 1`] = ` +Map { + "jni/union_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 \\"union_module.h\\" + +namespace facebook::react { + +static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getUnion(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + static jmethodID cachedMethodId = nullptr; + return static_cast(turboModule).invokeJavaMethod(rt, ObjectKind, \\"getUnion\\", \\"(DDLcom/facebook/react/bridge/ReadableMap;Ljava/lang/String;)Lcom/facebook/react/bridge/WritableMap;\\", args, count, cachedMethodId); +} + +NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const JavaTurboModule::InitParams ¶ms) + : JavaTurboModule(params) { + methodMap_[\\"getUnion\\"] = MethodMetadata {4, __hostFunction_NativeSampleTurboModuleSpecJSI_getUnion}; +} + +std::shared_ptr union_module_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + if (moduleName == \\"SampleTurboModule\\") { + return std::make_shared(params); + } + return nullptr; +} + +} // namespace facebook::react +", +} +`; 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 f656df76b87..9126401fbeb 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 @@ -674,3 +674,77 @@ target_compile_options( ", } `; + +exports[`GenerateModuleJniH can generate fixture union_module 1`] = ` +Map { + "jni/union_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 union_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/union_module/*.cpp) + +add_library( + react_codegen_union_module + OBJECT + \${react_codegen_SRCS} +) + +target_include_directories(react_codegen_union_module PUBLIC . react/renderer/components/union_module) + +target_link_libraries( + react_codegen_union_module + fbjni + jsi + # We need to link different libraries based on whether we are building rncore or not, that's necessary + # because we want to break a circular dependency between react_codegen_rncore and reactnative + reactnative +) + +target_compile_options( + react_codegen_union_module + PRIVATE + -DLOG_TAG=\\\\\\"ReactNative\\\\\\" + -fexceptions + -frtti + -std=c++20 + -Wall +) +", +} +`; 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 13be394c79d..656296fd539 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 @@ -700,3 +700,48 @@ namespace facebook::react { ", } `; + +exports[`GenerateModuleMm can generate fixture union_module 1`] = ` +Map { + "union_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 \\"union_module.h\\" + + +@implementation NativeSampleTurboModuleSpecBase + + +- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper +{ + _eventEmitterCallback = std::move(eventEmitterCallbackWrapper->_eventEmitterCallback); +} +@end + + +namespace facebook::react { + + static facebook::jsi::Value __hostFunction_NativeSampleTurboModuleSpecJSI_getUnion(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, ObjectKind, \\"getUnion\\", @selector(getUnion:chooseFloat:chooseObject:chooseString:), args, count); + } + + NativeSampleTurboModuleSpecJSI::NativeSampleTurboModuleSpecJSI(const ObjCTurboModule::InitParams ¶ms) + : ObjCTurboModule(params) { + + methodMap_[\\"getUnion\\"] = MethodMetadata {4, __hostFunction_NativeSampleTurboModuleSpecJSI_getUnion}; + + } +} // namespace facebook::react +", +} +`; diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js index 9544c8999ce..8a0b3934810 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/__test_fixtures__/fixtures.js @@ -619,7 +619,35 @@ export interface Spec extends TurboModule { } export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); +`; +const NATIVE_MODULE_WITH_UNION_RETURN_TYPES = ` +/** + * 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 {TurboModule} from '../../../../Libraries/TurboModule/RCTExport'; + +import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getStringUnion: () => 'light' | 'dark'; + +setStringUnion: (strings: 'light' | 'dark') => void; + + +getNumberUnion: () => 1 | 2; + +setNumberUnion: (numbers: 1 | 2) => void; + + +getObjectUnion: () => {a: 1} | {b: 2}; + +setObjectUnion: (objects: {a: 1} | {b: 2}) => void; +} + +export default (TurboModuleRegistry.get('SampleTurboModule'): ?Spec); `; const NATIVE_MODULE_WITH_EVENT_EMITTERS = ` @@ -854,6 +882,7 @@ module.exports = { NATIVE_MODULE_WITH_BASIC_PARAM_TYPES, NATIVE_MODULE_WITH_CALLBACK, NATIVE_MODULE_WITH_UNION, + NATIVE_MODULE_WITH_UNION_RETURN_TYPES, NATIVE_MODULE_WITH_EVENT_EMITTERS, EMPTY_NATIVE_MODULE, ANDROID_ONLY_NATIVE_MODULE, diff --git a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap index be6a7997ced..6580851a5af 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/modules/__tests__/__snapshots__/module-parser-snapshot-test.js.snap @@ -2281,6 +2281,120 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNION 1` }" `; +exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNION_RETURN_TYPES 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliasMap': {}, + 'enumMap': {}, + 'spec': { + 'eventEmitters': [], + 'methods': [ + { + 'name': 'getStringUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'StringTypeAnnotation' + }, + 'params': [] + } + }, + { + 'name': 'setStringUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'strings', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'getNumberUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + }, + 'params': [] + } + }, + { + 'name': 'setNumberUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'numbers', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'getObjectUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + }, + 'params': [] + } + }, + { + 'name': 'setObjectUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'objects', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_UNSAFE_OBJECT 1`] = ` "{ 'modules': { diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js index 41495d6dc54..5c28d3955d4 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__test_fixtures__/fixtures.js @@ -725,6 +725,33 @@ export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); `; +const NATIVE_MODULE_WITH_UNION_RETURN_TYPES = ` +/** + * 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. + * + * @format + */ + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + readonly getStringUnion: () => 'light' | 'dark'; + readonly setStringUnion: (strings: 'light' | 'dark') => void; + + readonly getNumberUnion: () => 1 | 2; + readonly setNumberUnion: (numbers: 1 | 2) => void; + + readonly getObjectUnion: () => {a: 1} | {b: 2}; + readonly setObjectUnion: (objects: {a: 1} | {b: 2}) => void; +} + +export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); +`; + const NATIVE_MODULE_WITH_EVENT_EMITTERS = ` /** * Copyright (c) Meta Platforms, Inc. and affiliates. @@ -912,6 +939,7 @@ module.exports = { NATIVE_MODULE_WITH_BASIC_PARAM_TYPES, NATIVE_MODULE_WITH_CALLBACK, NATIVE_MODULE_WITH_UNION, + NATIVE_MODULE_WITH_UNION_RETURN_TYPES, NATIVE_MODULE_WITH_EVENT_EMITTERS, EMPTY_NATIVE_MODULE, ANDROID_ONLY_NATIVE_MODULE, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap index 8e99438fd9e..0f3cd82c2e5 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap +++ b/packages/react-native-codegen/src/parsers/typescript/modules/__tests__/__snapshots__/typescript-module-parser-snapshot-test.js.snap @@ -2759,6 +2759,120 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_UN }" `; +exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_UNION_RETURN_TYPES 1`] = ` +"{ + 'modules': { + 'NativeSampleTurboModule': { + 'type': 'NativeModule', + 'aliasMap': {}, + 'enumMap': {}, + 'spec': { + 'eventEmitters': [], + 'methods': [ + { + 'name': 'getStringUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'StringTypeAnnotation' + }, + 'params': [] + } + }, + { + 'name': 'setStringUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'strings', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'StringTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'getNumberUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + }, + 'params': [] + } + }, + { + 'name': 'setNumberUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'numbers', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'NumberTypeAnnotation' + } + } + ] + } + }, + { + 'name': 'getObjectUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + }, + 'params': [] + } + }, + { + 'name': 'setObjectUnion', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'VoidTypeAnnotation' + }, + 'params': [ + { + 'name': 'objects', + 'optional': false, + 'typeAnnotation': { + 'type': 'UnionTypeAnnotation', + 'memberType': 'ObjectTypeAnnotation' + } + } + ] + } + } + ] + }, + 'moduleName': 'SampleTurboModule' + } + } +}" +`; + exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_UNSAFE_OBJECT 1`] = ` "{ 'modules': {