// src/router/reg-exp-router/node.ts var LABEL_REG_EXP_STR = "[^/]+"; var ONLY_WILDCARD_REG_EXP_STR = ".*"; var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)"; var PATH_ERROR = /* @__PURE__ */ Symbol(); var regExpMetaChars = new Set(".\\+*[^]$()"); function compareKey(a, b) { if (a.length === 1) { return b.length === 1 ? a < b ? -1 : 1 : -1; } if (b.length === 1) { return 1; } if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) { return b === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1; } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) { return -1; } if (a === LABEL_REG_EXP_STR) { return 1; } else if (b === LABEL_REG_EXP_STR) { return -1; } return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length; } var Node = class _Node { // handler index of a dynamic path, or -1 for a static path terminal #index; #varIndex; #children = /* @__PURE__ */ Object.create(null); insert(tokens, index, paramMap, context, isStatic) { let node = this; for (let i = 0, len = tokens.length; i < len; i++) { const token = tokens[i]; const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : null : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); let nextNode; if (pattern) { const name = pattern[1]; let regexpStr = pattern[2] || LABEL_REG_EXP_STR; if (name && pattern[2]) { if (regexpStr === ".*") { throw PATH_ERROR; } regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:"); if (/\((?!\?:)/.test(regexpStr)) { throw PATH_ERROR; } if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) { throw PATH_ERROR; } } nextNode = node.#children[regexpStr]; if (!nextNode) { if (regexpStr !== ONLY_WILDCARD_REG_EXP_STR && regexpStr !== TAIL_WILDCARD_REG_EXP_STR) { for (const k in node.#children) { if ( // a single-char pattern coexists with single-char literals as a literal does (regexpStr.length > 1 || k.length > 1) && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR ) { throw PATH_ERROR; } } } nextNode = node.#children[regexpStr] = new _Node(); } if (name !== "") { nextNode.#varIndex ??= context.varIndex++; paramMap.push([name, nextNode.#varIndex]); } } else { nextNode = node.#children[token]; if (!nextNode) { for (const k in node.#children) { if (k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR) { throw PATH_ERROR; } } nextNode = node.#children[token] = new _Node(); } } node = nextNode; } if (node.#index !== void 0) { throw PATH_ERROR; } node.#index = isStatic ? -1 : index; } buildRegExpStr() { const childKeys = Object.keys(this.#children).sort(compareKey); const strList = childKeys.map((k) => { const c = this.#children[k]; const childStr = c.buildRegExpStr(); return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr; }).filter(Boolean); if (typeof this.#index === "number" && this.#index !== -1) { strList.unshift(`#${this.#index}`); } if (strList.length === 0) { return ""; } if (strList.length === 1) { return strList[0]; } return "(?:" + strList.join("|") + ")"; } }; export { Node, PATH_ERROR };