import { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_INVALID_FILE_URL_HOST, ERR_INVALID_FILE_URL_PATH, ERR_INVALID_URL_SCHEME,} from "./internal/errors.ts";import { CHAR_0, CHAR_9, CHAR_AT, CHAR_BACKWARD_SLASH, CHAR_CARRIAGE_RETURN, CHAR_CIRCUMFLEX_ACCENT, CHAR_DOT, CHAR_DOUBLE_QUOTE, CHAR_FORM_FEED, CHAR_FORWARD_SLASH, CHAR_GRAVE_ACCENT, CHAR_HASH, CHAR_HYPHEN_MINUS, CHAR_LEFT_ANGLE_BRACKET, CHAR_LEFT_CURLY_BRACKET, CHAR_LEFT_SQUARE_BRACKET, CHAR_LINE_FEED, CHAR_LOWERCASE_A, CHAR_LOWERCASE_Z, CHAR_NO_BREAK_SPACE, CHAR_PERCENT, CHAR_PLUS, CHAR_QUESTION_MARK, CHAR_RIGHT_ANGLE_BRACKET, CHAR_RIGHT_CURLY_BRACKET, CHAR_RIGHT_SQUARE_BRACKET, CHAR_SEMICOLON, CHAR_SINGLE_QUOTE, CHAR_SPACE, CHAR_TAB, CHAR_UNDERSCORE, CHAR_UPPERCASE_A, CHAR_UPPERCASE_Z, CHAR_VERTICAL_LINE, CHAR_ZERO_WIDTH_NOBREAK_SPACE,} from "../path/_constants.ts";import * as path from "./path.ts";import { toASCII } from "./internal/idna.ts";import { isWindows, osType } from "../_util/os.ts";import { encodeStr, hexTable } from "./internal/querystring.ts";import querystring from "./querystring.ts";import type { ParsedUrlQuery } from "./querystring.ts";
const forwardSlashRegEx = /\//g;const percentRegEx = /%/g;const backslashRegEx = /\\/g;const newlineRegEx = /\n/g;const carriageReturnRegEx = /\r/g;const tabRegEx = /\t/g;
const protocolPattern = /^[a-z0-9.+-]+:/i;const portPattern = /:[0-9]*$/;const hostPattern = /^\/\/[^@/]+@[^@/]+/;const simplePathPattern = /^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/;const unsafeProtocol = new Set(["javascript", "javascript:"]);const hostlessProtocol = new Set(["javascript", "javascript:"]);const slashedProtocol = new Set([ "http", "http:", "https", "https:", "ftp", "ftp:", "gopher", "gopher:", "file", "file:", "ws", "ws:", "wss", "wss:",]);
const hostnameMaxLen = 255;
const noEscapeAuth = new Int8Array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, ]);
const _url = URL;export { _url as URL };
export class Url { public protocol: string | null; public slashes: boolean | null; public auth: string | null; public host: string | null; public port: string | null; public hostname: string | null; public hash: string | null; public search: string | null; public query: string | ParsedUrlQuery | null; public pathname: string | null; public path: string | null; public href: string | null; [key: string]: unknown;
constructor() { this.protocol = null; this.slashes = null; this.auth = null; this.host = null; this.port = null; this.hostname = null; this.hash = null; this.search = null; this.query = null; this.pathname = null; this.path = null; this.href = null; }
#parseHost() { let host = this.host || ""; let port: RegExpExecArray | null | string = portPattern.exec(host); if (port) { port = port[0]; if (port !== ":") { this.port = port.slice(1); } host = host.slice(0, host.length - port.length); } if (host) this.hostname = host; }
public resolve(relative: string) { return this.resolveObject(parse(relative, false, true)).format(); }
public resolveObject(relative: string | Url) { if (typeof relative === "string") { const rel = new Url(); rel.urlParse(relative, false, true); relative = rel; }
const result = new Url(); const tkeys = Object.keys(this); for (let tk = 0; tk < tkeys.length; tk++) { const tkey = tkeys[tk]; result[tkey] = this[tkey]; }
result.hash = relative.hash;
if (relative.href === "") { result.href = result.format(); return result; }
if (relative.slashes && !relative.protocol) { const rkeys = Object.keys(relative); for (let rk = 0; rk < rkeys.length; rk++) { const rkey = rkeys[rk]; if (rkey !== "protocol") result[rkey] = relative[rkey]; }
if ( result.protocol && slashedProtocol.has(result.protocol) && result.hostname && !result.pathname ) { result.path = result.pathname = "/"; }
result.href = result.format(); return result; }
if (relative.protocol && relative.protocol !== result.protocol) { if (!slashedProtocol.has(relative.protocol)) { const keys = Object.keys(relative); for (let v = 0; v < keys.length; v++) { const k = keys[v]; result[k] = relative[k]; } result.href = result.format(); return result; }
result.protocol = relative.protocol; if ( !relative.host && !/^file:?$/.test(relative.protocol) && !hostlessProtocol.has(relative.protocol) ) { const relPath = (relative.pathname || "").split("/"); while (relPath.length && !(relative.host = relPath.shift() || null)); if (!relative.host) relative.host = ""; if (!relative.hostname) relative.hostname = ""; if (relPath[0] !== "") relPath.unshift(""); if (relPath.length < 2) relPath.unshift(""); result.pathname = relPath.join("/"); } else { result.pathname = relative.pathname; } result.search = relative.search; result.query = relative.query; result.host = relative.host || ""; result.auth = relative.auth; result.hostname = relative.hostname || relative.host; result.port = relative.port; if (result.pathname || result.search) { const p = result.pathname || ""; const s = result.search || ""; result.path = p + s; } result.slashes = result.slashes || relative.slashes; result.href = result.format(); return result; }
const isSourceAbs = result.pathname && result.pathname.charAt(0) === "/"; const isRelAbs = relative.host || (relative.pathname && relative.pathname.charAt(0) === "/"); let mustEndAbs: string | boolean | number | null = isRelAbs || isSourceAbs || (result.host && relative.pathname); const removeAllDots = mustEndAbs; let srcPath = (result.pathname && result.pathname.split("/")) || []; const relPath = (relative.pathname && relative.pathname.split("/")) || []; const noLeadingSlashes = result.protocol && !slashedProtocol.has(result.protocol);
if (noLeadingSlashes) { result.hostname = ""; result.port = null; if (result.host) { if (srcPath[0] === "") srcPath[0] = result.host; else srcPath.unshift(result.host); } result.host = ""; if (relative.protocol) { relative.hostname = null; relative.port = null; result.auth = null; if (relative.host) { if (relPath[0] === "") relPath[0] = relative.host; else relPath.unshift(relative.host); } relative.host = null; } mustEndAbs = mustEndAbs && (relPath[0] === "" || srcPath[0] === ""); }
if (isRelAbs) { if (relative.host || relative.host === "") { if (result.host !== relative.host) result.auth = null; result.host = relative.host; result.port = relative.port; } if (relative.hostname || relative.hostname === "") { if (result.hostname !== relative.hostname) result.auth = null; result.hostname = relative.hostname; } result.search = relative.search; result.query = relative.query; srcPath = relPath; } else if (relPath.length) { if (!srcPath) srcPath = []; srcPath.pop(); srcPath = srcPath.concat(relPath); result.search = relative.search; result.query = relative.query; } else if (relative.search !== null && relative.search !== undefined) { if (noLeadingSlashes) { result.hostname = result.host = srcPath.shift() || null; const authInHost = result.host && result.host.indexOf("@") > 0 && result.host.split("@"); if (authInHost) { result.auth = authInHost.shift() || null; result.host = result.hostname = authInHost.shift() || null; } } result.search = relative.search; result.query = relative.query; if (result.pathname !== null || result.search !== null) { result.path = (result.pathname ? result.pathname : "") + (result.search ? result.search : ""); } result.href = result.format(); return result; }
if (!srcPath.length) { result.pathname = null; if (result.search) { result.path = "/" + result.search; } else { result.path = null; } result.href = result.format(); return result; }
let last = srcPath.slice(-1)[0]; const hasTrailingSlash = ((result.host || relative.host || srcPath.length > 1) && (last === "." || last === "..")) || last === "";
let up = 0; for (let i = srcPath.length - 1; i >= 0; i--) { last = srcPath[i]; if (last === ".") { srcPath.splice(i, 1); } else if (last === "..") { srcPath.splice(i, 1); up++; } else if (up) { srcPath.splice(i, 1); up--; } }
if (!mustEndAbs && !removeAllDots) { while (up--) { srcPath.unshift(".."); } }
if ( mustEndAbs && srcPath[0] !== "" && (!srcPath[0] || srcPath[0].charAt(0) !== "/") ) { srcPath.unshift(""); }
if (hasTrailingSlash && srcPath.join("/").substr(-1) !== "/") { srcPath.push(""); }
const isAbsolute = srcPath[0] === "" || (srcPath[0] && srcPath[0].charAt(0) === "/");
if (noLeadingSlashes) { result.hostname = result.host = isAbsolute ? "" : srcPath.length ? srcPath.shift() || null : ""; const authInHost = result.host && result.host.indexOf("@") > 0 ? result.host.split("@") : false; if (authInHost) { result.auth = authInHost.shift() || null; result.host = result.hostname = authInHost.shift() || null; } }
mustEndAbs = mustEndAbs || (result.host && srcPath.length);
if (mustEndAbs && !isAbsolute) { srcPath.unshift(""); }
if (!srcPath.length) { result.pathname = null; result.path = null; } else { result.pathname = srcPath.join("/"); }
if (result.pathname !== null || result.search !== null) { result.path = (result.pathname ? result.pathname : "") + (result.search ? result.search : ""); } result.auth = relative.auth || result.auth; result.slashes = result.slashes || relative.slashes; result.href = result.format(); return result; }
format() { let auth = this.auth || ""; if (auth) { auth = encodeStr(auth, noEscapeAuth, hexTable); auth += "@"; }
let protocol = this.protocol || ""; let pathname = this.pathname || ""; let hash = this.hash || ""; let host = ""; let query = "";
if (this.host) { host = auth + this.host; } else if (this.hostname) { host = auth + (this.hostname.includes(":") && !isIpv6Hostname(this.hostname) ? "[" + this.hostname + "]" : this.hostname); if (this.port) { host += ":" + this.port; } }
if (this.query !== null && typeof this.query === "object") { query = querystring.stringify(this.query); }
let search = this.search || (query && "?" + query) || "";
if (protocol && protocol.charCodeAt(protocol.length - 1) !== 58 ) { protocol += ":"; }
let newPathname = ""; let lastPos = 0; for (let i = 0; i < pathname.length; ++i) { switch (pathname.charCodeAt(i)) { case CHAR_HASH: if (i - lastPos > 0) { newPathname += pathname.slice(lastPos, i); } newPathname += "%23"; lastPos = i + 1; break; case CHAR_QUESTION_MARK: if (i - lastPos > 0) { newPathname += pathname.slice(lastPos, i); } newPathname += "%3F"; lastPos = i + 1; break; } } if (lastPos > 0) { if (lastPos !== pathname.length) { pathname = newPathname + pathname.slice(lastPos); } else pathname = newPathname; }
if (this.slashes || slashedProtocol.has(protocol)) { if (this.slashes || host) { if (pathname && pathname.charCodeAt(0) !== CHAR_FORWARD_SLASH) { pathname = "/" + pathname; } host = "//" + host; } else if ( protocol.length >= 4 && protocol.charCodeAt(0) === 102 && protocol.charCodeAt(1) === 105 && protocol.charCodeAt(2) === 108 && protocol.charCodeAt(3) === 101 ) { host = "//"; } }
search = search.replace(/#/g, "%23");
if (hash && hash.charCodeAt(0) !== CHAR_HASH) { hash = "#" + hash; } if (search && search.charCodeAt(0) !== CHAR_QUESTION_MARK) { search = "?" + search; }
return protocol + host + pathname + search + hash; }
public urlParse( url: string, parseQueryString: boolean, slashesDenoteHost: boolean, ) { let hasHash = false; let start = -1; let end = -1; let rest = ""; let lastPos = 0; for (let i = 0, inWs = false, split = false; i < url.length; ++i) { const code = url.charCodeAt(i);
const isWs = code === CHAR_SPACE || code === CHAR_TAB || code === CHAR_CARRIAGE_RETURN || code === CHAR_LINE_FEED || code === CHAR_FORM_FEED || code === CHAR_NO_BREAK_SPACE || code === CHAR_ZERO_WIDTH_NOBREAK_SPACE; if (start === -1) { if (isWs) continue; lastPos = start = i; } else if (inWs) { if (!isWs) { end = -1; inWs = false; } } else if (isWs) { end = i; inWs = true; }
if (!split) { switch (code) { case CHAR_HASH: hasHash = true; case CHAR_QUESTION_MARK: split = true; break; case CHAR_BACKWARD_SLASH: if (i - lastPos > 0) rest += url.slice(lastPos, i); rest += "/"; lastPos = i + 1; break; } } else if (!hasHash && code === CHAR_HASH) { hasHash = true; } }
if (start !== -1) { if (lastPos === start) {
if (end === -1) { if (start === 0) rest = url; else rest = url.slice(start); } else { rest = url.slice(start, end); } } else if (end === -1 && lastPos < url.length) { rest += url.slice(lastPos); } else if (end !== -1 && lastPos < end) { rest += url.slice(lastPos, end); } }
if (!slashesDenoteHost && !hasHash) { const simplePath = simplePathPattern.exec(rest); if (simplePath) { this.path = rest; this.href = rest; this.pathname = simplePath[1]; if (simplePath[2]) { this.search = simplePath[2]; if (parseQueryString) { this.query = querystring.parse(this.search.slice(1)); } else { this.query = this.search.slice(1); } } else if (parseQueryString) { this.search = null; this.query = Object.create(null); } return this; } }
let proto: RegExpExecArray | null | string = protocolPattern.exec(rest); let lowerProto = ""; if (proto) { proto = proto[0]; lowerProto = proto.toLowerCase(); this.protocol = lowerProto; rest = rest.slice(proto.length); }
let slashes; if (slashesDenoteHost || proto || hostPattern.test(rest)) { slashes = rest.charCodeAt(0) === CHAR_FORWARD_SLASH && rest.charCodeAt(1) === CHAR_FORWARD_SLASH; if (slashes && !(proto && hostlessProtocol.has(lowerProto))) { rest = rest.slice(2); this.slashes = true; } }
if ( !hostlessProtocol.has(lowerProto) && (slashes || (proto && !slashedProtocol.has(proto))) ) {
let hostEnd = -1; let atSign = -1; let nonHost = -1; for (let i = 0; i < rest.length; ++i) { switch (rest.charCodeAt(i)) { case CHAR_TAB: case CHAR_LINE_FEED: case CHAR_CARRIAGE_RETURN: case CHAR_SPACE: case CHAR_DOUBLE_QUOTE: case CHAR_PERCENT: case CHAR_SINGLE_QUOTE: case CHAR_SEMICOLON: case CHAR_LEFT_ANGLE_BRACKET: case CHAR_RIGHT_ANGLE_BRACKET: case CHAR_BACKWARD_SLASH: case CHAR_CIRCUMFLEX_ACCENT: case CHAR_GRAVE_ACCENT: case CHAR_LEFT_CURLY_BRACKET: case CHAR_VERTICAL_LINE: case CHAR_RIGHT_CURLY_BRACKET: if (nonHost === -1) nonHost = i; break; case CHAR_HASH: case CHAR_FORWARD_SLASH: case CHAR_QUESTION_MARK: if (nonHost === -1) nonHost = i; hostEnd = i; break; case CHAR_AT: atSign = i; nonHost = -1; break; } if (hostEnd !== -1) break; } start = 0; if (atSign !== -1) { this.auth = decodeURIComponent(rest.slice(0, atSign)); start = atSign + 1; } if (nonHost === -1) { this.host = rest.slice(start); rest = ""; } else { this.host = rest.slice(start, nonHost); rest = rest.slice(nonHost); }
this.#parseHost();
if (typeof this.hostname !== "string") this.hostname = "";
const hostname = this.hostname;
const ipv6Hostname = isIpv6Hostname(hostname);
if (!ipv6Hostname) { rest = getHostname(this, rest, hostname); }
if (this.hostname.length > hostnameMaxLen) { this.hostname = ""; } else { this.hostname = this.hostname.toLowerCase(); }
if (!ipv6Hostname) {
this.hostname = toASCII(this.hostname); }
const p = this.port ? ":" + this.port : ""; const h = this.hostname || ""; this.host = h + p;
if (ipv6Hostname) { this.hostname = this.hostname.slice(1, -1); if (rest[0] !== "/") { rest = "/" + rest; } } }
if (!unsafeProtocol.has(lowerProto)) { rest = autoEscapeStr(rest); }
let questionIdx = -1; let hashIdx = -1; for (let i = 0; i < rest.length; ++i) { const code = rest.charCodeAt(i); if (code === CHAR_HASH) { this.hash = rest.slice(i); hashIdx = i; break; } else if (code === CHAR_QUESTION_MARK && questionIdx === -1) { questionIdx = i; } }
if (questionIdx !== -1) { if (hashIdx === -1) { this.search = rest.slice(questionIdx); this.query = rest.slice(questionIdx + 1); } else { this.search = rest.slice(questionIdx, hashIdx); this.query = rest.slice(questionIdx + 1, hashIdx); } if (parseQueryString) { this.query = querystring.parse(this.query); } } else if (parseQueryString) { this.search = null; this.query = Object.create(null); }
const useQuestionIdx = questionIdx !== -1 && (hashIdx === -1 || questionIdx < hashIdx); const firstIdx = useQuestionIdx ? questionIdx : hashIdx; if (firstIdx === -1) { if (rest.length > 0) this.pathname = rest; } else if (firstIdx > 0) { this.pathname = rest.slice(0, firstIdx); } if (slashedProtocol.has(lowerProto) && this.hostname && !this.pathname) { this.pathname = "/"; }
if (this.pathname || this.search) { const p = this.pathname || ""; const s = this.search || ""; this.path = p + s; }
this.href = this.format(); return this; }}
export function format( urlObject: string | URL | Url, options?: { auth: boolean; fragment: boolean; search: boolean; unicode: boolean; },): string { if (urlObject instanceof URL) { return formatWhatwg(urlObject, options); }
urlObject = parse(urlObject, true, false); return urlObject.format();}
function formatWhatwg( urlObject: string | URL, options?: { auth: boolean; fragment: boolean; search: boolean; unicode: boolean; },): string { if (typeof urlObject === "string") { urlObject = new URL(urlObject); } if (options) { if (typeof options !== "object") { throw new ERR_INVALID_ARG_TYPE("options", "object", options); } }
options = { auth: true, fragment: true, search: true, unicode: false, ...options, };
let ret = urlObject.protocol; if (urlObject.host !== null) { ret += "//"; const hasUsername = !!urlObject.username; const hasPassword = !!urlObject.password; if (options.auth && (hasUsername || hasPassword)) { if (hasUsername) { ret += urlObject.username; } if (hasPassword) { ret += `:${urlObject.password}`; } ret += "@"; } ret += urlObject.host; if (urlObject.port) { ret += `:${urlObject.port}`; } }
ret += urlObject.pathname;
if (options.search && urlObject.search) { ret += urlObject.search; } if (options.fragment && urlObject.hash) { ret += urlObject.hash; }
return ret;}
function isIpv6Hostname(hostname: string) { return ( hostname.charCodeAt(0) === CHAR_LEFT_SQUARE_BRACKET && hostname.charCodeAt(hostname.length - 1) === CHAR_RIGHT_SQUARE_BRACKET );}
function getHostname(self: Url, rest: string, hostname: string) { for (let i = 0; i < hostname.length; ++i) { const code = hostname.charCodeAt(i); const isValid = (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z) || code === CHAR_DOT || (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || (code >= CHAR_0 && code <= CHAR_9) || code === CHAR_HYPHEN_MINUS || code === CHAR_PLUS || code === CHAR_UNDERSCORE || code > 127;
if (!isValid) { self.hostname = hostname.slice(0, i); return `/${hostname.slice(i)}${rest}`; } } return rest;}
const escapedCodes = [ "", "", "", "", "", "", "", "", "", "%09", "%0A", "", "", "%0D", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "%20", "", "%22", "", "", "", "", "%27", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "%3C", "", "%3E", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "%5C", "", "%5E", "", "%60", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "%7B", "%7C", "%7D"];
function autoEscapeStr(rest: string) { let escaped = ""; let lastEscapedPos = 0; for (let i = 0; i < rest.length; ++i) { const escapedChar = escapedCodes[rest.charCodeAt(i)]; if (escapedChar) { if (i > lastEscapedPos) { escaped += rest.slice(lastEscapedPos, i); } escaped += escapedChar; lastEscapedPos = i + 1; } } if (lastEscapedPos === 0) { return rest; }
if (lastEscapedPos < rest.length) { escaped += rest.slice(lastEscapedPos); }
return escaped;}
export function parse( url: string | Url, parseQueryString: boolean, slashesDenoteHost: boolean,) { if (url instanceof Url) return url;
const urlObject = new Url(); urlObject.urlParse(url, parseQueryString, slashesDenoteHost); return urlObject;}
export function resolve(from: string, to: string) { return parse(from, false, true).resolve(to);}
export function resolveObject(source: string | Url, relative: string) { if (!source) return relative; return parse(source, false, true).resolveObject(relative);}
export function fileURLToPath(path: string | URL): string { if (typeof path === "string") path = new URL(path); else if (!(path instanceof URL)) { throw new ERR_INVALID_ARG_TYPE("path", ["string", "URL"], path); } if (path.protocol !== "file:") { throw new ERR_INVALID_URL_SCHEME("file"); } 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) || (pathname[n + 1] === "5" && third === 99) ) { throw new ERR_INVALID_FILE_URL_PATH( "must not include encoded \\ or / characters", ); } } }
pathname = pathname.replace(forwardSlashRegEx, "\\"); pathname = decodeURIComponent(pathname); if (hostname !== "") { return `\\\\${hostname}${pathname}`; } else { const letter = pathname.codePointAt(1)! | 0x20; const sep = pathname[2]; if ( letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z || sep !== ":" ) { throw new ERR_INVALID_FILE_URL_PATH("must be absolute"); } return pathname.slice(1); }}
function getPathFromURLPosix(url: URL): string { if (url.hostname !== "") { throw new ERR_INVALID_FILE_URL_HOST(osType); } 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 ERR_INVALID_FILE_URL_PATH( "must not include encoded / characters", ); } } } return decodeURIComponent(pathname);}
function encodePathChars(filepath: string): string { if (filepath.includes("%")) { filepath = filepath.replace(percentRegEx, "%25"); } if (!isWindows && filepath.includes("\\")) { filepath = filepath.replace(backslashRegEx, "%5C"); } if (filepath.includes("\n")) { filepath = filepath.replace(newlineRegEx, "%0A"); } if (filepath.includes("\r")) { filepath = filepath.replace(carriageReturnRegEx, "%0D"); } if (filepath.includes("\t")) { filepath = filepath.replace(tabRegEx, "%09"); } return filepath;}
export function pathToFileURL(filepath: string): URL { const outURL = new URL("file://"); if (isWindows && filepath.startsWith("\\\\")) { const paths = filepath.split("\\"); if (paths.length <= 3) { throw new ERR_INVALID_ARG_VALUE( "filepath", filepath, "Missing UNC resource path", ); } const hostname = paths[2]; if (hostname.length === 0) { throw new ERR_INVALID_ARG_VALUE( "filepath", filepath, "Empty UNC servername", ); }
outURL.hostname = hostname; outURL.pathname = encodePathChars(paths.slice(3).join("/")); } else { let resolved = path.resolve(filepath); const filePathLast = filepath.charCodeAt(filepath.length - 1); if ( (filePathLast === CHAR_FORWARD_SLASH || (isWindows && filePathLast === CHAR_BACKWARD_SLASH)) && resolved[resolved.length - 1] !== path.sep ) { resolved += "/"; }
outURL.pathname = encodePathChars(resolved); } return outURL;}
interface HttpOptions { protocol: string; hostname: string; hash: string; search: string; pathname: string; path: string; href: string; port?: number; auth?: string;}
export function urlToHttpOptions(url: URL): HttpOptions { const options: HttpOptions = { protocol: url.protocol, hostname: typeof url.hostname === "string" && url.hostname.startsWith("[") ? url.hostname.slice(1, -1) : url.hostname, hash: url.hash, search: url.search, pathname: url.pathname, path: `${url.pathname || ""}${url.search || ""}`, href: url.href, }; if (url.port !== "") { options.port = Number(url.port); } if (url.username || url.password) { options.auth = `${decodeURIComponent(url.username)}:${ decodeURIComponent( url.password, ) }`; } return options;}
const URLSearchParams_ = URLSearchParams;export { URLSearchParams_ as URLSearchParams };
export default { parse, format, resolve, resolveObject, fileURLToPath, pathToFileURL, urlToHttpOptions, Url, URL, URLSearchParams,};