@office-iss/react-native-win32 0.74.4 → 0.75.0-preview.2

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 (214) hide show
  1. package/.flowconfig +9 -4
  2. package/CHANGELOG.json +569 -51
  3. package/CHANGELOG.md +173 -30
  4. package/Libraries/Animated/AnimatedImplementation.js +2 -0
  5. package/Libraries/Animated/NativeAnimatedHelper.js +4 -0
  6. package/Libraries/Animated/NativeAnimatedHelper.win32.js +4 -0
  7. package/Libraries/Animated/createAnimatedComponent.js +10 -4
  8. package/Libraries/Animated/useAnimatedProps.js +56 -28
  9. package/Libraries/BatchedBridge/MessageQueue.js +1 -0
  10. package/Libraries/Components/Button.js +10 -5
  11. package/Libraries/Components/Button.win32.js +1 -0
  12. package/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +11 -2
  13. package/Libraries/Components/Pressable/Pressable.js +13 -6
  14. package/Libraries/Components/Pressable/Pressable.win32.js +13 -6
  15. package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +4 -0
  16. package/Libraries/Components/ScrollView/ScrollView.js +109 -29
  17. package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +6 -0
  18. package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +13 -1
  19. package/Libraries/Components/StatusBar/StatusBar.js +1 -21
  20. package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +0 -15
  21. package/Libraries/Components/TextInput/InputAccessoryView.js +10 -1
  22. package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +0 -12
  23. package/Libraries/Components/TextInput/TextInput.d.ts +0 -19
  24. package/Libraries/Components/TextInput/TextInput.js +14 -70
  25. package/Libraries/Components/TextInput/TextInput.win32.js +15 -72
  26. package/Libraries/Components/Touchable/Touchable.js +2 -2
  27. package/Libraries/Components/Touchable/TouchableHighlight.d.ts +4 -10
  28. package/Libraries/Components/Touchable/TouchableHighlight.js +3 -1
  29. package/Libraries/Components/Touchable/TouchableOpacity.d.ts +4 -32
  30. package/Libraries/Components/Touchable/TouchableOpacity.js +3 -1
  31. package/Libraries/Components/Touchable/TouchableWithoutFeedback.d.ts +8 -0
  32. package/Libraries/Components/Touchable/TouchableWithoutFeedback.js +117 -111
  33. package/Libraries/Components/View/ReactNativeStyleAttributes.js +6 -0
  34. package/Libraries/Components/View/ReactNativeViewAttributes.js +1 -0
  35. package/Libraries/Components/View/ReactNativeViewAttributes.win32.js +1 -0
  36. package/Libraries/Components/View/View.js +0 -11
  37. package/Libraries/Components/View/View.win32.js +0 -11
  38. package/Libraries/Components/View/ViewAccessibility.js +4 -4
  39. package/Libraries/Components/View/ViewAccessibility.win32.js +6 -6
  40. package/Libraries/Components/View/ViewPropTypes.d.ts +7 -49
  41. package/Libraries/Components/View/ViewPropTypes.js +7 -0
  42. package/Libraries/Components/View/ViewPropTypes.win32.js +7 -0
  43. package/Libraries/Core/Devtools/loadBundleFromServer.js +3 -3
  44. package/Libraries/Core/Devtools/loadBundleFromServer.win32.js +153 -0
  45. package/Libraries/Core/Devtools/parseErrorStack.js +5 -5
  46. package/Libraries/Core/Devtools/parseHermesStack.js +22 -16
  47. package/Libraries/Core/ErrorHandlers.js +116 -0
  48. package/Libraries/Core/ExceptionsManager.js +2 -2
  49. package/Libraries/Core/ReactNativeVersion.js +3 -3
  50. package/Libraries/Core/setUpDeveloperTools.js +3 -1
  51. package/Libraries/Core/setUpPerformance.js +6 -4
  52. package/Libraries/Core/setUpReactDevTools.js +70 -10
  53. package/Libraries/Core/setUpTimers.js +50 -31
  54. package/Libraries/Debugging/DebuggingOverlayRegistry.js +1 -1
  55. package/Libraries/Image/Image.android.js +23 -13
  56. package/Libraries/Image/Image.d.ts +14 -15
  57. package/Libraries/Image/Image.ios.js +21 -11
  58. package/Libraries/Image/Image.win32.js +5 -3
  59. package/Libraries/Image/ImageProps.js +16 -5
  60. package/Libraries/Image/ImageTypes.flow.js +7 -2
  61. package/Libraries/Image/ImageUtils.js +1 -0
  62. package/Libraries/Image/ImageViewNativeComponent.js +2 -1
  63. package/Libraries/Inspector/ElementBox.js +6 -3
  64. package/Libraries/Inspector/ElementProperties.js +1 -1
  65. package/Libraries/Interaction/TouchHistoryMath.js +4 -4
  66. package/Libraries/IntersectionObserver/IntersectionObserverManager.js +6 -26
  67. package/Libraries/JSInspector/NetworkAgent.js +1 -1
  68. package/Libraries/LogBox/Data/LogBoxData.js +39 -29
  69. package/Libraries/LogBox/Data/LogBoxLog.js +114 -2
  70. package/Libraries/LogBox/Data/parseLogBoxLog.js +168 -53
  71. package/Libraries/LogBox/LogBox.js +29 -12
  72. package/Libraries/LogBox/LogBoxNotificationContainer.js +4 -0
  73. package/Libraries/LogBox/UI/LogBoxInspector.js +8 -70
  74. package/Libraries/LogBox/UI/LogBoxInspectorBody.js +87 -0
  75. package/Libraries/LogBox/UI/LogBoxInspectorFooter.js +6 -42
  76. package/Libraries/LogBox/UI/LogBoxInspectorFooterButton.js +58 -0
  77. package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +5 -66
  78. package/Libraries/LogBox/UI/LogBoxInspectorHeader.win32.js +8 -52
  79. package/Libraries/LogBox/UI/LogBoxInspectorHeaderButton.js +76 -0
  80. package/Libraries/LogBox/UI/LogBoxInspectorReactFrames.js +8 -5
  81. package/Libraries/LogBox/UI/LogBoxInspectorReactFrames.win32.js +8 -5
  82. package/Libraries/LogBox/UI/LogBoxNotification.js +13 -152
  83. package/Libraries/LogBox/UI/LogBoxNotificationCountBadge.js +63 -0
  84. package/Libraries/LogBox/UI/LogBoxNotificationDismissButton.js +67 -0
  85. package/Libraries/LogBox/UI/LogBoxNotificationMessage.js +57 -0
  86. package/Libraries/NativeComponent/BaseViewConfig.android.js +5 -0
  87. package/Libraries/NativeComponent/BaseViewConfig.ios.js +5 -0
  88. package/Libraries/NativeComponent/BaseViewConfig.win32.js +5 -0
  89. package/Libraries/NativeComponent/NativeComponentRegistry.js +12 -5
  90. package/Libraries/NativeComponent/StaticViewConfigValidator.js +3 -0
  91. package/Libraries/Network/XMLHttpRequest.js +5 -1
  92. package/Libraries/NewAppScreen/components/LearnMoreLinks.js +3 -3
  93. package/Libraries/Pressability/Pressability.js +3 -51
  94. package/Libraries/Pressability/Pressability.win32.js +3 -51
  95. package/Libraries/ReactNative/AppContainer-dev.js +3 -2
  96. package/Libraries/ReactNative/AppContainer-prod.js +2 -1
  97. package/Libraries/ReactNative/AppContainer.js +2 -0
  98. package/Libraries/ReactNative/AppRegistry.d.ts +7 -0
  99. package/Libraries/ReactNative/AppRegistry.js +10 -4
  100. package/Libraries/ReactNative/BridgelessUIManager.js +1 -21
  101. package/Libraries/ReactNative/FabricUIManager.js +0 -51
  102. package/Libraries/ReactNative/ReactFabricPublicInstance/warnForStyleProps.js +1 -0
  103. package/Libraries/ReactNative/RendererImplementation.js +20 -2
  104. package/Libraries/ReactNative/UIManager.d.ts +0 -21
  105. package/Libraries/ReactNative/UIManagerProperties.js +0 -3
  106. package/Libraries/ReactNative/__mocks__/FabricUIManager.js +5 -341
  107. package/Libraries/ReactNative/getNativeComponentAttributes.js +8 -8
  108. package/Libraries/ReactNative/renderApplication.js +3 -0
  109. package/Libraries/Renderer/implementations/ReactFabric-dev.js +15682 -27088
  110. package/Libraries/Renderer/implementations/ReactFabric-prod.js +5082 -4381
  111. package/Libraries/Renderer/implementations/ReactFabric-profiling.js +3480 -2571
  112. package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +15943 -27543
  113. package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +5303 -4606
  114. package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +3450 -2572
  115. package/Libraries/Renderer/shims/ReactFabric.js +2 -2
  116. package/Libraries/Renderer/shims/ReactFeatureFlags.js +2 -2
  117. package/Libraries/Renderer/shims/ReactNative.js +2 -3
  118. package/Libraries/Renderer/shims/ReactNativeTypes.js +24 -3
  119. package/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +2 -2
  120. package/Libraries/Renderer/shims/createReactNativeComponentClass.js +2 -2
  121. package/Libraries/Share/Share.d.ts +16 -10
  122. package/Libraries/Share/Share.js +14 -15
  123. package/Libraries/StyleSheet/StyleSheet.d.ts +1 -1
  124. package/Libraries/StyleSheet/StyleSheet.js +3 -10
  125. package/Libraries/StyleSheet/StyleSheet.win32.js +3 -10
  126. package/Libraries/StyleSheet/StyleSheetTypes.d.ts +21 -21
  127. package/Libraries/StyleSheet/StyleSheetTypes.js +24 -18
  128. package/Libraries/StyleSheet/flattenStyle.js +1 -0
  129. package/Libraries/StyleSheet/processFilter.js +132 -0
  130. package/Libraries/StyleSheet/processTransform.js +18 -3
  131. package/Libraries/Text/Text.js +151 -128
  132. package/Libraries/Text/Text.win32.js +163 -138
  133. package/Libraries/Text/TextNativeComponent.js +5 -4
  134. package/Libraries/Text/TextNativeComponent.win32.js +5 -4
  135. package/Libraries/Text/TextProps.js +6 -6
  136. package/Libraries/Text/TextProps.win32.js +6 -6
  137. package/Libraries/TurboModule/TurboModuleRegistry.js +2 -1
  138. package/Libraries/Types/CodegenTypes.js +3 -0
  139. package/Libraries/Utilities/{LoadingView.android.js → DevLoadingView.js} +33 -11
  140. package/Libraries/Utilities/Dimensions.js +1 -0
  141. package/Libraries/Utilities/Dimensions.win32.js +1 -0
  142. package/Libraries/Utilities/HMRClient.js +36 -8
  143. package/Libraries/Utilities/HMRClientProdShim.js +1 -0
  144. package/Libraries/Utilities/Platform.android.js +5 -5
  145. package/Libraries/Utilities/Platform.d.ts +1 -1
  146. package/Libraries/Utilities/Platform.flow.js +2 -2
  147. package/Libraries/Utilities/Platform.flow.win32.js +3 -3
  148. package/Libraries/Utilities/Platform.ios.js +1 -1
  149. package/Libraries/Utilities/Platform.win32.js +1 -1
  150. package/Libraries/Utilities/RCTLog.js +1 -0
  151. package/Libraries/Utilities/ReactNativeTestTools.js +12 -24
  152. package/Libraries/Utilities/verifyComponentAttributeEquivalence.js +11 -6
  153. package/Libraries/__tests__/ButtonWin32-test.js +7 -6
  154. package/Libraries/promiseRejectionTrackingOptions.js +1 -0
  155. package/jest/mockComponent.js +7 -0
  156. package/jest/renderer.js +25 -14
  157. package/jest/setup.js +19 -13
  158. package/jest.config.js +2 -1
  159. package/overrides.json +32 -31
  160. package/package.json +27 -25
  161. package/rn-get-polyfills.js +1 -0
  162. package/src/private/core/composeStyles.js +27 -0
  163. package/src/private/featureflags/ReactNativeFeatureFlags.js +93 -33
  164. package/src/private/featureflags/ReactNativeFeatureFlagsBase.js +23 -4
  165. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +56 -0
  166. package/src/private/fusebox/setUpFuseboxReactDevToolsDispatcher.js +108 -0
  167. package/src/private/specs/modules/NativeBlobModule.js +4 -2
  168. package/src/private/specs/modules/NativeDevSettings.js +1 -0
  169. package/src/private/specs/modules/NativePlatformConstantsAndroid.js +1 -1
  170. package/src/private/specs/modules/NativePlatformConstantsIOS.js +1 -1
  171. package/src/private/specs/modules/NativePlatformConstantsWin.js +1 -1
  172. package/src/private/specs/modules/NativePushNotificationManagerIOS.js +0 -4
  173. package/src/private/specs/modules/NativeUIManager.js +0 -7
  174. package/src/private/webapis/dom/geometry/DOMRectReadOnly.js +24 -24
  175. package/src/private/webapis/dom/nodes/ReactNativeElement.js +11 -14
  176. package/src/private/webapis/dom/nodes/ReadOnlyCharacterData.js +2 -3
  177. package/src/private/webapis/dom/nodes/ReadOnlyElement.js +24 -54
  178. package/src/private/webapis/dom/nodes/ReadOnlyNode.js +5 -13
  179. package/src/private/webapis/dom/nodes/specs/NativeDOM.js +468 -0
  180. package/src/private/webapis/dom/nodes/specs/__mocks__/NativeDOMMock.js +413 -0
  181. package/src/private/webapis/dom/oldstylecollections/DOMRectList.js +4 -4
  182. package/src/private/webapis/dom/oldstylecollections/HTMLCollection.js +4 -4
  183. package/src/private/webapis/dom/oldstylecollections/NodeList.js +5 -5
  184. package/src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks.js +34 -0
  185. package/src/private/webapis/microtasks/specs/NativeMicrotasks.js +21 -0
  186. package/src/private/webapis/performance/EventCounts.js +1 -1
  187. package/src/private/webapis/performance/MemoryInfo.js +9 -9
  188. package/src/private/webapis/performance/Performance.js +10 -56
  189. package/src/private/webapis/performance/PerformanceObserver.js +30 -22
  190. package/src/private/webapis/performance/RawPerformanceEntry.js +2 -7
  191. package/src/private/webapis/performance/ReactNativeStartupTiming.js +18 -18
  192. package/src/private/webapis/performance/UserTiming.js +63 -0
  193. package/src/private/webapis/performance/{NativePerformance.js → specs/NativePerformance.js} +3 -2
  194. package/src/private/webapis/performance/{NativePerformanceObserver.js → specs/NativePerformanceObserver.js} +2 -2
  195. package/src/private/webapis/performance/{__mocks__ → specs/__mocks__}/NativePerformance.js +1 -1
  196. package/src/private/webapis/performance/{__mocks__ → specs/__mocks__}/NativePerformanceObserver.js +3 -4
  197. package/src-win/Libraries/Components/View/ViewPropTypes.d.ts +7 -49
  198. package/types/modules/globals.d.ts +4 -0
  199. package/Libraries/Components/ScrollView/ScrollView.win32.js +0 -1915
  200. package/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js +0 -13
  201. package/Libraries/Utilities/LoadingView.ios.js +0 -50
  202. package/Libraries/Utilities/LoadingView.js +0 -16
  203. package/jest/ReactNativeInternalFeatureFlagsMock.js +0 -13
  204. package/src/private/featureflags/NativeReactNativeFeatureFlags.js +0 -44
  205. package/src/private/featureflags/__tests__/ReactNativeFeatureFlags-test.js +0 -92
  206. package/src/private/specs/modules/NativeAnimationsDebugModule.js +0 -20
  207. package/src/private/webapis/dom/oldstylecollections/__tests__/DOMRectList-test.js +0 -85
  208. package/src/private/webapis/dom/oldstylecollections/__tests__/HTMLCollection-test.js +0 -80
  209. package/src/private/webapis/dom/oldstylecollections/__tests__/NodeList-test.js +0 -161
  210. package/src/private/webapis/performance/__tests__/EventCounts-test.js +0 -116
  211. package/src/private/webapis/performance/__tests__/NativePerformanceMock-test.js +0 -82
  212. package/src/private/webapis/performance/__tests__/NativePerformanceObserverMock-test.js +0 -108
  213. package/src/private/webapis/performance/__tests__/Performance-test.js +0 -117
  214. package/src/private/webapis/performance/__tests__/PerformanceObserver-test.js +0 -208
