@e22m4u/js-trie-router 0.2.0 → 0.3.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.
Files changed (69) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/index.cjs +225 -213
  3. package/examples/{cookie-parsing-example.js → cookies-parsing-example.js} +8 -8
  4. package/examples/params-parsing-example.js +11 -7
  5. package/examples/query-parsing-example.js +11 -7
  6. package/examples/uptime-example.js +4 -4
  7. package/package.json +9 -8
  8. package/src/debuggable-service.d.ts +2 -10
  9. package/src/debuggable-service.js +16 -17
  10. package/src/hooks/hook-invoker.js +3 -4
  11. package/src/hooks/hook-invoker.spec.js +3 -3
  12. package/src/hooks/hook-registry.d.ts +1 -1
  13. package/src/hooks/hook-registry.js +6 -7
  14. package/src/hooks/hook-registry.spec.js +14 -5
  15. package/src/parsers/body-parser.js +10 -11
  16. package/src/parsers/body-parser.spec.js +4 -4
  17. package/src/parsers/cookies-parser.d.ts +15 -0
  18. package/src/parsers/cookies-parser.js +33 -0
  19. package/src/parsers/{cookie-parser.spec.js → cookies-parser.spec.js} +6 -6
  20. package/src/parsers/index.d.ts +1 -1
  21. package/src/parsers/index.js +1 -1
  22. package/src/parsers/query-parser.js +4 -3
  23. package/src/parsers/request-parser.d.ts +2 -2
  24. package/src/parsers/request-parser.js +7 -7
  25. package/src/parsers/request-parser.spec.js +12 -12
  26. package/src/request-context.d.ts +3 -3
  27. package/src/request-context.js +5 -5
  28. package/src/request-context.spec.js +3 -3
  29. package/src/route-registry.js +14 -14
  30. package/src/route-registry.spec.js +4 -1
  31. package/src/route.d.ts +12 -7
  32. package/src/route.js +16 -14
  33. package/src/route.spec.js +13 -7
  34. package/src/router-options.js +1 -1
  35. package/src/router-options.spec.js +1 -1
  36. package/src/senders/data-sender.js +6 -5
  37. package/src/senders/error-sender.js +11 -4
  38. package/src/trie-router.js +46 -38
  39. package/src/trie-router.spec.js +54 -3
  40. package/src/utils/create-cookies-string.d.ts +6 -0
  41. package/src/utils/{create-cookie-string.js → create-cookies-string.js} +4 -4
  42. package/src/utils/{create-cookie-string.spec.js → create-cookies-string.spec.js} +7 -7
  43. package/src/utils/create-debugger.js +1 -1
  44. package/src/utils/create-debugger.spec.js +1 -1
  45. package/src/utils/create-error.js +2 -2
  46. package/src/utils/create-error.spec.js +2 -2
  47. package/src/utils/create-request-mock.d.ts +1 -1
  48. package/src/utils/create-request-mock.js +47 -43
  49. package/src/utils/create-request-mock.spec.js +18 -18
  50. package/src/utils/fetch-request-body.d.ts +11 -2
  51. package/src/utils/fetch-request-body.js +10 -17
  52. package/src/utils/fetch-request-body.spec.js +8 -9
  53. package/src/utils/get-request-pathname.js +1 -1
  54. package/src/utils/get-request-pathname.spec.js +1 -1
  55. package/src/utils/index.d.ts +2 -2
  56. package/src/utils/index.js +2 -2
  57. package/src/utils/is-readable-stream.js +1 -2
  58. package/src/utils/is-response-sent.js +1 -1
  59. package/src/utils/is-response-sent.spec.js +1 -1
  60. package/src/utils/parse-content-type.js +1 -1
  61. package/src/utils/parse-cookies.d.ts +19 -0
  62. package/src/utils/{parse-cookie.js → parse-cookies.js} +8 -5
  63. package/src/utils/{parse-cookie.spec.js → parse-cookies.spec.js} +13 -8
  64. package/src/utils/to-camel-case.js +1 -1
  65. package/src/utils/to-camel-case.spec.js +1 -1
  66. package/src/parsers/cookie-parser.d.ts +0 -15
  67. package/src/parsers/cookie-parser.js +0 -32
  68. package/src/utils/create-cookie-string.d.ts +0 -6
  69. package/src/utils/parse-cookie.d.ts +0 -19
