109 lines
3.2 KiB
JavaScript
109 lines
3.2 KiB
JavaScript
// 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 = 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 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 {
|
|
index;
|
|
varIndex;
|
|
children = /* @__PURE__ */ Object.create(null);
|
|
insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
|
|
if (tokens.length === 0) {
|
|
if (this.index !== void 0) {
|
|
throw PATH_ERROR;
|
|
}
|
|
if (pathErrorCheckOnly) {
|
|
return;
|
|
}
|
|
this.index = index;
|
|
return;
|
|
}
|
|
const [token, ...restTokens] = tokens;
|
|
const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
let node;
|
|
if (pattern) {
|
|
const name = pattern[1];
|
|
let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
|
|
if (name && pattern[2]) {
|
|
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
if (/\((?!\?:)/.test(regexpStr)) {
|
|
throw PATH_ERROR;
|
|
}
|
|
}
|
|
node = this.children[regexpStr];
|
|
if (!node) {
|
|
if (Object.keys(this.children).some(
|
|
(k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
)) {
|
|
throw PATH_ERROR;
|
|
}
|
|
if (pathErrorCheckOnly) {
|
|
return;
|
|
}
|
|
node = this.children[regexpStr] = new Node();
|
|
if (name !== "") {
|
|
node.varIndex = context.varIndex++;
|
|
}
|
|
}
|
|
if (!pathErrorCheckOnly && name !== "") {
|
|
paramMap.push([name, node.varIndex]);
|
|
}
|
|
} else {
|
|
node = this.children[token];
|
|
if (!node) {
|
|
if (Object.keys(this.children).some(
|
|
(k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
)) {
|
|
throw PATH_ERROR;
|
|
}
|
|
if (pathErrorCheckOnly) {
|
|
return;
|
|
}
|
|
node = this.children[token] = new Node();
|
|
}
|
|
}
|
|
node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
|
|
}
|
|
buildRegExpStr() {
|
|
const childKeys = Object.keys(this.children).sort(compareKey);
|
|
const strList = childKeys.map((k) => {
|
|
const c = this.children[k];
|
|
return (typeof c.varIndex === "number" ? `(${k})@${c.varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr();
|
|
});
|
|
if (typeof this.index === "number") {
|
|
strList.unshift(`#${this.index}`);
|
|
}
|
|
if (strList.length === 0) {
|
|
return "";
|
|
}
|
|
if (strList.length === 1) {
|
|
return strList[0];
|
|
}
|
|
return "(?:" + strList.join("|") + ")";
|
|
}
|
|
};
|
|
export {
|
|
Node,
|
|
PATH_ERROR
|
|
};
|