gingersnap 0.23.9 → 0.23.10
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/data-structures/object/BufferQueue.cjs +25 -0
- package/data-structures/object/BufferQueue.d.ts +4 -0
- package/data-structures/object/BufferQueue.mjs +25 -0
- package/data-structures/object/Queue.cjs +50 -11
- package/data-structures/object/Queue.d.ts +10 -0
- package/data-structures/object/Queue.mjs +50 -11
- package/package.json +1 -1
- package/stream/index.d.ts +13 -2
- package/stream.cjs +66 -11
- package/stream.mjs +66 -11
|
@@ -58,6 +58,31 @@ class BufferQueue extends WatchableObject.WatchableObject {
|
|
|
58
58
|
});
|
|
59
59
|
}));
|
|
60
60
|
}
|
|
61
|
+
flushableStream(ignoreCache = false) {
|
|
62
|
+
let pointer = ignoreCache ? this.tail : 0;
|
|
63
|
+
return new stream.Stream(((signal) => {
|
|
64
|
+
const value = this.get(pointer);
|
|
65
|
+
if (value !== undefined) {
|
|
66
|
+
pointer++;
|
|
67
|
+
return {
|
|
68
|
+
value,
|
|
69
|
+
done: () => {
|
|
70
|
+
this.delete(pointer);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
const unsubscribe = this.on(pointer, (v) => {
|
|
76
|
+
pointer++;
|
|
77
|
+
resolve(v);
|
|
78
|
+
}, false);
|
|
79
|
+
signal.onabort = () => {
|
|
80
|
+
unsubscribe();
|
|
81
|
+
resolve(new stream_state.ExecutorState(true));
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
61
86
|
clone() {
|
|
62
87
|
const obj = super.clone();
|
|
63
88
|
obj.head = this.head;
|
|
@@ -11,6 +11,10 @@ export declare class BufferQueue<T> extends WatchableObject<number, T> {
|
|
|
11
11
|
constructor(objectMaxSize?: number, expiryPeriod?: WaitPeriod);
|
|
12
12
|
ingest(stream: Stream<T>): Future<void>;
|
|
13
13
|
streamEntries(ignoreCache?: boolean): Stream<T>;
|
|
14
|
+
flushableStream(ignoreCache?: boolean): Stream<{
|
|
15
|
+
value: T;
|
|
16
|
+
done: () => void;
|
|
17
|
+
}>;
|
|
14
18
|
clone(): BufferQueue<T>;
|
|
15
19
|
enqueue(value: T, tracker?: string | number): void;
|
|
16
20
|
clear(): void;
|
|
@@ -37,6 +37,31 @@ class BufferQueue extends WatchableObject {
|
|
|
37
37
|
});
|
|
38
38
|
}));
|
|
39
39
|
}
|
|
40
|
+
flushableStream(ignoreCache = false) {
|
|
41
|
+
let pointer = ignoreCache ? this.tail : 0;
|
|
42
|
+
return new Stream(((signal) => {
|
|
43
|
+
const value = this.get(pointer);
|
|
44
|
+
if (value !== undefined) {
|
|
45
|
+
pointer++;
|
|
46
|
+
return {
|
|
47
|
+
value,
|
|
48
|
+
done: () => {
|
|
49
|
+
this.delete(pointer);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
const unsubscribe = this.on(pointer, (v) => {
|
|
55
|
+
pointer++;
|
|
56
|
+
resolve(v);
|
|
57
|
+
}, false);
|
|
58
|
+
signal.onabort = () => {
|
|
59
|
+
unsubscribe();
|
|
60
|
+
resolve(new ExecutorState(true));
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
40
65
|
clone() {
|
|
41
66
|
const obj = super.clone();
|
|
42
67
|
obj.head = this.head;
|
|
@@ -7,6 +7,7 @@ var future = require('../../future/future.cjs');
|
|
|
7
7
|
require('ramda');
|
|
8
8
|
var synchronize = require('../../synchronize.cjs');
|
|
9
9
|
var stream = require('../../stream.cjs');
|
|
10
|
+
var stream_state = require('../../stream/state.cjs');
|
|
10
11
|
var QueueFullError = require('../../errors/QueueFullError.cjs');
|
|
11
12
|
var ValueDestroyedError = require('../../errors/ValueDestroyedError.cjs');
|
|
12
13
|
var Publisher = require('./Publisher.cjs');
|
|
@@ -26,6 +27,41 @@ class Queue extends WatchableObject.WatchableObject {
|
|
|
26
27
|
get streamEntries() {
|
|
27
28
|
return stream.Stream.of(this.asyncIterator);
|
|
28
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* A stream where data is only removed from the queue once the terminal action of the stream is finished with the data.
|
|
32
|
+
* Useful for cases where the stream is canceled in the middle and that data must not be removed from the queue as
|
|
33
|
+
* operations on it were not finished.
|
|
34
|
+
*
|
|
35
|
+
* Important Note: transactions means the data is not removed until finalized, therefore if more than one transactionalStream
|
|
36
|
+
* is open, each stream may see the same data from the queue if one stream is faster than another
|
|
37
|
+
*/
|
|
38
|
+
get transactionStream() {
|
|
39
|
+
let collected = [];
|
|
40
|
+
return new stream.Stream((signal) => {
|
|
41
|
+
if (this.closed) {
|
|
42
|
+
return new stream_state.ExecutorState(true);
|
|
43
|
+
}
|
|
44
|
+
const forwardHead = collected || collected[collected.length - 1] > this.head ? this.head + collected.length : this.head;
|
|
45
|
+
collected.push(forwardHead);
|
|
46
|
+
if (forwardHead > this.tail) {
|
|
47
|
+
return this.await(forwardHead, signal);
|
|
48
|
+
}
|
|
49
|
+
return this.get(forwardHead);
|
|
50
|
+
}).onFinalAction(() => {
|
|
51
|
+
try {
|
|
52
|
+
const lastHead = collected[collected.length - 1];
|
|
53
|
+
while (this.head <= lastHead) {
|
|
54
|
+
this.internalDequeue(true);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
// possible cause is another transaction is running
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
collected = [];
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
29
65
|
createPublisher(transformer) {
|
|
30
66
|
return new Publisher.Publisher(this, transformer);
|
|
31
67
|
}
|
|
@@ -68,17 +104,7 @@ class Queue extends WatchableObject.WatchableObject {
|
|
|
68
104
|
}));
|
|
69
105
|
}
|
|
70
106
|
dequeue() {
|
|
71
|
-
|
|
72
|
-
throw new ValueDestroyedError.ValueDestroyedError();
|
|
73
|
-
}
|
|
74
|
-
const value = this.get(this.head);
|
|
75
|
-
if (value !== undefined && value !== null) {
|
|
76
|
-
this.delete(this.head);
|
|
77
|
-
this.head++;
|
|
78
|
-
this.dequeueEvt.set();
|
|
79
|
-
return value;
|
|
80
|
-
}
|
|
81
|
-
throw new QueueEmptyError.QueueEmptyError();
|
|
107
|
+
return this.internalDequeue();
|
|
82
108
|
}
|
|
83
109
|
awaitDequeue(abortSignal) {
|
|
84
110
|
if (this.empty && !this.closed) {
|
|
@@ -182,6 +208,19 @@ class Queue extends WatchableObject.WatchableObject {
|
|
|
182
208
|
throw(e) {
|
|
183
209
|
throw e;
|
|
184
210
|
}
|
|
211
|
+
internalDequeue(soft = false) {
|
|
212
|
+
if (this.closed && !soft) {
|
|
213
|
+
throw new ValueDestroyedError.ValueDestroyedError();
|
|
214
|
+
}
|
|
215
|
+
const value = this.get(this.head);
|
|
216
|
+
if (value !== undefined && value !== null) {
|
|
217
|
+
this.delete(this.head);
|
|
218
|
+
this.head++;
|
|
219
|
+
this.dequeueEvt.set();
|
|
220
|
+
return value;
|
|
221
|
+
}
|
|
222
|
+
throw new QueueEmptyError.QueueEmptyError();
|
|
223
|
+
}
|
|
185
224
|
}
|
|
186
225
|
|
|
187
226
|
exports.Queue = Queue;
|
|
@@ -13,6 +13,15 @@ export declare class Queue<T> extends WatchableObject<number, T> implements Iter
|
|
|
13
13
|
private readonly dequeueEvt;
|
|
14
14
|
constructor(objectMaxSize?: number, expiryPeriod?: WaitPeriod);
|
|
15
15
|
get streamEntries(): Stream<T>;
|
|
16
|
+
/**
|
|
17
|
+
* A stream where data is only removed from the queue once the terminal action of the stream is finished with the data.
|
|
18
|
+
* Useful for cases where the stream is canceled in the middle and that data must not be removed from the queue as
|
|
19
|
+
* operations on it were not finished.
|
|
20
|
+
*
|
|
21
|
+
* Important Note: transactions means the data is not removed until finalized, therefore if more than one transactionalStream
|
|
22
|
+
* is open, each stream may see the same data from the queue if one stream is faster than another
|
|
23
|
+
*/
|
|
24
|
+
get transactionStream(): Stream<T>;
|
|
16
25
|
createPublisher<K>(transformer: (v: K) => T): Publisher<T, K>;
|
|
17
26
|
close(): void;
|
|
18
27
|
clone(): Queue<T>;
|
|
@@ -31,4 +40,5 @@ export declare class Queue<T> extends WatchableObject<number, T> implements Iter
|
|
|
31
40
|
next(...args: [] | [undefined]): IteratorResult<T, any>;
|
|
32
41
|
return?(value?: any): IteratorResult<T, any>;
|
|
33
42
|
throw?(e?: any): IteratorResult<T, any>;
|
|
43
|
+
private internalDequeue;
|
|
34
44
|
}
|
|
@@ -5,6 +5,7 @@ import { Future } from '../../future/future.mjs';
|
|
|
5
5
|
import 'ramda';
|
|
6
6
|
import { FutureEvent } from '../../synchronize.mjs';
|
|
7
7
|
import { Stream } from '../../stream.mjs';
|
|
8
|
+
import { ExecutorState } from '../../stream/state.mjs';
|
|
8
9
|
import { QueueFullError } from '../../errors/QueueFullError.mjs';
|
|
9
10
|
import { ValueDestroyedError } from '../../errors/ValueDestroyedError.mjs';
|
|
10
11
|
import { Publisher } from './Publisher.mjs';
|
|
@@ -24,6 +25,41 @@ class Queue extends WatchableObject {
|
|
|
24
25
|
get streamEntries() {
|
|
25
26
|
return Stream.of(this.asyncIterator);
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* A stream where data is only removed from the queue once the terminal action of the stream is finished with the data.
|
|
30
|
+
* Useful for cases where the stream is canceled in the middle and that data must not be removed from the queue as
|
|
31
|
+
* operations on it were not finished.
|
|
32
|
+
*
|
|
33
|
+
* Important Note: transactions means the data is not removed until finalized, therefore if more than one transactionalStream
|
|
34
|
+
* is open, each stream may see the same data from the queue if one stream is faster than another
|
|
35
|
+
*/
|
|
36
|
+
get transactionStream() {
|
|
37
|
+
let collected = [];
|
|
38
|
+
return new Stream((signal) => {
|
|
39
|
+
if (this.closed) {
|
|
40
|
+
return new ExecutorState(true);
|
|
41
|
+
}
|
|
42
|
+
const forwardHead = collected || collected[collected.length - 1] > this.head ? this.head + collected.length : this.head;
|
|
43
|
+
collected.push(forwardHead);
|
|
44
|
+
if (forwardHead > this.tail) {
|
|
45
|
+
return this.await(forwardHead, signal);
|
|
46
|
+
}
|
|
47
|
+
return this.get(forwardHead);
|
|
48
|
+
}).onFinalAction(() => {
|
|
49
|
+
try {
|
|
50
|
+
const lastHead = collected[collected.length - 1];
|
|
51
|
+
while (this.head <= lastHead) {
|
|
52
|
+
this.internalDequeue(true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
// possible cause is another transaction is running
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
collected = [];
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
27
63
|
createPublisher(transformer) {
|
|
28
64
|
return new Publisher(this, transformer);
|
|
29
65
|
}
|
|
@@ -66,17 +102,7 @@ class Queue extends WatchableObject {
|
|
|
66
102
|
}));
|
|
67
103
|
}
|
|
68
104
|
dequeue() {
|
|
69
|
-
|
|
70
|
-
throw new ValueDestroyedError();
|
|
71
|
-
}
|
|
72
|
-
const value = this.get(this.head);
|
|
73
|
-
if (value !== undefined && value !== null) {
|
|
74
|
-
this.delete(this.head);
|
|
75
|
-
this.head++;
|
|
76
|
-
this.dequeueEvt.set();
|
|
77
|
-
return value;
|
|
78
|
-
}
|
|
79
|
-
throw new QueueEmptyError();
|
|
105
|
+
return this.internalDequeue();
|
|
80
106
|
}
|
|
81
107
|
awaitDequeue(abortSignal) {
|
|
82
108
|
if (this.empty && !this.closed) {
|
|
@@ -180,6 +206,19 @@ class Queue extends WatchableObject {
|
|
|
180
206
|
throw(e) {
|
|
181
207
|
throw e;
|
|
182
208
|
}
|
|
209
|
+
internalDequeue(soft = false) {
|
|
210
|
+
if (this.closed && !soft) {
|
|
211
|
+
throw new ValueDestroyedError();
|
|
212
|
+
}
|
|
213
|
+
const value = this.get(this.head);
|
|
214
|
+
if (value !== undefined && value !== null) {
|
|
215
|
+
this.delete(this.head);
|
|
216
|
+
this.head++;
|
|
217
|
+
this.dequeueEvt.set();
|
|
218
|
+
return value;
|
|
219
|
+
}
|
|
220
|
+
throw new QueueEmptyError();
|
|
221
|
+
}
|
|
183
222
|
}
|
|
184
223
|
|
|
185
224
|
export { Queue };
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"gingersnap","version":"0.23.
|
|
1
|
+
{"name":"gingersnap","version":"0.23.10","description":"A general purpose library built with the aim of filling the gaps of javascript shortcomings","dependencies":{"@msgpack/msgpack":"^3.0.0-beta2","browser-or-node":"^3.0.0-pre.0","modern-isomorphic-ws":"^1.0.5","object-hash":"^3.0.0","papaparse":"^5.4.1","protobufjs":"^7.2.6","ramda":"^0.30.1","reflect-metadata":"^0.2.2","tslib":"^2.6.3","uuid":"^9.0.1","ws":"^8.16.0","x2js":"^3.4.4"},"author":"CookieNerds LLC","exports":{"./synchronize":{"import":{"types":"./synchronize.d.ts","default":"./synchronize.mjs"},"require":{"types":"./synchronize.d.ts","default":"./synchronize.cjs"}},"./mocks":{"import":{"types":"./mocks.d.ts","default":"./mocks.mjs"},"require":{"types":"./mocks.d.ts","default":"./mocks.cjs"}},"./socket":{"import":{"types":"./socket.d.ts","default":"./socket.mjs"},"require":{"types":"./socket.d.ts","default":"./socket.cjs"}},"./typing":{"import":{"types":"./typing.d.ts","default":"./typing.mjs"},"require":{"types":"./typing.d.ts","default":"./typing.cjs"}},"./stream":{"import":{"types":"./stream/index.d.ts","default":"./stream.mjs"},"require":{"types":"./stream/index.d.ts","default":"./stream.cjs"}},"./reflection/injector":{"import":{"types":"./reflection/injector.d.ts","default":"./reflection/injector.mjs"},"require":{"types":"./reflection/injector.d.ts","default":"./reflection/injector.cjs"}},"./stream/call":{"import":{"types":"./stream/call.d.ts","default":"./stream/call.mjs"},"require":{"types":"./stream/call.d.ts","default":"./stream/call.cjs"}},"./stream/state":{"import":{"types":"./stream/state.d.ts","default":"./stream/state.mjs"},"require":{"types":"./stream/state.d.ts","default":"./stream/state.cjs"}},"./stream/collector":{"import":{"types":"./stream/collector.d.ts","default":"./stream/collector.mjs"},"require":{"types":"./stream/collector.d.ts","default":"./stream/collector.cjs"}},"./stream/observable":{"import":{"types":"./stream/observable.d.ts","default":"./stream/observable.mjs"},"require":{"types":"./stream/observable.d.ts","default":"./stream/observable.cjs"}},"./networking":{"import":{"types":"./networking/index.d.ts","default":"./networking.mjs"},"require":{"types":"./networking/index.d.ts","default":"./networking.cjs"}},"./managers":{"import":{"types":"./managers/index.d.ts","default":"./managers.mjs"},"require":{"types":"./managers/index.d.ts","default":"./managers.cjs"}},"./future":{"import":{"types":"./future/index.d.ts","default":"./future.mjs"},"require":{"types":"./future/index.d.ts","default":"./future.cjs"}},"./errors":{"import":{"types":"./errors/index.d.ts","default":"./errors.mjs"},"require":{"types":"./errors/index.d.ts","default":"./errors.cjs"}},"./data-structures/array":{"import":{"types":"./data-structures/array/index.d.ts","default":"./data-structures/array.mjs"},"require":{"types":"./data-structures/array/index.d.ts","default":"./data-structures/array.cjs"}},"./data-structures/object":{"import":{"types":"./data-structures/object/index.d.ts","default":"./data-structures/object.mjs"},"require":{"types":"./data-structures/object/index.d.ts","default":"./data-structures/object.cjs"}},"./data/decoders":{"import":{"types":"./data/decoders/index.d.ts","default":"./data/decoders.mjs"},"require":{"types":"./data/decoders/index.d.ts","default":"./data/decoders.cjs"}},"./data/model":{"import":{"types":"./data/model/index.d.ts","default":"./data/model.mjs"},"require":{"types":"./data/model/index.d.ts","default":"./data/model.cjs"}},"./data/bus":{"import":{"types":"./data/bus.d.ts","default":"./data/bus.mjs"},"require":{"types":"./data/bus.d.ts","default":"./data/bus.cjs"}},"./data/AtomicValue":{"import":{"types":"./data/AtomicValue.d.ts","default":"./data/AtomicValue.mjs"},"require":{"types":"./data/AtomicValue.d.ts","default":"./data/AtomicValue.cjs"}},"./data/store":{"import":{"types":"./data/store/index.d.ts","default":"./data/store.mjs"},"require":{"types":"./data/store/index.d.ts","default":"./data/store.cjs"}},"./functools":{"import":{"types":"./functools/index.d.ts","default":"./functools.mjs"},"require":{"types":"./functools/index.d.ts","default":"./functools.cjs"}}}}
|
package/stream/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
32
32
|
}>;
|
|
33
33
|
protected cancelHooks: Set<() => any>;
|
|
34
34
|
protected completionHooks: Set<() => any>;
|
|
35
|
+
protected finalActionHooks: Set<() => any>;
|
|
35
36
|
protected completionHookInvoked: boolean;
|
|
36
37
|
protected monitorHooks: Set<(v: T) => void>;
|
|
37
38
|
private frozen;
|
|
@@ -180,7 +181,17 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
180
181
|
* @param hook
|
|
181
182
|
*/
|
|
182
183
|
onCompletion(hook: () => any): this;
|
|
184
|
+
/**
|
|
185
|
+
* Register hook that is called at the terminal end of a stream after each value is being consumed
|
|
186
|
+
* E.g. stream.onFinalAction(() => console.log('called after every foreach')).forEach(v => ....)
|
|
187
|
+
*
|
|
188
|
+
* Terminal Actions are those that consume the stream, and would be the final action that can be performed on the stream,
|
|
189
|
+
* usually returning a future
|
|
190
|
+
* @param hook
|
|
191
|
+
*/
|
|
192
|
+
onFinalAction(hook: () => any): this;
|
|
183
193
|
removeCompletionHook(hook: () => any): this;
|
|
194
|
+
removeFinalActionHook(hook: () => any): this;
|
|
184
195
|
/**
|
|
185
196
|
* Cancels the stream
|
|
186
197
|
* @param reason
|
|
@@ -258,7 +269,7 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
258
269
|
*/
|
|
259
270
|
catch<K>(callback: (v: Error) => K | null | undefined): Stream<InferErrorResult<K, T> | T>;
|
|
260
271
|
/**
|
|
261
|
-
* Consumes the entire stream and store the data in
|
|
272
|
+
* Consumes the entire stream and store the data in a collection. Future is immediately executed
|
|
262
273
|
*/
|
|
263
274
|
collect<K>(collector: Collector<K, T>): Future<K>;
|
|
264
275
|
/**
|
|
@@ -271,7 +282,7 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
271
282
|
* Iterates over the stream of values, used as a collector. Future is immediately executed
|
|
272
283
|
* @param callback
|
|
273
284
|
*/
|
|
274
|
-
forEach(callback: (v: T) => void | Future<void>): Future<void>;
|
|
285
|
+
forEach(callback: (v: T) => void | Future<void> | Promise<void>): Future<void>;
|
|
275
286
|
forEachLatest(callback: (v: T) => void | Future<void>): Future<void>;
|
|
276
287
|
/**
|
|
277
288
|
* Runs the stream only once. After this call, the stream is closed. Future is immediately executed
|
package/stream.cjs
CHANGED
|
@@ -65,6 +65,7 @@ class Stream {
|
|
|
65
65
|
this.backlog = [];
|
|
66
66
|
this.cancelHooks = new Set();
|
|
67
67
|
this.completionHooks = new Set();
|
|
68
|
+
this.finalActionHooks = new Set();
|
|
68
69
|
this.completionHookInvoked = false;
|
|
69
70
|
this.runLock = new synchronize.Lock();
|
|
70
71
|
this.concurrencyLimit = 0;
|
|
@@ -225,6 +226,7 @@ class Stream {
|
|
|
225
226
|
}
|
|
226
227
|
else {
|
|
227
228
|
resolve(v.value);
|
|
229
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
228
230
|
}
|
|
229
231
|
})
|
|
230
232
|
.catch(reject);
|
|
@@ -358,6 +360,7 @@ class Stream {
|
|
|
358
360
|
newStream.done = this.done;
|
|
359
361
|
newStream.cancelHooks = new Set(this.cancelHooks);
|
|
360
362
|
newStream.completionHooks = new Set(this.completionHooks);
|
|
363
|
+
newStream.finalActionHooks = new Set(this.finalActionHooks);
|
|
361
364
|
newStream.completionHookInvoked = this.completionHookInvoked;
|
|
362
365
|
return newStream;
|
|
363
366
|
}
|
|
@@ -553,6 +556,7 @@ class Stream {
|
|
|
553
556
|
newStream.backlog = [...this.backlog];
|
|
554
557
|
newStream.cancelHooks = new Set(this.cancelHooks);
|
|
555
558
|
newStream.completionHooks = new Set(this.completionHooks);
|
|
559
|
+
newStream.finalActionHooks = new Set(this.finalActionHooks);
|
|
556
560
|
newStream.completionHookInvoked = this.completionHookInvoked;
|
|
557
561
|
if (withSignals) {
|
|
558
562
|
newStream.controller = this.controller;
|
|
@@ -579,10 +583,26 @@ class Stream {
|
|
|
579
583
|
this.completionHooks.add(hook);
|
|
580
584
|
return this;
|
|
581
585
|
}
|
|
586
|
+
/**
|
|
587
|
+
* Register hook that is called at the terminal end of a stream after each value is being consumed
|
|
588
|
+
* E.g. stream.onFinalAction(() => console.log('called after every foreach')).forEach(v => ....)
|
|
589
|
+
*
|
|
590
|
+
* Terminal Actions are those that consume the stream, and would be the final action that can be performed on the stream,
|
|
591
|
+
* usually returning a future
|
|
592
|
+
* @param hook
|
|
593
|
+
*/
|
|
594
|
+
onFinalAction(hook) {
|
|
595
|
+
this.finalActionHooks.add(hook);
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
582
598
|
removeCompletionHook(hook) {
|
|
583
599
|
this.completionHooks.delete(hook);
|
|
584
600
|
return this;
|
|
585
601
|
}
|
|
602
|
+
removeFinalActionHook(hook) {
|
|
603
|
+
this.finalActionHooks.delete(hook);
|
|
604
|
+
return this;
|
|
605
|
+
}
|
|
586
606
|
/**
|
|
587
607
|
* Cancels the stream
|
|
588
608
|
* @param reason
|
|
@@ -861,10 +881,18 @@ class Stream {
|
|
|
861
881
|
return this;
|
|
862
882
|
}
|
|
863
883
|
/**
|
|
864
|
-
* Consumes the entire stream and store the data in
|
|
884
|
+
* Consumes the entire stream and store the data in a collection. Future is immediately executed
|
|
865
885
|
*/
|
|
866
886
|
collect(collector) {
|
|
867
|
-
return collector(this.isParallel
|
|
887
|
+
return collector(this.isParallel
|
|
888
|
+
? this.join().map((v) => {
|
|
889
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
890
|
+
return v;
|
|
891
|
+
})
|
|
892
|
+
: this.map((v) => {
|
|
893
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
894
|
+
return v;
|
|
895
|
+
})).schedule();
|
|
868
896
|
}
|
|
869
897
|
/**
|
|
870
898
|
* Continuously exhaust the stream until the stream ends or the limit is reached. No result will be provided at
|
|
@@ -887,6 +915,7 @@ class Stream {
|
|
|
887
915
|
_h = false;
|
|
888
916
|
try {
|
|
889
917
|
const _ = _c;
|
|
918
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
890
919
|
if (++index >= limit)
|
|
891
920
|
break;
|
|
892
921
|
}
|
|
@@ -911,6 +940,7 @@ class Stream {
|
|
|
911
940
|
_l = false;
|
|
912
941
|
try {
|
|
913
942
|
const _ = _f;
|
|
943
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
914
944
|
}
|
|
915
945
|
finally {
|
|
916
946
|
_l = true;
|
|
@@ -937,16 +967,38 @@ class Stream {
|
|
|
937
967
|
* @param callback
|
|
938
968
|
*/
|
|
939
969
|
forEach(callback) {
|
|
940
|
-
return new future.Future((resolve, reject
|
|
941
|
-
var _a;
|
|
970
|
+
return new future.Future((resolve, reject) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
971
|
+
var _a, e_4, _b, _c;
|
|
972
|
+
var _d;
|
|
942
973
|
try {
|
|
943
|
-
|
|
944
|
-
.
|
|
945
|
-
|
|
974
|
+
try {
|
|
975
|
+
for (var _e = true, _f = _tslib.__asyncValues(this), _g; _g = yield _f.next(), _a = _g.done, !_a;) {
|
|
976
|
+
_c = _g.value;
|
|
977
|
+
_e = false;
|
|
978
|
+
try {
|
|
979
|
+
const value = _c;
|
|
980
|
+
const result = callback(value);
|
|
981
|
+
if (result instanceof future.Future || result instanceof Promise) {
|
|
982
|
+
yield result;
|
|
983
|
+
}
|
|
984
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
985
|
+
}
|
|
986
|
+
finally {
|
|
987
|
+
_e = true;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
992
|
+
finally {
|
|
993
|
+
try {
|
|
994
|
+
if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
|
|
995
|
+
}
|
|
996
|
+
finally { if (e_4) throw e_4.error; }
|
|
997
|
+
}
|
|
946
998
|
resolve();
|
|
947
999
|
}
|
|
948
1000
|
catch (error) {
|
|
949
|
-
reject(error instanceof FutureError.FutureError ? error : new FutureError.FutureError((
|
|
1001
|
+
reject(error instanceof FutureError.FutureError ? error : new FutureError.FutureError((_d = error === null || error === void 0 ? void 0 : error.message) !== null && _d !== void 0 ? _d : "Unknown"));
|
|
950
1002
|
}
|
|
951
1003
|
})).schedule();
|
|
952
1004
|
}
|
|
@@ -957,6 +1009,7 @@ class Stream {
|
|
|
957
1009
|
let pending = null;
|
|
958
1010
|
while (!signal.aborted) {
|
|
959
1011
|
const value = yield this.internalNext().registerSignal(signal);
|
|
1012
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
960
1013
|
if (!value.done) {
|
|
961
1014
|
pending === null || pending === void 0 ? void 0 : pending.cancel();
|
|
962
1015
|
const result = callback(value.value);
|
|
@@ -990,6 +1043,7 @@ class Stream {
|
|
|
990
1043
|
if (value !== null && value !== undefined) {
|
|
991
1044
|
this.monitorHooks.forEach((hook) => hook(value));
|
|
992
1045
|
}
|
|
1046
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
993
1047
|
if (state !== exports.State.CONTINUE) {
|
|
994
1048
|
this.done = true;
|
|
995
1049
|
this.invokeCompletionHooks();
|
|
@@ -1097,6 +1151,7 @@ class Stream {
|
|
|
1097
1151
|
const preResult = yield this.yieldTrueResult(preProcessor(data), signal);
|
|
1098
1152
|
const result = yield this.yieldTrueResult(functor(preResult instanceof Promise ? yield preResult : preResult), signal);
|
|
1099
1153
|
if (result === null || result === undefined) {
|
|
1154
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
1100
1155
|
return resolve({ state: exports.State.CONTINUE });
|
|
1101
1156
|
}
|
|
1102
1157
|
data = result;
|
|
@@ -1309,7 +1364,7 @@ class Stream {
|
|
|
1309
1364
|
}
|
|
1310
1365
|
forwardExecute(preProcessor = R__namespace.identity) {
|
|
1311
1366
|
return future.Future.of((resolve, reject, signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1312
|
-
var _a,
|
|
1367
|
+
var _a, e_5, _b, _c;
|
|
1313
1368
|
let pending = [];
|
|
1314
1369
|
try {
|
|
1315
1370
|
for (var _d = true, _e = _tslib.__asyncValues(this.sourceStream.internalIterator()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
@@ -1333,12 +1388,12 @@ class Stream {
|
|
|
1333
1388
|
}
|
|
1334
1389
|
}
|
|
1335
1390
|
}
|
|
1336
|
-
catch (
|
|
1391
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
1337
1392
|
finally {
|
|
1338
1393
|
try {
|
|
1339
1394
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1340
1395
|
}
|
|
1341
|
-
finally { if (
|
|
1396
|
+
finally { if (e_5) throw e_5.error; }
|
|
1342
1397
|
}
|
|
1343
1398
|
const { state, value } = yield this.collectResult(pending, signal);
|
|
1344
1399
|
if (state === exports.State.CONTINUE) {
|
package/stream.mjs
CHANGED
|
@@ -44,6 +44,7 @@ class Stream {
|
|
|
44
44
|
this.backlog = [];
|
|
45
45
|
this.cancelHooks = new Set();
|
|
46
46
|
this.completionHooks = new Set();
|
|
47
|
+
this.finalActionHooks = new Set();
|
|
47
48
|
this.completionHookInvoked = false;
|
|
48
49
|
this.runLock = new Lock();
|
|
49
50
|
this.concurrencyLimit = 0;
|
|
@@ -204,6 +205,7 @@ class Stream {
|
|
|
204
205
|
}
|
|
205
206
|
else {
|
|
206
207
|
resolve(v.value);
|
|
208
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
207
209
|
}
|
|
208
210
|
})
|
|
209
211
|
.catch(reject);
|
|
@@ -337,6 +339,7 @@ class Stream {
|
|
|
337
339
|
newStream.done = this.done;
|
|
338
340
|
newStream.cancelHooks = new Set(this.cancelHooks);
|
|
339
341
|
newStream.completionHooks = new Set(this.completionHooks);
|
|
342
|
+
newStream.finalActionHooks = new Set(this.finalActionHooks);
|
|
340
343
|
newStream.completionHookInvoked = this.completionHookInvoked;
|
|
341
344
|
return newStream;
|
|
342
345
|
}
|
|
@@ -532,6 +535,7 @@ class Stream {
|
|
|
532
535
|
newStream.backlog = [...this.backlog];
|
|
533
536
|
newStream.cancelHooks = new Set(this.cancelHooks);
|
|
534
537
|
newStream.completionHooks = new Set(this.completionHooks);
|
|
538
|
+
newStream.finalActionHooks = new Set(this.finalActionHooks);
|
|
535
539
|
newStream.completionHookInvoked = this.completionHookInvoked;
|
|
536
540
|
if (withSignals) {
|
|
537
541
|
newStream.controller = this.controller;
|
|
@@ -558,10 +562,26 @@ class Stream {
|
|
|
558
562
|
this.completionHooks.add(hook);
|
|
559
563
|
return this;
|
|
560
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Register hook that is called at the terminal end of a stream after each value is being consumed
|
|
567
|
+
* E.g. stream.onFinalAction(() => console.log('called after every foreach')).forEach(v => ....)
|
|
568
|
+
*
|
|
569
|
+
* Terminal Actions are those that consume the stream, and would be the final action that can be performed on the stream,
|
|
570
|
+
* usually returning a future
|
|
571
|
+
* @param hook
|
|
572
|
+
*/
|
|
573
|
+
onFinalAction(hook) {
|
|
574
|
+
this.finalActionHooks.add(hook);
|
|
575
|
+
return this;
|
|
576
|
+
}
|
|
561
577
|
removeCompletionHook(hook) {
|
|
562
578
|
this.completionHooks.delete(hook);
|
|
563
579
|
return this;
|
|
564
580
|
}
|
|
581
|
+
removeFinalActionHook(hook) {
|
|
582
|
+
this.finalActionHooks.delete(hook);
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
565
585
|
/**
|
|
566
586
|
* Cancels the stream
|
|
567
587
|
* @param reason
|
|
@@ -840,10 +860,18 @@ class Stream {
|
|
|
840
860
|
return this;
|
|
841
861
|
}
|
|
842
862
|
/**
|
|
843
|
-
* Consumes the entire stream and store the data in
|
|
863
|
+
* Consumes the entire stream and store the data in a collection. Future is immediately executed
|
|
844
864
|
*/
|
|
845
865
|
collect(collector) {
|
|
846
|
-
return collector(this.isParallel
|
|
866
|
+
return collector(this.isParallel
|
|
867
|
+
? this.join().map((v) => {
|
|
868
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
869
|
+
return v;
|
|
870
|
+
})
|
|
871
|
+
: this.map((v) => {
|
|
872
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
873
|
+
return v;
|
|
874
|
+
})).schedule();
|
|
847
875
|
}
|
|
848
876
|
/**
|
|
849
877
|
* Continuously exhaust the stream until the stream ends or the limit is reached. No result will be provided at
|
|
@@ -866,6 +894,7 @@ class Stream {
|
|
|
866
894
|
_h = false;
|
|
867
895
|
try {
|
|
868
896
|
const _ = _c;
|
|
897
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
869
898
|
if (++index >= limit)
|
|
870
899
|
break;
|
|
871
900
|
}
|
|
@@ -890,6 +919,7 @@ class Stream {
|
|
|
890
919
|
_l = false;
|
|
891
920
|
try {
|
|
892
921
|
const _ = _f;
|
|
922
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
893
923
|
}
|
|
894
924
|
finally {
|
|
895
925
|
_l = true;
|
|
@@ -916,16 +946,38 @@ class Stream {
|
|
|
916
946
|
* @param callback
|
|
917
947
|
*/
|
|
918
948
|
forEach(callback) {
|
|
919
|
-
return new Future((resolve, reject
|
|
920
|
-
var _a;
|
|
949
|
+
return new Future((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
950
|
+
var _a, e_4, _b, _c;
|
|
951
|
+
var _d;
|
|
921
952
|
try {
|
|
922
|
-
|
|
923
|
-
.
|
|
924
|
-
|
|
953
|
+
try {
|
|
954
|
+
for (var _e = true, _f = __asyncValues(this), _g; _g = yield _f.next(), _a = _g.done, !_a;) {
|
|
955
|
+
_c = _g.value;
|
|
956
|
+
_e = false;
|
|
957
|
+
try {
|
|
958
|
+
const value = _c;
|
|
959
|
+
const result = callback(value);
|
|
960
|
+
if (result instanceof Future || result instanceof Promise) {
|
|
961
|
+
yield result;
|
|
962
|
+
}
|
|
963
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
964
|
+
}
|
|
965
|
+
finally {
|
|
966
|
+
_e = true;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
971
|
+
finally {
|
|
972
|
+
try {
|
|
973
|
+
if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
|
|
974
|
+
}
|
|
975
|
+
finally { if (e_4) throw e_4.error; }
|
|
976
|
+
}
|
|
925
977
|
resolve();
|
|
926
978
|
}
|
|
927
979
|
catch (error) {
|
|
928
|
-
reject(error instanceof FutureError ? error : new FutureError((
|
|
980
|
+
reject(error instanceof FutureError ? error : new FutureError((_d = error === null || error === void 0 ? void 0 : error.message) !== null && _d !== void 0 ? _d : "Unknown"));
|
|
929
981
|
}
|
|
930
982
|
})).schedule();
|
|
931
983
|
}
|
|
@@ -936,6 +988,7 @@ class Stream {
|
|
|
936
988
|
let pending = null;
|
|
937
989
|
while (!signal.aborted) {
|
|
938
990
|
const value = yield this.internalNext().registerSignal(signal);
|
|
991
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
939
992
|
if (!value.done) {
|
|
940
993
|
pending === null || pending === void 0 ? void 0 : pending.cancel();
|
|
941
994
|
const result = callback(value.value);
|
|
@@ -969,6 +1022,7 @@ class Stream {
|
|
|
969
1022
|
if (value !== null && value !== undefined) {
|
|
970
1023
|
this.monitorHooks.forEach((hook) => hook(value));
|
|
971
1024
|
}
|
|
1025
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
972
1026
|
if (state !== State.CONTINUE) {
|
|
973
1027
|
this.done = true;
|
|
974
1028
|
this.invokeCompletionHooks();
|
|
@@ -1076,6 +1130,7 @@ class Stream {
|
|
|
1076
1130
|
const preResult = yield this.yieldTrueResult(preProcessor(data), signal);
|
|
1077
1131
|
const result = yield this.yieldTrueResult(functor(preResult instanceof Promise ? yield preResult : preResult), signal);
|
|
1078
1132
|
if (result === null || result === undefined) {
|
|
1133
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
1079
1134
|
return resolve({ state: State.CONTINUE });
|
|
1080
1135
|
}
|
|
1081
1136
|
data = result;
|
|
@@ -1288,7 +1343,7 @@ class Stream {
|
|
|
1288
1343
|
}
|
|
1289
1344
|
forwardExecute(preProcessor = R.identity) {
|
|
1290
1345
|
return Future.of((resolve, reject, signal) => __awaiter(this, void 0, void 0, function* () {
|
|
1291
|
-
var _a,
|
|
1346
|
+
var _a, e_5, _b, _c;
|
|
1292
1347
|
let pending = [];
|
|
1293
1348
|
try {
|
|
1294
1349
|
for (var _d = true, _e = __asyncValues(this.sourceStream.internalIterator()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
@@ -1312,12 +1367,12 @@ class Stream {
|
|
|
1312
1367
|
}
|
|
1313
1368
|
}
|
|
1314
1369
|
}
|
|
1315
|
-
catch (
|
|
1370
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
1316
1371
|
finally {
|
|
1317
1372
|
try {
|
|
1318
1373
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1319
1374
|
}
|
|
1320
|
-
finally { if (
|
|
1375
|
+
finally { if (e_5) throw e_5.error; }
|
|
1321
1376
|
}
|
|
1322
1377
|
const { state, value } = yield this.collectResult(pending, signal);
|
|
1323
1378
|
if (state === State.CONTINUE) {
|