UNPKG

@tscircuit/routematch

Version:

TypeScript route matcher with Next.js-style dynamic routes

194 lines (139 loc) 3.94 kB
# @tscircuit/routematch A TypeScript route matcher with Next.js-style dynamic routes ## Features - 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'] } } ``` ## Route Patterns ### Static Routes ```typescript '/about' '/api/health' ``` ### Dynamic Routes ```typescript '/users/[id]' // matches /users/123 '/posts/[slug]' // matches /posts/hello-world ``` ### Catch-all Routes ```typescript '/api/[...path]' // matches /api/v1/users/123 '/docs/[...slug]' // matches /docs/getting-started/installation ``` ### Optional Routes ```typescript '/blog/[[...slug]]' // matches /blog and /blog/category/post ``` ## API Reference ### `createRouteMatcher(routes: string[])` 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' } } ``` ### `isValidRoute(route: string): boolean` 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) ]) ``` ## Development ### Build ```bash bun run build ``` ### Test ```bash bun test ``` ### Development with Hot Reload ```bash bun --hot lib/index.ts ``` ## Examples ### Basic Web Server ```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)) } }) ``` ### Express-like Router ```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' } ``` ## License MIT