diff --git a/src/http/routing/RouteGroup.ts b/src/http/routing/RouteGroup.ts index 62c2836..19a0d0d 100644 --- a/src/http/routing/RouteGroup.ts +++ b/src/http/routing/RouteGroup.ts @@ -1,16 +1,39 @@ -import {Collection} from "@extollo/util" +import {Collection, ErrorWithContext} from "@extollo/util" import {AppClass} from "../../lifecycle/AppClass" import {RouteHandler} from "./Route" +import {Container} from "@extollo/di" +import {Logging} from "../../service/Logging"; export class RouteGroup extends AppClass { private static currentGroupNesting: RouteGroup[] = [] + protected static namedGroups: {[key: string]: () => void } = {} + protected middlewares: Collection<{ stage: 'pre' | 'post', handler: RouteHandler }> = new Collection<{stage: "pre" | "post"; handler: RouteHandler}>() public static getCurrentGroupHierarchy(): RouteGroup[] { return [...this.currentGroupNesting] } + public static named(name: string, define: () => void) { + if ( this.namedGroups[name] ) { + Container.getContainer() + .make(Logging) + .warn(`Replacing named route group: ${name}`) + } + + this.namedGroups[name] = define + } + + public static include(name: string) { + if (!this.namedGroups[name]) { + throw new ErrorWithContext(`No route group exists with name: ${name}`, {name}) + } + + this.namedGroups[name]() + } + + constructor( public readonly group: () => void | Promise, public readonly prefix: string diff --git a/src/service/Canonical.ts b/src/service/Canonical.ts index afc2170..f0f3868 100644 --- a/src/service/Canonical.ts +++ b/src/service/Canonical.ts @@ -2,7 +2,7 @@ * Base type for a canonical definition. */ import {Canon} from "./Canon"; -import {universalPath, UniversalPath} from "@extollo/util"; +import {universalPath, UniversalPath, ErrorWithContext} from "@extollo/util"; import {Logging} from "./Logging"; import {Inject} from "@extollo/di"; import * as nodePath from 'path' @@ -14,6 +14,8 @@ export interface CanonicalDefinition { imported: any, } +export type CanonicalResolver = (key: string) => T | undefined + /** * Base type for a canonical name reference. */ @@ -55,6 +57,12 @@ export abstract class Canonical extends Unit { */ protected loadedItems: { [key: string]: T } = {} + /** + * Object mapping canonical namespaces to resolver functions. + * @protected + */ + protected loadedNamespaces: { [key: string]: CanonicalResolver } = {} + /** * Resolve a canonical reference from its string form to a CanonicalReference. * @param {string} reference @@ -86,9 +94,36 @@ export abstract class Canonical extends Unit { } public get(key: string): T | undefined { + if ( key.startsWith('@') ) { + const [namespace, ...rest] = key.split(':') + key = rest.join(':') + + if ( !this.loadedNamespaces[namespace] ) { + throw new ErrorWithContext(`Unable to find namespace for ${this.canonicalItem}: ${namespace}`, { + canonicalItem: this.canonicalItem, + namespace, + key, + }) + } + + return this.loadedNamespaces[namespace](key) + } + return this.loadedItems[key] } + public registerNamespace(name: string, resolver: CanonicalResolver) { + if ( !name.startsWith('@') ) { + throw new ErrorWithContext(`Canonical namespaces must start with @.`, { name }) + } + + if ( this.loadedNamespaces[name] ) { + this.logging.warn(`Replacing canonical namespace resolver for: ${name}`) + } + + this.loadedNamespaces[name] = resolver + } + public async up() { for await ( const entry of this.path.walk() ) { if ( !entry.endsWith(this.suffix) ) {