@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndiinginc/router",
3
- "version": "4.14.0",
3
+ "version": "4.15.0",
4
4
  "description": "",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
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
- /**@type {import('http').ServerOptions}*/
7
- const SERVER_OPTIONS = {
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(res, err) {
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, paramsLength, handlers, errorHandlers } = this.find(req.method, req.path);
69
- req.params = paramsLength ? Object.assign(Object.create(null), params) : Object.create(null);
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(res, err);
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 requestListener = (req, res) => this.handle(req, res);
103
- const server = http.createServer(SERVER_OPTIONS, requestListener);
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.SERVER_OPTIONS = SERVER_OPTIONS;
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;
@@ -21,6 +21,7 @@ function cors({ origin = "*", credentials = false, headers, maxAge = 0, methods
21
21
  if (Array.isArray(headers)) {
22
22
  headers = headers.map((h) => h.toLowerCase());
23
23
  }
24
+
24
25
  if (Array.isArray(methods)) {
25
26
  methods = methods.map((m) => m.toUpperCase());
26
27
  }
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|Function} path
59
- * @param {Function[]} handlers
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|Function} path
105
- * @param {Function[]} handlers
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|Function} path
115
- * @param {Function[]} handlers
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|Function} path
125
- * @param {Function[]} handlers
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|Function} path
135
- * @param {Function[]} handlers
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|Function} path
145
- * @param {Function[]} handlers
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|Function} path
155
- * @param {Function[]} handlers
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|Function} path
165
- * @param {Function[]} handlers
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|Function} path
175
- * @param {Function[]} handlers
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|Function} path
185
- * @param {Function[]} handlers
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|Function} path
195
- * @param {Function[]} handlers
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|Function} path
205
- * @param {Function[]} handlers
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 = { nodes: nodes.slice(), params: { ...params } };
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 [segment, child] of node.params) {
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]: decodeParam(value) };
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 = { nodes: nodes.slice(), params: { ...params } };
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} r
266
+ * @param {Node} node
267
267
  * @param {String} method
268
268
  * @param {Object} handlers
269
269
  */
270
- collectHandler(r, method, handlers) {
271
- if (r.handlers.has(method)) {
272
- for (const entry of r.handlers.get(method)) {
273
- handlers[entry.seq] = entry.handler;
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} r
279
+ * @param {Node} node
280
280
  * @param {Object} handlers
281
281
  * @param {Object} errorHandlers
282
282
  */
283
- collectMiddleware(r, handlers, errorHandlers) {
284
- this.collectHandler(r, "ALL", handlers);
285
- this.collectHandler(r, "CATCH", errorHandlers);
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 {{matched: boolean;params: Object;paramsLength: number;handlers: any[];errorHandlers: any[];}}
299
+ * @returns {{params: Object;handlers: any[];errorHandlers: any[];}}
292
300
  */
293
301
  find(method, path) {
294
- let res = this.search(method, path, this.root);
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, this.root);
305
+ res = this.search(method, alt);
299
306
  }
300
307
  const handlers = {};
301
308
  const errorHandlers = {};
302
- for (const r of res.nodes) {
303
- this.collectMiddleware(r, handlers, errorHandlers);
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.at(-1), method, handlers);
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;