135 lines
4.5 KiB
Plaintext
135 lines
4.5 KiB
Plaintext
import { getPattern, splitPath, splitRoutingPath } from "../../utils/url.js";
|
|
import "../../router.js";
|
|
import { createNullObject } from "../utils.js";
|
|
//#region src/router/trie-router/node.ts
|
|
const emptyParams = createNullObject();
|
|
let order = 0;
|
|
var Node = class Node {
|
|
#methods = [];
|
|
#children = createNullObject();
|
|
#patterns = [];
|
|
#pattern;
|
|
#params = emptyParams;
|
|
insert(method, path, handler) {
|
|
let curNode = this;
|
|
const parts = splitRoutingPath(path);
|
|
const possibleKeys = /* @__PURE__ */ new Set();
|
|
let i = 0;
|
|
for (const p of parts) {
|
|
const nextP = parts[++i];
|
|
const pattern = getPattern(p, nextP) || (nextP === void 0 && p && p.indexOf("*") === p.length - 1 ? p : null);
|
|
const isParam = Array.isArray(pattern);
|
|
const key = isParam ? pattern[0] : pattern || p;
|
|
const child = curNode.#children[key] ||= new Node();
|
|
if (pattern && !child.#pattern) {
|
|
child.#pattern = pattern;
|
|
curNode.#patterns.push(child);
|
|
}
|
|
curNode = child;
|
|
if (isParam) possibleKeys.add(pattern[1]);
|
|
}
|
|
curNode.#methods.push({ [method]: {
|
|
handler,
|
|
possibleKeys: [...possibleKeys],
|
|
score: ++order
|
|
} });
|
|
}
|
|
#pushHandlerSets(handlerSets, node, method, nodeParams, params) {
|
|
for (let i = 0, len = node.#methods.length; i < len; i++) {
|
|
const m = node.#methods[i];
|
|
const handlerSet = m[method] || m["ALL"];
|
|
if (handlerSet) {
|
|
handlerSet.params = createNullObject();
|
|
handlerSets.push(handlerSet);
|
|
for (let i = 0, len = handlerSet.possibleKeys.length; i < len; i++) {
|
|
const key = handlerSet.possibleKeys[i];
|
|
handlerSet.params[key] = params?.[key] && !i ? params[key] : nodeParams[key] ?? params?.[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
search(method, path) {
|
|
const handlerSets = [];
|
|
this.#params = emptyParams;
|
|
let curNodes = [this];
|
|
const parts = splitPath(path);
|
|
const curNodesQueue = [];
|
|
const len = parts.length;
|
|
let partOffsets = null;
|
|
for (let i = 0; i < len; i++) {
|
|
const part = parts[i];
|
|
const isLast = i === len - 1;
|
|
const tempNodes = [];
|
|
for (let j = 0, len2 = curNodes.length; j < len2; j++) {
|
|
const node = curNodes[j];
|
|
const nextNode = node.#children[part];
|
|
if (nextNode) {
|
|
nextNode.#params = node.#params;
|
|
if (isLast) {
|
|
if (nextNode.#children["*"]) this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
|
|
this.#pushHandlerSets(handlerSets, nextNode, method, node.#params);
|
|
} else tempNodes.push(nextNode);
|
|
}
|
|
for (const child of node.#patterns) {
|
|
const pattern = child.#pattern;
|
|
const params = node.#params === emptyParams ? {} : { ...node.#params };
|
|
if (typeof pattern === "string") {
|
|
if (pattern === "*" || part.startsWith(pattern.slice(0, -1))) {
|
|
this.#pushHandlerSets(handlerSets, child, method, node.#params);
|
|
if (pattern === "*") {
|
|
child.#params = params;
|
|
tempNodes.push(child);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
const [, name, matcher] = pattern;
|
|
if (!part && matcher === true) continue;
|
|
if (matcher !== true) {
|
|
if (!partOffsets) {
|
|
partOffsets = [];
|
|
let offset = path[0] === "/" ? 1 : 0;
|
|
for (let p = 0; p < len; p++) {
|
|
partOffsets[p] = offset;
|
|
offset += parts[p].length + 1;
|
|
}
|
|
}
|
|
const restPathString = path.slice(partOffsets[i]);
|
|
const m = matcher.exec(restPathString);
|
|
if (m) {
|
|
params[name] = m[0];
|
|
this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
|
|
if (m[0].length === restPathString.length && child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, node.#params, params);
|
|
for (const _ in child.#children) {
|
|
child.#params = params;
|
|
const componentCount = m[0].match(/\//g)?.length ?? 0;
|
|
(curNodesQueue[componentCount] ||= []).push(child);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if (matcher === true || matcher.test(part)) {
|
|
params[name] = part;
|
|
if (isLast) {
|
|
this.#pushHandlerSets(handlerSets, child, method, params, node.#params);
|
|
if (child.#children["*"]) this.#pushHandlerSets(handlerSets, child.#children["*"], method, params, node.#params);
|
|
} else {
|
|
child.#params = params;
|
|
tempNodes.push(child);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const shifted = curNodesQueue.shift();
|
|
curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
|
|
}
|
|
if (handlerSets[1]) handlerSets.sort((a, b) => {
|
|
return a.score - b.score;
|
|
});
|
|
return [handlerSets.map(({ handler, params }) => [handler, params])];
|
|
}
|
|
};
|
|
//#endregion
|
|
export { Node };
|