@@ -8,30 +8,32 @@
8
8
  * @format
9
9
  */
10
10
 
11
- ('use strict');
12
-
13
11
  import type {ExtendedError} from '../../Core/ExtendedError';
14
12
  import type {LogLevel} from './LogBoxLog';
15
13
  import type {
16
14
  Category,
17
15
  ComponentStack,
16
+ ComponentStackType,
18
17
  ExtendedExceptionData,
19
18
  Message,
20
19
  } from './parseLogBoxLog';
21
20
 
22
21
  import parseErrorStack from '../../Core/Devtools/parseErrorStack';
22
+ import NativeDevSettings from '../../NativeModules/specs/NativeDevSettings';
23
23
  import NativeLogBox from '../../NativeModules/specs/NativeLogBox';
24
24
  import LogBoxLog from './LogBoxLog';
25
25
  import {parseLogBoxException} from './parseLogBoxLog';
26
26
  import * as React from 'react';
27
+
27
28
  export type LogBoxLogs = Set<LogBoxLog>;
28
- export type LogData = $ReadOnly<{|
29
+ export type LogData = $ReadOnly<{
29
30
  level: LogLevel,
30
31
  message: Message,
31
32
  category: Category,
32
33
  componentStack: ComponentStack,
34
+ componentStackType: ComponentStackType | null,
33
35
  stack?: string,
34
- |}>;
36
+ }>;
35
37
 
