1a5fb1ba8SEvan Bacon"use strict";
226ad19fcSEvan Bacon/**
326ad19fcSEvan Bacon * Copyright (c) 650 Industries.
426ad19fcSEvan Bacon * Copyright (c) Meta Platforms, Inc. and affiliates.
526ad19fcSEvan Bacon *
626ad19fcSEvan Bacon * This source code is licensed under the MIT license found in the
726ad19fcSEvan Bacon * LICENSE file in the root directory of this source tree.
826ad19fcSEvan Bacon */
9a5fb1ba8SEvan Baconvar __importDefault = (this && this.__importDefault) || function (mod) {
10a5fb1ba8SEvan Bacon    return (mod && mod.__esModule) ? mod : { "default": mod };
11a5fb1ba8SEvan Bacon};
12a5fb1ba8SEvan BaconObject.defineProperty(exports, "__esModule", { value: true });
13a5fb1ba8SEvan Baconexports.parseLogBoxLog = exports.parseLogBoxException = exports.parseComponentStack = exports.parseInterpolation = void 0;
14a5fb1ba8SEvan Baconconst parseErrorStack_1 = __importDefault(require("../modules/parseErrorStack"));
15a5fb1ba8SEvan Baconconst stringifySafe_1 = __importDefault(require("../modules/stringifySafe"));
1626ad19fcSEvan Baconconst BABEL_TRANSFORM_ERROR_FORMAT = /^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;
1726ad19fcSEvan Baconconst BABEL_CODE_FRAME_ERROR_FORMAT = /^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;
1826ad19fcSEvan Baconconst METRO_ERROR_FORMAT = /^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;
19*4a8c0978SEvan Baconconst SUBSTITUTION = '\ufeff%s';
20a5fb1ba8SEvan Baconfunction parseInterpolation(args) {
2126ad19fcSEvan Bacon    const categoryParts = [];
2226ad19fcSEvan Bacon    const contentParts = [];
2326ad19fcSEvan Bacon    const substitutionOffsets = [];
2426ad19fcSEvan Bacon    const remaining = [...args];
2526ad19fcSEvan Bacon    if (typeof remaining[0] === 'string') {
2626ad19fcSEvan Bacon        const formatString = String(remaining.shift());
2726ad19fcSEvan Bacon        const formatStringParts = formatString.split('%s');
2826ad19fcSEvan Bacon        const substitutionCount = formatStringParts.length - 1;
2926ad19fcSEvan Bacon        const substitutions = remaining.splice(0, substitutionCount);
3026ad19fcSEvan Bacon        let categoryString = '';
3126ad19fcSEvan Bacon        let contentString = '';
3226ad19fcSEvan Bacon        let substitutionIndex = 0;
3326ad19fcSEvan Bacon        for (const formatStringPart of formatStringParts) {
3426ad19fcSEvan Bacon            categoryString += formatStringPart;
3526ad19fcSEvan Bacon            contentString += formatStringPart;
3626ad19fcSEvan Bacon            if (substitutionIndex < substitutionCount) {
3726ad19fcSEvan Bacon                if (substitutionIndex < substitutions.length) {
3826ad19fcSEvan Bacon                    // Don't stringify a string type.
3926ad19fcSEvan Bacon                    // It adds quotation mark wrappers around the string,
4026ad19fcSEvan Bacon                    // which causes the LogBox to look odd.
4126ad19fcSEvan Bacon                    const substitution = typeof substitutions[substitutionIndex] === 'string'
4226ad19fcSEvan Bacon                        ? substitutions[substitutionIndex]
43a5fb1ba8SEvan Bacon                        : (0, stringifySafe_1.default)(substitutions[substitutionIndex]);
4426ad19fcSEvan Bacon                    substitutionOffsets.push({
4526ad19fcSEvan Bacon                        length: substitution.length,
4626ad19fcSEvan Bacon                        offset: contentString.length,
4726ad19fcSEvan Bacon                    });
4826ad19fcSEvan Bacon                    categoryString += SUBSTITUTION;
4926ad19fcSEvan Bacon                    contentString += substitution;
5026ad19fcSEvan Bacon                }
5126ad19fcSEvan Bacon                else {
5226ad19fcSEvan Bacon                    substitutionOffsets.push({
5326ad19fcSEvan Bacon                        length: 2,
5426ad19fcSEvan Bacon                        offset: contentString.length,
5526ad19fcSEvan Bacon                    });
5626ad19fcSEvan Bacon                    categoryString += '%s';
5726ad19fcSEvan Bacon                    contentString += '%s';
5826ad19fcSEvan Bacon                }
5926ad19fcSEvan Bacon                substitutionIndex++;
6026ad19fcSEvan Bacon            }
6126ad19fcSEvan Bacon        }
6226ad19fcSEvan Bacon        categoryParts.push(categoryString);
6326ad19fcSEvan Bacon        contentParts.push(contentString);
6426ad19fcSEvan Bacon    }
6526ad19fcSEvan Bacon    const remainingArgs = remaining.map((arg) => {
6626ad19fcSEvan Bacon        // Don't stringify a string type.
6726ad19fcSEvan Bacon        // It adds quotation mark wrappers around the string,
6826ad19fcSEvan Bacon        // which causes the LogBox to look odd.
69a5fb1ba8SEvan Bacon        return typeof arg === 'string' ? arg : (0, stringifySafe_1.default)(arg);
7026ad19fcSEvan Bacon    });
7126ad19fcSEvan Bacon    categoryParts.push(...remainingArgs);
7226ad19fcSEvan Bacon    contentParts.push(...remainingArgs);
7326ad19fcSEvan Bacon    return {
7426ad19fcSEvan Bacon        category: categoryParts.join(' '),
7526ad19fcSEvan Bacon        message: {
7626ad19fcSEvan Bacon            content: contentParts.join(' '),
7726ad19fcSEvan Bacon            substitutions: substitutionOffsets,
7826ad19fcSEvan Bacon        },
7926ad19fcSEvan Bacon    };
8026ad19fcSEvan Bacon}
81a5fb1ba8SEvan Baconexports.parseInterpolation = parseInterpolation;
8226ad19fcSEvan Baconfunction isComponentStack(consoleArgument) {
8326ad19fcSEvan Bacon    const isOldComponentStackFormat = / {4}in/.test(consoleArgument);
8426ad19fcSEvan Bacon    const isNewComponentStackFormat = / {4}at/.test(consoleArgument);
8526ad19fcSEvan Bacon    const isNewJSCComponentStackFormat = /@.*\n/.test(consoleArgument);
8626ad19fcSEvan Bacon    return isOldComponentStackFormat || isNewComponentStackFormat || isNewJSCComponentStackFormat;
8726ad19fcSEvan Bacon}
88a5fb1ba8SEvan Baconfunction parseComponentStack(message) {
8926ad19fcSEvan Bacon    // In newer versions of React, the component stack is formatted as a call stack frame.
9026ad19fcSEvan Bacon    // First try to parse the component stack as a call stack frame, and if that doesn't
9126ad19fcSEvan Bacon    // work then we'll fallback to the old custom component stack format parsing.
92a5fb1ba8SEvan Bacon    const stack = (0, parseErrorStack_1.default)(message);
9326ad19fcSEvan Bacon    if (stack && stack.length > 0) {
9426ad19fcSEvan Bacon        return stack.map((frame) => ({
9526ad19fcSEvan Bacon            content: frame.methodName,
9626ad19fcSEvan Bacon            collapse: frame.collapse || false,
9726ad19fcSEvan Bacon            fileName: frame.file == null ? 'unknown' : frame.file,
9826ad19fcSEvan Bacon            location: {
9926ad19fcSEvan Bacon                column: frame.column == null ? -1 : frame.column,
10026ad19fcSEvan Bacon                row: frame.lineNumber == null ? -1 : frame.lineNumber,
10126ad19fcSEvan Bacon            },
10226ad19fcSEvan Bacon        }));
10326ad19fcSEvan Bacon    }
10426ad19fcSEvan Bacon    return message
10526ad19fcSEvan Bacon        .split(/\n {4}in /g)
10626ad19fcSEvan Bacon        .map((s) => {
10726ad19fcSEvan Bacon        if (!s) {
10826ad19fcSEvan Bacon            return null;
10926ad19fcSEvan Bacon        }
11026ad19fcSEvan Bacon        const match = s.match(/(.*) \(at (.*\.js):([\d]+)\)/);
11126ad19fcSEvan Bacon        if (!match) {
11226ad19fcSEvan Bacon            return null;
11326ad19fcSEvan Bacon        }
11426ad19fcSEvan Bacon        const [content, fileName, row] = match.slice(1);
11526ad19fcSEvan Bacon        return {
11626ad19fcSEvan Bacon            content,
11726ad19fcSEvan Bacon            fileName,
11826ad19fcSEvan Bacon            location: { column: -1, row: parseInt(row, 10) },
11926ad19fcSEvan Bacon        };
12026ad19fcSEvan Bacon    })
12126ad19fcSEvan Bacon        .filter(Boolean);
12226ad19fcSEvan Bacon}
123a5fb1ba8SEvan Baconexports.parseComponentStack = parseComponentStack;
124a5fb1ba8SEvan Baconfunction parseLogBoxException(error) {
12526ad19fcSEvan Bacon    const message = error.originalMessage != null ? error.originalMessage : 'Unknown';
12626ad19fcSEvan Bacon    const metroInternalError = message.match(METRO_ERROR_FORMAT);
12726ad19fcSEvan Bacon    if (metroInternalError) {
12826ad19fcSEvan Bacon        const [content, fileName, row, column, codeFrame] = metroInternalError.slice(1);
12926ad19fcSEvan Bacon        return {
13026ad19fcSEvan Bacon            level: 'fatal',
13126ad19fcSEvan Bacon            type: 'Metro Error',
13226ad19fcSEvan Bacon            stack: [],
13326ad19fcSEvan Bacon            isComponentError: false,
13426ad19fcSEvan Bacon            componentStack: [],
13526ad19fcSEvan Bacon            codeFrame: {
13626ad19fcSEvan Bacon                fileName,
13726ad19fcSEvan Bacon                location: {
13826ad19fcSEvan Bacon                    row: parseInt(row, 10),
13926ad19fcSEvan Bacon                    column: parseInt(column, 10),
14026ad19fcSEvan Bacon                },
14126ad19fcSEvan Bacon                content: codeFrame,
14226ad19fcSEvan Bacon            },
14326ad19fcSEvan Bacon            message: {
14426ad19fcSEvan Bacon                content,
14526ad19fcSEvan Bacon                substitutions: [],
14626ad19fcSEvan Bacon            },
14726ad19fcSEvan Bacon            category: `${fileName}-${row}-${column}`,
14826ad19fcSEvan Bacon        };
14926ad19fcSEvan Bacon    }
15026ad19fcSEvan Bacon    const babelTransformError = message.match(BABEL_TRANSFORM_ERROR_FORMAT);
15126ad19fcSEvan Bacon    if (babelTransformError) {
15226ad19fcSEvan Bacon        // Transform errors are thrown from inside the Babel transformer.
15326ad19fcSEvan Bacon        const [fileName, content, row, column, codeFrame] = babelTransformError.slice(1);
15426ad19fcSEvan Bacon        return {
15526ad19fcSEvan Bacon            level: 'syntax',
15626ad19fcSEvan Bacon            stack: [],
15726ad19fcSEvan Bacon            isComponentError: false,
15826ad19fcSEvan Bacon            componentStack: [],
15926ad19fcSEvan Bacon            codeFrame: {
16026ad19fcSEvan Bacon                fileName,
16126ad19fcSEvan Bacon                location: {
16226ad19fcSEvan Bacon                    row: parseInt(row, 10),
16326ad19fcSEvan Bacon                    column: parseInt(column, 10),
16426ad19fcSEvan Bacon                },
16526ad19fcSEvan Bacon                content: codeFrame,
16626ad19fcSEvan Bacon            },
16726ad19fcSEvan Bacon            message: {
16826ad19fcSEvan Bacon                content,
16926ad19fcSEvan Bacon                substitutions: [],
17026ad19fcSEvan Bacon            },
17126ad19fcSEvan Bacon            category: `${fileName}-${row}-${column}`,
17226ad19fcSEvan Bacon        };
17326ad19fcSEvan Bacon    }
17426ad19fcSEvan Bacon    const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
17526ad19fcSEvan Bacon    if (babelCodeFrameError) {
17626ad19fcSEvan Bacon        // Codeframe errors are thrown from any use of buildCodeFrameError.
17726ad19fcSEvan Bacon        const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
17826ad19fcSEvan Bacon        return {
17926ad19fcSEvan Bacon            level: 'syntax',
18026ad19fcSEvan Bacon            stack: [],
18126ad19fcSEvan Bacon            isComponentError: false,
18226ad19fcSEvan Bacon            componentStack: [],
18326ad19fcSEvan Bacon            codeFrame: {
18426ad19fcSEvan Bacon                fileName,
18526ad19fcSEvan Bacon                location: null,
18626ad19fcSEvan Bacon                content: codeFrame,
18726ad19fcSEvan Bacon            },
18826ad19fcSEvan Bacon            message: {
18926ad19fcSEvan Bacon                content,
19026ad19fcSEvan Bacon                substitutions: [],
19126ad19fcSEvan Bacon            },
19226ad19fcSEvan Bacon            category: `${fileName}-${1}-${1}`,
19326ad19fcSEvan Bacon        };
19426ad19fcSEvan Bacon    }
19526ad19fcSEvan Bacon    if (message.match(/^TransformError /)) {
19626ad19fcSEvan Bacon        return {
19726ad19fcSEvan Bacon            level: 'syntax',
19826ad19fcSEvan Bacon            stack: error.stack,
19926ad19fcSEvan Bacon            isComponentError: error.isComponentError,
20026ad19fcSEvan Bacon            componentStack: [],
20126ad19fcSEvan Bacon            message: {
20226ad19fcSEvan Bacon                content: message,
20326ad19fcSEvan Bacon                substitutions: [],
20426ad19fcSEvan Bacon            },
20526ad19fcSEvan Bacon            category: message,
20626ad19fcSEvan Bacon        };
20726ad19fcSEvan Bacon    }
20826ad19fcSEvan Bacon    const componentStack = error.componentStack;
20926ad19fcSEvan Bacon    if (error.isFatal || error.isComponentError) {
21026ad19fcSEvan Bacon        return {
21126ad19fcSEvan Bacon            level: 'fatal',
21226ad19fcSEvan Bacon            stack: error.stack,
21326ad19fcSEvan Bacon            isComponentError: error.isComponentError,
21426ad19fcSEvan Bacon            componentStack: componentStack != null ? parseComponentStack(componentStack) : [],
21526ad19fcSEvan Bacon            ...parseInterpolation([message]),
21626ad19fcSEvan Bacon        };
21726ad19fcSEvan Bacon    }
21826ad19fcSEvan Bacon    if (componentStack != null) {
21926ad19fcSEvan Bacon        // It is possible that console errors have a componentStack.
22026ad19fcSEvan Bacon        return {
22126ad19fcSEvan Bacon            level: 'error',
22226ad19fcSEvan Bacon            stack: error.stack,
22326ad19fcSEvan Bacon            isComponentError: error.isComponentError,
22426ad19fcSEvan Bacon            componentStack: parseComponentStack(componentStack),
22526ad19fcSEvan Bacon            ...parseInterpolation([message]),
22626ad19fcSEvan Bacon        };
22726ad19fcSEvan Bacon    }
22826ad19fcSEvan Bacon    // Most `console.error` calls won't have a componentStack. We parse them like
22926ad19fcSEvan Bacon    // regular logs which have the component stack burried in the message.
23026ad19fcSEvan Bacon    return {
23126ad19fcSEvan Bacon        level: 'error',
23226ad19fcSEvan Bacon        stack: error.stack,
23326ad19fcSEvan Bacon        isComponentError: error.isComponentError,
23426ad19fcSEvan Bacon        ...parseLogBoxLog([message]),
23526ad19fcSEvan Bacon    };
23626ad19fcSEvan Bacon}
237a5fb1ba8SEvan Baconexports.parseLogBoxException = parseLogBoxException;
238a5fb1ba8SEvan Baconfunction parseLogBoxLog(args) {
23926ad19fcSEvan Bacon    const message = args[0];
24026ad19fcSEvan Bacon    let argsWithoutComponentStack = [];
24126ad19fcSEvan Bacon    let componentStack = [];
24226ad19fcSEvan Bacon    // Extract component stack from warnings like "Some warning%s".
24326ad19fcSEvan Bacon    if (typeof message === 'string' && message.slice(-2) === '%s' && args.length > 0) {
24426ad19fcSEvan Bacon        const lastArg = args[args.length - 1];
24526ad19fcSEvan Bacon        if (typeof lastArg === 'string' && isComponentStack(lastArg)) {
24626ad19fcSEvan Bacon            argsWithoutComponentStack = args.slice(0, -1);
24726ad19fcSEvan Bacon            argsWithoutComponentStack[0] = message.slice(0, -2);
24826ad19fcSEvan Bacon            componentStack = parseComponentStack(lastArg);
24926ad19fcSEvan Bacon        }
25026ad19fcSEvan Bacon    }
25126ad19fcSEvan Bacon    if (componentStack.length === 0) {
25226ad19fcSEvan Bacon        // Try finding the component stack elsewhere.
25326ad19fcSEvan Bacon        for (const arg of args) {
25426ad19fcSEvan Bacon            if (typeof arg === 'string' && isComponentStack(arg)) {
25526ad19fcSEvan Bacon                // Strip out any messages before the component stack.
25626ad19fcSEvan Bacon                let messageEndIndex = arg.search(/\n {4}(in|at) /);
25726ad19fcSEvan Bacon                if (messageEndIndex < 0) {
25826ad19fcSEvan Bacon                    // Handle JSC component stacks.
25926ad19fcSEvan Bacon                    messageEndIndex = arg.search(/\n/);
26026ad19fcSEvan Bacon                }
26126ad19fcSEvan Bacon                if (messageEndIndex > 0) {
26226ad19fcSEvan Bacon                    argsWithoutComponentStack.push(arg.slice(0, messageEndIndex));
26326ad19fcSEvan Bacon                }
26426ad19fcSEvan Bacon                componentStack = parseComponentStack(arg);
26526ad19fcSEvan Bacon            }
26626ad19fcSEvan Bacon            else {
26726ad19fcSEvan Bacon                argsWithoutComponentStack.push(arg);
26826ad19fcSEvan Bacon            }
26926ad19fcSEvan Bacon        }
27026ad19fcSEvan Bacon    }
27126ad19fcSEvan Bacon    return {
27226ad19fcSEvan Bacon        ...parseInterpolation(argsWithoutComponentStack),
27326ad19fcSEvan Bacon        componentStack,
27426ad19fcSEvan Bacon    };
27526ad19fcSEvan Bacon}
276a5fb1ba8SEvan Baconexports.parseLogBoxLog = parseLogBoxLog;
27726ad19fcSEvan Bacon//# sourceMappingURL=parseLogBoxLog.js.map