@e22m4u/js-trie-router 0.3.2 → 0.3.4

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.
@@ -39,7 +39,6 @@ __export(index_exports, {
39
39
  ErrorSender: () => ErrorSender,
40
40
  HookInvoker: () => HookInvoker,
41
41
  HookRegistry: () => HookRegistry,
42
- HookType: () => HookType,
43
42
  HttpMethod: () => HttpMethod,
44
43
  METHODS_WITH_BODY: () => METHODS_WITH_BODY,
45
44
  QueryParser: () => QueryParser,
@@ -47,6 +46,7 @@ __export(index_exports, {
47
46
  RequestParser: () => RequestParser,
48
47
  Route: () => Route,
49
48
  RouteRegistry: () => RouteRegistry,
49
+ RouterHookType: () => RouterHookType,
50
50
  RouterOptions: () => RouterOptions,
51
51
  TrieRouter: () => TrieRouter,
52
52
  UNPARSABLE_MEDIA_TYPES: () => UNPARSABLE_MEDIA_TYPES,
@@ -70,6 +70,7 @@ module.exports = __toCommonJS(index_exports);
70
70
 
71
71
  // src/route.js
72
72
  var import_js_format14 = require("@e22m4u/js-format");
73
+ var import_js_debug = require("@e22m4u/js-debug");
73
74
 
74
75
  // src/hooks/hook-invoker.js
75
76
  var import_js_format13 = require("@e22m4u/js-format");
@@ -635,7 +636,7 @@ __name(getRequestPathname, "getRequestPathname");
635
636
 
636
637
  // src/hooks/hook-registry.js
637
638
  var import_js_format12 = require("@e22m4u/js-format");
638
- var HookType = {
639
+ var RouterHookType = {
639
640
  PRE_HANDLER: "preHandler",
640
641
  POST_HANDLER: "postHandler"
641
642
  };
@@ -657,7 +658,7 @@ var _HookRegistry = class _HookRegistry {
657
658
  addHook(type, hook) {
658
659
  if (!type || typeof type !== "string")
659
660
  throw new import_js_format12.Errorf("The hook type is required, but %v was given.", type);
660
- if (!Object.values(HookType).includes(type))
661
+ if (!Object.values(RouterHookType).includes(type))
661
662
  throw new import_js_format12.Errorf("The hook type %v is not supported.", type);
662
663
  if (!hook || typeof hook !== "function")
663
664
  throw new import_js_format12.Errorf(
@@ -680,7 +681,7 @@ var _HookRegistry = class _HookRegistry {
680
681
  hasHook(type, hook) {
681
682
  if (!type || typeof type !== "string")
682
683
  throw new import_js_format12.Errorf("The hook type is required, but %v was given.", type);
683
- if (!Object.values(HookType).includes(type))
684
+ if (!Object.values(RouterHookType).includes(type))
684
685
  throw new import_js_format12.Errorf("The hook type %v is not supported.", type);
685
686
  if (!hook || typeof hook !== "function")
686
687
  throw new import_js_format12.Errorf(
@@ -700,7 +701,7 @@ var _HookRegistry = class _HookRegistry {
700
701
  getHooks(type) {
701
702
  if (!type || typeof type !== "string")
702
703
  throw new import_js_format12.Errorf("The hook type is required, but %v was given.", type);
703
- if (!Object.values(HookType).includes(type))
704
+ if (!Object.values(RouterHookType).includes(type))
704
705
  throw new import_js_format12.Errorf("The hook type %v is not supported.", type);
705
706
  return this._hooks.get(type) || [];
706
707
  }
@@ -749,7 +750,7 @@ var _HookInvoker = class _HookInvoker extends DebuggableService {
749
750
  'The parameter "hookType" of the HookInvoker.invokeAndContinueUntilValueReceived should be a non-empty String, but %v was given.',
750
751
  hookType
751
752
  );
752
- if (!Object.values(HookType).includes(hookType))
753
+ if (!Object.values(RouterHookType).includes(hookType))
753
754
  throw new import_js_format13.Errorf("The hook type %v is not supported.", hookType);
754
755
  if (!response || typeof response !== "object" || Array.isArray(response) || typeof response.headersSent !== "boolean") {
755
756
  throw new import_js_format13.Errorf(
@@ -788,7 +789,6 @@ __name(_HookInvoker, "HookInvoker");
788
789
  var HookInvoker = _HookInvoker;
789
790
 
790
791
  // src/route.js
791
- var import_js_debug = require("@e22m4u/js-debug");
792
792
  var HttpMethod = {
793
793
  GET: "GET",
794
794
  POST: "POST",
@@ -894,13 +894,13 @@ var _Route = class _Route extends import_js_debug.Debuggable {
894
894
  if (routeDef.preHandler != null) {
895
895
  const preHandlerHooks = Array.isArray(routeDef.preHandler) ? routeDef.preHandler : [routeDef.preHandler];
896
896
  preHandlerHooks.forEach((hook) => {
897
- this._hookRegistry.addHook(HookType.PRE_HANDLER, hook);
897
+ this._hookRegistry.addHook(RouterHookType.PRE_HANDLER, hook);
898
898
  });
899
899
  }
900
900
  if (routeDef.postHandler != null) {
901
901
  const postHandlerHooks = Array.isArray(routeDef.postHandler) ? routeDef.postHandler : [routeDef.postHandler];
902
902
  postHandlerHooks.forEach((hook) => {
903
- this._hookRegistry.addHook(HookType.POST_HANDLER, hook);
903
+ this._hookRegistry.addHook(RouterHookType.POST_HANDLER, hook);
904
904
  });
905
905
  }
906
906
  this.ctorDebug("A new route %s %v was created.", this._method, this._path);
@@ -1393,7 +1393,8 @@ var _RouteRegistry = class _RouteRegistry extends DebuggableService {
1393
1393
  req.method.toUpperCase(),
1394
1394
  requestPath
1395
1395
  );
1396
- const triePath = `${req.method.toUpperCase()}/${requestPath}`;
1396
+ const rawTriePath = `${req.method.toUpperCase()}/${requestPath}`;
1397
+ const triePath = rawTriePath.replace(/\/+/, "/");
1397
1398
  const resolved = this._trie.match(triePath);
1398
1399
  if (resolved) {
1399
1400
  const route = resolved.value;
@@ -1638,7 +1639,7 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
1638
1639
  const hookInvoker = this.getService(HookInvoker);
1639
1640
  data = hookInvoker.invokeAndContinueUntilValueReceived(
1640
1641
  route,
1641
- HookType.PRE_HANDLER,
1642
+ RouterHookType.PRE_HANDLER,
1642
1643
  res,
1643
1644
  context
1644
1645
  );
@@ -1648,7 +1649,7 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
1648
1649
  if (isPromise(data)) data = await data;
1649
1650
  let postHandlerData = hookInvoker.invokeAndContinueUntilValueReceived(
1650
1651
  route,
1651
- HookType.POST_HANDLER,
1652
+ RouterHookType.POST_HANDLER,
1652
1653
  res,
1653
1654
  context,
1654
1655
  data
@@ -1672,20 +1673,20 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
1672
1673
  * Example:
1673
1674
  * ```
1674
1675
  * import {TrieRouter} from '@e22m4u/js-trie-router';
1675
- * import {HookType} from '@e22m4u/js-trie-router';
1676
+ * import {RouterHookType} from '@e22m4u/js-trie-router';
1676
1677
  *
1677
1678
  * // Router instance.
1678
1679
  * const router = new TrieRouter();
1679
1680
  *
1680
1681
  * // Adds the "preHandler" hook for each route.
1681
1682
  * router.addHook(
1682
- * HookType.PRE_HANDLER,
1683
+ * RouterHookType.PRE_HANDLER,
1683
1684
  * ctx => { ... },
1684
1685
  * );
1685
1686
  *
1686
1687
  * // Adds the "postHandler" hook for each route.
1687
1688
  * router.addHook(
1688
- * HookType.POST_HANDLER,
1689
+ * RouterHookType.POST_HANDLER,
1689
1690
  * ctx => { ... },
1690
1691
  * );
1691
1692
  * ```
@@ -1711,7 +1712,6 @@ var TrieRouter = _TrieRouter;
1711
1712
  ErrorSender,
1712
1713
  HookInvoker,
1713
1714
  HookRegistry,
1714
- HookType,
1715
1715
  HttpMethod,
1716
1716
  METHODS_WITH_BODY,
1717
1717
  QueryParser,
@@ -1719,6 +1719,7 @@ var TrieRouter = _TrieRouter;
1719
1719
  RequestParser,
1720
1720
  Route,
1721
1721
  RouteRegistry,
1722
+ RouterHookType,
1722
1723
  RouterOptions,
1723
1724
  TrieRouter,
1724
1725
  UNPARSABLE_MEDIA_TYPES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-trie-router",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "HTTP маршрутизатор для Node.js на основе префиксного дерева",
5
5
  "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
6
6
  "license": "MIT",
@@ -38,10 +38,10 @@
38
38
  "prepare": "husky"
39
39
  },
40
40
  "dependencies": {
41
- "@e22m4u/js-debug": "~0.3.1",
41
+ "@e22m4u/js-debug": "~0.3.2",
42
42
  "@e22m4u/js-format": "~0.2.0",
43
43
  "@e22m4u/js-path-trie": "~0.0.12",
44
- "@e22m4u/js-service": "~0.4.3",
44
+ "@e22m4u/js-service": "~0.4.4",
45
45
  "debug": "~4.4.3",
46
46
  "http-errors": "~2.0.0",
47
47
  "statuses": "~2.0.2"
@@ -49,16 +49,16 @@
49
49
  "devDependencies": {
50
50
  "@commitlint/cli": "~20.1.0",
51
51
  "@commitlint/config-conventional": "~20.0.0",
52
- "@eslint/js": "~9.37.0",
52
+ "@eslint/js": "~9.38.0",
53
53
  "@types/chai-as-promised": "~8.0.2",
54
54
  "c8": "~10.1.3",
55
55
  "chai": "~6.2.0",
56
56
  "chai-as-promised": "~8.0.2",
57
- "esbuild": "~0.25.10",
58
- "eslint": "~9.37.0",
57
+ "esbuild": "~0.25.11",
58
+ "eslint": "~9.38.0",
59
59
  "eslint-config-prettier": "~10.1.8",
60
60
  "eslint-plugin-chai-expect": "~3.1.0",
61
- "eslint-plugin-jsdoc": "~61.1.1",
61
+ "eslint-plugin-jsdoc": "~61.1.11",
62
62
  "eslint-plugin-mocha": "~11.2.0",
63
63
  "globals": "~16.4.0",
64
64
  "husky": "~9.1.7",
@@ -1,7 +1,7 @@
1
1
  import {Route} from '../route.js';
2
2
  import {ServerResponse} from 'http';
3
3
  import {ValueOrPromise} from '../types.js';
4
- import {HookType} from './hook-registry.js';
4
+ import {RouterHookType} from './hook-registry.js';
5
5
  import {DebuggableService} from '../debuggable-service.js';
6
6
 
7
7
  /**
@@ -18,7 +18,7 @@ export declare class HookInvoker extends DebuggableService {
18
18
  */
19
19
  invokeAndContinueUntilValueReceived(
20
20
  route: Route,
21
- hookType: HookType,
21
+ hookType: RouterHookType,
22
22
  response: ServerResponse,
23
23
  ...args: unknown[]
24
24
  ): ValueOrPromise<unknown>;
@@ -1,9 +1,9 @@
1
1
  import {Route} from '../route.js';
2
2
  import {Errorf} from '@e22m4u/js-format';
3
3
  import {isPromise} from '../utils/index.js';
4
- import {HookType} from './hook-registry.js';
5
4
  import {HookRegistry} from './hook-registry.js';
6
5
  import {isResponseSent} from '../utils/index.js';
6
+ import {RouterHookType} from './hook-registry.js';
7
7
  import {DebuggableService} from '../debuggable-service.js';
8
8
 
9
9
  /**
@@ -34,7 +34,7 @@ export class HookInvoker extends DebuggableService {
34
34
  'should be a non-empty String, but %v was given.',
35
35
  hookType,
36
36
  );
37
- if (!Object.values(HookType).includes(hookType))
37
+ if (!Object.values(RouterHookType).includes(hookType))
38
38
  throw new Errorf('The hook type %v is not supported.', hookType);
39
39
  if (
40
40
  !response ||
@@ -2,9 +2,9 @@ import {expect} from '../chai.js';
2
2
  import {Route} from '../route.js';
3
3
  import {HttpMethod} from '../route.js';
4
4
  import {format} from '@e22m4u/js-format';
5
- import {HookType} from './hook-registry.js';
6
5
  import {HookInvoker} from './hook-invoker.js';
7
6
  import {HookRegistry} from './hook-registry.js';
7
+ import {RouterHookType} from './hook-registry.js';
8
8
  import {createResponseMock} from '../utils/index.js';
9
9
 
10
10
  describe('HookInvoker', function () {
@@ -13,7 +13,11 @@ describe('HookInvoker', function () {
13
13
  const s = new HookInvoker();
14
14
  const res = createResponseMock();
15
15
  const throwable = v => () =>
16
- s.invokeAndContinueUntilValueReceived(v, HookType.PRE_HANDLER, res);
16
+ s.invokeAndContinueUntilValueReceived(
17
+ v,
18
+ RouterHookType.PRE_HANDLER,
19
+ res,
20
+ );
17
21
  const error = v =>
18
22
  format(
19
23
  'The parameter "route" of ' +
@@ -66,7 +70,7 @@ describe('HookInvoker', function () {
66
70
  expect(throwable({})).to.throw(error('Object'));
67
71
  expect(throwable([])).to.throw(error('Array'));
68
72
  expect(throwable(undefined)).to.throw(error('undefined'));
69
- throwable(HookType.PRE_HANDLER)();
73
+ throwable(RouterHookType.PRE_HANDLER)();
70
74
  });
71
75
 
72
76
  it('requires the parameter "hookType" to be a supported hook', function () {
@@ -77,7 +81,7 @@ describe('HookInvoker', function () {
77
81
  handler: () => undefined,
78
82
  });
79
83
  const res = createResponseMock();
80
- Object.values(HookType).forEach(type =>
84
+ Object.values(RouterHookType).forEach(type =>
81
85
  s.invokeAndContinueUntilValueReceived(route, type, res),
82
86
  );
83
87
  const throwable = () =>
@@ -93,7 +97,11 @@ describe('HookInvoker', function () {
93
97
  handler: () => undefined,
94
98
  });
95
99
  const throwable = v => () =>
96
- s.invokeAndContinueUntilValueReceived(route, HookType.PRE_HANDLER, v);
100
+ s.invokeAndContinueUntilValueReceived(
101
+ route,
102
+ RouterHookType.PRE_HANDLER,
103
+ v,
104
+ );
97
105
  const error = v =>
98
106
  format(
99
107
  'The parameter "response" of ' +
@@ -117,10 +125,10 @@ describe('HookInvoker', function () {
117
125
  it('invokes global hooks in priority', function () {
118
126
  const s = new HookInvoker();
119
127
  const order = [];
120
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
128
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
121
129
  order.push('globalHook1');
122
130
  });
123
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
131
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
124
132
  order.push('globalHook2');
125
133
  });
126
134
  const route = new Route({
@@ -138,7 +146,7 @@ describe('HookInvoker', function () {
138
146
  });
139
147
  s.invokeAndContinueUntilValueReceived(
140
148
  route,
141
- HookType.PRE_HANDLER,
149
+ RouterHookType.PRE_HANDLER,
142
150
  createResponseMock(),
143
151
  );
144
152
  expect(order).to.be.eql([
@@ -153,14 +161,14 @@ describe('HookInvoker', function () {
153
161
  const s = new HookInvoker();
154
162
  const order = [];
155
163
  const ret = 'OK';
156
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
164
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
157
165
  order.push('globalHook1');
158
166
  });
159
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
167
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
160
168
  order.push('globalHook2');
161
169
  return ret;
162
170
  });
163
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
171
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
164
172
  order.push('globalHook3');
165
173
  });
166
174
  const route = new Route({
@@ -178,7 +186,7 @@ describe('HookInvoker', function () {
178
186
  });
179
187
  const result = s.invokeAndContinueUntilValueReceived(
180
188
  route,
181
- HookType.PRE_HANDLER,
189
+ RouterHookType.PRE_HANDLER,
182
190
  createResponseMock(),
183
191
  );
184
192
  expect(result).to.be.eq(ret);
@@ -189,10 +197,10 @@ describe('HookInvoker', function () {
189
197
  const s = new HookInvoker();
190
198
  const order = [];
191
199
  const ret = 'OK';
192
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
200
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
193
201
  order.push('globalHook1');
194
202
  });
195
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
203
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
196
204
  order.push('globalHook2');
197
205
  });
198
206
  const route = new Route({
@@ -214,7 +222,7 @@ describe('HookInvoker', function () {
214
222
  });
215
223
  const result = s.invokeAndContinueUntilValueReceived(
216
224
  route,
217
- HookType.PRE_HANDLER,
225
+ RouterHookType.PRE_HANDLER,
218
226
  createResponseMock(),
219
227
  );
220
228
  expect(result).to.be.eq(ret);
@@ -230,14 +238,14 @@ describe('HookInvoker', function () {
230
238
  const s = new HookInvoker();
231
239
  const order = [];
232
240
  const res = createResponseMock();
233
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
241
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
234
242
  order.push('globalHook1');
235
243
  });
236
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
244
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
237
245
  order.push('globalHook2');
238
246
  res._headersSent = true;
239
247
  });
240
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
248
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
241
249
  order.push('globalHook3');
242
250
  });
243
251
  const route = new Route({
@@ -255,7 +263,7 @@ describe('HookInvoker', function () {
255
263
  });
256
264
  const result = s.invokeAndContinueUntilValueReceived(
257
265
  route,
258
- HookType.PRE_HANDLER,
266
+ RouterHookType.PRE_HANDLER,
259
267
  res,
260
268
  );
261
269
  expect(result).to.be.eq(res);
@@ -266,10 +274,10 @@ describe('HookInvoker', function () {
266
274
  const s = new HookInvoker();
267
275
  const order = [];
268
276
  const res = createResponseMock();
269
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
277
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
270
278
  order.push('globalHook1');
271
279
  });
272
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
280
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
273
281
  order.push('globalHook2');
274
282
  });
275
283
  const route = new Route({
@@ -291,7 +299,7 @@ describe('HookInvoker', function () {
291
299
  });
292
300
  const result = s.invokeAndContinueUntilValueReceived(
293
301
  route,
294
- HookType.PRE_HANDLER,
302
+ RouterHookType.PRE_HANDLER,
295
303
  res,
296
304
  );
297
305
  expect(result).to.be.eq(res);
@@ -306,13 +314,16 @@ describe('HookInvoker', function () {
306
314
  it('returns a Promise if any global hook is asynchronous', async function () {
307
315
  const s = new HookInvoker();
308
316
  const order = [];
309
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
317
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
310
318
  order.push('globalHook1');
311
319
  });
312
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, async () => {
313
- order.push('globalHook2');
314
- });
315
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
320
+ s.getService(HookRegistry).addHook(
321
+ RouterHookType.PRE_HANDLER,
322
+ async () => {
323
+ order.push('globalHook2');
324
+ },
325
+ );
326
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
316
327
  order.push('globalHook3');
317
328
  });
318
329
  const route = new Route({
@@ -330,7 +341,7 @@ describe('HookInvoker', function () {
330
341
  });
331
342
  const promise = s.invokeAndContinueUntilValueReceived(
332
343
  route,
333
- HookType.PRE_HANDLER,
344
+ RouterHookType.PRE_HANDLER,
334
345
  createResponseMock(),
335
346
  );
336
347
  expect(promise).to.be.instanceof(Promise);
@@ -347,12 +358,18 @@ describe('HookInvoker', function () {
347
358
  it('returns a Promise if entire global hooks are asynchronous', async function () {
348
359
  const s = new HookInvoker();
349
360
  const order = [];
350
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, async () => {
351
- order.push('globalHook1');
352
- });
353
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, async () => {
354
- order.push('globalHook2');
355
- });
361
+ s.getService(HookRegistry).addHook(
362
+ RouterHookType.PRE_HANDLER,
363
+ async () => {
364
+ order.push('globalHook1');
365
+ },
366
+ );
367
+ s.getService(HookRegistry).addHook(
368
+ RouterHookType.PRE_HANDLER,
369
+ async () => {
370
+ order.push('globalHook2');
371
+ },
372
+ );
356
373
  const route = new Route({
357
374
  method: HttpMethod.GET,
358
375
  path: '/',
@@ -368,7 +385,7 @@ describe('HookInvoker', function () {
368
385
  });
369
386
  const promise = s.invokeAndContinueUntilValueReceived(
370
387
  route,
371
- HookType.PRE_HANDLER,
388
+ RouterHookType.PRE_HANDLER,
372
389
  createResponseMock(),
373
390
  );
374
391
  expect(promise).to.be.instanceof(Promise);
@@ -384,10 +401,10 @@ describe('HookInvoker', function () {
384
401
  it('returns a Promise if any route hook is asynchronous', async function () {
385
402
  const s = new HookInvoker();
386
403
  const order = [];
387
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
404
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
388
405
  order.push('globalHook1');
389
406
  });
390
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
407
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
391
408
  order.push('globalHook2');
392
409
  });
393
410
  const route = new Route({
@@ -408,7 +425,7 @@ describe('HookInvoker', function () {
408
425
  });
409
426
  const promise = s.invokeAndContinueUntilValueReceived(
410
427
  route,
411
- HookType.PRE_HANDLER,
428
+ RouterHookType.PRE_HANDLER,
412
429
  createResponseMock(),
413
430
  );
414
431
  expect(promise).to.be.instanceof(Promise);
@@ -425,10 +442,10 @@ describe('HookInvoker', function () {
425
442
  it('returns a Promise if entire route hooks are asynchronous', async function () {
426
443
  const s = new HookInvoker();
427
444
  const order = [];
428
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
445
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
429
446
  order.push('globalHook1');
430
447
  });
431
- s.getService(HookRegistry).addHook(HookType.PRE_HANDLER, () => {
448
+ s.getService(HookRegistry).addHook(RouterHookType.PRE_HANDLER, () => {
432
449
  order.push('globalHook2');
433
450
  });
434
451
  const route = new Route({
@@ -446,7 +463,7 @@ describe('HookInvoker', function () {
446
463
  });
447
464
  const promise = s.invokeAndContinueUntilValueReceived(
448
465
  route,
449
- HookType.PRE_HANDLER,
466
+ RouterHookType.PRE_HANDLER,
450
467
  createResponseMock(),
451
468
  );
452
469
  expect(promise).to.be.instanceof(Promise);
@@ -1,23 +1,35 @@
1
1
  import {Callable} from '../types.js';
2
+ import {RequestContext} from '../request-context.js';
2
3
  import {DebuggableService} from '../debuggable-service.js';
3
4
 
4
5
  /**
5
6
  * Hook type.
6
7
  */
7
- export declare const HookType: {
8
+ export declare const RouterHookType: {
8
9
  PRE_HANDLER: 'preHandler';
9
10
  POST_HANDLER: 'postHandler';
10
11
  };
11
12
 
12
13
  /**
13
- * Type of HookType.
14
+ * Type of RouterHookType.
14
15
  */
15
- export type HookType = (typeof HookType)[keyof typeof HookType];
16
+ export type RouterHookType =
17
+ (typeof RouterHookType)[keyof typeof RouterHookType];
16
18
 
17
19
  /**
18
20
  * Router hook.
19
21
  */
20
- export type RouterHook<T = unknown> = Callable<T>;
22
+ export type RouterHook = Callable;
23
+
24
+ /**
25
+ * Pre handler hook.
26
+ */
27
+ export type PreHandlerHook = (ctx: RequestContext) => unknown;
28
+
29
+ /**
30
+ * Post handler hook.
31
+ */
32
+ export type PostHandlerHook = (ctx: RequestContext, data: unknown) => unknown;
21
33
 
22
34
  /**
23
35
  * Hook registry.
@@ -29,7 +41,26 @@ export declare class HookRegistry extends DebuggableService {
29
41
  * @param type
30
42
  * @param hook
31
43
  */
32
- addHook(type: HookType, hook: RouterHook): this;
44
+ addHook(type: typeof RouterHookType.PRE_HANDLER, hook: PreHandlerHook): this;
45
+
46
+ /**
47
+ * Add hook.
48
+ *
49
+ * @param type
50
+ * @param hook
51
+ */
52
+ addHook(
53
+ type: typeof RouterHookType.POST_HANDLER,
54
+ hook: PostHandlerHook,
55
+ ): this;
56
+
57
+ /**
58
+ * Add hook.
59
+ *
60
+ * @param type
61
+ * @param hook
62
+ */
63
+ addHook(type: RouterHookType, hook: RouterHook): this;
33
64
 
34
65
  /**
35
66
  * Has hook.
@@ -37,12 +68,26 @@ export declare class HookRegistry extends DebuggableService {
37
68
  * @param type
38
69
  * @param hook
39
70
  */
40
- hasHook(type: HookType, hook: RouterHook): boolean;
71
+ hasHook(type: RouterHookType, hook: RouterHook): boolean;
72
+
73
+ /**
74
+ * Get hooks.
75
+ *
76
+ * @param type
77
+ */
78
+ getHooks(type: typeof RouterHookType.PRE_HANDLER): PreHandlerHook[];
79
+
80
+ /**
81
+ * Get hooks.
82
+ *
83
+ * @param type
84
+ */
85
+ getHooks(type: typeof RouterHookType.POST_HANDLER): PostHandlerHook[];
41
86
 
42
87
  /**
43
88
  * Get hooks.
44
89
  *
45
90
  * @param type
46
91
  */
47
- getHooks(type: HookType): RouterHook[];
92
+ getHooks(type: RouterHookType): RouterHook[];
48
93
  }
@@ -8,7 +8,7 @@ import {Errorf} from '@e22m4u/js-format';
8
8
  * POST_HANDLER: 'postHandler',
9
9
  * }}
10
10
  */
11
- export const HookType = {
11
+ export const RouterHookType = {
12
12
  PRE_HANDLER: 'preHandler',
13
13
  POST_HANDLER: 'postHandler',
14
14
  };
@@ -35,7 +35,7 @@ export class HookRegistry {
35
35
  addHook(type, hook) {
36
36
  if (!type || typeof type !== 'string')
37
37
  throw new Errorf('The hook type is required, but %v was given.', type);
38
- if (!Object.values(HookType).includes(type))
38
+ if (!Object.values(RouterHookType).includes(type))
39
39
  throw new Errorf('The hook type %v is not supported.', type);
40
40
  if (!hook || typeof hook !== 'function')
41
41
  throw new Errorf(
@@ -59,7 +59,7 @@ export class HookRegistry {
59
59
  hasHook(type, hook) {
60
60
  if (!type || typeof type !== 'string')
61
61
  throw new Errorf('The hook type is required, but %v was given.', type);
62
- if (!Object.values(HookType).includes(type))
62
+ if (!Object.values(RouterHookType).includes(type))
63
63
  throw new Errorf('The hook type %v is not supported.', type);
64
64
  if (!hook || typeof hook !== 'function')
65
65
  throw new Errorf(
@@ -80,7 +80,7 @@ export class HookRegistry {
80
80
  getHooks(type) {
81
81
  if (!type || typeof type !== 'string')
82
82
  throw new Errorf('The hook type is required, but %v was given.', type);
83
- if (!Object.values(HookType).includes(type))
83
+ if (!Object.values(RouterHookType).includes(type))
84
84
  throw new Errorf('The hook type %v is not supported.', type);
85
85
  return this._hooks.get(type) || [];
86
86
  }
@@ -1,7 +1,7 @@
1
1
  import {expect} from '../chai.js';
2
2
  import {format} from '@e22m4u/js-format';
3
- import {HookType} from './hook-registry.js';
4
3
  import {HookRegistry} from './hook-registry.js';
4
+ import {RouterHookType} from './hook-registry.js';
5
5
 
6
6
  describe('HookRegistry', function () {
7
7
  describe('addHook', function () {
@@ -20,12 +20,12 @@ describe('HookRegistry', function () {
20
20
  expect(throwable([])).to.throw(error('Array'));
21
21
  expect(throwable(undefined)).to.throw(error('undefined'));
22
22
  expect(throwable(() => undefined)).to.throw(error('Function'));
23
- throwable(HookType.PRE_HANDLER)();
23
+ throwable(RouterHookType.PRE_HANDLER)();
24
24
  });
25
25
 
26
26
  it('requires the parameter "hook" to be a Function', function () {
27
27
  const s = new HookRegistry();
28
- const throwable = v => () => s.addHook(HookType.PRE_HANDLER, v);
28
+ const throwable = v => () => s.addHook(RouterHookType.PRE_HANDLER, v);
29
29
  const error = v =>
30
30
  format(
31
31
  'The hook "preHandler" should be a Function, but %s was given.',
@@ -47,14 +47,14 @@ describe('HookRegistry', function () {
47
47
  it('requires the parameter "type" to be a supported hook', function () {
48
48
  const s = new HookRegistry();
49
49
  const hook = () => undefined;
50
- Object.values(HookType).forEach(type => s.addHook(type, hook));
50
+ Object.values(RouterHookType).forEach(type => s.addHook(type, hook));
51
51
  const throwable = () => s.addHook('unknown', hook);
52
52
  expect(throwable).to.throw('The hook type "unknown" is not supported.');
53
53
  });
54
54
 
55
55
  it('sets the given function to the map array by the hook type', function () {
56
56
  const s = new HookRegistry();
57
- const type = HookType.PRE_HANDLER;
57
+ const type = RouterHookType.PRE_HANDLER;
58
58
  const hook = () => undefined;
59
59
  s.addHook(type, hook);
60
60
  expect(s._hooks.get(type)).to.include(hook);
@@ -63,7 +63,7 @@ describe('HookRegistry', function () {
63
63
  it('returns this', function () {
64
64
  const s = new HookRegistry();
65
65
  const hook = () => undefined;
66
- const type = HookType.PRE_HANDLER;
66
+ const type = RouterHookType.PRE_HANDLER;
67
67
  const res = s.addHook(type, hook);
68
68
  expect(res).to.be.eq(s);
69
69
  });
@@ -85,12 +85,12 @@ describe('HookRegistry', function () {
85
85
  expect(throwable([])).to.throw(error('Array'));
86
86
  expect(throwable(undefined)).to.throw(error('undefined'));
87
87
  expect(throwable(() => undefined)).to.throw(error('Function'));
88
- throwable(HookType.PRE_HANDLER)();
88
+ throwable(RouterHookType.PRE_HANDLER)();
89
89
  });
90
90
 
91
91
  it('requires the parameter "hook" to be a Function', function () {
92
92
  const s = new HookRegistry();
93
- const throwable = v => () => s.hasHook(HookType.PRE_HANDLER, v);
93
+ const throwable = v => () => s.hasHook(RouterHookType.PRE_HANDLER, v);
94
94
  const error = v =>
95
95
  format(
96
96
  'The hook "preHandler" should be a Function, but %s was given.',
@@ -112,14 +112,14 @@ describe('HookRegistry', function () {
112
112
  it('requires the parameter "type" to be a supported hook', function () {
113
113
  const s = new HookRegistry();
114
114
  const hook = () => undefined;
115
- Object.values(HookType).forEach(type => s.hasHook(type, hook));
115
+ Object.values(RouterHookType).forEach(type => s.hasHook(type, hook));
116
116
  const throwable = () => s.hasHook('unknown', hook);
117
117
  expect(throwable).to.throw('The hook type "unknown" is not supported.');
118
118
  });
119
119
 
120
120
  it('returns true if the given hook is set or false', function () {
121
121
  const s = new HookRegistry();
122
- const type = HookType.PRE_HANDLER;
122
+ const type = RouterHookType.PRE_HANDLER;
123
123
  const hook = () => undefined;
124
124
  expect(s.hasHook(type, hook)).to.be.false;
125
125
  s.addHook(type, hook);
@@ -143,12 +143,12 @@ describe('HookRegistry', function () {
143
143
  expect(throwable([])).to.throw(error('Array'));
144
144
  expect(throwable(undefined)).to.throw(error('undefined'));
145
145
  expect(throwable(() => undefined)).to.throw(error('Function'));
146
- throwable(HookType.PRE_HANDLER)();
146
+ throwable(RouterHookType.PRE_HANDLER)();
147
147
  });
148
148
 
149
149
  it('requires the parameter "type" to be a supported hook', function () {
150
150
  const s = new HookRegistry();
151
- Object.values(HookType).forEach(type => s.getHooks(type));
151
+ Object.values(RouterHookType).forEach(type => s.getHooks(type));
152
152
  const throwable = () => s.getHooks('unknown');
153
153
  expect(throwable).to.throw('The hook type "unknown" is not supported.');
154
154
  });
@@ -156,7 +156,7 @@ describe('HookRegistry', function () {
156
156
  it('returns existing hooks', function () {
157
157
  const s = new HookRegistry();
158
158
  const hook = () => undefined;
159
- const type = HookType.PRE_HANDLER;
159
+ const type = RouterHookType.PRE_HANDLER;
160
160
  const res1 = s.getHooks(type);
161
161
  expect(res1).to.be.eql([]);
162
162
  s.addHook(type, hook);
@@ -167,7 +167,7 @@ describe('HookRegistry', function () {
167
167
 
168
168
  it('returns an empty array if no hook exists', function () {
169
169
  const s = new HookRegistry();
170
- const res = s.getHooks(HookType.PRE_HANDLER);
170
+ const res = s.getHooks(RouterHookType.PRE_HANDLER);
171
171
  expect(res).to.be.eql([]);
172
172
  });
173
173
  });
@@ -63,7 +63,10 @@ export class RouteRegistry extends DebuggableService {
63
63
  req.method.toUpperCase(),
64
64
  requestPath,
65
65
  );
66
- const triePath = `${req.method.toUpperCase()}/${requestPath}`;
66
+ const rawTriePath = `${req.method.toUpperCase()}/${requestPath}`;
67
+ // маршрут формируется с удалением дубликатов косой черты
68
+ // "OPTIONS//api/users/login" => "OPTIONS/api/users/login"
69
+ const triePath = rawTriePath.replace(/\/+/, '/');
67
70
  const resolved = this._trie.match(triePath);
68
71
  if (resolved) {
69
72
  const route = resolved.value;
package/src/route.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {Errorf} from '@e22m4u/js-format';
2
- import {HookType} from './hooks/index.js';
3
2
  import {Debuggable} from '@e22m4u/js-debug';
4
3
  import {HookRegistry} from './hooks/index.js';
4
+ import {RouterHookType} from './hooks/index.js';
5
5
  import {getRequestPathname} from './utils/index.js';
6
6
  import {MODULE_DEBUG_NAMESPACE} from './debuggable-service.js';
7
7
 
@@ -153,7 +153,7 @@ export class Route extends Debuggable {
153
153
  ? routeDef.preHandler
154
154
  : [routeDef.preHandler];
155
155
  preHandlerHooks.forEach(hook => {
156
- this._hookRegistry.addHook(HookType.PRE_HANDLER, hook);
156
+ this._hookRegistry.addHook(RouterHookType.PRE_HANDLER, hook);
157
157
  });
158
158
  }
159
159
  if (routeDef.postHandler != null) {
@@ -161,7 +161,7 @@ export class Route extends Debuggable {
161
161
  ? routeDef.postHandler
162
162
  : [routeDef.postHandler];
163
163
  postHandlerHooks.forEach(hook => {
164
- this._hookRegistry.addHook(HookType.POST_HANDLER, hook);
164
+ this._hookRegistry.addHook(RouterHookType.POST_HANDLER, hook);
165
165
  });
166
166
  }
167
167
  this.ctorDebug('A new route %s %v was created.', this._method, this._path);
package/src/route.spec.js CHANGED
@@ -2,7 +2,7 @@ import {Route} from './route.js';
2
2
  import {expect} from './chai.js';
3
3
  import {HttpMethod} from './route.js';
4
4
  import {format} from '@e22m4u/js-format';
5
- import {HookType} from './hooks/index.js';
5
+ import {RouterHookType} from './hooks/index.js';
6
6
  import {createRequestMock} from './utils/index.js';
7
7
  import {createResponseMock} from './utils/index.js';
8
8
  import {RequestContext} from './request-context.js';
@@ -238,8 +238,8 @@ describe('Route', function () {
238
238
  preHandler: value,
239
239
  handler: () => undefined,
240
240
  });
241
- expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value)).to.be
242
- .true;
241
+ expect(route.hookRegistry.hasHook(RouterHookType.PRE_HANDLER, value)).to
242
+ .be.true;
243
243
  });
244
244
 
245
245
  it('adds Function items of an Array to "preHandler" hooks', function () {
@@ -250,10 +250,10 @@ describe('Route', function () {
250
250
  preHandler: value,
251
251
  handler: () => undefined,
252
252
  });
253
- expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value[0])).to.be
254
- .true;
255
- expect(route.hookRegistry.hasHook(HookType.PRE_HANDLER, value[1])).to.be
256
- .true;
253
+ expect(route.hookRegistry.hasHook(RouterHookType.PRE_HANDLER, value[0]))
254
+ .to.be.true;
255
+ expect(route.hookRegistry.hasHook(RouterHookType.PRE_HANDLER, value[1]))
256
+ .to.be.true;
257
257
  });
258
258
 
259
259
  it('adds a Function to "postHandler" hooks', function () {
@@ -264,8 +264,8 @@ describe('Route', function () {
264
264
  handler: () => undefined,
265
265
  postHandler: value,
266
266
  });
267
- expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value)).to.be
268
- .true;
267
+ expect(route.hookRegistry.hasHook(RouterHookType.POST_HANDLER, value)).to
268
+ .be.true;
269
269
  });
270
270
 
271
271
  it('adds Function items of an Array to "postHandler" hooks', function () {
@@ -276,10 +276,10 @@ describe('Route', function () {
276
276
  handler: () => undefined,
277
277
  postHandler: value,
278
278
  });
279
- expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value[0])).to.be
280
- .true;
281
- expect(route.hookRegistry.hasHook(HookType.POST_HANDLER, value[1])).to.be
282
- .true;
279
+ expect(route.hookRegistry.hasHook(RouterHookType.POST_HANDLER, value[0]))
280
+ .to.be.true;
281
+ expect(route.hookRegistry.hasHook(RouterHookType.POST_HANDLER, value[1]))
282
+ .to.be.true;
283
283
  });
284
284
  });
285
285
 
@@ -1,10 +1,15 @@
1
1
  import {Route} from './route.js';
2
2
  import {RequestListener} from 'http';
3
- import {HookType} from './hooks/index.js';
4
3
  import {RouteDefinition} from './route.js';
5
- import {RouterHook} from './hooks/index.js';
6
4
  import {DebuggableService} from './debuggable-service.js';
7
5
 
6
+ import {
7
+ RouterHook,
8
+ RouterHookType,
9
+ PostHandlerHook,
10
+ PreHandlerHook,
11
+ } from './hooks/index.js';
12
+
8
13
  /**
9
14
  * Trie router.
10
15
  */
@@ -62,5 +67,24 @@ export declare class TrieRouter extends DebuggableService {
62
67
  * @param type
63
68
  * @param hook
64
69
  */
65
- addHook(type: HookType, hook: RouterHook): this;
70
+ addHook(type: typeof RouterHookType.PRE_HANDLER, hook: PreHandlerHook): this;
71
+
72
+ /**
73
+ * Add hook.
74
+ *
75
+ * @param type
76
+ * @param hook
77
+ */
78
+ addHook(
79
+ type: typeof RouterHookType.POST_HANDLER,
80
+ hook: PostHandlerHook,
81
+ ): this;
82
+
83
+ /**
84
+ * Add hook.
85
+ *
86
+ * @param type
87
+ * @param hook
88
+ */
89
+ addHook(type: RouterHookType, hook: RouterHook): this;
66
90
  }
@@ -1,12 +1,12 @@
1
1
  import {ServerResponse} from 'http';
2
2
  import {IncomingMessage} from 'http';
3
- import {HookType} from './hooks/index.js';
4
3
  import {isPromise} from './utils/index.js';
5
4
  import {HookInvoker} from './hooks/index.js';
6
5
  import {DataSender} from './senders/index.js';
7
6
  import {HookRegistry} from './hooks/index.js';
8
7
  import {ErrorSender} from './senders/index.js';
9
8
  import {isResponseSent} from './utils/index.js';
9
+ import {RouterHookType} from './hooks/index.js';
10
10
  import {RequestParser} from './parsers/index.js';
11
11
  import {RouteRegistry} from './route-registry.js';
12
12
  import {RequestContext} from './request-context.js';
@@ -134,7 +134,7 @@ export class TrieRouter extends DebuggableService {
134
134
  // то такое значение используется в качестве ответа
135
135
  data = hookInvoker.invokeAndContinueUntilValueReceived(
136
136
  route,
137
- HookType.PRE_HANDLER,
137
+ RouterHookType.PRE_HANDLER,
138
138
  res,
139
139
  context,
140
140
  );
@@ -150,7 +150,7 @@ export class TrieRouter extends DebuggableService {
150
150
  // также может быть использован в качестве ответа
151
151
  let postHandlerData = hookInvoker.invokeAndContinueUntilValueReceived(
152
152
  route,
153
- HookType.POST_HANDLER,
153
+ RouterHookType.POST_HANDLER,
154
154
  res,
155
155
  context,
156
156
  data,
@@ -178,20 +178,20 @@ export class TrieRouter extends DebuggableService {
178
178
  * Example:
179
179
  * ```
180
180
  * import {TrieRouter} from '@e22m4u/js-trie-router';
181
- * import {HookType} from '@e22m4u/js-trie-router';
181
+ * import {RouterHookType} from '@e22m4u/js-trie-router';
182
182
  *
183
183
  * // Router instance.
184
184
  * const router = new TrieRouter();
185
185
  *
186
186
  * // Adds the "preHandler" hook for each route.
187
187
  * router.addHook(
188
- * HookType.PRE_HANDLER,
188
+ * RouterHookType.PRE_HANDLER,
189
189
  * ctx => { ... },
190
190
  * );
191
191
  *
192
192
  * // Adds the "postHandler" hook for each route.
193
193
  * router.addHook(
194
- * HookType.POST_HANDLER,
194
+ * RouterHookType.POST_HANDLER,
195
195
  * ctx => { ... },
196
196
  * );
197
197
  * ```
@@ -3,11 +3,11 @@ import {expect} from './chai.js';
3
3
  import {ServerResponse} from 'http';
4
4
  import {IncomingMessage} from 'http';
5
5
  import {HttpMethod} from './route.js';
6
- import {HookType} from './hooks/index.js';
7
6
  import {TrieRouter} from './trie-router.js';
8
7
  import {HookRegistry} from './hooks/index.js';
9
8
  import {DataSender} from './senders/index.js';
10
9
  import {ErrorSender} from './senders/index.js';
10
+ import {RouterHookType} from './hooks/index.js';
11
11
  import {createRequestMock} from './utils/index.js';
12
12
  import {createResponseMock} from './utils/index.js';
13
13
  import {RequestContext} from './request-context.js';
@@ -563,7 +563,7 @@ describe('TrieRouter', function () {
563
563
  it('adds the given hook to the HookRegistry and returns itself', function () {
564
564
  const router = new TrieRouter();
565
565
  const reg = router.getService(HookRegistry);
566
- const type = HookType.PRE_HANDLER;
566
+ const type = RouterHookType.PRE_HANDLER;
567
567
  const hook = () => undefined;
568
568
  expect(reg.hasHook(type, hook)).to.be.false;
569
569
  const res = router.addHook(type, hook);