import {Singleton, Inject} from '../di' import {UniversalPath, Collection} from '../util' import {Unit} from '../lifecycle/Unit' import {Logging} from './Logging' import {Route} from '../http/routing/Route' import {HTTPMethod} from '../http/lifecycle/Request' import {ViewEngineFactory} from '../views/ViewEngineFactory' import {ViewEngine} from '../views/ViewEngine' import {lib} from '../lib' /** * Application unit that loads the various route files from `app/http/routes` and pre-compiles the route handlers. */ @Singleton() export class Routing extends Unit { @Inject() protected readonly logging!: Logging protected compiledRoutes: Collection = new Collection() public async up(): Promise { this.app().registerFactory(new ViewEngineFactory()) const engine = this.make(ViewEngine) this.logging.verbose('Registering @extollo view engine namespace.') engine.registerNamespace('extollo', lib().concat('resources', 'views')) for await ( const entry of this.path.walk() ) { if ( !entry.endsWith('.routes.js') ) { this.logging.debug(`Skipping routes file with invalid suffix: ${entry}`) continue } this.logging.info(`Importing routes from: ${entry}`) await import(entry) } this.logging.info('Compiling routes...') this.compiledRoutes = new Collection(await Route.compile()) this.logging.info(`Compiled ${this.compiledRoutes.length} route(s).`) this.compiledRoutes.each(route => { this.logging.verbose(`${route}`) }) } /** * Given an HTTPMethod and route path, return the Route instance that matches them, * if one exists. * @param method * @param path */ public match(method: HTTPMethod, path: string): Route | undefined { return this.compiledRoutes.firstWhere(route => { return route.match(method, path) }) } /** * Get the universal path to the root directory of the route definitions. */ public get path(): UniversalPath { return this.app().appPath('http', 'routes') } /** * Get the collection of compiled routes. */ public getCompiled(): Collection { return this.compiledRoutes } }