@bodil/signal 0.3.5 → 0.4.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/array.d.ts +144 -15
- package/dist/array.js +213 -53
- package/dist/array.js.map +1 -1
- package/dist/index.d.ts +1 -120
- package/dist/index.js +1 -197
- package/dist/index.js.map +1 -1
- package/dist/map.d.ts +130 -0
- package/dist/map.js +227 -0
- package/dist/map.js.map +1 -0
- package/dist/map.test.d.ts +1 -0
- package/dist/map.test.js +52 -0
- package/dist/map.test.js.map +1 -0
- package/dist/signal.d.ts +200 -0
- package/dist/signal.js +263 -0
- package/dist/signal.js.map +1 -0
- package/dist/signal.test.js +6 -6
- package/dist/signal.test.js.map +1 -1
- package/package.json +4 -1
- package/src/array.ts +233 -67
- package/src/index.ts +1 -265
- package/src/map.test.ts +62 -0
- package/src/map.ts +263 -0
- package/src/signal.test.ts +7 -7
- package/src/signal.ts +361 -0
package/dist/index.js
CHANGED
|
@@ -3,201 +3,5 @@
|
|
|
3
3
|
* Proposal](https://github.com/tc39/proposal-signals).
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import { toDisposable } from "@bodil/core/disposable";
|
|
8
|
-
import { Err, Ok } from "@bodil/opt";
|
|
9
|
-
import { Signal } from "signal-polyfill";
|
|
10
|
-
import { SignalArray } from "./array";
|
|
11
|
-
/**
|
|
12
|
-
* A writable state signal.
|
|
13
|
-
*/
|
|
14
|
-
class StateSignal extends Signal.State {
|
|
15
|
-
get value() {
|
|
16
|
-
return this.get();
|
|
17
|
-
}
|
|
18
|
-
set value(value) {
|
|
19
|
-
this.set(value);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Update the current value of this signal using a function.
|
|
23
|
-
*/
|
|
24
|
-
update(fn) {
|
|
25
|
-
this.set(Signal.subtle.untrack(() => fn(this.get())));
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Get a read only version of this signal.
|
|
29
|
-
*/
|
|
30
|
-
readOnly() {
|
|
31
|
-
return SignalGlobal.computed(() => this.get());
|
|
32
|
-
}
|
|
33
|
-
map(fn) {
|
|
34
|
-
return SignalGlobal.computed(() => fn(this.get()));
|
|
35
|
-
}
|
|
36
|
-
on(callback) {
|
|
37
|
-
return SignalGlobal.subscribe(this, callback);
|
|
38
|
-
}
|
|
39
|
-
static is(v) {
|
|
40
|
-
return v instanceof StateSignal;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* A read only signal computed from the values of other signals.
|
|
45
|
-
*/
|
|
46
|
-
class ComputedSignal extends Signal.Computed {
|
|
47
|
-
get value() {
|
|
48
|
-
return this.get();
|
|
49
|
-
}
|
|
50
|
-
map(fn) {
|
|
51
|
-
return SignalGlobal.computed(() => fn(this.get()));
|
|
52
|
-
}
|
|
53
|
-
on(callback) {
|
|
54
|
-
return SignalGlobal.subscribe(this, callback);
|
|
55
|
-
}
|
|
56
|
-
static is(v) {
|
|
57
|
-
return v instanceof ComputedSignal;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
let effectNeedsEnqueue = true;
|
|
61
|
-
const effectWatcher = new Signal.subtle.Watcher(() => {
|
|
62
|
-
if (effectNeedsEnqueue) {
|
|
63
|
-
effectNeedsEnqueue = false;
|
|
64
|
-
queueMicrotask(effectProcess);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
function effectProcess() {
|
|
68
|
-
effectNeedsEnqueue = true;
|
|
69
|
-
for (const sig of effectWatcher.getPending()) {
|
|
70
|
-
sig.get();
|
|
71
|
-
}
|
|
72
|
-
effectWatcher.watch();
|
|
73
|
-
}
|
|
74
|
-
const SignalGlobal = Object.assign(
|
|
75
|
-
/**
|
|
76
|
-
* Construct a new {@link Signal.State} signal containing the provided value.
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* const sig = Signal("Hello Joe!");
|
|
80
|
-
*/
|
|
81
|
-
function (value, options) {
|
|
82
|
-
return new SignalGlobal.State(value, options);
|
|
83
|
-
}, {
|
|
84
|
-
/**
|
|
85
|
-
* Test whether the given value is a signal.
|
|
86
|
-
*/
|
|
87
|
-
is(v) {
|
|
88
|
-
return SignalGlobal.State.is(v) || SignalGlobal.Computed.is(v);
|
|
89
|
-
},
|
|
90
|
-
/**
|
|
91
|
-
* Construct a new {@link Signal.Computed} signal using the provided
|
|
92
|
-
* computation function.
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* const sig1 = Signal(2);
|
|
96
|
-
* const sig2 = Signal(3);
|
|
97
|
-
* const sum = Signal.computed(() => sig1.get() + sig2.get());
|
|
98
|
-
* assert(sum.get() === 5);
|
|
99
|
-
*/
|
|
100
|
-
computed(fn, options) {
|
|
101
|
-
return new SignalGlobal.Computed(fn, options);
|
|
102
|
-
},
|
|
103
|
-
/**
|
|
104
|
-
* Suscribe to a signal.
|
|
105
|
-
*
|
|
106
|
-
* The provided callback will be called every time the value of the
|
|
107
|
-
* signal changes.
|
|
108
|
-
*/
|
|
109
|
-
subscribe(signal, callback) {
|
|
110
|
-
return SignalGlobal.effect(() => callback(signal.value));
|
|
111
|
-
},
|
|
112
|
-
/**
|
|
113
|
-
* Create an effect responding to signal changes.
|
|
114
|
-
*
|
|
115
|
-
* The provided function will be called immediately, and again every
|
|
116
|
-
* time a signal that was read by the function changes.
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* const sig = Signal("Hello Joe!");
|
|
120
|
-
* effect(() => console.log("Signal value is:", sig.get()));
|
|
121
|
-
* // prints "Signal value is: Hello Joe!"
|
|
122
|
-
* sig.set("Hello Mike!");
|
|
123
|
-
* // prints "Signal value is: Hello Mike!"
|
|
124
|
-
*/
|
|
125
|
-
effect(fn) {
|
|
126
|
-
let cleanup;
|
|
127
|
-
const computed = new SignalGlobal.Computed(() => {
|
|
128
|
-
if (cleanup !== undefined) {
|
|
129
|
-
cleanup[Symbol.dispose]();
|
|
130
|
-
}
|
|
131
|
-
const result = fn();
|
|
132
|
-
cleanup = result !== undefined ? toDisposable(result) : undefined;
|
|
133
|
-
});
|
|
134
|
-
effectWatcher.watch(computed);
|
|
135
|
-
computed.get();
|
|
136
|
-
return toDisposable(() => {
|
|
137
|
-
effectWatcher.unwatch(computed);
|
|
138
|
-
if (cleanup !== undefined) {
|
|
139
|
-
cleanup[Symbol.dispose]();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
},
|
|
143
|
-
/**
|
|
144
|
-
* Construct a new {@link Signal.Computed} signal using an async
|
|
145
|
-
* computation function.
|
|
146
|
-
*
|
|
147
|
-
* This returns a promise which will resolve to a
|
|
148
|
-
* {@link Signal.Computed} signal once the promise returned by the
|
|
149
|
-
* computation function resolves, and will update itself whenever
|
|
150
|
-
* subsequent calls to the computation function resolve.
|
|
151
|
-
*
|
|
152
|
-
* The function is provided with an {@link AbortSignal} which any async
|
|
153
|
-
* jobs started from it should abide by. If a signal dependency changes
|
|
154
|
-
* while the job is running, the {@link AbortSignal} will be triggered
|
|
155
|
-
* and the job restarted.
|
|
156
|
-
*/
|
|
157
|
-
asyncComputed(fn, options) {
|
|
158
|
-
const result = Promise.withResolvers();
|
|
159
|
-
const stream = SignalGlobal.computed(() => AbortablePromise.run((resolve, reject, abort) => {
|
|
160
|
-
try {
|
|
161
|
-
fn(abort).then(resolve, reject);
|
|
162
|
-
}
|
|
163
|
-
catch (e) {
|
|
164
|
-
reject(e);
|
|
165
|
-
}
|
|
166
|
-
}));
|
|
167
|
-
const sig = SignalGlobal(Err(new Error()));
|
|
168
|
-
let job = undefined;
|
|
169
|
-
let resolved = false;
|
|
170
|
-
const resolve = () => {
|
|
171
|
-
if (!resolved) {
|
|
172
|
-
resolved = true;
|
|
173
|
-
result.resolve(SignalGlobal.computed(() => sig.get().unwrapExact(), options));
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
SignalGlobal.effect(() => {
|
|
177
|
-
if (job !== undefined) {
|
|
178
|
-
job.abort();
|
|
179
|
-
}
|
|
180
|
-
job = stream.get();
|
|
181
|
-
job.then((next) => {
|
|
182
|
-
sig.set(Ok(next));
|
|
183
|
-
resolve();
|
|
184
|
-
}, (error) => {
|
|
185
|
-
if (job?.signal.aborted === true) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
sig.set(Err(error));
|
|
189
|
-
resolve();
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
return result.promise;
|
|
193
|
-
},
|
|
194
|
-
array(values) {
|
|
195
|
-
return SignalArray.from(values);
|
|
196
|
-
},
|
|
197
|
-
State: StateSignal,
|
|
198
|
-
Computed: ComputedSignal,
|
|
199
|
-
Array: SignalArray,
|
|
200
|
-
subtle: Signal.subtle,
|
|
201
|
-
});
|
|
202
|
-
export { SignalGlobal as Signal };
|
|
6
|
+
export * as Signal from "./signal";
|
|
203
7
|
//# 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;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC"}
|
package/dist/map.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { Equals } from "@bodil/core/types";
|
|
2
|
+
import { type Option } from "@bodil/opt";
|
|
3
|
+
import * as Signal from "./signal";
|
|
4
|
+
declare const instance: unique symbol;
|
|
5
|
+
type InstanceProps<K, V> = {
|
|
6
|
+
map: Map<K, V>;
|
|
7
|
+
signal: Signal.State<null>;
|
|
8
|
+
signals: Map<K, WeakRef<Signal.State<Option<V>>>>;
|
|
9
|
+
readonlySignals: WeakMap<Signal.State<Option<V>>, Signal.Computed<Option<V>>>;
|
|
10
|
+
registry: FinalizationRegistry<K>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A read-only view of a {@link Signal.Map}.
|
|
14
|
+
*
|
|
15
|
+
* This acts just like the {@link Signal.Map} it was created from, mirroring
|
|
16
|
+
* the current contents of the source map, but without the ability to modify
|
|
17
|
+
* it.
|
|
18
|
+
*/
|
|
19
|
+
export declare class ReadonlySignalMap<K, V> implements Iterable<[K, V]>, Equals {
|
|
20
|
+
/** @ignore */
|
|
21
|
+
protected readonly [instance]: InstanceProps<K, V>;
|
|
22
|
+
/** @ignore */
|
|
23
|
+
protected constructor(instanceProps: InstanceProps<K, V>);
|
|
24
|
+
/**
|
|
25
|
+
* Test whether a value is a `Signal.ReadonlyMap`.
|
|
26
|
+
*/
|
|
27
|
+
static is(value: unknown): value is ReadonlySignalMap<unknown, unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* Obtain a {@link Signal.Computed} representing the current value of the
|
|
30
|
+
* given key in the map. The signal will update when the value changes, and
|
|
31
|
+
* will not respond to changes to any other elements of the map.
|
|
32
|
+
*/
|
|
33
|
+
signal(key: K): Signal.Computed<Option<V>>;
|
|
34
|
+
/**
|
|
35
|
+
* Get the value associated with the given key in the map.
|
|
36
|
+
*/
|
|
37
|
+
get(key: K): Option<V>;
|
|
38
|
+
/**
|
|
39
|
+
* Test whether the given key is defined in the map.
|
|
40
|
+
*/
|
|
41
|
+
has(key: K): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Get the size of the map.
|
|
44
|
+
*/
|
|
45
|
+
size(): number;
|
|
46
|
+
/**
|
|
47
|
+
* Test whether the map is empty.
|
|
48
|
+
*/
|
|
49
|
+
isEmpty(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Iterate over the key/value pairs the map contains.
|
|
52
|
+
*/
|
|
53
|
+
entries(): MapIterator<[K, V]>;
|
|
54
|
+
/**
|
|
55
|
+
* Iterate over the keys the map contains.
|
|
56
|
+
*/
|
|
57
|
+
keys(): MapIterator<K>;
|
|
58
|
+
/**
|
|
59
|
+
* Iterate over the values associated with every key in the map.
|
|
60
|
+
*/
|
|
61
|
+
values(): MapIterator<V>;
|
|
62
|
+
/**
|
|
63
|
+
* Test whether a given value is a `Signal.Map` with identical contents to
|
|
64
|
+
* this map.
|
|
65
|
+
*/
|
|
66
|
+
equals(other: unknown): other is ReadonlySignalMap<K, V>;
|
|
67
|
+
/**
|
|
68
|
+
* Iterate over the key/value pairs the map contains.
|
|
69
|
+
*/
|
|
70
|
+
[Symbol.iterator](): MapIterator<[K, V]>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A map which behaves like a signal.
|
|
74
|
+
*
|
|
75
|
+
* Any read operation on the map, like {@link Signal.Map.get},
|
|
76
|
+
* {@link Signal.Map.size}, or iteration, acts like a
|
|
77
|
+
* {@link Signal.State.get}, registering the map as a dependency in any
|
|
78
|
+
* computed signals or effects it's used in. Correspondingly, any write
|
|
79
|
+
* operation to the map will cause all of these dependencies to update as
|
|
80
|
+
* with a {@link Signal.State.set}.
|
|
81
|
+
*
|
|
82
|
+
* Note that there's no granularity to this access by default: if you read only
|
|
83
|
+
* a single key from the map inside a computed signal, *any* write to the map,
|
|
84
|
+
* even to a different key, causes the signal to recompute. If you want
|
|
85
|
+
* granularity (and you normally do), use {@link Signal.Map.signal} instead of
|
|
86
|
+
* {@link Signal.Map.get}.
|
|
87
|
+
*/
|
|
88
|
+
export declare class SignalMap<K, V> extends ReadonlySignalMap<K, V> {
|
|
89
|
+
/**
|
|
90
|
+
* Test whether a value is a `Signal.Map`.
|
|
91
|
+
*/
|
|
92
|
+
static is(value: unknown): value is SignalMap<unknown, unknown>;
|
|
93
|
+
/**
|
|
94
|
+
* Construct a new map, optionally populating it with the provided key/value
|
|
95
|
+
* pairs.
|
|
96
|
+
*/
|
|
97
|
+
constructor(entries?: Iterable<readonly [K, V]>);
|
|
98
|
+
/**
|
|
99
|
+
* Discard every key/value pair defined in the map, leaving an empty map.
|
|
100
|
+
*/
|
|
101
|
+
clear(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Remove the given key from the map, returning its associated value. If the
|
|
104
|
+
* key isn't defined in the map, return {@link None}.
|
|
105
|
+
*/
|
|
106
|
+
remove(key: K): Option<V>;
|
|
107
|
+
/**
|
|
108
|
+
* Add the given key/value pair to the map, overwriting any previous
|
|
109
|
+
* definitions of the same key.
|
|
110
|
+
*/
|
|
111
|
+
set(key: K, value: V): this;
|
|
112
|
+
/**
|
|
113
|
+
* Get the value associated with the given key, or, if the key doesn't
|
|
114
|
+
* already exist, call the provided function to create a new value and
|
|
115
|
+
* insert it into the map under the given key.
|
|
116
|
+
*/
|
|
117
|
+
getOrSet(key: K, defaultFn: (this: SignalMap<K, V>) => V): V;
|
|
118
|
+
/**
|
|
119
|
+
* Get a signal reflecting the value at the given key, as in
|
|
120
|
+
* {@link Signal.Map.signal}, except that if the key isn't defined,
|
|
121
|
+
* initialise it with the value produced by calling `defaultFn` first, as in
|
|
122
|
+
* {@link Signal.Map.getOrSet}.
|
|
123
|
+
*/
|
|
124
|
+
signalOrSet(key: K, defaultFn: (this: SignalMap<K, V>) => V): Signal.Computed<Option<V>>;
|
|
125
|
+
/**
|
|
126
|
+
* Return a read-only view of the map.
|
|
127
|
+
*/
|
|
128
|
+
readOnly(): ReadonlySignalMap<K, V>;
|
|
129
|
+
}
|
|
130
|
+
export {};
|
package/dist/map.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { present } from "@bodil/core/assert";
|
|
2
|
+
import { None, Some } from "@bodil/opt";
|
|
3
|
+
import * as Signal from "./signal";
|
|
4
|
+
const instance = Symbol("Signal.Map");
|
|
5
|
+
/**
|
|
6
|
+
* A read-only view of a {@link Signal.Map}.
|
|
7
|
+
*
|
|
8
|
+
* This acts just like the {@link Signal.Map} it was created from, mirroring
|
|
9
|
+
* the current contents of the source map, but without the ability to modify
|
|
10
|
+
* it.
|
|
11
|
+
*/
|
|
12
|
+
export class ReadonlySignalMap {
|
|
13
|
+
/** @ignore */
|
|
14
|
+
constructor(instanceProps) {
|
|
15
|
+
this[instance] = instanceProps;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Test whether a value is a `Signal.ReadonlyMap`.
|
|
19
|
+
*/
|
|
20
|
+
static is(value) {
|
|
21
|
+
return value instanceof ReadonlySignalMap;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Obtain a {@link Signal.Computed} representing the current value of the
|
|
25
|
+
* given key in the map. The signal will update when the value changes, and
|
|
26
|
+
* will not respond to changes to any other elements of the map.
|
|
27
|
+
*/
|
|
28
|
+
signal(key) {
|
|
29
|
+
const self = this[instance];
|
|
30
|
+
const active = self.signals.get(key)?.deref();
|
|
31
|
+
if (active !== undefined) {
|
|
32
|
+
return present(self.readonlySignals.get(active), "Signal.Map.signal(): unexpected absence of readonly signal for a signal which still exists");
|
|
33
|
+
}
|
|
34
|
+
const sig = new Signal.State(self.map.has(key) ? Some(self.map.get(key)) : None);
|
|
35
|
+
self.registry.register(sig, key);
|
|
36
|
+
self.signals.set(key, new WeakRef(sig));
|
|
37
|
+
const roSig = sig.readOnly();
|
|
38
|
+
self.readonlySignals.set(sig, roSig);
|
|
39
|
+
return roSig;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get the value associated with the given key in the map.
|
|
43
|
+
*/
|
|
44
|
+
get(key) {
|
|
45
|
+
return this.has(key) ? Some(this[instance].map.get(key)) : None;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Test whether the given key is defined in the map.
|
|
49
|
+
*/
|
|
50
|
+
has(key) {
|
|
51
|
+
const self = this[instance];
|
|
52
|
+
self.signal.get();
|
|
53
|
+
return self.map.has(key);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the size of the map.
|
|
57
|
+
*/
|
|
58
|
+
size() {
|
|
59
|
+
const self = this[instance];
|
|
60
|
+
self.signal.get();
|
|
61
|
+
return self.map.size;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Test whether the map is empty.
|
|
65
|
+
*/
|
|
66
|
+
isEmpty() {
|
|
67
|
+
return this.size() === 0;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Iterate over the key/value pairs the map contains.
|
|
71
|
+
*/
|
|
72
|
+
entries() {
|
|
73
|
+
const self = this[instance];
|
|
74
|
+
self.signal.get();
|
|
75
|
+
return self.map.entries();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Iterate over the keys the map contains.
|
|
79
|
+
*/
|
|
80
|
+
keys() {
|
|
81
|
+
const self = this[instance];
|
|
82
|
+
self.signal.get();
|
|
83
|
+
return self.map.keys();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Iterate over the values associated with every key in the map.
|
|
87
|
+
*/
|
|
88
|
+
values() {
|
|
89
|
+
const self = this[instance];
|
|
90
|
+
self.signal.get();
|
|
91
|
+
return self.map.values();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Test whether a given value is a `Signal.Map` with identical contents to
|
|
95
|
+
* this map.
|
|
96
|
+
*/
|
|
97
|
+
equals(other) {
|
|
98
|
+
if (!ReadonlySignalMap.is(other) || this.size() !== other.size()) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
for (const [key, value] of this) {
|
|
102
|
+
const otherValue = other.get(key);
|
|
103
|
+
if (otherValue.isNone() || !Object.is(value, otherValue.value)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Iterate over the key/value pairs the map contains.
|
|
111
|
+
*/
|
|
112
|
+
[Symbol.iterator]() {
|
|
113
|
+
const self = this[instance];
|
|
114
|
+
self.signal.get();
|
|
115
|
+
return self.map[Symbol.iterator]();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A map which behaves like a signal.
|
|
120
|
+
*
|
|
121
|
+
* Any read operation on the map, like {@link Signal.Map.get},
|
|
122
|
+
* {@link Signal.Map.size}, or iteration, acts like a
|
|
123
|
+
* {@link Signal.State.get}, registering the map as a dependency in any
|
|
124
|
+
* computed signals or effects it's used in. Correspondingly, any write
|
|
125
|
+
* operation to the map will cause all of these dependencies to update as
|
|
126
|
+
* with a {@link Signal.State.set}.
|
|
127
|
+
*
|
|
128
|
+
* Note that there's no granularity to this access by default: if you read only
|
|
129
|
+
* a single key from the map inside a computed signal, *any* write to the map,
|
|
130
|
+
* even to a different key, causes the signal to recompute. If you want
|
|
131
|
+
* granularity (and you normally do), use {@link Signal.Map.signal} instead of
|
|
132
|
+
* {@link Signal.Map.get}.
|
|
133
|
+
*/
|
|
134
|
+
export class SignalMap extends ReadonlySignalMap {
|
|
135
|
+
/**
|
|
136
|
+
* Test whether a value is a `Signal.Map`.
|
|
137
|
+
*/
|
|
138
|
+
static is(value) {
|
|
139
|
+
return value instanceof SignalMap;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Construct a new map, optionally populating it with the provided key/value
|
|
143
|
+
* pairs.
|
|
144
|
+
*/
|
|
145
|
+
constructor(entries = []) {
|
|
146
|
+
const signals = new Map();
|
|
147
|
+
super({
|
|
148
|
+
map: new Map(entries),
|
|
149
|
+
signal: new Signal.State(null, { equals: () => false }),
|
|
150
|
+
signals,
|
|
151
|
+
readonlySignals: new WeakMap(),
|
|
152
|
+
registry: new FinalizationRegistry((key) => signals.delete(key)),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Discard every key/value pair defined in the map, leaving an empty map.
|
|
157
|
+
*/
|
|
158
|
+
clear() {
|
|
159
|
+
const self = this[instance];
|
|
160
|
+
self.map.clear();
|
|
161
|
+
self.signals.forEach((sig) => sig.deref()?.set(None));
|
|
162
|
+
self.signal.set(null);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Remove the given key from the map, returning its associated value. If the
|
|
166
|
+
* key isn't defined in the map, return {@link None}.
|
|
167
|
+
*/
|
|
168
|
+
remove(key) {
|
|
169
|
+
const self = this[instance];
|
|
170
|
+
if (!self.map.has(key)) {
|
|
171
|
+
return None;
|
|
172
|
+
}
|
|
173
|
+
const result = Some(self.map.get(key));
|
|
174
|
+
self.map.delete(key);
|
|
175
|
+
self.signals.get(key)?.deref()?.set(None);
|
|
176
|
+
self.signal.set(null);
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Add the given key/value pair to the map, overwriting any previous
|
|
181
|
+
* definitions of the same key.
|
|
182
|
+
*/
|
|
183
|
+
set(key, value) {
|
|
184
|
+
const self = this[instance];
|
|
185
|
+
self.map.set(key, value);
|
|
186
|
+
self.signals.get(key)?.deref()?.set(Some(value));
|
|
187
|
+
self.signal.set(null);
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get the value associated with the given key, or, if the key doesn't
|
|
192
|
+
* already exist, call the provided function to create a new value and
|
|
193
|
+
* insert it into the map under the given key.
|
|
194
|
+
*/
|
|
195
|
+
getOrSet(key, defaultFn) {
|
|
196
|
+
const self = this[instance];
|
|
197
|
+
self.signal.get();
|
|
198
|
+
if (self.map.has(key)) {
|
|
199
|
+
return self.map.get(key);
|
|
200
|
+
}
|
|
201
|
+
const value = defaultFn.call(this);
|
|
202
|
+
self.map.set(key, value);
|
|
203
|
+
self.signal.set(null);
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get a signal reflecting the value at the given key, as in
|
|
208
|
+
* {@link Signal.Map.signal}, except that if the key isn't defined,
|
|
209
|
+
* initialise it with the value produced by calling `defaultFn` first, as in
|
|
210
|
+
* {@link Signal.Map.getOrSet}.
|
|
211
|
+
*/
|
|
212
|
+
signalOrSet(key, defaultFn) {
|
|
213
|
+
const self = this[instance];
|
|
214
|
+
if (!self.map.has(key)) {
|
|
215
|
+
self.map.set(key, defaultFn.call(this));
|
|
216
|
+
self.signal.set(null);
|
|
217
|
+
}
|
|
218
|
+
return this.signal(key);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Return a read-only view of the map.
|
|
222
|
+
*/
|
|
223
|
+
readOnly() {
|
|
224
|
+
return new ReadonlySignalMap(this[instance]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=map.js.map
|
package/dist/map.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../src/map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/map.test.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { None, Some } from "@bodil/opt";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
import { Signal } from ".";
|
|
4
|
+
test("SignalMap", () => {
|
|
5
|
+
const map = Signal.map([
|
|
6
|
+
["Joe", "Armstrong"],
|
|
7
|
+
["Mike", "Williams"],
|
|
8
|
+
["Robert", "Virding"],
|
|
9
|
+
]);
|
|
10
|
+
expect(map.entries().toArray()).toEqual([
|
|
11
|
+
["Joe", "Armstrong"],
|
|
12
|
+
["Mike", "Williams"],
|
|
13
|
+
["Robert", "Virding"],
|
|
14
|
+
]);
|
|
15
|
+
const mike = map.signal("Mike");
|
|
16
|
+
expect(mike.get()).toEqual(Some("Williams"));
|
|
17
|
+
const bjarne = map.signal("Bjarne");
|
|
18
|
+
expect(bjarne.get()).toEqual(None);
|
|
19
|
+
const size = Signal.computed(() => map.size());
|
|
20
|
+
expect(map.size()).toBe(3);
|
|
21
|
+
expect(size.get()).toBe(3);
|
|
22
|
+
expect(mike.get()).toEqual(Some("Williams"));
|
|
23
|
+
expect(bjarne.get()).toEqual(None);
|
|
24
|
+
map.set("Bjarne", "Däcker");
|
|
25
|
+
expect(map.size()).toBe(4);
|
|
26
|
+
expect(size.get()).toBe(4);
|
|
27
|
+
expect(mike.get()).toEqual(Some("Williams"));
|
|
28
|
+
expect(bjarne.get()).toEqual(Some("Däcker"));
|
|
29
|
+
expect(map.entries().toArray()).toEqual([
|
|
30
|
+
["Joe", "Armstrong"],
|
|
31
|
+
["Mike", "Williams"],
|
|
32
|
+
["Robert", "Virding"],
|
|
33
|
+
["Bjarne", "Däcker"],
|
|
34
|
+
]);
|
|
35
|
+
expect(map.remove("Mike")).toEqual(Some("Williams"));
|
|
36
|
+
expect(map.size()).toBe(3);
|
|
37
|
+
expect(size.get()).toBe(3);
|
|
38
|
+
expect(mike.get()).toEqual(None);
|
|
39
|
+
expect(bjarne.get()).toEqual(Some("Däcker"));
|
|
40
|
+
expect(map.entries().toArray()).toEqual([
|
|
41
|
+
["Joe", "Armstrong"],
|
|
42
|
+
["Robert", "Virding"],
|
|
43
|
+
["Bjarne", "Däcker"],
|
|
44
|
+
]);
|
|
45
|
+
map.clear();
|
|
46
|
+
expect(map.size()).toBe(0);
|
|
47
|
+
expect(size.get()).toBe(0);
|
|
48
|
+
expect(mike.get()).toEqual(None);
|
|
49
|
+
expect(bjarne.get()).toEqual(None);
|
|
50
|
+
expect(map.entries().toArray()).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=map.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.test.js","sourceRoot":"","sources":["../src/map.test.ts"],"names":[],"mappings":"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"}
|