Skip to content

Commit 2b34740

Browse files
committed
ref(integrations): Rewrite pluggable integrations to use functional style
1 parent 52810b3 commit 2b34740

18 files changed

+685
-893
lines changed

packages/core/src/integration.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,10 @@ export function convertIntegrationFnToClass<Fn extends IntegrationFn>(
176176
name: string,
177177
fn: Fn,
178178
): IntegrationClass<
179-
Integration & {
180-
setupOnce: (addGlobalEventProcessor?: (callback: EventProcessor) => void, getCurrentHub?: () => Hub) => void;
181-
}
179+
Integration &
180+
ReturnType<Fn> & {
181+
setupOnce: (addGlobalEventProcessor?: (callback: EventProcessor) => void, getCurrentHub?: () => Hub) => void;
182+
}
182183
> {
183184
return Object.assign(
184185
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -191,8 +192,9 @@ export function convertIntegrationFnToClass<Fn extends IntegrationFn>(
191192
},
192193
{ id: name },
193194
) as unknown as IntegrationClass<
194-
Integration & {
195-
setupOnce: (addGlobalEventProcessor?: (callback: EventProcessor) => void, getCurrentHub?: () => Hub) => void;
196-
}
195+
Integration &
196+
ReturnType<Fn> & {
197+
setupOnce: (addGlobalEventProcessor?: (callback: EventProcessor) => void, getCurrentHub?: () => Hub) => void;
198+
}
197199
>;
198200
}

