summaryrefslogtreecommitdiff
path: root/packages/cli/src/utils/paths.ts
blob: a5368463e0651d6ac82e50e465437e97c361e4fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import process from 'node:process';
import path from 'node:path'; // Import the 'path' module

/**
 * Returns the target directory, using the provided argument or the current working directory.
 */
export function getTargetDirectory(targetDirArg: string | undefined): string {
    return targetDirArg || process.cwd();
}

/**
 * Shortens a path string if it exceeds maxLen, prioritizing the start and end segments.
 * Example: /path/to/a/very/long/file.txt -> /path/.../long/file.txt
 */
export function shortenPath(filePath: string, maxLen: number = 35): string {
    if (filePath.length <= maxLen) {
        return filePath;
    }

    const parsedPath = path.parse(filePath);
    const root = parsedPath.root;
    const separator = path.sep;

    // Get segments of the path *after* the root
    const relativePath = filePath.substring(root.length);
    const segments = relativePath.split(separator).filter(s => s !== ''); // Filter out empty segments

    // Handle cases with no segments after root (e.g., "/", "C:\") or only one segment
    if (segments.length <= 1) {
        // Fallback to simple start/end truncation for very short paths or single segments
        const keepLen = Math.floor((maxLen - 3) / 2);
        // Ensure keepLen is not negative if maxLen is very small
        if (keepLen <= 0) {
             return filePath.substring(0, maxLen - 3) + '...';
        }
        const start = filePath.substring(0, keepLen);
        const end = filePath.substring(filePath.length - keepLen);
        return `${start}...${end}`;
    }

    const firstDir = segments[0];
    const startComponent = root + firstDir;

    const endPartSegments: string[] = [];
    // Base length: startComponent + separator + "..."
    let currentLength = startComponent.length + separator.length + 3;

    // Iterate backwards through segments (excluding the first one)
    for (let i = segments.length - 1; i >= 1; i--) {
        const segment = segments[i];
        // Length needed if we add this segment: current + separator + segment
        const lengthWithSegment = currentLength + separator.length + segment.length;

        if (lengthWithSegment <= maxLen) {
            endPartSegments.unshift(segment); // Add to the beginning of the end part
            currentLength = lengthWithSegment;
        } else {
            // Adding this segment would exceed maxLen
            break;
        }
    }

    // Construct the final path
    let result = startComponent + separator + '...';
    if (endPartSegments.length > 0) {
        result += separator + endPartSegments.join(separator);
    }

    // As a final check, if the result is somehow still too long (e.g., startComponent + ... is too long)
    // fallback to simple truncation of the original path
    if (result.length > maxLen) {
         const keepLen = Math.floor((maxLen - 3) / 2);
         if (keepLen <= 0) {
              return filePath.substring(0, maxLen - 3) + '...';
         }
         const start = filePath.substring(0, keepLen);
         const end = filePath.substring(filePath.length - keepLen);
         return `${start}...${end}`;
    }


    return result;
}

/**
 * Calculates the relative path from a root directory to a target path.
 * Ensures both paths are resolved before calculating.
 * Returns '.' if the target path is the same as the root directory.
 *
 * @param targetPath The absolute or relative path to make relative.
 * @param rootDirectory The absolute path of the directory to make the target path relative to.
 * @returns The relative path from rootDirectory to targetPath.
 */
export function makeRelative(targetPath: string, rootDirectory: string): string {
    const resolvedTargetPath = path.resolve(targetPath);
    const resolvedRootDirectory = path.resolve(rootDirectory);

    const relativePath = path.relative(resolvedRootDirectory, resolvedTargetPath);

    // If the paths are the same, path.relative returns '', return '.' instead
    return relativePath || '.';
}