UNPKG

6.08 kBJavaScriptView Raw
1Object.defineProperty(exports, '__esModule', { value: true });
2
3const utils = require('@sentry/utils');
4
5// global reference to slice
6const UNKNOWN_FUNCTION = '?';
7
8const OPERA10_PRIORITY = 10;
9const OPERA11_PRIORITY = 20;
10const CHROME_PRIORITY = 30;
11const WINJS_PRIORITY = 40;
12const GECKO_PRIORITY = 50;
13
14function createFrame(filename, func, lineno, colno) {
15 const frame = {
16 filename,
17 function: func,
18 in_app: true, // All browser frames are considered in_app
19 };
20
21 if (lineno !== undefined) {
22 frame.lineno = lineno;
23 }
24
25 if (colno !== undefined) {
26 frame.colno = colno;
27 }
28
29 return frame;
30}
31
32// Chromium based browsers: Chrome, Brave, new Opera, new Edge
33const chromeRegex =
34 /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
35const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
36
37const chrome = line => {
38 const parts = chromeRegex.exec(line);
39
40 if (parts) {
41 const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
42
43 if (isEval) {
44 const subMatch = chromeEvalRegex.exec(parts[2]);
45
46 if (subMatch) {
47 // throw out eval line/column and use top-most line/column number
48 parts[2] = subMatch[1]; // url
49 parts[3] = subMatch[2]; // line
50 parts[4] = subMatch[3]; // column
51 }
52 }
53
54 // Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now
55 // would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)
56 const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);
57
58 return createFrame(filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);
59 }
60
61 return;
62};
63
64const chromeStackLineParser = [CHROME_PRIORITY, chrome];
65
66// gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it
67// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
68// We need this specific case for now because we want no other regex to match.
69const geckoREgex =
70 /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
71const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
72
73const gecko = line => {
74 const parts = geckoREgex.exec(line);
75
76 if (parts) {
77 const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
78 if (isEval) {
79 const subMatch = geckoEvalRegex.exec(parts[3]);
80
81 if (subMatch) {
82 // throw out eval line/column and use top-most line number
83 parts[1] = parts[1] || 'eval';
84 parts[3] = subMatch[1];
85 parts[4] = subMatch[2];
86 parts[5] = ''; // no column when eval
87 }
88 }
89
90 let filename = parts[3];
91 let func = parts[1] || UNKNOWN_FUNCTION;
92 [func, filename] = extractSafariExtensionDetails(func, filename);
93
94 return createFrame(filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);
95 }
96
97 return;
98};
99
100const geckoStackLineParser = [GECKO_PRIORITY, gecko];
101
102const winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
103
104const winjs = line => {
105 const parts = winjsRegex.exec(line);
106
107 return parts
108 ? createFrame(parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined)
109 : undefined;
110};
111
112const winjsStackLineParser = [WINJS_PRIORITY, winjs];
113
114const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
115
116const opera10 = line => {
117 const parts = opera10Regex.exec(line);
118 return parts ? createFrame(parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;
119};
120
121const opera10StackLineParser = [OPERA10_PRIORITY, opera10];
122
123const opera11Regex =
124 / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
125
126const opera11 = line => {
127 const parts = opera11Regex.exec(line);
128 return parts ? createFrame(parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;
129};
130
131const opera11StackLineParser = [OPERA11_PRIORITY, opera11];
132
133const defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser, winjsStackLineParser];
134
135const defaultStackParser = utils.createStackParser(...defaultStackLineParsers);
136
137/**
138 * Safari web extensions, starting version unknown, can produce "frames-only" stacktraces.
139 * What it means, is that instead of format like:
140 *
141 * Error: wat
142 * at function@url:row:col
143 * at function@url:row:col
144 * at function@url:row:col
145 *
146 * it produces something like:
147 *
148 * function@url:row:col
149 * function@url:row:col
150 * function@url:row:col
151 *
152 * Because of that, it won't be captured by `chrome` RegExp and will fall into `Gecko` branch.
153 * This function is extracted so that we can use it in both places without duplicating the logic.
154 * Unfortunately "just" changing RegExp is too complicated now and making it pass all tests
155 * and fix this case seems like an impossible, or at least way too time-consuming task.
156 */
157const extractSafariExtensionDetails = (func, filename) => {
158 const isSafariExtension = func.indexOf('safari-extension') !== -1;
159 const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;
160
161 return isSafariExtension || isSafariWebExtension
162 ? [
163 func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION,
164 isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`,
165 ]
166 : [func, filename];
167};
168
169exports.chromeStackLineParser = chromeStackLineParser;
170exports.defaultStackLineParsers = defaultStackLineParsers;
171exports.defaultStackParser = defaultStackParser;
172exports.geckoStackLineParser = geckoStackLineParser;
173exports.opera10StackLineParser = opera10StackLineParser;
174exports.opera11StackLineParser = opera11StackLineParser;
175exports.winjsStackLineParser = winjsStackLineParser;
176//# sourceMappingURL=stack-parsers.js.map