UNPKG

9.04 kBJavaScriptView Raw
1/**
2 * This was originally forked from https://github.com/occ/TraceKit, but has since been
3 * largely modified and is now maintained as part of Sentry JS SDK.
4 */
5import { __assign } from "tslib";
6// global reference to slice
7var UNKNOWN_FUNCTION = '?';
8// Chromium based browsers: Chrome, Brave, new Opera, new Edge
9var chrome = /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
10// gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it
11// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
12// We need this specific case for now because we want no other regex to match.
13var gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpack|resource|moz-extension|capacitor).*?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
14var winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
15var geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
16var chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/;
17// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108
18var reactMinifiedRegexp = /Minified React error #\d+;/i;
19/** JSDoc */
20// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
21export function computeStackTrace(ex) {
22 var stack = null;
23 var popSize = 0;
24 if (ex) {
25 if (typeof ex.framesToPop === 'number') {
26 popSize = ex.framesToPop;
27 }
28 else if (reactMinifiedRegexp.test(ex.message)) {
29 popSize = 1;
30 }
31 }
32 try {
33 // This must be tried first because Opera 10 *destroys*
34 // its stacktrace property if you try to access the stack
35 // property first!!
36 stack = computeStackTraceFromStacktraceProp(ex);
37 if (stack) {
38 return popFrames(stack, popSize);
39 }
40 }
41 catch (e) {
42 // no-empty
43 }
44 try {
45 stack = computeStackTraceFromStackProp(ex);
46 if (stack) {
47 return popFrames(stack, popSize);
48 }
49 }
50 catch (e) {
51 // no-empty
52 }
53 return {
54 message: extractMessage(ex),
55 name: ex && ex.name,
56 stack: [],
57 failed: true,
58 };
59}
60/** JSDoc */
61// eslint-disable-next-line @typescript-eslint/no-explicit-any, complexity
62function computeStackTraceFromStackProp(ex) {
63 if (!ex || !ex.stack) {
64 return null;
65 }
66 var stack = [];
67 var lines = ex.stack.split('\n');
68 var isEval;
69 var submatch;
70 var parts;
71 var element;
72 for (var i = 0; i < lines.length; ++i) {
73 if ((parts = chrome.exec(lines[i]))) {
74 var isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
75 isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
76 if (isEval && (submatch = chromeEval.exec(parts[2]))) {
77 // throw out eval line/column and use top-most line/column number
78 parts[2] = submatch[1]; // url
79 parts[3] = submatch[2]; // line
80 parts[4] = submatch[3]; // column
81 }
82 // Arpad: Working with the regexp above is super painful. it is quite a hack, but just stripping the `address at `
83 // prefix here seems like the quickest solution for now.
84 var url = parts[2] && parts[2].indexOf('address at ') === 0 ? parts[2].substr('address at '.length) : parts[2];
85 // Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now
86 // would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)
87 var func = parts[1] || UNKNOWN_FUNCTION;
88 var isSafariExtension = func.indexOf('safari-extension') !== -1;
89 var isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;
90 if (isSafariExtension || isSafariWebExtension) {
91 func = func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION;
92 url = isSafariExtension ? "safari-extension:" + url : "safari-web-extension:" + url;
93 }
94 element = {
95 url: url,
96 func: func,
97 args: isNative ? [parts[2]] : [],
98 line: parts[3] ? +parts[3] : null,
99 column: parts[4] ? +parts[4] : null,
100 };
101 }
102 else if ((parts = winjs.exec(lines[i]))) {
103 element = {
104 url: parts[2],
105 func: parts[1] || UNKNOWN_FUNCTION,
106 args: [],
107 line: +parts[3],
108 column: parts[4] ? +parts[4] : null,
109 };
110 }
111 else if ((parts = gecko.exec(lines[i]))) {
112 isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
113 if (isEval && (submatch = geckoEval.exec(parts[3]))) {
114 // throw out eval line/column and use top-most line number
115 parts[1] = parts[1] || "eval";
116 parts[3] = submatch[1];
117 parts[4] = submatch[2];
118 parts[5] = ''; // no column when eval
119 }
120 else if (i === 0 && !parts[5] && ex.columnNumber !== void 0) {
121 // FireFox uses this awesome columnNumber property for its top frame
122 // Also note, Firefox's column number is 0-based and everything else expects 1-based,
123 // so adding 1
124 // NOTE: this hack doesn't work if top-most frame is eval
125 stack[0].column = ex.columnNumber + 1;
126 }
127 element = {
128 url: parts[3],
129 func: parts[1] || UNKNOWN_FUNCTION,
130 args: parts[2] ? parts[2].split(',') : [],
131 line: parts[4] ? +parts[4] : null,
132 column: parts[5] ? +parts[5] : null,
133 };
134 }
135 else {
136 continue;
137 }
138 if (!element.func && element.line) {
139 element.func = UNKNOWN_FUNCTION;
140 }
141 stack.push(element);
142 }
143 if (!stack.length) {
144 return null;
145 }
146 return {
147 message: extractMessage(ex),
148 name: ex.name,
149 stack: stack,
150 };
151}
152/** JSDoc */
153// eslint-disable-next-line @typescript-eslint/no-explicit-any
154function computeStackTraceFromStacktraceProp(ex) {
155 if (!ex || !ex.stacktrace) {
156 return null;
157 }
158 // Access and store the stacktrace property before doing ANYTHING
159 // else to it because Opera is not very good at providing it
160 // reliably in other circumstances.
161 var stacktrace = ex.stacktrace;
162 var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
163 var opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\((.*)\))? in (.*):\s*$/i;
164 var lines = stacktrace.split('\n');
165 var stack = [];
166 var parts;
167 for (var line = 0; line < lines.length; line += 2) {
168 var element = null;
169 if ((parts = opera10Regex.exec(lines[line]))) {
170 element = {
171 url: parts[2],
172 func: parts[3],
173 args: [],
174 line: +parts[1],
175 column: null,
176 };
177 }
178 else if ((parts = opera11Regex.exec(lines[line]))) {
179 element = {
180 url: parts[6],
181 func: parts[3] || parts[4],
182 args: parts[5] ? parts[5].split(',') : [],
183 line: +parts[1],
184 column: +parts[2],
185 };
186 }
187 if (element) {
188 if (!element.func && element.line) {
189 element.func = UNKNOWN_FUNCTION;
190 }
191 stack.push(element);
192 }
193 }
194 if (!stack.length) {
195 return null;
196 }
197 return {
198 message: extractMessage(ex),
199 name: ex.name,
200 stack: stack,
201 };
202}
203/** Remove N number of frames from the stack */
204function popFrames(stacktrace, popSize) {
205 try {
206 return __assign(__assign({}, stacktrace), { stack: stacktrace.stack.slice(popSize) });
207 }
208 catch (e) {
209 return stacktrace;
210 }
211}
212/**
213 * There are cases where stacktrace.message is an Event object
214 * https://github.com/getsentry/sentry-javascript/issues/1949
215 * In this specific case we try to extract stacktrace.message.error.message
216 */
217// eslint-disable-next-line @typescript-eslint/no-explicit-any
218function extractMessage(ex) {
219 var message = ex && ex.message;
220 if (!message) {
221 return 'No error message';
222 }
223 if (message.error && typeof message.error.message === 'string') {
224 return message.error.message;
225 }
226 return message;
227}
228//# sourceMappingURL=tracekit.js.map
\No newline at end of file