gingersnap 0.23.9 → 0.23.11
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 +14 -2
- package/stream.cjs +69 -11
- package/stream.mjs +69 -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.11","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;
|
|
@@ -143,6 +144,7 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
143
144
|
* @param callback
|
|
144
145
|
*/
|
|
145
146
|
filter(callback: (v: T) => boolean | Promise<boolean> | Future<boolean>): Stream<T>;
|
|
147
|
+
filterNotNull(): Stream<NonNullable<T>>;
|
|
146
148
|
reduce<K, V>(initialData: K, functor: (v: T, prev: K | V) => V, exhaustive?: boolean): Stream<V>;
|
|
147
149
|
reduceWhile<K, V>(predicate: (v: T) => boolean, initialData: K, functor: (v: T, prev: K | V) => V, exhaustive?: boolean): Stream<V>;
|
|
148
150
|
/**
|
|
@@ -180,7 +182,17 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
180
182
|
* @param hook
|
|
181
183
|
*/
|
|
182
184
|
onCompletion(hook: () => any): this;
|
|
185
|
+
/**
|
|
186
|
+
* Register hook that is called at the terminal end of a stream after each value is being consumed
|
|
187
|
+
* E.g. stream.onFinalAction(() => console.log('called after every foreach')).forEach(v => ....)
|
|
188
|
+
*
|
|
189
|
+
* Terminal Actions are those that consume the stream, and would be the final action that can be performed on the stream,
|
|
190
|
+
* usually returning a future
|
|
191
|
+
* @param hook
|
|
192
|
+
*/
|
|
193
|
+
onFinalAction(hook: () => any): this;
|
|
183
194
|
removeCompletionHook(hook: () => any): this;
|
|
195
|
+
removeFinalActionHook(hook: () => any): this;
|
|
184
196
|
/**
|
|
185
197
|
* Cancels the stream
|
|
186
198
|
* @param reason
|
|
@@ -258,7 +270,7 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
258
270
|
*/
|
|
259
271
|
catch<K>(callback: (v: Error) => K | null | undefined): Stream<InferErrorResult<K, T> | T>;
|
|
260
272
|
/**
|
|
261
|
-
* Consumes the entire stream and store the data in
|
|
273
|
+
* Consumes the entire stream and store the data in a collection. Future is immediately executed
|
|
262
274
|
*/
|
|
263
275
|
collect<K>(collector: Collector<K, T>): Future<K>;
|
|
264
276
|
/**
|
|
@@ -271,7 +283,7 @@ export declare class Stream<T> implements AsyncGenerator<T> {
|
|
|
271
283
|
* Iterates over the stream of values, used as a collector. Future is immediately executed
|
|
272
284
|
* @param callback
|
|
273
285
|
*/
|
|
274
|
-
forEach(callback: (v: T) => void | Future<void>): Future<void>;
|
|
286
|
+
forEach(callback: (v: T) => void | Future<void> | Promise<void>): Future<void>;
|
|
275
287
|
forEachLatest(callback: (v: T) => void | Future<void>): Future<void>;
|
|
276
288
|
/**
|
|
277
289
|
* 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
|
}
|
|
@@ -393,6 +396,9 @@ class Stream {
|
|
|
393
396
|
});
|
|
394
397
|
return this;
|
|
395
398
|
}
|
|
399
|
+
filterNotNull() {
|
|
400
|
+
return this.filter((it) => it !== null || it !== undefined);
|
|
401
|
+
}
|
|
396
402
|
reduce(initialData, functor, exhaustive = true) {
|
|
397
403
|
if (!this.canAlterStream)
|
|
398
404
|
throw new IllegalOperationError.IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
@@ -553,6 +559,7 @@ class Stream {
|
|
|
553
559
|
newStream.backlog = [...this.backlog];
|
|
554
560
|
newStream.cancelHooks = new Set(this.cancelHooks);
|
|
555
561
|
newStream.completionHooks = new Set(this.completionHooks);
|
|
562
|
+
newStream.finalActionHooks = new Set(this.finalActionHooks);
|
|
556
563
|
newStream.completionHookInvoked = this.completionHookInvoked;
|
|
557
564
|
if (withSignals) {
|
|
558
565
|
newStream.controller = this.controller;
|
|
@@ -579,10 +586,26 @@ class Stream {
|
|
|
579
586
|
this.completionHooks.add(hook);
|
|
580
587
|
return this;
|
|
581
588
|
}
|
|
589
|
+
/**
|
|
590
|
+
* Register hook that is called at the terminal end of a stream after each value is being consumed
|
|
591
|
+
* E.g. stream.onFinalAction(() => console.log('called after every foreach')).forEach(v => ....)
|
|
592
|
+
*
|
|
593
|
+
* Terminal Actions are those that consume the stream, and would be the final action that can be performed on the stream,
|
|
594
|
+
* usually returning a future
|
|
595
|
+
* @param hook
|
|
596
|
+
*/
|
|
597
|
+
onFinalAction(hook) {
|
|
598
|
+
this.finalActionHooks.add(hook);
|
|
599
|
+
return this;
|
|
600
|
+
}
|
|
582
601
|
removeCompletionHook(hook) {
|
|
583
602
|
this.completionHooks.delete(hook);
|
|
584
603
|
return this;
|
|
585
604
|
}
|
|
605
|
+
removeFinalActionHook(hook) {
|
|
606
|
+
this.finalActionHooks.delete(hook);
|
|
607
|
+
return this;
|
|
608
|
+
}
|
|
586
609
|
/**
|
|
587
610
|
* Cancels the stream
|
|
588
611
|
* @param reason
|
|
@@ -861,10 +884,18 @@ class Stream {
|
|
|
861
884
|
return this;
|
|
862
885
|
}
|
|
863
886
|
/**
|
|
864
|
-
* Consumes the entire stream and store the data in
|
|
887
|
+
* Consumes the entire stream and store the data in a collection. Future is immediately executed
|
|
865
888
|
*/
|
|
866
889
|
collect(collector) {
|
|
867
|
-
return collector(this.isParallel
|
|
890
|
+
return collector(this.isParallel
|
|
891
|
+
? this.join().map((v) => {
|
|
892
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
893
|
+
return v;
|
|
894
|
+
})
|
|
895
|
+
: this.map((v) => {
|
|
896
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
897
|
+
return v;
|
|
898
|
+
})).schedule();
|
|
868
899
|
}
|
|
869
900
|
/**
|
|
870
901
|
* Continuously exhaust the stream until the stream ends or the limit is reached. No result will be provided at
|
|
@@ -887,6 +918,7 @@ class Stream {
|
|
|
887
918
|
_h = false;
|
|
888
919
|
try {
|
|
889
920
|
const _ = _c;
|
|
921
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
890
922
|
if (++index >= limit)
|
|
891
923
|
break;
|
|
892
924
|
}
|
|
@@ -911,6 +943,7 @@ class Stream {
|
|
|
911
943
|
_l = false;
|
|
912
944
|
try {
|
|
913
945
|
const _ = _f;
|
|
946
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
914
947
|
}
|
|
915
948
|
finally {
|
|
916
949
|
_l = true;
|
|
@@ -937,16 +970,38 @@ class Stream {
|
|
|
937
970
|
* @param callback
|
|
938
971
|
*/
|
|
939
972
|
forEach(callback) {
|
|
940
|
-
return new future.Future((resolve, reject
|
|
941
|
-
var _a;
|
|
973
|
+
return new future.Future((resolve, reject) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
974
|
+
var _a, e_4, _b, _c;
|
|
975
|
+
var _d;
|
|
942
976
|
try {
|
|
943
|
-
|
|
944
|
-
.
|
|
945
|
-
|
|
977
|
+
try {
|
|
978
|
+
for (var _e = true, _f = _tslib.__asyncValues(this), _g; _g = yield _f.next(), _a = _g.done, !_a;) {
|
|
979
|
+
_c = _g.value;
|
|
980
|
+
_e = false;
|
|
981
|
+
try {
|
|
982
|
+
const value = _c;
|
|
983
|
+
const result = callback(value);
|
|
984
|
+
if (result instanceof future.Future || result instanceof Promise) {
|
|
985
|
+
yield result;
|
|
986
|
+
}
|
|
987
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
988
|
+
}
|
|
989
|
+
finally {
|
|
990
|
+
_e = true;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
995
|
+
finally {
|
|
996
|
+
try {
|
|
997
|
+
if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
|
|
998
|
+
}
|
|
999
|
+
finally { if (e_4) throw e_4.error; }
|
|
1000
|
+
}
|
|
946
1001
|
resolve();
|
|
947
1002
|
}
|
|
948
1003
|
catch (error) {
|
|
949
|
-
reject(error instanceof FutureError.FutureError ? error : new FutureError.FutureError((
|
|
1004
|
+
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
1005
|
}
|
|
951
1006
|
})).schedule();
|
|
952
1007
|
}
|
|
@@ -957,6 +1012,7 @@ class Stream {
|
|
|
957
1012
|
let pending = null;
|
|
958
1013
|
while (!signal.aborted) {
|
|
959
1014
|
const value = yield this.internalNext().registerSignal(signal);
|
|
1015
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
960
1016
|
if (!value.done) {
|
|
961
1017
|
pending === null || pending === void 0 ? void 0 : pending.cancel();
|
|
962
1018
|
const result = callback(value.value);
|
|
@@ -990,6 +1046,7 @@ class Stream {
|
|
|
990
1046
|
if (value !== null && value !== undefined) {
|
|
991
1047
|
this.monitorHooks.forEach((hook) => hook(value));
|
|
992
1048
|
}
|
|
1049
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
993
1050
|
if (state !== exports.State.CONTINUE) {
|
|
994
1051
|
this.done = true;
|
|
995
1052
|
this.invokeCompletionHooks();
|
|
@@ -1097,6 +1154,7 @@ class Stream {
|
|
|
1097
1154
|
const preResult = yield this.yieldTrueResult(preProcessor(data), signal);
|
|
1098
1155
|
const result = yield this.yieldTrueResult(functor(preResult instanceof Promise ? yield preResult : preResult), signal);
|
|
1099
1156
|
if (result === null || result === undefined) {
|
|
1157
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
1100
1158
|
return resolve({ state: exports.State.CONTINUE });
|
|
1101
1159
|
}
|
|
1102
1160
|
data = result;
|
|
@@ -1309,7 +1367,7 @@ class Stream {
|
|
|
1309
1367
|
}
|
|
1310
1368
|
forwardExecute(preProcessor = R__namespace.identity) {
|
|
1311
1369
|
return future.Future.of((resolve, reject, signal) => _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1312
|
-
var _a,
|
|
1370
|
+
var _a, e_5, _b, _c;
|
|
1313
1371
|
let pending = [];
|
|
1314
1372
|
try {
|
|
1315
1373
|
for (var _d = true, _e = _tslib.__asyncValues(this.sourceStream.internalIterator()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
@@ -1333,12 +1391,12 @@ class Stream {
|
|
|
1333
1391
|
}
|
|
1334
1392
|
}
|
|
1335
1393
|
}
|
|
1336
|
-
catch (
|
|
1394
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
1337
1395
|
finally {
|
|
1338
1396
|
try {
|
|
1339
1397
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1340
1398
|
}
|
|
1341
|
-
finally { if (
|
|
1399
|
+
finally { if (e_5) throw e_5.error; }
|
|
1342
1400
|
}
|
|
1343
1401
|
const { state, value } = yield this.collectResult(pending, signal);
|
|
1344
1402
|
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
|
}
|
|
@@ -372,6 +375,9 @@ class Stream {
|
|
|
372
375
|
});
|
|
373
376
|
return this;
|
|
374
377
|
}
|
|
378
|
+
filterNotNull() {
|
|
379
|
+
return this.filter((it) => it !== null || it !== undefined);
|
|
380
|
+
}
|
|
375
381
|
reduce(initialData, functor, exhaustive = true) {
|
|
376
382
|
if (!this.canAlterStream)
|
|
377
383
|
throw new IllegalOperationError("Cannot alter the stream as it is frozen");
|
|
@@ -532,6 +538,7 @@ class Stream {
|
|
|
532
538
|
newStream.backlog = [...this.backlog];
|
|
533
539
|
newStream.cancelHooks = new Set(this.cancelHooks);
|
|
534
540
|
newStream.completionHooks = new Set(this.completionHooks);
|
|
541
|
+
newStream.finalActionHooks = new Set(this.finalActionHooks);
|
|
535
542
|
newStream.completionHookInvoked = this.completionHookInvoked;
|
|
536
543
|
if (withSignals) {
|
|
537
544
|
newStream.controller = this.controller;
|
|
@@ -558,10 +565,26 @@ class Stream {
|
|
|
558
565
|
this.completionHooks.add(hook);
|
|
559
566
|
return this;
|
|
560
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Register hook that is called at the terminal end of a stream after each value is being consumed
|
|
570
|
+
* E.g. stream.onFinalAction(() => console.log('called after every foreach')).forEach(v => ....)
|
|
571
|
+
*
|
|
572
|
+
* Terminal Actions are those that consume the stream, and would be the final action that can be performed on the stream,
|
|
573
|
+
* usually returning a future
|
|
574
|
+
* @param hook
|
|
575
|
+
*/
|
|
576
|
+
onFinalAction(hook) {
|
|
577
|
+
this.finalActionHooks.add(hook);
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
561
580
|
removeCompletionHook(hook) {
|
|
562
581
|
this.completionHooks.delete(hook);
|
|
563
582
|
return this;
|
|
564
583
|
}
|
|
584
|
+
removeFinalActionHook(hook) {
|
|
585
|
+
this.finalActionHooks.delete(hook);
|
|
586
|
+
return this;
|
|
587
|
+
}
|
|
565
588
|
/**
|
|
566
589
|
* Cancels the stream
|
|
567
590
|
* @param reason
|
|
@@ -840,10 +863,18 @@ class Stream {
|
|
|
840
863
|
return this;
|
|
841
864
|
}
|
|
842
865
|
/**
|
|
843
|
-
* Consumes the entire stream and store the data in
|
|
866
|
+
* Consumes the entire stream and store the data in a collection. Future is immediately executed
|
|
844
867
|
*/
|
|
845
868
|
collect(collector) {
|
|
846
|
-
return collector(this.isParallel
|
|
869
|
+
return collector(this.isParallel
|
|
870
|
+
? this.join().map((v) => {
|
|
871
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
872
|
+
return v;
|
|
873
|
+
})
|
|
874
|
+
: this.map((v) => {
|
|
875
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
876
|
+
return v;
|
|
877
|
+
})).schedule();
|
|
847
878
|
}
|
|
848
879
|
/**
|
|
849
880
|
* Continuously exhaust the stream until the stream ends or the limit is reached. No result will be provided at
|
|
@@ -866,6 +897,7 @@ class Stream {
|
|
|
866
897
|
_h = false;
|
|
867
898
|
try {
|
|
868
899
|
const _ = _c;
|
|
900
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
869
901
|
if (++index >= limit)
|
|
870
902
|
break;
|
|
871
903
|
}
|
|
@@ -890,6 +922,7 @@ class Stream {
|
|
|
890
922
|
_l = false;
|
|
891
923
|
try {
|
|
892
924
|
const _ = _f;
|
|
925
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
893
926
|
}
|
|
894
927
|
finally {
|
|
895
928
|
_l = true;
|
|
@@ -916,16 +949,38 @@ class Stream {
|
|
|
916
949
|
* @param callback
|
|
917
950
|
*/
|
|
918
951
|
forEach(callback) {
|
|
919
|
-
return new Future((resolve, reject
|
|
920
|
-
var _a;
|
|
952
|
+
return new Future((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
953
|
+
var _a, e_4, _b, _c;
|
|
954
|
+
var _d;
|
|
921
955
|
try {
|
|
922
|
-
|
|
923
|
-
.
|
|
924
|
-
|
|
956
|
+
try {
|
|
957
|
+
for (var _e = true, _f = __asyncValues(this), _g; _g = yield _f.next(), _a = _g.done, !_a;) {
|
|
958
|
+
_c = _g.value;
|
|
959
|
+
_e = false;
|
|
960
|
+
try {
|
|
961
|
+
const value = _c;
|
|
962
|
+
const result = callback(value);
|
|
963
|
+
if (result instanceof Future || result instanceof Promise) {
|
|
964
|
+
yield result;
|
|
965
|
+
}
|
|
966
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
967
|
+
}
|
|
968
|
+
finally {
|
|
969
|
+
_e = true;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
974
|
+
finally {
|
|
975
|
+
try {
|
|
976
|
+
if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
|
|
977
|
+
}
|
|
978
|
+
finally { if (e_4) throw e_4.error; }
|
|
979
|
+
}
|
|
925
980
|
resolve();
|
|
926
981
|
}
|
|
927
982
|
catch (error) {
|
|
928
|
-
reject(error instanceof FutureError ? error : new FutureError((
|
|
983
|
+
reject(error instanceof FutureError ? error : new FutureError((_d = error === null || error === void 0 ? void 0 : error.message) !== null && _d !== void 0 ? _d : "Unknown"));
|
|
929
984
|
}
|
|
930
985
|
})).schedule();
|
|
931
986
|
}
|
|
@@ -936,6 +991,7 @@ class Stream {
|
|
|
936
991
|
let pending = null;
|
|
937
992
|
while (!signal.aborted) {
|
|
938
993
|
const value = yield this.internalNext().registerSignal(signal);
|
|
994
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
939
995
|
if (!value.done) {
|
|
940
996
|
pending === null || pending === void 0 ? void 0 : pending.cancel();
|
|
941
997
|
const result = callback(value.value);
|
|
@@ -969,6 +1025,7 @@ class Stream {
|
|
|
969
1025
|
if (value !== null && value !== undefined) {
|
|
970
1026
|
this.monitorHooks.forEach((hook) => hook(value));
|
|
971
1027
|
}
|
|
1028
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
972
1029
|
if (state !== State.CONTINUE) {
|
|
973
1030
|
this.done = true;
|
|
974
1031
|
this.invokeCompletionHooks();
|
|
@@ -1076,6 +1133,7 @@ class Stream {
|
|
|
1076
1133
|
const preResult = yield this.yieldTrueResult(preProcessor(data), signal);
|
|
1077
1134
|
const result = yield this.yieldTrueResult(functor(preResult instanceof Promise ? yield preResult : preResult), signal);
|
|
1078
1135
|
if (result === null || result === undefined) {
|
|
1136
|
+
this.finalActionHooks.forEach((hook) => hook());
|
|
1079
1137
|
return resolve({ state: State.CONTINUE });
|
|
1080
1138
|
}
|
|
1081
1139
|
data = result;
|
|
@@ -1288,7 +1346,7 @@ class Stream {
|
|
|
1288
1346
|
}
|
|
1289
1347
|
forwardExecute(preProcessor = R.identity) {
|
|
1290
1348
|
return Future.of((resolve, reject, signal) => __awaiter(this, void 0, void 0, function* () {
|
|
1291
|
-
var _a,
|
|
1349
|
+
var _a, e_5, _b, _c;
|
|
1292
1350
|
let pending = [];
|
|
1293
1351
|
try {
|
|
1294
1352
|
for (var _d = true, _e = __asyncValues(this.sourceStream.internalIterator()), _f; _f = yield _e.next(), _a = _f.done, !_a;) {
|
|
@@ -1312,12 +1370,12 @@ class Stream {
|
|
|
1312
1370
|
}
|
|
1313
1371
|
}
|
|
1314
1372
|
}
|
|
1315
|
-
catch (
|
|
1373
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
1316
1374
|
finally {
|
|
1317
1375
|
try {
|
|
1318
1376
|
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
1319
1377
|
}
|
|
1320
|
-
finally { if (
|
|
1378
|
+
finally { if (e_5) throw e_5.error; }
|
|
1321
1379
|
}
|
|
1322
1380
|
const { state, value } = yield this.collectResult(pending, signal);
|
|
1323
1381
|
if (state === State.CONTINUE) {
|