import * as path from 'path'; export interface Frame { functionName?: string; fileName: string; line?: number; column?: number; } /** Converts an error into a list of frames based on the error stack */ 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 { if (line.match(/^\s*[-]{4,}$/)) { return { fileName: line }; } let pieces = line.trim().split(' '); // pieces[0] will always be 'at' function parseData(fileUri: string, functionName?: string): Frame { let pieces = fileUri.split(':'); let column: number | undefined = parseInt(pieces[pieces.length - 1]); if (Number.isNaN(column)) column = undefined; let line: number | undefined = parseInt(pieces[pieces.length - 2]); if (Number.isNaN(line)) line = undefined; let colLinePieces = (column ? 1 : 0) + (line ? 1 : 0) let fileName = pieces.slice(0, pieces.length - colLinePieces).join(':'); return { fileName: fileName, line: line, column: column, functionName: functionName }; } if (pieces.length === 2) { return parseData(pieces[1]); } else { // chop of parenthesis chop off 'at' and file path return parseData(pieces[pieces.length - 1].slice(1, -1), pieces.slice(1, -1).join(' ')); } }); } export function relativizeFilePath(frame: Frame, baseDir: string): Frame { if (frame.fileName && frame.fileName[0] === '/') { let relativeFileName = path.relative(baseDir, frame.fileName); return Object.assign({}, frame, { fileName: relativeFileName }); } return frame; } /** Converts a parsed frame into a line that "could have come from an Error" */ export function getFrameLine(frame: Frame): string { if (frame.functionName) { if (frame.line) { if (frame.column) { return ` at ${frame.functionName} (${frame.fileName}:${frame.line}:${frame.column})`; } else { return ` at ${frame.functionName} (${frame.fileName}:${frame.line})`; } } else { return ` at ${frame.functionName} (${frame.fileName})`; } } else { if (frame.line) { if (frame.column) { return ` at ${frame.fileName}:${frame.line}:${frame.column}`; } else { return ` at ${frame.fileName}:${frame.line}`; } } else { return ` at ${frame.fileName}`; } } }