1import {
2 fileBasename,
3 stripSlashPrefixedWindowsDrive,
4 isWindowsAbsolutePath,
5} from "@t3tools/shared/path";
6import { formatFilePathPosition, splitFilePathPosition } from "@t3tools/shared/fileLinks";
7
8function normalizePathSeparators(path: string): string {
9 return path.replaceAll("\\", "/");
10}
11
12function trimTrailingPathSeparators(path: string): string {
13 return path.replace(/[\\/]+$/, "");
14}
15
16function stripRelativePrefixes(path: string): string {
17 return path.replace(/^\.\/+/, "").replace(/^\/+/, "");
18}
19
20export function formatWorkspaceRelativePath(
21 pathWithPosition: string,
22 workspaceRoot: string | undefined,
23): string {
24 const position = splitFilePathPosition(pathWithPosition);
25 const normalizedPath = stripSlashPrefixedWindowsDrive(normalizePathSeparators(position.path));
26
27 let displayPath = normalizedPath;
28 if (workspaceRoot) {
29 const normalizedWorkspaceRoot = stripSlashPrefixedWindowsDrive(
30 normalizePathSeparators(trimTrailingPathSeparators(workspaceRoot)),
31 );
32 const workspaceLabel = fileBasename(normalizedWorkspaceRoot);
33 const caseInsensitive = isWindowsAbsolutePath(stripSlashPrefixedWindowsDrive(workspaceRoot));
34 const pathForCompare = caseInsensitive ? normalizedPath.toLowerCase() : normalizedPath;
35 const workspaceForCompare = caseInsensitive
36 ? normalizedWorkspaceRoot.toLowerCase()
37 : normalizedWorkspaceRoot;
38 const workspaceWithSeparator = `${workspaceForCompare}/`;
39 const workspaceLabelWithSeparator = `${caseInsensitive ? workspaceLabel.toLowerCase() : workspaceLabel}/`;
40
41 if (pathForCompare === workspaceForCompare) {
42 displayPath = workspaceLabel;
43 } else if (pathForCompare.startsWith(workspaceWithSeparator)) {
44 const relativeSuffix = normalizedPath.slice(normalizedWorkspaceRoot.length + 1);
45 displayPath = `${workspaceLabel}/${relativeSuffix}`;
46 } else if (!normalizedPath.startsWith("/")) {
47 const relativePath = stripRelativePrefixes(normalizedPath);
48 displayPath = pathForCompare.startsWith(workspaceLabelWithSeparator)
49 ? normalizedPath
50 : `${workspaceLabel}/${relativePath}`;
51 }
52 }
53
54 return formatFilePathPosition({ ...position, path: displayPath });
55}