* Split path into components (OS-aware) * * @param filePath - Path to parse * @returns Object with root, segments, and basename * * @example * // Unix * parse("/home/user/project") // => { root: "/", segments: ["home", "user"], basename: "project" } * * // Windows * par
(filePath: string)
| 81 | * parse("C:\\Users\\user\\project") // => { root: "C:\\", segments: ["Users", "user"], basename: "project" } |
| 82 | */ |
| 83 | static parse(filePath: string): PathComponents { |
| 84 | if (!filePath || typeof filePath !== "string") { |
| 85 | return { root: "", segments: [], basename: filePath }; |
| 86 | } |
| 87 | |
| 88 | const original = filePath; |
| 89 | let root = ""; |
| 90 | let dir = ""; |
| 91 | let base = ""; |
| 92 | |
| 93 | // Determine basename and directory |
| 94 | const lastSlash = isWindowsPlatform() |
| 95 | ? Math.max(original.lastIndexOf("/"), original.lastIndexOf("\\")) |
| 96 | : original.lastIndexOf("/"); |
| 97 | if (lastSlash === -1) { |
| 98 | base = original; |
| 99 | dir = ""; |
| 100 | } else { |
| 101 | base = original.slice(lastSlash + 1); |
| 102 | dir = original.slice(0, lastSlash); |
| 103 | } |
| 104 | |
| 105 | // Determine root |
| 106 | if (isWindowsPlatform()) { |
| 107 | const driveMatch = /^[A-Za-z]:[\\/]/.exec(original); |
| 108 | if (driveMatch) { |
| 109 | root = driveMatch[0]; |
| 110 | // Ensure dir does not include root |
| 111 | if (dir.startsWith(root)) { |
| 112 | dir = dir.slice(root.length); |
| 113 | } |
| 114 | } else if (original.startsWith("\\\\")) { |
| 115 | // UNC paths - treat leading double-backslash as root |
| 116 | root = "\\\\"; |
| 117 | if (dir.startsWith(root)) { |
| 118 | dir = dir.slice(root.length); |
| 119 | } |
| 120 | } |
| 121 | // Also treat Unix-style absolute paths as absolute even on Windows |
| 122 | if (!root && original.startsWith("/")) { |
| 123 | root = "/"; |
| 124 | if (dir.startsWith(root)) { |
| 125 | dir = dir.slice(root.length); |
| 126 | } |
| 127 | } |
| 128 | } else if (original.startsWith("/")) { |
| 129 | root = "/"; |
| 130 | if (dir.startsWith(root)) { |
| 131 | dir = dir.slice(root.length); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | const separatorRegex = isWindowsPlatform() ? /[\\/]+/ : /\/+/; |
| 136 | const segments = dir ? dir.split(separatorRegex).filter(Boolean) : []; |
| 137 | |
| 138 | return { |
| 139 | root, |
| 140 | segments, |