@thi.ng/rstream 8.2.12 → 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/iterable.js CHANGED
@@ -1,48 +1,26 @@
1
1
  import { CloseMode } from "./api.js";
2
2
  import { __optsWithID } from "./idgen.js";
3
3
  import { stream } from "./stream.js";
4
- /**
5
- * Returns a {@link Stream} of values from provided iterable, emitted at
6
- * the given `delay` interval.
7
- *
8
- * @remarks
9
- * Asynchronously starts pulling values from source iterable when the
10
- * first subscriber becomes available. The values are processed &
11
- * emitted via `setInterval()`, using the given `delay` value (default:
12
- * 0). By default, once the iterable is exhausted (if finite), calls
13
- * {@link ISubscriber.done} to close the stream, but this can be
14
- * re-configured via provided {@link CommonOpts | options}.
15
- *
16
- * @param src -
17
- * @param opts -
18
- */
19
- export const fromIterable = (src, opts = {}) => stream((stream) => {
20
- const iter = src[Symbol.iterator]();
21
- const id = setInterval(() => {
22
- let val;
23
- if ((val = iter.next()).done) {
24
- clearInterval(id);
25
- stream.closeIn !== CloseMode.NEVER && stream.done();
26
- }
27
- else {
28
- stream.next(val.value);
29
- }
30
- }, opts.delay || 0);
31
- return () => clearInterval(id);
32
- }, __optsWithID("iterable", opts));
33
- /**
34
- * Creates a new {@link Stream} of given iterable which synchronously calls
35
- * {@link ISubscriber.next} for each item of the iterable when the first (and in
36
- * this case the only one) subscriber becomes available. Once the iterable is
37
- * exhausted (MUST be finite!), then calls {@link ISubscriber.done} by default,
38
- * but can be avoided by passing `false` as last argument.
39
- *
40
- * @param src -
41
- * @param opts -
42
- */
43
- export const fromIterableSync = (src, opts) => stream((stream) => {
44
- for (let s of src) {
45
- stream.next(s);
4
+ const fromIterable = (src, opts = {}) => stream((stream2) => {
5
+ const iter = src[Symbol.iterator]();
6
+ const id = setInterval(() => {
7
+ let val;
8
+ if ((val = iter.next()).done) {
9
+ clearInterval(id);
10
+ stream2.closeIn !== CloseMode.NEVER && stream2.done();
11
+ } else {
12
+ stream2.next(val.value);
46
13
  }
47
- stream.closeIn !== CloseMode.NEVER && stream.done();
14
+ }, opts.delay || 0);
15
+ return () => clearInterval(id);
16
+ }, __optsWithID("iterable", opts));
17
+ const fromIterableSync = (src, opts) => stream((stream2) => {
18
+ for (let s of src) {
19
+ stream2.next(s);
20
+ }
21
+ stream2.closeIn !== CloseMode.NEVER && stream2.done();
48
22
  }, __optsWithID("iterable-sync", opts));
23
+ export {
24
+ fromIterable,
25
+ fromIterableSync
26
+ };
package/logger.js CHANGED
@@ -1,3 +1,7 @@
1
1
  import { NULL_LOGGER } from "@thi.ng/logger/null";
2
- export let LOGGER = NULL_LOGGER;
3
- export const setLogger = (logger) => (LOGGER = logger);
2
+ let LOGGER = NULL_LOGGER;
3
+ const setLogger = (logger) => LOGGER = logger;
4
+ export {
5
+ LOGGER,
6
+ setLogger
7
+ };
package/merge.js CHANGED
@@ -1,127 +1,81 @@
1
- import { State, } from "./api.js";
1
+ import {
2
+ State
3
+ } from "./api.js";
2
4
  import { isFirstOrLastInput } from "./checks.js";
3
5
  import { __optsWithID } from "./idgen.js";
4
6
  import { __removeAllIDs } from "./internal/remove.js";
5
7
  import { Subscription } from "./subscription.js";
6
- /**
7
- * Returns a new {@link StreamMerge} subscription, consuming values from
8
- * multiple inputs and passing received values on to any subscribers.
9
- *
10
- * @remarks
11
- * Input streams can be added and removed dynamically. By default, `StreamMerge`
12
- * calls {@link ISubscriber.done} when the last active input is done, but this
13
- * behavior can be overridden via the provided
14
- * {@link StreamMergeOpts | options}.
15
- *
16
- * @example
17
- * ```ts
18
- * merge({
19
- * // input streams w/ different frequencies
20
- * src: [
21
- * fromIterable([1, 2, 3], { delay: 10 }),
22
- * fromIterable([10, 20, 30], { delay: 21 }),
23
- * fromIterable([100, 200, 300], { delay: 7 })
24
- * ]
25
- * }).subscribe(trace());
26
- * // 100
27
- * // 1
28
- * // 200
29
- * // 10
30
- * // 2
31
- * // 300
32
- * // 3
33
- * // 20
34
- * // 30
35
- * ```
36
- *
37
- * @example
38
- * Use the
39
- * [`labeled()`](https://docs.thi.ng/umbrella/transducers/functions/labeled.html)
40
- * transducer for each input to create a stream of labeled values and
41
- * track their provenance:
42
- *
43
- * @example
44
- * ```ts
45
- * merge({
46
- * src: [
47
- * fromIterable([1, 2, 3]).transform(tx.labeled("a")),
48
- * fromIterable([10, 20, 30]).transform(tx.labeled("b")),
49
- * ]
50
- * }).subscribe(trace());
51
- * // ["a", 1]
52
- * // ["b", 10]
53
- * // ["a", 2]
54
- * // ["b", 20]
55
- * // ["a", 3]
56
- * // ["b", 30]
57
- * ```
58
- *
59
- * @param opts -
60
- */
61
- export const merge = (opts) => new StreamMerge(opts);
62
- /**
63
- * @see {@link merge} for reference & examples.
64
- */
65
- export class StreamMerge extends Subscription {
66
- sources;
67
- constructor(opts) {
68
- opts = opts || {};
69
- super(undefined, __optsWithID("streammerge", opts));
70
- this.sources = new Map();
71
- opts.src && this.addAll(opts.src);
8
+ const merge = (opts) => new StreamMerge(opts);
9
+ class StreamMerge extends Subscription {
10
+ sources;
11
+ constructor(opts) {
12
+ opts = opts || {};
13
+ super(void 0, __optsWithID("streammerge", opts));
14
+ this.sources = /* @__PURE__ */ new Map();
15
+ opts.src && this.addAll(opts.src);
16
+ }
17
+ add(src) {
18
+ this.ensureState();
19
+ this.sources.set(
20
+ src,
21
+ src.subscribe(
22
+ {
23
+ next: (x) => x instanceof Subscription ? this.add(x) : this.next(x),
24
+ done: () => this.markDone(src),
25
+ __owner: this
26
+ },
27
+ { id: `in-${src.id}` }
28
+ )
29
+ );
30
+ }
31
+ addAll(src) {
32
+ for (let s of src) {
33
+ this.add(s);
72
34
  }
73
- add(src) {
74
- this.ensureState();
75
- this.sources.set(src, src.subscribe({
76
- next: (x) => x instanceof Subscription ? this.add(x) : this.next(x),
77
- done: () => this.markDone(src),
78
- __owner: this,
79
- }, { id: `in-${src.id}` }));
35
+ }
36
+ remove(src) {
37
+ const sub = this.sources.get(src);
38
+ if (sub) {
39
+ this.sources.delete(src);
40
+ sub.unsubscribe();
41
+ return true;
80
42
  }
81
- addAll(src) {
82
- for (let s of src) {
83
- this.add(s);
84
- }
43
+ return false;
44
+ }
45
+ removeID(id) {
46
+ for (let s of this.sources) {
47
+ if (s[0].id === id) {
48
+ return this.remove(s[0]);
49
+ }
85
50
  }
86
- remove(src) {
87
- const sub = this.sources.get(src);
88
- if (sub) {
89
- this.sources.delete(src);
90
- sub.unsubscribe();
91
- return true;
92
- }
93
- return false;
51
+ return false;
52
+ }
53
+ removeAll(src) {
54
+ let ok = true;
55
+ for (let s of src) {
56
+ ok = this.remove(s) && ok;
94
57
  }
95
- removeID(id) {
96
- for (let s of this.sources) {
97
- if (s[0].id === id) {
98
- return this.remove(s[0]);
99
- }
100
- }
101
- return false;
102
- }
103
- removeAll(src) {
104
- let ok = true;
105
- for (let s of src) {
106
- ok = this.remove(s) && ok;
107
- }
108
- return ok;
109
- }
110
- removeAllIDs(ids) {
111
- return __removeAllIDs(this, ids);
112
- }
113
- unsubscribe(sub) {
114
- if (!sub) {
115
- for (let s of this.sources.values()) {
116
- s.unsubscribe();
117
- }
118
- this.state = State.DONE;
119
- this.sources.clear();
120
- }
121
- return super.unsubscribe(sub);
122
- }
123
- markDone(src) {
124
- this.remove(src);
125
- isFirstOrLastInput(this.closeIn, this.sources.size) && this.done();
58
+ return ok;
59
+ }
60
+ removeAllIDs(ids) {
61
+ return __removeAllIDs(this, ids);
62
+ }
63
+ unsubscribe(sub) {
64
+ if (!sub) {
65
+ for (let s of this.sources.values()) {
66
+ s.unsubscribe();
67
+ }
68
+ this.state = State.DONE;
69
+ this.sources.clear();
126
70
  }
71
+ return super.unsubscribe(sub);
72
+ }
73
+ markDone(src) {
74
+ this.remove(src);
75
+ isFirstOrLastInput(this.closeIn, this.sources.size) && this.done();
76
+ }
127
77
  }
78
+ export {
79
+ StreamMerge,
80
+ merge
81
+ };
package/metastream.js CHANGED
@@ -1,151 +1,75 @@
1
1
  import { assert } from "@thi.ng/errors/assert";
2
- import { CloseMode, State, } from "./api.js";
2
+ import {
3
+ CloseMode,
4
+ State
5
+ } from "./api.js";
3
6
  import { __optsWithID } from "./idgen.js";
4
7
  import { Subscription } from "./subscription.js";
5
- /**
6
- * Returns a {@link Subscription} which transforms each incoming value into a
7
- * new {@link ISubscription}, subscribes to it (via an hidden / internal
8
- * subscription) and then only passes values from that stream to its own
9
- * subscribers.
10
- *
11
- * @remarks
12
- * If a new value is received, the metastream first unsubscribes from any still
13
- * active previous stream (if any), before creating and subscribing to the new
14
- * one. Hence this stream type is useful for cases where streams need to be
15
- * dynamically created & inserted into an existing dataflow topology.
16
- *
17
- * The user supplied `factory` function will be called for each incoming value
18
- * and is responsible for creating the new stream instances. If the function
19
- * returns null/undefined, no further action will be taken (acts like a filter
20
- * transducer).
21
- *
22
- * The factory function does NOT need to create *new* streams, but can merely
23
- * return other existing streams, and so making the meta stream act like a
24
- * switch with arbitrary criteria. However, if the meta stream itself is the
25
- * only subscriber to such existing input streams, you'll need to configure the
26
- * input's {@link CommonOpts.closeOut} option to keep them alive and support
27
- * dynamic switching between them.
28
- *
29
- * @example
30
- * ```ts
31
- * // transform each received odd number into a stream
32
- * // producing 3 copies of that number in the metastream
33
- * // even numbers are ignored
34
- * a = metastream(
35
- * (x) => (x & 1)
36
- * ? fromIterable(tx.repeat(x, 3), { delay: 100 })
37
- * : null
38
- * );
39
- *
40
- * a.subscribe(trace())
41
- * a.next(23)
42
- *
43
- * // 23
44
- * // 23
45
- * // 23
46
- *
47
- * a.next(42) // ignored by factory fn
48
- *
49
- * a.next(43)
50
- * // 43
51
- * // 43
52
- * // 43
53
- * ```
54
- *
55
- * @example
56
- * ```ts
57
- * // infinite inputs
58
- * a = fromIterable(
59
- * tx.repeat("a"),
60
- * { delay: 1000, closeOut: CloseMode.NEVER }
61
- * );
62
- * b = fromIterable(
63
- * tx.repeat("b"),
64
- * { delay: 1000, closeOut: CloseMode.NEVER }
65
- * );
66
- *
67
- * // stream selector / switch
68
- * m = metaStream((x) => x ? a : b);
69
- * m.subscribe(trace("meta from: "));
70
- *
71
- * m.next(true);
72
- * // meta from: a
73
- *
74
- * m.next(false);
75
- * // meta from: b
76
- *
77
- * m.next(true);
78
- * // meta from: a
79
- * ```
80
- *
81
- * @param factory -
82
- * @param id -
83
- */
84
- export const metaStream = (factory, opts) => new MetaStream(factory, opts);
85
- /**
86
- * @see {@link metaStream} for reference & examples.
87
- */
88
- export class MetaStream extends Subscription {
89
- factory;
90
- stream;
91
- sub;
92
- emitLast;
93
- doneRequested;
94
- constructor(factory, opts = {}) {
95
- super(undefined, __optsWithID("metastram", opts));
96
- this.factory = factory;
97
- this.emitLast = opts.emitLast === true;
98
- this.doneRequested = false;
99
- }
100
- next(x) {
101
- if (this.state < State.DONE) {
102
- if (this.stream) {
103
- this.stream.unsubscribe(this.sub);
104
- }
105
- let stream = this.factory(x);
106
- if (stream) {
107
- this.stream = stream;
108
- this.sub = this.stream.subscribe({
109
- next: (x) => {
110
- stream === this.stream && super.dispatch(x);
111
- this.doneRequested && this.done();
112
- },
113
- done: () => {
114
- this.stream.unsubscribe(this.sub);
115
- if (stream === this.stream) {
116
- this.stream = undefined;
117
- this.sub = undefined;
118
- }
119
- },
120
- error: (e) => super.error(e),
121
- __owner: this,
122
- });
8
+ const metaStream = (factory, opts) => new MetaStream(factory, opts);
9
+ class MetaStream extends Subscription {
10
+ factory;
11
+ stream;
12
+ sub;
13
+ emitLast;
14
+ doneRequested;
15
+ constructor(factory, opts = {}) {
16
+ super(void 0, __optsWithID("metastram", opts));
17
+ this.factory = factory;
18
+ this.emitLast = opts.emitLast === true;
19
+ this.doneRequested = false;
20
+ }
21
+ next(x) {
22
+ if (this.state < State.DONE) {
23
+ if (this.stream) {
24
+ this.stream.unsubscribe(this.sub);
25
+ }
26
+ let stream = this.factory(x);
27
+ if (stream) {
28
+ this.stream = stream;
29
+ this.sub = this.stream.subscribe({
30
+ next: (x2) => {
31
+ stream === this.stream && super.dispatch(x2);
32
+ this.doneRequested && this.done();
33
+ },
34
+ done: () => {
35
+ this.stream.unsubscribe(this.sub);
36
+ if (stream === this.stream) {
37
+ this.stream = void 0;
38
+ this.sub = void 0;
123
39
  }
124
- }
40
+ },
41
+ error: (e) => super.error(e),
42
+ __owner: this
43
+ });
44
+ }
125
45
  }
126
- done() {
127
- if (this.emitLast && !this.doneRequested) {
128
- this.doneRequested = true;
129
- }
130
- else {
131
- if (this.stream) {
132
- this.detach(true);
133
- }
134
- this.closeIn !== CloseMode.NEVER && super.done();
135
- }
46
+ }
47
+ done() {
48
+ if (this.emitLast && !this.doneRequested) {
49
+ this.doneRequested = true;
50
+ } else {
51
+ if (this.stream) {
52
+ this.detach(true);
53
+ }
54
+ this.closeIn !== CloseMode.NEVER && super.done();
136
55
  }
137
- unsubscribe(sub) {
138
- if (this.stream && (!sub || this.subs.length === 1)) {
139
- this.detach(!sub);
140
- }
141
- return super.unsubscribe(sub);
56
+ }
57
+ unsubscribe(sub) {
58
+ if (this.stream && (!sub || this.subs.length === 1)) {
59
+ this.detach(!sub);
142
60
  }
143
- detach(force) {
144
- if (force || this.closeOut !== CloseMode.NEVER) {
145
- assert(!!this.stream, "input stream already removed");
146
- this.stream.unsubscribe(this.sub);
147
- delete this.stream;
148
- delete this.sub;
149
- }
61
+ return super.unsubscribe(sub);
62
+ }
63
+ detach(force) {
64
+ if (force || this.closeOut !== CloseMode.NEVER) {
65
+ assert(!!this.stream, "input stream already removed");
66
+ this.stream.unsubscribe(this.sub);
67
+ delete this.stream;
68
+ delete this.sub;
150
69
  }
70
+ }
151
71
  }
72
+ export {
73
+ MetaStream,
74
+ metaStream
75
+ };
package/nodejs.js CHANGED
@@ -1,54 +1,14 @@
1
1
  import { rechunk } from "@thi.ng/transducers/rechunk";
2
2
  import { stream } from "./stream.js";
3
- /**
4
- * Adapter bridge from NodeJS streams. Creates and returns a new {@link stream}
5
- * of type `T` and pipes in data from `stdout` (also assumed to produce data of
6
- * type `T`). If given, also connects `stderr` to new rstream's error handler.
7
- * Unless `close` is false, the new stream closes once `stdout` is closed.
8
- *
9
- * @param stdout -
10
- * @param stderr -
11
- * @param close -
12
- */
13
- export const fromNodeJS = (stdout, stderr, close = true) => {
14
- const ingest = stream();
15
- stdout.on("data", (data) => ingest.next(data));
16
- stderr && stderr.on("data", (data) => ingest.error(data));
17
- close && stdout.on("close", () => ingest.done());
18
- return ingest;
3
+ const fromNodeJS = (stdout, stderr, close = true) => {
4
+ const ingest = stream();
5
+ stdout.on("data", (data) => ingest.next(data));
6
+ stderr && stderr.on("data", (data) => ingest.error(data));
7
+ close && stdout.on("close", () => ingest.done());
8
+ return ingest;
9
+ };
10
+ const linesFromNodeJS = (stdout, stderr, re, close) => fromNodeJS(stdout, stderr, close).transform(rechunk(re));
11
+ export {
12
+ fromNodeJS,
13
+ linesFromNodeJS
19
14
  };
20
- /**
21
- * Specialized version of {@link fromNodeJS} for string inputs and automatic
22
- * rechunking/splitting of the input using the optionally provided regexp (line
23
- * breaks by default).
24
- *
25
- * @remarks
26
- * Internally uses https://docs.thi.ng/umbrella/transducers/functions/rechunk.html
27
- * to rechunk input.
28
- *
29
- * @example
30
- * ```ts
31
- * import { spawn } from "child_process"
32
- * import { linesFromNodeJS, trace } from "@thi.ng/rstream";
33
- *
34
- * const cmd = spawn("ls", ["-la"]);
35
- *
36
- * linesFromNodeJS<string>(cmd.stdout, cmd.stderr).subscribe(trace("output"));
37
- *
38
- * // output total 12760
39
- * // output drwxr-xr-x 37 foo staff 1184 Nov 15 15:29 .
40
- * // output drwxr-xr-x 143 foo staff 4576 Nov 11 21:08 ..
41
- * // output drwxr-xr-x 17 foo staff 544 Nov 15 17:39 .git
42
- * // output -rw-r--r-- 1 foo staff 149 Aug 4 15:32 .gitattributes
43
- * // output drwxr-xr-x 5 foo staff 160 Apr 12 2021 .github
44
- * // output -rw-r--r-- 1 foo staff 659 Sep 10 22:55 .gitignore
45
- * // ...
46
- * // output done
47
- * ```
48
- *
49
- * @param stdout -
50
- * @param stderr -
51
- * @param re -
52
- * @param close -
53
- */
54
- export const linesFromNodeJS = (stdout, stderr, re, close) => (fromNodeJS(stdout, stderr, close).transform(rechunk(re)));