Skip to content

Commit 84d194e

Browse files
committed
More simplify
1 parent 8723236 commit 84d194e

13 files changed

+717
-921
lines changed

packages/browser/src/eventbuilder.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import {
1111
resolvedSyncPromise,
1212
} from '@sentry/utils';
1313

14-
import { eventFromPlainObject, eventFromStacktrace, prepareFramesForEvent } from './parsers';
15-
import { computeStackTrace } from './tracekit';
14+
import { eventFromError, eventFromPlainObject, parseStackFrames, prepareFramesForEvent } from './parsers';
1615

1716
/**
1817
* Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`.
@@ -70,7 +69,7 @@ export function eventFromUnknownInput(
7069
const errorEvent = exception as ErrorEvent;
7170
// eslint-disable-next-line no-param-reassign
7271
exception = errorEvent.error;
73-
event = eventFromStacktrace(computeStackTrace(exception as Error));
72+
event = eventFromError(exception as Error);
7473
return event;
7574
}
7675

@@ -85,7 +84,7 @@ export function eventFromUnknownInput(
8584
const domException = exception as DOMException;
8685

8786
if ('stack' in (exception as Error)) {
88-
event = eventFromStacktrace(computeStackTrace(exception as Error));
87+
event = eventFromError(exception as Error);
8988
} else {
9089
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
9190
const message = domException.message ? `${name}: ${domException.message}` : name;
@@ -100,7 +99,7 @@ export function eventFromUnknownInput(
10099
}
101100
if (isError(exception as Error)) {
102101
// we have a real Error object, do nothing
103-
event = eventFromStacktrace(computeStackTrace(exception as Error));
102+
event = eventFromError(exception as Error);
104103
return event;
105104
}
106105
if (isPlainObject(exception) || isEvent(exception)) {
@@ -148,8 +147,8 @@ export function eventFromString(
148147
};
149148

150149
if (options.attachStacktrace && syntheticException) {
151-
const stacktrace = computeStackTrace(syntheticException);
152-
const frames = prepareFramesForEvent(stacktrace.stack);
150+
const stacktrace = parseStackFrames(syntheticException);
151+
const frames = prepareFramesForEvent(stacktrace);
153152
event.stacktrace = {
154153
frames,
155154
};

packages/browser/src/integrations/linkederrors.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core';
22
import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types';
33
import { isInstanceOf } from '@sentry/utils';
44

5-
import { exceptionFromStacktrace } from '../parsers';
6-
import { computeStackTrace } from '../tracekit';
5+
import { exceptionFromError } from '../parsers';
76

87
const DEFAULT_KEY = 'cause';
98
const DEFAULT_LIMIT = 5;
@@ -73,7 +72,6 @@ export function _walkErrorTree(limit: number, error: ExtendedError, key: string,
7372
if (!isInstanceOf(error[key], Error) || stack.length + 1 >= limit) {
7473
return stack;
7574
}
76-
const stacktrace = computeStackTrace(error[key]);
77-
const exception = exceptionFromStacktrace(stacktrace);
75+
const exception = exceptionFromError(error[key]);
7876
return _walkErrorTree(limit, error[key], key, [exception, ...stack]);
7977
}

packages/browser/src/parsers.ts

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
12
import { Event, Exception, StackFrame } from '@sentry/types';
2-
import { extractExceptionKeysForMessage, isEvent, normalizeToSize } from '@sentry/utils';
3+
import { createStackParser, extractExceptionKeysForMessage, isEvent, normalizeToSize } from '@sentry/utils';
34

4-
import { computeStackTrace, StackTrace as TraceKitStackTrace } from './tracekit';
5+
import { chrome, gecko, opera10, opera11, winjs } from './stack-parsers';
56

67
const STACKTRACE_LIMIT = 50;
78

@@ -10,14 +11,14 @@ const STACKTRACE_LIMIT = 50;
1011
* @param stacktrace TraceKitStackTrace that will be converted to an exception
1112
* @hidden
1213
*/
13-
export function exceptionFromStacktrace(stacktrace: TraceKitStackTrace): Exception {
14-
const frames = prepareFramesForEvent(stacktrace.stack);
15-
14+
export function exceptionFromError(ex: Error): Exception {
1615
const exception: Exception = {
17-
type: stacktrace.name,
18-
value: stacktrace.message,
16+
type: ex && ex.name,
17+
value: extractMessage(ex),
1918
};
2019

20+
const frames = parseStackFrames(ex);
21+
2122
if (frames && frames.length) {
2223
exception.stacktrace = { frames };
2324
}
@@ -54,8 +55,8 @@ export function eventFromPlainObject(
5455
};
5556

5657
if (syntheticException) {
57-
const stacktrace = computeStackTrace(syntheticException);
58-
const frames = prepareFramesForEvent(stacktrace.stack);
58+
const stacktrace = parseStackFrames(syntheticException);
59+
const frames = prepareFramesForEvent(stacktrace);
5960
event.stacktrace = {
6061
frames,
6162
};
@@ -67,16 +68,61 @@ export function eventFromPlainObject(
6768
/**
6869
* @hidden
6970
*/
70-
export function eventFromStacktrace(stacktrace: TraceKitStackTrace): Event {
71-
const exception = exceptionFromStacktrace(stacktrace);
72-
71+
export function eventFromError(ex: Error): Event {
7372
return {
7473
exception: {
75-
values: [exception],
74+
values: [exceptionFromError(ex)],
7675
},
7776
};
7877
}
7978

79+
// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108
80+
const reactMinifiedRegexp = /Minified React error #\d+;/i;
81+
82+
/** JSDoc */
83+
export function parseStackFrames(ex: Error & { framesToPop?: number; stacktrace?: string }): StackFrame[] {
84+
let popSize = 0;
85+
86+
if (ex) {
87+
if (typeof ex.framesToPop === 'number') {
88+
popSize = ex.framesToPop;
89+
} else if (reactMinifiedRegexp.test(ex.message)) {
90+
popSize = 1;
91+
}
92+
}
93+
94+
try {
95+
// Access and store the stacktrace property before doing ANYTHING
96+
// else to it because Opera is not very good at providing it
97+
// reliably in other circumstances.
98+
const stacktrace = ex.stacktrace || ex.stack || '';
99+
const frames = createStackParser(opera10, opera11, chrome, winjs, gecko)(stacktrace);
100+
101+
return popSize > 0 && frames.length >= popSize ? frames.slice(popSize) : frames;
102+
} catch (e) {
103+
// no-empty
104+
}
105+
106+
return [];
107+
}
108+
109+
/**
110+
* There are cases where stacktrace.message is an Event object
111+
* https://github.com/getsentry/sentry-javascript/issues/1949
112+
* In this specific case we try to extract stacktrace.message.error.message
113+
*/
114+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
115+
function extractMessage(ex: any): string {
116+
const message = ex && ex.message;
117+
if (!message) {
118+
return 'No error message';
119+
}
120+
if (message.error && typeof message.error.message === 'string') {
121+
return message.error.message;
122+
}
123+
return message;
124+
}
125+
80126
/**
81127
* @hidden
82128
*/

packages/browser/src/tracekit.ts renamed to packages/browser/src/stack-parsers.ts

Lines changed: 7 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,14 @@
1-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
2-
import { StackFrame } from '@sentry/types';
1+
import { StackLineParser } from '@sentry/utils';
32

43
// global reference to slice
54
const UNKNOWN_FUNCTION = '?';
65

7-
/**
8-
* An object representing a JavaScript stack trace.
9-
* {Object} StackTrace
10-
* {string} name The name of the thrown exception.
11-
* {string} message The exception error message.
12-
* {TraceKit.StackFrame[]} stack An array of stack frames.
13-
*/
14-
export interface StackTrace {
15-
name: string;
16-
message: string;
17-
stack: StackFrame[];
18-
}
19-
20-
type StackLineParser = (line: string) => StackFrame | undefined;
21-
226
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
237
const chromeRegex =
248
/^\s*at (?:(.*?) ?\((?:address at )?)?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
259
const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
2610

27-
const chrome: StackLineParser = line => {
11+
export const chrome: StackLineParser = line => {
2812
const parts = chromeRegex.exec(line);
2913

3014
if (parts) {
@@ -63,7 +47,7 @@ const geckoREgex =
6347
/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpack|resource|moz-extension|capacitor).*?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
6448
const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
6549

66-
const gecko: StackLineParser = line => {
50+
export const gecko: StackLineParser = line => {
6751
const parts = geckoREgex.exec(line);
6852

6953
if (parts) {
@@ -98,7 +82,7 @@ const gecko: StackLineParser = line => {
9882
const winjsRegex =
9983
/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
10084

101-
const winjs: StackLineParser = line => {
85+
export const winjs: StackLineParser = line => {
10286
const parts = winjsRegex.exec(line);
10387

10488
return parts
@@ -113,7 +97,7 @@ const winjs: StackLineParser = line => {
11397

11498
const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
11599

116-
const opera10: StackLineParser = line => {
100+
export const opera10: StackLineParser = line => {
117101
const parts = opera10Regex.exec(line);
118102

119103
return parts
@@ -128,7 +112,7 @@ const opera10: StackLineParser = line => {
128112
const opera11Regex =
129113
/ line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
130114

131-
const opera11: StackLineParser = line => {
115+
export const opera11: StackLineParser = line => {
132116
const parts = opera11Regex.exec(line);
133117

134118
return parts
@@ -141,53 +125,6 @@ const opera11: StackLineParser = line => {
141125
: undefined;
142126
};
143127

144-
// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108
145-
const reactMinifiedRegexp = /Minified React error #\d+;/i;
146-
147-
/** JSDoc */
148-
export function computeStackTrace(ex: Error & { framesToPop?: number; stacktrace?: string }): StackTrace {
149-
let frames: StackFrame[] = [];
150-
let popSize = 0;
151-
152-
if (ex) {
153-
if (typeof ex.framesToPop === 'number') {
154-
popSize = ex.framesToPop;
155-
} else if (reactMinifiedRegexp.test(ex.message)) {
156-
popSize = 1;
157-
}
158-
}
159-
160-
try {
161-
// Access and store the stacktrace property before doing ANYTHING
162-
// else to it because Opera is not very good at providing it
163-
// reliably in other circumstances.
164-
const stacktrace = ex.stacktrace || ex.stack || '';
165-
166-
for (const line of stacktrace.split('\n')) {
167-
for (const parser of [opera10, opera11, chrome, winjs, gecko]) {
168-
const frame = parser(line);
169-
170-
if (frame) {
171-
frames.push(frame);
172-
break;
173-
}
174-
}
175-
}
176-
} catch (e) {
177-
// no-empty
178-
}
179-
180-
if (frames.length && popSize > 0) {
181-
frames = frames.slice(popSize);
182-
}
183-
184-
return {
185-
message: extractMessage(ex),
186-
name: ex && ex.name,
187-
stack: frames,
188-
};
189-
}
190-
191128
/**
192129
* Safari web extensions, starting version unknown, can produce "frames-only" stacktraces.
193130
* What it means, is that instead of format like:
@@ -205,7 +142,7 @@ export function computeStackTrace(ex: Error & { framesToPop?: number; stacktrace
205142
*
206143
* Because of that, it won't be captured by `chrome` RegExp and will fall into `Gecko` branch.
207144
* This function is extracted so that we can use it in both places without duplicating the logic.
208-
* Unfortunatelly "just" changing RegExp is too complicated now and making it pass all tests
145+
* Unfortunately "just" changing RegExp is too complicated now and making it pass all tests
209146
* and fix this case seems like an impossible, or at least way too time-consuming task.
210147
*/
211148
const extractSafariExtensionDetails = (func: string, filename: string): [string, string] => {
@@ -219,20 +156,3 @@ const extractSafariExtensionDetails = (func: string, filename: string): [string,
219156
]
220157
: [func, filename];
221158
};
222-
223-
/**
224-
* There are cases where stacktrace.message is an Event object
225-
* https://github.com/getsentry/sentry-javascript/issues/1949
226-
* In this specific case we try to extract stacktrace.message.error.message
227-
*/
228-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
229-
function extractMessage(ex: any): string {
230-
const message = ex && ex.message;
231-
if (!message) {
232-
return 'No error message';
233-
}
234-
if (message.error && typeof message.error.message === 'string') {
235-
return message.error.message;
236-
}
237-
return message;
238-
}

0 commit comments

Comments
 (0)