diff --git a/js/src/stackutil.test.ts b/js/src/stackutil.test.ts new file mode 100644 index 000000000..d492234b4 --- /dev/null +++ b/js/src/stackutil.test.ts @@ -0,0 +1,37 @@ +import { expect, test } from "vitest"; +import { + callerFromAnonymousFunction, + callerFromModuleInit, + callerFromNamedFunction, +} from "../tests/helpers/stackutil-caller"; + +function normalizeFileName(fileName: string) { + return fileName.replace(/^file:\/\//, ""); +} + +test("getCallerLocation works with a real top-level caller frame", () => { + expect(callerFromModuleInit).toBeDefined(); + expect(callerFromModuleInit!.caller_lineno).toBeGreaterThan(1); + expect(normalizeFileName(callerFromModuleInit!.caller_filename)).toMatch( + /tests[\\/]helpers[\\/]stackutil-caller\.(ts|js)$/, + ); +}); + +test("getCallerLocation works with a real named function caller frame", () => { + const location = callerFromNamedFunction(); + expect(location).toBeDefined(); + expect(location!.caller_lineno).toBeGreaterThan(1); + expect(normalizeFileName(location!.caller_filename)).toMatch( + /tests[\\/]helpers[\\/]stackutil-caller\.(ts|js)$/, + ); + expect(location!.caller_functionname).toContain("callerFromNamedFunction"); +}); + +test("getCallerLocation works with a real anonymous function caller frame", () => { + const location = callerFromAnonymousFunction(); + expect(location).toBeDefined(); + expect(location!.caller_lineno).toBeGreaterThan(1); + expect(normalizeFileName(location!.caller_filename)).toMatch( + /tests[\\/]helpers[\\/]stackutil-caller\.(ts|js)$/, + ); +}); diff --git a/js/src/stackutil.ts b/js/src/stackutil.ts index 71d9ae9ba..45cbda0c6 100644 --- a/js/src/stackutil.ts +++ b/js/src/stackutil.ts @@ -13,14 +13,14 @@ function getStackTrace(): StackTraceEntry[] { } const traceLines = trace.split("\n"); const out: StackTraceEntry[] = []; - const stackFrameRegex = /at(.*)\((.*):(\d+):(\d+)\)/; + const stackFrameRegex = /^\s*at\s+(?:(.+?)\s+\()?(.*):(\d+):(\d+)\)?\s*$/; for (const traceLine of traceLines.slice(1)) { const matches = traceLine.match(stackFrameRegex); if (matches === null || matches.length !== 5) { continue; } const entry: StackTraceEntry = { - functionName: matches[1].trim(), + functionName: matches[1]?.trim() ?? "", fileName: matches[2], lineNo: parseInt(matches[3]), }; diff --git a/js/tests/helpers/stackutil-caller.ts b/js/tests/helpers/stackutil-caller.ts new file mode 100644 index 000000000..e0d3a40da --- /dev/null +++ b/js/tests/helpers/stackutil-caller.ts @@ -0,0 +1,14 @@ +import { configureNode } from "../../src/node/config"; +import { getCallerLocation } from "../../src/stackutil"; + +configureNode(); + +export const callerFromModuleInit = getCallerLocation(); + +export function callerFromNamedFunction() { + return getCallerLocation(); +} + +export function callerFromAnonymousFunction() { + return (() => getCallerLocation())(); +}