1"use strict";
2/**
3 * Copyright (c) 650 Industries.
4 * Copyright (c) Meta Platforms, Inc. and affiliates.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE file in the root directory of this source tree.
8 */
9var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10    if (k2 === undefined) k2 = k;
11    var desc = Object.getOwnPropertyDescriptor(m, k);
12    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13      desc = { enumerable: true, get: function() { return m[k]; } };
14    }
15    Object.defineProperty(o, k2, desc);
16}) : (function(o, m, k, k2) {
17    if (k2 === undefined) k2 = k;
18    o[k2] = m[k];
19}));
20var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21    Object.defineProperty(o, "default", { enumerable: true, value: v });
22}) : function(o, v) {
23    o["default"] = v;
24});
25var __importStar = (this && this.__importStar) || function (mod) {
26    if (mod && mod.__esModule) return mod;
27    var result = {};
28    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
29    __setModuleDefault(result, mod);
30    return result;
31};
32var __importDefault = (this && this.__importDefault) || function (mod) {
33    return (mod && mod.__esModule) ? mod : { "default": mod };
34};
35Object.defineProperty(exports, "__esModule", { value: true });
36exports.withSubscription = exports.observe = exports.isDisabled = exports.setDisabled = exports.addIgnorePatterns = exports.getIgnorePatterns = exports.dismiss = exports.clearErrors = exports.clearWarnings = exports.setSelectedLog = exports.clear = exports.symbolicateLogLazy = exports.retrySymbolicateLogNow = exports.symbolicateLogNow = exports.addException = exports.addLog = exports.isMessageIgnored = exports.isLogBoxErrorMessage = exports.reportUnexpectedLogBoxError = exports.reportLogBoxError = void 0;
37const React = __importStar(require("react"));
38const LogBoxLog_1 = require("./LogBoxLog");
39const LogContext_1 = require("./LogContext");
40const parseLogBoxLog_1 = require("./parseLogBoxLog");
41const NativeLogBox_1 = __importDefault(require("../modules/NativeLogBox"));
42const parseErrorStack_1 = __importDefault(require("../modules/parseErrorStack"));
43const observers = new Set();
44const ignorePatterns = new Set();
45let logs = new Set();
46let updateTimeout = null;
47let _isDisabled = false;
48let _selectedIndex = -1;
49const LOGBOX_ERROR_MESSAGE = 'An error was thrown when attempting to render log messages via LogBox.';
50function getNextState() {
51    return {
52        logs,
53        isDisabled: _isDisabled,
54        selectedLogIndex: _selectedIndex,
55    };
56}
57function reportLogBoxError(error, componentStack) {
58    const ExceptionsManager = require('../modules/ExceptionsManager').default;
59    if (componentStack != null) {
60        error.componentStack = componentStack;
61    }
62    ExceptionsManager.handleException(error);
63}
64exports.reportLogBoxError = reportLogBoxError;
65function reportUnexpectedLogBoxError(error, componentStack) {
66    error.message = `${LOGBOX_ERROR_MESSAGE}\n\n${error.message}`;
67    return reportLogBoxError(error, componentStack);
68}
69exports.reportUnexpectedLogBoxError = reportUnexpectedLogBoxError;
70function isLogBoxErrorMessage(message) {
71    return typeof message === 'string' && message.includes(LOGBOX_ERROR_MESSAGE);
72}
73exports.isLogBoxErrorMessage = isLogBoxErrorMessage;
74function isMessageIgnored(message) {
75    for (const pattern of ignorePatterns) {
76        if ((pattern instanceof RegExp && pattern.test(message)) ||
77            (typeof pattern === 'string' && message.includes(pattern))) {
78            return true;
79        }
80    }
81    return false;
82}
83exports.isMessageIgnored = isMessageIgnored;
84function setImmediateShim(callback) {
85    if (!global.setImmediate) {
86        return setTimeout(callback, 0);
87    }
88    return global.setImmediate(callback);
89}
90function handleUpdate() {
91    if (updateTimeout == null) {
92        updateTimeout = setImmediateShim(() => {
93            updateTimeout = null;
94            const nextState = getNextState();
95            observers.forEach(({ observer }) => observer(nextState));
96        });
97    }
98}
99function appendNewLog(newLog) {
100    // Don't want store these logs because they trigger a
101    // state update when we add them to the store.
102    if (isMessageIgnored(newLog.message.content)) {
103        return;
104    }
105    // If the next log has the same category as the previous one
106    // then roll it up into the last log in the list by incrementing
107    // the count (similar to how Chrome does it).
108    const lastLog = Array.from(logs).pop();
109    if (lastLog && lastLog.category === newLog.category) {
110        lastLog.incrementCount();
111        handleUpdate();
112        return;
113    }
114    if (newLog.level === 'fatal') {
115        // If possible, to avoid jank, we don't want to open the error before
116        // it's symbolicated. To do that, we optimistically wait for
117        // symbolication for up to a second before adding the log.
118        const OPTIMISTIC_WAIT_TIME = 1000;
119        let addPendingLog = () => {
120            logs.add(newLog);
121            if (_selectedIndex < 0) {
122                setSelectedLog(logs.size - 1);
123            }
124            else {
125                handleUpdate();
126            }
127            addPendingLog = null;
128        };
129        const optimisticTimeout = setTimeout(() => {
130            if (addPendingLog) {
131                addPendingLog();
132            }
133        }, OPTIMISTIC_WAIT_TIME);
134        // TODO: HANDLE THIS
135        newLog.symbolicate('component');
136        newLog.symbolicate('stack', (status) => {
137            if (addPendingLog && status !== 'PENDING') {
138                addPendingLog();
139                clearTimeout(optimisticTimeout);
140            }
141            else if (status !== 'PENDING') {
142                // The log has already been added but we need to trigger a render.
143                handleUpdate();
144            }
145        });
146    }
147    else if (newLog.level === 'syntax') {
148        logs.add(newLog);
149        setSelectedLog(logs.size - 1);
150    }
151    else {
152        logs.add(newLog);
153        handleUpdate();
154    }
155}
156function addLog(log) {
157    const errorForStackTrace = new Error();
158    // Parsing logs are expensive so we schedule this
159    // otherwise spammy logs would pause rendering.
160    setImmediate(() => {
161        try {
162            const stack = (0, parseErrorStack_1.default)(errorForStackTrace?.stack);
163            appendNewLog(new LogBoxLog_1.LogBoxLog({
164                level: log.level,
165                message: log.message,
166                isComponentError: false,
167                stack,
168                category: log.category,
169                componentStack: log.componentStack,
170            }));
171        }
172        catch (error) {
173            reportUnexpectedLogBoxError(error);
174        }
175    });
176}
177exports.addLog = addLog;
178function addException(error) {
179    // Parsing logs are expensive so we schedule this
180    // otherwise spammy logs would pause rendering.
181    setImmediate(() => {
182        try {
183            appendNewLog(new LogBoxLog_1.LogBoxLog((0, parseLogBoxLog_1.parseLogBoxException)(error)));
184        }
185        catch (loggingError) {
186            reportUnexpectedLogBoxError(loggingError);
187        }
188    });
189}
190exports.addException = addException;
191function symbolicateLogNow(type, log) {
192    log.symbolicate(type, () => {
193        handleUpdate();
194    });
195}
196exports.symbolicateLogNow = symbolicateLogNow;
197function retrySymbolicateLogNow(type, log) {
198    log.retrySymbolicate(type, () => {
199        handleUpdate();
200    });
201}
202exports.retrySymbolicateLogNow = retrySymbolicateLogNow;
203function symbolicateLogLazy(type, log) {
204    log.symbolicate(type);
205}
206exports.symbolicateLogLazy = symbolicateLogLazy;
207function clear() {
208    if (logs.size > 0) {
209        logs = new Set();
210        setSelectedLog(-1);
211    }
212}
213exports.clear = clear;
214function setSelectedLog(proposedNewIndex) {
215    const oldIndex = _selectedIndex;
216    let newIndex = proposedNewIndex;
217    const logArray = Array.from(logs);
218    let index = logArray.length - 1;
219    while (index >= 0) {
220        // The latest syntax error is selected and displayed before all other logs.
221        if (logArray[index].level === 'syntax') {
222            newIndex = index;
223            break;
224        }
225        index -= 1;
226    }
227    _selectedIndex = newIndex;
228    handleUpdate();
229    if (NativeLogBox_1.default) {
230        setTimeout(() => {
231            if (oldIndex < 0 && newIndex >= 0) {
232                NativeLogBox_1.default.show();
233            }
234            else if (oldIndex >= 0 && newIndex < 0) {
235                NativeLogBox_1.default.hide();
236            }
237        }, 0);
238    }
239}
240exports.setSelectedLog = setSelectedLog;
241function clearWarnings() {
242    const newLogs = Array.from(logs).filter((log) => log.level !== 'warn');
243    if (newLogs.length !== logs.size) {
244        logs = new Set(newLogs);
245        setSelectedLog(-1);
246        handleUpdate();
247    }
248}
249exports.clearWarnings = clearWarnings;
250function clearErrors() {
251    const newLogs = Array.from(logs).filter((log) => log.level !== 'error' && log.level !== 'fatal');
252    if (newLogs.length !== logs.size) {
253        logs = new Set(newLogs);
254        setSelectedLog(-1);
255    }
256}
257exports.clearErrors = clearErrors;
258function dismiss(log) {
259    if (logs.has(log)) {
260        logs.delete(log);
261        handleUpdate();
262    }
263}
264exports.dismiss = dismiss;
265function getIgnorePatterns() {
266    return Array.from(ignorePatterns);
267}
268exports.getIgnorePatterns = getIgnorePatterns;
269function addIgnorePatterns(patterns) {
270    const existingSize = ignorePatterns.size;
271    // The same pattern may be added multiple times, but adding a new pattern
272    // can be expensive so let's find only the ones that are new.
273    patterns.forEach((pattern) => {
274        if (pattern instanceof RegExp) {
275            for (const existingPattern of ignorePatterns) {
276                if (existingPattern instanceof RegExp &&
277                    existingPattern.toString() === pattern.toString()) {
278                    return;
279                }
280            }
281            ignorePatterns.add(pattern);
282        }
283        ignorePatterns.add(pattern);
284    });
285    if (ignorePatterns.size === existingSize) {
286        return;
287    }
288    // We need to recheck all of the existing logs.
289    // This allows adding an ignore pattern anywhere in the codebase.
290    // Without this, if you ignore a pattern after the a log is created,
291    // then we would keep showing the log.
292    logs = new Set(Array.from(logs).filter((log) => !isMessageIgnored(log.message.content)));
293    handleUpdate();
294}
295exports.addIgnorePatterns = addIgnorePatterns;
296function setDisabled(value) {
297    if (value === _isDisabled) {
298        return;
299    }
300    _isDisabled = value;
301    handleUpdate();
302}
303exports.setDisabled = setDisabled;
304function isDisabled() {
305    return _isDisabled;
306}
307exports.isDisabled = isDisabled;
308function observe(observer) {
309    const subscription = { observer };
310    observers.add(subscription);
311    observer(getNextState());
312    return {
313        unsubscribe() {
314            observers.delete(subscription);
315        },
316    };
317}
318exports.observe = observe;
319function withSubscription(WrappedComponent) {
320    class LogBoxStateSubscription extends React.Component {
321        static getDerivedStateFromError() {
322            return { hasError: true };
323        }
324        componentDidCatch(err, errorInfo) {
325            /* $FlowFixMe[class-object-subtyping] added when improving typing for
326             * this parameters */
327            reportLogBoxError(err, errorInfo.componentStack);
328        }
329        _subscription;
330        state = {
331            logs: new Set(),
332            isDisabled: false,
333            hasError: false,
334            selectedLogIndex: -1,
335        };
336        render() {
337            if (this.state.hasError) {
338                // This happens when the component failed to render, in which case we delegate to the native redbox.
339                // We can't show any fallback UI here, because the error may be with <View> or <Text>.
340                return null;
341            }
342            return (React.createElement(LogContext_1.LogContext.Provider, { value: {
343                    selectedLogIndex: this.state.selectedLogIndex,
344                    isDisabled: this.state.isDisabled,
345                    logs: Array.from(this.state.logs),
346                } },
347                this.props.children,
348                React.createElement(WrappedComponent, null)));
349        }
350        componentDidMount() {
351            this._subscription = observe((data) => {
352                this.setState(data);
353            });
354        }
355        componentWillUnmount() {
356            if (this._subscription != null) {
357                this._subscription.unsubscribe();
358            }
359        }
360        _handleDismiss = () => {
361            // Here we handle the cases when the log is dismissed and it
362            // was either the last log, or when the current index
363            // is now outside the bounds of the log array.
364            const { selectedLogIndex, logs: stateLogs } = this.state;
365            const logsArray = Array.from(stateLogs);
366            if (selectedLogIndex != null) {
367                if (logsArray.length - 1 <= 0) {
368                    setSelectedLog(-1);
369                }
370                else if (selectedLogIndex >= logsArray.length - 1) {
371                    setSelectedLog(selectedLogIndex - 1);
372                }
373                dismiss(logsArray[selectedLogIndex]);
374            }
375        };
376        _handleMinimize = () => {
377            setSelectedLog(-1);
378        };
379        _handleSetSelectedLog = (index) => {
380            setSelectedLog(index);
381        };
382    }
383    // @ts-expect-error
384    return LogBoxStateSubscription;
385}
386exports.withSubscription = withSubscription;
387//# sourceMappingURL=LogBoxData.js.map