@trpc/server 11.0.0-rc.693 → 11.0.0-rc.695
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/dist/adapters/ws.js +1 -1
- package/dist/adapters/ws.mjs +1 -1
- package/dist/bundle-analysis.json +99 -83
- package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/jsonl.js +154 -188
- package/dist/unstable-core-do-not-import/stream/jsonl.mjs +156 -190
- package/dist/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.d.ts +17 -0
- package/dist/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.js +241 -0
- package/dist/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.mjs +239 -0
- package/package.json +2 -2
- package/src/unstable-core-do-not-import/stream/jsonl.ts +14 -46
- package/src/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.ts +193 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isObject, isFunction, isAsyncIterable, run } from '../utils.mjs';
|
|
1
|
+
import { isObject, isFunction, run, isAsyncIterable } from '../utils.mjs';
|
|
3
2
|
import { iteratorResource } from './utils/asyncIterable.mjs';
|
|
4
3
|
import { createDeferred } from './utils/createDeferred.mjs';
|
|
5
|
-
import {
|
|
4
|
+
import { makeResource } from './utils/disposable.mjs';
|
|
5
|
+
import { mergeAsyncIterables } from './utils/mergeAsyncIterables.mjs';
|
|
6
6
|
import { readableStreamFrom } from './utils/readableStreamFrom.mjs';
|
|
7
7
|
|
|
8
8
|
function _define_property(obj, key, value) {
|
|
@@ -101,223 +101,189 @@ class MaxDepthError extends Error {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
async function* createBatchStreamProducer(opts) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
104
|
+
const { data } = opts;
|
|
105
|
+
let counter = 0;
|
|
106
|
+
const placeholder = 0;
|
|
107
|
+
const mergedIterables = mergeAsyncIterables();
|
|
108
|
+
function registerAsync(callback) {
|
|
109
|
+
const idx = counter++;
|
|
110
|
+
const iterable = callback(idx);
|
|
111
|
+
mergedIterables.add(iterable);
|
|
112
|
+
return idx;
|
|
113
|
+
}
|
|
114
|
+
function encodePromise(promise, path) {
|
|
115
|
+
return registerAsync(async function*(idx) {
|
|
116
|
+
const error = checkMaxDepth(path);
|
|
117
|
+
if (error) {
|
|
118
|
+
// Catch any errors from the original promise to ensure they're reported
|
|
119
|
+
promise.catch((cause)=>{
|
|
120
|
+
opts.onError?.({
|
|
121
|
+
error: cause,
|
|
122
|
+
path
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
// Replace the promise with a rejected one containing the max depth error
|
|
126
|
+
promise = Promise.reject(error);
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const next = await promise;
|
|
130
|
+
yield [
|
|
131
|
+
idx,
|
|
132
|
+
PROMISE_STATUS_FULFILLED,
|
|
133
|
+
encode(next, path)
|
|
134
|
+
];
|
|
135
|
+
} catch (cause) {
|
|
136
|
+
opts.onError?.({
|
|
137
|
+
error: cause,
|
|
138
|
+
path
|
|
139
|
+
});
|
|
140
|
+
yield [
|
|
141
|
+
idx,
|
|
142
|
+
PROMISE_STATUS_REJECTED,
|
|
143
|
+
opts.formatError?.({
|
|
144
|
+
error: cause,
|
|
145
|
+
path
|
|
146
|
+
})
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
function encodeAsyncIterable(iterable, path) {
|
|
152
|
+
return registerAsync(async function*(idx) {
|
|
153
|
+
const env = {
|
|
154
|
+
stack: [],
|
|
155
|
+
error: void 0,
|
|
156
|
+
hasError: false
|
|
157
|
+
};
|
|
158
|
+
try {
|
|
132
159
|
const error = checkMaxDepth(path);
|
|
133
160
|
if (error) {
|
|
134
|
-
|
|
135
|
-
promise.catch((cause)=>{
|
|
136
|
-
opts.onError?.({
|
|
137
|
-
error: cause,
|
|
138
|
-
path
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
// Replace the promise with a rejected one containing the max depth error
|
|
142
|
-
promise = Promise.reject(error);
|
|
161
|
+
throw error;
|
|
143
162
|
}
|
|
163
|
+
const iterator = _ts_add_disposable_resource(env, iteratorResource(iterable), true);
|
|
164
|
+
;
|
|
144
165
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
166
|
+
while(true){
|
|
167
|
+
const next = await iterator.next();
|
|
168
|
+
if (next.done) {
|
|
169
|
+
yield [
|
|
170
|
+
idx,
|
|
171
|
+
ASYNC_ITERABLE_STATUS_RETURN,
|
|
172
|
+
encode(next.value, path)
|
|
173
|
+
];
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
yield [
|
|
177
|
+
idx,
|
|
178
|
+
ASYNC_ITERABLE_STATUS_YIELD,
|
|
179
|
+
encode(next.value, path)
|
|
180
|
+
];
|
|
181
|
+
}
|
|
151
182
|
} catch (cause) {
|
|
152
183
|
opts.onError?.({
|
|
153
184
|
error: cause,
|
|
154
185
|
path
|
|
155
186
|
});
|
|
156
|
-
|
|
187
|
+
yield [
|
|
157
188
|
idx,
|
|
158
|
-
|
|
189
|
+
ASYNC_ITERABLE_STATUS_ERROR,
|
|
159
190
|
opts.formatError?.({
|
|
160
191
|
error: cause,
|
|
161
192
|
path
|
|
162
193
|
})
|
|
163
194
|
];
|
|
164
195
|
}
|
|
165
|
-
})
|
|
196
|
+
} catch (e) {
|
|
197
|
+
env.error = e;
|
|
198
|
+
env.hasError = true;
|
|
199
|
+
} finally{
|
|
200
|
+
const result = _ts_dispose_resources(env);
|
|
201
|
+
if (result) await result;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function checkMaxDepth(path) {
|
|
206
|
+
if (opts.maxDepth && path.length > opts.maxDepth) {
|
|
207
|
+
return new MaxDepthError(path);
|
|
166
208
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const error = checkMaxDepth(path);
|
|
176
|
-
if (error) {
|
|
177
|
-
throw error;
|
|
178
|
-
}
|
|
179
|
-
const iterator = _ts_add_disposable_resource(env, iteratorResource(iterable), true);
|
|
180
|
-
;
|
|
181
|
-
try {
|
|
182
|
-
while(true){
|
|
183
|
-
const next = await iterator.next();
|
|
184
|
-
if (next.done) {
|
|
185
|
-
return [
|
|
186
|
-
idx,
|
|
187
|
-
ASYNC_ITERABLE_STATUS_RETURN,
|
|
188
|
-
encode(next.value, path)
|
|
189
|
-
];
|
|
190
|
-
}
|
|
191
|
-
yield [
|
|
192
|
-
idx,
|
|
193
|
-
ASYNC_ITERABLE_STATUS_YIELD,
|
|
194
|
-
encode(next.value, path)
|
|
195
|
-
];
|
|
196
|
-
}
|
|
197
|
-
} catch (cause) {
|
|
198
|
-
opts.onError?.({
|
|
199
|
-
error: cause,
|
|
200
|
-
path
|
|
201
|
-
});
|
|
202
|
-
return [
|
|
203
|
-
idx,
|
|
204
|
-
ASYNC_ITERABLE_STATUS_ERROR,
|
|
205
|
-
opts.formatError?.({
|
|
206
|
-
error: cause,
|
|
207
|
-
path
|
|
208
|
-
})
|
|
209
|
-
];
|
|
210
|
-
}
|
|
211
|
-
} catch (e) {
|
|
212
|
-
env.error = e;
|
|
213
|
-
env.hasError = true;
|
|
214
|
-
} finally{
|
|
215
|
-
const result = _ts_dispose_resources(env);
|
|
216
|
-
if (result) await result;
|
|
217
|
-
}
|
|
218
|
-
});
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
function encodeAsync(value, path) {
|
|
212
|
+
if (isPromise(value)) {
|
|
213
|
+
return [
|
|
214
|
+
CHUNK_VALUE_TYPE_PROMISE,
|
|
215
|
+
encodePromise(value, path)
|
|
216
|
+
];
|
|
219
217
|
}
|
|
220
|
-
|
|
221
|
-
if (opts.maxDepth && path.length
|
|
222
|
-
|
|
218
|
+
if (isAsyncIterable(value)) {
|
|
219
|
+
if (opts.maxDepth && path.length >= opts.maxDepth) {
|
|
220
|
+
throw new Error('Max depth reached');
|
|
223
221
|
}
|
|
224
|
-
return
|
|
222
|
+
return [
|
|
223
|
+
CHUNK_VALUE_TYPE_ASYNC_ITERABLE,
|
|
224
|
+
encodeAsyncIterable(value, path)
|
|
225
|
+
];
|
|
225
226
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
]
|
|
232
|
-
|
|
233
|
-
if (isAsyncIterable(value)) {
|
|
234
|
-
if (opts.maxDepth && path.length >= opts.maxDepth) {
|
|
235
|
-
throw new Error('Max depth reached');
|
|
236
|
-
}
|
|
237
|
-
return [
|
|
238
|
-
CHUNK_VALUE_TYPE_ASYNC_ITERABLE,
|
|
239
|
-
encodeAsyncIterable(value, path)
|
|
240
|
-
];
|
|
241
|
-
}
|
|
242
|
-
return null;
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
function encode(value, path) {
|
|
230
|
+
if (value === undefined) {
|
|
231
|
+
return [
|
|
232
|
+
[]
|
|
233
|
+
];
|
|
243
234
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
]
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
value
|
|
254
|
-
]
|
|
255
|
-
];
|
|
256
|
-
}
|
|
257
|
-
const reg = encodeAsync(value, path);
|
|
258
|
-
if (reg) {
|
|
259
|
-
return [
|
|
260
|
-
[
|
|
261
|
-
placeholder
|
|
262
|
-
],
|
|
263
|
-
[
|
|
264
|
-
null,
|
|
265
|
-
...reg
|
|
266
|
-
]
|
|
267
|
-
];
|
|
268
|
-
}
|
|
269
|
-
const newObj = {};
|
|
270
|
-
const asyncValues = [];
|
|
271
|
-
for (const [key, item] of Object.entries(value)){
|
|
272
|
-
const transformed = encodeAsync(item, [
|
|
273
|
-
...path,
|
|
274
|
-
key
|
|
275
|
-
]);
|
|
276
|
-
if (!transformed) {
|
|
277
|
-
newObj[key] = item;
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
newObj[key] = placeholder;
|
|
281
|
-
asyncValues.push([
|
|
282
|
-
key,
|
|
283
|
-
...transformed
|
|
284
|
-
]);
|
|
285
|
-
}
|
|
235
|
+
if (!isObject(value)) {
|
|
236
|
+
return [
|
|
237
|
+
[
|
|
238
|
+
value
|
|
239
|
+
]
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
const reg = encodeAsync(value, path);
|
|
243
|
+
if (reg) {
|
|
286
244
|
return [
|
|
287
245
|
[
|
|
288
|
-
|
|
246
|
+
placeholder
|
|
289
247
|
],
|
|
290
|
-
|
|
248
|
+
[
|
|
249
|
+
null,
|
|
250
|
+
...reg
|
|
251
|
+
]
|
|
291
252
|
];
|
|
292
253
|
}
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
254
|
+
const newObj = {};
|
|
255
|
+
const asyncValues = [];
|
|
256
|
+
for (const [key, item] of Object.entries(value)){
|
|
257
|
+
const transformed = encodeAsync(item, [
|
|
258
|
+
...path,
|
|
296
259
|
key
|
|
297
260
|
]);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
while(queue.size > 0){
|
|
302
|
-
// Race all iterators to get the next value from any of them
|
|
303
|
-
const [entry, res] = await Unpromise.race(Array.from(queue).map(async (it)=>[
|
|
304
|
-
it,
|
|
305
|
-
await it.nextPromise
|
|
306
|
-
]));
|
|
307
|
-
yield res.value;
|
|
308
|
-
// Remove current iterator and re-add if not done
|
|
309
|
-
queue.delete(entry);
|
|
310
|
-
if (!res.done) {
|
|
311
|
-
entry.nextPromise = entry.iterator.next();
|
|
312
|
-
queue.add(entry);
|
|
261
|
+
if (!transformed) {
|
|
262
|
+
newObj[key] = item;
|
|
263
|
+
continue;
|
|
313
264
|
}
|
|
265
|
+
newObj[key] = placeholder;
|
|
266
|
+
asyncValues.push([
|
|
267
|
+
key,
|
|
268
|
+
...transformed
|
|
269
|
+
]);
|
|
314
270
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
271
|
+
return [
|
|
272
|
+
[
|
|
273
|
+
newObj
|
|
274
|
+
],
|
|
275
|
+
...asyncValues
|
|
276
|
+
];
|
|
277
|
+
}
|
|
278
|
+
const newHead = {};
|
|
279
|
+
for (const [key, item] of Object.entries(data)){
|
|
280
|
+
newHead[key] = encode(item, [
|
|
281
|
+
key
|
|
282
|
+
]);
|
|
283
|
+
}
|
|
284
|
+
yield newHead;
|
|
285
|
+
for await (const value of mergedIterables){
|
|
286
|
+
yield value;
|
|
321
287
|
}
|
|
322
288
|
}
|
|
323
289
|
/**
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface MergedAsyncIterables<TYield> extends AsyncIterable<TYield, void, unknown> {
|
|
2
|
+
add(iterable: AsyncIterable<TYield>): void;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new async iterable that merges multiple async iterables into a single stream.
|
|
6
|
+
* Values from the input iterables are yielded in the order they resolve, similar to Promise.race().
|
|
7
|
+
*
|
|
8
|
+
* New iterables can be added dynamically using the returned {@link MergedAsyncIterables.add} method, even after iteration has started.
|
|
9
|
+
*
|
|
10
|
+
* If any of the input iterables throws an error, that error will be propagated through the merged stream.
|
|
11
|
+
* Other iterables will not continue to be processed.
|
|
12
|
+
*
|
|
13
|
+
* @template TYield The type of values yielded by the input iterables
|
|
14
|
+
*/
|
|
15
|
+
export declare function mergeAsyncIterables<TYield>(): MergedAsyncIterables<TYield>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=mergeAsyncIterables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeAsyncIterables.d.ts","sourceRoot":"","sources":["../../../../src/unstable-core-do-not-import/stream/utils/mergeAsyncIterables.ts"],"names":[],"mappings":"AAyDA,UAAU,oBAAoB,CAAC,MAAM,CACnC,SAAQ,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IAC5C,GAAG,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,KAAK,oBAAoB,CAAC,MAAM,CAAC,CAuH1E"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var createDeferred = require('./createDeferred.js');
|
|
4
|
+
var disposable = require('./disposable.js');
|
|
5
|
+
|
|
6
|
+
function _ts_add_disposable_resource(env, value, async) {
|
|
7
|
+
if (value !== null && value !== void 0) {
|
|
8
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
9
|
+
var dispose, inner;
|
|
10
|
+
{
|
|
11
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
12
|
+
dispose = value[Symbol.asyncDispose];
|
|
13
|
+
}
|
|
14
|
+
if (dispose === void 0) {
|
|
15
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
16
|
+
dispose = value[Symbol.dispose];
|
|
17
|
+
inner = dispose;
|
|
18
|
+
}
|
|
19
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
20
|
+
if (inner) dispose = function() {
|
|
21
|
+
try {
|
|
22
|
+
inner.call(this);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
return Promise.reject(e);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
env.stack.push({
|
|
28
|
+
value: value,
|
|
29
|
+
dispose: dispose,
|
|
30
|
+
async: async
|
|
31
|
+
});
|
|
32
|
+
} else {
|
|
33
|
+
env.stack.push({
|
|
34
|
+
async: true
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function _ts_dispose_resources(env) {
|
|
40
|
+
var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
41
|
+
var e = new Error(message);
|
|
42
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
43
|
+
};
|
|
44
|
+
return (_ts_dispose_resources = function _ts_dispose_resources(env) {
|
|
45
|
+
function fail(e) {
|
|
46
|
+
env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
47
|
+
env.hasError = true;
|
|
48
|
+
}
|
|
49
|
+
var r, s = 0;
|
|
50
|
+
function next() {
|
|
51
|
+
while(r = env.stack.pop()){
|
|
52
|
+
try {
|
|
53
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
54
|
+
if (r.dispose) {
|
|
55
|
+
var result = r.dispose.call(r.value);
|
|
56
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
57
|
+
fail(e);
|
|
58
|
+
return next();
|
|
59
|
+
});
|
|
60
|
+
} else s |= 1;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
fail(e);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
66
|
+
if (env.hasError) throw env.error;
|
|
67
|
+
}
|
|
68
|
+
return next();
|
|
69
|
+
})(env);
|
|
70
|
+
}
|
|
71
|
+
function createManagedIterator(iterable, onResult) {
|
|
72
|
+
const iterator = iterable[Symbol.asyncIterator]();
|
|
73
|
+
let state = 'idle';
|
|
74
|
+
function cleanup() {
|
|
75
|
+
state = 'done';
|
|
76
|
+
onResult = ()=>{
|
|
77
|
+
// noop
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function pull() {
|
|
81
|
+
if (state !== 'idle') {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
state = 'pending';
|
|
85
|
+
const next = iterator.next();
|
|
86
|
+
next.then((result)=>{
|
|
87
|
+
if (result.done) {
|
|
88
|
+
state = 'done';
|
|
89
|
+
onResult({
|
|
90
|
+
status: 'return',
|
|
91
|
+
value: result.value
|
|
92
|
+
});
|
|
93
|
+
cleanup();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
state = 'idle';
|
|
97
|
+
onResult({
|
|
98
|
+
status: 'yield',
|
|
99
|
+
value: result.value
|
|
100
|
+
});
|
|
101
|
+
}).catch((cause)=>{
|
|
102
|
+
onResult({
|
|
103
|
+
status: 'error',
|
|
104
|
+
error: cause
|
|
105
|
+
});
|
|
106
|
+
cleanup();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
pull,
|
|
111
|
+
destroy: async ()=>{
|
|
112
|
+
cleanup();
|
|
113
|
+
await iterator.return?.();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Creates a new async iterable that merges multiple async iterables into a single stream.
|
|
119
|
+
* Values from the input iterables are yielded in the order they resolve, similar to Promise.race().
|
|
120
|
+
*
|
|
121
|
+
* New iterables can be added dynamically using the returned {@link MergedAsyncIterables.add} method, even after iteration has started.
|
|
122
|
+
*
|
|
123
|
+
* If any of the input iterables throws an error, that error will be propagated through the merged stream.
|
|
124
|
+
* Other iterables will not continue to be processed.
|
|
125
|
+
*
|
|
126
|
+
* @template TYield The type of values yielded by the input iterables
|
|
127
|
+
*/ function mergeAsyncIterables() {
|
|
128
|
+
let state = 'idle';
|
|
129
|
+
let flushSignal = createDeferred.createDeferred();
|
|
130
|
+
/**
|
|
131
|
+
* used while {@link state} is `idle`
|
|
132
|
+
*/ const iterables = [];
|
|
133
|
+
/**
|
|
134
|
+
* used while {@link state} is `pending`
|
|
135
|
+
*/ const iterators = new Set();
|
|
136
|
+
const buffer = [];
|
|
137
|
+
function initIterable(iterable) {
|
|
138
|
+
if (state !== 'pending') {
|
|
139
|
+
// shouldn't happen
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const iterator = createManagedIterator(iterable, (result)=>{
|
|
143
|
+
if (state !== 'pending') {
|
|
144
|
+
// shouldn't happen
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
switch(result.status){
|
|
148
|
+
case 'yield':
|
|
149
|
+
buffer.push([
|
|
150
|
+
iterator,
|
|
151
|
+
result
|
|
152
|
+
]);
|
|
153
|
+
break;
|
|
154
|
+
case 'return':
|
|
155
|
+
iterators.delete(iterator);
|
|
156
|
+
break;
|
|
157
|
+
case 'error':
|
|
158
|
+
buffer.push([
|
|
159
|
+
iterator,
|
|
160
|
+
result
|
|
161
|
+
]);
|
|
162
|
+
iterators.delete(iterator);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
flushSignal.resolve();
|
|
166
|
+
});
|
|
167
|
+
iterators.add(iterator);
|
|
168
|
+
iterator.pull();
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
add (iterable) {
|
|
172
|
+
switch(state){
|
|
173
|
+
case 'idle':
|
|
174
|
+
iterables.push(iterable);
|
|
175
|
+
break;
|
|
176
|
+
case 'pending':
|
|
177
|
+
initIterable(iterable);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
async *[Symbol.asyncIterator] () {
|
|
182
|
+
const env = {
|
|
183
|
+
stack: [],
|
|
184
|
+
error: void 0,
|
|
185
|
+
hasError: false
|
|
186
|
+
};
|
|
187
|
+
try {
|
|
188
|
+
if (state !== 'idle') {
|
|
189
|
+
throw new Error('Cannot iterate twice');
|
|
190
|
+
}
|
|
191
|
+
state = 'pending';
|
|
192
|
+
const _finally = _ts_add_disposable_resource(env, disposable.makeAsyncResource({}, async ()=>{
|
|
193
|
+
state = 'done';
|
|
194
|
+
const errors = [];
|
|
195
|
+
await Promise.all(Array.from(iterators.values()).map(async (it)=>{
|
|
196
|
+
try {
|
|
197
|
+
await it.destroy();
|
|
198
|
+
} catch (cause) {
|
|
199
|
+
errors.push(cause);
|
|
200
|
+
}
|
|
201
|
+
}));
|
|
202
|
+
buffer.length = 0;
|
|
203
|
+
iterators.clear();
|
|
204
|
+
flushSignal.resolve();
|
|
205
|
+
if (errors.length > 0) {
|
|
206
|
+
throw new AggregateError(errors);
|
|
207
|
+
}
|
|
208
|
+
}), true);
|
|
209
|
+
;
|
|
210
|
+
while(iterables.length > 0){
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
212
|
+
initIterable(iterables.shift());
|
|
213
|
+
}
|
|
214
|
+
while(iterators.size > 0){
|
|
215
|
+
await flushSignal.promise;
|
|
216
|
+
while(buffer.length > 0){
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
218
|
+
const [iterator, result] = buffer.shift();
|
|
219
|
+
switch(result.status){
|
|
220
|
+
case 'yield':
|
|
221
|
+
yield result.value;
|
|
222
|
+
iterator.pull();
|
|
223
|
+
break;
|
|
224
|
+
case 'error':
|
|
225
|
+
throw result.error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
flushSignal = createDeferred.createDeferred();
|
|
229
|
+
}
|
|
230
|
+
} catch (e) {
|
|
231
|
+
env.error = e;
|
|
232
|
+
env.hasError = true;
|
|
233
|
+
} finally{
|
|
234
|
+
const result = _ts_dispose_resources(env);
|
|
235
|
+
if (result) await result;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
exports.mergeAsyncIterables = mergeAsyncIterables;
|