import {HTTP_METHODS} from './requester'; import Middleware from './middleware'; class Route { constructor(router, uriPart, method, middleware) { this.router = router; this.uriPart = uriPart; this.method = method; this.middleware = middleware; this.visited = false; } get uri() { if (!this.uriPart && !this.method) { return undefined; } if (this.uriPart instanceof RegExp) { return this.uriPart; } if (this.router.baseUri instanceof RegExp) { return this.router.baseUri; } if (this.router.baseUri && this.uriPart) { return (this.router.baseUri.trim() + this.uriPart.trim()).replace(/\/{2,}/, '/'); } if (this.router.baseUri) { return this.router.baseUri.trim(); } return this.uriPart; } } export default class Router { constructor(uri) { if (uri) { this._baseUri = uri; } this._routes = []; } set baseUri(uri) { if (!uri) { return; } if (!this._baseUri) { this._baseUri = uri; return; } if (this._baseUri instanceof RegExp) { throw new TypeError(`the router already contains a regexp uri ${this._baseUri.toString()} It cannot be mixed with ${uri.toString()}`); } if (uri instanceof RegExp) { throw new TypeError(`the router already contains an uri ${this._baseUri.toString()} It cannot be mixed with regexp ${uri.toString()}`); } } get baseUri() { return this._baseUri; } _add(route) { this._routes.push(route); return this; } routes(uri, method) { return this._routes.filter((route) => { if (!route.uri && !route.method) { return true; } if (route.method !== method) { return false; } if (!route.uri) { return true; } let uriToCheck = uri; //remove query string from uri to test const questionMarkIndex = uriToCheck.indexOf('?'); if (questionMarkIndex >= 0) { uriToCheck = uriToCheck.slice(0, questionMarkIndex); } //remove anchor from uri to test const hashIndex = uriToCheck.indexOf('#'); if (hashIndex >= 0) { uriToCheck = uriToCheck.slice(0, hashIndex); } if (route.uri instanceof RegExp) { return uriToCheck.match(route.uri); } return route.uri === uriToCheck; }); } visited() { return this._routes.filter((route) => { return route.visited; }); } use(middleware) { if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) { throw new TypeError('use method takes at least a middleware'); } this._add(new Route(this, undefined, undefined, middleware)); return this; } all(...args) { if (args.length === 0) { throw new TypeError('use all method takes at least a middleware'); } let middleware; if (args.length === 1) { [middleware,] = args; } else { [, middleware,] = args; } if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) { throw new TypeError('use all method takes at least a middleware'); } for (const method of Object.keys(HTTP_METHODS)) { this[method.toLowerCase()](...args); } return this; } } for (const method of Object.keys(HTTP_METHODS)) { const methodName = method.toLowerCase(); Router.prototype[methodName] = function(...args) { if (args.length === 0) { throw new TypeError(`use ${methodName} method takes at least a middleware`); } let uri, middleware; if (args.length === 1) { [middleware,] = args; } else { [uri, middleware,] = args; } if (!(middleware instanceof Middleware) && (typeof middleware !== 'function') ) { throw new TypeError(`use ${methodName} method takes at least a middleware`); } if (uri && this._baseUri && this._baseUri instanceof RegExp) { throw new TypeError('router contains a regexp cannot mix with route uri/regexp'); } this._add(new Route(this, uri, method, middleware)); return this; }; }