/** @format */ import { Middleware, MiddlewareObj } from './middleware' import Composer from './composer' import Context from './context' type NonemptyReadonlyArray = readonly [T, ...T[]] type RouteFn = (ctx: TContext) => { route: string context?: Partial state?: Partial } | null /** @deprecated in favor of {@link Composer.dispatch} */ export class Router implements MiddlewareObj { private otherwiseHandler: Middleware = Composer.passThru() constructor( private readonly routeFn: RouteFn, public handlers = new Map>() ) { if (typeof routeFn !== 'function') { throw new Error('Missing routing function') } } on(route: string, ...fns: NonemptyReadonlyArray>) { if (fns.length === 0) { throw new TypeError('At least one handler must be provided') } this.handlers.set(route, Composer.compose(fns)) return this } otherwise(...fns: NonemptyReadonlyArray>) { if (fns.length === 0) { throw new TypeError('At least one otherwise handler must be provided') } this.otherwiseHandler = Composer.compose(fns) return this } middleware() { return Composer.lazy((ctx) => { const result = this.routeFn(ctx) if (result == null) { return this.otherwiseHandler } Object.assign(ctx, result.context) Object.assign(ctx.state, result.state) return this.handlers.get(result.route) ?? this.otherwiseHandler }) } }