( fs: FsOperations, absolutePath: string, )
| 213 | * symlinks. Same core algorithm as teamMemPaths.ts:realpathDeepestExisting. |
| 214 | */ |
| 215 | export function resolveDeepestExistingAncestorSync( |
| 216 | fs: FsOperations, |
| 217 | absolutePath: string, |
| 218 | ): string | undefined { |
| 219 | let dir = absolutePath |
| 220 | const segments: string[] = [] |
| 221 | // Walk up using lstat (cheap, O(1)) to find the first existing component. |
| 222 | // lstat does not follow symlinks, so dangling symlinks are detected here. |
| 223 | // Only call realpathSync (expensive, O(depth)) once at the end. |
| 224 | while (dir !== nodePath.dirname(dir)) { |
| 225 | let st: fs.Stats |
| 226 | try { |
| 227 | st = fs.lstatSync(dir) |
| 228 | } catch { |
| 229 | // lstat failed: truly non-existent. Walk up. |
| 230 | segments.unshift(nodePath.basename(dir)) |
| 231 | dir = nodePath.dirname(dir) |
| 232 | continue |
| 233 | } |
| 234 | if (st.isSymbolicLink()) { |
| 235 | // Found a symlink (live or dangling). Try realpath first (resolves |
| 236 | // chained symlinks); fall back to readlink for dangling symlinks. |
| 237 | try { |
| 238 | const resolved = fs.realpathSync(dir) |
| 239 | return segments.length === 0 |
| 240 | ? resolved |
| 241 | : nodePath.join(resolved, ...segments) |
| 242 | } catch { |
| 243 | // Dangling: realpath failed but lstat saw the link entry. |
| 244 | const target = fs.readlinkSync(dir) |
| 245 | const absTarget = nodePath.isAbsolute(target) |
| 246 | ? target |
| 247 | : nodePath.resolve(nodePath.dirname(dir), target) |
| 248 | return segments.length === 0 |
| 249 | ? absTarget |
| 250 | : nodePath.join(absTarget, ...segments) |
| 251 | } |
| 252 | } |
| 253 | // Existing non-symlink component. One realpath call resolves any |
| 254 | // symlinks in its ancestors. If none, return undefined (no symlink). |
| 255 | try { |
| 256 | const resolved = fs.realpathSync(dir) |
| 257 | if (resolved !== dir) { |
| 258 | return segments.length === 0 |
| 259 | ? resolved |
| 260 | : nodePath.join(resolved, ...segments) |
| 261 | } |
| 262 | } catch { |
| 263 | // realpath can still fail (e.g. EACCES in ancestors). Return |
| 264 | // undefined — we can't resolve, and the logical path is already |
| 265 | // in pathSet for the caller. |
| 266 | } |
| 267 | return undefined |
| 268 | } |
| 269 | return undefined |
| 270 | } |
| 271 | |
| 272 | /** |
no test coverage detected