react-native-windows 0.82.1 → 0.83.0-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/.flowconfig +2 -7
  2. package/Libraries/Animated/components/AnimatedFlatList.js +5 -3
  3. package/Libraries/Animated/components/AnimatedImage.js +4 -3
  4. package/Libraries/Animated/components/AnimatedSectionList.js +2 -2
  5. package/Libraries/Animated/components/AnimatedText.js +7 -3
  6. package/Libraries/Animated/components/AnimatedView.js +3 -2
  7. package/Libraries/Animated/createAnimatedComponent.js +24 -12
  8. package/Libraries/Animated/nodes/AnimatedColor.js +26 -10
  9. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +43 -15
  10. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.windows.js +43 -15
  11. package/Libraries/Components/ActivityIndicator/ActivityIndicator.d.ts +2 -2
  12. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.d.ts +2 -2
  13. package/Libraries/Components/Glyph/Glyph.js +4 -1
  14. package/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.d.ts +2 -2
  15. package/Libraries/Components/RefreshControl/RefreshControl.d.ts +3 -3
  16. package/Libraries/Components/SafeAreaView/SafeAreaView.d.ts +2 -2
  17. package/Libraries/Components/ScrollView/ScrollView.js +1 -0
  18. package/Libraries/Components/ScrollView/ScrollView.windows.js +1 -0
  19. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +6 -6
  20. package/Libraries/Components/Switch/Switch.d.ts +2 -2
  21. package/Libraries/Components/Switch/Switch.windows.js +1 -1
  22. package/Libraries/Components/TextInput/TextInput.d.ts +2 -5
  23. package/Libraries/Components/TextInput/TextInput.js +6 -0
  24. package/Libraries/Components/TextInput/TextInput.windows.js +6 -0
  25. package/Libraries/Components/Touchable/TouchableBounce.js +7 -7
  26. package/Libraries/Components/Touchable/TouchableBounce.windows.js +7 -7
  27. package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +1 -1
  28. package/Libraries/Components/View/ReactNativeStyleAttributes.js +19 -1
  29. package/Libraries/Components/View/View.d.ts +2 -2
  30. package/Libraries/Components/View/View.windows.js +0 -1
  31. package/Libraries/Components/View/ViewNativeComponent.js +13 -1
  32. package/Libraries/Core/ReactNativeVersion.js +3 -3
  33. package/Libraries/Core/setUpPerformance.js +2 -0
  34. package/Libraries/Debugging/DebuggingOverlay.js +14 -14
  35. package/Libraries/Debugging/DebuggingOverlayRegistry.js +8 -2
  36. package/Libraries/EventEmitter/RCTDeviceEventEmitter.js +5 -2
  37. package/Libraries/Image/Image.d.ts +3 -3
  38. package/Libraries/Image/ImageInjection.js +3 -6
  39. package/Libraries/Image/ImageTypes.flow.js +3 -7
  40. package/Libraries/Lists/FlatList.js +8 -8
  41. package/Libraries/Lists/SectionList.d.ts +5 -1
  42. package/Libraries/Lists/ViewabilityHelper.js +1 -1
  43. package/Libraries/Lists/VirtualizedList.js +1 -0
  44. package/Libraries/LogBox/UI/AnsiHighlight.js +4 -1
  45. package/Libraries/NativeComponent/BaseViewConfig.android.js +11 -2
  46. package/Libraries/NativeComponent/NativeComponentRegistry.d.ts +98 -0
  47. package/Libraries/NativeComponent/NativeComponentRegistry.js +2 -0
  48. package/Libraries/NativeComponent/NativeComponentRegistryUnstable.js +3 -1
  49. package/Libraries/NativeComponent/ViewConfigIgnore.windows.js +45 -0
  50. package/Libraries/Network/RCTNetworking.android.js +3 -1
  51. package/Libraries/Network/RCTNetworking.ios.js +3 -0
  52. package/Libraries/Network/RCTNetworking.windows.js +3 -0
  53. package/Libraries/Network/XMLHttpRequest.js +1 -41
  54. package/Libraries/Pressability/usePressability.js +14 -3
  55. package/Libraries/ReactNative/PaperUIManager.windows.js +3 -3
  56. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstance.js +20 -82
  57. package/Libraries/ReactNative/getNativeComponentAttributes.js +12 -0
  58. package/Libraries/Renderer/implementations/ReactFabric-dev.js +6759 -4478
  59. package/Libraries/Renderer/implementations/ReactFabric-prod.js +3169 -3119
  60. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +4732 -3535
  61. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +6646 -4070
  62. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +3136 -2825
  63. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +4761 -3312
  64. package/Libraries/Renderer/shims/ReactNative.js +3 -1
  65. package/Libraries/Renderer/shims/ReactNativeTypes.js +2 -1
  66. package/Libraries/Renderer/shims/ReactNativeTypes.windows.js +2 -1
  67. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +1 -1
  68. package/Libraries/StyleSheet/StyleSheetTypes.js +44 -0
  69. package/Libraries/StyleSheet/processBackgroundPosition.js +284 -0
  70. package/Libraries/StyleSheet/processBackgroundRepeat.js +105 -0
  71. package/Libraries/StyleSheet/processBackgroundSize.js +104 -0
  72. package/Libraries/Text/Text.d.ts +2 -2
  73. package/Libraries/Text/TextNativeComponent.js +10 -0
  74. package/Libraries/TurboModule/TurboModuleRegistry.js +3 -9
  75. package/Libraries/Utilities/DevLoadingView.js +14 -6
  76. package/Libraries/Utilities/HMRClient.js +13 -5
  77. package/Microsoft.ReactNative/Base/CxxReactIncludes.h +11 -0
  78. package/Microsoft.ReactNative/CompositionComponentView.idl +2 -0
  79. package/Microsoft.ReactNative/CompositionHwndHost.idl +1 -0
  80. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +1 -1
  81. package/Microsoft.ReactNative/Fabric/ComponentView.h +1 -1
  82. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +10 -40
  83. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +3 -80
  84. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +45 -12
  85. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +8 -0
  86. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +61 -74
  87. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +4 -0
  88. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +1 -0
  89. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +4 -3
  90. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +2 -1
  91. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeWindow.cpp +245 -0
  92. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeWindow.h +80 -0
  93. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentDescriptor.h +20 -36
  94. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +70 -49
  95. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +4 -1
  96. package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.cpp +5 -0
  97. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.cpp +7 -2
  98. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +1 -0
  99. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -1
  100. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +1 -1
  101. package/Microsoft.ReactNative/Modules/LogBoxModule.cpp +20 -94
  102. package/Microsoft.ReactNative/Modules/LogBoxModule.h +1 -3
  103. package/Microsoft.ReactNative/Pch/pch.h +2 -0
  104. package/Microsoft.ReactNative/ReactHost/CrashManager.cpp +5 -0
  105. package/Microsoft.ReactNative/ReactHost/ReactNativeHeaders.h +1 -0
  106. package/Microsoft.ReactNative/ReactNativeAppBuilder.cpp +0 -41
  107. package/Microsoft.ReactNative/ReactNativeAppBuilder.idl +0 -11
  108. package/Microsoft.ReactNative/ReactNativeIsland.idl +2 -3
  109. package/Microsoft.ReactNative/ReactNativeWin32App.cpp +31 -101
  110. package/Microsoft.ReactNative/ReactNativeWin32App.h +2 -13
  111. package/Microsoft.ReactNative/ReactNativeWindow.idl +44 -0
  112. package/Microsoft.ReactNative.Cxx/AutoDraw.h +9 -1
  113. package/Microsoft.ReactNative.Cxx/ReactCommon/CallInvoker.h +13 -16
  114. package/Microsoft.ReactNative.Cxx/ReactCommon/TurboModule.h +24 -36
  115. package/Microsoft.ReactNative.Cxx/ReactCommon/TurboModuleUtils.h +5 -8
  116. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/AString.h +8 -6
  117. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Array.h +32 -49
  118. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Base.h +27 -76
  119. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Bool.h +4 -2
  120. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/CallbackWrapper.h +19 -18
  121. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Class.h +25 -48
  122. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Convert.h +38 -31
  123. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Error.h +11 -6
  124. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/EventEmitter.h +47 -45
  125. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Function.h +69 -89
  126. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/HighResTimeStamp.h +8 -8
  127. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/LongLivedObject.h +6 -6
  128. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Number.h +16 -8
  129. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Object.h +17 -24
  130. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Promise.h +17 -17
  131. package/Microsoft.ReactNative.Cxx/ReactCommon/react/bridging/Value.h +20 -29
  132. package/Microsoft.ReactNative.Cxx/ReactCommon/react/debug/react_native_assert.h +2 -7
  133. package/Microsoft.ReactNative.Cxx/ReactCommon/react/timing/primitives.h +127 -115
  134. package/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.props +10 -0
  135. package/PropertySheets/External/Microsoft.ReactNative.Uwp.CppLib.props +10 -0
  136. package/PropertySheets/Generated/PackageVersion.g.props +5 -5
  137. package/PropertySheets/Warnings.props +2 -1
  138. package/ReactCommon/ReactCommon.vcxproj +21 -12
  139. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/CxxNativeModule.cpp +2 -2
  140. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/Instance.cpp +381 -0
  141. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.cpp +49 -0
  142. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSIndexedRAMBundle.cpp +145 -0
  143. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/MethodCall.cpp +100 -0
  144. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/ModuleRegistry.cpp +256 -0
  145. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.cpp +13 -4
  146. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/RAMBundleRegistry.cpp +93 -0
  147. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/ReactMarker.cpp +149 -0
  148. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/TraceSection.h +25 -35
  149. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/test/testlib.cpp +86 -67
  150. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsiexecutor/jsireact/JSIExecutor.cpp +629 -0
  151. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsiexecutor/jsireact/JSINativeModules.cpp +123 -0
  152. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.cpp +84 -68
  153. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.h +31 -35
  154. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/Utf8.h +4 -5
  155. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/network/HttpUtils.cpp +2 -1
  156. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModule.h +24 -36
  157. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/dom/NativeDOM.h +28 -66
  158. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/webperformance/NativePerformance.cpp +414 -0
  159. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp +3 -3
  160. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/image/conversions.h +8 -4
  161. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/ParagraphShadowNode.cpp +19 -16
  162. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/text/platform/android/react/renderer/components/text/ParagraphState.h +8 -9
  163. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/AccessibilityPrimitives.h +25 -95
  164. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/accessibilityPropsConversions.h +85 -42
  165. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/core/EventDispatcher.cpp +81 -0
  166. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/core/EventQueueProcessor.cpp +140 -0
  167. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/imagemanager/primitives.h +25 -31
  168. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/uimanager/UIManager.cpp +746 -0
  169. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/ReactInstance.cpp +702 -0
  170. package/Scripts/Tfs/Layout-Desktop-Headers.ps1 +1 -15
  171. package/Scripts/creaternwapp.cmd +1 -1
  172. package/Scripts/perf/compare-results.js +357 -0
  173. package/Scripts/perf/create-perf-test.js +343 -0
  174. package/Scripts/perf/post-pr-comment.js +210 -0
  175. package/Shared/Hermes/HermesRuntimeTargetDelegate.cpp +8 -0
  176. package/Shared/Hermes/HermesRuntimeTargetDelegate.h +3 -0
  177. package/Shared/Shared.vcxitems +24 -12
  178. package/Shared/Shared.vcxitems.filters +11 -3
  179. package/codegen/NativeIntersectionObserverSpec.g.h +2 -0
  180. package/codegen/NativeNetworkingIOSSpec.g.h +2 -0
  181. package/codegen/NativePerformanceSpec.g.h +6 -0
  182. package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +229 -139
  183. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +2 -1
  184. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +42 -25
  185. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +2 -1
  186. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +2 -1
  187. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +11 -6
  188. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +11 -6
  189. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +1 -0
  190. package/codegen/react/components/rnwcore/InputAccessory.g.h +2 -1
  191. package/codegen/react/components/rnwcore/ModalHostView.g.h +40 -23
  192. package/codegen/react/components/rnwcore/Props.cpp +6 -1
  193. package/codegen/react/components/rnwcore/Props.h +1 -0
  194. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +11 -6
  195. package/codegen/react/components/rnwcore/SafeAreaView.g.h +1 -0
  196. package/codegen/react/components/rnwcore/Switch.g.h +11 -6
  197. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +2 -1
  198. package/codegen/react/components/rnwcore/VirtualView.g.h +41 -8
  199. package/codegen/react/components/rnwcore/VirtualViewExperimental.g.h +45 -8
  200. package/codegen/rnwcoreJSI.h +3973 -6059
  201. package/index.js +6 -0
  202. package/index.windows.js +6 -0
  203. package/jest/mockComponent.js +6 -6
  204. package/jest/setup.js +15 -10
  205. package/package.json +27 -27
  206. package/src/private/components/virtualview/VirtualView.js +22 -27
  207. package/src/private/components/virtualview/VirtualViewExperimentalNativeComponent.js +6 -0
  208. package/src/private/featureflags/ReactNativeFeatureFlags.js +100 -19
  209. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +18 -3
  210. package/src/private/setup/setUpDefaultReactNativeEnvironment.js +6 -0
  211. package/src/private/specs_DEPRECATED/components/SwitchNativeComponent.js +1 -1
  212. package/src/private/specs_DEPRECATED/modules/NativeNetworkingIOS.js +1 -0
  213. package/src/private/webapis/dom/nodes/ReactNativeElement.js +12 -2
  214. package/src/private/webapis/intersectionobserver/IntersectionObserver.js +76 -15
  215. package/src/private/webapis/intersectionobserver/internals/IntersectionObserverManager.js +1 -0
  216. package/src/private/webapis/intersectionobserver/specs/NativeIntersectionObserver.js +1 -0
  217. package/src/private/webapis/performance/ResourceTiming.js +31 -4
  218. package/src/private/webapis/performance/internals/RawPerformanceEntry.js +4 -1
  219. package/src/private/webapis/performance/specs/NativePerformance.js +3 -0
  220. package/stubs/double-conversion/double-conversion.h +5 -0
  221. package/templates/cpp-app/template.config.js +1 -1
  222. package/templates/cpp-app/windows/MyApp/MyApp.vcxproj +3 -1
  223. package/templates/cpp-lib/template.config.js +1 -1
  224. package/templates/cpp-lib/windows/MyLib/MyLib.vcxproj +1 -1
  225. package/types/index.d.ts +1 -0
  226. package/types/public/ReactNativeTypes.d.ts +115 -2
  227. package/Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricHostComponent.js +0 -152
  228. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/components/view/conversions.h +0 -1574
  229. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/core/ShadowNode.cpp +0 -528
  230. package/Scripts/OpenSSL.nuspec +0 -39
  231. package/Scripts/OpenSSL.targets +0 -36
  232. package/codegen/rnwcoreJSI-generated.cpp +0 -3470
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Copyright (c) Microsoft Corporation.
4
+ * Licensed under the MIT License.
5
+ *
6
+ * Interactive CLI to scaffold a new component performance test.
7
+ *
8
+ * Usage:
9
+ * node vnext/Scripts/perf/create-perf-test.js
10
+ * yarn perf:create (from e2e-test-app-fabric)
11
+ *
12
+ * Generates a `.perf-test.tsx` file with:
13
+ * - Class extending ComponentPerfTestBase
14
+ * - Standard mount / unmount / rerender tests
15
+ * - Placeholder for custom scenarios
16
+ * - Correct imports, test ID, and category
17
+ *
18
+ * @format
19
+ */
20
+
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+ const readline = require('readline');
24
+
25
+ function ask(rl, question, defaultValue) {
26
+ const suffix = defaultValue ? ` (${defaultValue})` : '';
27
+ return new Promise(resolve => {
28
+ rl.question(`${question}${suffix}: `, answer => {
29
+ resolve(answer.trim() || defaultValue || '');
30
+ });
31
+ });
32
+ }
33
+
34
+ function choose(rl, question, options, defaultIndex = 0) {
35
+ return new Promise(resolve => {
36
+ console.log(`\n${question}`);
37
+ options.forEach((opt, i) => {
38
+ const marker = i === defaultIndex ? ' (default)' : '';
39
+ console.log(` ${i + 1}. ${opt}${marker}`);
40
+ });
41
+ rl.question(`Choice [${defaultIndex + 1}]: `, answer => {
42
+ const idx = parseInt(answer, 10) - 1;
43
+ resolve(
44
+ idx >= 0 && idx < options.length ? options[idx] : options[defaultIndex],
45
+ );
46
+ });
47
+ });
48
+ }
49
+
50
+ function toPascalCase(str) {
51
+ return str
52
+ .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
53
+ .replace(/^(.)/, (_, c) => c.toUpperCase());
54
+ }
55
+
56
+ function toKebabCase(str) {
57
+ return str
58
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
59
+ .replace(/[\s_]+/g, '-')
60
+ .toLowerCase();
61
+ }
62
+
63
+ /**
64
+ * Split a props string into individual prop tokens,
65
+ * correctly handling nested braces like onPress={() => {}}.
66
+ */
67
+ function splitProps(propsStr) {
68
+ const props = [];
69
+ let current = '';
70
+ let braceDepth = 0;
71
+ let inString = null; // '"' or "'"
72
+
73
+ for (let i = 0; i < propsStr.length; i++) {
74
+ const ch = propsStr[i];
75
+
76
+ // Track string boundaries
77
+ if ((ch === '"' || ch === "'") && !inString) {
78
+ inString = ch;
79
+ } else if (ch === inString) {
80
+ inString = null;
81
+ }
82
+
83
+ if (!inString) {
84
+ if (ch === '{') braceDepth++;
85
+ if (ch === '}') braceDepth--;
86
+ }
87
+
88
+ // Split on whitespace only when outside braces/strings
89
+ if (ch === ' ' && braceDepth === 0 && !inString) {
90
+ if (current.trim()) props.push(current.trim());
91
+ current = '';
92
+ } else {
93
+ current += ch;
94
+ }
95
+ }
96
+ if (current.trim()) props.push(current.trim());
97
+ return props;
98
+ }
99
+
100
+ const CATEGORIES = ['core', 'extended', 'interactive', 'list', 'community'];
101
+
102
+ const PERF_TEST_ROOT = path.resolve(
103
+ __dirname,
104
+ '../../..',
105
+ 'packages/e2e-test-app-fabric/test/__perf__',
106
+ );
107
+
108
+ // Known required props for common RN components.
109
+ // These are auto-applied so the generated test works out of the box.
110
+ const KNOWN_REQUIRED_PROPS = {
111
+ Button: 'title="Perf Test" onPress={() => {}}',
112
+ Switch: 'value={false}',
113
+ Image: 'source={{uri: "https://example.com/img.png"}}',
114
+ FlatList: 'data={[]} renderItem={() => null}',
115
+ SectionList: 'sections={[]} renderItem={() => null}',
116
+ Modal: 'visible={true}',
117
+ TouchableHighlight: 'onPress={() => {}}',
118
+ TouchableOpacity: 'onPress={() => {}}',
119
+ Pressable: 'onPress={() => {}}',
120
+ };
121
+
122
+ function generateTestFile({
123
+ componentName,
124
+ pascalName,
125
+ kebabName,
126
+ importPath,
127
+ category,
128
+ hasChildren,
129
+ childrenText,
130
+ requiredProps,
131
+ }) {
132
+ const testId = `perf-test-${kebabName}`;
133
+ const instanceName = `${pascalName.charAt(0).toLowerCase() + pascalName.slice(1)}PerfTest`;
134
+
135
+ const allProps = [`testID={this.testId}`];
136
+ if (requiredProps) {
137
+ // Parse individual JSX props, handling nested braces like {() => {}}
138
+ allProps.push(...splitProps(requiredProps));
139
+ }
140
+ allProps.push('style={styles.default}', '{...props}');
141
+
142
+ let createComponentBody;
143
+ if (hasChildren) {
144
+ const propLines = allProps.map(p => ` ${p}`).join('\n');
145
+ createComponentBody = ` return (\n <${componentName}\n${propLines}>\n ${childrenText}\n </${componentName}>\n );`;
146
+ } else if (allProps.length > 3) {
147
+ const propLines = allProps.map(p => ` ${p}`).join('\n');
148
+ createComponentBody = ` return (\n <${componentName}\n${propLines}\n />\n );`;
149
+ } else {
150
+ createComponentBody = ` return <${componentName} ${allProps.join(' ')} />;`;
151
+ }
152
+
153
+ return `/**
154
+ * Copyright (c) Microsoft Corporation.
155
+ * Licensed under the MIT License.
156
+ *
157
+ * Performance tests for ${componentName} component.
158
+ *
159
+ * @format
160
+ */
161
+
162
+ import * as React from 'react';
163
+ import {${componentName}, StyleSheet} from '${importPath}';
164
+ import {
165
+ ComponentPerfTestBase,
166
+ measurePerf,
167
+ } from '@react-native-windows/perf-testing';
168
+ import type {IScenario, PerfMetrics} from '@react-native-windows/perf-testing';
169
+
170
+ class ${pascalName}PerfTest extends ComponentPerfTestBase {
171
+ readonly componentName = '${componentName}';
172
+ readonly category = '${category}' as const;
173
+ readonly testId = '${testId}';
174
+
175
+ createComponent(props?: Record<string, unknown>): React.ReactElement {
176
+ ${createComponentBody}
177
+ }
178
+
179
+ getCustomScenarios(): IScenario[] {
180
+ return [];
181
+ }
182
+ }
183
+
184
+ const ${instanceName} = new ${pascalName}PerfTest();
185
+
186
+ describe('${componentName} Performance', () => {
187
+ test('mount time', async () => {
188
+ const perf = await ${instanceName}.measureMount();
189
+ expect(perf).toMatchPerfSnapshot();
190
+ });
191
+
192
+ test('unmount time', async () => {
193
+ const perf = await ${instanceName}.measureUnmount();
194
+ expect(perf).toMatchPerfSnapshot();
195
+ });
196
+
197
+ test('rerender time', async () => {
198
+ const perf = await ${instanceName}.measureRerender();
199
+ expect(perf).toMatchPerfSnapshot();
200
+ });
201
+ });
202
+
203
+ const styles = StyleSheet.create({
204
+ default: {
205
+ });
206
+ `;
207
+ }
208
+
209
+ async function main() {
210
+ const rl = readline.createInterface({
211
+ input: process.stdin,
212
+ output: process.stdout,
213
+ });
214
+
215
+ console.log('\n🧪 React Native Windows — Performance Test Generator\n');
216
+ console.log('This will create a new .perf-test.tsx file with mount,');
217
+ console.log('unmount, and rerender tests for your component.\n');
218
+ console.log('Examples:');
219
+ console.log(
220
+ ' Component: ScrollView | Import: react-native | Category: core | Children: yes',
221
+ );
222
+ console.log(
223
+ ' Component: Button | Import: react-native | Category: core | Children: no',
224
+ );
225
+ console.log(
226
+ ' Component: Image | Import: react-native | Category: core | Children: no',
227
+ );
228
+ console.log(
229
+ ' Component: Pressable | Import: react-native | Category: interactive | Children: yes',
230
+ );
231
+ console.log(
232
+ ' Component: Slider | Import: @react-native-community/slider | Category: community | Children: no',
233
+ );
234
+ console.log('');
235
+
236
+ const rawName = await ask(
237
+ rl,
238
+ 'Component name (e.g. ScrollView, Image, Pressable)',
239
+ );
240
+ if (!rawName) {
241
+ console.error('❌ Component name is required.');
242
+ rl.close();
243
+ process.exit(1);
244
+ }
245
+
246
+ const pascalName = toPascalCase(rawName);
247
+ const kebabName = toKebabCase(rawName);
248
+
249
+ const importPath = await ask(
250
+ rl,
251
+ 'Import path for the component',
252
+ 'react-native',
253
+ );
254
+
255
+ const category = await choose(
256
+ rl,
257
+ 'Select component category:',
258
+ CATEGORIES,
259
+ 0,
260
+ );
261
+
262
+ const hasChildrenAnswer = await ask(
263
+ rl,
264
+ 'Does this component render children? (y/N)',
265
+ 'N',
266
+ );
267
+ const hasChildren = hasChildrenAnswer.toLowerCase() === 'y';
268
+ let childrenText = 'Sample Content';
269
+ if (hasChildren) {
270
+ const customChildren = await ask(
271
+ rl,
272
+ 'Children text/content',
273
+ 'Sample Content',
274
+ );
275
+ childrenText = customChildren;
276
+ }
277
+
278
+ let requiredProps = KNOWN_REQUIRED_PROPS[rawName] || '';
279
+ if (requiredProps) {
280
+ console.log(`\n Auto-detected required props: ${requiredProps}`);
281
+ const override = await ask(
282
+ rl,
283
+ 'Required props (Enter to accept, or type custom)',
284
+ requiredProps,
285
+ );
286
+ requiredProps = override;
287
+ } else {
288
+ const customProps = await ask(
289
+ rl,
290
+ 'Required props (e.g. title="Test" onPress={() => {}}) – leave blank if none',
291
+ '',
292
+ );
293
+ requiredProps = customProps;
294
+ }
295
+
296
+ rl.close();
297
+
298
+ const categoryDir = path.join(PERF_TEST_ROOT, category);
299
+ if (!fs.existsSync(categoryDir)) {
300
+ fs.mkdirSync(categoryDir, {recursive: true});
301
+ console.log(
302
+ `\n📁 Created directory: ${path.relative(process.cwd(), categoryDir)}`,
303
+ );
304
+ }
305
+
306
+ const outputFile = path.join(categoryDir, `${pascalName}.perf-test.tsx`);
307
+ if (fs.existsSync(outputFile)) {
308
+ console.error(
309
+ `\n❌ File already exists: ${path.relative(process.cwd(), outputFile)}`,
310
+ );
311
+ console.error(' Delete it first or choose a different name.');
312
+ process.exit(1);
313
+ }
314
+
315
+ const content = generateTestFile({
316
+ componentName: rawName,
317
+ pascalName,
318
+ kebabName,
319
+ importPath,
320
+ category,
321
+ hasChildren,
322
+ childrenText,
323
+ requiredProps,
324
+ });
325
+
326
+ fs.writeFileSync(outputFile, content, 'utf8');
327
+
328
+ const relPath = path.relative(process.cwd(), outputFile);
329
+ console.log(`\n✅ Created: ${relPath}`);
330
+ console.log(`\nNext steps:`);
331
+ console.log(` 1. Review and customize the generated test file`);
332
+ console.log(` 2. Add any component-specific custom scenarios`);
333
+ console.log(` 3. Run: yarn perf --testPathPattern=${pascalName}`);
334
+ console.log(
335
+ ` 4. Generate baseline: yarn perf:update --testPathPattern=${pascalName}`,
336
+ );
337
+ console.log('');
338
+ }
339
+
340
+ main().catch(err => {
341
+ console.error('Error:', err);
342
+ process.exit(1);
343
+ });
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ * Licensed under the MIT License.
4
+ *
5
+ * Post perf test results as a GitHub PR comment.
6
+ *
7
+ * Uses the GitHub API to find/update an existing perf comment on the PR,
8
+ * or create a new one. Designed to be called from GitHub Actions.
9
+ *
10
+ * Usage:
11
+ * node vnext/Scripts/perf/post-pr-comment.js [options]
12
+ *
13
+ * Options:
14
+ * --report <path> Path to markdown report (default: .perf-results/report.md)
15
+ * --summary <path> Path to JSON summary (default: .perf-results/report.json)
16
+ * --pr <number> PR number (default: from GITHUB_EVENT)
17
+ * --dry-run Print the comment but don't post it
18
+ *
19
+ * Environment:
20
+ * GITHUB_TOKEN Required for posting comments
21
+ * GITHUB_REPOSITORY e.g. microsoft/react-native-windows
22
+ * GITHUB_EVENT_PATH Path to event.json (auto-set in GH Actions)
23
+ *
24
+ * @format
25
+ */
26
+
27
+ 'use strict';
28
+
29
+ const fs = require('fs');
30
+ const https = require('https');
31
+ const path = require('path');
32
+
33
+ const COMMENT_MARKER = '<!-- rnw-perf-results -->';
34
+
35
+ function parseArgs() {
36
+ const args = process.argv.slice(2);
37
+ const opts = {
38
+ report: '.perf-results/report.md',
39
+ summary: '.perf-results/report.json',
40
+ pr: null,
41
+ dryRun: false,
42
+ };
43
+
44
+ for (let i = 0; i < args.length; i++) {
45
+ switch (args[i]) {
46
+ case '--report':
47
+ opts.report = args[++i];
48
+ break;
49
+ case '--summary':
50
+ opts.summary = args[++i];
51
+ break;
52
+ case '--pr':
53
+ opts.pr = parseInt(args[++i], 10);
54
+ break;
55
+ case '--dry-run':
56
+ opts.dryRun = true;
57
+ break;
58
+ }
59
+ }
60
+
61
+ // Attempt to detect PR number from GH Actions event
62
+ if (!opts.pr && process.env.GITHUB_EVENT_PATH) {
63
+ try {
64
+ const event = JSON.parse(
65
+ fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf-8'),
66
+ );
67
+ if (event.pull_request) {
68
+ opts.pr = event.pull_request.number;
69
+ } else if (event.number) {
70
+ opts.pr = event.number;
71
+ }
72
+ } catch {
73
+ // ignore
74
+ }
75
+ }
76
+
77
+ return opts;
78
+ }
79
+
80
+ function githubRequest(method, apiPath, body) {
81
+ const token = process.env.GITHUB_TOKEN;
82
+ if (!token) {
83
+ throw new Error('GITHUB_TOKEN environment variable is required');
84
+ }
85
+
86
+ const repo =
87
+ process.env.GITHUB_REPOSITORY || 'microsoft/react-native-windows';
88
+
89
+ return new Promise((resolve, reject) => {
90
+ const options = {
91
+ hostname: 'api.github.com',
92
+ port: 443,
93
+ path: `/repos/${repo}${apiPath}`,
94
+ method,
95
+ headers: {
96
+ Authorization: `token ${token}`,
97
+ Accept: 'application/vnd.github.v3+json',
98
+ 'User-Agent': 'rnw-perf-tests',
99
+ 'Content-Type': 'application/json',
100
+ },
101
+ };
102
+
103
+ const req = https.request(options, res => {
104
+ let data = '';
105
+ res.on('data', chunk => (data += chunk));
106
+ res.on('end', () => {
107
+ if (res.statusCode >= 200 && res.statusCode < 300) {
108
+ resolve(data ? JSON.parse(data) : null);
109
+ } else {
110
+ reject(
111
+ new Error(
112
+ `GitHub API ${method} ${apiPath} returned ${res.statusCode}: ${data}`,
113
+ ),
114
+ );
115
+ }
116
+ });
117
+ });
118
+
119
+ req.on('error', reject);
120
+
121
+ if (body) {
122
+ req.write(JSON.stringify(body));
123
+ }
124
+ req.end();
125
+ });
126
+ }
127
+
128
+ async function findExistingComment(prNumber) {
129
+ let page = 1;
130
+ while (true) {
131
+ const comments = await githubRequest(
132
+ 'GET',
133
+ `/issues/${prNumber}/comments?per_page=100&page=${page}`,
134
+ );
135
+ if (!comments || comments.length === 0) break;
136
+
137
+ const existing = comments.find(
138
+ c => c.body && c.body.includes(COMMENT_MARKER),
139
+ );
140
+ if (existing) return existing;
141
+
142
+ if (comments.length < 100) break;
143
+ page++;
144
+ }
145
+ return null;
146
+ }
147
+
148
+ async function main() {
149
+ const opts = parseArgs();
150
+
151
+ // Load markdown report
152
+ if (!fs.existsSync(opts.report)) {
153
+ console.error(`❌ Report not found: ${opts.report}`);
154
+ console.error('Run compare-results.js first.');
155
+ process.exit(1);
156
+ }
157
+
158
+ const markdown = fs.readFileSync(opts.report, 'utf-8');
159
+
160
+ // Load summary for status message
161
+ let summary = {hasRegressions: false};
162
+ if (fs.existsSync(opts.summary)) {
163
+ summary = JSON.parse(fs.readFileSync(opts.summary, 'utf-8'));
164
+ }
165
+
166
+ // Build comment body with hidden marker for idempotent updates
167
+ const commentBody = `${COMMENT_MARKER}\n${markdown}`;
168
+
169
+ if (opts.dryRun) {
170
+ console.log('=== DRY RUN — would post the following comment ===\n');
171
+ console.log(commentBody);
172
+ console.log('\n=== End of comment ===');
173
+ process.exit(summary.hasRegressions ? 1 : 0);
174
+ }
175
+
176
+ if (!opts.pr) {
177
+ console.error('❌ Could not determine PR number.');
178
+ console.error('Use --pr <number> or ensure GITHUB_EVENT_PATH is set.');
179
+ process.exit(1);
180
+ }
181
+
182
+ console.log(`📤 Posting perf results to PR #${opts.pr}...`);
183
+
184
+ try {
185
+ // Try to update existing comment
186
+ const existing = await findExistingComment(opts.pr);
187
+ if (existing) {
188
+ await githubRequest('PATCH', `/issues/comments/${existing.id}`, {
189
+ body: commentBody,
190
+ });
191
+ console.log(`✅ Updated existing comment (id: ${existing.id})`);
192
+ } else {
193
+ await githubRequest('POST', `/issues/${opts.pr}/comments`, {
194
+ body: commentBody,
195
+ });
196
+ console.log('✅ Created new comment');
197
+ }
198
+ } catch (err) {
199
+ console.error(`❌ Failed to post comment: ${err.message}`);
200
+ // Don't fail the build if commenting fails — the results are in artifacts
201
+ console.log('Results are still available as workflow artifacts.');
202
+ }
203
+
204
+ process.exit(summary.hasRegressions ? 1 : 0);
205
+ }
206
+
207
+ main().catch(err => {
208
+ console.error(err);
209
+ process.exit(1);
210
+ });
@@ -275,4 +275,12 @@ tracing::RuntimeSamplingProfile HermesRuntimeTargetDelegate::collectSamplingProf
275
275
  std::make_unique<HermesRawRuntimeProfile>(std::move(profile)));
276
276
  }
277
277
 
278
+ std::optional<folly::dynamic> HermesRuntimeTargetDelegate::serializeStackTrace(
279
+ const facebook::react::jsinspector_modern::StackTrace &stackTrace) {
280
+ // #TODO :
281
+ // react native implementation:
282
+ // https://github.com/facebook/react-native/commit/b31a2fb4b8d3a5e1f12efc8ec3951a0e02004757
283
+ return std::nullopt;
284
+ }
285
+
278
286
  } // namespace Microsoft::ReactNative
@@ -69,6 +69,9 @@ class HermesRuntimeTargetDelegate : public facebook::react::jsinspector_modern::
69
69
  */
70
70
  facebook::react::jsinspector_modern::tracing::RuntimeSamplingProfile collectSamplingProfile() override;
71
71
 
72
+ std::optional<folly::dynamic> serializeStackTrace(
73
+ const facebook::react::jsinspector_modern::StackTrace &stackTrace) override;
74
+
72
75
  private:
73
76
  std::shared_ptr<HermesRuntimeHolder> hermesRuntimeHolder_;
74
77
  const HermesUniqueCdpDebugApi hermesCdpDebugApi_;