@thi.ng/rstream 8.2.13 → 8.2.15

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/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)));
package/object.js CHANGED
@@ -1,103 +1,39 @@
1
1
  import { dedupe } from "@thi.ng/transducers/dedupe";
2
2
  import { __nextID } from "./idgen.js";
3
3
  import { subscription } from "./subscription.js";
4
- /**
5
- * Takes an arbitrary object `src` and object of options (see
6
- * {@link StreamObjOpts}). Creates a new object and for each selected
7
- * key creates a new stream, optionally seeded with the key's value in
8
- * `src`. Returns new object of streams.
9
- *
10
- * @remarks
11
- * The structure of the returned object is
12
- * {@link StreamObj | as follows}:
13
- *
14
- * ```ts
15
- * {
16
- * streams: { ... },
17
- * next(x): void;
18
- * done(): void;
19
- * }
20
- * ```
21
- *
22
- * All streams will be stored under `streams`. The `next()` and `done()`
23
- * functions/methods allow the object itself to be used as subscriber
24
- * for an upstream subscribable (see 2nd example below):
25
- *
26
- * - `next()` - takes a object of same type as `src` and feeds each
27
- * key's new value into its respective stream. If the `defaults`
28
- * option is given, `undefined` key values are replaced with their
29
- * specified default. If `dedupe` is enabled (default) only changed
30
- * values (as per `equiv` predicate option) will be propagated
31
- * downstream.
32
- * - `done()` - calls {@link ISubscriber.done} on all streams
33
- *
34
- * The optional `opts` arg is used to customize overall behavior of
35
- * `fromObject` and specify shared options for *all* created streams.
36
- *
37
- * @example
38
- * ```ts
39
- * type Foo = { a?: number; b: string; };
40
- *
41
- * const obj = fromObject(<Foo>{ a: 1, b: "foo" })
42
- *
43
- * obj.streams.a.subscribe(trace("a"))
44
- * // a 1
45
- * obj.streams.b.subscribe(trace("b"))
46
- * // b foo
47
- *
48
- * obj.next({ b: "bar" })
49
- * // a undefined
50
- * // b bar
51
- * ```
52
- *
53
- * @example
54
- * ```ts
55
- * const obj = fromObject(<Foo>{}, ["a", "b"], { initial: false });
56
- * obj.streams.a.subscribe(trace("a"));
57
- * obj.streams.b.subscribe(trace("b"));
58
- *
59
- * const src = subscription<Foo, Foo>();
60
- * // use as subscriber
61
- * src.subscribe(obj);
62
- *
63
- * src.next({ a: 1, b: "foo" });
64
- * // a 1
65
- * // b foo
66
- * ```
67
- *
68
- * @param src -
69
- * @param opts -
70
- */
71
- export const fromObject = (src, opts = {}) => {
72
- const id = opts.id || `obj${__nextID()}`;
73
- const keys = opts.keys || Object.keys(src);
74
- const _opts = opts.dedupe !== false
75
- ? {
76
- xform: dedupe(opts.equiv || ((a, b) => a === b)),
77
- ...opts,
78
- }
79
- : opts;
80
- const streams = {};
81
- for (let k of keys) {
82
- streams[k] = subscription(undefined, {
83
- ..._opts,
84
- id: `${id}-${String(k)}`,
85
- });
4
+ const fromObject = (src, opts = {}) => {
5
+ const id = opts.id || `obj${__nextID()}`;
6
+ const keys = opts.keys || Object.keys(src);
7
+ const _opts = opts.dedupe !== false ? {
8
+ xform: dedupe(opts.equiv || ((a, b) => a === b)),
9
+ ...opts
10
+ } : opts;
11
+ const streams = {};
12
+ for (let k of keys) {
13
+ streams[k] = subscription(void 0, {
14
+ ..._opts,
15
+ id: `${id}-${String(k)}`
16
+ });
17
+ }
18
+ const res = {
19
+ streams,
20
+ next(state) {
21
+ for (let k of keys) {
22
+ const val = state[k];
23
+ streams[k].next(
24
+ opts.defaults && val === void 0 ? opts.defaults[k] : val
25
+ );
26
+ }
27
+ },
28
+ done() {
29
+ for (let k of keys) {
30
+ streams[k].done();
31
+ }
86
32
  }
87
- const res = {
88
- streams,
89
- next(state) {
90
- for (let k of keys) {
91
- const val = state[k];
92
- streams[k].next(opts.defaults && val === undefined ? opts.defaults[k] : val);
93
- }
94
- },
95
- done() {
96
- for (let k of keys) {
97
- streams[k].done();
98
- }
99
- },
100
- };
101
- opts.initial !== false && res.next(src);
102
- return res;
33
+ };
34
+ opts.initial !== false && res.next(src);
35
+ return res;
36
+ };
37
+ export {
38
+ fromObject
103
39
  };