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