import {Collection, ErrorWithContext} from '../../util' import {AppClass} from '../../lifecycle/AppClass' import {RouteHandler} from './Route' import {Container} from '../../di' import {Logging} from '../../service/Logging' /** * Class that defines a group of Routes in the application, with a prefix. */ export class RouteGroup extends AppClass { /** * The current set of nested groups. This is used when compiling route groups. * @private */ private static currentGroupNesting: RouteGroup[] = [] /** * Mapping of group names to group registration functions. * @protected */ protected static namedGroups: {[key: string]: () => void } = {} /** * Array of middlewares that should apply to all routes in this group. * @protected */ protected middlewares: Collection<{ stage: 'pre' | 'post', handler: RouteHandler }> = new Collection<{stage: 'pre' | 'post'; handler: RouteHandler}>() /** * Get the current group nesting. */ public static getCurrentGroupHierarchy(): RouteGroup[] { return [...this.currentGroupNesting] } /** * Create a new named group that can be registered at a later time, by name. * * @example * ```typescript * RouteGroup.named('auth', () => { * Route.group('/auth', () => { * Route.get('/login', 'auth:Forms.getLogin') * }) * }) * ``` * * @param name * @param define */ public static named(name: string, define: () => void): void { if ( this.namedGroups[name] ) { Container.getContainer() .make(Logging) .warn(`Replacing named route group: ${name}`) } this.namedGroups[name] = define } /** * Register the routes from a named group by calling its registration function. * * @example * From the example above, we can register the auth `/auth/*` routes, like so: * ```typescript * RouteGroup.include('auth') * ``` * * @param name */ public static include(name: string): void { if (!this.namedGroups[name]) { throw new ErrorWithContext(`No route group exists with name: ${name}`, {name}) } this.namedGroups[name]() } constructor( /** Function to register routes for this group. */ public readonly group: () => void | Promise, /** The route prefix of this group. */ public readonly prefix: string, ) { super() } /** Register the given middleware to be applied before all routes in this group. */ pre(middleware: RouteHandler): this { this.middlewares.push({ stage: 'pre', handler: middleware, }) return this } /** Register the given middleware to be applied after all routes in this group. */ post(middleware: RouteHandler): this { this.middlewares.push({ stage: 'post', handler: middleware, }) return this } /** Return the middlewares that apply to this group. */ getGroupMiddlewareDefinitions(): Collection<{ stage: 'pre' | 'post', handler: RouteHandler }> { return this.middlewares } }