diff --git a/lib/utils/normalize-path.ts b/lib/utils/normalize-path.ts index debc468..7b8c4af 100644 --- a/lib/utils/normalize-path.ts +++ b/lib/utils/normalize-path.ts @@ -1,6 +1,6 @@ export function normalizePath(path: string): string { if (!path || path === "/") return "" - let normalized = path.replace(/\\+/g, "/").replace(/\/\/+/, "/") + let normalized = path.replace(/\\+/g, "/").replace(/\/\/+/g, "/") if (normalized.startsWith("/")) { normalized = normalized.slice(1) } diff --git a/tests/utils/normalize-path.test.ts b/tests/utils/normalize-path.test.ts new file mode 100644 index 0000000..3854b1c --- /dev/null +++ b/tests/utils/normalize-path.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from "bun:test" +import { normalizePath } from "../../lib/utils/normalize-path" + +describe("normalizePath", () => { + it("collapses multiple internal repeated-slash groups", () => { + expect(normalizePath("a///b///c.txt")).toBe("a/b/c.txt") + }) + + it("collapses every repeated-slash group", () => { + expect(normalizePath("a//b//c//d")).toBe("a/b/c/d") + }) + + it("handles repeated leading and trailing slashes", () => { + expect(normalizePath("///a///b///")).toBe("a/b") + }) + + it("normalizes three repeated-slash groups", () => { + expect(normalizePath("a////b//c///d")).toBe("a/b/c/d") + }) + + it("is idempotent", () => { + const once = normalizePath("a///b///c.txt") + expect(normalizePath(once)).toBe(once) + }) + + it("keeps ordinary paths unchanged", () => { + expect(normalizePath("a/b/c.txt")).toBe("a/b/c.txt") + }) + + it("handles empty and root paths", () => { + expect(normalizePath("")).toBe("") + expect(normalizePath("/")).toBe("") + expect(normalizePath("////")).toBe("") + }) + + it("normalizes Windows-style separators", () => { + expect(normalizePath(String.raw`a\b\c.txt`)).toBe("a/b/c.txt") + }) + + it("removes a single leading and trailing slash", () => { + expect(normalizePath("/a/b/")).toBe("a/b") + }) +})