Big News: Socket Selected for OpenAI's Cybersecurity Grant Program.Details
Socket
Book a DemoSign in
Socket

radix3

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

radix3 - npm Package Compare versions

Comparing version
1.1.0
to
1.1.1
+85
dist/index.d.cts
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;
parent: RadixNode<T> | null;
children: Map<string, RadixNode<T>>;
data: RadixNodeData | null;
paramName: string | null;
wildcardChildNode: RadixNode<T> | null;
placeholderChildNode: RadixNode<T> | null;
}
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 };
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;
parent: RadixNode<T> | null;
children: Map<string, RadixNode<T>>;
data: RadixNodeData | null;
paramName: string | null;
wildcardChildNode: RadixNode<T> | null;
placeholderChildNode: RadixNode<T> | null;
}
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 };
+28
-21

@@ -23,3 +23,2 @@ 'use strict';

ctx,
// @ts-ignore
lookup: (path) => lookup(ctx, normalizeTrailingSlash(path)),

@@ -48,12 +47,14 @@ insert: (path, data) => insert(ctx, normalizeTrailingSlash(path), data),

const nextNode = node.children.get(section);
if (nextNode !== void 0) {
node = nextNode;
} else {
if (nextNode === void 0) {
node = node.placeholderChildNode;
if (node !== null) {
params[node.paramName] = section;
if (node === null) {
break;
} else {
if (node.paramName) {
params[node.paramName] = section;
}
paramsFound = true;
} else {
break;
}
} else {
node = nextNode;
}

@@ -122,9 +123,8 @@ }

if (node.data) {
const lastSection = sections[sections.length - 1];
const lastSection = sections.at(-1) || "";
node.data = null;
if (Object.keys(node.children).length === 0) {
const parentNode = node.parent;
parentNode.children.delete(lastSection);
parentNode.wildcardChildNode = null;
parentNode.placeholderChildNode = null;
if (Object.keys(node.children).length === 0 && node.parent) {
node.parent.children.delete(lastSection);
node.parent.wildcardChildNode = null;
node.parent.placeholderChildNode = null;
}

@@ -158,8 +158,8 @@ success = true;

const table = _routerNodeToTable("", router.ctx.rootNode);
return _createMatcher(table);
return _createMatcher(table, router.ctx.options.strictTrailingSlash);
}
function _createMatcher(table) {
function _createMatcher(table, strictTrailingSlash) {
return {
ctx: { table },
matchAll: (path) => _matchRoutes(path, table)
matchAll: (path) => _matchRoutes(path, table, strictTrailingSlash)
};

@@ -197,3 +197,5 @@ }

])
) : new Map(Object.entries(matcherExport[property]));
) : new Map(
Object.entries(matcherExport[property])
);
}

