@ndiinginc/router 4.14.1 → 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.1",
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) {
@@ -226,8 +228,8 @@ class Router {
226
228
  return { nodes, params, matched: true };
227
229
  }
228
230
  if (nodes.length > state.nodes.length) {
229
- state.nodes=nodes.slice()
230
- params={...params}
231
+ state.nodes = nodes.slice();
232
+ params = { ...params };
231
233
  }
232
234
  nodes.pop();
233
235
  return { nodes: state.nodes, params: state.params, matched: false };
@@ -238,83 +240,79 @@ class Router {
238
240
  if (res.matched) return res;
239
241
  }
240
242
  }
241
- for (const [segment, child] of node.params) {
243
+ for (const [, child] of node.params) {
242
244
  const slashIdx = path.indexOf("/");
243
245
  const value = slashIdx === -1 ? path : path.slice(0, slashIdx);
244
246
  const rest = slashIdx === -1 ? "" : path.slice(slashIdx);
245
247
  if (value.length > 0) {
246
- const next = { ...params, [child.name]: decodeParam(value) };
248
+ const next = { ...params, [child.name]: value };
247
249
  const result = this.search(method, rest, child, nodes, next, state);
248
250
  if (result.matched) return result;
249
251
  }
250
252
  }
251
253
  if (node.wildcard && (node.wildcard.handlers.get(method) || node.wildcard.handlers.get("ALL"))) {
252
254
  nodes.push(node.wildcard);
253
- return {
254
- nodes,
255
- params: { ...params, wildcard: path },
256
- matched: true,
257
- };
255
+ return { nodes, params: { ...params, wildcard: path }, matched: true };
258
256
  }
259
257
  if (nodes.length > state.nodes.length) {
260
- state.nodes=nodes.slice()
261
- params={...params}
258
+ state.nodes = nodes.slice();
259
+ params = { ...params };
262
260
  }
263
261
  nodes.pop();
264
262
  return { nodes: state.nodes, params: state.params, matched: false };
265
263
  }
266
264
 
267
265
  /**
268
- * @param {Node} r
266
+ * @param {Node} node
269
267
  * @param {String} method
270
268
  * @param {Object} handlers
271
269
  */
272
- collectHandler(r, method, handlers) {
273
- if (r.handlers.has(method)) {
274
- for (const entry of r.handlers.get(method)) {
275
- 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;
276
274
  }
277
275
  }
278
276
  }
279
277
 
280
278
  /**
281
- * @param {Node} r
279
+ * @param {Node} node
282
280
  * @param {Object} handlers
283
281
  * @param {Object} errorHandlers
284
282
  */
285
- collectMiddleware(r, handlers, errorHandlers) {
286
- this.collectHandler(r, "ALL", handlers);
287
- 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;
288
294
  }
289
295
 
290
296
  /**
291
297
  * @param {String} method
292
298
  * @param {String} path
293
- * @returns {{matched: boolean;params: Object;paramsLength: number;handlers: any[];errorHandlers: any[];}}
299
+ * @returns {{params: Object;handlers: any[];errorHandlers: any[];}}
294
300
  */
295
301
  find(method, path) {
296
302
  let res = this.search(method, path);
297
-
298
303
  if (!res.matched && path.length > 1) {
299
304
  const alt = path.endsWith("/") ? path.slice(0, -1) : path + "/";
300
305
  res = this.search(method, alt);
301
306
  }
302
307
  const handlers = {};
303
308
  const errorHandlers = {};
304
- for (const r of res.nodes) {
305
- this.collectMiddleware(r, handlers, errorHandlers);
309
+ for (const node of res.nodes) {
310
+ this.collectMiddleware(node, handlers, errorHandlers);
306
311
  }
307
312
  if (res.matched) {
308
- this.collectHandler(res.nodes.at(-1), method, handlers);
313
+ this.collectHandler(res.nodes[res.nodes.length - 1], method, handlers);
309
314
  }
310
- return {
311
- matched: res.matched,
312
- params: res.params,
313
- paramsLength: Object.keys(res.params).length,
314
- handlers: Object.values(handlers),
315
- errorHandlers: Object.values(errorHandlers),
316
- };
315
+ return { params: res.params, handlers, errorHandlers };
317
316
  }
318
-
319
317
  }
320
318
  exports.Router = Router;