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