packages/integrations/src/captureconsole.ts

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { captureException, captureMessage, getClient, withScope } from '@sentry/core';
2-
import type { CaptureContext, Client, EventProcessor, Hub, Integration } from '@sentry/types';
1+
import { captureException, captureMessage, convertIntegrationFnToClass, getClient, withScope } from '@sentry/core';
2+
import type { CaptureContext, IntegrationFn } from '@sentry/types';
33
import {
44
CONSOLE_LEVELS,
55
GLOBAL_OBJ,
@@ -9,55 +9,36 @@ import {
99
severityLevelFromString,
1010
} from '@sentry/utils';
1111

12-
/** Send Console API calls as Sentry Events */
13-
export class CaptureConsole implements Integration {
14-
/**
15-
* @inheritDoc
16-
*/
17-
public static id: string = 'CaptureConsole';
18-
19-
/**
20-
* @inheritDoc
21-
*/
22-
public name: string;
23-
24-
/**
25-
* @inheritDoc
26-
*/
27-
private readonly _levels: readonly string[];
28-
29-
/**
30-
* @inheritDoc
31-
*/
32-
public constructor(options: { levels?: string[] } = {}) {
33-
this.name = CaptureConsole.id;
34-
this._levels = options.levels || CONSOLE_LEVELS;
35-
}
36-
37-
/**
38-
* @inheritDoc
39-
*/
40-
public setupOnce(_: (callback: EventProcessor) => void, _getCurrentHub: () => Hub): void {
41-
// noop
42-
}
12+
interface CaptureConsoleOptions {
13+
levels?: string[];
14+
}
4315

44-
/** @inheritdoc */
45-
public setup(client: Client): void {
46-
if (!('console' in GLOBAL_OBJ)) {
47-
return;
48-
}
16+
const INTEGRATION_NAME = 'CaptureConsole';
4917

50-
const levels = this._levels;
18+
const captureConsoleIntegration = ((options: CaptureConsoleOptions = {}) => {
19+
const levels = options.levels || CONSOLE_LEVELS;
5120

52-
addConsoleInstrumentationHandler(({ args, level }) => {
53-
if (getClient() !== client || !levels.includes(level)) {
21+
return {
22+
name: INTEGRATION_NAME,
23+
setup(client) {
24+
if (!('console' in GLOBAL_OBJ)) {
5425
return;
5526
}
5627

57-
consoleHandler(args, level);
58-
});
59-
}
60-
}
28+
addConsoleInstrumentationHandler(({ args, level }) => {
29+
if (getClient() !== client || !levels.includes(level)) {
30+
return;
31+
}
32+
33+
consoleHandler(args, level);
34+
});
35+
},
36+
};
37+
}) satisfies IntegrationFn;
38+
39+
/** Send Console API calls as Sentry Events */
40+
// eslint-disable-next-line deprecation/deprecation
41+
export const CaptureConsole = convertIntegrationFnToClass(INTEGRATION_NAME, captureConsoleIntegration);
6142

6243
function consoleHandler(args: unknown[], level: string): void {
6344
const captureContext: CaptureContext = {

packages/integrations/src/contextlines.ts

Lines changed: 40 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import type { Event, Integration, StackFrame } from '@sentry/types';
1+
import { convertIntegrationFnToClass } from '@sentry/core';
2+
import type { Event, IntegrationFn, StackFrame } from '@sentry/types';
23
import { GLOBAL_OBJ, addContextToFrame, stripUrlQueryAndFragment } from '@sentry/utils';
34

45
const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;
56

67
const DEFAULT_LINES_OF_CONTEXT = 7;
78

9+
const INTEGRATION_NAME = 'ContextLines';
10+
811
interface ContextLinesOptions {
912
/**
1013
* Sets the number of context lines for each frame when loading a file.
@@ -15,6 +18,17 @@ interface ContextLinesOptions {
1518
frameContextLines?: number;
1619
}
1720

21+
const contextLinesIntegration: IntegrationFn = (options: ContextLinesOptions = {}) => {
22+
const contextLines = options.frameContextLines != null ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT;
23+
24+
return {
25+
name: INTEGRATION_NAME,
26+
processEvent(event) {
27+
return addSourceContext(event, contextLines);
28+
},
29+
};
30+
};
31+
1832
/**
1933
* Collects source context lines around the lines of stackframes pointing to JS embedded in
2034
* the current page's HTML.
@@ -26,73 +40,41 @@ interface ContextLinesOptions {
2640
* Use this integration if you have inline JS code in HTML pages that can't be accessed
2741
* by our backend (e.g. due to a login-protected page).
2842
*/
29-
export class ContextLines implements Integration {
30-
/**
31-
* @inheritDoc
32-
*/
33-
public static id: string = 'ContextLines';
34-
35-
/**
36-
* @inheritDoc
37-
*/
38-
public name: string;
43+
// eslint-disable-next-line deprecation/deprecation
44+
export const ContextLines = convertIntegrationFnToClass(INTEGRATION_NAME, contextLinesIntegration);
3945

40-
public constructor(private readonly _options: ContextLinesOptions = {}) {
41-
this.name = ContextLines.id;
46+
/**
47+
* Processes an event and adds context lines.
48+
*/
49+
function addSourceContext(event: Event, contextLines: number): Event {
50+
const doc = WINDOW.document;
51+
const htmlFilename = WINDOW.location && stripUrlQueryAndFragment(WINDOW.location.href);
52+
if (!doc || !htmlFilename) {
53+
return event;
4254
}
4355

44-
/**
45-
* @inheritDoc
46-
*/
47-
public setupOnce(_addGlobalEventProcessor: unknown, _getCurrentHub: unknown): void {
48-
// noop
56+
const exceptions = event.exception && event.exception.values;
57+
if (!exceptions || !exceptions.length) {
58+
return event;
4959
}
5060

51-
/** @inheritDoc */
52-
public processEvent(event: Event): Event {
53-
return this.addSourceContext(event);
61+
const html = doc.documentElement.innerHTML;
62+
if (!html) {
63+
return event;
5464
}
5565

56-
/**
57-
* Processes an event and adds context lines.
58-
*
59-
* TODO (v8): Make this internal/private
60-
*/
61-
public addSourceContext(event: Event): Event {
62-
const doc = WINDOW.document;
63-
const htmlFilename = WINDOW.location && stripUrlQueryAndFragment(WINDOW.location.href);
64-
if (!doc || !htmlFilename) {
65-
return event;
66-
}
67-
68-
const exceptions = event.exception && event.exception.values;
69-
if (!exceptions || !exceptions.length) {
70-
return event;
71-
}
66+
const htmlLines = ['<!DOCTYPE html>', '<html>', ...html.split('\n'), '</html>'];
7267

73-
const html = doc.documentElement.innerHTML;
74-
if (!html) {
75-
return event;
68+
exceptions.forEach(exception => {
69+
const stacktrace = exception.stacktrace;
70+
if (stacktrace && stacktrace.frames) {
71+
stacktrace.frames = stacktrace.frames.map(frame =>
72+
applySourceContextToFrame(frame, htmlLines, htmlFilename, contextLines),
73+
);
7674
}
75+
});
7776

78-
const htmlLines = ['<!DOCTYPE html>', '<html>', ...html.split('\n'), '</html>'];
79-
80-
exceptions.forEach(exception => {
81-
const stacktrace = exception.stacktrace;
82-
if (stacktrace && stacktrace.frames) {
83-
stacktrace.frames = stacktrace.frames.map(frame =>
84-
applySourceContextToFrame(
85-
frame,
86-
htmlLines,
87-
htmlFilename,
88-
this._options.frameContextLines != null ? this._options.frameContextLines : DEFAULT_LINES_OF_CONTEXT,
89-
),
90-
);
91-
}
92-
});
93-
94-
return event;
95-
}
77+
return event;
9678
}
9779

9880
/**

packages/integrations/src/debug.ts

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,59 @@
1-
import type { Client, Event, EventHint, EventProcessor, Hub, Integration } from '@sentry/types';
1+
import { convertIntegrationFnToClass } from '@sentry/core';
2+
import type { Event, EventHint, IntegrationFn } from '@sentry/types';
23
import { consoleSandbox } from '@sentry/utils';
34

5+
const INTEGRATION_NAME = 'Debug';
6+
47
interface DebugOptions {
58
/** Controls whether console output created by this integration should be stringified. Default: `false` */
69
stringify?: boolean;
710
/** Controls whether a debugger should be launched before an event is sent. Default: `false` */
811
debugger?: boolean;
912
}
1013

11-
/**
12-
* Integration to debug sent Sentry events.
13-
* This integration should not be used in production
14-
*/
15-
export class Debug implements Integration {
16-
/**
17-
* @inheritDoc
18-
*/
19-
public static id: string = 'Debug';
20-
21-
/**
22-
* @inheritDoc
23-
*/
24-
public name: string;
25-
26-
private readonly _options: DebugOptions;
27-
28-
public constructor(options?: DebugOptions) {
29-
this.name = Debug.id;
30-
31-
this._options = {
32-
debugger: false,
33-
stringify: false,
34-
...options,
35-
};
36-
}
37-
38-
/**
39-
* @inheritDoc
40-
*/
41-
public setupOnce(
42-
_addGlobalEventProcessor: (eventProcessor: EventProcessor) => void,
43-
_getCurrentHub: () => Hub,
44-
): void {
45-
// noop
46-
}
47-
48-
/** @inheritdoc */
49-
public setup(client: Client): void {
50-
if (!client.on) {
51-
return;
52-
}
53-
54-
client.on('beforeSendEvent', (event: Event, hint?: EventHint) => {
55-
if (this._options.debugger) {
56-
// eslint-disable-next-line no-debugger
57-
debugger;
14+
const debugIntegration = ((options: DebugOptions = {}) => {
15+
const _options = {
16+
debugger: false,
17+
stringify: false,
18+
...options,
19+
};
20+
21+
return {
22+
name: INTEGRATION_NAME,
23+
setup(client) {
24+
if (!client.on) {
25+
return;
5826
}
5927

60-
/* eslint-disable no-console */
61-
consoleSandbox(() => {
62-
if (this._options.stringify) {
63-
console.log(JSON.stringify(event, null, 2));
64-
if (hint && Object.keys(hint).length) {
65-
console.log(JSON.stringify(hint, null, 2));
66-
}
67-
} else {
68-
console.log(event);
69-
if (hint && Object.keys(hint).length) {
70-
console.log(hint);
71-
}
28+
client.on('beforeSendEvent', (event: Event, hint?: EventHint) => {
29+
if (_options.debugger) {
30+
// eslint-disable-next-line no-debugger
31+
debugger;
7232
}
33+
34+
/* eslint-disable no-console */
35+
consoleSandbox(() => {
36+
if (_options.stringify) {
37+
console.log(JSON.stringify(event, null, 2));
38+
if (hint && Object.keys(hint).length) {
39+
console.log(JSON.stringify(hint, null, 2));
40+
}
41+
} else {
42+
console.log(event);
43+
if (hint && Object.keys(hint).length) {
44+
console.log(hint);
45+
}
46+
}
47+
});
48+
/* eslint-enable no-console */
7349
});
74-
/* eslint-enable no-console */
75-
});
76-
}
77-
}
50+
},
51+
};
52+
}) satisfies IntegrationFn;
53+
54+
/**
55+
* Integration to debug sent Sentry events.
56+
* This integration should not be used in production
57+
*/
58+
// eslint-disable-next-line deprecation/deprecation
59+
export const Debug = convertIntegrationFnToClass(INTEGRATION_NAME, debugIntegration);

0 commit comments

Comments
 (0)