@tscircuit/routematch
Version:
TypeScript route matcher with Next.js-style dynamic routes
194 lines (139 loc) • 3.94 kB
Markdown
A TypeScript route matcher with Next.js-style dynamic routes
- Next.js-style dynamic routes (`[id]`, `[...slug]`, `[[optional]]`)
- Server-side and client-side compatible
- TypeScript support with full type safety
- Zero dependencies
- High performance route matching with priority sorting
- URL decoding support
- Comprehensive test coverage
## Installation
```bash
bun install @tscircuit/routematch
```
## Quick Start
```typescript
import createRouteMatcher from '@tscircuit/routematch'
const routeMatcher = createRouteMatcher([
'/health',
'/api/users/[id]',
'/api/posts/[...slug]',
'/blog/[[...path]]'
])
// Match routes
const result = routeMatcher('/api/users/123')
// { matchedRoute: '/api/users/[id]', routeParams: { id: '123' } }
const catchAll = routeMatcher('/api/posts/2023/hello-world')
// { matchedRoute: '/api/posts/[...slug]', routeParams: { slug: ['2023', 'hello-world'] } }
```
```typescript
'/about'
'/api/health'
```
```typescript
'/users/[id]' // matches /users/123
'/posts/[slug]' // matches /posts/hello-world
```
```typescript
'/api/[...path]' // matches /api/v1/users/123
'/docs/[...slug]' // matches /docs/getting-started/installation
```
```typescript
'/blog/[[...slug]]' // matches /blog and /blog/category/post
```
Creates a route matcher function from an array of route patterns.
**Parameters:**
- `routes`: Array of route pattern strings
**Returns:** A matcher function that takes a path and returns a match result or `null`
**Example:**
```typescript
const matcher = createRouteMatcher(['/api/[id]', '/health'])
const result = matcher('/api/123') // { matchedRoute: '/api/[id]', routeParams: { id: '123' } }
```
Validates if a route pattern is syntactically correct.
```typescript
isValidRoute('/api/[id]') // true
isValidRoute('/api/[...slug]') // true
```
### `getRouteParameters(route: string): string[]`
Extracts parameter names from a route pattern.
```typescript
getRouteParameters('/api/[id]/posts/[slug]') // ['id', 'slug']
getRouteParameters('/docs/[...path]') // ['path']
```
## Route Priority
Routes are matched in priority order:
1. **Exact matches** (highest priority)
2. **Fewer parameters** (higher priority)
3. **Catch-all routes** (lowest priority)
```typescript
const matcher = createRouteMatcher([
'/api/[id]/[action]', // Lower priority (2 params)
'/api/[id]/edit', // Higher priority (1 param + exact)
'/api/users' // Highest priority (exact match)
])
```
```bash
bun run build
```
```bash
bun test
```
```bash
bun --hot lib/index.ts
```
```typescript
import { serve } from 'bun'
import createRouteMatcher from '@tscircuit/routematch'
const routeMatcher = createRouteMatcher([
'/',
'/api/users/[id]',
'/api/posts/[...slug]'
])
serve({
port: 3000,
fetch(request) {
const url = new URL(request.url)
const match = routeMatcher(url.pathname)
if (!match) {
return new Response('Not Found', { status: 404 })
}
return new Response(JSON.stringify(match))
}
})
```
```typescript
import createRouteMatcher from '@tscircuit/routematch'
const routes = {
'/': () => 'Home',
'/users/[id]': ({ id }) => `User: ${id}`,
'/posts/[...slug]': ({ slug }) => `Post: ${slug.join('/')}`
}
const routeMatcher = createRouteMatcher(Object.keys(routes))
function handleRequest(path: string) {
const match = routeMatcher(path)
if (match) {
const handler = routes[match.matchedRoute]
return handler(match.routeParams)
}
return 'Not Found'
}
```
MIT