@koa/router 13.1.0 → 14.0.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.
- package/README.md +3 -1
- package/lib/layer.js +32 -9
- package/lib/router.js +27 -17
- package/package.json +14 -12
package/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
> Router middleware for [Koa](https://github.com/koajs/koa). Maintained by [Forward Email][forward-email] and [Lad][].
|
|
4
4
|
|
|
5
5
|
[](https://github.com/koajs/router/actions/workflows/ci.yml)
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
<!-- [](https://github.com/sindresorhus/xo) -->
|
|
8
|
+
|
|
7
9
|
[](https://github.com/prettier/prettier)
|
|
8
10
|
[](https://lass.js.org)
|
|
9
11
|
[](LICENSE)
|
package/lib/layer.js
CHANGED
|
@@ -13,6 +13,7 @@ module.exports = class Layer {
|
|
|
13
13
|
* @param {String=} opts.name route name
|
|
14
14
|
* @param {String=} opts.sensitive case sensitive (default: false)
|
|
15
15
|
* @param {String=} opts.strict require the trailing slash (default: false)
|
|
16
|
+
* @param {Boolean=} opts.pathAsRegExp if true, treat `path` as a regular expression
|
|
16
17
|
* @returns {Layer}
|
|
17
18
|
* @private
|
|
18
19
|
*/
|
|
@@ -20,14 +21,12 @@ module.exports = class Layer {
|
|
|
20
21
|
this.opts = opts;
|
|
21
22
|
this.name = this.opts.name || null;
|
|
22
23
|
this.methods = [];
|
|
23
|
-
this.paramNames = [];
|
|
24
|
-
this.stack = Array.isArray(middleware) ? middleware : [middleware];
|
|
25
|
-
|
|
26
24
|
for (const method of methods) {
|
|
27
25
|
const l = this.methods.push(method.toUpperCase());
|
|
28
26
|
if (this.methods[l - 1] === 'GET') this.methods.unshift('HEAD');
|
|
29
27
|
}
|
|
30
28
|
|
|
29
|
+
this.stack = Array.isArray(middleware) ? middleware : [middleware];
|
|
31
30
|
// ensure middleware is a function
|
|
32
31
|
for (let i = 0; i < this.stack.length; i++) {
|
|
33
32
|
const fn = this.stack[i];
|
|
@@ -41,7 +40,20 @@ module.exports = class Layer {
|
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
this.path = path;
|
|
44
|
-
this.
|
|
43
|
+
this.paramNames = [];
|
|
44
|
+
|
|
45
|
+
if (this.opts.pathAsRegExp === true) {
|
|
46
|
+
this.regexp = new RegExp(path);
|
|
47
|
+
} else if (this.path) {
|
|
48
|
+
if ('strict' in this.opts) {
|
|
49
|
+
// path-to-regexp renamed strict to trailing in v8.1.0
|
|
50
|
+
this.opts.trailing = this.opts.strict !== true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { regexp, keys } = pathToRegexp(this.path, this.opts);
|
|
54
|
+
this.regexp = regexp;
|
|
55
|
+
this.paramNames = keys;
|
|
56
|
+
}
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
/**
|
|
@@ -116,13 +128,14 @@ module.exports = class Layer {
|
|
|
116
128
|
|
|
117
129
|
const toPath = compile(url, { encode: encodeURIComponent, ...options });
|
|
118
130
|
let replaced;
|
|
119
|
-
|
|
120
|
-
const tokens = parse(url);
|
|
131
|
+
const { tokens } = parse(url);
|
|
121
132
|
let replace = {};
|
|
122
133
|
|
|
123
134
|
if (Array.isArray(args)) {
|
|
124
135
|
for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
|
|
125
|
-
if (tokens[i].name)
|
|
136
|
+
if (tokens[i].name) {
|
|
137
|
+
replace[tokens[i].name] = args[j++];
|
|
138
|
+
}
|
|
126
139
|
}
|
|
127
140
|
} else if (tokens.some((token) => token.name)) {
|
|
128
141
|
replace = params;
|
|
@@ -130,6 +143,10 @@ module.exports = class Layer {
|
|
|
130
143
|
options = params;
|
|
131
144
|
}
|
|
132
145
|
|
|
146
|
+
for (const [key, value] of Object.entries(replace)) {
|
|
147
|
+
replace[key] = String(value);
|
|
148
|
+
}
|
|
149
|
+
|
|
133
150
|
replaced = toPath(replace);
|
|
134
151
|
|
|
135
152
|
if (options && options.query) {
|
|
@@ -212,8 +229,13 @@ module.exports = class Layer {
|
|
|
212
229
|
this.path !== '/' || this.opts.strict === true
|
|
213
230
|
? `${prefix}${this.path}`
|
|
214
231
|
: prefix;
|
|
215
|
-
this.
|
|
216
|
-
|
|
232
|
+
if (this.opts.pathAsRegExp === true || prefix instanceof RegExp) {
|
|
233
|
+
this.regexp = new RegExp(this.path);
|
|
234
|
+
} else if (this.path) {
|
|
235
|
+
const { regexp, keys } = pathToRegexp(this.path, this.opts);
|
|
236
|
+
this.regexp = regexp;
|
|
237
|
+
this.paramNames = keys;
|
|
238
|
+
}
|
|
217
239
|
}
|
|
218
240
|
|
|
219
241
|
return this;
|
|
@@ -231,6 +253,7 @@ module.exports = class Layer {
|
|
|
231
253
|
|
|
232
254
|
function safeDecodeURIComponent(text) {
|
|
233
255
|
try {
|
|
256
|
+
// TODO: take a look on `safeDecodeURIComponent` if we use it only with route params let's remove the `replace` method otherwise make it flexible.
|
|
234
257
|
// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#decoding_query_parameters_from_a_url
|
|
235
258
|
return decodeURIComponent(text.replace(/\+/g, ' '));
|
|
236
259
|
} catch {
|
package/lib/router.js
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* @link https://github.com/alexmingoia/koa-router
|
|
6
6
|
*/
|
|
7
7
|
const http = require('node:http');
|
|
8
|
-
const util = require('node:util');
|
|
9
8
|
|
|
10
|
-
const debug =
|
|
9
|
+
const debug = require('debug')('koa-router');
|
|
11
10
|
|
|
12
11
|
const compose = require('koa-compose');
|
|
13
12
|
const HttpError = require('http-errors');
|
|
@@ -52,7 +51,7 @@ class Router {
|
|
|
52
51
|
* @constructor
|
|
53
52
|
*/
|
|
54
53
|
constructor(opts = {}) {
|
|
55
|
-
if (!(this instanceof Router)) return new Router(opts);
|
|
54
|
+
if (!(this instanceof Router)) return new Router(opts);
|
|
56
55
|
|
|
57
56
|
this.opts = opts;
|
|
58
57
|
this.methods = this.opts.methods || [
|
|
@@ -165,14 +164,14 @@ class Router {
|
|
|
165
164
|
}
|
|
166
165
|
}
|
|
167
166
|
} else {
|
|
168
|
-
const keys =
|
|
169
|
-
pathToRegexp(router.opts.prefix || '', keys);
|
|
167
|
+
const { keys } = pathToRegexp(router.opts.prefix || '', router.opts);
|
|
170
168
|
const routerPrefixHasParam = Boolean(
|
|
171
169
|
router.opts.prefix && keys.length > 0
|
|
172
170
|
);
|
|
173
171
|
router.register(path || '([^/]*)', [], m, {
|
|
174
172
|
end: false,
|
|
175
|
-
ignoreCaptures: !hasPath && !routerPrefixHasParam
|
|
173
|
+
ignoreCaptures: !hasPath && !routerPrefixHasParam,
|
|
174
|
+
pathAsRegExp: true
|
|
176
175
|
});
|
|
177
176
|
}
|
|
178
177
|
}
|
|
@@ -380,7 +379,7 @@ class Router {
|
|
|
380
379
|
* @returns {Router}
|
|
381
380
|
*/
|
|
382
381
|
all(name, path, middleware) {
|
|
383
|
-
if (typeof path === 'string') {
|
|
382
|
+
if (typeof path === 'string' || path instanceof RegExp) {
|
|
384
383
|
middleware = Array.prototype.slice.call(arguments, 2);
|
|
385
384
|
} else {
|
|
386
385
|
middleware = Array.prototype.slice.call(arguments, 1);
|
|
@@ -396,7 +395,12 @@ class Router {
|
|
|
396
395
|
)
|
|
397
396
|
throw new Error('You have to provide a path when adding an all handler');
|
|
398
397
|
|
|
399
|
-
|
|
398
|
+
const opts = {
|
|
399
|
+
name,
|
|
400
|
+
pathAsRegExp: path instanceof RegExp
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
this.register(path, methods, middleware, { ...this.opts, ...opts });
|
|
400
404
|
|
|
401
405
|
return this;
|
|
402
406
|
}
|
|
@@ -455,10 +459,10 @@ class Router {
|
|
|
455
459
|
* @returns {Layer}
|
|
456
460
|
* @private
|
|
457
461
|
*/
|
|
458
|
-
register(path, methods, middleware,
|
|
462
|
+
register(path, methods, middleware, newOpts = {}) {
|
|
459
463
|
const router = this;
|
|
460
464
|
const { stack } = this;
|
|
461
|
-
|
|
465
|
+
const opts = { ...this.opts, ...newOpts };
|
|
462
466
|
// support array of paths
|
|
463
467
|
if (Array.isArray(path)) {
|
|
464
468
|
for (const curPath of path) {
|
|
@@ -472,12 +476,14 @@ class Router {
|
|
|
472
476
|
const route = new Layer(path, methods, middleware, {
|
|
473
477
|
end: opts.end === false ? opts.end : true,
|
|
474
478
|
name: opts.name,
|
|
475
|
-
sensitive: opts.sensitive ||
|
|
476
|
-
strict: opts.strict ||
|
|
477
|
-
prefix: opts.prefix ||
|
|
478
|
-
ignoreCaptures: opts.ignoreCaptures
|
|
479
|
+
sensitive: opts.sensitive || false,
|
|
480
|
+
strict: opts.strict || false,
|
|
481
|
+
prefix: opts.prefix || '',
|
|
482
|
+
ignoreCaptures: opts.ignoreCaptures,
|
|
483
|
+
pathAsRegExp: opts.pathAsRegExp
|
|
479
484
|
});
|
|
480
485
|
|
|
486
|
+
// if parent prefix exists, add prefix to new route
|
|
481
487
|
if (this.opts.prefix) {
|
|
482
488
|
route.setPrefix(this.opts.prefix);
|
|
483
489
|
}
|
|
@@ -575,7 +581,6 @@ class Router {
|
|
|
575
581
|
|
|
576
582
|
debug('test %s %s', layer.path, layer.regexp);
|
|
577
583
|
|
|
578
|
-
// eslint-disable-next-line unicorn/prefer-regexp-test
|
|
579
584
|
if (layer.match(path)) {
|
|
580
585
|
matched.path.push(layer);
|
|
581
586
|
|
|
@@ -812,14 +817,19 @@ for (const method of methods) {
|
|
|
812
817
|
`You have to provide a path when adding a ${method} handler`
|
|
813
818
|
);
|
|
814
819
|
|
|
815
|
-
|
|
820
|
+
const opts = {
|
|
821
|
+
name,
|
|
822
|
+
pathAsRegExp: path instanceof RegExp
|
|
823
|
+
};
|
|
816
824
|
|
|
825
|
+
// pass opts to register call on verb methods
|
|
826
|
+
this.register(path, [method], middleware, { ...this.opts, ...opts });
|
|
817
827
|
return this;
|
|
818
828
|
};
|
|
819
829
|
}
|
|
820
830
|
|
|
821
831
|
// Alias for `router.delete()` because delete is a reserved word
|
|
822
|
-
|
|
832
|
+
|
|
823
833
|
Router.prototype.del = Router.prototype['delete'];
|
|
824
834
|
|
|
825
835
|
module.exports = Router;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koa/router",
|
|
3
3
|
"description": "Router middleware for koa. Maintained by Forward Email and Lad.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "14.0.0",
|
|
5
5
|
"author": "Alex Mingoia <talk@alexmingoia.com>",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/koajs/router/issues",
|
|
@@ -21,30 +21,31 @@
|
|
|
21
21
|
}
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"debug": "^4.4.1",
|
|
24
25
|
"http-errors": "^2.0.0",
|
|
25
26
|
"koa-compose": "^4.1.0",
|
|
26
|
-
"path-to-regexp": "^
|
|
27
|
+
"path-to-regexp": "^8.2.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@commitlint/cli": "^17.7.2",
|
|
30
31
|
"@commitlint/config-conventional": "^17.7.0",
|
|
31
32
|
"@ladjs/env": "^4.0.0",
|
|
32
|
-
"
|
|
33
|
-
"eslint
|
|
33
|
+
"chalk": "^5.4.1",
|
|
34
|
+
"eslint": "^9.32.0",
|
|
35
|
+
"eslint-plugin-unicorn": "^60.0.0",
|
|
34
36
|
"fixpack": "^4.0.0",
|
|
35
|
-
"husky": "^
|
|
37
|
+
"husky": "^9.1.7",
|
|
36
38
|
"jsdoc-to-markdown": "^8.0.0",
|
|
37
|
-
"koa": "^
|
|
39
|
+
"koa": "^3.0.1",
|
|
38
40
|
"lint-staged": "^14.0.1",
|
|
39
|
-
"mocha": "^
|
|
41
|
+
"mocha": "^11.7.1",
|
|
40
42
|
"nyc": "^17.0.0",
|
|
41
43
|
"remark-cli": "11",
|
|
42
44
|
"remark-preset-github": "^4.0.4",
|
|
43
|
-
"supertest": "^7.0.0"
|
|
44
|
-
"xo": "0.53.1"
|
|
45
|
+
"supertest": "^7.0.0"
|
|
45
46
|
},
|
|
46
47
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
48
|
+
"node": ">= 20"
|
|
48
49
|
},
|
|
49
50
|
"files": [
|
|
50
51
|
"lib"
|
|
@@ -64,11 +65,12 @@
|
|
|
64
65
|
},
|
|
65
66
|
"scripts": {
|
|
66
67
|
"bench": "make -C bench",
|
|
68
|
+
"benchmark": "node bench/run.js",
|
|
67
69
|
"coverage": "nyc npm run test",
|
|
68
70
|
"docs": "NODE_ENV=test jsdoc2md -t ./lib/API_tpl.hbs --src ./lib/*.js >| API.md",
|
|
69
|
-
"lint": "
|
|
71
|
+
"lint": "eslint . --fix && remark . -qfo && fixpack",
|
|
70
72
|
"prepare": "husky install",
|
|
71
|
-
"
|
|
73
|
+
"pretest": "npm run lint",
|
|
72
74
|
"test": "mocha test/**/*.js",
|
|
73
75
|
"test:watch": "mocha test/**/*.js --watch"
|
|
74
76
|
}
|