@hpcc-js/dataflow 9.6.7 → 9.6.9
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.
- package/LICENSE +43 -43
- package/README.md +530 -530
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +3 -3
- package/src/__package__.ts +3 -3
- package/src/activities/activity.ts +8 -8
- package/src/activities/concat.ts +14 -14
- package/src/activities/each.ts +19 -19
- package/src/activities/entries.ts +17 -17
- package/src/activities/filter.ts +20 -20
- package/src/activities/first.ts +20 -20
- package/src/activities/group.ts +27 -27
- package/src/activities/histogram.ts +99 -99
- package/src/activities/join.ts +19 -19
- package/src/activities/map.ts +18 -18
- package/src/activities/normalize.ts +21 -21
- package/src/activities/skip.ts +18 -18
- package/src/activities/sort.ts +16 -16
- package/src/index.ts +27 -27
- package/src/observers/count.ts +15 -15
- package/src/observers/deviation.ts +24 -24
- package/src/observers/distribution.ts +51 -51
- package/src/observers/extent.ts +24 -24
- package/src/observers/max.ts +24 -24
- package/src/observers/mean.ts +26 -26
- package/src/observers/median.ts +30 -30
- package/src/observers/min.ts +24 -24
- package/src/observers/observer.ts +52 -52
- package/src/observers/quartile.ts +43 -43
- package/src/observers/reduce.ts +22 -22
- package/src/observers/variance.ts +29 -29
- package/src/utils/generate.ts +6 -6
- package/src/utils/pipe.ts +233 -233
package/src/utils/pipe.ts
CHANGED
|
@@ -1,233 +1,233 @@
|
|
|
1
|
-
import { IterableActivity, ScalarActivity, Source, isSource } from "../activities/activity.ts";
|
|
2
|
-
|
|
3
|
-
// =============================================================================
|
|
4
|
-
// Constants and Base Types
|
|
5
|
-
// =============================================================================
|
|
6
|
-
|
|
7
|
-
const GeneratorFunction = (function* () { }).constructor;
|
|
8
|
-
|
|
9
|
-
type AnyIterableActivity = IterableActivity<any, any>;
|
|
10
|
-
type AnyScalarActivity = ScalarActivity<any, any>;
|
|
11
|
-
type AnyActivity = AnyIterableActivity | AnyScalarActivity;
|
|
12
|
-
|
|
13
|
-
// =============================================================================
|
|
14
|
-
// Type Utilities for Activity Analysis
|
|
15
|
-
// =============================================================================
|
|
16
|
-
|
|
17
|
-
type ActivityIn<A extends AnyActivity> = Parameters<A>[0] extends Source<infer Input> ? Input : never;
|
|
18
|
-
type ActivityOut<A extends AnyActivity> = ReturnType<A> extends IterableIterator<infer Output> ? Output : ReturnType<A>;
|
|
19
|
-
type ActivityIsScalar<A extends AnyActivity> = ReturnType<A> extends IterableIterator<any> ? false : true;
|
|
20
|
-
|
|
21
|
-
type FirstActivity<Activities extends readonly [AnyActivity, ...AnyActivity[]]> = Activities[0];
|
|
22
|
-
|
|
23
|
-
// =============================================================================
|
|
24
|
-
// Type Resolution for Activity Chains (Without Source)
|
|
25
|
-
// =============================================================================
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Recursively resolves the output type of a chain of activities starting from an iterable activity.
|
|
29
|
-
* Validates that each activity's input type matches the previous activity's output type.
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
// Handle a scalar (non-iterable) activity in the chain
|
|
33
|
-
type ResolveScalarActivity<CurrentOut, InitialIn, Next extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
34
|
-
CurrentOut extends ActivityIn<Next>
|
|
35
|
-
? Rest extends []
|
|
36
|
-
? { kind: "scalar"; in: InitialIn; out: ActivityOut<Next> }
|
|
37
|
-
: { kind: "error" } // Scalar activities must be terminal
|
|
38
|
-
: { kind: "error" }; // Type mismatch
|
|
39
|
-
|
|
40
|
-
// Handle an iterable activity in the chain
|
|
41
|
-
type ResolveIterableActivity<CurrentOut, InitialIn, Next extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
42
|
-
CurrentOut extends ActivityIn<Next>
|
|
43
|
-
? ResolveIterableTail<ActivityOut<Next>, InitialIn, Rest>
|
|
44
|
-
: { kind: "error" }; // Type mismatch
|
|
45
|
-
|
|
46
|
-
// Process the next activity in the chain
|
|
47
|
-
type ResolveNextActivity<CurrentOut, InitialIn, Next extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
48
|
-
ActivityIsScalar<Next> extends true
|
|
49
|
-
? ResolveScalarActivity<CurrentOut, InitialIn, Next, Rest>
|
|
50
|
-
: ResolveIterableActivity<CurrentOut, InitialIn, Next, Rest>;
|
|
51
|
-
|
|
52
|
-
// Check if we've reached the end of the activity chain
|
|
53
|
-
type ResolveIterableTail<CurrentOut, InitialIn, Tail extends readonly AnyActivity[]> =
|
|
54
|
-
Tail extends []
|
|
55
|
-
? { kind: "iterable"; in: InitialIn; out: CurrentOut }
|
|
56
|
-
: Tail extends readonly [infer Next extends AnyActivity, ...infer Rest extends readonly AnyActivity[]]
|
|
57
|
-
? ResolveNextActivity<CurrentOut, InitialIn, Next, Rest>
|
|
58
|
-
: { kind: "error" };
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Resolves the complete type signature for a chain of activities without a source.
|
|
62
|
-
* Determines the input, output, and whether the final result is scalar or iterable.
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
// Handle when the first activity is scalar (must be the only activity)
|
|
66
|
-
type ResolveFirstScalarActivity<First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
67
|
-
Rest extends []
|
|
68
|
-
? { kind: "scalar"; in: ActivityIn<First>; out: ActivityOut<First> }
|
|
69
|
-
: { kind: "error" }; // Scalar activities cannot be followed by others
|
|
70
|
-
|
|
71
|
-
// Handle when the first activity is iterable
|
|
72
|
-
type ResolveFirstIterableActivity<First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
73
|
-
Rest extends []
|
|
74
|
-
? { kind: "iterable"; in: ActivityIn<First>; out: ActivityOut<First> }
|
|
75
|
-
: ResolveIterableTail<ActivityOut<First>, ActivityIn<First>, Rest>;
|
|
76
|
-
|
|
77
|
-
// Determine how to handle the first activity based on whether it's scalar or iterable
|
|
78
|
-
type ResolveFirstActivity<First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
79
|
-
ActivityIsScalar<First> extends true
|
|
80
|
-
? ResolveFirstScalarActivity<First, Rest>
|
|
81
|
-
: ResolveFirstIterableActivity<First, Rest>;
|
|
82
|
-
|
|
83
|
-
type ResolveActivities<Activities extends readonly [AnyActivity, ...AnyActivity[]]> =
|
|
84
|
-
Activities extends readonly [infer First extends AnyActivity, ...infer Rest extends readonly AnyActivity[]]
|
|
85
|
-
? ResolveFirstActivity<First, Rest>
|
|
86
|
-
: { kind: "error" };
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Return type for pipe when called without a source - returns a reusable activity function.
|
|
90
|
-
*/
|
|
91
|
-
type PipeWithoutSourceReturn<Activities extends readonly [AnyActivity, ...AnyActivity[]]> =
|
|
92
|
-
ResolveActivities<Activities> extends infer Result
|
|
93
|
-
? Result extends { kind: "iterable"; in: infer In; out: infer Out }
|
|
94
|
-
? IterableActivity<In & ActivityIn<FirstActivity<Activities>>, Out>
|
|
95
|
-
: Result extends { kind: "scalar"; in: infer In; out: infer Out }
|
|
96
|
-
? ScalarActivity<In & ActivityIn<FirstActivity<Activities>>, Out>
|
|
97
|
-
: never
|
|
98
|
-
: never;
|
|
99
|
-
|
|
100
|
-
// =============================================================================
|
|
101
|
-
// Type Resolution for Activity Chains (With Source)
|
|
102
|
-
// =============================================================================
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Resolves the output type when a source is provided as the first argument to pipe.
|
|
106
|
-
* Validates that the source type is compatible with the first activity's input.
|
|
107
|
-
*/
|
|
108
|
-
|
|
109
|
-
// Extract the final result kind from ResolveIterableTail
|
|
110
|
-
type ExtractFinalResultKind<Result> =
|
|
111
|
-
Result extends { kind: "iterable"; out: infer Out }
|
|
112
|
-
? { kind: "iterable"; out: Out }
|
|
113
|
-
: Result extends { kind: "scalar"; out: infer Out }
|
|
114
|
-
? { kind: "scalar"; out: Out }
|
|
115
|
-
: { kind: "error" };
|
|
116
|
-
|
|
117
|
-
// Handle when the first activity after source is scalar
|
|
118
|
-
type ResolveSourceWithScalarActivity<TSource, First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
119
|
-
TSource extends ActivityIn<First>
|
|
120
|
-
? Rest extends []
|
|
121
|
-
? { kind: "scalar"; out: ActivityOut<First> }
|
|
122
|
-
: { kind: "error" } // Scalar activities must be terminal
|
|
123
|
-
: { kind: "error" }; // Type mismatch
|
|
124
|
-
|
|
125
|
-
// Handle when the first activity after source is iterable
|
|
126
|
-
type ResolveSourceWithIterableActivity<TSource, First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
127
|
-
TSource extends ActivityIn<First>
|
|
128
|
-
? Rest extends []
|
|
129
|
-
? { kind: "iterable"; out: ActivityOut<First> }
|
|
130
|
-
: ExtractFinalResultKind<ResolveIterableTail<ActivityOut<First>, ActivityIn<First>, Rest>>
|
|
131
|
-
: { kind: "error" }; // Type mismatch
|
|
132
|
-
|
|
133
|
-
// Determine how to handle the source with the first activity
|
|
134
|
-
type ResolveSourceWithFirstActivity<TSource, First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
135
|
-
ActivityIsScalar<First> extends true
|
|
136
|
-
? ResolveSourceWithScalarActivity<TSource, First, Rest>
|
|
137
|
-
: ResolveSourceWithIterableActivity<TSource, First, Rest>;
|
|
138
|
-
|
|
139
|
-
type ResolveSourceActivities<TSource, Activities extends readonly AnyActivity[]> =
|
|
140
|
-
Activities extends []
|
|
141
|
-
? { kind: "source"; out: TSource }
|
|
142
|
-
: Activities extends readonly [infer First extends AnyActivity, ...infer Rest extends readonly AnyActivity[]]
|
|
143
|
-
? ResolveSourceWithFirstActivity<TSource, First, Rest>
|
|
144
|
-
: { kind: "error" };
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Return type for pipe when called with a source - executes immediately and returns the result.
|
|
148
|
-
*/
|
|
149
|
-
type PipeWithSourceReturn<TSource, Activities extends readonly AnyActivity[]> =
|
|
150
|
-
ResolveSourceActivities<TSource, Activities> extends infer Result
|
|
151
|
-
? Result extends { kind: "iterable"; out: infer Out }
|
|
152
|
-
? IterableIterator<Out>
|
|
153
|
-
: Result extends { kind: "scalar"; out: infer Out }
|
|
154
|
-
? Out
|
|
155
|
-
: Result extends { kind: "source"; out: infer Out }
|
|
156
|
-
? Source<Out>
|
|
157
|
-
: never
|
|
158
|
-
: never;
|
|
159
|
-
|
|
160
|
-
// =============================================================================
|
|
161
|
-
// Runtime Implementation
|
|
162
|
-
// =============================================================================
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Internal helper that chains activities together at runtime.
|
|
166
|
-
* Returns a function that accepts a source and applies all activities in sequence.
|
|
167
|
-
* Handles both generator (iterable) and scalar activities appropriately.
|
|
168
|
-
*/
|
|
169
|
-
function chainGen(...activities: AnyActivity[]) {
|
|
170
|
-
if (activities.length === 0) {
|
|
171
|
-
return <T>(source: Source<T>) => source;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const isGenerator = activities[activities.length - 1] instanceof GeneratorFunction;
|
|
175
|
-
const len = activities.length;
|
|
176
|
-
|
|
177
|
-
if (isGenerator) {
|
|
178
|
-
return function* (source: Source<unknown>) {
|
|
179
|
-
let tail: unknown = source;
|
|
180
|
-
for (let i = 0; i < len; i++) {
|
|
181
|
-
tail = activities[i](tail as Source<unknown>);
|
|
182
|
-
}
|
|
183
|
-
yield* tail as IterableIterator<unknown>;
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return (source: Source<unknown>) => {
|
|
188
|
-
let tail: unknown = source;
|
|
189
|
-
for (let i = 0; i < len; i++) {
|
|
190
|
-
tail = activities[i](tail as Source<unknown>);
|
|
191
|
-
}
|
|
192
|
-
return tail;
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// =============================================================================
|
|
197
|
-
// Public API
|
|
198
|
-
// =============================================================================
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Pipes activities together to create a data processing pipeline.
|
|
202
|
-
*
|
|
203
|
-
* Two usage modes:
|
|
204
|
-
* 1. Without source: pipe(activity1, activity2, ...) - returns a reusable activity function
|
|
205
|
-
* 2. With source: pipe(source, activity1, activity2, ...) - executes immediately and returns result
|
|
206
|
-
*
|
|
207
|
-
* Activities are chained left-to-right, with type checking ensuring output of each activity
|
|
208
|
-
* matches the input of the next.
|
|
209
|
-
*/
|
|
210
|
-
export function pipe<const Activities extends readonly [AnyActivity, ...AnyActivity[]]>(...activities: Activities): PipeWithoutSourceReturn<Activities>;
|
|
211
|
-
export function pipe<TSource, const Activities extends readonly AnyActivity[]>(source: Source<TSource>, ...activities: Activities): PipeWithSourceReturn<TSource, Activities>;
|
|
212
|
-
export function pipe(...args: any[]): any {
|
|
213
|
-
if (args.length === 0) {
|
|
214
|
-
throw new TypeError("pipe requires at least one argument");
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Handle source-based invocation
|
|
218
|
-
if (isSource(args[0])) {
|
|
219
|
-
return args.length === 1 ? args[0] : chainGen(...args.slice(1))(args[0]);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Handle activity-based invocation
|
|
223
|
-
return chainGen(...args);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// =============================================================================
|
|
227
|
-
// Backward Compatibility
|
|
228
|
-
// =============================================================================
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* @deprecated Use pipe instead. Maintained for backward compatibility.
|
|
232
|
-
*/
|
|
233
|
-
export const chain = pipe;
|
|
1
|
+
import { IterableActivity, ScalarActivity, Source, isSource } from "../activities/activity.ts";
|
|
2
|
+
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Constants and Base Types
|
|
5
|
+
// =============================================================================
|
|
6
|
+
|
|
7
|
+
const GeneratorFunction = (function* () { }).constructor;
|
|
8
|
+
|
|
9
|
+
type AnyIterableActivity = IterableActivity<any, any>;
|
|
10
|
+
type AnyScalarActivity = ScalarActivity<any, any>;
|
|
11
|
+
type AnyActivity = AnyIterableActivity | AnyScalarActivity;
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Type Utilities for Activity Analysis
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
type ActivityIn<A extends AnyActivity> = Parameters<A>[0] extends Source<infer Input> ? Input : never;
|
|
18
|
+
type ActivityOut<A extends AnyActivity> = ReturnType<A> extends IterableIterator<infer Output> ? Output : ReturnType<A>;
|
|
19
|
+
type ActivityIsScalar<A extends AnyActivity> = ReturnType<A> extends IterableIterator<any> ? false : true;
|
|
20
|
+
|
|
21
|
+
type FirstActivity<Activities extends readonly [AnyActivity, ...AnyActivity[]]> = Activities[0];
|
|
22
|
+
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Type Resolution for Activity Chains (Without Source)
|
|
25
|
+
// =============================================================================
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Recursively resolves the output type of a chain of activities starting from an iterable activity.
|
|
29
|
+
* Validates that each activity's input type matches the previous activity's output type.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
// Handle a scalar (non-iterable) activity in the chain
|
|
33
|
+
type ResolveScalarActivity<CurrentOut, InitialIn, Next extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
34
|
+
CurrentOut extends ActivityIn<Next>
|
|
35
|
+
? Rest extends []
|
|
36
|
+
? { kind: "scalar"; in: InitialIn; out: ActivityOut<Next> }
|
|
37
|
+
: { kind: "error" } // Scalar activities must be terminal
|
|
38
|
+
: { kind: "error" }; // Type mismatch
|
|
39
|
+
|
|
40
|
+
// Handle an iterable activity in the chain
|
|
41
|
+
type ResolveIterableActivity<CurrentOut, InitialIn, Next extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
42
|
+
CurrentOut extends ActivityIn<Next>
|
|
43
|
+
? ResolveIterableTail<ActivityOut<Next>, InitialIn, Rest>
|
|
44
|
+
: { kind: "error" }; // Type mismatch
|
|
45
|
+
|
|
46
|
+
// Process the next activity in the chain
|
|
47
|
+
type ResolveNextActivity<CurrentOut, InitialIn, Next extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
48
|
+
ActivityIsScalar<Next> extends true
|
|
49
|
+
? ResolveScalarActivity<CurrentOut, InitialIn, Next, Rest>
|
|
50
|
+
: ResolveIterableActivity<CurrentOut, InitialIn, Next, Rest>;
|
|
51
|
+
|
|
52
|
+
// Check if we've reached the end of the activity chain
|
|
53
|
+
type ResolveIterableTail<CurrentOut, InitialIn, Tail extends readonly AnyActivity[]> =
|
|
54
|
+
Tail extends []
|
|
55
|
+
? { kind: "iterable"; in: InitialIn; out: CurrentOut }
|
|
56
|
+
: Tail extends readonly [infer Next extends AnyActivity, ...infer Rest extends readonly AnyActivity[]]
|
|
57
|
+
? ResolveNextActivity<CurrentOut, InitialIn, Next, Rest>
|
|
58
|
+
: { kind: "error" };
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Resolves the complete type signature for a chain of activities without a source.
|
|
62
|
+
* Determines the input, output, and whether the final result is scalar or iterable.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
// Handle when the first activity is scalar (must be the only activity)
|
|
66
|
+
type ResolveFirstScalarActivity<First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
67
|
+
Rest extends []
|
|
68
|
+
? { kind: "scalar"; in: ActivityIn<First>; out: ActivityOut<First> }
|
|
69
|
+
: { kind: "error" }; // Scalar activities cannot be followed by others
|
|
70
|
+
|
|
71
|
+
// Handle when the first activity is iterable
|
|
72
|
+
type ResolveFirstIterableActivity<First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
73
|
+
Rest extends []
|
|
74
|
+
? { kind: "iterable"; in: ActivityIn<First>; out: ActivityOut<First> }
|
|
75
|
+
: ResolveIterableTail<ActivityOut<First>, ActivityIn<First>, Rest>;
|
|
76
|
+
|
|
77
|
+
// Determine how to handle the first activity based on whether it's scalar or iterable
|
|
78
|
+
type ResolveFirstActivity<First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
79
|
+
ActivityIsScalar<First> extends true
|
|
80
|
+
? ResolveFirstScalarActivity<First, Rest>
|
|
81
|
+
: ResolveFirstIterableActivity<First, Rest>;
|
|
82
|
+
|
|
83
|
+
type ResolveActivities<Activities extends readonly [AnyActivity, ...AnyActivity[]]> =
|
|
84
|
+
Activities extends readonly [infer First extends AnyActivity, ...infer Rest extends readonly AnyActivity[]]
|
|
85
|
+
? ResolveFirstActivity<First, Rest>
|
|
86
|
+
: { kind: "error" };
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Return type for pipe when called without a source - returns a reusable activity function.
|
|
90
|
+
*/
|
|
91
|
+
type PipeWithoutSourceReturn<Activities extends readonly [AnyActivity, ...AnyActivity[]]> =
|
|
92
|
+
ResolveActivities<Activities> extends infer Result
|
|
93
|
+
? Result extends { kind: "iterable"; in: infer In; out: infer Out }
|
|
94
|
+
? IterableActivity<In & ActivityIn<FirstActivity<Activities>>, Out>
|
|
95
|
+
: Result extends { kind: "scalar"; in: infer In; out: infer Out }
|
|
96
|
+
? ScalarActivity<In & ActivityIn<FirstActivity<Activities>>, Out>
|
|
97
|
+
: never
|
|
98
|
+
: never;
|
|
99
|
+
|
|
100
|
+
// =============================================================================
|
|
101
|
+
// Type Resolution for Activity Chains (With Source)
|
|
102
|
+
// =============================================================================
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Resolves the output type when a source is provided as the first argument to pipe.
|
|
106
|
+
* Validates that the source type is compatible with the first activity's input.
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
// Extract the final result kind from ResolveIterableTail
|
|
110
|
+
type ExtractFinalResultKind<Result> =
|
|
111
|
+
Result extends { kind: "iterable"; out: infer Out }
|
|
112
|
+
? { kind: "iterable"; out: Out }
|
|
113
|
+
: Result extends { kind: "scalar"; out: infer Out }
|
|
114
|
+
? { kind: "scalar"; out: Out }
|
|
115
|
+
: { kind: "error" };
|
|
116
|
+
|
|
117
|
+
// Handle when the first activity after source is scalar
|
|
118
|
+
type ResolveSourceWithScalarActivity<TSource, First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
119
|
+
TSource extends ActivityIn<First>
|
|
120
|
+
? Rest extends []
|
|
121
|
+
? { kind: "scalar"; out: ActivityOut<First> }
|
|
122
|
+
: { kind: "error" } // Scalar activities must be terminal
|
|
123
|
+
: { kind: "error" }; // Type mismatch
|
|
124
|
+
|
|
125
|
+
// Handle when the first activity after source is iterable
|
|
126
|
+
type ResolveSourceWithIterableActivity<TSource, First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
127
|
+
TSource extends ActivityIn<First>
|
|
128
|
+
? Rest extends []
|
|
129
|
+
? { kind: "iterable"; out: ActivityOut<First> }
|
|
130
|
+
: ExtractFinalResultKind<ResolveIterableTail<ActivityOut<First>, ActivityIn<First>, Rest>>
|
|
131
|
+
: { kind: "error" }; // Type mismatch
|
|
132
|
+
|
|
133
|
+
// Determine how to handle the source with the first activity
|
|
134
|
+
type ResolveSourceWithFirstActivity<TSource, First extends AnyActivity, Rest extends readonly AnyActivity[]> =
|
|
135
|
+
ActivityIsScalar<First> extends true
|
|
136
|
+
? ResolveSourceWithScalarActivity<TSource, First, Rest>
|
|
137
|
+
: ResolveSourceWithIterableActivity<TSource, First, Rest>;
|
|
138
|
+
|
|
139
|
+
type ResolveSourceActivities<TSource, Activities extends readonly AnyActivity[]> =
|
|
140
|
+
Activities extends []
|
|
141
|
+
? { kind: "source"; out: TSource }
|
|
142
|
+
: Activities extends readonly [infer First extends AnyActivity, ...infer Rest extends readonly AnyActivity[]]
|
|
143
|
+
? ResolveSourceWithFirstActivity<TSource, First, Rest>
|
|
144
|
+
: { kind: "error" };
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Return type for pipe when called with a source - executes immediately and returns the result.
|
|
148
|
+
*/
|
|
149
|
+
type PipeWithSourceReturn<TSource, Activities extends readonly AnyActivity[]> =
|
|
150
|
+
ResolveSourceActivities<TSource, Activities> extends infer Result
|
|
151
|
+
? Result extends { kind: "iterable"; out: infer Out }
|
|
152
|
+
? IterableIterator<Out>
|
|
153
|
+
: Result extends { kind: "scalar"; out: infer Out }
|
|
154
|
+
? Out
|
|
155
|
+
: Result extends { kind: "source"; out: infer Out }
|
|
156
|
+
? Source<Out>
|
|
157
|
+
: never
|
|
158
|
+
: never;
|
|
159
|
+
|
|
160
|
+
// =============================================================================
|
|
161
|
+
// Runtime Implementation
|
|
162
|
+
// =============================================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Internal helper that chains activities together at runtime.
|
|
166
|
+
* Returns a function that accepts a source and applies all activities in sequence.
|
|
167
|
+
* Handles both generator (iterable) and scalar activities appropriately.
|
|
168
|
+
*/
|
|
169
|
+
function chainGen(...activities: AnyActivity[]) {
|
|
170
|
+
if (activities.length === 0) {
|
|
171
|
+
return <T>(source: Source<T>) => source;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const isGenerator = activities[activities.length - 1] instanceof GeneratorFunction;
|
|
175
|
+
const len = activities.length;
|
|
176
|
+
|
|
177
|
+
if (isGenerator) {
|
|
178
|
+
return function* (source: Source<unknown>) {
|
|
179
|
+
let tail: unknown = source;
|
|
180
|
+
for (let i = 0; i < len; i++) {
|
|
181
|
+
tail = activities[i](tail as Source<unknown>);
|
|
182
|
+
}
|
|
183
|
+
yield* tail as IterableIterator<unknown>;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return (source: Source<unknown>) => {
|
|
188
|
+
let tail: unknown = source;
|
|
189
|
+
for (let i = 0; i < len; i++) {
|
|
190
|
+
tail = activities[i](tail as Source<unknown>);
|
|
191
|
+
}
|
|
192
|
+
return tail;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// =============================================================================
|
|
197
|
+
// Public API
|
|
198
|
+
// =============================================================================
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Pipes activities together to create a data processing pipeline.
|
|
202
|
+
*
|
|
203
|
+
* Two usage modes:
|
|
204
|
+
* 1. Without source: pipe(activity1, activity2, ...) - returns a reusable activity function
|
|
205
|
+
* 2. With source: pipe(source, activity1, activity2, ...) - executes immediately and returns result
|
|
206
|
+
*
|
|
207
|
+
* Activities are chained left-to-right, with type checking ensuring output of each activity
|
|
208
|
+
* matches the input of the next.
|
|
209
|
+
*/
|
|
210
|
+
export function pipe<const Activities extends readonly [AnyActivity, ...AnyActivity[]]>(...activities: Activities): PipeWithoutSourceReturn<Activities>;
|
|
211
|
+
export function pipe<TSource, const Activities extends readonly AnyActivity[]>(source: Source<TSource>, ...activities: Activities): PipeWithSourceReturn<TSource, Activities>;
|
|
212
|
+
export function pipe(...args: any[]): any {
|
|
213
|
+
if (args.length === 0) {
|
|
214
|
+
throw new TypeError("pipe requires at least one argument");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Handle source-based invocation
|
|
218
|
+
if (isSource(args[0])) {
|
|
219
|
+
return args.length === 1 ? args[0] : chainGen(...args.slice(1))(args[0]);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Handle activity-based invocation
|
|
223
|
+
return chainGen(...args);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// =============================================================================
|
|
227
|
+
// Backward Compatibility
|
|
228
|
+
// =============================================================================
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @deprecated Use pipe instead. Maintained for backward compatibility.
|
|
232
|
+
*/
|
|
233
|
+
export const chain = pipe;
|