-
Notifications
You must be signed in to change notification settings - Fork 2
/
app.js
129 lines (108 loc) · 3.34 KB
/
app.js
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
const response = require('./response')
const Method = method => req =>
req.method.toLowerCase() === method.toLowerCase()
const Connect = Method('connect')
const Delete = Method('delete')
const Get = Method('get')
const Head = Method('head')
const Options = Method('options')
const Patch = Method('patch')
const Post = Method('post')
const Put = Method('put')
const Trace = Method('trace')
const Header = (header, val) => req => req.headers.get(header) === val
const Host = host => Header('host', host.toLowerCase())
const Referrer = host => Header('referrer', host.toLowerCase())
const AddSlash = s => s.replace(/\/$/, "") + "/"
const LoadParams = (path, base) => req => {
const urlPath = req.url.replace(base, "")
var params = {}
var ParamValues = urlPath.split("/")
var Keys = path.split("/")
ParamValues.reverse()
Keys.reverse()
for (let key in Keys) {
const paramKey = Keys[key]
if (paramKey.includes(":")) {
params[paramKey.replace(':', '')] = ParamValues[key]
}
}
return params
}
const Path = regExp => req => {
const url = new URL(req.url)
const path = AddSlash(url.pathname)
const alphanum = new RegExp(/\:[\w\d]+/, "gi")
var expr = AddSlash(regExp)
const newExpr = expr.replace(alphanum, alphanum.source.toString())
if (expr != newExpr) {
expr = new RegExp(newExpr.replace(/\\:/g, ''))
}
const match = path.match(expr) || []
return match[0] === path
}
class App {
constructor(base) {
this.base = base ? base.replace(/\/$/, "") : ""
this.routes = []
}
handle(conditions, handler, params) {
this.routes.push({
conditions,
handler,
params
})
return this
}
connect(url, handler) {
return this.handle([Connect, Path(this.base + url)], handler, LoadParams(url, this.base))
}
delete(url, handler) {
return this.handle([Delete, Path(this.base + url)], handler, LoadParams(url, this.base))
}
get(url, handler) {
return this.handle([Get, Path(this.base + url)], handler, LoadParams(url, this.base))
}
head(url, handler) {
return this.handle([Head, Path(this.base + url)], handler, LoadParams(url, this.base))
}
options(url, handler) {
return this.handle([Options, Path(this.base + url)], handler, LoadParams(url, this.base))
}
patch(url, handler) {
return this.handle([Patch, Path(this.base + url)], handler, LoadParams(url, this.base))
}
post(url, handler) {
return this.handle([Post, Path(this.base + url)], handler, LoadParams(url, this.base))
}
put(url, handler) {
return this.handle([Put, Path(this.base + url)], handler, LoadParams(url, this.base))
}
trace(url, handler) {
return this.handle([Trace, Path(this.base + url)], handler, LoadParams(url, this.base))
}
all(handler) {
return this.handle([], handler, LoadParams(url, this.base))
}
render(req) {
const route = this.resolve(req)
if (route) {
var request = req
request['params'] = route.params(request)
return route.handler(request, response)
}
return response.error(404, "No such route found")
}
resolve(req) {
return this.routes.find(r => {
if (!r.conditions || (Array.isArray(r) && !r.conditions.length)) {
return true
}
if (typeof r.conditions === 'function') {
return r.conditions(req)
}
return r.conditions.every(c => c(req))
})
}
}
module.exports = App