@eggjs/router 3.0.6 → 4.0.0-beta.17

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 CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/@eggjs/router.svg?style=flat-square)](https://npmjs.org/package/@eggjs/router)
4
4
  [![NPM download](https://img.shields.io/npm/dm/@eggjs/router.svg?style=flat-square)](https://npmjs.org/package/@eggjs/router)
5
- [![Node.js CI](https://github.com/eggjs/router/actions/workflows/nodejs.yml/badge.svg?branch=master)](https://github.com/eggjs/router/actions/workflows/nodejs.yml)
6
- [![Test coverage](https://img.shields.io/codecov/c/github/eggjs/router.svg?style=flat-square)](https://codecov.io/gh/eggjs/router)
7
5
  [![Known Vulnerabilities](https://snyk.io/test/npm/@eggjs/router/badge.svg?style=flat-square)](https://snyk.io/test/npm/@eggjs/router)
8
6
  [![Node.js Version](https://img.shields.io/node/v/@eggjs/router.svg?style=flat)](https://nodejs.org/en/download/)
9
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
@@ -51,9 +49,9 @@ Router core component for [Egg.js](https://github.com/eggjs).
51
49
 
52
50
  Create a new router.
53
51
 
54
- | Param | Type | Description |
55
- | --- | --- | --- |
56
- | [opts] | <code>Object</code> | |
52
+ | Param | Type | Description |
53
+ | ------------- | ------------------- | ------------------- |
54
+ | [opts] | <code>Object</code> | |
57
55
  | [opts.prefix] | <code>String</code> | prefix router paths |
58
56
 
59
57
  **Example**
@@ -70,16 +68,14 @@ router.get('/', async (ctx, next) => {
70
68
  // ctx.router available
71
69
  });
72
70
 
73
- app
74
- .use(router.routes())
75
- .use(router.allowedMethods());
71
+ app.use(router.routes()).use(router.allowedMethods());
76
72
  ```
77
73
 
78
74
  <a name="module_egg-router--Router+get|put|post|patch|delete|del"></a>
79
75
 
80
76
  #### router.get|put|post|patch|delete|del ⇒ <code>Router</code>
81
77
 
82
- Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
78
+ Create `router.verb()` methods, where _verb_ is one of the HTTP verbs such
83
79
  as `router.get()` or `router.post()`.
84
80
 
85
81
  Match URL patterns to callback functions or controller actions using `router.verb()`,
@@ -121,7 +117,7 @@ renaming of URLs during development.
121
117
 
122
118
  ```ts
123
119
  router.get('user', '/users/:id', (ctx, next) => {
124
- // ...
120
+ // ...
125
121
  });
126
122
 
127
123
  router.url('user', 3);
@@ -136,7 +132,7 @@ Multiple middleware may be given:
136
132
  router.get(
137
133
  '/users/:id',
138
134
  (ctx, next) => {
139
- return User.findOne(ctx.params.id).then(function(user) {
135
+ return User.findOne(ctx.params.id).then(function (user) {
140
136
  ctx.user = user;
141
137
  next();
142
138
  });
@@ -193,15 +189,16 @@ used to convert paths to regular expressions.
193
189
 
194
190
  **Kind**: instance property of <code>[Router](#exp_module_egg-router--Router)</code>
195
191
 
196
- | Param | Type | Description |
197
- | --- | --- | --- |
198
- | path | <code>String</code> | |
192
+ | Param | Type | Description |
193
+ | ------------ | --------------------- | ------------------- |
194
+ | path | <code>String</code> | |
199
195
  | [middleware] | <code>function</code> | route middleware(s) |
200
- | callback | <code>function</code> | route callback |
196
+ | callback | <code>function</code> | route callback |
201
197
 
202
198
  <a name="module_egg-router--Router+routes"></a>
203
199
 
204
200
  #### router.routes ⇒ <code>function</code>
201
+
205
202
  Returns router middleware which dispatches a route matching the request.
206
203
 
207
204
  **Kind**: instance property of <code>[Router](#exp_module_egg-router--Router)</code>
@@ -217,19 +214,17 @@ sequentially, requests start at the first middleware and work their way
217
214
 
218
215
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
219
216
 
220
- | Param | Type |
221
- | --- | --- |
222
- | [path] | <code>String</code> |
217
+ | Param | Type |
218
+ | ---------- | --------------------- |
219
+ | [path] | <code>String</code> |
223
220
  | middleware | <code>function</code> |
224
- | [...] | <code>function</code> |
221
+ | [...] | <code>function</code> |
225
222
 
226
223
  **Example**
227
224
 
228
225
  ```ts
229
226
  // session middleware will run before authorize
230
- router
231
- .use(session())
232
- .use(authorize());
227
+ router.use(session()).use(authorize());
233
228
 
234
229
  // use middleware only with given path
235
230
  router.use('/users', userAuth());
@@ -248,14 +243,14 @@ Set the path prefix for a Router instance that was already initialized.
248
243
 
249
244
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
250
245
 
251
- | Param | Type |
252
- | --- | --- |
246
+ | Param | Type |
247
+ | ------ | ------------------- |
253
248
  | prefix | <code>String</code> |
254
249
 
255
250
  **Example**
256
251
 
257
252
  ```ts
258
- router.prefix('/things/:thing_id')
253
+ router.prefix('/things/:thing_id');
259
254
  ```
260
255
 
261
256
  <a name="module_egg-router--Router+allowedMethods"></a>
@@ -268,11 +263,11 @@ with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
268
263
 
269
264
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
270
265
 
271
- | Param | Type | Description |
272
- | --- | --- | --- |
273
- | [options] | <code>Object</code> | |
274
- | [options.throw] | <code>Boolean</code> | throw error instead of setting status and header |
275
- | [options.notImplemented] | <code>function</code> | throw the returned value in place of the default NotImplemented error |
266
+ | Param | Type | Description |
267
+ | -------------------------- | --------------------- | ----------------------------------------------------------------------- |
268
+ | [options] | <code>Object</code> | |
269
+ | [options.throw] | <code>Boolean</code> | throw error instead of setting status and header |
270
+ | [options.notImplemented] | <code>function</code> | throw the returned value in place of the default NotImplemented error |
276
271
  | [options.methodNotAllowed] | <code>function</code> | throw the returned value in place of the default MethodNotAllowed error |
277
272
 
278
273
  **Example**
@@ -299,11 +294,13 @@ const app = new Koa();
299
294
  const router = new Router();
300
295
 
301
296
  app.use(router.routes());
302
- app.use(router.allowedMethods({
303
- throw: true,
304
- notImplemented: () => new Boom.notImplemented(),
305
- methodNotAllowed: () => new Boom.methodNotAllowed()
306
- }));
297
+ app.use(
298
+ router.allowedMethods({
299
+ throw: true,
300
+ notImplemented: () => new Boom.notImplemented(),
301
+ methodNotAllowed: () => new Boom.methodNotAllowed(),
302
+ })
303
+ );
307
304
  ```
308
305
 
309
306
  <a name="module_egg-router--Router+redirect"></a>
@@ -329,11 +326,11 @@ router.all('/login', ctx => {
329
326
 
330
327
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
331
328
 
332
- | Param | Type | Description |
333
- | --- | --- | --- |
334
- | source | <code>String</code> | URL or route name. |
335
- | destination | <code>String</code> | URL or route name. |
336
- | [code] | <code>Number</code> | HTTP status code (default: 301). |
329
+ | Param | Type | Description |
330
+ | ----------- | ------------------- | -------------------------------- |
331
+ | source | <code>String</code> | URL or route name. |
332
+ | destination | <code>String</code> | URL or route name. |
333
+ | [code] | <code>Number</code> | HTTP status code (default: 301). |
337
334
 
338
335
  <a name="module_egg-router--Router+route"></a>
339
336
 
@@ -343,9 +340,9 @@ Lookup route with given `name`.
343
340
 
344
341
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
345
342
 
346
- | Param | Type |
347
- | --- | --- |
348
- | name | <code>String</code> |
343
+ | Param | Type |
344
+ | ----- | ------------------- |
345
+ | name | <code>String</code> |
349
346
 
350
347
  <a name="module_egg-router--Router+url"></a>
351
348
 
@@ -355,12 +352,12 @@ Generate URL for route. Takes a route name and map of named `params`.
355
352
 
356
353
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
357
354
 
358
- | Param | Type | Description |
359
- | --- | --- | --- |
360
- | name | <code>String</code> | route name |
361
- | params | <code>Object</code> | url parameters |
362
- | [options] | <code>Object</code> | options parameter |
363
- | [options.query] | <code>Object</code> &#124; <code>String</code> | query options |
355
+ | Param | Type | Description |
356
+ | --------------- | ---------------------------------------------- | ----------------- |
357
+ | name | <code>String</code> | route name |
358
+ | params | <code>Object</code> | url parameters |
359
+ | [options] | <code>Object</code> | options parameter |
360
+ | [options.query] | <code>Object</code> &#124; <code>String</code> | query options |
364
361
 
365
362
  **Example**
366
363
 
@@ -378,12 +375,12 @@ router.url('user', { id: 3 });
378
375
  router.use((ctx, next) => {
379
376
  // redirect to named route
380
377
  ctx.redirect(ctx.router.url('sign-in'));
381
- })
378
+ });
382
379
 
383
380
  router.url('user', { id: 3 }, { query: { limit: 1 } });
384
381
  // => "/users/3?limit=1"
385
382
 
386
- router.url('user', { id: 3 }, { query: "limit=1" });
383
+ router.url('user', { id: 3 }, { query: 'limit=1' });
387
384
  // => "/users/3?limit=1"
388
385
  ```
389
386
 
@@ -396,9 +393,9 @@ validation.
396
393
 
397
394
  **Kind**: instance method of <code>[Router](#exp_module_egg-router--Router)</code>
398
395
 
399
- | Param | Type |
400
- | --- | --- |
401
- | param | <code>String</code> |
396
+ | Param | Type |
397
+ | ---------- | --------------------- |
398
+ | param | <code>String</code> |
402
399
  | middleware | <code>function</code> |
403
400
 
404
401
  **Example**
@@ -407,19 +404,19 @@ validation.
407
404
  router
408
405
  .param('user', (id, ctx, next) => {
409
406
  ctx.user = users[id];
410
- if (!ctx.user) return ctx.status = 404;
407
+ if (!ctx.user) return (ctx.status = 404);
411
408
  return next();
412
409
  })
413
410
  .get('/users/:user', ctx => {
414
411
  ctx.body = ctx.user;
415
412
  })
416
413
  .get('/users/:user/friends', ctx => {
417
- return ctx.user.getFriends().then(function(friends) {
414
+ return ctx.user.getFriends().then(function (friends) {
418
415
  ctx.body = friends;
419
416
  });
420
- })
421
- // /users/3 => {"id": 3, "name": "Alex"}
422
- // /users/3/friends => [{"id": 4, "name": "TJ"}]
417
+ });
418
+ // /users/3 => {"id": 3, "name": "Alex"}
419
+ // /users/3/friends => [{"id": 4, "name": "TJ"}]
423
420
  ```
424
421
 
425
422
  <a name="module_egg-router--Router.url"></a>
@@ -430,20 +427,20 @@ Generate URL from url pattern and given `params`.
430
427
 
431
428
  **Kind**: static method of <code>[Router](#exp_module_egg-router--Router)</code>
432
429
 
433
- | Param | Type | Description |
434
- | --- | --- | --- |
435
- | path | <code>String</code> | url pattern |
436
- | params | <code>Object</code> | url parameters |
437
- | [options] | <code>Object</code> | options parameter |
438
- | [options.query] | <code>Object</code> &#124; <code>String</code> | query options |
430
+ | Param | Type | Description |
431
+ | --------------- | ---------------------------------------------- | ----------------- |
432
+ | path | <code>String</code> | url pattern |
433
+ | params | <code>Object</code> | url parameters |
434
+ | [options] | <code>Object</code> | options parameter |
435
+ | [options.query] | <code>Object</code> &#124; <code>String</code> | query options |
439
436
 
440
437
  **Example**
441
438
 
442
439
  ```ts
443
- const url = Router.url('/users/:id', {id: 1});
440
+ const url = Router.url('/users/:id', { id: 1 });
444
441
  // => "/users/1"
445
442
 
446
- const url = Router.url('/users/:id', {id: 1}, {query: { active: true }});
443
+ const url = Router.url('/users/:id', { id: 1 }, { query: { active: true } });
447
444
  // => "/users/1?active=true"
448
445
  ```
449
446
 
@@ -462,6 +459,6 @@ Run tests using `npm test`.
462
459
 
463
460
  ## Contributors
464
461
 
465
- [![Contributors](https://contrib.rocks/image?repo=eggjs/router)](https://github.com/eggjs/router/graphs/contributors)
462
+ [![Contributors](https://contrib.rocks/image?repo=eggjs/egg)](https://github.com/eggjs/egg/graphs/contributors)
466
463
 
467
464
  Made with [contributors-img](https://contrib.rocks).
@@ -0,0 +1,108 @@
1
+ import { MiddlewareFunc, ResourcesController } from "./types.js";
2
+ import { Layer } from "./Layer.js";
3
+ import { RegisterOptions, Router, RouterMethod, RouterOptions } from "./Router.js";
4
+
5
+ //#region src/EggRouter.d.ts
6
+ interface Application {
7
+ controller: Record<string, any>;
8
+ }
9
+ /**
10
+ * FIXME: move these patch into @eggjs/router
11
+ */
12
+ declare class EggRouter extends Router {
13
+ readonly app: Application;
14
+ /**
15
+ * @class
16
+ * @param {Object} opts - Router options.
17
+ * @param {Application} app - Application object.
18
+ */
19
+ constructor(opts: RouterOptions, app: Application);
20
+ verb(method: RouterMethod | RouterMethod[], nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc, ...middleware: (MiddlewareFunc | string)[]): this;
21
+ head(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
22
+ head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
23
+ options(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
24
+ options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
25
+ get(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
26
+ get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
27
+ put(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
28
+ put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
29
+ patch(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
30
+ patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
31
+ post(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
32
+ post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
33
+ delete(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
34
+ delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
35
+ all(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
36
+ all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
37
+ register(path: string | RegExp | (string | RegExp)[], methods: string[], middleware: MiddlewareFunc | string | (MiddlewareFunc | string | ResourcesController)[], opts?: RegisterOptions): Layer | Layer[];
38
+ /**
39
+ * restful router api
40
+ * @param {String} name - Router name
41
+ * @param {String} prefix - url prefix
42
+ * @param {Function} middleware - middleware or controller
43
+ * @example
44
+ * ```js
45
+ * app.resources('/posts', 'posts')
46
+ * app.resources('posts', '/posts', 'posts')
47
+ * app.resources('posts', '/posts', app.role.can('user'), app.controller.posts)
48
+ * app.resources('posts', '/posts', middleware1, middleware2, app.controller.posts)
49
+ * ```
50
+ *
51
+ * Examples:
52
+ *
53
+ * ```js
54
+ * app.resources('/posts', 'posts')
55
+ * ```
56
+ *
57
+ * yield router mapping
58
+ *
59
+ * Method | Path | Route Name | Controller.Action
60
+ * -------|-----------------|----------------|-----------------------------
61
+ * GET | /posts | posts | app.controller.posts.index
62
+ * GET | /posts/new | new_post | app.controller.posts.new
63
+ * GET | /posts/:id | post | app.controller.posts.show
64
+ * GET | /posts/:id/edit | edit_post | app.controller.posts.edit
65
+ * POST | /posts | posts | app.controller.posts.create
66
+ * PATCH | /posts/:id | post | app.controller.posts.update
67
+ * DELETE | /posts/:id | post | app.controller.posts.destroy
68
+ *
69
+ * app.router.url can generate url based on arguments
70
+ * ```js
71
+ * app.router.url('posts')
72
+ * => /posts
73
+ * app.router.url('post', { id: 1 })
74
+ * => /posts/1
75
+ * app.router.url('new_post')
76
+ * => /posts/new
77
+ * app.router.url('edit_post', { id: 1 })
78
+ * => /posts/1/edit
79
+ * ```
80
+ * @return {Router} return route object.
81
+ * @since 1.0.0
82
+ */
83
+ resources(prefix: string, controller: string | ResourcesController): Router;
84
+ resources(prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
85
+ resources(name: string, prefix: string, controller: string | ResourcesController): Router;
86
+ resources(name: string, prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
87
+ resources(nameOrPath: string | RegExp, ...middleware: (MiddlewareFunc | string | ResourcesController)[]): Router;
88
+ /**
89
+ * @param {String} name - Router name
90
+ * @param {Object} params - more parameters
91
+ * @example
92
+ * ```js
93
+ * router.url('edit_post', { id: 1, name: 'foo', page: 2 })
94
+ * => /posts/1/edit?name=foo&page=2
95
+ * router.url('posts', { name: 'foo&1', page: 2 })
96
+ * => /posts?name=foo%261&page=2
97
+ * ```
98
+ * @return {String} url by path name and query params.
99
+ * @since 1.0.0
100
+ */
101
+ url(name: string, params?: Record<string, string | number | (string | number)[]>): string;
102
+ /**
103
+ * @alias to url()
104
+ */
105
+ pathFor(name: string, params?: Record<string, string | number | (string | number)[]>): string;
106
+ }
107
+ //#endregion
108
+ export { EggRouter };
@@ -0,0 +1,208 @@
1
+ import { Router } from "./Router.js";
2
+ import assert from "node:assert";
3
+ import { encodeURIComponent } from "utility";
4
+ import inflection from "inflection";
5
+ import methods from "methods";
6
+ import { isGeneratorFunction } from "is-type-of";
7
+
8
+ //#region src/EggRouter.ts
9
+ const REST_MAP = {
10
+ index: {
11
+ suffix: "",
12
+ method: "GET"
13
+ },
14
+ new: {
15
+ namePrefix: "new_",
16
+ member: true,
17
+ suffix: "new",
18
+ method: "GET"
19
+ },
20
+ create: {
21
+ suffix: "",
22
+ method: "POST"
23
+ },
24
+ show: {
25
+ member: true,
26
+ suffix: ":id",
27
+ method: "GET"
28
+ },
29
+ edit: {
30
+ member: true,
31
+ namePrefix: "edit_",
32
+ suffix: ":id/edit",
33
+ method: "GET"
34
+ },
35
+ update: {
36
+ member: true,
37
+ namePrefix: "",
38
+ suffix: ":id",
39
+ method: ["PATCH", "PUT"]
40
+ },
41
+ destroy: {
42
+ member: true,
43
+ namePrefix: "destroy_",
44
+ suffix: ":id",
45
+ method: "DELETE"
46
+ }
47
+ };
48
+ /**
49
+ * FIXME: move these patch into @eggjs/router
50
+ */
51
+ var EggRouter = class extends Router {
52
+ app;
53
+ /**
54
+ * @class
55
+ * @param {Object} opts - Router options.
56
+ * @param {Application} app - Application object.
57
+ */
58
+ constructor(opts, app) {
59
+ super(opts);
60
+ this.app = app;
61
+ }
62
+ verb(method, nameOrPath, pathOrMiddleware, ...middleware) {
63
+ const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
64
+ if (typeof method === "string") method = [method];
65
+ this.register(path, method, middlewares, options);
66
+ return this;
67
+ }
68
+ head(nameOrPath, pathOrMiddleware, ...middlewares) {
69
+ return this.verb("head", nameOrPath, pathOrMiddleware, ...middlewares);
70
+ }
71
+ options(nameOrPath, pathOrMiddleware, ...middlewares) {
72
+ return this.verb("options", nameOrPath, pathOrMiddleware, ...middlewares);
73
+ }
74
+ get(nameOrPath, pathOrMiddleware, ...middlewares) {
75
+ return this.verb("get", nameOrPath, pathOrMiddleware, ...middlewares);
76
+ }
77
+ put(nameOrPath, pathOrMiddleware, ...middlewares) {
78
+ return this.verb("put", nameOrPath, pathOrMiddleware, ...middlewares);
79
+ }
80
+ patch(nameOrPath, pathOrMiddleware, ...middlewares) {
81
+ return this.verb("patch", nameOrPath, pathOrMiddleware, ...middlewares);
82
+ }
83
+ post(nameOrPath, pathOrMiddleware, ...middlewares) {
84
+ return this.verb("post", nameOrPath, pathOrMiddleware, ...middlewares);
85
+ }
86
+ delete(nameOrPath, pathOrMiddleware, ...middlewares) {
87
+ return this.verb("delete", nameOrPath, pathOrMiddleware, ...middlewares);
88
+ }
89
+ all(nameOrPath, pathOrMiddleware, ...middlewares) {
90
+ return this.verb(methods, nameOrPath, pathOrMiddleware, ...middlewares);
91
+ }
92
+ register(path, methods$1, middleware, opts) {
93
+ middleware = Array.isArray(middleware) ? middleware : [middleware];
94
+ for (const mw of middleware) if (isGeneratorFunction(mw)) throw new TypeError(methods$1.toString() + " `" + path + "`: Please use async function instead of generator function");
95
+ const middlewares = convertMiddlewares(middleware, this.app);
96
+ return super.register(path, methods$1, middlewares, opts);
97
+ }
98
+ resources(nameOrPath, pathOrMiddleware, ...middleware) {
99
+ const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
100
+ const controller = resolveController(middlewares.pop(), this.app);
101
+ for (const key in REST_MAP) {
102
+ const action = controller[key];
103
+ if (!action) continue;
104
+ const opts = REST_MAP[key];
105
+ let routeName;
106
+ if (opts.member) routeName = inflection.singularize(options.name ?? "");
107
+ else routeName = inflection.pluralize(options.name ?? "");
108
+ if (opts.namePrefix) routeName = opts.namePrefix + routeName;
109
+ const prefix = path.replace(/\/$/, "");
110
+ const urlPath = opts.suffix ? `${prefix}/${opts.suffix}` : prefix;
111
+ const method = Array.isArray(opts.method) ? opts.method : [opts.method];
112
+ this.register(urlPath, method, middlewares.concat(action), { name: routeName });
113
+ }
114
+ return this;
115
+ }
116
+ /**
117
+ * @param {String} name - Router name
118
+ * @param {Object} params - more parameters
119
+ * @example
120
+ * ```js
121
+ * router.url('edit_post', { id: 1, name: 'foo', page: 2 })
122
+ * => /posts/1/edit?name=foo&page=2
123
+ * router.url('posts', { name: 'foo&1', page: 2 })
124
+ * => /posts?name=foo%261&page=2
125
+ * ```
126
+ * @return {String} url by path name and query params.
127
+ * @since 1.0.0
128
+ */
129
+ url(name, params) {
130
+ const route = this.route(name);
131
+ if (!route) return "";
132
+ const args = params;
133
+ let url = route.path;
134
+ assert(!(url instanceof RegExp), `Can't get the url for regExp ${url} for by name '${name}'`);
135
+ const queries = [];
136
+ if (typeof args === "object" && args !== null) {
137
+ const replacedParams = [];
138
+ url = url.replace(/:([a-zA-Z_]\w*)/g, ($0, key) => {
139
+ if (key in args) {
140
+ const values = args[key];
141
+ replacedParams.push(key);
142
+ return encodeURIComponent(Array.isArray(values) ? String(values[0]) : String(values));
143
+ }
144
+ return $0;
145
+ });
146
+ for (const key in args) {
147
+ if (replacedParams.includes(key)) continue;
148
+ const values = args[key];
149
+ const encodedKey = encodeURIComponent(key);
150
+ if (Array.isArray(values)) for (const val of values) queries.push(`${encodedKey}=${encodeURIComponent(String(val))}`);
151
+ else queries.push(`${encodedKey}=${encodeURIComponent(String(values))}`);
152
+ }
153
+ }
154
+ if (queries.length > 0) {
155
+ const queryStr = queries.join("&");
156
+ if (!url.includes("?")) url = `${url}?${queryStr}`;
157
+ else url = `${url}&${queryStr}`;
158
+ }
159
+ return url;
160
+ }
161
+ /**
162
+ * @alias to url()
163
+ */
164
+ pathFor(name, params) {
165
+ return this.url(name, params);
166
+ }
167
+ };
168
+ /**
169
+ * resolve controller from string to function
170
+ * @param {String|Function} controller input controller
171
+ * @param {Application} app egg application instance
172
+ */
173
+ function resolveController(controller, app) {
174
+ if (typeof controller === "string") {
175
+ const actions = controller.split(".");
176
+ let obj = app.controller;
177
+ actions.forEach((key) => {
178
+ obj = obj[key];
179
+ if (!obj) throw new Error(`app.controller.${controller} not exists`);
180
+ });
181
+ controller = obj;
182
+ }
183
+ if (!controller) throw new Error("controller not exists");
184
+ return controller;
185
+ }
186
+ /**
187
+ * 1. ensure controller(last argument) support string
188
+ * - [url, controller]: app.get('/home', 'home');
189
+ * - [name, url, controller(string)]: app.get('posts', '/posts', 'posts.list');
190
+ * - [name, url, controller]: app.get('posts', '/posts', app.controller.posts.list);
191
+ * - [name, url(regexp), controller]: app.get('regRouter', /\/home\/index/, 'home.index');
192
+ * - [name, url, middleware, [...], controller]: `app.get(/user/:id', hasLogin, canGetUser, 'user.show');`
193
+ *
194
+ * 2. bind ctx to controller `this`
195
+ *
196
+ * @param {Array} middlewares middlewares and controller(last middleware)
197
+ * @param {Application} app egg application instance
198
+ */
199
+ function convertMiddlewares(middlewares, app) {
200
+ const controller = resolveController(middlewares.pop(), app);
201
+ function wrappedController(ctx, next) {
202
+ return controller.apply(ctx, [ctx, next]);
203
+ }
204
+ return [...middlewares, wrappedController];
205
+ }
206
+
207
+ //#endregion
208
+ export { EggRouter };