@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,191 @@
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, { useCallback, useEffect, useState } from 'react';
9
+ import { Keyboard, ScrollView, View, StyleSheet } from 'react-native';
10
+
11
+ import * as LogBoxData from './Data/LogBoxData';
12
+ import { LogBoxLog, StackType } from './Data/LogBoxLog';
13
+ import { useLogs, useSelectedLog } from './Data/LogContext';
14
+ import * as LogBoxStyle from './UI/LogBoxStyle';
15
+ import { LogBoxInspectorCodeFrame } from './overlay/LogBoxInspectorCodeFrame';
16
+ import { LogBoxInspectorFooter as ErrorOverlayFooter } from './overlay/LogBoxInspectorFooter';
17
+ import { LogBoxInspectorHeader as ErrorOverlayHeader } from './overlay/LogBoxInspectorHeader';
18
+ import { LogBoxInspectorMessageHeader } from './overlay/LogBoxInspectorMessageHeader';
19
+ import { LogBoxInspectorStackFrames } from './overlay/LogBoxInspectorStackFrames';
20
+
21
+ const HEADER_TITLE_MAP = {
22
+ warn: 'Console Warning',
23
+ error: 'Console Error',
24
+ fatal: 'Uncaught Error',
25
+ syntax: 'Syntax Error',
26
+ static: 'Static Rendering Error (Node.js)',
27
+ component: 'Render Error',
28
+ };
29
+
30
+ export function LogBoxInspectorContainer() {
31
+ const { selectedLogIndex, logs } = useLogs();
32
+ const log = logs[selectedLogIndex];
33
+ if (log == null) {
34
+ return null;
35
+ }
36
+ return <LogBoxInspector log={log} selectedLogIndex={selectedLogIndex} logs={logs} />;
37
+ }
38
+
39
+ export function LogBoxInspector({
40
+ log,
41
+ selectedLogIndex,
42
+ logs,
43
+ }: {
44
+ log: LogBoxLog;
45
+ selectedLogIndex: number;
46
+ logs: LogBoxLog[];
47
+ }) {
48
+ const onDismiss = useCallback((): void => {
49
+ // Here we handle the cases when the log is dismissed and it
50
+ // was either the last log, or when the current index
51
+ // is now outside the bounds of the log array.
52
+ const logsArray = Array.from(logs);
53
+ if (selectedLogIndex != null) {
54
+ if (logsArray.length - 1 <= 0) {
55
+ LogBoxData.setSelectedLog(-1);
56
+ } else if (selectedLogIndex >= logsArray.length - 1) {
57
+ LogBoxData.setSelectedLog(selectedLogIndex - 1);
58
+ }
59
+
60
+ LogBoxData.dismiss(logsArray[selectedLogIndex]);
61
+ }
62
+ }, [selectedLogIndex]);
63
+
64
+ const onMinimize = useCallback((): void => {
65
+ LogBoxData.setSelectedLog(-1);
66
+ }, []);
67
+
68
+ const onChangeSelectedIndex = useCallback((index: number): void => {
69
+ LogBoxData.setSelectedLog(index);
70
+ }, []);
71
+
72
+ useEffect(() => {
73
+ if (log) {
74
+ LogBoxData.symbolicateLogNow('stack', log);
75
+ LogBoxData.symbolicateLogNow('component', log);
76
+ }
77
+ }, [log]);
78
+
79
+ useEffect(() => {
80
+ // Optimistically symbolicate the last and next logs.
81
+ if (logs.length > 1) {
82
+ const selected = selectedLogIndex;
83
+ const lastIndex = logs.length - 1;
84
+ const prevIndex = selected - 1 < 0 ? lastIndex : selected - 1;
85
+ const nextIndex = selected + 1 > lastIndex ? 0 : selected + 1;
86
+ for (const type of ['component', 'stack'] as const) {
87
+ LogBoxData.symbolicateLogLazy(type, logs[prevIndex]);
88
+ LogBoxData.symbolicateLogLazy(type, logs[nextIndex]);
89
+ }
90
+ }
91
+ }, [logs, selectedLogIndex]);
92
+
93
+ useEffect(() => {
94
+ Keyboard.dismiss();
95
+ }, []);
96
+
97
+ const _handleRetry = useCallback(
98
+ (type: StackType) => {
99
+ LogBoxData.retrySymbolicateLogNow(type, log);
100
+ },
101
+ [log]
102
+ );
103
+
104
+ return (
105
+ <View style={styles.container}>
106
+ <ErrorOverlayHeader onSelectIndex={onChangeSelectedIndex} level={log.level} />
107
+ <ErrorOverlayBody onRetry={_handleRetry} />
108
+ <ErrorOverlayFooter onDismiss={onDismiss} onMinimize={onMinimize} />
109
+ </View>
110
+ );
111
+ }
112
+
113
+ export function ErrorOverlayBody({ onRetry }: { onRetry: (type: StackType) => void }) {
114
+ const log = useSelectedLog();
115
+ return <ErrorOverlayBodyContents log={log} onRetry={onRetry} />;
116
+ }
117
+
118
+ export function ErrorOverlayBodyContents({
119
+ log,
120
+ onRetry,
121
+ }: {
122
+ log: LogBoxLog;
123
+ onRetry: (type: StackType) => void;
124
+ }) {
125
+ const [collapsed, setCollapsed] = useState(true);
126
+
127
+ useEffect(() => {
128
+ setCollapsed(true);
129
+ }, [log]);
130
+
131
+ const headerTitle = HEADER_TITLE_MAP[log.isComponentError ? 'component' : log.level] ?? log.type;
132
+
133
+ const header = (
134
+ <LogBoxInspectorMessageHeader
135
+ collapsed={collapsed}
136
+ onPress={() => setCollapsed(!collapsed)}
137
+ message={log.message}
138
+ level={log.level}
139
+ title={headerTitle}
140
+ />
141
+ );
142
+
143
+ // Hide useless React stack.
144
+ const needsStack = !log.message.content.match(
145
+ /(Expected server HTML to contain a matching|Text content did not match\.)/
146
+ );
147
+
148
+ return (
149
+ <>
150
+ {collapsed && header}
151
+ <ScrollView style={styles.scrollBody}>
152
+ {!collapsed && header}
153
+
154
+ <LogBoxInspectorCodeFrame codeFrame={log.codeFrame} />
155
+ {needsStack && (
156
+ <LogBoxInspectorStackFrames
157
+ type="stack"
158
+ // eslint-disable-next-line react/jsx-no-bind
159
+ onRetry={onRetry.bind(onRetry, 'stack')}
160
+ />
161
+ )}
162
+ {!!log?.componentStack?.length && (
163
+ <LogBoxInspectorStackFrames
164
+ type="component"
165
+ // eslint-disable-next-line react/jsx-no-bind
166
+ onRetry={onRetry.bind(onRetry, 'component')}
167
+ />
168
+ )}
169
+ </ScrollView>
170
+ </>
171
+ );
172
+ }
173
+
174
+ const styles = StyleSheet.create({
175
+ scrollBody: {
176
+ backgroundColor: LogBoxStyle.getBackgroundColor(1),
177
+ flex: 1,
178
+ },
179
+ container: {
180
+ top: 0,
181
+ left: 0,
182
+ bottom: 0,
183
+ right: 0,
184
+ zIndex: 999,
185
+ flex: 1,
186
+ // @ts-expect-error: fixed is not in the RN types but it works on web
187
+ position: 'fixed',
188
+ },
189
+ });
190
+
191
+ export default LogBoxData.withSubscription(LogBoxInspectorContainer);
@@ -0,0 +1,51 @@
1
+ import { IgnorePattern, LogData } from './Data/LogBoxData';
2
+ import { ExtendedExceptionData } from './Data/parseLogBoxLog';
3
+
4
+ export { LogData, ExtendedExceptionData, IgnorePattern };
5
+
6
+ interface ILogBox {
7
+ install(): void;
8
+ uninstall(): void;
9
+ isInstalled(): boolean;
10
+ ignoreLogs(patterns: readonly IgnorePattern[]): void;
11
+ ignoreAllLogs(ignore?: boolean): void;
12
+ clearAllLogs(): void;
13
+ addLog(log: LogData): void;
14
+ addException(error: ExtendedExceptionData): void;
15
+ }
16
+
17
+ const LogBox: ILogBox = {
18
+ install(): void {
19
+ // Do nothing.
20
+ },
21
+
22
+ uninstall(): void {
23
+ // Do nothing.
24
+ },
25
+
26
+ isInstalled(): boolean {
27
+ return false;
28
+ },
29
+
30
+ ignoreLogs(patterns: readonly IgnorePattern[]): void {
31
+ // Do nothing.
32
+ },
33
+
34
+ ignoreAllLogs(value?: boolean): void {
35
+ // Do nothing.
36
+ },
37
+
38
+ clearAllLogs(): void {
39
+ // Do nothing.
40
+ },
41
+
42
+ addLog(log: LogData): void {
43
+ // Do nothing.
44
+ },
45
+
46
+ addException(ex: ExtendedExceptionData): void {
47
+ // Do nothing.
48
+ },
49
+ };
50
+
51
+ export default LogBox;
@@ -0,0 +1,174 @@
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 { IgnorePattern, LogData } from './Data/LogBoxData';
10
+ import { ExtendedExceptionData } from './Data/parseLogBoxLog';
11
+
12
+ export { LogData, ExtendedExceptionData, IgnorePattern };
13
+
14
+ let LogBox: ILogBox;
15
+
16
+ interface ILogBox {
17
+ install(): void;
18
+ uninstall(): void;
19
+ isInstalled(): boolean;
20
+ ignoreLogs(patterns: readonly IgnorePattern[]): void;
21
+ ignoreAllLogs(ignore?: boolean): void;
22
+ clearAllLogs(): void;
23
+ addLog(log: LogData): void;
24
+ addException(error: ExtendedExceptionData): void;
25
+ }
26
+
27
+ /**
28
+ * LogBox displays logs in the app.
29
+ */
30
+ if (__DEV__) {
31
+ const LogBoxData = require('./Data/LogBoxData');
32
+ const { parseLogBoxLog, parseInterpolation } =
33
+ require('./Data/parseLogBoxLog') as typeof import('./Data/parseLogBoxLog');
34
+
35
+ let originalConsoleError: typeof console.error | undefined;
36
+ let consoleErrorImpl: typeof console.error | undefined;
37
+
38
+ let isLogBoxInstalled: boolean = false;
39
+
40
+ LogBox = {
41
+ install(): void {
42
+ if (isLogBoxInstalled) {
43
+ return;
44
+ }
45
+
46
+ isLogBoxInstalled = true;
47
+
48
+ // Trigger lazy initialization of module.
49
+ // require("../NativeModules/specs/NativeLogBox");
50
+
51
+ // IMPORTANT: we only overwrite `console.error` and `console.warn` once.
52
+ // When we uninstall we keep the same reference and only change its
53
+ // internal implementation
54
+ const isFirstInstall = originalConsoleError == null;
55
+ if (isFirstInstall) {
56
+ originalConsoleError = console.error.bind(console);
57
+
58
+ console.error = (...args) => {
59
+ consoleErrorImpl?.(...args);
60
+ };
61
+ }
62
+
63
+ consoleErrorImpl = registerError;
64
+
65
+ if (process.env.NODE_ENV === 'test') {
66
+ LogBoxData.setDisabled(true);
67
+ }
68
+ },
69
+
70
+ uninstall(): void {
71
+ if (!isLogBoxInstalled) {
72
+ return;
73
+ }
74
+
75
+ isLogBoxInstalled = false;
76
+
77
+ // IMPORTANT: we don't re-assign to `console` in case the method has been
78
+ // decorated again after installing LogBox. E.g.:
79
+ // Before uninstalling: original > LogBox > OtherErrorHandler
80
+ // After uninstalling: original > LogBox (noop) > OtherErrorHandler
81
+ consoleErrorImpl = originalConsoleError;
82
+ delete (console as any).disableLogBox;
83
+ },
84
+
85
+ isInstalled(): boolean {
86
+ return isLogBoxInstalled;
87
+ },
88
+
89
+ ignoreLogs(patterns: readonly IgnorePattern[]): void {
90
+ LogBoxData.addIgnorePatterns(patterns);
91
+ },
92
+
93
+ ignoreAllLogs(value?: boolean): void {
94
+ LogBoxData.setDisabled(value == null ? true : value);
95
+ },
96
+
97
+ clearAllLogs(): void {
98
+ LogBoxData.clear();
99
+ },
100
+
101
+ addLog(log: LogData): void {
102
+ if (isLogBoxInstalled) {
103
+ LogBoxData.addLog(log);
104
+ }
105
+ },
106
+
107
+ addException(error: ExtendedExceptionData): void {
108
+ if (isLogBoxInstalled) {
109
+ LogBoxData.addException(error);
110
+ }
111
+ },
112
+ };
113
+
114
+ const isWarningModuleWarning = (...args: any) => {
115
+ return typeof args[0] === 'string' && args[0].startsWith('Warning: ');
116
+ };
117
+
118
+ const registerError = (...args: Parameters<typeof console.error>): void => {
119
+ // Let errors within LogBox itself fall through.
120
+ if (LogBoxData.isLogBoxErrorMessage(args[0])) {
121
+ originalConsoleError?.(...args);
122
+ return;
123
+ }
124
+
125
+ try {
126
+ if (!isWarningModuleWarning(...args)) {
127
+ // Only show LogBox for the 'warning' module, otherwise pass through.
128
+ // By passing through, this will get picked up by the React console override,
129
+ // potentially adding the component stack. React then passes it back to the
130
+ // React Native ExceptionsManager, which reports it to LogBox as an error.
131
+ //
132
+ // The 'warning' module needs to be handled here because React internally calls
133
+ // `console.error('Warning: ')` with the component stack already included.
134
+ originalConsoleError?.(...args);
135
+ return;
136
+ }
137
+
138
+ const { category, message, componentStack } = parseLogBoxLog(args);
139
+
140
+ if (!LogBoxData.isMessageIgnored(message.content)) {
141
+ // Interpolate the message so they are formatted for adb and other CLIs.
142
+ // This is different than the message.content above because it includes component stacks.
143
+ const interpolated = parseInterpolation(args);
144
+ originalConsoleError?.(interpolated.message.content);
145
+
146
+ LogBoxData.addLog({
147
+ // Always show the static rendering issues as full screen since they
148
+ // are too confusing otherwise.
149
+ level: /did not match\. Server:/.test(message.content) ? 'fatal' : 'error',
150
+ category,
151
+ message,
152
+ componentStack,
153
+ });
154
+ }
155
+ } catch (err) {
156
+ LogBoxData.reportUnexpectedLogBoxError(err);
157
+ }
158
+ };
159
+ } else {
160
+ LogBox = {
161
+ install(): void {},
162
+ uninstall(): void {},
163
+ isInstalled(): boolean {
164
+ return false;
165
+ },
166
+ ignoreLogs(patterns: readonly IgnorePattern[]): void {},
167
+ ignoreAllLogs(value?: boolean): void {},
168
+ clearAllLogs(): void {},
169
+ addLog(log: LogData): void {},
170
+ addException(ex: ExtendedExceptionData): void {},
171
+ };
172
+ }
173
+
174
+ export default LogBox;
@@ -0,0 +1,96 @@
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 Anser from 'anser';
9
+ import React from 'react';
10
+ import { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native';
11
+
12
+ // Afterglow theme from https://iterm2colorschemes.com/
13
+ const COLORS: Record<string, string> = {
14
+ 'ansi-black': 'rgb(27, 27, 27)',
15
+ 'ansi-red': 'rgb(187, 86, 83)',
16
+ 'ansi-green': 'rgb(144, 157, 98)',
17
+ 'ansi-yellow': 'rgb(234, 193, 121)',
18
+ 'ansi-blue': 'rgb(125, 169, 199)',
19
+ 'ansi-magenta': 'rgb(176, 101, 151)',
20
+ 'ansi-cyan': 'rgb(140, 220, 216)',
21
+ // Instead of white, use the default color provided to the component
22
+ // 'ansi-white': 'rgb(216, 216, 216)',
23
+ 'ansi-bright-black': 'rgb(98, 98, 98)',
24
+ 'ansi-bright-red': 'rgb(187, 86, 83)',
25
+ 'ansi-bright-green': 'rgb(144, 157, 98)',
26
+ 'ansi-bright-yellow': 'rgb(234, 193, 121)',
27
+ 'ansi-bright-blue': 'rgb(125, 169, 199)',
28
+ 'ansi-bright-magenta': 'rgb(176, 101, 151)',
29
+ 'ansi-bright-cyan': 'rgb(140, 220, 216)',
30
+ 'ansi-bright-white': 'rgb(247, 247, 247)',
31
+ };
32
+
33
+ export function Ansi({ text, style }: { text: string; style: StyleProp<TextStyle> }) {
34
+ let commonWhitespaceLength = Infinity;
35
+ const parsedLines = text.split(/\n/).map((line) =>
36
+ Anser.ansiToJson(line, {
37
+ json: true,
38
+ remove_empty: true,
39
+ use_classes: true,
40
+ })
41
+ );
42
+
43
+ parsedLines.map((lines) => {
44
+ // The third item on each line includes the whitespace of the source code.
45
+ // We are looking for the least amount of common whitespace to trim all lines.
46
+ // Example: Array [" ", " 96 |", " text", ...]
47
+ const match = lines[2] && lines[2]?.content?.match(/^ +/);
48
+ const whitespaceLength = (match && match[0]?.length) || 0;
49
+ if (whitespaceLength < commonWhitespaceLength) {
50
+ commonWhitespaceLength = whitespaceLength;
51
+ }
52
+ });
53
+
54
+ const getText = (content: string, key: number) => {
55
+ if (key === 1) {
56
+ // Remove the vertical bar after line numbers
57
+ return content.replace(/\| $/, ' ');
58
+ } else if (key === 2 && commonWhitespaceLength < Infinity) {
59
+ // Remove common whitespace at the beginning of the line
60
+ return content.substr(commonWhitespaceLength);
61
+ } else {
62
+ return content;
63
+ }
64
+ };
65
+
66
+ return (
67
+ <View>
68
+ {parsedLines.map((items, i) => (
69
+ <View style={styles.line} key={i}>
70
+ {items.map((bundle, key) => {
71
+ const textStyle =
72
+ bundle.fg && COLORS[bundle.fg]
73
+ ? {
74
+ backgroundColor: bundle.bg && COLORS[bundle.bg],
75
+ color: bundle.fg && COLORS[bundle.fg],
76
+ }
77
+ : {
78
+ backgroundColor: bundle.bg && COLORS[bundle.bg],
79
+ };
80
+ return (
81
+ <Text style={[style, textStyle]} key={key}>
82
+ {getText(bundle.content, key)}
83
+ </Text>
84
+ );
85
+ })}
86
+ </View>
87
+ ))}
88
+ </View>
89
+ );
90
+ }
91
+
92
+ const styles = StyleSheet.create({
93
+ line: {
94
+ flexDirection: 'row',
95
+ },
96
+ });
@@ -0,0 +1,63 @@
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, { useState } from 'react';
9
+ import { GestureResponderEvent, Insets, Platform, Pressable, View, ViewStyle } from 'react-native';
10
+
11
+ import * as LogBoxStyle from './LogBoxStyle';
12
+
13
+ type Props = {
14
+ backgroundColor: {
15
+ default: string;
16
+ pressed: string;
17
+ };
18
+ children?: any;
19
+ hitSlop?: Insets;
20
+ onPress?: ((event: GestureResponderEvent) => void) | null;
21
+ style?: ViewStyle;
22
+ };
23
+
24
+ export function LogBoxButton(props: Props) {
25
+ const [pressed, setPressed] = useState(false);
26
+
27
+ let backgroundColor = props.backgroundColor;
28
+ if (!backgroundColor) {
29
+ backgroundColor = {
30
+ default: LogBoxStyle.getBackgroundColor(0.95),
31
+ pressed: LogBoxStyle.getBackgroundColor(0.6),
32
+ };
33
+ }
34
+
35
+ const content = (
36
+ <View
37
+ style={[
38
+ {
39
+ backgroundColor: pressed ? backgroundColor.pressed : backgroundColor.default,
40
+ ...Platform.select({
41
+ web: {
42
+ cursor: 'pointer',
43
+ },
44
+ }),
45
+ },
46
+ props.style,
47
+ ]}>
48
+ {props.children}
49
+ </View>
50
+ );
51
+
52
+ return props.onPress == null ? (
53
+ content
54
+ ) : (
55
+ <Pressable
56
+ hitSlop={props.hitSlop}
57
+ onPress={props.onPress}
58
+ onPressIn={() => setPressed(true)}
59
+ onPressOut={() => setPressed(false)}>
60
+ {content}
61
+ </Pressable>
62
+ );
63
+ }
@@ -0,0 +1,73 @@
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 { StyleProp, Text, TextStyle } from 'react-native';
10
+
11
+ import type { Message } from '../Data/parseLogBoxLog';
12
+
13
+ type Props = {
14
+ message: Message;
15
+ style: StyleProp<TextStyle>;
16
+ plaintext?: boolean;
17
+ maxLength?: number;
18
+ };
19
+
20
+ const cleanContent = (content: string) =>
21
+ content.replace(/^(TransformError |Warning: (Warning: )?|Error: )/g, '');
22
+
23
+ export function LogBoxMessage(props: Props): JSX.Element {
24
+ const { content, substitutions }: Message = props.message;
25
+
26
+ if (props.plaintext === true) {
27
+ return <Text>{cleanContent(content)}</Text>;
28
+ }
29
+
30
+ const maxLength = props.maxLength != null ? props.maxLength : Infinity;
31
+ const substitutionStyle: StyleProp<TextStyle> = props.style;
32
+ const elements: JSX.Element[] = [];
33
+ let length = 0;
34
+ const createUnderLength = (key: string | '-1', message: string, style?: StyleProp<TextStyle>) => {
35
+ let cleanMessage = cleanContent(message);
36
+
37
+ if (props.maxLength != null) {
38
+ cleanMessage = cleanMessage.slice(0, props.maxLength - length);
39
+ }
40
+
41
+ if (length < maxLength) {
42
+ elements.push(
43
+ <Text key={key} style={style}>
44
+ {cleanMessage}
45
+ </Text>
46
+ );
47
+ }
48
+
49
+ length += cleanMessage.length;
50
+ };
51
+
52
+ const lastOffset = substitutions.reduce((prevOffset, substitution, index) => {
53
+ const key = String(index);
54
+
55
+ if (substitution.offset > prevOffset) {
56
+ const prevPart = content.substr(prevOffset, substitution.offset - prevOffset);
57
+
58
+ createUnderLength(key, prevPart);
59
+ }
60
+
61
+ const substititionPart = content.substr(substitution.offset, substitution.length);
62
+
63
+ createUnderLength(key + '.5', substititionPart, substitutionStyle);
64
+ return substitution.offset + substitution.length;
65
+ }, 0);
66
+
67
+ if (lastOffset < content.length) {
68
+ const lastPart = content.substr(lastOffset);
69
+ createUnderLength('-1', lastPart);
70
+ }
71
+
72
+ return <>{elements}</>;
73
+ }