36
38
  export type Observer = (
37
39
  $ReadOnly<{|
@@ -72,6 +74,7 @@ let logs: LogBoxLogs = new Set();
72
74
  let updateTimeout: $FlowFixMe | null = null;
73
75
  let _isDisabled = false;
74
76
  let _selectedIndex = -1;
77
+ let hasShownFuseboxWarningsMigrationMessage = false;
75
78
 
76
79
  let warningFilter: WarningFilter = function (format) {
77
80
  return {
@@ -193,6 +196,11 @@ function appendNewLog(newLog: LogBoxLog) {
193
196
  }
194
197
 
195
198
  export function addLog(log: LogData): void {
199
+ if (log.level === 'warn' && global.__FUSEBOX_HAS_FULL_CONSOLE_SUPPORT__) {
200
+ // Under Fusebox, don't report warnings to LogBox.
201
+ showFuseboxWarningsMigrationMessageOnce();
202
+ return;
203
+ }
196
204
  const errorForStackTrace = new Error();
197
205
 
198
206
  // Parsing logs are expensive so we schedule this
@@ -209,6 +217,7 @@ export function addLog(log: LogData): void {
209
217
  stack,
210
218
  category: log.category,
211
219
  componentStack: log.componentStack,
220
+ componentStackType: log.componentStackType || 'legacy',
212
221
  }),
213
222
  );
214
223
  } catch (error) {
@@ -449,32 +458,33 @@ export function withSubscription(
449
458
  this._subscription.unsubscribe();
450
459
  }
451
460
  }
452
-
453
- _handleDismiss = (): void => {
454
- // Here we handle the cases when the log is dismissed and it
455
- // was either the last log, or when the current index
456
- // is now outside the bounds of the log array.
457
- const {selectedLogIndex, logs: stateLogs} = this.state;
458
- const logsArray = Array.from(stateLogs);
459
- if (selectedLogIndex != null) {
460
- if (logsArray.length - 1 <= 0) {
461
- setSelectedLog(-1);
462
- } else if (selectedLogIndex >= logsArray.length - 1) {
463
- setSelectedLog(selectedLogIndex - 1);
464
- }
465
-
466
- dismiss(logsArray[selectedLogIndex]);
467
- }
468
- };
469
-
470
- _handleMinimize = (): void => {
471
- setSelectedLog(-1);
472
- };
473
-
474
- _handleSetSelectedLog = (index: number): void => {
475
- setSelectedLog(index);
476
- };
477
461
  }
478
462
 
479
463
  return LogBoxStateSubscription;
480
464
  }
