@sentry/browser
Version:
Official Sentry SDK for browsers
171 lines (132 loc) • 5.85 kB
JavaScript
import { createStackParser } from '@sentry/utils';
// global reference to slice
var UNKNOWN_FUNCTION = '?';
var OPERA10_PRIORITY = 10;
var OPERA11_PRIORITY = 20;
var CHROME_PRIORITY = 30;
var WINJS_PRIORITY = 40;
var GECKO_PRIORITY = 50;
function createFrame(filename, func, lineno, colno) {
var frame = {
filename,
function: func,
// All browser frames are considered in_app
in_app: true,
};
if (lineno !== undefined) {
frame.lineno = lineno;
}
if (colno !== undefined) {
frame.colno = colno;
}
return frame;
}
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
var chromeRegex =
/^\s*at (?:(.*?) ?\((?:address at )?)?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
var chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
var chrome = line => {
var parts = chromeRegex.exec(line);
if (parts) {
var isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
if (isEval) {
var subMatch = chromeEvalRegex.exec(parts[2]);
if (subMatch) {
// throw out eval line/column and use top-most line/column number
parts[2] = subMatch[1]; // url
parts[3] = subMatch[2]; // line
parts[4] = subMatch[3]; // column
}
}
// Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now
// would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)
const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);
return createFrame(filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);
}
return;
};
var chromeStackLineParser = [CHROME_PRIORITY, chrome];
// gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it
// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
// We need this specific case for now because we want no other regex to match.
var geckoREgex =
/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpack|resource|moz-extension|capacitor).*?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
var geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
var gecko = line => {
var parts = geckoREgex.exec(line);
if (parts) {
var isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
if (isEval) {
var subMatch = geckoEvalRegex.exec(parts[3]);
if (subMatch) {
// throw out eval line/column and use top-most line number
parts[1] = parts[1] || 'eval';
parts[3] = subMatch[1];
parts[4] = subMatch[2];
parts[5] = ''; // no column when eval
}
}
let filename = parts[3];
let func = parts[1] || UNKNOWN_FUNCTION;
[func, filename] = extractSafariExtensionDetails(func, filename);
return createFrame(filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);
}
return;
};
var geckoStackLineParser = [GECKO_PRIORITY, gecko];
var winjsRegex =
/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
var winjs = line => {
var parts = winjsRegex.exec(line);
return parts
? createFrame(parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined)
: undefined;
};
var winjsStackLineParser = [WINJS_PRIORITY, winjs];
var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
var opera10 = line => {
var parts = opera10Regex.exec(line);
return parts ? createFrame(parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;
};
var opera10StackLineParser = [OPERA10_PRIORITY, opera10];
var opera11Regex =
/ line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
var opera11 = line => {
var parts = opera11Regex.exec(line);
return parts ? createFrame(parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;
};
var opera11StackLineParser = [OPERA11_PRIORITY, opera11];
var defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser, winjsStackLineParser];
var defaultStackParser = createStackParser(...defaultStackLineParsers);
/**
* Safari web extensions, starting version unknown, can produce "frames-only" stacktraces.
* What it means, is that instead of format like:
*
* Error: wat
* at function@url:row:col
* at function@url:row:col
* at function@url:row:col
*
* it produces something like:
*
* function@url:row:col
* function@url:row:col
* function@url:row:col
*
* Because of that, it won't be captured by `chrome` RegExp and will fall into `Gecko` branch.
* This function is extracted so that we can use it in both places without duplicating the logic.
* Unfortunately "just" changing RegExp is too complicated now and making it pass all tests
* and fix this case seems like an impossible, or at least way too time-consuming task.
*/
var extractSafariExtensionDetails = (func, filename) => {
var isSafariExtension = func.indexOf('safari-extension') !== -1;
var isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;
return isSafariExtension || isSafariWebExtension
? [
func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION,
isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`,
]
: [func, filename];
};
export { chromeStackLineParser, defaultStackLineParsers, defaultStackParser, geckoStackLineParser, opera10StackLineParser, opera11StackLineParser, winjsStackLineParser };
//# sourceMappingURL=stack-parsers.js.map