diff options
| author | Luke Parker <[email protected]> | 2026-02-25 00:03:15 +1000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-02-25 00:03:15 +1000 |
| commit | 082f0cc12734ccc961797ab9a63dd88a2ce3eed5 (patch) | |
| tree | b3f3471be01ba08942c67fd4542874605bd44e2f /packages/app/src/context/file | |
| parent | 2cee947671fa373098db308b173c859cada0b108 (diff) | |
| download | opencode-082f0cc12734ccc961797ab9a63dd88a2ce3eed5.tar.gz opencode-082f0cc12734ccc961797ab9a63dd88a2ce3eed5.zip | |
fix(app): preserve native path separators in file path helpers (#14912)
Diffstat (limited to 'packages/app/src/context/file')
| -rw-r--r-- | packages/app/src/context/file/path.test.ts | 4 | ||||
| -rw-r--r-- | packages/app/src/context/file/path.ts | 24 |
2 files changed, 13 insertions, 15 deletions
diff --git a/packages/app/src/context/file/path.test.ts b/packages/app/src/context/file/path.test.ts index 7eb5e8b2a..feef6d466 100644 --- a/packages/app/src/context/file/path.test.ts +++ b/packages/app/src/context/file/path.test.ts @@ -15,10 +15,10 @@ describe("file path helpers", () => { test("normalizes Windows absolute paths with mixed separators", () => { const path = createPathHelpers(() => "C:\\repo") - expect(path.normalize("C:\\repo\\src\\app.ts")).toBe("src/app.ts") + expect(path.normalize("C:\\repo\\src\\app.ts")).toBe("src\\app.ts") expect(path.normalize("C:/repo/src/app.ts")).toBe("src/app.ts") expect(path.normalize("file://C:/repo/src/app.ts")).toBe("src/app.ts") - expect(path.normalize("c:\\repo\\src\\app.ts")).toBe("src/app.ts") + expect(path.normalize("c:\\repo\\src\\app.ts")).toBe("src\\app.ts") }) test("keeps query/hash stripping behavior stable", () => { diff --git a/packages/app/src/context/file/path.ts b/packages/app/src/context/file/path.ts index 72c058aec..53f072b6c 100644 --- a/packages/app/src/context/file/path.ts +++ b/packages/app/src/context/file/path.ts @@ -103,32 +103,30 @@ export function encodeFilePath(filepath: string): string { export function createPathHelpers(scope: () => string) { const normalize = (input: string) => { - const root = scope().replace(/\\/g, "/") + const root = scope() - let path = unquoteGitPath(decodeFilePath(stripQueryAndHash(stripFileProtocol(input)))).replace(/\\/g, "/") + let path = unquoteGitPath(decodeFilePath(stripQueryAndHash(stripFileProtocol(input)))) - // Remove initial root prefix, if it's a complete match or followed by / - // (don't want /foo/bar to root of /f). - // For Windows paths, also check for case-insensitive match. - const windows = /^[A-Za-z]:/.test(root) - const canonRoot = windows ? root.toLowerCase() : root - const canonPath = windows ? path.toLowerCase() : path + // Separator-agnostic prefix stripping for Cygwin/native Windows compatibility + // Only case-insensitive on Windows (drive letter or UNC paths) + const windows = /^[A-Za-z]:/.test(root) || root.startsWith("\\\\") + const canonRoot = windows ? root.replace(/\\/g, "/").toLowerCase() : root.replace(/\\/g, "/") + const canonPath = windows ? path.replace(/\\/g, "/").toLowerCase() : path.replace(/\\/g, "/") if ( canonPath.startsWith(canonRoot) && - (canonRoot.endsWith("/") || canonPath === canonRoot || canonPath.startsWith(canonRoot + "/")) + (canonRoot.endsWith("/") || canonPath === canonRoot || canonPath[canonRoot.length] === "/") ) { - // If we match canonRoot + "/", the slash will be removed below. + // Slice from original path to preserve native separators path = path.slice(root.length) } - if (path.startsWith("./")) { + if (path.startsWith("./") || path.startsWith(".\\")) { path = path.slice(2) } - if (path.startsWith("/")) { + if (path.startsWith("/") || path.startsWith("\\")) { path = path.slice(1) } - return path } |
