- fs-tree: symlink 目标 stat 从串行改为 32 并发工作池(readdir 流关闭后统一 探测),symlink 密集/网络目标目录不再累加延迟;顺序与分类语义不变 - html-route: 解码不再重建反斜杠 UNC,统一重建为平台中性的 //server/share/... 前斜杠形态(win32/POSIX 均正确 resolve),从而删除 windowsPathStyle 平台信号 与 client isWindowsStylePath 助手;同时解决无 cwd 时正斜杠 UNC 的往返盲点 - 测试/文档同步;移除未使用的 isPosix
48 lines
2.1 KiB
TypeScript
48 lines
2.1 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.
|
|
*
|
|
* This module is dependency-free (no node:path in the client bundle): the
|
|
* host is the authority for path semantics, so this mirror deliberately
|
|
* accepts a SUPERSET of absolute forms — anything a Windows host would emit
|
|
* (drive letters, UNC) plus POSIX roots. A form the host would reject
|
|
* (e.g. a backslash UNC path on a POSIX host) passes through here and then
|
|
* fails loudly in the host's requireAbsolute instead of being silently
|
|
* joined onto the cwd.
|
|
*/
|
|
|
|
/**
|
|
* Mirror of the host's absolute-path notion (see fs-tree.requireAbsolute):
|
|
* POSIX roots, Windows drive letters, and Windows UNC network shares in
|
|
* both backslash (`\\server\share\...`) and forward-slash
|
|
* (`//server/share/...`) form. Deliberately a superset — see the module
|
|
* comment — so a produced UNC path is never joined onto the cwd.
|
|
*/
|
|
export function isAbsolutePath(path: string): boolean {
|
|
return path.startsWith('/') || /^[A-Za-z]:[\\/]/.test(path) || /^[\\/]{2}[^\\/]/.test(path)
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
}
|