const PLUS_RE = /\+/g; function decode(text = "") { try { return decodeURIComponent("" + text); } catch { return "" + text; } } function decodeQueryValue(text) { return decode(text.replace(PLUS_RE, " ")); } function parseQuery(parametersString = "") { const object = {}; if (parametersString[0] === "?") { parametersString = parametersString.slice(1); } for (const parameter of parametersString.split("&")) { const s = parameter.match(/([^=]+)=?(.*)/) || []; if (s.length < 2) { continue; } const key = decode(s[1]); if (key === "__proto__" || key === "constructor") { continue; } const value = decodeQueryValue(s[2] || ""); if (object[key]) { if (Array.isArray(object[key])) { object[key].push(value); } else { object[key] = [object[key], value]; } } else { object[key] = value; } } return object; } const PROTOCOL_REGEX = /^\w+:(\/\/)?/; const PROTOCOL_RELATIVE_REGEX = /^\/\/[^/]+/; function hasProtocol(inputString, acceptProtocolRelative = false) { return PROTOCOL_REGEX.test(inputString) || acceptProtocolRelative && PROTOCOL_RELATIVE_REGEX.test(inputString); } const TRAILING_SLASH_RE = /\/$|\/\?/; function hasTrailingSlash(input = "", queryParameters = false) { if (!queryParameters) { return input.endsWith("/"); } return TRAILING_SLASH_RE.test(input); } function withoutTrailingSlash(input = "", queryParameters = false) { if (!queryParameters) { return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || "/"; } if (!hasTrailingSlash(input, true)) { return input || "/"; } const [s0, ...s] = input.split("?"); return (s0.slice(0, -1) || "/") + (s.length > 0 ? `?${s.join("?")}` : ""); } function withTrailingSlash(input = "", queryParameters = false) { if (!queryParameters) { return input.endsWith("/") ? input : input + "/"; } if (hasTrailingSlash(input, true)) { return input || "/"; } const [s0, ...s] = input.split("?"); return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : ""); } function hasLeadingSlash(input = "") { return input.startsWith("/"); } function withoutLeadingSlash(input = "") { return (hasLeadingSlash(input) ? input.slice(1) : input) || "/"; } function withoutBase(input, base) { if (isEmptyURL(base)) { return input; } const _base = withoutTrailingSlash(base); if (!input.startsWith(_base)) { return input; } const trimmed = input.slice(_base.length); return trimmed[0] === "/" ? trimmed : "/" + trimmed; } function getQuery(input) { return parseQuery(parseURL(input).search); } function isEmptyURL(url) { return !url || url === "/"; } function isNonEmptyURL(url) { return url && url !== "/"; } function joinURL(base, ...input) { let url = base || ""; for (const index of input.filter((url2) => isNonEmptyURL(url2))) { url = url ? withTrailingSlash(url) + withoutLeadingSlash(index) : index; } return url; } function parseURL(input = "", defaultProto) { if (!hasProtocol(input, true)) { return defaultProto ? parseURL(defaultProto + input) : parsePath(input); } const [protocol = "", auth, hostAndPath = ""] = (input.replace(/\\/g, "/").match(/([^/:]+:)?\/\/([^/@]+@)?(.*)/) || []).splice(1); const [host = "", path = ""] = (hostAndPath.match(/([^#/?]*)(.*)?/) || []).splice(1); const { pathname, search, hash } = parsePath(path.replace(/\/(?=[A-Za-z]:)/, "")); return { protocol, auth: auth ? auth.slice(0, Math.max(0, auth.length - 1)) : "", host, pathname, search, hash }; } function parsePath(input = "") { const [pathname = "", search = "", hash = ""] = (input.match(/([^#?]*)(\?[^#]*)?(#.*)?/) || []).splice(1); return { pathname, search, hash }; } export { withoutTrailingSlash as a, withoutBase as b, getQuery as g, joinURL as j, withTrailingSlash as w };