@expo/metro-runtime 3.0.1 → 3.0.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 (112) hide show
  1. package/build/LoadingView.d.ts +6 -0
  2. package/build/LoadingView.d.ts.map +1 -1
  3. package/build/LoadingView.js +9 -3
  4. package/build/LoadingView.js.map +1 -1
  5. package/build/async-require/fetchAsync.d.ts +6 -0
  6. package/build/async-require/fetchAsync.d.ts.map +1 -1
  7. package/build/async-require/fetchAsync.js +1 -2
  8. package/build/async-require/fetchAsync.js.map +1 -1
  9. package/build/async-require/fetchThenEval.d.ts +1 -6
  10. package/build/async-require/fetchThenEval.d.ts.map +1 -1
  11. package/build/async-require/fetchThenEval.js +2 -32
  12. package/build/async-require/fetchThenEval.js.map +1 -1
  13. package/build/async-require/fetchThenEval.web.js +1 -1
  14. package/build/async-require/fetchThenEval.web.js.map +1 -1
  15. package/build/async-require/fetchThenEvalJs.d.ts +7 -0
  16. package/build/async-require/fetchThenEvalJs.d.ts.map +1 -0
  17. package/build/async-require/fetchThenEvalJs.js +36 -0
  18. package/build/async-require/fetchThenEvalJs.js.map +1 -0
  19. package/build/async-require/index.native.d.ts +7 -0
  20. package/build/async-require/index.native.d.ts.map +1 -0
  21. package/build/async-require/index.native.js +14 -0
  22. package/build/async-require/index.native.js.map +1 -0
  23. package/build/effects.d.ts +0 -1
  24. package/build/effects.js +1 -6
  25. package/build/effects.js.map +1 -1
  26. package/build/error-overlay/Data/parseLogBoxLog.d.ts.map +1 -1
  27. package/build/error-overlay/Data/parseLogBoxLog.js +1 -2
  28. package/build/error-overlay/Data/parseLogBoxLog.js.map +1 -1
  29. package/build/error-overlay/LogBox.web.d.ts.map +1 -1
  30. package/build/error-overlay/LogBox.web.js +1 -2
  31. package/build/error-overlay/LogBox.web.js.map +1 -1
  32. package/build/error-overlay/index.d.ts.map +1 -1
  33. package/build/error-overlay/index.js +1 -0
  34. package/build/error-overlay/index.js.map +1 -1
  35. package/build/getDevServer.d.ts.map +1 -1
  36. package/build/getDevServer.js +2 -6
  37. package/build/getDevServer.js.map +1 -1
  38. package/build/index.d.ts +8 -0
  39. package/build/index.d.ts.map +1 -1
  40. package/build/index.js +10 -8
  41. package/build/index.js.map +1 -1
  42. package/build/setupHMR.js +21 -24
  43. package/build/setupHMR.js.map +1 -1
  44. package/package.json +5 -2
  45. package/src/HMRClient.native.ts +3 -0
  46. package/src/HMRClient.ts +316 -0
  47. package/src/LoadingView.native.ts +3 -0
  48. package/src/LoadingView.ts +24 -0
  49. package/src/__mocks__/LoadingView.ts +4 -0
  50. package/src/async-require/buildAsyncRequire.ts +34 -0
  51. package/src/async-require/buildUrlForBundle.native.ts +28 -0
  52. package/src/async-require/buildUrlForBundle.ts +18 -0
  53. package/src/async-require/fetchAsync.native.ts +72 -0
  54. package/src/async-require/fetchAsync.ts +19 -0
  55. package/src/async-require/fetchThenEval.ts +1 -0
  56. package/src/async-require/fetchThenEval.web.ts +70 -0
  57. package/src/async-require/fetchThenEvalJs.ts +39 -0
  58. package/src/async-require/index.native.ts +15 -0
  59. package/src/async-require/index.ts +10 -0
  60. package/src/async-require/loadBundle.ts +46 -0
  61. package/src/effects.native.ts +0 -0
  62. package/src/effects.ts +11 -0
  63. package/src/error-overlay/Data/LogBoxData.tsx +438 -0
  64. package/src/error-overlay/Data/LogBoxLog.ts +221 -0
  65. package/src/error-overlay/Data/LogBoxSymbolication.tsx +64 -0
  66. package/src/error-overlay/Data/LogContext.tsx +41 -0
  67. package/src/error-overlay/Data/parseLogBoxLog.tsx +342 -0
  68. package/src/error-overlay/ErrorOverlay.tsx +191 -0
  69. package/src/error-overlay/LogBox.ts +51 -0
  70. package/src/error-overlay/LogBox.web.ts +174 -0
  71. package/src/error-overlay/UI/AnsiHighlight.tsx +96 -0
  72. package/src/error-overlay/UI/LogBoxButton.tsx +63 -0
  73. package/src/error-overlay/UI/LogBoxMessage.tsx +73 -0
  74. package/src/error-overlay/UI/LogBoxStyle.ts +64 -0
  75. package/src/error-overlay/UI/constants.ts +7 -0
  76. package/src/error-overlay/formatProjectFilePath.ts +38 -0
  77. package/src/error-overlay/index.tsx +34 -0
  78. package/src/error-overlay/modules/ExceptionsManager/index.native.ts +4 -0
  79. package/src/error-overlay/modules/ExceptionsManager/index.ts +82 -0
  80. package/src/error-overlay/modules/NativeLogBox/index.native.ts +3 -0
  81. package/src/error-overlay/modules/NativeLogBox/index.tsx +27 -0
  82. package/src/error-overlay/modules/openFileInEditor/index.native.ts +3 -0
  83. package/src/error-overlay/modules/openFileInEditor/index.ts +16 -0
  84. package/src/error-overlay/modules/parseErrorStack/index.ts +26 -0
  85. package/src/error-overlay/modules/parseErrorStack/parseHermesStack.ts +3 -0
  86. package/src/error-overlay/modules/stringifySafe/index.ts +115 -0
  87. package/src/error-overlay/modules/symbolicateStackTrace/index.native.ts +3 -0
  88. package/src/error-overlay/modules/symbolicateStackTrace/index.ts +39 -0
  89. package/src/error-overlay/overlay/LogBoxInspectorCodeFrame.tsx +102 -0
  90. package/src/error-overlay/overlay/LogBoxInspectorFooter.tsx +111 -0
  91. package/src/error-overlay/overlay/LogBoxInspectorHeader.tsx +167 -0
  92. package/src/error-overlay/overlay/LogBoxInspectorMessageHeader.tsx +116 -0
  93. package/src/error-overlay/overlay/LogBoxInspectorSection.tsx +52 -0
  94. package/src/error-overlay/overlay/LogBoxInspectorSourceMapStatus.tsx +125 -0
  95. package/src/error-overlay/overlay/LogBoxInspectorStackFrame.tsx +89 -0
  96. package/src/error-overlay/overlay/LogBoxInspectorStackFrames.tsx +201 -0
  97. package/src/error-overlay/toast/ErrorToast.tsx +167 -0
  98. package/src/error-overlay/toast/ErrorToastContainer.tsx +9 -0
  99. package/src/error-overlay/toast/ErrorToastContainer.web.tsx +92 -0
  100. package/src/error-overlay/toast/ErrorToastMessage.tsx +28 -0
  101. package/src/error-overlay/useRejectionHandler.ts +61 -0
  102. package/src/getDevServer.native.ts +3 -0
  103. package/src/getDevServer.ts +34 -0
  104. package/src/index.ts +12 -0
  105. package/src/location/Location.native.ts +201 -0
  106. package/src/location/Location.ts +3 -0
  107. package/src/location/install.native.ts +90 -0
  108. package/src/location/install.ts +0 -0
  109. package/src/messageSocket.ts +25 -0
  110. package/src/setupFastRefresh.ts +30 -0
  111. package/src/setupHMR.ts +28 -0
  112. package/src/symbolicate.ts +6 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Copyright (c) 650 Industries.
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ export function getBackgroundColor(opacity?: number): string {
10
+ return `rgba(0, 0, 0, ${opacity == null ? 1 : opacity})`;
11
+ // return `rgba(51, 51, 51, ${opacity == null ? 1 : opacity})`;
12
+ }
13
+
14
+ export function getBackgroundLightColor(opacity?: number): string {
15
+ return `rgba(69, 69, 69, ${opacity == null ? 1 : opacity})`;
16
+ }
17
+
18
+ export function getBackgroundDarkColor(opacity?: number): string {
19
+ return `rgba(34, 34, 34, ${opacity == null ? 1 : opacity})`;
20
+ }
21
+
22
+ export function getWarningColor(opacity?: number): string {
23
+ return `rgba(250, 186, 48, ${opacity == null ? 1 : opacity})`;
24
+ }
25
+
26
+ export function getWarningDarkColor(opacity?: number): string {
27
+ return `rgba(224, 167, 8, ${opacity == null ? 1 : opacity})`;
28
+ }
29
+
30
+ export function getFatalColor(opacity?: number): string {
31
+ return `rgba(243, 83, 105, ${opacity == null ? 1 : opacity})`;
32
+ }
33
+
34
+ export function getFatalDarkColor(opacity?: number): string {
35
+ return `rgba(208, 75, 95, ${opacity == null ? 1 : opacity})`;
36
+ }
37
+
38
+ export function getErrorColor(opacity?: number): string {
39
+ return `rgba(243, 83, 105, ${opacity == null ? 1 : opacity})`;
40
+ }
41
+
42
+ export function getErrorDarkColor(opacity?: number): string {
43
+ return `rgba(208, 75, 95, ${opacity == null ? 1 : opacity})`;
44
+ }
45
+
46
+ export function getLogColor(opacity?: number): string {
47
+ return `rgba(119, 119, 119, ${opacity == null ? 1 : opacity})`;
48
+ }
49
+
50
+ export function getWarningHighlightColor(opacity?: number): string {
51
+ return `rgba(252, 176, 29, ${opacity == null ? 1 : opacity})`;
52
+ }
53
+
54
+ export function getDividerColor(opacity?: number): string {
55
+ return `rgba(255, 255, 255, ${opacity == null ? 1 : opacity})`;
56
+ }
57
+
58
+ export function getHighlightColor(opacity?: number): string {
59
+ return `rgba(252, 176, 29, ${opacity == null ? 1 : opacity})`;
60
+ }
61
+
62
+ export function getTextColor(opacity?: number): string {
63
+ return `rgba(255, 255, 255, ${opacity == null ? 1 : opacity})`;
64
+ }
@@ -0,0 +1,7 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ export const CODE_FONT = Platform.select({
4
+ default: 'Courier',
5
+ ios: 'Courier New',
6
+ android: 'monospace',
7
+ });
@@ -0,0 +1,38 @@
1
+ import type { StackFrame } from 'stacktrace-parser';
2
+
3
+ export type MetroStackFrame = StackFrame & { collapse?: boolean };
4
+
5
+ export function formatProjectFilePath(projectRoot: string, file?: string | null): string {
6
+ if (file == null) {
7
+ return '<unknown>';
8
+ }
9
+
10
+ return pathRelativeToPath(file.replace(/\\/g, '/'), projectRoot.replace(/\\/g, '/')).replace(
11
+ /\?.*$/,
12
+ ''
13
+ );
14
+ }
15
+
16
+ function pathRelativeToPath(path: string, relativeTo: string, sep = '/') {
17
+ const relativeToParts = relativeTo.split(sep);
18
+ const pathParts = path.split(sep);
19
+ let i = 0;
20
+ while (i < relativeToParts.length && i < pathParts.length) {
21
+ if (relativeToParts[i] !== pathParts[i]) {
22
+ break;
23
+ }
24
+ i++;
25
+ }
26
+ return pathParts.slice(i).join(sep);
27
+ }
28
+
29
+ export function getStackFormattedLocation(projectRoot: string, frame: MetroStackFrame) {
30
+ const column = frame.column != null && parseInt(String(frame.column), 10);
31
+ const location =
32
+ formatProjectFilePath(projectRoot, frame.file) +
33
+ (frame.lineNumber != null
34
+ ? ':' + frame.lineNumber + (column && !isNaN(column) ? ':' + (column + 1) : '')
35
+ : '');
36
+
37
+ return location;
38
+ }
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ // TODO: This will break tree shaking due to how we transpile this package.
3
+ import { Platform } from 'react-native';
4
+
5
+ import ErrorToastContainer from './toast/ErrorToastContainer';
6
+
7
+ declare const process: any;
8
+
9
+ if (!global.setImmediate) {
10
+ global.setImmediate = function (fn) {
11
+ return setTimeout(fn, 0);
12
+ };
13
+ }
14
+
15
+ if (process.env.NODE_ENV === 'development') {
16
+ if (Platform.OS === 'web') {
17
+ // Stack traces are big with React Navigation
18
+
19
+ require('./LogBox').default.install();
20
+ }
21
+ }
22
+
23
+ export function withErrorOverlay(Comp: React.ComponentType<any>) {
24
+ if (process.env.NODE_ENV === 'production') {
25
+ return Comp;
26
+ }
27
+ return function ErrorOverlay(props: any) {
28
+ return (
29
+ <ErrorToastContainer>
30
+ <Comp {...props} />
31
+ </ErrorToastContainer>
32
+ );
33
+ };
34
+ }
@@ -0,0 +1,4 @@
1
+ // @ts-expect-error
2
+ import ExceptionsManager from 'react-native/Library/Core/ExceptionsManager';
3
+
4
+ export default ExceptionsManager;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Copyright (c) 650 Industries.
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ import parseErrorStack from '../parseErrorStack';
10
+
11
+ type ExtendedError = any;
12
+
13
+ class SyntheticError extends Error {
14
+ name: string = '';
15
+ }
16
+
17
+ /**
18
+ * Handles the developer-visible aspect of errors and exceptions
19
+ */
20
+ let exceptionID = 0;
21
+
22
+ function parseException(e: ExtendedError, isFatal: boolean) {
23
+ const stack = parseErrorStack(e?.stack);
24
+ const currentExceptionID = ++exceptionID;
25
+ const originalMessage = e.message || '';
26
+ let message = originalMessage;
27
+ if (e.componentStack != null) {
28
+ message += `\n\nThis error is located at:${e.componentStack}`;
29
+ }
30
+ const namePrefix = e.name == null || e.name === '' ? '' : `${e.name}: `;
31
+
32
+ if (!message.startsWith(namePrefix)) {
33
+ message = namePrefix + message;
34
+ }
35
+
36
+ message = e.jsEngine == null ? message : `${message}, js engine: ${e.jsEngine}`;
37
+
38
+ const data = {
39
+ message,
40
+ originalMessage: message === originalMessage ? null : originalMessage,
41
+ name: e.name == null || e.name === '' ? null : e.name,
42
+ componentStack: typeof e.componentStack === 'string' ? e.componentStack : null,
43
+ stack,
44
+ id: currentExceptionID,
45
+ isFatal,
46
+ extraData: {
47
+ jsEngine: e.jsEngine,
48
+ rawStack: e.stack,
49
+ },
50
+ };
51
+
52
+ return {
53
+ ...data,
54
+ isComponentError: !!e.isComponentError,
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Logs exceptions to the (native) console and displays them
60
+ */
61
+ function handleException(e: any) {
62
+ let error: Error;
63
+ if (e instanceof Error) {
64
+ error = e;
65
+ } else {
66
+ // Workaround for reporting errors caused by `throw 'some string'`
67
+ // Unfortunately there is no way to figure out the stacktrace in this
68
+ // case, so if you ended up here trying to trace an error, look for
69
+ // `throw '<error message>'` somewhere in your codebase.
70
+ error = new SyntheticError(e);
71
+ }
72
+
73
+ require('../../LogBox').default.addException(parseException(error, true));
74
+ }
75
+
76
+ const ErrorUtils = {
77
+ parseException,
78
+ handleException,
79
+ SyntheticError,
80
+ };
81
+
82
+ export default ErrorUtils;
@@ -0,0 +1,3 @@
1
+ import NativeLogBox from 'react-native/Libraries/NativeModules/specs/NativeLogBox';
2
+
3
+ export default NativeLogBox;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ let currentRoot: ReactDOM.Root | null = null;
4
+ export default {
5
+ show() {
6
+ if (currentRoot) {
7
+ return;
8
+ }
9
+ const ErrorOverlay: React.ComponentType = require('../../ErrorOverlay').default;
10
+ // Create a new div with ID `error-overlay` element and render LogBoxInspector into it.
11
+ const div = document.createElement('div');
12
+ div.id = 'error-overlay';
13
+ document.body.appendChild(div);
14
+
15
+ currentRoot = ReactDOM.createRoot(div);
16
+ currentRoot.render(<ErrorOverlay />);
17
+ },
18
+ hide() {
19
+ // Remove div with ID `error-overlay`
20
+ if (currentRoot) {
21
+ currentRoot.unmount();
22
+ currentRoot = null;
23
+ }
24
+ const div = document.getElementById('error-overlay');
25
+ div?.remove();
26
+ },
27
+ };
@@ -0,0 +1,3 @@
1
+ import openFileInEditor from 'react-native/Libraries/Core/Devtools/openFileInEditor';
2
+
3
+ export default openFileInEditor;
@@ -0,0 +1,16 @@
1
+ declare const process: any;
2
+
3
+ function openFileInEditor(file: string, lineNumber: number) {
4
+ if (process.env.NODE_ENV !== 'production') {
5
+ // TODO: This is not a great URL since it now blocks users from accessing the `/open-stack-frame` url in their router
6
+ // ideally it would be something like `/_devtools/open-stack-frame`.
7
+ const baseUrl = window.location.protocol + '//' + window.location.host;
8
+
9
+ fetch(baseUrl + '/open-stack-frame', {
10
+ method: 'POST',
11
+ body: JSON.stringify({ file, lineNumber }),
12
+ });
13
+ }
14
+ }
15
+
16
+ export default openFileInEditor;
@@ -0,0 +1,26 @@
1
+ import { parse, StackFrame } from 'stacktrace-parser';
2
+
3
+ function parseErrorStack(stack?: string): (StackFrame & { collapse?: boolean })[] {
4
+ if (stack == null) {
5
+ return [];
6
+ }
7
+ if (Array.isArray(stack)) {
8
+ return stack;
9
+ }
10
+
11
+ // This file seems to be web-only, so we can remove this.
12
+ // // Native support for parsing for non-standard Hermes stack traces.
13
+ // if (global.HermesInternal) {
14
+ // return require('./parseHermesStack').parseErrorStack(stack);
15
+ // }
16
+
17
+ return parse(stack).map((frame) => {
18
+ // frame.file will mostly look like `http://localhost:8081/index.bundle?platform=web&dev=true&hot=false`
19
+ return {
20
+ ...frame,
21
+ column: frame.column != null ? frame.column - 1 : null,
22
+ };
23
+ });
24
+ }
25
+
26
+ export default parseErrorStack;
@@ -0,0 +1,3 @@
1
+ import parseErrorStack from 'react-native/Libraries/Core/Devtools/parseErrorStack';
2
+
3
+ export { parseErrorStack };
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Copyright (c) 650 Industries.
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ /**
10
+ * Tries to stringify with JSON.stringify and toString, but catches exceptions
11
+ * (e.g. from circular objects) and always returns a string and never throws.
12
+ */
13
+ export function createStringifySafeWithLimits(limits: {
14
+ maxDepth?: number;
15
+ maxStringLimit?: number;
16
+ maxArrayLimit?: number;
17
+ maxObjectKeysLimit?: number;
18
+ }): (foo: any) => string {
19
+ const {
20
+ maxDepth = Number.POSITIVE_INFINITY,
21
+ maxStringLimit = Number.POSITIVE_INFINITY,
22
+ maxArrayLimit = Number.POSITIVE_INFINITY,
23
+ maxObjectKeysLimit = Number.POSITIVE_INFINITY,
24
+ } = limits;
25
+ const stack: any[] = [];
26
+ function replacer(this: unknown, _key: string, value: any): any {
27
+ while (stack.length && this !== stack[0]) {
28
+ stack.shift();
29
+ }
30
+
31
+ if (typeof value === 'string') {
32
+ const truncatedString = '...(truncated)...';
33
+ if (value.length > maxStringLimit + truncatedString.length) {
34
+ return value.substring(0, maxStringLimit) + truncatedString;
35
+ }
36
+ return value;
37
+ }
38
+ if (typeof value !== 'object' || value === null) {
39
+ return value;
40
+ }
41
+
42
+ let retval = value;
43
+ if (Array.isArray(value)) {
44
+ if (stack.length >= maxDepth) {
45
+ retval = `[ ... array with ${value.length} values ... ]`;
46
+ } else if (value.length > maxArrayLimit) {
47
+ retval = value
48
+ .slice(0, maxArrayLimit)
49
+ .concat([`... extra ${value.length - maxArrayLimit} values truncated ...`]);
50
+ }
51
+ } else {
52
+ // Add refinement after Array.isArray call.
53
+ if (typeof value !== 'object') {
54
+ throw new Error('This was already found earlier');
55
+ }
56
+ const keys = Object.keys(value);
57
+ if (stack.length >= maxDepth) {
58
+ retval = `{ ... object with ${keys.length} keys ... }`;
59
+ } else if (keys.length > maxObjectKeysLimit) {
60
+ // Return a sample of the keys.
61
+ retval = {};
62
+ for (const k of keys.slice(0, maxObjectKeysLimit)) {
63
+ retval[k] = value[k];
64
+ }
65
+ const truncatedKey = '...(truncated keys)...';
66
+ retval[truncatedKey] = keys.length - maxObjectKeysLimit;
67
+ }
68
+ }
69
+ stack.unshift(retval);
70
+ return retval;
71
+ }
72
+
73
+ return function stringifySafe(arg: any): string {
74
+ if (arg === undefined) {
75
+ return 'undefined';
76
+ } else if (arg === null) {
77
+ return 'null';
78
+ } else if (typeof arg === 'function') {
79
+ try {
80
+ return arg.toString();
81
+ } catch {
82
+ return '[function unknown]';
83
+ }
84
+ } else if (arg instanceof Error) {
85
+ return arg.name + ': ' + arg.message;
86
+ } else {
87
+ // Perform a try catch, just in case the object has a circular
88
+ // reference or stringify throws for some other reason.
89
+ try {
90
+ const ret = JSON.stringify(arg, replacer);
91
+ if (ret === undefined) {
92
+ return '["' + typeof arg + '" failed to stringify]';
93
+ }
94
+ return ret;
95
+ } catch {
96
+ if (typeof arg.toString === 'function') {
97
+ try {
98
+ // $FlowFixMe[incompatible-use] : toString shouldn't take any arguments in general.
99
+ return arg.toString();
100
+ } catch {}
101
+ }
102
+ }
103
+ }
104
+ return '["' + typeof arg + '" failed to stringify]';
105
+ };
106
+ }
107
+
108
+ const stringifySafe = createStringifySafeWithLimits({
109
+ maxDepth: 10,
110
+ maxStringLimit: 100,
111
+ maxArrayLimit: 50,
112
+ maxObjectKeysLimit: 50,
113
+ });
114
+
115
+ export default stringifySafe;
@@ -0,0 +1,3 @@
1
+ import symbolicateStackTrace from 'react-native/Libraries/Core/Devtools/symbolicateStackTrace';
2
+
3
+ export default symbolicateStackTrace;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) 650 Industries.
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ import { StackFrame } from 'stacktrace-parser';
10
+
11
+ export type CodeFrame = {
12
+ content: string;
13
+ location?: {
14
+ row: number;
15
+ column: number;
16
+ [key: string]: any;
17
+ };
18
+ fileName: string;
19
+ };
20
+
21
+ export type SymbolicatedStackTrace = {
22
+ stack: StackFrame[];
23
+ codeFrame?: CodeFrame;
24
+ };
25
+
26
+ async function symbolicateStackTrace(stack: StackFrame[]): Promise<SymbolicatedStackTrace> {
27
+ const baseUrl =
28
+ typeof window === 'undefined'
29
+ ? process.env.EXPO_DEV_SERVER_ORIGIN
30
+ : window.location.protocol + '//' + window.location.host;
31
+
32
+ const response = await fetch(baseUrl + '/symbolicate', {
33
+ method: 'POST',
34
+ body: JSON.stringify({ stack }),
35
+ });
36
+ return await response.json();
37
+ }
38
+
39
+ export default symbolicateStackTrace;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Copyright (c) 650 Industries.
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ import React from 'react';
9
+ import { ScrollView, StyleSheet, Text, View } from 'react-native';
10
+
11
+ import { LogBoxInspectorSection } from './LogBoxInspectorSection';
12
+ import type { CodeFrame } from '../Data/parseLogBoxLog';
13
+ import { Ansi } from '../UI/AnsiHighlight';
14
+ import { LogBoxButton } from '../UI/LogBoxButton';
15
+ import * as LogBoxStyle from '../UI/LogBoxStyle';
16
+ import { CODE_FONT } from '../UI/constants';
17
+ import { formatProjectFilePath } from '../formatProjectFilePath';
18
+ import openFileInEditor from '../modules/openFileInEditor';
19
+
20
+ declare const process: any;
21
+
22
+ export function LogBoxInspectorCodeFrame({ codeFrame }: { codeFrame?: CodeFrame }) {
23
+ if (codeFrame == null) {
24
+ return null;
25
+ }
26
+
27
+ function getFileName() {
28
+ return formatProjectFilePath(process.env.EXPO_PROJECT_ROOT, codeFrame?.fileName);
29
+ }
30
+
31
+ function getLocation() {
32
+ const location = codeFrame?.location;
33
+ if (location != null) {
34
+ return ` (${location.row}:${location.column + 1 /* Code frame columns are zero indexed */})`;
35
+ }
36
+
37
+ return null;
38
+ }
39
+
40
+ return (
41
+ <LogBoxInspectorSection heading="Source">
42
+ <View style={styles.box}>
43
+ <View style={styles.frame}>
44
+ <ScrollView horizontal>
45
+ <Ansi style={styles.content} text={codeFrame.content} />
46
+ </ScrollView>
47
+ </View>
48
+ <LogBoxButton
49
+ backgroundColor={{
50
+ default: 'transparent',
51
+ pressed: LogBoxStyle.getBackgroundDarkColor(1),
52
+ }}
53
+ style={styles.button}
54
+ onPress={() => {
55
+ openFileInEditor(codeFrame.fileName, codeFrame.location?.row ?? 0);
56
+ }}>
57
+ <Text style={styles.fileText}>
58
+ {getFileName()}
59
+ {getLocation()}
60
+ </Text>
61
+ </LogBoxButton>
62
+ </View>
63
+ </LogBoxInspectorSection>
64
+ );
65
+ }
66
+
67
+ const styles = StyleSheet.create({
68
+ box: {
69
+ backgroundColor: LogBoxStyle.getBackgroundColor(),
70
+ borderWidth: 1,
71
+ borderColor: '#323232',
72
+ marginLeft: 10,
73
+ marginRight: 10,
74
+ marginTop: 5,
75
+ borderRadius: 3,
76
+ },
77
+ frame: {
78
+ padding: 10,
79
+ borderBottomColor: LogBoxStyle.getTextColor(0.1),
80
+ borderBottomWidth: 1,
81
+ },
82
+ button: {
83
+ paddingTop: 10,
84
+ paddingBottom: 10,
85
+ },
86
+ content: {
87
+ color: LogBoxStyle.getTextColor(1),
88
+ fontSize: 12,
89
+ includeFontPadding: false,
90
+ lineHeight: 20,
91
+ fontFamily: CODE_FONT,
92
+ },
93
+ fileText: {
94
+ userSelect: 'none',
95
+ color: LogBoxStyle.getTextColor(0.5),
96
+ textAlign: 'center',
97
+ flex: 1,
98
+ fontSize: 16,
99
+ includeFontPadding: false,
100
+ fontFamily: CODE_FONT,
101
+ },
102
+ });