-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpipeline.ts
133 lines (98 loc) · 3.61 KB
/
pipeline.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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//@ts-nocheck
import { afterEach } from "node:test";
export type Args<T = unknown> = ReadonlyArray<T>;
export type Middleware<I extends Args = unknown[], O = unknown> = (...inputs: I) => O
export type Middlewares<I extends Args = unknown[], O = unknown> = Middleware<I, O>[]
export type PipelineLike<I extends Args = unknown[], O = unknown> = { middlewares: Middlewares<I, O> }
export type MiddlewareInput<I extends Args = unknown[], O = unknown> =
| Middleware<I, O>
| Middlewares<I, O>
| PipelineLike<I, O>
export function isMiddleware<I extends Args, O>(input: unknown): input is Middleware<I, O> {
return typeof input === 'function';
}
export function isMiddlewares<I extends Args, O>(input: unknown): input is Middlewares<I, O> {
return Array.isArray(input);
}
export function isPipelineLike<I extends Args, O>(input: unknown): input is PipelineLike<I, O> {
return typeof input === 'object' && input !== null && 'middlewares' in input;
}
export function getMiddlewares<I extends Args, O>(
input: MiddlewareInput<I, O>
): Middlewares<I, O> {
if (isMiddleware<I, O>(input))
return [input]
if (isMiddlewares<I, O>(input))
return input.flatMap(getMiddlewares);
if (isPipelineLike<I, O>(input))
return getMiddlewares(input.middlewares);
throw new Error(`The provided input is of type ${input}, but a Middleware, Middlewares array,
or PipelineLike object was expected.`);
}
export abstract class Pipeline<I extends Args = unknown[], O = unknown> implements PipelineLike<I, O> {
public readonly middlewares: Middlewares<I, O> = [];
public use(...inputs: MiddlewareInput<I, O>[]): Pipeline<I, O> {
this.middlewares.push(...inputs.flatMap(getMiddlewares));
return this as Pipeline<I, O>;
}
public run(...inputs: I): O | void {
return this.dispatch(0, inputs)
}
public abstract dispatch(index: number, inputs: I): O;
}
// export class SyncHook<I extends Args = unknown[], O = unknown> extends Pipeline<I, O> {
// public dispatch(index: number, input: I): void {
// if (index >= this.middlewares.length) return;
// this.middlewares[index](input)
// this.dispatch(index + 1, input)
// }
// }
// export class SyncBailHook<I = unknown, O = unknown> extends Pipeline<I, O> {
// public dispatch(index: number, input: I): void {
// if (index >= this.middlewares.length) return;
// const middleware = this.middlewares[index]
// const result = middleware(input)
// result === undefined && this.dispatch(index + 1, input)
// }
// }
export class SyncWaterfallHook<I extends Args = unknown[], O = unknown> extends Pipeline<I, O> {
public dispatch(index: number, inputs: I): void {
if (index >= this.middlewares.length) return;
const middleware = this.middlewares[index]
const result = middleware(...inputs)
this.dispatch(index + 1, result === undefined ? inputs : [result, ...inputs])
}
}
export type Hook = () => void
export type Api = () => void
export type PluginOptions<Setup = undefined> = {
name?: string;
pre?: string[];
post?: string[];
rivals?: string[];
required?: string[];
setup?: Setup;
}
export type Setup<Hooks, API, Context> = (
api: API,
context: Context
) => void;
export type Plugin = Required<PluginOptions<Setup>>
export class Pluggable<
H extends Record<string, Hook>,
A extends Record<string, Api>
> {
public readonly plugins: Map<string, Plugin> = new Map()
public constructor(
public readonly hooks?: Partial<H>,
public readonly api?: A
) {
}
public addPlugin() { }
public usePlugin() { }
public createPlugin() { }
public start() { }
public reset(): void {
this.plugins.clear()
}
}