feat: init
This commit is contained in:
265
node_modules/rou3/dist/index.mjs
generated
vendored
Normal file
265
node_modules/rou3/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
const NullProtoObj = /* @__PURE__ */ (() => {
|
||||
const e = function() {};
|
||||
return e.prototype = Object.create(null), Object.freeze(e.prototype), e;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Create a new router context.
|
||||
*/
|
||||
function createRouter() {
|
||||
return {
|
||||
root: { key: "" },
|
||||
static: new NullProtoObj()
|
||||
};
|
||||
}
|
||||
|
||||
function splitPath(path) {
|
||||
const [_, ...s] = path.split("/");
|
||||
return s[s.length - 1] === "" ? s.slice(0, -1) : s;
|
||||
}
|
||||
function getMatchParams(segments, paramsMap) {
|
||||
const params = new NullProtoObj();
|
||||
for (const [index, name] of paramsMap) {
|
||||
const segment = index < 0 ? segments.slice(-(index + 1)).join("/") : segments[index];
|
||||
if (typeof name === "string") params[name] = segment;
|
||||
else {
|
||||
const match = segment.match(name);
|
||||
if (match) for (const key in match.groups) params[key] = match.groups[key];
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a route to the router context.
|
||||
*/
|
||||
function addRoute(ctx, method = "", path, data) {
|
||||
method = method.toUpperCase();
|
||||
if (path.charCodeAt(0) !== 47) path = `/${path}`;
|
||||
path = path.replace(/\\:/g, "%3A");
|
||||
const segments = splitPath(path);
|
||||
let node = ctx.root;
|
||||
let _unnamedParamIndex = 0;
|
||||
const paramsMap = [];
|
||||
const paramsRegexp = [];
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
let segment = segments[i];
|
||||
if (segment.startsWith("**")) {
|
||||
if (!node.wildcard) node.wildcard = { key: "**" };
|
||||
node = node.wildcard;
|
||||
paramsMap.push([
|
||||
-(i + 1),
|
||||
segment.split(":")[1] || "_",
|
||||
segment.length === 2
|
||||
]);
|
||||
break;
|
||||
}
|
||||
if (segment === "*" || segment.includes(":")) {
|
||||
if (!node.param) node.param = { key: "*" };
|
||||
node = node.param;
|
||||
if (segment === "*") paramsMap.push([
|
||||
i,
|
||||
`_${_unnamedParamIndex++}`,
|
||||
true
|
||||
]);
|
||||
else if (segment.includes(":", 1)) {
|
||||
const regexp = getParamRegexp(segment);
|
||||
paramsRegexp[i] = regexp;
|
||||
node.hasRegexParam = true;
|
||||
paramsMap.push([
|
||||
i,
|
||||
regexp,
|
||||
false
|
||||
]);
|
||||
} else paramsMap.push([
|
||||
i,
|
||||
segment.slice(1),
|
||||
false
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
if (segment === "\\*") segment = segments[i] = "*";
|
||||
else if (segment === "\\*\\*") segment = segments[i] = "**";
|
||||
const child = node.static?.[segment];
|
||||
if (child) node = child;
|
||||
else {
|
||||
const staticNode = { key: segment };
|
||||
if (!node.static) node.static = new NullProtoObj();
|
||||
node.static[segment] = staticNode;
|
||||
node = staticNode;
|
||||
}
|
||||
}
|
||||
const hasParams = paramsMap.length > 0;
|
||||
if (!node.methods) node.methods = new NullProtoObj();
|
||||
node.methods[method] ??= [];
|
||||
node.methods[method].push({
|
||||
data: data || null,
|
||||
paramsRegexp,
|
||||
paramsMap: hasParams ? paramsMap : void 0
|
||||
});
|
||||
if (!hasParams) ctx.static["/" + segments.join("/")] = node;
|
||||
}
|
||||
function getParamRegexp(segment) {
|
||||
const regex = segment.replace(/:(\w+)/g, (_, id) => `(?<${id}>[^/]+)`).replace(/\./g, "\\.");
|
||||
return /* @__PURE__ */ new RegExp(`^${regex}$`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a route by path.
|
||||
*/
|
||||
function findRoute(ctx, method = "", path, opts) {
|
||||
if (path.charCodeAt(path.length - 1) === 47) path = path.slice(0, -1);
|
||||
const staticNode = ctx.static[path];
|
||||
if (staticNode && staticNode.methods) {
|
||||
const staticMatch = staticNode.methods[method] || staticNode.methods[""];
|
||||
if (staticMatch !== void 0) return staticMatch[0];
|
||||
}
|
||||
const segments = splitPath(path);
|
||||
const match = _lookupTree(ctx, ctx.root, method, segments, 0)?.[0];
|
||||
if (match === void 0) return;
|
||||
if (opts?.params === false) return match;
|
||||
return {
|
||||
data: match.data,
|
||||
params: match.paramsMap ? getMatchParams(segments, match.paramsMap) : void 0
|
||||
};
|
||||
}
|
||||
function _lookupTree(ctx, node, method, segments, index) {
|
||||
if (index === segments.length) {
|
||||
if (node.methods) {
|
||||
const match = node.methods[method] || node.methods[""];
|
||||
if (match) return match;
|
||||
}
|
||||
if (node.param && node.param.methods) {
|
||||
const match = node.param.methods[method] || node.param.methods[""];
|
||||
if (match) {
|
||||
const pMap = match[0].paramsMap;
|
||||
if (pMap?.[pMap?.length - 1]?.[2]) return match;
|
||||
}
|
||||
}
|
||||
if (node.wildcard && node.wildcard.methods) {
|
||||
const match = node.wildcard.methods[method] || node.wildcard.methods[""];
|
||||
if (match) {
|
||||
const pMap = match[0].paramsMap;
|
||||
if (pMap?.[pMap?.length - 1]?.[2]) return match;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
const segment = segments[index];
|
||||
if (node.static) {
|
||||
const staticChild = node.static[segment];
|
||||
if (staticChild) {
|
||||
const match = _lookupTree(ctx, staticChild, method, segments, index + 1);
|
||||
if (match) return match;
|
||||
}
|
||||
}
|
||||
if (node.param) {
|
||||
const match = _lookupTree(ctx, node.param, method, segments, index + 1);
|
||||
if (match) {
|
||||
if (node.param.hasRegexParam) {
|
||||
const exactMatch = match.find((m) => m.paramsRegexp[index]?.test(segment)) || match.find((m) => !m.paramsRegexp[index]);
|
||||
return exactMatch ? [exactMatch] : void 0;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
}
|
||||
if (node.wildcard && node.wildcard.methods) return node.wildcard.methods[method] || node.wildcard.methods[""];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a route from the router context.
|
||||
*/
|
||||
function removeRoute(ctx, method, path) {
|
||||
const segments = splitPath(path);
|
||||
return _remove(ctx.root, method || "", segments, 0);
|
||||
}
|
||||
function _remove(node, method, segments, index) {
|
||||
if (index === segments.length) {
|
||||
if (node.methods && method in node.methods) {
|
||||
delete node.methods[method];
|
||||
if (Object.keys(node.methods).length === 0) node.methods = void 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const segment = segments[index];
|
||||
if (segment === "*") {
|
||||
if (node.param) {
|
||||
_remove(node.param, method, segments, index + 1);
|
||||
if (_isEmptyNode(node.param)) node.param = void 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (segment.startsWith("**")) {
|
||||
if (node.wildcard) {
|
||||
_remove(node.wildcard, method, segments, index + 1);
|
||||
if (_isEmptyNode(node.wildcard)) node.wildcard = void 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const childNode = node.static?.[segment];
|
||||
if (childNode) {
|
||||
_remove(childNode, method, segments, index + 1);
|
||||
if (_isEmptyNode(childNode)) {
|
||||
delete node.static[segment];
|
||||
if (Object.keys(node.static).length === 0) node.static = void 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
function _isEmptyNode(node) {
|
||||
return node.methods === void 0 && node.static === void 0 && node.param === void 0 && node.wildcard === void 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all route patterns that match the given path.
|
||||
*/
|
||||
function findAllRoutes(ctx, method = "", path, opts) {
|
||||
if (path.charCodeAt(path.length - 1) === 47) path = path.slice(0, -1);
|
||||
const segments = splitPath(path);
|
||||
const matches = _findAll(ctx, ctx.root, method, segments, 0);
|
||||
if (opts?.params === false) return matches;
|
||||
return matches.map((m) => {
|
||||
return {
|
||||
data: m.data,
|
||||
params: m.paramsMap ? getMatchParams(segments, m.paramsMap) : void 0
|
||||
};
|
||||
});
|
||||
}
|
||||
function _findAll(ctx, node, method, segments, index, matches = []) {
|
||||
const segment = segments[index];
|
||||
if (node.wildcard && node.wildcard.methods) {
|
||||
const match = node.wildcard.methods[method] || node.wildcard.methods[""];
|
||||
if (match) matches.push(...match);
|
||||
}
|
||||
if (node.param) {
|
||||
_findAll(ctx, node.param, method, segments, index + 1, matches);
|
||||
if (index === segments.length && node.param.methods) {
|
||||
const match = node.param.methods[method] || node.param.methods[""];
|
||||
if (match) {
|
||||
const pMap = match[0].paramsMap;
|
||||
if (pMap?.[pMap?.length - 1]?.[2]) matches.push(...match);
|
||||
}
|
||||
}
|
||||
}
|
||||
const staticChild = node.static?.[segment];
|
||||
if (staticChild) _findAll(ctx, staticChild, method, segments, index + 1, matches);
|
||||
if (index === segments.length && node.methods) {
|
||||
const match = node.methods[method] || node.methods[""];
|
||||
if (match) matches.push(...match);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
function routeToRegExp(route = "/") {
|
||||
const reSegments = [];
|
||||
let idCtr = 0;
|
||||
for (const segment of route.split("/")) {
|
||||
if (!segment) continue;
|
||||
if (segment === "*") reSegments.push(`(?<_${idCtr++}>[^/]*)`);
|
||||
else if (segment.startsWith("**")) reSegments.push(segment === "**" ? "?(?<_>.*)" : `?(?<${segment.slice(3)}>.+)`);
|
||||
else if (segment.includes(":")) reSegments.push(segment.replace(/:(\w+)/g, (_, id) => `(?<${id}>[^/]+)`).replace(/\./g, "\\."));
|
||||
else reSegments.push(segment);
|
||||
}
|
||||
return /* @__PURE__ */ new RegExp(`^/${reSegments.join("/")}/?$`);
|
||||
}
|
||||
|
||||
export { NullProtoObj, addRoute, createRouter, findAllRoutes, findRoute, removeRoute, routeToRegExp };
|
||||
Reference in New Issue
Block a user