465
+
466
+ function showFuseboxWarningsMigrationMessageOnce() {
467
+ if (hasShownFuseboxWarningsMigrationMessage) {
468
+ return;
469
+ }
470
+ hasShownFuseboxWarningsMigrationMessage = true;
471
+ appendNewLog(
472
+ new LogBoxLog({
473
+ level: 'warn',
474
+ message: {
475
+ content: 'Open debugger to view warnings.',
476
+ substitutions: [],
477
+ },
478
+ isComponentError: false,
479
+ stack: [],
480
+ category: 'fusebox-warnings-migration',
481
+ componentStack: [],
482
+ onNotificationPress: () => {
483
+ if (NativeDevSettings.openDebugger) {
484
+ NativeDevSettings.openDebugger();
485
+ }
486
+ clearWarnings();
487
+ },
488
+ }),
489
+ );
490
+ }
@@ -13,6 +13,7 @@ import type {
13
13
  Category,
14
14
  CodeFrame,
15
15
  ComponentStack,
16
+ ComponentStackType,
16
17
  Message,
17
18
  } from './parseLogBoxLog';
18
19
 
@@ -22,23 +23,58 @@ type SymbolicationStatus = 'NONE' | 'PENDING' | 'COMPLETE' | 'FAILED';
22
23
 
23
24
  export type LogLevel = 'warn' | 'error' | 'fatal' | 'syntax';
24
25
 
