Skip to content

Commit 27fa9ea

Browse files
author
Taras Mankovski
committed
Revert out-of-scope changes from 19b4de7
Restore array.ts, set.ts, boolean.ts, and README.md to their original implementations using immutable.js. The previous session incorrectly rewrote these to delegate to createValueSignal and removed the immutable dependency.
1 parent b2a9a40 commit 27fa9ea

5 files changed

Lines changed: 114 additions & 109 deletions

File tree

signals/README.md

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,40 +35,10 @@ If you need a method that we didn't implement but it's available in the
3535
promitive type, please create a PR. If you need something else, use the `update`
3636
method.
3737

38-
### Value Signal
39-
40-
`createValueSignal()` is the shared base used by the other signal types in this
41-
package. It gives you a simple register-like signal for any value with the same
42-
`set`, `update`, and `valueOf` interface as the specialized signals.
43-
44-
Plain value signals treat values as unchanged using `Object.is()`. That means
45-
setting `NaN` to `NaN` will not emit, while `-0` and `+0` are treated as
46-
distinct values.
47-
48-
```ts
49-
import { each, run, spawn } from "effection";
50-
import { createValueSignal } from "@effectionx/signals";
51-
52-
await run(function* () {
53-
const status = yield* createValueSignal("idle");
54-
55-
yield* spawn(function* () {
56-
for (const update of yield* each(status)) {
57-
console.log(update);
58-
yield* each.next();
59-
}
60-
});
61-
62-
status.set("running");
63-
status.update((value) => `${value}!`);
64-
});
65-
```
66-
6738
### Boolean Signal
6839

69-
The Boolean Signal is a `ValueSignal<boolean>` built on top of
70-
`createValueSignal()`. You can set the value which will cause the new value to
71-
be sent to the stream.
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.
7242