@@ -4,25 +4,25 @@ import {HttpMethod} from '../src/route.js';
4
4
 
5
5
  const router = new TrieRouter();
6
6
 
7
- // регистрация роута для вывода
8
- // переданных Cookie
7
+ // регистрация маршрута для разбора
8
+ // передаваемого заголовка "Cookie"
9
9
  router.defineRoute({
10
10
  method: HttpMethod.GET,
11
- path: '/showCookie',
12
- handler: ({cookie}) => cookie,
11
+ path: '/parseCookies',
12
+ handler: ({cookies}) => cookies,
13
13
  });
14
14
 
15
- // создаем экземпляр HTTP сервера
16
- // и подключаем обработчик запросов
15
+ // создание экземпляра HTTP сервера
16
+ // и подключение обработчика запросов
17
17
  const server = new http.Server();
18
18
  server.on('request', router.requestListener);
19
19
 
20
- // слушаем входящие запросы
20
+ // прослушивание входящих запросов
21
21
  // на указанный адрес и порт
22
22
  const port = 3000;
23
23
  const host = '0.0.0.0';
24
24
  server.listen(port, host, function () {
25
25
  const cyan = '\x1b[36m%s\x1b[0m';
26
26
  console.log(cyan, 'Server listening on port:', port);
27
- console.log(cyan, 'Open in browser:', `http://${host}:${port}/showCookie`);
27
+ console.log(cyan, 'Open in browser:', `http://${host}:${port}/parseCookies`);
28
28
  });
@@ -4,25 +4,29 @@ import {HttpMethod} from '../src/route.js';
4
4
 
5
5
  const router = new TrieRouter();
6
6
 
7
- // регистрация роута для вывода
8
- // переданных параметров пути
7
+ // регистрация маршрута для разбора
8
+ // передаваемых параметров пути
9
9
  router.defineRoute({
10
10
  method: HttpMethod.GET,
11
- path: '/showParams/:p1/:p2',
11
+ path: '/parseParams/:p1/:p2',
12
12
  handler: ({params}) => params,
13
13
  });
14
14
 
15
- // создаем экземпляр HTTP сервера
16
- // и подключаем обработчик запросов
15
+ // создание экземпляра HTTP сервера
16
+ // и подключение обработчика запросов
17
17
  const server = new http.Server();
18
18
  server.on('request', router.requestListener);
19
19
 
20
- // слушаем входящие запросы
20
+ // прослушивание входящих запросов
21
21
  // на указанный адрес и порт
22
22
  const port = 3000;
23
23
  const host = '0.0.0.0';
24
24
  server.listen(port, host, function () {
25
25
  const cyan = '\x1b[36m%s\x1b[0m';
26
26
  console.log(cyan, 'Server listening on port:', port);
27
- console.log(cyan, 'Open in browser:', `http://${host}:${port}/showParams/foo/bar`);
27
+ console.log(
28
+ cyan,
29
+ 'Open in browser:',
30
+ `http://${host}:${port}/parseParams/foo/bar`,
31
+ );
28
32
  });
@@ -4,25 +4,29 @@ import {HttpMethod} from '../src/route.js';
4
4
 
5
5
  const router = new TrieRouter();
6
6
 
7
- // регистрация роута для вывода
8
- // переданных "query" параметров
7
+ // регистрация маршрута для разбора
8
+ // передаваемых параметров запроса
9
9
  router.defineRoute({
10
10
  method: HttpMethod.GET,
11
- path: '/showQuery',
11
+ path: '/parseQuery',
12
12
  handler: ({query}) => query,
13
13
  });
14
14
 
15
- // создаем экземпляр HTTP сервера
16
- // и подключаем обработчик запросов
15
+ // создание экземпляра HTTP сервера
16
+ // и подключение обработчика запросов
17
17
  const server = new http.Server();
18
18
  server.on('request', router.requestListener);
19
19
 
