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