full site update

This commit is contained in:
2025-07-24 18:46:24 +02:00
parent bfe2b90d8d
commit 37a6e0ab31
6912 changed files with 540482 additions and 361712 deletions

21
node_modules/radix3/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

171
node_modules/radix3/README.md generated vendored Normal file
View File

@@ -0,0 +1,171 @@
# 🌳 radix3
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![bundle][bundle-src]][bundle-href]
[![Codecov][codecov-src]][codecov-href]
[![License][license-src]][license-href]
[![JSDocs][jsdocs-src]][jsdocs-href]
Lightweight and fast router for JavaScript based on [Radix Tree](https://en.wikipedia.org/wiki/Radix_tree).
## Usage
**Install package:**
```sh
# npm
npm i radix3
# yarn
yarn add radix3
# pnpm
pnpm i radix3
```
**Import:**
```js
// ESM
import { createRouter } from "radix3";
// CJS
const { createRouter } = require("radix3");
```
**Create a router instance and insert routes:**
```js
const router = createRouter(/* options */);
router.insert("/path", { payload: "this path" });
router.insert("/path/:name", { payload: "named route" });
router.insert("/path/foo/**", { payload: "wildcard route" });
router.insert("/path/foo/**:name", { payload: "named wildcard route" });
```
**Match route to access matched data:**
```js
router.lookup("/path");
// { payload: 'this path' }
router.lookup("/path/fooval");
// { payload: 'named route', params: { name: 'fooval' } }
router.lookup("/path/foo/bar/baz");
// { payload: 'wildcard route' }
router.lookup("/");
// null (no route matched for/)
```
## Methods
### `router.insert(path, data)`
`path` can be static or using `:placeholder` or `**` for wildcard paths.
The `data` object will be returned on matching params. It should be an object like `{ handler }` and not containing reserved keyword `params`.
### `router.lookup(path)`
Returns matched data for `path` with optional `params` key if mached route using placeholders.
### `router.remove(path)`
Remove route matching `path`.
## Options
You can initialize router instance with options:
```ts
const router = createRouter({
strictTrailingSlash: true,
routes: {
"/foo": {},
},
});
```
- `routes`: An object specifying initial routes to add
- `strictTrailingSlash`: By default router ignored trailing slash for matching and adding routes. When set to `true`, matching with trailing slash is different.
### Route Matcher
Creates a multi matcher from router tree that can match **all routes** matching path:
```ts
import { createRouter, toRouteMatcher } from "radix3";
const router = createRouter({
routes: {
"/foo": { m: "foo" }, // Matches /foo only
"/foo/**": { m: "foo/**" }, // Matches /foo/<any>
"/foo/bar": { m: "foo/bar" }, // Matches /foo/bar only
"/foo/bar/baz": { m: "foo/bar/baz" }, // Matches /foo/bar/baz only
"/foo/*/baz": { m: "foo/*/baz" }, // Matches /foo/<any>/baz
},
});
const matcher = toRouteMatcher(router);
const matches = matcher.matchAll("/foo/bar/baz");
// [
// {
// "m": "foo/**",
// },
// {
// "m": "foo/*/baz",
// },
// {
// "m": "foo/bar/baz",
// },
// ]
```
### Route Matcher Export
It is also possible to export and then rehydrate a matcher from pre-compiled rules.
```ts
import { exportMatcher, createMatcherFromExport } from "radix3";
// Assuming you already have a matcher
// you can export this to a JSON-type object
const json = exportMatcher(matcher);
// and then rehydrate this later
const newMatcher = createMatcherFromExport(json);
const matches = newMatcher.matchAll("/foo/bar/baz");
```
## Performance
See [benchmark](./benchmark).
## License
Based on original work of [`charlieduong94/radix-router`](https://github.com/charlieduong94/radix-router)
by [Charlie Duong](https://github.com/charlieduong94) (MIT)
[MIT](./LICENSE) - Made with ❤️
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/radix3?style=flat&colorA=18181B&colorB=F0DB4F
[npm-version-href]: https://npmjs.com/package/radix3
[npm-downloads-src]: https://img.shields.io/npm/dm/radix3?style=flat&colorA=18181B&colorB=F0DB4F
[npm-downloads-href]: https://npmjs.com/package/radix3
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/radix3/main?style=flat&colorA=18181B&colorB=F0DB4F
[codecov-href]: https://codecov.io/gh/unjs/radix3
[bundle-src]: https://img.shields.io/bundlephobia/minzip/radix3?style=flat&colorA=18181B&colorB=F0DB4F
[bundle-href]: https://bundlephobia.com/result?p=radix3
[license-src]: https://img.shields.io/github/license/unjs/radix3.svg?style=flat&colorA=18181B&colorB=F0DB4F
[license-href]: https://github.com/unjs/radix3/blob/main/LICENSE
[jsdocs-src]: https://img.shields.io/badge/jsDocs.io-reference-18181B?style=flat&colorA=18181B&colorB=F0DB4F
[jsdocs-href]: https://www.jsdocs.io/package/radix3

268
node_modules/radix3/dist/index.cjs generated vendored Normal file
View File

@@ -0,0 +1,268 @@
'use strict';
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) {
if (node && node.placeholderChildren.length > 1) {
const remaining = sections.length - i;
node = node.placeholderChildren.find((c) => c.maxDepth === remaining) || null;
} else {
node = node.placeholderChildren[0] || null;
}
if (!node) {
break;
}
if (node.paramName) {
params[node.paramName] = section;
}
paramsFound = true;
} else {
node = nextNode;
}
}
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;
const matchedNodes = [node];
for (const section of sections) {
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.placeholderChildren.push(childNode);
isStaticRoute = false;
} else if (type === NODE_TYPES.WILDCARD) {
node.wildcardChildNode = childNode;
childNode.paramName = section.slice(
3
/* "**:" */
) || "_";
isStaticRoute = false;
}
matchedNodes.push(childNode);
node = childNode;
}
}
for (const [depth, node2] of matchedNodes.entries()) {
node2.maxDepth = Math.max(matchedNodes.length - depth, node2.maxDepth || 0);
}
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 (const section of sections) {
node = node.children.get(section);
if (!node) {
return success;
}
}
if (node.data) {
const lastSection = sections.at(-1) || "";
node.data = null;
if (Object.keys(node.children).length === 0 && node.parent) {
node.parent.children.delete(lastSection);
node.parent.wildcardChildNode = null;
node.parent.placeholderChildren = [];
}
success = true;
}
return success;
}
function createRadixNode(options = {}) {
return {
type: options.type || NODE_TYPES.NORMAL,
maxDepth: 0,
parent: options.parent || null,
children: /* @__PURE__ */ new Map(),
data: options.data || null,
paramName: options.paramName || null,
wildcardChildNode: null,
placeholderChildren: []
};
}
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, router.ctx.options.strictTrailingSlash);
}
function _createMatcher(table, strictTrailingSlash) {
return {
ctx: { table },
matchAll: (path) => _matchRoutes(path, table, strictTrailingSlash)
};
}
function _createRouteTable() {
return {
static: /* @__PURE__ */ new Map(),
wildcard: /* @__PURE__ */ new Map(),
dynamic: /* @__PURE__ */ new Map()
};
}
function _exportMatcherFromTable(table) {
const obj = /* @__PURE__ */ Object.create(null);
for (const property in table) {
obj[property] = property === "dynamic" ? Object.fromEntries(
[...table[property].entries()].map(([key, value]) => [
key,
_exportMatcherFromTable(value)
])
) : Object.fromEntries(table[property].entries());
}
return obj;
}
function exportMatcher(matcher) {
return _exportMatcherFromTable(matcher.ctx.table);
}
function _createTableFromExport(matcherExport) {
const table = {};
for (const property in matcherExport) {
table[property] = property === "dynamic" ? new Map(
Object.entries(matcherExport[property]).map(([key, value]) => [
key,
_createTableFromExport(value)
])
) : new Map(
Object.entries(matcherExport[property])
);
}
return table;
}
function createMatcherFromExport(matcherExport) {
return _createMatcher(_createTableFromExport(matcherExport));
}
function _matchRoutes(path, table, strictTrailingSlash) {
if (strictTrailingSlash !== true && path.endsWith("/")) {
path = path.slice(0, -1) || "/";
}
const matches = [];
for (const [key, value] of _sortRoutesMap(table.wildcard)) {
if (path === key || path.startsWith(key + "/")) {
matches.push(value);
}
}
for (const [key, value] of _sortRoutesMap(table.dynamic)) {
if (path.startsWith(key + "/")) {
const subPath = "/" + path.slice(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 _sortRoutesMap(m) {
return [...m.entries()].sort((a, b) => a[0].length - b[0].length);
}
function _routerNodeToTable(initialPath, initialNode) {
const table = _createRouteTable();
function _addNode(path, node) {
if (path) {
if (node.type === NODE_TYPES.NORMAL && !(path.includes("*") || path.includes(":"))) {
if (node.data) {
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;
}
exports.NODE_TYPES = NODE_TYPES;
exports.createMatcherFromExport = createMatcherFromExport;
exports.createRouter = createRouter;
exports.exportMatcher = exportMatcher;
exports.toRouteMatcher = toRouteMatcher;

86
node_modules/radix3/dist/index.d.cts generated vendored Normal file
View File

@@ -0,0 +1,86 @@
declare const NODE_TYPES: {
NORMAL: 0;
WILDCARD: 1;
PLACEHOLDER: 2;
};
type _NODE_TYPES = typeof NODE_TYPES;
type NODE_TYPE = _NODE_TYPES[keyof _NODE_TYPES];
type _RadixNodeDataObject = {
params?: never;
[key: string]: any;
};
type RadixNodeData<T extends _RadixNodeDataObject = _RadixNodeDataObject> = T;
type MatchedRoute<T extends RadixNodeData = RadixNodeData> = Omit<T, "params"> & {
params?: Record<string, any>;
};
interface RadixNode<T extends RadixNodeData = RadixNodeData> {
type: NODE_TYPE;
maxDepth: number;
parent: RadixNode<T> | null;
children: Map<string, RadixNode<T>>;
data: RadixNodeData | null;
paramName: string | null;
wildcardChildNode: RadixNode<T> | null;
placeholderChildren: RadixNode<T>[];
}
interface RadixRouterOptions {
strictTrailingSlash?: boolean;
routes?: Record<string, any>;
}
interface RadixRouterContext<T extends RadixNodeData = RadixNodeData> {
options: RadixRouterOptions;
rootNode: RadixNode<T>;
staticRoutesMap: Record<string, RadixNode>;
}
interface RadixRouter<T extends RadixNodeData = RadixNodeData> {
ctx: RadixRouterContext<T>;
/**
* Perform lookup of given path in radix tree
* @param path - the path to search for
*
* @returns The data that was originally inserted into the tree
*/
lookup(path: string): MatchedRoute<T> | null;
/**
* Perform an insert into the radix tree
* @param path - the prefix to match
* @param data - the associated data to path
*
*/
insert(path: string, data: T): void;
/**
* Perform a remove on the tree
* @param { string } data.path - the route to match
*
* @returns A boolean signifying if the remove was successful or not
*/
remove(path: string): boolean;
}
interface MatcherExport {
dynamic: Map<string, MatcherExport>;
wildcard: Map<string, {
pattern: string;
}>;
static: Map<string, {
pattern: string;
}>;
}
declare function createRouter<T extends RadixNodeData = RadixNodeData>(options?: RadixRouterOptions): RadixRouter<T>;
interface RouteTable {
static: Map<string, RadixNodeData | null>;
wildcard: Map<string, RadixNodeData | null>;
dynamic: Map<string, RouteTable>;
}
interface RouteMatcher {
ctx: {
table: RouteTable;
};
matchAll: (path: string) => RadixNodeData[];
}
declare function toRouteMatcher(router: RadixRouter): RouteMatcher;
declare function exportMatcher(matcher: RouteMatcher): MatcherExport;
declare function createMatcherFromExport(matcherExport: MatcherExport): RouteMatcher;
export { type MatchedRoute, type MatcherExport, type NODE_TYPE, NODE_TYPES, type RadixNode, type RadixNodeData, type RadixRouter, type RadixRouterContext, type RadixRouterOptions, type RouteMatcher, type RouteTable, createMatcherFromExport, createRouter, exportMatcher, toRouteMatcher };

86
node_modules/radix3/dist/index.d.mts generated vendored Normal file
View File

@@ -0,0 +1,86 @@
declare const NODE_TYPES: {
NORMAL: 0;
WILDCARD: 1;
PLACEHOLDER: 2;
};
type _NODE_TYPES = typeof NODE_TYPES;
type NODE_TYPE = _NODE_TYPES[keyof _NODE_TYPES];
type _RadixNodeDataObject = {
params?: never;
[key: string]: any;
};
type RadixNodeData<T extends _RadixNodeDataObject = _RadixNodeDataObject> = T;
type MatchedRoute<T extends RadixNodeData = RadixNodeData> = Omit<T, "params"> & {
params?: Record<string, any>;
};
interface RadixNode<T extends RadixNodeData = RadixNodeData> {
type: NODE_TYPE;
maxDepth: number;
parent: RadixNode<T> | null;
children: Map<string, RadixNode<T>>;
data: RadixNodeData | null;
paramName: string | null;
wildcardChildNode: RadixNode<T> | null;
placeholderChildren: RadixNode<T>[];
}
interface RadixRouterOptions {
strictTrailingSlash?: boolean;
routes?: Record<string, any>;
}
interface RadixRouterContext<T extends RadixNodeData = RadixNodeData> {
options: RadixRouterOptions;
rootNode: RadixNode<T>;
staticRoutesMap: Record<string, RadixNode>;
}
interface RadixRouter<T extends RadixNodeData = RadixNodeData> {
ctx: RadixRouterContext<T>;
/**
* Perform lookup of given path in radix tree
* @param path - the path to search for
*
* @returns The data that was originally inserted into the tree
*/
lookup(path: string): MatchedRoute<T> | null;
/**
* Perform an insert into the radix tree
* @param path - the prefix to match
* @param data - the associated data to path
*
*/
insert(path: string, data: T): void;
/**
* Perform a remove on the tree
* @param { string } data.path - the route to match
*
* @returns A boolean signifying if the remove was successful or not
*/
remove(path: string): boolean;
}
interface MatcherExport {
dynamic: Map<string, MatcherExport>;
wildcard: Map<string, {
pattern: string;
}>;
static: Map<string, {
pattern: string;
}>;
}
declare function createRouter<T extends RadixNodeData = RadixNodeData>(options?: RadixRouterOptions): RadixRouter<T>;
interface RouteTable {
static: Map<string, RadixNodeData | null>;
wildcard: Map<string, RadixNodeData | null>;
dynamic: Map<string, RouteTable>;
}
interface RouteMatcher {
ctx: {
table: RouteTable;
};
matchAll: (path: string) => RadixNodeData[];
}
declare function toRouteMatcher(router: RadixRouter): RouteMatcher;
declare function exportMatcher(matcher: RouteMatcher): MatcherExport;
declare function createMatcherFromExport(matcherExport: MatcherExport): RouteMatcher;
export { type MatchedRoute, type MatcherExport, type NODE_TYPE, NODE_TYPES, type RadixNode, type RadixNodeData, type RadixRouter, type RadixRouterContext, type RadixRouterOptions, type RouteMatcher, type RouteTable, createMatcherFromExport, createRouter, exportMatcher, toRouteMatcher };

86
node_modules/radix3/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,86 @@
declare const NODE_TYPES: {
NORMAL: 0;
WILDCARD: 1;
PLACEHOLDER: 2;
};
type _NODE_TYPES = typeof NODE_TYPES;
type NODE_TYPE = _NODE_TYPES[keyof _NODE_TYPES];
type _RadixNodeDataObject = {
params?: never;
[key: string]: any;
};
type RadixNodeData<T extends _RadixNodeDataObject = _RadixNodeDataObject> = T;
type MatchedRoute<T extends RadixNodeData = RadixNodeData> = Omit<T, "params"> & {
params?: Record<string, any>;
};
interface RadixNode<T extends RadixNodeData = RadixNodeData> {
type: NODE_TYPE;
maxDepth: number;
parent: RadixNode<T> | null;
children: Map<string, RadixNode<T>>;
data: RadixNodeData | null;
paramName: string | null;
wildcardChildNode: RadixNode<T> | null;
placeholderChildren: RadixNode<T>[];
}
interface RadixRouterOptions {
strictTrailingSlash?: boolean;
routes?: Record<string, any>;
}
interface RadixRouterContext<T extends RadixNodeData = RadixNodeData> {
options: RadixRouterOptions;
rootNode: RadixNode<T>;
staticRoutesMap: Record<string, RadixNode>;
}
interface RadixRouter<T extends RadixNodeData = RadixNodeData> {
ctx: RadixRouterContext<T>;
/**
* Perform lookup of given path in radix tree
* @param path - the path to search for
*
* @returns The data that was originally inserted into the tree
*/
lookup(path: string): MatchedRoute<T> | null;
/**
* Perform an insert into the radix tree
* @param path - the prefix to match
* @param data - the associated data to path
*
*/
insert(path: string, data: T): void;
/**
* Perform a remove on the tree
* @param { string } data.path - the route to match
*
* @returns A boolean signifying if the remove was successful or not
*/
remove(path: string): boolean;
}
interface MatcherExport {
dynamic: Map<string, MatcherExport>;
wildcard: Map<string, {
pattern: string;
}>;
static: Map<string, {
pattern: string;
}>;
}
declare function createRouter<T extends RadixNodeData = RadixNodeData>(options?: RadixRouterOptions): RadixRouter<T>;
interface RouteTable {
static: Map<string, RadixNodeData | null>;
wildcard: Map<string, RadixNodeData | null>;
dynamic: Map<string, RouteTable>;
}
interface RouteMatcher {
ctx: {
table: RouteTable;
};
matchAll: (path: string) => RadixNodeData[];
}
declare function toRouteMatcher(router: RadixRouter): RouteMatcher;
declare function exportMatcher(matcher: RouteMatcher): MatcherExport;
declare function createMatcherFromExport(matcherExport: MatcherExport): RouteMatcher;
export { type MatchedRoute, type MatcherExport, type NODE_TYPE, NODE_TYPES, type RadixNode, type RadixNodeData, type RadixRouter, type RadixRouterContext, type RadixRouterOptions, type RouteMatcher, type RouteTable, createMatcherFromExport, createRouter, exportMatcher, toRouteMatcher };

262
node_modules/radix3/dist/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,262 @@
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) {
if (node && node.placeholderChildren.length > 1) {
const remaining = sections.length - i;
node = node.placeholderChildren.find((c) => c.maxDepth === remaining) || null;
} else {
node = node.placeholderChildren[0] || null;
}
if (!node) {
break;
}
if (node.paramName) {
params[node.paramName] = section;
}
paramsFound = true;
} else {
node = nextNode;
}
}
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;
const matchedNodes = [node];
for (const section of sections) {
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.placeholderChildren.push(childNode);
isStaticRoute = false;
} else if (type === NODE_TYPES.WILDCARD) {
node.wildcardChildNode = childNode;
childNode.paramName = section.slice(
3
/* "**:" */
) || "_";
isStaticRoute = false;
}
matchedNodes.push(childNode);
node = childNode;
}
}
for (const [depth, node2] of matchedNodes.entries()) {
node2.maxDepth = Math.max(matchedNodes.length - depth, node2.maxDepth || 0);
}
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 (const section of sections) {
node = node.children.get(section);
if (!node) {
return success;
}
}
if (node.data) {
const lastSection = sections.at(-1) || "";
node.data = null;
if (Object.keys(node.children).length === 0 && node.parent) {
node.parent.children.delete(lastSection);
node.parent.wildcardChildNode = null;
node.parent.placeholderChildren = [];
}
success = true;
}
return success;
}
function createRadixNode(options = {}) {
return {
type: options.type || NODE_TYPES.NORMAL,
maxDepth: 0,
parent: options.parent || null,
children: /* @__PURE__ */ new Map(),
data: options.data || null,
paramName: options.paramName || null,
wildcardChildNode: null,
placeholderChildren: []
};
}
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, router.ctx.options.strictTrailingSlash);
}
function _createMatcher(table, strictTrailingSlash) {
return {
ctx: { table },
matchAll: (path) => _matchRoutes(path, table, strictTrailingSlash)
};
}
function _createRouteTable() {
return {
static: /* @__PURE__ */ new Map(),
wildcard: /* @__PURE__ */ new Map(),
dynamic: /* @__PURE__ */ new Map()
};
}
function _exportMatcherFromTable(table) {
const obj = /* @__PURE__ */ Object.create(null);
for (const property in table) {
obj[property] = property === "dynamic" ? Object.fromEntries(
[...table[property].entries()].map(([key, value]) => [
key,
_exportMatcherFromTable(value)
])
) : Object.fromEntries(table[property].entries());
}
return obj;
}
function exportMatcher(matcher) {
return _exportMatcherFromTable(matcher.ctx.table);
}
function _createTableFromExport(matcherExport) {
const table = {};
for (const property in matcherExport) {
table[property] = property === "dynamic" ? new Map(
Object.entries(matcherExport[property]).map(([key, value]) => [
key,
_createTableFromExport(value)
])
) : new Map(
Object.entries(matcherExport[property])
);
}
return table;
}
function createMatcherFromExport(matcherExport) {
return _createMatcher(_createTableFromExport(matcherExport));
}
function _matchRoutes(path, table, strictTrailingSlash) {
if (strictTrailingSlash !== true && path.endsWith("/")) {
path = path.slice(0, -1) || "/";
}
const matches = [];
for (const [key, value] of _sortRoutesMap(table.wildcard)) {
if (path === key || path.startsWith(key + "/")) {
matches.push(value);
}
}
for (const [key, value] of _sortRoutesMap(table.dynamic)) {
if (path.startsWith(key + "/")) {
const subPath = "/" + path.slice(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 _sortRoutesMap(m) {
return [...m.entries()].sort((a, b) => a[0].length - b[0].length);
}
function _routerNodeToTable(initialPath, initialNode) {
const table = _createRouteTable();
function _addNode(path, node) {
if (path) {
if (node.type === NODE_TYPES.NORMAL && !(path.includes("*") || path.includes(":"))) {
if (node.data) {
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, createMatcherFromExport, createRouter, exportMatcher, toRouteMatcher };

52
node_modules/radix3/package.json generated vendored Normal file
View File

@@ -0,0 +1,52 @@
{
"name": "radix3",
"version": "1.1.2",
"description": "Lightweight and fast router for JavaScript based on Radix Tree",
"repository": "unjs/radix3",
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.cjs",
"import": "./dist/index.mjs"
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"bench": "node ./benchmark/direct.mjs",
"bench:http": "node ./benchmark/http.mjs",
"bench:profile": "0x -o -D benchmark/.profile -- node ./benchmark/direct.mjs",
"build": "unbuild",
"dev": "vitest",
"lint": "eslint --ext .ts,.mjs . && prettier -c src tests",
"lint:fix": "eslint --fix --ext .ts,.mjs . && prettier -w src tests",
"playground": "pnpm jiti ./playground.ts",
"release": "pnpm test && pnpm build && changelogen --release && git push --follow-tags && npm publish",
"test": "pnpm lint && pnpm test:types && vitest run",
"test:types": "tsc --noEmit"
},
"devDependencies": {
"0x": "^5.7.0",
"@vitest/coverage-v8": "^1.4.0",
"autocannon": "^7.15.0",
"benchmark": "^2.1.4",
"changelogen": "^0.5.5",
"eslint": "^8.57.0",
"eslint-config-unjs": "^0.2.1",
"jiti": "^1.21.0",
"listhen": "^1.7.2",
"prettier": "^3.2.5",
"standard-version": "^9.5.0",
"typescript": "^5.4.3",
"unbuild": "^2.0.0",
"vitest": "^1.4.0"
},
"packageManager": "pnpm@8.15.5"
}