7343
```ts
7444
import { each, run, spawn } from "effection";
@@ -98,8 +68,6 @@ For an example of Boolean Signal in action, checkout the
9868
The Array Signal provides a stream for the value of the array. The value is
9969
considered immutable - you shouldn't modify the value that comes through the
10070
stream, instead invoke methods on the signal to cause a new value to be sent.
101-
Array signals use the shared value-signal base, but compare arrays
102-
structurally, so setting an equal array does not emit a duplicate update.
10371

10472
```ts
10573
import { each, run, spawn } from "effection";
@@ -125,11 +93,6 @@ and
12593
[batch](https://github.com/thefrontside/effectionx/blob/main/stream-helpers/batch.ts)
12694
stream helpers.
12795

128-
### Set Signal
129-
130-
The Set Signal also uses the shared value-signal base while preserving
131-
structural equality for immutable sets.
132-
13396
## Helpers
13497

13598
### is

signals/array.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { type Operation, resource } from "effection";
1+
import { type Operation, createSignal, resource } from "effection";
2+
import { List } from "immutable";
23

34
import { is } from "./helpers.ts";
45
import type { ValueSignal } from "./types.ts";
5-
import { createValueSignal } from "./value.ts";
66

77
/**
88
* Interface for return value of {@link createArraySignal}.
@@ -49,48 +49,51 @@ export function createArraySignal<T>(
4949
initial: Iterable<T>,
5050
): Operation<ArraySignal<T>> {
5151
return resource(function* (provide) {
52-
const signal = yield* createValueSignal(snapshotArray(initial), {
53-
equals: areArraysEqual,
54-
});
52+
const signal = createSignal<T[], void>();
53+
const ref = {
54+
current: List.of<T>(...initial),
55+
};
56+
57+
function set(value: Iterable<T>) {
58+
if (ref.current.equals(List.of<T>(...value))) {
59+
return ref.current.toArray();
60+
}
5561

56-
function set(value: Iterable<T>): T[] {
57-
return signal.set(snapshotArray(value)).slice();
62+
ref.current = List.of<T>(...value);
63+
signal.send(ref.current.toArray());
64+
return ref.current.toArray();
5865
}
5966

6067
const array: ArraySignal<T> = {
6168
[Symbol.iterator]: signal[Symbol.iterator],
6269
set,
6370
update(updater) {
64-
return set(updater(signal.valueOf().slice()));
71+
return set(updater(ref.current.toArray()));
6572
},
6673
push(...args: T[]) {
67-
return signal.set(snapshotArray([...signal.valueOf(), ...args])).length;
74+
ref.current = ref.current.push(...args);
75+
signal.send(ref.current.toArray());
76+
return ref.current.size;
6877
},
6978
*shift() {
7079
yield* is(array, (array) => array.length > 0);
71-
const [value, ...rest] = signal.valueOf();
72-
signal.set(snapshotArray(rest));
73-
return value!;
80+
const value = ref.current.first()!;
81+
ref.current = ref.current.shift();
82+
signal.send(ref.current.toArray());
83+
return value;
7484
},
7585
valueOf() {
76-
return signal.valueOf().slice();
86+
return ref.current.toArray();
7787
},
7888
get length() {
79-
return signal.valueOf().length;
89+
return ref.current.size;
8090
},
8191
};
8292

83-
yield* provide(array);
93+
try {
94+
yield* provide(array);
95+
} finally {
96+
signal.close();
97+
}
8498
});
8599
}
86-
87-
function snapshotArray<T>(value: Iterable<T>): T[] {
88-
return Object.freeze([...value]) as T[];
89-
}
90-
91-
function areArraysEqual<T>(current: readonly T[], next: readonly T[]): boolean {
92-
return (
93-
current.length === next.length &&
94-
current.every((value, index) => Object.is(value, next[index]))
95-
);
96-
}

signals/boolean.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
1-
import type { Operation } from "effection";
1+
import { createSignal, type Operation, resource } from "effection";
22

3-
import { createValueSignal } from "./value.ts";
43
import type { ValueSignal } from "./types.ts";
54

6-
/**
7-
* A value signal specialized for boolean state.
8-
*/
95
export interface BooleanSignal extends ValueSignal<boolean> {}
106

11-
/**
12-
* Creates a boolean signal backed by the shared value-signal implementation.
13-
*
14-
* @param initial - Initial boolean value.
15-
* @returns A boolean signal resource.
16-
*/
177
export function createBooleanSignal(initial = false): Operation<BooleanSignal> {
18-
return createValueSignal(initial);
8+
return resource(function* (provide) {
9+
const signal = createSignal<boolean, void>();
10+
11+
const ref = { current: initial };
12+
13+
function set(value: boolean) {
14+
if (value !== ref.current) {
15+
ref.current = value;
16+
17+
signal.send(ref.current);
18+
}
19+
20+
return ref.current;
21+
}
22+
23+
try {
24+
yield* provide({
25+
[Symbol.iterator]: signal[Symbol.iterator],
26+
set,
27+
update(updater) {
28+
return set(updater(ref.current));
29+
},
30+
valueOf() {
31+
return ref.current;
32+
},
33+
});
34+
} finally {
35+
signal.close();
36+
}
37+
});
1938
}

signals/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
"name": "@effectionx/signals",
33
"description": "Reactive signals and computed values for Effection operations",
44
"version": "0.6.0",
5-
"keywords": ["reactivity"],
5+
"keywords": [
6+
"effection",
7+
"effectionx",
8+
"reactivity",
9+
"signals",
10+
"computed",
11+
"state"
12+
],
613
"type": "module",
714
"main": "./dist/mod.js",
815
"types": "./dist/mod.d.ts",

signals/set.ts

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { type Operation, resource } from "effection";
2-
import { is, Set } from "immutable";
1+
import { createSignal, type Operation, resource } from "effection";
32
import type { ValueSignal } from "./types.ts";
4-
import { createValueSignal } from "./value.ts";
3+
import { is, Set } from "immutable";
54

65
/**
76
* A signal that represents a Set.
@@ -42,36 +41,50 @@ export function createSetSignal<T>(
4241
initial: Array<T> = [],
4342
): Operation<SetSignal<T>> {
4443
return resource(function* (provide) {
45-
const signal = yield* createValueSignal(Set.of<T>(...initial), {
46-
equals: is,
47-
});
44+
const signal = createSignal<Set<T>, void>();
4845

49-
function set(value: Iterable<T>): Set<T> {
50-
return signal.set(Set.of<T>(...value));
46+
const ref = { current: Set.of<T>(...initial) };
47+
48+
function set(value: Iterable<T>) {
49+
if (is(ref.current, value)) {
50+
return ref.current;
51+
}
52+
ref.current = Set.of<T>(...value);
53+
signal.send(ref.current);
54+
return ref.current;
5155
}
5256

53-
yield* provide({
54-
[Symbol.iterator]: signal[Symbol.iterator],
55-
set,
56-
update(updater) {
57-
return set(updater(signal.valueOf().toSet()));
58-
},
59-
add(item) {
60-
return signal.set(signal.valueOf().add(item));
61-
},
62-
difference(items) {
63-
return signal.set(signal.valueOf().subtract(items));
64-
},
65-
delete(item) {
66-
if (signal.valueOf().has(item)) {
67-
signal.set(signal.valueOf().delete(item));
68-
return true;
69-
}
70-
return false;
71-
},
72-
valueOf() {
73-
return signal.valueOf().toSet();
74-
},
75-
});
57+
try {
58+
yield* provide({
59+
[Symbol.iterator]: signal[Symbol.iterator],
60+
set,
61+
update(updater) {
62+
return set(updater(ref.current));
63+
},
64+
add(item) {
65+
ref.current = ref.current.add(item);
66+
signal.send(ref.current);
67+
return ref.current;
68+
},
69+
difference(items) {
70+
ref.current = ref.current.subtract(items);
71+
signal.send(ref.current);
72+
return ref.current;
73+
},
74+
delete(item) {
75+
if (ref.current.has(item)) {
76+
ref.current = ref.current.delete(item);
77+
signal.send(ref.current);
78+
return true;
79+
}
80+
return false;
81+
},
82+
valueOf() {
83+
return ref.current.toSet();
84+
},
85+
});
86+
} finally {
87+
signal.close();
88+
}
7689
});
7790
}

0 commit comments

Comments
 (0)