From 3d045750f8ac48b07201fba06460f46e9196598b Mon Sep 17 00:00:00 2001 From: AnastasiiaSvietlova Date: Mon, 26 May 2025 13:38:22 +0200 Subject: [PATCH] convert node-fallback-stack to typescript --- packages/core/package.json | 1 - packages/core/src/index.ts | 1 + packages/core/src/lib/node-fallback-stack.js | 28 -------------- packages/core/src/lib/node-fallback-stack.ts | 37 +++++++++++++++++++ .../plugin-contextualize/contextualize.js | 5 +-- packages/plugin-intercept/intercept.js | 6 +-- .../uncaught-exception.js | 4 +- 7 files changed, 45 insertions(+), 37 deletions(-) delete mode 100644 packages/core/src/lib/node-fallback-stack.js create mode 100644 packages/core/src/lib/node-fallback-stack.ts diff --git a/packages/core/package.json b/packages/core/package.json index e5d048dc43..1b34529edf 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -17,7 +17,6 @@ "./lib/derecursify": "./src/lib/derecursify.js", "./lib/metadata-delegate": "./src/lib/metadata-delegate.js", "./lib/callback-runner": "./src/lib/callback-runner.js", - "./lib/node-fallback-stack": "./src/lib/node-fallback-stack.js", "./lib/sync-callback-runner": "./src/lib/sync-callback-runner.js", "./lib/path-normalizer": "./src/lib/path-normalizer.js", "./lib/validators/string-with-length": "./src/lib/validators/string-with-length.js", diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 48f4122236..129d3c573f 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -7,5 +7,6 @@ export { default as cloneClient } from './lib/clone-client' export { default as jsonPayload } from './lib/json-payload' export { default as intRange } from './lib/validators/int-range' export { default as isError } from './lib/iserror' +export { default as nodeFallbackStack } from './lib/node-fallback-stack' export * from './common' diff --git a/packages/core/src/lib/node-fallback-stack.js b/packages/core/src/lib/node-fallback-stack.js deleted file mode 100644 index 7504b9b567..0000000000 --- a/packages/core/src/lib/node-fallback-stack.js +++ /dev/null @@ -1,28 +0,0 @@ -// The utilities in this file are used to save the stackframes from a known execution context -// to use when a subsequent error has no stack frames. This happens with a lot of -// node's builtin async callbacks when they return from the native layer with no context -// for example: -// -// fs.readFile('does not exist', (err) => { -// /* node 8 */ -// err.stack = "ENOENT: no such file or directory, open 'nope'" -// /* node 4,6 */ -// err.stack = "Error: ENOENT: no such file or directory, open 'nope'\n at Error (native)" -// }) - -// Gets the stack string for the current execution context -exports.getStack = () => { - // slice(3) removes the first line + this function's frame + the caller's frame, - // so the stack begins with the caller of this function - return (new Error()).stack.split('\n').slice(3).join('\n') -} - -// Given an Error and a fallbackStack from getStack(), use the fallbackStack -// if error.stack has no genuine stackframes (according to the example above) -exports.maybeUseFallbackStack = (err, fallbackStack) => { - const lines = err.stack.split('\n') - if (lines.length === 1 || (lines.length === 2 && /at Error \(native\)/.test(lines[1]))) { - err.stack = `${lines[0]}\n${fallbackStack}` - } - return err -} diff --git a/packages/core/src/lib/node-fallback-stack.ts b/packages/core/src/lib/node-fallback-stack.ts new file mode 100644 index 0000000000..03dd4dfdac --- /dev/null +++ b/packages/core/src/lib/node-fallback-stack.ts @@ -0,0 +1,37 @@ +// The utilities in this file are used to save the stackframes from a known execution context +// to use when a subsequent error has no stack frames. This happens with a lot of +// node's builtin async callbacks when they return from the native layer with no context +// for example: +// +// fs.readFile('does not exist', (err) => { +// /* node 8 */ +// err.stack = "ENOENT: no such file or directory, open 'nope'" +// /* node 4,6 */ +// err.stack = "Error: ENOENT: no such file or directory, open 'nope'\n at Error (native)" +// }) + +interface NodeFallbackStack { + getStack: () => string | undefined + maybeUseFallbackStack: (err: Error, fallbackStack: string) => Error +} + +const nodeFallbackStack: NodeFallbackStack = { + // Gets the stack string for the current execution context + getStack: () => { + // slice(3) removes the first line + this function's frame + the caller's frame, + // so the stack begins with the caller of this function + return (new Error()).stack?.split('\n').slice(3).join('\n') + }, + + // Given an Error and a fallbackStack from getStack(), use the fallbackStack + // if error.stack has no genuine stackframes (according to the example above) + maybeUseFallbackStack: (err, fallbackStack) => { + const lines = err.stack?.split('\n') + if (lines?.length === 1 || (lines?.length === 2 && /at Error \(native\)/.test(lines[1]))) { + err.stack = `${lines[0]}\n${fallbackStack}` + } + return err + } +} + +export default nodeFallbackStack \ No newline at end of file diff --git a/packages/plugin-contextualize/contextualize.js b/packages/plugin-contextualize/contextualize.js index 6c4ee02687..5097089475 100644 --- a/packages/plugin-contextualize/contextualize.js +++ b/packages/plugin-contextualize/contextualize.js @@ -1,12 +1,11 @@ -const { getStack } = require('@bugsnag/core/lib/node-fallback-stack') -const { cloneClient } = require('@bugsnag/core') +const { cloneClient, nodeFallbackStack } = require('@bugsnag/core') module.exports = { name: 'contextualize', load: client => { const contextualize = (fn, onError) => { // capture a stacktrace in case a resulting error has nothing - const fallbackStack = getStack() + const fallbackStack = nodeFallbackStack.getStack() const clonedClient = cloneClient(client) diff --git a/packages/plugin-intercept/intercept.js b/packages/plugin-intercept/intercept.js index 5741a9d57f..3ff68ce004 100644 --- a/packages/plugin-intercept/intercept.js +++ b/packages/plugin-intercept/intercept.js @@ -1,4 +1,4 @@ -const { getStack, maybeUseFallbackStack } = require('@bugsnag/core/lib/node-fallback-stack') +const { nodeFallbackStack } = require('@bugsnag/core') module.exports = { name: 'intercept', @@ -10,12 +10,12 @@ module.exports = { } // capture a stacktrace in case a resulting error has nothing - const fallbackStack = getStack() + const fallbackStack = nodeFallbackStack.getStack() return (err, ...data) => { if (err) { // check if the stacktrace has no context, if so, if so append the frames we created earlier - if (err.stack) maybeUseFallbackStack(err, fallbackStack) + if (err.stack) nodeFallbackStack.maybeUseFallbackStack(err, fallbackStack) const event = client.Event.create(err, true, { severity: 'warning', unhandled: false, diff --git a/packages/plugin-node-uncaught-exception/uncaught-exception.js b/packages/plugin-node-uncaught-exception/uncaught-exception.js index db10be6397..c07015cce8 100644 --- a/packages/plugin-node-uncaught-exception/uncaught-exception.js +++ b/packages/plugin-node-uncaught-exception/uncaught-exception.js @@ -1,4 +1,4 @@ -const { maybeUseFallbackStack } = require('@bugsnag/core/lib/node-fallback-stack') +const { nodeFallbackStack } = require('@bugsnag/core') let _handler module.exports = { @@ -12,7 +12,7 @@ module.exports = { // check if the stacktrace has no context, if so append the frames we created earlier // see plugin-contextualize for where this is created - if (err.stack && c.fallbackStack) maybeUseFallbackStack(err, c.fallbackStack) + if (err.stack && c.fallbackStack) nodeFallbackStack.maybeUseFallbackStack(err, c.fallbackStack) const event = c.Event.create(err, false, { severity: 'error',