@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/rstream",
3
- "version": "8.2.13",
3
+ "version": "8.2.15",
4
4
  "description": "Reactive streams & subscription primitives for constructing dataflow graphs / pipelines",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -28,7 +28,9 @@
28
28
  ],
29
29
  "license": "Apache-2.0",
30
30
  "scripts": {
31
- "build": "yarn clean && tsc --declaration",
31
+ "build": "yarn build:esbuild && yarn build:decl",
32
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
33
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
32
34
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc internal",
33
35
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
34
36
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -37,17 +39,18 @@
37
39
  "test": "bun test"
38
40
  },
39
41
  "dependencies": {
40
- "@thi.ng/api": "^8.9.11",
41
- "@thi.ng/arrays": "^2.7.7",
42
- "@thi.ng/associative": "^6.3.23",
43
- "@thi.ng/atom": "^5.2.17",
44
- "@thi.ng/checks": "^3.4.11",
45
- "@thi.ng/errors": "^2.4.5",
46
- "@thi.ng/logger": "^2.0.1",
47
- "@thi.ng/transducers": "^8.8.14"
42
+ "@thi.ng/api": "^8.9.13",
43
+ "@thi.ng/arrays": "^2.7.9",
44
+ "@thi.ng/associative": "^6.3.25",
45
+ "@thi.ng/atom": "^5.2.19",
46
+ "@thi.ng/checks": "^3.4.13",
47
+ "@thi.ng/errors": "^2.4.7",
48
+ "@thi.ng/logger": "^2.1.0",
49
+ "@thi.ng/transducers": "^8.8.16"
48
50
  },
49
51
  "devDependencies": {
50
52
  "@microsoft/api-extractor": "^7.38.3",
53
+ "esbuild": "^0.19.8",
51
54
  "rimraf": "^5.0.5",
52
55
  "tools": "^0.0.1",
53
56
  "typedoc": "^0.25.4",
@@ -74,7 +77,7 @@
74
77
  "access": "public"
75
78
  },
76
79
  "engines": {
77
- "node": ">=12.7"
80
+ "node": ">=18"
78
81
  },
79
82
  "files": [
80
83
  "./*.js",
@@ -212,5 +215,5 @@
212
215
  ],
213
216
  "year": 2017
214
217
  },
215
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
218
+ "gitHead": "25a42a81fac8603a1e440a7aa8bc343276211ff4\n"
216
219
  }
package/post-worker.js CHANGED
@@ -2,64 +2,33 @@ import { isTransferable } from "@thi.ng/checks/is-transferable";
2
2
  import { isTypedArray } from "@thi.ng/checks/is-typedarray";
3
3
  import { LOGGER } from "./logger.js";
4
4
  import { defWorker } from "./defworker.js";
