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 === '') { 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; }