@koa/router 10.1.1 → 11.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/LICENSE CHANGED
@@ -1,7 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Alexander C. Mingoia
4
- Copyright (c) 2019-present Nick Baugh and Koajs contributors
3
+ Copyright (c) 2015 Alexander C. Mingoia and @koajs contributors
5
4
 
6
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
6
  of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- THE SOFTWARE.
21
+ THE SOFTWARE.
package/README.md CHANGED
@@ -1,12 +1,26 @@
1
1
  # [@koa/router](https://github.com/koajs/router)
2
2
 
3
- > Router middleware for [Koa](https://github.com/koajs/koa).
3
+ > Router middleware for [Koa](https://github.com/koajs/koa). Maintained by [Forward Email][forward-email] and [Lad][].
4
4
 
5
- [![NPM version](https://img.shields.io/npm/v/@koa/router.svg?style=flat)](https://npmjs.org/package/@koa/router)
6
- [![NPM Downloads](https://img.shields.io/npm/dm/@koa/router.svg?style=flat)](https://npmjs.org/package/@koa/router)
7
- [![Node.js Version](https://img.shields.io/node/v/@koa/router.svg?style=flat)](http://nodejs.org/download/)
8
- [![Build Status](https://img.shields.io/travis/koajs/router.svg?style=flat)](http://travis-ci.org/koajs/router)
9
- [![gitter](https://img.shields.io/gitter/room/koajs/koa.svg?style=flat)](https://gitter.im/koajs/koa)
5
+ [![build status](https://github.com/koajs/router/actions/workflows/ci.yml/badge.svg)](https://github.com/koajs/router/actions/workflows/ci.yml)
6
+ [![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)
7
+ [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
8
+ [![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)
9
+ [![license](https://img.shields.io/github/license/koajs/router.svg)](LICENSE)
10
+
11
+
12
+ ## Table of Contents
13
+
14
+ * [Features](#features)
15
+ * [Migrating to 7 / Koa 2](#migrating-to-7--koa-2)
16
+ * [Install](#install)
17
+ * [Typescript Support](#typescript-support)
18
+ * [API Reference](#api-reference)
19
+ * [Contributors](#contributors)
20
+ * [License](#license)
21
+
22
+
23
+ ## Features
10
24
 
11
25
  * Express-style routing (`app.get`, `app.put`, `app.post`, etc.)
12
26
  * Named URL parameters
@@ -17,39 +31,54 @@
17
31
  * Multiple and nestable routers
18
32
  * `async/await` support
19
33
 
34
+
20
35
  ## Migrating to 7 / Koa 2
21
36
 
22
- - The API has changed to match the new promise-based middleware
37
+ * The API has changed to match the new promise-based middleware
23
38
  signature of koa 2. See the [koa 2.x readme](https://github.com/koajs/koa/tree/2.0.0-alpha.3) for more
24
39
  information.
25
- - Middleware is now always run in the order declared by `.use()` (or `.get()`,
40
+ * Middleware is now always run in the order declared by `.use()` (or `.get()`,
26
41
  etc.), which matches Express 4 API.
27
42
 
28
- ## Installation
29
43
 
30
- ```bash
31
- # npm ..
32
- npm i @koa/router
33
- # yarn ..
34
- yarn add @koa/router
44
+ ## Install
45
+
46
+ [npm][]:
47
+
48
+ ```sh
49
+ npm install @koa/router
35
50
  ```
36
51
 
37
- ## [API Reference](./API.md)
38
52
 
39
- ## Contributing
53
+ ## Typescript Support
54
+
55
+ ```sh
56
+ npm install @types/koa__router
57
+ ```
58
+
59
+
60
+ ## API Reference
61
+
62
+ See [API Reference](./API.md) for more documentation.
63
+
64
+
65
+ ## Contributors
66
+
67
+ | Name |
68
+ | ---------------- |
69
+ | **Alex Mingoia** |
70
+ | **@koajs** |
40
71
 
41
- Please submit all issues and pull requests to the [koajs/router](http://github.com/koajs/router) repository!
42
72
 
43
- ## Support
73
+ ## License
44
74
 
45
- If you have any problem or suggestion please open an issue [here](https://github.com/koajs/router/issues).
75
+ [MIT](LICENSE) © Alex Mingoia
46
76
 
47
- ## Call for Maintainers
48
77
 
49
- This module is forked from the original [koa-router](https://github.com/ZijianHe/koa-router) due to its lack of activity. `koa-router` is the most widely used router module in the Koa community and we need maintainers. If you're interested in fixing bugs or implementing new features feel free to open a pull request. We'll be adding active contributors as collaborators.
78
+ ##
50
79
 
51
- Thanks to the original authors @alexmingoia and the original team for their great work.
80
+ [forward-email]: https://forwardemail.net
52
81
 
53
- ### License
82
+ [lad]: https://lad.js.org
54
83
 
55
- [MIT](LICENSE)
84
+ [npm]: https//www.npmjs.com
package/lib/layer.js CHANGED
@@ -1,5 +1,5 @@
1
- const { pathToRegexp, compile, parse } = require('path-to-regexp');
2
1
  const { parse: parseUrl, format: formatUrl } = require('url');
2
+ const { pathToRegexp, compile, parse } = require('path-to-regexp');
3
3
 
4
4
  module.exports = Layer;
5
5
 
@@ -17,31 +17,33 @@ module.exports = Layer;
17
17
  * @private
18
18
  */
19
19
 
20
- function Layer(path, methods, middleware, opts) {
21
- this.opts = opts || {};
20
+ function Layer(path, methods, middleware, opts = {}) {
21
+ this.opts = opts;
22
22
  this.name = this.opts.name || null;
23
23
  this.methods = [];
24
24
  this.paramNames = [];
25
25
  this.stack = Array.isArray(middleware) ? middleware : [middleware];
26
26
 
27
- for (let i = 0; i < methods.length; i++) {
28
- const l = this.methods.push(methods[i].toUpperCase());
27
+ for (const method of methods) {
28
+ const l = this.methods.push(method.toUpperCase());
29
29
  if (this.methods[l - 1] === 'GET') this.methods.unshift('HEAD');
30
30
  }
31
31
 
32
32
  // ensure middleware is a function
33
33
  for (let i = 0; i < this.stack.length; i++) {
34
34
  const fn = this.stack[i];
35
- const type = (typeof fn);
35
+ const type = typeof fn;
36
36
  if (type !== 'function')
37
37
  throw new Error(
38
- `${methods.toString()} \`${this.opts.name || path}\`: \`middleware\` must be a function, not \`${type}\``
38
+ `${methods.toString()} \`${
39
+ this.opts.name || path
40
+ }\`: \`middleware\` must be a function, not \`${type}\``
39
41
  );
40
42
  }
41
43
 
42
44
  this.path = path;
43
45
  this.regexp = pathToRegexp(path, this.paramNames, this.opts);
44
- };
46
+ }
45
47
 
46
48
  /**
47
49
  * Returns whether request `path` matches route.
@@ -60,18 +62,17 @@ Layer.prototype.match = function (path) {
60
62
  *
61
63
  * @param {String} path
62
64
  * @param {Array.<String>} captures
63
- * @param {Object=} existingParams
65
+ * @param {Object=} params
64
66
  * @returns {Object}
65
67
  * @private
66
68
  */
67
69
 
68
- Layer.prototype.params = function (path, captures, existingParams) {
69
- const params = existingParams || {};
70
-
70
+ Layer.prototype.params = function (path, captures, params = {}) {
71
71
  for (let len = captures.length, i = 0; i < len; i++) {
72
72
  if (this.paramNames[i]) {
73
73
  const c = captures[i];
74
- if (c && c.length !== 0) params[this.paramNames[i].name] = c ? safeDecodeURIComponent(c) : c;
74
+ if (c && c.length > 0)
75
+ params[this.paramNames[i].name] = c ? safeDecodeURIComponent(c) : c;
75
76
  }
76
77
  }
77
78
 
@@ -110,11 +111,11 @@ Layer.prototype.url = function (params, options) {
110
111
  let args = params;
111
112
  const url = this.path.replace(/\(\.\*\)/g, '');
112
113
 
113
- if (typeof params != 'object') {
114
+ if (typeof params !== 'object') {
114
115
  args = Array.prototype.slice.call(arguments);
115
- if (typeof args[args.length - 1] == 'object') {
116
+ if (typeof args[args.length - 1] === 'object') {
116
117
  options = args[args.length - 1];
117
- args = args.slice(0, args.length - 1);
118
+ args = args.slice(0, -1);
118
119
  }
119
120
  }
120
121
 
@@ -124,11 +125,11 @@ Layer.prototype.url = function (params, options) {
124
125
  const tokens = parse(url);
125
126
  let replace = {};
126
127
 
127
- if (args instanceof Array) {
128
+ if (Array.isArray(args)) {
128
129
  for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
129
130
  if (tokens[i].name) replace[tokens[i].name] = args[j++];
130
131
  }
131
- } else if (tokens.some(token => token.name)) {
132
+ } else if (tokens.some((token) => token.name)) {
132
133
  replace = params;
133
134
  } else if (!options) {
134
135
  options = params;
@@ -144,6 +145,7 @@ Layer.prototype.url = function (params, options) {
144
145
  replaced.search = undefined;
145
146
  replaced.query = options.query;
146
147
  }
148
+
147
149
  return formatUrl(replaced);
148
150
  }
149
151
 
@@ -159,7 +161,7 @@ Layer.prototype.url = function (params, options) {
159
161
  * router
160
162
  * .param('user', function (id, ctx, next) {
161
163
  * ctx.user = users[id];
162
- * if (!user) return ctx.status = 404;
164
+ * if (!ctx.user) return ctx.status = 404;
163
165
  * next();
164
166
  * })
165
167
  * .get('/users/:user', function (ctx, next) {
@@ -174,11 +176,12 @@ Layer.prototype.url = function (params, options) {
174
176
  */
175
177
 
176
178
  Layer.prototype.param = function (param, fn) {
177
- const stack = this.stack;
179
+ const { stack } = this;
178
180
  const params = this.paramNames;
179
181
  const middleware = function (ctx, next) {
180
182
  return fn.call(this, ctx.params[param], ctx, next);
181
183
  };
184
+
182
185
  middleware.param = param;
183
186
 
184
187
  const names = params.map(function (p) {
@@ -212,7 +215,10 @@ Layer.prototype.param = function (param, fn) {
212
215
 
213
216
  Layer.prototype.setPrefix = function (prefix) {
214
217
  if (this.path) {
215
- this.path = (this.path !== '/' || this.opts.strict === true) ? `${prefix}${this.path}` : prefix
218
+ this.path =
219
+ this.path !== '/' || this.opts.strict === true
220
+ ? `${prefix}${this.path}`
221
+ : prefix;
216
222
  this.paramNames = [];
217
223
  this.regexp = pathToRegexp(this.path, this.paramNames, this.opts);
218
224
  }
@@ -232,7 +238,7 @@ Layer.prototype.setPrefix = function (prefix) {
232
238
  function safeDecodeURIComponent(text) {
233
239
  try {
234
240
  return decodeURIComponent(text);
235
- } catch (e) {
241
+ } catch {
236
242
  return text;
237
243
  }
238
244
  }
package/lib/router.js CHANGED
@@ -5,12 +5,15 @@
5
5
  * @link https://github.com/alexmingoia/koa-router
6
6
  */
7
7
 
8
- const debug = require('debug')('koa-router');
8
+ const { debuglog } = require('util');
9
+
9
10
  const compose = require('koa-compose');
10
11
  const HttpError = require('http-errors');
11
12
  const methods = require('methods');
12
- const Layer = require('./layer');
13
13
  const { pathToRegexp } = require('path-to-regexp');
14
+ const Layer = require('./layer');
15
+
16
+ const debug = debuglog('koa-router');
14
17
 
15
18
  /**
16
19
  * @module koa-router
@@ -43,14 +46,15 @@ module.exports = Router;
43
46
  *
44
47
  * @alias module:koa-router
45
48
  * @param {Object=} opts
49
+ * @param {Boolean=false} opts.exclusive only run last matched route's controller when there are multiple matches
46
50
  * @param {String=} opts.prefix prefix router paths
47
51
  * @constructor
48
52
  */
49
53
 
50
- function Router(opts) {
54
+ function Router(opts = {}) {
51
55
  if (!(this instanceof Router)) return new Router(opts);
52
56
 
53
- this.opts = opts || {};
57
+ this.opts = opts;
54
58
  this.methods = this.opts.methods || [
55
59
  'HEAD',
56
60
  'OPTIONS',
@@ -60,10 +64,11 @@ function Router(opts) {
60
64
  'POST',
61
65
  'DELETE'
62
66
  ];
67
+ this.exclusive = Boolean(this.opts.exclusive);
63
68
 
64
69
  this.params = {};
65
70
  this.stack = [];
66
- };
71
+ }
67
72
 
68
73
  /**
69
74
  * Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
@@ -72,7 +77,7 @@ function Router(opts) {
72
77
  * Match URL patterns to callback functions or controller actions using `router.verb()`,
73
78
  * where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
74
79
  *
75
- * Additionaly, `router.all()` can be used to match against all methods.
80
+ * Additionally, `router.all()` can be used to match against all methods.
76
81
  *
77
82
  * ```javascript
78
83
  * router
@@ -186,10 +191,10 @@ function Router(opts) {
186
191
  * @returns {Router}
187
192
  */
188
193
 
189
- for (let i = 0; i < methods.length; i++) {
194
+ for (const method_ of methods) {
190
195
  function setMethodVerb(method) {
191
- Router.prototype[method] = function(name, path, middleware) {
192
- if (typeof path === "string" || path instanceof RegExp) {
196
+ Router.prototype[method] = function (name, path, middleware) {
197
+ if (typeof path === 'string' || path instanceof RegExp) {
193
198
  middleware = Array.prototype.slice.call(arguments, 2);
194
199
  } else {
195
200
  middleware = Array.prototype.slice.call(arguments, 1);
@@ -197,17 +202,27 @@ for (let i = 0; i < methods.length; i++) {
197
202
  name = null;
198
203
  }
199
204
 
200
- this.register(path, [method], middleware, {
201
- name: name
202
- });
205
+ // Sanity check to ensure we have a viable path candidate (eg: string|regex|non-empty array)
206
+ if (
207
+ typeof path !== 'string' &&
208
+ !(path instanceof RegExp) &&
209
+ (!Array.isArray(path) || path.length === 0)
210
+ )
211
+ throw new Error(
212
+ `You have to provide a path when adding a ${method} handler`
213
+ );
214
+
215
+ this.register(path, [method], middleware, { name });
203
216
 
204
217
  return this;
205
218
  };
206
219
  }
207
- setMethodVerb(methods[i]);
220
+
221
+ setMethodVerb(method_);
208
222
  }
209
223
 
210
224
  // Alias for `router.delete()` because delete is a reserved word
225
+ // eslint-disable-next-line dot-notation
211
226
  Router.prototype.del = Router.prototype['delete'];
212
227
 
213
228
  /**
@@ -247,9 +262,8 @@ Router.prototype.use = function () {
247
262
 
248
263
  // support array of paths
249
264
  if (Array.isArray(middleware[0]) && typeof middleware[0][0] === 'string') {
250
- let arrPaths = middleware[0];
251
- for (let i = 0; i < arrPaths.length; i++) {
252
- const p = arrPaths[i];
265
+ const arrPaths = middleware[0];
266
+ for (const p of arrPaths) {
253
267
  router.use.apply(router, [p].concat(middleware.slice(1)));
254
268
  }
255
269
 
@@ -259,12 +273,15 @@ Router.prototype.use = function () {
259
273
  const hasPath = typeof middleware[0] === 'string';
260
274
  if (hasPath) path = middleware.shift();
261
275
 
262
- for (let i = 0; i < middleware.length; i++) {
263
- const m = middleware[i];
276
+ for (const m of middleware) {
264
277
  if (m.router) {
265
- const cloneRouter = Object.assign(Object.create(Router.prototype), m.router, {
266
- stack: m.router.stack.slice(0)
267
- });
278
+ const cloneRouter = Object.assign(
279
+ Object.create(Router.prototype),
280
+ m.router,
281
+ {
282
+ stack: [...m.router.stack]
283
+ }
284
+ );
268
285
 
269
286
  for (let j = 0; j < cloneRouter.stack.length; j++) {
270
287
  const nestedLayer = cloneRouter.stack[j];
@@ -282,18 +299,21 @@ Router.prototype.use = function () {
282
299
  if (router.params) {
283
300
  function setRouterParams(paramArr) {
284
301
  const routerParams = paramArr;
285
- for (let j = 0; j < routerParams.length; j++) {
286
- const key = routerParams[j];
302
+ for (const key of routerParams) {
287
303
  cloneRouter.param(key, router.params[key]);
288
304
  }
289
305
  }
306
+
290
307
  setRouterParams(Object.keys(router.params));
291
308
  }
292
309
  } else {
293
310
  const keys = [];
294
311
  pathToRegexp(router.opts.prefix || '', keys);
295
312
  const routerPrefixHasParam = router.opts.prefix && keys.length;
296
- router.register(path || '([^\/]*)', [], m, { end: false, ignoreCaptures: !hasPath && !routerPrefixHasParam });
313
+ router.register(path || '([^/]*)', [], m, {
314
+ end: false,
315
+ ignoreCaptures: !hasPath && !routerPrefixHasParam
316
+ });
297
317
  }
298
318
  }
299
319
 
@@ -335,7 +355,7 @@ Router.prototype.prefix = function (prefix) {
335
355
  Router.prototype.routes = Router.prototype.middleware = function () {
336
356
  const router = this;
337
357
 
338
- let dispatch = function dispatch(ctx, next) {
358
+ const dispatch = function dispatch(ctx, next) {
339
359
  debug('%s %s', ctx.method, ctx.path);
340
360
 
341
361
  const path = router.opts.routerPath || ctx.routerPath || ctx.path;
@@ -352,23 +372,30 @@ Router.prototype.routes = Router.prototype.middleware = function () {
352
372
 
353
373
  if (!matched.route) return next();
354
374
 
355
- const matchedLayers = matched.pathAndMethod
356
- const mostSpecificLayer = matchedLayers[matchedLayers.length - 1]
375
+ const matchedLayers = matched.pathAndMethod;
376
+ const mostSpecificLayer = matchedLayers[matchedLayers.length - 1];
357
377
  ctx._matchedRoute = mostSpecificLayer.path;
358
378
  if (mostSpecificLayer.name) {
359
379
  ctx._matchedRouteName = mostSpecificLayer.name;
360
380
  }
361
381
 
362
- layerChain = matchedLayers.reduce(function(memo, layer) {
363
- memo.push(function(ctx, next) {
382
+ layerChain = (
383
+ router.exclusive ? [mostSpecificLayer] : matchedLayers
384
+ ).reduce(function (memo, layer) {
385
+ memo.push(function (ctx, next) {
364
386
  ctx.captures = layer.captures(path, ctx.captures);
365
- ctx.params = ctx.request.params = layer.params(path, ctx.captures, ctx.params);
387
+ ctx.params = ctx.request.params = layer.params(
388
+ path,
389
+ ctx.captures,
390
+ ctx.params
391
+ );
366
392
  ctx.routerPath = layer.path;
367
393
  ctx.routerName = layer.name;
368
394
  ctx._matchedRoute = layer.path;
369
395
  if (layer.name) {
370
396
  ctx._matchedRouteName = layer.name;
371
397
  }
398
+
372
399
  return next();
373
400
  });
374
401
  return memo.concat(layer.stack);
@@ -425,12 +452,11 @@ Router.prototype.routes = Router.prototype.middleware = function () {
425
452
  * @returns {Function}
426
453
  */
427
454
 
428
- Router.prototype.allowedMethods = function (options) {
429
- options = options || {};
455
+ Router.prototype.allowedMethods = function (options = {}) {
430
456
  const implemented = this.methods;
431
457
 
432
458
  return function allowedMethods(ctx, next) {
433
- return next().then(function() {
459
+ return next().then(function () {
434
460
  const allowed = {};
435
461
 
436
462
  if (!ctx.status || ctx.status === 404) {
@@ -446,25 +472,27 @@ Router.prototype.allowedMethods = function (options) {
446
472
 
447
473
  if (!~implemented.indexOf(ctx.method)) {
448
474
  if (options.throw) {
449
- let notImplementedThrowable = (typeof options.notImplemented === 'function')
450
- ? options.notImplemented() // set whatever the user returns from their function
451
- : new HttpError.NotImplemented();
475
+ const notImplementedThrowable =
476
+ typeof options.notImplemented === 'function'
477
+ ? options.notImplemented() // set whatever the user returns from their function
478
+ : new HttpError.NotImplemented();
452
479
 
453
480
  throw notImplementedThrowable;
454
481
  } else {
455
482
  ctx.status = 501;
456
483
  ctx.set('Allow', allowedArr.join(', '));
457
484
  }
458
- } else if (allowedArr.length) {
485
+ } else if (allowedArr.length > 0) {
459
486
  if (ctx.method === 'OPTIONS') {
460
487
  ctx.status = 200;
461
488
  ctx.body = '';
462
489
  ctx.set('Allow', allowedArr.join(', '));
463
490
  } else if (!allowed[ctx.method]) {
464
491
  if (options.throw) {
465
- let notAllowedThrowable = (typeof options.methodNotAllowed === 'function')
466
- ? options.methodNotAllowed() // set whatever the user returns from their function
467
- : new HttpError.MethodNotAllowed();
492
+ const notAllowedThrowable =
493
+ typeof options.methodNotAllowed === 'function'
494
+ ? options.methodNotAllowed() // set whatever the user returns from their function
495
+ : new HttpError.MethodNotAllowed();
468
496
 
469
497
  throw notAllowedThrowable;
470
498
  } else {
@@ -486,7 +514,6 @@ Router.prototype.allowedMethods = function (options) {
486
514
  * @param {Function=} middleware You may also pass multiple middleware.
487
515
  * @param {Function} callback
488
516
  * @returns {Router}
489
- * @private
490
517
  */
491
518
 
492
519
  Router.prototype.all = function (name, path, middleware) {
@@ -498,6 +525,14 @@ Router.prototype.all = function (name, path, middleware) {
498
525
  name = null;
499
526
  }
500
527
 
528
+ // Sanity check to ensure we have a viable path candidate (eg: string|regex|non-empty array)
529
+ if (
530
+ typeof path !== 'string' &&
531
+ !(path instanceof RegExp) &&
532
+ (!Array.isArray(path) || path.length === 0)
533
+ )
534
+ throw new Error('You have to provide a path when adding an all handler');
535
+
501
536
  this.register(path, methods, middleware, { name });
502
537
 
503
538
  return this;
@@ -529,12 +564,21 @@ Router.prototype.all = function (name, path, middleware) {
529
564
 
530
565
  Router.prototype.redirect = function (source, destination, code) {
531
566
  // lookup source route by name
532
- if (source[0] !== '/') source = this.url(source);
567
+ if (typeof source === 'symbol' || source[0] !== '/') {
568
+ source = this.url(source);
569
+ if (source instanceof Error) throw source;
570
+ }
533
571
 
534
572
  // lookup destination route by name
535
- if (destination[0] !== '/' && !destination.includes('://')) destination = this.url(destination);
573
+ if (
574
+ typeof destination === 'symbol' ||
575
+ (destination[0] !== '/' && !destination.includes('://'))
576
+ ) {
577
+ destination = this.url(destination);
578
+ if (destination instanceof Error) throw destination;
579
+ }
536
580
 
537
- return this.all(source, ctx => {
581
+ return this.all(source, (ctx) => {
538
582
  ctx.redirect(destination);
539
583
  ctx.status = code || 301;
540
584
  });
@@ -550,16 +594,13 @@ Router.prototype.redirect = function (source, destination, code) {
550
594
  * @private
551
595
  */
552
596
 
553
- Router.prototype.register = function (path, methods, middleware, opts) {
554
- opts = opts || {};
555
-
597
+ Router.prototype.register = function (path, methods, middleware, opts = {}) {
556
598
  const router = this;
557
- const stack = this.stack;
599
+ const { stack } = this;
558
600
 
559
601
  // support array of paths
560
602
  if (Array.isArray(path)) {
561
- for (let i = 0; i < path.length; i++) {
562
- const curPath = path[i];
603
+ for (const curPath of path) {
563
604
  router.register.call(router, curPath, methods, middleware, opts);
564
605
  }
565
606
 
@@ -572,7 +613,7 @@ Router.prototype.register = function (path, methods, middleware, opts) {
572
613
  name: opts.name,
573
614
  sensitive: opts.sensitive || this.opts.sensitive || false,
574
615
  strict: opts.strict || this.opts.strict || false,
575
- prefix: opts.prefix || this.opts.prefix || "",
616
+ prefix: opts.prefix || this.opts.prefix || '',
576
617
  ignoreCaptures: opts.ignoreCaptures
577
618
  });
578
619
 
@@ -603,7 +644,7 @@ Router.prototype.register = function (path, methods, middleware, opts) {
603
644
  Router.prototype.route = function (name) {
604
645
  const routes = this.stack;
605
646
 
606
- for (let len = routes.length, i=0; i<len; i++) {
647
+ for (let len = routes.length, i = 0; i < len; i++) {
607
648
  if (routes[i].name && routes[i].name === name) return routes[i];
608
649
  }
609
650
 
@@ -653,7 +694,7 @@ Router.prototype.url = function (name, params) {
653
694
  return route.url.apply(route, args);
654
695
  }
655
696
 
656
- return new Error(`No route found for name: ${name}`);
697
+ return new Error(`No route found for name: ${String(name)}`);
657
698
  };
658
699
 
659
700
  /**
@@ -680,12 +721,13 @@ Router.prototype.match = function (path, method) {
680
721
 
681
722
  debug('test %s %s', layer.path, layer.regexp);
682
723
 
724
+ // eslint-disable-next-line unicorn/prefer-regexp-test
683
725
  if (layer.match(path)) {
684
726
  matched.path.push(layer);
685
727
 
686
728
  if (layer.methods.length === 0 || ~layer.methods.indexOf(method)) {
687
729
  matched.pathAndMethod.push(layer);
688
- if (layer.methods.length) matched.route = true;
730
+ if (layer.methods.length > 0) matched.route = true;
689
731
  }
690
732
  }
691
733
  }
@@ -723,7 +765,7 @@ Router.prototype.match = function (path, method) {
723
765
  * @returns {Router}
724
766
  */
725
767
 
726
- Router.prototype.param = function(param, middleware) {
768
+ Router.prototype.param = function (param, middleware) {
727
769
  this.params[param] = middleware;
728
770
  for (let i = 0; i < this.stack.length; i++) {
729
771
  const route = this.stack[i];
package/package.json CHANGED
@@ -1,32 +1,47 @@
1
1
  {
2
2
  "name": "@koa/router",
3
- "description": "Router middleware for koa. Provides RESTful resource routing.",
4
- "version": "10.1.1",
3
+ "description": "Router middleware for koa. Maintained by Forward Email and Lad.",
4
+ "version": "11.0.0",
5
5
  "author": "Alex Mingoia <talk@alexmingoia.com>",
6
6
  "bugs": {
7
7
  "url": "https://github.com/koajs/router/issues",
8
8
  "email": "niftylettuce@gmail.com"
9
9
  },
10
+ "contributors": [
11
+ "Alex Mingoia <talk@alexmingoia.com>",
12
+ "@koajs"
13
+ ],
10
14
  "dependencies": {
11
- "debug": "^4.1.1",
12
- "http-errors": "^1.7.3",
15
+ "http-errors": "^2.0.0",
13
16
  "koa-compose": "^4.1.0",
14
17
  "methods": "^1.1.2",
15
- "path-to-regexp": "^6.1.0"
18
+ "path-to-regexp": "^6.2.1"
16
19
  },
17
20
  "devDependencies": {
18
- "@ladjs/env": "^1.0.0",
21
+ "@commitlint/cli": "^17.0.3",
22
+ "@commitlint/config-conventional": "^17.0.3",
23
+ "@ladjs/env": "^3.0.0",
24
+ "ava": "^4.3.0",
25
+ "cross-env": "^7.0.3",
26
+ "eslint": "^8.19.0",
27
+ "eslint-config-xo-lass": "^2.0.1",
19
28
  "expect.js": "^0.3.1",
20
- "jsdoc-to-markdown": "^5.0.3",
21
- "koa": "^2.11.0",
22
- "mocha": "^7.0.1",
23
- "nyc": "^15.0.0",
29
+ "fixpack": "^4.0.0",
30
+ "husky": "^8.0.1",
31
+ "jsdoc-to-markdown": "^7.1.1",
32
+ "koa": "^2.13.4",
33
+ "lint-staged": "^13.0.3",
34
+ "mocha": "^10.0.0",
35
+ "nyc": "^15.1.0",
36
+ "remark-cli": "^11.0.0",
37
+ "remark-preset-github": "^4.0.4",
24
38
  "should": "^13.2.3",
25
- "supertest": "^4.0.2",
26
- "wrk": "^1.2.0"
39
+ "supertest": "^6.2.4",
40
+ "wrk": "^1.2.1",
41
+ "xo": "^0.50.0"
27
42
  },
28
43
  "engines": {
29
- "node": ">= 8.0.0"
44
+ "node": ">= 12"
30
45
  },
31
46
  "files": [
32
47
  "lib"
@@ -45,9 +60,13 @@
45
60
  "url": "https://github.com/koajs/router.git"
46
61
  },
47
62
  "scripts": {
63
+ "bench": "make -C bench",
64
+ "coverage": "nyc npm run test",
48
65
  "docs": "NODE_ENV=test jsdoc2md -t ./lib/API_tpl.hbs --src ./lib/*.js >| API.md",
66
+ "lint": "xo --fix && remark . -qfo && fixpack",
67
+ "prepare": "husky install",
68
+ "pretest": "npm run lint",
49
69
  "test": "mocha test/**/*.js",
50
- "coverage": "nyc npm run test",
51
- "bench": "make -C bench"
70
+ "test:watch": "mocha test/**/*.js --watch"
52
71
  }
53
72
  }
package/history.md DELETED
@@ -1,157 +0,0 @@
1
- 9.0.0 / 2020-04-09
2
- ==================
3
-
4
- - Update `path-to-regexp`. Migration path: change usage of `'*'` in routes to `(.*)` or `:splat*`.
5
- - Example: `router.get('*', ....)` becomes `router.get('(.*)') ....)`
6
-
7
-
8
- 8.0.0 / 2019-06-16
9
- ==================
10
-
11
- **others**
12
- * [[`b5dd5e8`](http://github.com/koajs/koa-router/commit/b5dd5e8f00e841b7061a62ab6228cbe96a999470)] - chore: rename to @koa/router (dead-horse <<dead_horse@qq.com>>)
13
-
14
- -------------
15
-
16
- # Changelogs inherit from koa-router.
17
-
18
- ## 7.4.0
19
-
20
- - Fix router.url() for multiple nested routers [#407](https://github.com/alexmingoia/koa-router/pull/407)
21
- - `layer.name` added to `ctx` at `ctx.routerName` during routing [#412](https://github.com/alexmingoia/koa-router/pull/412)
22
- - Router.use() was erroneously settings `(.*)` as a prefix to all routers nested with .use that did not pass an explicit prefix string as the first argument. This resulted in routes being matched that should not have been, included the running of multiple route handlers in error. [#369](https://github.com/alexmingoia/koa-router/issues/369) and [#410](https://github.com/alexmingoia/koa-router/issues/410) include information on this issue.
23
-
24
- ## 7.3.0
25
-
26
- - Router#url() now accepts query parameters to add to generated urls [#396](https://github.com/alexmingoia/koa-router/pull/396)
27
-
28
- ## 7.2.1
29
-
30
- - Respond to CORS preflights with 200, 0 length body [#359](https://github.com/alexmingoia/koa-router/issues/359)
31
-
32
- ## 7.2.0
33
-
34
- - Fix a bug in Router#url and append Router object to ctx. [#350](https://github.com/alexmingoia/koa-router/pull/350)
35
- - Adds `_matchedRouteName` to context [#337](https://github.com/alexmingoia/koa-router/pull/337)
36
- - Respond to CORS preflights with 200, 0 length body [#359](https://github.com/alexmingoia/koa-router/issues/359)
37
-
38
- ## 7.1.1
39
-
40
- - Fix bug where param handlers were run out of order [#282](https://github.com/alexmingoia/koa-router/pull/282)
41
-
42
- ## 7.1.0
43
-
44
- - Backports: merge 5.4 work into the 7.x upstream. See 5.4.0 updates for more details.
45
-
46
- ## 7.0.1
47
-
48
- - Fix: allowedMethods should be ctx.method not this.method [#215](https://github.com/alexmingoia/koa-router/pull/215)
49
-
50
- ## 7.0.0
51
-
52
- - The API has changed to match the new promise-based middleware
53
- signature of koa 2. See the
54
- [koa 2.x readme](https://github.com/koajs/koa/tree/2.0.0-alpha.3) for more
55
- information.
56
- - Middleware is now always run in the order declared by `.use()` (or `.get()`,
57
- etc.), which matches Express 4 API.
58
-
59
- ## 5.4.0
60
-
61
- - Expose matched route at `ctx._matchedRoute`.
62
-
63
- ## 5.3.0
64
-
65
- - Register multiple routes with array of paths [#203](https://github.com/alexmingoia/koa-router/issue/143).
66
- - Improved router.url() [#143](https://github.com/alexmingoia/koa-router/pull/143)
67
- - Adds support for named routes and regular expressions
68
- [#152](https://github.com/alexmingoia/koa-router/pull/152)
69
- - Add support for custom throw functions for 405 and 501 responses [#206](https://github.com/alexmingoia/koa-router/pull/206)
70
-
71
- ## 5.2.3
72
-
73
- - Fix for middleware running twice when nesting routes [#184](https://github.com/alexmingoia/koa-router/issues/184)
74
-
75
- ## 5.2.2
76
-
77
- - Register routes without params before those with params [#183](https://github.com/alexmingoia/koa-router/pull/183)
78
- - Fix for allowed methods [#182](https://github.com/alexmingoia/koa-router/issues/182)
79
-
80
- ## 5.2.0
81
-
82
- - Add support for async/await. Resolves [#130](https://github.com/alexmingoia/koa-router/issues/130).
83
- - Add support for array of paths by Router#use(). Resolves [#175](https://github.com/alexmingoia/koa-router/issues/175).
84
- - Inherit param middleware when nesting routers. Fixes [#170](https://github.com/alexmingoia/koa-router/issues/170).
85
- - Default router middleware without path to root. Fixes [#161](https://github.com/alexmingoia/koa-router/issues/161), [#155](https://github.com/alexmingoia/koa-router/issues/155), [#156](https://github.com/alexmingoia/koa-router/issues/156).
86
- - Run nested router middleware after parent's. Fixes [#156](https://github.com/alexmingoia/koa-router/issues/156).
87
- - Remove dependency on koa-compose.
88
-
89
- ## 5.1.1
90
-
91
- - Match routes in order they were defined. Fixes #131.
92
-
93
- ## 5.1.0
94
-
95
- - Support mounting router middleware at a given path.
96
-
97
- ## 5.0.1
98
-
99
- - Fix bug with missing parameters when nesting routers.
100
-
101
- ## 5.0.0
102
-
103
- - Remove confusing API for extending koa app with router methods. Router#use()
104
- does not have the same behavior as app#use().
105
- - Add support for nesting routes.
106
- - Remove support for regular expression routes to achieve nestable routers and
107
- enable future trie-based routing optimizations.
108
-
109
- ## 4.3.2
110
-
111
- - Do not send 405 if route matched but status is 404. Fixes #112, closes #114.
112
-
113
- ## 4.3.1
114
-
115
- - Do not run middleware if not yielded to by previous middleware. Fixes #115.
116
-
117
- ## 4.3.0
118
-
119
- - Add support for router prefixes.
120
- - Add MIT license.
121
-
122
- ## 4.2.0
123
-
124
- - Fixed issue with router middleware being applied even if no route was
125
- matched.
126
- - Router.url - new static method to generate url from url pattern and data
127
-
128
- ## 4.1.0
129
-
130
- Private API changed to separate context parameter decoration from route
131
- matching. `Router#match` and `Route#match` are now pure functions that return
132
- an array of routes that match the URL path.
133
-
134
- For modules using this private API that need to determine if a method and path
135
- match a route, `route.methods` must be checked against the routes returned from
136
- `router.match()`:
137
-
138
- ```javascript
139
- var matchedRoute = router.match(path).filter(function (route) {
140
- return ~route.methods.indexOf(method);
141
- }).shift();
142
- ```
143
-
144
- ## 4.0.0
145
-
146
- 405, 501, and OPTIONS response handling was moved into separate middleware
147
- `router.allowedMethods()`. This resolves incorrect 501 or 405 responses when
148
- using multiple routers.
149
-
150
- ### Breaking changes
151
-
152
- 4.x is mostly backwards compatible with 3.x, except for the following:
153
-
154
- - Instantiating a router with `new` and `app` returns the router instance,
155
- whereas 3.x returns the router middleware. When creating a router in 4.x, the
156
- only time router middleware is returned is when creating using the
157
- `Router(app)` signature (with `app` and without `new`).