Files
apes-sidebar/src/client/paths.ts
T
Menghuan1918 81ab0c5312 fix: cross-platform path handling and tests
- fs-tree joins listed paths with the platform separator (Windows rows
  previously leaked mixed separators)
- media route containment check goes through isWithin(): separator-
  tolerant and case-insensitive on win32, so case-mismatched Windows
  paths are not misclassified
- relativeTo compares case-insensitively (Windows / case-insensitive
  macOS volumes) while keeping the caller's own casing in the output
- tests: platform-conditional path assertions, os.tmpdir() instead of
  /tmp, isWithin/relativeTo/resolveSidebarPath win32 coverage
2026-08-09 22:07:03 +08:00

29 lines
1.2 KiB
TypeScript

/**
* Path projection helpers shared by the explorer rows: a path relative to
* the session cwd (for the @-reference button and "copy relative path").
* The fs-tree joins with '/' even on Windows, so both separators normalize
* to '/' before comparison.
*/
/**
* The path relative to the session's working directory.
* @param cwd - the explorer root (absolute).
* @param path - an absolute entry path from the fs-tree.
* @returns the relative path with '/' separators ('.' for the cwd itself),
* or `path` unchanged when it lies outside the cwd.
*
* The prefix test is case-insensitive: Windows paths (and macOS's
* case-insensitive volumes) may arrive with different casing than the cwd
* row, and the containment decision must not depend on it. The returned
* relative text keeps the caller's own casing.
*/
export function relativeTo(cwd: string, path: string): string {
const base = cwd.replace(/[\\/]+$/, '')
const norm = (value: string): string => value.replace(/\\/g, '/')
const nBase = norm(base)
const nPath = norm(path)
if (nPath === nBase) return '.'
if (nPath.toLowerCase().startsWith(`${nBase.toLowerCase()}/`)) return nPath.slice(nBase.length + 1)
return path
}