2016-07-15 19:34:24 +00:00
|
|
|
/**
|
|
|
|
* Module dependencies.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-07-14 13:14:16 +00:00
|
|
|
import HTTP_METHODS from './methods';
|
2017-01-14 14:02:50 +00:00
|
|
|
import {toParameters} from './application';
|
2016-06-26 10:10:37 +00:00
|
|
|
import Middleware from './middleware';
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Route object.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-09-15 17:16:42 +00:00
|
|
|
export class Route {
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the route.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-06-26 10:10:37 +00:00
|
|
|
constructor(router, uriPart, method, middleware) {
|
|
|
|
this.router = router;
|
|
|
|
this.uriPart = uriPart;
|
|
|
|
this.method = method;
|
|
|
|
this.middleware = middleware;
|
2016-06-30 21:35:20 +00:00
|
|
|
this.visited = false;
|
2016-06-26 10:10:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return route's uri.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-06-26 10:10:37 +00:00
|
|
|
get uri() {
|
2016-07-09 22:58:03 +00:00
|
|
|
if (!this.uriPart && !this.method) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:10:37 +00:00
|
|
|
if (this.uriPart instanceof RegExp) {
|
|
|
|
return this.uriPart;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.router.baseUri instanceof RegExp) {
|
|
|
|
return this.router.baseUri;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.router.baseUri) {
|
2017-01-14 14:02:50 +00:00
|
|
|
const baseUri = this.router.baseUri.trim();
|
|
|
|
if (this.uriPart) {
|
|
|
|
return ( baseUri + this.uriPart.trim()).replace(/\/{2,}/, '/');
|
|
|
|
}
|
|
|
|
return baseUri;
|
2016-06-26 10:10:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.uriPart;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Router object.
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
|
2017-01-14 14:02:50 +00:00
|
|
|
const error_middleware_message = 'method takes at least a middleware';
|
2016-06-26 10:10:37 +00:00
|
|
|
export default class Router {
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the router.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-07-09 00:58:41 +00:00
|
|
|
constructor(uri) {
|
2017-01-14 14:02:50 +00:00
|
|
|
this._baseUri = uri;
|
2016-06-30 21:35:20 +00:00
|
|
|
this._routes = [];
|
2016-06-26 10:10:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Do some checks and set _baseUri.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-07-08 21:29:40 +00:00
|
|
|
set baseUri(uri) {
|
2017-01-14 14:02:50 +00:00
|
|
|
if (this._baseUri) {
|
|
|
|
throw new TypeError('base uri is already set');
|
2016-07-08 21:29:40 +00:00
|
|
|
}
|
2017-01-14 14:02:50 +00:00
|
|
|
this._baseUri = uri;
|
2016-07-08 21:29:40 +00:00
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return router's _baseUri.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-07-08 21:29:40 +00:00
|
|
|
get baseUri() {
|
|
|
|
return this._baseUri;
|
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a route to the router.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-06-26 10:10:37 +00:00
|
|
|
_add(route) {
|
2016-06-30 21:35:20 +00:00
|
|
|
this._routes.push(route);
|
2016-06-26 10:10:37 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gather routes from routers filtered by _uri_ and HTTP _method_.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-06-30 21:35:20 +00:00
|
|
|
routes(uri, method) {
|
|
|
|
return this._routes.filter((route) => {
|
2017-01-14 14:02:50 +00:00
|
|
|
if (route.method && route.method !== method) {
|
2016-06-26 10:10:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-14 14:02:50 +00:00
|
|
|
if (!route.uri || !uri) {
|
2016-06-26 10:10:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-02 13:45:54 +00:00
|
|
|
//remove query string from uri to test
|
|
|
|
//remove anchor from uri to test
|
2017-01-14 14:02:50 +00:00
|
|
|
const match = /^(.*)\?.*#.*|(.*)(?=\?|#)|(.*[^\?#])$/.exec(uri);
|
|
|
|
const baseUriToCheck = match[1] || match[2] || match[3];
|
2016-07-02 13:45:54 +00:00
|
|
|
|
|
|
|
if (route.uri instanceof RegExp) {
|
2017-01-14 14:02:50 +00:00
|
|
|
return baseUriToCheck.match(route.uri);
|
2016-07-02 13:45:54 +00:00
|
|
|
}
|
|
|
|
|
2017-01-14 14:02:50 +00:00
|
|
|
return route.uri === baseUriToCheck;
|
2016-06-26 10:10:37 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gather visited routes from routers.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
|
2016-06-30 21:35:20 +00:00
|
|
|
visited() {
|
2017-01-14 14:02:50 +00:00
|
|
|
return this._routes.filter(route => route.visited);
|
2016-06-30 21:35:20 +00:00
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Use the given middleware function or object on this router.
|
|
|
|
*
|
|
|
|
* // middleware function
|
|
|
|
* router.use((req, res, next) => {console.log('Hello')});
|
|
|
|
*
|
|
|
|
* // middleware object
|
|
|
|
* router.use(new Middleware());
|
|
|
|
*
|
2016-07-23 08:48:26 +00:00
|
|
|
* @param {Middleware|Function} middleware object or function
|
2016-07-15 19:34:24 +00:00
|
|
|
* @return {Router} for chaining
|
|
|
|
*
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
|
2016-07-09 22:58:03 +00:00
|
|
|
use(middleware) {
|
|
|
|
if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) {
|
2017-01-14 14:02:50 +00:00
|
|
|
throw new TypeError(error_middleware_message);
|
2016-07-09 22:58:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this._add(new Route(this, undefined, undefined, middleware));
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Use the given middleware function or object on this router for
|
|
|
|
* all HTTP methods.
|
|
|
|
*
|
|
|
|
* // middleware function
|
|
|
|
* router.all((req, res, next) => {console.log('Hello')});
|
|
|
|
*
|
|
|
|
* // middleware object
|
|
|
|
* router.all(new Middleware());
|
|
|
|
*
|
2016-07-23 08:48:26 +00:00
|
|
|
* @param {Middleware|Function} middleware object or function
|
2016-07-15 19:34:24 +00:00
|
|
|
* @return {Router} for chaining
|
|
|
|
*
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
|
2016-06-26 10:10:37 +00:00
|
|
|
all(...args) {
|
2017-01-14 14:02:50 +00:00
|
|
|
const {middleware} = toParameters(args);
|
|
|
|
if (!middleware) {
|
|
|
|
throw new TypeError(error_middleware_message);
|
2016-06-26 10:10:37 +00:00
|
|
|
}
|
|
|
|
|
2016-07-14 13:14:16 +00:00
|
|
|
for (const method of HTTP_METHODS) {
|
2016-06-26 10:10:37 +00:00
|
|
|
this[method.toLowerCase()](...args);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 13:14:16 +00:00
|
|
|
for (const method of HTTP_METHODS) {
|
2016-07-15 19:34:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use the given middleware function or object, with optional _uri_ on
|
|
|
|
* HTTP methods: get, post, put, delete...
|
|
|
|
* Default _uri_ is "/".
|
|
|
|
*
|
|
|
|
* // middleware function will be applied on path "/"
|
|
|
|
* router.get((req, res, next) => {console.log('Hello')});
|
|
|
|
*
|
|
|
|
* // middleware object will be applied on path "/" and
|
|
|
|
* router.get(new Middleware());
|
|
|
|
*
|
|
|
|
* // middleware function will be applied on path "/user"
|
|
|
|
* router.post('/user', (req, res, next) => {console.log('Hello')});
|
|
|
|
*
|
|
|
|
* // middleware object will be applied on path "/user" and
|
|
|
|
* router.post('/user', new Middleware());
|
|
|
|
*
|
2016-07-23 08:48:26 +00:00
|
|
|
* @param {String} uri
|
|
|
|
* @param {Middleware|Function} middleware object or function
|
2016-07-15 19:34:24 +00:00
|
|
|
* @return {Router} for chaining
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
|
2016-06-26 10:10:37 +00:00
|
|
|
const methodName = method.toLowerCase();
|
|
|
|
Router.prototype[methodName] = function(...args) {
|
2017-01-14 14:02:50 +00:00
|
|
|
const {baseUri, middleware} = toParameters(args);
|
|
|
|
if (!middleware) {
|
|
|
|
throw new TypeError(error_middleware_message);
|
2016-07-02 13:45:54 +00:00
|
|
|
}
|
|
|
|
|
2017-01-14 14:02:50 +00:00
|
|
|
if (baseUri && this._baseUri && this._baseUri instanceof RegExp) {
|
|
|
|
throw new TypeError('router cannot mix uri/regexp');
|
2016-06-26 10:10:37 +00:00
|
|
|
}
|
|
|
|
|
2017-01-14 14:02:50 +00:00
|
|
|
this._add(new Route(this, baseUri, method, middleware));
|
2016-06-26 10:10:37 +00:00
|
|
|
|
|
|
|
return this;
|
2016-07-09 22:58:03 +00:00
|
|
|
};
|
2016-06-26 10:10:37 +00:00
|
|
|
}
|