From 3c569f546ca78b23fbcb9773a1273dd9710f8c60 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 24 May 2022 19:35:29 -0700 Subject: [PATCH] Support mixed types only for C++ Summary: There are cases where we want to pass arbitrary types to a TurboModule, which may then handle the values appropriately, but we haven't supported this use case. Since C++ TurboModules can accept any `jsi::Value` (unlike Java/ObjC) and we have real-world need for this (otherwise we must require JSON serialization), this now allows `mixed` (`unknown` in TypeScript) for C++-only TurboModules. Changelog: [General][Added] C++ TurboModule methods can now use mixed types Reviewed By: RSNara Differential Revision: D36611299 fbshipit-source-id: bbf29dfcc6aed67e213bb3eab06537c18c7db1fe --- .../react-native-codegen/src/CodegenSchema.js | 7 +- .../generators/modules/GenerateModuleCpp.js | 28 ++--- .../src/generators/modules/GenerateModuleH.js | 2 + .../modules/GenerateModuleJavaSpec.js | 6 +- .../modules/GenerateModuleJniCpp.js | 6 +- .../GenerateModuleObjCpp/StructCollector.js | 2 + .../GenerateModuleObjCpp/serializeMethod.js | 4 +- .../modules/__test_fixtures__/fixtures.js | 35 ++++++ .../GenerateModuleCpp-test.js.snap | 32 ++++++ .../GenerateModuleH-test.js.snap | 68 ++++++++++++ .../GenerateModuleHObjCpp-test.js.snap | 35 ++++++ .../GenerateModuleJavaSpec-test.js.snap | 2 + .../GenerateModuleJniCpp-test.js.snap | 30 ++++++ .../GenerateModuleJniH-test.js.snap | 102 ++++++++++++++++++ .../GenerateModuleMm-test.js.snap | 22 ++++ .../modules/__test_fixtures__/fixtures.js | 1 + .../module-parser-snapshot-test.js.snap | 19 ++++ .../src/parsers/flow/modules/index.js | 8 ++ .../modules/__test_fixtures__/fixtures.js | 1 + ...script-module-parser-snapshot-test.js.snap | 19 ++++ .../src/parsers/typescript/modules/index.js | 8 ++ 21 files changed, 415 insertions(+), 22 deletions(-) diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 5e152e001481ba..8776caaa9232a9 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -295,6 +295,10 @@ export type NativeModulePromiseTypeAnnotation = $ReadOnly<{ type: 'PromiseTypeAnnotation', }>; +export type NativeModuleMixedTypeAnnotation = $ReadOnly<{ + type: 'MixedTypeAnnotation', +}>; + export type NativeModuleBaseTypeAnnotation = | NativeModuleStringTypeAnnotation | NativeModuleNumberTypeAnnotation @@ -306,7 +310,8 @@ export type NativeModuleBaseTypeAnnotation = | ReservedTypeAnnotation | NativeModuleTypeAliasTypeAnnotation | NativeModuleArrayTypeAnnotation> - | NativeModuleObjectTypeAnnotation; + | NativeModuleObjectTypeAnnotation + | NativeModuleMixedTypeAnnotation; export type NativeModuleParamTypeAnnotation = | NativeModuleBaseTypeAnnotation diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js index 2e6da494e43117..5bc19c9b8f7b00 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleCpp.js @@ -114,9 +114,9 @@ function serializeArg( realTypeAnnotation = resolveAlias(realTypeAnnotation.name); } - function wrap(suffix) { + function wrap(callback) { const val = `args[${index}]`; - const expression = `${val}${suffix}`; + const expression = callback(val); if (nullable) { return `${val}.isNull() || ${val}.isUndefined() ? std::nullopt : std::make_optional(${expression})`; @@ -129,7 +129,7 @@ function serializeArg( case 'ReservedTypeAnnotation': switch (realTypeAnnotation.name) { case 'RootTag': - return wrap('.getNumber()'); + return wrap(val => `${val}.getNumber()`); default: (realTypeAnnotation.name: empty); throw new Error( @@ -137,25 +137,27 @@ function serializeArg( ); } case 'StringTypeAnnotation': - return wrap('.asString(rt)'); + return wrap(val => `${val}.asString(rt)`); case 'BooleanTypeAnnotation': - return wrap('.asBool()'); + return wrap(val => `${val}.asBool()`); case 'NumberTypeAnnotation': - return wrap('.asNumber()'); + return wrap(val => `${val}.asNumber()`); case 'FloatTypeAnnotation': - return wrap('.asNumber()'); + return wrap(val => `${val}.asNumber()`); case 'DoubleTypeAnnotation': - return wrap('.asNumber()'); + return wrap(val => `${val}.asNumber()`); case 'Int32TypeAnnotation': - return wrap('.asNumber()'); + return wrap(val => `${val}.asNumber()`); case 'ArrayTypeAnnotation': - return wrap('.asObject(rt).asArray(rt)'); + return wrap(val => `${val}.asObject(rt).asArray(rt)`); case 'FunctionTypeAnnotation': - return wrap('.asObject(rt).asFunction(rt)'); + return wrap(val => `${val}.asObject(rt).asFunction(rt)`); case 'GenericObjectTypeAnnotation': - return wrap('.asObject(rt)'); + return wrap(val => `${val}.asObject(rt)`); case 'ObjectTypeAnnotation': - return wrap('.asObject(rt)'); + return wrap(val => `${val}.asObject(rt)`); + case 'MixedTypeAnnotation': + return wrap(val => `jsi::Value(rt, ${val})`); default: (realTypeAnnotation.type: empty); throw new Error( diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js index 17c4f927118b59..d21f33c928355c 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleH.js @@ -156,6 +156,8 @@ function translatePrimitiveJSTypeToCpp( return wrap('jsi::Function'); case 'PromiseTypeAnnotation': return wrap('jsi::Value'); + case 'MixedTypeAnnotation': + return wrap('jsi::Value'); default: (realTypeAnnotation.type: empty); throw new Error(createErrorMessage(realTypeAnnotation.type)); diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js index 940b721ad41647..538371a7c49520 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJavaSpec.js @@ -156,7 +156,7 @@ function translateFunctionParamToJavaType( imports.add('com.facebook.react.bridge.Callback'); return 'Callback'; default: - (realTypeAnnotation.type: empty); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -220,7 +220,7 @@ function translateFunctionReturnTypeToJavaType( imports.add('com.facebook.react.bridge.WritableArray'); return wrapIntoNullableIfNeeded('WritableArray'); default: - (realTypeAnnotation.type: empty); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } @@ -272,7 +272,7 @@ function getFalsyReturnStatementFromReturnType( case 'ArrayTypeAnnotation': return 'return null;'; default: - (realTypeAnnotation.type: empty); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error(createErrorMessage(realTypeAnnotation.type)); } } diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js index 756bde5fa6bbb5..4adb37c943c56d 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleJniCpp.js @@ -171,7 +171,7 @@ function translateReturnTypeToKind( case 'ArrayTypeAnnotation': return 'ArrayKind'; default: - (realTypeAnnotation.type: empty); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unknown prop type for returning value, found: ${realTypeAnnotation.type}"`, ); @@ -226,7 +226,7 @@ function translateParamTypeToJniType( case 'FunctionTypeAnnotation': return 'Lcom/facebook/react/bridge/Callback;'; default: - (realTypeAnnotation.type: empty); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unknown prop type for method arg, found: ${realTypeAnnotation.type}"`, ); @@ -278,7 +278,7 @@ function translateReturnTypeToJniType( case 'ArrayTypeAnnotation': return 'Lcom/facebook/react/bridge/WritableArray;'; default: - (realTypeAnnotation.type: empty); + (realTypeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unknown prop type for method return type, found: ${realTypeAnnotation.type}"`, ); 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 725809dfdf65d0..e942ff3c978255 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/StructCollector.js @@ -112,6 +112,8 @@ class StructCollector { this._insertAlias(typeAnnotation.name, structContext, resolveAlias); return wrapNullable(nullable, typeAnnotation); } + case 'MixedTypeAnnotation': + throw new Error('Mixed types are unsupported in structs'); default: { return wrapNullable(nullable, typeAnnotation); } diff --git a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js index bb258919c6bc4b..8bedb6cb61f929 100644 --- a/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js +++ b/packages/react-native-codegen/src/generators/modules/GenerateModuleObjCpp/serializeMethod.js @@ -338,7 +338,7 @@ function getReturnObjCType( case 'GenericObjectTypeAnnotation': return wrapIntoNullableIfNeeded('NSDictionary *'); default: - (typeAnnotation.type: empty); + (typeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, ); @@ -378,7 +378,7 @@ function getReturnJSType( case 'GenericObjectTypeAnnotation': return 'ObjectKind'; default: - (typeAnnotation.type: empty); + (typeAnnotation.type: 'MixedTypeAnnotation'); throw new Error( `Unsupported return type for ${methodName}. Found: ${typeAnnotation.type}`, ); 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 48647b993c0105..5c11544020f8ec 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 @@ -1502,6 +1502,40 @@ const REAL_MODULE_EXAMPLE: SchemaType = { }, }; +const CXX_ONLY_NATIVE_MODULES: SchemaType = { + modules: { + NativeSampleTurboModule: { + type: 'NativeModule', + aliases: {}, + spec: { + properties: [ + { + name: 'getMixed', + optional: false, + typeAnnotation: { + type: 'FunctionTypeAnnotation', + returnTypeAnnotation: { + type: 'MixedTypeAnnotation', + }, + params: [ + { + name: 'arg', + optional: false, + typeAnnotation: { + type: 'MixedTypeAnnotation', + }, + }, + ], + }, + }, + ], + }, + moduleNames: ['SampleTurboModuleCxx'], + excludedPlatforms: ['iOS', 'android'], + }, + }, +}; + const SAMPLE_WITH_UPPERCASE_NAME: SchemaType = { modules: { NativeSampleTurboModule: { @@ -1522,5 +1556,6 @@ module.exports = { simple_native_modules: SIMPLE_NATIVE_MODULES, native_modules_with_type_aliases: NATIVE_MODULES_WITH_TYPE_ALIASES, real_module_example: REAL_MODULE_EXAMPLE, + cxx_only_native_modules: CXX_ONLY_NATIVE_MODULES, SampleWithUppercaseName: SAMPLE_WITH_UPPERCASE_NAME, }; 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 c4713fb7431cf1..34baec11bd61e3 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 @@ -83,6 +83,38 @@ NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared } +} // namespace react +} // namespace facebook +", +} +`; + +exports[`GenerateModuleCpp can generate fixture cxx_only_native_modules 1`] = ` +Map { + "cxx_only_native_modulesJSI-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: GenerateModuleH.js + */ + +#include \\"cxx_only_native_modulesJSI.h\\" + +namespace facebook { +namespace react { + +static jsi::Value __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getMixed(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getMixed(rt, jsi::Value(rt, args[0])); +} + +NativeSampleTurboModuleCxxSpecJSI::NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleCxx\\", jsInvoker) { + methodMap_[\\"getMixed\\"] = MethodMetadata {1, __hostFunction_NativeSampleTurboModuleCxxSpecJSI_getMixed}; +} + + } // namespace react } // namespace facebook ", 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 5bbd47d7380f70..64ce2ccd861741 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 @@ -183,6 +183,74 @@ private: } `; +exports[`GenerateModuleH can generate fixture cxx_only_native_modules 1`] = ` +Map { + "cxx_only_native_modulesJSI.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 { +namespace react { + +class JSI_EXPORT NativeSampleTurboModuleCxxSpecJSI : public TurboModule { +protected: + NativeSampleTurboModuleCxxSpecJSI(std::shared_ptr jsInvoker); + +public: + virtual jsi::Value getMixed(jsi::Runtime &rt, jsi::Value arg) = 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); + } + +protected: + NativeSampleTurboModuleCxxSpec(std::shared_ptr jsInvoker) + : TurboModule(\\"SampleTurboModuleCxx\\", jsInvoker), + delegate_(static_cast(this), jsInvoker) {} + +private: + class Delegate : public NativeSampleTurboModuleCxxSpecJSI { + public: + Delegate(T *instance, std::shared_ptr jsInvoker) : + NativeSampleTurboModuleCxxSpecJSI(std::move(jsInvoker)), instance_(instance) {} + + jsi::Value getMixed(jsi::Runtime &rt, jsi::Value arg) override { + static_assert( + bridging::getParameterCount(&T::getMixed) == 2, + \\"Expected getMixed(...) to have 2 parameters\\"); + + return bridging::callFromJs( + rt, &T::getMixed, jsInvoker_, instance_, std::move(arg)); + } + + private: + T *instance_; + }; + + Delegate delegate_; +}; + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GenerateModuleH can generate fixture empty_native_modules 1`] = ` Map { "empty_native_modulesJSI.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 d17ebebe5f6644..07ab8ba9129c19 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 @@ -308,6 +308,41 @@ inline facebook::react::LazyVector "/** + * 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 +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + + + ", } `; 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 fed306c0cea645..3fec5218b9ffa3 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 @@ -100,6 +100,8 @@ public abstract class NativeSampleTurboModuleSpec extends ReactContextBaseJavaMo } `; +exports[`GenerateModuleJavaSpec can generate fixture cxx_only_native_modules 1`] = `Map {}`; + exports[`GenerateModuleJavaSpec can generate fixture empty_native_modules 1`] = ` Map { "java/com/facebook/fbreact/specs/NativeSampleTurboModuleSpec.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 323cb75d3122b2..9d771b73dddaa2 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 @@ -113,6 +113,36 @@ std::shared_ptr complex_objects_ModuleProvider(const std::string &m } `; +exports[`GenerateModuleJniCpp can generate fixture cxx_only_native_modules 1`] = ` +Map { + "jni/cxx_only_native_modules-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 \\"cxx_only_native_modules.h\\" + +namespace facebook { +namespace react { + + + +std::shared_ptr cxx_only_native_modules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms) { + + return nullptr; +} + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GenerateModuleJniCpp can generate fixture empty_native_modules 1`] = ` Map { "jni/empty_native_modules-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 2a041e62bb68ce..9f39609d66e8a8 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 @@ -218,6 +218,108 @@ target_compile_options( } `; +exports[`GenerateModuleJniH can generate fixture cxx_only_native_modules 1`] = ` +Map { + "jni/cxx_only_native_modules.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 { +namespace react { + + + +std::shared_ptr cxx_only_native_modules_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams ¶ms); + +} // namespace react +} // namespace facebook +", + "jni/Android.mk" => "# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := react_codegen_cxx_only_native_modules + +LOCAL_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(LOCAL_PATH)/react/renderer/components/cxx_only_native_modules/*.cpp) +LOCAL_SRC_FILES := $(subst $(LOCAL_PATH)/,,$(LOCAL_SRC_FILES)) + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/react/renderer/components/cxx_only_native_modules + +LOCAL_SHARED_LIBRARIES := libfbjni libfolly_runtime libglog libjsi libreact_codegen_rncore libreact_debug libreact_nativemodule_core libreact_render_core libreact_render_debug libreact_render_graphics librrc_view libturbomodulejsijni libyoga + +LOCAL_CFLAGS := \\\\ + -DLOG_TAG=\\\\\\"ReactNative\\\\\\" + +LOCAL_CFLAGS += -fexceptions -frtti -std=c++17 -Wall + +include $(BUILD_SHARED_LIBRARY) +", + "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/cxx_only_native_modules/*.cpp) + +add_library( + react_codegen_cxx_only_native_modules + SHARED + \${react_codegen_SRCS} +) + +target_include_directories(react_codegen_cxx_only_native_modules PUBLIC . react/renderer/components/cxx_only_native_modules) + +target_link_libraries( + react_codegen_cxx_only_native_modules + fbjni + folly_runtime + glog + react_codegen_rncore + react_debug + react_nativemodule_core + react_render_core + react_render_debug + react_render_graphics + rrc_view + turbomodulejsijni + yoga +) + +target_compile_options( + react_codegen_cxx_only_native_modules + PRIVATE + -DLOG_TAG=\\\\\\"ReactNative\\\\\\" + -fexceptions + -frtti + -std=c++17 + -Wall +) +", +} +`; + exports[`GenerateModuleJniH can generate fixture empty_native_modules 1`] = ` Map { "jni/empty_native_modules.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 584f1017ea5c05..3b2acb73c23930 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 @@ -146,6 +146,28 @@ namespace facebook { } `; +exports[`GenerateModuleMm can generate fixture cxx_only_native_modules 1`] = ` +Map { + "cxx_only_native_modules-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 \\"cxx_only_native_modules.h\\" + + +", +} +`; + exports[`GenerateModuleMm can generate fixture empty_native_modules 1`] = ` Map { "empty_native_modules-generated.mm" => "/** 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 ef8938c70efb6f..1583f3f2daa051 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 @@ -591,6 +591,7 @@ import * as TurboModuleRegistry from '../TurboModuleRegistry'; export interface Spec extends TurboModule { +getCallback: () => () => void; + +getMixed: (arg: mixed) => mixed; } export default TurboModuleRegistry.getEnforcing('SampleTurboModuleCxx'); 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 d6858f03512932..66a8b5f4a87fa5 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 @@ -58,6 +58,25 @@ exports[`RN Codegen Flow Parser can generate fixture CXX_ONLY_NATIVE_MODULE 1`] }, 'params': [] } + }, + { + 'name': 'getMixed', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'MixedTypeAnnotation' + }, + 'params': [ + { + 'name': 'arg', + 'optional': false, + 'typeAnnotation': { + 'type': 'MixedTypeAnnotation' + } + } + ] + } } ] }, diff --git a/packages/react-native-codegen/src/parsers/flow/modules/index.js b/packages/react-native-codegen/src/parsers/flow/modules/index.js index 293981660cef23..307ffb01854ee4 100644 --- a/packages/react-native-codegen/src/parsers/flow/modules/index.js +++ b/packages/react-native-codegen/src/parsers/flow/modules/index.js @@ -363,6 +363,14 @@ function translateTypeAnnotation( ), ); } + case 'MixedTypeAnnotation': { + if (cxxOnly) { + return wrapNullable(nullable, { + type: 'MixedTypeAnnotation', + }); + } + // Fallthrough + } default: { throw new UnsupportedFlowTypeAnnotationParserError( hasteModuleName, 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 553ac7becabd28..665e33e0b0eebd 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 @@ -519,6 +519,7 @@ import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboMo export interface Spec extends TurboModule { readonly getCallback: () => () => void; + readonly getMixed: (arg: unknown) => unknown; } export default TurboModuleRegistry.getEnforcing( 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 68272d1141126f..faafd1d1334b19 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 @@ -56,6 +56,25 @@ exports[`RN Codegen TypeScript Parser can generate fixture CXX_ONLY_NATIVE_MODUL }, 'params': [] } + }, + { + 'name': 'getMixed', + 'optional': false, + 'typeAnnotation': { + 'type': 'FunctionTypeAnnotation', + 'returnTypeAnnotation': { + 'type': 'MixedTypeAnnotation' + }, + 'params': [ + { + 'name': 'arg', + 'optional': false, + 'typeAnnotation': { + 'type': 'MixedTypeAnnotation' + } + } + ] + } } ] }, diff --git a/packages/react-native-codegen/src/parsers/typescript/modules/index.js b/packages/react-native-codegen/src/parsers/typescript/modules/index.js index 564497cf707d0b..96ff34e5a549e3 100644 --- a/packages/react-native-codegen/src/parsers/typescript/modules/index.js +++ b/packages/react-native-codegen/src/parsers/typescript/modules/index.js @@ -363,6 +363,14 @@ function translateTypeAnnotation( ), ); } + case 'TSUnknownKeyword': { + if (cxxOnly) { + return wrapNullable(nullable, { + type: 'MixedTypeAnnotation', + }); + } + // Fallthrough + } default: { throw new UnsupportedTypeScriptTypeAnnotationParserError( hasteModuleName,