@thi.ng/rstream 8.2.13 → 8.2.14

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/sync.js CHANGED
@@ -1,193 +1,150 @@
1
1
  import { comp } from "@thi.ng/transducers/comp";
2
2
  import { labeled } from "@thi.ng/transducers/labeled";
3
3
  import { mapVals } from "@thi.ng/transducers/map-vals";
4
- import { partitionSync, } from "@thi.ng/transducers/partition-sync";
4
+ import {
5
+ partitionSync
6
+ } from "@thi.ng/transducers/partition-sync";
5
7
  import { isFirstOrLastInput } from "./checks.js";
6
8
  import { __optsWithID } from "./idgen.js";
7
9
  import { __removeAllIDs } from "./internal/remove.js";
8
10
  import { LOGGER } from "./logger.js";
9
11
  import { Subscription } from "./subscription.js";
10
- /**
11
- * Similar to {@link StreamMerge}, but with extra synchronization of inputs.
12
- * Before emitting any new values, {@link StreamSync} collects values until at
13
- * least one has been received from *all* inputs. Once that's the case, the
14
- * collected values are sent as labeled tuple object to downstream subscribers.
15
- *
16
- * @remarks
17
- * Each value in the emitted tuple objects is stored under their input stream's
18
- * ID. Only the last value received from each input is passed on. After the
19
- * initial tuple has been emitted, you can choose from two possible behaviors:
20
- *
21
- * 1) Any future change in any input will produce a new result tuple. These
22
- * tuples will retain the most recently read values from other inputs. This
23
- * behavior is the default and illustrated in the above schematic.
24
- * 2) If the `reset` option is `true`, every input will have to provide at least
25
- * one new value again until another result tuple is produced.
26
- *
27
- * Any done inputs are automatically removed. By default, `StreamSync` calls
28
- * {@link ISubscriber.done} when the last active input is done, but this
29
- * behavior can be overridden via the provided options.
30
- *
31
- * Input streams can be added and removed dynamically and the emitted tuple size
32
- * adjusts to the current number of inputs (the next time a value is received
33
- * from any input). After an input is removed (or done) its last received value
34
- * can also be removed from the result tuple. This behavior can be configured
35
- * via the `clean` option given to `sync()` (disabled by default).
36
- *
37
- * If the `reset` option is enabled, the last emitted tuple is allowed to be
38
- * incomplete, by default. To only allow complete tuples, also set the `all`
39
- * option to `false`.
40
- *
41
- * The synchronization is done via the
42
- * [`partitionSync()`](https://docs.thi.ng/umbrella/transducers/functions/partitionSync-1.html)
43
- * transducer from the [`thi.ng/transducers`](https://thi.ng/transducers)
44
- * package. See this function's docs for further details.
45
- *
46
- * @example
47
- * ```ts
48
- * const a = stream();
49
- * const b = stream();
50
- * s = sync({ src: { a, b } }).subscribe(trace("result: "));
51
- * a.next(1);
52
- * b.next(2);
53
- * // result: { a: 1, b: 2 }
54
- * ```
55
- *
56
- * Also see: {@link StreamSyncOpts}
57
- *
58
- * @param opts -
59
- */
60
- export const sync = (opts) => new StreamSync(opts);
61
- /**
62
- * @see {@link sync} for reference & examples.
63
- */
64
- export class StreamSync extends Subscription {
65
- /**
66
- * maps actual inputs to their virtual input subs
67
- */
68
- sources;
69
- /**
70
- * maps real source IDs to their actual input
71
- */
72
- idSources;
73
- /**
74
- * maps (potentially aliased) input IDs to their actual src.id
75
- */
76
- realSourceIDs;
77
- /**
78
- * maps real src.id to (potentially aliased) input IDs
79
- */
80
- invRealSourceIDs;
81
- psync;
82
- clean;
83
- constructor(opts) {
84
- const psync = partitionSync(new Set(), {
85
- key: (x) => x[0],
86
- mergeOnly: opts.mergeOnly === true,
87
- reset: opts.reset === true,
88
- all: opts.all !== false,
89
- backPressure: opts.backPressure || 0,
90
- });
91
- const mapv = mapVals((x) => x[1]);
92
- super(undefined, __optsWithID("streamsync", {
93
- ...opts,
94
- xform: opts.xform
95
- ? comp(psync, mapv, opts.xform)
96
- : comp(psync, mapv),
97
- }));
98
- this.sources = new Map();
99
- this.realSourceIDs = new Map();
100
- this.invRealSourceIDs = new Map();
101
- this.idSources = new Map();
102
- this.psync = psync;
103
- this.clean = !!opts.clean;
104
- opts.src && this.addAll(opts.src);
105
- }
106
- add(src, id) {
107
- id || (id = src.id);
108
- this.ensureState();
109
- this.psync.add(id);
110
- this.realSourceIDs.set(id, src.id);
111
- this.invRealSourceIDs.set(src.id, id);
112
- this.idSources.set(src.id, src);
113
- this.sources.set(src, src.subscribe({
114
- next: (x) =>
12
+ const sync = (opts) => new StreamSync(opts);
13
+ class StreamSync extends Subscription {
14
+ /**
15
+ * maps actual inputs to their virtual input subs
16
+ */
17
+ sources;
18
+ /**
19
+ * maps real source IDs to their actual input
20
+ */
21
+ idSources;
22
+ /**
23
+ * maps (potentially aliased) input IDs to their actual src.id
24
+ */
25
+ realSourceIDs;
26
+ /**
27
+ * maps real src.id to (potentially aliased) input IDs
28
+ */
29
+ invRealSourceIDs;
30
+ psync;
31
+ clean;
32
+ constructor(opts) {
33
+ const psync = partitionSync(/* @__PURE__ */ new Set(), {
34
+ key: (x) => x[0],
35
+ mergeOnly: opts.mergeOnly === true,
36
+ reset: opts.reset === true,
37
+ all: opts.all !== false,
38
+ backPressure: opts.backPressure || 0
39
+ });
40
+ const mapv = mapVals((x) => x[1]);
41
+ super(
42
+ void 0,
43
+ __optsWithID("streamsync", {
44
+ ...opts,
45
+ xform: opts.xform ? comp(psync, mapv, opts.xform) : comp(psync, mapv)
46
+ })
47
+ );
48
+ this.sources = /* @__PURE__ */ new Map();
49
+ this.realSourceIDs = /* @__PURE__ */ new Map();
50
+ this.invRealSourceIDs = /* @__PURE__ */ new Map();
51
+ this.idSources = /* @__PURE__ */ new Map();
52
+ this.psync = psync;
53
+ this.clean = !!opts.clean;
54
+ opts.src && this.addAll(opts.src);
55
+ }
56
+ add(src, id) {
57
+ id || (id = src.id);
58
+ this.ensureState();
59
+ this.psync.add(id);
60
+ this.realSourceIDs.set(id, src.id);
61
+ this.invRealSourceIDs.set(src.id, id);
62
+ this.idSources.set(src.id, src);
63
+ this.sources.set(
64
+ src,
65
+ src.subscribe(
66
+ {
67
+ next: (x) => (
115
68
  // if received value is sub, add it as source
116
- x[1] instanceof Subscription
117
- ? this.add(x[1])
118
- : this.next(x),
119
- done: () => this.markDone(src),
120
- __owner: this,
121
- }, { xform: labeled(id), id: `in-${id}` }));
122
- }
123
- addAll(src) {
124
- // pre-add all source ids for partitionSync
125
- for (let id in src) {
126
- this.psync.add(id);
127
- }
128
- for (let id in src) {
129
- this.add(src[id], id);
130
- }
131
- }
132
- remove(src) {
133
- const sub = this.sources.get(src);
134
- if (sub) {
135
- const id = this.invRealSourceIDs.get(src.id);
136
- LOGGER.info(`removing src: ${src.id} (${id})`);
137
- this.psync.delete(id, this.clean);
138
- this.realSourceIDs.delete(id);
139
- this.invRealSourceIDs.delete(src.id);
140
- this.idSources.delete(src.id);
141
- this.sources.delete(src);
142
- sub.unsubscribe();
143
- return true;
144
- }
145
- return false;
146
- }
147
- removeID(id) {
148
- const src = this.getSourceForID(id);
149
- return src ? this.remove(src) : false;
69
+ x[1] instanceof Subscription ? this.add(x[1]) : this.next(x)
70
+ ),
71
+ done: () => this.markDone(src),
72
+ __owner: this
73
+ },
74
+ { xform: labeled(id), id: `in-${id}` }
75
+ )
76
+ );
77
+ }
78
+ addAll(src) {
79
+ for (let id in src) {
80
+ this.psync.add(id);
150
81
  }
151
- removeAll(src) {
152
- // pre-remove all source ids for partitionSync
153
- for (let s of src) {
154
- this.psync.delete(this.invRealSourceIDs.get(s.id));
155
- }
156
- let ok = true;
157
- for (let s of src) {
158
- ok = this.remove(s) && ok;
159
- }
160
- return ok;
82
+ for (let id in src) {
83
+ this.add(src[id], id);
161
84
  }
162
- removeAllIDs(ids) {
163
- return __removeAllIDs(this, ids);
85
+ }
86
+ remove(src) {
87
+ const sub = this.sources.get(src);
88
+ if (sub) {
89
+ const id = this.invRealSourceIDs.get(src.id);
90
+ LOGGER.info(`removing src: ${src.id} (${id})`);
91
+ this.psync.delete(id, this.clean);
92
+ this.realSourceIDs.delete(id);
93
+ this.invRealSourceIDs.delete(src.id);
94
+ this.idSources.delete(src.id);
95
+ this.sources.delete(src);
96
+ sub.unsubscribe();
97
+ return true;
164
98
  }
165
- getSourceForID(id) {
166
- return this.idSources.get(this.realSourceIDs.get(id));
99
+ return false;
100
+ }
101
+ removeID(id) {
102
+ const src = this.getSourceForID(id);
103
+ return src ? this.remove(src) : false;
104
+ }
105
+ removeAll(src) {
106
+ for (let s of src) {
107
+ this.psync.delete(this.invRealSourceIDs.get(s.id));
167
108
  }
168
- getSources() {
169
- const res = {};
170
- for (let [id, src] of this.idSources) {
171
- res[this.invRealSourceIDs.get(id)] = src;
172
- }
173
- return res;
109
+ let ok = true;
110
+ for (let s of src) {
111
+ ok = this.remove(s) && ok;
174
112
  }
175
- unsubscribe(sub) {
176
- if (!sub) {
177
- LOGGER.debug(this.id, "unsub sources");
178
- for (let s of this.sources.values()) {
179
- s.unsubscribe();
180
- }
181
- this.sources.clear();
182
- this.psync.clear();
183
- this.realSourceIDs.clear();
184
- this.invRealSourceIDs.clear();
185
- this.idSources.clear();
186
- }
187
- return super.unsubscribe(sub);
113
+ return ok;
114
+ }
115
+ removeAllIDs(ids) {
116
+ return __removeAllIDs(this, ids);
117
+ }
118
+ getSourceForID(id) {
119
+ return this.idSources.get(this.realSourceIDs.get(id));
120
+ }
121
+ getSources() {
122
+ const res = {};
123
+ for (let [id, src] of this.idSources) {
124
+ res[this.invRealSourceIDs.get(id)] = src;
188
125
  }
189
- markDone(src) {
190
- this.remove(src);
191
- isFirstOrLastInput(this.closeIn, this.sources.size) && this.done();
126
+ return res;
127
+ }
128
+ unsubscribe(sub) {
129
+ if (!sub) {
130
+ LOGGER.debug(this.id, "unsub sources");
131
+ for (let s of this.sources.values()) {
132
+ s.unsubscribe();
133
+ }
134
+ this.sources.clear();
135
+ this.psync.clear();
136
+ this.realSourceIDs.clear();
137
+ this.invRealSourceIDs.clear();
138
+ this.idSources.clear();
192
139
  }
140
+ return super.unsubscribe(sub);
141
+ }
142
+ markDone(src) {
143
+ this.remove(src);
144
+ isFirstOrLastInput(this.closeIn, this.sources.size) && this.done();
145
+ }
193
146
  }
147
+ export {
148
+ StreamSync,
149
+ sync
150
+ };
package/timeout.js CHANGED
@@ -1,55 +1,44 @@
1
1
  import { State } from "./api.js";
2
2
  import { __optsWithID } from "./idgen.js";
3
3
  import { Subscription } from "./subscription.js";
4
- /**
5
- * Returns a {@link Subscription} that calls the
6
- * {@link ISubscriber.error} handlers of all child subscriptions with an
7
- * arbitrary error object after a given time.
8
- *
9
- * @remarks
10
- * If no `error` is given, uses a new `Error` instance by default. If
11
- * `resetTimeout` is false (default), the error is emitted regardless of
12
- * any received values in the meantime. However, if `true`, the timeout
13
- * resets with each received value and then only triggers once the time
14
- * interval since the last value has exceeded.
15
- *
16
- * @param timeoutMs - timeout period in milliseconds
17
- * @param opts -
18
- */
19
- export const timeout = (timeoutMs, opts) => new Timeout(timeoutMs, opts);
20
- /**
21
- * @see {@link timeout} for reference & examples.
22
- */
4
+ const timeout = (timeoutMs, opts) => new Timeout(timeoutMs, opts);
23
5
  class Timeout extends Subscription {
24
- timeoutMs;
25
- timeoutId;
26
- errorObj;
27
- resetTimeout;
28
- constructor(timeoutMs, opts) {
29
- opts = __optsWithID("timeout", opts);
30
- super(undefined, opts);
31
- this.timeoutMs = timeoutMs;
32
- this.errorObj = opts.error;
33
- this.resetTimeout = opts.reset === true;
34
- this.reset();
35
- }
36
- next(x) {
37
- if (this.resetTimeout) {
38
- clearTimeout(this.timeoutId);
39
- this.reset();
40
- }
41
- super.next(x);
42
- }
43
- reset() {
44
- this.timeoutId = setTimeout(() => {
45
- if (this.state < State.DONE) {
46
- this.dispatchTo("error", this.errorObj ||
47
- new Error(`Timeout '${this.id}' after ${this.timeoutMs} ms`));
48
- }
49
- }, this.timeoutMs);
50
- }
51
- release() {
52
- clearTimeout(this.timeoutId);
53
- super.release();
6
+ timeoutMs;
7
+ timeoutId;
8
+ errorObj;
9
+ resetTimeout;
10
+ constructor(timeoutMs, opts) {
11
+ opts = __optsWithID("timeout", opts);
12
+ super(void 0, opts);
13
+ this.timeoutMs = timeoutMs;
14
+ this.errorObj = opts.error;
15
+ this.resetTimeout = opts.reset === true;
16
+ this.reset();
17
+ }
18
+ next(x) {
19
+ if (this.resetTimeout) {
20
+ clearTimeout(this.timeoutId);
21
+ this.reset();
54
22
  }
23
+ super.next(x);
24
+ }
25
+ reset() {
26
+ this.timeoutId = setTimeout(() => {
27
+ if (this.state < State.DONE) {
28
+ this.dispatchTo(
29
+ "error",
30
+ this.errorObj || new Error(
31
+ `Timeout '${this.id}' after ${this.timeoutMs} ms`
32
+ )
33
+ );
34
+ }
35
+ }, this.timeoutMs);
36
+ }
37
+ release() {
38
+ clearTimeout(this.timeoutId);
39
+ super.release();
40
+ }
55
41
  }
42
+ export {
43
+ timeout
44
+ };
package/toggle.js CHANGED
@@ -1,32 +1,13 @@
1
1
  import { toggle as $toggle } from "@thi.ng/transducers/toggle";
2
2
  import { Subscription } from "./subscription.js";
3
- /**
4
- * Returns a {@link Subscription} which toggles between true/false for each
5
- * {@link Subscription.next} call. The sub will be seeded with the given
6
- * `initial` value.
7
- *
8
- * @examples
9
- * ```ts
10
- * const mute = toggle(false);
11
- *
12
- * mute.subscribe(trace("mute"));
13
- * // mute false
14
- *
15
- * mute.next();
16
- * // mute true
17
- *
18
- * mute.next();
19
- * // mute false
20
- * ```
21
- *
22
- * @param initial
23
- * @param opts
24
- */
25
- export function toggle(initial, opts) {
26
- const sub = new Subscription(undefined, {
27
- xform: $toggle(true, false, !initial),
28
- ...opts,
29
- });
30
- sub.next();
31
- return sub;
3
+ function toggle(initial, opts) {
4
+ const sub = new Subscription(void 0, {
5
+ xform: $toggle(true, false, !initial),
6
+ ...opts
7
+ });
8
+ sub.next();
9
+ return sub;
32
10
  }
11
+ export {
12
+ toggle
13
+ };
package/trace.js CHANGED
@@ -1,19 +1,15 @@
1
- /**
2
- * Helper {@link ISubscriber} for inspection / debugging purposes.
3
- * Simply logs received values to console, optionally with given
4
- * `prefix`.
5
- *
6
- * @param prefix -
7
- */
8
- export const trace = (prefix) => ({
9
- next(x) {
10
- prefix ? console.log(prefix, x) : console.log(x);
11
- },
12
- done() {
13
- prefix ? console.log(prefix, "done") : console.log("done");
14
- },
15
- error(e) {
16
- prefix ? console.log(prefix, "error", e) : console.log("error", e);
17
- return false;
18
- },
1
+ const trace = (prefix) => ({
2
+ next(x) {
3
+ prefix ? console.log(prefix, x) : console.log(x);
4
+ },
5
+ done() {
6
+ prefix ? console.log(prefix, "done") : console.log("done");
7
+ },
8
+ error(e) {
9
+ prefix ? console.log(prefix, "error", e) : console.log("error", e);
10
+ return false;
11
+ }
19
12
  });
13
+ export {
14
+ trace
15
+ };
package/transduce.js CHANGED
@@ -1,62 +1,45 @@
1
1
  import { isReduced } from "@thi.ng/transducers/reduced";
2
- /**
3
- * Returns a promise which subscribes to given input and transforms
4
- * incoming values using given transducer `xform` and reducer `rfn`.
5
- *
6
- * @remarks
7
- * Once the input or the reducer is done, the promise will resolve with
8
- * the final reduced result (or fail with error).
9
- *
10
- * @example
11
- * ```ts
12
- * transduce(
13
- * fromIterable(tx.range(10)),
14
- * tx.map((x) => x * 10),
15
- * tx.add()
16
- * ).then((x) => console.log("result", x))
17
- *
18
- * // result 450
19
- * ```
20
- *
21
- * @param src -
22
- * @param xform -
23
- * @param rfn -
24
- * @param init -
25
- */
26
- export const transduce = (src, xform, rfn, init) => {
27
- let acc = init !== undefined ? init : rfn[0]();
28
- let sub;
29
- return new Promise((resolve, reject) => {
30
- sub = src.subscribe({
31
- next(x) {
32
- let _acc;
33
- try {
34
- _acc = rfn[2](acc, x);
35
- }
36
- catch (e) {
37
- reject(e);
38
- return;
39
- }
40
- if (isReduced(_acc)) {
41
- resolve(_acc.deref());
42
- }
43
- else {
44
- acc = _acc;
45
- }
46
- },
47
- done() {
48
- resolve(acc);
49
- },
50
- error(e) {
51
- reject(e);
52
- return false;
53
- },
54
- }, { xform });
55
- }).then((fulfilled) => {
56
- sub.unsubscribe();
57
- return fulfilled;
58
- }, (rejected) => {
59
- sub.unsubscribe();
60
- throw rejected;
61
- });
2
+ const transduce = (src, xform, rfn, init) => {
3
+ let acc = init !== void 0 ? init : rfn[0]();
4
+ let sub;
5
+ return new Promise((resolve, reject) => {
6
+ sub = src.subscribe(
7
+ {
8
+ next(x) {
9
+ let _acc;
10
+ try {
11
+ _acc = rfn[2](acc, x);
12
+ } catch (e) {
13
+ reject(e);
14
+ return;
15
+ }
16
+ if (isReduced(_acc)) {
17
+ resolve(_acc.deref());
18
+ } else {
19
+ acc = _acc;
20
+ }
21
+ },
22
+ done() {
23
+ resolve(acc);
24
+ },
25
+ error(e) {
26
+ reject(e);
27
+ return false;
28
+ }
29
+ },
30
+ { xform }
31
+ );
32
+ }).then(
33
+ (fulfilled) => {
34
+ sub.unsubscribe();
35
+ return fulfilled;
36
+ },
37
+ (rejected) => {
38
+ sub.unsubscribe();
39
+ throw rejected;
40
+ }
41
+ );
42
+ };
43
+ export {
44
+ transduce
62
45
  };
package/trigger.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import { __optsWithID } from "./idgen.js";
2
2
  import { fromIterableSync } from "./iterable.js";
3
- export function trigger(x = true, opts) {
4
- return fromIterableSync([x], __optsWithID("trigger", opts));
3
+ function trigger(x = true, opts) {
4
+ return fromIterableSync([x], __optsWithID("trigger", opts));
5
5
  }
6
+ export {
7
+ trigger
8
+ };