@bodil/signal 0.3.0 → 0.3.1
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 +20 -16
- package/dist/index.js +22 -22
- package/dist/index.js.map +1 -1
- package/dist/signal.test.js +10 -0
- package/dist/signal.test.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +42 -34
- package/src/signal.test.ts +14 -2
package/dist/index.d.ts
CHANGED
|
@@ -2,33 +2,37 @@ import { Signal } from "signal-polyfill";
|
|
|
2
2
|
import { type Disposifiable } from "@bodil/disposable";
|
|
3
3
|
interface ISignal<A> {
|
|
4
4
|
readonly value: A;
|
|
5
|
-
map<B>(fn: (value: A) => B):
|
|
5
|
+
map<B>(fn: (value: A) => B): ComputedSignal<B>;
|
|
6
6
|
on(callback: (value: A) => void): Disposable;
|
|
7
7
|
}
|
|
8
|
-
declare class
|
|
8
|
+
declare class StateSignal<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(): ComputedSignal<A>;
|
|
13
|
+
map<B>(fn: (value: A) => B): ComputedSignal<B>;
|
|
14
14
|
on(callback: (value: A) => void): Disposable;
|
|
15
|
-
static is(v: unknown): v is
|
|
15
|
+
static is(v: unknown): v is StateSignal<unknown>;
|
|
16
16
|
}
|
|
17
|
-
declare class
|
|
17
|
+
declare class ComputedSignal<A> extends Signal.Computed<A> implements ISignal<A> {
|
|
18
18
|
get value(): A;
|
|
19
|
-
map<B>(fn: (value: A) => B):
|
|
19
|
+
map<B>(fn: (value: A) => B): ComputedSignal<B>;
|
|
20
20
|
on(callback: (value: A) => void): Disposable;
|
|
21
|
-
static is(v: unknown): v is
|
|
21
|
+
static is(v: unknown): v is ComputedSignal<unknown>;
|
|
22
22
|
}
|
|
23
|
-
type
|
|
24
|
-
declare const
|
|
25
|
-
is(v: unknown): v is
|
|
26
|
-
computed<A>(fn: (this:
|
|
23
|
+
type SignalGlobal<A> = StateSignal<A> | ComputedSignal<A>;
|
|
24
|
+
declare const SignalGlobal: (<A>(value: A, options?: Signal.Options<A>) => SignalGlobal.State<A>) & {
|
|
25
|
+
is(v: unknown): v is SignalGlobal<unknown>;
|
|
26
|
+
computed<A>(fn: (this: ComputedSignal<A>) => A, options?: Signal.Options<A>): SignalGlobal.Computed<A>;
|
|
27
27
|
subscribe<A>(signal: ISignal<A>, callback: (value: A) => void): Disposable;
|
|
28
28
|
effect(fn: () => Disposifiable | void): Disposable;
|
|
29
|
-
asyncComputed<A>(fn: (abort: AbortSignal) => Promise<A>, options?: Signal.Options<A>): Promise<Computed<A>>;
|
|
30
|
-
State: typeof
|
|
31
|
-
Computed: typeof
|
|
29
|
+
asyncComputed<A>(fn: (abort: AbortSignal) => Promise<A>, options?: Signal.Options<A>): Promise<SignalGlobal.Computed<A>>;
|
|
30
|
+
State: typeof StateSignal;
|
|
31
|
+
Computed: typeof ComputedSignal;
|
|
32
32
|
subtle: typeof Signal.subtle;
|
|
33
33
|
};
|
|
34
|
-
|
|
34
|
+
declare namespace SignalGlobal {
|
|
35
|
+
type State<A> = StateSignal<A>;
|
|
36
|
+
type Computed<A> = ComputedSignal<A>;
|
|
37
|
+
}
|
|
38
|
+
export { SignalGlobal 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
|
-
class
|
|
4
|
+
class StateSignal extends Signal.State {
|
|
5
5
|
get value() {
|
|
6
6
|
return this.get();
|
|
7
7
|
}
|
|
@@ -12,30 +12,30 @@ class State extends Signal.State {
|
|
|
12
12
|
this.set(Signal.subtle.untrack(() => fn(this.get())));
|
|
13
13
|
}
|
|
14
14
|
readOnly() {
|
|
15
|
-
return
|
|
15
|
+
return SignalGlobal.computed(() => this.get());
|
|
16
16
|
}
|
|
17
17
|
map(fn) {
|
|
18
|
-
return
|
|
18
|
+
return SignalGlobal.computed(() => fn(this.get()));
|
|
19
19
|
}
|
|
20
20
|
on(callback) {
|
|
21
|
-
return
|
|
21
|
+
return SignalGlobal.subscribe(this, callback);
|
|
22
22
|
}
|
|
23
23
|
static is(v) {
|
|
24
|
-
return v instanceof
|
|
24
|
+
return v instanceof StateSignal;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
class
|
|
27
|
+
class ComputedSignal extends Signal.Computed {
|
|
28
28
|
get value() {
|
|
29
29
|
return this.get();
|
|
30
30
|
}
|
|
31
31
|
map(fn) {
|
|
32
|
-
return
|
|
32
|
+
return SignalGlobal.computed(() => fn(this.get()));
|
|
33
33
|
}
|
|
34
34
|
on(callback) {
|
|
35
|
-
return
|
|
35
|
+
return SignalGlobal.subscribe(this, callback);
|
|
36
36
|
}
|
|
37
37
|
static is(v) {
|
|
38
|
-
return v instanceof
|
|
38
|
+
return v instanceof ComputedSignal;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
let effectNeedsEnqueue = true;
|
|
@@ -52,21 +52,21 @@ function effectProcess() {
|
|
|
52
52
|
}
|
|
53
53
|
effectWatcher.watch();
|
|
54
54
|
}
|
|
55
|
-
const
|
|
56
|
-
return new
|
|
55
|
+
const SignalGlobal = Object.assign(function (value, options) {
|
|
56
|
+
return new StateSignal(value, options);
|
|
57
57
|
}, {
|
|
58
58
|
is(v) {
|
|
59
|
-
return
|
|
59
|
+
return StateSignal.is(v) || ComputedSignal.is(v);
|
|
60
60
|
},
|
|
61
61
|
computed(fn, options) {
|
|
62
|
-
return new
|
|
62
|
+
return new ComputedSignal(fn, options);
|
|
63
63
|
},
|
|
64
64
|
subscribe(signal, callback) {
|
|
65
|
-
return
|
|
65
|
+
return SignalGlobal.effect(() => callback(signal.value));
|
|
66
66
|
},
|
|
67
67
|
effect(fn) {
|
|
68
68
|
let cleanup;
|
|
69
|
-
const computed = new
|
|
69
|
+
const computed = new ComputedSignal(() => {
|
|
70
70
|
if (cleanup !== undefined) {
|
|
71
71
|
cleanup[Symbol.dispose]();
|
|
72
72
|
}
|
|
@@ -84,17 +84,17 @@ const AnySignal = Object.assign(function (value, options) {
|
|
|
84
84
|
},
|
|
85
85
|
asyncComputed(fn, options) {
|
|
86
86
|
const result = Promise.withResolvers();
|
|
87
|
-
const stream =
|
|
88
|
-
const sig =
|
|
87
|
+
const stream = SignalGlobal.computed(() => Async.abortable(fn));
|
|
88
|
+
const sig = SignalGlobal(Err(new Error()));
|
|
89
89
|
let job = undefined;
|
|
90
90
|
let resolved = false;
|
|
91
91
|
const resolve = () => {
|
|
92
92
|
if (!resolved) {
|
|
93
93
|
resolved = true;
|
|
94
|
-
result.resolve(
|
|
94
|
+
result.resolve(SignalGlobal.computed(() => sig.get().unwrapExact(), options));
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
|
-
|
|
97
|
+
SignalGlobal.effect(() => {
|
|
98
98
|
if (job !== undefined) {
|
|
99
99
|
job.abort();
|
|
100
100
|
}
|
|
@@ -112,9 +112,9 @@ const AnySignal = Object.assign(function (value, options) {
|
|
|
112
112
|
});
|
|
113
113
|
return result.promise;
|
|
114
114
|
},
|
|
115
|
-
State,
|
|
116
|
-
Computed,
|
|
115
|
+
State: StateSignal,
|
|
116
|
+
Computed: ComputedSignal,
|
|
117
117
|
subtle: Signal.subtle,
|
|
118
118
|
});
|
|
119
|
-
export {
|
|
119
|
+
export { SignalGlobal as Signal };
|
|
120
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
|
@@ -85,4 +85,14 @@ test("isSignal", () => {
|
|
|
85
85
|
expect(Signal.Computed.is(s2)).toBeTruthy();
|
|
86
86
|
expect(Signal.is("wibble")).toBeFalsy();
|
|
87
87
|
});
|
|
88
|
+
test("Signal types", () => {
|
|
89
|
+
const s1 = Signal(1);
|
|
90
|
+
const s2 = Signal.computed(() => s1.get());
|
|
91
|
+
function foo(_signal) {
|
|
92
|
+
// ensure Signal<A> is an accessible type
|
|
93
|
+
// and that it accepts both concrete signal types.
|
|
94
|
+
}
|
|
95
|
+
foo(s1);
|
|
96
|
+
foo(s2);
|
|
97
|
+
});
|
|
88
98
|
//# 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,
|
|
1
|
+
{"version":3,"file":"signal.test.js","sourceRoot":"","sources":["../src/signal.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -4,11 +4,11 @@ import { Err, Ok, type Result, Async } from "@bodil/core";
|
|
|
4
4
|
|
|
5
5
|
interface ISignal<A> {
|
|
6
6
|
readonly value: A;
|
|
7
|
-
map<B>(fn: (value: A) => B):
|
|
7
|
+
map<B>(fn: (value: A) => B): ComputedSignal<B>;
|
|
8
8
|
on(callback: (value: A) => void): Disposable;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
class
|
|
11
|
+
class StateSignal<A> extends Signal.State<A> implements ISignal<A> {
|
|
12
12
|
get value(): A {
|
|
13
13
|
return this.get();
|
|
14
14
|
}
|
|
@@ -21,38 +21,38 @@ class State<A> extends Signal.State<A> implements ISignal<A> {
|
|
|
21
21
|
this.set(Signal.subtle.untrack(() => fn(this.get())));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
readOnly():
|
|
25
|
-
return
|
|
24
|
+
readOnly(): ComputedSignal<A> {
|
|
25
|
+
return SignalGlobal.computed(() => this.get());
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
map<B>(fn: (value: A) => B):
|
|
29
|
-
return
|
|
28
|
+
map<B>(fn: (value: A) => B): ComputedSignal<B> {
|
|
29
|
+
return SignalGlobal.computed(() => fn(this.get()));
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
on(callback: (value: A) => void): Disposable {
|
|
33
|
-
return
|
|
33
|
+
return SignalGlobal.subscribe(this, callback);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
static is(v: unknown): v is
|
|
37
|
-
return v instanceof
|
|
36
|
+
static is(v: unknown): v is StateSignal<unknown> {
|
|
37
|
+
return v instanceof StateSignal;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
class
|
|
41
|
+
class ComputedSignal<A> extends Signal.Computed<A> implements ISignal<A> {
|
|
42
42
|
get value(): A {
|
|
43
43
|
return this.get();
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
map<B>(fn: (value: A) => B):
|
|
47
|
-
return
|
|
46
|
+
map<B>(fn: (value: A) => B): ComputedSignal<B> {
|
|
47
|
+
return SignalGlobal.computed(() => fn(this.get()));
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
on(callback: (value: A) => void): Disposable {
|
|
51
|
-
return
|
|
51
|
+
return SignalGlobal.subscribe(this, callback);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
static is(v: unknown): v is
|
|
55
|
-
return v instanceof
|
|
54
|
+
static is(v: unknown): v is ComputedSignal<unknown> {
|
|
55
|
+
return v instanceof ComputedSignal;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -72,28 +72,31 @@ function effectProcess(): void {
|
|
|
72
72
|
effectWatcher.watch();
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
type
|
|
75
|
+
type SignalGlobal<A> = StateSignal<A> | ComputedSignal<A>;
|
|
76
76
|
|
|
77
|
-
const
|
|
78
|
-
function <A>(value: A, options?: Signal.Options<A>): State<A> {
|
|
79
|
-
return new
|
|
77
|
+
const SignalGlobal = Object.assign(
|
|
78
|
+
function <A>(value: A, options?: Signal.Options<A>): SignalGlobal.State<A> {
|
|
79
|
+
return new StateSignal(value, options);
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
|
-
is(v: unknown): v is
|
|
83
|
-
return
|
|
82
|
+
is(v: unknown): v is SignalGlobal<unknown> {
|
|
83
|
+
return StateSignal.is(v) || ComputedSignal.is(v);
|
|
84
84
|
},
|
|
85
85
|
|
|
86
|
-
computed<A>(
|
|
87
|
-
|
|
86
|
+
computed<A>(
|
|
87
|
+
fn: (this: ComputedSignal<A>) => A,
|
|
88
|
+
options?: Signal.Options<A>
|
|
89
|
+
): SignalGlobal.Computed<A> {
|
|
90
|
+
return new ComputedSignal(fn, options);
|
|
88
91
|
},
|
|
89
92
|
|
|
90
93
|
subscribe<A>(signal: ISignal<A>, callback: (value: A) => void): Disposable {
|
|
91
|
-
return
|
|
94
|
+
return SignalGlobal.effect(() => callback(signal.value));
|
|
92
95
|
},
|
|
93
96
|
|
|
94
97
|
effect(fn: () => Disposifiable | void): Disposable {
|
|
95
98
|
let cleanup: Disposable | undefined;
|
|
96
|
-
const computed = new
|
|
99
|
+
const computed = new ComputedSignal(() => {
|
|
97
100
|
if (cleanup !== undefined) {
|
|
98
101
|
cleanup[Symbol.dispose]();
|
|
99
102
|
}
|
|
@@ -113,19 +116,19 @@ const AnySignal = Object.assign(
|
|
|
113
116
|
asyncComputed<A>(
|
|
114
117
|
fn: (abort: AbortSignal) => Promise<A>,
|
|
115
118
|
options?: Signal.Options<A>
|
|
116
|
-
): Promise<Computed<A>> {
|
|
117
|
-
const result = Promise.withResolvers<
|
|
118
|
-
const stream =
|
|
119
|
-
const sig:
|
|
119
|
+
): Promise<SignalGlobal.Computed<A>> {
|
|
120
|
+
const result = Promise.withResolvers<ComputedSignal<A>>();
|
|
121
|
+
const stream = SignalGlobal.computed(() => Async.abortable(fn));
|
|
122
|
+
const sig: StateSignal<Result<A, Error>> = SignalGlobal(Err(new Error()));
|
|
120
123
|
let job: Async.AbortableJob<A> | undefined = undefined;
|
|
121
124
|
let resolved = false;
|
|
122
125
|
const resolve = () => {
|
|
123
126
|
if (!resolved) {
|
|
124
127
|
resolved = true;
|
|
125
|
-
result.resolve(
|
|
128
|
+
result.resolve(SignalGlobal.computed(() => sig.get().unwrapExact(), options));
|
|
126
129
|
}
|
|
127
130
|
};
|
|
128
|
-
|
|
131
|
+
SignalGlobal.effect(() => {
|
|
129
132
|
if (job !== undefined) {
|
|
130
133
|
job.abort();
|
|
131
134
|
}
|
|
@@ -147,10 +150,15 @@ const AnySignal = Object.assign(
|
|
|
147
150
|
return result.promise;
|
|
148
151
|
},
|
|
149
152
|
|
|
150
|
-
State,
|
|
151
|
-
Computed,
|
|
153
|
+
State: StateSignal,
|
|
154
|
+
Computed: ComputedSignal,
|
|
152
155
|
subtle: Signal.subtle,
|
|
153
156
|
}
|
|
154
157
|
);
|
|
155
158
|
|
|
156
|
-
|
|
159
|
+
declare namespace SignalGlobal {
|
|
160
|
+
export type State<A> = StateSignal<A>;
|
|
161
|
+
export type Computed<A> = ComputedSignal<A>;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { SignalGlobal as Signal };
|
package/src/signal.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sleep } from "@bodil/core/async";
|
|
2
|
-
import { expect, test } from "vitest";
|
|
2
|
+
import { expect, expectTypeOf, test } from "vitest";
|
|
3
3
|
import { Signal } from ".";
|
|
4
4
|
|
|
5
5
|
test("Signal", async () => {
|
|
@@ -77,7 +77,7 @@ test("asyncComputed", async () => {
|
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
test("isSignal", () => {
|
|
80
|
-
const s1 = Signal(1);
|
|
80
|
+
const s1: Signal.State<number> = Signal(1);
|
|
81
81
|
expect(Signal.is(s1)).toBeTruthy();
|
|
82
82
|
expect(Signal.State.is(s1)).toBeTruthy();
|
|
83
83
|
expect(Signal.Computed.is(s1)).toBeFalsy();
|
|
@@ -89,3 +89,15 @@ test("isSignal", () => {
|
|
|
89
89
|
|
|
90
90
|
expect(Signal.is("wibble")).toBeFalsy();
|
|
91
91
|
});
|
|
92
|
+
|
|
93
|
+
test("Signal types", () => {
|
|
94
|
+
const s1: Signal.State<number> = Signal(1);
|
|
95
|
+
const s2: Signal.Computed<number> = Signal.computed(() => s1.get());
|
|
96
|
+
|
|
97
|
+
function foo(_signal: Signal<unknown>) {
|
|
98
|
+
// ensure Signal<A> is an accessible type
|
|
99
|
+
// and that it accepts both concrete signal types.
|
|
100
|
+
}
|
|
101
|
+
foo(s1);
|
|
102
|
+
foo(s2);
|
|
103
|
+
});
|