summaryrefslogtreecommitdiff
path: root/std/node/_url.ts
diff options
context:
space:
mode:
authorGuy Bedford <guybedford@gmail.com>2020-11-09 06:25:13 -0800
committerGitHub <noreply@github.com>2020-11-09 09:25:13 -0500
commit8b7f5531ee1ccde897e87890e9aabc554fedb9dd (patch)
tree117a85b98d1488c290d8acc392cfb99b1b21f8e0 /std/node/_url.ts
parent293cae5e1ff2a5768e2f3a73cc18f99acc3fbfbd (diff)
feat(std/node): consistent Node.js builtin shapes (#8274)
Diffstat (limited to 'std/node/_url.ts')
-rw-r--r--std/node/_url.ts140
1 files changed, 140 insertions, 0 deletions
diff --git a/std/node/_url.ts b/std/node/_url.ts
new file mode 100644
index 000000000..82daa25e9
--- /dev/null
+++ b/std/node/_url.ts
@@ -0,0 +1,140 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import {
+ CHAR_BACKWARD_SLASH,
+ CHAR_FORWARD_SLASH,
+ CHAR_LOWERCASE_A,
+ CHAR_LOWERCASE_Z,
+} from "../path/_constants.ts";
+import * as path from "./path.ts";
+
+const isWindows = Deno.build.os === "windows";
+
+const forwardSlashRegEx = /\//g;
+const percentRegEx = /%/g;
+const backslashRegEx = /\\/g;
+const newlineRegEx = /\n/g;
+const carriageReturnRegEx = /\r/g;
+const tabRegEx = /\t/g;
+
+const _url = URL;
+export { _url as URL };
+
+/**
+ * Get fully resolved platform-specific file path from the given URL string/ object
+ * @param path The file URL string or URL object to convert to a path
+ */
+export function fileURLToPath(path: string | URL): string {
+ if (typeof path === "string") path = new URL(path);
+ else if (!(path instanceof URL)) {
+ throw new Deno.errors.InvalidData(
+ "invalid argument path , must be a string or URL",
+ );
+ }
+ if (path.protocol !== "file:") {
+ throw new Deno.errors.InvalidData("invalid url scheme");
+ }
+ return isWindows ? getPathFromURLWin(path) : getPathFromURLPosix(path);
+}
+
+function getPathFromURLWin(url: URL): string {
+ const hostname = url.hostname;
+ let pathname = url.pathname;
+ for (let n = 0; n < pathname.length; n++) {
+ if (pathname[n] === "%") {
+ const third = pathname.codePointAt(n + 2) || 0x20;
+ if (
+ (pathname[n + 1] === "2" && third === 102) || // 2f 2F /
+ (pathname[n + 1] === "5" && third === 99)
+ ) {
+ // 5c 5C \
+ throw new Deno.errors.InvalidData(
+ "must not include encoded \\ or / characters",
+ );
+ }
+ }
+ }
+
+ pathname = pathname.replace(forwardSlashRegEx, "\\");
+ pathname = decodeURIComponent(pathname);
+ if (hostname !== "") {
+ //TODO add support for punycode encodings
+ return `\\\\${hostname}${pathname}`;
+ } else {
+ // Otherwise, it's a local path that requires a drive letter
+ const letter = pathname.codePointAt(1)! | 0x20;
+ const sep = pathname[2];
+ if (
+ letter < CHAR_LOWERCASE_A ||
+ letter > CHAR_LOWERCASE_Z || // a..z A..Z
+ sep !== ":"
+ ) {
+ throw new Deno.errors.InvalidData("file url path must be absolute");
+ }
+ return pathname.slice(1);
+ }
+}
+
+function getPathFromURLPosix(url: URL): string {
+ if (url.hostname !== "") {
+ throw new Deno.errors.InvalidData("invalid file url hostname");
+ }
+ const pathname = url.pathname;
+ for (let n = 0; n < pathname.length; n++) {
+ if (pathname[n] === "%") {
+ const third = pathname.codePointAt(n + 2) || 0x20;
+ if (pathname[n + 1] === "2" && third === 102) {
+ throw new Deno.errors.InvalidData(
+ "must not include encoded / characters",
+ );
+ }
+ }
+ }
+ return decodeURIComponent(pathname);
+}
+
+/** Get fully resolved platform-specific File URL from the given file path */
+export function pathToFileURL(filepath: string): URL {
+ let resolved = path.resolve(filepath);
+ // path.resolve strips trailing slashes so we must add them back
+ const filePathLast = filepath.charCodeAt(filepath.length - 1);
+ if (
+ (filePathLast === CHAR_FORWARD_SLASH ||
+ (isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
+ resolved[resolved.length - 1] !== path.sep
+ ) {
+ resolved += "/";
+ }
+ const outURL = new URL("file://");
+ if (resolved.includes("%")) resolved = resolved.replace(percentRegEx, "%25");
+ // In posix, "/" is a valid character in paths
+ if (!isWindows && resolved.includes("\\")) {
+ resolved = resolved.replace(backslashRegEx, "%5C");
+ }
+ if (resolved.includes("\n")) resolved = resolved.replace(newlineRegEx, "%0A");
+ if (resolved.includes("\r")) {
+ resolved = resolved.replace(carriageReturnRegEx, "%0D");
+ }
+ if (resolved.includes("\t")) resolved = resolved.replace(tabRegEx, "%09");
+ outURL.pathname = resolved;
+ return outURL;
+}