5
- /**
6
- * Creates a {@link ISubscriber | subscriber} which forwards received
7
- * values to given worker.
8
- *
9
- * @remarks
10
- * The `worker` can be an existing `Worker` instance, a JS source code
11
- * `Blob` or an URL string. In the latter two cases, a worker is created
12
- * automatically. If `transfer` is true, the received values will be
13
- * marked as *transferrable* and the host app loses all access
14
- * permissions to these marked values. See `Worker.postMessage()` for
15
- * details.
16
- *
17
- * If `terminate` is set to a positive number, then the worker will be
18
- * automatically terminated after the stated number of milliseconds
19
- * since the parent subscription is {@link ISubscriber.done}.
20
- *
21
- * @example
22
- * ```ts
23
- * // worker source code
24
- * src = `self.onmessage = (e) => console.log("worker", e.data);`;
25
- *
26
- * a = stream();
27
- * a.subscribe(
28
- * postWorker(src, { type: "application/javascript" }))
29
- * );
30
- *
31
- * a.next(42)
32
- * // worker 42
33
- * ```
34
- *
35
- * @param worker -
36
- * @param transfer -
37
- * @param terminate - worker termination delay (ms)
38
- */
39
- export const postWorker = (worker, transfer = false, terminate = 0) => {
40
- const _worker = defWorker(worker);
41
- return {
42
- next(x) {
43
- if (x instanceof Promise) {
44
- x.then((y) => this.next(y));
45
- return;
46
- }
47
- let tx;
48
- if (transfer) {
49
- const ta = isTypedArray(x);
50
- if (ta || isTransferable(x)) {
51
- tx = [ta ? x.buffer : x];
52
- }
53
- }
54
- _worker.postMessage(x, tx || []);
55
- },
56
- done() {
57
- if (terminate > 0) {
58
- setTimeout(() => {
59
- LOGGER.info("terminating worker...");
60
- _worker.terminate();
61
- }, terminate);
62
- }
63
- },
64
- };
5
+ const postWorker = (worker, transfer = false, terminate = 0) => {
6
+ const _worker = defWorker(worker);
7
+ return {
8
+ next(x) {
9
+ if (x instanceof Promise) {
10
+ x.then((y) => this.next(y));
11
+ return;
12
+ }
13
+ let tx;
14
+ if (transfer) {
15
+ const ta = isTypedArray(x);
16
+ if (ta || isTransferable(x)) {
17
+ tx = [ta ? x.buffer : x];
18
+ }
19
+ }
20
+ _worker.postMessage(x, tx || []);
21
+ },
22
+ done() {
23
+ if (terminate > 0) {
24
+ setTimeout(() => {
25
+ LOGGER.info("terminating worker...");
26
+ _worker.terminate();
27
+ }, terminate);
28
+ }
29
+ }
30
+ };
31
+ };
32
+ export {
33
+ postWorker
65
34
  };
package/promise.js CHANGED
@@ -1,40 +1,34 @@
1
1
  import { CloseMode, State } from "./api.js";
2
2
  import { __optsWithID } from "./idgen.js";
3
3
  import { stream } from "./stream.js";
4
- /**
5
- * Yields a single-value {@link Stream} of the resolved promise and then
6
- * automatically marks itself done.
7
- *
8
- * @remarks
9
- * It doesn't matter if the promise resolves before the first subscriber
10
- * has attached.
11
- *
12
- * @param src -
13
- * @param opts -
14
- */
15
- export const fromPromise = (src, opts) => {
16
- let canceled = false;
17
- let isError = false;
18
- let err = {};
19
- src.catch((e) => {
20
- err = e;
21
- isError = true;
22
- });
23
- return stream((stream) => {
24
- src.then((x) => {
25
- if (!canceled && stream.getState() < State.DONE) {
26
- if (isError) {
27
- stream.error(err);
28
- err = null;
29
- }
30
- else {
31
- stream.next(x);
32
- stream.closeIn !== CloseMode.NEVER && stream.done();
33
- }
34
- }
35
- }, (e) => stream.error(e));
36
- return () => {
37
- canceled = true;
38
- };
39
- }, __optsWithID("promise", opts));
4
+ const fromPromise = (src, opts) => {
5
+ let canceled = false;
6
+ let isError = false;
7
+ let err = {};
8
+ src.catch((e) => {
9
+ err = e;
10
+ isError = true;
11
+ });
12
+ return stream((stream2) => {
13
+ src.then(
14
+ (x) => {
15
+ if (!canceled && stream2.getState() < State.DONE) {
16
+ if (isError) {
17
+ stream2.error(err);
18
+ err = null;
19
+ } else {
20
+ stream2.next(x);
21
+ stream2.closeIn !== CloseMode.NEVER && stream2.done();
22
+ }
23
+ }
24
+ },
25
+ (e) => stream2.error(e)
26
+ );
27
+ return () => {
28
+ canceled = true;
29
+ };
30
+ }, __optsWithID("promise", opts));
31
+ };
32
+ export {
33
+ fromPromise
40
34
  };
package/promises.js CHANGED
@@ -1,44 +1,10 @@
1
1
  import { mapcat } from "@thi.ng/transducers/mapcat";
2
2
  import { __optsWithID } from "./idgen.js";
3
3
  import { fromPromise } from "./promise.js";
4
- /**
5
- * Wraps given iterable in `Promise.all()` to yield {@link Stream} of results in
6
- * same order as arguments, then closes.
7
- *
8
- * @remarks
9
- * If any of the promises rejects, all others will do so too. In this case the
10
- * stream calls {@link ISubscriber.error} in all of its subscribers.
11
- *
12
- * @remarks
13
- * Type signature updated to use `Awaited<T>`, a new core type introduced in
14
- * TypeScript 4.5.
15
- *
16
- * @example
17
- * ```ts
18
- * fromPromises([
19
- * Promise.resolve(1),
20
- * Promise.resolve(2),
21
- * Promise.resolve(3)
22
- * ]).subscribe(trace())
23
- * // 1
24
- * // 2
25
- * // 3
26
- * // done
27
- * ```
28
- *
29
- * @example
30
- * If individual error handling is required, an alternative is below
31
- * (however this approach provides no ordering guarantees):
32
- *
33
- * ```ts
34
- * fromIterable([
35
- * Promise.resolve(1),
36
- * new Promise(() => setTimeout(() => { throw new Error("eeek"); }, 10)),
37
- * Promise.resolve(3)
38
- * ]).subscribe(resolve()).subscribe(trace())
39
- * ```
40
- *
41
- * @param promises -
42
- * @param opts -
43
- */
44
- export const fromPromises = (promises, opts) => fromPromise(Promise.all(promises), __optsWithID("promises", opts)).transform(mapcat((x) => x));
4
+ const fromPromises = (promises, opts) => fromPromise(
5
+ Promise.all(promises),
6
+ __optsWithID("promises", opts)
7
+ ).transform(mapcat((x) => x));
8
+ export {
9
+ fromPromises
10
+ };
package/pubsub.js CHANGED
@@ -1,115 +1,101 @@
1
1
  import { EquivMap } from "@thi.ng/associative/equiv-map";
2
2
  import { unsupported } from "@thi.ng/errors/unsupported";
3
- import { CloseMode, } from "./api.js";
3
+ import {
4
+ CloseMode
5
+ } from "./api.js";
4
6
  import { __optsWithID } from "./idgen.js";
5
7
  import { LOGGER } from "./logger.js";
6
8
  import { Subscription, subscription } from "./subscription.js";
7
- /**
8
- * Topic based stream splitter. Applies `topic` function to each received value
9
- * and only forwards it to the child subscriptions of the returned topic.
10
- *
11
- * @remarks
12
- * The actual topic (return value from `topic` fn) can be of any type `T`, or
13
- * `undefined`. If the latter is returned, the incoming value will not be
14
- * processed further. Complex topics (e.g objects / arrays) are allowed and
15
- * they're matched against registered topics using
16
- * [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) by
17
- * default (but customizable via `equiv` option). Each topic can have any number
18
- * of subscribers.
19
- *
20
- * If a `xform` transducer is given, it is always applied prior to passing the
21
- * input to the topic function. I.e. in this case the topic function will
22
- * receive the transformed inputs.
23
- *
24
- * {@link PubSub} supports dynamic topic subscriptions and unsubscriptions via
25
- * {@link PubSub.(subscribeTopic:1)} and {@link PubSub.unsubscribeTopic}.
26
- * However, the standard {@link ISubscribable.(subscribe:1)} /
27
- * {@link ISubscribable.unsubscribe} methods are NOT supported (since
28
- * meaningless) and will throw an error! `unsubscribe()` can only be called
29
- * WITHOUT argument to unsubscribe the entire `PubSub` instance (incl. all topic
30
- * subscriptions) from the parent stream.
31
- *
32
- * @param opts -
33
- */
34
- export const pubsub = (opts) => new PubSub(opts);
35
- /**
36
- * @see {@link pubsub} for reference & examples.
37
- */
38
- export class PubSub extends Subscription {
39
- topicfn;
40
- topics;
41
- constructor(opts) {
42
- super(undefined, __optsWithID("pubsub", {
43
- xform: opts.xform,
44
- }));
45
- this.topicfn = opts.topic;
46
- this.topics = new EquivMap(undefined, {
47
- equiv: opts.equiv,
48
- });
9
+ const pubsub = (opts) => new PubSub(opts);
10
+ class PubSub extends Subscription {
11
+ topicfn;
12
+ topics;
13
+ constructor(opts) {
14
+ super(
15
+ void 0,
16
+ __optsWithID("pubsub", {
17
+ xform: opts.xform
18
+ })
19
+ );
20
+ this.topicfn = opts.topic;
21
+ this.topics = new EquivMap(void 0, {
22
+ equiv: opts.equiv
23
+ });
24
+ }
25
+ /**
26
+ * Unsupported. Use {@link PubSub.(subscribeTopic:1)} instead.
27
+ */
28
+ subscribe() {
29
+ return unsupported(`use subscribeTopic() instead`);
30
+ }
31
+ /**
32
+ * Unsupported. Use {@link PubSub.(subscribeTopic:1)} instead.
33
+ */
34
+ transform() {
35
+ return unsupported(`use subscribeTopic() instead`);
36
+ }
37
+ subscribeTopic(topicID, sub, opts) {
38
+ let t = this.topics.get(topicID);
39
+ !t && this.topics.set(
40
+ topicID,
41
+ t = subscription(
42
+ void 0,
43
+ __optsWithID("topic", {
44
+ closeOut: CloseMode.NEVER
45
+ })
46
+ )
47
+ );
48
+ return t.subscribe(sub, opts);
49
+ }
50
+ transformTopic(topicID, xform, opts = {}) {
51
+ return this.subscribeTopic(
52
+ topicID,
53
+ { error: opts.error },
54
+ {
55
+ ...opts,
56
+ xform
57
+ }
58
+ );
59
+ }
60
+ unsubscribeTopic(topicID, sub) {
61
+ const t = this.topics.get(topicID);
62
+ return t ? t.unsubscribe(sub) : false;
63
+ }
64
+ unsubscribe(sub) {
65
+ if (!sub) {
66
+ for (let t of this.topics.values()) {
67
+ t.unsubscribe();
68
+ }
69
+ this.topics.clear();
70
+ return super.unsubscribe();
49
71
  }
50
- /**
51
- * Unsupported. Use {@link PubSub.(subscribeTopic:1)} instead.
52
- */
53
- subscribe() {
54
- return unsupported(`use subscribeTopic() instead`);
72
+ return unsupported();
73
+ }
74
+ done() {
75
+ for (let t of this.topics.values()) {
76
+ t.done();
55
77
  }
56
- /**
57
- * Unsupported. Use {@link PubSub.(subscribeTopic:1)} instead.
58
- */
59
- transform() {
60
- return unsupported(`use subscribeTopic() instead`);
61
- }
62
- subscribeTopic(topicID, sub, opts) {
63
- let t = this.topics.get(topicID);
64
- !t &&
65
- this.topics.set(topicID, (t = subscription(undefined, __optsWithID("topic", {
66
- closeOut: CloseMode.NEVER,
67
- }))));
68
- return t.subscribe(sub, opts);
69
- }
70
- transformTopic(topicID, xform, opts = {}) {
71
- return this.subscribeTopic(topicID, { error: opts.error }, {
72
- ...opts,
73
- xform,
74
- });
75
- }
76
- unsubscribeTopic(topicID, sub) {
77
- const t = this.topics.get(topicID);
78
- return t ? t.unsubscribe(sub) : false;
79
- }
80
- unsubscribe(sub) {
81
- if (!sub) {
82
- for (let t of this.topics.values()) {
83
- t.unsubscribe();
84
- }
85
- this.topics.clear();
86
- return super.unsubscribe();
87
- }
88
- // only the PubSub itself can be unsubscribed
89
- return unsupported();
90
- }
91
- done() {
92
- for (let t of this.topics.values()) {
93
- t.done();
94
- }
95
- super.done();
96
- }
97
- dispatch(x) {
98
- LOGGER.debug(this.id, "dispatch", x);
99
- this.cacheLast && (this.last = x);
100
- const t = this.topicfn(x);
101
- if (t !== undefined) {
102
- const sub = this.topics.get(t);
103
- if (sub) {
104
- try {
105
- sub.next && sub.next(x);
106
- }
107
- catch (e) {
108
- if (!sub.error || !sub.error(e)) {
109
- return this.unhandledError(e);
110
- }
111
- }
112
- }
78
+ super.done();
79
+ }
80
+ dispatch(x) {
81
+ LOGGER.debug(this.id, "dispatch", x);
82
+ this.cacheLast && (this.last = x);
83
+ const t = this.topicfn(x);
84
+ if (t !== void 0) {
85
+ const sub = this.topics.get(t);
86
+ if (sub) {
87
+ try {
88
+ sub.next && sub.next(x);
89
+ } catch (e) {
90
+ if (!sub.error || !sub.error(e)) {
91
+ return this.unhandledError(e);
92
+ }
113
93
  }
94
+ }
114
95
  }
96
+ }
115
97
  }
98
+ export {
99
+ PubSub,
100
+ pubsub
101
+ };
package/raf.js CHANGED
@@ -2,31 +2,19 @@ import { isNode } from "@thi.ng/checks/is-node";
2
2
  import { __optsWithID } from "./idgen.js";
3
3
  import { fromInterval } from "./interval.js";
4
4
  import { stream } from "./stream.js";
5
- /**
6
- * Yields {@link Stream} of a monotonically increasing counter (or timestamps),
7
- * triggered by a `requestAnimationFrame()` loop (only available in browser
8
- * environments).
9
- *
10
- * @remarks
11
- * In NodeJS, this function falls back to {@link fromInterval}, yielding a
12
- * similar (approx. 60Hz) stream (the {@link FromRAFOpts.timestamp} option will
13
- * be ignored).
14
- *
15
- * All subscribers to this stream will be processed during that same RAF loop
16
- * iteration.
17
- */
18
- export const fromRAF = (opts = {}) => isNode()
19
- ? fromInterval(16, opts)
20
- : stream((stream) => {
21
- let i = 0;
22
- let isActive = true;
23
- const loop = (time) => {
24
- isActive && stream.next(opts.timestamp ? time : i++);
25
- isActive && (id = requestAnimationFrame(loop));
26
- };
27
- let id = requestAnimationFrame(loop);
28
- return () => {
29
- isActive = false;
30
- cancelAnimationFrame(id);
31
- };
32
- }, __optsWithID("raf", opts));
5
+ const fromRAF = (opts = {}) => isNode() ? fromInterval(16, opts) : stream((stream2) => {
6
+ let i = 0;
7
+ let isActive = true;
8
+ const loop = (time) => {
9
+ isActive && stream2.next(opts.timestamp ? time : i++);
10
+ isActive && (id = requestAnimationFrame(loop));
11
+ };
12
+ let id = requestAnimationFrame(loop);
13
+ return () => {
14
+ isActive = false;
15
+ cancelAnimationFrame(id);
16
+ };
17
+ }, __optsWithID("raf", opts));
18
+ export {
19
+ fromRAF
20
+ };
package/resolve.js CHANGED
@@ -2,64 +2,43 @@ import { State } from "./api.js";
2
2
  import { __optsWithID } from "./idgen.js";
3
3
  import { LOGGER } from "./logger.js";
4
4
  import { Subscription } from "./subscription.js";
5
- /**
6
- * Creates a {@link Subscription} which receives promises, buffers them
7
- * and then passes their resolved values downstream.
8
- *
9
- * @remarks
10
- * If the optional `fail` handler is provided, it'll be called with the
11
- * error of each failed promise. If none is provided, the sub's
12
- * {@link ISubscriber.error} handler is called, which then stops the sub
13
- * from receiving further values.
14
- *
15
- * @example
16
- * ```ts
17
- * fromIterable([1, 2, 3], 100)
18
- * .transform(tx.delayed(1000))
19
- * .subscribe(resolve())
20
- * .subscribe(trace("result"))
21
- * // result 1
22
- * // result 2
23
- * // result 3
24
- * // result done
25
- * ```
26
- *
27
- * @param opts -
28
- */
29
- export const resolve = (opts) => new Resolver(opts);
30
- export class Resolver extends Subscription {
31
- outstanding = 0;
32
- fail;
33
- constructor(opts = {}) {
34
- super(undefined, __optsWithID("resolve"));
35
- this.fail = opts.fail;
36
- }
37
- next(x) {
38
- this.outstanding++;
39
- x.then((y) => {
40
- if (this.state < State.DONE) {
41
- this.dispatch(y);
42
- if (--this.outstanding === 0) {
43
- this.done();
44
- }
45
- }
46
- else {
47
- LOGGER.warn(`resolved value in state ${this.state} (${x})`);
48
- }
49
- }, (e) => {
50
- if (this.fail) {
51
- this.fail(e);
52
- }
53
- else {
54
- this.error(e);
55
- }
56
- });
57
- }
58
- done() {
59
- if (this.parent &&
60
- this.parent.getState() === State.DONE &&
61
- this.outstanding === 0) {
62
- super.done();
5
+ const resolve = (opts) => new Resolver(opts);
6
+ class Resolver extends Subscription {
7
+ outstanding = 0;
8
+ fail;
9
+ constructor(opts = {}) {
10
+ super(void 0, __optsWithID("resolve"));
11
+ this.fail = opts.fail;
12
+ }
13
+ next(x) {
14
+ this.outstanding++;
15
+ x.then(
16
+ (y) => {
17
+ if (this.state < State.DONE) {
18
+ this.dispatch(y);
19
+ if (--this.outstanding === 0) {
20
+ this.done();
21
+ }
22
+ } else {
23
+ LOGGER.warn(`resolved value in state ${this.state} (${x})`);
24
+ }
25
+ },
26
+ (e) => {
27
+ if (this.fail) {
28
+ this.fail(e);
29
+ } else {
30
+ this.error(e);
63
31
  }
32
+ }
33
+ );
34
+ }
35
+ done() {
36
+ if (this.parent && this.parent.getState() === State.DONE && this.outstanding === 0) {
37
+ super.done();
64
38
  }
39
+ }
65
40
  }
41
+ export {
42
+ Resolver,
43
+ resolve
44
+ };