Files
discord-clone/node_modules/radix3/dist/index.mjs
2023-01-03 09:29:04 -06:00

211 lines
5.8 KiB
JavaScript

const NODE_TYPES = {
NORMAL: 0,
WILDCARD: 1,
PLACEHOLDER: 2
};
function createRouter(options = {}) {
const ctx = {
options,
rootNode: createRadixNode(),
staticRoutesMap: {}
};
const normalizeTrailingSlash = (p) => options.strictTrailingSlash ? p : p.replace(/\/$/, "") || "/";
if (options.routes) {
for (const path in options.routes) {
insert(ctx, normalizeTrailingSlash(path), options.routes[path]);
}
}
return {
ctx,
lookup: (path) => lookup(ctx, normalizeTrailingSlash(path)),
insert: (path, data) => insert(ctx, normalizeTrailingSlash(path), data),
remove: (path) => remove(ctx, normalizeTrailingSlash(path))
};
}
function lookup(ctx, path) {
const staticPathNode = ctx.staticRoutesMap[path];
if (staticPathNode) {
return staticPathNode.data;
}
const sections = path.split("/");
const params = {};
let paramsFound = false;
let wildcardNode = null;
let node = ctx.rootNode;
let wildCardParam = null;
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
if (node.wildcardChildNode !== null) {
wildcardNode = node.wildcardChildNode;
wildCardParam = sections.slice(i).join("/");
}
const nextNode = node.children.get(section);
if (nextNode !== void 0) {
node = nextNode;
} else {
node = node.placeholderChildNode;
if (node !== null) {
params[node.paramName] = section;
paramsFound = true;
} else {
break;
}
}
}
if ((node === null || node.data === null) && wildcardNode !== null) {
node = wildcardNode;
params[node.paramName || "_"] = wildCardParam;
paramsFound = true;
}
if (!node) {
return null;
}
if (paramsFound) {
return {
...node.data,
params: paramsFound ? params : void 0
};
}
return node.data;
}
function insert(ctx, path, data) {
let isStaticRoute = true;
const sections = path.split("/");
let node = ctx.rootNode;
let _unnamedPlaceholderCtr = 0;
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
let childNode;
if (childNode = node.children.get(section)) {
node = childNode;
} else {
const type = getNodeType(section);
childNode = createRadixNode({ type, parent: node });
node.children.set(section, childNode);
if (type === NODE_TYPES.PLACEHOLDER) {
childNode.paramName = section === "*" ? `_${_unnamedPlaceholderCtr++}` : section.slice(1);
node.placeholderChildNode = childNode;
isStaticRoute = false;
} else if (type === NODE_TYPES.WILDCARD) {
node.wildcardChildNode = childNode;
childNode.paramName = section.substring(3) || "_";
isStaticRoute = false;
}
node = childNode;
}
}
node.data = data;
if (isStaticRoute === true) {
ctx.staticRoutesMap[path] = node;
}
return node;
}
function remove(ctx, path) {
let success = false;
const sections = path.split("/");
let node = ctx.rootNode;
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
node = node.children.get(section);
if (!node) {
return success;
}
}
if (node.data) {
const lastSection = sections[sections.length - 1];
node.data = null;
if (Object.keys(node.children).length === 0) {
const parentNode = node.parent;
delete parentNode[lastSection];
parentNode.wildcardChildNode = null;
parentNode.placeholderChildNode = null;
}
success = true;
}
return success;
}
function createRadixNode(options = {}) {
return {
type: options.type || NODE_TYPES.NORMAL,
parent: options.parent || null,
children: /* @__PURE__ */ new Map(),
data: options.data || null,
paramName: options.paramName || null,
wildcardChildNode: null,
placeholderChildNode: null
};
}
function getNodeType(str) {
if (str.startsWith("**")) {
return NODE_TYPES.WILDCARD;
}
if (str[0] === ":" || str === "*") {
return NODE_TYPES.PLACEHOLDER;
}
return NODE_TYPES.NORMAL;
}
function toRouteMatcher(router) {
const table = _routerNodeToTable("", router.ctx.rootNode);
return _createMatcher(table);
}
function _createMatcher(table) {
return {
ctx: { table },
matchAll: (path) => _matchRoutes(path, table)
};
}
function _createRouteTable() {
return {
static: /* @__PURE__ */ new Map(),
wildcard: /* @__PURE__ */ new Map(),
dynamic: /* @__PURE__ */ new Map()
};
}
function _matchRoutes(path, table) {
const matches = [];
for (const [key, value] of table.wildcard) {
if (path.startsWith(key)) {
matches.push(value);
}
}
for (const [key, value] of table.dynamic) {
if (path.startsWith(key + "/")) {
const subPath = "/" + path.substring(key.length).split("/").splice(2).join("/");
matches.push(..._matchRoutes(subPath, value));
}
}
const staticMatch = table.static.get(path);
if (staticMatch) {
matches.push(staticMatch);
}
return matches.filter(Boolean);
}
function _routerNodeToTable(initialPath, initialNode) {
const table = _createRouteTable();
function _addNode(path, node) {
if (path) {
if (node.type === NODE_TYPES.NORMAL && !(path.includes("*") || path.includes(":"))) {
table.static.set(path, node.data);
} else if (node.type === NODE_TYPES.WILDCARD) {
table.wildcard.set(path.replace("/**", ""), node.data);
} else if (node.type === NODE_TYPES.PLACEHOLDER) {
const subTable = _routerNodeToTable("", node);
if (node.data) {
subTable.static.set("/", node.data);
}
table.dynamic.set(path.replace(/\/\*|\/:\w+/, ""), subTable);
return;
}
}
for (const [childPath, child] of node.children.entries()) {
_addNode(`${path}/${childPath}`.replace("//", "/"), child);
}
}
_addNode(initialPath, initialNode);
return table;
}
export { NODE_TYPES, createRouter, toRouteMatcher };