package.build.npm.cjs.stack-parsers.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of browser Show documentation
Show all versions of browser Show documentation
Official Sentry SDK for browsers
Object.defineProperty(exports, '__esModule', { value: true });
const utils = require('@sentry/utils');
const OPERA10_PRIORITY = 10;
const OPERA11_PRIORITY = 20;
const CHROME_PRIORITY = 30;
const WINJS_PRIORITY = 40;
const GECKO_PRIORITY = 50;
function createFrame(filename, func, lineno, colno) {
const frame = {
filename,
function: func === '' ? utils.UNKNOWN_FUNCTION : func,
in_app: true, // All browser frames are considered in_app
};
if (lineno !== undefined) {
frame.lineno = lineno;
}
if (colno !== undefined) {
frame.colno = colno;
}
return frame;
}
// This regex matches frames that have no function name (ie. are at the top level of a module).
// For example "at http://localhost:5000//script.js:1:126"
// Frames _with_ function names usually look as follows: "at commitLayoutEffects (react-dom.development.js:23426:1)"
const chromeRegexNoFnName = /^\s*at (\S+?)(?::(\d+))(?::(\d+))\s*$/i;
// This regex matches all the frames that have a function name.
const chromeRegex =
/^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
// We cannot call this variable `chrome` because it can conflict with global `chrome` variable in certain environments
// See: https://github.com/getsentry/sentry-javascript/issues/6880
const chromeStackParserFn = line => {
// If the stack line has no function name, we need to parse it differently
const noFnParts = chromeRegexNoFnName.exec(line) ;
if (noFnParts) {
const [, filename, line, col] = noFnParts;
return createFrame(filename, utils.UNKNOWN_FUNCTION, +line, +col);
}
const parts = chromeRegex.exec(line) ;
if (parts) {
const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
if (isEval) {
const 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] || utils.UNKNOWN_FUNCTION, parts[2]);
return createFrame(filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);
}
return;
};
const chromeStackLineParser = [CHROME_PRIORITY, chromeStackParserFn];
// 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.
const geckoREgex =
/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
const gecko = line => {
const parts = geckoREgex.exec(line) ;
if (parts) {
const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
if (isEval) {
const 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] || utils.UNKNOWN_FUNCTION;
[func, filename] = extractSafariExtensionDetails(func, filename);
return createFrame(filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);
}
return;
};
const geckoStackLineParser = [GECKO_PRIORITY, gecko];
const winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
const winjs = line => {
const parts = winjsRegex.exec(line) ;
return parts
? createFrame(parts[2], parts[1] || utils.UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined)
: undefined;
};
const winjsStackLineParser = [WINJS_PRIORITY, winjs];
const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
const opera10 = line => {
const parts = opera10Regex.exec(line) ;
return parts ? createFrame(parts[2], parts[3] || utils.UNKNOWN_FUNCTION, +parts[1]) : undefined;
};
const opera10StackLineParser = [OPERA10_PRIORITY, opera10];
const opera11Regex =
/ line (\d+), column (\d+)\s*(?:in (?:]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
const opera11 = line => {
const parts = opera11Regex.exec(line) ;
return parts ? createFrame(parts[5], parts[3] || parts[4] || utils.UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;
};
const opera11StackLineParser = [OPERA11_PRIORITY, opera11];
const defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser];
const defaultStackParser = utils.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.
*/
const extractSafariExtensionDetails = (func, filename) => {
const isSafariExtension = func.indexOf('safari-extension') !== -1;
const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;
return isSafariExtension || isSafariWebExtension
? [
func.indexOf('@') !== -1 ? (func.split('@')[0] ) : utils.UNKNOWN_FUNCTION,
isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`,
]
: [func, filename];
};
exports.chromeStackLineParser = chromeStackLineParser;
exports.defaultStackLineParsers = defaultStackLineParsers;
exports.defaultStackParser = defaultStackParser;
exports.geckoStackLineParser = geckoStackLineParser;
exports.opera10StackLineParser = opera10StackLineParser;
exports.opera11StackLineParser = opera11StackLineParser;
exports.winjsStackLineParser = winjsStackLineParser;
//# sourceMappingURL=stack-parsers.js.map