diff --git a/src/utils/joinPath.test.ts b/src/utils/joinPath.test.ts new file mode 100644 index 0000000000..6c9780447f --- /dev/null +++ b/src/utils/joinPath.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from "vitest"; +import { joinPath } from "./joinPath"; + +describe("joinPath", () => { + it("returns an empty string when no paths are provided", () => { + expect(joinPath()).toBe(""); + }); + + it("joins paths", () => { + expect(joinPath("foo", "bar", "baz")).toBe("foo/bar/baz"); + expect(joinPath("foo", "/bar", "baz")).toBe("foo/bar/baz"); + expect(joinPath("foo", "bar/", "baz")).toBe("foo/bar/baz"); + expect(joinPath("foo", "/bar/", "baz")).toBe("foo/bar/baz"); + }); + + it("joins paths with leading slashes", () => { + expect(joinPath("/foo", "bar", "baz")).toBe("/foo/bar/baz"); + }); + + it("joins paths with trailing slashes", () => { + expect(joinPath("foo", "bar", "baz/")).toBe("foo/bar/baz/"); + }); +}); diff --git a/src/utils/joinPath.ts b/src/utils/joinPath.ts new file mode 100644 index 0000000000..ccf4eff9c6 --- /dev/null +++ b/src/utils/joinPath.ts @@ -0,0 +1,22 @@ +const PATH_SEPARATOR = "/"; + +export function joinPath(...paths: string[]) { + const normalizedPaths = paths.map((path, index) => { + const isFirst = index === 0; + const isLast = index === paths.length - 1; + + // Strip out any leading slashes from the path. + if (!isFirst && path.startsWith(PATH_SEPARATOR)) { + path = path.slice(1); + } + + // Strip out any trailing slashes from the path. + if (!isLast && path.endsWith(PATH_SEPARATOR)) { + path = path.slice(0, -1); + } + + return path; + }, []); + + return normalizedPaths.join(PATH_SEPARATOR); +}