1 | Object.defineProperty(exports, '__esModule', { value: true });
|
2 |
|
3 | const utils = require('@sentry/utils');
|
4 |
|
5 |
|
6 | const UNKNOWN_FUNCTION = '?';
|
7 |
|
8 | const OPERA10_PRIORITY = 10;
|
9 | const OPERA11_PRIORITY = 20;
|
10 | const CHROME_PRIORITY = 30;
|
11 | const WINJS_PRIORITY = 40;
|
12 | const GECKO_PRIORITY = 50;
|
13 |
|
14 | function 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 |
|
33 | const chromeRegex =
|
34 | /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
|
35 | const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
|
36 |
|
37 | const 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 |
|
64 | const 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.
|
69 | const geckoREgex =
|
70 | /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
|
71 | const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
|
72 |
|
73 | const 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 |
|
100 | const geckoStackLineParser = [GECKO_PRIORITY, gecko];
|
101 |
|
102 | const winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
|
103 |
|
104 | const 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 |
|
112 | const winjsStackLineParser = [WINJS_PRIORITY, winjs];
|
113 |
|
114 | const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
|
115 |
|
116 | const opera10 = line => {
|
117 | const parts = opera10Regex.exec(line);
|
118 | return parts ? createFrame(parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;
|
119 | };
|
120 |
|
121 | const opera10StackLineParser = [OPERA10_PRIORITY, opera10];
|
122 |
|
123 | const opera11Regex =
|
124 | / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
|
125 |
|
126 | const 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 |
|
131 | const opera11StackLineParser = [OPERA11_PRIORITY, opera11];
|
132 |
|
133 | const defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser, winjsStackLineParser];
|
134 |
|
135 | const 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 | */
|
157 | const 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 |
|
169 | exports.chromeStackLineParser = chromeStackLineParser;
|
170 | exports.defaultStackLineParsers = defaultStackLineParsers;
|
171 | exports.defaultStackParser = defaultStackParser;
|
172 | exports.geckoStackLineParser = geckoStackLineParser;
|
173 | exports.opera10StackLineParser = opera10StackLineParser;
|
174 | exports.opera11StackLineParser = opera11StackLineParser;
|
175 | exports.winjsStackLineParser = winjsStackLineParser;
|
176 | //# sourceMappingURL=stack-parsers.js.map
|