@ndiinginc/router 4.14.0 → 4.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/app.js +21 -17
- package/src/index.js +0 -9
- package/src/middleware/cors.js +1 -0
- package/src/node.js +2 -9
- package/src/router.js +62 -61
package/package.json
CHANGED
package/src/app.js
CHANGED
|
@@ -2,12 +2,9 @@ const http = require("http");
|
|
|
2
2
|
const { Router } = require("./router");
|
|
3
3
|
const { Request } = require("./request");
|
|
4
4
|
const { Response } = require("./response");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
IncomingMessage: Request,
|
|
9
|
-
ServerResponse: Response,
|
|
10
|
-
};
|
|
5
|
+
const { json } = require("./middleware/json");
|
|
6
|
+
const { cors } = require("./middleware/cors");
|
|
7
|
+
const { urlencoded } = require("./middleware/urlencoded");
|
|
11
8
|
|
|
12
9
|
class App extends Router {
|
|
13
10
|
/**
|
|
@@ -28,7 +25,6 @@ class App extends Router {
|
|
|
28
25
|
const promise = handlerPromise().catch((error) => {
|
|
29
26
|
if (!req.controller.signal.aborted) {
|
|
30
27
|
req.controller.abort(error);
|
|
31
|
-
} else {
|
|
32
28
|
}
|
|
33
29
|
});
|
|
34
30
|
try {
|
|
@@ -40,10 +36,10 @@ class App extends Router {
|
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
/**
|
|
43
|
-
* @param {Response} res
|
|
44
39
|
* @param {Error} err
|
|
40
|
+
* @param {Response} res
|
|
45
41
|
*/
|
|
46
|
-
fallback(
|
|
42
|
+
fallback(err, res) {
|
|
47
43
|
if (!res.writableEnded) {
|
|
48
44
|
if (!err) {
|
|
49
45
|
res.statusCode = 404;
|
|
@@ -65,12 +61,12 @@ class App extends Router {
|
|
|
65
61
|
* @param {Response} res
|
|
66
62
|
*/
|
|
67
63
|
async handle(req, res) {
|
|
68
|
-
const { params,
|
|
69
|
-
req.params =
|
|
64
|
+
const { params, handlers, errorHandlers } = this.find(req.method, req.path);
|
|
65
|
+
req.params = this.decodeParams(params);
|
|
70
66
|
let err;
|
|
71
67
|
try {
|
|
72
68
|
const handlerPromise = async () => {
|
|
73
|
-
for (const handler of handlers) {
|
|
69
|
+
for (const handler of Object.values(handlers)) {
|
|
74
70
|
if (res.writableEnded) break;
|
|
75
71
|
await handler(req, res);
|
|
76
72
|
}
|
|
@@ -83,7 +79,7 @@ class App extends Router {
|
|
|
83
79
|
} catch (error) {
|
|
84
80
|
err = error;
|
|
85
81
|
try {
|
|
86
|
-
for (const handler of errorHandlers) {
|
|
82
|
+
for (const handler of Object.values(errorHandlers)) {
|
|
87
83
|
if (res.writableEnded) break;
|
|
88
84
|
await handler(err, req, res);
|
|
89
85
|
}
|
|
@@ -91,7 +87,7 @@ class App extends Router {
|
|
|
91
87
|
err = new Error(error.message, { cause: err });
|
|
92
88
|
}
|
|
93
89
|
}
|
|
94
|
-
this.fallback(
|
|
90
|
+
this.fallback(err, res);
|
|
95
91
|
}
|
|
96
92
|
|
|
97
93
|
/**
|
|
@@ -99,13 +95,21 @@ class App extends Router {
|
|
|
99
95
|
* @returns {import('http').Server}
|
|
100
96
|
*/
|
|
101
97
|
listen(...args) {
|
|
102
|
-
const
|
|
103
|
-
|
|
98
|
+
const server = http.createServer(
|
|
99
|
+
{
|
|
100
|
+
IncomingMessage: Request,
|
|
101
|
+
ServerResponse: Response,
|
|
102
|
+
},
|
|
103
|
+
(req, res) => this.handle(req, res),
|
|
104
|
+
);
|
|
104
105
|
server.listen(...args);
|
|
105
106
|
return server;
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
App.
|
|
110
|
+
App.Router = Router;
|
|
111
|
+
App.json = json;
|
|
112
|
+
App.cors = cors;
|
|
113
|
+
App.urlencoded = urlencoded;
|
|
110
114
|
|
|
111
115
|
exports.App = App;
|
package/src/index.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
require("./polyfill");
|
|
2
2
|
const { App } = require("./app");
|
|
3
|
-
const { Router } = require("./router");
|
|
4
|
-
const { json } = require("./middleware/json");
|
|
5
|
-
const { cors } = require("./middleware/cors");
|
|
6
|
-
const { urlencoded } = require("./middleware/urlencoded");
|
|
7
|
-
|
|
8
|
-
App.Router = Router;
|
|
9
|
-
App.json = json;
|
|
10
|
-
App.cors = cors;
|
|
11
|
-
App.urlencoded = urlencoded;
|
|
12
3
|
|
|
13
4
|
module.exports = App;
|
package/src/middleware/cors.js
CHANGED
package/src/node.js
CHANGED
|
@@ -8,13 +8,10 @@ class Node {
|
|
|
8
8
|
/**@type {String}*/
|
|
9
9
|
this.name = segment.slice(1);
|
|
10
10
|
}
|
|
11
|
-
|
|
12
11
|
/**@type {Map<string,Node>}*/
|
|
13
12
|
this.children = new Map();
|
|
14
|
-
|
|
15
13
|
/**@type {Map<string,Node>}*/
|
|
16
14
|
this.params = new Map();
|
|
17
|
-
|
|
18
15
|
/**@type {Node}*/
|
|
19
16
|
this.wildcard = null;
|
|
20
17
|
/**@type {Map<string,Function[]>}*/
|
|
@@ -31,13 +28,9 @@ class Node {
|
|
|
31
28
|
return this.wildcard;
|
|
32
29
|
}
|
|
33
30
|
if (segment.startsWith(":")) {
|
|
34
|
-
return this.params.getOrInsertComputed(segment, (segment) =>
|
|
35
|
-
return new Node(segment);
|
|
36
|
-
});
|
|
31
|
+
return this.params.getOrInsertComputed(segment, (segment) => new Node(segment));
|
|
37
32
|
}
|
|
38
|
-
return this.children.getOrInsertComputed(segment, (segment) =>
|
|
39
|
-
return new Node(segment);
|
|
40
|
-
});
|
|
33
|
+
return this.children.getOrInsertComputed(segment, (segment) => new Node(segment));
|
|
41
34
|
}
|
|
42
35
|
|
|
43
36
|
/**
|
package/src/router.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
const { decodeParam } = require("./util");
|
|
2
2
|
const { Node } = require("./node");
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @callback Callback
|
|
6
|
+
* @param {import('./request').Request} req
|
|
7
|
+
* @param {import('./response').Response} res
|
|
8
|
+
*/
|
|
9
|
+
|
|
4
10
|
/**
|
|
5
11
|
* @typedef {Object} Options
|
|
6
12
|
* @property {Number} [requestTimeout=0]
|
|
@@ -12,7 +18,6 @@ class Router {
|
|
|
12
18
|
*/
|
|
13
19
|
constructor(options = {}) {
|
|
14
20
|
this.requestTimeout = options.requestTimeout ?? 0;
|
|
15
|
-
|
|
16
21
|
this.root = new Node();
|
|
17
22
|
this.seq = 0;
|
|
18
23
|
}
|
|
@@ -55,17 +60,15 @@ class Router {
|
|
|
55
60
|
|
|
56
61
|
/**
|
|
57
62
|
* @param {String} method
|
|
58
|
-
* @param {String|
|
|
59
|
-
* @param {
|
|
63
|
+
* @param {String|Callback} path
|
|
64
|
+
* @param {Callback[]} handlers
|
|
60
65
|
*/
|
|
61
66
|
add(method, path, ...handlers) {
|
|
62
67
|
if (typeof path === "function") {
|
|
63
68
|
handlers = [path, ...handlers];
|
|
64
69
|
path = null;
|
|
65
70
|
}
|
|
66
|
-
|
|
67
71
|
let node = this.root;
|
|
68
|
-
let params = [];
|
|
69
72
|
if (path) {
|
|
70
73
|
let i = 0;
|
|
71
74
|
while (i < path.length) {
|
|
@@ -74,7 +77,6 @@ class Router {
|
|
|
74
77
|
while (j < path.length && path[j] !== "/") j++;
|
|
75
78
|
let segment = path.slice(i, j);
|
|
76
79
|
node = node.add(segment);
|
|
77
|
-
params.push(segment.slice(1));
|
|
78
80
|
i = j;
|
|
79
81
|
} else if (path[i] === "*") {
|
|
80
82
|
let j = i + 1;
|
|
@@ -101,8 +103,8 @@ class Router {
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
/**
|
|
104
|
-
* @param {String|
|
|
105
|
-
* @param {
|
|
106
|
+
* @param {String|Callback} path
|
|
107
|
+
* @param {Callback[]} handlers
|
|
106
108
|
* @returns {this}
|
|
107
109
|
*/
|
|
108
110
|
use(path, ...handlers) {
|
|
@@ -111,8 +113,8 @@ class Router {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
/**
|
|
114
|
-
* @param {String|
|
|
115
|
-
* @param {
|
|
116
|
+
* @param {String|Callback} path
|
|
117
|
+
* @param {Callback[]} handlers
|
|
116
118
|
* @returns {this}
|
|
117
119
|
*/
|
|
118
120
|
get(path, ...handlers) {
|
|
@@ -121,8 +123,8 @@ class Router {
|
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
/**
|
|
124
|
-
* @param {String|
|
|
125
|
-
* @param {
|
|
126
|
+
* @param {String|Callback} path
|
|
127
|
+
* @param {Callback[]} handlers
|
|
126
128
|
* @returns {this}
|
|
127
129
|
*/
|
|
128
130
|
query(path, ...handlers) {
|
|
@@ -131,8 +133,8 @@ class Router {
|
|
|
131
133
|
}
|
|
132
134
|
|
|
133
135
|
/**
|
|
134
|
-
* @param {String|
|
|
135
|
-
* @param {
|
|
136
|
+
* @param {String|Callback} path
|
|
137
|
+
* @param {Callback[]} handlers
|
|
136
138
|
* @returns {this}
|
|
137
139
|
*/
|
|
138
140
|
head(path, ...handlers) {
|
|
@@ -141,8 +143,8 @@ class Router {
|
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
/**
|
|
144
|
-
* @param {String|
|
|
145
|
-
* @param {
|
|
146
|
+
* @param {String|Callback} path
|
|
147
|
+
* @param {Callback[]} handlers
|
|
146
148
|
* @returns {this}
|
|
147
149
|
*/
|
|
148
150
|
options(path, ...handlers) {
|
|
@@ -151,8 +153,8 @@ class Router {
|
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
/**
|
|
154
|
-
* @param {String|
|
|
155
|
-
* @param {
|
|
156
|
+
* @param {String|Callback} path
|
|
157
|
+
* @param {Callback[]} handlers
|
|
156
158
|
* @returns {this}
|
|
157
159
|
*/
|
|
158
160
|
trace(path, ...handlers) {
|
|
@@ -161,8 +163,8 @@ class Router {
|
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
/**
|
|
164
|
-
* @param {String|
|
|
165
|
-
* @param {
|
|
166
|
+
* @param {String|Callback} path
|
|
167
|
+
* @param {Callback[]} handlers
|
|
166
168
|
* @returns {this}
|
|
167
169
|
*/
|
|
168
170
|
put(path, ...handlers) {
|
|
@@ -171,8 +173,8 @@ class Router {
|
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
/**
|
|
174
|
-
* @param {String|
|
|
175
|
-
* @param {
|
|
176
|
+
* @param {String|Callback} path
|
|
177
|
+
* @param {Callback[]} handlers
|
|
176
178
|
* @returns {this}
|
|
177
179
|
*/
|
|
178
180
|
delete(path, ...handlers) {
|
|
@@ -181,8 +183,8 @@ class Router {
|
|
|
181
183
|
}
|
|
182
184
|
|
|
183
185
|
/**
|
|
184
|
-
* @param {String|
|
|
185
|
-
* @param {
|
|
186
|
+
* @param {String|Callback} path
|
|
187
|
+
* @param {Callback[]} handlers
|
|
186
188
|
* @returns {this}
|
|
187
189
|
*/
|
|
188
190
|
post(path, ...handlers) {
|
|
@@ -191,8 +193,8 @@ class Router {
|
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
/**
|
|
194
|
-
* @param {String|
|
|
195
|
-
* @param {
|
|
196
|
+
* @param {String|Callback} path
|
|
197
|
+
* @param {Callback[]} handlers
|
|
196
198
|
* @returns {this}
|
|
197
199
|
*/
|
|
198
200
|
patch(path, ...handlers) {
|
|
@@ -201,8 +203,8 @@ class Router {
|
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
/**
|
|
204
|
-
* @param {String|
|
|
205
|
-
* @param {
|
|
206
|
+
* @param {String|Callback} path
|
|
207
|
+
* @param {Callback[]} handlers
|
|
206
208
|
* @returns {this}
|
|
207
209
|
*/
|
|
208
210
|
connect(path, ...handlers) {
|
|
@@ -219,14 +221,15 @@ class Router {
|
|
|
219
221
|
* @param {Object} state
|
|
220
222
|
* @returns {{path:Array,params:Object,matched:Boolean}}
|
|
221
223
|
*/
|
|
222
|
-
search(method, path, node, nodes = [], params = {}, state = { nodes: [], params: {} }) {
|
|
224
|
+
search(method, path, node = this.root, nodes = [], params = {}, state = { nodes: [], params: {} }) {
|
|
223
225
|
nodes.push(node);
|
|
224
226
|
if (0 === path.length) {
|
|
225
227
|
if (node.handlers.has(method) || node.handlers.has("ALL")) {
|
|
226
228
|
return { nodes, params, matched: true };
|
|
227
229
|
}
|
|
228
230
|
if (nodes.length > state.nodes.length) {
|
|
229
|
-
state =
|
|
231
|
+
state.nodes = nodes.slice();
|
|
232
|
+
params = { ...params };
|
|
230
233
|
}
|
|
231
234
|
nodes.pop();
|
|
232
235
|
return { nodes: state.nodes, params: state.params, matched: false };
|
|
@@ -237,81 +240,79 @@ class Router {
|
|
|
237
240
|
if (res.matched) return res;
|
|
238
241
|
}
|
|
239
242
|
}
|
|
240
|
-
for (const [
|
|
243
|
+
for (const [, child] of node.params) {
|
|
241
244
|
const slashIdx = path.indexOf("/");
|
|
242
245
|
const value = slashIdx === -1 ? path : path.slice(0, slashIdx);
|
|
243
246
|
const rest = slashIdx === -1 ? "" : path.slice(slashIdx);
|
|
244
247
|
if (value.length > 0) {
|
|
245
|
-
const next = { ...params, [child.name]:
|
|
248
|
+
const next = { ...params, [child.name]: value };
|
|
246
249
|
const result = this.search(method, rest, child, nodes, next, state);
|
|
247
250
|
if (result.matched) return result;
|
|
248
251
|
}
|
|
249
252
|
}
|
|
250
253
|
if (node.wildcard && (node.wildcard.handlers.get(method) || node.wildcard.handlers.get("ALL"))) {
|
|
251
254
|
nodes.push(node.wildcard);
|
|
252
|
-
return {
|
|
253
|
-
nodes,
|
|
254
|
-
params: { ...params, wildcard: path },
|
|
255
|
-
matched: true,
|
|
256
|
-
};
|
|
255
|
+
return { nodes, params: { ...params, wildcard: path }, matched: true };
|
|
257
256
|
}
|
|
258
257
|
if (nodes.length > state.nodes.length) {
|
|
259
|
-
state =
|
|
258
|
+
state.nodes = nodes.slice();
|
|
259
|
+
params = { ...params };
|
|
260
260
|
}
|
|
261
261
|
nodes.pop();
|
|
262
262
|
return { nodes: state.nodes, params: state.params, matched: false };
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
/**
|
|
266
|
-
* @param {Node}
|
|
266
|
+
* @param {Node} node
|
|
267
267
|
* @param {String} method
|
|
268
268
|
* @param {Object} handlers
|
|
269
269
|
*/
|
|
270
|
-
collectHandler(
|
|
271
|
-
if (
|
|
272
|
-
for (const
|
|
273
|
-
handlers[
|
|
270
|
+
collectHandler(node, method, handlers) {
|
|
271
|
+
if (node.handlers.has(method)) {
|
|
272
|
+
for (const { seq, handler } of node.handlers.get(method)) {
|
|
273
|
+
handlers[seq] = handler;
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
/**
|
|
279
|
-
* @param {Node}
|
|
279
|
+
* @param {Node} node
|
|
280
280
|
* @param {Object} handlers
|
|
281
281
|
* @param {Object} errorHandlers
|
|
282
282
|
*/
|
|
283
|
-
collectMiddleware(
|
|
284
|
-
this.collectHandler(
|
|
285
|
-
this.collectHandler(
|
|
283
|
+
collectMiddleware(node, handlers, errorHandlers) {
|
|
284
|
+
this.collectHandler(node, "ALL", handlers);
|
|
285
|
+
this.collectHandler(node, "CATCH", errorHandlers);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
decodeParams(obj) {
|
|
289
|
+
const params = Object.create(null);
|
|
290
|
+
for (const key of Object.keys(obj)) {
|
|
291
|
+
params[key] = decodeParam(obj[key]);
|
|
292
|
+
}
|
|
293
|
+
return params;
|
|
286
294
|
}
|
|
287
295
|
|
|
288
296
|
/**
|
|
289
297
|
* @param {String} method
|
|
290
298
|
* @param {String} path
|
|
291
|
-
* @returns {{
|
|
299
|
+
* @returns {{params: Object;handlers: any[];errorHandlers: any[];}}
|
|
292
300
|
*/
|
|
293
301
|
find(method, path) {
|
|
294
|
-
let res = this.search(method, path
|
|
295
|
-
|
|
302
|
+
let res = this.search(method, path);
|
|
296
303
|
if (!res.matched && path.length > 1) {
|
|
297
304
|
const alt = path.endsWith("/") ? path.slice(0, -1) : path + "/";
|
|
298
|
-
res = this.search(method, alt
|
|
305
|
+
res = this.search(method, alt);
|
|
299
306
|
}
|
|
300
307
|
const handlers = {};
|
|
301
308
|
const errorHandlers = {};
|
|
302
|
-
for (const
|
|
303
|
-
this.collectMiddleware(
|
|
309
|
+
for (const node of res.nodes) {
|
|
310
|
+
this.collectMiddleware(node, handlers, errorHandlers);
|
|
304
311
|
}
|
|
305
312
|
if (res.matched) {
|
|
306
|
-
this.collectHandler(res.nodes.
|
|
313
|
+
this.collectHandler(res.nodes[res.nodes.length - 1], method, handlers);
|
|
307
314
|
}
|
|
308
|
-
return {
|
|
309
|
-
matched: res.matched,
|
|
310
|
-
params: res.params,
|
|
311
|
-
paramsLength: Object.keys(res.params).length,
|
|
312
|
-
handlers: Object.values(handlers),
|
|
313
|
-
errorHandlers: Object.values(errorHandlers),
|
|
314
|
-
};
|
|
315
|
+
return { params: res.params, handlers, errorHandlers };
|
|
315
316
|
}
|
|
316
317
|
}
|
|
317
318
|
exports.Router = Router;
|