@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.
- package/build/LoadingView.d.ts +6 -0
- package/build/LoadingView.d.ts.map +1 -1
- package/build/LoadingView.js +9 -3
- package/build/LoadingView.js.map +1 -1
- package/build/async-require/fetchAsync.d.ts +6 -0
- package/build/async-require/fetchAsync.d.ts.map +1 -1
- package/build/async-require/fetchAsync.js +1 -2
- package/build/async-require/fetchAsync.js.map +1 -1
- package/build/async-require/fetchThenEval.d.ts +1 -6
- package/build/async-require/fetchThenEval.d.ts.map +1 -1
- package/build/async-require/fetchThenEval.js +2 -32
- package/build/async-require/fetchThenEval.js.map +1 -1
- package/build/async-require/fetchThenEval.web.js +1 -1
- package/build/async-require/fetchThenEval.web.js.map +1 -1
- package/build/async-require/fetchThenEvalJs.d.ts +7 -0
- package/build/async-require/fetchThenEvalJs.d.ts.map +1 -0
- package/build/async-require/fetchThenEvalJs.js +36 -0
- package/build/async-require/fetchThenEvalJs.js.map +1 -0
- package/build/async-require/index.native.d.ts +7 -0
- package/build/async-require/index.native.d.ts.map +1 -0
- package/build/async-require/index.native.js +14 -0
- package/build/async-require/index.native.js.map +1 -0
- package/build/effects.d.ts +0 -1
- package/build/effects.js +1 -6
- package/build/effects.js.map +1 -1
- package/build/error-overlay/Data/parseLogBoxLog.d.ts.map +1 -1
- package/build/error-overlay/Data/parseLogBoxLog.js +1 -2
- package/build/error-overlay/Data/parseLogBoxLog.js.map +1 -1
- package/build/error-overlay/LogBox.web.d.ts.map +1 -1
- package/build/error-overlay/LogBox.web.js +1 -2
- package/build/error-overlay/LogBox.web.js.map +1 -1
- package/build/error-overlay/index.d.ts.map +1 -1
- package/build/error-overlay/index.js +1 -0
- package/build/error-overlay/index.js.map +1 -1
- package/build/getDevServer.d.ts.map +1 -1
- package/build/getDevServer.js +2 -6
- package/build/getDevServer.js.map +1 -1
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10 -8
- package/build/index.js.map +1 -1
- package/build/setupHMR.js +21 -24
- package/build/setupHMR.js.map +1 -1
- package/package.json +5 -2
- package/src/HMRClient.native.ts +3 -0
- package/src/HMRClient.ts +316 -0
- package/src/LoadingView.native.ts +3 -0
- package/src/LoadingView.ts +24 -0
- package/src/__mocks__/LoadingView.ts +4 -0
- package/src/async-require/buildAsyncRequire.ts +34 -0
- package/src/async-require/buildUrlForBundle.native.ts +28 -0
- package/src/async-require/buildUrlForBundle.ts +18 -0
- package/src/async-require/fetchAsync.native.ts +72 -0
- package/src/async-require/fetchAsync.ts +19 -0
- package/src/async-require/fetchThenEval.ts +1 -0
- package/src/async-require/fetchThenEval.web.ts +70 -0
- package/src/async-require/fetchThenEvalJs.ts +39 -0
- package/src/async-require/index.native.ts +15 -0
- package/src/async-require/index.ts +10 -0
- package/src/async-require/loadBundle.ts +46 -0
- package/src/effects.native.ts +0 -0
- package/src/effects.ts +11 -0
- package/src/error-overlay/Data/LogBoxData.tsx +438 -0
- package/src/error-overlay/Data/LogBoxLog.ts +221 -0
- package/src/error-overlay/Data/LogBoxSymbolication.tsx +64 -0
- package/src/error-overlay/Data/LogContext.tsx +41 -0
- package/src/error-overlay/Data/parseLogBoxLog.tsx +342 -0
- package/src/error-overlay/ErrorOverlay.tsx +191 -0
- package/src/error-overlay/LogBox.ts +51 -0
- package/src/error-overlay/LogBox.web.ts +174 -0
- package/src/error-overlay/UI/AnsiHighlight.tsx +96 -0
- package/src/error-overlay/UI/LogBoxButton.tsx +63 -0
- package/src/error-overlay/UI/LogBoxMessage.tsx +73 -0
- package/src/error-overlay/UI/LogBoxStyle.ts +64 -0
- package/src/error-overlay/UI/constants.ts +7 -0
- package/src/error-overlay/formatProjectFilePath.ts +38 -0
- package/src/error-overlay/index.tsx +34 -0
- package/src/error-overlay/modules/ExceptionsManager/index.native.ts +4 -0
- package/src/error-overlay/modules/ExceptionsManager/index.ts +82 -0
- package/src/error-overlay/modules/NativeLogBox/index.native.ts +3 -0
- package/src/error-overlay/modules/NativeLogBox/index.tsx +27 -0
- package/src/error-overlay/modules/openFileInEditor/index.native.ts +3 -0
- package/src/error-overlay/modules/openFileInEditor/index.ts +16 -0
- package/src/error-overlay/modules/parseErrorStack/index.ts +26 -0
- package/src/error-overlay/modules/parseErrorStack/parseHermesStack.ts +3 -0
- package/src/error-overlay/modules/stringifySafe/index.ts +115 -0
- package/src/error-overlay/modules/symbolicateStackTrace/index.native.ts +3 -0
- package/src/error-overlay/modules/symbolicateStackTrace/index.ts +39 -0
- package/src/error-overlay/overlay/LogBoxInspectorCodeFrame.tsx +102 -0
- package/src/error-overlay/overlay/LogBoxInspectorFooter.tsx +111 -0
- package/src/error-overlay/overlay/LogBoxInspectorHeader.tsx +167 -0
- package/src/error-overlay/overlay/LogBoxInspectorMessageHeader.tsx +116 -0
- package/src/error-overlay/overlay/LogBoxInspectorSection.tsx +52 -0
- package/src/error-overlay/overlay/LogBoxInspectorSourceMapStatus.tsx +125 -0
- package/src/error-overlay/overlay/LogBoxInspectorStackFrame.tsx +89 -0
- package/src/error-overlay/overlay/LogBoxInspectorStackFrames.tsx +201 -0
- package/src/error-overlay/toast/ErrorToast.tsx +167 -0
- package/src/error-overlay/toast/ErrorToastContainer.tsx +9 -0
- package/src/error-overlay/toast/ErrorToastContainer.web.tsx +92 -0
- package/src/error-overlay/toast/ErrorToastMessage.tsx +28 -0
- package/src/error-overlay/useRejectionHandler.ts +61 -0
- package/src/getDevServer.native.ts +3 -0
- package/src/getDevServer.ts +34 -0
- package/src/index.ts +12 -0
- package/src/location/Location.native.ts +201 -0
- package/src/location/Location.ts +3 -0
- package/src/location/install.native.ts +90 -0
- package/src/location/install.ts +0 -0
- package/src/messageSocket.ts +25 -0
- package/src/setupFastRefresh.ts +30 -0
- package/src/setupHMR.ts +28 -0
- 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,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,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,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,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,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,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
|
+
});
|