@e22m4u/js-trie-router 0.6.0 → 0.6.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/dist/cjs/index.cjs +160 -98
- package/package.json +4 -4
- package/src/branch/merge-router-branch-definition.spec.js +17 -15
- package/src/branch/router-branch.js +4 -3
- package/src/branch/router-branch.spec.js +71 -9
- package/src/branch/validate-router-branch-definition.js +4 -3
- package/src/branch/validate-router-branch-definition.spec.js +16 -16
- package/src/debuggable-service.spec.js +10 -2
- package/src/hooks/router-hook-invoker.js +5 -3
- package/src/hooks/router-hook-invoker.spec.js +19 -17
- package/src/hooks/router-hook-registry.spec.js +32 -18
- package/src/parsers/body-parser.d.ts +11 -4
- package/src/parsers/body-parser.js +28 -12
- package/src/parsers/body-parser.spec.js +136 -92
- package/src/parsers/cookies-parser.spec.js +3 -3
- package/src/parsers/query-parser.spec.js +3 -3
- package/src/parsers/request-parser.js +2 -2
- package/src/parsers/request-parser.spec.js +9 -9
- package/src/request-context.js +7 -8
- package/src/request-context.spec.js +17 -18
- package/src/route/route.d.ts +1 -0
- package/src/route/route.js +2 -0
- package/src/route/route.spec.js +30 -30
- package/src/route/validate-route-definition.js +6 -4
- package/src/route/validate-route-definition.spec.js +16 -16
- package/src/route-registry.d.ts +8 -1
- package/src/route-registry.js +35 -5
- package/src/route-registry.spec.js +98 -7
- package/src/router-options.js +2 -2
- package/src/router-options.spec.js +6 -6
- package/src/senders/data-sender.spec.js +7 -7
- package/src/senders/error-sender.spec.js +3 -3
- package/src/trie-router.d.ts +6 -6
- package/src/trie-router.js +25 -3
- package/src/trie-router.spec.js +150 -22
- package/src/utils/clone-deep.spec.js +7 -7
- package/src/utils/create-cookie-string.js +1 -2
- package/src/utils/create-cookie-string.spec.js +4 -8
- package/src/utils/create-error.js +2 -4
- package/src/utils/create-error.spec.js +5 -13
- package/src/utils/create-request-mock.d.ts +4 -4
- package/src/utils/create-request-mock.js +73 -90
- package/src/utils/create-request-mock.spec.js +61 -98
- package/src/utils/create-response-mock.d.ts +1 -0
- package/src/utils/create-response-mock.js +1 -0
- package/src/utils/create-response-mock.spec.js +20 -13
- package/src/utils/create-route-mock.spec.js +4 -4
- package/src/utils/fetch-request-body.js +3 -4
- package/src/utils/fetch-request-body.spec.js +22 -23
- package/src/utils/get-request-pathname.js +2 -2
- package/src/utils/get-request-pathname.spec.js +11 -4
- package/src/utils/is-promise.spec.js +2 -2
- package/src/utils/is-readable-stream.spec.js +2 -2
- package/src/utils/is-response-sent.js +2 -2
- package/src/utils/is-response-sent.spec.js +5 -5
- package/src/utils/is-writable-stream.spec.js +2 -2
- package/src/utils/merge-deep.spec.js +2 -2
- package/src/utils/parse-content-type.js +1 -2
- package/src/utils/parse-content-type.spec.js +7 -11
- package/src/utils/parse-cookie-string.js +1 -2
- package/src/utils/parse-cookie-string.spec.js +2 -6
- package/src/utils/to-camel-case.js +1 -2
- package/src/utils/to-camel-case.spec.js +3 -7
- package/src/utils/to-pascal-case.spec.js +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -166,13 +166,13 @@ var import_js_format = require("@e22m4u/js-format");
|
|
|
166
166
|
function createError(errorCtor, message, ...args) {
|
|
167
167
|
if (typeof errorCtor !== "function") {
|
|
168
168
|
throw new import_js_format.InvalidArgumentError(
|
|
169
|
-
'
|
|
169
|
+
'Parameter "errorCtor" must be a Function, but %v was given.',
|
|
170
170
|
errorCtor
|
|
171
171
|
);
|
|
172
172
|
}
|
|
173
173
|
if (message != null && typeof message !== "string") {
|
|
174
174
|
throw new import_js_format.InvalidArgumentError(
|
|
175
|
-
'
|
|
175
|
+
'Parameter "message" must be a String, but %v was given.',
|
|
176
176
|
message
|
|
177
177
|
);
|
|
178
178
|
}
|
|
@@ -189,7 +189,7 @@ var import_js_format2 = require("@e22m4u/js-format");
|
|
|
189
189
|
function toCamelCase(input) {
|
|
190
190
|
if (typeof input !== "string") {
|
|
191
191
|
throw new import_js_format2.InvalidArgumentError(
|
|
192
|
-
'
|
|
192
|
+
'Parameter "input" must be a String, but %v was given.',
|
|
193
193
|
input
|
|
194
194
|
);
|
|
195
195
|
}
|
|
@@ -211,7 +211,7 @@ var import_js_format3 = require("@e22m4u/js-format");
|
|
|
211
211
|
function isResponseSent(response) {
|
|
212
212
|
if (!response || typeof response !== "object" || Array.isArray(response) || typeof response.headersSent !== "boolean") {
|
|
213
213
|
throw new import_js_format3.InvalidArgumentError(
|
|
214
|
-
'
|
|
214
|
+
'Parameter "response" must be an instance of ServerResponse, but %v was given.',
|
|
215
215
|
response
|
|
216
216
|
);
|
|
217
217
|
}
|
|
@@ -243,7 +243,7 @@ var import_js_format4 = require("@e22m4u/js-format");
|
|
|
243
243
|
function parseContentType(input) {
|
|
244
244
|
if (typeof input !== "string") {
|
|
245
245
|
throw new import_js_format4.InvalidArgumentError(
|
|
246
|
-
"
|
|
246
|
+
'Parameter "input" must be a String, but %v was given.',
|
|
247
247
|
input
|
|
248
248
|
);
|
|
249
249
|
}
|
|
@@ -289,13 +289,13 @@ var CHARACTER_ENCODING_LIST = [
|
|
|
289
289
|
function fetchRequestBody(request, bodyBytesLimit = 0) {
|
|
290
290
|
if (!(request instanceof import_http.IncomingMessage)) {
|
|
291
291
|
throw new import_js_format5.InvalidArgumentError(
|
|
292
|
-
'
|
|
292
|
+
'Parameter "request" must be an instance of IncomingMessage, but %v was given.',
|
|
293
293
|
request
|
|
294
294
|
);
|
|
295
295
|
}
|
|
296
296
|
if (typeof bodyBytesLimit !== "number") {
|
|
297
297
|
throw new import_js_format5.InvalidArgumentError(
|
|
298
|
-
'
|
|
298
|
+
'Parameter "bodyBytesLimit" must be a Number, but %v was given.',
|
|
299
299
|
bodyBytesLimit
|
|
300
300
|
);
|
|
301
301
|
}
|
|
@@ -382,7 +382,7 @@ var import_js_format6 = require("@e22m4u/js-format");
|
|
|
382
382
|
function parseCookieString(input) {
|
|
383
383
|
if (typeof input !== "string") {
|
|
384
384
|
throw new import_js_format6.InvalidArgumentError(
|
|
385
|
-
'
|
|
385
|
+
'Parameter "input" must be a String, but %v was given.',
|
|
386
386
|
input
|
|
387
387
|
);
|
|
388
388
|
}
|
|
@@ -410,7 +410,7 @@ var import_js_format7 = require("@e22m4u/js-format");
|
|
|
410
410
|
function createCookieString(data) {
|
|
411
411
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
412
412
|
throw new import_js_format7.InvalidArgumentError(
|
|
413
|
-
|
|
413
|
+
"Cookie data must be an Object, but %v was given.",
|
|
414
414
|
data
|
|
415
415
|
);
|
|
416
416
|
}
|
|
@@ -430,111 +430,111 @@ function createCookieString(data) {
|
|
|
430
430
|
__name(createCookieString, "createCookieString");
|
|
431
431
|
|
|
432
432
|
// src/utils/create-request-mock.js
|
|
433
|
-
function createRequestMock(
|
|
434
|
-
if (
|
|
433
|
+
function createRequestMock(options) {
|
|
434
|
+
if (options != null && typeof options !== "object" || Array.isArray(options)) {
|
|
435
435
|
throw new import_js_format8.InvalidArgumentError(
|
|
436
|
-
'
|
|
437
|
-
|
|
436
|
+
'Parameter "options" must be an Object, but %v was given.',
|
|
437
|
+
options
|
|
438
438
|
);
|
|
439
439
|
}
|
|
440
|
-
|
|
441
|
-
if (
|
|
440
|
+
options = options || {};
|
|
441
|
+
if (options.host != null && typeof options.host !== "string") {
|
|
442
442
|
throw new import_js_format8.InvalidArgumentError(
|
|
443
|
-
'
|
|
444
|
-
|
|
443
|
+
'Option "host" must be a String, but %v was given.',
|
|
444
|
+
options.host
|
|
445
445
|
);
|
|
446
446
|
}
|
|
447
|
-
if (
|
|
447
|
+
if (options.method != null && typeof options.method !== "string") {
|
|
448
448
|
throw new import_js_format8.InvalidArgumentError(
|
|
449
|
-
'
|
|
450
|
-
|
|
449
|
+
'Option "method" must be a String, but %v was given.',
|
|
450
|
+
options.method
|
|
451
451
|
);
|
|
452
452
|
}
|
|
453
|
-
if (
|
|
453
|
+
if (options.secure != null && typeof options.secure !== "boolean") {
|
|
454
454
|
throw new import_js_format8.InvalidArgumentError(
|
|
455
|
-
'
|
|
456
|
-
|
|
455
|
+
'Option "secure" must be a Boolean, but %v was given.',
|
|
456
|
+
options.secure
|
|
457
457
|
);
|
|
458
458
|
}
|
|
459
|
-
if (
|
|
459
|
+
if (options.path != null && typeof options.path !== "string") {
|
|
460
460
|
throw new import_js_format8.InvalidArgumentError(
|
|
461
|
-
'
|
|
462
|
-
|
|
461
|
+
'Option "path" must be a String, but %v was given.',
|
|
462
|
+
options.path
|
|
463
463
|
);
|
|
464
464
|
}
|
|
465
|
-
if (
|
|
465
|
+
if (options.query != null && typeof options.query !== "object" && typeof options.query !== "string" || Array.isArray(options.query)) {
|
|
466
466
|
throw new import_js_format8.InvalidArgumentError(
|
|
467
|
-
'
|
|
468
|
-
|
|
467
|
+
'Option "query" must be a String or Object, but %v was given.',
|
|
468
|
+
options.query
|
|
469
469
|
);
|
|
470
470
|
}
|
|
471
|
-
if (
|
|
471
|
+
if (options.cookies != null && typeof options.cookies !== "string" && typeof options.cookies !== "object" || Array.isArray(options.cookies)) {
|
|
472
472
|
throw new import_js_format8.InvalidArgumentError(
|
|
473
|
-
'
|
|
474
|
-
|
|
473
|
+
'Option "cookies" must be a String or Object, but %v was given.',
|
|
474
|
+
options.cookies
|
|
475
475
|
);
|
|
476
476
|
}
|
|
477
|
-
if (
|
|
477
|
+
if (options.headers != null && typeof options.headers !== "object" || Array.isArray(options.headers)) {
|
|
478
478
|
throw new import_js_format8.InvalidArgumentError(
|
|
479
|
-
'
|
|
480
|
-
|
|
479
|
+
'Option "headers" must be an Object, but %v was given.',
|
|
480
|
+
options.headers
|
|
481
481
|
);
|
|
482
482
|
}
|
|
483
|
-
if (
|
|
483
|
+
if (options.stream != null && !isReadableStream(options.stream)) {
|
|
484
484
|
throw new import_js_format8.InvalidArgumentError(
|
|
485
|
-
'
|
|
486
|
-
|
|
485
|
+
'Option "stream" must be a Stream, but %v was given.',
|
|
486
|
+
options.stream
|
|
487
487
|
);
|
|
488
488
|
}
|
|
489
|
-
if (
|
|
490
|
-
if (typeof
|
|
489
|
+
if (options.encoding != null) {
|
|
490
|
+
if (typeof options.encoding !== "string") {
|
|
491
491
|
throw new import_js_format8.InvalidArgumentError(
|
|
492
|
-
'
|
|
493
|
-
|
|
492
|
+
'Option "encoding" must be a String, but %v was given.',
|
|
493
|
+
options.encoding
|
|
494
494
|
);
|
|
495
495
|
}
|
|
496
|
-
if (!CHARACTER_ENCODING_LIST.includes(
|
|
496
|
+
if (!CHARACTER_ENCODING_LIST.includes(options.encoding)) {
|
|
497
497
|
throw new import_js_format8.InvalidArgumentError(
|
|
498
498
|
"Character encoding %v is not supported.",
|
|
499
|
-
|
|
499
|
+
options.encoding
|
|
500
500
|
);
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
|
-
if (
|
|
504
|
-
if (
|
|
503
|
+
if (options.stream) {
|
|
504
|
+
if (options.secure != null) {
|
|
505
505
|
throw new import_js_format8.InvalidArgumentError(
|
|
506
|
-
'The "
|
|
506
|
+
'The "stream" and "secure" options cannot be used together.'
|
|
507
507
|
);
|
|
508
508
|
}
|
|
509
|
-
if (
|
|
509
|
+
if (options.body != null) {
|
|
510
510
|
throw new import_js_format8.InvalidArgumentError(
|
|
511
|
-
'The "
|
|
511
|
+
'The "stream" and "body" options cannot be used together.'
|
|
512
512
|
);
|
|
513
513
|
}
|
|
514
|
-
if (
|
|
514
|
+
if (options.encoding != null) {
|
|
515
515
|
throw new import_js_format8.InvalidArgumentError(
|
|
516
|
-
'The "
|
|
516
|
+
'The "stream" and "encoding" options cannot be used together.'
|
|
517
517
|
);
|
|
518
518
|
}
|
|
519
519
|
}
|
|
520
|
-
const request =
|
|
521
|
-
request.url = createRequestUrl(
|
|
520
|
+
const request = options.stream || createRequestStream(options.secure, options.body, options.encoding);
|
|
521
|
+
request.url = createRequestUrl(options.path || "/", options.query);
|
|
522
522
|
request.headers = createRequestHeaders(
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
523
|
+
options.host,
|
|
524
|
+
options.secure,
|
|
525
|
+
options.body,
|
|
526
|
+
options.cookies,
|
|
527
|
+
options.encoding,
|
|
528
|
+
options.headers
|
|
529
529
|
);
|
|
530
|
-
request.method = (
|
|
530
|
+
request.method = (options.method || "get").toUpperCase();
|
|
531
531
|
return request;
|
|
532
532
|
}
|
|
533
533
|
__name(createRequestMock, "createRequestMock");
|
|
534
534
|
function createRequestStream(secure, body, encoding) {
|
|
535
535
|
if (encoding != null && typeof encoding !== "string") {
|
|
536
536
|
throw new import_js_format8.InvalidArgumentError(
|
|
537
|
-
'
|
|
537
|
+
'Parameter "encoding" must be a String, but %v was given.',
|
|
538
538
|
encoding
|
|
539
539
|
);
|
|
540
540
|
}
|
|
@@ -560,13 +560,13 @@ __name(createRequestStream, "createRequestStream");
|
|
|
560
560
|
function createRequestUrl(path, query) {
|
|
561
561
|
if (typeof path !== "string") {
|
|
562
562
|
throw new import_js_format8.InvalidArgumentError(
|
|
563
|
-
'
|
|
563
|
+
'Parameter "path" must be a String, but %v was given.',
|
|
564
564
|
path
|
|
565
565
|
);
|
|
566
566
|
}
|
|
567
567
|
if (query != null && typeof query !== "string" && typeof query !== "object" || Array.isArray(query)) {
|
|
568
568
|
throw new import_js_format8.InvalidArgumentError(
|
|
569
|
-
'
|
|
569
|
+
'Parameter "query" must be a String or Object, but %v was given.',
|
|
570
570
|
query
|
|
571
571
|
);
|
|
572
572
|
}
|
|
@@ -585,34 +585,34 @@ __name(createRequestUrl, "createRequestUrl");
|
|
|
585
585
|
function createRequestHeaders(host, secure, body, cookies, encoding, headers) {
|
|
586
586
|
if (host != null && typeof host !== "string") {
|
|
587
587
|
throw new import_js_format8.InvalidArgumentError(
|
|
588
|
-
'
|
|
588
|
+
'Parameter "host" must be a non-empty String, but %v was given.',
|
|
589
589
|
host
|
|
590
590
|
);
|
|
591
591
|
}
|
|
592
592
|
host = host || "localhost";
|
|
593
593
|
if (secure != null && typeof secure !== "boolean") {
|
|
594
594
|
throw new import_js_format8.InvalidArgumentError(
|
|
595
|
-
'
|
|
595
|
+
'Parameter "secure" must be a String, but %v was given.',
|
|
596
596
|
secure
|
|
597
597
|
);
|
|
598
598
|
}
|
|
599
599
|
secure = Boolean(secure);
|
|
600
600
|
if (cookies != null && typeof cookies !== "object" && typeof cookies !== "string" || Array.isArray(cookies)) {
|
|
601
601
|
throw new import_js_format8.InvalidArgumentError(
|
|
602
|
-
'
|
|
602
|
+
'Parameter "cookies" must be a String or an Object, but %v was given.',
|
|
603
603
|
cookies
|
|
604
604
|
);
|
|
605
605
|
}
|
|
606
606
|
if (headers != null && typeof headers !== "object" || Array.isArray(headers)) {
|
|
607
607
|
throw new import_js_format8.InvalidArgumentError(
|
|
608
|
-
'
|
|
608
|
+
'Parameter "headers" must be an Object, but %v was given.',
|
|
609
609
|
headers
|
|
610
610
|
);
|
|
611
611
|
}
|
|
612
612
|
headers = headers || {};
|
|
613
613
|
if (encoding != null && typeof encoding !== "string") {
|
|
614
614
|
throw new import_js_format8.InvalidArgumentError(
|
|
615
|
-
'
|
|
615
|
+
'Parameter "encoding" must be a String, but %v was given.',
|
|
616
616
|
encoding
|
|
617
617
|
);
|
|
618
618
|
}
|
|
@@ -662,6 +662,7 @@ __name(createRequestHeaders, "createRequestHeaders");
|
|
|
662
662
|
var import_stream = require("stream");
|
|
663
663
|
function createResponseMock() {
|
|
664
664
|
const response = new import_stream.PassThrough();
|
|
665
|
+
response.statusCode = 200;
|
|
665
666
|
patchEncoding(response);
|
|
666
667
|
patchHeaders(response);
|
|
667
668
|
patchBody(response);
|
|
@@ -768,7 +769,7 @@ var import_js_format9 = require("@e22m4u/js-format");
|
|
|
768
769
|
function getRequestPathname(request) {
|
|
769
770
|
if (!request || typeof request !== "object" || Array.isArray(request) || typeof request.url !== "string") {
|
|
770
771
|
throw new import_js_format9.InvalidArgumentError(
|
|
771
|
-
'
|
|
772
|
+
'Parameter "request" must be an instance of IncomingMessage, but %v was given.',
|
|
772
773
|
request
|
|
773
774
|
);
|
|
774
775
|
}
|
|
@@ -891,7 +892,7 @@ var _RouterHookInvoker = class _RouterHookInvoker extends DebuggableService {
|
|
|
891
892
|
invokeAndContinueUntilValueReceived(route, hookType, response, ...args) {
|
|
892
893
|
if (!route || !(route instanceof Route)) {
|
|
893
894
|
throw new import_js_format11.InvalidArgumentError(
|
|
894
|
-
'Parameter "route" must be
|
|
895
|
+
'Parameter "route" must be an instance of Route, but %v was given.',
|
|
895
896
|
route
|
|
896
897
|
);
|
|
897
898
|
}
|
|
@@ -909,7 +910,7 @@ var _RouterHookInvoker = class _RouterHookInvoker extends DebuggableService {
|
|
|
909
910
|
}
|
|
910
911
|
if (!response || typeof response !== "object" || Array.isArray(response) || typeof response.headersSent !== "boolean") {
|
|
911
912
|
throw new import_js_format11.InvalidArgumentError(
|
|
912
|
-
'Parameter "response" must be
|
|
913
|
+
'Parameter "response" must be an instance of ServerResponse, but %v was given.',
|
|
913
914
|
response
|
|
914
915
|
);
|
|
915
916
|
}
|
|
@@ -1018,7 +1019,7 @@ function validateRouteDefinition(routeDef) {
|
|
|
1018
1019
|
routeDef.preHandler.forEach((preHandler) => {
|
|
1019
1020
|
if (typeof preHandler !== "function") {
|
|
1020
1021
|
throw new import_js_format12.InvalidArgumentError(
|
|
1021
|
-
"
|
|
1022
|
+
'Hook "preHandler" must be a Function, but %v was given.',
|
|
1022
1023
|
preHandler
|
|
1023
1024
|
);
|
|
1024
1025
|
}
|
|
@@ -1035,7 +1036,7 @@ function validateRouteDefinition(routeDef) {
|
|
|
1035
1036
|
routeDef.postHandler.forEach((postHandler) => {
|
|
1036
1037
|
if (typeof postHandler !== "function") {
|
|
1037
1038
|
throw new import_js_format12.InvalidArgumentError(
|
|
1038
|
-
"
|
|
1039
|
+
'Hook "postHandler" must be a Function, but %v was given.',
|
|
1039
1040
|
postHandler
|
|
1040
1041
|
);
|
|
1041
1042
|
}
|
|
@@ -1064,7 +1065,8 @@ var HttpMethod = {
|
|
|
1064
1065
|
POST: "POST",
|
|
1065
1066
|
PUT: "PUT",
|
|
1066
1067
|
PATCH: "PATCH",
|
|
1067
|
-
DELETE: "DELETE"
|
|
1068
|
+
DELETE: "DELETE",
|
|
1069
|
+
OPTIONS: "OPTIONS"
|
|
1068
1070
|
};
|
|
1069
1071
|
var DEFAULT_META = Object.freeze({});
|
|
1070
1072
|
var _Route = class _Route extends import_js_debug.Debuggable {
|
|
@@ -1203,7 +1205,7 @@ var _RouterOptions = class _RouterOptions extends DebuggableService {
|
|
|
1203
1205
|
setRequestBodyBytesLimit(input) {
|
|
1204
1206
|
if (typeof input !== "number" || input < 0) {
|
|
1205
1207
|
throw new import_js_format13.InvalidArgumentError(
|
|
1206
|
-
'
|
|
1208
|
+
'Option "requestBodyBytesLimit" must be a positive Number or 0, but %v was given.',
|
|
1207
1209
|
input
|
|
1208
1210
|
);
|
|
1209
1211
|
}
|
|
@@ -1238,13 +1240,13 @@ var _BodyParser = class _BodyParser extends DebuggableService {
|
|
|
1238
1240
|
defineParser(mediaType, parser) {
|
|
1239
1241
|
if (!mediaType || typeof mediaType !== "string") {
|
|
1240
1242
|
throw new import_js_format14.InvalidArgumentError(
|
|
1241
|
-
'
|
|
1243
|
+
'Parameter "mediaType" must be a non-empty String, but %v was given.',
|
|
1242
1244
|
mediaType
|
|
1243
1245
|
);
|
|
1244
1246
|
}
|
|
1245
1247
|
if (!parser || typeof parser !== "function") {
|
|
1246
1248
|
throw new import_js_format14.InvalidArgumentError(
|
|
1247
|
-
'
|
|
1249
|
+
'Parameter "parser" must be a Function, but %v was given.',
|
|
1248
1250
|
parser
|
|
1249
1251
|
);
|
|
1250
1252
|
}
|
|
@@ -1260,29 +1262,44 @@ var _BodyParser = class _BodyParser extends DebuggableService {
|
|
|
1260
1262
|
hasParser(mediaType) {
|
|
1261
1263
|
if (!mediaType || typeof mediaType !== "string") {
|
|
1262
1264
|
throw new import_js_format14.InvalidArgumentError(
|
|
1263
|
-
'
|
|
1265
|
+
'Parameter "mediaType" must be a non-empty String, but %v was given.',
|
|
1264
1266
|
mediaType
|
|
1265
1267
|
);
|
|
1266
1268
|
}
|
|
1267
1269
|
return Boolean(this._parsers[mediaType]);
|
|
1268
1270
|
}
|
|
1269
1271
|
/**
|
|
1270
|
-
*
|
|
1272
|
+
* Get parser.
|
|
1271
1273
|
*
|
|
1272
1274
|
* @param {string} mediaType
|
|
1273
|
-
* @returns {
|
|
1275
|
+
* @returns {Function}
|
|
1274
1276
|
*/
|
|
1275
|
-
|
|
1277
|
+
getParser(mediaType) {
|
|
1276
1278
|
if (!mediaType || typeof mediaType !== "string") {
|
|
1277
1279
|
throw new import_js_format14.InvalidArgumentError(
|
|
1278
|
-
'
|
|
1280
|
+
'Parameter "mediaType" must be a non-empty String, but %v was given.',
|
|
1279
1281
|
mediaType
|
|
1280
1282
|
);
|
|
1281
1283
|
}
|
|
1282
1284
|
const parser = this._parsers[mediaType];
|
|
1283
1285
|
if (!parser) {
|
|
1284
1286
|
throw new import_js_format14.InvalidArgumentError(
|
|
1285
|
-
"
|
|
1287
|
+
"Media type %v does not have a parser.",
|
|
1288
|
+
mediaType
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
return parser;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Remove parser.
|
|
1295
|
+
*
|
|
1296
|
+
* @param {string} mediaType
|
|
1297
|
+
* @returns {this}
|
|
1298
|
+
*/
|
|
1299
|
+
removeParser(mediaType) {
|
|
1300
|
+
if (!mediaType || typeof mediaType !== "string") {
|
|
1301
|
+
throw new import_js_format14.InvalidArgumentError(
|
|
1302
|
+
'Parameter "mediaType" must be a non-empty String, but %v was given.',
|
|
1286
1303
|
mediaType
|
|
1287
1304
|
);
|
|
1288
1305
|
}
|
|
@@ -1437,7 +1454,7 @@ var _RequestParser = class _RequestParser extends DebuggableService {
|
|
|
1437
1454
|
parse(request) {
|
|
1438
1455
|
if (!(request instanceof import_http3.IncomingMessage)) {
|
|
1439
1456
|
throw new import_js_format15.InvalidArgumentError(
|
|
1440
|
-
"
|
|
1457
|
+
'Parameter "request" must be an instance of IncomingMessage, but %v was given.',
|
|
1441
1458
|
request
|
|
1442
1459
|
);
|
|
1443
1460
|
}
|
|
@@ -1476,7 +1493,7 @@ var _RouteRegistry = class _RouteRegistry extends DebuggableService {
|
|
|
1476
1493
|
/**
|
|
1477
1494
|
* Constructor.
|
|
1478
1495
|
*
|
|
1479
|
-
* @param {ServiceContainer} container
|
|
1496
|
+
* @param {ServiceContainer} [container]
|
|
1480
1497
|
*/
|
|
1481
1498
|
constructor(container) {
|
|
1482
1499
|
super(container);
|
|
@@ -1492,7 +1509,7 @@ var _RouteRegistry = class _RouteRegistry extends DebuggableService {
|
|
|
1492
1509
|
const debug = this.getDebuggerFor(this.defineRoute);
|
|
1493
1510
|
if (!routeDef || typeof routeDef !== "object" || Array.isArray(routeDef)) {
|
|
1494
1511
|
throw new import_js_format16.InvalidArgumentError(
|
|
1495
|
-
"
|
|
1512
|
+
"Route definition must be an Object, but %v was given.",
|
|
1496
1513
|
routeDef
|
|
1497
1514
|
);
|
|
1498
1515
|
}
|
|
@@ -1562,6 +1579,35 @@ var _RouteRegistry = class _RouteRegistry extends DebuggableService {
|
|
|
1562
1579
|
requestPath
|
|
1563
1580
|
);
|
|
1564
1581
|
}
|
|
1582
|
+
/**
|
|
1583
|
+
* Get allowed methods for request path.
|
|
1584
|
+
*
|
|
1585
|
+
* @param {string} requestPath
|
|
1586
|
+
* @returns {string[]}
|
|
1587
|
+
*/
|
|
1588
|
+
getAllowedMethodsForRequestPath(requestPath) {
|
|
1589
|
+
if (typeof requestPath !== "string") {
|
|
1590
|
+
throw new import_js_format16.InvalidArgumentError(
|
|
1591
|
+
'Parameter "requestPath" must be a String, but %v was given.',
|
|
1592
|
+
requestPath
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
const debug = this.getDebuggerFor(this.getAllowedMethodsForRequestPath);
|
|
1596
|
+
const allowedMethods = [];
|
|
1597
|
+
for (const method of Object.values(HttpMethod)) {
|
|
1598
|
+
const rawTriePath = `${method}/${requestPath}`;
|
|
1599
|
+
const triePath = rawTriePath.replace(/\/+/g, "/");
|
|
1600
|
+
if (this._trie.match(triePath)) {
|
|
1601
|
+
allowedMethods.push(method);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
if (allowedMethods.length) {
|
|
1605
|
+
debug("Allowed methods for %v are: %l.", requestPath, allowedMethods);
|
|
1606
|
+
} else {
|
|
1607
|
+
debug("Path %v does not have allowed methods.", requestPath);
|
|
1608
|
+
}
|
|
1609
|
+
return allowedMethods;
|
|
1610
|
+
}
|
|
1565
1611
|
};
|
|
1566
1612
|
__name(_RouteRegistry, "RouteRegistry");
|
|
1567
1613
|
var RouteRegistry = _RouteRegistry;
|
|
@@ -1716,28 +1762,28 @@ var _RequestContext = class _RequestContext {
|
|
|
1716
1762
|
constructor(container, request, response, route) {
|
|
1717
1763
|
if (!(0, import_js_service3.isServiceContainer)(container)) {
|
|
1718
1764
|
throw new import_js_format17.InvalidArgumentError(
|
|
1719
|
-
'
|
|
1765
|
+
'Parameter "container" must be an instance of ServiceContainer, but %v was given.',
|
|
1720
1766
|
container
|
|
1721
1767
|
);
|
|
1722
1768
|
}
|
|
1723
1769
|
this._container = container;
|
|
1724
1770
|
if (!request || typeof request !== "object" || Array.isArray(request) || !isReadableStream(request)) {
|
|
1725
1771
|
throw new import_js_format17.InvalidArgumentError(
|
|
1726
|
-
'
|
|
1772
|
+
'Parameter "request" must be an instance of IncomingMessage, but %v was given.',
|
|
1727
1773
|
request
|
|
1728
1774
|
);
|
|
1729
1775
|
}
|
|
1730
1776
|
this._request = request;
|
|
1731
1777
|
if (!response || typeof response !== "object" || Array.isArray(response) || !isWritableStream(response)) {
|
|
1732
1778
|
throw new import_js_format17.InvalidArgumentError(
|
|
1733
|
-
'
|
|
1779
|
+
'Parameter "response" must be an instance of ServerResponse, but %v was given.',
|
|
1734
1780
|
response
|
|
1735
1781
|
);
|
|
1736
1782
|
}
|
|
1737
1783
|
this._response = response;
|
|
1738
1784
|
if (!(route instanceof Route)) {
|
|
1739
1785
|
throw new import_js_format17.InvalidArgumentError(
|
|
1740
|
-
'
|
|
1786
|
+
'Parameter "route" must be an instance of Route, but %v was given.',
|
|
1741
1787
|
route
|
|
1742
1788
|
);
|
|
1743
1789
|
}
|
|
@@ -1792,7 +1838,7 @@ function validateRouterBranchDefinition(branchDef) {
|
|
|
1792
1838
|
branchDef.preHandler.forEach((preHandler) => {
|
|
1793
1839
|
if (typeof preHandler !== "function") {
|
|
1794
1840
|
throw new import_js_format18.InvalidArgumentError(
|
|
1795
|
-
"
|
|
1841
|
+
'Hook "preHandler" must be a Function, but %v was given.',
|
|
1796
1842
|
preHandler
|
|
1797
1843
|
);
|
|
1798
1844
|
}
|
|
@@ -1809,7 +1855,7 @@ function validateRouterBranchDefinition(branchDef) {
|
|
|
1809
1855
|
branchDef.postHandler.forEach((postHandler) => {
|
|
1810
1856
|
if (typeof postHandler !== "function") {
|
|
1811
1857
|
throw new import_js_format18.InvalidArgumentError(
|
|
1812
|
-
"
|
|
1858
|
+
'Hook "postHandler" must be a Function, but %v was given.',
|
|
1813
1859
|
postHandler
|
|
1814
1860
|
);
|
|
1815
1861
|
}
|
|
@@ -1924,17 +1970,17 @@ var _RouterBranch = class _RouterBranch extends DebuggableService {
|
|
|
1924
1970
|
* @param {RouterBranch} [parentBranch]
|
|
1925
1971
|
*/
|
|
1926
1972
|
constructor(router, branchDef, parentBranch) {
|
|
1927
|
-
super(router.container);
|
|
1928
1973
|
if (!(router instanceof TrieRouter)) {
|
|
1929
1974
|
throw new import_js_format19.InvalidArgumentError(
|
|
1930
|
-
'Parameter "router" must be
|
|
1975
|
+
'Parameter "router" must be an instance of TrieRouter, but %v was given.',
|
|
1931
1976
|
router
|
|
1932
1977
|
);
|
|
1933
1978
|
}
|
|
1979
|
+
super(router.container);
|
|
1934
1980
|
this._router = router;
|
|
1935
1981
|
if (parentBranch !== void 0 && !(parentBranch instanceof _RouterBranch)) {
|
|
1936
1982
|
throw new import_js_format19.InvalidArgumentError(
|
|
1937
|
-
'Parameter "parentBranch" must be
|
|
1983
|
+
'Parameter "parentBranch" must be an instance of RouterBranch, but %v was given.',
|
|
1938
1984
|
parentBranch
|
|
1939
1985
|
);
|
|
1940
1986
|
}
|
|
@@ -2154,9 +2200,9 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
|
|
|
2154
2200
|
* router.defineRoute({
|
|
2155
2201
|
* method: HttpMethod.POST, // Request method.
|
|
2156
2202
|
* path: '/users/:id', // The path template may have parameters.
|
|
2157
|
-
* preHandler(ctx) { ... }, // The "preHandler" executes before a route handler.
|
|
2158
|
-
* handler(ctx) { ... }, //
|
|
2159
|
-
* postHandler(ctx, data) { ... }, // The "postHandler" executes after a route handler.
|
|
2203
|
+
* preHandler(ctx) { ... }, // The hook "preHandler" executes before a route handler.
|
|
2204
|
+
* handler(ctx) { ... }, // Route handler function.
|
|
2205
|
+
* postHandler(ctx, data) { ... }, // The hook "postHandler" executes after a route handler.
|
|
2160
2206
|
* });
|
|
2161
2207
|
* ```
|
|
2162
2208
|
*
|
|
@@ -2218,9 +2264,25 @@ var _TrieRouter = class _TrieRouter extends DebuggableService {
|
|
|
2218
2264
|
async _handleRequest(request, response) {
|
|
2219
2265
|
const debug = this.getDebuggerFor(this._handleRequest);
|
|
2220
2266
|
const requestPath = getRequestPathname(request);
|
|
2267
|
+
const routeRegistry = this.getService(RouteRegistry);
|
|
2221
2268
|
debug("Handling an incoming request %s %v.", request.method, requestPath);
|
|
2222
2269
|
const resolved = this.getService(RouteRegistry).matchRouteByRequest(request);
|
|
2223
2270
|
if (!resolved) {
|
|
2271
|
+
if (request.method.toUpperCase() === HttpMethod.OPTIONS) {
|
|
2272
|
+
const allowedMethods = routeRegistry.getAllowedMethodsForRequestPath(requestPath);
|
|
2273
|
+
if (allowedMethods.length > 0) {
|
|
2274
|
+
debug("Auto-handling OPTIONS request.");
|
|
2275
|
+
if (!allowedMethods.includes("OPTIONS")) {
|
|
2276
|
+
allowedMethods.push("OPTIONS");
|
|
2277
|
+
}
|
|
2278
|
+
const allowHeader = allowedMethods.join(", ");
|
|
2279
|
+
response.statusCode = 204;
|
|
2280
|
+
response.setHeader("Allow", allowHeader);
|
|
2281
|
+
response.setHeader("Access-Control-Allow-Methods", allowHeader);
|
|
2282
|
+
response.end();
|
|
2283
|
+
return;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2224
2286
|
debug(
|
|
2225
2287
|
"No route found for the request %s %v.",
|
|
2226
2288
|
request.method,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e22m4u/js-trie-router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "HTTP маршрутизатор для Node.js на основе префиксного дерева",
|
|
5
5
|
"author": "Mikhail Evstropov <e22m4u@yandex.ru>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"statuses": "~2.0.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@commitlint/cli": "~20.4.
|
|
51
|
-
"@commitlint/config-conventional": "~20.4.
|
|
50
|
+
"@commitlint/cli": "~20.4.2",
|
|
51
|
+
"@commitlint/config-conventional": "~20.4.2",
|
|
52
52
|
"@eslint/js": "~9.39.2",
|
|
53
53
|
"@types/chai": "~5.2.3",
|
|
54
54
|
"@types/chai-as-promised": "~8.0.2",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"eslint-config-prettier": "~10.1.8",
|
|
62
62
|
"eslint-plugin-chai-expect": "~3.1.0",
|
|
63
63
|
"eslint-plugin-import": "~2.32.0",
|
|
64
|
-
"eslint-plugin-jsdoc": "~62.
|
|
64
|
+
"eslint-plugin-jsdoc": "~62.7.0",
|
|
65
65
|
"eslint-plugin-mocha": "~11.2.0",
|
|
66
66
|
"globals": "~17.3.0",
|
|
67
67
|
"husky": "~9.1.7",
|