@modern-js/plugin 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/js/modern/manager/async.js +53 -26
  3. package/dist/js/modern/manager/index.js +2 -1
  4. package/dist/js/modern/manager/sync.js +73 -58
  5. package/dist/js/modern/manager/types.js +0 -0
  6. package/dist/js/modern/waterfall/async.js +6 -7
  7. package/dist/js/modern/waterfall/sync.js +2 -3
  8. package/dist/js/modern/workflow/async.js +3 -4
  9. package/dist/js/modern/workflow/parallel.js +2 -2
  10. package/dist/js/modern/workflow/sync.js +2 -3
  11. package/dist/js/node/manager/async.js +51 -23
  12. package/dist/js/node/manager/index.js +13 -0
  13. package/dist/js/node/manager/sync.js +78 -56
  14. package/dist/js/node/manager/types.js +0 -0
  15. package/dist/js/node/waterfall/async.js +6 -7
  16. package/dist/js/node/waterfall/sync.js +2 -3
  17. package/dist/js/node/workflow/async.js +3 -4
  18. package/dist/js/node/workflow/parallel.js +2 -2
  19. package/dist/js/node/workflow/sync.js +2 -3
  20. package/dist/js/treeshaking/manager/async.js +57 -32
  21. package/dist/js/treeshaking/manager/index.js +2 -1
  22. package/dist/js/treeshaking/manager/sync.js +79 -60
  23. package/dist/js/treeshaking/manager/types.js +0 -0
  24. package/dist/js/treeshaking/waterfall/async.js +6 -7
  25. package/dist/js/treeshaking/waterfall/sync.js +2 -3
  26. package/dist/js/treeshaking/workflow/async.js +4 -5
  27. package/dist/js/treeshaking/workflow/parallel.js +2 -2
  28. package/dist/js/treeshaking/workflow/sync.js +2 -3
  29. package/dist/types/manager/async.d.ts +60 -21
  30. package/dist/types/manager/index.d.ts +2 -1
  31. package/dist/types/manager/sync.d.ts +74 -43
  32. package/dist/types/manager/types.d.ts +41 -0
  33. package/dist/types/waterfall/async.d.ts +2 -2
  34. package/jest.config.js +8 -0
  35. package/modern.config.js +1 -9
  36. package/package.json +10 -5
  37. package/tests/async.test.ts +132 -14
  38. package/tests/fixtures/async/core/index.ts +12 -4
  39. package/tests/fixtures/async/dynamic/foo.ts +2 -2
  40. package/tests/fixtures/sync/core/index.ts +9 -4
  41. package/tests/fixtures/sync/dynamic/foo.ts +2 -2
  42. package/tests/pipeline.test.ts +2 -2
  43. package/tests/sync.test.ts +126 -13
  44. package/tests/tsconfig.json +1 -3
  45. package/tests/waterfall.test.ts +2 -2
  46. package/tests/workflow.test.ts +2 -2
  47. package/tsconfig.json +1 -3
  48. package/src/index.ts +0 -5
  49. package/src/manager/async.ts +0 -248
  50. package/src/manager/index.ts +0 -3
  51. package/src/manager/runner.ts +0 -15
  52. package/src/manager/sync.ts +0 -458
  53. package/src/waterfall/async.ts +0 -109
  54. package/src/waterfall/index.ts +0 -2
  55. package/src/waterfall/sync.ts +0 -110
  56. package/src/workflow/async.ts +0 -96
  57. package/src/workflow/index.ts +0 -3
  58. package/src/workflow/parallel.ts +0 -97
  59. package/src/workflow/sync.ts +0 -82
