-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ref(node): Allow node stack parser to work in browser context (#5135)
- Loading branch information
1 parent
8fcf3ff
commit 31be2be
Showing
8 changed files
with
116 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { basename, dirname } from '@sentry/utils'; | ||
|
||
/** Gets the module from a filename */ | ||
export function getModule(filename: string | undefined): string | undefined { | ||
if (!filename) { | ||
return; | ||
} | ||
|
||
// We could use optional chaining here but webpack does like that mixed with require | ||
const base = `${ | ||
(require && require.main && require.main.filename && dirname(require.main.filename)) || global.process.cwd() | ||
}/`; | ||
|
||
// It's specifically a module | ||
const file = basename(filename, '.js'); | ||
|
||
const path = dirname(filename); | ||
let n = path.lastIndexOf('/node_modules/'); | ||
if (n > -1) { | ||
// /node_modules/ is 14 chars | ||
return `${path.substr(n + 14).replace(/\//g, '.')}:${file}`; | ||
} | ||
// Let's see if it's a part of the main module | ||
// To be a part of main module, it has to share the same base | ||
n = `${path}/`.lastIndexOf(base, 0); | ||
|
||
if (n === 0) { | ||
let moduleName = path.substr(base.length).replace(/\//g, '.'); | ||
if (moduleName) { | ||
moduleName += ':'; | ||
} | ||
moduleName += file; | ||
return moduleName; | ||
} | ||
return file; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,89 @@ | ||
import { StackLineParser, StackLineParserFn } from '@sentry/types'; | ||
import { basename, createStackParser, dirname } from '@sentry/utils'; | ||
|
||
/** Gets the module */ | ||
function getModule(filename: string | undefined): string | undefined { | ||
if (!filename) { | ||
return; | ||
} | ||
|
||
// We could use optional chaining here but webpack does like that mixed with require | ||
const base = `${ | ||
(require && require.main && require.main.filename && dirname(require.main.filename)) || global.process.cwd() | ||
}/`; | ||
|
||
// It's specifically a module | ||
const file = basename(filename, '.js'); | ||
|
||
const path = dirname(filename); | ||
let n = path.lastIndexOf('/node_modules/'); | ||
if (n > -1) { | ||
// /node_modules/ is 14 chars | ||
return `${path.substr(n + 14).replace(/\//g, '.')}:${file}`; | ||
} | ||
// Let's see if it's a part of the main module | ||
// To be a part of main module, it has to share the same base | ||
n = `${path}/`.lastIndexOf(base, 0); | ||
|
||
if (n === 0) { | ||
let moduleName = path.substr(base.length).replace(/\//g, '.'); | ||
if (moduleName) { | ||
moduleName += ':'; | ||
} | ||
moduleName += file; | ||
return moduleName; | ||
} | ||
return file; | ||
} | ||
|
||
const FILENAME_MATCH = /^\s*[-]{4,}$/; | ||
const FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/; | ||
|
||
type GetModuleFn = (filename: string | undefined) => string | undefined; | ||
|
||
// eslint-disable-next-line complexity | ||
const node: StackLineParserFn = (line: string) => { | ||
if (line.match(FILENAME_MATCH)) { | ||
return { | ||
filename: line, | ||
}; | ||
} | ||
function node(getModule?: GetModuleFn): StackLineParserFn { | ||
// eslint-disable-next-line complexity | ||
return (line: string) => { | ||
if (line.match(FILENAME_MATCH)) { | ||
return { | ||
filename: line, | ||
}; | ||
} | ||
|
||
const lineMatch = line.match(FULL_MATCH); | ||
if (!lineMatch) { | ||
return undefined; | ||
} | ||
const lineMatch = line.match(FULL_MATCH); | ||
if (!lineMatch) { | ||
return undefined; | ||
} | ||
|
||
let object: string | undefined; | ||
let method: string | undefined; | ||
let functionName: string | undefined; | ||
let typeName: string | undefined; | ||
let methodName: string | undefined; | ||
let object: string | undefined; | ||
let method: string | undefined; | ||
let functionName: string | undefined; | ||
let typeName: string | undefined; | ||
let methodName: string | undefined; | ||
|
||
if (lineMatch[1]) { | ||
functionName = lineMatch[1]; | ||
if (lineMatch[1]) { | ||
functionName = lineMatch[1]; | ||
|
||
let methodStart = functionName.lastIndexOf('.'); | ||
if (functionName[methodStart - 1] === '.') { | ||
// eslint-disable-next-line no-plusplus | ||
methodStart--; | ||
} | ||
let methodStart = functionName.lastIndexOf('.'); | ||
if (functionName[methodStart - 1] === '.') { | ||
// eslint-disable-next-line no-plusplus | ||
methodStart--; | ||
} | ||
|
||
if (methodStart > 0) { | ||
object = functionName.substr(0, methodStart); | ||
method = functionName.substr(methodStart + 1); | ||
const objectEnd = object.indexOf('.Module'); | ||
if (objectEnd > 0) { | ||
functionName = functionName.substr(objectEnd + 1); | ||
object = object.substr(0, objectEnd); | ||
if (methodStart > 0) { | ||
object = functionName.substr(0, methodStart); | ||
method = functionName.substr(methodStart + 1); | ||
const objectEnd = object.indexOf('.Module'); | ||
if (objectEnd > 0) { | ||
functionName = functionName.substr(objectEnd + 1); | ||
object = object.substr(0, objectEnd); | ||
} | ||
} | ||
typeName = undefined; | ||
} | ||
typeName = undefined; | ||
} | ||
|
||
if (method) { | ||
typeName = object; | ||
methodName = method; | ||
} | ||
if (method) { | ||
typeName = object; | ||
methodName = method; | ||
} | ||
|
||
if (method === '<anonymous>') { | ||
methodName = undefined; | ||
functionName = undefined; | ||
} | ||
if (method === '<anonymous>') { | ||
methodName = undefined; | ||
functionName = undefined; | ||
} | ||
|
||
if (functionName === undefined) { | ||
methodName = methodName || '<anonymous>'; | ||
functionName = typeName ? `${typeName}.${methodName}` : methodName; | ||
} | ||
if (functionName === undefined) { | ||
methodName = methodName || '<anonymous>'; | ||
functionName = typeName ? `${typeName}.${methodName}` : methodName; | ||
} | ||
|
||
const filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].substr(7) : lineMatch[2]; | ||
const isNative = lineMatch[5] === 'native'; | ||
const isInternal = | ||
isNative || (filename && !filename.startsWith('/') && !filename.startsWith('.') && filename.indexOf(':\\') !== 1); | ||
const filename = lineMatch[2]?.startsWith('file://') ? lineMatch[2].substr(7) : lineMatch[2]; | ||
const isNative = lineMatch[5] === 'native'; | ||
const isInternal = | ||
isNative || (filename && !filename.startsWith('/') && !filename.startsWith('.') && filename.indexOf(':\\') !== 1); | ||
|
||
// in_app is all that's not an internal Node function or a module within node_modules | ||
// note that isNative appears to return true even for node core libraries | ||
// see https://github.com/getsentry/raven-node/issues/176 | ||
const in_app = !isInternal && filename !== undefined && !filename.includes('node_modules/'); | ||
// in_app is all that's not an internal Node function or a module within node_modules | ||
// note that isNative appears to return true even for node core libraries | ||
// see https://github.com/getsentry/raven-node/issues/176 | ||
const in_app = !isInternal && filename !== undefined && !filename.includes('node_modules/'); | ||
|
||
return { | ||
filename, | ||
module: getModule(filename), | ||
function: functionName, | ||
lineno: parseInt(lineMatch[3], 10) || undefined, | ||
colno: parseInt(lineMatch[4], 10) || undefined, | ||
in_app, | ||
return { | ||
filename, | ||
module: getModule?.(filename), | ||
function: functionName, | ||
lineno: parseInt(lineMatch[3], 10) || undefined, | ||
colno: parseInt(lineMatch[4], 10) || undefined, | ||
in_app, | ||
}; | ||
}; | ||
}; | ||
|
||
export const nodeStackLineParser: StackLineParser = [90, node]; | ||
} | ||
|
||
export const defaultStackParser = createStackParser(nodeStackLineParser); | ||
/** Node.js stack line parser */ | ||
export function nodeStackLineParser(getModule?: GetModuleFn): StackLineParser { | ||
return [90, node(getModule)]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters