-
Notifications
You must be signed in to change notification settings - Fork 12k
/
Copy pathdispatcher.ts
78 lines (68 loc) · 2.71 KB
/
dispatcher.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import { JsonValue } from '@angular-devkit/core';
import { Job, JobDescription, JobHandler, JobHandlerContext, JobName, isJobHandler } from './api';
import { JobDoesNotExistException } from './exception';
import { Readwrite } from './types';
/**
* A JobDispatcher can be used to dispatch between multiple jobs.
*/
export interface JobDispatcher<A extends JsonValue, I extends JsonValue, O extends JsonValue>
extends JobHandler<A, I, O> {
/**
* Set the default job if all conditionals failed.
* @param name The default name if all conditions are false.
*/
setDefaultJob(name: JobName | null | JobHandler<JsonValue, JsonValue, JsonValue>): void;
/**
* Add a conditional job that will be selected if the input fits a predicate.
* @param predicate
* @param name
*/
addConditionalJob(predicate: (args: A) => boolean, name: string): void;
}
/**
* OnReady a dispatcher that can dispatch to a sub job, depending on conditions.
* @param options
*/
export function createDispatcher<A extends JsonValue, I extends JsonValue, O extends JsonValue>(
options: Partial<Readwrite<JobDescription>> = {},
): JobDispatcher<A, I, O> {
let defaultDelegate: JobName | null = null;
const conditionalDelegateList: [(args: JsonValue) => boolean, JobName][] = [];
const job: JobHandler<JsonValue, JsonValue, JsonValue> = Object.assign(
(argument: JsonValue, context: JobHandlerContext) => {
const maybeDelegate = conditionalDelegateList.find(([predicate]) => predicate(argument));
let delegate: Job<JsonValue, JsonValue, JsonValue> | null = null;
if (maybeDelegate) {
delegate = context.scheduler.schedule(maybeDelegate[1], argument);
} else if (defaultDelegate) {
delegate = context.scheduler.schedule(defaultDelegate, argument);
} else {
throw new JobDoesNotExistException('<null>');
}
context.inboundBus.subscribe(delegate.inboundBus);
return delegate.outboundBus;
},
{
jobDescription: options,
},
);
return Object.assign(job, {
setDefaultJob(name: JobName | null | JobHandler<JsonValue, JsonValue, JsonValue>) {
if (isJobHandler(name)) {
name = name.jobDescription.name === undefined ? null : name.jobDescription.name;
}
defaultDelegate = name;
},
addConditionalJob(predicate: (args: JsonValue) => boolean, name: JobName) {
conditionalDelegateList.push([predicate, name]);
},
// TODO: Remove return-only generic from createDispatcher() API.
}) as unknown as JobDispatcher<A, I, O>;
}