UNPKG

1.53 kBPlain TextView Raw
1/** @format */
2
3import { Middleware, MiddlewareObj } from './middleware'
4import Composer from './composer'
5import Context from './context'
6
7type NonemptyReadonlyArray<T> = readonly [T, ...T[]]
8
9type RouteFn<TContext extends Context> = (
10 ctx: TContext
11) => {
12 route: string
13 context?: Partial<TContext>
14 state?: Partial<TContext['state']>
15} | null
16
17export class Router<C extends Context> implements MiddlewareObj<C> {
18 private otherwiseHandler: Middleware<C> = Composer.passThru()
19
20 constructor(
21 private readonly routeFn: RouteFn<C>,
22 public handlers = new Map<string, Middleware<C>>()
23 ) {
24 if (typeof routeFn !== 'function') {
25 throw new Error('Missing routing function')
26 }
27 }
28
29 on(route: string, ...fns: NonemptyReadonlyArray<Middleware<C>>) {
30 if (fns.length === 0) {
31 throw new TypeError('At least one handler must be provided')
32 }
33 this.handlers.set(route, Composer.compose(fns))
34 return this
35 }
36
37 otherwise(...fns: NonemptyReadonlyArray<Middleware<C>>) {
38 if (fns.length === 0) {
39 throw new TypeError('At least one otherwise handler must be provided')
40 }
41 this.otherwiseHandler = Composer.compose(fns)
42 return this
43 }
44
45 middleware() {
46 return Composer.lazy<C>((ctx) => {
47 const result = this.routeFn(ctx)
48 if (result == null) {
49 return this.otherwiseHandler
50 }
51 Object.assign(ctx, result.context)
52 Object.assign(ctx.state, result.state)
53 return this.handlers.get(result.route) ?? this.otherwiseHandler
54 })
55 }
56}
57
\No newline at end of file