-
-
Notifications
You must be signed in to change notification settings - Fork 80
/
IttyRouter.ts
57 lines (54 loc) · 2.36 KB
/
IttyRouter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import {
IRequest,
IttyRouterOptions,
IttyRouterType,
RequestHandler,
RequestLike,
} from './types'
export const IttyRouter = <
RequestType extends IRequest = IRequest,
Args extends any[] = any[],
ResponseType = any,
>({ base = '', routes = [], ...other }: IttyRouterOptions = {}): IttyRouterType<RequestType, Args, ResponseType> =>
// @ts-ignore
({
__proto__: new Proxy({}, {
// @ts-expect-error (we're adding an expected prop "path" to the get)
get: (target: any, prop: string, receiver: object, path: string) =>
(route: string, ...handlers: RequestHandler<RequestType, Args>[]) =>
routes.push(
[
prop.toUpperCase(),
RegExp(`^${(path = (base + route)
.replace(/\/+(\/|$)/g, '$1')) // strip double & trailing splash
.replace(/(\/?\.?):(\w+)\+/g, '($1(?<$2>*))') // greedy params
.replace(/(\/?\.?):(\w+)/g, '($1(?<$2>[^$1/]+?))') // named params and image format
.replace(/\./g, '\\.') // dot in path
.replace(/(\/?)\*/g, '($1.*)?') // wildcard
}/*$`),
// @ts-ignore
handlers, // embed handlers
path, // embed clean route path
]
) && receiver
}),
routes,
...other,
async fetch (request: RequestLike, ...args) {
let response,
match,
url = new URL(request.url),
query: Record<string, any> = request.query = { __proto__: null }
// 1. parse query params
for (let [k, v] of url.searchParams)
query[k] = query[k] ? ([] as string[]).concat(query[k], v) : v
// 2. then test routes
for (let [method, regex, handlers, path] of routes)
if ((method == request.method || method == 'ALL') && (match = url.pathname.match(regex))) {
request.params = match.groups || {} // embed params in request
request.route = path // embed route path in request
for (let handler of handlers)
if ((response = await handler(request.proxy ?? request, ...args)) != null) return response
}
},
})