Skip to content

Commit a1c79cd

Browse files
authored
ref(node): Move stack parser to utils so it can be used from Electron (#5286)
1 parent 638b2f4 commit a1c79cd

File tree

3 files changed

+95
-91
lines changed

3 files changed

+95
-91
lines changed

packages/node/src/sdk.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
extractRequestData as _extractRequestData,
1111
getGlobalObject,
1212
logger,
13+
nodeStackLineParser,
1314
stackParserFromStackParserOptions,
1415
} from '@sentry/utils';
1516
import * as cookie from 'cookie';
@@ -19,7 +20,6 @@ import * as url from 'url';
1920
import { NodeClient } from './client';
2021
import { Console, ContextLines, Http, LinkedErrors, OnUncaughtException, OnUnhandledRejection } from './integrations';
2122
import { getModule } from './module';
22-
import { nodeStackLineParser } from './stack-parser';
2323
import { makeNodeTransport } from './transports';
2424
import { NodeClientOptions, NodeOptions } from './types';
2525

packages/node/src/stack-parser.ts

-89
This file was deleted.

packages/utils/src/stacktrace.ts

+94-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { StackFrame, StackLineParser, StackParser } from '@sentry/types';
1+
import { StackFrame, StackLineParser, StackLineParserFn, StackParser } from '@sentry/types';
22

33
const STACKTRACE_LIMIT = 50;
44

@@ -94,3 +94,96 @@ export function getFunctionName(fn: unknown): string {
9494
return defaultFunctionName;
9595
}
9696
}
97+
98+
type GetModuleFn = (filename: string | undefined) => string | undefined;
99+
100+
// eslint-disable-next-line complexity
101+
function node(getModule?: GetModuleFn): StackLineParserFn {
102+
const FILENAME_MATCH = /^\s*[-]{4,}$/;
103+
const FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/;
104+
105+
// eslint-disable-next-line complexity
106+
return (line: string) => {
107+
if (line.match(FILENAME_MATCH)) {
108+
return {
109+
filename: line,
110+
};
111+
}
112+
113+
const lineMatch = line.match(FULL_MATCH);
114+
if (!lineMatch) {
115+
return undefined;
116+
}
117+
118+
let object: string | undefined;
119+
let method: string | undefined;
120+
let functionName: string | undefined;
121+
let typeName: string | undefined;
122+
let methodName: string | undefined;
123+
124+
if (lineMatch[1]) {
125+
functionName = lineMatch[1];
126+
127+
let methodStart = functionName.lastIndexOf('.');
128+
if (functionName[methodStart - 1] === '.') {
129+
// eslint-disable-next-line no-plusplus
130+
methodStart--;
131+
}
132+
133+
if (methodStart > 0) {
134+
object = functionName.substr(0, methodStart);
135+
method = functionName.substr(methodStart + 1);
136+
const objectEnd = object.indexOf('.Module');
137+
if (objectEnd > 0) {
138+
functionName = functionName.substr(objectEnd + 1);
139+
object = object.substr(0, objectEnd);
140+
}
141+
}
142+
typeName = undefined;
143+
}
144+
145+
if (method) {
146+
typeName = object;
147+
methodName = method;
148+
}
149+
150+
if (method === '<anonymous>') {
151+
methodName = undefined;
152+
functionName = undefined;
153+
}
154+
155+
if (functionName === undefined) {
156+
methodName = methodName || '<anonymous>';
157+
functionName = typeName ? `${typeName}.${methodName}` : methodName;
158+
}
159+
160+
const filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].substr(7) : lineMatch[2];
161+
const isNative = lineMatch[5] === 'native';
162+
const isInternal =
163+
isNative || (filename && !filename.startsWith('/') && !filename.startsWith('.') && filename.indexOf(':\\') !== 1);
164+
165+
// in_app is all that's not an internal Node function or a module within node_modules
166+
// note that isNative appears to return true even for node core libraries
167+
// see https://github.com/getsentry/raven-node/issues/176
168+
const in_app = !isInternal && filename !== undefined && !filename.includes('node_modules/');
169+
170+
return {
171+
filename,
172+
module: getModule?.(filename),
173+
function: functionName,
174+
lineno: parseInt(lineMatch[3], 10) || undefined,
175+
colno: parseInt(lineMatch[4], 10) || undefined,
176+
in_app,
177+
};
178+
};
179+
}
180+
181+
/**
182+
* Node.js stack line parser
183+
*
184+
* This is in @sentry/utils so it can be used from the Electron SDK in the browser for when `nodeIntegration == true`.
185+
* This allows it to be used without referencing or importing any node specific code which causes bundlers to complain
186+
*/
187+
export function nodeStackLineParser(getModule?: GetModuleFn): StackLineParser {
188+
return [90, node(getModule)];
189+
}

0 commit comments

Comments
 (0)