mirror of
https://github.com/denoland/deno.git
synced 2024-11-29 16:30:56 -05:00
feat(std/node): first pass at url module (#4700)
This commit is contained in:
parent
7630326b4c
commit
22da75b8e5
3 changed files with 196 additions and 0 deletions
|
@ -39,3 +39,8 @@ export function intoCallbackAPIWithIntercept<T1, T2>(
|
||||||
.then((value) => cb && cb(null, interceptor(value)))
|
.then((value) => cb && cb(null, interceptor(value)))
|
||||||
.catch((err) => cb && cb(err, null));
|
.catch((err) => cb && cb(err, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function spliceOne(list: string[], index: number): void {
|
||||||
|
for (; index + 1 < list.length; index++) list[index] = list[index + 1];
|
||||||
|
list.pop();
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ interface ParseOptions {
|
||||||
decodeURIComponent?: (string: string) => string;
|
decodeURIComponent?: (string: string) => string;
|
||||||
maxKeys?: number;
|
maxKeys?: number;
|
||||||
}
|
}
|
||||||
|
export const hexTable = new Array(256);
|
||||||
|
for (let i = 0; i < 256; ++i)
|
||||||
|
hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
|
||||||
|
|
||||||
export function parse(
|
export function parse(
|
||||||
str: string,
|
str: string,
|
||||||
|
@ -43,6 +46,67 @@ interface StringifyOptions {
|
||||||
encodeURIComponent?: (string: string) => string;
|
encodeURIComponent?: (string: string) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function encodeStr(
|
||||||
|
str: string,
|
||||||
|
noEscapeTable: number[],
|
||||||
|
hexTable: string[]
|
||||||
|
): string {
|
||||||
|
const len = str.length;
|
||||||
|
if (len === 0) return "";
|
||||||
|
|
||||||
|
let out = "";
|
||||||
|
let lastPos = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
let c = str.charCodeAt(i);
|
||||||
|
// ASCII
|
||||||
|
if (c < 0x80) {
|
||||||
|
if (noEscapeTable[c] === 1) continue;
|
||||||
|
if (lastPos < i) out += str.slice(lastPos, i);
|
||||||
|
lastPos = i + 1;
|
||||||
|
out += hexTable[c];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastPos < i) out += str.slice(lastPos, i);
|
||||||
|
|
||||||
|
// Multi-byte characters ...
|
||||||
|
if (c < 0x800) {
|
||||||
|
lastPos = i + 1;
|
||||||
|
out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c < 0xd800 || c >= 0xe000) {
|
||||||
|
lastPos = i + 1;
|
||||||
|
out +=
|
||||||
|
hexTable[0xe0 | (c >> 12)] +
|
||||||
|
hexTable[0x80 | ((c >> 6) & 0x3f)] +
|
||||||
|
hexTable[0x80 | (c & 0x3f)];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Surrogate pair
|
||||||
|
++i;
|
||||||
|
|
||||||
|
// This branch should never happen because all URLSearchParams entries
|
||||||
|
// should already be converted to USVString. But, included for
|
||||||
|
// completion's sake anyway.
|
||||||
|
if (i >= len) throw new Deno.errors.InvalidData("invalid URI");
|
||||||
|
|
||||||
|
const c2 = str.charCodeAt(i) & 0x3ff;
|
||||||
|
|
||||||
|
lastPos = i + 1;
|
||||||
|
c = 0x10000 + (((c & 0x3ff) << 10) | c2);
|
||||||
|
out +=
|
||||||
|
hexTable[0xf0 | (c >> 18)] +
|
||||||
|
hexTable[0x80 | ((c >> 12) & 0x3f)] +
|
||||||
|
hexTable[0x80 | ((c >> 6) & 0x3f)] +
|
||||||
|
hexTable[0x80 | (c & 0x3f)];
|
||||||
|
}
|
||||||
|
if (lastPos === 0) return str;
|
||||||
|
if (lastPos < len) return out + str.slice(lastPos);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
export function stringify(
|
export function stringify(
|
||||||
obj: object,
|
obj: object,
|
||||||
sep = "&",
|
sep = "&",
|
||||||
|
|
127
std/node/url.ts
Normal file
127
std/node/url.ts
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
// 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_LOWERCASE_A,
|
||||||
|
CHAR_LOWERCASE_Z,
|
||||||
|
CHAR_FORWARD_SLASH,
|
||||||
|
CHAR_BACKWARD_SLASH,
|
||||||
|
} 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in a new issue