@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
@@ -1,7 +1,7 @@
1
1
  import {IncomingMessage} from 'http';
2
2
  import {ValueOrPromise} from '../types.js';
3
3
  import {ParsedQuery} from './query-parser.js';
4
- import {ParsedCookie} from '../utils/index.js';
4
+ import {ParsedCookies} from '../utils/index.js';
5
5
  import {DebuggableService} from '../debuggable-service.js';
6
6
 
7
7
  /**
@@ -16,7 +16,7 @@ export type ParsedHeaders = {
16
16
  */
17
17
  type ParsedRequestData = {
18
18
  query: ParsedQuery;
19
- cookie: ParsedCookie;
19
+ cookies: ParsedCookies;
20
20
  body: unknown;
21
21
  headers: ParsedHeaders;
22
22
  };
@@ -3,7 +3,7 @@ import {Errorf} from '@e22m4u/js-format';
3
3
  import {isPromise} from '../utils/index.js';
4
4
  import {BodyParser} from './body-parser.js';
5
5
  import {QueryParser} from './query-parser.js';
6
- import {CookieParser} from './cookie-parser.js';
6
+ import {CookiesParser} from './cookies-parser.js';
7
7
  import {DebuggableService} from '../debuggable-service.js';
8
8
 
9
9
  /**
@@ -20,7 +20,7 @@ export class RequestParser extends DebuggableService {
20
20
  if (!(req instanceof IncomingMessage))
21
21
  throw new Errorf(
22
22
  'The first argument of RequestParser.parse should be ' +
23
- 'an instance of IncomingMessage, but %v given.',
23
+ 'an instance of IncomingMessage, but %v was given.',
24
24
  req,
25
25
  );
26
26
  const data = {};
@@ -39,11 +39,11 @@ export class RequestParser extends DebuggableService {
39
39
  // данные заголовка "cookie" с проверкой
40
40
  // значения на Promise, и разрываем
41
41
  // "eventLoop" при необходимости
42
- const parsedCookie = this.getService(CookieParser).parse(req);
43
- if (isPromise(parsedCookie)) {
44
- promises.push(parsedCookie.then(v => (data.cookie = v)));
42
+ const parsedCookies = this.getService(CookiesParser).parse(req);
43
+ if (isPromise(parsedCookies)) {
44
+ promises.push(parsedCookies.then(v => (data.cookies = v)));
45
45
  } else {
46
- data.cookie = parsedCookie;
46
+ data.cookies = parsedCookies;
47
47
  }
48
48
  // аналогично предыдущей операции, разбираем
49
49
  // тело запроса с проверкой результата
@@ -56,7 +56,7 @@ export class RequestParser extends DebuggableService {
56
56
  }
57
57
  // что бы предотвратить модификацию
58
58
  // заголовков, возвращаем их копию
59
- data.headers = JSON.parse(JSON.stringify(req.headers));
59
+ data.headers = Object.assign({}, req.headers);
60
60
  // если имеются асинхронные операции, то результат
61
61
  // будет обернут в Promise, в противном случае
62
62
  // данные возвращаются сразу
@@ -12,7 +12,7 @@ describe('RequestParser', function () {
12
12
  const error = v =>
13
13
  format(
14
14
  'The first argument of RequestParser.parse should be ' +
15
- 'an instance of IncomingMessage, but %s given.',
15
+ 'an instance of IncomingMessage, but %s was given.',
16
16
  v,
17
17
  );
18
18
  expect(throwable('str')).to.throw(error('"str"'));
@@ -29,13 +29,13 @@ describe('RequestParser', function () {
29
29
  throwable(createRequestMock())();
30
30
  });
31
31
 
32
- it('returns the result object if no request body to parse', function () {
32
+ it('returns the result object if no request body', function () {
33
33
  const s = new RequestParser();
34
34
  const req = createRequestMock();
35
35
  const res = s.parse(req);
36
36
  expect(res).to.be.eql({
37
37
  query: {},
38
- cookie: {},
38
+ cookies: {},
39
39
  body: undefined,
40
40
  headers: {host: 'localhost'},
41
41
  });
@@ -54,7 +54,7 @@ describe('RequestParser', function () {
54
54
  const res = await promise;
55
55
  expect(res).to.be.eql({
56
56
  query: {},
57
- cookie: {},
57
+ cookies: {},
58
58
  body,
59
59
  headers: {
60
60
  host: 'localhost',
@@ -64,25 +64,25 @@ describe('RequestParser', function () {
64
64
  });
65
65
  });
66
66
 
67
- it('returns the parsed query in the result object', function () {
67
+ it('returns the result object with the parsed query', function () {
68
68
  const s = new RequestParser();
69
69
  const req = createRequestMock({path: '/path?p1=foo&p2=bar'});
70
70
  const res = s.parse(req);
71
71
  expect(res).to.be.eql({
72
72
  query: {p1: 'foo', p2: 'bar'},
73
- cookie: {},
73
+ cookies: {},
74
74
  body: undefined,
75
75
  headers: {host: 'localhost'},
76
76
  });
77
77
  });
78
78
 
79
- it('returns the parsed cookie in the result object', function () {
79
+ it('returns the result object with the parsed cookies', function () {
80
80
  const s = new RequestParser();
81
81
  const req = createRequestMock({headers: {cookie: 'p1=foo; p2=bar;'}});
82
82
  const res = s.parse(req);
83
83
  expect(res).to.be.eql({
84
84
  query: {},
85
- cookie: {p1: 'foo', p2: 'bar'},
85
+ cookies: {p1: 'foo', p2: 'bar'},
86
86
  body: undefined,
87
87
  headers: {
88
88
  host: 'localhost',
@@ -91,7 +91,7 @@ describe('RequestParser', function () {
91
91
  });
92
92
  });
93
93
 
94
- it('returns the parsed body of the media type "text/plain" in the result object', async function () {
94
+ it('returns the result object with the parsed body of the media type "text/plain"', async function () {
95
95
  const s = new RequestParser();
96
96
  const body = 'Lorem Ipsum is simply dummy text.';
97
97
  const req = createRequestMock({
@@ -102,7 +102,7 @@ describe('RequestParser', function () {
102
102
  const res = await s.parse(req);
103
103
  expect(res).to.be.eql({
104
104
  query: {},
105
- cookie: {},
105
+ cookies: {},
106
106
  body,
107
107
  headers: {
108
108
  host: 'localhost',
@@ -112,7 +112,7 @@ describe('RequestParser', function () {
112
112
  });
113
113
  });
114
114
 
115
- it('returns the parsed body of the media type "application/json" in the result object', async function () {
115
+ it('returns the result object with the parsed body of the media type "application/json"', async function () {
116
116
  const s = new RequestParser();
117
117
  const body = {foo: 'bar', baz: 'qux'};
118
118
  const json = JSON.stringify(body);
@@ -124,7 +124,7 @@ describe('RequestParser', function () {
124
124
  const res = await s.parse(req);
125
125
  expect(res).to.be.eql({
126
126
  query: {},
127
- cookie: {},
127
+ cookies: {},
128
128
  body,
129
129
  headers: {
130
130
  host: 'localhost',
@@ -1,7 +1,7 @@
1
1
  import {ServerResponse} from 'http';
2
2
  import {IncomingMessage} from 'http';
3
- import {ParsedCookie} from './utils/index.js';
4
3
  import {ParsedQuery} from './parsers/index.js';
4
+ import {ParsedCookies} from './utils/index.js';
5
5
  import {ParsedHeaders} from './parsers/index.js';
6
6
  import {ServiceContainer} from '@e22m4u/js-service';
7
7
 
@@ -47,9 +47,9 @@ export declare class RequestContext {
47
47
  headers: ParsedHeaders;
48
48
 
49
49
  /**
50
- * Cookie.
50
+ * Cookies.
51
51
  */
52
- cookie: ParsedCookie;
52
+ cookies: ParsedCookies;
53
53
 
54
54
  /**
55
55
  * Body.
@@ -52,11 +52,11 @@ export class RequestContext {
52
52
  headers = {};
53
53
 
54
54
  /**
55
- * Parsed cookie.
55
+ * Parsed cookies.
56
56
  *
57
57
  * @type {object}
58
58
  */
59
- cookie = {};
59
+ cookies = {};
60
60
 
61
61
  /**
62
62
  * Parsed body.
@@ -113,7 +113,7 @@ export class RequestContext {
113
113
  if (!isServiceContainer(container))
114
114
  throw new Errorf(
115
115
  'The parameter "container" of RequestContext.constructor ' +
116
- 'should be an instance of ServiceContainer, but %v given.',
116
+ 'should be an instance of ServiceContainer, but %v was given.',
117
117
  container,
118
118
  );
119
119
  this.container = container;
@@ -125,7 +125,7 @@ export class RequestContext {
125
125
  ) {
126
126
  throw new Errorf(
127
127
  'The parameter "request" of RequestContext.constructor ' +
128
- 'should be an instance of IncomingMessage, but %v given.',
128
+ 'should be an instance of IncomingMessage, but %v was given.',
129
129
  request,
130
130
  );
131
131
  }
@@ -138,7 +138,7 @@ export class RequestContext {
138
138
  ) {
139
139
  throw new Errorf(
140
140
  'The parameter "response" of RequestContext.constructor ' +
141
- 'should be an instance of ServerResponse, but %v given.',
141
+ 'should be an instance of ServerResponse, but %v was given.',
142
142
  response,
143
143
  );
144
144
  }
@@ -14,7 +14,7 @@ describe('RequestContext', function () {
14
14
  const error = v =>
15
15
  format(
16
16
  'The parameter "container" of RequestContext.constructor ' +
17
- 'should be an instance of ServiceContainer, but %s given.',
17
+ 'should be an instance of ServiceContainer, but %s was given.',
18
18
  v,
19
19
  );
20
20
  expect(throwable('str')).to.throw(error('"str"'));
@@ -37,7 +37,7 @@ describe('RequestContext', function () {
37
37
  const error = v =>
38
38
  format(
39
39
  'The parameter "request" of RequestContext.constructor ' +
40
- 'should be an instance of IncomingMessage, but %s given.',
40
+ 'should be an instance of IncomingMessage, but %s was given.',
41
41
  v,
42
42
  );
43
43
  expect(throwable('str')).to.throw(error('"str"'));
@@ -60,7 +60,7 @@ describe('RequestContext', function () {
60
60
  const error = v =>
61
61
  format(
62
62
  'The parameter "response" of RequestContext.constructor ' +
63
- 'should be an instance of ServerResponse, but %s given.',
63
+ 'should be an instance of ServerResponse, but %s was given.',
64
64
  v,
65
65
  );
66
66
  expect(throwable('str')).to.throw(error('"str"'));
@@ -32,16 +32,17 @@ export class RouteRegistry extends DebuggableService {
32
32
  * @returns {Route}
33
33
  */
34
34
  defineRoute(routeDef) {
35
+ const debug = this.getDebuggerFor(this.defineRoute);
35
36
  if (!routeDef || typeof routeDef !== 'object' || Array.isArray(routeDef))
36
37
  throw new Errorf(
37
- 'The route definition should be an Object, but %v given.',
38
+ 'The route definition should be an Object, but %v was given.',
38
39
  routeDef,
39
40
  );
40
41
  const route = new Route(routeDef);
41
42
  const triePath = `${route.method}/${route.path}`;
42
43
  this._trie.add(triePath, route);
43
- this.debug(
44
- 'The route %s %v is registered.',
44
+ debug(
45
+ 'The route %s %v was registered.',
45
46
  route.method.toUpperCase(),
46
47
  route.path,
47
48
  );
@@ -55,9 +56,10 @@ export class RouteRegistry extends DebuggableService {
55
56
  * @returns {ResolvedRoute|undefined}
56
57
  */
57
58
  matchRouteByRequest(req) {
59
+ const debug = this.getDebuggerFor(this.matchRouteByRequest);
58
60
  const requestPath = (req.url || '/').replace(/\?.*$/, '');
59
- this.debug(
60
- 'Matching %s %v with registered routes.',
61
+ debug(
62
+ 'Matching routes with the request %s %v.',
61
63
  req.method.toUpperCase(),
62
64
  requestPath,
63
65
  );
@@ -65,28 +67,26 @@ export class RouteRegistry extends DebuggableService {
65
67
  const resolved = this._trie.match(triePath);
66
68
  if (resolved) {
67
69
  const route = resolved.value;
68
- this.debug(
69
- 'The request %s %v was matched to the route %s %v.',
70
- req.method.toUpperCase(),
71
- requestPath,
70
+ debug(
71
+ 'The route %s %v was matched.',
72
72
  route.method.toUpperCase(),
73
73
  route.path,
74
74
  );
75
75
  const paramNames = Object.keys(resolved.params);
76
- if (paramNames) {
76
+ if (paramNames.length) {
77
77
  paramNames.forEach(name => {
78
- this.debug(
79
- 'The path parameter %v has the value %v.',
78
+ debug(
79
+ 'The path parameter %v had the value %v.',
80
80
  name,
81
81
  resolved.params[name],
82
82
  );
83
83
  });
84
84
  } else {
85
- this.debug('No path parameters found.');
85
+ debug('No path parameters found.');
86
86
  }
87
87
  return {route, params: resolved.params};
88
88
  }
89
- this.debug(
89
+ debug(
90
90
  'No matched route for the request %s %v.',
91
91
  req.method.toUpperCase(),
92
92
  requestPath,
@@ -11,7 +11,10 @@ describe('RouteRegistry', function () {
11
11
  const s = new RouteRegistry();
12
12
  const throwable = v => () => s.defineRoute(v);
13
13
  const error = v =>
14
- format('The route definition should be an Object, but %s given.', v);
14
+ format(
15
+ 'The route definition should be an Object, but %s was given.',
16
+ v,
17
+ );
15
18
  expect(throwable('str')).to.throw(error('"str"'));
16
19
  expect(throwable('')).to.throw(error('""'));
17
20
  expect(throwable(10)).to.throw(error('10'));
package/src/route.d.ts CHANGED
@@ -5,13 +5,18 @@ import {RequestContext} from './request-context.js';
5
5
  /**
6
6
  * Http method.
7
7
  */
8
- export enum HttpMethod {
9
- GET = 'get',
10
- POST = 'post',
11
- PUT = 'put',
12
- PATCH = 'patch',
13
- DELETE = 'delete',
14
- }
8
+ export declare const HttpMethod: {
9
+ GET: 'GET';
10
+ POST: 'POST';
11
+ PUT: 'PUT';
12
+ PATCH: 'PATCH';
13
+ DELETE: 'DELETE';
14
+ };
15
+
16
+ /**
17
+ * Type of HttpMethod.
18
+ */
19
+ export type HttpMethod = (typeof HttpMethod)[keyof typeof HttpMethod];
15
20
 
16
21
  /**
17
22
  * Route handler.
package/src/route.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import {Errorf} from '@e22m4u/js-format';
2
2
  import {HookType} from './hooks/index.js';
3
+ import {Debuggable} from '@e22m4u/js-debug';
3
4
  import {HookRegistry} from './hooks/index.js';
4
- import {createDebugger} from './utils/index.js';
5
5
  import {getRequestPathname} from './utils/index.js';
6
+ import {MODULE_DEBUG_NAMESPACE} from './debuggable-service.js';
6
7
 
7
8
  /**
8
9
  * @typedef {import('./request-context.js').RequestContext} RequestContext
@@ -37,17 +38,10 @@ export const HttpMethod = {
37
38
  DELETE: 'DELETE',
38
39
  };
39
40
 
40
- /**
41
- * Debugger.
42
- *
43
- * @type {Function}
44
- */
45
- const debug = createDebugger('route');
46
-
47
41
  /**
48
42
  * Route.
49
43
  */
50
- export class Route {
44
+ export class Route extends Debuggable {
51
45
  /**
52
46
  * Method.
53
47
  *
@@ -122,29 +116,35 @@ export class Route {
122
116
  * @param {RouteDefinition} routeDef
123
117
  */
124
118
  constructor(routeDef) {
119
+ super({
120
+ namespace: MODULE_DEBUG_NAMESPACE,
121
+ noEnvironmentNamespace: true,
122
+ noInstantiationMessage: true,
123
+ });
125
124
  if (!routeDef || typeof routeDef !== 'object' || Array.isArray(routeDef))
126
125
  throw new Errorf(
127
- 'The first parameter of Route.controller ' +
128
- 'should be an Object, but %v given.',
126
+ 'The first parameter of Route.constructor ' +
127
+ 'should be an Object, but %v was given.',
129
128
  routeDef,
130
129
  );
131
130
  if (!routeDef.method || typeof routeDef.method !== 'string')
132
131
  throw new Errorf(
133
132
  'The option "method" of the Route should be ' +
134
- 'a non-empty String, but %v given.',
133
+ 'a non-empty String, but %v was given.',
135
134
  routeDef.method,
136
135
  );
137
136
  this._method = routeDef.method.toUpperCase();
138
137
  if (typeof routeDef.path !== 'string')
139
138
  throw new Errorf(
140
- 'The option "path" of the Route should be ' + 'a String, but %v given.',
139
+ 'The option "path" of the Route should be ' +
140
+ 'a String, but %v was given.',
141
141
  routeDef.path,
142
142
  );
143
143
  this._path = routeDef.path;
144
144
  if (typeof routeDef.handler !== 'function')
145
145
  throw new Errorf(
146
146
  'The option "handler" of the Route should be ' +
147
- 'a Function, but %v given.',
147
+ 'a Function, but %v was given.',
148
148
  routeDef.handler,
149
149
  );
150
150
  this._handler = routeDef.handler;
@@ -164,6 +164,7 @@ export class Route {
164
164
  this._hookRegistry.addHook(HookType.POST_HANDLER, hook);
165
165
  });
166
166
  }
167
+ this.ctorDebug('A new route %s %v was created.', this._method, this._path);
167
168
  }
168
169
 
169
170
  /**
@@ -173,6 +174,7 @@ export class Route {
173
174
  * @returns {*}
174
175
  */
175
176
  handle(context) {
177
+ const debug = this.getDebuggerFor(this.handle);
176
178
  const requestPath = getRequestPathname(context.req);
177
179
  debug(
178
180
  'Invoking the Route handler for the request %s %v.',
package/src/route.spec.js CHANGED
@@ -14,8 +14,8 @@ describe('Route', function () {
14
14
  const throwable = v => () => new Route(v);
15
15
  const error = v =>
16
16
  format(
17
- 'The first parameter of Route.controller ' +
18
- 'should be an Object, but %s given.',
17
+ 'The first parameter of Route.constructor ' +
18
+ 'should be an Object, but %s was given.',
19
19
  v,
20
20
  );
21
21
  expect(throwable('str')).to.throw(error('"str"'));
@@ -45,7 +45,7 @@ describe('Route', function () {
45
45
  const error = v =>
46
46
  format(
47
47
  'The option "method" of the Route should be ' +
48
- 'a non-empty String, but %s given.',
48
+ 'a non-empty String, but %s was given.',
49
49
  v,
50
50
  );
51
51
  expect(throwable('')).to.throw(error('""'));
@@ -71,7 +71,7 @@ describe('Route', function () {
71
71
  const error = v =>
72
72
  format(
73
73
  'The option "path" of the Route should be ' +
74
- 'a String, but %s given.',
74
+ 'a String, but %s was given.',
75
75
  v,
76
76
  );
77
77
  expect(throwable(10)).to.throw(error('10'));
@@ -97,7 +97,7 @@ describe('Route', function () {
97
97
  const error = v =>
98
98
  format(
99
99
  'The option "handler" of the Route should be ' +
100
- 'a Function, but %s given.',
100
+ 'a Function, but %s was given.',
101
101
  v,
102
102
  );
103
103
  expect(throwable('str')).to.throw(error('"str"'));
@@ -122,7 +122,10 @@ describe('Route', function () {
122
122
  handler: () => undefined,
123
123
  });
124
124
  const error = v =>
125
- format('The hook "preHandler" should be a Function, but %s given.', v);
125
+ format(
126
+ 'The hook "preHandler" should be a Function, but %s was given.',
127
+ v,
128
+ );
126
129
  expect(throwable1('str')).to.throw(error('"str"'));
127
130
  expect(throwable1('')).to.throw(error('""'));
128
131
  expect(throwable1(10)).to.throw(error('10'));
@@ -163,7 +166,10 @@ describe('Route', function () {
163
166
  postHandler: v,
164
167
  });
165
168
  const error = v =>
166
- format('The hook "postHandler" should be a Function, but %s given.', v);
169
+ format(
170
+ 'The hook "postHandler" should be a Function, but %s was given.',
171
+ v,
172
+ );
167
173
  expect(throwable1('str')).to.throw(error('"str"'));
168
174
  expect(throwable1('')).to.throw(error('""'));
169
175
  expect(throwable1(10)).to.throw(error('10'));
@@ -32,7 +32,7 @@ export class RouterOptions extends DebuggableService {
32
32
  if (typeof input !== 'number' || input < 0)
33
33
  throw new Errorf(
34
34
  'The option "requestBodyBytesLimit" must be ' +
35
- 'a positive Number or 0, but %v given.',
35
+ 'a positive Number or 0, but %v was given.',
36
36
  input,
37
37
  );
38
38
  this._requestBodyBytesLimit = input;
@@ -25,7 +25,7 @@ describe('RouterOptions', function () {
25
25
  const error = v =>
26
26
  format(
27
27
  'The option "requestBodyBytesLimit" must be ' +
28
- 'a positive Number or 0, but %s given.',
28
+ 'a positive Number or 0, but %s was given.',
29
29
  v,
30
30
  );
31
31
  expect(throwable('str')).to.throw(error('"str"'));
@@ -14,14 +14,15 @@ export class DataSender extends DebuggableService {
14
14
  * @returns {undefined}
15
15
  */
16
16
  send(res, data) {
17
+ const debug = this.getDebuggerFor(this.send);
17
18
  // если ответ контроллера является объектом
18
19
  // ServerResponse, или имеются отправленные
19
20
  // заголовки, то считаем, что контроллер
20
21
  // уже отправил ответ самостоятельно
21
22
  if (data === res || res.headersSent) {
22
- this.debug(
23
+ debug(
23
24
  'Response sending was skipped because ' +
24
- 'its headers where sent already .',
25
+ 'its headers where sent already.',
25
26
  );
26
27
  return;
27
28
  }
@@ -30,7 +31,7 @@ export class DataSender extends DebuggableService {
30
31
  if (data == null) {
31
32
  res.statusCode = 204;
32
33
  res.end();
33
- this.debug('The empty response was sent.');
34
+ debug('The empty response was sent.');
34
35
  return;
35
36
  }
36
37
  // если ответ контроллера является стримом,
@@ -38,7 +39,7 @@ export class DataSender extends DebuggableService {
38
39
  if (isReadableStream(data)) {
39
40
  res.setHeader('Content-Type', 'application/octet-stream');
40
41
  data.pipe(res);
41
- this.debug('The stream response was sent.');
42
+ debug('The stream response was sent.');
42
43
  return;
43
44
  }
44
45
  // подготовка данных перед отправкой, и установка
@@ -67,6 +68,6 @@ export class DataSender extends DebuggableService {
67
68
  }
68
69
  // отправка подготовленных данных
69
70
  res.end(data);
70
- this.debug(debugMsg);
71
+ debug(debugMsg);
71
72
  }
72
73
  }
@@ -23,6 +23,7 @@ export class ErrorSender extends DebuggableService {
23
23
  * @returns {undefined}
24
24
  */
25
25
  send(req, res, error) {
26
+ const debug = this.getDebuggerFor(this.send);
26
27
  let safeError = {};
27
28
  if (error) {
28
29
  if (typeof error === 'object') {
@@ -54,11 +55,16 @@ export class ErrorSender extends DebuggableService {
54
55
  };
55
56
  console.warn(inspect(requestData, inspectOptions));
56
57
  console.warn(inspect(body, inspectOptions));
58
+ if (error.stack) {
59
+ console.log(error.stack);
60
+ } else {
61
+ console.error(error);
62
+ }
57
63
  res.statusCode = statusCode;
58
64
  res.setHeader('content-type', 'application/json; charset=utf-8');
59
65
  res.end(JSON.stringify(body, null, 2), 'utf-8');
60
- this.debug(
61
- 'The %s error is sent for the request %s %v.',
66
+ debug(
67
+ 'The %s error was sent for the request %s %v.',
62
68
  statusCode,
63
69
  req.method,
64
70
  getRequestPathname(req),
@@ -73,11 +79,12 @@ export class ErrorSender extends DebuggableService {
73
79
  * @returns {undefined}
74
80
  */
75
81
  send404(req, res) {
82
+ const debug = this.getDebuggerFor(this.send404);
76
83
  res.statusCode = 404;
77
84
  res.setHeader('content-type', 'text/plain; charset=utf-8');
78
85
  res.end('404 Not Found', 'utf-8');
79
- this.debug(
80
- 'The 404 error is sent for the request %s %v.',
86
+ debug(
87
+ 'The 404 error was sent for the request %s %v.',
81
88
  req.method,
82
89
  getRequestPathname(req),
83
90
  );