From 505e01f9c544b948512626ba155c86ca8ab01005 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Thu, 29 Aug 2024 16:33:23 +0900 Subject: [PATCH 1/4] feat(path/unstable): support URL in first arg of join --- path/join.ts | 22 ++++++++++++++++++++-- path/join_test.ts | 20 +++++++++++++++----- path/posix/join.ts | 26 +++++++++++++++++--------- path/windows/join.ts | 23 ++++++++++++++++++++++- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/path/join.ts b/path/join.ts index 3c09ef727a29..72198451286e 100644 --- a/path/join.ts +++ b/path/join.ts @@ -23,6 +23,24 @@ import { join as windowsJoin } from "./windows/join.ts"; * @param paths Paths to be joined and normalized. * @returns The joined and normalized path. */ -export function join(...paths: string[]): string { - return isWindows ? windowsJoin(...paths) : posixJoin(...paths); +export function join(...paths: string[]): string; +/** + * Join all given a sequence of `paths`,then normalizes the resulting path. + * + * @example Usage + * ```ts + * import { join } from "@std/path/posix/join"; + * import { assertEquals } from "@std/assert"; + * + * const path = join(new URL("file:///foo"), "bar", "baz/asdf", "quux", ".."); + * assertEquals(path, "/foo/bar/baz/asdf"); + * ``` + * + * @param path The path to join. This can be string or file URL. + * @param paths The paths to join. + * @returns The joined path. + */ +export function join(path?: URL | string, ...paths: string[]): string; +export function join(path?: URL | string, ...paths: string[]): string { + return isWindows ? windowsJoin(path, ...paths) : posixJoin(path, ...paths); } diff --git a/path/join_test.ts b/path/join_test.ts index c23d725b8073..88b04b57b32a 100644 --- a/path/join_test.ts +++ b/path/join_test.ts @@ -6,7 +6,9 @@ import { join } from "./join.ts"; const backslashRE = /\\/g; -const joinTests = +type TestCase = [string[] | [URL, ...string[]], string]; + +const joinTests: TestCase[] = // arguments result [ [[".", "x/b", "..", "/b/c.js"], "x/b/c.js"], @@ -56,10 +58,14 @@ const joinTests = [["/", "", "/foo"], "/foo"], [["", "/", "foo"], "/foo"], [["", "/", "/foo"], "/foo"], + + // URLs + [[new URL("file:///"), "x/b", "..", "/b/c.js"], "/x/b/c.js"], + [[new URL("file:///foo"), "../../../bar"], "/bar"], ]; // Windows-specific join tests -const windowsJoinTests = [ +const windowsJoinTests: TestCase[] = [ // arguments result // UNC path expected [["//foo/bar"], "\\\\foo\\bar\\"], @@ -106,11 +112,15 @@ const windowsJoinTests = [ [["c:.", "file"], "c:file"], [["c:", "/"], "c:\\"], [["c:", "file"], "c:\\file"], + // URLs + [[new URL("file:///c:")], "c:\\"], + [[new URL("file:///c:"), "file"], "c:\\file"], + [[new URL("file:///c:/"), "file"], "c:\\file"], ]; Deno.test("posix.join()", function () { joinTests.forEach(function (p) { - const _p = p[0] as string[]; + const _p = p[0]; const actual = posix.join.apply(null, _p); assertEquals(actual, p[1]); }); @@ -118,12 +128,12 @@ Deno.test("posix.join()", function () { Deno.test("windows.join()", function () { joinTests.forEach(function (p) { - const _p = p[0] as string[]; + const _p = p[0]; const actual = windows.join.apply(null, _p).replace(backslashRE, "/"); assertEquals(actual, p[1]); }); windowsJoinTests.forEach(function (p) { - const _p = p[0] as string[]; + const _p = p[0]; const actual = windows.join.apply(null, _p); assertEquals(actual, p[1]); }); diff --git a/path/posix/join.ts b/path/posix/join.ts index 032b1e63ad0c..4634c89735a4 100644 --- a/path/posix/join.ts +++ b/path/posix/join.ts @@ -3,6 +3,7 @@ import { assertPath } from "../_common/assert_path.ts"; import { normalize } from "./normalize.ts"; +import { fromFileUrl } from "./from_file_url.ts"; /** * Join all given a sequence of `paths`,then normalizes the resulting path. @@ -16,24 +17,31 @@ import { normalize } from "./normalize.ts"; * assertEquals(path, "/foo/bar/baz/asdf"); * ``` * - * @example Working with URLs + * @param paths The paths to join. + * @returns The joined path. + */ +export function join(...paths: string[]): string; +/** + * Join all given a sequence of `paths`,then normalizes the resulting path. + * + * @example Usage * ```ts * import { join } from "@std/path/posix/join"; * import { assertEquals } from "@std/assert"; * - * const url = new URL("https://deno.land"); - * url.pathname = join("std", "path", "mod.ts"); - * assertEquals(url.href, "https://deno.land/std/path/mod.ts"); - * - * url.pathname = join("//std", "path/", "/mod.ts"); - * assertEquals(url.href, "https://deno.land/std/path/mod.ts"); + * const path = join(new URL("file:///foo"), "bar", "baz/asdf", "quux", ".."); + * assertEquals(path, "/foo/bar/baz/asdf"); * ``` * + * @param path The path to join. This can be string or file URL. * @param paths The paths to join. * @returns The joined path. */ -export function join(...paths: string[]): string { - if (paths.length === 0) return "."; +export function join(path?: URL | string, ...paths: string[]): string; +export function join(path?: URL | string, ...paths: string[]): string { + if (path === undefined) return "."; + path = path instanceof URL ? fromFileUrl(path) : path; + paths = path ? [path, ...paths] : paths; paths.forEach((path) => assertPath(path)); const joined = paths.filter((path) => path.length > 0).join("/"); return joined === "" ? "." : normalize(joined); diff --git a/path/windows/join.ts b/path/windows/join.ts index 58f0e9592149..dcbb1b6186a6 100644 --- a/path/windows/join.ts +++ b/path/windows/join.ts @@ -4,6 +4,7 @@ import { assertPath } from "../_common/assert_path.ts"; import { isPathSeparator } from "./_util.ts"; import { normalize } from "./normalize.ts"; +import { fromFileUrl } from "./from_file_url.ts"; /** * Join all given a sequence of `paths`,then normalizes the resulting path. @@ -20,7 +21,27 @@ import { normalize } from "./normalize.ts"; * @param paths The paths to join. * @returns The joined path. */ -export function join(...paths: string[]): string { +export function join(...paths: string[]): string; +/** + * Join all given a sequence of `paths`,then normalizes the resulting path. + * + * @example Usage + * ```ts + * import { join } from "@std/path/windows/join"; + * import { assertEquals } from "@std/assert"; + * + * const joined = join(new URL("file:///C:/foo"), "bar", "baz\\.."); + * assertEquals(joined, "C:\\foo\\bar"); + * ``` + * + * @param path The path to join. This can be string or file URL. + * @param paths The paths to join. + * @returns The joined path. + */ +export function join(path?: URL | string, ...paths: string[]): string; +export function join(path?: URL | string, ...paths: string[]): string { + path = path instanceof URL ? fromFileUrl(path) : path; + paths = path ? [path, ...paths] : paths; paths.forEach((path) => assertPath(path)); paths = paths.filter((path) => path.length > 0); if (paths.length === 0) return "."; From be38e342affeb46dd18087046a08d75894a2850f Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Thu, 29 Aug 2024 16:34:33 +0900 Subject: [PATCH 2/4] add experimental tag --- path/join.ts | 2 ++ path/posix/join.ts | 2 ++ path/windows/join.ts | 2 ++ 3 files changed, 6 insertions(+) diff --git a/path/join.ts b/path/join.ts index 72198451286e..b81da133adc6 100644 --- a/path/join.ts +++ b/path/join.ts @@ -27,6 +27,8 @@ export function join(...paths: string[]): string; /** * Join all given a sequence of `paths`,then normalizes the resulting path. * + * @experimental **UNSTABLE**: New API, yet to be vetted. + * * @example Usage * ```ts * import { join } from "@std/path/posix/join"; diff --git a/path/posix/join.ts b/path/posix/join.ts index 4634c89735a4..2ce2b5fab469 100644 --- a/path/posix/join.ts +++ b/path/posix/join.ts @@ -24,6 +24,8 @@ export function join(...paths: string[]): string; /** * Join all given a sequence of `paths`,then normalizes the resulting path. * + * @experimental **UNSTABLE**: New API, yet to be vetted. + * * @example Usage * ```ts * import { join } from "@std/path/posix/join"; diff --git a/path/windows/join.ts b/path/windows/join.ts index dcbb1b6186a6..8d6a66564eb0 100644 --- a/path/windows/join.ts +++ b/path/windows/join.ts @@ -25,6 +25,8 @@ export function join(...paths: string[]): string; /** * Join all given a sequence of `paths`,then normalizes the resulting path. * + * @experimental **UNSTABLE**: New API, yet to be vetted. + * * @example Usage * ```ts * import { join } from "@std/path/windows/join"; From b63f04a5f1895f27ecc8f22fa63a452a93afea0b Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Fri, 30 Aug 2024 10:10:13 +1000 Subject: [PATCH 3/4] Apply suggestions from code review --- path/join.ts | 2 +- path/posix/join.ts | 2 +- path/windows/join.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/path/join.ts b/path/join.ts index b81da133adc6..dc86795e1611 100644 --- a/path/join.ts +++ b/path/join.ts @@ -25,7 +25,7 @@ import { join as windowsJoin } from "./windows/join.ts"; */ export function join(...paths: string[]): string; /** - * Join all given a sequence of `paths`,then normalizes the resulting path. + * Join all given a sequence of `paths`, then normalizes the resulting path. * * @experimental **UNSTABLE**: New API, yet to be vetted. * diff --git a/path/posix/join.ts b/path/posix/join.ts index 2ce2b5fab469..4500650a448b 100644 --- a/path/posix/join.ts +++ b/path/posix/join.ts @@ -22,7 +22,7 @@ import { fromFileUrl } from "./from_file_url.ts"; */ export function join(...paths: string[]): string; /** - * Join all given a sequence of `paths`,then normalizes the resulting path. + * Join all given a sequence of `paths`, then normalizes the resulting path. * * @experimental **UNSTABLE**: New API, yet to be vetted. * diff --git a/path/windows/join.ts b/path/windows/join.ts index 8d6a66564eb0..029b36e85200 100644 --- a/path/windows/join.ts +++ b/path/windows/join.ts @@ -23,7 +23,7 @@ import { fromFileUrl } from "./from_file_url.ts"; */ export function join(...paths: string[]): string; /** - * Join all given a sequence of `paths`,then normalizes the resulting path. + * Join all given a sequence of `paths`, then normalizes the resulting path. * * @experimental **UNSTABLE**: New API, yet to be vetted. * From 97942c10b2d78abfae7532f4154be03e3e76b151 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 30 Aug 2024 12:53:31 +0900 Subject: [PATCH 4/4] test(path): add a test case --- path/join_test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/path/join_test.ts b/path/join_test.ts index 88b04b57b32a..c91a9c9a5f55 100644 --- a/path/join_test.ts +++ b/path/join_test.ts @@ -62,6 +62,10 @@ const joinTests: TestCase[] = // URLs [[new URL("file:///"), "x/b", "..", "/b/c.js"], "/x/b/c.js"], [[new URL("file:///foo"), "../../../bar"], "/bar"], + [ + [new URL("file:///foo"), "bar", "baz/asdf", "quux", ".."], + "/foo/bar/baz/asdf", + ], ]; // Windows-specific join tests