-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.mjs
More file actions
72 lines (62 loc) · 2.53 KB
/
Copy pathapp.mjs
File metadata and controls
72 lines (62 loc) · 2.53 KB
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { isFn } from './util.mjs'
var routeRe = /\{([\w%.]+)([^}]?)\}|\\(\{)|[^{\\]+/g
, routeEsc = s => s.replace(/[.*+?^=!:${}()|\[\]\/\\]/g, '\\$&')
, App = opts => {
var methods = { DELETE: 'del', GET: 'get', PATCH: 'patch', POST: 'post', PUT: 'put', ...opts?.method }
, keys = Object.keys(methods)
, notAllowed = opts?.notAllowed || (req => ((req.resHeaders ??= {}).Allow = keys.join(', '), 405))
, app = (req, env, ctx) => (routers[req.method === 'HEAD' ? 'GET' : req.method]?.handle || notAllowed)(req, env, ctx)
, each = fn => (keys.forEach(method => fn(routers[method], method)), app)
, routers = app.routers = Object.create(null)
each((_, method) => app[methods[method]] = (routers[method] = Router(opts)).add)
app.all = (route, handler, _raw) => each(r => r.add(route, handler, _raw))
app.mount = (path, sub) => app.all(
path,
(req, env, ctx) => (req.path = req.path.slice((req.mount = path).length + 1) || '/', sub(req, env, ctx)),
routeEsc(path) + '(?:\\/.*|)'
)
app.use = (...fns) => each(r => r.use(...fns))
return app
}
, Router = opts => {
var re
, reStr = ''
, exts = { '*': '(.*)', '+': '(\\d+)', '/': '((?:[^/]+\\/)*)', ...opts?.extensions }
, groups = 1
, routes = []
return {
routes,
add(route, handler, _raw) {
var endSlot = routes.push(groups++, re = 0, route) - 2
reStr += (reStr ? '|(' : '(') + (_raw || route.replace(routeRe, (_, expr, ext, toEsc) =>
expr ? (routes.push(expr), groups++, exts[ext] || '([^/]+)') : routeEsc(toEsc || _)
)) + ')'
routes[endSlot] = routes.push(handler)
return this
},
use(...fns) {
routes.push(0, 2 + routes.length + fns.length, ...fns)
},
async handle(req, env, ctx) {
var match = req && (re || (re = RegExp('^\\/*(?:' + reStr + ')[\\/\\s]*$'))).exec(req.path || '')
if (!match) return opts?.notFound?.(req, env, ctx) ?? 404
// Handlers and middleware throw on error; the worker owns error -> response.
for (var end, m, res, pos = 0, len = routes.length, param = req.param ??= {}; pos < len; pos = end) {
end = routes[pos + 1]
if ((m = routes[pos++]) < 1) {
// Middleware: [0, end, ...fns]
for (; !res && ++pos < end; ) if ((res = await routes[pos](req, env, ctx))) end = len
} else if (match[m] != null) {
// Matched route: [group, end, routeStr, ...paramNames, handler]
req.route = routes[++pos]
for (end--; ++pos < end; ) param[routes[pos]] = decodeURIComponent(match[++m])
m = routes[pos]
res = isFn(m) ? await m(req, env, ctx) : m
end = len
}
}
return res
}
}
}
export { App, Router }