Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
884 lines
21 KiB
Text
884 lines
21 KiB
Text
import * as querystring from "node:querystring";
|
|
import * as punnycode from "./punycode.mjs";
|
|
import { encodeStr, hexTable } from "./internal/querystring/querystring.mjs";
|
|
import { spliceOne } from "./internal/url/util.mjs";
|
|
import { ERR_INVALID_ARG_TYPE, ERR_INVALID_URL } from "./internal/url/errors.mjs";
|
|
import { pathToFileURL as _pathToFileURL, fileURLToPath, unsafeProtocol, hostlessProtocol, slashedProtocol, urlToHttpOptions } from "./internal/url/url.mjs";
|
|
import { CHAR_SPACE, CHAR_TAB, CHAR_CARRIAGE_RETURN, CHAR_LINE_FEED, CHAR_NO_BREAK_SPACE, CHAR_ZERO_WIDTH_NOBREAK_SPACE, CHAR_HASH, CHAR_FORWARD_SLASH, CHAR_LEFT_SQUARE_BRACKET, CHAR_RIGHT_SQUARE_BRACKET, CHAR_LEFT_ANGLE_BRACKET, CHAR_RIGHT_ANGLE_BRACKET, CHAR_LEFT_CURLY_BRACKET, CHAR_RIGHT_CURLY_BRACKET, CHAR_QUESTION_MARK, CHAR_DOUBLE_QUOTE, CHAR_SINGLE_QUOTE, CHAR_PERCENT, CHAR_SEMICOLON, CHAR_BACKWARD_SLASH, CHAR_CIRCUMFLEX_ACCENT, CHAR_GRAVE_ACCENT, CHAR_VERTICAL_LINE, CHAR_AT, CHAR_COLON } from "./internal/url/constants.mjs";
|
|
class Url {
|
|
auth = null;
|
|
hash = null;
|
|
host = null;
|
|
hostname = null;
|
|
href = null;
|
|
path = null;
|
|
pathname = null;
|
|
protocol = null;
|
|
search = null;
|
|
slashes = null;
|
|
port = null;
|
|
query = null;
|
|
parse(url, parseQueryString, slashesDenoteHost) {
|
|
if (typeof url !== "string") {
|
|
throw new ERR_INVALID_ARG_TYPE("url", "string", url);
|
|
}
|
|
let hasHash = false;
|
|
let hasAt = 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 < 33 || 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_AT:
|
|
hasAt = true;
|
|
break;
|
|
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 && !hasAt) {
|
|
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 = { __proto__: null };
|
|
}
|
|
return this;
|
|
}
|
|
}
|
|
const protoMatch = protocolPattern.exec(rest);
|
|
let proto, lowerProto;
|
|
if (protoMatch) {
|
|
proto = protoMatch[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:
|
|
rest = rest.slice(0, i) + rest.slice(i + 1);
|
|
i -= 1;
|
|
break;
|
|
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, url);
|
|
}
|
|
if (this.hostname.length > hostnameMaxLen) {
|
|
this.hostname = "";
|
|
} else {
|
|
this.hostname = this.hostname.toLowerCase();
|
|
}
|
|
if (this.hostname !== "") {
|
|
if (ipv6Hostname) {
|
|
if (forbiddenHostCharsIpv6.test(this.hostname)) {
|
|
throw new ERR_INVALID_URL(url);
|
|
}
|
|
} else {
|
|
this.hostname = punnycode.toASCII(this.hostname);
|
|
if (this.hostname === "" || forbiddenHostChars.test(this.hostname)) {
|
|
throw new ERR_INVALID_URL(url);
|
|
}
|
|
}
|
|
}
|
|
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 = { __proto__: 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;
|
|
}
|
|
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;
|
|
} else {
|
|
pathname = newPathname + pathname.slice(lastPos);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
resolve(relative) {
|
|
return this.resolveObject(urlParse(relative, false, true)).format();
|
|
}
|
|
resolveObject(relative) {
|
|
if (typeof relative === "string") {
|
|
const rel = new Url();
|
|
rel.parse(relative, false, true);
|
|
relative = rel;
|
|
}
|
|
const result = new Url();
|
|
Object.assign(result, this);
|
|
result.hash = relative.hash;
|
|
if (relative.href === "") {
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
if (relative.slashes && !relative.protocol) {
|
|
const relativeWithoutProtocol = Object.keys(relative).reduce((acc, key) => {
|
|
if (key !== "protocol") {
|
|
acc[key] = relative[key];
|
|
}
|
|
return acc;
|
|
}, {});
|
|
Object.assign(result, relativeWithoutProtocol);
|
|
if (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)) {
|
|
Object.assign(result, relative);
|
|
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 > 0 && !(relative.host = relPath.shift()));
|
|
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 = 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 > 0) {
|
|
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();
|
|
const authInHost = result.host && result.host.indexOf("@") > 0 && result.host.split("@");
|
|
if (authInHost) {
|
|
result.auth = authInHost.shift();
|
|
result.host = result.hostname = authInHost.shift();
|
|
}
|
|
}
|
|
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 === 0) {
|
|
result.pathname = null;
|
|
if (result.search) {
|
|
result.path = "/" + result.search;
|
|
} else {
|
|
result.path = null;
|
|
}
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
let last = srcPath.at(-1);
|
|
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 === ".") {
|
|
spliceOne(srcPath, i);
|
|
} else if (last === "..") {
|
|
spliceOne(srcPath, i);
|
|
up++;
|
|
} else if (up) {
|
|
spliceOne(srcPath, i);
|
|
up--;
|
|
}
|
|
}
|
|
if (!mustEndAbs && !removeAllDots) {
|
|
while (up--) {
|
|
srcPath.unshift("..");
|
|
}
|
|
}
|
|
if (mustEndAbs && srcPath[0] !== "" && (!srcPath[0] || srcPath[0].charAt(0) !== "/")) {
|
|
srcPath.unshift("");
|
|
}
|
|
if (hasTrailingSlash && srcPath.join("/").slice(-1) !== "/") {
|
|
srcPath.push("");
|
|
}
|
|
const isAbsolute = srcPath[0] === "" || srcPath[0] && srcPath[0].charAt(0) === "/";
|
|
if (noLeadingSlashes) {
|
|
result.hostname = result.host = isAbsolute ? "" : srcPath.length > 0 ? srcPath.shift() : "";
|
|
const authInHost = result.host && result.host.indexOf("@") > 0 ? result.host.split("@") : false;
|
|
if (authInHost) {
|
|
result.auth = authInHost.shift();
|
|
result.host = result.hostname = authInHost.shift();
|
|
}
|
|
}
|
|
mustEndAbs = mustEndAbs || result.host && srcPath.length;
|
|
if (mustEndAbs && !isAbsolute) {
|
|
srcPath.unshift("");
|
|
}
|
|
if (srcPath.length === 0) {
|
|
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;
|
|
}
|
|
parseHost() {
|
|
let host = this.host;
|
|
const portMatch = portPattern.exec(host);
|
|
if (portMatch) {
|
|
const port = portMatch[0];
|
|
if (port !== ":") {
|
|
this.port = port.slice(1);
|
|
}
|
|
host = host.slice(0, host.length - port.length);
|
|
}
|
|
if (host) this.hostname = host;
|
|
}
|
|
}
|
|
const protocolPattern = /^[\d+.a-z-]+:/i;
|
|
const portPattern = /:\d*$/;
|
|
const hostPattern = /^\/\/[^/@]+@[^/@]+/;
|
|
const simplePathPattern = /^(\/\/?(?!\/)[^\s?]*)(\?\S*)?$/;
|
|
const forbiddenHostChars = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
|
|
const forbiddenHostCharsIpv6 = /[\0\t\n\r #%/<>?@\\^|]/;
|
|
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 escapedCodes = [
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%09",
|
|
"%0A",
|
|
"",
|
|
"",
|
|
"%0D",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%20",
|
|
"",
|
|
"%22",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%27",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%3C",
|
|
"",
|
|
"%3E",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%5C",
|
|
"",
|
|
"%5E",
|
|
"",
|
|
"%60",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"%7B",
|
|
"%7C",
|
|
"%7D"
|
|
];
|
|
const hostnameMaxLen = 255;
|
|
let urlParseWarned = false;
|
|
function urlParse(url, parseQueryString, slashesDenoteHost) {
|
|
if (!urlParseWarned) {
|
|
urlParseWarned = true;
|
|
console.warn("[DeprecationWarning] [unenv] [node:url] DEP0169: `url.parse()` behavior is not standardized and prone to " + "errors that have security implications. Use the WHATWG URL API " + "instead. CVEs are not issued for `url.parse()` vulnerabilities.");
|
|
}
|
|
if (url instanceof Url) return url;
|
|
const urlObject = new Url();
|
|
urlObject.parse(url, parseQueryString, slashesDenoteHost);
|
|
return urlObject;
|
|
}
|
|
function isIpv6Hostname(hostname) {
|
|
return String.prototype.charCodeAt.call(hostname, 0) === CHAR_LEFT_SQUARE_BRACKET && String.prototype.charCodeAt.call(hostname, hostname.length - 1) === CHAR_RIGHT_SQUARE_BRACKET;
|
|
}
|
|
let warnInvalidPort = true;
|
|
function getHostname(self, rest, hostname, url) {
|
|
for (let i = 0; i < hostname.length; ++i) {
|
|
const code = hostname.charCodeAt(i);
|
|
const isValid = code !== CHAR_FORWARD_SLASH && code !== CHAR_BACKWARD_SLASH && code !== CHAR_HASH && code !== CHAR_QUESTION_MARK && code !== CHAR_COLON;
|
|
if (!isValid) {
|
|
if (warnInvalidPort && code === CHAR_COLON) {
|
|
console.warn(`[DeprecationWarning] [unenv] [node:url] DEP0170: The URL ${url} is invalid. Future versions of Node.js will throw an error.`);
|
|
warnInvalidPort = false;
|
|
}
|
|
self.hostname = hostname.slice(0, i);
|
|
return `/${hostname.slice(i)}${rest}`;
|
|
}
|
|
}
|
|
return rest;
|
|
}
|
|
function autoEscapeStr(rest) {
|
|
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;
|
|
}
|
|
function urlFormat(urlObject, options) {
|
|
if (typeof urlObject === "string") {
|
|
urlObject = urlParse(urlObject);
|
|
} else if (typeof urlObject !== "object" || urlObject === null) {
|
|
throw new ERR_INVALID_ARG_TYPE("urlObject", ["Object", "string"], urlObject);
|
|
} else if (urlObject instanceof URL) {
|
|
let fragment = true;
|
|
let unicode = false;
|
|
let search = true;
|
|
let auth = true;
|
|
if (options) {
|
|
if (options.fragment != null) {
|
|
fragment = Boolean(options.fragment);
|
|
}
|
|
if (options.unicode != null) {
|
|
unicode = Boolean(options.unicode);
|
|
}
|
|
if (options.search != null) {
|
|
search = Boolean(options.search);
|
|
}
|
|
if (options.auth != null) {
|
|
auth = Boolean(options.auth);
|
|
}
|
|
}
|
|
const _url = new URL(urlObject.href);
|
|
if (!fragment) _url.hash = "";
|
|
if (!search) _url.search = "";
|
|
if (!auth) _url.username = _url.password = "";
|
|
if (unicode) {
|
|
return Url.prototype.format.call(_url);
|
|
}
|
|
return _url.href;
|
|
}
|
|
return Url.prototype.format.call(urlObject);
|
|
}
|
|
function urlResolve(source, relative) {
|
|
return urlParse(source, false, true).resolve(relative);
|
|
}
|
|
function urlResolveObject(source, relative) {
|
|
if (!source) return relative;
|
|
return urlParse(source, false, true).resolveObject(relative);
|
|
}
|
|
function pathToFileURL(path, options) {
|
|
return _pathToFileURL(path, options);
|
|
}
|
|
const URL = globalThis.URL;
|
|
const URLSearchParams = globalThis.URLSearchParams;
|
|
const domainToASCII = punnycode.toASCII;
|
|
const domainToUnicode = punnycode.toUnicode;
|
|
export { Url, urlParse as parse, urlResolve as resolve, urlResolveObject as resolveObject, urlFormat as format, URL, URLSearchParams, domainToASCII, domainToUnicode, pathToFileURL, fileURLToPath, urlToHttpOptions };
|
|
export default {
|
|
Url,
|
|
parse: urlParse,
|
|
resolve: urlResolve,
|
|
resolveObject: urlResolveObject,
|
|
format: urlFormat,
|
|
URL,
|
|
URLSearchParams,
|
|
domainToASCII,
|
|
domainToUnicode,
|
|
pathToFileURL,
|
|
fileURLToPath,
|
|
urlToHttpOptions
|
|
};
|