Files
SnowLuma/.pnpm-store/v11/files/1b/36a40de75dfdd9de86c802d789c43f0e05fc101983e2d552b26fa4d48f652bc01bae440985b85b47f5f89ae9255329e97d85a161ef8468f814d3536a51a966
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

92 lines
3.1 KiB
Plaintext

import { createNullObject } from "../utils.js";
//#region src/router/reg-exp-router/node.ts
const LABEL_REG_EXP_STR = "[^/]+";
const ONLY_WILDCARD_REG_EXP_STR = ".*";
const TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
const PATH_ERROR = Symbol();
const regExpMetaChars = /* @__PURE__ */ new Set(".\\+*[^]$()");
/**
* Sort order:
* 1. literal
* 2. special pattern (e.g. :label{[0-9]+})
* 3. common label pattern (e.g. :label)
* 4. wildcard
*/
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 === ".*" || a === "(?:|/.*)") return b === "(?:|/.*)" ? -1 : 1;
else if (b === ".*" || b === "(?:|/.*)") return -1;
if (a === "[^/]+") return 1;
else if (b === "[^/]+") return -1;
return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
}
var Node = class Node {
#index;
#varIndex;
#children = createNullObject();
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 ? [
"",
"",
".*"
] : [
"",
"",
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] || "[^/]+";
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 !== ".*" && regexpStr !== "(?:|/.*)") {
for (const k in node.#children) if ((regexpStr.length > 1 || k.length > 1) && k !== ".*" && k !== "(?:|/.*)") 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 !== ".*" && k !== "(?:|/.*)") 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 strList = Object.keys(this.#children).sort(compareKey).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("|") + ")";
}
};
//#endregion
export { LABEL_REG_EXP_STR, Node, ONLY_WILDCARD_REG_EXP_STR, PATH_ERROR, TAIL_WILDCARD_REG_EXP_STR };