@bodil/signal 0.2.2 → 0.3.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/dist/index.d.ts +21 -18
- package/dist/index.js +76 -72
- package/dist/index.js.map +1 -1
- package/dist/signal.test.js +17 -17
- package/dist/signal.test.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +100 -98
- package/src/signal.test.ts +17 -25
package/dist/index.d.ts
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
import { Signal } from "signal-polyfill";
|
|
2
2
|
import { type Disposifiable } from "@bodil/disposable";
|
|
3
|
-
interface
|
|
3
|
+
interface ISignal<A> {
|
|
4
4
|
readonly value: A;
|
|
5
|
-
map<B>(fn: (value: A) => B):
|
|
5
|
+
map<B>(fn: (value: A) => B): Computed<B>;
|
|
6
6
|
on(callback: (value: A) => void): Disposable;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
declare class State<A> extends Signal.State<A> implements ISignal<A> {
|
|
9
9
|
get value(): A;
|
|
10
10
|
set value(value: A);
|
|
11
11
|
update(fn: (value: A) => A): void;
|
|
12
|
-
readOnly():
|
|
13
|
-
map<B>(fn: (value: A) => B):
|
|
12
|
+
readOnly(): Computed<A>;
|
|
13
|
+
map<B>(fn: (value: A) => B): Computed<B>;
|
|
14
14
|
on(callback: (value: A) => void): Disposable;
|
|
15
|
+
static is(v: unknown): v is State<unknown>;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
declare class Computed<A> extends Signal.Computed<A> implements ISignal<A> {
|
|
17
18
|
get value(): A;
|
|
18
|
-
map<B>(fn: (value: A) => B):
|
|
19
|
+
map<B>(fn: (value: A) => B): Computed<B>;
|
|
19
20
|
on(callback: (value: A) => void): Disposable;
|
|
21
|
+
static is(v: unknown): v is Computed<unknown>;
|
|
20
22
|
}
|
|
21
|
-
type AnySignal<A> =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
type AnySignal<A> = State<A> | Computed<A>;
|
|
24
|
+
declare const AnySignal: (<A>(value: A, options?: Signal.Options<A>) => State<A>) & {
|
|
25
|
+
is(v: unknown): v is AnySignal<unknown>;
|
|
26
|
+
computed<A>(fn: (this: Computed<A>) => A, options?: Signal.Options<A>): Computed<A>;
|
|
27
|
+
subscribe<A>(signal: ISignal<A>, callback: (value: A) => void): Disposable;
|
|
28
|
+
effect(fn: () => Disposifiable | void): Disposable;
|
|
29
|
+
asyncComputed<A>(fn: (abort: AbortSignal) => Promise<A>, options?: Signal.Options<A>): Promise<Computed<A>>;
|
|
30
|
+
State: typeof State;
|
|
31
|
+
Computed: typeof Computed;
|
|
32
|
+
subtle: typeof Signal.subtle;
|
|
33
|
+
};
|
|
34
|
+
export { AnySignal as Signal };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Signal } from "signal-polyfill";
|
|
2
2
|
import { toDisposable } from "@bodil/disposable";
|
|
3
3
|
import { Err, Ok, Async } from "@bodil/core";
|
|
4
|
-
|
|
4
|
+
class State extends Signal.State {
|
|
5
5
|
get value() {
|
|
6
6
|
return this.get();
|
|
7
7
|
}
|
|
@@ -12,41 +12,31 @@ export class StateSignal extends Signal.State {
|
|
|
12
12
|
this.set(Signal.subtle.untrack(() => fn(this.get())));
|
|
13
13
|
}
|
|
14
14
|
readOnly() {
|
|
15
|
-
return computed(() => this.get());
|
|
15
|
+
return AnySignal.computed(() => this.get());
|
|
16
16
|
}
|
|
17
17
|
map(fn) {
|
|
18
|
-
return computed(() => fn(this.get()));
|
|
18
|
+
return AnySignal.computed(() => fn(this.get()));
|
|
19
19
|
}
|
|
20
20
|
on(callback) {
|
|
21
|
-
return subscribe(this, callback);
|
|
21
|
+
return AnySignal.subscribe(this, callback);
|
|
22
|
+
}
|
|
23
|
+
static is(v) {
|
|
24
|
+
return v instanceof State;
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
|
-
|
|
27
|
+
class Computed extends Signal.Computed {
|
|
25
28
|
get value() {
|
|
26
29
|
return this.get();
|
|
27
30
|
}
|
|
28
31
|
map(fn) {
|
|
29
|
-
return computed(() => fn(this.get()));
|
|
32
|
+
return AnySignal.computed(() => fn(this.get()));
|
|
30
33
|
}
|
|
31
34
|
on(callback) {
|
|
32
|
-
return subscribe(this, callback);
|
|
35
|
+
return AnySignal.subscribe(this, callback);
|
|
36
|
+
}
|
|
37
|
+
static is(v) {
|
|
38
|
+
return v instanceof Computed;
|
|
33
39
|
}
|
|
34
|
-
}
|
|
35
|
-
export const subtle = Signal.subtle;
|
|
36
|
-
export function isStateSignal(v) {
|
|
37
|
-
return v instanceof StateSignal;
|
|
38
|
-
}
|
|
39
|
-
export function isComputedSignal(v) {
|
|
40
|
-
return v instanceof ComputedSignal;
|
|
41
|
-
}
|
|
42
|
-
export function isSignal(v) {
|
|
43
|
-
return isStateSignal(v) || isComputedSignal(v);
|
|
44
|
-
}
|
|
45
|
-
export function signal(value, options) {
|
|
46
|
-
return new StateSignal(value, options);
|
|
47
|
-
}
|
|
48
|
-
export function computed(fn, options) {
|
|
49
|
-
return new ComputedSignal(fn, options);
|
|
50
40
|
}
|
|
51
41
|
let effectNeedsEnqueue = true;
|
|
52
42
|
const effectWatcher = new Signal.subtle.Watcher(() => {
|
|
@@ -62,55 +52,69 @@ function effectProcess() {
|
|
|
62
52
|
}
|
|
63
53
|
effectWatcher.watch();
|
|
64
54
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
export function subscribe(signal, callback) {
|
|
84
|
-
return effect(() => callback(signal.value));
|
|
85
|
-
}
|
|
86
|
-
export function asyncComputed(fn, options) {
|
|
87
|
-
const result = Promise.withResolvers();
|
|
88
|
-
const stream = computed(() => Async.abortable(fn));
|
|
89
|
-
const sig = signal(Err(new Error()));
|
|
90
|
-
let job = undefined;
|
|
91
|
-
let resolved = false;
|
|
92
|
-
const resolve = () => {
|
|
93
|
-
if (!resolved) {
|
|
94
|
-
resolved = true;
|
|
95
|
-
result.resolve(computed(() => sig.get().unwrapExact(), options));
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
effect(() => {
|
|
99
|
-
if (job !== undefined) {
|
|
100
|
-
job.abort();
|
|
101
|
-
}
|
|
102
|
-
job = stream.get();
|
|
103
|
-
job.result.then((next) => {
|
|
104
|
-
sig.set(Ok(next));
|
|
105
|
-
resolve();
|
|
106
|
-
}, (error) => {
|
|
107
|
-
if (job?.signal.aborted === true) {
|
|
108
|
-
return;
|
|
55
|
+
const AnySignal = Object.assign(function (value, options) {
|
|
56
|
+
return new State(value, options);
|
|
57
|
+
}, {
|
|
58
|
+
is(v) {
|
|
59
|
+
return State.is(v) || Computed.is(v);
|
|
60
|
+
},
|
|
61
|
+
computed(fn, options) {
|
|
62
|
+
return new Computed(fn, options);
|
|
63
|
+
},
|
|
64
|
+
subscribe(signal, callback) {
|
|
65
|
+
return AnySignal.effect(() => callback(signal.value));
|
|
66
|
+
},
|
|
67
|
+
effect(fn) {
|
|
68
|
+
let cleanup;
|
|
69
|
+
const computed = new Computed(() => {
|
|
70
|
+
if (cleanup !== undefined) {
|
|
71
|
+
cleanup[Symbol.dispose]();
|
|
109
72
|
}
|
|
110
|
-
|
|
111
|
-
|
|
73
|
+
const result = fn();
|
|
74
|
+
cleanup = result !== undefined ? toDisposable(result) : undefined;
|
|
112
75
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
76
|
+
effectWatcher.watch(computed);
|
|
77
|
+
computed.get();
|
|
78
|
+
return toDisposable(() => {
|
|
79
|
+
effectWatcher.unwatch(computed);
|
|
80
|
+
if (cleanup !== undefined) {
|
|
81
|
+
cleanup[Symbol.dispose]();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
asyncComputed(fn, options) {
|
|
86
|
+
const result = Promise.withResolvers();
|
|
87
|
+
const stream = AnySignal.computed(() => Async.abortable(fn));
|
|
88
|
+
const sig = AnySignal(Err(new Error()));
|
|
89
|
+
let job = undefined;
|
|
90
|
+
let resolved = false;
|
|
91
|
+
const resolve = () => {
|
|
92
|
+
if (!resolved) {
|
|
93
|
+
resolved = true;
|
|
94
|
+
result.resolve(AnySignal.computed(() => sig.get().unwrapExact(), options));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
AnySignal.effect(() => {
|
|
98
|
+
if (job !== undefined) {
|
|
99
|
+
job.abort();
|
|
100
|
+
}
|
|
101
|
+
job = stream.get();
|
|
102
|
+
job.result.then((next) => {
|
|
103
|
+
sig.set(Ok(next));
|
|
104
|
+
resolve();
|
|
105
|
+
}, (error) => {
|
|
106
|
+
if (job?.signal.aborted === true) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
sig.set(Err(error));
|
|
110
|
+
resolve();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
return result.promise;
|
|
114
|
+
},
|
|
115
|
+
State,
|
|
116
|
+
Computed,
|
|
117
|
+
subtle: Signal.subtle,
|
|
118
|
+
});
|
|
119
|
+
export { AnySignal as Signal };
|
|
116
120
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAsB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,KAAK,EAAE,MAAM,aAAa,CAAC;AAQ1D,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/signal.test.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { sleep } from "@bodil/core/async";
|
|
2
2
|
import { expect, test } from "vitest";
|
|
3
|
-
import {
|
|
3
|
+
import { Signal } from ".";
|
|
4
4
|
test("Signal", async () => {
|
|
5
|
-
const sig =
|
|
5
|
+
const sig = Signal(0);
|
|
6
6
|
const result = [];
|
|
7
|
-
effect(() => void result.push(sig.value));
|
|
7
|
+
Signal.effect(() => void result.push(sig.value));
|
|
8
8
|
expect(result).toEqual([0]);
|
|
9
9
|
sig.value = 1;
|
|
10
10
|
sig.value = 2;
|
|
@@ -24,8 +24,8 @@ test("Signal", async () => {
|
|
|
24
24
|
});
|
|
25
25
|
test("signal equality", async () => {
|
|
26
26
|
const result = [];
|
|
27
|
-
const sig =
|
|
28
|
-
effect(() => void result.push(sig.value));
|
|
27
|
+
const sig = Signal(0);
|
|
28
|
+
Signal.effect(() => void result.push(sig.value));
|
|
29
29
|
expect(result).toEqual([0]);
|
|
30
30
|
sig.value = 1;
|
|
31
31
|
await sleep(1);
|
|
@@ -50,11 +50,11 @@ test("signal equality", async () => {
|
|
|
50
50
|
expect(result).toEqual([0, 1, 2, 3, 2]);
|
|
51
51
|
});
|
|
52
52
|
test("asyncComputed", async () => {
|
|
53
|
-
const s =
|
|
54
|
-
const c = await asyncComputed(() => Promise.resolve(s.value + 1));
|
|
53
|
+
const s = Signal(1);
|
|
54
|
+
const c = await Signal.asyncComputed(() => Promise.resolve(s.value + 1));
|
|
55
55
|
expect(c.value).toEqual(2);
|
|
56
56
|
try {
|
|
57
|
-
await asyncComputed(() => {
|
|
57
|
+
await Signal.asyncComputed(() => {
|
|
58
58
|
throw new Error("welp!");
|
|
59
59
|
});
|
|
60
60
|
throw new Error("computed error failed to throw");
|
|
@@ -75,14 +75,14 @@ test("asyncComputed", async () => {
|
|
|
75
75
|
expect(c.value).toEqual(4);
|
|
76
76
|
});
|
|
77
77
|
test("isSignal", () => {
|
|
78
|
-
const s1 =
|
|
79
|
-
expect(
|
|
80
|
-
expect(
|
|
81
|
-
expect(
|
|
82
|
-
const s2 = computed(() => 2);
|
|
83
|
-
expect(
|
|
84
|
-
expect(
|
|
85
|
-
expect(
|
|
86
|
-
expect(
|
|
78
|
+
const s1 = Signal(1);
|
|
79
|
+
expect(Signal.is(s1)).toBeTruthy();
|
|
80
|
+
expect(Signal.State.is(s1)).toBeTruthy();
|
|
81
|
+
expect(Signal.Computed.is(s1)).toBeFalsy();
|
|
82
|
+
const s2 = Signal.computed(() => 2);
|
|
83
|
+
expect(Signal.is(s2)).toBeTruthy();
|
|
84
|
+
expect(Signal.State.is(s2)).toBeFalsy();
|
|
85
|
+
expect(Signal.Computed.is(s2)).toBeTruthy();
|
|
86
|
+
expect(Signal.is("wibble")).toBeFalsy();
|
|
87
87
|
});
|
|
88
88
|
//# sourceMappingURL=signal.test.js.map
|
package/dist/signal.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signal.test.js","sourceRoot":"","sources":["../src/signal.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,
|
|
1
|
+
{"version":3,"file":"signal.test.js","sourceRoot":"","sources":["../src/signal.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bodil/signal",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Signal implementation built on the TC39 Signals Proposal",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/bodil/signal.git"
|
package/src/index.ts
CHANGED
|
@@ -2,13 +2,13 @@ import { Signal } from "signal-polyfill";
|
|
|
2
2
|
import { toDisposable, type Disposifiable } from "@bodil/disposable";
|
|
3
3
|
import { Err, Ok, type Result, Async } from "@bodil/core";
|
|
4
4
|
|
|
5
|
-
interface
|
|
5
|
+
interface ISignal<A> {
|
|
6
6
|
readonly value: A;
|
|
7
|
-
map<B>(fn: (value: A) => B):
|
|
7
|
+
map<B>(fn: (value: A) => B): Computed<B>;
|
|
8
8
|
on(callback: (value: A) => void): Disposable;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
class State<A> extends Signal.State<A> implements ISignal<A> {
|
|
12
12
|
get value(): A {
|
|
13
13
|
return this.get();
|
|
14
14
|
}
|
|
@@ -21,60 +21,39 @@ export class StateSignal<A> extends Signal.State<A> implements ReadableSignal<A>
|
|
|
21
21
|
this.set(Signal.subtle.untrack(() => fn(this.get())));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
readOnly():
|
|
25
|
-
return computed(() => this.get());
|
|
24
|
+
readOnly(): Computed<A> {
|
|
25
|
+
return AnySignal.computed(() => this.get());
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
map<B>(fn: (value: A) => B):
|
|
29
|
-
return computed(() => fn(this.get()));
|
|
28
|
+
map<B>(fn: (value: A) => B): Computed<B> {
|
|
29
|
+
return AnySignal.computed(() => fn(this.get()));
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
on(callback: (value: A) => void): Disposable {
|
|
33
|
-
return subscribe(this, callback);
|
|
33
|
+
return AnySignal.subscribe(this, callback);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static is(v: unknown): v is State<unknown> {
|
|
37
|
+
return v instanceof State;
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
class Computed<A> extends Signal.Computed<A> implements ISignal<A> {
|
|
38
42
|
get value(): A {
|
|
39
43
|
return this.get();
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
map<B>(fn: (value: A) => B):
|
|
43
|
-
return computed(() => fn(this.get()));
|
|
46
|
+
map<B>(fn: (value: A) => B): Computed<B> {
|
|
47
|
+
return AnySignal.computed(() => fn(this.get()));
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
on(callback: (value: A) => void): Disposable {
|
|
47
|
-
return subscribe(this, callback);
|
|
51
|
+
return AnySignal.subscribe(this, callback);
|
|
48
52
|
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
type AnySignal<A> = StateSignal<A> | ComputedSignal<A>;
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export function isStateSignal(v: unknown): v is StateSignal<unknown> {
|
|
58
|
-
return v instanceof StateSignal;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function isComputedSignal(v: unknown): v is ComputedSignal<unknown> {
|
|
62
|
-
return v instanceof ComputedSignal;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function isSignal(v: unknown): v is AnySignal<unknown> {
|
|
66
|
-
return isStateSignal(v) || isComputedSignal(v);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function signal<A>(value: A, options?: Signal.Options<A>): StateSignal<A> {
|
|
70
|
-
return new StateSignal(value, options);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function computed<A>(
|
|
74
|
-
fn: (this: ComputedSignal<A>) => A,
|
|
75
|
-
options?: Signal.Options<A>
|
|
76
|
-
): ComputedSignal<A> {
|
|
77
|
-
return new ComputedSignal(fn, options);
|
|
54
|
+
static is(v: unknown): v is Computed<unknown> {
|
|
55
|
+
return v instanceof Computed;
|
|
56
|
+
}
|
|
78
57
|
}
|
|
79
58
|
|
|
80
59
|
let effectNeedsEnqueue = true;
|
|
@@ -93,62 +72,85 @@ function effectProcess(): void {
|
|
|
93
72
|
effectWatcher.watch();
|
|
94
73
|
}
|
|
95
74
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
fn: (abort: AbortSignal) => Promise<A>,
|
|
121
|
-
options?: Signal.Options<A>
|
|
122
|
-
): Promise<ComputedSignal<A>> {
|
|
123
|
-
const result = Promise.withResolvers<ComputedSignal<A>>();
|
|
124
|
-
const stream = computed(() => Async.abortable(fn));
|
|
125
|
-
const sig: StateSignal<Result<A, Error>> = signal(Err(new Error()));
|
|
126
|
-
let job: Async.AbortableJob<A> | undefined = undefined;
|
|
127
|
-
let resolved = false;
|
|
128
|
-
const resolve = () => {
|
|
129
|
-
if (!resolved) {
|
|
130
|
-
resolved = true;
|
|
131
|
-
result.resolve(computed(() => sig.get().unwrapExact(), options));
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
effect(() => {
|
|
135
|
-
if (job !== undefined) {
|
|
136
|
-
job.abort();
|
|
137
|
-
}
|
|
138
|
-
job = stream.get();
|
|
139
|
-
job.result.then(
|
|
140
|
-
(next) => {
|
|
141
|
-
sig.set(Ok(next));
|
|
142
|
-
resolve();
|
|
143
|
-
},
|
|
144
|
-
(error) => {
|
|
145
|
-
if (job?.signal.aborted === true) {
|
|
146
|
-
return;
|
|
75
|
+
type AnySignal<A> = State<A> | Computed<A>;
|
|
76
|
+
|
|
77
|
+
const AnySignal = Object.assign(
|
|
78
|
+
function <A>(value: A, options?: Signal.Options<A>): State<A> {
|
|
79
|
+
return new State(value, options);
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
is(v: unknown): v is AnySignal<unknown> {
|
|
83
|
+
return State.is(v) || Computed.is(v);
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
computed<A>(fn: (this: Computed<A>) => A, options?: Signal.Options<A>): Computed<A> {
|
|
87
|
+
return new Computed(fn, options);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
subscribe<A>(signal: ISignal<A>, callback: (value: A) => void): Disposable {
|
|
91
|
+
return AnySignal.effect(() => callback(signal.value));
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
effect(fn: () => Disposifiable | void): Disposable {
|
|
95
|
+
let cleanup: Disposable | undefined;
|
|
96
|
+
const computed = new Computed(() => {
|
|
97
|
+
if (cleanup !== undefined) {
|
|
98
|
+
cleanup[Symbol.dispose]();
|
|
147
99
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
100
|
+
const result = fn();
|
|
101
|
+
cleanup = result !== undefined ? toDisposable(result) : undefined;
|
|
102
|
+
});
|
|
103
|
+
effectWatcher.watch(computed);
|
|
104
|
+
computed.get();
|
|
105
|
+
return toDisposable(() => {
|
|
106
|
+
effectWatcher.unwatch(computed);
|
|
107
|
+
if (cleanup !== undefined) {
|
|
108
|
+
cleanup[Symbol.dispose]();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
asyncComputed<A>(
|
|
114
|
+
fn: (abort: AbortSignal) => Promise<A>,
|
|
115
|
+
options?: Signal.Options<A>
|
|
116
|
+
): Promise<Computed<A>> {
|
|
117
|
+
const result = Promise.withResolvers<Computed<A>>();
|
|
118
|
+
const stream = AnySignal.computed(() => Async.abortable(fn));
|
|
119
|
+
const sig: State<Result<A, Error>> = AnySignal(Err(new Error()));
|
|
120
|
+
let job: Async.AbortableJob<A> | undefined = undefined;
|
|
121
|
+
let resolved = false;
|
|
122
|
+
const resolve = () => {
|
|
123
|
+
if (!resolved) {
|
|
124
|
+
resolved = true;
|
|
125
|
+
result.resolve(AnySignal.computed(() => sig.get().unwrapExact(), options));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
AnySignal.effect(() => {
|
|
129
|
+
if (job !== undefined) {
|
|
130
|
+
job.abort();
|
|
131
|
+
}
|
|
132
|
+
job = stream.get();
|
|
133
|
+
job.result.then(
|
|
134
|
+
(next) => {
|
|
135
|
+
sig.set(Ok(next));
|
|
136
|
+
resolve();
|
|
137
|
+
},
|
|
138
|
+
(error) => {
|
|
139
|
+
if (job?.signal.aborted === true) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
sig.set(Err(error));
|
|
143
|
+
resolve();
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
return result.promise;
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
State,
|
|
151
|
+
Computed,
|
|
152
|
+
subtle: Signal.subtle,
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
export { AnySignal as Signal };
|
package/src/signal.test.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import { sleep } from "@bodil/core/async";
|
|
2
2
|
import { expect, test } from "vitest";
|
|
3
|
-
import {
|
|
4
|
-
asyncComputed,
|
|
5
|
-
computed,
|
|
6
|
-
effect,
|
|
7
|
-
isComputedSignal,
|
|
8
|
-
isSignal,
|
|
9
|
-
isStateSignal,
|
|
10
|
-
signal,
|
|
11
|
-
} from ".";
|
|
3
|
+
import { Signal } from ".";
|
|
12
4
|
|
|
13
5
|
test("Signal", async () => {
|
|
14
|
-
const sig =
|
|
6
|
+
const sig = Signal(0);
|
|
15
7
|
const result: Array<number> = [];
|
|
16
|
-
effect(() => void result.push(sig.value));
|
|
8
|
+
Signal.effect(() => void result.push(sig.value));
|
|
17
9
|
expect(result).toEqual([0]);
|
|
18
10
|
sig.value = 1;
|
|
19
11
|
sig.value = 2;
|
|
@@ -33,8 +25,8 @@ test("Signal", async () => {
|
|
|
33
25
|
|
|
34
26
|
test("signal equality", async () => {
|
|
35
27
|
const result: Array<number> = [];
|
|
36
|
-
const sig =
|
|
37
|
-
effect(() => void result.push(sig.value));
|
|
28
|
+
const sig = Signal(0);
|
|
29
|
+
Signal.effect(() => void result.push(sig.value));
|
|
38
30
|
expect(result).toEqual([0]);
|
|
39
31
|
sig.value = 1;
|
|
40
32
|
await sleep(1);
|
|
@@ -60,11 +52,11 @@ test("signal equality", async () => {
|
|
|
60
52
|
});
|
|
61
53
|
|
|
62
54
|
test("asyncComputed", async () => {
|
|
63
|
-
const s =
|
|
64
|
-
const c = await asyncComputed(() => Promise.resolve(s.value + 1));
|
|
55
|
+
const s = Signal(1);
|
|
56
|
+
const c = await Signal.asyncComputed(() => Promise.resolve(s.value + 1));
|
|
65
57
|
expect(c.value).toEqual(2);
|
|
66
58
|
try {
|
|
67
|
-
await asyncComputed(() => {
|
|
59
|
+
await Signal.asyncComputed(() => {
|
|
68
60
|
throw new Error("welp!");
|
|
69
61
|
});
|
|
70
62
|
throw new Error("computed error failed to throw");
|
|
@@ -85,15 +77,15 @@ test("asyncComputed", async () => {
|
|
|
85
77
|
});
|
|
86
78
|
|
|
87
79
|
test("isSignal", () => {
|
|
88
|
-
const s1 =
|
|
89
|
-
expect(
|
|
90
|
-
expect(
|
|
91
|
-
expect(
|
|
80
|
+
const s1 = Signal(1);
|
|
81
|
+
expect(Signal.is(s1)).toBeTruthy();
|
|
82
|
+
expect(Signal.State.is(s1)).toBeTruthy();
|
|
83
|
+
expect(Signal.Computed.is(s1)).toBeFalsy();
|
|
92
84
|
|
|
93
|
-
const s2 = computed(() => 2);
|
|
94
|
-
expect(
|
|
95
|
-
expect(
|
|
96
|
-
expect(
|
|
85
|
+
const s2 = Signal.computed(() => 2);
|
|
86
|
+
expect(Signal.is(s2)).toBeTruthy();
|
|
87
|
+
expect(Signal.State.is(s2)).toBeFalsy();
|
|
88
|
+
expect(Signal.Computed.is(s2)).toBeTruthy();
|
|
97
89
|
|
|
98
|
-
expect(
|
|
90
|
+
expect(Signal.is("wibble")).toBeFalsy();
|
|
99
91
|
});
|