-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
111 lines (87 loc) · 2.33 KB
/
index.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
'use strict';
const Route = require('./route');
const methods = [
'HEAD',
'OPTIONS',
'GET',
'PUT',
'PATCH',
'POST',
'DELETE'
];
class Router {
constructor() {
this._stack = [];
}
register(path, methods, middleware) {
const stack = this._stack;
const route = new Route(path, methods, middleware);
if (methods.length > 0 || stack.length === 0) {
// If we don't have parameters, put before any with same route nesting level but with parameters
let added = false;
if (route.paramNames.length === 0) {
const routeNestingLevel = route.path.toString().split('/').length;
added = stack.some((m, i) => {
const mNestingLevel = m.path.toString().split('/').length;
const isParamRoute = Boolean(m.paramNames.length);
if (routeNestingLevel === mNestingLevel && isParamRoute) {
return stack.splice(i, 0, route);
}
return false;
});
}
if (!added) {
stack.push(route);
}
}
return route;
}
routes() {
return ctx => {
const path = ctx.path;
const matched = this.match(path, ctx.method.toLowerCase());
let next;
ctx.matched = matched.path;
if (matched.pathAndMethod.length > 0) {
const route = matched.pathAndMethod[0];
const params = ctx.request.params || {};
// Extract the `params` from the route
Object.defineProperty(ctx.request, 'params', {enumerable: true, writable: true, value: Object.assign(params, route.getParams(path))});
next = route.stack.reduce((promise, fn) => {
return promise.then(result => fn(ctx, result));
}, Promise.resolve());
}
return next;
};
}
match(path, method) {
const stack = this._stack;
const matched = {
path: [],
pathAndMethod: [],
route: false
};
for (const route of stack) {
if (route.match(path)) {
matched.path.push(route);
if (route.methods.length === 0 || route.methods.indexOf(method) !== -1) {
matched.pathAndMethod.push(route);
if (route.methods.length > 0) {
matched.route = true;
}
}
}
}
return matched;
}
}
methods.forEach(method => {
method = method.toLowerCase();
Router.prototype[method] = function (path) {
const middleware = Array.prototype.slice.call(arguments, 1);
this.register(path, [method], middleware);
return this;
};
});
Router.prototype.del = Router.prototype.delete;
module.exports = () => new Router();