@@ -1,458 +0,0 @@
1
- // eslint-disable-next-line eslint-comments/disable-enable-pair
2
- /* eslint-disable max-lines */
3
- import {
4
- Middleware,
5
- Pipeline,
6
- isPipeline,
7
- createPipeline,
8
- AsyncPipeline,
9
- MaybeAsync,
10
- runWithContainer,
11
- createContainer,
12
- Container,
13
- } from 'farrow-pipeline';
14
- import {
15
- Waterfall,
16
- Brook,
17
- isWaterfall,
18
- createWaterfall,
19
- AsyncWaterfall,
20
- AsyncBrook,
21
- isAsyncWaterfall,
22
- createAsyncWaterfall,
23
- } from '../waterfall';
24
- import {
25
- Worker,
26
- Workflow,
27
- isWorkflow,
28
- createWorkflow,
29
- AsyncWorker,
30
- AsyncWorkflow,
31
- isAsyncWorkflow,
32
- createAsyncWorkflow,
33
- ParallelWorkflow,
34
- isParallelWorkflow,
35
- createParallelWorkflow,
36
- } from '../workflow';
37
- import { RunnerContext, useRunner } from './runner';
38
-
39
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
40
- export type Initializer<O> = () => O | void;
41
-
42
- const SYNC_PLUGIN_SYMBOL = 'SYNC_PLUGIN_SYMBOL';
43
-
44
- export type Plugin<O> = {
45
- initializer: Initializer<O>;
46
- SYNC_PLUGIN_SYMBOL: typeof SYNC_PLUGIN_SYMBOL;
47
- } & Required<PluginOptions>;
48
-
49
- export type IndexPlugin<O> = Plugin<O> & {
50
- index: number;
51
- };
52
-
53
- export type Plugins<O> = Plugin<O>[];
54
- export type IndexPlugins<O> = IndexPlugin<O>[];
55
-
56
- export type PluginOptions = {
57
- name?: string;
58
- pre?: string[];
59
- post?: string[];
60
- rivals?: string[];
61
- required?: string[];
62
- };
63
-
64
- export type Progress =
65
- | Waterfall<any>
66
- | AsyncWaterfall<any>
67
- | Workflow<any, any>
68
- | AsyncWorkflow<any, any>
69
- | ParallelWorkflow<any>
70
- | Pipeline<any, any>
71
- | AsyncPipeline<any, any>;
72
-
73
- export type Progress2Thread<P extends Progress> = P extends Workflow<
74
- infer I,
75
- infer O
76
- >
77
- ? Worker<I, O>
78
- : P extends AsyncWorkflow<infer I, infer O>
79
- ? AsyncWorker<I, O>
80
- : P extends ParallelWorkflow<infer I, infer O>
81
- ? AsyncWorker<I, O>
82
- : P extends Waterfall<infer I>
83
- ? Brook<I>
84
- : P extends AsyncWaterfall<infer I>
85
- ? AsyncBrook<I>
86
- : P extends Pipeline<infer I, infer O>
87
- ? Middleware<I, O>
88
- : P extends AsyncPipeline<infer I, infer O>
89
- ? Middleware<I, MaybeAsync<O>>
90
- : never;
91
-
92
- export type ProgressRecord = Record<string, Progress>;
93
-
94
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
95
- export type Progresses2Threads<PS extends ProgressRecord | void> = {
96
- [K in keyof PS]: PS[K] extends Progress
97
- ? Progress2Thread<PS[K]>
98
- : // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
99
- PS[K] extends void
100
- ? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
101
- void
102
- : never;
103
- };
104
-
105
- export type RunnerFromProgress<P extends Progress> = P extends Waterfall<
106
- infer I
107
- >
108
- ? Waterfall<I>['run']
109
- : P extends AsyncWaterfall<infer I>
110
- ? AsyncWaterfall<I>['run']
111
- : P extends Workflow<infer I, infer O>
112
- ? Workflow<I, O>['run']
113
- : P extends AsyncWorkflow<infer I, infer O>
114
- ? AsyncWorkflow<I, O>['run']
115
- : P extends ParallelWorkflow<infer I, infer O>
116
- ? ParallelWorkflow<I, O>['run']
117
- : P extends Pipeline<infer I, infer O>
118
- ? Pipeline<I, O>['run']
119
- : P extends AsyncPipeline<infer I, infer O>
120
- ? AsyncPipeline<I, O>['run']
121
- : never;
122
-
123
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
124
- export type Progresses2Runners<PS extends ProgressRecord | void> = {
125
- [K in keyof PS]: PS[K] extends Progress
126
- ? RunnerFromProgress<PS[K]>
127
- : // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
128
- PS[K] extends void
129
- ? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
130
- void
131
- : never;
132
- };
133
-
134
- export type ClearDraftProgress<I extends Record<string, any>> = {
135
- [K in keyof I]: I[K] extends Progress ? I[K] : never;
136
- };
137
-
138
- export type PluginFromManager<M extends Manager<any, any>> = M extends Manager<
139
- infer EP,
140
- infer PR
141
- >
142
- ? Plugin<Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>>
143
- : never;
144
- export type InitOptions = {
145
- container?: Container;
146
- };
147
- export type Manager<
148
- EP extends Record<string, any>,
149
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
150
- PR extends ProgressRecord | void = void,
151
- > = {
152
- createPlugin: (
153
- initializer: Initializer<
154
- Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>
155
- >,
156
- options?: PluginOptions,
157
- ) => Plugin<Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>>;
158
- isPlugin: (
159
- input: Record<string, unknown>,
160
- ) => input is Plugin<
161
- Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>
162
- >;
163
- usePlugin: (
164
- ...input: Plugins<Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>>
165
- ) => Manager<EP, PR>;
166
- init: (
167
- options?: InitOptions,
168
- ) => Progresses2Runners<PR & ClearDraftProgress<EP>>;
169
- run: <O>(cb: () => O, options?: InitOptions) => O;
170
- registe: (newShape: Partial<EP>) => void;
171
- clear: () => void;
172
- clone: () => Manager<EP, PR>;
173
- useRunner: () => Progresses2Runners<PR & ClearDraftProgress<EP>>;
174
- };
175
-
176
- export const DEFAULT_OPTIONS: Required<PluginOptions> = {
177
- name: 'untitled',
178
- pre: [],
179
- post: [],
180
- rivals: [],
181
- required: [],
182
- };
183
-
184
- export const createManager = <
185
- // eslint-disable-next-line @typescript-eslint/ban-types
186
- EP extends Record<string, any> = {},
187
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
188
- PR extends ProgressRecord | void = void,
189
- >(
190
- processes?: PR,
191
- ): Manager<EP, PR> => {
192
- let index = 0;
193
- const createPlugin: Manager<EP, PR>['createPlugin'] = (
194
- initializer,
195
- options = {},
196
- ) => ({
197
- ...DEFAULT_OPTIONS,
198
- name: `No.${index++} plugin`,
199
- ...options,
200
- SYNC_PLUGIN_SYMBOL,
201
- initializer,
202
- });
203
-
204
- const isPlugin: Manager<EP, PR>['isPlugin'] = (
205
- input,
206
- ): input is Plugin<
207
- Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>
208
- > =>
209
- hasOwnProperty(input, SYNC_PLUGIN_SYMBOL) &&
210
- input[SYNC_PLUGIN_SYMBOL] === SYNC_PLUGIN_SYMBOL;
211
-
212
- const registe: Manager<EP, PR>['registe'] = extraProcesses => {
213
- // eslint-disable-next-line no-param-reassign
214
- processes = {
215
- ...extraProcesses,
216
- ...processes,
217
- } as any;
218
- };
219
-
220
- const clone = () => {
221
- let plugins: IndexPlugins<
222
- Partial<Progresses2Threads<PR & ClearDraftProgress<EP>>>
223
- > = [];
224
-
225
- const usePlugin: Manager<EP, PR>['usePlugin'] = (...input) => {
226
- for (const plugin of input) {
227
- if (isPlugin(plugin)) {
228
- if (!includePlugin(plugins, plugin)) {
229
- plugins.push({
230
- ...plugin,
231
- index: plugins.length,
232
- });
233
- }
234
- } else {
235
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
236
- // @ts-expect-error
237
- console.warn(`Unknown plugin: ${plugin.name}`);
238
- }
239
- }
240
-
241
- return {
242
- createPlugin,
243
- isPlugin,
244
- usePlugin,
245
- init,
246
- run,
247
- clear,
248
- registe,
249
- useRunner,
250
- clone,
251
- };
252
- };
253
-
254
- const clear = () => {
255
- plugins = [];
256
- };
257
-
258
- const currentContainer = createContainer();
259
-
260
- const init: Manager<EP, PR>['init'] = options => {
261
- const container = options?.container || currentContainer;
262
-
263
- const sortedPlugins = sortPlugins(plugins);
264
-
265
- checkPlugins(sortedPlugins);
266
-
267
- const hooksList = sortedPlugins.map(plugin =>
268
- runWithContainer(() => plugin.initializer(), container),
269
- );
270
-
271
- return generateRunner<EP, PR>(hooksList, container, processes);
272
- };
273
-
274
- const run: Manager<EP, PR>['run'] = (cb, options) => {
275
- const container = options?.container || currentContainer;
276
-
277
- return runWithContainer(cb, container);
278
- };
279
-
280
- return {
281
- createPlugin,
282
- isPlugin,
283
- usePlugin,
284
- init,
285
- clear,
286
- run,
287
- registe,
288
- useRunner,
289
- clone,
290
- };
291
- };
292
-
293
- return clone();
294
- };
295
-
296
- export const generateRunner = <
297
- // eslint-disable-next-line @typescript-eslint/ban-types
298
- EP extends Record<string, any> = {},
299
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
300
- PR extends ProgressRecord | void = void,
301
- >(
302
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
303
- hooksList: (void | Partial<
304
- Progresses2Threads<PR & ClearDraftProgress<EP>>
305
- >)[],
306
- container: Container,
307
- processes?: PR,
308
- ): Progresses2Runners<PR & ClearDraftProgress<EP>> => {
309
- const runner = {};
310
- const cloneShape = cloneProgressRecord(processes);
311
-
312
- if (processes) {
313
- for (const key in cloneShape) {
314
- for (const hooks of hooksList) {
315
- if (!hooks) {
316
- continue;
317
- }
318
- if (hooks[key]) {
319
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
320
- // @ts-expect-error
321
- cloneShape[key].use(hooks[key]);
322
- }
323
- }
324
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
325
- // @ts-expect-error
326
- runner[key] = (input: any, options: any) =>
327
- (cloneShape[key] as any).run(input, {
328
- container,
329
- ...options,
330
- });
331
- }
332
- }
333
-
334
- container.write(RunnerContext, runner);
335
- return runner as any;
336
- };
337
-
338
- export const cloneProgress = (progress: Progress): Progress => {
339
- if (isWaterfall(progress)) {
340
- return createWaterfall();
341
- }
342
-
343
- if (isAsyncWaterfall(progress)) {
344
- return createAsyncWaterfall();
345
- }
346
-
347
- if (isWorkflow(progress)) {
348
- return createWorkflow();
349
- }
350
-
351
- if (isAsyncWorkflow(progress)) {
352
- return createAsyncWorkflow();
353
- }
354
-
355
- if (isParallelWorkflow(progress)) {
356
- return createParallelWorkflow();
357
- }
358
-
359
- if (isPipeline(progress)) {
360
- return createPipeline();
361
- }
362
-
363
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
364
- throw new Error(`Unknown progress: ${progress}`);
365
- };
366
-
367
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
368
- export const cloneProgressRecord = <PR extends ProgressRecord | void>(
369
- record: PR,
370
- ): PR => {
371
- if (!record) {
372
- return record;
373
- }
374
-
375
- const result: PR = {} as any;
376
-
377
- for (const key in record) {
378
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
379
- // @ts-expect-error
380
- result[key] = cloneProgress(record[key]);
381
- }
382
-
383
- return result;
384
- };
385
-
386
- const includePlugin = <O>(plugins: Plugins<O>, input: Plugin<O>): boolean => {
387
- for (const plugin of plugins) {
388
- if (plugin.name === input.name) {
389
- return true;
390
- }
391
- }
392
-
393
- return false;
394
- };
395
-
396
- const sortPlugins = <O>(input: IndexPlugins<O>): IndexPlugins<O> => {
397
- let plugins = input.slice();
398
-
399
- for (let i = 0; i < plugins.length; i++) {
400
- const plugin = plugins[i];
401
-
402
- for (const pre of plugin.pre) {
403
- for (let j = i + 1; j < plugins.length; j++) {
404
- if (plugins[j].name === pre) {
405
- plugins = [
406
- ...plugins.slice(0, i),
407
- plugins[j],
408
- ...plugins.slice(i, j),
409
- ...plugins.slice(j + 1, plugins.length),
410
- ];
411
- }
412
- }
413
- }
414
-
415
- for (const post of plugin.post) {
416
- for (let j = 0; j < i; j++) {
417
- if (plugins[j].name === post) {
418
- plugins = [
419
- ...plugins.slice(0, j),
420
- ...plugins.slice(j + 1, i + 1),
421
- plugins[j],
422
- ...plugins.slice(i + 1, plugins.length),
423
- ];
424
- }
425
- }
426
- }
427
- }
428
-
429
- return plugins;
430
- };
431
-
432
- const checkPlugins = <O>(plugins: Plugins<O>) => {
433
- for (const origin of plugins) {
434
- for (const rival of origin.rivals) {
435
- for (const plugin of plugins) {
436
- if (rival === plugin.name) {
437
- throw new Error(`${origin.name} has rival ${plugin.name}`);
438
- }
439
- }
440
- }
441
-
442
- for (const required of origin.required) {
443
- if (!plugins.some(plugin => plugin.name === required)) {
444
- throw new Error(
445
- `The plugin: ${required} is required when plugin: ${origin.name} is exist.`,
446
- );
447
- }
448
- }
449
- }
450
- };
451
-
452
- export const hasOwnProperty = <
453
- X extends Record<string, unknown>,
454
- Y extends PropertyKey,
455
- >(
456
- obj: X,
457
- prop: Y,
458
- ): obj is X & Record<Y, unknown> => obj.hasOwnProperty(prop);
@@ -1,109 +0,0 @@
1
- import {
2
- createAsyncPipeline,
3
- Middleware,
4
- MaybeAsync,
5
- Container,
6
- useContainer,
7
- } from 'farrow-pipeline';
8
-
9
- const ASYNC_WATERFALL_SYMBOL = Symbol('ASYNC_WATERFALL_SYMBOL');
10
-
11
- export type AsyncBrook<I = unknown> = (I: I) => MaybeAsync<I>;
12
- export type AsyncBrookInput<I = unknown> =
13
- | AsyncBrook<I>
14
- | { middlware: AsyncBrook<I> };
15
- export type AsyncBrooks<I = unknown> = AsyncBrook<I>[];
16
- export type AsyncBrookInputs<I = unknown> = AsyncBrookInput<I>[];
17
-
18
- export const getAsyncBrook = <I>(input: AsyncBrookInput<I>) => {
19
- if (typeof input === 'function') {
20
- return input;
21
- } else if (input && typeof input.middlware === 'function') {
22
- return input.middlware;
23
- }
24
- // eslint-disable-next-line @typescript-eslint/no-base-to-string,@typescript-eslint/restrict-template-expressions
25
- throw new Error(`${input} is not a AsyncBrook or { brook: AsyncBrook }`);
26
- };
27
-
28
- export type RunAsyncWaterfallOptions<I = unknown> = {
29
- container?: Container;
30
- onLast?: AsyncBrook<I>;
31
- };
32
-
33
- export type AsyncWaterfall<I> = {
34
- run: (input: I, options?: RunAsyncWaterfallOptions<I>) => MaybeAsync<I>;
35
- use: (...I: AsyncBrookInputs<I>) => AsyncWaterfall<I>;
36
- middlware: AsyncBrook<I>;
37
- [ASYNC_WATERFALL_SYMBOL]: true;
38
- };
39
-
40
- export type AsyncWaterfall2AsyncBrook<P extends AsyncWaterfall<any>> =
41
- P extends AsyncWaterfall<infer I> ? AsyncBrook<I> : never;
42
-
43
- export type AsyncWaterfallRecord = Record<string, AsyncWaterfall<any>>;
44
-
45
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
46
- export type AsyncWaterfalls2Brooks<PS extends AsyncWaterfallRecord | void> = {
47
- [K in keyof PS]: PS[K] extends AsyncWaterfall<any>
48
- ? AsyncWaterfall2AsyncBrook<PS[K]>
49
- : // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
50
- PS[K] extends void
51
- ? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
52
- void
53
- : never;
54
- };
55
-
56
- export type RunnerFromAsyncWaterfall<M extends AsyncWaterfall<any>> =
57
- M extends AsyncWaterfall<infer VS> ? AsyncWaterfall<VS>['run'] : never;
58
-
59
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
60
- export type AsyncWaterfalls2Runners<PS extends AsyncWaterfallRecord | void> = {
61
- [K in keyof PS]: PS[K] extends AsyncWaterfall<any>
62
- ? RunnerFromAsyncWaterfall<PS[K]>
63
- : // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
64
- PS[K] extends void
65
- ? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
66
- void
67
- : never;
68
- };
69
-
70
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
71
- export const createAsyncWaterfall = <I = void>(): AsyncWaterfall<I> => {
72
- const pipeline = createAsyncPipeline<I, I>();
73
-
74
- const use: AsyncWaterfall<I>['use'] = (...input) => {
75
- pipeline.use(
76
- ...input.map(getAsyncBrook).map(mapAsyncBrookToAsyncMiddleware),
77
- );
78
- return waterfall;
79
- };
80
-
81
- const run: AsyncWaterfall<I>['run'] = (input, options) =>
82
- // eslint-disable-next-line @typescript-eslint/no-shadow
83
- pipeline.run(input, { ...options, onLast: input => input });
84
-
85
- const middlware: AsyncWaterfall<I>['middlware'] = input => {
86
- // eslint-disable-next-line react-hooks/rules-of-hooks
87
- const container = useContainer();
88
- // eslint-disable-next-line @typescript-eslint/no-shadow
89
- return pipeline.run(input, { container, onLast: input => input });
90
- };
91
-
92
- const waterfall: AsyncWaterfall<I> = {
93
- ...pipeline,
94
- use,
95
- run,
96
- middlware,
97
- [ASYNC_WATERFALL_SYMBOL]: true as const,
98
- };
99
-
100
- return waterfall;
101
- };
102
-
103
- export const isAsyncWaterfall = (input: any): input is AsyncWaterfall<any> =>
104
- Boolean(input?.[ASYNC_WATERFALL_SYMBOL]);
105
-
106
- const mapAsyncBrookToAsyncMiddleware =
107
- <I>(brook: AsyncBrook<I>): Middleware<I, MaybeAsync<I>> =>
108
- async (input, next) =>
109
- next(await brook(input));
@@ -1,2 +0,0 @@
1
- export * from './sync';
2
- export * from './async';
@@ -1,110 +0,0 @@
1
- import {
2
- Container,
3
- useContainer,
4
- createPipeline,
5
- Middleware,
6
- } from 'farrow-pipeline';
7
-
8
- const WATERFALL_SYMBOL = Symbol('WATERFALL_SYMBOL');
9
-
10
- export type Brook<I = unknown> = (I: I) => I;
11
- export type BrookInput<I = unknown> = Brook<I> | { middleware: Brook<I> };
12
- export type Brooks<I = unknown> = Brook<I>[];
13
- export type BrookInputs<I = unknown> = BrookInput<I>[];
14
-
15
- export const getBrook = <I>(input: BrookInput<I>) => {
16
- if (typeof input === 'function') {
17
- return input;
18
- } else if (input && typeof input.middleware === 'function') {
19
- return input.middleware;
20
- }
21
- // eslint-disable-next-line @typescript-eslint/no-base-to-string,@typescript-eslint/restrict-template-expressions
22
- throw new Error(`${input} is not a Brook or { brook: Brook }`);
23
- };
24
-
25
- export type RunWaterfallOptions<I = unknown> = {
26
- container?: Container;
27
- onLast?: Brook<I>;
28
- };
29
-
30
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
31
- export type Waterfall<I = void> = {
32
- run: (input: I, options?: RunWaterfallOptions<I>) => I;
33
- use: (...I: BrookInputs<I>) => Waterfall<I>;
34
- middleware: Brook<I>;
35
- [WATERFALL_SYMBOL]: true;
36
- };
37
-
38
- export type Waterfall2Brook<P extends Waterfall<any>> = P extends Waterfall<
39
- infer I
40
- >
41
- ? Brook<I>
42
- : never;
43
-
44
- export type WaterfallRecord = Record<string, Waterfall<any>>;
45
-
46
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
47
- export type Waterfalls2Brooks<PS extends WaterfallRecord | void> = {
48
- [K in keyof PS]: PS[K] extends Waterfall<any>
49
- ? Waterfall2Brook<PS[K]>
50
- : // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
51
- PS[K] extends void
52
- ? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
53
- void
54
- : never;
55
- };
56
-
57
- export type RunnerFromWaterfall<M extends Waterfall<any>> = M extends Waterfall<
58
- infer VS
59
- >
60
- ? Waterfall<VS>['run']
61
- : never;
62
-
63
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
64
- export type Waterfalls2Runners<PS extends WaterfallRecord | void> = {
65
- [K in keyof PS]: PS[K] extends Waterfall<any>
66
- ? RunnerFromWaterfall<PS[K]>
67
- : // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
68
- PS[K] extends void
69
- ? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
70
- void
71
- : never;
72
- };
73
-
74
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
75
- export const createWaterfall = <I = void>(): Waterfall<I> => {
76
- const pipeline = createPipeline<I, I>();
77
-
78
- const use: Waterfall<I>['use'] = (...brooks) => {
79
- pipeline.use(...brooks.map(getBrook).map(mapBrookToMiddleware));
80
- return waterfall;
81
- };
82
-
83
- const run: Waterfall<I>['run'] = (input, options) =>
84
- // eslint-disable-next-line @typescript-eslint/no-shadow
85
- pipeline.run(input, { ...options, onLast: input => input });
86
-
87
- const middleware: Waterfall<I>['middleware'] = input => {
88
- // eslint-disable-next-line react-hooks/rules-of-hooks
89
- const container = useContainer();
90
- // eslint-disable-next-line @typescript-eslint/no-shadow
91
- return pipeline.run(input, { container, onLast: input => input });
92
- };
93
-
94
- const waterfall: Waterfall<I> = {
95
- ...pipeline,
96
- use,
97
- run,
98
- middleware,
99
- [WATERFALL_SYMBOL]: true,
100
- };
101
- return waterfall;
102
- };
103
-
104
- export const isWaterfall = (input: any): input is Waterfall<any> =>
105
- Boolean(input?.[WATERFALL_SYMBOL]);
106
-
107
- const mapBrookToMiddleware =
108
- <I>(brook: Brook<I>): Middleware<I, I> =>
109
- (input, next) =>
110
- next(brook(input));