20
- // слушаем входящие запросы
20
+ // прослушивание входящих запросов
21
21
  // на указанный адрес и порт
22
22
  const port = 3000;
23
23
  const host = '0.0.0.0';
24
24
  server.listen(port, host, function () {
25
25
  const cyan = '\x1b[36m%s\x1b[0m';
26
26
  console.log(cyan, 'Server listening on port:', port);
27
- console.log(cyan, 'Open in browser:', `http://${host}:${port}/showQuery?foo=bar&baz=qux`);
27
+ console.log(
28
+ cyan,
29
+ 'Open in browser:',
30
+ `http://${host}:${port}/parseQuery?foo=bar&baz=qux`,
31
+ );
28
32
  });
@@ -4,7 +4,7 @@ import {HttpMethod} from '../src/route.js';
4
4
 
5
5
  const router = new TrieRouter();
6
6
 
7
- // регистрация роута для вывода
7
+ // регистрация маршрута для вывода
8
8
  // времени работы сервера
9
9
  router.defineRoute({
10
10
  method: HttpMethod.GET,
@@ -24,12 +24,12 @@ router.defineRoute({
24
24
  },
25
25
  })
26
26
 
27
- // создаем экземпляр HTTP сервера
28
- // и подключаем обработчик запросов
27
+ // создание экземпляра HTTP сервера
28
+ // и подключение обработчика запросов
29
29
  const server = new http.Server();
30
30
  server.on('request', router.requestListener);
31
31
 
32
- // слушаем входящие запросы
32
+ // прослушивание входящих запросов
33
33
  // на указанный адрес и порт
34
34
  const port = 3000;
35
35
  const host = '0.0.0.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-trie-router",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "HTTP маршрутизатор для Node.js на основе префиксного дерева",
5
5
  "author": "Mikhail Evstropov <e22m4u@yandex.ru>",
6
6
  "license": "MIT",
@@ -38,30 +38,31 @@
38
38
  "prepare": "husky"
39
39
  },
40
40
  "dependencies": {
41
+ "@e22m4u/js-debug": "~0.3.1",
41
42
  "@e22m4u/js-format": "~0.2.0",
42
- "@e22m4u/js-path-trie": "~0.0.10",
43
- "@e22m4u/js-service": "~0.3.8",
43
+ "@e22m4u/js-path-trie": "~0.0.11",
44
+ "@e22m4u/js-service": "~0.4.0",
44
45
  "debug": "~4.4.3",
45
46
  "http-errors": "~2.0.0",
46
47
  "statuses": "~2.0.2"
47
48
  },