@@ -205,6 +207,9 @@ return table;

}
function _matchRoutes(path, table) {
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.startsWith(key)) {
if (path === key || path.startsWith(key + "/")) {
matches.push(value);

@@ -233,3 +238,5 @@ }

if (node.type === NODE_TYPES.NORMAL && !(path.includes("*") || path.includes(":"))) {
table.static.set(path, node.data);
if (node.data) {
table.static.set(path, node.data);
}
} else if (node.type === NODE_TYPES.WILDCARD) {

@@ -236,0 +243,0 @@ table.wildcard.set(path.replace("/**", ""), node.data);

@@ -71,4 +71,4 @@ declare const NODE_TYPES: {

interface RouteTable {
static: Map<string, RadixNodeData>;
wildcard: Map<string, RadixNodeData>;
static: Map<string, RadixNodeData | null>;
wildcard: Map<string, RadixNodeData | null>;
dynamic: Map<string, RouteTable>;

@@ -86,2 +86,2 @@ }

export { MatchedRoute, MatcherExport, NODE_TYPE, NODE_TYPES, RadixNode, RadixNodeData, RadixRouter, RadixRouterContext, RadixRouterOptions, RouteMatcher, RouteTable, createMatcherFromExport, createRouter, exportMatcher, toRouteMatcher };
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 };

@@ -21,3 +21,2 @@ const NODE_TYPES = {

ctx,
// @ts-ignore
lookup: (path) => lookup(ctx, normalizeTrailingSlash(path)),

@@ -46,12 +45,14 @@ insert: (path, data) => insert(ctx, normalizeTrailingSlash(path), data),

const nextNode = node.children.get(section);
if (nextNode !== void 0) {
node = nextNode;
} else {
if (nextNode === void 0) {
node = node.placeholderChildNode;
if (node !== null) {
params[node.paramName] = section;
if (node === null) {
break;
} else {
if (node.paramName) {
params[node.paramName] = section;
}
paramsFound = true;
} else {
break;
}
} else {
node = nextNode;
}

@@ -120,9 +121,8 @@ }

if (node.data) {
const lastSection = sections[sections.length - 1];
const lastSection = sections.at(-1) || "";
node.data = null;
if (Object.keys(node.children).length === 0) {
const parentNode = node.parent;
parentNode.children.delete(lastSection);
parentNode.wildcardChildNode = null;
parentNode.placeholderChildNode = null;
if (Object.keys(node.children).length === 0 && node.parent) {
node.parent.children.delete(lastSection);
node.parent.wildcardChildNode = null;
node.parent.placeholderChildNode = null;
}

@@ -156,8 +156,8 @@ success = true;

const table = _routerNodeToTable("", router.ctx.rootNode);
return _createMatcher(table);
return _createMatcher(table, router.ctx.options.strictTrailingSlash);
}
function _createMatcher(table) {
function _createMatcher(table, strictTrailingSlash) {
return {
ctx: { table },
matchAll: (path) => _matchRoutes(path, table)
matchAll: (path) => _matchRoutes(path, table, strictTrailingSlash)
};

@@ -195,3 +195,5 @@ }

])
) : new Map(Object.entries(matcherExport[property]));
) : new Map(
Object.entries(matcherExport[property])
);
}

@@ -203,6 +205,9 @@ return table;

}
function _matchRoutes(path, table) {
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.startsWith(key)) {
if (path === key || path.startsWith(key + "/")) {
matches.push(value);

@@ -231,3 +236,5 @@ }

if (node.type === NODE_TYPES.NORMAL && !(path.includes("*") || path.includes(":"))) {
table.static.set(path, node.data);
if (node.data) {
table.static.set(path, node.data);
}
} else if (node.type === NODE_TYPES.WILDCARD) {

@@ -234,0 +241,0 @@ table.wildcard.set(path.replace("/**", ""), node.data);

{
"name": "radix3",
"version": "1.1.0",
"version": "1.1.1",
"description": "Lightweight and fast router for JavaScript based on Radix Tree",

@@ -22,20 +22,2 @@ "repository": "unjs/radix3",

],
"devDependencies": {
"0x": "^5.5.0",
"@vitest/coverage-c8": "^0.30.1",
"autocannon": "^7.10.0",
"benchmark": "^2.1.4",
"changelogen": "^0.5.3",
"eslint": "^8.39.0",
"eslint-config-unjs": "^0.1.0",
"jiti": "^1.18.2",
"listhen": "^1.0.4",
"ohmyfetch": "^0.4.21",
"prettier": "^2.8.8",
"standard-version": "^9.5.0",
"typescript": "^5.0.4",
"unbuild": "^1.2.1",
"vitest": "^0.30.1"
},
"packageManager": "pnpm@7.32.2",
"scripts": {

@@ -51,4 +33,22 @@ "bench": "node ./benchmark/direct.mjs",

"release": "pnpm test && pnpm build && changelogen --release && git push --follow-tags && pnpm publish",
"test": "pnpm lint && vitest run"
}
"test": "pnpm lint && pnpm test:types && vitest run",
"test:types": "tsc --noEmit"
},
"devDependencies": {
"0x": "^5.7.0",
"@vitest/coverage-v8": "^1.3.1",
"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.2",
"unbuild": "^2.0.0",
"vitest": "^1.3.1"
},
"packageManager": "pnpm@8.15.4"
}
+29
-28

@@ -31,6 +31,6 @@ # 🌳 radix3

// ESM
import { createRouter } from 'radix3'
import { createRouter } from "radix3";
// CJS
const { createRouter } = require('radix3')
const { createRouter } = require("radix3");
```

@@ -41,8 +41,8 @@

```js
const router = createRouter(/* options */)
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' })
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" });
```

@@ -53,12 +53,12 @@

```js
router.lookup('/path')
router.lookup("/path");
// { payload: 'this path' }
router.lookup('/path/fooval')
router.lookup("/path/fooval");
// { payload: 'named route', params: { name: 'fooval' } }
router.lookup('/path/foo/bar/baz')
router.lookup("/path/foo/bar/baz");
// { payload: 'wildcard route' }
router.lookup('/')
router.lookup("/");
// null (no route matched for/)

@@ -91,5 +91,5 @@ ```

routes: {
'/foo': {}
}
})
"/foo": {},
},
});
```

@@ -105,17 +105,17 @@

```ts
import { createRouter, toRouteMatcher } from 'radix3'
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
}
})
"/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 matcher = toRouteMatcher(router);
const matches = matcher.matchAll('/foo/bar/baz')
const matches = matcher.matchAll("/foo/bar/baz");

@@ -140,12 +140,12 @@ // [

```ts
import { exportMatcher, createMatcherFromExport } from 'radix3'
import { exportMatcher, createMatcherFromExport } from "radix3";
// Assuming you already have a matcher
// you can export this to a JSON-type object
const json = exportMatcher(matcher)
const json = exportMatcher(matcher);
// and then rehydrate this later
const newMatcher = createMatcherFromExport(json)
const newMatcher = createMatcherFromExport(json);
const matches = newMatcher.matchAll('/foo/bar/baz')
const matches = newMatcher.matchAll("/foo/bar/baz");
```

@@ -165,2 +165,3 @@

<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/radix3?style=flat&colorA=18181B&colorB=F0DB4F

@@ -167,0 +168,0 @@ [npm-version-href]: https://npmjs.com/package/radix3

'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,
// @ts-ignore
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 (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.placeholderChildNode = childNode;
isStaticRoute = false;
} else if (type === NODE_TYPES.WILDCARD) {
node.wildcardChildNode = childNode;
childNode.paramName = section.slice(
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 (const section of sections) {
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;
parentNode.children.delete(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 _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) {
const matches = [];
for (const [key, value] of _sortRoutesMap(table.wildcard)) {
if (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(":"))) {
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;