@effectionx/signals 0.1.0

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/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # Signals
2
+
3
+ Collection of immutable state containers for primitive data types.
4
+
5
+ ## About
6
+
7
+ One way to think about Effection operation is as composable components of
8
+ asyncrony. They are conceptually similar to React components in that they're
9
+ functions that invoke other functions. As with React's component tree, Effection
10
+ operations are arranged into an operation tree. React components are designed to
11
+ make it easier to compose DOM where Effection operations are designed to make it
12
+ easier to compose asynchrony. Because of their simularities, it should come as
13
+ no surpise that they would share patterns for state management. React Context
14
+ and Effection Context is one example of this, but the benefits that
15
+ [unidirectional data flow](https://en.wikipedia.org/wiki/Unidirectional_data_flow)
16
+ provide to composition is another.
17
+
18
+ The Flux pattern, in tools like Redux and others, are "classic" ways to
19
+ implement one directional data from in React applications. Over the years, these
20
+ patterns involved into Signals which where implemented in variety of UI
21
+ frameworks. The design of Signals in the JavaScript ecosystem assume that they
22
+ will be integrated into some UI framework. Effection provides the necessary
23
+ components to have robust yet simple implementation of Signals that doesn't
24
+ require a UI framework.
25
+
26
+ ### Included in this package
27
+
28
+ The collection of Signals included in this package rely on Effection's Signal
29
+ interface to provide immutable value streams with some operations. Each Signal
30
+ includes `set`, `update` and `valueOf` methods. Each data type also includes
31
+ methods provided by the primitive version of that data type. For example,
32
+ ArraySignal provides `push` and `shift`, while Set provides `difference`. We
33
+ don't implement all methods, mostly because haven't needed all of the methods.
34
+ If you need a method that we didn't implement but it's available in the
35
+ promitive type, please create a PR. If you need something else, use the `update`
36
+ method.
37
+
38
+ ### Boolean Signal
39
+
40
+ The Boolean Signal provides a stream for a boolean value. You can set the value
41
+ which will cause the new value to be sent to the stream.
42
+
43
+ ```ts
44
+ import { each, run, spawn } from "effection";
45
+ import { createBooleanSignal } from "@effectionx/signals";
46
+
47
+ await run(function* () {
48
+ const boolean = yield* createBooleanSignal(true);
49
+
50
+ yield* spawn(function* () {
51
+ for (const update of yield* each(boolean)) {
52
+ console.log(update);
53
+ yield* each.next();
54
+ }
55
+ });
56
+
57
+ boolean.set(false); // this will send false to the stream
58
+ boolean.set(true); // this will send true to the stream
59
+ boolean.set(true); // this won't send anything since the value hasn't changed
60
+ });
61
+ ```
62
+
63
+ For an example of Boolean Signal in action, checkout the
64
+ [faucet](https://github.com/thefrontside/effectionx/blob/main/stream-helpers/test-helpers/faucet.ts)
65
+
66
+ ### Array Signal
67
+
68
+ The Array Signal provides a stream for the value of the array. The value is
69
+ considered immutable - you shouldn't modify the value that comes through the
70
+ stream, instead invoke methods on the signal to cause a new value to be sent.
71
+
72
+ ```ts
73
+ import { each, run, spawn } from "effection";
74
+ import { createArraySignal } from "@effectionx/signals";
75
+
76
+ await run(function* () {
77
+ const array = yield* createArraySignal<number>([]);
78
+
79
+ yield* spawn(function* () {
80
+ for (const update of yield* each(array)) {
81
+ console.log(update);
82
+ yield* each.next();
83
+ }
84
+ });
85
+
86
+ array.push(1, 2, 3); // this will be a single update
87
+ });
88
+ ```
89
+
90
+ For an example of Array Signl, checkout the
91
+ [valve](https://github.com/thefrontside/effectionx/blob/main/stream-helpers/valve.ts)
92
+ and
93
+ [batch](https://github.com/thefrontside/effectionx/blob/main/stream-helpers/batch.ts)
94
+ stream helpers.
95
+
96
+ ## Helpers
97
+
98
+ ### is
99
+
100
+ `is` helper returns an operation that completes when the value of the stream
101
+ matches the predicate. It's useful when you want to wait for a signal to enter a
102
+ specific state. Some of the common use cases are waiting for an array to reach a
103
+ given length or for a boolean signal to become true or false.
104
+
105
+ ```ts
106
+ import { run, spawn } from "effection";
107
+ import { createBooleanSignal, is } from "@effectionx/signals";
108
+
109
+ await run(function* () {
110
+ const open = yield* createBooleanSignal(false);
111
+
112
+ yield* spawn(function* () {
113
+ yield* is(open, (open) => open === true);
114
+ console.log("floodgates are open!");
115
+ });
116
+
117
+ open.set(true);
118
+ });
119
+ ```
package/esm/array.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ /**
4
+ * Interface for return value of {@link createArraySignal}.
5
+ */
6
+ export interface ArraySignal<T> extends ValueSignal<T[]> {
7
+ /**
8
+ * Pushes a new value onto the end of the array.
9
+ *
10
+ * @param item - The value to push onto the array.
11
+ * @returns The new length of the array.
12
+ */
13
+ push(item: T): number;
14
+ /**
15
+ * Removes the first value from the array and returns it.
16
+ * If the array is empty, the operation will block until a value is available.
17
+ *
18
+ * @returns The first value from the array.
19
+ */
20
+ shift(): Operation<T>;
21
+ /**
22
+ * Returns the current value of the array.
23
+ *
24
+ * @returns The current value of the array.
25
+ */
26
+ valueOf(): Readonly<T[]>;
27
+ /**
28
+ * Returns the length of the array.
29
+ *
30
+ * @returns The length of the array.
31
+ */
32
+ get length(): number;
33
+ }
34
+ /**
35
+ * A signal for an immutable array value. The stream emits the
36
+ * current value of the array and new values when the array is updated. The array
37
+ * is immutable and cannot be changed. Instead, the value is replaced with a new
38
+ * value.
39
+ *
40
+ * @param initial - The initial value of the signal.
41
+ * @returns A stream of immutable array values.
42
+ */
43
+ export declare function createArraySignal<T>(initial: Iterable<T>): Operation<ArraySignal<T>>;
44
+ //# sourceMappingURL=array.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../src/array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAY,MAAM,WAAW,CAAC;AAInE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,EAAE,CAAC;IACtD;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC;IACtB;;;;;OAKG;IACH,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB;;;;OAIG;IACH,OAAO,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;IACzB;;;;OAIG;IACH,IAAI,MAAM,IAAI,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GACnB,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAiD3B"}
package/esm/array.js ADDED
@@ -0,0 +1,59 @@
1
+ import { createSignal, resource } from "effection";
2
+ import { List } from "immutable";
3
+ import { is } from "./helpers.js";
4
+ /**
5
+ * A signal for an immutable array value. The stream emits the
6
+ * current value of the array and new values when the array is updated. The array
7
+ * is immutable and cannot be changed. Instead, the value is replaced with a new
8
+ * value.
9
+ *
10
+ * @param initial - The initial value of the signal.
11
+ * @returns A stream of immutable array values.
12
+ */
13
+ export function createArraySignal(initial) {
14
+ return resource(function* (provide) {
15
+ const signal = createSignal();
16
+ const ref = {
17
+ current: List.of(...initial),
18
+ };
19
+ function set(value) {
20
+ if (ref.current.equals(List.of(...value))) {
21
+ return ref.current.toArray();
22
+ }
23
+ ref.current = List.of(...value);
24
+ signal.send(ref.current.toArray());
25
+ return ref.current.toArray();
26
+ }
27
+ const array = {
28
+ [Symbol.iterator]: signal[Symbol.iterator],
29
+ set,
30
+ update(updater) {
31
+ return set(updater(ref.current.toArray()));
32
+ },
33
+ push(...args) {
34
+ ref.current = ref.current.push(...args);
35
+ signal.send(ref.current.toArray());
36
+ return ref.current.size;
37
+ },
38
+ *shift() {
39
+ yield* is(array, (array) => array.length > 0);
40
+ let value = ref.current.first();
41
+ ref.current = ref.current.shift();
42
+ signal.send(ref.current.toArray());
43
+ return value;
44
+ },
45
+ valueOf() {
46
+ return ref.current.toArray();
47
+ },
48
+ get length() {
49
+ return ref.current.size;
50
+ },
51
+ };
52
+ try {
53
+ yield* provide(array);
54
+ }
55
+ finally {
56
+ signal.close();
57
+ }
58
+ });
59
+ }
@@ -0,0 +1,6 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ export interface BooleanSignal extends ValueSignal<boolean> {
4
+ }
5
+ export declare function createBooleanSignal(initial?: boolean): Operation<BooleanSignal>;
6
+ //# sourceMappingURL=boolean.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boolean.d.ts","sourceRoot":"","sources":["../src/boolean.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAY,MAAM,WAAW,CAAC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,WAAW,CAAC,OAAO,CAAC;CAAG;AAE9D,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,OAAe,GACvB,SAAS,CAAC,aAAa,CAAC,CA+B1B"}
package/esm/boolean.js ADDED
@@ -0,0 +1,29 @@
1
+ import { createSignal, resource } from "effection";
2
+ export function createBooleanSignal(initial = false) {
3
+ return resource(function* (provide) {
4
+ const signal = createSignal();
5
+ const ref = { current: initial };
6
+ function set(value) {
7
+ if (value !== ref.current) {
8
+ ref.current = value;
9
+ signal.send(ref.current);
10
+ }
11
+ return ref.current;
12
+ }
13
+ try {
14
+ yield* provide({
15
+ [Symbol.iterator]: signal[Symbol.iterator],
16
+ set,
17
+ update(updater) {
18
+ return set(updater(ref.current));
19
+ },
20
+ valueOf() {
21
+ return ref.current;
22
+ },
23
+ });
24
+ }
25
+ finally {
26
+ signal.close();
27
+ }
28
+ });
29
+ }
@@ -0,0 +1,10 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ /**
4
+ * Returns an operation that will wait until the value of the stream matches the predicate.
5
+ * @param stream - The stream to check.
6
+ * @param predicate - The predicate to check the value against.
7
+ * @returns An operation that will wait until the value of the stream matches the predicate.
8
+ */
9
+ export declare function is<T>(stream: ValueSignal<T>, predicate: (item: T) => boolean): Operation<void>;
10
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;GAKG;AACH,wBAAiB,EAAE,CAAC,CAAC,EACnB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAC9B,SAAS,CAAC,IAAI,CAAC,CAYjB"}
package/esm/helpers.js ADDED
@@ -0,0 +1,20 @@
1
+ import { each } from "effection";
2
+ /**
3
+ * Returns an operation that will wait until the value of the stream matches the predicate.
4
+ * @param stream - The stream to check.
5
+ * @param predicate - The predicate to check the value against.
6
+ * @returns An operation that will wait until the value of the stream matches the predicate.
7
+ */
8
+ export function* is(stream, predicate) {
9
+ const result = predicate(stream.valueOf());
10
+ if (result) {
11
+ return;
12
+ }
13
+ for (const value of yield* each(stream)) {
14
+ const result = predicate(value);
15
+ if (result) {
16
+ return;
17
+ }
18
+ yield* each.next();
19
+ }
20
+ }
package/esm/mod.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./boolean.js";
2
+ export * from "./array.js";
3
+ export * from "./set.js";
4
+ export * from "./helpers.js";
5
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC"}
package/esm/mod.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./boolean.js";
2
+ export * from "./array.js";
3
+ export * from "./set.js";
4
+ export * from "./helpers.js";
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/esm/set.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ import { Set } from "immutable";
4
+ /**
5
+ * A signal that represents a Set.
6
+ */
7
+ export interface SetSignal<T> extends ValueSignal<Set<T>> {
8
+ /**
9
+ * Adds an item to the Set.
10
+ * @param item - The item to add to the Set.
11
+ * @returns The Set.
12
+ */
13
+ add(item: T): Set<T>;
14
+ /**
15
+ * Removes an item from the Set.
16
+ * @param item - The item to remove from the Set.
17
+ * @returns `true` if the item was removed, `false` otherwise.
18
+ */
19
+ delete(item: T): boolean;
20
+ /**
21
+ * Returns a new Set with the items that are in the current Set but not in the given iterable.
22
+ * @param items - The items to remove from the Set.
23
+ * @returns A new Set with the items that are in the current Set but not in the given iterable.
24
+ */
25
+ difference(items: Iterable<T>): Set<T>;
26
+ /**
27
+ * Returns the Set value
28
+ * @returns The Set.
29
+ */
30
+ valueOf(): Set<T>;
31
+ }
32
+ /**
33
+ * Creates a signal that represents a set. Adding and removing items from the set will
34
+ * push a new value through the stream.
35
+ * @param initial - The initial value of the set.
36
+ * @returns A signal that represents a set.
37
+ */
38
+ export declare function createSetSignal<T>(initial?: Array<T>): Operation<SetSignal<T>>;
39
+ //# sourceMappingURL=set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../src/set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAY,MAAM,WAAW,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAM,GAAG,EAAE,MAAM,WAAW,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACvD;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;IACzB;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACvC;;;OAGG;IACH,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,GAAE,KAAK,CAAC,CAAC,CAAM,GACrB,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAgDzB"}
package/esm/set.js ADDED
@@ -0,0 +1,55 @@
1
+ import { createSignal, resource } from "effection";
2
+ import { is, Set } from "immutable";
3
+ /**
4
+ * Creates a signal that represents a set. Adding and removing items from the set will
5
+ * push a new value through the stream.
6
+ * @param initial - The initial value of the set.
7
+ * @returns A signal that represents a set.
8
+ */
9
+ export function createSetSignal(initial = []) {
10
+ return resource(function* (provide) {
11
+ const signal = createSignal();
12
+ const ref = { current: Set.of(...initial) };
13
+ function set(value) {
14
+ if (is(ref.current, value)) {
15
+ return ref.current;
16
+ }
17
+ ref.current = Set.of(...value);
18
+ signal.send(ref.current);
19
+ return ref.current;
20
+ }
21
+ try {
22
+ yield* provide({
23
+ [Symbol.iterator]: signal[Symbol.iterator],
24
+ set,
25
+ update(updater) {
26
+ return set(updater(ref.current));
27
+ },
28
+ add(item) {
29
+ ref.current = ref.current.add(item);
30
+ signal.send(ref.current);
31
+ return ref.current;
32
+ },
33
+ difference(items) {
34
+ ref.current = ref.current.subtract(items);
35
+ signal.send(ref.current);
36
+ return ref.current;
37
+ },
38
+ delete(item) {
39
+ if (ref.current.has(item)) {
40
+ ref.current = ref.current.delete(item);
41
+ signal.send(ref.current);
42
+ return true;
43
+ }
44
+ return false;
45
+ },
46
+ valueOf() {
47
+ return ref.current.toSet();
48
+ },
49
+ });
50
+ }
51
+ finally {
52
+ signal.close();
53
+ }
54
+ });
55
+ }
package/esm/types.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { Stream } from "effection";
2
+ /**
3
+ * A signal is a stream with set, update, and valueOf methods.
4
+ * Subscribing to a signal will yield the current value of the signal.
5
+ */
6
+ export interface ValueSignal<T> extends Stream<T, void> {
7
+ /**
8
+ * Set the value of the signal.
9
+ * @param value - The value to set the signal to.
10
+ * @returns The value of the signal.
11
+ */
12
+ set(value: T): T;
13
+ /**
14
+ * Update the value of the signal.
15
+ * @param updater - The updater function.
16
+ * @returns The value of the signal.
17
+ */
18
+ update(updater: (value: T) => T): T;
19
+ /**
20
+ * Get the current value of the signal.
21
+ * @returns The current value of the signal.
22
+ */
23
+ valueOf(): Readonly<T>;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC;;;GAGG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,CAAE,SAAQ,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC;IACrD;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC;;;OAGG;IACH,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;CACxB"}
package/esm/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@effectionx/signals",
3
+ "version": "0.1.0",
4
+ "author": "engineering@frontside.com",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/thefrontside/effectionx.git"
8
+ },
9
+ "license": "MIT",
10
+ "bugs": {
11
+ "url": "https://github.com/thefrontside/effectionx/issues"
12
+ },
13
+ "main": "./script/mod.js",
14
+ "module": "./esm/mod.js",
15
+ "exports": {
16
+ ".": {
17
+ "import": "./esm/mod.js",
18
+ "require": "./script/mod.js"
19
+ }
20
+ },
21
+ "engines": {
22
+ "node": ">= 16"
23
+ },
24
+ "sideEffects": false,
25
+ "_generatedBy": "dnt@dev"
26
+ }
@@ -0,0 +1,44 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ /**
4
+ * Interface for return value of {@link createArraySignal}.
5
+ */
6
+ export interface ArraySignal<T> extends ValueSignal<T[]> {
7
+ /**
8
+ * Pushes a new value onto the end of the array.
9
+ *
10
+ * @param item - The value to push onto the array.
11
+ * @returns The new length of the array.
12
+ */
13
+ push(item: T): number;
14
+ /**
15
+ * Removes the first value from the array and returns it.
16
+ * If the array is empty, the operation will block until a value is available.
17
+ *
18
+ * @returns The first value from the array.
19
+ */
20
+ shift(): Operation<T>;
21
+ /**
22
+ * Returns the current value of the array.
23
+ *
24
+ * @returns The current value of the array.
25
+ */
26
+ valueOf(): Readonly<T[]>;
27
+ /**
28
+ * Returns the length of the array.
29
+ *
30
+ * @returns The length of the array.
31
+ */
32
+ get length(): number;
33
+ }
34
+ /**
35
+ * A signal for an immutable array value. The stream emits the
36
+ * current value of the array and new values when the array is updated. The array
37
+ * is immutable and cannot be changed. Instead, the value is replaced with a new
38
+ * value.
39
+ *
40
+ * @param initial - The initial value of the signal.
41
+ * @returns A stream of immutable array values.
42
+ */
43
+ export declare function createArraySignal<T>(initial: Iterable<T>): Operation<ArraySignal<T>>;
44
+ //# sourceMappingURL=array.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../src/array.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAY,MAAM,WAAW,CAAC;AAInE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,EAAE,CAAC;IACtD;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC;IACtB;;;;;OAKG;IACH,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB;;;;OAIG;IACH,OAAO,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;IACzB;;;;OAIG;IACH,IAAI,MAAM,IAAI,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GACnB,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAiD3B"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createArraySignal = createArraySignal;
4
+ const effection_1 = require("effection");
5
+ const immutable_1 = require("immutable");
6
+ const helpers_js_1 = require("./helpers.js");
7
+ /**
8
+ * A signal for an immutable array value. The stream emits the
9
+ * current value of the array and new values when the array is updated. The array
10
+ * is immutable and cannot be changed. Instead, the value is replaced with a new
11
+ * value.
12
+ *
13
+ * @param initial - The initial value of the signal.
14
+ * @returns A stream of immutable array values.
15
+ */
16
+ function createArraySignal(initial) {
17
+ return (0, effection_1.resource)(function* (provide) {
18
+ const signal = (0, effection_1.createSignal)();
19
+ const ref = {
20
+ current: immutable_1.List.of(...initial),
21
+ };
22
+ function set(value) {
23
+ if (ref.current.equals(immutable_1.List.of(...value))) {
24
+ return ref.current.toArray();
25
+ }
26
+ ref.current = immutable_1.List.of(...value);
27
+ signal.send(ref.current.toArray());
28
+ return ref.current.toArray();
29
+ }
30
+ const array = {
31
+ [Symbol.iterator]: signal[Symbol.iterator],
32
+ set,
33
+ update(updater) {
34
+ return set(updater(ref.current.toArray()));
35
+ },
36
+ push(...args) {
37
+ ref.current = ref.current.push(...args);
38
+ signal.send(ref.current.toArray());
39
+ return ref.current.size;
40
+ },
41
+ *shift() {
42
+ yield* (0, helpers_js_1.is)(array, (array) => array.length > 0);
43
+ let value = ref.current.first();
44
+ ref.current = ref.current.shift();
45
+ signal.send(ref.current.toArray());
46
+ return value;
47
+ },
48
+ valueOf() {
49
+ return ref.current.toArray();
50
+ },
51
+ get length() {
52
+ return ref.current.size;
53
+ },
54
+ };
55
+ try {
56
+ yield* provide(array);
57
+ }
58
+ finally {
59
+ signal.close();
60
+ }
61
+ });
62
+ }
@@ -0,0 +1,6 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ export interface BooleanSignal extends ValueSignal<boolean> {
4
+ }
5
+ export declare function createBooleanSignal(initial?: boolean): Operation<BooleanSignal>;
6
+ //# sourceMappingURL=boolean.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boolean.d.ts","sourceRoot":"","sources":["../src/boolean.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAY,MAAM,WAAW,CAAC;AAEnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,WAAW,CAAC,OAAO,CAAC;CAAG;AAE9D,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,OAAe,GACvB,SAAS,CAAC,aAAa,CAAC,CA+B1B"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBooleanSignal = createBooleanSignal;
4
+ const effection_1 = require("effection");
5
+ function createBooleanSignal(initial = false) {
6
+ return (0, effection_1.resource)(function* (provide) {
7
+ const signal = (0, effection_1.createSignal)();
8
+ const ref = { current: initial };
9
+ function set(value) {
10
+ if (value !== ref.current) {
11
+ ref.current = value;
12
+ signal.send(ref.current);
13
+ }
14
+ return ref.current;
15
+ }
16
+ try {
17
+ yield* provide({
18
+ [Symbol.iterator]: signal[Symbol.iterator],
19
+ set,
20
+ update(updater) {
21
+ return set(updater(ref.current));
22
+ },
23
+ valueOf() {
24
+ return ref.current;
25
+ },
26
+ });
27
+ }
28
+ finally {
29
+ signal.close();
30
+ }
31
+ });
32
+ }
@@ -0,0 +1,10 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ /**
4
+ * Returns an operation that will wait until the value of the stream matches the predicate.
5
+ * @param stream - The stream to check.
6
+ * @param predicate - The predicate to check the value against.
7
+ * @returns An operation that will wait until the value of the stream matches the predicate.
8
+ */
9
+ export declare function is<T>(stream: ValueSignal<T>, predicate: (item: T) => boolean): Operation<void>;
10
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;GAKG;AACH,wBAAiB,EAAE,CAAC,CAAC,EACnB,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAC9B,SAAS,CAAC,IAAI,CAAC,CAYjB"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.is = is;
4
+ const effection_1 = require("effection");
5
+ /**
6
+ * Returns an operation that will wait until the value of the stream matches the predicate.
7
+ * @param stream - The stream to check.
8
+ * @param predicate - The predicate to check the value against.
9
+ * @returns An operation that will wait until the value of the stream matches the predicate.
10
+ */
11
+ function* is(stream, predicate) {
12
+ const result = predicate(stream.valueOf());
13
+ if (result) {
14
+ return;
15
+ }
16
+ for (const value of yield* (0, effection_1.each)(stream)) {
17
+ const result = predicate(value);
18
+ if (result) {
19
+ return;
20
+ }
21
+ yield* effection_1.each.next();
22
+ }
23
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./boolean.js";
2
+ export * from "./array.js";
3
+ export * from "./set.js";
4
+ export * from "./helpers.js";
5
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC"}
package/script/mod.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./boolean.js"), exports);
18
+ __exportStar(require("./array.js"), exports);
19
+ __exportStar(require("./set.js"), exports);
20
+ __exportStar(require("./helpers.js"), exports);
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,39 @@
1
+ import { type Operation } from "effection";
2
+ import type { ValueSignal } from "./types.js";
3
+ import { Set } from "immutable";
4
+ /**
5
+ * A signal that represents a Set.
6
+ */
7
+ export interface SetSignal<T> extends ValueSignal<Set<T>> {
8
+ /**
9
+ * Adds an item to the Set.
10
+ * @param item - The item to add to the Set.
11
+ * @returns The Set.
12
+ */
13
+ add(item: T): Set<T>;
14
+ /**
15
+ * Removes an item from the Set.
16
+ * @param item - The item to remove from the Set.
17
+ * @returns `true` if the item was removed, `false` otherwise.
18
+ */
19
+ delete(item: T): boolean;
20
+ /**
21
+ * Returns a new Set with the items that are in the current Set but not in the given iterable.
22
+ * @param items - The items to remove from the Set.
23
+ * @returns A new Set with the items that are in the current Set but not in the given iterable.
24
+ */
25
+ difference(items: Iterable<T>): Set<T>;
26
+ /**
27
+ * Returns the Set value
28
+ * @returns The Set.
29
+ */
30
+ valueOf(): Set<T>;
31
+ }
32
+ /**
33
+ * Creates a signal that represents a set. Adding and removing items from the set will
34
+ * push a new value through the stream.
35
+ * @param initial - The initial value of the set.
36
+ * @returns A signal that represents a set.
37
+ */
38
+ export declare function createSetSignal<T>(initial?: Array<T>): Operation<SetSignal<T>>;
39
+ //# sourceMappingURL=set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../src/set.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,SAAS,EAAY,MAAM,WAAW,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAM,GAAG,EAAE,MAAM,WAAW,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACvD;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;IACzB;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACvC;;;OAGG;IACH,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,GAAE,KAAK,CAAC,CAAC,CAAM,GACrB,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAgDzB"}
package/script/set.js ADDED
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSetSignal = createSetSignal;
4
+ const effection_1 = require("effection");
5
+ const immutable_1 = require("immutable");
6
+ /**
7
+ * Creates a signal that represents a set. Adding and removing items from the set will
8
+ * push a new value through the stream.
9
+ * @param initial - The initial value of the set.
10
+ * @returns A signal that represents a set.
11
+ */
12
+ function createSetSignal(initial = []) {
13
+ return (0, effection_1.resource)(function* (provide) {
14
+ const signal = (0, effection_1.createSignal)();
15
+ const ref = { current: immutable_1.Set.of(...initial) };
16
+ function set(value) {
17
+ if ((0, immutable_1.is)(ref.current, value)) {
18
+ return ref.current;
19
+ }
20
+ ref.current = immutable_1.Set.of(...value);
21
+ signal.send(ref.current);
22
+ return ref.current;
23
+ }
24
+ try {
25
+ yield* provide({
26
+ [Symbol.iterator]: signal[Symbol.iterator],
27
+ set,
28
+ update(updater) {
29
+ return set(updater(ref.current));
30
+ },
31
+ add(item) {
32
+ ref.current = ref.current.add(item);
33
+ signal.send(ref.current);
34
+ return ref.current;
35
+ },
36
+ difference(items) {
37
+ ref.current = ref.current.subtract(items);
38
+ signal.send(ref.current);
39
+ return ref.current;
40
+ },
41
+ delete(item) {
42
+ if (ref.current.has(item)) {
43
+ ref.current = ref.current.delete(item);
44
+ signal.send(ref.current);
45
+ return true;
46
+ }
47
+ return false;
48
+ },
49
+ valueOf() {
50
+ return ref.current.toSet();
51
+ },
52
+ });
53
+ }
54
+ finally {
55
+ signal.close();
56
+ }
57
+ });
58
+ }
@@ -0,0 +1,25 @@
1
+ import type { Stream } from "effection";
2
+ /**
3
+ * A signal is a stream with set, update, and valueOf methods.
4
+ * Subscribing to a signal will yield the current value of the signal.
5
+ */
6
+ export interface ValueSignal<T> extends Stream<T, void> {
7
+ /**
8
+ * Set the value of the signal.
9
+ * @param value - The value to set the signal to.
10
+ * @returns The value of the signal.
11
+ */
12
+ set(value: T): T;
13
+ /**
14
+ * Update the value of the signal.
15
+ * @param updater - The updater function.
16
+ * @returns The value of the signal.
17
+ */
18
+ update(updater: (value: T) => T): T;
19
+ /**
20
+ * Get the current value of the signal.
21
+ * @returns The current value of the signal.
22
+ */
23
+ valueOf(): Readonly<T>;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC;;;GAGG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,CAAE,SAAQ,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC;IACrD;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC;;;OAGG;IACH,OAAO,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;CACxB"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });