@e22m4u/js-trie-router 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.cjs +1 -0
- package/README.md +49 -36
- package/dist/cjs/index.cjs +216 -157
- package/mocha-setup.js +4 -0
- package/package.json +2 -2
- package/src/debuggable-service.spec.js +1 -1
- package/src/hooks/hook-invoker.spec.js +1 -1
- package/src/hooks/hook-registry.spec.js +1 -1
- package/src/parsers/body-parser.d.ts +2 -2
- package/src/parsers/body-parser.js +6 -6
- package/src/parsers/body-parser.spec.js +2 -2
- package/src/parsers/cookies-parser.d.ts +2 -2
- package/src/parsers/cookies-parser.js +5 -5
- package/src/parsers/cookies-parser.spec.js +1 -1
- package/src/parsers/query-parser.d.ts +2 -2
- package/src/parsers/query-parser.js +5 -5
- package/src/parsers/query-parser.spec.js +1 -1
- package/src/parsers/request-parser.d.ts +2 -2
- package/src/parsers/request-parser.js +8 -8
- package/src/parsers/request-parser.spec.js +1 -1
- package/src/request-context.d.ts +13 -9
- package/src/request-context.js +75 -18
- package/src/request-context.spec.js +46 -18
- package/src/route-registry.d.ts +2 -2
- package/src/route-registry.js +7 -7
- package/src/route-registry.spec.js +1 -1
- package/src/route.js +1 -1
- package/src/route.spec.js +2 -2
- package/src/router-options.spec.js +1 -1
- package/src/senders/data-sender.d.ts +2 -2
- package/src/senders/data-sender.js +11 -11
- package/src/senders/data-sender.spec.js +1 -1
- package/src/senders/error-sender.d.ts +11 -6
- package/src/senders/error-sender.js +19 -19
- package/src/senders/error-sender.spec.js +6 -3
- package/src/trie-router.js +20 -24
- package/src/trie-router.spec.js +37 -25
- package/src/utils/clone-deep.js +1 -1
- package/src/utils/clone-deep.spec.js +1 -1
- package/src/utils/create-cookies-string.spec.js +1 -1
- package/src/utils/create-debugger.spec.js +1 -1
- package/src/utils/create-error.spec.js +1 -1
- package/src/utils/create-request-mock.js +11 -11
- package/src/utils/create-request-mock.spec.js +1 -1
- package/src/utils/create-response-mock.d.ts +2 -1
- package/src/utils/create-response-mock.js +30 -30
- package/src/utils/create-response-mock.spec.js +1 -1
- package/src/utils/create-route-mock.d.ts +19 -0
- package/src/utils/create-route-mock.js +22 -0
- package/src/utils/create-route-mock.spec.js +28 -0
- package/src/utils/fetch-request-body.d.ts +2 -2
- package/src/utils/fetch-request-body.js +16 -13
- package/src/utils/fetch-request-body.spec.js +1 -1
- package/src/utils/get-request-pathname.d.ts +2 -2
- package/src/utils/get-request-pathname.js +8 -8
- package/src/utils/get-request-pathname.spec.js +1 -1
- package/src/utils/index.d.ts +1 -0
- package/src/utils/index.js +1 -0
- package/src/utils/is-promise.spec.js +1 -1
- package/src/utils/is-readable-stream.spec.js +1 -1
- package/src/utils/is-response-sent.d.ts +2 -2
- package/src/utils/is-response-sent.js +8 -8
- package/src/utils/is-response-sent.spec.js +1 -1
- package/src/utils/is-writable-stream.spec.js +1 -1
- package/src/utils/parse-content-type.spec.js +1 -1
- package/src/utils/parse-cookies.spec.js +1 -1
- package/src/utils/to-camel-case.spec.js +1 -1
- package/src/chai.js +0 -7
|
@@ -136,11 +136,11 @@ export function createRequestMock(patch) {
|
|
|
136
136
|
// если передан поток, он будет использован
|
|
137
137
|
// в качестве объекта запроса, в противном
|
|
138
138
|
// случае создается новый
|
|
139
|
-
const
|
|
139
|
+
const request =
|
|
140
140
|
patch.stream ||
|
|
141
141
|
createRequestStream(patch.secure, patch.body, patch.encoding);
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
request.url = createRequestUrl(patch.path || '/', patch.query);
|
|
143
|
+
request.headers = createRequestHeaders(
|
|
144
144
|
patch.host,
|
|
145
145
|
patch.secure,
|
|
146
146
|
patch.body,
|
|
@@ -148,8 +148,8 @@ export function createRequestMock(patch) {
|
|
|
148
148
|
patch.encoding,
|
|
149
149
|
patch.headers,
|
|
150
150
|
);
|
|
151
|
-
|
|
152
|
-
return
|
|
151
|
+
request.method = (patch.method || 'get').toUpperCase();
|
|
152
|
+
return request;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
/**
|
|
@@ -172,22 +172,22 @@ function createRequestStream(secure, body, encoding) {
|
|
|
172
172
|
// использует обертка TLSSocket
|
|
173
173
|
let socket = new Socket();
|
|
174
174
|
if (secure) socket = new TLSSocket(socket);
|
|
175
|
-
const
|
|
175
|
+
const request = new IncomingMessage(socket);
|
|
176
176
|
// тело запроса должно являться
|
|
177
177
|
// строкой или бинарными данными
|
|
178
178
|
if (body != null) {
|
|
179
179
|
if (typeof body === 'string') {
|
|
180
|
-
|
|
180
|
+
request.push(body, encoding);
|
|
181
181
|
} else if (Buffer.isBuffer(body)) {
|
|
182
|
-
|
|
182
|
+
request.push(body);
|
|
183
183
|
} else {
|
|
184
|
-
|
|
184
|
+
request.push(JSON.stringify(body));
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
// передача "null" определяет
|
|
188
188
|
// конец данных
|
|
189
|
-
|
|
190
|
-
return
|
|
189
|
+
request.push(null);
|
|
190
|
+
return request;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {Socket} from 'net';
|
|
2
2
|
import {Stream} from 'stream';
|
|
3
3
|
import {TLSSocket} from 'tls';
|
|
4
|
-
import {expect} from '
|
|
4
|
+
import {expect} from 'chai';
|
|
5
5
|
import {format} from '@e22m4u/js-format';
|
|
6
6
|
import {createRequestMock} from './create-request-mock.js';
|
|
7
7
|
import {CHARACTER_ENCODING_LIST} from './fetch-request-body.js';
|
|
@@ -6,7 +6,8 @@ import {ServerResponse} from 'http';
|
|
|
6
6
|
export type ServerResponseMock = ServerResponse & {
|
|
7
7
|
_headersSent: boolean;
|
|
8
8
|
_headers: {[name: string]: string | undefined};
|
|
9
|
-
|
|
9
|
+
setEncoding(encoding: string): ServerResponseMock;
|
|
10
|
+
getEncoding(): string | undefined;
|
|
10
11
|
getBody(): Promise<string>;
|
|
11
12
|
};
|
|
12
13
|
|
|
@@ -6,32 +6,32 @@ import {PassThrough} from 'stream';
|
|
|
6
6
|
* @returns {import('http').ServerResponse}
|
|
7
7
|
*/
|
|
8
8
|
export function createResponseMock() {
|
|
9
|
-
const
|
|
10
|
-
patchEncoding(
|
|
11
|
-
patchHeaders(
|
|
12
|
-
patchBody(
|
|
13
|
-
return
|
|
9
|
+
const response = new PassThrough();
|
|
10
|
+
patchEncoding(response);
|
|
11
|
+
patchHeaders(response);
|
|
12
|
+
patchBody(response);
|
|
13
|
+
return response;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Patch encoding.
|
|
18
18
|
*
|
|
19
|
-
* @param {object}
|
|
19
|
+
* @param {object} response
|
|
20
20
|
*/
|
|
21
|
-
function patchEncoding(
|
|
22
|
-
Object.defineProperty(
|
|
21
|
+
function patchEncoding(response) {
|
|
22
|
+
Object.defineProperty(response, '_encoding', {
|
|
23
23
|
configurable: true,
|
|
24
24
|
writable: true,
|
|
25
25
|
value: undefined,
|
|
26
26
|
});
|
|
27
|
-
Object.defineProperty(
|
|
27
|
+
Object.defineProperty(response, 'setEncoding', {
|
|
28
28
|
configurable: true,
|
|
29
29
|
value: function (enc) {
|
|
30
30
|
this._encoding = enc;
|
|
31
31
|
return this;
|
|
32
32
|
},
|
|
33
33
|
});
|
|
34
|
-
Object.defineProperty(
|
|
34
|
+
Object.defineProperty(response, 'getEncoding', {
|
|
35
35
|
configurable: true,
|
|
36
36
|
value: function () {
|
|
37
37
|
return this._encoding;
|
|
@@ -42,26 +42,26 @@ function patchEncoding(res) {
|
|
|
42
42
|
/**
|
|
43
43
|
* Patch headers.
|
|
44
44
|
*
|
|
45
|
-
* @param {object}
|
|
45
|
+
* @param {object} response
|
|
46
46
|
*/
|
|
47
|
-
function patchHeaders(
|
|
48
|
-
Object.defineProperty(
|
|
47
|
+
function patchHeaders(response) {
|
|
48
|
+
Object.defineProperty(response, '_headersSent', {
|
|
49
49
|
configurable: true,
|
|
50
50
|
writable: true,
|
|
51
51
|
value: false,
|
|
52
52
|
});
|
|
53
|
-
Object.defineProperty(
|
|
53
|
+
Object.defineProperty(response, 'headersSent', {
|
|
54
54
|
configurable: true,
|
|
55
55
|
get() {
|
|
56
56
|
return this._headersSent;
|
|
57
57
|
},
|
|
58
58
|
});
|
|
59
|
-
Object.defineProperty(
|
|
59
|
+
Object.defineProperty(response, '_headers', {
|
|
60
60
|
configurable: true,
|
|
61
61
|
writable: true,
|
|
62
62
|
value: {},
|
|
63
63
|
});
|
|
64
|
-
Object.defineProperty(
|
|
64
|
+
Object.defineProperty(response, 'setHeader', {
|
|
65
65
|
configurable: true,
|
|
66
66
|
value: function (name, value) {
|
|
67
67
|
if (this.headersSent)
|
|
@@ -74,13 +74,13 @@ function patchHeaders(res) {
|
|
|
74
74
|
return this;
|
|
75
75
|
},
|
|
76
76
|
});
|
|
77
|
-
Object.defineProperty(
|
|
77
|
+
Object.defineProperty(response, 'getHeader', {
|
|
78
78
|
configurable: true,
|
|
79
79
|
value: function (name) {
|
|
80
80
|
return this._headers[name.toLowerCase()];
|
|
81
81
|
},
|
|
82
82
|
});
|
|
83
|
-
Object.defineProperty(
|
|
83
|
+
Object.defineProperty(response, 'getHeaders', {
|
|
84
84
|
configurable: true,
|
|
85
85
|
value: function () {
|
|
86
86
|
return JSON.parse(JSON.stringify(this._headers));
|
|
@@ -91,30 +91,30 @@ function patchHeaders(res) {
|
|
|
91
91
|
/**
|
|
92
92
|
* Patch body.
|
|
93
93
|
*
|
|
94
|
-
* @param {object}
|
|
94
|
+
* @param {object} response
|
|
95
95
|
*/
|
|
96
|
-
function patchBody(
|
|
96
|
+
function patchBody(response) {
|
|
97
97
|
let resolve, reject;
|
|
98
|
-
const promise = new Promise((
|
|
99
|
-
resolve =
|
|
98
|
+
const promise = new Promise((rsv, rej) => {
|
|
99
|
+
resolve = rsv;
|
|
100
100
|
reject = rej;
|
|
101
101
|
});
|
|
102
102
|
const data = [];
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
response.on('data', c => data.push(c));
|
|
104
|
+
response.on('error', e => reject(e));
|
|
105
|
+
response.on('end', () => {
|
|
106
106
|
resolve(Buffer.concat(data));
|
|
107
107
|
});
|
|
108
108
|
// флаг _headersSent должен быть установлен синхронно
|
|
109
|
-
// после вызова метода
|
|
110
|
-
// установка (к примеру в
|
|
109
|
+
// после вызова метода response.end, так как асинхронная
|
|
110
|
+
// установка (к примеру в response.on('end')) не позволит
|
|
111
111
|
// отследить отправку ответа при синхронном выполнении
|
|
112
|
-
const originalEnd =
|
|
113
|
-
|
|
112
|
+
const originalEnd = response.end.bind(response);
|
|
113
|
+
response.end = function (...args) {
|
|
114
114
|
this._headersSent = true;
|
|
115
115
|
return originalEnd(...args);
|
|
116
116
|
};
|
|
117
|
-
Object.defineProperty(
|
|
117
|
+
Object.defineProperty(response, 'getBody', {
|
|
118
118
|
configurable: true,
|
|
119
119
|
value: function () {
|
|
120
120
|
return promise.then(buffer => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {Route, HttpMethod} from '../route.js';
|
|
2
|
+
import type {RouteHandler} from '../route.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Route mock options.
|
|
6
|
+
*/
|
|
7
|
+
type RouteMockOptions = {
|
|
8
|
+
method?: HttpMethod;
|
|
9
|
+
path?: string;
|
|
10
|
+
handler?: RouteHandler;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create route mock.
|
|
15
|
+
*
|
|
16
|
+
* @param {Route} options
|
|
17
|
+
* @returns {Route}
|
|
18
|
+
*/
|
|
19
|
+
export function createRouteMock(options: RouteMockOptions): Route;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {Route, HttpMethod} from '../route.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} RouteMockOptions
|
|
5
|
+
* @property {HttpMethod} method
|
|
6
|
+
* @property {string} path
|
|
7
|
+
* @property {import('../route.js').RouteHandler} handler
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create route mock.
|
|
12
|
+
*
|
|
13
|
+
* @param {Route} options
|
|
14
|
+
* @returns {Route}
|
|
15
|
+
*/
|
|
16
|
+
export function createRouteMock(options = {}) {
|
|
17
|
+
return new Route({
|
|
18
|
+
method: options.method || HttpMethod.GET,
|
|
19
|
+
path: options.path || '/',
|
|
20
|
+
handler: options.handler || (() => 'OK'),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {HttpMethod, Route} from '../route.js';
|
|
3
|
+
import {createRouteMock} from './create-route-mock.js';
|
|
4
|
+
|
|
5
|
+
describe('createRouteMock', function () {
|
|
6
|
+
it('returns an instance of Route with default options', function () {
|
|
7
|
+
const res = createRouteMock();
|
|
8
|
+
expect(res).to.be.instanceof(Route);
|
|
9
|
+
expect(res.method).to.be.eq(HttpMethod.GET);
|
|
10
|
+
expect(res.path).to.be.eq('/');
|
|
11
|
+
expect(res.handler()).to.be.eq('OK');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('sets the "method" option', function () {
|
|
15
|
+
const res = createRouteMock({method: HttpMethod.POST});
|
|
16
|
+
expect(res.method).to.be.eq(HttpMethod.POST);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('sets the "path" option', function () {
|
|
20
|
+
const res = createRouteMock({path: 'test'});
|
|
21
|
+
expect(res.path).to.be.eq('test');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('sets the "handler" option', function () {
|
|
25
|
+
const res = createRouteMock({handler: () => 'Hey!'});
|
|
26
|
+
expect(res.handler()).to.be.eq('Hey!');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -17,10 +17,10 @@ export const CHARACTER_ENCODING_LIST: (
|
|
|
17
17
|
/**
|
|
18
18
|
* Fetch request body.
|
|
19
19
|
*
|
|
20
|
-
* @param
|
|
20
|
+
* @param request
|
|
21
21
|
* @param bodyBytesLimit
|
|
22
22
|
*/
|
|
23
23
|
export declare function fetchRequestBody(
|
|
24
|
-
|
|
24
|
+
request: IncomingMessage,
|
|
25
25
|
bodyBytesLimit?: number,
|
|
26
26
|
): Promise<string>;
|
|
@@ -21,16 +21,16 @@ export const CHARACTER_ENCODING_LIST = [
|
|
|
21
21
|
/**
|
|
22
22
|
* Fetch request body.
|
|
23
23
|
*
|
|
24
|
-
* @param {IncomingMessage}
|
|
24
|
+
* @param {IncomingMessage} request
|
|
25
25
|
* @param {number} bodyBytesLimit
|
|
26
26
|
* @returns {Promise<string|undefined>}
|
|
27
27
|
*/
|
|
28
|
-
export function fetchRequestBody(
|
|
29
|
-
if (!(
|
|
28
|
+
export function fetchRequestBody(request, bodyBytesLimit = 0) {
|
|
29
|
+
if (!(request instanceof IncomingMessage))
|
|
30
30
|
throw new Errorf(
|
|
31
31
|
'The first parameter of "fetchRequestBody" should be ' +
|
|
32
32
|
'an IncomingMessage instance, but %v was given.',
|
|
33
|
-
|
|
33
|
+
request,
|
|
34
34
|
);
|
|
35
35
|
if (typeof bodyBytesLimit !== 'number')
|
|
36
36
|
throw new Errorf(
|
|
@@ -42,7 +42,10 @@ export function fetchRequestBody(req, bodyBytesLimit = 0) {
|
|
|
42
42
|
// сравнение внутреннего ограничения
|
|
43
43
|
// размера тела запроса с заголовком
|
|
44
44
|
// "content-length"
|
|
45
|
-
const contentLength = parseInt(
|
|
45
|
+
const contentLength = parseInt(
|
|
46
|
+
request.headers['content-length'] || '0',
|
|
47
|
+
10,
|
|
48
|
+
);
|
|
46
49
|
if (bodyBytesLimit && contentLength && contentLength > bodyBytesLimit)
|
|
47
50
|
throw createError(
|
|
48
51
|
HttpErrors.PayloadTooLarge,
|
|
@@ -53,7 +56,7 @@ export function fetchRequestBody(req, bodyBytesLimit = 0) {
|
|
|
53
56
|
// определение кодировки
|
|
54
57
|
// по заголовку "content-type"
|
|
55
58
|
let encoding = 'utf-8';
|
|
56
|
-
const contentType =
|
|
59
|
+
const contentType = request.headers['content-type'] || '';
|
|
57
60
|
if (contentType) {
|
|
58
61
|
const parsedContentType = parseContentType(contentType);
|
|
59
62
|
if (parsedContentType && parsedContentType.charset) {
|
|
@@ -75,7 +78,7 @@ export function fetchRequestBody(req, bodyBytesLimit = 0) {
|
|
|
75
78
|
const onData = chunk => {
|
|
76
79
|
receivedLength += chunk.length;
|
|
77
80
|
if (bodyBytesLimit && receivedLength > bodyBytesLimit) {
|
|
78
|
-
|
|
81
|
+
request.removeAllListeners();
|
|
79
82
|
const error = createError(
|
|
80
83
|
HttpErrors.PayloadTooLarge,
|
|
81
84
|
'Request body limit is %v bytes, but %v bytes given.',
|
|
@@ -91,7 +94,7 @@ export function fetchRequestBody(req, bodyBytesLimit = 0) {
|
|
|
91
94
|
// обработчики событий, и сравнить полученный объем
|
|
92
95
|
// данных с заявленным в заголовке "content-length"
|
|
93
96
|
const onEnd = () => {
|
|
94
|
-
|
|
97
|
+
request.removeAllListeners();
|
|
95
98
|
if (contentLength && contentLength !== receivedLength) {
|
|
96
99
|
const error = createError(
|
|
97
100
|
HttpErrors.BadRequest,
|
|
@@ -112,15 +115,15 @@ export function fetchRequestBody(req, bodyBytesLimit = 0) {
|
|
|
112
115
|
// и отклоняется ожидающий Promise
|
|
113
116
|
// ошибкой с кодом 400
|
|
114
117
|
const onError = error => {
|
|
115
|
-
|
|
118
|
+
request.removeAllListeners();
|
|
116
119
|
reject(HttpErrors(400, error));
|
|
117
120
|
};
|
|
118
121
|
// добавление обработчиков прослушивающих
|
|
119
122
|
// события входящего запроса и возобновление
|
|
120
123
|
// потока данных
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
request.on('data', onData);
|
|
125
|
+
request.on('end', onEnd);
|
|
126
|
+
request.on('error', onError);
|
|
127
|
+
request.resume();
|
|
125
128
|
});
|
|
126
129
|
}
|
|
@@ -3,6 +3,6 @@ import {IncomingMessage} from 'http';
|
|
|
3
3
|
/**
|
|
4
4
|
* Get request pathname.
|
|
5
5
|
*
|
|
6
|
-
* @param
|
|
6
|
+
* @param request
|
|
7
7
|
*/
|
|
8
|
-
export declare function getRequestPathname(
|
|
8
|
+
export declare function getRequestPathname(request: IncomingMessage): string;
|
|
@@ -3,21 +3,21 @@ import {Errorf} from '@e22m4u/js-format';
|
|
|
3
3
|
/**
|
|
4
4
|
* Get request pathname.
|
|
5
5
|
*
|
|
6
|
-
* @param {import('http').IncomingMessage}
|
|
6
|
+
* @param {import('http').IncomingMessage} request
|
|
7
7
|
* @returns {string}
|
|
8
8
|
*/
|
|
9
|
-
export function getRequestPathname(
|
|
9
|
+
export function getRequestPathname(request) {
|
|
10
10
|
if (
|
|
11
|
-
!
|
|
12
|
-
typeof
|
|
13
|
-
Array.isArray(
|
|
14
|
-
typeof
|
|
11
|
+
!request ||
|
|
12
|
+
typeof request !== 'object' ||
|
|
13
|
+
Array.isArray(request) ||
|
|
14
|
+
typeof request.url !== 'string'
|
|
15
15
|
) {
|
|
16
16
|
throw new Errorf(
|
|
17
17
|
'The first argument of "getRequestPathname" should be ' +
|
|
18
18
|
'an instance of IncomingMessage, but %v was given.',
|
|
19
|
-
|
|
19
|
+
request,
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
|
-
return (
|
|
22
|
+
return (request.url || '/').replace(/\?.*$/, '');
|
|
23
23
|
}
|
package/src/utils/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './parse-cookies.js';
|
|
|
5
5
|
export * from './to-camel-case.js';
|
|
6
6
|
export * from './create-debugger.js';
|
|
7
7
|
export * from './is-response-sent.js';
|
|
8
|
+
export * from './create-route-mock.js';
|
|
8
9
|
export * from './is-readable-stream.js';
|
|
9
10
|
export * from './parse-content-type.js';
|
|
10
11
|
export * from './is-writable-stream.js';
|
package/src/utils/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export * from './parse-cookies.js';
|
|
|
5
5
|
export * from './to-camel-case.js';
|
|
6
6
|
export * from './create-debugger.js';
|
|
7
7
|
export * from './is-response-sent.js';
|
|
8
|
+
export * from './create-route-mock.js';
|
|
8
9
|
export * from './is-readable-stream.js';
|
|
9
10
|
export * from './parse-content-type.js';
|
|
10
11
|
export * from './is-writable-stream.js';
|
|
@@ -3,21 +3,21 @@ import {Errorf} from '@e22m4u/js-format';
|
|
|
3
3
|
/**
|
|
4
4
|
* Is response sent.
|
|
5
5
|
*
|
|
6
|
-
* @param {import('http').ServerResponse}
|
|
6
|
+
* @param {import('http').ServerResponse} response
|
|
7
7
|
* @returns {boolean}
|
|
8
8
|
*/
|
|
9
|
-
export function isResponseSent(
|
|
9
|
+
export function isResponseSent(response) {
|
|
10
10
|
if (
|
|
11
|
-
!
|
|
12
|
-
typeof
|
|
13
|
-
Array.isArray(
|
|
14
|
-
typeof
|
|
11
|
+
!response ||
|
|
12
|
+
typeof response !== 'object' ||
|
|
13
|
+
Array.isArray(response) ||
|
|
14
|
+
typeof response.headersSent !== 'boolean'
|
|
15
15
|
) {
|
|
16
16
|
throw new Errorf(
|
|
17
17
|
'The first argument of "isResponseSent" should be ' +
|
|
18
18
|
'an instance of ServerResponse, but %v was given.',
|
|
19
|
-
|
|
19
|
+
response,
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
|
-
return
|
|
22
|
+
return response.headersSent;
|
|
23
23
|
}
|