Parse V8 Stack Traces Into Frames
Turn V8 stack strings into structured frames with function names, file paths, line and column numbers, async and native markers.
Code
export interface StackFrame {
readonly functionName: string | null;
readonly file: string | null;
readonly line: number | null;
readonly column: number | null;
readonly native: boolean;
readonly async: boolean;
}
export function parseStackTrace(stack: string): StackFrame[] {
if (typeof stack !== "string") throw new TypeError("stack must be a string");
const frames: StackFrame[] = [];
for (const rawLine of stack.split("\n")) {
const line = rawLine.trim();
if (!line.startsWith("at ")) continue;
const frame = parseFrame(line.slice(3));
if (frame !== null) frames.push(frame);
}
return frames;
}
function parseFrame(value: string): StackFrame | null {
if (value === "native") {
return { functionName: null, file: null, line: null, column: null, native: true, async: false };
}
let text = value;
let isAsync = false;
if (text.startsWith("async ")) {
isAsync = true;
text = text.slice(6);
}
const locationMatch = /^(.*?) \((.+):(\d+):(\d+)\)$/.exec(text);
if (locationMatch !== null) {
return {
functionName: normalizeName(locationMatch[1] ?? ""),
file: locationMatch[2] ?? null,
line: Number(locationMatch[3]),
column: Number(locationMatch[4]),
native: false,
async: isAsync,
};
}
const bareMatch = /^(.+):(\d+):(\d+)$/.exec(text);
if (bareMatch !== null) {
return {
functionName: null,
file: bareMatch[1] ?? null,
line: Number(bareMatch[2]),
column: Number(bareMatch[3]),
native: false,
async: isAsync,
};
}
return {
functionName: normalizeName(text),
file: null,
line: null,
column: null,
native: false,
async: isAsync,
};
}
function normalizeName(value: string): string | null {
const name = value.trim();
if (name === "" || name === "eval") return null;
return name;
}
const stack = [
"Error: boom",
" at fetchUser (/app/src/users.js:42:13)",
" at async loadProfile (/app/src/profile.js:8:20)",
" at /app/src/index.js:3:1",
" at native",
].join("\n");
console.log(parseStackTrace(stack));
console.log(parseStackTrace("Error: empty"));Report a problem with this exampleOpens a pre-filled issue on GitHub.