@modern-js/plugin 1.0.0 → 1.1.2

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 (107) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -4
  3. package/dist/js/modern/index.js +2 -3
  4. package/dist/js/modern/manager/async.js +1 -1
  5. package/dist/js/modern/manager/runner.js +1 -1
  6. package/dist/js/modern/manager/sync.js +1 -6
  7. package/dist/js/modern/waterfall/async.js +28 -34
  8. package/dist/js/modern/waterfall/sync.js +29 -36
  9. package/dist/js/modern/workflow/async.js +31 -30
  10. package/dist/js/modern/workflow/parallel.js +20 -29
  11. package/dist/js/modern/workflow/sync.js +20 -27
  12. package/dist/js/node/index.js +12 -25
  13. package/dist/js/node/manager/async.js +4 -4
  14. package/dist/js/node/manager/runner.js +2 -2
  15. package/dist/js/node/manager/sync.js +6 -12
  16. package/dist/js/node/waterfall/async.js +27 -34
  17. package/dist/js/node/waterfall/sync.js +29 -36
  18. package/dist/js/node/workflow/async.js +30 -30
  19. package/dist/js/node/workflow/parallel.js +19 -29
  20. package/dist/js/node/workflow/sync.js +19 -27
  21. package/dist/js/treeshaking/index.js +2 -3
  22. package/dist/js/treeshaking/manager/async.js +1 -1
  23. package/dist/js/treeshaking/manager/runner.js +1 -1
  24. package/dist/js/treeshaking/manager/sync.js +1 -6
  25. package/dist/js/treeshaking/waterfall/async.js +63 -108
  26. package/dist/js/treeshaking/waterfall/sync.js +36 -39
  27. package/dist/js/treeshaking/workflow/async.js +89 -88
  28. package/dist/js/treeshaking/workflow/parallel.js +42 -66
  29. package/dist/js/treeshaking/workflow/sync.js +50 -30
  30. package/dist/types/index.d.ts +2 -3
  31. package/dist/types/manager/runner.d.ts +1 -1
  32. package/dist/types/manager/sync.d.ts +2 -3
  33. package/dist/types/waterfall/async.d.ts +9 -5
  34. package/dist/types/waterfall/sync.d.ts +4 -4
  35. package/dist/types/workflow/async.d.ts +3 -2
  36. package/dist/types/workflow/parallel.d.ts +1 -1
  37. package/dist/types/workflow/sync.d.ts +1 -1
  38. package/node.d.ts +1 -1
  39. package/node.js +1 -1
  40. package/package.json +5 -4
  41. package/src/index.ts +2 -2
  42. package/src/manager/async.ts +1 -1
  43. package/src/manager/runner.ts +1 -1
  44. package/src/manager/sync.ts +12 -16
  45. package/src/waterfall/async.ts +34 -49
  46. package/src/waterfall/sync.ts +26 -45
  47. package/src/workflow/async.ts +29 -33
  48. package/src/workflow/parallel.ts +17 -35
  49. package/src/workflow/sync.ts +13 -35
  50. package/tests/.eslintrc.js +6 -0
  51. package/tests/async.test.ts +7 -3
  52. package/tests/fixtures/async/base/foo.ts +0 -1
  53. package/tests/fixtures/async/base/fooManager.ts +1 -1
  54. package/tests/fixtures/async/core/index.ts +1 -1
  55. package/tests/fixtures/async/dynamic/bar.ts +0 -1
  56. package/tests/fixtures/async/dynamic/foo.ts +1 -1
  57. package/tests/fixtures/sync/base/foo.ts +0 -2
  58. package/tests/fixtures/sync/base/fooManager.ts +1 -1
  59. package/tests/fixtures/sync/core/index.ts +1 -1
  60. package/tests/fixtures/sync/dynamic/bar.ts +0 -1
  61. package/tests/fixtures/sync/dynamic/foo.ts +1 -1
  62. package/tests/pipeline.test.ts +4 -15
  63. package/tests/sync.test.ts +6 -2
  64. package/tests/waterfall.test.ts +1 -2
  65. package/dist/js/modern/asyncHooksImpl.js +0 -63
  66. package/dist/js/modern/asyncHooksInterface.js +0 -16
  67. package/dist/js/modern/context.js +0 -130
  68. package/dist/js/modern/counter.js +0 -40
  69. package/dist/js/modern/hook.js +0 -47
  70. package/dist/js/modern/pipeline/async.js +0 -97
  71. package/dist/js/modern/pipeline/index.js +0 -2
  72. package/dist/js/modern/pipeline/sync.js +0 -97
  73. package/dist/js/node/asyncHooksImpl.js +0 -82
  74. package/dist/js/node/asyncHooksInterface.js +0 -30
  75. package/dist/js/node/context.js +0 -164
  76. package/dist/js/node/counter.js +0 -52
  77. package/dist/js/node/hook.js +0 -57
  78. package/dist/js/node/pipeline/async.js +0 -110
  79. package/dist/js/node/pipeline/index.js +0 -31
  80. package/dist/js/node/pipeline/sync.js +0 -110
  81. package/dist/js/treeshaking/asyncHooksImpl.js +0 -65
  82. package/dist/js/treeshaking/asyncHooksInterface.js +0 -16
  83. package/dist/js/treeshaking/context.js +0 -137
  84. package/dist/js/treeshaking/counter.js +0 -74
  85. package/dist/js/treeshaking/hook.js +0 -51
  86. package/dist/js/treeshaking/pipeline/async.js +0 -165
  87. package/dist/js/treeshaking/pipeline/index.js +0 -2
  88. package/dist/js/treeshaking/pipeline/sync.js +0 -118
  89. package/dist/types/asyncHooksImpl.d.ts +0 -10
  90. package/dist/types/asyncHooksInterface.d.ts +0 -21
  91. package/dist/types/context.d.ts +0 -47
  92. package/dist/types/counter.d.ts +0 -22
  93. package/dist/types/hook.d.ts +0 -13
  94. package/dist/types/pipeline/async.d.ts +0 -35
  95. package/dist/types/pipeline/index.d.ts +0 -2
  96. package/dist/types/pipeline/sync.d.ts +0 -37
  97. package/src/asyncHooksImpl.ts +0 -64
  98. package/src/asyncHooksInterface.ts +0 -34
  99. package/src/context.ts +0 -184
  100. package/src/counter.ts +0 -78
  101. package/src/hook.ts +0 -46
  102. package/src/pipeline/async.ts +0 -155
  103. package/src/pipeline/index.ts +0 -2
  104. package/src/pipeline/sync.ts +0 -152
  105. package/tests/context.test.ts +0 -114
  106. package/tests/counter.test.ts +0 -32
  107. package/tests/hook.test.ts +0 -113
