export function isWindowsDrivePath(value: string): boolean { return /^[a-zA-Z]:([/\\]|$)/.test(value); } export function isUncPath(value: string): boolean { return value.startsWith("\\\\"); } export function isWindowsAbsolutePath(value: string): boolean { return isUncPath(value) || isWindowsDrivePath(value); } export function isExplicitRelativePath(value: string): boolean { return ( value === "." || value === ".." || value.startsWith("./") || value.startsWith("../") || value.startsWith(".\\") || value.startsWith("..\\") ); } function isRootPath(value: string): boolean { return value === "/" || value === "\\" || /^[a-zA-Z]:[/\\]?$/.test(value); } function trimTrailingPathSeparators(value: string): string { if (value.length === 0 || isRootPath(value)) { return value; } const trimmed = value.startsWith("/") ? value.replace(/\/+$/g, "") : value.replace(/[\\/]+$/g, ""); if (trimmed.length === 0) { return value; } return /^[a-zA-Z]:$/.test(trimmed) ? `${trimmed}\\` : trimmed; } export function normalizeProjectPathForDispatch(value: string): string { return trimTrailingPathSeparators(value.trim()); } export function normalizeProjectPathForComparison(value: string): string { const normalized = normalizeProjectPathForDispatch(value); if (isWindowsDrivePath(normalized) || isUncPath(normalized)) { return normalized.replaceAll("/", "\\").toLowerCase(); } return normalized; }