UNPKG

ufiber

Version:

Next-gen webserver for node-js developer

145 lines (143 loc) 4.81 kB
import { METHOD_NAME_ALL } from "../../consts.js"; import { getPattern, splitPath, splitRoutingPath } from "./utils.js"; //#region src/router/trie-tree/node.ts const emptyParams = Object.create(null); var Node = class Node { #methods; #children; #patterns; #order = 0; #params = emptyParams; constructor(method, handler, children) { this.#children = children || Object.create(null); this.#methods = []; if (method && handler) { const m = Object.create(null); m[method] = { handler, possibleKeys: [], score: 0 }; this.#methods = [m]; } this.#patterns = []; } insert(method, path, handler) { this.#order = ++this.#order; let curNode = this; const parts = splitRoutingPath(path); const possibleKeys = []; for (let i = 0, len = parts.length; i < len; i++) { const p = parts[i]; const nextP = parts[i + 1]; const pattern = getPattern(p, nextP); const key = Array.isArray(pattern) ? pattern[0] : p; if (key in curNode.#children) { curNode = curNode.#children[key]; if (pattern) possibleKeys.push(pattern[1]); continue; } curNode.#children[key] = new Node(); if (pattern) { curNode.#patterns.push(pattern); possibleKeys.push(pattern[1]); } curNode = curNode.#children[key]; } curNode.#methods.push({ [method]: { handler, possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i), score: this.#order } }); return curNode; } #getHandlerSets(node, method, nodeParams, params) { const handlerSets = []; for (let i = 0, len = node.#methods.length; i < len; i++) { const m = node.#methods[i]; const handlerSet = m[method] || m[METHOD_NAME_ALL]; const processedSet = {}; if (handlerSet !== void 0) { handlerSet.params = Object.create(null); handlerSets.push(handlerSet); if (nodeParams !== emptyParams || params && params !== emptyParams) for (let i$1 = 0, len$1 = handlerSet.possibleKeys.length; i$1 < len$1; i$1++) { const key = handlerSet.possibleKeys[i$1]; const processed = processedSet[handlerSet.score]; handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key]; processedSet[handlerSet.score] = true; } } } return handlerSets; } search(method, path) { const handlerSets = []; this.#params = emptyParams; let curNodes = [this]; const parts = splitPath(path); const curNodesQueue = []; for (let i = 0, len = parts.length; 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["*"]) handlerSets.push(...this.#getHandlerSets(nextNode.#children["*"], method, node.#params)); handlerSets.push(...this.#getHandlerSets(nextNode, method, node.#params)); } else tempNodes.push(nextNode); } for (let k = 0, len3 = node.#patterns.length; k < len3; k++) { const pattern = node.#patterns[k]; const params = node.#params === emptyParams ? {} : { ...node.#params }; if (pattern === "*") { const astNode = node.#children["*"]; if (astNode) { handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params)); astNode.#params = params; tempNodes.push(astNode); } continue; } const [key, name, matcher] = pattern; if (!part && !(matcher instanceof RegExp)) continue; const child = node.#children[key]; const restPathString = parts.slice(i).join("/"); if (matcher instanceof RegExp) { const m = matcher.exec(restPathString); if (m) { params[name] = m[0]; handlerSets.push(...this.#getHandlerSets(child, method, node.#params, params)); if (Object.keys(child.#children).length) { child.#params = params; const componentCount = m[0].match(/\//)?.length ?? 0; (curNodesQueue[componentCount] ||= []).push(child); } continue; } } if (matcher === true || matcher.test(part)) { params[name] = part; if (isLast) { handlerSets.push(...this.#getHandlerSets(child, method, params, node.#params)); if (child.#children["*"]) handlerSets.push(...this.#getHandlerSets(child.#children["*"], method, params, node.#params)); } else { child.#params = params; tempNodes.push(child); } } } } curNodes = tempNodes.concat(curNodesQueue.shift() ?? []); } if (handlerSets.length > 1) handlerSets.sort((a, b) => { return a.score - b.score; }); return [handlerSets.map(({ handler, params }) => [handler, params])]; } }; //#endregion export { Node };