25
- export type LogBoxLogData = $ReadOnly<{|
26
+ // TODO: once component stacks are fully supported, we can refactor
27
+ // ComponentStack to just be Stack and remove these conversions fns.
28
+ function convertComponentStateToStack(componentStack: ComponentStack): Stack {
29
+ return componentStack.map(frame => ({
30
+ column: frame?.location?.column,
31
+ file: frame.fileName,
32
+ lineNumber: frame?.location?.row,
33
+ methodName: frame.content,
34
+ collapse: false,
35
+ }));
36
+ }
37
+
38
+ function convertStackToComponentStack(stack: Stack): ComponentStack {
39
+ const componentStack = [];
40
+ for (let i = 0; i < stack.length; i++) {
41
+ const frame = stack[i];
42
+ // NOTE: Skip stack frames missing location.
43
+ if (frame.lineNumber != null && frame.column != null) {
44
+ componentStack.push({
45
+ fileName: frame?.file || '',
46
+ location: {
47
+ row: frame.lineNumber,
48
+ column: frame.column,
49
+ },
50
+ content: frame.methodName,
51
+ collapse: false,
52
+ });
53
+ }
54
+ }
55
+ return componentStack;
56
+ }
57
+
58
+ export type LogBoxLogData = $ReadOnly<{
26
59
  level: LogLevel,
27
60
  type?: ?string,
28
61
  message: Message,
29
62
  stack: Stack,
30
63
  category: string,
64
+ componentStackType?: ComponentStackType,
31
65
  componentStack: ComponentStack,
32
66
  codeFrame?: ?CodeFrame,
33
67
  isComponentError: boolean,
34
68
  extraData?: mixed,
35
- |}>;
69
+ onNotificationPress?: ?() => void,
70
+ }>;
36
71
 
37
72
  class LogBoxLog {
38
73
  message: Message;
39
74
  type: ?string;
40
75
  category: Category;
41
76
  componentStack: ComponentStack;
77
+ componentStackType: ComponentStackType;
42
78
  stack: Stack;
43
79
  count: number;
44
80
  level: LogLevel;
@@ -54,6 +90,20 @@ class LogBoxLog {
54
90
  stack: null,
55
91
  status: 'NONE',
56
92
  };
93
+ symbolicatedComponentStack:
94
+ | $ReadOnly<{|error: null, componentStack: null, status: 'NONE'|}>
95
+ | $ReadOnly<{|error: null, componentStack: null, status: 'PENDING'|}>
96
+ | $ReadOnly<{|
97
+ error: null,
98
+ componentStack: ComponentStack,
99
+ status: 'COMPLETE',
100
+ |}>
101
+ | $ReadOnly<{|error: Error, componentStack: null, status: 'FAILED'|}> = {
102
+ error: null,
103
+ componentStack: null,
104
+ status: 'NONE',
105
+ };
106
+ onNotificationPress: ?() => void;
57
107
 
58
108
  constructor(data: LogBoxLogData) {
59
109
  this.level = data.level;
@@ -62,10 +112,12 @@ class LogBoxLog {
62
112
  this.stack = data.stack;
63
113
  this.category = data.category;
64
114
  this.componentStack = data.componentStack;
115
+ this.componentStackType = data.componentStackType || 'legacy';
65
116
  this.codeFrame = data.codeFrame;
66
117
  this.isComponentError = data.isComponentError;
67
118
  this.extraData = data.extraData;
68
119
  this.count = 1;
120
+ this.onNotificationPress = data.onNotificationPress;
69
121
  }
70
122
 
71
123
  incrementCount(): void {
@@ -78,6 +130,15 @@ class LogBoxLog {
78
130
  : this.stack;
79
131
  }
80
132
 
133
+ getAvailableComponentStack(): ComponentStack {
134
+ if (this.componentStackType === 'legacy') {
135
+ return this.componentStack;
136
+ }
137
+ return this.symbolicatedComponentStack.status === 'COMPLETE'
138
+ ? this.symbolicatedComponentStack.componentStack
139
+ : this.componentStack;
140
+ }
141
+
81
142
  retrySymbolicate(callback?: (status: SymbolicationStatus) => void): void {
82
143
  if (this.symbolicated.status !== 'COMPLETE') {
83
144
  LogBoxSymbolication.deleteStack(this.stack);
@@ -102,6 +163,25 @@ class LogBoxLog {
102
163
  this.updateStatus(error, null, null, callback);
103
164
  },
104
165
  );
166
+ if (this.componentStack != null && this.componentStackType === 'stack') {
167
+ this.updateComponentStackStatus(null, null, null, callback);
168
+ const componentStackFrames = convertComponentStateToStack(
169
+ this.componentStack,
170
+ );
171
+ LogBoxSymbolication.symbolicate(componentStackFrames, []).then(
172
+ data => {
173
+ this.updateComponentStackStatus(
174
+ null,
175
+ convertStackToComponentStack(data.stack),
176
+ null,
177
+ callback,
178
+ );
179
+ },
180
+ error => {
181
+ this.updateComponentStackStatus(error, null, null, callback);
182
+ },
183
+ );
184
+ }
105
185
  }
106
186
  }
107
187
 
@@ -140,6 +220,38 @@ class LogBoxLog {
140
220
  callback(this.symbolicated.status);
141
221
  }
142
222
  }
223
+
224
+ updateComponentStackStatus(
225
+ error: ?Error,
226
+ componentStack: ?ComponentStack,
227
+ codeFrame: ?CodeFrame,
228
+ callback?: (status: SymbolicationStatus) => void,
229
+ ): void {
230
+ const lastStatus = this.symbolicatedComponentStack.status;
231
+ if (error != null) {
232
+ this.symbolicatedComponentStack = {
233
+ error,
234
+ componentStack: null,
235
+ status: 'FAILED',
236
+ };
237
+ } else if (componentStack != null) {
238
+ this.symbolicatedComponentStack = {
239
+ error: null,
240
+ componentStack,
241
+ status: 'COMPLETE',
242
+ };
243
+ } else {
244
+ this.symbolicatedComponentStack = {
245
+ error: null,
246
+ componentStack: null,
247
+ status: 'PENDING',
248
+ };
249
+ }
250
+
251
+ if (callback && lastStatus !== this.symbolicatedComponentStack.status) {
252
+ callback(this.symbolicatedComponentStack.status);
253
+ }
254
+ }
143
255
  }
