Skip to content

Commit

Permalink
feat(std/path): Add toFileUrl() (denoland#7971)
Browse files Browse the repository at this point in the history
  • Loading branch information
nayeemrmn committed Oct 19, 2020
1 parent 342b151 commit 19b918d
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 5 deletions.
1 change: 1 addition & 0 deletions std/path/mod.ts
Expand Up @@ -24,6 +24,7 @@ export const {
relative,
resolve,
sep,
toFileUrl,
toNamespacedPath,
} = path;

Expand Down
13 changes: 13 additions & 0 deletions std/path/posix.ts
Expand Up @@ -440,3 +440,16 @@ export function fromFileUrl(url: string | URL): string {
url.pathname.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"),
);
}

/** Converts a path string to a file URL.
*
* toFileUrl("/home/foo"); // new URL("file:///home/foo")
*/
export function toFileUrl(path: string): URL {
if (!isAbsolute(path)) {
throw new TypeError("Must be an absolute path.");
}
const url = new URL("file:///");
url.pathname = path.replace(/%/g, "%25").replace(/\\/g, "%5C");
return url;
}
49 changes: 49 additions & 0 deletions std/path/to_file_url_test.ts
@@ -0,0 +1,49 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { posix, win32 } from "./mod.ts";
import { assertEquals, assertThrows } from "../testing/asserts.ts";

Deno.test("[path] toFileUrl", function () {
assertEquals(posix.toFileUrl("/home/foo").href, "file:///home/foo");
assertEquals(posix.toFileUrl("/home/ ").href, "file:///home/%20");
assertEquals(posix.toFileUrl("/home/%20").href, "file:///home/%2520");
assertEquals(posix.toFileUrl("/home\\foo").href, "file:///home%5Cfoo");
assertThrows(
() => posix.toFileUrl("foo").href,
TypeError,
"Must be an absolute path.",
);
assertThrows(
() => posix.toFileUrl("C:/"),
TypeError,
"Must be an absolute path.",
);
assertEquals(
posix.toFileUrl("//localhost/home/foo").href,
"file:////localhost/home/foo",
);
assertEquals(posix.toFileUrl("//localhost/").href, "file:////localhost/");
assertEquals(posix.toFileUrl("//:/home/foo").href, "file:////:/home/foo");
});

Deno.test("[path] toFileUrl (win32)", function () {
assertEquals(win32.toFileUrl("/home/foo").href, "file:///home/foo");
assertEquals(win32.toFileUrl("/home/ ").href, "file:///home/%20");
assertEquals(win32.toFileUrl("/home/%20").href, "file:///home/%2520");
assertEquals(win32.toFileUrl("/home\\foo").href, "file:///home/foo");
assertThrows(
() => win32.toFileUrl("foo").href,
TypeError,
"Must be an absolute path.",
);
assertEquals(win32.toFileUrl("C:/").href, "file:///C:/");
assertEquals(
win32.toFileUrl("//localhost/home/foo").href,
"file://localhost/home/foo",
);
assertEquals(win32.toFileUrl("//localhost/").href, "file:////localhost/");
assertThrows(
() => win32.toFileUrl("//:/home/foo").href,
TypeError,
"Invalid hostname.",
);
});
31 changes: 26 additions & 5 deletions std/path/win32.ts
Expand Up @@ -917,11 +917,8 @@ export function fromFileUrl(url: string | URL): string {
throw new TypeError("Must be a file URL.");
}
let path = decodeURIComponent(
url.pathname
.replace(/^\/*([A-Za-z]:)(\/|$)/, "$1/")
.replace(/\//g, "\\")
.replace(/%(?![0-9A-Fa-f]{2})/g, "%25"),
);
url.pathname.replace(/\//g, "\\").replace(/%(?![0-9A-Fa-f]{2})/g, "%25"),
).replace(/^\\*([A-Za-z]:)(\\|$)/, "$1\\");
if (url.hostname != "") {
// Note: The `URL` implementation guarantees that the drive letter and
// hostname are mutually exclusive. Otherwise it would not have been valid
Expand All @@ -930,3 +927,27 @@ export function fromFileUrl(url: string | URL): string {
}
return path;
}

/** Converts a path string to a file URL.
*
* toFileUrl("\\home\\foo"); // new URL("file:///home/foo")
* toFileUrl("C:\\Users\\foo"); // new URL("file:///C:/Users/foo")
* toFileUrl("\\\\localhost\\home\\foo"); // new URL("file://localhost/home/foo")
*/
export function toFileUrl(path: string): URL {
if (!isAbsolute(path)) {
throw new TypeError("Must be an absolute path.");
}
const [, hostname, pathname] = path.match(
/^(?:[/\\]{2}([^/\\]+)(?=[/\\][^/\\]))?(.*)/,
)!;
const url = new URL("file:///");
url.pathname = pathname.replace(/%/g, "%25");
if (hostname != null) {
url.hostname = hostname;
if (!url.hostname) {
throw new TypeError("Invalid hostname.");
}
}
return url;
}

0 comments on commit 19b918d

Please sign in to comment.