import {Collection, ErrorWithContext} from '../../util' import {AppClass} from '../../lifecycle/AppClass' import {Container, Instantiable} from '../../di' import {Logging} from '../../service/Logging' import {Middleware} from './Middleware' /** * Class that defines a group of Routes in the application, with a prefix. */ export class RouteGroup extends AppClass { protected preflight: Collection> = new Collection() protected postflight: Collection> = new Collection() /** * 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 } = {} /** * 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: Instantiable): this { this.preflight.prepend(middleware) return this } /** Register the given middleware to be applied after all routes in this group. */ post(middleware: Instantiable): this { this.postflight.push(middleware) return this } getPreflight(): Collection> { return this.preflight } getPostflight(): Collection> { return this.postflight } }