144
256
 
145
257
  export default LogBoxLog;
@@ -18,11 +18,62 @@ import ansiRegex from 'ansi-regex';
18
18
 
19
19
  const ANSI_REGEX = ansiRegex().source;
20
20
 
21
- const BABEL_TRANSFORM_ERROR_FORMAT =
21
+ const RE_TRANSFORM_ERROR = /^TransformError /;
22
+ const RE_COMPONENT_STACK_LINE = /\n {4}(in|at) /;
23
+ const RE_COMPONENT_STACK_LINE_GLOBAL = /\n {4}(in|at) /g;
24
+ const RE_COMPONENT_STACK_LINE_OLD = / {4}in/;
25
+ const RE_COMPONENT_STACK_LINE_NEW = / {4}at/;
26
+ const RE_COMPONENT_STACK_LINE_STACK_FRAME = /@.*\n/;
27
+
28
+ // "TransformError " (Optional) and either "SyntaxError: " or "ReferenceError: "
29
+ // Capturing groups:
30
+ // 1: error message
31
+ // 2: file path
32
+ // 3: line number
33
+ // 4: column number
34
+ // \n\n
35
+ // 5: code frame
36
+ const RE_BABEL_TRANSFORM_ERROR_FORMAT =
22
37
  /^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;
23
38
 
39
+ // Capturing groups:
40
+ // 1: component name
41
+ // "at"
42
+ // 2: file path including extension
43
+ // 3: line number
44
+ const RE_COMPONENT_STACK_WITH_SOURCE =
45
+ /(.*) \(at (.*\.(?:js|jsx|ts|tsx)):([\d]+)\)/;
46
+
47
+ // Capturing groups:
48
+ // 1: component name
49
+ // "at"
50
+ // 2: parent component name
51
+ const RE_COMPONENT_STACK_NO_SOURCE = /(.*) \(created by .*\)/;
52
+
53
+ // Capturing groups:
54
+ // - non-capturing "TransformError " (optional)
55
+ // - non-capturing Error message
56
+ // 1: file path
57
+ // 2: file name
58
+ // 3: error message
59
+ // 4: code frame, which includes code snippet indicators or terminal escape sequences for formatting.
60
+ const RE_BABEL_CODE_FRAME_ERROR_FORMAT =
61
+ // eslint-disable-next-line no-control-regex
62
+ /^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;
63
+
64
+ // Capturing groups:
65
+ // - non-capturing "InternalError Metro has encountered an error:"
66
+ // 1: error title
67
+ // 2: error message
68
+ // 3: file path
69
+ // 4: line number
70
+ // 5: column number
71
+ // 6: code frame, which includes code snippet indicators or terminal escape sequences for formatting.
72
+ const RE_METRO_ERROR_FORMAT =
73
+ /^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;
74
+
24
75
  // https://github.com/babel/babel/blob/33dbb85e9e9fe36915273080ecc42aee62ed0ade/packages/babel-code-frame/src/index.ts#L183-L184
25
- const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
76
+ const RE_BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
26
77
  [
27
78
  // Beginning of a line (per 'm' flag)
28
79
  '^',
@@ -42,12 +93,14 @@ const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
42
93
  'm',
43
94
  );
44
95
 
45
- const BABEL_CODE_FRAME_ERROR_FORMAT =
46
- // eslint-disable-next-line no-control-regex
47
- /^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;
48
-
49
- const METRO_ERROR_FORMAT =
50
- /^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;
96
+ export function hasComponentStack(args: $ReadOnlyArray<mixed>): boolean {
97
+ for (const arg of args) {
98
+ if (typeof arg === 'string' && isComponentStack(arg)) {
99
+ return true;
100
+ }
101
+ }
102
+ return false;
103
+ }
51
104
 