package/src/context.ts DELETED
@@ -1,184 +0,0 @@
1
- /**
2
- * Copyright Lucifier129 and other contributors.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file at
6
- * https://github.com/farrow-js/farrow/blob/master/LICENSE
7
- *
8
- */
9
-
10
- import { createHooks } from './hook';
11
-
12
- const ContextSymbol = Symbol('Context');
13
-
14
- export type Context<T = any> = {
15
- id: symbol;
16
- [ContextSymbol]: T;
17
- // create a new context equipped a new value
18
- create: (value: T) => Context<T>;
19
- // get context ref { value } for accessing context in current container of waterfall
20
- use: () => {
21
- value: T;
22
- };
23
- // get context value
24
- get: () => T;
25
- // set context value
26
- set: (value: T) => void;
27
- // assert context value is not null or undefined and return context value
28
- assert: () => Exclude<T, undefined | null>;
29
- };
30
-
31
- export const isContext = (input: any): input is Context =>
32
- Object.prototype.hasOwnProperty.call(input, ContextSymbol);
33
-
34
- type AssertContext = (input: any) => asserts input is Context;
35
-
36
- export const assertContext: AssertContext = input => {
37
- if (!isContext(input)) {
38
- throw new Error(`Expected Context, but received ${input}`);
39
- }
40
- };
41
-
42
- export const createContext = <T>(value: T) => {
43
- const id = Symbol('ContextID');
44
-
45
- // eslint-disable-next-line @typescript-eslint/no-shadow
46
- const create = (value: T): Context<T> => {
47
- const use = () => {
48
- // eslint-disable-next-line react-hooks/rules-of-hooks
49
- const container = useContainer();
50
- return Object.seal({
51
- get value() {
52
- return container.read(Context);
53
- },
54
- set value(v) {
55
- container.write(Context, v);
56
- },
57
- });
58
- };
59
- const get = () => {
60
- // eslint-disable-next-line react-hooks/rules-of-hooks
61
- const container = useContainer();
62
- return container.read(Context);
63
- };
64
- const set = (v: T) => {
65
- // eslint-disable-next-line react-hooks/rules-of-hooks
66
- const container = useContainer();
67
- container.write(Context, v);
68
- };
69
- const assert = () => {
70
- // eslint-disable-next-line @typescript-eslint/no-shadow
71
- const value = get();
72
- if (value === null || value === undefined) {
73
- throw new Error(
74
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
75
- `Expected value is not null or undefined, but got: ${value}`,
76
- );
77
- }
78
- return value as Exclude<T, null | undefined>;
79
- };
80
- const Context: Context<T> = {
81
- id,
82
- [ContextSymbol]: value,
83
- create,
84
- use,
85
- get,
86
- set,
87
- assert,
88
- };
89
- return Context;
90
- };
91
-
92
- return create(value);
93
- };
94
-
95
- export type ContextStorage = {
96
- [key: string]: Context;
97
- };
98
-
99
- export const ContainerSymbol = Symbol('Container');
100
-
101
- // eslint-disable-next-line @typescript-eslint/no-redeclare
102
- export type ContextSymbol = typeof ContainerSymbol;
103
-
104
- export const isContainer = (input: any): input is Container =>
105
- Boolean(input?.[ContainerSymbol]);
106
-
107
- type AssertContainer = (input: any) => asserts input is Container;
108
-
109
- export const assertContainer: AssertContainer = input => {
110
- if (!isContainer(input)) {
111
- throw new Error(`Expected Context, but received ${input}`);
112
- }
113
- };
114
-
115
- export type Container = {
116
- [ContainerSymbol]: true;
117
- read: <V>(Context: Context<V>) => V;
118
- write: <V>(Context: Context<V>, value: V) => void;
119
- };
120
-
121
- const createContextMap = (storage: ContextStorage) => {
122
- const contextMap = new Map<symbol, Context>();
123
-
124
- Object.values(storage).forEach(context => {
125
- contextMap.set(context.id, context);
126
- });
127
-
128
- return contextMap;
129
- };
130
-
131
- export const createContainer = (
132
- ContextStorage: ContextStorage = {},
133
- ): Container => {
134
- const contextMap = createContextMap(ContextStorage);
135
-
136
- const read: Container['read'] = context => {
137
- const target = contextMap.get(context.id);
138
- if (target) {
139
- return target[ContextSymbol];
140
- }
141
- return context[ContextSymbol];
142
- };
143
-
144
- const write: Container['write'] = (context, value) => {
145
- contextMap.set(context.id, context.create(value));
146
- };
147
-
148
- const container: Container = Object.freeze({
149
- [ContainerSymbol]: true,
150
- read,
151
- write,
152
- });
153
-
154
- return container;
155
- };
156
-
157
- export type ValueFromContext<C extends Context> = C extends Context<infer V>
158
- ? V
159
- : never;
160
-
161
- export type Hooks = {
162
- useContainer: () => Container;
163
- };
164
-
165
- const { run, hooks } = createHooks<Hooks>({
166
- useContainer: () => {
167
- throw new Error(
168
- `Can't call useContainer out of scope, it should be placed on top of the function`,
169
- );
170
- },
171
- });
172
-
173
- export const runHooks = run;
174
-
175
- export const { useContainer } = hooks;
176
-
177
- export const fromContainer = (container: Container): Hooks => ({
178
- useContainer: () => container,
179
- });
180
-
181
- export const runWithContainer = <F extends (...args: any) => any>(
182
- f: F,
183
- container: Container,
184
- ) => runHooks(f, fromContainer(container));
package/src/counter.ts DELETED
@@ -1,78 +0,0 @@
1
- /**
2
- * Copyright Lucifier129 and other contributors.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file at
6
- * https://github.com/farrow-js/farrow/blob/master/LICENSE
7
- *
8
- */
9
-
10
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
11
- export type Next<I = unknown, O = void> = (input?: I) => O;
12
-
13
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
14
- export type CounterCallback<I = unknown, O = void> = (
15
- index: number,
16
- input: I,
17
- next: Next<I, O>,
18
- ) => O;
19
-
20
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
21
- export type Counter<I = unknown, O = void> = {
22
- start: (input: I) => O;
23
- dispatch: (index: number, input: I) => O;
24
- };
25
-
26
- export const createCounter = <I, O>(
27
- callback: CounterCallback<I, O>,
28
- ): Counter<I, O> => {
29
- type Dispatch = Counter<I, O>['dispatch'];
30
- type Start = Counter<I, O>['start'];
31
-
32
- const dispatch: Dispatch = (index, input) => {
33
- const next = (nextInput = input) => dispatch(index + 1, nextInput);
34
- return callback(index, input, next);
35
- };
36
-
37
- const start: Start = input => dispatch(0, input);
38
-
39
- return {
40
- start,
41
- dispatch,
42
- };
43
- };
44
-
45
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
46
- export type AsyncNext<I = unknown, O = void> = (input: I) => Promise<O>;
47
-
48
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
49
- export type AsyncCounterCallback<I = unknown, O = void> = (
50
- index: number,
51
- input: I,
52
- next: AsyncNext<I, O>,
53
- ) => Promise<O>;
54
-
55
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
56
- export type AsyncCounter<I = unknown, O = void> = {
57
- start: (input: I) => Promise<O>;
58
- dispatch: (index: number, input: I) => Promise<O>;
59
- };
60
-
61
- export const createAsyncCounter = <I, O>(
62
- callback: AsyncCounterCallback<I, O>,
63
- ): AsyncCounter<I, O> => {
64
- type Dispatch = AsyncCounter<I, O>['dispatch'];
65
- type Start = AsyncCounter<I, O>['start'];
66
-
67
- const dispatch: Dispatch = async (index, input) => {
68
- const next = (nextInput = input) => dispatch(index + 1, nextInput);
69
- return callback(index, input, next);
70
- };
71
-
72
- const start: Start = input => dispatch(0, input);
73
-
74
- return {
75
- start,
76
- dispatch,
77
- };
78
- };
package/src/hook.ts DELETED
@@ -1,46 +0,0 @@
1
- /**
2
- * Copyright Lucifier129 and other contributors.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file at
6
- * https://github.com/farrow-js/farrow/blob/master/LICENSE
7
- *
8
- */
9
-
10
- import { Hooks, AnyFn, asyncHooks } from './asyncHooksInterface';
11
-
12
- export const createHooks = <HS extends Hooks>(defaultHooks: HS) => {
13
- let currentHooks = {} as HS;
14
-
15
- const hooks = {} as HS;
16
-
17
- for (const key in defaultHooks) {
18
- // eslint-disable-next-line @typescript-eslint/no-loop-func
19
- const f = ((...args) => {
20
- // eslint-disable-next-line @typescript-eslint/no-shadow
21
- const hooks =
22
- currentHooks === defaultHooks
23
- ? asyncHooks?.get() ?? defaultHooks
24
- : currentHooks;
25
- let handler = hooks[key];
26
- if (typeof handler !== 'function') {
27
- handler = defaultHooks[key];
28
- }
29
- return handler(...args);
30
- }) as HS[typeof key];
31
-
32
- hooks[key] = f;
33
- }
34
-
35
- const run = <F extends AnyFn>(f: F, implementations?: HS): ReturnType<F> => {
36
- try {
37
- currentHooks = implementations || defaultHooks;
38
- asyncHooks?.set(currentHooks);
39
- return f();
40
- } finally {
41
- currentHooks = defaultHooks;
42
- }
43
- };
44
-
45
- return { run, hooks };
46
- };
@@ -1,155 +0,0 @@
1
- /**
2
- * Copyright Lucifier129 and other contributors.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file at
6
- * https://github.com/farrow-js/farrow/blob/master/LICENSE
7
- *
8
- */
9
-
10
- import {
11
- createContainer,
12
- Container,
13
- fromContainer,
14
- runHooks,
15
- useContainer,
16
- Hooks,
17
- } from '../context';
18
-
19
- import { AsyncNext, createAsyncCounter } from '../counter';
20
-
21
- import type { PipelineOptions } from './sync';
22
-
23
- export type AsyncMiddleware<I = unknown, O = unknown> = (
24
- input: I,
25
- next: AsyncNext<I, O>,
26
- ) => O | Promise<O>;
27
-
28
- export type AsyncMiddlewares<I = unknown, O = unknown> = AsyncMiddleware<
29
- I,
30
- O
31
- >[];
32
-
33
- const ASYNC_PIPELINE_SYMBOL = Symbol('ASYNC_PIPELINE_SYMBOL');
34
- export const isAsyncPipeline = (input: any): input is AsyncPipeline =>
35
- Boolean(input?.[ASYNC_PIPELINE_SYMBOL]);
36
-
37
- export type RunAsyncPipelineOptions<I = unknown, O = unknown> = {
38
- container?: Container;
39
- onLast?: (input: I) => O | Promise<O>;
40
- };
41
-
42
- export type AsyncMiddlewareInput<I = unknown, O = unknown> =
43
- | AsyncMiddleware<I, O>
44
- | { middleware: AsyncMiddleware<I, O> };
45
-
46
- export type AsyncMiddlewareType<T extends AsyncMiddlewareInput> =
47
- T extends AsyncMiddlewareInput<infer I, infer O>
48
- ? AsyncMiddleware<I, O>
49
- : never;
50
-
51
- export const getAsyncMiddleware = <I, O>(input: AsyncMiddlewareInput<I, O>) => {
52
- if (typeof input === 'function') {
53
- return input;
54
- } else if (input && typeof input.middleware === 'function') {
55
- return input.middleware;
56
- }
57
- // eslint-disable-next-line @typescript-eslint/no-base-to-string,@typescript-eslint/restrict-template-expressions
58
- throw new Error(`${input} is not a Middleware or { middleware: Middleware }`);
59
- };
60
-
61
- export type AsyncPipeline<I = unknown, O = unknown> = {
62
- [ASYNC_PIPELINE_SYMBOL]: true;
63
- use: (...inputs: AsyncMiddlewareInput<I, O>[]) => AsyncPipeline<I, O>;
64
- run: (input: I, options?: RunAsyncPipelineOptions<I, O>) => Promise<O>;
65
- middleware: AsyncMiddleware<I, O>;
66
- };
67
-
68
- export const createAsyncPipeline = <I, O>(options?: PipelineOptions) => {
69
- const config = { ...options };
70
-
71
- const middlewares: AsyncMiddlewares<I, O> = [];
72
-
73
- const use: AsyncPipeline<I, O>['use'] = (...inputs) => {
74
- middlewares.push(...inputs.map(getAsyncMiddleware));
75
- return pipeline;
76
- };
77
-
78
- const createCurrentCounter = (
79
- hooks: Hooks,
80
- onLast?: (input: I) => O | Promise<O>,
81
- ) =>
82
- createAsyncCounter<I, O>(async (index, input, next) => {
83
- if (index >= middlewares.length) {
84
- if (onLast) {
85
- return onLast(input);
86
- }
87
- throw new Error(
88
- `Expect returning a value, but all middlewares just calling next()`,
89
- );
90
- }
91
-
92
- const middleware = middlewares[index];
93
- const result = await runHooks(async () => middleware(input, next), hooks);
94
-
95
- return result;
96
- });
97
-
98
- const currentContainer = createContainer(config.contexts);
99
- const currentHooks = fromContainer(currentContainer);
100
- const currentCounter = createCurrentCounter(currentHooks);
101
-
102
- // eslint-disable-next-line @typescript-eslint/no-shadow
103
- const run: AsyncPipeline<I, O>['run'] = (input, options) => {
104
- const container = options?.container ?? currentContainer;
105
- const hooks =
106
- container === currentContainer ? currentHooks : fromContainer(container);
107
- let counter =
108
- container === currentContainer
109
- ? currentCounter
110
- : createCurrentCounter(hooks);
111
-
112
- if (options?.onLast) {
113
- counter = createCurrentCounter(hooks, options.onLast);
114
- }
115
-
116
- const result = counter.start(input);
117
-
118
- return result;
119
- };
120
-
121
- const middleware: AsyncPipeline<I, O>['middleware'] = (input, next) => {
122
- // eslint-disable-next-line react-hooks/rules-of-hooks
123
- const container = useContainer();
124
- return run(input, {
125
- container,
126
- onLast: next,
127
- });
128
- };
129
-
130
- const pipeline: AsyncPipeline<I, O> = {
131
- [ASYNC_PIPELINE_SYMBOL]: true,
132
- use,
133
- run,
134
- middleware,
135
- };
136
-
137
- return pipeline;
138
- };
139
-
140
- export type AsyncPipelineInput<T extends AsyncPipeline> =
141
- T extends AsyncPipeline<infer I> ? I : never;
142
-
143
- export type AsyncPipelineOutput<T extends AsyncPipeline> =
144
- T extends AsyncPipeline<any, infer O> ? O : never;
145
-
146
- export const useAsyncPipeline = <I, O>(pipeline: AsyncPipeline<I, O>) => {
147
- const container = useContainer();
148
-
149
- const runPipeline = (
150
- input: I,
151
- options?: RunAsyncPipelineOptions<I, O>,
152
- ): Promise<O> => pipeline.run(input, { ...options, container });
153
-
154
- return runPipeline;
155
- };
@@ -1,2 +0,0 @@
1
- export * from './sync';
2
- export * from './async';
@@ -1,152 +0,0 @@
1
- /**
2
- * Copyright Lucifier129 and other contributors.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file at
6
- * https://github.com/farrow-js/farrow/blob/master/LICENSE
7
- *
8
- */
9
-
10
- import {
11
- createContainer,
12
- ContextStorage,
13
- Container,
14
- fromContainer,
15
- runHooks,
16
- useContainer,
17
- Hooks,
18
- } from '../context';
19
-
20
- import { Next, createCounter } from '../counter';
21
-
22
- export type Middleware<I = unknown, O = unknown> = (
23
- input: I,
24
- next: Next<I, O>,
25
- ) => O;
26
-
27
- export type Middlewares<I = unknown, O = unknown> = Middleware<I, O>[];
28
-
29
- const PIPELINE_SYMBOL = Symbol('PIPELINE_SYMBOL');
30
- export const isPipeline = (input: any): input is Pipeline =>
31
- Boolean(input?.[PIPELINE_SYMBOL]);
32
-
33
- export type PipelineOptions = {
34
- contexts?: ContextStorage;
35
- };
36
-
37
- export type RunPipelineOptions<I = unknown, O = unknown> = {
38
- container?: Container;
39
- onLast?: (input: I) => O;
40
- };
41
-
42
- export type MiddlewareInput<I = unknown, O = unknown> =
43
- | Middleware<I, O>
44
- | { middleware: Middleware<I, O> };
45
-
46
- export type MiddlewareType<T extends MiddlewareInput> =
47
- T extends MiddlewareInput<infer I, infer O> ? Middleware<I, O> : never;
48
-
49
- export const getMiddleware = <I, O>(input: MiddlewareInput<I, O>) => {
50
- if (typeof input === 'function') {
51
- return input;
52
- } else if (input && typeof input.middleware === 'function') {
53
- return input.middleware;
54
- }
55
- // eslint-disable-next-line @typescript-eslint/no-base-to-string,@typescript-eslint/restrict-template-expressions
56
- throw new Error(`${input} is not a Middleware or { middleware: Middleware }`);
57
- };
58
-
59
- export type Pipeline<I = unknown, O = unknown> = {
60
- [PIPELINE_SYMBOL]: true;
61
- use: (...inputs: MiddlewareInput<I, O>[]) => Pipeline<I, O>;
62
- run: (input: I, options?: RunPipelineOptions<I, O>) => O;
63
- middleware: Middleware<I, O>;
64
- };
65
-
66
- export const createPipeline = <I, O>(options?: PipelineOptions) => {
67
- const config = { ...options };
68
-
69
- const middlewares: Middlewares<I, O> = [];
70
-
71
- const use: Pipeline<I, O>['use'] = (...inputs) => {
72
- middlewares.push(...inputs.map(getMiddleware));
73
- return pipeline;
74
- };
75
-
76
- const createCurrentCounter = (hooks: Hooks, onLast?: (input: I) => O) =>
77
- createCounter<I, O>((index, input, next) => {
78
- if (index >= middlewares.length) {
79
- if (onLast) {
80
- return onLast(input);
81
- }
82
- throw new Error(
83
- `Expect returning a value, but all middlewares just calling next()`,
84
- );
85
- }
86
-
87
- const middleware = middlewares[index];
88
- const result = runHooks(() => middleware(input, next), hooks);
89
-
90
- return result;
91
- });
92
-
93
- const currentContainer = createContainer(config.contexts);
94
- const currentHooks = fromContainer(currentContainer);
95
- const currentCounter = createCurrentCounter(currentHooks);
96
-
97
- // eslint-disable-next-line @typescript-eslint/no-shadow
98
- const run: Pipeline<I, O>['run'] = (input, options) => {
99
- const container = options?.container ?? currentContainer;
100
- const hooks =
101
- container === currentContainer ? currentHooks : fromContainer(container);
102
- let counter =
103
- container === currentContainer
104
- ? currentCounter
105
- : createCurrentCounter(hooks);
106
-
107
- if (options?.onLast) {
108
- counter = createCurrentCounter(hooks, options.onLast);
109
- }
110
-
111
- const result = counter.start(input);
112
-
113
- return result;
114
- };
115
-
116
- const middleware: Pipeline<I, O>['middleware'] = (input, next) => {
117
- // eslint-disable-next-line react-hooks/rules-of-hooks
118
- const container = useContainer();
119
- return run(input, {
120
- container,
121
- onLast: next,
122
- });
123
- };
124
-
125
- const pipeline: Pipeline<I, O> = {
126
- [PIPELINE_SYMBOL]: true,
127
- use,
128
- run,
129
- middleware,
130
- };
131
-
132
- return pipeline;
133
- };
134
-
135
- export type PipelineInput<T extends Pipeline> = T extends Pipeline<infer I>
136
- ? I
137
- : never;
138
- export type PipelineOutput<T extends Pipeline> = T extends Pipeline<
139
- any,
140
- infer O
141
- >
142
- ? O
143
- : never;
144
-
145
- export const usePipeline = <I, O>(pipeline: Pipeline<I, O>) => {
146
- const container = useContainer();
147
-
148
- const runPipeline = (input: I, options?: RunPipelineOptions<I, O>): O =>
149
- pipeline.run(input, { ...options, container });
150
-
151
- return runPipeline;
152
- };