Compare commits

..
Author SHA1 Message Date
Rob HoganandFacebook GitHub Bot 6e128d707d Fix Android JSC compatibility - replaceAll -> replace
Summary:
JSC for Android does not implement `String.prototype.replaceAll`:

 {F1971791988} 

https://github.com/facebook/react-native/pull/47466 introduced a use of it into runtime code, breaking JSC compatibility.

This.. replaces it.. with `replace`. Since the argument is already a regex with a `g` modifier, `replaceAll` wasn't necessary anyway.

Changelog:
[ANDROID][FIXED] Fix JSC by avoiding use of unavailable `str.replaceAll()`

Differential Revision: D66712312
2024-12-03 10:56:32 -08:00
Pieter De BaetsandFacebook GitHub Bot 9800c8e47e Improve differentiator logging (#48061)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48061

Improve consistency of debug logs in differentiator.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D66654292

fbshipit-source-id: f4accdea184b932f94359c893e6de59f8139ca22
2024-12-03 10:17:02 -08:00
Pieter De BaetsandFacebook GitHub Bot 34901d4861 Fix differentiator emitting updates with incorrect parentTag (#48055)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48055

Address the test-case identified in D66557919, where Differentiator could emit updates for views referencing an incorrect parentTag.

The longer-term fix here is to avoid emitting any updates for nodes which are being reparented, but that requires bigger changes, including to the LayoutAnimation system. As a short-term patch, we're passing through an explicit `parentShadowViewForUpdate` which will be used as the current parent for update purposes.

 {F1971278019}

Changelog: [Android][Fixed] Fix Fabric mutations sometimes triggering a `getViewState` crash when referencing an invalid parentTag.

Reviewed By: rubennorte

Differential Revision: D66654293

fbshipit-source-id: cd5b3e577ad1eede1b6dea834582ac6d750cbb81
2024-12-03 10:17:02 -08:00
Fabrizio CucciandFacebook GitHub Bot 21c9491926 Migrate package com.facebook.react.uimanager.RootView to Kotlin (#47701)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47701

As per title.

Changelog:
[Android][Breaking] Convert RootView to Kotlin

Reviewed By: cortinico

Differential Revision: D66159881

fbshipit-source-id: 082881a03946088293dde3c085e1d1882bac96be
2024-12-03 09:59:48 -08:00
Blake FriedmanandFacebook GitHub Bot 9df20d414e Log out which workflow artifact we're using (#48046)
Summary:
Make it clearer to the release crew to avoid using an outdated artifact
for testing a release.

{F1971030533}

Changelog: [Internal]

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

Test Plan:
```
yarn test-e2e-local -t "RNTester" -p "Android" -h true -c $GITHUB_TOKEN
```

Reviewed By: robhogan

Differential Revision: D66657082

Pulled By: blakef

fbshipit-source-id: 225128690c180bee7a3d28fdcc7f8c9885a37f0d
2024-12-03 09:34:48 -08:00
Alex HuntandFacebook GitHub Bot d6f286a4a0 Add description to React-jsinspector.podspec, refactoring (#48066)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48066

Minor edits to this build spec to align with other packages in `ReactCommon/`.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D66700351

fbshipit-source-id: 47942c27d6154b78c165508447a3056f1354f5c3
2024-12-03 08:44:48 -08:00
29 changed files with 359 additions and 160 deletions
+1 -1
View File
@@ -559,7 +559,7 @@ if (global.nativeLoggingHook) {
let originalConsoleError = console.error;
console.reportErrorsAsExceptions = true;
function stringifySafe(arg) {
return inspect(arg, {depth: 10}).replaceAll(/\n\s*/g, ' ');
return inspect(arg, {depth: 10}).replace(/\n\s*/g, ' ');
}
console.error = function (...args) {
originalConsoleError.apply(this, args);
@@ -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<<6d8d8f4b81d7be882b315d0960499dcb>>
* @generated SignedSource<<4a219bb47b1b9d988a164bca19eb4fa9>>
*/
/**
@@ -202,6 +202,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun excludeYogaFromRawProps(): Boolean = accessor.excludeYogaFromRawProps()
/**
* Fixes a bug in Differentiator where parent views may be referenced before they're created
*/
@JvmStatic
public fun fixDifferentiatorEmittingUpdatesWithWrongParentTag(): Boolean = accessor.fixDifferentiatorEmittingUpdatesWithWrongParentTag()
/**
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
*/
@@ -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<<031fce8e8b4c20a3e3d6dbecf94d138a>>
* @generated SignedSource<<d75efd6beee8dd9d38b5d648fbecbcda>>
*/
/**
@@ -49,6 +49,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var enableUIConsistencyCache: Boolean? = null
private var enableViewRecyclingCache: Boolean? = null
private var excludeYogaFromRawPropsCache: Boolean? = null
private var fixDifferentiatorEmittingUpdatesWithWrongParentTagCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fixMountingCoordinatorReportedPendingTransactionsOnAndroidCache: Boolean? = null
private var fuseboxEnabledDebugCache: Boolean? = null
@@ -328,6 +329,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}
override fun fixDifferentiatorEmittingUpdatesWithWrongParentTag(): Boolean {
var cached = fixDifferentiatorEmittingUpdatesWithWrongParentTagCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.fixDifferentiatorEmittingUpdatesWithWrongParentTag()
fixDifferentiatorEmittingUpdatesWithWrongParentTagCache = cached
}
return cached
}
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
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<<35811667ac2543e1f64e27bbdb483ec1>>
* @generated SignedSource<<7454ab19a01cfbb0a54f14bd83fc3a90>>
*/
/**
@@ -86,6 +86,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun excludeYogaFromRawProps(): Boolean
@DoNotStrip @JvmStatic public external fun fixDifferentiatorEmittingUpdatesWithWrongParentTag(): Boolean
@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
@DoNotStrip @JvmStatic public external fun fixMountingCoordinatorReportedPendingTransactionsOnAndroid(): 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<<9d829c58e49164a0b2b6b66bc0ce088a>>
* @generated SignedSource<<70d951b2956759280afae4af8f9a2869>>
*/
/**
@@ -81,6 +81,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun excludeYogaFromRawProps(): Boolean = false
override fun fixDifferentiatorEmittingUpdatesWithWrongParentTag(): Boolean = true
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
override fun fixMountingCoordinatorReportedPendingTransactionsOnAndroid(): 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<<0121e113410a5b0e14eaf74a3076df2f>>
* @generated SignedSource<<f60000cb58a9632c3aa193854be3de4e>>
*/
/**
@@ -53,6 +53,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var enableUIConsistencyCache: Boolean? = null
private var enableViewRecyclingCache: Boolean? = null
private var excludeYogaFromRawPropsCache: Boolean? = null
private var fixDifferentiatorEmittingUpdatesWithWrongParentTagCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fixMountingCoordinatorReportedPendingTransactionsOnAndroidCache: Boolean? = null
private var fuseboxEnabledDebugCache: Boolean? = null
@@ -361,6 +362,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun fixDifferentiatorEmittingUpdatesWithWrongParentTag(): Boolean {
var cached = fixDifferentiatorEmittingUpdatesWithWrongParentTagCache
if (cached == null) {
cached = currentProvider.fixDifferentiatorEmittingUpdatesWithWrongParentTag()
accessedFeatureFlags.add("fixDifferentiatorEmittingUpdatesWithWrongParentTag")
fixDifferentiatorEmittingUpdatesWithWrongParentTagCache = cached
}
return cached
}
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
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<<2787d9027695dd14ec6b917a32a1a6de>>
* @generated SignedSource<<d62af893c5d18a2152f098ff305ae41e>>
*/
/**
@@ -81,6 +81,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun excludeYogaFromRawProps(): Boolean
@DoNotStrip public fun fixDifferentiatorEmittingUpdatesWithWrongParentTag(): Boolean
@DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
@DoNotStrip public fun fixMountingCoordinatorReportedPendingTransactionsOnAndroid(): Boolean
@@ -5,10 +5,10 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.uimanager;
package com.facebook.react.uimanager
import android.view.MotionEvent;
import android.view.View;
import android.view.MotionEvent
import android.view.View
/** Interface for the root native view of a React native application. */
public interface RootView {
@@ -17,21 +17,20 @@ public interface RootView {
* Called when a child starts a native gesture (e.g. a scroll in a ScrollView). Should be called
* from the child's onTouchIntercepted implementation.
*/
void onChildStartedNativeGesture(View childView, MotionEvent ev);
public fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent)
/**
* @deprecated
*/
@Deprecated
default void onChildStartedNativeGesture(MotionEvent ev) {
onChildStartedNativeGesture(null, ev);
@Deprecated(
message = "Use onChildStartedNativeGesture with a childView parameter.",
replaceWith = ReplaceWith("onChildStartedNativeGesture"))
public fun onChildStartedNativeGesture(ev: MotionEvent) {
onChildStartedNativeGesture(null, ev)
}
/**
* Called when a child ends a native gesture. Should be called from the child's onTouchIntercepted
* implementation.
*/
void onChildEndedNativeGesture(View childView, MotionEvent ev);
public fun onChildEndedNativeGesture(childView: View, ev: MotionEvent)
void handleException(Throwable t);
public fun handleException(t: Throwable)
}
@@ -495,7 +495,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
return super.onHoverEvent(event)
}
override fun onChildStartedNativeGesture(childView: View, ev: MotionEvent) {
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
eventDispatcher?.let { eventDispatcher ->
jSTouchDispatcher.onChildStartedNativeGesture(ev, eventDispatcher)
jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
@@ -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<<902b269e45fcb4970c6f8a86818e1940>>
* @generated SignedSource<<640630d7a40b53f7d507569aa6409f69>>
*/
/**
@@ -213,6 +213,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}
bool fixDifferentiatorEmittingUpdatesWithWrongParentTag() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fixDifferentiatorEmittingUpdatesWithWrongParentTag");
return method(javaProvider_);
}
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fixMappingOfEventPrioritiesBetweenFabricAndReact");
@@ -464,6 +470,11 @@ bool JReactNativeFeatureFlagsCxxInterop::excludeYogaFromRawProps(
return ReactNativeFeatureFlags::excludeYogaFromRawProps();
}
bool JReactNativeFeatureFlagsCxxInterop::fixDifferentiatorEmittingUpdatesWithWrongParentTag(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::fixDifferentiatorEmittingUpdatesWithWrongParentTag();
}
bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
@@ -667,6 +678,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"excludeYogaFromRawProps",
JReactNativeFeatureFlagsCxxInterop::excludeYogaFromRawProps),
makeNativeMethod(
"fixDifferentiatorEmittingUpdatesWithWrongParentTag",
JReactNativeFeatureFlagsCxxInterop::fixDifferentiatorEmittingUpdatesWithWrongParentTag),
makeNativeMethod(
"fixMappingOfEventPrioritiesBetweenFabricAndReact",
JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact),
@@ -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<<17da0d7937c5c0c533293b86c8cdc9be>>
* @generated SignedSource<<4218168e779a2241d0752771c1f51b12>>
*/
/**
@@ -117,6 +117,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool excludeYogaFromRawProps(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool fixDifferentiatorEmittingUpdatesWithWrongParentTag(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -20,31 +20,39 @@ folly_config = get_folly_config()
folly_compiler_flags = folly_config[:compiler_flags]
folly_version = folly_config[:version]
use_frameworks = ENV['USE_FRAMEWORKS'] != nil
header_search_paths = [
"\"$(PODS_TARGET_SRCROOT)/..\"",
"\"$(PODS_ROOT)/boost\"",
"\"$(PODS_ROOT)/DoubleConversion\"",
"\"$(PODS_ROOT)/fast_float/include\"",
"\"$(PODS_ROOT)/fmt/include\"",
"\"$(PODS_ROOT)/RCT-Folly\"",
]
header_dir = 'jsinspector-modern'
module_name = "jsinspector_modern"
Pod::Spec.new do |s|
s.name = "React-jsinspector"
s.version = version
s.summary = "-" # TODO
s.summary = "React Native subsystem for modern debugging over the Chrome DevTools Protocol (CDP)"
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = "*.{cpp,h,def}"
s.header_dir = 'jsinspector-modern'
s.header_dir = header_dir
s.compiler_flags = folly_compiler_flags
s.pod_target_xcconfig = {
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/..\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fast_float/include\" \"$(PODS_ROOT)/fmt/include\"",
"HEADER_SEARCH_PATHS" => header_search_paths.join(' '),
"CLANG_CXX_LANGUAGE_STANDARD" => rct_cxx_language_standard(),
"DEFINES_MODULE" => "YES"
}.merge!(use_frameworks ? {
}.merge!(ENV['USE_FRAMEWORKS'] ? {
"PUBLIC_HEADERS_FOLDER_PATH" => "#{module_name}.framework/Headers/#{header_dir}"
} : {})
if use_frameworks
if ENV['USE_FRAMEWORKS']
s.module_name = module_name
end
@@ -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<<ef215623465d45c563030d724287b1c9>>
* @generated SignedSource<<2409869111055ff0b32c1f40c10042d7>>
*/
/**
@@ -142,6 +142,10 @@ bool ReactNativeFeatureFlags::excludeYogaFromRawProps() {
return getAccessor().excludeYogaFromRawProps();
}
bool ReactNativeFeatureFlags::fixDifferentiatorEmittingUpdatesWithWrongParentTag() {
return getAccessor().fixDifferentiatorEmittingUpdatesWithWrongParentTag();
}
bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact() {
return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact();
}
@@ -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<<f741660e4cf2528defe0ab1f61858aab>>
* @generated SignedSource<<e628af8109a1d8bb6425515d824852a3>>
*/
/**
@@ -184,6 +184,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool excludeYogaFromRawProps();
/**
* Fixes a bug in Differentiator where parent views may be referenced before they're created
*/
RN_EXPORT static bool fixDifferentiatorEmittingUpdatesWithWrongParentTag();
/**
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
*/
@@ -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<<4c3956150bbf826c2abf4f8daf569b88>>
* @generated SignedSource<<1e5b87b564e880cfb1423a85692092ba>>
*/
/**
@@ -551,6 +551,24 @@ bool ReactNativeFeatureFlagsAccessor::excludeYogaFromRawProps() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::fixDifferentiatorEmittingUpdatesWithWrongParentTag() {
auto flagValue = fixDifferentiatorEmittingUpdatesWithWrongParentTag_.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(29, "fixDifferentiatorEmittingUpdatesWithWrongParentTag");
flagValue = currentProvider_->fixDifferentiatorEmittingUpdatesWithWrongParentTag();
fixDifferentiatorEmittingUpdatesWithWrongParentTag_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAndReact() {
auto flagValue = fixMappingOfEventPrioritiesBetweenFabricAndReact_.load();
@@ -560,7 +578,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(29, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
markFlagAsAccessed(30, "fixMappingOfEventPrioritiesBetweenFabricAndReact");
flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact();
fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue;
@@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMountingCoordinatorReportedPendingTrans
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(30, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid");
markFlagAsAccessed(31, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid");
flagValue = currentProvider_->fixMountingCoordinatorReportedPendingTransactionsOnAndroid();
fixMountingCoordinatorReportedPendingTransactionsOnAndroid_ = flagValue;
@@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledDebug() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(31, "fuseboxEnabledDebug");
markFlagAsAccessed(32, "fuseboxEnabledDebug");
flagValue = currentProvider_->fuseboxEnabledDebug();
fuseboxEnabledDebug_ = flagValue;
@@ -614,7 +632,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(32, "fuseboxEnabledRelease");
markFlagAsAccessed(33, "fuseboxEnabledRelease");
flagValue = currentProvider_->fuseboxEnabledRelease();
fuseboxEnabledRelease_ = flagValue;
@@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::initEagerTurboModulesOnNativeModulesQueueA
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(33, "initEagerTurboModulesOnNativeModulesQueueAndroid");
markFlagAsAccessed(34, "initEagerTurboModulesOnNativeModulesQueueAndroid");
flagValue = currentProvider_->initEagerTurboModulesOnNativeModulesQueueAndroid();
initEagerTurboModulesOnNativeModulesQueueAndroid_ = flagValue;
@@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::lazyAnimationCallbacks() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(34, "lazyAnimationCallbacks");
markFlagAsAccessed(35, "lazyAnimationCallbacks");
flagValue = currentProvider_->lazyAnimationCallbacks();
lazyAnimationCallbacks_ = flagValue;
@@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::loadVectorDrawablesOnImages() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(35, "loadVectorDrawablesOnImages");
markFlagAsAccessed(36, "loadVectorDrawablesOnImages");
flagValue = currentProvider_->loadVectorDrawablesOnImages();
loadVectorDrawablesOnImages_ = flagValue;
@@ -686,7 +704,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(36, "traceTurboModulePromiseRejectionsOnAndroid");
markFlagAsAccessed(37, "traceTurboModulePromiseRejectionsOnAndroid");
flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid();
traceTurboModulePromiseRejectionsOnAndroid_ = flagValue;
@@ -704,7 +722,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(37, "useAlwaysAvailableJSErrorHandling");
markFlagAsAccessed(38, "useAlwaysAvailableJSErrorHandling");
flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling();
useAlwaysAvailableJSErrorHandling_ = flagValue;
@@ -722,7 +740,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(38, "useFabricInterop");
markFlagAsAccessed(39, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless()
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(39, "useImmediateExecutorInAndroidBridgeless");
markFlagAsAccessed(40, "useImmediateExecutorInAndroidBridgeless");
flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless();
useImmediateExecutorInAndroidBridgeless_ = flagValue;
@@ -758,7 +776,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(40, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(41, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimisedViewPreallocationOnAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(41, "useOptimisedViewPreallocationOnAndroid");
markFlagAsAccessed(42, "useOptimisedViewPreallocationOnAndroid");
flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid();
useOptimisedViewPreallocationOnAndroid_ = flagValue;
@@ -794,7 +812,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(42, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(43, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(43, "useRuntimeShadowNodeReferenceUpdate");
markFlagAsAccessed(44, "useRuntimeShadowNodeReferenceUpdate");
flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate();
useRuntimeShadowNodeReferenceUpdate_ = flagValue;
@@ -830,7 +848,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(44, "useTurboModuleInterop");
markFlagAsAccessed(45, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -848,7 +866,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(45, "useTurboModules");
markFlagAsAccessed(46, "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<<3d98085a73dfc51541342dbb42ed89ab>>
* @generated SignedSource<<eb44aabe7e352481267aa9a6bf035ff1>>
*/
/**
@@ -61,6 +61,7 @@ class ReactNativeFeatureFlagsAccessor {
bool enableUIConsistency();
bool enableViewRecycling();
bool excludeYogaFromRawProps();
bool fixDifferentiatorEmittingUpdatesWithWrongParentTag();
bool fixMappingOfEventPrioritiesBetweenFabricAndReact();
bool fixMountingCoordinatorReportedPendingTransactionsOnAndroid();
bool fuseboxEnabledDebug();
@@ -89,7 +90,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 46> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 47> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> completeReactInstanceCreationOnBgThreadOnAndroid_;
@@ -120,6 +121,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> enableUIConsistency_;
std::atomic<std::optional<bool>> enableViewRecycling_;
std::atomic<std::optional<bool>> excludeYogaFromRawProps_;
std::atomic<std::optional<bool>> fixDifferentiatorEmittingUpdatesWithWrongParentTag_;
std::atomic<std::optional<bool>> fixMappingOfEventPrioritiesBetweenFabricAndReact_;
std::atomic<std::optional<bool>> fixMountingCoordinatorReportedPendingTransactionsOnAndroid_;
std::atomic<std::optional<bool>> fuseboxEnabledDebug_;
@@ -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<<aff3c46b8d2db3bde519e1392569d53d>>
* @generated SignedSource<<ee899be30798eb6d386b44bc6bc027ea>>
*/
/**
@@ -143,6 +143,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool fixDifferentiatorEmittingUpdatesWithWrongParentTag() override {
return true;
}
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() 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<<8f8c7a372cdf9a3c06bc0d71f1ed85ad>>
* @generated SignedSource<<e5d1c60102f7444332bd34627c02eddd>>
*/
/**
@@ -54,6 +54,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool enableUIConsistency() = 0;
virtual bool enableViewRecycling() = 0;
virtual bool excludeYogaFromRawProps() = 0;
virtual bool fixDifferentiatorEmittingUpdatesWithWrongParentTag() = 0;
virtual bool fixMappingOfEventPrioritiesBetweenFabricAndReact() = 0;
virtual bool fixMountingCoordinatorReportedPendingTransactionsOnAndroid() = 0;
virtual bool fuseboxEnabledDebug() = 0;
@@ -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<<4808c1455f8e17c42036055dd6a81d7d>>
* @generated SignedSource<<4055a9b5e34ff6740a99d4e08853fe7d>>
*/
/**
@@ -189,6 +189,11 @@ bool NativeReactNativeFeatureFlags::excludeYogaFromRawProps(
return ReactNativeFeatureFlags::excludeYogaFromRawProps();
}
bool NativeReactNativeFeatureFlags::fixDifferentiatorEmittingUpdatesWithWrongParentTag(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::fixDifferentiatorEmittingUpdatesWithWrongParentTag();
}
bool NativeReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
@@ -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<<6b4909879b76908792d89e3f24c1453a>>
* @generated SignedSource<<9541abe6da92d991557ca6d2f1e36a9a>>
*/
/**
@@ -95,6 +95,8 @@ class NativeReactNativeFeatureFlags
bool excludeYogaFromRawProps(jsi::Runtime& runtime);
bool fixDifferentiatorEmittingUpdatesWithWrongParentTag(jsi::Runtime& runtime);
bool fixMappingOfEventPrioritiesBetweenFabricAndReact(jsi::Runtime& runtime);
bool fixMountingCoordinatorReportedPendingTransactionsOnAndroid(jsi::Runtime& runtime);
@@ -13,7 +13,7 @@
#include <react/debug/flags.h>
#include <react/debug/react_native_assert.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/animations/conversions.h>
#include <react/renderer/animations/utils.h>
#include <react/renderer/components/image/ImageProps.h>
@@ -392,6 +392,14 @@ LayoutAnimationKeyFrameManager::pullTransaction(
if (keyframe.type == AnimationConfigurationType::Update &&
mutation.newChildShadowView.tag > 0) {
keyframe.viewPrev = mutation.newChildShadowView;
if (ReactNativeFeatureFlags::
fixDifferentiatorEmittingUpdatesWithWrongParentTag()) {
keyframe.parentView = mutation.parentShadowView;
react_native_assert(
keyframe.finalMutationsForKeyFrame.size() == 1);
keyframe.finalMutationsForKeyFrame[0].parentShadowView =
mutation.parentShadowView;
}
}
}
}
@@ -50,6 +50,33 @@ bool ShadowViewNodePair::operator!=(const ShadowViewNodePair& rhs) const {
return !(*this == rhs);
}
#ifdef DEBUG_LOGS_DIFFER
static std::ostream& operator<<(
std::ostream& out,
const ShadowViewNodePair& pair) {
out << pair.shadowNode->getTag();
if (!pair.isConcreteView) {
out << '\'';
}
if (pair.flattened) {
out << '*';
}
return out;
}
static std::ostream& operator<<(
std::ostream& out,
std::vector<ShadowViewNodePair*> vec) {
for (int i = 0; i < vec.size(); i++) {
if (i > 0) {
out << ", ";
}
out << *vec[i];
}
return out;
}
#endif
/*
* Extremely simple and naive implementation of a map.
* The map is simple but it's optimized for particular constraints that we have
@@ -182,6 +209,21 @@ class TinyMap final {
size_t erasedAtFront_{0};
};
#ifdef DEBUG_LOGS_DIFFER
template <typename KeyT, typename ValueT>
static std::ostream& operator<<(std::ostream& out, TinyMap<KeyT, ValueT>& map) {
auto it = map.begin();
if (it != map.end()) {
out << *it->second;
++it;
}
for (; it != map.end(); ++it) {
out << ", " << *it->second;
}
return out;
}
#endif
/*
* Sorting comparator for `reorderInPlaceIfNeeded`.
*/
@@ -403,6 +445,7 @@ static void calculateShadowViewMutationsFlattener(
const ShadowView& parentShadowView,
TinyMap<Tag, ShadowViewNodePair*>& unvisitedOtherNodes,
const ShadowViewNodePair& node,
const ShadowView& parentShadowViewForUpdate,
TinyMap<Tag, ShadowViewNodePair*>* parentSubVisitedOtherNewNodes = nullptr,
TinyMap<Tag, ShadowViewNodePair*>* parentSubVisitedOtherOldNodes = nullptr);
@@ -431,11 +474,10 @@ static void updateMatchedPairSubtrees(
// We are either flattening or unflattening this node.
if (oldPair.flattened != newPair.flattened) {
DEBUG_LOGS({
LOG(ERROR)
<< "Differ: flattening or unflattening in updateMatchedPairSubtrees: ["
<< oldPair.shadowView.tag << "] [" << newPair.shadowView.tag << "] "
<< oldPair.flattened << " " << newPair.flattened << " with parent: ["
<< parentShadowView.tag << "]";
LOG(ERROR) << "Differ: "
<< (newPair.flattened ? "flattening" : "unflattening")
<< " in updateMatchedPairSubtrees: " << oldPair << " and "
<< newPair << " with parent [" << parentShadowView.tag << "]";
});
// Flattening
@@ -450,7 +492,8 @@ static void updateMatchedPairSubtrees(
mutationContainer,
parentShadowView,
newRemainingPairs,
oldPair);
oldPair,
oldPair.shadowView);
}
// Unflattening
else {
@@ -480,7 +523,8 @@ static void updateMatchedPairSubtrees(
mutationContainer,
parentShadowView,
unvisitedOldChildPairs,
newPair);
newPair,
parentShadowView);
// If old nodes were not visited, we know that we can delete
// them now. They will be removed from the hierarchy by the
@@ -621,6 +665,10 @@ static void updateMatchedPair(
* performed in the subtree. If it *is* in the map, it means the node is not
* in the Tree, and should be Deleted/Created **after this function is
* called**, by the caller.
*
* @param parentShadowView shadowView under which nodes should be mounted
* @param parentShadowViewForUpdate current parent in which node is mounted,
* used for update mutations
*/
static void calculateShadowViewMutationsFlattener(
ViewNodePairScope& scope,
@@ -629,44 +677,20 @@ static void calculateShadowViewMutationsFlattener(
const ShadowView& parentShadowView,
TinyMap<Tag, ShadowViewNodePair*>& unvisitedOtherNodes,
const ShadowViewNodePair& node,
const ShadowView& parentShadowViewForUpdate,
TinyMap<Tag, ShadowViewNodePair*>* parentSubVisitedOtherNewNodes,
TinyMap<Tag, ShadowViewNodePair*>* parentSubVisitedOtherOldNodes) {
DEBUG_LOGS({
LOG(ERROR) << "Differ Flattener 1: "
<< (reparentMode == ReparentMode::Unflatten ? "Unflattening"
: "Flattening")
<< " [" << node.shadowView.tag << "]";
});
// Step 1: iterate through entire tree
std::vector<ShadowViewNodePair*> treeChildren =
sliceChildShadowNodeViewPairsFromViewNodePair(node, scope);
DEBUG_LOGS({
LOG(ERROR) << "Differ Flattener 1.4: "
LOG(ERROR) << "Differ Flattener: "
<< (reparentMode == ReparentMode::Unflatten ? "Unflattening"
: "Flattening")
<< " [" << node.shadowView.tag << "]";
LOG(ERROR) << "Differ Flattener Entry: Child Pairs: ";
std::string strTreeChildPairs;
for (size_t k = 0; k < treeChildren.size(); k++) {
strTreeChildPairs.append(std::to_string(treeChildren[k]->shadowView.tag));
strTreeChildPairs.append(treeChildren[k]->isConcreteView ? "" : "'");
strTreeChildPairs.append(treeChildren[k]->flattened ? "*" : "");
strTreeChildPairs.append(", ");
}
std::string strListChildPairs;
for (auto& unvisitedNode : unvisitedOtherNodes) {
strListChildPairs.append(
std::to_string(unvisitedNode.second->shadowView.tag));
strListChildPairs.append(unvisitedNode.second->isConcreteView ? "" : "'");
strListChildPairs.append(unvisitedNode.second->flattened ? "*" : "");
strListChildPairs.append(", ");
}
LOG(ERROR) << "Differ Flattener Entry: Tree Child Pairs: "
<< strTreeChildPairs;
LOG(ERROR) << "Differ Flattener Entry: List Child Pairs: "
<< strListChildPairs;
LOG(ERROR) << "> Tree Child Pairs: " << treeChildren;
LOG(ERROR) << "> List Child Pairs: " << unvisitedOtherNodes;
});
// Views in other tree that are visited by sub-flattening or
@@ -838,11 +862,18 @@ static void calculateShadowViewMutationsFlattener(
// ShadowNode.
if (newTreeNodePair.shadowView != oldTreeNodePair.shadowView &&
newTreeNodePair.isConcreteView && oldTreeNodePair.isConcreteView) {
// We execute updates before creates, so pass the current parent in when
// unflattening.
// TODO: whenever we insert, we already update the relevant properties,
// so this update is redundant. We should remove this.
mutationContainer.updateMutations.push_back(
ShadowViewMutation::UpdateMutation(
oldTreeNodePair.shadowView,
newTreeNodePair.shadowView,
node.shadowView));
ReactNativeFeatureFlags::
fixDifferentiatorEmittingUpdatesWithWrongParentTag()
? parentShadowViewForUpdate
: node.shadowView));
}
// Update children if appropriate.
@@ -877,6 +908,9 @@ static void calculateShadowViewMutationsFlattener(
: newTreeNodePair.shadowView),
unvisitedOtherNodes,
treeChildPair,
(reparentMode == ReparentMode::Flatten
? oldTreeNodePair.shadowView
: parentShadowView),
subVisitedNewMap,
subVisitedOldMap);
} else {
@@ -918,6 +952,9 @@ static void calculateShadowViewMutationsFlattener(
: newTreeNodePair.shadowView),
unvisitedRecursiveChildPairs,
oldTreeNodePair,
(reparentMode == ReparentMode::Flatten
? oldTreeNodePair.shadowView
: parentShadowView),
subVisitedNewMap,
subVisitedOldMap);
}
@@ -933,6 +970,9 @@ static void calculateShadowViewMutationsFlattener(
: newTreeNodePair.shadowView),
unvisitedRecursiveChildPairs,
newTreeNodePair,
(reparentMode == ReparentMode::Flatten
? oldTreeNodePair.shadowView
: parentShadowView),
subVisitedNewMap,
subVisitedOldMap);
@@ -1069,26 +1109,8 @@ static void calculateShadowViewMutations(
DEBUG_LOGS({
LOG(ERROR) << "Differ Entry: Child Pairs of node: [" << parentShadowView.tag
<< "]";
std::string strOldChildPairs;
for (size_t oldIndex = 0; oldIndex < oldChildPairs.size(); oldIndex++) {
strOldChildPairs.append(
std::to_string(oldChildPairs[oldIndex]->shadowView.tag));
strOldChildPairs.append(
oldChildPairs[oldIndex]->isConcreteView ? "" : "'");
strOldChildPairs.append(oldChildPairs[oldIndex]->flattened ? "*" : "");
strOldChildPairs.append(", ");
}
std::string strNewChildPairs;
for (size_t newIndex = 0; newIndex < newChildPairs.size(); newIndex++) {
strNewChildPairs.append(
std::to_string(newChildPairs[newIndex]->shadowView.tag));
strNewChildPairs.append(
newChildPairs[newIndex]->isConcreteView ? "" : "'");
strNewChildPairs.append(newChildPairs[newIndex]->flattened ? "*" : "");
strNewChildPairs.append(", ");
}
LOG(ERROR) << "Differ Entry: Old Child Pairs: " << strOldChildPairs;
LOG(ERROR) << "Differ Entry: New Child Pairs: " << strNewChildPairs;
LOG(ERROR) << "> Old Child Pairs: " << oldChildPairs;
LOG(ERROR) << "> New Child Pairs: " << newChildPairs;
});
// Stage 1: Collecting `Update` mutations
@@ -1117,14 +1139,9 @@ static void calculateShadowViewMutations(
}
DEBUG_LOGS({
LOG(ERROR) << "Differ Branch 1.2: Same tags, update and recurse: ["
<< oldChildPair.shadowView.tag << "]"
<< (oldChildPair.flattened ? " (flattened)" : "")
<< (oldChildPair.isConcreteView ? " (concrete)" : "") << "["
<< newChildPair.shadowView.tag << "]"
<< (newChildPair.flattened ? " (flattened)" : "")
<< (newChildPair.isConcreteView ? " (concrete)" : "")
<< " with parent: [" << parentShadowView.tag << "]";
LOG(ERROR) << "Differ Branch 1.2: Same tags, update and recurse: "
<< oldChildPair << " and " << newChildPair << " with parent: ["
<< parentShadowView.tag << "]";
});
if (newChildPair.isConcreteView &&
@@ -1165,9 +1182,8 @@ static void calculateShadowViewMutations(
const auto& oldChildPair = *oldChildPairs[index];
DEBUG_LOGS({
LOG(ERROR) << "Differ Branch 2: Deleting Tag/Tree: ["
<< oldChildPair.shadowView.tag << "]" << " with parent: ["
<< parentShadowView.tag << "]";
LOG(ERROR) << "Differ Branch 2: Deleting Tag/Tree: " << oldChildPair
<< " with parent: [" << parentShadowView.tag << "]";
});
if (!oldChildPair.isConcreteView) {
@@ -1200,9 +1216,8 @@ static void calculateShadowViewMutations(
const auto& newChildPair = *newChildPairs[index];
DEBUG_LOGS({
LOG(ERROR) << "Differ Branch 3: Creating Tag/Tree: ["
<< newChildPair.shadowView.tag << "]" << " with parent: ["
<< parentShadowView.tag << "]";
LOG(ERROR) << "Differ Branch 3: Creating Tag/Tree: " << newChildPair
<< " with parent: [" << parentShadowView.tag << "]";
});
if (!newChildPair.isConcreteView) {
@@ -1257,14 +1272,9 @@ static void calculateShadowViewMutations(
if (newTag == oldTag) {
DEBUG_LOGS({
LOG(ERROR) << "Differ Branch 5: Matched Tags at indices: "
<< oldIndex << " " << newIndex << ": ["
<< oldChildPair.shadowView.tag << "]"
<< (oldChildPair.flattened ? "(flattened)" : "")
<< (oldChildPair.isConcreteView ? "(concrete)" : "")
<< " [" << newChildPair.shadowView.tag << "]"
<< (newChildPair.flattened ? "(flattened)" : "")
<< (newChildPair.isConcreteView ? "(concrete)" : "")
LOG(ERROR) << "Differ Branch 4: Matched Tags at indices: "
<< oldIndex << " and " << newIndex << ": "
<< oldChildPair << " and " << newChildPair
<< " with parent: [" << parentShadowView.tag << "]";
});
@@ -1306,6 +1316,13 @@ static void calculateShadowViewMutations(
if (insertedIt != newInsertedPairs.end()) {
const auto& newChildPair = *insertedIt->second;
DEBUG_LOGS({
LOG(ERROR) << "Differ Branch 5: Founded reordered tags at indices: "
<< oldIndex << ": " << oldChildPair << " and "
<< newChildPair << " with parent: ["
<< parentShadowView.tag << "]";
});
updateMatchedPair(
mutationContainer,
true,
@@ -1345,13 +1362,10 @@ static void calculateShadowViewMutations(
DEBUG_LOGS({
LOG(ERROR)
<< "Differ Branch 9: Removing tag that was not reinserted: "
<< oldIndex << ": [" << oldChildPair.shadowView.tag << "]"
<< (oldChildPair.flattened ? " (flattened)" : "")
<< (oldChildPair.isConcreteView ? " (concrete)" : "")
<< " with parent: [" << parentShadowView.tag << "] "
<< "node is in other tree? "
<< (oldChildPair.inOtherTree() ? "yes" : "no");
<< "Differ Branch 6: Removing tag that was not re-inserted: "
<< oldChildPair << " with parent: [" << parentShadowView.tag
<< "], which is " << (oldChildPair.inOtherTree() ? "" : "not ")
<< "in other tree";
});
// Edge case: node is not found in `newRemainingPairs`, due to
@@ -1398,11 +1412,8 @@ static void calculateShadowViewMutations(
auto& newChildPair = *newChildPairs[newIndex];
DEBUG_LOGS({
LOG(ERROR)
<< "Differ Branch 10: Inserting tag/tree that was not (yet?) removed from hierarchy: "
<< newIndex << "/" << newSize << ": ["
<< newChildPair.shadowView.tag << "]"
<< (newChildPair.flattened ? " (flattened)" : "")
<< (newChildPair.isConcreteView ? " (concrete)" : "")
<< "Differ Branch 7: Inserting tag/tree that was not (yet?) removed from hierarchy: "
<< newChildPair << " @ " << newIndex << "/" << newSize
<< " with parent: [" << parentShadowView.tag << "]";
});
if (newChildPair.isConcreteView) {
@@ -1438,10 +1449,8 @@ static void calculateShadowViewMutations(
DEBUG_LOGS({
LOG(ERROR)
<< "Differ Branch 11: Deleting tag/tree that was not in new hierarchy: "
<< "[" << oldChildPair.shadowView.tag << "]"
<< (oldChildPair.flattened ? "(flattened)" : "")
<< (oldChildPair.isConcreteView ? "(concrete)" : "")
<< "Differ Branch 8: Deleting tag/tree that was not in new hierarchy: "
<< oldChildPair
<< (oldChildPair.inOtherTree() ? "(in other tree)" : "")
<< " with parent: [" << parentShadowView.tag << "] ##"
<< std::hash<ShadowView>{}(oldChildPair.shadowView);
@@ -1480,10 +1489,8 @@ static void calculateShadowViewMutations(
DEBUG_LOGS({
LOG(ERROR)
<< "Differ Branch 12: Inserting tag/tree that was not in old hierarchy: "
<< "[" << newChildPair.shadowView.tag << "]"
<< (newChildPair.flattened ? "(flattened)" : "")
<< (newChildPair.isConcreteView ? "(concrete)" : "")
<< "Differ Branch 9: Inserting tag/tree that was not in old hierarchy: "
<< newChildPair
<< (newChildPair.inOtherTree() ? "(in other tree)" : "")
<< " with parent: [" << parentShadowView.tag << "]";
});
@@ -1575,6 +1582,40 @@ ShadowViewMutation::List calculateShadowViewMutations(
ShadowViewNodePair{.shadowNode = &newRootShadowNode},
viewNodePairScope));
DEBUG_LOGS({
LOG(ERROR) << "Differ Completed: " << mutations.size() << " mutations";
for (size_t i = 0; i < mutations.size(); i++) {
auto& mutation = mutations[i];
switch (mutation.type) {
case ShadowViewMutation::Type::Create:
LOG(ERROR) << "[" << i << "] CREATE "
<< mutation.newChildShadowView.tag;
break;
case ShadowViewMutation::Type::Delete:
LOG(ERROR) << "[" << i << "] DELETE "
<< mutation.oldChildShadowView.tag;
break;
case ShadowViewMutation::Type::Insert:
LOG(ERROR) << "[" << i << "] INSERT "
<< mutation.newChildShadowView.tag << " INTO "
<< mutation.parentShadowView.tag << " @ "
<< mutation.index;
break;
case ShadowViewMutation::Type::Remove:
LOG(ERROR) << "[" << i << "] REMOVE "
<< mutation.oldChildShadowView.tag << " FROM "
<< mutation.parentShadowView.tag << " @ "
<< mutation.index;
break;
case ShadowViewMutation::Type::Update:
LOG(ERROR) << "[" << i << "] UPDATE "
<< mutation.newChildShadowView.tag << " IN "
<< mutation.parentShadowView.tag;
break;
}
}
});
return mutations;
}
@@ -221,6 +221,11 @@ void StubViewTree::mutate(const ShadowViewMutationList& mutations) {
react_native_assert(hasTag(mutation.newChildShadowView.tag));
auto oldStubView = registry_[mutation.newChildShadowView.tag];
react_native_assert(oldStubView->tag != 0);
if (mutation.parentShadowView.tag != 0) {
react_native_assert(hasTag(mutation.parentShadowView.tag));
react_native_assert(
oldStubView->parentTag == mutation.parentShadowView.tag);
}
if ((ShadowView)(*oldStubView) != mutation.oldChildShadowView) {
LOG(ERROR)
<< "StubView: ASSERT FAILURE: UPDATE mutation assertion failure: oldChildShadowView does not match oldStubView: ["
@@ -558,8 +558,7 @@ TEST(MountingTest, testViewReparentingInstructionGeneration) {
EXPECT_EQ(mutations1[0].oldChildShadowView.tag, childG->getTag());
EXPECT_EQ(mutations1[1].type, ShadowViewMutation::Update);
EXPECT_EQ(mutations1[1].oldChildShadowView.tag, reparentedViewA->getTag());
// This is incorrect! ChildH does not exist yet at this point
EXPECT_EQ(mutations1[1].parentShadowView.tag, childH->getTag());
EXPECT_EQ(mutations1[1].parentShadowView.tag, childG->getTag());
EXPECT_EQ(mutations1[2].type, ShadowViewMutation::Remove);
EXPECT_EQ(mutations1[2].oldChildShadowView.tag, reparentedViewA->getTag());
EXPECT_EQ(mutations1[3].type, ShadowViewMutation::Create);
@@ -292,6 +292,14 @@ const definitions: FeatureFlagDefinitions = {
purpose: 'experimentation',
},
},
fixDifferentiatorEmittingUpdatesWithWrongParentTag: {
defaultValue: true,
metadata: {
description:
"Fixes a bug in Differentiator where parent views may be referenced before they're created",
purpose: 'release',
},
},
fixMappingOfEventPrioritiesBetweenFabricAndReact: {
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<<38ad29621eeb29a9f82735dc187c13d4>>
* @generated SignedSource<<ceb682684f8c9df33a3f432033ab266a>>
* @flow strict
*/
@@ -80,6 +80,7 @@ export type ReactNativeFeatureFlags = {
enableUIConsistency: Getter<boolean>,
enableViewRecycling: Getter<boolean>,
excludeYogaFromRawProps: Getter<boolean>,
fixDifferentiatorEmittingUpdatesWithWrongParentTag: Getter<boolean>,
fixMappingOfEventPrioritiesBetweenFabricAndReact: Getter<boolean>,
fixMountingCoordinatorReportedPendingTransactionsOnAndroid: Getter<boolean>,
fuseboxEnabledDebug: Getter<boolean>,
@@ -304,6 +305,10 @@ export const enableViewRecycling: Getter<boolean> = createNativeFlagGetter('enab
* When enabled, rawProps in Props will not include Yoga specific props.
*/
export const excludeYogaFromRawProps: Getter<boolean> = createNativeFlagGetter('excludeYogaFromRawProps', false);
/**
* Fixes a bug in Differentiator where parent views may be referenced before they're created
*/
export const fixDifferentiatorEmittingUpdatesWithWrongParentTag: Getter<boolean> = createNativeFlagGetter('fixDifferentiatorEmittingUpdatesWithWrongParentTag', true);
/**
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
*/
@@ -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<<17c0e677f7b308795e836c558b15d1d1>>
* @generated SignedSource<<b36732a4a633b239ebd6d12d1ef460cb>>
* @flow strict
*/
@@ -53,6 +53,7 @@ export interface Spec extends TurboModule {
+enableUIConsistency?: () => boolean;
+enableViewRecycling?: () => boolean;
+excludeYogaFromRawProps?: () => boolean;
+fixDifferentiatorEmittingUpdatesWithWrongParentTag?: () => boolean;
+fixMappingOfEventPrioritiesBetweenFabricAndReact?: () => boolean;
+fixMountingCoordinatorReportedPendingTransactionsOnAndroid?: () => boolean;
+fuseboxEnabledDebug?: () => boolean;
+2 -3
View File
@@ -300,10 +300,9 @@ async function testRNTestProject(
'reactNativeArchitectures=arm64-v8a',
'android/gradle.properties',
);
const hermesEnabled = (await argv).hermes === true;
// Update gradle properties to set Hermes as false
if (!hermesEnabled) {
if (argv.hermes == null) {
sed(
'-i',
'hermesEnabled=true',
@@ -318,7 +317,7 @@ async function testRNTestProject(
exec('bundle install');
exec(
`HERMES_ENGINE_TARBALL_PATH=${hermesPath} USE_HERMES=${
hermesEnabled ? 1 : 0
argv.hermes === true ? 1 : 0
} bundle exec pod install --ansi`,
);
@@ -11,6 +11,7 @@
'use strict';
const chalk = require('chalk');
const {execSync: exec} = require('child_process');
const fetch = require('node-fetch');
@@ -30,6 +31,18 @@ type WorkflowRun = {
url: string,
created_at: string,
conclusion: "success" | "failure" | "neutral" | "cancelled" | "skipped" | "timed_out" | "action_required" | null,
head_commit: {
author: {
name: string,
},
message: string,
...
};
triggering_actor: {
login: string,
...
};
run_started_at: string,
};
@@ -102,6 +115,13 @@ async function _getArtifacts(run_id /*: number */) /*: Promise<Artifacts> */ {
return body;
}
function quote(text /*: string*/, prefix /*: string */ = ' > ') {
return text
.split('\n')
.map(line => prefix + line)
.join('\n');
}
// === Public Interface === //
async function initialize(
ciToken /*: string */,
@@ -149,6 +169,21 @@ async function initialize(
) ?? workflow;
}
const commit = workflow.head_commit;
const hours =
(new Date().getTime() - new Date(workflow.run_started_at).getTime()) /
(60 * 60 * 1000);
const started_by = workflow.triggering_actor.login;
console.log(
chalk.green(`The artifact being used is from a workflow started ${chalk.bold.magentaBright(hours.toFixed(0))} hours ago by ${chalk.bold.magentaBright(started_by)}:
Author: ${chalk.bold(commit.author.name)}
Message:
${chalk.magentaBright(quote(commit.message))}
`),
);
artifacts = await _getArtifacts(workflow.id);
}