UNPKG

@appolo/router

Version:
169 lines (113 loc) 4.47 kB
import {IOptions} from "./IOptions"; import {Methods} from "./enums"; import {Tree} from "./tree"; import {Util} from "./util"; import {Params} from "./leaf"; export class Router { private _forest: { [index: string]: Tree } = {}; private _staticRoutes: { [index: string]: { [index: string]: any } } = {}; private _cachedRoutes: { [index: string]: Map<string, { params: Params, handler: any }> } = {}; private readonly _options: IOptions; private readonly _useCache: boolean; public constructor(options?: IOptions) { this._options = Object.assign({ useCache: true, decodeUrlParams: false, maxCacheSize: 10000 }, options || {}); this._useCache = this._options.useCache; this.reset(); } public reset() { Object.keys(Methods) .forEach(method => this._forest[method] = new Tree(this._options)); Object.keys(Methods) .forEach(method => this._staticRoutes[method] = {}); Object.keys(Methods) .forEach(method => this._cachedRoutes[method] = new Map<string, { params: Params, handler: any }>()); } public get(path: string, handler: any): this { return this.add(Methods.GET, path, handler); } public post(path: string, handler: any): this { return this.add(Methods.POST, path, handler); } public put(path: string, handler: any): this { return this.add(Methods.PUT, path, handler); } public patch(path: string, handler: any): this { return this.add(Methods.PATCH, path, handler); } public delete(path: string, handler: any): this { return this.add(Methods.DELETE, path, handler); } public head(path: string, handler: any): this { return this.add(Methods.HEAD, path, handler); } public add(method: keyof typeof Methods | (keyof typeof Methods)[], path: string, handler: any): this { path = Util.removeHeadSlash(path); this._add(method, path, handler); return this; } private _add(method: keyof typeof Methods | (keyof typeof Methods)[], path: string, handler: any): this { path = Util.removeTailSlash(path); let parts = path.split("/"); let methods = Array.isArray(method) ? method : [method]; methods.forEach(method => { let tree = this._forest[method]; let leaf = tree.add(parts); leaf.handler = handler; if (Util.isStaticRoute(path)) { this._staticRoutes[method][`/${path}`] = handler; this._staticRoutes[method][`/${path}/`] = handler; } }); return this } public remove(method: keyof typeof Methods | (keyof typeof Methods)[], path: string) { path = Util.removeTailSlash(path); path = Util.removeHeadSlash(path); let methods = Array.isArray(method) ? method : [method]; let parts = path.split("/"); methods.forEach(method => { let tree = this._forest[method]; tree.remove(parts, 0); if (Util.isStaticRoute(path)) { delete this._staticRoutes[method][`/${path}`]; delete this._staticRoutes[method][`/${path}/`]; } this._cachedRoutes[method].delete(`/${path}`); this._cachedRoutes[method].delete(`/${path}/`); }); } public find(method: keyof typeof Methods, path: string): { params: Params, handler: any } { let staticRote = this._staticRoutes[method][path]; if (staticRote) { return {handler: staticRote, params: {}} } let map = this._cachedRoutes[method]; if (this._useCache) { let cached = map.get(path); if (cached) { return {handler: cached.handler, params: cached.params} } } let parts = path.split("/"); //remove "/" if (parts[parts.length - 1] == "") { parts.pop(); } let tree = this._forest[method]; let params = {}; let found = tree.check(parts, 0, params); if (!found) { return null; } let dto = {params, handler: found.handler}; map.set(path, dto); if(map.size > this._options.maxCacheSize){ map.delete(map.keys().next().value) } return dto; } }