Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: rewrite library #107

Merged
merged 15 commits into from
Jul 4, 2024
205 changes: 92 additions & 113 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,81 +1,116 @@
# 🌳 radix3
# 🌳 rou3

[![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]
<!-- automd:badges -->

Lightweight and fast router for JavaScript based on [Radix Tree](https://en.wikipedia.org/wiki/Radix_tree).
[![npm version](https://img.shields.io/npm/v/rou3)](https://npmjs.com/package/rou3)
[![npm downloads](https://img.shields.io/npm/dm/rou3)](https://npmjs.com/package/rou3)

<!-- /automd -->

Lightweight and fast router for JavaScript.

> [!NOTE]
> Radix3 migrated to Rou3! See [#108](https://github.com/unjs/radix3/issues/108) for notes and [radix3 branch](https://github.com/unjs/rou3/tree/radix3) for legacy codebase.

## Usage

**Install package:**
**Install:**

<!-- automd:pm-install -->

```sh
# ✨ Auto-detect
npx nypm install rou3

# npm
npm i radix3
npm install rou3

# yarn
yarn add radix3
yarn add rou3

# pnpm
pnpm i radix3
pnpm install rou3

# bun
bun install rou3
```

<!-- /automd -->

**Import:**

```js
// ESM
import { createRouter } from "radix3";
<!-- automd:jsimport cdn cjs src="./src/index.ts"-->

**ESM** (Node.js, Bun)

// CJS
const { createRouter } = require("radix3");
```js
import {
createRouter,
addRoute,
findRoute,
removeRoute,
matchAllRoutes,
} from "rou3";
```

**Create a router instance and insert routes:**
**CommonJS** (Legacy Node.js)

```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" });
const {
createRouter,
addRoute,
findRoute,
removeRoute,
matchAllRoutes,
} = require("rou3");
```

**Match route to access matched data:**
**CDN** (Deno, Bun and Browsers)

```js
router.lookup("/path");
// { payload: 'this path' }
import {
createRouter,
addRoute,
findRoute,
removeRoute,
matchAllRoutes,
} from "https://esm.sh/rou3";
```

router.lookup("/path/fooval");
// { payload: 'named route', params: { name: 'fooval' } }
<!-- /automd -->

router.lookup("/path/foo/bar/baz");
// { payload: 'wildcard route' }
**Create a router instance and insert routes:**

router.lookup("/");
// null (no route matched for/)
```
```js
import { createRouter, addRoute } from "rou3";

## Methods
const router = createRouter(/* options */);

### `router.insert(path, data)`
addRoute(router, "/path", "GET", { payload: "this path" });
addRoute(router, "/path/:name", "GET", { payload: "named route" });
addRoute(router, "/path/foo/**", "GET", { payload: "wildcard route" });
addRoute(router, "/path/foo/**:name", "GET", {
payload: "named wildcard route",
});
```

`path` can be static or using `:placeholder` or `**` for wildcard paths.
**Match route to access matched data:**

The `data` object will be returned on matching params. It should be an object like `{ handler }` and not containing reserved keyword `params`.
```js
// Returns { payload: 'this path' }
findRoute(router, "/path", "GET");

### `router.lookup(path)`
// Returns { payload: 'named route', params: { name: 'fooval' } }
findRoute(router, "/path/fooval", "GET");

Returns matched data for `path` with optional `params` key if mached route using placeholders.
// Returns { payload: 'wildcard route' }
findRoute(router, "/path/foo/bar/baz", "GET");

### `router.remove(path)`
// Returns undefined (no route matched for/)
findRoute(router, "/", "GET");
```

Remove route matching `path`.
## Methods

## Options

Expand All @@ -84,88 +119,32 @@ 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
## Performance

It is also possible to export and then rehydrate a matcher from pre-compiled rules.
See [benchmark](./benchmark).

```ts
import { exportMatcher, createMatcherFromExport } from "radix3";
## License

// Assuming you already have a matcher
// you can export this to a JSON-type object
const json = exportMatcher(matcher);
<!-- automd:contributors license=MIT author="pi0" -->

// and then rehydrate this later
const newMatcher = createMatcherFromExport(json);
Published under the [MIT](https://github.com/unjs/h3/blob/main/LICENSE) license.
Made by [@pi0](https://github.com/pi0) and [community](https://github.com/unjs/h3/graphs/contributors) 💛
<br><br>
<a href="https://github.com/unjs/h3/graphs/contributors">
<img src="https://contrib.rocks/image?repo=unjs/h3" />
</a>

const matches = newMatcher.matchAll("/foo/bar/baz");
```
<!-- /automd -->

## Performance
<!-- automd:with-automd -->

See [benchmark](./benchmark).
---

## License
_🤖 auto updated with [automd](https://automd.unjs.io)_

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
<!-- /automd -->
104 changes: 0 additions & 104 deletions benchmark/README.md

This file was deleted.

21 changes: 21 additions & 0 deletions benchmark/bench.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { bench, group, run } from 'mitata'
import "./test.mjs"
import { routers } from './routers.mjs'
import { requests, routes } from './input.mjs'

const withParams = !process.argv.includes('--no-params')

// Benchmark all routers
group(`All requests (match params: ${withParams})`, () => {
for (const name in routers) {
const router = new routers[name](routes, withParams)
router.init()
bench(name, () => {
for (const request of requests) {
router.match(request)
}
})
}
})

run({})
Loading
Loading