1*26ad19fcSEvan Baconimport type { StackFrame } from 'stacktrace-parser'; 2*26ad19fcSEvan Bacon 3*26ad19fcSEvan Baconexport type MetroStackFrame = StackFrame & { collapse?: boolean }; 4*26ad19fcSEvan Bacon 5*26ad19fcSEvan Baconexport function formatProjectFilePath(projectRoot: string, file?: string | null): string { 6*26ad19fcSEvan Bacon if (file == null) { 7*26ad19fcSEvan Bacon return '<unknown>'; 8*26ad19fcSEvan Bacon } 9*26ad19fcSEvan Bacon 10*26ad19fcSEvan Bacon return pathRelativeToPath(file.replace(/\\/g, '/'), projectRoot.replace(/\\/g, '/')).replace( 11*26ad19fcSEvan Bacon /\?.*$/, 12*26ad19fcSEvan Bacon '' 13*26ad19fcSEvan Bacon ); 14*26ad19fcSEvan Bacon} 15*26ad19fcSEvan Bacon 16*26ad19fcSEvan Baconfunction pathRelativeToPath(path: string, relativeTo: string, sep = '/') { 17*26ad19fcSEvan Bacon const relativeToParts = relativeTo.split(sep); 18*26ad19fcSEvan Bacon const pathParts = path.split(sep); 19*26ad19fcSEvan Bacon let i = 0; 20*26ad19fcSEvan Bacon while (i < relativeToParts.length && i < pathParts.length) { 21*26ad19fcSEvan Bacon if (relativeToParts[i] !== pathParts[i]) { 22*26ad19fcSEvan Bacon break; 23*26ad19fcSEvan Bacon } 24*26ad19fcSEvan Bacon i++; 25*26ad19fcSEvan Bacon } 26*26ad19fcSEvan Bacon return pathParts.slice(i).join(sep); 27*26ad19fcSEvan Bacon} 28*26ad19fcSEvan Bacon 29*26ad19fcSEvan Baconexport function getStackFormattedLocation(projectRoot: string, frame: MetroStackFrame) { 30*26ad19fcSEvan Bacon const column = frame.column != null && parseInt(String(frame.column), 10); 31*26ad19fcSEvan Bacon const location = 32*26ad19fcSEvan Bacon formatProjectFilePath(projectRoot, frame.file) + 33*26ad19fcSEvan Bacon (frame.lineNumber != null 34*26ad19fcSEvan Bacon ? ':' + frame.lineNumber + (column && !isNaN(column) ? ':' + (column + 1) : '') 35*26ad19fcSEvan Bacon : ''); 36*26ad19fcSEvan Bacon 37*26ad19fcSEvan Bacon return location; 38*26ad19fcSEvan Bacon} 39