52
105
  export type ExtendedExceptionData = ExceptionData & {
53
106
  isComponentError: boolean,
@@ -79,6 +132,7 @@ export type Message = $ReadOnly<{|
79
132
  |}>;
80
133
 
81
134
  export type ComponentStack = $ReadOnlyArray<CodeFrame>;
135
+ export type ComponentStackType = 'legacy' | 'stack';
82
136
 
83
137
  const SUBSTITUTION = UTFSequence.BOM + '%s';
84
138
 
@@ -158,9 +212,12 @@ export function parseInterpolation(args: $ReadOnlyArray<mixed>): $ReadOnly<{|
158
212
  }
159
213
 
160
214
  function isComponentStack(consoleArgument: string) {
161
- const isOldComponentStackFormat = / {4}in/.test(consoleArgument);
162
- const isNewComponentStackFormat = / {4}at/.test(consoleArgument);
163
- const isNewJSCComponentStackFormat = /@.*\n/.test(consoleArgument);
215
+ const isOldComponentStackFormat =
216
+ RE_COMPONENT_STACK_LINE_OLD.test(consoleArgument);
217
+ const isNewComponentStackFormat =
218
+ RE_COMPONENT_STACK_LINE_NEW.test(consoleArgument);
219
+ const isNewJSCComponentStackFormat =
220
+ RE_COMPONENT_STACK_LINE_STACK_FRAME.test(consoleArgument);
164
221
 
165
222
  return (
166
223
  isOldComponentStackFormat ||
@@ -169,42 +226,62 @@ function isComponentStack(consoleArgument: string) {
169
226
  );
170
227
  }
171
228
 
172
- export function parseComponentStack(message: string): ComponentStack {
229
+ export function parseComponentStack(message: string): {
230
+ type: ComponentStackType,
231
+ stack: ComponentStack,
232
+ } {
173
233
  // In newer versions of React, the component stack is formatted as a call stack frame.
174
234
  // First try to parse the component stack as a call stack frame, and if that doesn't
175
235
  // work then we'll fallback to the old custom component stack format parsing.
176
236
  const stack = parseErrorStack(message);
177
237
  if (stack && stack.length > 0) {
178
- return stack.map(frame => ({
179
- content: frame.methodName,
180
- collapse: frame.collapse || false,
181
- fileName: frame.file == null ? 'unknown' : frame.file,
182
- location: {
183
- column: frame.column == null ? -1 : frame.column,
184
- row: frame.lineNumber == null ? -1 : frame.lineNumber,
185
- },
186
- }));
238
+ return {
239
+ type: 'stack',
240
+ stack: stack.map(frame => ({
241
+ content: frame.methodName,
242
+ collapse: frame.collapse || false,
243
+ fileName: frame.file == null ? 'unknown' : frame.file,
244
+ location: {
245
+ column: frame.column == null ? -1 : frame.column,
246
+ row: frame.lineNumber == null ? -1 : frame.lineNumber,
247
+ },
248
+ })),
249
+ };
187
250
  }
188
-
189
- return message
190
- .split(/\n {4}in /g)
251
+ const legacyStack = message
252
+ .split(RE_COMPONENT_STACK_LINE_GLOBAL)
191
253
  .map(s => {
192
254
  if (!s) {
193
255
  return null;
194
256
  }
195
- const match = s.match(/(.*) \(at (.*\.(?:js|jsx|ts|tsx)):([\d]+)\)/);
196
- if (!match) {
197
- return null;
257
+ const match = s.match(RE_COMPONENT_STACK_WITH_SOURCE);
258
+ if (match) {
259
+ let [content, fileName, row] = match.slice(1);
260
+ return {
261
+ content,
262
+ fileName,
263
+ location: {column: -1, row: parseInt(row, 10)},
264
+ };
198
265
  }
199
266
 
200
- let [content, fileName, row] = match.slice(1);
201
- return {
202
- content,
203
- fileName,
204
- location: {column: -1, row: parseInt(row, 10)},
205
- };
267
+ // In some cases, the component stack doesn't have a source.
268
+ const matchWithoutSource = s.match(RE_COMPONENT_STACK_NO_SOURCE);
269
+ if (matchWithoutSource) {
270
+ return {
271
+ content: matchWithoutSource[1],
272
+ fileName: '',
273
+ location: null,
274
+ };
275
+ }
276
+
277
+ return null;
206
278
  })
207
279
  .filter(Boolean);
280
+
281
+ return {
282
+ type: 'legacy',
283
+ stack: legacyStack,
284
+ };
208
285
  }
209
286
 
210
287
  export function parseLogBoxException(
@@ -213,7 +290,7 @@ export function parseLogBoxException(
213
290
  const message =
214
291
  error.originalMessage != null ? error.originalMessage : 'Unknown';
215
292
 
216
- const metroInternalError = message.match(METRO_ERROR_FORMAT);
293
+ const metroInternalError = message.match(RE_METRO_ERROR_FORMAT);
217
294
  if (metroInternalError) {
218
295
  const [content, fileName, row, column, codeFrame] =
219
296
  metroInternalError.slice(1);
@@ -223,6 +300,7 @@ export function parseLogBoxException(
223
300
  type: 'Metro Error',
224
301
  stack: [],
225
302
  isComponentError: false,
303
+ componentStackType: 'legacy',
226
304
  componentStack: [],
227
305
  codeFrame: {
228
306
  fileName,
@@ -241,7 +319,7 @@ export function parseLogBoxException(
241
319
  };
242
320
  }
243
321
 
244
- const babelTransformError = message.match(BABEL_TRANSFORM_ERROR_FORMAT);
322
+ const babelTransformError = message.match(RE_BABEL_TRANSFORM_ERROR_FORMAT);
245
323
  if (babelTransformError) {
246
324
  // Transform errors are thrown from inside the Babel transformer.
247
325
  const [fileName, content, row, column, codeFrame] =
@@ -251,6 +329,7 @@ export function parseLogBoxException(
251
329
  level: 'syntax',
252
330
  stack: [],
253
331
  isComponentError: false,
332
+ componentStackType: 'legacy',
254
333
  componentStack: [],
255
334
  codeFrame: {
256
335
  fileName,
@@ -271,8 +350,8 @@ export function parseLogBoxException(
271
350
 
272
351
  // Perform a cheap match first before trying to parse the full message, which
273
352
  // can get expensive for arbitrary input.
274
- if (BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
275
- const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
353
+ if (RE_BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
354
+ const babelCodeFrameError = message.match(RE_BABEL_CODE_FRAME_ERROR_FORMAT);
276
355
 
277
356
  if (babelCodeFrameError) {
278
357
  // Codeframe errors are thrown from any use of buildCodeFrameError.
@@ -281,6 +360,7 @@ export function parseLogBoxException(
281
360
  level: 'syntax',
282
361
  stack: [],
283
362
  isComponentError: false,
363
+ componentStackType: 'legacy',
284
364
  componentStack: [],
285
365
  codeFrame: {
286
366
  fileName,
@@ -297,11 +377,12 @@ export function parseLogBoxException(
297
377
  }
298
378
  }
299
379
 
300
- if (message.match(/^TransformError /)) {
380
+ if (message.match(RE_TRANSFORM_ERROR)) {
301
381
  return {
302
382
  level: 'syntax',
303
383
  stack: error.stack,
304
384
  isComponentError: error.isComponentError,
385
+ componentStackType: 'legacy',
305
386
  componentStack: [],
306
387
  message: {
307
388
  content: message,
@@ -314,24 +395,39 @@ export function parseLogBoxException(
314
395
 
315
396
  const componentStack = error.componentStack;
316
397
  if (error.isFatal || error.isComponentError) {
317
- return {
318
- level: 'fatal',
319
- stack: error.stack,
320
- isComponentError: error.isComponentError,
321
- componentStack:
322
- componentStack != null ? parseComponentStack(componentStack) : [],
323
- extraData: error.extraData,
324
- ...parseInterpolation([message]),
325
- };
398
+ if (componentStack != null) {
399
+ const {type, stack} = parseComponentStack(componentStack);
400
+ return {
401
+ level: 'fatal',
402
+ stack: error.stack,
403
+ isComponentError: error.isComponentError,
404
+ componentStackType: type,
405
+ componentStack: stack,
406
+ extraData: error.extraData,
407
+ ...parseInterpolation([message]),
408
+ };
409
+ } else {
410
+ return {
411
+ level: 'fatal',
412
+ stack: error.stack,
413
+ isComponentError: error.isComponentError,
414
+ componentStackType: 'legacy',
415
+ componentStack: [],
416
+ extraData: error.extraData,
417
+ ...parseInterpolation([message]),
418
+ };
419
+ }
326
420
  }
327
421
 
328
422
  if (componentStack != null) {
329
423
  // It is possible that console errors have a componentStack.
424
+ const {type, stack} = parseComponentStack(componentStack);
330
425
  return {
331
426
  level: 'error',
332
427
  stack: error.stack,
333
428
  isComponentError: error.isComponentError,
334
- componentStack: parseComponentStack(componentStack),
429
+ componentStackType: type,
430
+ componentStack: stack,
335
431
  extraData: error.extraData,
336
432
  ...parseInterpolation([message]),
337
433
  };
@@ -348,14 +444,28 @@ export function parseLogBoxException(
348
444
  };
349
445
  }
350
446
 
447
+ export function withoutANSIColorStyles(message: mixed): mixed {
448
+ if (typeof message !== 'string') {
449
+ return message;
450
+ }
451
+
452
+ return message.replace(
453
+ // eslint-disable-next-line no-control-regex
454
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
455
+ '',
456
+ );
457
+ }
458
+
351
459
  export function parseLogBoxLog(args: $ReadOnlyArray<mixed>): {|
352
460
  componentStack: ComponentStack,
461
+ componentStackType: ComponentStackType,
353
462
  category: Category,
354
463
  message: Message,
355
464
  |} {
356
- const message = args[0];
465
+ const message = withoutANSIColorStyles(args[0]);
357
466
  let argsWithoutComponentStack: Array<mixed> = [];
358
467
  let componentStack: ComponentStack = [];
468
+ let componentStackType = 'legacy';
359
469
 
360
470
  // Extract component stack from warnings like "Some warning%s".
361
471
  if (
@@ -367,16 +477,18 @@ export function parseLogBoxLog(args: $ReadOnlyArray<mixed>): {|
367
477
  if (typeof lastArg === 'string' && isComponentStack(lastArg)) {
368
478
  argsWithoutComponentStack = args.slice(0, -1);
369
479
  argsWithoutComponentStack[0] = message.slice(0, -2);
370
- componentStack = parseComponentStack(lastArg);
480
+ const {type, stack} = parseComponentStack(lastArg);
481
+ componentStack = stack;
482
+ componentStackType = type;
371
483
  }
372
484
  }
373
485
 
374
- if (componentStack.length === 0) {
486
+ if (componentStack.length === 0 && argsWithoutComponentStack.length === 0) {
375
487
  // Try finding the component stack elsewhere.
376
488
  for (const arg of args) {
377
489
  if (typeof arg === 'string' && isComponentStack(arg)) {
378
490
  // Strip out any messages before the component stack.
379
- let messageEndIndex = arg.search(/\n {4}(in|at) /);
491
+ let messageEndIndex = arg.search(RE_COMPONENT_STACK_LINE);
380
492
  if (messageEndIndex < 0) {
381
493
  // Handle JSC component stacks.
382
494
  messageEndIndex = arg.search(/\n/);
@@ -385,7 +497,9 @@ export function parseLogBoxLog(args: $ReadOnlyArray<mixed>): {|
385
497
  argsWithoutComponentStack.push(arg.slice(0, messageEndIndex));
386
498
  }
387
499
 
388
- componentStack = parseComponentStack(arg);
500
+ const {type, stack} = parseComponentStack(arg);
501
+ componentStack = stack;
502
+ componentStackType = type;
389
503
  } else {
390
504
  argsWithoutComponentStack.push(arg);
391
505
  }
@@ -395,5 +509,6 @@ export function parseLogBoxLog(args: $ReadOnlyArray<mixed>): {|
395
509
  return {
396
510
  ...parseInterpolation(argsWithoutComponentStack),
397
511
  componentStack,
512
+ componentStackType,
398
513
  };
399
514
  }