|
24 | 24 | #include <fbjni/fbjni.h> |
25 | 25 | #include <glog/logging.h> |
26 | 26 |
|
| 27 | +#include <algorithm> |
27 | 28 | #include <cfenv> |
28 | 29 | #include <cmath> |
29 | | -#include <unordered_set> |
30 | 30 | #include <vector> |
31 | 31 |
|
32 | 32 | namespace facebook::react { |
@@ -54,6 +54,80 @@ void FabricMountingManager::onSurfaceStop(SurfaceId surfaceId) { |
54 | 54 |
|
55 | 55 | namespace { |
56 | 56 |
|
| 57 | +#ifdef REACT_NATIVE_DEBUG |
| 58 | +// List of layout-only props extracted from ViewProps.kt used to filter out |
| 59 | +// component props from Props 1.5 to validate the Props 2.0 output |
| 60 | +inline bool isLayoutOnlyProp(const std::string& propName) { |
| 61 | + static const std::vector<std::string> layoutOnlyProps = { |
| 62 | + // Flexbox Alignment |
| 63 | + "alignItems", |
| 64 | + "alignSelf", |
| 65 | + "alignContent", |
| 66 | + |
| 67 | + // Flexbox Properties |
| 68 | + "flex", |
| 69 | + "flexBasis", |
| 70 | + "flexDirection", |
| 71 | + "flexGrow", |
| 72 | + "flexShrink", |
| 73 | + "flexWrap", |
| 74 | + "justifyContent", |
| 75 | + |
| 76 | + // Gaps |
| 77 | + "rowGap", |
| 78 | + "columnGap", |
| 79 | + "gap", |
| 80 | + |
| 81 | + // Display & Position |
| 82 | + "display", |
| 83 | + "position", |
| 84 | + |
| 85 | + // Positioning |
| 86 | + "right", |
| 87 | + "top", |
| 88 | + "bottom", |
| 89 | + "left", |
| 90 | + "start", |
| 91 | + "end", |
| 92 | + |
| 93 | + // Dimensions |
| 94 | + "width", |
| 95 | + "height", |
| 96 | + "minWidth", |
| 97 | + "maxWidth", |
| 98 | + "minHeight", |
| 99 | + "maxHeight", |
| 100 | + |
| 101 | + // Margins |
| 102 | + "margin", |
| 103 | + "marginVertical", |
| 104 | + "marginHorizontal", |
| 105 | + "marginLeft", |
| 106 | + "marginRight", |
| 107 | + "marginTop", |
| 108 | + "marginBottom", |
| 109 | + "marginStart", |
| 110 | + "marginEnd", |
| 111 | + |
| 112 | + // Paddings |
| 113 | + "padding", |
| 114 | + "paddingVertical", |
| 115 | + "paddingHorizontal", |
| 116 | + "paddingLeft", |
| 117 | + "paddingRight", |
| 118 | + "paddingTop", |
| 119 | + "paddingBottom", |
| 120 | + "paddingStart", |
| 121 | + "paddingEnd", |
| 122 | + |
| 123 | + // Other |
| 124 | + "collapsable", |
| 125 | + }; |
| 126 | + return std::find(layoutOnlyProps.begin(), layoutOnlyProps.end(), propName) != |
| 127 | + layoutOnlyProps.end(); |
| 128 | +} |
| 129 | +#endif |
| 130 | + |
57 | 131 | inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) { |
58 | 132 | switch (mountItemType) { |
59 | 133 | case CppMountItem::Type::Create: |
@@ -232,8 +306,29 @@ jni::local_ref<jobject> getProps( |
232 | 306 | strcmp( |
233 | 307 | newShadowView.componentName, |
234 | 308 | newProps->getDiffPropsImplementationTarget()) == 0) { |
235 | | - return ReadableNativeMap::newObjectCxxArgs( |
236 | | - newProps->getDiffProps(oldProps)); |
| 309 | + auto diff = newProps->getDiffProps(oldProps); |
| 310 | + |
| 311 | +#ifdef REACT_NATIVE_DEBUG |
| 312 | + if (oldProps != nullptr) { |
| 313 | + auto controlDiff = |
| 314 | + diffDynamicProps(oldProps->rawProps, newProps->rawProps); |
| 315 | + |
| 316 | + for (const auto& [prop, value] : controlDiff.items()) { |
| 317 | + if (diff.count(prop) == 0) { |
| 318 | + // Skip layout-only props since they are not included in Props 2.0 |
| 319 | + if (!isLayoutOnlyProp(prop.asString())) { |
| 320 | + LOG(ERROR) << "Props diff validation failed: Props 1.5 has prop '" |
| 321 | + << prop.asString() |
| 322 | + << "' = " << (value != nullptr ? value : "NULL") |
| 323 | + << " that Props 2.0 doesn't have for component " |
| 324 | + << newShadowView.componentName; |
| 325 | + } |
| 326 | + } |
| 327 | + } |
| 328 | + } |
| 329 | +#endif |
| 330 | + |
| 331 | + return ReadableNativeMap::newObjectCxxArgs(std::move(diff)); |
237 | 332 | } |
238 | 333 | if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) { |
239 | 334 | if (oldProps == nullptr) { |
|
0 commit comments