UNPKG

@akala/core

Version:
140 lines (127 loc) 5.4 kB
import { type Middleware, type SpecialNextParam, convertToMiddleware } from '../middlewares/shared.js'; import { MiddlewareComposite } from '../middlewares/composite-sync.js'; import { MiddlewareRoute, type Routable, type RouteBuilder, type RouteBuilderArguments } from './route.js'; import { each } from '../each.js'; import type { UriTemplate } from '../uri-template/index.js'; export interface RouterOptions { caseSensitive?: boolean; mergeParams?: boolean; strict?: boolean; length?: number; separator?: string; name?: string; } export type Routes<T extends [Routable, ...unknown[]], TReturnType, TSpecialNextParam extends SpecialNextParam = SpecialNextParam> = { [key: string]: ((...args: T) => TReturnType) | Routes<T, TReturnType, TSpecialNextParam> }; export type ParamCallback<T> = (req, paramVal: unknown, name: string, ...rest) => Promise<T>; /** * Use routes. * @param {Routes<T, TReturnType>} routes - The routes. * @param {MiddlewareComposite<T> & { route: RouteBuilder<T> }} [parent] - The parent middleware composite. * @returns {MiddlewareComposite<T>} The middleware composite. */ export function useRoutes<T extends [Routable, ...unknown[]], TReturnType, TSpecialNextParam extends SpecialNextParam = SpecialNextParam>(routes: Routes<T, TReturnType, TSpecialNextParam>, parent?: MiddlewareComposite<T> & { route: RouteBuilder<T, TSpecialNextParam> }): MiddlewareComposite<T> { if (!parent) parent = Object.assign(new MiddlewareComposite<T, TSpecialNextParam>('byroutes'), { route(...args: RouteBuilderArguments) { return new MiddlewareRoute<T, TSpecialNextParam>(...args) } }); each(routes, (route: ((...args: T) => TReturnType) | Routes<T, TReturnType, TSpecialNextParam>, match) => { if (typeof match == 'number') return; const routed = new MiddlewareRoute<T, TSpecialNextParam>(match as string); if (typeof (route) == 'object') { useRoutes(route, routed); } else routed.useMiddleware(convertToMiddleware<T, TSpecialNextParam>(route)); parent.useMiddleware(routed); }); return parent; } /** * Router class. * @template T * @extends {MiddlewareComposite<T>} * @implements {Middleware<T>} */ export class Router<T extends [{ path: string, params?: Record<string, unknown> }, ...unknown[]], TSpecialNextParam extends SpecialNextParam = SpecialNextParam> extends MiddlewareComposite<T, TSpecialNextParam> implements Middleware<T, TSpecialNextParam> { /** * Creates an instance of Router. * @param {RouterOptions} [options] - The router options. */ constructor(options?: RouterOptions) { super(options && options.name); } /** * Creates a new route. * @param {...RouteBuilderArguments} args - The route builder arguments. * @returns {MiddlewareRoute<T>} The middleware route. */ public route(...args: RouteBuilderArguments): MiddlewareRoute<T, TSpecialNextParam> { return new MiddlewareRoute<T, TSpecialNextParam>(...args); } /** * Uses routes. * @param {Routes<T, unknown>} routes - The routes. * @returns {this} The router instance. */ public useRoutes(routes: Routes<T, unknown, TSpecialNextParam>): this { useRoutes(routes, this); return this; } /** * Uses middleware. * @param {string | UriTemplate} route - The route. * @param {...Middleware<T>} middlewares - The middlewares. * @returns {this} The router instance. */ public useMiddleware(route: string | UriTemplate, ...middlewares: Middleware<T, TSpecialNextParam>[]): this public useMiddleware(...middlewares: Middleware<T, TSpecialNextParam>[]): this public useMiddleware(route: string | UriTemplate | Middleware<T, TSpecialNextParam>, ...middlewares: Middleware<T, TSpecialNextParam>[]): this { if (typeof route === 'string' || Array.isArray(route)) { const routed = new MiddlewareRoute<T, TSpecialNextParam>(route); routed.useMiddleware(...middlewares); super.useMiddleware(routed); } else super.useMiddleware(route, ...middlewares); return this; } /** * Uses middleware. * @param {string | UriTemplate} route - The route. * @param {...((...args: T) => unknown)} middlewares - The middlewares. * @returns {this} The router instance. */ public use(route: string | UriTemplate, ...middlewares: ((...args: T) => unknown)[]): this public use(...middlewares: ((...args: T) => unknown)[]): this public use(route: string | UriTemplate | ((...args: T) => unknown), ...middlewares: ((...args: T) => unknown)[]): this { if (typeof route === 'string' || Array.isArray(route)) { const routed = new MiddlewareRoute<T, TSpecialNextParam>(route); routed.use(...middlewares); super.useMiddleware(routed); return this; } else return super.use(route, ...middlewares); } } // // create Router#VERB functions // methods.concat('all').forEach(function (method) // { // Router.prototype[method] = function (path) // { // var route = this.route(path) // route[method].apply(route, slice.call(arguments, 1)) // return this // } // })