exstack
Version:
A utility library designed to simplify and enhance Express.js applications.
77 lines (75 loc) • 2.43 kB
JavaScript
//#region src/router/utils.ts
/**
* 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 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;
}
});
}
};
/**
* Detects and expands optional parameters in a route path.
*
* Example:
* /api/animals/:type?
* → ['/api/animals', '/api/animals/:type']
*
* If there is no optional parameter, returns null.
*/
const checkOptionalParameter = (path) => {
if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) return null;
const segments = path.split("/");
const results = [];
let basePath = "";
for (const segment of segments) if (segment && !segment.includes(":")) basePath += "/" + segment;
else if (segment.includes(":")) if (segment.includes("?")) {
results.push(basePath === "" ? "/" : basePath);
const optionalSegment = segment.replace("?", "");
basePath += "/" + optionalSegment;
results.push(basePath);
} else basePath += "/" + segment;
return [...new Set(results)];
};
/**
* Cache for precompiled wildcard regular expressions.
*/
let wildcardRegExpCache = Object.create(null);
/**
* Converts a path with wildcards into a RegExp for quick matching.
* Example:
* /api/* → /^\/api(?:|\/.*)$/
*/
function buildWildcardRegExp(path) {
return wildcardRegExpCache[path] ??= /* @__PURE__ */ new RegExp(path === "*" ? "" : `^${path.replace(/\/\*$|([.\\+*[^\]$()])/g, (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)")}$`);
}
/**
* Clears wildcard cache (useful after routes are built).
*/
function clearWildcardRegExpCache() {
wildcardRegExpCache = Object.create(null);
}
//#endregion
exports.buildWildcardRegExp = buildWildcardRegExp;
exports.checkOptionalParameter = checkOptionalParameter;
exports.clearWildcardRegExpCache = clearWildcardRegExpCache;
exports.mergePath = mergePath;
exports.tryDecode = tryDecode;