48
49
  "devDependencies": {
49
- "@commitlint/cli": "~19.8.1",
50
- "@commitlint/config-conventional": "~19.8.1",
50
+ "@commitlint/cli": "~20.1.0",
51
+ "@commitlint/config-conventional": "~20.0.0",
51
52
  "@eslint/js": "~9.36.0",
52
53
  "@types/chai-as-promised": "~8.0.2",
53
54
  "c8": "~10.1.3",
54
- "chai": "~6.0.1",
55
+ "chai": "~6.2.0",
55
56
  "chai-as-promised": "~8.0.2",
56
57
  "esbuild": "~0.25.10",
57
58
  "eslint": "~9.36.0",
58
59
  "eslint-config-prettier": "~10.1.8",
59
60
  "eslint-plugin-chai-expect": "~3.1.0",
60
- "eslint-plugin-jsdoc": "~60.2.0",
61
+ "eslint-plugin-jsdoc": "~60.5.0",
61
62
  "eslint-plugin-mocha": "~11.1.0",
62
63
  "globals": "~16.4.0",
63
64
  "husky": "~9.1.7",
64
- "mocha": "~11.7.2",
65
+ "mocha": "~11.7.3",
65
66
  "prettier": "~3.6.2",
66
67
  "rimraf": "~6.0.1",
67
68
  "typescript": "~5.9.2"
@@ -1,14 +1,6 @@
1
- import {Debugger} from './utils/index.js';
2
- import {Service} from '@e22m4u/js-service';
1
+ import {DebuggableService as BaseDebuggableService} from '@e22m4u/js-service';
3
2
 
4
3
  /**
5
4
  * Debuggable service.
6
5
  */
7
- declare class DebuggableService extends Service {
8
- /**
9
- * Debug.
10
- *
11
- * @protected
12
- */
13
- protected debug: Debugger;
14
- }
6
+ declare class DebuggableService extends BaseDebuggableService {}
@@ -1,28 +1,27 @@
1
- import {Service} from '@e22m4u/js-service';
2
- import {toCamelCase} from './utils/index.js';
3
- import {createDebugger} from './utils/index.js';
4
- import {ServiceContainer} from '@e22m4u/js-service';
1
+ import {DebuggableService as BaseDebuggableService} from '@e22m4u/js-service';
5
2
 
6
3
  /**
7
- * Debuggable service.
4
+ * @typedef {import('@e22m4u/js-service').ServiceContainer} ServiceContainer
8
5
  */
9
- export class DebuggableService extends Service {
10
- /**
11
- * Debug.
12
- *
13
- * @type {Function}
14
- */
15
- debug;
16
6
 
7
+ /**
8
+ * Module debug namespace.
9
+ */
10
+ export const MODULE_DEBUG_NAMESPACE = 'jsTrieRouter';
11
+
12
+ /**
13
+ * Debuggable service.
14
+ */
15
+ export class DebuggableService extends BaseDebuggableService {
17
16
  /**
18
17
  * Constructor.
19
18
  *
20
19
  * @param {ServiceContainer} container
21
20
  */
22
- constructor(container) {
23
- super(container);
24
- const serviceName = toCamelCase(this.constructor.name);
25
- this.debug = createDebugger(serviceName);
26
- this.debug('The %v is created.', this.constructor);
21
+ constructor(container = undefined) {
22
+ super(container, {
23
+ namespace: MODULE_DEBUG_NAMESPACE,
24
+ noEnvironmentNamespace: true,
25
+ });
27
26
  }
28
27
  }
@@ -24,14 +24,14 @@ export class HookInvoker extends DebuggableService {
24
24
  throw new Errorf(
25
25
  'The parameter "route" of ' +
26
26
  'the HookInvoker.invokeAndContinueUntilValueReceived ' +
27
- 'should be a Route instance, but %v given.',
27
+ 'should be a Route instance, but %v was given.',
28
28
  route,
29
29
  );
30
30
  if (!hookType || typeof hookType !== 'string')
31
31
  throw new Errorf(
32
32
  'The parameter "hookType" of ' +
33
33
  'the HookInvoker.invokeAndContinueUntilValueReceived ' +
34
- 'should be a non-empty String, but %v given.',
34
+ 'should be a non-empty String, but %v was given.',
35
35
  hookType,
36
36
  );
37
37
  if (!Object.values(HookType).includes(hookType))
@@ -45,7 +45,7 @@ export class HookInvoker extends DebuggableService {
45
45
  throw new Errorf(
46
46
  'The parameter "response" of ' +
47
47
  'the HookInvoker.invokeAndContinueUntilValueReceived ' +
48
- 'should be a ServerResponse instance, but %v given.',
48
+ 'should be a ServerResponse instance, but %v was given.',
49
49
  response,
50
50
  );
51
51
  }
@@ -82,7 +82,6 @@ export class HookInvoker extends DebuggableService {
82
82
  // если ответ уже был отправлен,
83
83
  // то останавливаем выполнение
84
84
  if (isResponseSent(response)) {
85
- result = response;
86
85
  return;
87
86
  }
88
87
  // если предыдущий Promise вернул значение
@@ -18,7 +18,7 @@ describe('HookInvoker', function () {
18
18
  format(
19
19
  'The parameter "route" of ' +
20
20
  'the HookInvoker.invokeAndContinueUntilValueReceived ' +
21
- 'should be a Route instance, but %s given.',
21
+ 'should be a Route instance, but %s was given.',
22
22
  v,
23
23
  );
24
24
  expect(throwable('str')).to.throw(error('"str"'));
@@ -54,7 +54,7 @@ describe('HookInvoker', function () {
54
54
  format(
55
55
  'The parameter "hookType" of ' +
56
56
  'the HookInvoker.invokeAndContinueUntilValueReceived ' +
57
- 'should be a non-empty String, but %s given.',
57
+ 'should be a non-empty String, but %s was given.',
58
58
  v,
59
59
  );
60
60
  expect(throwable('')).to.throw(error('""'));
@@ -98,7 +98,7 @@ describe('HookInvoker', function () {
98
98
  format(
99
99
  'The parameter "response" of ' +
100
100
  'the HookInvoker.invokeAndContinueUntilValueReceived ' +
101
- 'should be a ServerResponse instance, but %s given.',
101
+ 'should be a ServerResponse instance, but %s was given.',
102
102
  v,
103
103
  );
104
104
  expect(throwable('str')).to.throw(error('"str"'));
@@ -37,7 +37,7 @@ export declare class HookRegistry extends DebuggableService {
37
37
  * @param type
38
38
  * @param hook
39
39
  */
40
- hasHook(type: HookType, hook: RouterHook): this;
40
+ hasHook(type: HookType, hook: RouterHook): boolean;
41
41
 
42
42
  /**
43
43
  * Get hooks.
@@ -1,5 +1,4 @@
1
1
  import {Errorf} from '@e22m4u/js-format';
2
- import {DebuggableService} from '../debuggable-service.js';
3
2
 
4
3
  /**
5
4
  * Hook type.
@@ -17,7 +16,7 @@ export const HookType = {
17
16
  /**
18
17
  * Hook registry.
19
18
  */
20
- export class HookRegistry extends DebuggableService {
19
+ export class HookRegistry {
21
20
  /**
22
21
  * Hooks.
23
22
  *
@@ -35,12 +34,12 @@ export class HookRegistry extends DebuggableService {
35
34
  */
36
35
  addHook(type, hook) {
37
36
  if (!type || typeof type !== 'string')
38
- throw new Errorf('The hook type is required, but %v given.', type);
37
+ throw new Errorf('The hook type is required, but %v was given.', type);
39
38
  if (!Object.values(HookType).includes(type))
40
39
  throw new Errorf('The hook type %v is not supported.', type);
41
40
  if (!hook || typeof hook !== 'function')
42
41
  throw new Errorf(
43
- 'The hook %v should be a Function, but %v given.',
42
+ 'The hook %v should be a Function, but %v was given.',
44
43
  type,
45
44
  hook,
46
45
  );
@@ -59,12 +58,12 @@ export class HookRegistry extends DebuggableService {
59
58
  */
60
59
  hasHook(type, hook) {
61
60
  if (!type || typeof type !== 'string')
62
- throw new Errorf('The hook type is required, but %v given.', type);
61
+ throw new Errorf('The hook type is required, but %v was given.', type);
63
62
  if (!Object.values(HookType).includes(type))
64
63
  throw new Errorf('The hook type %v is not supported.', type);
65
64
  if (!hook || typeof hook !== 'function')
66
65
  throw new Errorf(
67
- 'The hook %v should be a Function, but %v given.',
66
+ 'The hook %v should be a Function, but %v was given.',
68
67
  type,
69
68
  hook,
70
69
  );
@@ -80,7 +79,7 @@ export class HookRegistry extends DebuggableService {
80
79
  */
81
80
  getHooks(type) {
82
81
  if (!type || typeof type !== 'string')
83
- throw new Errorf('The hook type is required, but %v given.', type);
82
+ throw new Errorf('The hook type is required, but %v was given.', type);
84
83
  if (!Object.values(HookType).includes(type))
85
84
  throw new Errorf('The hook type %v is not supported.', type);
86
85
  return this._hooks.get(type) || [];
@@ -8,7 +8,8 @@ describe('HookRegistry', function () {
8
8
  it('requires the parameter "type" to be a non-empty String', function () {
9
9
  const s = new HookRegistry();
10
10
  const throwable = v => () => s.addHook(v, () => undefined);
11
- const error = v => format('The hook type is required, but %s given.', v);
11
+ const error = v =>
12
+ format('The hook type is required, but %s was given.', v);
12
13
  expect(throwable('')).to.throw(error('""'));
13
14
  expect(throwable(10)).to.throw(error('10'));
14
15
  expect(throwable(0)).to.throw(error('0'));
@@ -26,7 +27,10 @@ describe('HookRegistry', function () {
26
27
  const s = new HookRegistry();
27
28
  const throwable = v => () => s.addHook(HookType.PRE_HANDLER, v);
28
29
  const error = v =>
29
- format('The hook "preHandler" should be a Function, but %s given.', v);
30
+ format(
31
+ 'The hook "preHandler" should be a Function, but %s was given.',
32
+ v,
33
+ );
30
34
  expect(throwable('str')).to.throw(error('"str"'));
31
35
  expect(throwable('')).to.throw(error('""'));
32
36
  expect(throwable(10)).to.throw(error('10'));
@@ -69,7 +73,8 @@ describe('HookRegistry', function () {
69
73
  it('requires the parameter "type" to be a non-empty String', function () {
70
74
  const s = new HookRegistry();
71
75
  const throwable = v => () => s.hasHook(v, () => undefined);
72
- const error = v => format('The hook type is required, but %s given.', v);
76
+ const error = v =>
77
+ format('The hook type is required, but %s was given.', v);
73
78
  expect(throwable('')).to.throw(error('""'));
74
79
  expect(throwable(10)).to.throw(error('10'));
75
80
  expect(throwable(0)).to.throw(error('0'));
@@ -87,7 +92,10 @@ describe('HookRegistry', function () {
87
92
  const s = new HookRegistry();
88
93
  const throwable = v => () => s.hasHook(HookType.PRE_HANDLER, v);
89
94
  const error = v =>
90
- format('The hook "preHandler" should be a Function, but %s given.', v);
95
+ format(
96
+ 'The hook "preHandler" should be a Function, but %s was given.',
97
+ v,
98
+ );
91
99
  expect(throwable('str')).to.throw(error('"str"'));
92
100
  expect(throwable('')).to.throw(error('""'));
93
101
  expect(throwable(10)).to.throw(error('10'));
@@ -123,7 +131,8 @@ describe('HookRegistry', function () {
123
131
  it('requires the parameter "type" to be a non-empty String', function () {
124
132
  const s = new HookRegistry();
125
133
  const throwable = v => () => s.getHooks(v);
126
- const error = v => format('The hook type is required, but %s given.', v);
134
+ const error = v =>
135
+ format('The hook type is required, but %s was given.', v);
127
136
  expect(throwable('')).to.throw(error('""'));
128
137
  expect(throwable(10)).to.throw(error('10'));
129
138
  expect(throwable(0)).to.throw(error('0'));
@@ -45,13 +45,13 @@ export class BodyParser extends DebuggableService {
45
45
  if (!mediaType || typeof mediaType !== 'string')
46
46
  throw new Errorf(
47
47
  'The parameter "mediaType" of BodyParser.defineParser ' +
48
- 'should be a non-empty String, but %v given.',
48
+ 'should be a non-empty String, but %v was given.',
49
49
  mediaType,
50
50
  );
51
51
  if (!parser || typeof parser !== 'function')
52
52
  throw new Errorf(
53
53
  'The parameter "parser" of BodyParser.defineParser ' +
54
- 'should be a Function, but %v given.',
54
+ 'should be a Function, but %v was given.',
55
55
  parser,
56
56
  );
57
57
  this._parsers[mediaType] = parser;
@@ -68,7 +68,7 @@ export class BodyParser extends DebuggableService {
68
68
  if (!mediaType || typeof mediaType !== 'string')
69
69
  throw new Errorf(
70
70
  'The parameter "mediaType" of BodyParser.hasParser ' +
71
- 'should be a non-empty String, but %v given.',
71
+ 'should be a non-empty String, but %v was given.',
72
72
  mediaType,
73
73
  );
74
74
  return Boolean(this._parsers[mediaType]);
@@ -84,7 +84,7 @@ export class BodyParser extends DebuggableService {
84
84
  if (!mediaType || typeof mediaType !== 'string')
85
85
  throw new Errorf(
86
86
  'The parameter "mediaType" of BodyParser.deleteParser ' +
87
- 'should be a non-empty String, but %v given.',
87
+ 'should be a non-empty String, but %v was given.',
88
88
  mediaType,
89
89
  );
90
90
  const parser = this._parsers[mediaType];
@@ -100,8 +100,9 @@ export class BodyParser extends DebuggableService {
100
100
  * @returns {Promise<*>|undefined}
101
101
  */
102
102
  parse(req) {
103
+ const debug = this.getDebuggerFor(this.parse);
103
104
  if (!METHODS_WITH_BODY.includes(req.method.toUpperCase())) {
104
- this.debug(
105
+ debug(
105
106
  'Body parsing was skipped for the %s request.',
106
107
  req.method.toUpperCase(),
107
108
  );
@@ -112,8 +113,8 @@ export class BodyParser extends DebuggableService {
112
113
  '$1',
113
114
  );
114
115
  if (!contentType) {
115
- this.debug(
116
- 'Body parsing was skipped because the request has no content type.',
116
+ debug(
117
+ 'Body parsing was skipped because the request had no content type.',
117
118
  );
118
119
  return;
119
120
  }
@@ -126,7 +127,7 @@ export class BodyParser extends DebuggableService {
126
127
  const parser = this._parsers[mediaType];
127
128
  if (!parser) {
128
129
  if (UNPARSABLE_MEDIA_TYPES.includes(mediaType)) {
129
- this.debug('Body parsing was skipped for %v.', mediaType);
130
+ debug('Body parsing was skipped for %v.', mediaType);
130
131
  return;
131
132
  }
132
133
  throw createError(
@@ -154,8 +155,6 @@ export function parseJsonBody(input) {
154
155
  try {
155
156
  return JSON.parse(input);
156
157
  } catch (error) {
157
- if (process.env['DEBUG'] || process.env['NODE_ENV'] === 'development')
158
- console.warn(error);
159
- throw createError(HttpErrors.BadRequest, 'Unable to parse request body.');
158
+ throw createError(HttpErrors.BadRequest, error.message);
160
159
  }
161
160
  }
@@ -16,7 +16,7 @@ describe('BodyParser', function () {
16
16
  const error = v =>
17
17
  format(
18
18
  'The parameter "mediaType" of BodyParser.defineParser ' +
19
- 'should be a non-empty String, but %s given.',
19
+ 'should be a non-empty String, but %s was given.',
20
20
  v,
21
21
  );
22
22
  expect(throwable('')).to.throw(error('""'));
@@ -38,7 +38,7 @@ describe('BodyParser', function () {
38
38
  const error = v =>
39
39
  format(
40
40
  'The parameter "parser" of BodyParser.defineParser ' +
41
- 'should be a Function, but %s given.',
41
+ 'should be a Function, but %s was given.',
42
42
  v,
43
43
  );
44
44
  expect(throwable('str')).to.throw(error('"str"'));
@@ -76,7 +76,7 @@ describe('BodyParser', function () {
76
76
  const error = v =>
77
77
  format(
78
78
  'The parameter "mediaType" of BodyParser.hasParser ' +
79
- 'should be a non-empty String, but %s given.',
79
+ 'should be a non-empty String, but %s was given.',
80
80
  v,
81
81
  );
82
82
  expect(throwable('')).to.throw(error('""'));
@@ -111,7 +111,7 @@ describe('BodyParser', function () {
111
111
  const error = v =>
112
112
  format(
113
113
  'The parameter "mediaType" of BodyParser.deleteParser ' +
114
- 'should be a non-empty String, but %s given.',
114
+ 'should be a non-empty String, but %s was given.',
115
115
  v,
116
116
  );
117
117
  expect(throwable('')).to.throw(error('""'));
@@ -0,0 +1,15 @@
1
+ import {IncomingMessage} from 'http';
2
+ import {ParsedCookies} from '../utils/index.js';
3
+ import {DebuggableService} from '../debuggable-service.js';
4
+
5
+ /**
6
+ * Cookies parser.
7
+ */
8
+ export declare class CookiesParser extends DebuggableService {
9
+ /**
10
+ * Parse.
11
+ *
12
+ * @param req
13
+ */
14
+ parse(req: IncomingMessage): ParsedCookies;
15
+ }
@@ -0,0 +1,33 @@
1
+ import {parseCookies} from '../utils/index.js';
2
+ import {getRequestPathname} from '../utils/index.js';
3
+ import {DebuggableService} from '../debuggable-service.js';
4
+
5
+ /**
6
+ * Cookies parser.
7
+ */
8
+ export class CookiesParser extends DebuggableService {
9
+ /**
10
+ * Parse
11
+ *
12
+ * @param {import('http').IncomingMessage} req
13
+ * @returns {object}
14
+ */
15
+ parse(req) {
16
+ const debug = this.getDebuggerFor(this.parse);
17
+ const cookiesString = req.headers['cookie'] || '';
18
+ const cookies = parseCookies(cookiesString);
19
+ const cookiesKeys = Object.keys(cookies);
20
+ if (cookiesKeys.length) {
21
+ cookiesKeys.forEach(key => {
22
+ debug('The cookie %v had the value %v.', key, cookies[key]);
23
+ });
24
+ } else {
25
+ debug(
26
+ 'The request %s %v had no cookies.',
27
+ req.method,
28
+ getRequestPathname(req),
29
+ );
30
+ }
31
+ return cookies;
32
+ }
33
+ }
@@ -1,10 +1,10 @@
1
1
  import {expect} from '../chai.js';
2
- import {CookieParser} from './cookie-parser.js';
2
+ import {CookiesParser} from './cookies-parser.js';
3
3
 
4
- describe('CookieParser', function () {
4
+ describe('CookiesParser', function () {
5
5
  describe('parse', function () {
6
- it('returns cookie parameters', function () {
7
- const parser = new CookieParser();
6
+ it('returns parsed cookies as a plain object', function () {
7
+ const parser = new CookiesParser();
8
8
  const value = 'pkg=math; equation=E%3Dmc%5E2';
9
9
  const result = parser.parse({url: '', headers: {cookie: value}});
10
10
  expect(result).to.have.property('pkg', 'math');
@@ -12,13 +12,13 @@ describe('CookieParser', function () {
12
12
  });
13
13
 
14
14
  it('returns an empty object if no cookies', function () {
15
- const parser = new CookieParser();
15
+ const parser = new CookiesParser();
16
16
  const result = parser.parse({url: '', headers: {}});
17
17
  expect(result).to.be.eql({});
18
18
  });
19
19
 
20
20
  it('returns an empty object for an empty string', function () {
21
- const parser = new CookieParser();
21
+ const parser = new CookiesParser();
22
22
  const result = parser.parse({url: '', headers: {cookie: ''}});
23
23
  expect(result).to.be.eql({});
24
24
  });
@@ -1,4 +1,4 @@
1
1
  export * from './body-parser.js';
2
2
  export * from './query-parser.js';
3
- export * from './cookie-parser.js';
3
+ export * from './cookies-parser.js';
4
4
  export * from './request-parser.js';
@@ -1,4 +1,4 @@
1
1
  export * from './body-parser.js';
2
2
  export * from './query-parser.js';
3
- export * from './cookie-parser.js';
3
+ export * from './cookies-parser.js';
4
4
  export * from './request-parser.js';
@@ -13,16 +13,17 @@ export class QueryParser extends DebuggableService {
13
13
  * @returns {object}
14
14
  */
15
15
  parse(req) {
16
+ const debug = this.getDebuggerFor(this.parse);
16
17
  const queryStr = req.url.replace(/^[^?]*\??/, '');
17
18
  const query = queryStr ? querystring.parse(queryStr) : {};
18
19
  const queryKeys = Object.keys(query);
19
20
  if (queryKeys.length) {
20
21
  queryKeys.forEach(key => {
21
- this.debug('The query %v has the value %v.', key, query[key]);
22
+ debug('The query parameter %v had the value %v.', key, query[key]);
22
23
  });
23
24
  } else {
24
- this.debug(
25
- 'The request %s %v has no query.',
25
+ debug(
26
+ 'The request %s %v had no query parameters.',
26
27
  req.method,
27
28
  getRequestPathname(req),
28
29
  );