cordis/stack-trace/stack-trace.ts
2021-10-30 12:26:41 -05:00

75 lines
1.8 KiB
TypeScript

export function parse(err: Error): Frame[] {
if (!err.stack) {
return [];
}
const lines = err.stack.split('\n').slice(1);
return lines
.map(function(line: string): Frame | null {
if (line.match(/^\s*[-]{4,}$/)) {
return { fileName: line };
}
const lineMatch = line.match(/at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/);
if (!lineMatch) {
return null;
}
let object: any = null;
let method: any = null;
let functionName: any = null;
let typeName: any = null;
let methodName: any = null;
let isNative: boolean = (lineMatch[5] === 'native');
if (lineMatch[1]) {
functionName = lineMatch[1];
let methodStart = functionName.lastIndexOf('.');
if (functionName[methodStart-1] == '.')
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 (method) {
typeName = object;
methodName = method;
}
if (method === '<anonymous>') {
methodName = null;
functionName = null;
}
return {
fileName: lineMatch[2] ?? undefined,
lineNumber: parseInt(lineMatch[3], 10) ?? undefined,
functionName: functionName,
typeName: typeName,
methodName: methodName,
columnNumber: parseInt(lineMatch[4], 10) ?? undefined,
native: isNative,
};
})
.filter(function(callSite): boolean {
return !!callSite;
}) as Frame[];
}
export interface Frame {
readonly native?: boolean;
readonly typeName?: string;
readonly functionName?: string;
readonly methodName?: string;
readonly fileName?: string;
readonly lineNumber?: number;
readonly columnNumber?: number;
}