-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
121 lines (117 loc) · 3.12 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
112
113
114
115
116
117
118
119
120
121
import {parse} from 'url';
const DEFAULT_METHOD = 'GET';
function createRouter(Target, options = {}) {
const methods = options.methods || [
'GET',
'POST',
'PUT',
'DELETE'
];
return (...args) => {
const target = new Target(...args);
if (!target._routes) {
throw new Error(`${Target.name} has no route connected`);
}
const routes = {};
for (const method of methods) {
routes[method] = [];
}
for (const route of target._routes) {
let method = route.method;
if (method === '*') {
method = methods;
} else if (typeof method === 'string') {
method = [method];
}
for (let key of method) {
key = key.toUpperCase();
if (!routes[key]) {
throw new Error(`${key} method is not allowed`);
}
routes[key].push(route);
}
}
return (req, res, next) => {
const method = req.method || DEFAULT_METHOD;
const path = req.path || parse(req.url).pathname;
if (routes[method]) {
for (const {matcher, middleware, fn} of routes[method]) {
const params = matcher(path);
if (params) {
req.params = params;
let idx = 0;
next = () => {
if (idx === middleware.length) {
Reflect.apply(fn, target, [req, res]);
} else {
middleware[idx++](req, res, next);
}
};
next();
return;
}
}
}
if (typeof next === 'function') {
next();
}
};
};
}
export function router(...args) {
if (typeof args[0] === 'function') {
return createRouter(...args);
}
return (Target) => createRouter(Target, ...args);
}
export function route(matcher, method = DEFAULT_METHOD, ...middleware) {
if (typeof method === 'function') {
middleware.unshift(method);
method = DEFAULT_METHOD;
}
return (target, key, descriptor) => {
let m;
if (typeof matcher === 'string') {
const components = [];
const names = [];
for (let component of matcher.split('/')) {
if (component[0] === ':') {
names.push(component.slice(1));
component = '([^/]*)';
}
components.push(component);
}
if (names.length) {
const re = new RegExp(`^${components.join('/')}$`);
m = (path) => {
const matches = re.exec(path);
if (matches) {
const params = {};
for (let i = 0, len = names.length; i < len; ++i) {
params[names[i]] = matches[i + 1];
}
return params;
}
return null;
};
} else {
m = (path) => path === matcher ?
{} :
null;
}
} else if (matcher instanceof RegExp) {
m = (path) => matcher.exec(path);
} else if (typeof matcher === 'function') {
m = matcher;
} else {
throw new Error('matcher is must be function');
}
target._routes = target._routes || [];
target._routes.push({
fn: descriptor.value,
matcher: m,
method,
middleware
});
};
}