🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@eggjs/router

Package Overview
Dependencies
Maintainers
13
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eggjs/router - npm Package Compare versions

Comparing version
2.0.1
to
3.0.0
+102
dist/commonjs/EggRouter.d.ts
import { RegisterOptions, Router, RouterMethod, RouterOptions } from './Router.js';
import { MiddlewareFunc, ResourcesController } from './types.js';
interface Application {
controller: Record<string, any>;
}
/**
* FIXME: move these patch into @eggjs/router
*/
export declare class EggRouter extends Router {
readonly app: Application;
/**
* @class
* @param {Object} opts - Router options.
* @param {Application} app - Application object.
*/
constructor(opts: RouterOptions, app: Application);
verb(method: RouterMethod | RouterMethod[], nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc, ...middleware: (MiddlewareFunc | string)[]): this;
head(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
options(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
get(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
put(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
patch(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
post(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
delete(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
all(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
register(path: string | RegExp | (string | RegExp)[], methods: string[], middleware: MiddlewareFunc | string | (MiddlewareFunc | string | ResourcesController)[], opts?: RegisterOptions): import("./Layer.js").Layer | import("./Layer.js").Layer[];
/**
* restful router api
* @param {String} name - Router name
* @param {String} prefix - url prefix
* @param {Function} middleware - middleware or controller
* @example
* ```js
* app.resources('/posts', 'posts')
* app.resources('posts', '/posts', 'posts')
* app.resources('posts', '/posts', app.role.can('user'), app.controller.posts)
* ```
*
* Examples:
*
* ```js
* app.resources('/posts', 'posts')
* ```
*
* yield router mapping
*
* Method | Path | Route Name | Controller.Action
* -------|-----------------|----------------|-----------------------------
* GET | /posts | posts | app.controller.posts.index
* GET | /posts/new | new_post | app.controller.posts.new
* GET | /posts/:id | post | app.controller.posts.show
* GET | /posts/:id/edit | edit_post | app.controller.posts.edit
* POST | /posts | posts | app.controller.posts.create
* PATCH | /posts/:id | post | app.controller.posts.update
* DELETE | /posts/:id | post | app.controller.posts.destroy
*
* app.router.url can generate url based on arguments
* ```js
* app.router.url('posts')
* => /posts
* app.router.url('post', { id: 1 })
* => /posts/1
* app.router.url('new_post')
* => /posts/new
* app.router.url('edit_post', { id: 1 })
* => /posts/1/edit
* ```
* @return {Router} return route object.
* @since 1.0.0
*/
resources(prefix: string, controller: string | ResourcesController): Router;
resources(prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
resources(name: string, prefix: string, controller: string | ResourcesController): Router;
resources(name: string, prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name: string, params?: Record<string, string | number | (string | number)[]>): string;
/**
* @alias to url()
*/
pathFor(name: string, params?: Record<string, string | number | (string | number)[]>): string;
}
export {};
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EggRouter = void 0;
const node_assert_1 = __importDefault(require("node:assert"));
const utility_1 = require("utility");
const inflection_1 = __importDefault(require("inflection"));
const methods_1 = __importDefault(require("methods"));
const Router_js_1 = require("./Router.js");
const REST_MAP = {
index: {
suffix: '',
method: 'GET',
},
new: {
namePrefix: 'new_',
member: true,
suffix: 'new',
method: 'GET',
},
create: {
suffix: '',
method: 'POST',
},
show: {
member: true,
suffix: ':id',
method: 'GET',
},
edit: {
member: true,
namePrefix: 'edit_',
suffix: ':id/edit',
method: 'GET',
},
update: {
member: true,
namePrefix: '',
suffix: ':id',
method: ['PATCH', 'PUT'],
},
destroy: {
member: true,
namePrefix: 'destroy_',
suffix: ':id',
method: 'DELETE',
},
};
/**
* FIXME: move these patch into @eggjs/router
*/
class EggRouter extends Router_js_1.Router {
app;
/**
* @class
* @param {Object} opts - Router options.
* @param {Application} app - Application object.
*/
constructor(opts, app) {
super(opts);
this.app = app;
}
verb(method, nameOrPath, pathOrMiddleware, ...middleware) {
const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
if (typeof method === 'string') {
method = [method];
}
this.register(path, method, middlewares, options);
return this;
}
head(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares);
}
options(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares);
}
get(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares);
}
put(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares);
}
patch(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares);
}
post(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares);
}
delete(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
all(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb(methods_1.default, nameOrPath, pathOrMiddleware, ...middlewares);
}
register(path, methods, middleware, opts) {
// patch register to support generator function middleware and string controller
middleware = Array.isArray(middleware) ? middleware : [middleware];
const middlewares = convertMiddlewares(middleware, this.app);
return super.register(path, methods, middlewares, opts);
}
resources(nameOrPath, pathOrMiddleware, ...middleware) {
const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
// last argument is Controller object
const controller = resolveController(middlewares.pop(), this.app);
for (const key in REST_MAP) {
const action = controller[key];
if (!action)
continue;
const opts = REST_MAP[key];
let routeName;
if (opts.member) {
routeName = inflection_1.default.singularize(options.name ?? '');
}
else {
routeName = inflection_1.default.pluralize(options.name ?? '');
}
if (opts.namePrefix) {
routeName = opts.namePrefix + routeName;
}
const prefix = path.replace(/\/$/, '');
const urlPath = opts.suffix ? `${prefix}/${opts.suffix}` : prefix;
const method = Array.isArray(opts.method) ? opts.method : [opts.method];
this.register(urlPath, method, middlewares.concat(action), { name: routeName });
}
return this;
}
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name, params) {
const route = this.route(name);
if (!route)
return '';
const args = params;
let url = route.path;
(0, node_assert_1.default)(!(url instanceof RegExp), `Can't get the url for regExp ${url} for by name '${name}'`);
const queries = [];
if (typeof args === 'object' && args !== null) {
const replacedParams = [];
url = url.replace(/:([a-zA-Z_]\w*)/g, ($0, key) => {
if (key in args) {
const values = args[key];
replacedParams.push(key);
return (0, utility_1.encodeURIComponent)(Array.isArray(values) ? String(values[0]) : String(values));
}
return $0;
});
for (const key in args) {
if (replacedParams.includes(key)) {
continue;
}
const values = args[key];
const encodedKey = (0, utility_1.encodeURIComponent)(key);
if (Array.isArray(values)) {
for (const val of values) {
queries.push(`${encodedKey}=${(0, utility_1.encodeURIComponent)(String(val))}`);
}
}
else {
queries.push(`${encodedKey}=${(0, utility_1.encodeURIComponent)(String(values))}`);
}
}
}
if (queries.length > 0) {
const queryStr = queries.join('&');
if (!url.includes('?')) {
url = `${url}?${queryStr}`;
}
else {
url = `${url}&${queryStr}`;
}
}
return url;
}
/**
* @alias to url()
*/
pathFor(name, params) {
return this.url(name, params);
}
}
exports.EggRouter = EggRouter;
/**
* resolve controller from string to function
* @param {String|Function} controller input controller
* @param {Application} app egg application instance
*/
function resolveController(controller, app) {
if (typeof controller === 'string') {
// resolveController('foo.bar.Home', app)
const actions = controller.split('.');
let obj = app.controller;
actions.forEach(key => {
obj = obj[key];
if (!obj)
throw new Error(`app.controller.${controller} not exists`);
});
controller = obj;
}
// ensure controller is exists
if (!controller)
throw new Error('controller not exists');
return controller;
}
/**
* 1. ensure controller(last argument) support string
* - [url, controller]: app.get('/home', 'home');
* - [name, url, controller(string)]: app.get('posts', '/posts', 'posts.list');
* - [name, url, controller]: app.get('posts', '/posts', app.controller.posts.list);
* - [name, url(regexp), controller]: app.get('regRouter', /\/home\/index/, 'home.index');
* - [name, url, middleware, [...], controller]: `app.get(/user/:id', hasLogin, canGetUser, 'user.show');`
*
* 2. make middleware support generator function
*
* @param {Array} middlewares middlewares and controller(last middleware)
* @param {Application} app egg application instance
*/
function convertMiddlewares(middlewares, app) {
// ensure controller is resolved
const controller = resolveController(middlewares.pop(), app);
return [...middlewares, controller];
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRWdnUm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0VnZ1JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSw4REFBaUM7QUFDakMscUNBQXVFO0FBQ3ZFLDREQUFvQztBQUNwQyxzREFBOEI7QUFDOUIsMkNBQW1GO0FBVW5GLE1BQU0sUUFBUSxHQUFtQztJQUMvQyxLQUFLLEVBQUU7UUFDTCxNQUFNLEVBQUUsRUFBRTtRQUNWLE1BQU0sRUFBRSxLQUFLO0tBQ2Q7SUFDRCxHQUFHLEVBQUU7UUFDSCxVQUFVLEVBQUUsTUFBTTtRQUNsQixNQUFNLEVBQUUsSUFBSTtRQUNaLE1BQU0sRUFBRSxLQUFLO1FBQ2IsTUFBTSxFQUFFLEtBQUs7S0FDZDtJQUNELE1BQU0sRUFBRTtRQUNOLE1BQU0sRUFBRSxFQUFFO1FBQ1YsTUFBTSxFQUFFLE1BQU07S0FDZjtJQUNELElBQUksRUFBRTtRQUNKLE1BQU0sRUFBRSxJQUFJO1FBQ1osTUFBTSxFQUFFLEtBQUs7UUFDYixNQUFNLEVBQUUsS0FBSztLQUNkO0lBQ0QsSUFBSSxFQUFFO1FBQ0osTUFBTSxFQUFFLElBQUk7UUFDWixVQUFVLEVBQUUsT0FBTztRQUNuQixNQUFNLEVBQUUsVUFBVTtRQUNsQixNQUFNLEVBQUUsS0FBSztLQUNkO0lBQ0QsTUFBTSxFQUFFO1FBQ04sTUFBTSxFQUFFLElBQUk7UUFDWixVQUFVLEVBQUUsRUFBRTtRQUNkLE1BQU0sRUFBRSxLQUFLO1FBQ2IsTUFBTSxFQUFFLENBQUUsT0FBTyxFQUFFLEtBQUssQ0FBRTtLQUMzQjtJQUNELE9BQU8sRUFBRTtRQUNQLE1BQU0sRUFBRSxJQUFJO1FBQ1osVUFBVSxFQUFFLFVBQVU7UUFDdEIsTUFBTSxFQUFFLEtBQUs7UUFDYixNQUFNLEVBQUUsUUFBUTtLQUNqQjtDQUNGLENBQUM7QUFNRjs7R0FFRztBQUNILE1BQWEsU0FBVSxTQUFRLGtCQUFNO0lBQzFCLEdBQUcsQ0FBYztJQUUxQjs7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
import { Router } from './Router.js';
export * from './Router.js';
export * from './EggRouter.js';
export declare const KoaRouter: typeof Router;
export default Router;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.KoaRouter = void 0;
const Router_js_1 = require("./Router.js");
__exportStar(require("./Router.js"), exports);
__exportStar(require("./EggRouter.js"), exports);
exports.KoaRouter = Router_js_1.Router;
exports.default = Router_js_1.Router;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQ0FBcUM7QUFFckMsOENBQTRCO0FBQzVCLGlEQUErQjtBQUVsQixRQUFBLFNBQVMsR0FBRyxrQkFBTSxDQUFDO0FBQ2hDLGtCQUFlLGtCQUFNLENBQUMifQ==
import { type Key } from 'path-to-regexp';
import type { MiddlewareFunc, MiddlewareFuncWithParamProperty, ParamMiddlewareFunc } from './types.js';
export interface LayerOptions {
prefix?: string;
/** route name */
name?: string;
/** case sensitive (default: false) */
sensitive?: boolean;
/** require the trailing slash (default: false) */
strict?: boolean;
ignoreCaptures?: boolean;
end?: boolean;
}
export interface LayerURLOptions {
query?: string | object;
}
export declare class Layer {
readonly opts: LayerOptions;
readonly name?: string;
readonly methods: string[];
readonly stack: MiddlewareFuncWithParamProperty[];
path: string | RegExp;
regexp: RegExp;
paramNames: Key[];
/**
* Initialize a new routing Layer with given `method`, `path`, and `middleware`.
*
* @param {String|RegExp} path Path string or regular expression.
* @param {Array} methods Array of HTTP verbs.
* @param {Array|Function} middlewares Layer callback/middleware or series of.
* @param {Object=} opts optional params
* @param {String=} opts.name route name
* @param {String=} opts.sensitive case sensitive (default: false)
* @param {String=} opts.strict require the trailing slash (default: false)
* @private
*/
constructor(path: string | RegExp, methods: string[], middlewares: MiddlewareFunc | MiddlewareFunc[], opts?: LayerOptions | string);
/**
* Returns whether request `path` matches route.
*
* @param {String} path path string
* @return {Boolean} matched or not
* @private
*/
match(path: string): boolean;
/**
* Returns map of URL parameters for given `path` and `paramNames`.
*
* @param {String} _path path string
* @param {Array.<String>} captures captures strings
* @param {Object=} [existingParams] existing params
* @return {Object} params object
* @private
*/
params(_path: string, captures: Array<string>, existingParams?: Record<string, string>): Record<string, string>;
/**
* Returns array of regexp url path captures.
*
* @param {String} path path string
* @return {Array.<String>} captures strings
* @private
*/
captures(path: string): Array<string>;
/**
* Generate URL for route using given `params`.
*
* @example
*
* ```javascript
* var route = new Layer(['GET'], '/users/:id', fn);
*
* route.url(123); // => "/users/123"
* route.url('123'); // => "/users/123"
* route.url({ id: 123 }); // => "/users/123"
* ```
*
* @param {Object} params url parameters
* @param {Object} paramsOrOptions optional parameters
* @return {String} url string
* @private
*/
url(params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string;
/**
* Run validations on route named parameters.
*
* @example
*
* ```javascript
* router
* .param('user', function (id, ctx, next) {
* ctx.user = users[id];
* if (!user) return ctx.status = 404;
* next();
* })
* .get('/users/:user', function (ctx, next) {
* ctx.body = ctx.user;
* });
* ```
*
* @param {String} param param string
* @param {Function} fn middleware function
* @return {Layer} layer instance
* @private
*/
param(param: string, fn: ParamMiddlewareFunc): Layer;
/**
* Prefix route path.
*
* @param {String} prefix prefix string
* @return {Layer} layer instance
* @private
*/
setPrefix(prefix: string): Layer;
}
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Layer = void 0;
const node_util_1 = require("node:util");
const path_to_regexp_1 = __importDefault(require("path-to-regexp"));
const urijs_1 = __importDefault(require("urijs"));
const utility_1 = require("utility");
const is_type_of_1 = require("is-type-of");
const debug = (0, node_util_1.debuglog)('egg-router:layer');
class Layer {
opts;
name;
methods = [];
stack;
path;
regexp;
paramNames = [];
/**
* Initialize a new routing Layer with given `method`, `path`, and `middleware`.
*
* @param {String|RegExp} path Path string or regular expression.
* @param {Array} methods Array of HTTP verbs.
* @param {Array|Function} middlewares Layer callback/middleware or series of.
* @param {Object=} opts optional params
* @param {String=} opts.name route name
* @param {String=} opts.sensitive case sensitive (default: false)
* @param {String=} opts.strict require the trailing slash (default: false)
* @private
*/
constructor(path, methods, middlewares, opts) {
if (typeof opts === 'string') {
// new Layer(path, methods, middlewares, name);
opts = { name: opts };
}
this.opts = opts ?? {};
this.opts.prefix = this.opts.prefix ?? '';
this.name = this.opts.name;
this.stack = Array.isArray(middlewares) ? middlewares : [middlewares];
for (const method of methods) {
const l = this.methods.push(method.toUpperCase());
if (this.methods[l - 1] === 'GET') {
this.methods.unshift('HEAD');
}
}
// ensure middleware is a function
this.stack.forEach(fn => {
const type = typeof fn;
if (type !== 'function') {
throw new TypeError(methods.toString() + ' `' + (this.opts.name || path) + '`: `middleware` '
+ 'must be a function, not `' + type + '`');
}
if ((0, is_type_of_1.isGeneratorFunction)(fn)) {
throw new TypeError(methods.toString() + ' `' + (this.opts.name || path) + '`: Please use async function instead of generator function');
}
});
this.path = path;
this.regexp = (0, path_to_regexp_1.default)(path, this.paramNames, this.opts);
debug('defined route %s %s', this.methods, this.opts.prefix + this.path);
}
/**
* Returns whether request `path` matches route.
*
* @param {String} path path string
* @return {Boolean} matched or not
* @private
*/
match(path) {
return this.regexp.test(path);
}
/**
* Returns map of URL parameters for given `path` and `paramNames`.
*
* @param {String} _path path string
* @param {Array.<String>} captures captures strings
* @param {Object=} [existingParams] existing params
* @return {Object} params object
* @private
*/
params(_path, captures, existingParams) {
const params = existingParams ?? {};
for (let len = captures.length, i = 0; i < len; i++) {
const paramName = this.paramNames[i];
if (paramName) {
const c = captures[i];
params[paramName.name] = c ? (0, utility_1.decodeURIComponent)(c) : c;
}
}
return params;
}
/**
* Returns array of regexp url path captures.
*
* @param {String} path path string
* @return {Array.<String>} captures strings
* @private
*/
captures(path) {
if (this.opts.ignoreCaptures)
return [];
const m = path.match(this.regexp);
return m ? m.slice(1) : [];
}
/**
* Generate URL for route using given `params`.
*
* @example
*
* ```javascript
* var route = new Layer(['GET'], '/users/:id', fn);
*
* route.url(123); // => "/users/123"
* route.url('123'); // => "/users/123"
* route.url({ id: 123 }); // => "/users/123"
* ```
*
* @param {Object} params url parameters
* @param {Object} paramsOrOptions optional parameters
* @return {String} url string
* @private
*/
url(params, ...paramsOrOptions) {
let args = params;
const url = this.path.replace(/\(\.\*\)/g, '');
const toPath = path_to_regexp_1.default.compile(url);
let options;
if (params !== undefined && typeof params !== 'object') {
args = [params, ...paramsOrOptions];
// route.url(stringOrNumber, params1, ..., options);
if (Array.isArray(args)) {
const lastIndex = args.length - 1;
if (typeof args[lastIndex] === 'object') {
options = args[lastIndex];
args = args.slice(0, lastIndex);
}
}
}
else if (typeof params === 'object') {
if (typeof paramsOrOptions[0] === 'object' && 'query' in paramsOrOptions[0]) {
// route.url(param, options);
options = paramsOrOptions[0];
}
}
const tokens = path_to_regexp_1.default.parse(url);
let replace = {};
if (Array.isArray(args)) {
for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
const token = tokens[i];
if (typeof token === 'object' && token.name) {
replace[token.name] = args[j++];
}
}
}
else if (tokens.some(token => typeof token === 'object' && token.name)) {
// route.url(params);
replace = params;
}
else {
// route.url(options);
options = params;
}
const replaced = toPath(replace);
if (options?.query) {
const urlObject = new urijs_1.default(replaced);
urlObject.search(options.query);
return urlObject.toString();
}
return replaced;
}
/**
* Run validations on route named parameters.
*
* @example
*
* ```javascript
* router
* .param('user', function (id, ctx, next) {
* ctx.user = users[id];
* if (!user) return ctx.status = 404;
* next();
* })
* .get('/users/:user', function (ctx, next) {
* ctx.body = ctx.user;
* });
* ```
*
* @param {String} param param string
* @param {Function} fn middleware function
* @return {Layer} layer instance
* @private
*/
param(param, fn) {
const stack = this.stack;
const params = this.paramNames;
const middleware = function (ctx, next) {
return fn.call(this, ctx.params[param], ctx, next);
};
middleware.param = param;
const names = params.map(p => {
return p.name;
});
const x = names.indexOf(param);
if (x > -1) {
// iterate through the stack, to figure out where to place the handler fn
stack.some(function (fn, i) {
// param handlers are always first, so when we find an fn w/o a param property, stop here
// if the param handler at this part of the stack comes after the one we are adding, stop here
if (!fn.param || names.indexOf(fn.param) > x) {
// inject this param handler right before the current item
stack.splice(i, 0, middleware);
return true; // then break the loop
}
return false;
});
}
return this;
}
/**
* Prefix route path.
*
* @param {String} prefix prefix string
* @return {Layer} layer instance
* @private
*/
setPrefix(prefix) {
if (this.path) {
this.path = prefix + this.path;
this.paramNames = [];
this.regexp = (0, path_to_regexp_1.default)(this.path, this.paramNames, this.opts);
}
return this;
}
}
exports.Layer = Layer;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvTGF5ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEseUNBQXFDO0FBQ3JDLG9FQUF3RDtBQUN4RCxrREFBd0I7QUFDeEIscUNBQXVFO0FBQ3ZFLDJDQUFpRDtBQU9qRCxNQUFNLEtBQUssR0FBRyxJQUFBLG9CQUFRLEVBQUMsa0JBQWtCLENBQUMsQ0FBQztBQWtCM0MsTUFBYSxLQUFLO0lBQ1AsSUFBSSxDQUFlO0lBQ25CLElBQUksQ0FBVTtJQUNkLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDdkIsS0FBSyxDQUFvQztJQUNsRCxJQUFJLENBQWtCO0lBQ3RCLE1BQU0sQ0FBUztJQUNmLFVBQVUsR0FBVSxFQUFFLENBQUM7SUFFdkI7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxZQUFZLElBQXFCLEVBQUUsT0FBaUIsRUFBRSxXQUE4QyxFQUNsRyxJQUE0QjtRQUM1QixJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzdCLCtDQUErQztZQUMvQyxJQUFJLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDeEIsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztRQUMzQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBRSxXQUFXLENBQUUsQ0FBQztRQUV4RSxLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQzdCLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1lBQ2xELElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQy9CLENBQUM7UUFDSCxDQUFDO1FBRUQsa0NBQWtDO1FBQ2xDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQ3RCLE1BQU0sSUFBSSxHQUFHLE9BQU8sRUFBRSxDQUFDO1lBQ3ZCLElBQUksSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUN4QixNQUFNLElBQUksU0FBUyxDQUNqQixPQUFPLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLEdBQUcsa0JBQWtCO3NCQUN2RSwyQkFBMkIsR0FBRyxJQUFJLEdBQUcsR0FBRyxDQUMzQyxDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksSUFBQSxnQ0FBbUIsRUFBQyxFQUFFLENBQUMsRUFBRSxDQUFDO2dCQUM1QixNQUFNLElBQUksU0FBUyxDQUNqQixPQUFPLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLEdBQUcsNERBQTRELENBQ3BILENBQUM7WUFDSixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUEsd0JBQVksRUFBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFN0QsS0FBSyxDQUFDLHFCQUFxQixFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxLQUFLLENBQUMsSUFBWTtRQUNoQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILE1BQU0sQ0FBQyxLQUFhLEVBQUUsUUFBdUIsRUFBRSxjQUF1QztRQUNwRixNQUFNLE1BQU0sR0FBRyxjQUFjLElBQUksRUFBRSxDQUFDO1FBRXBDLEtBQUssSUFBSSxHQUFHLEdBQUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNwRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3JDLElBQUksU0FBUyxFQUFFLENBQUM7Z0JBQ2QsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN0QixNQUFNLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBQSw0QkFBc0IsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzdELENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILFFBQVEsQ0FBQyxJQUFZO1FBQ25CLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFDeEMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7O09BaUJHO0lBQ0gsR0FBRyxDQUFDLE1BQWlDLEVBQUUsR0FBRyxlQUErRDtRQUN2RyxJQUFJLElBQUksR0FBNkMsTUFBZ0IsQ0FBQztRQUN0RSxNQUFNLEdBQUcsR0FBSSxJQUFJLENBQUMsSUFBZSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDM0QsTUFBTSxNQUFNLEdBQUcsd0JBQVksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDekMsSUFBSSxPQUFvQyxDQUFDO1FBRXpDLElBQUksTUFBTSxLQUFLLFNBQVMsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN2RCxJQUFJLEdBQUcsQ0FBRSxNQUFNLEVBQUUsR0FBRyxlQUFlLENBQUUsQ0FBQztZQUN0QyxvREFBb0Q7WUFDcEQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3hCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO2dCQUNsQyxJQUFJLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO29CQUN4QyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUMxQixJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUM7Z0JBQ2xDLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQzthQUFNLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDdEMsSUFBSSxPQUFPLGVBQWUsQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLElBQUksT0FBTyxJQUFJLGVBQWUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUM1RSw2QkFBNkI7Z0JBQzdCLE9BQU8sR0FBRyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0IsQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyx3QkFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLE9BQU8sR0FBd0IsRUFBRSxDQUFDO1FBRXRDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3hCLEtBQUssSUFBSSxHQUFHLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUN6RCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3hCLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDNUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDbEMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO2FBQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3pFLHFCQUFxQjtZQUNyQixPQUFPLEdBQUcsTUFBZ0IsQ0FBQztRQUM3QixDQUFDO2FBQU0sQ0FBQztZQUNOLHNCQUFzQjtZQUN0QixPQUFPLEdBQUcsTUFBeUIsQ0FBQztRQUN0QyxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRWpDLElBQUksT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO1lBQ25CLE1BQU0sU0FBUyxHQUFHLElBQUksZUFBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3BDLFNBQVMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2hDLE9BQU8sU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzlCLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQXFCRztJQUNILEtBQUssQ0FBQyxLQUFhLEVBQUUsRUFBdUI7UUFDMUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUN6QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQy9CLE1BQU0sVUFBVSxHQUFvQyxVQUFvQixHQUFHLEVBQUUsSUFBSTtZQUMvRSxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQztRQUNGLFVBQVUsQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRXpCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDM0IsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ2hCLENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ1gseUVBQXlFO1lBQ3pFLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBUyxFQUFFLEVBQUUsQ0FBQztnQkFDdkIseUZBQXlGO2dCQUN6Riw4RkFBOEY7Z0JBQzlGLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUM3QywwREFBMEQ7b0JBQzFELEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztvQkFDL0IsT0FBTyxJQUFJLENBQUMsQ0FBQyxzQkFBc0I7Z0JBQ3JDLENBQUM7Z0JBQ0QsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxTQUFTLENBQUMsTUFBYztRQUN0QixJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNkLElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDL0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFBLHdCQUFZLEVBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRSxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0NBQ0Y7QUFwUEQsc0JBb1BDIn0=
{
"type": "commonjs"
}
/**
* RESTful resource routing middleware for eggjs.
*/
import methods from 'methods';
import { Layer, LayerURLOptions } from './Layer.js';
import { MiddlewareFunc, MiddlewareFuncWithRouter, ParamMiddlewareFunc, ResourcesController } from './types.js';
export type RouterMethod = typeof methods[0];
export interface RouterOptions {
methods?: string[];
prefix?: string;
sensitive?: boolean;
strict?: boolean;
routerPath?: string;
}
export interface RegisterOptions {
name?: string;
prefix?: string;
sensitive?: boolean;
strict?: boolean;
ignoreCaptures?: boolean;
end?: boolean;
}
export interface AllowedMethodsOptions {
throw?: boolean;
notImplemented?: () => Error;
methodNotAllowed?: () => Error;
}
export interface MatchedResult {
path: Layer[];
pathAndMethod: Layer[];
route: boolean;
}
export declare class Router {
#private;
readonly opts: RouterOptions;
readonly methods: string[];
/** Layer stack */
readonly stack: Layer[];
readonly params: Record<string, ParamMiddlewareFunc>;
/**
* Create a new router.
*
* @example
*
* Basic usage:
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* router.get('/', (ctx, next) => {
* // ctx.router available
* });
*
* app
* .use(router.routes())
* .use(router.allowedMethods());
* ```
*
* @alias module:koa-router
* @param {Object=} opts optional
* @param {String=} opts.prefix prefix router paths
* @class
*/
constructor(opts?: RouterOptions);
/**
* Use given middleware.
*
* Middleware run in the order they are defined by `.use()`. They are invoked
* sequentially, requests start at the first middleware and work their way
* "down" the middleware stack.
*
* @example
*
* ```javascript
* // session middleware will run before authorize
* router
* .use(session())
* .use(authorize());
*
* // use middleware only with given path
* router.use('/users', userAuth());
*
* // or with an array of paths
* router.use(['/users', '/admin'], userAuth());
*
* app.use(router.routes());
* ```
*
* @param {String=} path path string
* @param {Function} middleware middleware function
* @return {Router} router instance
*/
use(...middlewares: MiddlewareFunc[]): Router;
use(path: string | string[], ...middlewares: MiddlewareFunc[]): Router;
/**
* Set the path prefix for a Router instance that was already initialized.
*
* @example
*
* ```javascript
* router.prefix('/things/:thing_id')
* ```
*
* @param {String} prefix prefix string
* @return {Router} router instance
*/
prefix(prefix: string): Router;
/**
* Returns router middleware which dispatches a route matching the request.
*
* @return {Function} middleware function
*/
routes(): MiddlewareFuncWithRouter<Router>;
/**
* @alias to routes()
*/
middleware(): MiddlewareFuncWithRouter<Router>;
/**
* Returns separate middleware for responding to `OPTIONS` requests with
* an `Allow` header containing the allowed methods, as well as responding
* with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
*
* @example
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods());
* ```
*
* **Example with [Boom](https://github.com/hapijs/boom)**
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
* var Boom = require('boom');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods({
* throw: true,
* notImplemented: () => new Boom.notImplemented(),
* methodNotAllowed: () => new Boom.methodNotAllowed()
* }));
* ```
*
* @param {Object=} options optional params
* @param {Boolean=} options.throw throw error instead of setting status and header
* @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
* @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
* @return {Function} middleware function
*/
allowedMethods(options?: AllowedMethodsOptions): MiddlewareFunc;
/**
* Redirect `source` to `destination` URL with optional 30x status `code`.
*
* Both `source` and `destination` can be route names.
*
* ```javascript
* router.redirect('/login', 'sign-in');
* ```
*
* This is equivalent to:
*
* ```javascript
* router.all('/login', ctx => {
* ctx.redirect('/sign-in');
* ctx.status = 301;
* });
* ```
*
* @param {String} source URL or route name.
* @param {String} destination URL or route name.
* @param {Number=} status HTTP status code (default: 301).
* @return {Router} router instance
*/
redirect(source: string, destination: string, status?: number): Router;
/**
* Create and register a route.
*
* @param {String|RegExp|(String|RegExp)[]} path Path string.
* @param {String[]} methods Array of HTTP verbs.
* @param {Function|Function[]} middleware Multiple middleware also accepted.
* @param {Object} [opts] optional params
* @private
*/
register(path: string | RegExp | (string | RegExp)[], methods: string[], middleware: MiddlewareFunc | MiddlewareFunc[], opts?: RegisterOptions): Layer | Layer[];
/**
* Lookup route with given `name`.
*
* @param {String} name route name
* @return {Layer|false} layer instance of false
*/
route(name: string): Layer | false;
/**
* Generate URL for route. Takes a route name and map of named `params`.
*
* @example
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
*
* router.url('user', { id: 3 });
* // => "/users/3"
*
* router.use((ctx, next) => {
* // redirect to named route
* ctx.redirect(ctx.router.url('sign-in'));
* })
*
* router.url('user', { id: 3 }, { query: { limit: 1 } });
* // => "/users/3?limit=1"
*
* router.url('user', { id: 3 }, { query: "limit=1" });
* // => "/users/3?limit=1"
* ```
*/
url(name: string, params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string | Error;
/**
* Generate URL from url pattern and given `params`.
*
* @example
*
* ```javascript
* var url = Router.url('/users/:id', { id: 1 });
* // => "/users/1"
* ```
*
* @param {String} path url pattern
* @param {Object} params url parameters
* @return {String} url string
*/
static url(path: string, params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string;
/**
* Match given `path` and return corresponding routes.
*
* @param {String} path path string
* @param {String} method method name
* @return {Object.<path, pathAndMethod>} returns layers that matched path and
* path and method.
* @private
*/
match(path: string, method: string): MatchedResult;
/**
* Run middleware for named route parameters. Useful for auto-loading or
* validation.
*
* @example
*
* ```javascript
* router
* .param('user', (id, ctx, next) => {
* ctx.user = users[id];
* if (!ctx.user) return ctx.status = 404;
* return next();
* })
* .get('/users/:user', ctx => {
* ctx.body = ctx.user;
* })
* .get('/users/:user/friends', ctx => {
* return ctx.user.getFriends().then(function(friends) {
* ctx.body = friends;
* });
* })
* // /users/3 => {"id": 3, "name": "Alex"}
* // /users/3/friends => [{"id": 4, "name": "TJ"}]
* ```
*
* @param {String} param param
* @param {Function} middleware route middleware
* @return {Router} instance
*/
param(param: string, middleware: ParamMiddlewareFunc): Router;
protected _formatRouteParams(nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc | ResourcesController, middlewares: (MiddlewareFunc | string | ResourcesController)[]): {
path: string | RegExp | (string | RegExp)[];
middlewares: (string | MiddlewareFunc | ResourcesController)[];
options: RegisterOptions;
};
/**
* Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
* as `router.get()` or `router.post()`.
*
* Match URL patterns to callback functions or controller actions using `router.verb()`,
* where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
*
* Additionally, `router.all()` can be used to match against all methods.
*
* ```javascript
* router
* .get('/', (ctx, next) => {
* ctx.body = 'Hello World!';
* })
* .post('/users', (ctx, next) => {
* // ...
* })
* .put('/users/:id', (ctx, next) => {
* // ...
* })
* .del('/users/:id', (ctx, next) => {
* // ...
* })
* .all('/users/:id', (ctx, next) => {
* // ...
* });
* ```
*
* When a route is matched, its path is available at `ctx._matchedRoute` and if named,
* the name is available at `ctx._matchedRouteName`
*
* Route paths will be translated to regular expressions using
* [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
*
* Query strings will not be considered when matching requests.
*
* #### Named routes
*
* Routes can optionally have names. This allows generation of URLs and easy
* renaming of URLs during development.
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
* ```
*
* #### Multiple middleware
*
* Multiple middleware may be given:
*
* ```javascript
* router.get(
* '/users/:id',
* (ctx, next) => {
* return User.findOne(ctx.params.id).then(function(user) {
* ctx.user = user;
* next();
* });
* },
* ctx => {
* console.log(ctx.user);
* // => { id: 17, name: "Alex" }
* }
* );
* ```
*
* ### Nested routers
*
* Nesting routers is supported:
*
* ```javascript
* var forums = new Router();
* var posts = new Router();
*
* posts.get('/', (ctx, next) => {...});
* posts.get('/:pid', (ctx, next) => {...});
* forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
*
* // responds to "/forums/123/posts" and "/forums/123/posts/123"
* app.use(forums.routes());
* ```
*
* #### Router prefixes
*
* Route paths can be prefixed at the router level:
*
* ```javascript
* var router = new Router({
* prefix: '/users'
* });
*
* router.get('/', ...); // responds to "/users"
* router.get('/:id', ...); // responds to "/users/:id"
* ```
*
* #### URL parameters
*
* Named route parameters are captured and added to `ctx.params`.
*
* ```javascript
* router.get('/:category/:title', (ctx, next) => {
* console.log(ctx.params);
* // => { category: 'programming', title: 'how-to-node' }
* });
* ```
*
* The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
* used to convert paths to regular expressions.
*
*/
verb(method: string | string[], nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc, ...middleware: MiddlewareFunc[]): Router;
/**
* Register route with all methods.
*
* @param {String} name Optional.
* @param {String} path path string
* @param {Function=} middleware You may also pass multiple middleware.
* @return {Router} router instance
* @private
*/
all(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
acl(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
acl(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
bind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
bind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
checkout(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
checkout(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
connect(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
connect(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
copy(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
copy(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
delete(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
/** Alias for `router.delete()` because delete is a reserved word */
del(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
del(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
get(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
query(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
query(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
head(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
link(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
link(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
lock(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
lock(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
['m-search'](path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
['m-search'](name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
merge(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
merge(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkactivity(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkactivity(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcalendar(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcalendar(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcol(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcol(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
move(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
move(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
notify(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
notify(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
options(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
patch(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
post(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
propfind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
propfind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
proppatch(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
proppatch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
purge(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
purge(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
put(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
rebind(path: string | RegExp, ...middlewares: MiddlewareFunc[]): Router;
rebind(name: string, path: string | RegExp, ...middlewares: MiddlewareFunc[]): Router;
report(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
report(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
search(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
search(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
source(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
source(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
subscribe(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
subscribe(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
trace(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
trace(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unbind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unbind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlink(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlink(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlock(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlock(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unsubscribe(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unsubscribe(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
}
"use strict";
/**
* RESTful resource routing middleware for eggjs.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Router = void 0;
const node_util_1 = require("node:util");
const node_assert_1 = __importDefault(require("node:assert"));
const koa_compose_1 = __importDefault(require("koa-compose"));
const http_errors_1 = __importDefault(require("http-errors"));
const methods_1 = __importDefault(require("methods"));
const Layer_js_1 = require("./Layer.js");
const debug = (0, node_util_1.debuglog)('egg-router:router');
class Router {
opts;
methods;
/** Layer stack */
stack = [];
params = {};
/**
* Create a new router.
*
* @example
*
* Basic usage:
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* router.get('/', (ctx, next) => {
* // ctx.router available
* });
*
* app
* .use(router.routes())
* .use(router.allowedMethods());
* ```
*
* @alias module:koa-router
* @param {Object=} opts optional
* @param {String=} opts.prefix prefix router paths
* @class
*/
constructor(opts) {
this.opts = opts ?? {};
this.methods = this.opts.methods ?? [
'HEAD',
'OPTIONS',
'GET',
'PUT',
'PATCH',
'POST',
'DELETE',
];
}
use(pathOrMiddleware, ...middlewares) {
// support array of paths
// use(paths, ...middlewares)
if (Array.isArray(pathOrMiddleware) && typeof pathOrMiddleware[0] === 'string') {
for (const path of pathOrMiddleware) {
this.use(path, ...middlewares);
}
return this;
}
let path = '';
let hasPath = false;
if (typeof pathOrMiddleware === 'string') {
// use(path, ...middlewares)
path = pathOrMiddleware;
hasPath = true;
}
else if (typeof pathOrMiddleware === 'function') {
// use(...middlewares)
middlewares = [pathOrMiddleware, ...middlewares];
}
for (const m of middlewares) {
if (m.router) {
for (const nestedLayer of m.router.stack) {
if (path) {
nestedLayer.setPrefix(path);
}
if (this.opts.prefix) {
nestedLayer.setPrefix(this.opts.prefix);
}
this.stack.push(nestedLayer);
}
if (this.params) {
for (const key in this.params) {
m.router.param(key, this.params[key]);
}
}
}
else {
this.register(path || '(.*)', [], m, { end: false, ignoreCaptures: !hasPath });
}
}
return this;
}
/**
* Set the path prefix for a Router instance that was already initialized.
*
* @example
*
* ```javascript
* router.prefix('/things/:thing_id')
* ```
*
* @param {String} prefix prefix string
* @return {Router} router instance
*/
prefix(prefix) {
prefix = prefix.replace(/\/$/, '');
this.opts.prefix = prefix;
for (const layer of this.stack) {
layer.setPrefix(prefix);
}
return this;
}
/**
* Returns router middleware which dispatches a route matching the request.
*
* @return {Function} middleware function
*/
routes() {
const dispatch = (ctx, next) => {
const routerPath = this.opts.routerPath || ctx.routerPath || ctx.path;
const matched = this.match(routerPath, ctx.method);
debug('dispatch: %s %s, routerPath: %s, matched: %s', ctx.method, ctx.path, routerPath, matched.route);
if (ctx.matched) {
ctx.matched.push(...matched.path);
}
else {
ctx.matched = matched.path;
}
ctx.router = this;
if (!matched.route) {
return next();
}
const matchedLayers = matched.pathAndMethod;
const layerChain = matchedLayers.reduce((memo, layer) => {
memo.push((ctx, next) => {
// ctx.captures = layer.captures(routerPath, ctx.captures);
ctx.captures = layer.captures(routerPath);
ctx.params = layer.params(routerPath, ctx.captures, ctx.params);
// ctx._matchedRouteName & ctx._matchedRoute for compatibility
ctx._matchedRouteName = ctx.routerName = layer.name;
if (!layer.name) {
ctx._matchedRouteName = undefined;
}
ctx._matchedRoute = ctx.routerPath = layer.path;
return next();
});
return memo.concat(layer.stack);
}, []);
return (0, koa_compose_1.default)(layerChain)(ctx, next);
};
dispatch.router = this;
return dispatch;
}
/**
* @alias to routes()
*/
middleware() {
return this.routes();
}
/**
* Returns separate middleware for responding to `OPTIONS` requests with
* an `Allow` header containing the allowed methods, as well as responding
* with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
*
* @example
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods());
* ```
*
* **Example with [Boom](https://github.com/hapijs/boom)**
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
* var Boom = require('boom');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods({
* throw: true,
* notImplemented: () => new Boom.notImplemented(),
* methodNotAllowed: () => new Boom.methodNotAllowed()
* }));
* ```
*
* @param {Object=} options optional params
* @param {Boolean=} options.throw throw error instead of setting status and header
* @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
* @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
* @return {Function} middleware function
*/
allowedMethods(options) {
const implemented = this.methods;
return async function allowedMethods(ctx, next) {
await next();
if (ctx.status && ctx.status !== 404)
return;
const allowed = {};
ctx.matched.forEach((route) => {
route.methods.forEach(method => {
allowed[method] = method;
});
});
const allowedMethods = Object.keys(allowed);
if (!implemented.includes(ctx.method)) {
if (options?.throw) {
let notImplementedThrowable;
if (typeof options?.notImplemented === 'function') {
notImplementedThrowable = options.notImplemented(); // set whatever the user returns from their function
}
else {
notImplementedThrowable = new http_errors_1.default.NotImplemented();
}
throw notImplementedThrowable;
}
else {
ctx.status = 501;
ctx.set('Allow', allowedMethods.join(', '));
}
}
else if (allowedMethods.length > 0) {
if (ctx.method === 'OPTIONS') {
ctx.status = 200;
ctx.body = '';
ctx.set('Allow', allowedMethods.join(', '));
}
else if (!allowed[ctx.method]) {
if (options?.throw) {
let notAllowedThrowable;
if (typeof options?.methodNotAllowed === 'function') {
notAllowedThrowable = options.methodNotAllowed(); // set whatever the user returns from their function
}
else {
notAllowedThrowable = new http_errors_1.default.MethodNotAllowed();
}
throw notAllowedThrowable;
}
else {
ctx.status = 405;
ctx.set('Allow', allowedMethods.join(', '));
}
}
}
};
}
/**
* Redirect `source` to `destination` URL with optional 30x status `code`.
*
* Both `source` and `destination` can be route names.
*
* ```javascript
* router.redirect('/login', 'sign-in');
* ```
*
* This is equivalent to:
*
* ```javascript
* router.all('/login', ctx => {
* ctx.redirect('/sign-in');
* ctx.status = 301;
* });
* ```
*
* @param {String} source URL or route name.
* @param {String} destination URL or route name.
* @param {Number=} status HTTP status code (default: 301).
* @return {Router} router instance
*/
redirect(source, destination, status = 301) {
// lookup source route by name
if (source[0] !== '/') {
const routeUrl = this.url(source);
if (routeUrl instanceof Error) {
throw routeUrl;
}
source = routeUrl;
}
// lookup destination route by name
if (destination[0] !== '/') {
const routeUrl = this.url(destination);
if (routeUrl instanceof Error) {
throw routeUrl;
}
destination = routeUrl;
}
return this.all(source, ctx => {
ctx.redirect(destination);
ctx.status = status;
});
}
/**
* Create and register a route.
*
* @param {String|RegExp|(String|RegExp)[]} path Path string.
* @param {String[]} methods Array of HTTP verbs.
* @param {Function|Function[]} middleware Multiple middleware also accepted.
* @param {Object} [opts] optional params
* @private
*/
register(path, methods, middleware, opts) {
// support array of paths
if (Array.isArray(path)) {
const routes = [];
for (const p of path) {
const route = this.#register(p, methods, middleware, opts);
routes.push(route);
}
return routes;
}
// create route
const route = this.#register(path, methods, middleware, opts);
return route;
}
#register(path, methods, middleware, opts) {
opts = opts ?? {};
// create route
const route = new Layer_js_1.Layer(path, methods, middleware, {
end: opts.end === false ? opts.end : true,
name: opts.name,
sensitive: opts.sensitive ?? this.opts.sensitive ?? false,
strict: opts.strict ?? this.opts.strict ?? false,
prefix: opts.prefix ?? this.opts.prefix ?? '',
ignoreCaptures: opts.ignoreCaptures,
});
// FIXME: why???
if (this.opts.prefix) {
route.setPrefix(this.opts.prefix);
}
// add parameter middleware to the new route layer
for (const param in this.params) {
route.param(param, this.params[param]);
}
this.stack.push(route);
return route;
}
/**
* Lookup route with given `name`.
*
* @param {String} name route name
* @return {Layer|false} layer instance of false
*/
route(name) {
for (const route of this.stack) {
if (route.name === name) {
return route;
}
}
return false;
}
/**
* Generate URL for route. Takes a route name and map of named `params`.
*
* @example
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
*
* router.url('user', { id: 3 });
* // => "/users/3"
*
* router.use((ctx, next) => {
* // redirect to named route
* ctx.redirect(ctx.router.url('sign-in'));
* })
*
* router.url('user', { id: 3 }, { query: { limit: 1 } });
* // => "/users/3?limit=1"
*
* router.url('user', { id: 3 }, { query: "limit=1" });
* // => "/users/3?limit=1"
* ```
*/
url(name, params, ...paramsOrOptions) {
const route = this.route(name);
if (route) {
return route.url(params, ...paramsOrOptions);
}
return new Error(`No route found for name: ${name}`);
}
/**
* Generate URL from url pattern and given `params`.
*
* @example
*
* ```javascript
* var url = Router.url('/users/:id', { id: 1 });
* // => "/users/1"
* ```
*
* @param {String} path url pattern
* @param {Object} params url parameters
* @return {String} url string
*/
static url(path, params, ...paramsOrOptions) {
return Layer_js_1.Layer.prototype.url.call({ path }, params, ...paramsOrOptions);
}
/**
* Match given `path` and return corresponding routes.
*
* @param {String} path path string
* @param {String} method method name
* @return {Object.<path, pathAndMethod>} returns layers that matched path and
* path and method.
* @private
*/
match(path, method) {
const matched = {
// matched path
path: [],
// matched path and method(including none method)
pathAndMethod: [],
// method matched or not
route: false,
};
for (const layer of this.stack) {
debug('test %s %s', layer.path, layer.regexp);
if (layer.match(path)) {
matched.path.push(layer);
if (layer.methods.length === 0 || layer.methods.includes(method)) {
matched.pathAndMethod.push(layer);
if (layer.methods.length > 0) {
matched.route = true;
}
}
// if (layer.methods.length === 0) {
// matched.pathAndMethod.push(layer);
// } else if (layer.methods.includes(method)) {
// matched.pathAndMethod.push(layer);
// matched.route = true;
// }
}
}
return matched;
}
/**
* Run middleware for named route parameters. Useful for auto-loading or
* validation.
*
* @example
*
* ```javascript
* router
* .param('user', (id, ctx, next) => {
* ctx.user = users[id];
* if (!ctx.user) return ctx.status = 404;
* return next();
* })
* .get('/users/:user', ctx => {
* ctx.body = ctx.user;
* })
* .get('/users/:user/friends', ctx => {
* return ctx.user.getFriends().then(function(friends) {
* ctx.body = friends;
* });
* })
* // /users/3 => {"id": 3, "name": "Alex"}
* // /users/3/friends => [{"id": 4, "name": "TJ"}]
* ```
*
* @param {String} param param
* @param {Function} middleware route middleware
* @return {Router} instance
*/
param(param, middleware) {
this.params[param] = middleware;
for (const route of this.stack) {
route.param(param, middleware);
}
return this;
}
_formatRouteParams(nameOrPath, pathOrMiddleware, middlewares) {
const options = {};
let path;
if (typeof pathOrMiddleware === 'string' || pathOrMiddleware instanceof RegExp) {
// verb(method, name, path, ...middlewares)
path = pathOrMiddleware;
(0, node_assert_1.default)(typeof nameOrPath === 'string', 'route name should be string');
options.name = nameOrPath;
}
else if (Array.isArray(pathOrMiddleware)) {
// verb(method, name, paths, ...middlewares)
path = pathOrMiddleware;
(0, node_assert_1.default)(typeof nameOrPath === 'string', 'route name should be string');
options.name = nameOrPath;
}
else {
// verb(method, path, ...middlewares)
path = nameOrPath;
middlewares = [pathOrMiddleware, ...middlewares];
}
return {
path,
middlewares,
options,
};
}
/**
* Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
* as `router.get()` or `router.post()`.
*
* Match URL patterns to callback functions or controller actions using `router.verb()`,
* where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
*
* Additionally, `router.all()` can be used to match against all methods.
*
* ```javascript
* router
* .get('/', (ctx, next) => {
* ctx.body = 'Hello World!';
* })
* .post('/users', (ctx, next) => {
* // ...
* })
* .put('/users/:id', (ctx, next) => {
* // ...
* })
* .del('/users/:id', (ctx, next) => {
* // ...
* })
* .all('/users/:id', (ctx, next) => {
* // ...
* });
* ```
*
* When a route is matched, its path is available at `ctx._matchedRoute` and if named,
* the name is available at `ctx._matchedRouteName`
*
* Route paths will be translated to regular expressions using
* [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
*
* Query strings will not be considered when matching requests.
*
* #### Named routes
*
* Routes can optionally have names. This allows generation of URLs and easy
* renaming of URLs during development.
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
* ```
*
* #### Multiple middleware
*
* Multiple middleware may be given:
*
* ```javascript
* router.get(
* '/users/:id',
* (ctx, next) => {
* return User.findOne(ctx.params.id).then(function(user) {
* ctx.user = user;
* next();
* });
* },
* ctx => {
* console.log(ctx.user);
* // => { id: 17, name: "Alex" }
* }
* );
* ```
*
* ### Nested routers
*
* Nesting routers is supported:
*
* ```javascript
* var forums = new Router();
* var posts = new Router();
*
* posts.get('/', (ctx, next) => {...});
* posts.get('/:pid', (ctx, next) => {...});
* forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
*
* // responds to "/forums/123/posts" and "/forums/123/posts/123"
* app.use(forums.routes());
* ```
*
* #### Router prefixes
*
* Route paths can be prefixed at the router level:
*
* ```javascript
* var router = new Router({
* prefix: '/users'
* });
*
* router.get('/', ...); // responds to "/users"
* router.get('/:id', ...); // responds to "/users/:id"
* ```
*
* #### URL parameters
*
* Named route parameters are captured and added to `ctx.params`.
*
* ```javascript
* router.get('/:category/:title', (ctx, next) => {
* console.log(ctx.params);
* // => { category: 'programming', title: 'how-to-node' }
* });
* ```
*
* The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
* used to convert paths to regular expressions.
*
*/
verb(method, nameOrPath, pathOrMiddleware, ...middleware) {
const { options, path, middlewares } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
if (typeof method === 'string') {
method = [method];
}
this.register(path, method, middlewares, options);
return this;
}
all(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb(methods_1.default, nameOrPath, pathOrMiddleware, ...middlewares);
}
acl(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('acl', nameOrPath, pathOrMiddleware, ...middlewares);
}
bind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('bind', nameOrPath, pathOrMiddleware, ...middlewares);
}
checkout(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('checkout', nameOrPath, pathOrMiddleware, ...middlewares);
}
connect(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('connect', nameOrPath, pathOrMiddleware, ...middlewares);
}
copy(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('copy', nameOrPath, pathOrMiddleware, ...middlewares);
}
delete(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
del(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
get(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares);
}
query(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('query', nameOrPath, pathOrMiddleware, ...middlewares);
}
head(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares);
}
link(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('link', nameOrPath, pathOrMiddleware, ...middlewares);
}
lock(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('lock', nameOrPath, pathOrMiddleware, ...middlewares);
}
['m-search'](nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('m-search', nameOrPath, pathOrMiddleware, ...middlewares);
}
merge(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('merge', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkactivity(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('mkactivity', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkcalendar(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('mkcalendar', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkcol(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('mkcol', nameOrPath, pathOrMiddleware, ...middlewares);
}
move(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('move', nameOrPath, pathOrMiddleware, ...middlewares);
}
notify(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('notify', nameOrPath, pathOrMiddleware, ...middlewares);
}
options(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares);
}
patch(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares);
}
post(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares);
}
propfind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('propfind', nameOrPath, pathOrMiddleware, ...middlewares);
}
proppatch(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('proppatch', nameOrPath, pathOrMiddleware, ...middlewares);
}
purge(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('purge', nameOrPath, pathOrMiddleware, ...middlewares);
}
put(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares);
}
rebind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('rebind', nameOrPath, pathOrMiddleware, ...middlewares);
}
report(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('report', nameOrPath, pathOrMiddleware, ...middlewares);
}
search(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('search', nameOrPath, pathOrMiddleware, ...middlewares);
}
source(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('source', nameOrPath, pathOrMiddleware, ...middlewares);
}
subscribe(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('subscribe', nameOrPath, pathOrMiddleware, ...middlewares);
}
trace(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('trace', nameOrPath, pathOrMiddleware, ...middlewares);
}
unbind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unbind', nameOrPath, pathOrMiddleware, ...middlewares);
}
unlink(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unlink', nameOrPath, pathOrMiddleware, ...middlewares);
}
unlock(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unlock', nameOrPath, pathOrMiddleware, ...middlewares);
}
unsubscribe(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unsubscribe', nameOrPath, pathOrMiddleware, ...middlewares);
}
}
exports.Router = Router;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7Ozs7OztBQUVILHlDQUFxQztBQUNyQyw4REFBaUM7QUFDakMsOERBQWtDO0FBQ2xDLDhEQUFvQztBQUNwQyxzREFBOEI7QUFDOUIseUNBQW9EO0FBR3BELE1BQU0sS0FBSyxHQUFHLElBQUEsb0JBQVEsRUFBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBb0M1QyxNQUFhLE1BQU07SUFDUixJQUFJLENBQWdCO0lBQ3BCLE9BQU8sQ0FBVztJQUMzQixrQkFBa0I7SUFDVCxLQUFLLEdBQVksRUFBRSxDQUFDO0lBQ3BCLE1BQU0sR0FBd0MsRUFBRSxDQUFDO0lBRTFEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0EyQkc7SUFDSCxZQUFZLElBQW9CO1FBQzlCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJO1lBQ2xDLE1BQU07WUFDTixTQUFTO1lBQ1QsS0FBSztZQUNMLEtBQUs7WUFDTCxPQUFPO1lBQ1AsTUFBTTtZQUNOLFFBQVE7U0FDVCxDQUFDO0lBQ0osQ0FBQztJQWdDRCxHQUFHLENBQUMsZ0JBQW9ELEVBQUUsR0FBRyxXQUE2QjtRQUN4Rix5QkFBeUI7UUFDekIsNkJBQTZCO1FBQzdCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLE9BQU8sZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0UsS0FBSyxNQUFNLElBQUksSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO2dCQUNwQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO1lBQ2pDLENBQUM7WUFDRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCxJQUFJLElBQUksR0FBRyxFQUFFLENBQUM7UUFDZCxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7UUFDcEIsSUFBSSxPQUFPLGdCQUFnQixLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3pDLDRCQUE0QjtZQUM1QixJQUFJLEdBQUcsZ0JBQWdCLENBQUM7WUFDeEIsT0FBTyxHQUFHLElBQUksQ0FBQztRQUNqQixDQUFDO2FBQU0sSUFBSSxPQUFPLGdCQUFnQixLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ2xELHNCQUFzQjtZQUN0QixXQUFXLEdBQUcsQ0FBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBRSxDQUFDO1FBQ3JELENBQUM7UUFFRCxLQUFLLE1BQU0sQ0FBQyxJQUFJLFdBQWlELEVBQUUsQ0FBQztZQUNsRSxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDYixLQUFLLE1BQU0sV0FBVyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7b0JBQ3pDLElBQUksSUFBSSxFQUFFLENBQUM7d0JBQ1QsV0FBVyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDOUIsQ0FBQztvQkFDRCxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7d0JBQ3JCLFdBQVcsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDMUMsQ0FBQztvQkFDRCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDL0IsQ0FBQztnQkFFRCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDaEIsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7d0JBQzlCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7b0JBQ3hDLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksSUFBSSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUNqRixDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsTUFBTSxDQUFDLE1BQWM7UUFDbkIsTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ25DLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUUxQixLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUMvQixLQUFLLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzFCLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsTUFBTTtRQUNKLE1BQU0sUUFBUSxHQUFHLENBQUMsR0FBUSxFQUFFLElBQVUsRUFBRSxFQUFFO1lBQ3hDLE1BQU0sVUFBVSxHQUFXLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLEdBQUcsQ0FBQyxVQUFVLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQztZQUM5RSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDbkQsS0FBSyxDQUFDLDhDQUE4QyxFQUNsRCxHQUFHLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUVuRCxJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDZixHQUFHLENBQUMsT0FBbUIsQ0FBQyxJQUFJLENBQUMsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDakQsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLEdBQUcsQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztZQUM3QixDQUFDO1lBQ0QsR0FBRyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7WUFFbEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbkIsT0FBTyxJQUFJLEVBQUUsQ0FBQztZQUNoQixDQUFDO1lBRUQsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQztZQUM1QyxNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFtQixDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRTtnQkFDeEUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRTtvQkFDdEIsMkRBQTJEO29CQUMzRCxHQUFHLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7b0JBQzFDLEdBQUcsQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7b0JBQ2hFLDhEQUE4RDtvQkFDOUQsR0FBRyxDQUFDLGlCQUFpQixHQUFHLEdBQUcsQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDcEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQzt3QkFDaEIsR0FBRyxDQUFDLGlCQUFpQixHQUFHLFNBQVMsQ0FBQztvQkFDcEMsQ0FBQztvQkFDRCxHQUFHLENBQUMsYUFBYSxHQUFHLEdBQUcsQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDaEQsT0FBTyxJQUFJLEVBQUUsQ0FBQztnQkFDaEIsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNsQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFFUCxPQUFPLElBQUEscUJBQU8sRUFBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDeEMsQ0FBQyxDQUFDO1FBRUYsUUFBUSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUM7UUFDdkIsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsVUFBVTtRQUNSLE9BQU8sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0F5Q0c7SUFDSCxjQUFjLENBQUMsT0FBK0I7UUFDNUMsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUVqQyxPQUFPLEtBQUssVUFBVSxjQUFjLENBQUMsR0FBUSxFQUFFLElBQVU7WUFDdkQsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUNiLElBQUksR0FBRyxDQUFDLE1BQU0sSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLEdBQUc7Z0JBQUUsT0FBTztZQUU3QyxNQUFNLE9BQU8sR0FBMkIsRUFBRSxDQUFDO1lBQzNDLEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBYSxFQUFFLEVBQUU7Z0JBQ3BDLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO29CQUM3QixPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDO2dCQUMzQixDQUFDLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUU1QyxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDdEMsSUFBSSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7b0JBQ25CLElBQUksdUJBQThCLENBQUM7b0JBQ25DLElBQUksT0FBTyxPQUFPLEVBQUUsY0FBYyxLQUFLLFVBQVUsRUFBRSxDQUFDO3dCQUNsRCx1QkFBdUIsR0FBRyxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxvREFBb0Q7b0JBQzFHLENBQUM7eUJBQU0sQ0FBQzt3QkFDTix1QkFBdUIsR0FBRyxJQUFJLHFCQUFTLENBQUMsY0FBYyxFQUFFLENBQUM7b0JBQzNELENBQUM7b0JBQ0QsTUFBTSx1QkFBdUIsQ0FBQztnQkFDaEMsQ0FBQztxQkFBTSxDQUFDO29CQUNOLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO29CQUNqQixHQUFHLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQzlDLENBQUM7WUFDSCxDQUFDO2lCQUFNLElBQUksY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDckMsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUM3QixHQUFHLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQztvQkFDakIsR0FBRyxDQUFDLElBQUksR0FBRyxFQUFFLENBQUM7b0JBQ2QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUM5QyxDQUFDO3FCQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7b0JBQ2hDLElBQUksT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO3dCQUNuQixJQUFJLG1CQUEwQixDQUFDO3dCQUMvQixJQUFJLE9BQU8sT0FBTyxFQUFFLGdCQUFnQixLQUFLLFVBQVUsRUFBRSxDQUFDOzRCQUNwRCxtQkFBbUIsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDLG9EQUFvRDt3QkFDeEcsQ0FBQzs2QkFBTSxDQUFDOzRCQUNOLG1CQUFtQixHQUFHLElBQUkscUJBQVMsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO3dCQUN6RCxDQUFDO3dCQUNELE1BQU0sbUJBQW1CLENBQUM7b0JBQzVCLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixHQUFHLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQzt3QkFDakIsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO29CQUM5QyxDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQyxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Bc0JHO0lBQ0gsUUFBUSxDQUFDLE1BQWMsRUFBRSxXQUFtQixFQUFFLFNBQWlCLEdBQUc7UUFDaEUsOEJBQThCO1FBQzlCLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDbEMsSUFBSSxRQUFRLFlBQVksS0FBSyxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sUUFBUSxDQUFDO1lBQ2pCLENBQUM7WUFDRCxNQUFNLEdBQUcsUUFBUSxDQUFDO1FBQ3BCLENBQUM7UUFFRCxtQ0FBbUM7UUFDbkMsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDM0IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUN2QyxJQUFJLFFBQVEsWUFBWSxLQUFLLEVBQUUsQ0FBQztnQkFDOUIsTUFBTSxRQUFRLENBQUM7WUFDakIsQ0FBQztZQUNELFdBQVcsR0FBRyxRQUFRLENBQUM7UUFDekIsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLEVBQUU7WUFDNUIsR0FBRyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMxQixHQUFHLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUN0QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILFFBQVEsQ0FBQyxJQUEyQyxFQUNsRCxPQUFpQixFQUNqQixVQUE2QyxFQUM3QyxJQUFzQjtRQUN0Qix5QkFBeUI7UUFDekIsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDeEIsTUFBTSxNQUFNLEdBQVksRUFBRSxDQUFDO1lBQzNCLEtBQUssTUFBTSxDQUFDLElBQUksSUFBSSxFQUFFLENBQUM7Z0JBQ3JCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQzNELE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDckIsQ0FBQztZQUNELE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7UUFFRCxlQUFlO1FBQ2YsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUM5RCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxTQUFTLENBQUMsSUFBcUIsRUFDN0IsT0FBaUIsRUFDakIsVUFBNkMsRUFDN0MsSUFBc0I7UUFDdEIsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDbEIsZUFBZTtRQUNmLE1BQU0sS0FBSyxHQUFHLElBQUksZ0JBQUssQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRTtZQUNqRCxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUk7WUFDekMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO1lBQ2YsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksS0FBSztZQUN6RCxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxLQUFLO1lBQ2hELE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLEVBQUU7WUFDN0MsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjO1NBQ3BDLENBQUMsQ0FBQztRQUVILGdCQUFnQjtRQUNoQixJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDckIsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFFRCxrREFBa0Q7UUFDbEQsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEMsS0FBSyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ3pDLENBQUM7UUFFRCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxJQUFZO1FBQ2hCLEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQy9CLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDeEIsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0EyQkc7SUFDSCxHQUFHLENBQUMsSUFBWSxFQUFFLE1BQWlDLEVBQ2pELEdBQUcsZUFBK0Q7UUFDbEUsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMvQixJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxHQUFHLGVBQWUsQ0FBQyxDQUFDO1FBQy9DLENBQUM7UUFDRCxPQUFPLElBQUksS0FBSyxDQUFDLDRCQUE0QixJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7OztPQWFHO0lBQ0gsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFZLEVBQUUsTUFBaUMsRUFDeEQsR0FBRyxlQUErRDtRQUNsRSxPQUFPLGdCQUFLLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxlQUFlLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxLQUFLLENBQUMsSUFBWSxFQUFFLE1BQWM7UUFDaEMsTUFBTSxPQUFPLEdBQWtCO1lBQzdCLGVBQWU7WUFDZixJQUFJLEVBQUUsRUFBRTtZQUNSLGlEQUFpRDtZQUNqRCxhQUFhLEVBQUUsRUFBRTtZQUNqQix3QkFBd0I7WUFDeEIsS0FBSyxFQUFFLEtBQUs7U0FDYixDQUFDO1FBRUYsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDL0IsS0FBSyxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUU5QyxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBRXpCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7b0JBQ2pFLE9BQU8sQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUNsQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO3dCQUM3QixPQUFPLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztvQkFDdkIsQ0FBQztnQkFDSCxDQUFDO2dCQUNELG9DQUFvQztnQkFDcEMsdUNBQXVDO2dCQUN2QywrQ0FBK0M7Z0JBQy9DLHVDQUF1QztnQkFDdkMsMEJBQTBCO2dCQUMxQixJQUFJO1lBQ04sQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0E0Qkc7SUFDSCxLQUFLLENBQUMsS0FBYSxFQUFFLFVBQStCO1FBQ2xELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsVUFBVSxDQUFDO1FBQ2hDLEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQy9CLEtBQUssQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFUyxrQkFBa0IsQ0FBQyxVQUFpRCxFQUM1RSxnQkFBOEYsRUFDOUYsV0FBOEQ7UUFDOUQsTUFBTSxPQUFPLEdBQW9CLEVBQUUsQ0FBQztRQUNwQyxJQUFJLElBQTJDLENBQUM7UUFDaEQsSUFBSSxPQUFPLGdCQUFnQixLQUFLLFFBQVEsSUFBSSxnQkFBZ0IsWUFBWSxNQUFNLEVBQUUsQ0FBQztZQUMvRSwyQ0FBMkM7WUFDM0MsSUFBSSxHQUFHLGdCQUFnQixDQUFDO1lBQ3hCLElBQUEscUJBQU0sRUFBQyxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUUsNkJBQTZCLENBQUMsQ0FBQztZQUN0RSxPQUFPLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztRQUM1QixDQUFDO2FBQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztZQUMzQyw0Q0FBNEM7WUFDNUMsSUFBSSxHQUFHLGdCQUFnQixDQUFDO1lBQ3hCLElBQUEscUJBQU0sRUFBQyxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUUsNkJBQTZCLENBQUMsQ0FBQztZQUN0RSxPQUFPLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztRQUM1QixDQUFDO2FBQU0sQ0FBQztZQUNOLHFDQUFxQztZQUNyQyxJQUFJLEdBQUcsVUFBVSxDQUFDO1lBQ2xCLFdBQVcsR0FBRyxDQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFFLENBQUM7UUFDckQsQ0FBQztRQUNELE9BQU87WUFDTCxJQUFJO1lBQ0osV0FBVztZQUNYLE9BQU87U0FDUixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQWlIRztJQUNILElBQUksQ0FBQyxNQUF5QixFQUM1QixVQUFpRCxFQUNqRCxnQkFBd0UsRUFDeEUsR0FBRyxVQUE0QjtRQUMvQixNQUFNLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsVUFBVSxFQUFFLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3pHLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0IsTUFBTSxHQUFHLENBQUUsTUFBTSxDQUFFLENBQUM7UUFDdEIsQ0FBQztRQUNELElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxXQUErQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3RFLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQWFELEdBQUcsQ0FBQyxVQUFpRCxFQUNuRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQU8sRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBUUQsR0FBRyxDQUFDLFVBQWlELEVBQ25ELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUlELElBQUksQ0FBQyxVQUFpRCxFQUNwRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7SUFJRCxRQUFRLENBQUMsVUFBaUQsRUFDeEQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBSUQsT0FBTyxDQUFDLFVBQWlELEVBQ3ZELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUlELElBQUksQ0FBQyxVQUFpRCxFQUNwRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7SUFJRCxNQUFNLENBQUMsVUFBaUQsRUFDdEQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBS0QsR0FBRyxDQUFDLFVBQWlELEVBQ25ELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUlELEdBQUcsQ0FBQyxVQUFpRCxFQUNuRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7SUFJRCxLQUFLLENBQUMsVUFBaUQsRUFDckQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBSUQsSUFBSSxDQUFDLFVBQWlELEVBQ3BELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDekUsQ0FBQztJQUlELElBQUksQ0FBQyxVQUFpRCxFQUNwRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7SUFJRCxJQUFJLENBQUMsVUFBaUQsRUFDcEQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBSUQsQ0FBQyxVQUFVLENBQUMsQ0FBQyxVQUFpRCxFQUM1RCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQzdFLENBQUM7SUFJRCxLQUFLLENBQUMsVUFBaUQsRUFDckQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBSUQsVUFBVSxDQUFDLFVBQWlELEVBQzFELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDL0UsQ0FBQztJQUlELFVBQVUsQ0FBQyxVQUFpRCxFQUMxRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFJRCxLQUFLLENBQUMsVUFBaUQsRUFDckQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBSUQsSUFBSSxDQUFDLFVBQWlELEVBQ3BELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDekUsQ0FBQztJQUlELE1BQU0sQ0FBQyxVQUFpRCxFQUN0RCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFJRCxPQUFPLENBQUMsVUFBaUQsRUFDdkQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUM1RSxDQUFDO0lBSUQsS0FBSyxDQUFDLFVBQWlELEVBQ3JELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUlELElBQUksQ0FBQyxVQUFpRCxFQUNwRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7SUFJRCxRQUFRLENBQUMsVUFBaUQsRUFDeEQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBSUQsU0FBUyxDQUFDLFVBQWlELEVBQ3pELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUlELEtBQUssQ0FBQyxVQUFpRCxFQUNyRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQzFFLENBQUM7SUFJRCxHQUFHLENBQUMsVUFBaUQsRUFDbkQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUN4RSxDQUFDO0lBSUQsTUFBTSxDQUFDLFVBQTJCLEVBQUUsZ0JBQWtELEVBQ3BGLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBSUQsTUFBTSxDQUFDLFVBQWlELEVBQ3RELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUlELE1BQU0sQ0FBQyxVQUFpRCxFQUN0RCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFJRCxNQUFNLENBQUMsVUFBaUQsRUFDdEQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBSUQsU0FBUyxDQUFDLFVBQWlELEVBQ3pELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUlELEtBQUssQ0FBQyxVQUFpRCxFQUNyRCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQzFFLENBQUM7SUFJRCxNQUFNLENBQUMsVUFBaUQsRUFDdEQsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBSUQsTUFBTSxDQUFDLFVBQWlELEVBQ3RELGdCQUF3RSxFQUN4RSxHQUFHLFdBQTZCO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUlELE1BQU0sQ0FBQyxVQUFpRCxFQUN0RCxnQkFBd0UsRUFDeEUsR0FBRyxXQUE2QjtRQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFJRCxXQUFXLENBQUMsVUFBaUQsRUFDM0QsZ0JBQXdFLEVBQ3hFLEdBQUcsV0FBNkI7UUFDaEMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxVQUFVLEVBQUUsZ0JBQWdCLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQztJQUNoRixDQUFDO0NBQ0Y7QUFuL0JELHdCQW0vQkMifQ==
export type Next = () => Promise<void>;
export type MiddlewareFunc = (ctx: any, next: Next) => Promise<void> | void;
export type MiddlewareFuncWithParamProperty = MiddlewareFunc & {
param?: string;
};
export type ParamMiddlewareFunc = (param: string, ctx: any, next: Next) => Promise<void> | void;
export type MiddlewareFuncWithRouter<T> = MiddlewareFunc & {
router: T;
};
export interface ResourcesController {
index?: MiddlewareFunc;
new?: MiddlewareFunc;
create?: MiddlewareFunc;
show?: MiddlewareFunc;
edit?: MiddlewareFunc;
update?: MiddlewareFunc;
destroy?: MiddlewareFunc;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
import { RegisterOptions, Router, RouterMethod, RouterOptions } from './Router.js';
import { MiddlewareFunc, ResourcesController } from './types.js';
interface Application {
controller: Record<string, any>;
}
/**
* FIXME: move these patch into @eggjs/router
*/
export declare class EggRouter extends Router {
readonly app: Application;
/**
* @class
* @param {Object} opts - Router options.
* @param {Application} app - Application object.
*/
constructor(opts: RouterOptions, app: Application);
verb(method: RouterMethod | RouterMethod[], nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc, ...middleware: (MiddlewareFunc | string)[]): this;
head(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
options(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
get(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
put(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
patch(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
post(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
delete(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
all(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
register(path: string | RegExp | (string | RegExp)[], methods: string[], middleware: MiddlewareFunc | string | (MiddlewareFunc | string | ResourcesController)[], opts?: RegisterOptions): import("./Layer.js").Layer | import("./Layer.js").Layer[];
/**
* restful router api
* @param {String} name - Router name
* @param {String} prefix - url prefix
* @param {Function} middleware - middleware or controller
* @example
* ```js
* app.resources('/posts', 'posts')
* app.resources('posts', '/posts', 'posts')
* app.resources('posts', '/posts', app.role.can('user'), app.controller.posts)
* ```
*
* Examples:
*
* ```js
* app.resources('/posts', 'posts')
* ```
*
* yield router mapping
*
* Method | Path | Route Name | Controller.Action
* -------|-----------------|----------------|-----------------------------
* GET | /posts | posts | app.controller.posts.index
* GET | /posts/new | new_post | app.controller.posts.new
* GET | /posts/:id | post | app.controller.posts.show
* GET | /posts/:id/edit | edit_post | app.controller.posts.edit
* POST | /posts | posts | app.controller.posts.create
* PATCH | /posts/:id | post | app.controller.posts.update
* DELETE | /posts/:id | post | app.controller.posts.destroy
*
* app.router.url can generate url based on arguments
* ```js
* app.router.url('posts')
* => /posts
* app.router.url('post', { id: 1 })
* => /posts/1
* app.router.url('new_post')
* => /posts/new
* app.router.url('edit_post', { id: 1 })
* => /posts/1/edit
* ```
* @return {Router} return route object.
* @since 1.0.0
*/
resources(prefix: string, controller: string | ResourcesController): Router;
resources(prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
resources(name: string, prefix: string, controller: string | ResourcesController): Router;
resources(name: string, prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name: string, params?: Record<string, string | number | (string | number)[]>): string;
/**
* @alias to url()
*/
pathFor(name: string, params?: Record<string, string | number | (string | number)[]>): string;
}
export {};
import assert from 'node:assert';
import { encodeURIComponent as safeEncodeURIComponent } from 'utility';
import inflection from 'inflection';
import methods from 'methods';
import { Router } from './Router.js';
const REST_MAP = {
index: {
suffix: '',
method: 'GET',
},
new: {
namePrefix: 'new_',
member: true,
suffix: 'new',
method: 'GET',
},
create: {
suffix: '',
method: 'POST',
},
show: {
member: true,
suffix: ':id',
method: 'GET',
},
edit: {
member: true,
namePrefix: 'edit_',
suffix: ':id/edit',
method: 'GET',
},
update: {
member: true,
namePrefix: '',
suffix: ':id',
method: ['PATCH', 'PUT'],
},
destroy: {
member: true,
namePrefix: 'destroy_',
suffix: ':id',
method: 'DELETE',
},
};
/**
* FIXME: move these patch into @eggjs/router
*/
export class EggRouter extends Router {
app;
/**
* @class
* @param {Object} opts - Router options.
* @param {Application} app - Application object.
*/
constructor(opts, app) {
super(opts);
this.app = app;
}
verb(method, nameOrPath, pathOrMiddleware, ...middleware) {
const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
if (typeof method === 'string') {
method = [method];
}
this.register(path, method, middlewares, options);
return this;
}
head(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares);
}
options(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares);
}
get(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares);
}
put(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares);
}
patch(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares);
}
post(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares);
}
delete(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
all(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb(methods, nameOrPath, pathOrMiddleware, ...middlewares);
}
register(path, methods, middleware, opts) {
// patch register to support generator function middleware and string controller
middleware = Array.isArray(middleware) ? middleware : [middleware];
const middlewares = convertMiddlewares(middleware, this.app);
return super.register(path, methods, middlewares, opts);
}
resources(nameOrPath, pathOrMiddleware, ...middleware) {
const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
// last argument is Controller object
const controller = resolveController(middlewares.pop(), this.app);
for (const key in REST_MAP) {
const action = controller[key];
if (!action)
continue;
const opts = REST_MAP[key];
let routeName;
if (opts.member) {
routeName = inflection.singularize(options.name ?? '');
}
else {
routeName = inflection.pluralize(options.name ?? '');
}
if (opts.namePrefix) {
routeName = opts.namePrefix + routeName;
}
const prefix = path.replace(/\/$/, '');
const urlPath = opts.suffix ? `${prefix}/${opts.suffix}` : prefix;
const method = Array.isArray(opts.method) ? opts.method : [opts.method];
this.register(urlPath, method, middlewares.concat(action), { name: routeName });
}
return this;
}
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name, params) {
const route = this.route(name);
if (!route)
return '';
const args = params;
let url = route.path;
assert(!(url instanceof RegExp), `Can't get the url for regExp ${url} for by name '${name}'`);
const queries = [];
if (typeof args === 'object' && args !== null) {
const replacedParams = [];
url = url.replace(/:([a-zA-Z_]\w*)/g, ($0, key) => {
if (key in args) {
const values = args[key];
replacedParams.push(key);
return safeEncodeURIComponent(Array.isArray(values) ? String(values[0]) : String(values));
}
return $0;
});
for (const key in args) {
if (replacedParams.includes(key)) {
continue;
}
const values = args[key];
const encodedKey = safeEncodeURIComponent(key);
if (Array.isArray(values)) {
for (const val of values) {
queries.push(`${encodedKey}=${safeEncodeURIComponent(String(val))}`);
}
}
else {
queries.push(`${encodedKey}=${safeEncodeURIComponent(String(values))}`);
}
}
}
if (queries.length > 0) {
const queryStr = queries.join('&');
if (!url.includes('?')) {
url = `${url}?${queryStr}`;
}
else {
url = `${url}&${queryStr}`;
}
}
return url;
}
/**
* @alias to url()
*/
pathFor(name, params) {
return this.url(name, params);
}
}
/**
* resolve controller from string to function
* @param {String|Function} controller input controller
* @param {Application} app egg application instance
*/
function resolveController(controller, app) {
if (typeof controller === 'string') {
// resolveController('foo.bar.Home', app)
const actions = controller.split('.');
let obj = app.controller;
actions.forEach(key => {
obj = obj[key];
if (!obj)
throw new Error(`app.controller.${controller} not exists`);
});
controller = obj;
}
// ensure controller is exists
if (!controller)
throw new Error('controller not exists');
return controller;
}
/**
* 1. ensure controller(last argument) support string
* - [url, controller]: app.get('/home', 'home');
* - [name, url, controller(string)]: app.get('posts', '/posts', 'posts.list');
* - [name, url, controller]: app.get('posts', '/posts', app.controller.posts.list);
* - [name, url(regexp), controller]: app.get('regRouter', /\/home\/index/, 'home.index');
* - [name, url, middleware, [...], controller]: `app.get(/user/:id', hasLogin, canGetUser, 'user.show');`
*
* 2. make middleware support generator function
*
* @param {Array} middlewares middlewares and controller(last middleware)
* @param {Application} app egg application instance
*/
function convertMiddlewares(middlewares, app) {
// ensure controller is resolved
const controller = resolveController(middlewares.pop(), app);
return [...middlewares, controller];
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRWdnUm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL0VnZ1JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDakMsT0FBTyxFQUFFLGtCQUFrQixJQUFJLHNCQUFzQixFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3ZFLE9BQU8sVUFBVSxNQUFNLFlBQVksQ0FBQztBQUNwQyxPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUM7QUFDOUIsT0FBTyxFQUFtQixNQUFNLEVBQStCLE1BQU0sYUFBYSxDQUFDO0FBVW5GLE1BQU0sUUFBUSxHQUFtQztJQUMvQyxLQUFLLEVBQUU7UUFDTCxNQUFNLEVBQUUsRUFBRTtRQUNWLE1BQU0sRUFBRSxLQUFLO0tBQ2Q7SUFDRCxHQUFHLEVBQUU7UUFDSCxVQUFVLEVBQUUsTUFBTTtRQUNsQixNQUFNLEVBQUUsSUFBSTtRQUNaLE1BQU0sRUFBRSxLQUFLO1FBQ2IsTUFBTSxFQUFFLEtBQUs7S0FDZDtJQUNELE1BQU0sRUFBRTtRQUNOLE1BQU0sRUFBRSxFQUFFO1FBQ1YsTUFBTSxFQUFFLE1BQU07S0FDZjtJQUNELElBQUksRUFBRTtRQUNKLE1BQU0sRUFBRSxJQUFJO1FBQ1osTUFBTSxFQUFFLEtBQUs7UUFDYixNQUFNLEVBQUUsS0FBSztLQUNkO0lBQ0QsSUFBSSxFQUFFO1FBQ0osTUFBTSxFQUFFLElBQUk7UUFDWixVQUFVLEVBQUUsT0FBTztRQUNuQixNQUFNLEVBQUUsVUFBVTtRQUNsQixNQUFNLEVBQUUsS0FBSztLQUNkO0lBQ0QsTUFBTSxFQUFFO1FBQ04sTUFBTSxFQUFFLElBQUk7UUFDWixVQUFVLEVBQUUsRUFBRTtRQUNkLE1BQU0sRUFBRSxLQUFLO1FBQ2IsTUFBTSxFQUFFLENBQUUsT0FBTyxFQUFFLEtBQUssQ0FBRTtLQUMzQjtJQUNELE9BQU8sRUFBRTtRQUNQLE1BQU0sRUFBRSxJQUFJO1FBQ1osVUFBVSxFQUFFLFVB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
import { Router } from './Router.js';
export * from './Router.js';
export * from './EggRouter.js';
export declare const KoaRouter: typeof Router;
export default Router;
import { Router } from './Router.js';
export * from './Router.js';
export * from './EggRouter.js';
export const KoaRouter = Router;
export default Router;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVyQyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGdCQUFnQixDQUFDO0FBRS9CLE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUM7QUFDaEMsZUFBZSxNQUFNLENBQUMifQ==
import { type Key } from 'path-to-regexp';
import type { MiddlewareFunc, MiddlewareFuncWithParamProperty, ParamMiddlewareFunc } from './types.js';
export interface LayerOptions {
prefix?: string;
/** route name */
name?: string;
/** case sensitive (default: false) */
sensitive?: boolean;
/** require the trailing slash (default: false) */
strict?: boolean;
ignoreCaptures?: boolean;
end?: boolean;
}
export interface LayerURLOptions {
query?: string | object;
}
export declare class Layer {
readonly opts: LayerOptions;
readonly name?: string;
readonly methods: string[];
readonly stack: MiddlewareFuncWithParamProperty[];
path: string | RegExp;
regexp: RegExp;
paramNames: Key[];
/**
* Initialize a new routing Layer with given `method`, `path`, and `middleware`.
*
* @param {String|RegExp} path Path string or regular expression.
* @param {Array} methods Array of HTTP verbs.
* @param {Array|Function} middlewares Layer callback/middleware or series of.
* @param {Object=} opts optional params
* @param {String=} opts.name route name
* @param {String=} opts.sensitive case sensitive (default: false)
* @param {String=} opts.strict require the trailing slash (default: false)
* @private
*/
constructor(path: string | RegExp, methods: string[], middlewares: MiddlewareFunc | MiddlewareFunc[], opts?: LayerOptions | string);
/**
* Returns whether request `path` matches route.
*
* @param {String} path path string
* @return {Boolean} matched or not
* @private
*/
match(path: string): boolean;
/**
* Returns map of URL parameters for given `path` and `paramNames`.
*
* @param {String} _path path string
* @param {Array.<String>} captures captures strings
* @param {Object=} [existingParams] existing params
* @return {Object} params object
* @private
*/
params(_path: string, captures: Array<string>, existingParams?: Record<string, string>): Record<string, string>;
/**
* Returns array of regexp url path captures.
*
* @param {String} path path string
* @return {Array.<String>} captures strings
* @private
*/
captures(path: string): Array<string>;
/**
* Generate URL for route using given `params`.
*
* @example
*
* ```javascript
* var route = new Layer(['GET'], '/users/:id', fn);
*
* route.url(123); // => "/users/123"
* route.url('123'); // => "/users/123"
* route.url({ id: 123 }); // => "/users/123"
* ```
*
* @param {Object} params url parameters
* @param {Object} paramsOrOptions optional parameters
* @return {String} url string
* @private
*/
url(params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string;
/**
* Run validations on route named parameters.
*
* @example
*
* ```javascript
* router
* .param('user', function (id, ctx, next) {
* ctx.user = users[id];
* if (!user) return ctx.status = 404;
* next();
* })
* .get('/users/:user', function (ctx, next) {
* ctx.body = ctx.user;
* });
* ```
*
* @param {String} param param string
* @param {Function} fn middleware function
* @return {Layer} layer instance
* @private
*/
param(param: string, fn: ParamMiddlewareFunc): Layer;
/**
* Prefix route path.
*
* @param {String} prefix prefix string
* @return {Layer} layer instance
* @private
*/
setPrefix(prefix: string): Layer;
}
import { debuglog } from 'node:util';
import pathToRegExp from 'path-to-regexp';
import URI from 'urijs';
import { decodeURIComponent as safeDecodeURIComponent } from 'utility';
import { isGeneratorFunction } from 'is-type-of';
const debug = debuglog('egg-router:layer');
export class Layer {
opts;
name;
methods = [];
stack;
path;
regexp;
paramNames = [];
/**
* Initialize a new routing Layer with given `method`, `path`, and `middleware`.
*
* @param {String|RegExp} path Path string or regular expression.
* @param {Array} methods Array of HTTP verbs.
* @param {Array|Function} middlewares Layer callback/middleware or series of.
* @param {Object=} opts optional params
* @param {String=} opts.name route name
* @param {String=} opts.sensitive case sensitive (default: false)
* @param {String=} opts.strict require the trailing slash (default: false)
* @private
*/
constructor(path, methods, middlewares, opts) {
if (typeof opts === 'string') {
// new Layer(path, methods, middlewares, name);
opts = { name: opts };
}
this.opts = opts ?? {};
this.opts.prefix = this.opts.prefix ?? '';
this.name = this.opts.name;
this.stack = Array.isArray(middlewares) ? middlewares : [middlewares];
for (const method of methods) {
const l = this.methods.push(method.toUpperCase());
if (this.methods[l - 1] === 'GET') {
this.methods.unshift('HEAD');
}
}
// ensure middleware is a function
this.stack.forEach(fn => {
const type = typeof fn;
if (type !== 'function') {
throw new TypeError(methods.toString() + ' `' + (this.opts.name || path) + '`: `middleware` '
+ 'must be a function, not `' + type + '`');
}
if (isGeneratorFunction(fn)) {
throw new TypeError(methods.toString() + ' `' + (this.opts.name || path) + '`: Please use async function instead of generator function');
}
});
this.path = path;
this.regexp = pathToRegExp(path, this.paramNames, this.opts);
debug('defined route %s %s', this.methods, this.opts.prefix + this.path);
}
/**
* Returns whether request `path` matches route.
*
* @param {String} path path string
* @return {Boolean} matched or not
* @private
*/
match(path) {
return this.regexp.test(path);
}
/**
* Returns map of URL parameters for given `path` and `paramNames`.
*
* @param {String} _path path string
* @param {Array.<String>} captures captures strings
* @param {Object=} [existingParams] existing params
* @return {Object} params object
* @private
*/
params(_path, captures, existingParams) {
const params = existingParams ?? {};
for (let len = captures.length, i = 0; i < len; i++) {
const paramName = this.paramNames[i];
if (paramName) {
const c = captures[i];
params[paramName.name] = c ? safeDecodeURIComponent(c) : c;
}
}
return params;
}
/**
* Returns array of regexp url path captures.
*
* @param {String} path path string
* @return {Array.<String>} captures strings
* @private
*/
captures(path) {
if (this.opts.ignoreCaptures)
return [];
const m = path.match(this.regexp);
return m ? m.slice(1) : [];
}
/**
* Generate URL for route using given `params`.
*
* @example
*
* ```javascript
* var route = new Layer(['GET'], '/users/:id', fn);
*
* route.url(123); // => "/users/123"
* route.url('123'); // => "/users/123"
* route.url({ id: 123 }); // => "/users/123"
* ```
*
* @param {Object} params url parameters
* @param {Object} paramsOrOptions optional parameters
* @return {String} url string
* @private
*/
url(params, ...paramsOrOptions) {
let args = params;
const url = this.path.replace(/\(\.\*\)/g, '');
const toPath = pathToRegExp.compile(url);
let options;
if (params !== undefined && typeof params !== 'object') {
args = [params, ...paramsOrOptions];
// route.url(stringOrNumber, params1, ..., options);
if (Array.isArray(args)) {
const lastIndex = args.length - 1;
if (typeof args[lastIndex] === 'object') {
options = args[lastIndex];
args = args.slice(0, lastIndex);
}
}
}
else if (typeof params === 'object') {
if (typeof paramsOrOptions[0] === 'object' && 'query' in paramsOrOptions[0]) {
// route.url(param, options);
options = paramsOrOptions[0];
}
}
const tokens = pathToRegExp.parse(url);
let replace = {};
if (Array.isArray(args)) {
for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
const token = tokens[i];
if (typeof token === 'object' && token.name) {
replace[token.name] = args[j++];
}
}
}
else if (tokens.some(token => typeof token === 'object' && token.name)) {
// route.url(params);
replace = params;
}
else {
// route.url(options);
options = params;
}
const replaced = toPath(replace);
if (options?.query) {
const urlObject = new URI(replaced);
urlObject.search(options.query);
return urlObject.toString();
}
return replaced;
}
/**
* Run validations on route named parameters.
*
* @example
*
* ```javascript
* router
* .param('user', function (id, ctx, next) {
* ctx.user = users[id];
* if (!user) return ctx.status = 404;
* next();
* })
* .get('/users/:user', function (ctx, next) {
* ctx.body = ctx.user;
* });
* ```
*
* @param {String} param param string
* @param {Function} fn middleware function
* @return {Layer} layer instance
* @private
*/
param(param, fn) {
const stack = this.stack;
const params = this.paramNames;
const middleware = function (ctx, next) {
return fn.call(this, ctx.params[param], ctx, next);
};
middleware.param = param;
const names = params.map(p => {
return p.name;
});
const x = names.indexOf(param);
if (x > -1) {
// iterate through the stack, to figure out where to place the handler fn
stack.some(function (fn, i) {
// param handlers are always first, so when we find an fn w/o a param property, stop here
// if the param handler at this part of the stack comes after the one we are adding, stop here
if (!fn.param || names.indexOf(fn.param) > x) {
// inject this param handler right before the current item
stack.splice(i, 0, middleware);
return true; // then break the loop
}
return false;
});
}
return this;
}
/**
* Prefix route path.
*
* @param {String} prefix prefix string
* @return {Layer} layer instance
* @private
*/
setPrefix(prefix) {
if (this.path) {
this.path = prefix + this.path;
this.paramNames = [];
this.regexp = pathToRegExp(this.path, this.paramNames, this.opts);
}
return this;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGF5ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvTGF5ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLFlBQTBCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEQsT0FBTyxHQUFHLE1BQU0sT0FBTyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxzQkFBc0IsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN2RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFPakQsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFrQjNDLE1BQU0sT0FBTyxLQUFLO0lBQ1AsSUFBSSxDQUFlO0lBQ25CLElBQUksQ0FBVTtJQUNkLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDdkIsS0FBSyxDQUFvQztJQUNsRCxJQUFJLENBQWtCO0lBQ3RCLE1BQU0sQ0FBUztJQUNmLFVBQVUsR0FBVSxFQUFFLENBQUM7SUFFdkI7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxZQUFZLElBQXFCLEVBQUUsT0FBaUIsRUFBRSxXQUE4QyxFQUNsRyxJQUE0QjtRQUM1QixJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzdCLCtDQUErQztZQUMvQyxJQUFJLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDeEIsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7UUFDMUMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztRQUMzQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBRSxXQUFXLENBQUUsQ0FBQztRQUV4RSxLQUFLLE1BQU0sTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQzdCLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1lBQ2xELElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQ2xDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQy9CLENBQUM7UUFDSCxDQUFDO1FBRUQsa0NBQWtDO1FBQ2xDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQ3RCLE1BQU0sSUFBSSxHQUFHLE9BQU8sRUFBRSxDQUFDO1lBQ3ZCLElBQUksSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUN4QixNQUFNLElBQUksU0FBUyxDQUNqQixPQUFPLENBQUMsUUFBUSxFQUFFLEdBQUcsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLEdBQUcsa0JBQWtCO3NCQUN2RSwyQkFBMkIsR0FBRyxJQUFJLEdBQUcsR0FBRyxDQUMzQyxDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksbUJBQW1CLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQkFDNUIsTUFBTSxJQUFJLFNBQVMsQ0FDakIsT0FBTyxDQUFDLFFBQVEsRUFBRSxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxHQUFHLDREQUE0RCxDQUNwSCxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLE1BQU0sR0FBRyxZQUFZLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRTdELEtBQUssQ0FBQyxxQkFBcUIsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLElBQVk7UUFDaEIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxNQUFNLENBQUMsS0FBYSxFQUFFLFFBQXVCLEVBQUUsY0FBdUM7UUFDcEYsTUFBTSxNQUFNLEdBQUcsY0FBYyxJQUFJLEVBQUUsQ0FBQztRQUVwQyxLQUFLLElBQUksR0FBRyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDcEQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNyQyxJQUFJLFNBQVMsRUFBRSxDQUFDO2dCQUNkLE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDdEIsTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDN0QsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsUUFBUSxDQUFDLElBQVk7UUFDbkIsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWM7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN4QyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSCxHQUFHLENBQUMsTUFBaUMsRUFBRSxHQUFHLGVBQStEO1FBQ3ZHLElBQUksSUFBSSxHQUE2QyxNQUFnQixDQUFDO1FBQ3RFLE1BQU0sR0FBRyxHQUFJLElBQUksQ0FBQyxJQUFlLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUMzRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLElBQUksT0FBb0MsQ0FBQztRQUV6QyxJQUFJLE1BQU0sS0FBSyxTQUFTLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDdkQsSUFBSSxHQUFHLENBQUUsTUFBTSxFQUFFLEdBQUcsZUFBZSxDQUFFLENBQUM7WUFDdEMsb0RBQW9EO1lBQ3BELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUN4QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztnQkFDbEMsSUFBSSxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDeEMsT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztvQkFDMUIsSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUNsQyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7YUFBTSxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3RDLElBQUksT0FBTyxlQUFlLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxJQUFJLE9BQU8sSUFBSSxlQUFlLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDNUUsNkJBQTZCO2dCQUM3QixPQUFPLEdBQUcsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLE9BQU8sR0FBd0IsRUFBRSxDQUFDO1FBRXRDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3hCLEtBQUssSUFBSSxHQUFHLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUN6RCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3hCLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztvQkFDNUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDbEMsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO2FBQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ3pFLHFCQUFxQjtZQUNyQixPQUFPLEdBQUcsTUFBZ0IsQ0FBQztRQUM3QixDQUFDO2FBQU0sQ0FBQztZQUNOLHNCQUFzQjtZQUN0QixPQUFPLEdBQUcsTUFBeUIsQ0FBQztRQUN0QyxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRWpDLElBQUksT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO1lBQ25CLE1BQU0sU0FBUyxHQUFHLElBQUksR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3BDLFNBQVMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2hDLE9BQU8sU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzlCLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQXFCRztJQUNILEtBQUssQ0FBQyxLQUFhLEVBQUUsRUFBdUI7UUFDMUMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUN6QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQy9CLE1BQU0sVUFBVSxHQUFvQyxVQUFvQixHQUFHLEVBQUUsSUFBSTtZQUMvRSxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQztRQUNGLFVBQVUsQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRXpCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDM0IsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ2hCLENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ1gseUVBQXlFO1lBQ3pFLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBUyxFQUFFLEVBQUUsQ0FBQztnQkFDdkIseUZBQXlGO2dCQUN6Riw4RkFBOEY7Z0JBQzlGLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUM3QywwREFBMEQ7b0JBQzFELEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztvQkFDL0IsT0FBTyxJQUFJLENBQUMsQ0FBQyxzQkFBc0I7Z0JBQ3JDLENBQUM7Z0JBQ0QsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxTQUFTLENBQUMsTUFBYztRQUN0QixJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNkLElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDL0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwRSxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0NBQ0YifQ==
{
"type": "module"
}
/**
* RESTful resource routing middleware for eggjs.
*/
import methods from 'methods';
import { Layer, LayerURLOptions } from './Layer.js';
import { MiddlewareFunc, MiddlewareFuncWithRouter, ParamMiddlewareFunc, ResourcesController } from './types.js';
export type RouterMethod = typeof methods[0];
export interface RouterOptions {
methods?: string[];
prefix?: string;
sensitive?: boolean;
strict?: boolean;
routerPath?: string;
}
export interface RegisterOptions {
name?: string;
prefix?: string;
sensitive?: boolean;
strict?: boolean;
ignoreCaptures?: boolean;
end?: boolean;
}
export interface AllowedMethodsOptions {
throw?: boolean;
notImplemented?: () => Error;
methodNotAllowed?: () => Error;
}
export interface MatchedResult {
path: Layer[];
pathAndMethod: Layer[];
route: boolean;
}
export declare class Router {
#private;
readonly opts: RouterOptions;
readonly methods: string[];
/** Layer stack */
readonly stack: Layer[];
readonly params: Record<string, ParamMiddlewareFunc>;
/**
* Create a new router.
*
* @example
*
* Basic usage:
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* router.get('/', (ctx, next) => {
* // ctx.router available
* });
*
* app
* .use(router.routes())
* .use(router.allowedMethods());
* ```
*
* @alias module:koa-router
* @param {Object=} opts optional
* @param {String=} opts.prefix prefix router paths
* @class
*/
constructor(opts?: RouterOptions);
/**
* Use given middleware.
*
* Middleware run in the order they are defined by `.use()`. They are invoked
* sequentially, requests start at the first middleware and work their way
* "down" the middleware stack.
*
* @example
*
* ```javascript
* // session middleware will run before authorize
* router
* .use(session())
* .use(authorize());
*
* // use middleware only with given path
* router.use('/users', userAuth());
*
* // or with an array of paths
* router.use(['/users', '/admin'], userAuth());
*
* app.use(router.routes());
* ```
*
* @param {String=} path path string
* @param {Function} middleware middleware function
* @return {Router} router instance
*/
use(...middlewares: MiddlewareFunc[]): Router;
use(path: string | string[], ...middlewares: MiddlewareFunc[]): Router;
/**
* Set the path prefix for a Router instance that was already initialized.
*
* @example
*
* ```javascript
* router.prefix('/things/:thing_id')
* ```
*
* @param {String} prefix prefix string
* @return {Router} router instance
*/
prefix(prefix: string): Router;
/**
* Returns router middleware which dispatches a route matching the request.
*
* @return {Function} middleware function
*/
routes(): MiddlewareFuncWithRouter<Router>;
/**
* @alias to routes()
*/
middleware(): MiddlewareFuncWithRouter<Router>;
/**
* Returns separate middleware for responding to `OPTIONS` requests with
* an `Allow` header containing the allowed methods, as well as responding
* with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
*
* @example
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods());
* ```
*
* **Example with [Boom](https://github.com/hapijs/boom)**
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
* var Boom = require('boom');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods({
* throw: true,
* notImplemented: () => new Boom.notImplemented(),
* methodNotAllowed: () => new Boom.methodNotAllowed()
* }));
* ```
*
* @param {Object=} options optional params
* @param {Boolean=} options.throw throw error instead of setting status and header
* @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
* @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
* @return {Function} middleware function
*/
allowedMethods(options?: AllowedMethodsOptions): MiddlewareFunc;
/**
* Redirect `source` to `destination` URL with optional 30x status `code`.
*
* Both `source` and `destination` can be route names.
*
* ```javascript
* router.redirect('/login', 'sign-in');
* ```
*
* This is equivalent to:
*
* ```javascript
* router.all('/login', ctx => {
* ctx.redirect('/sign-in');
* ctx.status = 301;
* });
* ```
*
* @param {String} source URL or route name.
* @param {String} destination URL or route name.
* @param {Number=} status HTTP status code (default: 301).
* @return {Router} router instance
*/
redirect(source: string, destination: string, status?: number): Router;
/**
* Create and register a route.
*
* @param {String|RegExp|(String|RegExp)[]} path Path string.
* @param {String[]} methods Array of HTTP verbs.
* @param {Function|Function[]} middleware Multiple middleware also accepted.
* @param {Object} [opts] optional params
* @private
*/
register(path: string | RegExp | (string | RegExp)[], methods: string[], middleware: MiddlewareFunc | MiddlewareFunc[], opts?: RegisterOptions): Layer | Layer[];
/**
* Lookup route with given `name`.
*
* @param {String} name route name
* @return {Layer|false} layer instance of false
*/
route(name: string): Layer | false;
/**
* Generate URL for route. Takes a route name and map of named `params`.
*
* @example
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
*
* router.url('user', { id: 3 });
* // => "/users/3"
*
* router.use((ctx, next) => {
* // redirect to named route
* ctx.redirect(ctx.router.url('sign-in'));
* })
*
* router.url('user', { id: 3 }, { query: { limit: 1 } });
* // => "/users/3?limit=1"
*
* router.url('user', { id: 3 }, { query: "limit=1" });
* // => "/users/3?limit=1"
* ```
*/
url(name: string, params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string | Error;
/**
* Generate URL from url pattern and given `params`.
*
* @example
*
* ```javascript
* var url = Router.url('/users/:id', { id: 1 });
* // => "/users/1"
* ```
*
* @param {String} path url pattern
* @param {Object} params url parameters
* @return {String} url string
*/
static url(path: string, params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string;
/**
* Match given `path` and return corresponding routes.
*
* @param {String} path path string
* @param {String} method method name
* @return {Object.<path, pathAndMethod>} returns layers that matched path and
* path and method.
* @private
*/
match(path: string, method: string): MatchedResult;
/**
* Run middleware for named route parameters. Useful for auto-loading or
* validation.
*
* @example
*
* ```javascript
* router
* .param('user', (id, ctx, next) => {
* ctx.user = users[id];
* if (!ctx.user) return ctx.status = 404;
* return next();
* })
* .get('/users/:user', ctx => {
* ctx.body = ctx.user;
* })
* .get('/users/:user/friends', ctx => {
* return ctx.user.getFriends().then(function(friends) {
* ctx.body = friends;
* });
* })
* // /users/3 => {"id": 3, "name": "Alex"}
* // /users/3/friends => [{"id": 4, "name": "TJ"}]
* ```
*
* @param {String} param param
* @param {Function} middleware route middleware
* @return {Router} instance
*/
param(param: string, middleware: ParamMiddlewareFunc): Router;
protected _formatRouteParams(nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc | ResourcesController, middlewares: (MiddlewareFunc | string | ResourcesController)[]): {
path: string | RegExp | (string | RegExp)[];
middlewares: (string | MiddlewareFunc | ResourcesController)[];
options: RegisterOptions;
};
/**
* Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
* as `router.get()` or `router.post()`.
*
* Match URL patterns to callback functions or controller actions using `router.verb()`,
* where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
*
* Additionally, `router.all()` can be used to match against all methods.
*
* ```javascript
* router
* .get('/', (ctx, next) => {
* ctx.body = 'Hello World!';
* })
* .post('/users', (ctx, next) => {
* // ...
* })
* .put('/users/:id', (ctx, next) => {
* // ...
* })
* .del('/users/:id', (ctx, next) => {
* // ...
* })
* .all('/users/:id', (ctx, next) => {
* // ...
* });
* ```
*
* When a route is matched, its path is available at `ctx._matchedRoute` and if named,
* the name is available at `ctx._matchedRouteName`
*
* Route paths will be translated to regular expressions using
* [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
*
* Query strings will not be considered when matching requests.
*
* #### Named routes
*
* Routes can optionally have names. This allows generation of URLs and easy
* renaming of URLs during development.
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
* ```
*
* #### Multiple middleware
*
* Multiple middleware may be given:
*
* ```javascript
* router.get(
* '/users/:id',
* (ctx, next) => {
* return User.findOne(ctx.params.id).then(function(user) {
* ctx.user = user;
* next();
* });
* },
* ctx => {
* console.log(ctx.user);
* // => { id: 17, name: "Alex" }
* }
* );
* ```
*
* ### Nested routers
*
* Nesting routers is supported:
*
* ```javascript
* var forums = new Router();
* var posts = new Router();
*
* posts.get('/', (ctx, next) => {...});
* posts.get('/:pid', (ctx, next) => {...});
* forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
*
* // responds to "/forums/123/posts" and "/forums/123/posts/123"
* app.use(forums.routes());
* ```
*
* #### Router prefixes
*
* Route paths can be prefixed at the router level:
*
* ```javascript
* var router = new Router({
* prefix: '/users'
* });
*
* router.get('/', ...); // responds to "/users"
* router.get('/:id', ...); // responds to "/users/:id"
* ```
*
* #### URL parameters
*
* Named route parameters are captured and added to `ctx.params`.
*
* ```javascript
* router.get('/:category/:title', (ctx, next) => {
* console.log(ctx.params);
* // => { category: 'programming', title: 'how-to-node' }
* });
* ```
*
* The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
* used to convert paths to regular expressions.
*
*/
verb(method: string | string[], nameOrPath: string | RegExp | (string | RegExp)[], pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc, ...middleware: MiddlewareFunc[]): Router;
/**
* Register route with all methods.
*
* @param {String} name Optional.
* @param {String} path path string
* @param {Function=} middleware You may also pass multiple middleware.
* @return {Router} router instance
* @private
*/
all(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
acl(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
acl(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
bind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
bind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
checkout(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
checkout(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
connect(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
connect(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
copy(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
copy(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
delete(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
/** Alias for `router.delete()` because delete is a reserved word */
del(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
del(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
get(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
query(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
query(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
head(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
link(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
link(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
lock(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
lock(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
['m-search'](path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
['m-search'](name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
merge(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
merge(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkactivity(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkactivity(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcalendar(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcalendar(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcol(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcol(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
move(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
move(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
notify(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
notify(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
options(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
patch(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
post(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
propfind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
propfind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
proppatch(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
proppatch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
purge(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
purge(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
put(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
rebind(path: string | RegExp, ...middlewares: MiddlewareFunc[]): Router;
rebind(name: string, path: string | RegExp, ...middlewares: MiddlewareFunc[]): Router;
report(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
report(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
search(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
search(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
source(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
source(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
subscribe(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
subscribe(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
trace(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
trace(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unbind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unbind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlink(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlink(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlock(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlock(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unsubscribe(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unsubscribe(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
}
/**
* RESTful resource routing middleware for eggjs.
*/
import { debuglog } from 'node:util';
import assert from 'node:assert';
import compose from 'koa-compose';
import HttpError from 'http-errors';
import methods from 'methods';
import { Layer } from './Layer.js';
const debug = debuglog('egg-router:router');
export class Router {
opts;
methods;
/** Layer stack */
stack = [];
params = {};
/**
* Create a new router.
*
* @example
*
* Basic usage:
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* router.get('/', (ctx, next) => {
* // ctx.router available
* });
*
* app
* .use(router.routes())
* .use(router.allowedMethods());
* ```
*
* @alias module:koa-router
* @param {Object=} opts optional
* @param {String=} opts.prefix prefix router paths
* @class
*/
constructor(opts) {
this.opts = opts ?? {};
this.methods = this.opts.methods ?? [
'HEAD',
'OPTIONS',
'GET',
'PUT',
'PATCH',
'POST',
'DELETE',
];
}
use(pathOrMiddleware, ...middlewares) {
// support array of paths
// use(paths, ...middlewares)
if (Array.isArray(pathOrMiddleware) && typeof pathOrMiddleware[0] === 'string') {
for (const path of pathOrMiddleware) {
this.use(path, ...middlewares);
}
return this;
}
let path = '';
let hasPath = false;
if (typeof pathOrMiddleware === 'string') {
// use(path, ...middlewares)
path = pathOrMiddleware;
hasPath = true;
}
else if (typeof pathOrMiddleware === 'function') {
// use(...middlewares)
middlewares = [pathOrMiddleware, ...middlewares];
}
for (const m of middlewares) {
if (m.router) {
for (const nestedLayer of m.router.stack) {
if (path) {
nestedLayer.setPrefix(path);
}
if (this.opts.prefix) {
nestedLayer.setPrefix(this.opts.prefix);
}
this.stack.push(nestedLayer);
}
if (this.params) {
for (const key in this.params) {
m.router.param(key, this.params[key]);
}
}
}
else {
this.register(path || '(.*)', [], m, { end: false, ignoreCaptures: !hasPath });
}
}
return this;
}
/**
* Set the path prefix for a Router instance that was already initialized.
*
* @example
*
* ```javascript
* router.prefix('/things/:thing_id')
* ```
*
* @param {String} prefix prefix string
* @return {Router} router instance
*/
prefix(prefix) {
prefix = prefix.replace(/\/$/, '');
this.opts.prefix = prefix;
for (const layer of this.stack) {
layer.setPrefix(prefix);
}
return this;
}
/**
* Returns router middleware which dispatches a route matching the request.
*
* @return {Function} middleware function
*/
routes() {
const dispatch = (ctx, next) => {
const routerPath = this.opts.routerPath || ctx.routerPath || ctx.path;
const matched = this.match(routerPath, ctx.method);
debug('dispatch: %s %s, routerPath: %s, matched: %s', ctx.method, ctx.path, routerPath, matched.route);
if (ctx.matched) {
ctx.matched.push(...matched.path);
}
else {
ctx.matched = matched.path;
}
ctx.router = this;
if (!matched.route) {
return next();
}
const matchedLayers = matched.pathAndMethod;
const layerChain = matchedLayers.reduce((memo, layer) => {
memo.push((ctx, next) => {
// ctx.captures = layer.captures(routerPath, ctx.captures);
ctx.captures = layer.captures(routerPath);
ctx.params = layer.params(routerPath, ctx.captures, ctx.params);
// ctx._matchedRouteName & ctx._matchedRoute for compatibility
ctx._matchedRouteName = ctx.routerName = layer.name;
if (!layer.name) {
ctx._matchedRouteName = undefined;
}
ctx._matchedRoute = ctx.routerPath = layer.path;
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
};
dispatch.router = this;
return dispatch;
}
/**
* @alias to routes()
*/
middleware() {
return this.routes();
}
/**
* Returns separate middleware for responding to `OPTIONS` requests with
* an `Allow` header containing the allowed methods, as well as responding
* with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
*
* @example
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods());
* ```
*
* **Example with [Boom](https://github.com/hapijs/boom)**
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
* var Boom = require('boom');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods({
* throw: true,
* notImplemented: () => new Boom.notImplemented(),
* methodNotAllowed: () => new Boom.methodNotAllowed()
* }));
* ```
*
* @param {Object=} options optional params
* @param {Boolean=} options.throw throw error instead of setting status and header
* @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
* @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
* @return {Function} middleware function
*/
allowedMethods(options) {
const implemented = this.methods;
return async function allowedMethods(ctx, next) {
await next();
if (ctx.status && ctx.status !== 404)
return;
const allowed = {};
ctx.matched.forEach((route) => {
route.methods.forEach(method => {
allowed[method] = method;
});
});
const allowedMethods = Object.keys(allowed);
if (!implemented.includes(ctx.method)) {
if (options?.throw) {
let notImplementedThrowable;
if (typeof options?.notImplemented === 'function') {
notImplementedThrowable = options.notImplemented(); // set whatever the user returns from their function
}
else {
notImplementedThrowable = new HttpError.NotImplemented();
}
throw notImplementedThrowable;
}
else {
ctx.status = 501;
ctx.set('Allow', allowedMethods.join(', '));
}
}
else if (allowedMethods.length > 0) {
if (ctx.method === 'OPTIONS') {
ctx.status = 200;
ctx.body = '';
ctx.set('Allow', allowedMethods.join(', '));
}
else if (!allowed[ctx.method]) {
if (options?.throw) {
let notAllowedThrowable;
if (typeof options?.methodNotAllowed === 'function') {
notAllowedThrowable = options.methodNotAllowed(); // set whatever the user returns from their function
}
else {
notAllowedThrowable = new HttpError.MethodNotAllowed();
}
throw notAllowedThrowable;
}
else {
ctx.status = 405;
ctx.set('Allow', allowedMethods.join(', '));
}
}
}
};
}
/**
* Redirect `source` to `destination` URL with optional 30x status `code`.
*
* Both `source` and `destination` can be route names.
*
* ```javascript
* router.redirect('/login', 'sign-in');
* ```
*
* This is equivalent to:
*
* ```javascript
* router.all('/login', ctx => {
* ctx.redirect('/sign-in');
* ctx.status = 301;
* });
* ```
*
* @param {String} source URL or route name.
* @param {String} destination URL or route name.
* @param {Number=} status HTTP status code (default: 301).
* @return {Router} router instance
*/
redirect(source, destination, status = 301) {
// lookup source route by name
if (source[0] !== '/') {
const routeUrl = this.url(source);
if (routeUrl instanceof Error) {
throw routeUrl;
}
source = routeUrl;
}
// lookup destination route by name
if (destination[0] !== '/') {
const routeUrl = this.url(destination);
if (routeUrl instanceof Error) {
throw routeUrl;
}
destination = routeUrl;
}
return this.all(source, ctx => {
ctx.redirect(destination);
ctx.status = status;
});
}
/**
* Create and register a route.
*
* @param {String|RegExp|(String|RegExp)[]} path Path string.
* @param {String[]} methods Array of HTTP verbs.
* @param {Function|Function[]} middleware Multiple middleware also accepted.
* @param {Object} [opts] optional params
* @private
*/
register(path, methods, middleware, opts) {
// support array of paths
if (Array.isArray(path)) {
const routes = [];
for (const p of path) {
const route = this.#register(p, methods, middleware, opts);
routes.push(route);
}
return routes;
}
// create route
const route = this.#register(path, methods, middleware, opts);
return route;
}
#register(path, methods, middleware, opts) {
opts = opts ?? {};
// create route
const route = new Layer(path, methods, middleware, {
end: opts.end === false ? opts.end : true,
name: opts.name,
sensitive: opts.sensitive ?? this.opts.sensitive ?? false,
strict: opts.strict ?? this.opts.strict ?? false,
prefix: opts.prefix ?? this.opts.prefix ?? '',
ignoreCaptures: opts.ignoreCaptures,
});
// FIXME: why???
if (this.opts.prefix) {
route.setPrefix(this.opts.prefix);
}
// add parameter middleware to the new route layer
for (const param in this.params) {
route.param(param, this.params[param]);
}
this.stack.push(route);
return route;
}
/**
* Lookup route with given `name`.
*
* @param {String} name route name
* @return {Layer|false} layer instance of false
*/
route(name) {
for (const route of this.stack) {
if (route.name === name) {
return route;
}
}
return false;
}
/**
* Generate URL for route. Takes a route name and map of named `params`.
*
* @example
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
*
* router.url('user', { id: 3 });
* // => "/users/3"
*
* router.use((ctx, next) => {
* // redirect to named route
* ctx.redirect(ctx.router.url('sign-in'));
* })
*
* router.url('user', { id: 3 }, { query: { limit: 1 } });
* // => "/users/3?limit=1"
*
* router.url('user', { id: 3 }, { query: "limit=1" });
* // => "/users/3?limit=1"
* ```
*/
url(name, params, ...paramsOrOptions) {
const route = this.route(name);
if (route) {
return route.url(params, ...paramsOrOptions);
}
return new Error(`No route found for name: ${name}`);
}
/**
* Generate URL from url pattern and given `params`.
*
* @example
*
* ```javascript
* var url = Router.url('/users/:id', { id: 1 });
* // => "/users/1"
* ```
*
* @param {String} path url pattern
* @param {Object} params url parameters
* @return {String} url string
*/
static url(path, params, ...paramsOrOptions) {
return Layer.prototype.url.call({ path }, params, ...paramsOrOptions);
}
/**
* Match given `path` and return corresponding routes.
*
* @param {String} path path string
* @param {String} method method name
* @return {Object.<path, pathAndMethod>} returns layers that matched path and
* path and method.
* @private
*/
match(path, method) {
const matched = {
// matched path
path: [],
// matched path and method(including none method)
pathAndMethod: [],
// method matched or not
route: false,
};
for (const layer of this.stack) {
debug('test %s %s', layer.path, layer.regexp);
if (layer.match(path)) {
matched.path.push(layer);
if (layer.methods.length === 0 || layer.methods.includes(method)) {
matched.pathAndMethod.push(layer);
if (layer.methods.length > 0) {
matched.route = true;
}
}
// if (layer.methods.length === 0) {
// matched.pathAndMethod.push(layer);
// } else if (layer.methods.includes(method)) {
// matched.pathAndMethod.push(layer);
// matched.route = true;
// }
}
}
return matched;
}
/**
* Run middleware for named route parameters. Useful for auto-loading or
* validation.
*
* @example
*
* ```javascript
* router
* .param('user', (id, ctx, next) => {
* ctx.user = users[id];
* if (!ctx.user) return ctx.status = 404;
* return next();
* })
* .get('/users/:user', ctx => {
* ctx.body = ctx.user;
* })
* .get('/users/:user/friends', ctx => {
* return ctx.user.getFriends().then(function(friends) {
* ctx.body = friends;
* });
* })
* // /users/3 => {"id": 3, "name": "Alex"}
* // /users/3/friends => [{"id": 4, "name": "TJ"}]
* ```
*
* @param {String} param param
* @param {Function} middleware route middleware
* @return {Router} instance
*/
param(param, middleware) {
this.params[param] = middleware;
for (const route of this.stack) {
route.param(param, middleware);
}
return this;
}
_formatRouteParams(nameOrPath, pathOrMiddleware, middlewares) {
const options = {};
let path;
if (typeof pathOrMiddleware === 'string' || pathOrMiddleware instanceof RegExp) {
// verb(method, name, path, ...middlewares)
path = pathOrMiddleware;
assert(typeof nameOrPath === 'string', 'route name should be string');
options.name = nameOrPath;
}
else if (Array.isArray(pathOrMiddleware)) {
// verb(method, name, paths, ...middlewares)
path = pathOrMiddleware;
assert(typeof nameOrPath === 'string', 'route name should be string');
options.name = nameOrPath;
}
else {
// verb(method, path, ...middlewares)
path = nameOrPath;
middlewares = [pathOrMiddleware, ...middlewares];
}
return {
path,
middlewares,
options,
};
}
/**
* Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
* as `router.get()` or `router.post()`.
*
* Match URL patterns to callback functions or controller actions using `router.verb()`,
* where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
*
* Additionally, `router.all()` can be used to match against all methods.
*
* ```javascript
* router
* .get('/', (ctx, next) => {
* ctx.body = 'Hello World!';
* })
* .post('/users', (ctx, next) => {
* // ...
* })
* .put('/users/:id', (ctx, next) => {
* // ...
* })
* .del('/users/:id', (ctx, next) => {
* // ...
* })
* .all('/users/:id', (ctx, next) => {
* // ...
* });
* ```
*
* When a route is matched, its path is available at `ctx._matchedRoute` and if named,
* the name is available at `ctx._matchedRouteName`
*
* Route paths will be translated to regular expressions using
* [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
*
* Query strings will not be considered when matching requests.
*
* #### Named routes
*
* Routes can optionally have names. This allows generation of URLs and easy
* renaming of URLs during development.
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
* ```
*
* #### Multiple middleware
*
* Multiple middleware may be given:
*
* ```javascript
* router.get(
* '/users/:id',
* (ctx, next) => {
* return User.findOne(ctx.params.id).then(function(user) {
* ctx.user = user;
* next();
* });
* },
* ctx => {
* console.log(ctx.user);
* // => { id: 17, name: "Alex" }
* }
* );
* ```
*
* ### Nested routers
*
* Nesting routers is supported:
*
* ```javascript
* var forums = new Router();
* var posts = new Router();
*
* posts.get('/', (ctx, next) => {...});
* posts.get('/:pid', (ctx, next) => {...});
* forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
*
* // responds to "/forums/123/posts" and "/forums/123/posts/123"
* app.use(forums.routes());
* ```
*
* #### Router prefixes
*
* Route paths can be prefixed at the router level:
*
* ```javascript
* var router = new Router({
* prefix: '/users'
* });
*
* router.get('/', ...); // responds to "/users"
* router.get('/:id', ...); // responds to "/users/:id"
* ```
*
* #### URL parameters
*
* Named route parameters are captured and added to `ctx.params`.
*
* ```javascript
* router.get('/:category/:title', (ctx, next) => {
* console.log(ctx.params);
* // => { category: 'programming', title: 'how-to-node' }
* });
* ```
*
* The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
* used to convert paths to regular expressions.
*
*/
verb(method, nameOrPath, pathOrMiddleware, ...middleware) {
const { options, path, middlewares } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
if (typeof method === 'string') {
method = [method];
}
this.register(path, method, middlewares, options);
return this;
}
all(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb(methods, nameOrPath, pathOrMiddleware, ...middlewares);
}
acl(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('acl', nameOrPath, pathOrMiddleware, ...middlewares);
}
bind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('bind', nameOrPath, pathOrMiddleware, ...middlewares);
}
checkout(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('checkout', nameOrPath, pathOrMiddleware, ...middlewares);
}
connect(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('connect', nameOrPath, pathOrMiddleware, ...middlewares);
}
copy(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('copy', nameOrPath, pathOrMiddleware, ...middlewares);
}
delete(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
del(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
get(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares);
}
query(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('query', nameOrPath, pathOrMiddleware, ...middlewares);
}
head(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares);
}
link(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('link', nameOrPath, pathOrMiddleware, ...middlewares);
}
lock(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('lock', nameOrPath, pathOrMiddleware, ...middlewares);
}
['m-search'](nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('m-search', nameOrPath, pathOrMiddleware, ...middlewares);
}
merge(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('merge', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkactivity(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('mkactivity', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkcalendar(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('mkcalendar', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkcol(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('mkcol', nameOrPath, pathOrMiddleware, ...middlewares);
}
move(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('move', nameOrPath, pathOrMiddleware, ...middlewares);
}
notify(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('notify', nameOrPath, pathOrMiddleware, ...middlewares);
}
options(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares);
}
patch(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares);
}
post(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares);
}
propfind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('propfind', nameOrPath, pathOrMiddleware, ...middlewares);
}
proppatch(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('proppatch', nameOrPath, pathOrMiddleware, ...middlewares);
}
purge(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('purge', nameOrPath, pathOrMiddleware, ...middlewares);
}
put(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares);
}
rebind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('rebind', nameOrPath, pathOrMiddleware, ...middlewares);
}
report(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('report', nameOrPath, pathOrMiddleware, ...middlewares);
}
search(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('search', nameOrPath, pathOrMiddleware, ...middlewares);
}
source(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('source', nameOrPath, pathOrMiddleware, ...middlewares);
}
subscribe(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('subscribe', nameOrPath, pathOrMiddleware, ...middlewares);
}
trace(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('trace', nameOrPath, pathOrMiddleware, ...middlewares);
}
unbind(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unbind', nameOrPath, pathOrMiddleware, ...middlewares);
}
unlink(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unlink', nameOrPath, pathOrMiddleware, ...middlewares);
}
unlock(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unlock', nameOrPath, pathOrMiddleware, ...middlewares);
}
unsubscribe(nameOrPath, pathOrMiddleware, ...middlewares) {
return this.verb('unsubscribe', nameOrPath, pathOrMiddleware, ...middlewares);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ2pDLE9BQU8sT0FBTyxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLFNBQVMsTUFBTSxhQUFhLENBQUM7QUFDcEMsT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxLQUFLLEVBQW1CLE1BQU0sWUFBWSxDQUFDO0FBR3BELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBb0M1QyxNQUFNLE9BQU8sTUFBTTtJQUNSLElBQUksQ0FBZ0I7SUFDcEIsT0FBTyxDQUFXO0lBQzNCLGtCQUFrQjtJQUNULEtBQUssR0FBWSxFQUFFLENBQUM7SUFDcEIsTUFBTSxHQUF3QyxFQUFFLENBQUM7SUFFMUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQTJCRztJQUNILFlBQVksSUFBb0I7UUFDOUIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUk7WUFDbEMsTUFBTTtZQUNOLFNBQVM7WUFDVCxLQUFLO1lBQ0wsS0FBSztZQUNMLE9BQU87WUFDUCxNQUFNO1lBQ04sUUFBUTtTQUNULENBQUM7SUFDSixDQUFDO0lBZ0NELEdBQUcsQ0FBQyxnQkFBb0QsRUFBRSxHQUFHLFdBQTZCO1FBQ3hGLHlCQUF5QjtRQUN6Qiw2QkFBNkI7UUFDN0IsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLElBQUksT0FBTyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMv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
export type Next = () => Promise<void>;
export type MiddlewareFunc = (ctx: any, next: Next) => Promise<void> | void;
export type MiddlewareFuncWithParamProperty = MiddlewareFunc & {
param?: string;
};
export type ParamMiddlewareFunc = (param: string, ctx: any, next: Next) => Promise<void> | void;
export type MiddlewareFuncWithRouter<T> = MiddlewareFunc & {
router: T;
};
export interface ResourcesController {
index?: MiddlewareFunc;
new?: MiddlewareFunc;
create?: MiddlewareFunc;
show?: MiddlewareFunc;
edit?: MiddlewareFunc;
update?: MiddlewareFunc;
destroy?: MiddlewareFunc;
}
export {};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
import assert from 'node:assert';
import { encodeURIComponent as safeEncodeURIComponent } from 'utility';
import inflection from 'inflection';
import methods from 'methods';
import { RegisterOptions, Router, RouterMethod, RouterOptions } from './Router.js';
import { MiddlewareFunc, ResourcesController } from './types.js';
interface RestfulOptions {
suffix?: string;
namePrefix?: string;
method: string | string[];
member?: true;
}
const REST_MAP: Record<string, RestfulOptions> = {
index: {
suffix: '',
method: 'GET',
},
new: {
namePrefix: 'new_',
member: true,
suffix: 'new',
method: 'GET',
},
create: {
suffix: '',
method: 'POST',
},
show: {
member: true,
suffix: ':id',
method: 'GET',
},
edit: {
member: true,
namePrefix: 'edit_',
suffix: ':id/edit',
method: 'GET',
},
update: {
member: true,
namePrefix: '',
suffix: ':id',
method: [ 'PATCH', 'PUT' ],
},
destroy: {
member: true,
namePrefix: 'destroy_',
suffix: ':id',
method: 'DELETE',
},
};
interface Application {
controller: Record<string, any>;
}
/**
* FIXME: move these patch into @eggjs/router
*/
export class EggRouter extends Router {
readonly app: Application;
/**
* @class
* @param {Object} opts - Router options.
* @param {Application} app - Application object.
*/
constructor(opts: RouterOptions, app: Application) {
super(opts);
this.app = app;
}
verb(method: RouterMethod | RouterMethod[],
nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middleware: (MiddlewareFunc | string)[]) {
const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
if (typeof method === 'string') {
method = [ method ];
}
this.register(path, method, middlewares, options);
return this;
}
// const METHODS = [ 'head', 'options', 'get', 'put', 'patch', 'post', 'delete', 'all' ];
head(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
head(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares);
}
options(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
options(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares);
}
get(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
get(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares);
}
put(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
put(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares);
}
patch(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
patch(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares);
}
post(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
post(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares);
}
delete(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
delete(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
all(path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: (MiddlewareFunc | string)[]): Router;
all(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: (MiddlewareFunc | string)[]): Router {
return this.verb(methods, nameOrPath, pathOrMiddleware, ...middlewares);
}
register(path: string | RegExp | (string | RegExp)[],
methods: string[],
middleware: MiddlewareFunc | string | (MiddlewareFunc | string | ResourcesController)[],
opts?: RegisterOptions) {
// patch register to support generator function middleware and string controller
middleware = Array.isArray(middleware) ? middleware : [ middleware ];
const middlewares = convertMiddlewares(middleware, this.app);
return super.register(path, methods, middlewares, opts);
}
/**
* restful router api
* @param {String} name - Router name
* @param {String} prefix - url prefix
* @param {Function} middleware - middleware or controller
* @example
* ```js
* app.resources('/posts', 'posts')
* app.resources('posts', '/posts', 'posts')
* app.resources('posts', '/posts', app.role.can('user'), app.controller.posts)
* ```
*
* Examples:
*
* ```js
* app.resources('/posts', 'posts')
* ```
*
* yield router mapping
*
* Method | Path | Route Name | Controller.Action
* -------|-----------------|----------------|-----------------------------
* GET | /posts | posts | app.controller.posts.index
* GET | /posts/new | new_post | app.controller.posts.new
* GET | /posts/:id | post | app.controller.posts.show
* GET | /posts/:id/edit | edit_post | app.controller.posts.edit
* POST | /posts | posts | app.controller.posts.create
* PATCH | /posts/:id | post | app.controller.posts.update
* DELETE | /posts/:id | post | app.controller.posts.destroy
*
* app.router.url can generate url based on arguments
* ```js
* app.router.url('posts')
* => /posts
* app.router.url('post', { id: 1 })
* => /posts/1
* app.router.url('new_post')
* => /posts/new
* app.router.url('edit_post', { id: 1 })
* => /posts/1/edit
* ```
* @return {Router} return route object.
* @since 1.0.0
*/
resources(prefix: string, controller: string | ResourcesController): Router;
resources(prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
resources(name: string, prefix: string, controller: string | ResourcesController): Router;
resources(name: string, prefix: string, middleware: MiddlewareFunc, controller: string | ResourcesController): Router;
resources(nameOrPath: string | RegExp, pathOrMiddleware: string | RegExp | MiddlewareFunc | ResourcesController,
...middleware: (MiddlewareFunc | string | ResourcesController)[]): Router {
const { path, middlewares, options } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
// last argument is Controller object
const controller = resolveController(middlewares.pop()!, this.app);
for (const key in REST_MAP) {
const action = controller[key] as MiddlewareFunc;
if (!action) continue;
const opts = REST_MAP[key];
let routeName;
if (opts.member) {
routeName = inflection.singularize(options.name ?? '');
} else {
routeName = inflection.pluralize(options.name ?? '');
}
if (opts.namePrefix) {
routeName = opts.namePrefix + routeName;
}
const prefix = (path as string).replace(/\/$/, '');
const urlPath = opts.suffix ? `${prefix}/${opts.suffix}` : prefix;
const method = Array.isArray(opts.method) ? opts.method : [ opts.method ];
this.register(urlPath, method, middlewares.concat(action), { name: routeName });
}
return this;
}
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name: string, params?: Record<string, string | number | (string | number)[]>): string {
const route = this.route(name);
if (!route) return '';
const args = params;
let url = route.path;
assert(!(url instanceof RegExp), `Can't get the url for regExp ${url} for by name '${name}'`);
const queries = [];
if (typeof args === 'object' && args !== null) {
const replacedParams: string[] = [];
url = url.replace(/:([a-zA-Z_]\w*)/g, ($0, key) => {
if (key in args) {
const values = args[key];
replacedParams.push(key);
return safeEncodeURIComponent(Array.isArray(values) ? String(values[0]) : String(values));
}
return $0;
});
for (const key in args) {
if (replacedParams.includes(key)) {
continue;
}
const values = args[key];
const encodedKey = safeEncodeURIComponent(key);
if (Array.isArray(values)) {
for (const val of values) {
queries.push(`${encodedKey}=${safeEncodeURIComponent(String(val))}`);
}
} else {
queries.push(`${encodedKey}=${safeEncodeURIComponent(String(values))}`);
}
}
}
if (queries.length > 0) {
const queryStr = queries.join('&');
if (!url.includes('?')) {
url = `${url}?${queryStr}`;
} else {
url = `${url}&${queryStr}`;
}
}
return url;
}
/**
* @alias to url()
*/
pathFor(name: string, params?: Record<string, string | number | (string | number)[]>) {
return this.url(name, params);
}
}
/**
* resolve controller from string to function
* @param {String|Function} controller input controller
* @param {Application} app egg application instance
*/
function resolveController(controller: string | MiddlewareFunc | ResourcesController, app: Application) {
if (typeof controller === 'string') {
// resolveController('foo.bar.Home', app)
const actions = controller.split('.');
let obj = app.controller;
actions.forEach(key => {
obj = obj[key];
if (!obj) throw new Error(`app.controller.${controller} not exists`);
});
controller = obj as any;
}
// ensure controller is exists
if (!controller) throw new Error('controller not exists');
return controller as any;
}
/**
* 1. ensure controller(last argument) support string
* - [url, controller]: app.get('/home', 'home');
* - [name, url, controller(string)]: app.get('posts', '/posts', 'posts.list');
* - [name, url, controller]: app.get('posts', '/posts', app.controller.posts.list);
* - [name, url(regexp), controller]: app.get('regRouter', /\/home\/index/, 'home.index');
* - [name, url, middleware, [...], controller]: `app.get(/user/:id', hasLogin, canGetUser, 'user.show');`
*
* 2. make middleware support generator function
*
* @param {Array} middlewares middlewares and controller(last middleware)
* @param {Application} app egg application instance
*/
function convertMiddlewares(middlewares: (MiddlewareFunc | string | ResourcesController)[], app: Application) {
// ensure controller is resolved
const controller = resolveController(middlewares.pop()!, app);
return [ ...middlewares as MiddlewareFunc[], controller ];
}
import { Router } from './Router.js';
export * from './Router.js';
export * from './EggRouter.js';
export const KoaRouter = Router;
export default Router;
import { debuglog } from 'node:util';
import pathToRegExp, { type Key } from 'path-to-regexp';
import URI from 'urijs';
import { decodeURIComponent as safeDecodeURIComponent } from 'utility';
import { isGeneratorFunction } from 'is-type-of';
import type {
MiddlewareFunc,
MiddlewareFuncWithParamProperty,
ParamMiddlewareFunc,
} from './types.js';
const debug = debuglog('egg-router:layer');
export interface LayerOptions {
prefix?: string;
/** route name */
name?: string;
/** case sensitive (default: false) */
sensitive?: boolean;
/** require the trailing slash (default: false) */
strict?: boolean;
ignoreCaptures?: boolean;
end?: boolean;
}
export interface LayerURLOptions {
query?: string | object;
}
export class Layer {
readonly opts: LayerOptions;
readonly name?: string;
readonly methods: string[] = [];
readonly stack: MiddlewareFuncWithParamProperty[];
path: string | RegExp;
regexp: RegExp;
paramNames: Key[] = [];
/**
* Initialize a new routing Layer with given `method`, `path`, and `middleware`.
*
* @param {String|RegExp} path Path string or regular expression.
* @param {Array} methods Array of HTTP verbs.
* @param {Array|Function} middlewares Layer callback/middleware or series of.
* @param {Object=} opts optional params
* @param {String=} opts.name route name
* @param {String=} opts.sensitive case sensitive (default: false)
* @param {String=} opts.strict require the trailing slash (default: false)
* @private
*/
constructor(path: string | RegExp, methods: string[], middlewares: MiddlewareFunc | MiddlewareFunc[],
opts?: LayerOptions | string) {
if (typeof opts === 'string') {
// new Layer(path, methods, middlewares, name);
opts = { name: opts };
}
this.opts = opts ?? {};
this.opts.prefix = this.opts.prefix ?? '';
this.name = this.opts.name;
this.stack = Array.isArray(middlewares) ? middlewares : [ middlewares ];
for (const method of methods) {
const l = this.methods.push(method.toUpperCase());
if (this.methods[l - 1] === 'GET') {
this.methods.unshift('HEAD');
}
}
// ensure middleware is a function
this.stack.forEach(fn => {
const type = typeof fn;
if (type !== 'function') {
throw new TypeError(
methods.toString() + ' `' + (this.opts.name || path) + '`: `middleware` '
+ 'must be a function, not `' + type + '`',
);
}
if (isGeneratorFunction(fn)) {
throw new TypeError(
methods.toString() + ' `' + (this.opts.name || path) + '`: Please use async function instead of generator function',
);
}
});
this.path = path;
this.regexp = pathToRegExp(path, this.paramNames, this.opts);
debug('defined route %s %s', this.methods, this.opts.prefix + this.path);
}
/**
* Returns whether request `path` matches route.
*
* @param {String} path path string
* @return {Boolean} matched or not
* @private
*/
match(path: string): boolean {
return this.regexp.test(path);
}
/**
* Returns map of URL parameters for given `path` and `paramNames`.
*
* @param {String} _path path string
* @param {Array.<String>} captures captures strings
* @param {Object=} [existingParams] existing params
* @return {Object} params object
* @private
*/
params(_path: string, captures: Array<string>, existingParams?: Record<string, string>): Record<string, string> {
const params = existingParams ?? {};
for (let len = captures.length, i = 0; i < len; i++) {
const paramName = this.paramNames[i];
if (paramName) {
const c = captures[i];
params[paramName.name] = c ? safeDecodeURIComponent(c) : c;
}
}
return params;
}
/**
* Returns array of regexp url path captures.
*
* @param {String} path path string
* @return {Array.<String>} captures strings
* @private
*/
captures(path: string): Array<string> {
if (this.opts.ignoreCaptures) return [];
const m = path.match(this.regexp);
return m ? m.slice(1) : [];
}
/**
* Generate URL for route using given `params`.
*
* @example
*
* ```javascript
* var route = new Layer(['GET'], '/users/:id', fn);
*
* route.url(123); // => "/users/123"
* route.url('123'); // => "/users/123"
* route.url({ id: 123 }); // => "/users/123"
* ```
*
* @param {Object} params url parameters
* @param {Object} paramsOrOptions optional parameters
* @return {String} url string
* @private
*/
url(params?: string | number | object, ...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string {
let args: Array<string | number | object> | object = params as object;
const url = (this.path as string).replace(/\(\.\*\)/g, '');
const toPath = pathToRegExp.compile(url);
let options: LayerURLOptions | undefined;
if (params !== undefined && typeof params !== 'object') {
args = [ params, ...paramsOrOptions ];
// route.url(stringOrNumber, params1, ..., options);
if (Array.isArray(args)) {
const lastIndex = args.length - 1;
if (typeof args[lastIndex] === 'object') {
options = args[lastIndex];
args = args.slice(0, lastIndex);
}
}
} else if (typeof params === 'object') {
if (typeof paramsOrOptions[0] === 'object' && 'query' in paramsOrOptions[0]) {
// route.url(param, options);
options = paramsOrOptions[0];
}
}
const tokens = pathToRegExp.parse(url);
let replace: Record<string, any> = {};
if (Array.isArray(args)) {
for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
const token = tokens[i];
if (typeof token === 'object' && token.name) {
replace[token.name] = args[j++];
}
}
} else if (tokens.some(token => typeof token === 'object' && token.name)) {
// route.url(params);
replace = params as object;
} else {
// route.url(options);
options = params as LayerURLOptions;
}
const replaced = toPath(replace);
if (options?.query) {
const urlObject = new URI(replaced);
urlObject.search(options.query);
return urlObject.toString();
}
return replaced;
}
/**
* Run validations on route named parameters.
*
* @example
*
* ```javascript
* router
* .param('user', function (id, ctx, next) {
* ctx.user = users[id];
* if (!user) return ctx.status = 404;
* next();
* })
* .get('/users/:user', function (ctx, next) {
* ctx.body = ctx.user;
* });
* ```
*
* @param {String} param param string
* @param {Function} fn middleware function
* @return {Layer} layer instance
* @private
*/
param(param: string, fn: ParamMiddlewareFunc): Layer {
const stack = this.stack;
const params = this.paramNames;
const middleware: MiddlewareFuncWithParamProperty = function(this: any, ctx, next) {
return fn.call(this, ctx.params[param], ctx, next);
};
middleware.param = param;
const names = params.map(p => {
return p.name;
});
const x = names.indexOf(param);
if (x > -1) {
// iterate through the stack, to figure out where to place the handler fn
stack.some(function(fn, i) {
// param handlers are always first, so when we find an fn w/o a param property, stop here
// if the param handler at this part of the stack comes after the one we are adding, stop here
if (!fn.param || names.indexOf(fn.param) > x) {
// inject this param handler right before the current item
stack.splice(i, 0, middleware);
return true; // then break the loop
}
return false;
});
}
return this;
}
/**
* Prefix route path.
*
* @param {String} prefix prefix string
* @return {Layer} layer instance
* @private
*/
setPrefix(prefix: string): Layer {
if (this.path) {
this.path = prefix + this.path;
this.paramNames = [];
this.regexp = pathToRegExp(this.path, this.paramNames, this.opts);
}
return this;
}
}
/**
* RESTful resource routing middleware for eggjs.
*/
import { debuglog } from 'node:util';
import assert from 'node:assert';
import compose from 'koa-compose';
import HttpError from 'http-errors';
import methods from 'methods';
import { Layer, LayerURLOptions } from './Layer.js';
import { MiddlewareFunc, MiddlewareFuncWithRouter, Next, ParamMiddlewareFunc, ResourcesController } from './types.js';
const debug = debuglog('egg-router:router');
export type RouterMethod = typeof methods[0];
export interface RouterOptions {
methods?: string[];
prefix?: string;
sensitive?: boolean;
strict?: boolean;
routerPath?: string;
}
export interface RegisterOptions {
name?: string;
prefix?: string;
sensitive?: boolean;
strict?: boolean;
ignoreCaptures?: boolean;
end?: boolean;
}
export interface AllowedMethodsOptions {
throw?: boolean;
notImplemented?: () => Error;
methodNotAllowed?: () => Error;
}
export interface MatchedResult {
// matched path
path: Layer[];
// matched path and method(including none method)
pathAndMethod: Layer[];
// method matched or not
route: boolean;
}
export class Router {
readonly opts: RouterOptions;
readonly methods: string[];
/** Layer stack */
readonly stack: Layer[] = [];
readonly params: Record<string, ParamMiddlewareFunc> = {};
/**
* Create a new router.
*
* @example
*
* Basic usage:
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* router.get('/', (ctx, next) => {
* // ctx.router available
* });
*
* app
* .use(router.routes())
* .use(router.allowedMethods());
* ```
*
* @alias module:koa-router
* @param {Object=} opts optional
* @param {String=} opts.prefix prefix router paths
* @class
*/
constructor(opts?: RouterOptions) {
this.opts = opts ?? {};
this.methods = this.opts.methods ?? [
'HEAD',
'OPTIONS',
'GET',
'PUT',
'PATCH',
'POST',
'DELETE',
];
}
/**
* Use given middleware.
*
* Middleware run in the order they are defined by `.use()`. They are invoked
* sequentially, requests start at the first middleware and work their way
* "down" the middleware stack.
*
* @example
*
* ```javascript
* // session middleware will run before authorize
* router
* .use(session())
* .use(authorize());
*
* // use middleware only with given path
* router.use('/users', userAuth());
*
* // or with an array of paths
* router.use(['/users', '/admin'], userAuth());
*
* app.use(router.routes());
* ```
*
* @param {String=} path path string
* @param {Function} middleware middleware function
* @return {Router} router instance
*/
use(...middlewares: MiddlewareFunc[]): Router;
use(path: string | string[], ...middlewares: MiddlewareFunc[]): Router;
use(pathOrMiddleware: string | string[] | MiddlewareFunc, ...middlewares: MiddlewareFunc[]): Router {
// support array of paths
// use(paths, ...middlewares)
if (Array.isArray(pathOrMiddleware) && typeof pathOrMiddleware[0] === 'string') {
for (const path of pathOrMiddleware) {
this.use(path, ...middlewares);
}
return this;
}
let path = '';
let hasPath = false;
if (typeof pathOrMiddleware === 'string') {
// use(path, ...middlewares)
path = pathOrMiddleware;
hasPath = true;
} else if (typeof pathOrMiddleware === 'function') {
// use(...middlewares)
middlewares = [ pathOrMiddleware, ...middlewares ];
}
for (const m of middlewares as MiddlewareFuncWithRouter<Router>[]) {
if (m.router) {
for (const nestedLayer of m.router.stack) {
if (path) {
nestedLayer.setPrefix(path);
}
if (this.opts.prefix) {
nestedLayer.setPrefix(this.opts.prefix);
}
this.stack.push(nestedLayer);
}
if (this.params) {
for (const key in this.params) {
m.router.param(key, this.params[key]);
}
}
} else {
this.register(path || '(.*)', [], m, { end: false, ignoreCaptures: !hasPath });
}
}
return this;
}
/**
* Set the path prefix for a Router instance that was already initialized.
*
* @example
*
* ```javascript
* router.prefix('/things/:thing_id')
* ```
*
* @param {String} prefix prefix string
* @return {Router} router instance
*/
prefix(prefix: string): Router {
prefix = prefix.replace(/\/$/, '');
this.opts.prefix = prefix;
for (const layer of this.stack) {
layer.setPrefix(prefix);
}
return this;
}
/**
* Returns router middleware which dispatches a route matching the request.
*
* @return {Function} middleware function
*/
routes(): MiddlewareFuncWithRouter<Router> {
const dispatch = (ctx: any, next: Next) => {
const routerPath: string = this.opts.routerPath || ctx.routerPath || ctx.path;
const matched = this.match(routerPath, ctx.method);
debug('dispatch: %s %s, routerPath: %s, matched: %s',
ctx.method, ctx.path, routerPath, matched.route);
if (ctx.matched) {
(ctx.matched as Layer[]).push(...matched.path);
} else {
ctx.matched = matched.path;
}
ctx.router = this;
if (!matched.route) {
return next();
}
const matchedLayers = matched.pathAndMethod;
const layerChain = matchedLayers.reduce<MiddlewareFunc[]>((memo, layer) => {
memo.push((ctx, next) => {
// ctx.captures = layer.captures(routerPath, ctx.captures);
ctx.captures = layer.captures(routerPath);
ctx.params = layer.params(routerPath, ctx.captures, ctx.params);
// ctx._matchedRouteName & ctx._matchedRoute for compatibility
ctx._matchedRouteName = ctx.routerName = layer.name;
if (!layer.name) {
ctx._matchedRouteName = undefined;
}
ctx._matchedRoute = ctx.routerPath = layer.path;
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
};
dispatch.router = this;
return dispatch;
}
/**
* @alias to routes()
*/
middleware() {
return this.routes();
}
/**
* Returns separate middleware for responding to `OPTIONS` requests with
* an `Allow` header containing the allowed methods, as well as responding
* with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
*
* @example
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods());
* ```
*
* **Example with [Boom](https://github.com/hapijs/boom)**
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
* var Boom = require('boom');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods({
* throw: true,
* notImplemented: () => new Boom.notImplemented(),
* methodNotAllowed: () => new Boom.methodNotAllowed()
* }));
* ```
*
* @param {Object=} options optional params
* @param {Boolean=} options.throw throw error instead of setting status and header
* @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
* @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
* @return {Function} middleware function
*/
allowedMethods(options?: AllowedMethodsOptions): MiddlewareFunc {
const implemented = this.methods;
return async function allowedMethods(ctx: any, next: Next) {
await next();
if (ctx.status && ctx.status !== 404) return;
const allowed: Record<string, string> = {};
ctx.matched.forEach((route: Router) => {
route.methods.forEach(method => {
allowed[method] = method;
});
});
const allowedMethods = Object.keys(allowed);
if (!implemented.includes(ctx.method)) {
if (options?.throw) {
let notImplementedThrowable: Error;
if (typeof options?.notImplemented === 'function') {
notImplementedThrowable = options.notImplemented(); // set whatever the user returns from their function
} else {
notImplementedThrowable = new HttpError.NotImplemented();
}
throw notImplementedThrowable;
} else {
ctx.status = 501;
ctx.set('Allow', allowedMethods.join(', '));
}
} else if (allowedMethods.length > 0) {
if (ctx.method === 'OPTIONS') {
ctx.status = 200;
ctx.body = '';
ctx.set('Allow', allowedMethods.join(', '));
} else if (!allowed[ctx.method]) {
if (options?.throw) {
let notAllowedThrowable: Error;
if (typeof options?.methodNotAllowed === 'function') {
notAllowedThrowable = options.methodNotAllowed(); // set whatever the user returns from their function
} else {
notAllowedThrowable = new HttpError.MethodNotAllowed();
}
throw notAllowedThrowable;
} else {
ctx.status = 405;
ctx.set('Allow', allowedMethods.join(', '));
}
}
}
};
}
/**
* Redirect `source` to `destination` URL with optional 30x status `code`.
*
* Both `source` and `destination` can be route names.
*
* ```javascript
* router.redirect('/login', 'sign-in');
* ```
*
* This is equivalent to:
*
* ```javascript
* router.all('/login', ctx => {
* ctx.redirect('/sign-in');
* ctx.status = 301;
* });
* ```
*
* @param {String} source URL or route name.
* @param {String} destination URL or route name.
* @param {Number=} status HTTP status code (default: 301).
* @return {Router} router instance
*/
redirect(source: string, destination: string, status: number = 301): Router {
// lookup source route by name
if (source[0] !== '/') {
const routeUrl = this.url(source);
if (routeUrl instanceof Error) {
throw routeUrl;
}
source = routeUrl;
}
// lookup destination route by name
if (destination[0] !== '/') {
const routeUrl = this.url(destination);
if (routeUrl instanceof Error) {
throw routeUrl;
}
destination = routeUrl;
}
return this.all(source, ctx => {
ctx.redirect(destination);
ctx.status = status;
});
}
/**
* Create and register a route.
*
* @param {String|RegExp|(String|RegExp)[]} path Path string.
* @param {String[]} methods Array of HTTP verbs.
* @param {Function|Function[]} middleware Multiple middleware also accepted.
* @param {Object} [opts] optional params
* @private
*/
register(path: string | RegExp | (string | RegExp)[],
methods: string[],
middleware: MiddlewareFunc | MiddlewareFunc[],
opts?: RegisterOptions): Layer | Layer[] {
// support array of paths
if (Array.isArray(path)) {
const routes: Layer[] = [];
for (const p of path) {
const route = this.#register(p, methods, middleware, opts);
routes.push(route);
}
return routes;
}
// create route
const route = this.#register(path, methods, middleware, opts);
return route;
}
#register(path: string | RegExp,
methods: string[],
middleware: MiddlewareFunc | MiddlewareFunc[],
opts?: RegisterOptions): Layer {
opts = opts ?? {};
// create route
const route = new Layer(path, methods, middleware, {
end: opts.end === false ? opts.end : true,
name: opts.name,
sensitive: opts.sensitive ?? this.opts.sensitive ?? false,
strict: opts.strict ?? this.opts.strict ?? false,
prefix: opts.prefix ?? this.opts.prefix ?? '',
ignoreCaptures: opts.ignoreCaptures,
});
// FIXME: why???
if (this.opts.prefix) {
route.setPrefix(this.opts.prefix);
}
// add parameter middleware to the new route layer
for (const param in this.params) {
route.param(param, this.params[param]);
}
this.stack.push(route);
return route;
}
/**
* Lookup route with given `name`.
*
* @param {String} name route name
* @return {Layer|false} layer instance of false
*/
route(name: string): Layer | false {
for (const route of this.stack) {
if (route.name === name) {
return route;
}
}
return false;
}
/**
* Generate URL for route. Takes a route name and map of named `params`.
*
* @example
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
*
* router.url('user', { id: 3 });
* // => "/users/3"
*
* router.use((ctx, next) => {
* // redirect to named route
* ctx.redirect(ctx.router.url('sign-in'));
* })
*
* router.url('user', { id: 3 }, { query: { limit: 1 } });
* // => "/users/3?limit=1"
*
* router.url('user', { id: 3 }, { query: "limit=1" });
* // => "/users/3?limit=1"
* ```
*/
url(name: string, params?: string | number | object,
...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string | Error {
const route = this.route(name);
if (route) {
return route.url(params, ...paramsOrOptions);
}
return new Error(`No route found for name: ${name}`);
}
/**
* Generate URL from url pattern and given `params`.
*
* @example
*
* ```javascript
* var url = Router.url('/users/:id', { id: 1 });
* // => "/users/1"
* ```
*
* @param {String} path url pattern
* @param {Object} params url parameters
* @return {String} url string
*/
static url(path: string, params?: string | number | object,
...paramsOrOptions: (string | number | object | LayerURLOptions)[]): string {
return Layer.prototype.url.call({ path }, params, ...paramsOrOptions);
}
/**
* Match given `path` and return corresponding routes.
*
* @param {String} path path string
* @param {String} method method name
* @return {Object.<path, pathAndMethod>} returns layers that matched path and
* path and method.
* @private
*/
match(path: string, method: string): MatchedResult {
const matched: MatchedResult = {
// matched path
path: [],
// matched path and method(including none method)
pathAndMethod: [],
// method matched or not
route: false,
};
for (const layer of this.stack) {
debug('test %s %s', layer.path, layer.regexp);
if (layer.match(path)) {
matched.path.push(layer);
if (layer.methods.length === 0 || layer.methods.includes(method)) {
matched.pathAndMethod.push(layer);
if (layer.methods.length > 0) {
matched.route = true;
}
}
// if (layer.methods.length === 0) {
// matched.pathAndMethod.push(layer);
// } else if (layer.methods.includes(method)) {
// matched.pathAndMethod.push(layer);
// matched.route = true;
// }
}
}
return matched;
}
/**
* Run middleware for named route parameters. Useful for auto-loading or
* validation.
*
* @example
*
* ```javascript
* router
* .param('user', (id, ctx, next) => {
* ctx.user = users[id];
* if (!ctx.user) return ctx.status = 404;
* return next();
* })
* .get('/users/:user', ctx => {
* ctx.body = ctx.user;
* })
* .get('/users/:user/friends', ctx => {
* return ctx.user.getFriends().then(function(friends) {
* ctx.body = friends;
* });
* })
* // /users/3 => {"id": 3, "name": "Alex"}
* // /users/3/friends => [{"id": 4, "name": "TJ"}]
* ```
*
* @param {String} param param
* @param {Function} middleware route middleware
* @return {Router} instance
*/
param(param: string, middleware: ParamMiddlewareFunc): Router {
this.params[param] = middleware;
for (const route of this.stack) {
route.param(param, middleware);
}
return this;
}
protected _formatRouteParams(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc | ResourcesController,
middlewares: (MiddlewareFunc | string | ResourcesController)[]) {
const options: RegisterOptions = {};
let path: string | RegExp | (string | RegExp)[];
if (typeof pathOrMiddleware === 'string' || pathOrMiddleware instanceof RegExp) {
// verb(method, name, path, ...middlewares)
path = pathOrMiddleware;
assert(typeof nameOrPath === 'string', 'route name should be string');
options.name = nameOrPath;
} else if (Array.isArray(pathOrMiddleware)) {
// verb(method, name, paths, ...middlewares)
path = pathOrMiddleware;
assert(typeof nameOrPath === 'string', 'route name should be string');
options.name = nameOrPath;
} else {
// verb(method, path, ...middlewares)
path = nameOrPath;
middlewares = [ pathOrMiddleware, ...middlewares ];
}
return {
path,
middlewares,
options,
};
}
/**
* Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
* as `router.get()` or `router.post()`.
*
* Match URL patterns to callback functions or controller actions using `router.verb()`,
* where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
*
* Additionally, `router.all()` can be used to match against all methods.
*
* ```javascript
* router
* .get('/', (ctx, next) => {
* ctx.body = 'Hello World!';
* })
* .post('/users', (ctx, next) => {
* // ...
* })
* .put('/users/:id', (ctx, next) => {
* // ...
* })
* .del('/users/:id', (ctx, next) => {
* // ...
* })
* .all('/users/:id', (ctx, next) => {
* // ...
* });
* ```
*
* When a route is matched, its path is available at `ctx._matchedRoute` and if named,
* the name is available at `ctx._matchedRouteName`
*
* Route paths will be translated to regular expressions using
* [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
*
* Query strings will not be considered when matching requests.
*
* #### Named routes
*
* Routes can optionally have names. This allows generation of URLs and easy
* renaming of URLs during development.
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
* ```
*
* #### Multiple middleware
*
* Multiple middleware may be given:
*
* ```javascript
* router.get(
* '/users/:id',
* (ctx, next) => {
* return User.findOne(ctx.params.id).then(function(user) {
* ctx.user = user;
* next();
* });
* },
* ctx => {
* console.log(ctx.user);
* // => { id: 17, name: "Alex" }
* }
* );
* ```
*
* ### Nested routers
*
* Nesting routers is supported:
*
* ```javascript
* var forums = new Router();
* var posts = new Router();
*
* posts.get('/', (ctx, next) => {...});
* posts.get('/:pid', (ctx, next) => {...});
* forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
*
* // responds to "/forums/123/posts" and "/forums/123/posts/123"
* app.use(forums.routes());
* ```
*
* #### Router prefixes
*
* Route paths can be prefixed at the router level:
*
* ```javascript
* var router = new Router({
* prefix: '/users'
* });
*
* router.get('/', ...); // responds to "/users"
* router.get('/:id', ...); // responds to "/users/:id"
* ```
*
* #### URL parameters
*
* Named route parameters are captured and added to `ctx.params`.
*
* ```javascript
* router.get('/:category/:title', (ctx, next) => {
* console.log(ctx.params);
* // => { category: 'programming', title: 'how-to-node' }
* });
* ```
*
* The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
* used to convert paths to regular expressions.
*
*/
verb(method: string | string[],
nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middleware: MiddlewareFunc[]): Router {
const { options, path, middlewares } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware);
if (typeof method === 'string') {
method = [ method ];
}
this.register(path, method, middlewares as MiddlewareFunc[], options);
return this;
}
/**
* Register route with all methods.
*
* @param {String} name Optional.
* @param {String} path path string
* @param {Function=} middleware You may also pass multiple middleware.
* @return {Router} router instance
* @private
*/
all(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
all(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
all(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb(methods, nameOrPath, pathOrMiddleware, ...middlewares);
}
// "acl", "bind", "checkout", "connect", "copy", "delete", "get", "head", "link", "lock",
// "m-search", "merge", "mkactivity", "mkcalendar", "mkcol", "move", "notify", "options",
// "patch", "post", "propfind", "proppatch", "purge", "put", "rebind", "report", "search",
// "source", "subscribe", "trace", "unbind", "unlink", "unlock", "unsubscribe"
acl(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
acl(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
acl(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('acl', nameOrPath, pathOrMiddleware, ...middlewares);
}
bind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
bind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
bind(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('bind', nameOrPath, pathOrMiddleware, ...middlewares);
}
checkout(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
checkout(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
checkout(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('checkout', nameOrPath, pathOrMiddleware, ...middlewares);
}
connect(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
connect(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
connect(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('connect', nameOrPath, pathOrMiddleware, ...middlewares);
}
copy(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
copy(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
copy(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('copy', nameOrPath, pathOrMiddleware, ...middlewares);
}
delete(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
delete(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
delete(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
/** Alias for `router.delete()` because delete is a reserved word */
del(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
del(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
del(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares);
}
get(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
get(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
get(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares);
}
query(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
query(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
query(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('query', nameOrPath, pathOrMiddleware, ...middlewares);
}
head(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
head(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
head(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares);
}
link(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
link(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
link(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('link', nameOrPath, pathOrMiddleware, ...middlewares);
}
lock(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
lock(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
lock(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('lock', nameOrPath, pathOrMiddleware, ...middlewares);
}
['m-search'](path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
['m-search'](name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
['m-search'](nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('m-search', nameOrPath, pathOrMiddleware, ...middlewares);
}
merge(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
merge(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
merge(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('merge', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkactivity(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkactivity(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkactivity(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('mkactivity', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkcalendar(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcalendar(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcalendar(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('mkcalendar', nameOrPath, pathOrMiddleware, ...middlewares);
}
mkcol(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcol(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
mkcol(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('mkcol', nameOrPath, pathOrMiddleware, ...middlewares);
}
move(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
move(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
move(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('move', nameOrPath, pathOrMiddleware, ...middlewares);
}
notify(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
notify(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
notify(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('notify', nameOrPath, pathOrMiddleware, ...middlewares);
}
options(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
options(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
options(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares);
}
patch(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
patch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
patch(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares);
}
post(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
post(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
post(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares);
}
propfind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
propfind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
propfind(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('propfind', nameOrPath, pathOrMiddleware, ...middlewares);
}
proppatch(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
proppatch(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
proppatch(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('proppatch', nameOrPath, pathOrMiddleware, ...middlewares);
}
purge(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
purge(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
purge(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('purge', nameOrPath, pathOrMiddleware, ...middlewares);
}
put(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
put(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
put(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares);
}
rebind(path: string | RegExp, ...middlewares: MiddlewareFunc[]): Router;
rebind(name: string, path: string | RegExp, ...middlewares: MiddlewareFunc[]): Router;
rebind(nameOrPath: string | RegExp, pathOrMiddleware: string | RegExp | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('rebind', nameOrPath, pathOrMiddleware, ...middlewares);
}
report(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
report(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
report(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('report', nameOrPath, pathOrMiddleware, ...middlewares);
}
search(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
search(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
search(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('search', nameOrPath, pathOrMiddleware, ...middlewares);
}
source(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
source(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
source(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('source', nameOrPath, pathOrMiddleware, ...middlewares);
}
subscribe(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
subscribe(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
subscribe(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('subscribe', nameOrPath, pathOrMiddleware, ...middlewares);
}
trace(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
trace(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
trace(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('trace', nameOrPath, pathOrMiddleware, ...middlewares);
}
unbind(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unbind(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unbind(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('unbind', nameOrPath, pathOrMiddleware, ...middlewares);
}
unlink(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlink(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlink(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('unlink', nameOrPath, pathOrMiddleware, ...middlewares);
}
unlock(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlock(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unlock(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('unlock', nameOrPath, pathOrMiddleware, ...middlewares);
}
unsubscribe(path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unsubscribe(name: string, path: string | RegExp | (string | RegExp)[], ...middlewares: MiddlewareFunc[]): Router;
unsubscribe(nameOrPath: string | RegExp | (string | RegExp)[],
pathOrMiddleware: string | RegExp | (string | RegExp)[] | MiddlewareFunc,
...middlewares: MiddlewareFunc[]): Router {
return this.verb('unsubscribe', nameOrPath, pathOrMiddleware, ...middlewares);
}
}
export type Next = () => Promise<void>;
export type MiddlewareFunc = (ctx: any, next: Next) => Promise<void> | void;
export type MiddlewareFuncWithParamProperty = MiddlewareFunc & { param?: string };
export type ParamMiddlewareFunc = (param: string, ctx: any, next: Next) => Promise<void> | void;
export type MiddlewareFuncWithRouter<T> = MiddlewareFunc & { router: T };
export interface ResourcesController {
index?: MiddlewareFunc;
new?: MiddlewareFunc;
create?: MiddlewareFunc;
show?: MiddlewareFunc;
edit?: MiddlewareFunc;
update?: MiddlewareFunc;
destroy?: MiddlewareFunc;
}
+64
-33
{
"name": "@eggjs/router",
"version": "2.0.1",
"version": "3.0.0",
"engines": {
"node": ">= 18.7.0"
},
"publishConfig": {
"access": "public"
},
"description": "Router middleware for egg/koa. Provides RESTful resource routing.",

@@ -12,6 +18,2 @@ "repository": {

},
"files": [
"lib",
"index.js"
],
"author": "eggjs",

@@ -25,39 +27,68 @@ "keywords": [

"dependencies": {
"co": "^4.6.0",
"debug": "^3.1.0",
"http-errors": "^1.3.1",
"inflection": "^1.12.0",
"is-type-of": "^1.2.1",
"koa-compose": "^3.0.0",
"koa-convert": "^1.2.0",
"methods": "^1.0.1",
"http-errors": "^2.0.0",
"inflection": "^3.0.0",
"is-type-of": "^2.1.0",
"koa-compose": "^4.1.0",
"methods": "^1.1.2",
"path-to-regexp": "^1.1.1",
"urijs": "^1.19.0",
"utility": "^1.15.0"
"urijs": "^1.19.11",
"utility": "^2.1.0"
},
"devDependencies": {
"egg-bin": "^4.10.0",
"egg-ci": "^1.11.0",
"eslint": "^5.13.0",
"eslint-config-egg": "^7.1.0",
"expect.js": "^0.3.1",
"koa": "^2.7.0",
"mocha": "^2.0.1",
"should": "^6.0.3",
"supertest": "^1.0.1"
"@eggjs/koa": "^2.18.1",
"@eggjs/tsconfig": "^1.3.3",
"@types/koa-compose": "^3.2.8",
"@types/methods": "^1.1.4",
"@types/mocha": "^10.0.6",
"@types/supertest": "^6.0.2",
"@types/urijs": "^1.19.25",
"egg-bin": "6",
"eslint": "8",
"eslint-config-egg": "13",
"git-contributor": "^2.1.5",
"supertest": "^1.0.1",
"tshy": "^1.15.1",
"tshy-after": "^1.0.0",
"typescript": "^5.4.5"
},
"scripts": {
"lint": "eslint src test --ext ts",
"pretest": "npm run lint -- --fix && npm run prepublishOnly",
"test": "egg-bin test",
"test-local": "egg-bin test",
"test": "npm run lint && egg-bin test",
"ci": "npm run lint && egg-bin cov",
"lint": "eslint ."
"preci": "npm run lint && npm run prepublishOnly",
"ci": "egg-bin cov",
"contributor": "git-contributor",
"prepublishOnly": "tshy && tshy-after",
"bench": "cd bench && make"
},
"ci": {
"type": "github",
"version": "8, 10, 11"
"license": "MIT",
"files": [
"dist",
"src"
],
"type": "module",
"tshy": {
"exports": {
"./package.json": "./package.json",
".": "./src/index.ts"
}
},
"engines": {
"node": ">= 8"
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"source": "./src/index.ts",
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"source": "./src/index.ts",
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.js"
}
}
},
"license": "MIT"
"main": "./dist/commonjs/index.js",
"types": "./dist/commonjs/index.d.ts"
}
+90
-53

@@ -6,22 +6,28 @@ # @eggjs/router

> **This repository is a fork of [koa-router](https://github.com/alexmingoia/koa-router).** with some additional features.
> And thanks for the great work of @alexmingoia and the original team.
> And thanks for the greate work of @alexmingoia and the original team.
## API Reference
* [egg-router](#module_egg-router)
* [Router](#exp_module_egg-router--Router) ⏏
* [new Router([opts])](#new_module_egg-router--Router_new)
* _instance_
* [.get|put|post|patch|delete|del](#module_egg-router--Router+get|put|post|patch|delete|del) ⇒ <code>Router</code>
* [.routes](#module_egg-router--Router+routes) ⇒ <code>function</code>
* [.use([path], middleware)](#module_egg-router--Router+use) ⇒ <code>Router</code>
* [.prefix(prefix)](#module_egg-router--Router+prefix) ⇒ <code>Router</code>
* [.allowedMethods([options])](#module_egg-router--Router+allowedMethods) ⇒ <code>function</code>
* [.redirect(source, destination, [code])](#module_egg-router--Router+redirect) ⇒ <code>Router</code>
* [.route(name)](#module_egg-router--Router+route) ⇒ <code>Layer</code> &#124; <code>false</code>
* [.url(name, params, [options])](#module_egg-router--Router+url) ⇒ <code>String</code> &#124; <code>Error</code>
* [.param(param, middleware)](#module_egg-router--Router+param) ⇒ <code>Router</code>
* _static_
* [.url(path, params)](#module_egg-router--Router.url) ⇒ <code>String</code>
- [@eggjs/router](#eggjsrouter)
- [API Reference](#api-reference)
- [Router ⏏](#router-)
- [new Router(\[opts\])](#new-routeropts)
- [router.get|put|post|patch|delete|del ⇒ Router](#routergetputpostpatchdeletedel--router)
- [Named routes](#named-routes)
- [Multiple middleware](#multiple-middleware)
- [Nested routers](#nested-routers)
- [Router prefixes](#router-prefixes)
- [URL parameters](#url-parameters)
- [router.routes ⇒ function](#routerroutes--function)
- [router.use(\[path\], middleware) ⇒ Router](#routerusepath-middleware--router)
- [router.prefix(prefix) ⇒ Router](#routerprefixprefix--router)
- [router.allowedMethods(\[options\]) ⇒ function](#routerallowedmethodsoptions--function)
- [router.redirect(source, destination, \[code\]) ⇒ Router](#routerredirectsource-destination-code--router)
- [router.route(name) ⇒ Layer | false](#routerroutename--layer--false)
- [router.url(name, params, \[options\]) ⇒ String | Error](#routerurlname-params-options--string--error)
- [router.param(param, middleware) ⇒ Router](#routerparamparam-middleware--router)
- [Router.url(path, params \[, options\]) ⇒ String](#routerurlpath-params--options--string)
- [Tests](#tests)
- [Breaking changes on v3](#breaking-changes-on-v3)
- [License](#license)

@@ -31,2 +37,3 @@ <a name="exp_module_egg-router--Router"></a>

### Router ⏏
**Kind**: Exported class

@@ -36,7 +43,7 @@ <a name="new_module_egg-router--Router_new"></a>

#### new Router([opts])
Create a new router.
| Param | Type | Description |
| --- | --- | --- |
| --- | --- | --- |
| [opts] | <code>Object</code> | |

@@ -48,10 +55,10 @@ | [opts.prefix] | <code>String</code> | prefix router paths |

```javascript
var Koa = require('koa');
var Router = require('@eggjs/router');
```ts
import Koa from '@eggjs/koa';
import Router from '@eggjs/router';
var app = new Koa();
var router = new Router();
const app = new Koa();
const router = new Router();
router.get('/', (ctx, next) => {
router.get('/', async (ctx, next) => {
// ctx.router available

@@ -64,5 +71,7 @@ });

```
<a name="module_egg-router--Router+get|put|post|patch|delete|del"></a>
#### router.get|put|post|patch|delete|del ⇒ <code>Router</code>
Create `router.verb()` methods, where *verb* is one of the HTTP verbs such

@@ -76,3 +85,3 @@ as `router.get()` or `router.post()`.

```javascript
```ts
router

@@ -109,3 +118,3 @@ .get('/', (ctx, next) => {

```javascript
```ts
router.get('user', '/users/:id', (ctx, next) => {

@@ -123,3 +132,3 @@ // ...

```javascript
```ts
router.get(

@@ -144,5 +153,5 @@ '/users/:id',

```javascript
var forums = new Router();
var posts = new Router();
```ts
const forums = new Router();
const posts = new Router();

@@ -161,4 +170,4 @@ posts.get('/', (ctx, next) => {...});

```javascript
var router = new Router({
```ts
const router = new Router({
prefix: '/users'

@@ -175,3 +184,3 @@ });

```javascript
```ts
router.get('/:category/:title', (ctx, next) => {

@@ -189,3 +198,3 @@ console.log(ctx.params);

| Param | Type | Description |
| --- | --- | --- |
| --- | --- | --- |
| path | <code>String</code> | |

@@ -204,2 +213,3 @@ | [middleware] | <code>function</code> | route middleware(s) |

#### router.use([path], middleware) ⇒ <code>Router</code>
Use given middleware.

@@ -220,3 +230,4 @@

**Example**
```javascript
```ts
// session middleware will run before authorize

@@ -235,5 +246,7 @@ router

```
<a name="module_egg-router--Router+prefix"></a>
#### router.prefix(prefix) ⇒ <code>Router</code>
Set the path prefix for a Router instance that was already initialized.

@@ -248,8 +261,11 @@

**Example**
```javascript
```ts
router.prefix('/things/:thing_id')
```
<a name="module_egg-router--Router+allowedMethods"></a>
#### router.allowedMethods([options]) ⇒ <code>function</code>
Returns separate middleware for responding to `OPTIONS` requests with

@@ -269,9 +285,10 @@ an `Allow` header containing the allowed methods, as well as responding

**Example**
```javascript
var Koa = require('koa');
var Router = require('egg-router');
var app = new Koa();
var router = new Router();
```ts
import Koa from '@eggjs/koa';
import Router from '@eggjs/router';
const app = new Koa();
const router = new Router();
app.use(router.routes());

@@ -283,9 +300,9 @@ app.use(router.allowedMethods());

```javascript
var Koa = require('koa');
var Router = require('egg-router');
var Boom = require('boom');
```ts
import Koa from '@eggjs/koa';
import Router from '@eggjs/router';
import Boom from 'boom';
var app = new Koa();
var router = new Router();
const app = new Koa();
const router = new Router();

@@ -299,5 +316,7 @@ app.use(router.routes());

```
<a name="module_egg-router--Router+redirect"></a>
#### router.redirect(source, destination, [code]) ⇒ <code>Router</code>
Redirect `source` to `destination` URL with optional 30x status `code`.

@@ -313,3 +332,3 @@

```javascript
```ts
router.all('/login', ctx => {

@@ -332,2 +351,3 @@ ctx.redirect('/sign-in');

#### router.route(name) ⇒ <code>Layer</code> &#124; <code>false</code>
Lookup route with given `name`.

@@ -344,2 +364,3 @@

#### router.url(name, params, [options]) ⇒ <code>String</code> &#124; <code>Error</code>
Generate URL for route. Takes a route name and map of named `params`.

@@ -357,3 +378,4 @@

**Example**
```javascript
```ts
router.get('user', '/users/:id', (ctx, next) => {

@@ -380,5 +402,7 @@ // ...

```
<a name="module_egg-router--Router+param"></a>
#### router.param(param, middleware) ⇒ <code>Router</code>
Run middleware for named route parameters. Useful for auto-loading or

@@ -395,3 +419,4 @@ validation.

**Example**
```javascript
```ts
router

@@ -414,5 +439,7 @@ .param('user', (id, ctx, next) => {

```
<a name="module_egg-router--Router.url"></a>
#### Router.url(path, params [, options]) ⇒ <code>String</code>
Generate URL from url pattern and given `params`.

@@ -430,4 +457,5 @@

**Example**
```javascript
var url = Router.url('/users/:id', {id: 1});
```ts
const url = Router.url('/users/:id', {id: 1});
// => "/users/1"

@@ -442,1 +470,10 @@

Run tests using `npm test`.
## Breaking changes on v3
- Drop generator function support
- Drop Node.js < 18.7.0 support
## License
[MIT](LICENSE)
2.0.1 / 2021-07-12
==================
**fixes**
* [[`2c44ec0`](http://github.com/eggjs/egg-router/commit/2c44ec0bdeff1e8f46d899ed4386d1e28a93a854)] - fix: ensure ctx._matchedRoute and ctx._matchedRouteName to be correct (#7) (Yiyu He <<dead_horse@qq.com>>)
2.0.0 / 2019-02-14
==================
**features**
* [[`f0b29ec`](https://github.com/eggjs/egg-router/commit/f0b29ec34df32ba9d872f6318f4febd2b4ef9359)] - refactor: use class instead prototype (#4) (fengmk2 <<fengmk2@gmail.com>>)
1.2.0 / 2019-02-13
==================
**features**
* [[`1a0036a`](http://github.com/eggjs/egg-router/commit/1a0036a64a023b6b7993fecffe8062d5d0150971)] - feat: add routerPath to respond to routerName (#2) (Khaidi Chu <<i@2333.moe>>)
**others**
* [[`ff723fd`](http://github.com/eggjs/egg-router/commit/ff723fd03630ec49d5fe861abf129a583d214d22)] - chore: add koa-router license (#3) (fengmk2 <<fengmk2@gmail.com>>)
1.1.0 / 2019-01-30
==================
**features**
* [[`b318dd5`](http://github.com/eggjs/egg-router/commit/b318dd5ff2eea60013ed62b2a435f803c12bf20f)] - feat: add egg-router (dead-horse <<dead_horse@qq.com>>)
**fixes**
* [[`b3db7b4`](http://github.com/eggjs/egg-router/commit/b3db7b41988d3bf1b4e885ed76b3a8165c1d3b1d)] - fix: add missing dependencies koa-convert (dead-horse <<dead_horse@qq.com>>)
* [[`c280336`](http://github.com/eggjs/egg-router/commit/c2803368a8256bc9504ae3c821eefeb9d1fcbc4d)] - fix: only support node@8 (dead-horse <<dead_horse@qq.com>>)
* [[`7a887a2`](http://github.com/eggjs/egg-router/commit/7a887a252445e602c2ea7e1c6f4cde52a433644d)] - fix: update license (dead-horse <<dead_horse@qq.com>>)
**others**
* [[`ae40168`](http://github.com/eggjs/egg-router/commit/ae4016862fb8bdaf30e730a9278fbb1455d8b75d)] - docs: clean doc (dead-horse <<dead_horse@qq.com>>)
* [[`e4f21a8`](http://github.com/eggjs/egg-router/commit/e4f21a8ed6dfd72c4d6f4a13bbda9a4e90b0401c)] - chore: fix history (dead-horse <<dead_horse@qq.com>>)
1.0.0 / 2019-01-30
==================
**others**
* [[`d6496e0`](http://github.com/eggjs/egg-router/commit/d6496e09be6b0f91dcb96611f31ec5ab6ad8ac78)] - refactor: rename to @eggjs/router (dead-horse <<dead_horse@qq.com>>)
-------------------------------
# Release History from koa-router
## 7.4.0
- Fix router.url() for multiple nested routers [#407](https://github.com/alexmingoia/koa-router/pull/407)
- `layer.name` added to `ctx` at `ctx.routerName` during routing [#412](https://github.com/alexmingoia/koa-router/pull/412)
- 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.
## 7.3.0
- Router#url() now accepts query parameters to add to generated urls [#396](https://github.com/alexmingoia/koa-router/pull/396)
## 7.2.1
- Respond to CORS preflights with 200, 0 length body [#359](https://github.com/alexmingoia/koa-router/issues/359)
## 7.2.0
- Fix a bug in Router#url and append Router object to ctx. [#350](https://github.com/alexmingoia/koa-router/pull/350)
- Adds `_matchedRouteName` to context [#337](https://github.com/alexmingoia/koa-router/pull/337)
- Respond to CORS preflights with 200, 0 length body [#359](https://github.com/alexmingoia/koa-router/issues/359)
## 7.1.1
- Fix bug where param handlers were run out of order [#282](https://github.com/alexmingoia/koa-router/pull/282)
## 7.1.0
- Backports: merge 5.4 work into the 7.x upstream. See 5.4.0 updates for more details.
## 7.0.1
- Fix: allowedMethods should be ctx.method not this.method [#215](https://github.com/alexmingoia/koa-router/pull/215)
## 7.0.0
- The API has changed to match the new promise-based middleware
signature of koa 2. See the
[koa 2.x readme](https://github.com/koajs/koa/tree/2.0.0-alpha.3) for more
information.
- Middleware is now always run in the order declared by `.use()` (or `.get()`,
etc.), which matches Express 4 API.
## 5.4.0
- Expose matched route at `ctx._matchedRoute`.
## 5.3.0
- Register multiple routes with array of paths [#203](https://github.com/alexmingoia/koa-router/issue/143).
- Improved router.url() [#143](https://github.com/alexmingoia/koa-router/pull/143)
- Adds support for named routes and regular expressions
[#152](https://github.com/alexmingoia/koa-router/pull/152)
- Add support for custom throw functions for 405 and 501 responses [#206](https://github.com/alexmingoia/koa-router/pull/206)
## 5.2.3
- Fix for middleware running twice when nesting routes [#184](https://github.com/alexmingoia/koa-router/issues/184)
## 5.2.2
- Register routes without params before those with params [#183](https://github.com/alexmingoia/koa-router/pull/183)
- Fix for allowed methods [#182](https://github.com/alexmingoia/koa-router/issues/182)
## 5.2.0
- Add support for async/await. Resolves [#130](https://github.com/alexmingoia/koa-router/issues/130).
- Add support for array of paths by Router#use(). Resolves [#175](https://github.com/alexmingoia/koa-router/issues/175).
- Inherit param middleware when nesting routers. Fixes [#170](https://github.com/alexmingoia/koa-router/issues/170).
- 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).
- Run nested router middleware after parent's. Fixes [#156](https://github.com/alexmingoia/koa-router/issues/156).
- Remove dependency on koa-compose.
## 5.1.1
- Match routes in order they were defined. Fixes #131.
## 5.1.0
- Support mounting router middleware at a given path.
## 5.0.1
- Fix bug with missing parameters when nesting routers.
## 5.0.0
- Remove confusing API for extending koa app with router methods. Router#use()
does not have the same behavior as app#use().
- Add support for nesting routes.
- Remove support for regular expression routes to achieve nestable routers and
enable future trie-based routing optimizations.
## 4.3.2
- Do not send 405 if route matched but status is 404. Fixes #112, closes #114.
## 4.3.1
- Do not run middleware if not yielded to by previous middleware. Fixes #115.
## 4.3.0
- Add support for router prefixes.
- Add MIT license.
## 4.2.0
- Fixed issue with router middleware being applied even if no route was
matched.
- Router.url - new static method to generate url from url pattern and data
## 4.1.0
Private API changed to separate context parameter decoration from route
matching. `Router#match` and `Route#match` are now pure functions that return
an array of routes that match the URL path.
For modules using this private API that need to determine if a method and path
match a route, `route.methods` must be checked against the routes returned from
`router.match()`:
```javascript
var matchedRoute = router.match(path).filter(function (route) {
return ~route.methods.indexOf(method);
}).shift();
```
## 4.0.0
405, 501, and OPTIONS response handling was moved into separate middleware
`router.allowedMethods()`. This resolves incorrect 501 or 405 responses when
using multiple routers.
### Breaking changes
4.x is mostly backwards compatible with 3.x, except for the following:
- Instantiating a router with `new` and `app` returns the router instance,
whereas 3.x returns the router middleware. When creating a router in 4.x, the
only time router middleware is returned is when creating using the
`Router(app)` signature (with `app` and without `new`).
'use strict';
const KoaRouter = require('./lib/router');
const EggRouter = require('./lib/egg_router');
// for compact
module.exports = KoaRouter;
module.exports.KoaRouter = KoaRouter;
module.exports.EggRouter = EggRouter;
'use strict';
const is = require('is-type-of');
const Router = require('./router');
const utility = require('utility');
const inflection = require('inflection');
const assert = require('assert');
const utils = require('./utils');
const METHODS = [ 'head', 'options', 'get', 'put', 'patch', 'post', 'delete' ];
const REST_MAP = {
index: {
suffix: '',
method: 'GET',
},
new: {
namePrefix: 'new_',
member: true,
suffix: 'new',
method: 'GET',
},
create: {
suffix: '',
method: 'POST',
},
show: {
member: true,
suffix: ':id',
method: 'GET',
},
edit: {
member: true,
namePrefix: 'edit_',
suffix: ':id/edit',
method: 'GET',
},
update: {
member: true,
namePrefix: '',
suffix: ':id',
method: [ 'PATCH', 'PUT' ],
},
destroy: {
member: true,
namePrefix: 'destroy_',
suffix: ':id',
method: 'DELETE',
},
};
/**
* FIXME: move these patch into @eggjs/router
*/
class EggRouter extends Router {
/**
* @class
* @param {Object} opts - Router options.
* @param {Application} app - Application object.
*/
constructor(opts, app) {
super(opts);
this.app = app;
this.patchRouterMethod();
}
patchRouterMethod() {
// patch router methods to support generator function middleware and string controller
METHODS.concat([ 'all' ]).forEach(method => {
this[method] = (...args) => {
const splited = spliteAndResolveRouterParams({ args, app: this.app });
// format and rebuild params
args = splited.prefix.concat(splited.middlewares);
return super[method](...args);
};
});
}
/**
* Create and register a route.
* @param {String} path - url path
* @param {Array} methods - Array of HTTP verbs
* @param {Array} middlewares -
* @param {Object} opts -
* @return {Route} this
*/
register(path, methods, middlewares, opts) {
// patch register to support generator function middleware and string controller
middlewares = Array.isArray(middlewares) ? middlewares : [ middlewares ];
middlewares = convertMiddlewares(middlewares, this.app);
path = Array.isArray(path) ? path : [ path ];
path.forEach(p => super.register(p, methods, middlewares, opts));
return this;
}
/**
* restful router api
* @param {String} name - Router name
* @param {String} prefix - url prefix
* @param {Function} middleware - middleware or controller
* @example
* ```js
* app.resources('/posts', 'posts')
* app.resources('posts', '/posts', 'posts')
* app.resources('posts', '/posts', app.role.can('user'), app.controller.posts)
* ```
*
* Examples:
*
* ```js
* app.resources('/posts', 'posts')
* ```
*
* yield router mapping
*
* Method | Path | Route Name | Controller.Action
* -------|-----------------|----------------|-----------------------------
* GET | /posts | posts | app.controller.posts.index
* GET | /posts/new | new_post | app.controller.posts.new
* GET | /posts/:id | post | app.controller.posts.show
* GET | /posts/:id/edit | edit_post | app.controller.posts.edit
* POST | /posts | posts | app.controller.posts.create
* PATCH | /posts/:id | post | app.controller.posts.update
* DELETE | /posts/:id | post | app.controller.posts.destroy
*
* app.router.url can generate url based on arguments
* ```js
* app.router.url('posts')
* => /posts
* app.router.url('post', { id: 1 })
* => /posts/1
* app.router.url('new_post')
* => /posts/new
* app.router.url('edit_post', { id: 1 })
* => /posts/1/edit
* ```
* @return {Router} return route object.
* @since 1.0.0
*/
resources(...args) {
const splited = spliteAndResolveRouterParams({ args, app: this.app });
const middlewares = splited.middlewares;
// last argument is Controller object
const controller = splited.middlewares.pop();
let name = '';
let prefix = '';
if (splited.prefix.length === 2) {
// router.get('users', '/users')
name = splited.prefix[0];
prefix = splited.prefix[1];
} else {
// router.get('/users')
prefix = splited.prefix[0];
}
for (const key in REST_MAP) {
const action = controller[key];
if (!action) continue;
const opts = REST_MAP[key];
let formatedName;
if (opts.member) {
formatedName = inflection.singularize(name);
} else {
formatedName = inflection.pluralize(name);
}
if (opts.namePrefix) {
formatedName = opts.namePrefix + formatedName;
}
prefix = prefix.replace(/\/$/, '');
const path = opts.suffix ? `${prefix}/${opts.suffix}` : prefix;
const method = Array.isArray(opts.method) ? opts.method : [ opts.method ];
this.register(path, method, middlewares.concat(action), { name: formatedName });
}
return this;
}
/**
* @param {String} name - Router name
* @param {Object} params - more parameters
* @example
* ```js
* router.url('edit_post', { id: 1, name: 'foo', page: 2 })
* => /posts/1/edit?name=foo&page=2
* router.url('posts', { name: 'foo&1', page: 2 })
* => /posts?name=foo%261&page=2
* ```
* @return {String} url by path name and query params.
* @since 1.0.0
*/
url(name, params) {
const route = this.route(name);
if (!route) return '';
const args = params;
let url = route.path;
assert(!is.regExp(url), `Can't get the url for regExp ${url} for by name '${name}'`);
const queries = [];
if (typeof args === 'object' && args !== null) {
const replacedParams = [];
url = url.replace(/:([a-zA-Z_]\w*)/g, function($0, key) {
if (utility.has(args, key)) {
const values = args[key];
replacedParams.push(key);
return utility.encodeURIComponent(Array.isArray(values) ? values[0] : values);
}
return $0;
});
for (const key in args) {
if (replacedParams.includes(key)) {
continue;
}
const values = args[key];
const encodedKey = utility.encodeURIComponent(key);
if (Array.isArray(values)) {
for (const val of values) {
queries.push(`${encodedKey}=${utility.encodeURIComponent(val)}`);
}
} else {
queries.push(`${encodedKey}=${utility.encodeURIComponent(values)}`);
}
}
}
if (queries.length > 0) {
const queryStr = queries.join('&');
if (!url.includes('?')) {
url = `${url}?${queryStr}`;
} else {
url = `${url}&${queryStr}`;
}
}
return url;
}
pathFor(name, params) {
return this.url(name, params);
}
}
/**
* 1. split (name, url, ...middleware, controller) to
* {
* prefix: [name, url]
* middlewares [...middleware, controller]
* }
*
* 2. resolve controller from string to function
*
* @param {Object} options inputs
* @param {Object} options.args router params
* @param {Object} options.app egg application instance
* @return {Object} prefix and middlewares
*/
function spliteAndResolveRouterParams({ args, app }) {
let prefix;
let middlewares;
if (args.length >= 3 && (is.string(args[1]) || is.regExp(args[1]))) {
// app.get(name, url, [...middleware], controller)
prefix = args.slice(0, 2);
middlewares = args.slice(2);
} else {
// app.get(url, [...middleware], controller)
prefix = args.slice(0, 1);
middlewares = args.slice(1);
}
// resolve controller
const controller = middlewares.pop();
middlewares.push(resolveController(controller, app));
return { prefix, middlewares };
}
/**
* resolve controller from string to function
* @param {String|Function} controller input controller
* @param {Application} app egg application instance
* @return {Function} controller function
*/
function resolveController(controller, app) {
if (is.string(controller)) {
const actions = controller.split('.');
let obj = app.controller;
actions.forEach(key => {
obj = obj[key];
if (!obj) throw new Error(`controller '${controller}' not exists`);
});
controller = obj;
}
// ensure controller is exists
if (!controller) throw new Error('controller not exists');
return controller;
}
/**
* 1. ensure controller(last argument) support string
* - [url, controller]: app.get('/home', 'home');
* - [name, url, controller(string)]: app.get('posts', '/posts', 'posts.list');
* - [name, url, controller]: app.get('posts', '/posts', app.controller.posts.list);
* - [name, url(regexp), controller]: app.get('regRouter', /\/home\/index/, 'home.index');
* - [name, url, middleware, [...], controller]: `app.get(/user/:id', hasLogin, canGetUser, 'user.show');`
*
* 2. make middleware support generator function
*
* @param {Array} middlewares middlewares and controller(last middleware)
* @param {Application} app egg application instance
* @return {Array} middlewares
*/
function convertMiddlewares(middlewares, app) {
// ensure controller is resolved
const controller = resolveController(middlewares.pop(), app);
// make middleware support generator function
middlewares = middlewares.map(utils.middleware);
const wrappedController = (ctx, next) => {
return utils.callFn(controller, [ ctx, next ], ctx);
};
return middlewares.concat([ wrappedController ]);
}
module.exports = EggRouter;
'use strict';
const debug = require('debug')('egg-router:layer');
const pathToRegExp = require('path-to-regexp');
const uri = require('urijs');
const utility = require('utility');
module.exports = class Layer {
/**
* Initialize a new routing Layer with given `method`, `path`, and `middleware`.
*
* @param {String|RegExp} path Path string or regular expression.
* @param {Array} methods Array of HTTP verbs.
* @param {Array} middleware Layer callback/middleware or series of.
* @param {Object=} opts optional params
* @param {String=} opts.name route name
* @param {String=} opts.sensitive case sensitive (default: false)
* @param {String=} opts.strict require the trailing slash (default: false)
* @private
*/
constructor(path, methods, middleware, opts) {
this.opts = opts || {};
this.name = this.opts.name || null;
this.methods = [];
this.paramNames = [];
this.stack = Array.isArray(middleware) ? middleware : [ middleware ];
methods.forEach(function(method) {
const l = this.methods.push(method.toUpperCase());
if (this.methods[l - 1] === 'GET') {
this.methods.unshift('HEAD');
}
}, this);
// ensure middleware is a function
this.stack.forEach(function(fn) {
const type = (typeof fn);
if (type !== 'function') {
throw new Error(
methods.toString() + ' `' + (this.opts.name || path) + '`: `middleware` '
+ 'must be a function, not `' + type + '`'
);
}
}, this);
this.path = path;
this.regexp = pathToRegExp(path, this.paramNames, this.opts);
debug('defined route %s %s', this.methods, this.opts.prefix + this.path);
}
/**
* Returns whether request `path` matches route.
*
* @param {String} path path string
* @return {Boolean} matched or not
* @private
*/
match(path) {
return this.regexp.test(path);
}
/**
* Returns map of URL parameters for given `path` and `paramNames`.
*
* @param {String} path path string
* @param {Array.<String>} captures captures strings
* @param {Object=} existingParams existing params
* @return {Object} params object
* @private
*/
params(path, captures, existingParams) {
const params = existingParams || {};
for (let len = captures.length, i = 0; i < len; i++) {
if (this.paramNames[i]) {
const c = captures[i];
params[this.paramNames[i].name] = c ? utility.decodeURIComponent(c) : c;
}
}
return params;
}
/**
* Returns array of regexp url path captures.
*
* @param {String} path path string
* @return {Array.<String>} captures strings
* @private
*/
captures(path) {
if (this.opts.ignoreCaptures) return [];
return path.match(this.regexp).slice(1);
}
/**
* Generate URL for route using given `params`.
*
* @example
*
* ```javascript
* var route = new Layer(['GET'], '/users/:id', fn);
*
* route.url({ id: 123 }); // => "/users/123"
* ```
*
* @param {Object} params url parameters
* @param {Object} [options] optional parameters
* @return {String} url string
* @private
*/
url(params, options) {
let args = params;
const url = this.path.replace(/\(\.\*\)/g, '');
const toPath = pathToRegExp.compile(url);
if (typeof params !== 'object') {
args = Array.prototype.slice.call(arguments);
if (typeof args[args.length - 1] === 'object') {
options = args[args.length - 1];
args = args.slice(0, args.length - 1);
}
}
const tokens = pathToRegExp.parse(url);
let replace = {};
if (args instanceof Array) {
for (let len = tokens.length, i = 0, j = 0; i < len; i++) {
if (tokens[i].name) replace[tokens[i].name] = args[j++];
}
} else if (tokens.some(token => token.name)) {
replace = params;
} else {
options = params;
}
let replaced = toPath(replace);
if (options && options.query) {
replaced = new uri(replaced);
replaced.search(options.query);
return replaced.toString();
}
return replaced;
}
/**
* Run validations on route named parameters.
*
* @example
*
* ```javascript
* router
* .param('user', function (id, ctx, next) {
* ctx.user = users[id];
* if (!user) return ctx.status = 404;
* next();
* })
* .get('/users/:user', function (ctx, next) {
* ctx.body = ctx.user;
* });
* ```
*
* @param {String} param param string
* @param {Function} fn middleware function
* @return {Layer} layer instance
* @private
*/
param(param, fn) {
const stack = this.stack;
const params = this.paramNames;
const middleware = function(ctx, next) {
return fn.call(this, ctx.params[param], ctx, next);
};
middleware.param = param;
const names = params.map(function(p) {
return p.name;
});
const x = names.indexOf(param);
if (x > -1) {
// iterate through the stack, to figure out where to place the handler fn
stack.some(function(fn, i) {
// param handlers are always first, so when we find an fn w/o a param property, stop here
// if the param handler at this part of the stack comes after the one we are adding, stop here
if (!fn.param || names.indexOf(fn.param) > x) {
// inject this param handler right before the current item
stack.splice(i, 0, middleware);
return true; // then break the loop
}
return false;
});
}
return this;
}
/**
* Prefix route path.
*
* @param {String} prefix prefix string
* @return {Layer} layer instance
* @private
*/
setPrefix(prefix) {
if (this.path) {
this.path = prefix + this.path;
this.paramNames = [];
this.regexp = pathToRegExp(this.path, this.paramNames, this.opts);
}
return this;
}
};
'use strict';
/**
* RESTful resource routing middleware for eggjs.
*/
const debug = require('debug')('egg-router');
const compose = require('koa-compose');
const HttpError = require('http-errors');
const methods = require('methods');
const Layer = require('./layer');
/**
* @module koa-router
*/
class Router {
/**
* Create a new router.
*
* @example
*
* Basic usage:
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* router.get('/', (ctx, next) => {
* // ctx.router available
* });
*
* app
* .use(router.routes())
* .use(router.allowedMethods());
* ```
*
* @alias module:koa-router
* @param {Object=} opts optional
* @param {String=} opts.prefix prefix router paths
* @class
*/
constructor(opts) {
this.opts = opts || {};
this.methods = this.opts.methods || [
'HEAD',
'OPTIONS',
'GET',
'PUT',
'PATCH',
'POST',
'DELETE',
];
this.params = {};
this.stack = [];
}
/**
* Use given middleware.
*
* Middleware run in the order they are defined by `.use()`. They are invoked
* sequentially, requests start at the first middleware and work their way
* "down" the middleware stack.
*
* @example
*
* ```javascript
* // session middleware will run before authorize
* router
* .use(session())
* .use(authorize());
*
* // use middleware only with given path
* router.use('/users', userAuth());
*
* // or with an array of paths
* router.use(['/users', '/admin'], userAuth());
*
* app.use(router.routes());
* ```
*
* @param {String=} path path string
* @param {Function} middleware middleware function
* @return {Router} router instance
*/
use(/* path, middleware */) {
const router = this;
const middleware = Array.prototype.slice.call(arguments);
let path;
// support array of paths
if (Array.isArray(middleware[0]) && typeof middleware[0][0] === 'string') {
middleware[0].forEach(function(p) {
router.use.apply(router, [ p ].concat(middleware.slice(1)));
});
return this;
}
const hasPath = typeof middleware[0] === 'string';
if (hasPath) {
path = middleware.shift();
}
middleware.forEach(function(m) {
if (m.router) {
m.router.stack.forEach(function(nestedLayer) {
if (path) nestedLayer.setPrefix(path);
if (router.opts.prefix) nestedLayer.setPrefix(router.opts.prefix);
router.stack.push(nestedLayer);
});
if (router.params) {
Object.keys(router.params).forEach(function(key) {
m.router.param(key, router.params[key]);
});
}
} else {
router.register(path || '(.*)', [], m, { end: false, ignoreCaptures: !hasPath });
}
});
return this;
}
/**
* Set the path prefix for a Router instance that was already initialized.
*
* @example
*
* ```javascript
* router.prefix('/things/:thing_id')
* ```
*
* @param {String} prefix prefix string
* @return {Router} router instance
*/
prefix(prefix) {
prefix = prefix.replace(/\/$/, '');
this.opts.prefix = prefix;
this.stack.forEach(function(route) {
route.setPrefix(prefix);
});
return this;
}
/**
* Returns router middleware which dispatches a route matching the request.
*
* @return {Function} middleware function
*/
routes() {
const router = this;
const dispatch = function dispatch(ctx, next) {
debug('%s %s', ctx.method, ctx.path);
const path = router.opts.routerPath || ctx.routerPath || ctx.path;
const matched = router.match(path, ctx.method);
if (ctx.matched) {
ctx.matched.push.apply(ctx.matched, matched.path);
} else {
ctx.matched = matched.path;
}
ctx.router = router;
if (!matched.route) return next();
const matchedLayers = matched.pathAndMethod;
const layerChain = matchedLayers.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
// ctx._matchedRouteName & ctx._matchedRoute for compatibility
ctx._matchedRouteName = ctx.routerName = layer.name;
if (!layer.name) ctx._matchedRouteName = undefined;
ctx._matchedRoute = ctx.routerPath = layer.path;
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
};
dispatch.router = this;
return dispatch;
}
/**
* Returns separate middleware for responding to `OPTIONS` requests with
* an `Allow` header containing the allowed methods, as well as responding
* with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
*
* @example
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods());
* ```
*
* **Example with [Boom](https://github.com/hapijs/boom)**
*
* ```javascript
* var Koa = require('koa');
* var Router = require('koa-router');
* var Boom = require('boom');
*
* var app = new Koa();
* var router = new Router();
*
* app.use(router.routes());
* app.use(router.allowedMethods({
* throw: true,
* notImplemented: () => new Boom.notImplemented(),
* methodNotAllowed: () => new Boom.methodNotAllowed()
* }));
* ```
*
* @param {Object=} options optional params
* @param {Boolean=} options.throw throw error instead of setting status and header
* @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
* @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
* @return {Function} middleware function
*/
allowedMethods(options) {
options = options || {};
const implemented = this.methods;
return function allowedMethods(ctx, next) {
return next().then(function() {
const allowed = {};
if (!ctx.status || ctx.status === 404) {
ctx.matched.forEach(function(route) {
route.methods.forEach(function(method) {
allowed[method] = method;
});
});
const allowedArr = Object.keys(allowed);
if (!implemented.includes(ctx.method)) {
if (options.throw) {
let notImplementedThrowable;
if (typeof options.notImplemented === 'function') {
notImplementedThrowable = options.notImplemented(); // set whatever the user returns from their function
} else {
notImplementedThrowable = new HttpError.NotImplemented();
}
throw notImplementedThrowable;
} else {
ctx.status = 501;
ctx.set('Allow', allowedArr.join(', '));
}
} else if (allowedArr.length) {
if (ctx.method === 'OPTIONS') {
ctx.status = 200;
ctx.body = '';
ctx.set('Allow', allowedArr.join(', '));
} else if (!allowed[ctx.method]) {
if (options.throw) {
let notAllowedThrowable;
if (typeof options.methodNotAllowed === 'function') {
notAllowedThrowable = options.methodNotAllowed(); // set whatever the user returns from their function
} else {
notAllowedThrowable = new HttpError.MethodNotAllowed();
}
throw notAllowedThrowable;
} else {
ctx.status = 405;
ctx.set('Allow', allowedArr.join(', '));
}
}
}
}
});
};
}
/**
* Register route with all methods.
*
* @param {String} name Optional.
* @param {String} path path string
* @param {Function=} middleware You may also pass multiple middleware.
* @param {Function} callback callback function
* @return {Router} router instance
* @private
*/
all(name, path/* , middleware */) {
let middleware;
if (typeof path === 'string') {
middleware = Array.prototype.slice.call(arguments, 2);
} else {
middleware = Array.prototype.slice.call(arguments, 1);
path = name;
name = null;
}
this.register(path, methods, middleware, {
name,
});
return this;
}
/**
* Redirect `source` to `destination` URL with optional 30x status `code`.
*
* Both `source` and `destination` can be route names.
*
* ```javascript
* router.redirect('/login', 'sign-in');
* ```
*
* This is equivalent to:
*
* ```javascript
* router.all('/login', ctx => {
* ctx.redirect('/sign-in');
* ctx.status = 301;
* });
* ```
*
* @param {String} source URL or route name.
* @param {String} destination URL or route name.
* @param {Number=} code HTTP status code (default: 301).
* @return {Router} router instance
*/
redirect(source, destination, code) {
// lookup source route by name
if (source[0] !== '/') {
source = this.url(source);
}
// lookup destination route by name
if (destination[0] !== '/') {
destination = this.url(destination);
}
return this.all(source, ctx => {
ctx.redirect(destination);
ctx.status = code || 301;
});
}
/**
* Create and register a route.
*
* @param {String} path Path string.
* @param {Array.<String>} methods Array of HTTP verbs.
* @param {Function} middleware Multiple middleware also accepted.
* @param {Object} [opts] optional params
* @return {Layer} layer instance
* @private
*/
register(path, methods, middleware, opts) {
opts = opts || {};
const router = this;
const stack = this.stack;
// support array of paths
if (Array.isArray(path)) {
path.forEach(function(p) {
router.register.call(router, p, methods, middleware, opts);
});
return this;
}
// create route
const route = new Layer(path, methods, middleware, {
end: opts.end === false ? opts.end : true,
name: opts.name,
sensitive: opts.sensitive || this.opts.sensitive || false,
strict: opts.strict || this.opts.strict || false,
prefix: opts.prefix || this.opts.prefix || '',
ignoreCaptures: opts.ignoreCaptures,
});
if (this.opts.prefix) {
route.setPrefix(this.opts.prefix);
}
// add parameter middleware
Object.keys(this.params).forEach(function(param) {
route.param(param, this.params[param]);
}, this);
stack.push(route);
return route;
}
/**
* Lookup route with given `name`.
*
* @param {String} name route name
* @return {Layer|false} layer instance of false
*/
route(name) {
const routes = this.stack;
for (let len = routes.length, i = 0; i < len; i++) {
if (routes[i].name && routes[i].name === name) {
return routes[i];
}
}
return false;
}
/**
* Generate URL for route. Takes a route name and map of named `params`.
*
* @example
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
*
* router.url('user', { id: 3 });
* // => "/users/3"
*
* router.use((ctx, next) => {
* // redirect to named route
* ctx.redirect(ctx.router.url('sign-in'));
* })
*
* router.url('user', { id: 3 }, { query: { limit: 1 } });
* // => "/users/3?limit=1"
*
* router.url('user', { id: 3 }, { query: "limit=1" });
* // => "/users/3?limit=1"
* ```
*
* @param {String} name route name
* @param {Object} params url parameters
* @param {Object} [options] options parameter
* @param {Object|String} [options.query] query options
* @return {String|Error} string or error instance
*/
url(name/* , params */) {
const route = this.route(name);
if (route) {
const args = Array.prototype.slice.call(arguments, 1);
return route.url.apply(route, args);
}
return new Error('No route found for name: ' + name);
}
/**
* Match given `path` and return corresponding routes.
*
* @param {String} path path string
* @param {String} method method name
* @return {Object.<path, pathAndMethod>} returns layers that matched path and
* path and method.
* @private
*/
match(path, method) {
const layers = this.stack;
let layer;
const matched = {
// matched path
path: [],
// matched path and method(including none method)
pathAndMethod: [],
// method matched or not
route: false,
};
for (let len = layers.length, i = 0; i < len; i++) {
layer = layers[i];
debug('test %s %s', layer.path, layer.regexp);
if (layer.match(path)) {
matched.path.push(layer);
if (layer.methods.length === 0 || layer.methods.includes(method)) {
matched.pathAndMethod.push(layer);
if (layer.methods.length) matched.route = true;
}
// if (layer.methods.length === 0) {
// matched.pathAndMethod.push(layer);
// } else if (layer.methods.includes(method)) {
// matched.pathAndMethod.push(layer);
// matched.route = true;
// }
}
}
return matched;
}
/**
* Run middleware for named route parameters. Useful for auto-loading or
* validation.
*
* @example
*
* ```javascript
* router
* .param('user', (id, ctx, next) => {
* ctx.user = users[id];
* if (!ctx.user) return ctx.status = 404;
* return next();
* })
* .get('/users/:user', ctx => {
* ctx.body = ctx.user;
* })
* .get('/users/:user/friends', ctx => {
* return ctx.user.getFriends().then(function(friends) {
* ctx.body = friends;
* });
* })
* // /users/3 => {"id": 3, "name": "Alex"}
* // /users/3/friends => [{"id": 4, "name": "TJ"}]
* ```
*
* @param {String} param param
* @param {Function} middleware route middleware
* @return {Router} instance
*/
param(param, middleware) {
this.params[param] = middleware;
this.stack.forEach(function(route) {
route.param(param, middleware);
});
return this;
}
}
/**
* Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
* as `router.get()` or `router.post()`.
*
* Match URL patterns to callback functions or controller actions using `router.verb()`,
* where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
*
* Additionaly, `router.all()` can be used to match against all methods.
*
* ```javascript
* router
* .get('/', (ctx, next) => {
* ctx.body = 'Hello World!';
* })
* .post('/users', (ctx, next) => {
* // ...
* })
* .put('/users/:id', (ctx, next) => {
* // ...
* })
* .del('/users/:id', (ctx, next) => {
* // ...
* })
* .all('/users/:id', (ctx, next) => {
* // ...
* });
* ```
*
* When a route is matched, its path is available at `ctx._matchedRoute` and if named,
* the name is available at `ctx._matchedRouteName`
*
* Route paths will be translated to regular expressions using
* [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
*
* Query strings will not be considered when matching requests.
*
* #### Named routes
*
* Routes can optionally have names. This allows generation of URLs and easy
* renaming of URLs during development.
*
* ```javascript
* router.get('user', '/users/:id', (ctx, next) => {
* // ...
* });
*
* router.url('user', 3);
* // => "/users/3"
* ```
*
* #### Multiple middleware
*
* Multiple middleware may be given:
*
* ```javascript
* router.get(
* '/users/:id',
* (ctx, next) => {
* return User.findOne(ctx.params.id).then(function(user) {
* ctx.user = user;
* next();
* });
* },
* ctx => {
* console.log(ctx.user);
* // => { id: 17, name: "Alex" }
* }
* );
* ```
*
* ### Nested routers
*
* Nesting routers is supported:
*
* ```javascript
* var forums = new Router();
* var posts = new Router();
*
* posts.get('/', (ctx, next) => {...});
* posts.get('/:pid', (ctx, next) => {...});
* forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
*
* // responds to "/forums/123/posts" and "/forums/123/posts/123"
* app.use(forums.routes());
* ```
*
* #### Router prefixes
*
* Route paths can be prefixed at the router level:
*
* ```javascript
* var router = new Router({
* prefix: '/users'
* });
*
* router.get('/', ...); // responds to "/users"
* router.get('/:id', ...); // responds to "/users/:id"
* ```
*
* #### URL parameters
*
* Named route parameters are captured and added to `ctx.params`.
*
* ```javascript
* router.get('/:category/:title', (ctx, next) => {
* console.log(ctx.params);
* // => { category: 'programming', title: 'how-to-node' }
* });
* ```
*
* The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
* used to convert paths to regular expressions.
*
* @name get|put|post|patch|delete|del
* @memberof module:koa-router.prototype
* @param {String} path
* @param {Function=} middleware route middleware(s)
* @param {Function} callback route callback
* @returns {Router}
*/
methods.forEach(function(method) {
Router.prototype[method] = function(name, path /* , middleware */) {
let middleware;
if (typeof path === 'string' || path instanceof RegExp) {
middleware = Array.prototype.slice.call(arguments, 2);
} else {
middleware = Array.prototype.slice.call(arguments, 1);
path = name;
name = null;
}
this.register(path, [ method ], middleware, {
name,
});
return this;
};
});
// Alias for `router.delete()` because delete is a reserved word
Router.prototype.del = Router.prototype.delete;
/**
* Generate URL from url pattern and given `params`.
*
* @example
*
* ```javascript
* var url = Router.url('/users/:id', {id: 1});
* // => "/users/1"
* ```
*
* @param {String} path url pattern
* @param {Object} params url parameters
* @return {String} url string
*/
Router.url = function(path/* , params */) {
const args = Array.prototype.slice.call(arguments, 1);
return Layer.prototype.url.apply({ path }, args);
};
Router.prototype.middleware = Router.prototype.routes;
module.exports = Router;
'use strict';
const convert = require('koa-convert');
const is = require('is-type-of');
const co = require('co');
module.exports = {
async callFn(fn, args, ctx) {
args = args || [];
if (!is.function(fn)) return;
if (is.generatorFunction(fn)) fn = co.wrap(fn);
return ctx ? fn.call(ctx, ...args) : fn(...args);
},
middleware(fn) {
return is.generatorFunction(fn) ? convert(fn) : fn;
},
};