216 lines
7.2 KiB
Plaintext
216 lines
7.2 KiB
Plaintext
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
//#region src/utils/url.ts
|
|
const splitPath = (path) => {
|
|
const paths = path.split("/");
|
|
if (paths[0] === "") paths.shift();
|
|
return paths;
|
|
};
|
|
const splitRoutingPath = (routePath) => {
|
|
const { groups, path } = extractGroupsFromPath(routePath);
|
|
const paths = splitPath(path);
|
|
return replaceGroupMarks(paths, groups);
|
|
};
|
|
const extractGroupsFromPath = (path) => {
|
|
const groups = [];
|
|
path = path.replace(/\{[^}]+\}/g, (match, index) => {
|
|
const mark = `@${index}`;
|
|
groups.push([mark, match]);
|
|
return mark;
|
|
});
|
|
return {
|
|
groups,
|
|
path
|
|
};
|
|
};
|
|
const replaceGroupMarks = (paths, groups) => {
|
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
const [mark] = groups[i];
|
|
for (let j = paths.length - 1; j >= 0; j--) if (paths[j].includes(mark)) {
|
|
paths[j] = paths[j].replace(mark, groups[i][1]);
|
|
break;
|
|
}
|
|
}
|
|
return paths;
|
|
};
|
|
const patternCache = {};
|
|
const getPattern = (label, next) => {
|
|
if (label === "*") return "*";
|
|
const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
if (match) {
|
|
const cacheKey = `${label}#${next}`;
|
|
if (!patternCache[cacheKey]) {
|
|
if (match[2]) patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [
|
|
cacheKey,
|
|
match[1],
|
|
new RegExp(`^${match[2]}(?=/${next})`)
|
|
] : [
|
|
label,
|
|
match[1],
|
|
new RegExp(`^${match[2]}$`)
|
|
];
|
|
else patternCache[cacheKey] = [
|
|
label,
|
|
match[1],
|
|
true
|
|
];
|
|
}
|
|
return patternCache[cacheKey];
|
|
}
|
|
return null;
|
|
};
|
|
const tryDecode = (str, decoder) => {
|
|
try {
|
|
return decoder(str);
|
|
} catch {
|
|
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
|
|
try {
|
|
return decoder(match);
|
|
} catch {
|
|
return match;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
/**
|
|
* Try to apply decodeURI() to given string.
|
|
* If it fails, skip invalid percent encoding or invalid UTF-8 sequences, and apply decodeURI() to the rest as much as possible.
|
|
* @param str The string to decode.
|
|
* @returns The decoded string that sometimes contains undecodable percent encoding.
|
|
* @example
|
|
* tryDecodeURI('Hello%20World') // 'Hello World'
|
|
* tryDecodeURI('Hello%20World/%A4%A2') // 'Hello World/%A4%A2'
|
|
*/
|
|
const tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
|
const getPath = (request) => {
|
|
const url = request.url;
|
|
const start = url.indexOf("/", url.indexOf(":") + 4);
|
|
let i = start;
|
|
for (; i < url.length; i++) {
|
|
const charCode = url.charCodeAt(i);
|
|
if (charCode === 37) {
|
|
const queryIndex = url.indexOf("?", i);
|
|
const hashIndex = url.indexOf("#", i);
|
|
const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
|
|
const path = url.slice(start, end);
|
|
return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
|
|
} else if (charCode === 63 || charCode === 35) break;
|
|
}
|
|
return url.slice(start, i);
|
|
};
|
|
/**
|
|
* @deprecated
|
|
* Use the `URL` API instead.
|
|
*/
|
|
const getQueryStrings = (url) => {
|
|
const queryIndex = url.indexOf("?", 8);
|
|
if (queryIndex === -1) return "";
|
|
const hashIndex = url.indexOf("#", 8);
|
|
return hashIndex === -1 ? url.slice(queryIndex) : queryIndex < hashIndex ? url.slice(queryIndex, hashIndex) : "";
|
|
};
|
|
const getPathNoStrict = (request) => {
|
|
const result = getPath(request);
|
|
return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
|
|
};
|
|
/**
|
|
* Merge paths.
|
|
* @param {string[]} ...paths - The paths to merge.
|
|
* @returns {string} The merged path.
|
|
* @example
|
|
* mergePath('/api', '/users') // '/api/users'
|
|
* mergePath('/api/', '/users') // '/api/users'
|
|
* mergePath('/api', '/') // '/api'
|
|
* mergePath('/api/', '/') // '/api/'
|
|
*/
|
|
const mergePath = (base, sub, ...rest) => {
|
|
if (rest.length) sub = mergePath(sub, ...rest);
|
|
return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
|
|
};
|
|
const checkOptionalParameter = (path) => {
|
|
if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) return null;
|
|
const segments = path.split("/");
|
|
const results = [];
|
|
let basePath = "";
|
|
segments.forEach((segment) => {
|
|
if (segment !== "" && !/\:/.test(segment)) basePath += "/" + segment;
|
|
else if (/\:/.test(segment)) {
|
|
if (segment.charCodeAt(segment.length - 1) === 63) {
|
|
if (results.length === 0 && basePath === "") results.push("/");
|
|
else results.push(basePath);
|
|
const optionalSegment = segment.slice(0, -1);
|
|
basePath += "/" + optionalSegment;
|
|
results.push(basePath);
|
|
} else basePath += "/" + segment;
|
|
}
|
|
});
|
|
return results.filter((v, i, a) => a.indexOf(v) === i);
|
|
};
|
|
const tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
|
|
const _decodeURI = (value) => {
|
|
if (value.indexOf("+") !== -1) value = value.replace(/\+/g, " ");
|
|
return tryDecodeURIComponent(value);
|
|
};
|
|
const _getQueryParam = (url, key, multiple) => {
|
|
const hashIndex = url.indexOf("#", 8);
|
|
if (hashIndex !== -1) url = url.slice(0, hashIndex);
|
|
let encoded;
|
|
if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
|
|
let keyIndex = url.indexOf("?", 8);
|
|
if (keyIndex === -1) return;
|
|
if (!url.startsWith(key, keyIndex + 1)) keyIndex = url.indexOf(`&${key}`, keyIndex + 1);
|
|
while (keyIndex !== -1) {
|
|
const trailingKeyCode = url.charCodeAt(keyIndex + key.length + 1);
|
|
if (trailingKeyCode === 61) {
|
|
const valueIndex = keyIndex + key.length + 2;
|
|
const endIndex = url.indexOf("&", valueIndex);
|
|
return _decodeURI(url.slice(valueIndex, endIndex === -1 ? void 0 : endIndex));
|
|
} else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) return "";
|
|
keyIndex = url.indexOf(`&${key}`, keyIndex + 1);
|
|
}
|
|
encoded = /[%+]/.test(url);
|
|
if (!encoded) return;
|
|
}
|
|
const results = Object.create(null);
|
|
encoded ??= /[%+]/.test(url);
|
|
let keyIndex = url.indexOf("?", 8);
|
|
while (keyIndex !== -1) {
|
|
const nextKeyIndex = url.indexOf("&", keyIndex + 1);
|
|
let valueIndex = url.indexOf("=", keyIndex);
|
|
if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) valueIndex = -1;
|
|
let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex);
|
|
if (encoded) name = _decodeURI(name);
|
|
keyIndex = nextKeyIndex;
|
|
if (name === "") continue;
|
|
let value;
|
|
if (valueIndex === -1) value = "";
|
|
else {
|
|
value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex);
|
|
if (encoded) value = _decodeURI(value);
|
|
}
|
|
if (multiple) {
|
|
if (!(results[name] && Array.isArray(results[name]))) results[name] = [];
|
|
results[name].push(value);
|
|
} else results[name] ??= value;
|
|
}
|
|
return key ? results[key] : results;
|
|
};
|
|
const getQueryParam = _getQueryParam;
|
|
const getQueryParams = (url, key) => {
|
|
return _getQueryParam(url, key, true);
|
|
};
|
|
const decodeURIComponent_ = decodeURIComponent;
|
|
//#endregion
|
|
exports.checkOptionalParameter = checkOptionalParameter;
|
|
exports.decodeURIComponent_ = decodeURIComponent_;
|
|
exports.getPath = getPath;
|
|
exports.getPathNoStrict = getPathNoStrict;
|
|
exports.getPattern = getPattern;
|
|
exports.getQueryParam = getQueryParam;
|
|
exports.getQueryParams = getQueryParams;
|
|
exports.getQueryStrings = getQueryStrings;
|
|
exports.mergePath = mergePath;
|
|
exports.splitPath = splitPath;
|
|
exports.splitRoutingPath = splitRoutingPath;
|
|
exports.tryDecode = tryDecode;
|
|
exports.tryDecodeURI = tryDecodeURI;
|
|
exports.tryDecodeURIComponent = tryDecodeURIComponent;
|