Turbo module: Fixes dictionary stripped out when value is null (#51103)

Summary:
Fixes https://github.com/facebook/react-native/issues/51083. Turbo stripped out the dictionary when the value is null. The old architecture transforms null to NSNull. The null seems useful in cases like #51803 for removing the storage of the key. cipolleschi can you please help to review?

## Changelog:

[IOS] [FIXED] - Turbo module: Fixes dictionary stripped out when value is null

Pull Request resolved: https://github.com/facebook/react-native/pull/51103

Test Plan: Repro please see https://github.com/facebook/react-native/issues/51083.

Reviewed By: rshest

Differential Revision: D74208525

Pulled By: javache

fbshipit-source-id: 53d630c265fba15d25309a3e1deb19dca24f298c
This commit is contained in:
zhongwuzw
2025-05-23 06:39:41 -07:00
committed by Facebook GitHub Bot
parent 6ff500d694
commit 4a4fd1cb8b
22 changed files with 187 additions and 54 deletions
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<62715a19c87a010716eb7d2e904258fa>>
* @generated SignedSource<<a5552614b746c732adb88a6640a7951a>>
*/
/**
@@ -174,6 +174,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableMainQueueModulesOnIOS(): Boolean = accessor.enableMainQueueModulesOnIOS()
/**
* Enable NSNull conversion when handling module arguments on iOS
*/
@JvmStatic
public fun enableModuleArgumentNSNullConversionIOS(): Boolean = accessor.enableModuleArgumentNSNullConversionIOS()
/**
* Parse CSS strings using the Fabric CSS parser instead of ViewConfig processing
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<53e2f9241b9b3396b1ddf5893c7f3c4e>>
* @generated SignedSource<<4665e190f626b377f37e14c1c19f809d>>
*/
/**
@@ -44,6 +44,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
private var enableMainQueueModulesOnIOSCache: Boolean? = null
private var enableModuleArgumentNSNullConversionIOSCache: Boolean? = null
private var enableNativeCSSParsingCache: Boolean? = null
private var enableNetworkEventReportingCache: Boolean? = null
private var enableNewBackgroundAndBorderDrawablesCache: Boolean? = null
@@ -287,6 +288,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun enableModuleArgumentNSNullConversionIOS(): Boolean {
var cached = enableModuleArgumentNSNullConversionIOSCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.enableModuleArgumentNSNullConversionIOS()
enableModuleArgumentNSNullConversionIOSCache = cached
}
return cached
}
override fun enableNativeCSSParsing(): Boolean {
var cached = enableNativeCSSParsingCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<918dcdb416bb3e2e3f83cded78e06363>>
* @generated SignedSource<<b68166d039f6214ff09dc30a742ebbf9>>
*/
/**
@@ -76,6 +76,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun enableMainQueueModulesOnIOS(): Boolean
@DoNotStrip @JvmStatic public external fun enableModuleArgumentNSNullConversionIOS(): Boolean
@DoNotStrip @JvmStatic public external fun enableNativeCSSParsing(): Boolean
@DoNotStrip @JvmStatic public external fun enableNetworkEventReporting(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7151e167c4e45a732a341a2cfcf67b58>>
* @generated SignedSource<<fcee66a9800d5b3b1105df73d33feea9>>
*/
/**
@@ -71,6 +71,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun enableMainQueueModulesOnIOS(): Boolean = false
override fun enableModuleArgumentNSNullConversionIOS(): Boolean = true
override fun enableNativeCSSParsing(): Boolean = false
override fun enableNetworkEventReporting(): Boolean = false
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<d2f4ae1cd4e33cb59903c3b2c3ef0fc2>>
* @generated SignedSource<<ebf6d5811f40eedd906c015283f5757f>>
*/
/**
@@ -48,6 +48,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
private var enableMainQueueModulesOnIOSCache: Boolean? = null
private var enableModuleArgumentNSNullConversionIOSCache: Boolean? = null
private var enableNativeCSSParsingCache: Boolean? = null
private var enableNetworkEventReportingCache: Boolean? = null
private var enableNewBackgroundAndBorderDrawablesCache: Boolean? = null
@@ -315,6 +316,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun enableModuleArgumentNSNullConversionIOS(): Boolean {
var cached = enableModuleArgumentNSNullConversionIOSCache
if (cached == null) {
cached = currentProvider.enableModuleArgumentNSNullConversionIOS()
accessedFeatureFlags.add("enableModuleArgumentNSNullConversionIOS")
enableModuleArgumentNSNullConversionIOSCache = cached
}
return cached
}
override fun enableNativeCSSParsing(): Boolean {
var cached = enableNativeCSSParsingCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<722ed5b36a043d4eadb095f092c95707>>
* @generated SignedSource<<1e5562ce20c0735c926c1cb029b93e18>>
*/
/**
@@ -71,6 +71,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun enableMainQueueModulesOnIOS(): Boolean
@DoNotStrip public fun enableModuleArgumentNSNullConversionIOS(): Boolean
@DoNotStrip public fun enableNativeCSSParsing(): Boolean
@DoNotStrip public fun enableNetworkEventReporting(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<422a5922cfe14a1c5f7c0728410dbe8a>>
* @generated SignedSource<<078954ede626079b7d36ab63cdbab761>>
*/
/**
@@ -183,6 +183,12 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}
bool enableModuleArgumentNSNullConversionIOS() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableModuleArgumentNSNullConversionIOS");
return method(javaProvider_);
}
bool enableNativeCSSParsing() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableNativeCSSParsing");
@@ -463,6 +469,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableMainQueueModulesOnIOS(
return ReactNativeFeatureFlags::enableMainQueueModulesOnIOS();
}
bool JReactNativeFeatureFlagsCxxInterop::enableModuleArgumentNSNullConversionIOS(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS();
}
bool JReactNativeFeatureFlagsCxxInterop::enableNativeCSSParsing(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::enableNativeCSSParsing();
@@ -696,6 +707,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"enableMainQueueModulesOnIOS",
JReactNativeFeatureFlagsCxxInterop::enableMainQueueModulesOnIOS),
makeNativeMethod(
"enableModuleArgumentNSNullConversionIOS",
JReactNativeFeatureFlagsCxxInterop::enableModuleArgumentNSNullConversionIOS),
makeNativeMethod(
"enableNativeCSSParsing",
JReactNativeFeatureFlagsCxxInterop::enableNativeCSSParsing),
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<18d7c9c2577450a0bb7e6da91b8597ed>>
* @generated SignedSource<<083e45ab99622254be46213ba07c586b>>
*/
/**
@@ -102,6 +102,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool enableMainQueueModulesOnIOS(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool enableModuleArgumentNSNullConversionIOS(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool enableNativeCSSParsing(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<9f34463a7cddcfd1a76631041297c4b7>>
* @generated SignedSource<<c099ce4bba5f6d14a83ad69a0fb3cbbf>>
*/
/**
@@ -122,6 +122,10 @@ bool ReactNativeFeatureFlags::enableMainQueueModulesOnIOS() {
return getAccessor().enableMainQueueModulesOnIOS();
}
bool ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS() {
return getAccessor().enableModuleArgumentNSNullConversionIOS();
}
bool ReactNativeFeatureFlags::enableNativeCSSParsing() {
return getAccessor().enableNativeCSSParsing();
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<cb84333e310cfc1a6a77f1b376723e93>>
* @generated SignedSource<<ac9a0bc61f58cce6fe9d229c551dc3f7>>
*/
/**
@@ -159,6 +159,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool enableMainQueueModulesOnIOS();
/**
* Enable NSNull conversion when handling module arguments on iOS
*/
RN_EXPORT static bool enableModuleArgumentNSNullConversionIOS();
/**
* Parse CSS strings using the Fabric CSS parser instead of ViewConfig processing
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ec175b9b320e8bf9b0811ba404cd6e5d>>
* @generated SignedSource<<955524ea199666cfdd38ab4b73efcd2a>>
*/
/**
@@ -461,6 +461,24 @@ bool ReactNativeFeatureFlagsAccessor::enableMainQueueModulesOnIOS() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::enableModuleArgumentNSNullConversionIOS() {
auto flagValue = enableModuleArgumentNSNullConversionIOS_.load();
if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(24, "enableModuleArgumentNSNullConversionIOS");
flagValue = currentProvider_->enableModuleArgumentNSNullConversionIOS();
enableModuleArgumentNSNullConversionIOS_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() {
auto flagValue = enableNativeCSSParsing_.load();
@@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(24, "enableNativeCSSParsing");
markFlagAsAccessed(25, "enableNativeCSSParsing");
flagValue = currentProvider_->enableNativeCSSParsing();
enableNativeCSSParsing_ = flagValue;
@@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNetworkEventReporting() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(25, "enableNetworkEventReporting");
markFlagAsAccessed(26, "enableNetworkEventReporting");
flagValue = currentProvider_->enableNetworkEventReporting();
enableNetworkEventReporting_ = flagValue;
@@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNewBackgroundAndBorderDrawables() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(26, "enableNewBackgroundAndBorderDrawables");
markFlagAsAccessed(27, "enableNewBackgroundAndBorderDrawables");
flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables();
enableNewBackgroundAndBorderDrawables_ = flagValue;
@@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreparedTextLayout() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(27, "enablePreparedTextLayout");
markFlagAsAccessed(28, "enablePreparedTextLayout");
flagValue = currentProvider_->enablePreparedTextLayout();
enablePreparedTextLayout_ = flagValue;
@@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(28, "enablePropsUpdateReconciliationAndroid");
markFlagAsAccessed(29, "enablePropsUpdateReconciliationAndroid");
flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid();
enablePropsUpdateReconciliationAndroid_ = flagValue;
@@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::enableResourceTimingAPI() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(29, "enableResourceTimingAPI");
markFlagAsAccessed(30, "enableResourceTimingAPI");
flagValue = currentProvider_->enableResourceTimingAPI();
enableResourceTimingAPI_ = flagValue;
@@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(30, "enableSynchronousStateUpdates");
markFlagAsAccessed(31, "enableSynchronousStateUpdates");
flagValue = currentProvider_->enableSynchronousStateUpdates();
enableSynchronousStateUpdates_ = flagValue;
@@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(31, "enableViewCulling");
markFlagAsAccessed(32, "enableViewCulling");
flagValue = currentProvider_->enableViewCulling();
enableViewCulling_ = flagValue;
@@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(32, "enableViewRecycling");
markFlagAsAccessed(33, "enableViewRecycling");
flagValue = currentProvider_->enableViewRecycling();
enableViewRecycling_ = flagValue;
@@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(33, "enableViewRecyclingForText");
markFlagAsAccessed(34, "enableViewRecyclingForText");
flagValue = currentProvider_->enableViewRecyclingForText();
enableViewRecyclingForText_ = flagValue;
@@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(34, "enableViewRecyclingForView");
markFlagAsAccessed(35, "enableViewRecyclingForView");
flagValue = currentProvider_->enableViewRecyclingForView();
enableViewRecyclingForView_ = flagValue;
@@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(35, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
markFlagAsAccessed(36, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact();
fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue;
@@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(36, "fuseboxEnabledRelease");
markFlagAsAccessed(37, "fuseboxEnabledRelease");
flagValue = currentProvider_->fuseboxEnabledRelease();
fuseboxEnabledRelease_ = flagValue;
@@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(37, "fuseboxNetworkInspectionEnabled");
markFlagAsAccessed(38, "fuseboxNetworkInspectionEnabled");
flagValue = currentProvider_->fuseboxNetworkInspectionEnabled();
fuseboxNetworkInspectionEnabled_ = flagValue;
@@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::incorporateMaxLinesDuringAndroidLayout() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(38, "incorporateMaxLinesDuringAndroidLayout");
markFlagAsAccessed(39, "incorporateMaxLinesDuringAndroidLayout");
flagValue = currentProvider_->incorporateMaxLinesDuringAndroidLayout();
incorporateMaxLinesDuringAndroidLayout_ = flagValue;
@@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(39, "traceTurboModulePromiseRejectionsOnAndroid");
markFlagAsAccessed(40, "traceTurboModulePromiseRejectionsOnAndroid");
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
@@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit(
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(40, "updateRuntimeShadowNodeReferencesOnCommit");
markFlagAsAccessed(41, "updateRuntimeShadowNodeReferencesOnCommit");
flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit();
updateRuntimeShadowNodeReferencesOnCommit_ = flagValue;
@@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(41, "useAlwaysAvailableJSErrorHandling");
markFlagAsAccessed(42, "useAlwaysAvailableJSErrorHandling");
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
useAlwaysAvailableJSErrorHandling_ = flagValue;
@@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useAndroidTextLayoutWidthDirectly() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(42, "useAndroidTextLayoutWidthDirectly");
markFlagAsAccessed(43, "useAndroidTextLayoutWidthDirectly");
flagValue = currentProvider_->useAndroidTextLayoutWidthDirectly();
useAndroidTextLayoutWidthDirectly_ = flagValue;
@@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(43, "useFabricInterop");
markFlagAsAccessed(44, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(44, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(45, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(45, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(46, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(46, "useRawPropsJsiValue");
markFlagAsAccessed(47, "useRawPropsJsiValue");
flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
@@ -884,7 +902,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(47, "useShadowNodeStateOnClone");
markFlagAsAccessed(48, "useShadowNodeStateOnClone");
flagValue = currentProvider_->useShadowNodeStateOnClone();
useShadowNodeStateOnClone_ = flagValue;
@@ -902,7 +920,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(48, "useTurboModuleInterop");
markFlagAsAccessed(49, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -920,7 +938,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(49, "useTurboModules");
markFlagAsAccessed(50, "useTurboModules");
flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<e1c1ba4c68d532a7296fa4f91a48de3a>>
* @generated SignedSource<<a95696cc00506fd1cc1e147e45a3098e>>
*/
/**
@@ -56,6 +56,7 @@ class ReactNativeFeatureFlagsAccessor {
bool enableLayoutAnimationsOnAndroid();
bool enableLayoutAnimationsOnIOS();
bool enableMainQueueModulesOnIOS();
bool enableModuleArgumentNSNullConversionIOS();
bool enableNativeCSSParsing();
bool enableNetworkEventReporting();
bool enableNewBackgroundAndBorderDrawables();
@@ -93,7 +94,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 50> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 51> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> animatedShouldSignalBatch_;
@@ -119,6 +120,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> enableLayoutAnimationsOnAndroid_;
std::atomic<std::optional<bool>> enableLayoutAnimationsOnIOS_;
std::atomic<std::optional<bool>> enableMainQueueModulesOnIOS_;
std::atomic<std::optional<bool>> enableModuleArgumentNSNullConversionIOS_;
std::atomic<std::optional<bool>> enableNativeCSSParsing_;
std::atomic<std::optional<bool>> enableNetworkEventReporting_;
std::atomic<std::optional<bool>> enableNewBackgroundAndBorderDrawables_;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<4c463bb7d1aa97478abe0e74955aa854>>
* @generated SignedSource<<c80be05a320b2cb0e78865492f503922>>
*/
/**
@@ -123,6 +123,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool enableModuleArgumentNSNullConversionIOS() override {
return true;
}
bool enableNativeCSSParsing() override {
return false;
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f0c9d2d7027f9408bb7f784adcccbd51>>
* @generated SignedSource<<75a1b352cffa84394393992484dcb33c>>
*/
/**
@@ -261,6 +261,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::enableMainQueueModulesOnIOS();
}
bool enableModuleArgumentNSNullConversionIOS() override {
auto value = values_["enableModuleArgumentNSNullConversionIOS"];
if (!value.isNull()) {
return value.getBool();
}
return ReactNativeFeatureFlagsDefaults::enableModuleArgumentNSNullConversionIOS();
}
bool enableNativeCSSParsing() override {
auto value = values_["enableNativeCSSParsing"];
if (!value.isNull()) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<53bd41086143a19f52e1e96025b24c76>>
* @generated SignedSource<<57a8881e00c4208f97c4eccac202a3bb>>
*/
/**
@@ -49,6 +49,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool enableLayoutAnimationsOnAndroid() = 0;
virtual bool enableLayoutAnimationsOnIOS() = 0;
virtual bool enableMainQueueModulesOnIOS() = 0;
virtual bool enableModuleArgumentNSNullConversionIOS() = 0;
virtual bool enableNativeCSSParsing() = 0;
virtual bool enableNetworkEventReporting() = 0;
virtual bool enableNewBackgroundAndBorderDrawables() = 0;
@@ -9,14 +9,21 @@
#import <ReactCommon/RCTTurboModule.h>
#import <hermes/hermes.h>
#import <react/featureflags/ReactNativeFeatureFlags.h>
#import <OCMock/OCMock.h>
using namespace facebook::react;
@protocol RCTTestTurboModule <RCTBridgeModule, RCTTurboModule>
@interface RCTTestTurboModule : NSObject <RCTBridgeModule>
- (void)testMethodWhichTakesObject:(id)object;
@end
@implementation RCTTestTurboModule
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(testMethodWhichTakesObject : (id)object) {}
@end
@@ -37,13 +44,13 @@ class StubNativeMethodCallInvoker : public NativeMethodCallInvoker {
@implementation RCTTurboModuleTests {
std::unique_ptr<ObjCTurboModule> module_;
id<RCTTestTurboModule> instance_;
RCTTestTurboModule *instance_;
}
- (void)setUp
{
[super setUp];
instance_ = OCMProtocolMock(@protocol(RCTTestTurboModule));
instance_ = OCMClassMock([RCTTestTurboModule class]);
ObjCTurboModule::InitParams params = {
.moduleName = "TestModule",
@@ -82,11 +89,14 @@ class StubNativeMethodCallInvoker : public NativeMethodCallInvoker {
OCMVerify(OCMTimes(1), [instance_ testMethodWhichTakesObject:@{@"foo" : @"bar"}]);
// Object with key without value
args[0].asObject(*rt).setProperty(*rt, "foo", "facebook::jsi::Value::undefined()");
args[0].asObject(*rt).setProperty(*rt, "foo", facebook::jsi::Value::null());
module_->invokeObjCMethod(
*rt, VoidKind, "testMethodWhichTakesObject", @selector(testMethodWhichTakesObject:), args, 1);
// FIXME this should be called with @{@"foo": kCFNull}
OCMVerify(OCMTimes(1), [instance_ testMethodWhichTakesObject:@{}]);
if (ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS()) {
OCMVerify(OCMTimes(1), [instance_ testMethodWhichTakesObject:@{@"foo" : (id)kCFNull}]);
} else {
OCMVerify(OCMTimes(2), [instance_ testMethodWhichTakesObject:@{}]);
}
// Null
args[0] = facebook::jsi::Value::null();
@@ -18,6 +18,7 @@
#import <ReactCommon/TurboModulePerfLogger.h>
#import <cxxreact/TraceSection.h>
#import <react/bridging/Bridging.h>
#import <react/featureflags/ReactNativeFeatureFlags.h>
#include <glog/logging.h>
@@ -622,7 +623,9 @@ void ObjCTurboModule::setInvocationArg(
/**
* Convert arg to ObjC objects.
*/
id objCArg = convertJSIValueToObjCObject(runtime, arg, jsInvoker_);
BOOL enableModuleArgumentNSNullConversionIOS = ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS();
id objCArg = TurboModuleConvertUtils::convertJSIValueToObjCObject(
runtime, arg, jsInvoker_, enableModuleArgumentNSNullConversionIOS);
if (objCArg) {
NSString *methodNameNSString = @(methodName);
@@ -640,6 +643,10 @@ void ObjCTurboModule::setInvocationArg(
id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend;
id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg);
if (enableModuleArgumentNSNullConversionIOS && convertedObjCArg == [NSNull null]) {
return;
}
[inv setArgument:(void *)&convertedObjCArg atIndex:i + 2];
if (convertedObjCArg) {
[retainedObjectsForInvocation addObject:convertedObjCArg];
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<74f011324e9d4647fa757f29b602c6c3>>
* @generated SignedSource<<167e35bd99451cbe24a2bb54db5c66b9>>
*/
/**
@@ -164,6 +164,11 @@ bool NativeReactNativeFeatureFlags::enableMainQueueModulesOnIOS(
return ReactNativeFeatureFlags::enableMainQueueModulesOnIOS();
}
bool NativeReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::enableModuleArgumentNSNullConversionIOS();
}
bool NativeReactNativeFeatureFlags::enableNativeCSSParsing(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::enableNativeCSSParsing();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<2b33a7fe9086343c427f06cc62c67a62>>
* @generated SignedSource<<196bc6e1f0196c39029c3d2a45d3254b>>
*/
/**
@@ -85,6 +85,8 @@ class NativeReactNativeFeatureFlags
bool enableMainQueueModulesOnIOS(jsi::Runtime& runtime);
bool enableModuleArgumentNSNullConversionIOS(jsi::Runtime& runtime);
bool enableNativeCSSParsing(jsi::Runtime& runtime);
bool enableNetworkEventReporting(jsi::Runtime& runtime);
@@ -299,6 +299,16 @@ const definitions: FeatureFlagDefinitions = {
},
ossReleaseStage: 'none',
},
enableModuleArgumentNSNullConversionIOS: {
defaultValue: true,
metadata: {
description:
'Enable NSNull conversion when handling module arguments on iOS',
expectedReleaseValue: true,
purpose: 'release',
},
ossReleaseStage: 'none',
},
enableNativeCSSParsing: {
defaultValue: false,
metadata: {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<e640d7299f0b0624f9dce91e7a39604c>>
* @generated SignedSource<<cbcc6da9a0d0652dddd99977690a258a>>
* @flow strict
* @noformat
*/
@@ -74,6 +74,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{
enableLayoutAnimationsOnAndroid: Getter<boolean>,
enableLayoutAnimationsOnIOS: Getter<boolean>,
enableMainQueueModulesOnIOS: Getter<boolean>,
enableModuleArgumentNSNullConversionIOS: Getter<boolean>,
enableNativeCSSParsing: Getter<boolean>,
enableNetworkEventReporting: Getter<boolean>,
enableNewBackgroundAndBorderDrawables: Getter<boolean>,
@@ -277,6 +278,10 @@ export const enableLayoutAnimationsOnIOS: Getter<boolean> = createNativeFlagGett
* Makes modules requiring main queue setup initialize on the main thread, during React Native init.
*/
export const enableMainQueueModulesOnIOS: Getter<boolean> = createNativeFlagGetter('enableMainQueueModulesOnIOS', false);
/**
* Enable NSNull conversion when handling module arguments on iOS
*/
export const enableModuleArgumentNSNullConversionIOS: Getter<boolean> = createNativeFlagGetter('enableModuleArgumentNSNullConversionIOS', true);
/**
* Parse CSS strings using the Fabric CSS parser instead of ViewConfig processing
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<620ba7ace3df80067aa6ba1ed44aec60>>
* @generated SignedSource<<b12383e2b1e15b8a062efd33eb52070f>>
* @flow strict
* @noformat
*/
@@ -49,6 +49,7 @@ export interface Spec extends TurboModule {
+enableLayoutAnimationsOnAndroid?: () => boolean;
+enableLayoutAnimationsOnIOS?: () => boolean;
+enableMainQueueModulesOnIOS?: () => boolean;
+enableModuleArgumentNSNullConversionIOS?: () => boolean;
+enableNativeCSSParsing?: () => boolean;
+enableNetworkEventReporting?: () => boolean;
+enableNewBackgroundAndBorderDrawables?: () => boolean;