@e280/strata 0.2.0-0 → 0.2.0-10
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 +95 -37
- package/package.json +4 -4
- package/s/signals/core/derived.ts +65 -0
- package/s/signals/{effect.ts → core/effect.ts} +1 -1
- package/s/signals/{lazy.ts → core/lazy.ts} +34 -3
- package/s/signals/{parts → core/parts}/readable.ts +1 -1
- package/s/signals/core/signal.ts +97 -0
- package/s/signals/index.ts +11 -8
- package/s/signals/porcelain.ts +30 -0
- package/s/signals/r/map.ts +63 -0
- package/s/signals/r/set.ts +43 -0
- package/s/signals/signals.test.ts +10 -264
- package/s/signals/tests/derived.test.ts +111 -0
- package/s/signals/tests/effect.test.ts +89 -0
- package/s/signals/tests/lazy.test.ts +64 -0
- package/s/signals/tests/signal.test.ts +115 -0
- package/s/signals/types.ts +23 -4
- package/s/tests.test.ts +2 -2
- package/s/tree/parts/branch.ts +4 -4
- package/s/tree/parts/trunk.ts +5 -5
- package/s/tree/tree.test.ts +1 -1
- package/x/signals/core/derived.d.ts +10 -0
- package/x/signals/core/derived.js +52 -0
- package/x/signals/core/derived.js.map +1 -0
- package/x/signals/{effect.js → core/effect.js} +1 -1
- package/x/signals/core/effect.js.map +1 -0
- package/x/signals/{lazy.d.ts → core/lazy.d.ts} +4 -1
- package/x/signals/{lazy.js → core/lazy.js} +25 -2
- package/x/signals/core/lazy.js.map +1 -0
- package/x/signals/core/parts/reactive.js.map +1 -0
- package/x/signals/{parts → core/parts}/readable.js +1 -1
- package/x/signals/core/parts/readable.js.map +1 -0
- package/x/signals/{signal.d.ts → core/signal.d.ts} +5 -2
- package/x/signals/core/signal.js +76 -0
- package/x/signals/core/signal.js.map +1 -0
- package/x/signals/index.d.ts +9 -7
- package/x/signals/index.js +9 -7
- package/x/signals/index.js.map +1 -1
- package/x/signals/porcelain.d.ts +8 -0
- package/x/signals/porcelain.js +15 -0
- package/x/signals/porcelain.js.map +1 -0
- package/x/signals/r/map.d.ts +14 -0
- package/x/signals/r/map.js +52 -0
- package/x/signals/r/map.js.map +1 -0
- package/x/signals/r/set.d.ts +10 -0
- package/x/signals/r/set.js +36 -0
- package/x/signals/r/set.js.map +1 -0
- package/x/signals/signals.test.d.ts +42 -19
- package/x/signals/signals.test.js +9 -217
- package/x/signals/signals.test.js.map +1 -1
- package/x/signals/tests/derived.test.d.ts +12 -0
- package/x/signals/tests/derived.test.js +91 -0
- package/x/signals/tests/derived.test.js.map +1 -0
- package/x/signals/tests/effect.test.d.ts +10 -0
- package/x/signals/tests/effect.test.js +72 -0
- package/x/signals/tests/effect.test.js.map +1 -0
- package/x/signals/tests/lazy.test.d.ts +10 -0
- package/x/signals/tests/lazy.test.js +51 -0
- package/x/signals/tests/lazy.test.js.map +1 -0
- package/x/signals/tests/signal.test.d.ts +18 -0
- package/x/signals/tests/signal.test.js +94 -0
- package/x/signals/tests/signal.test.js.map +1 -0
- package/x/signals/types.d.ts +19 -4
- package/x/tests.test.js +2 -2
- package/x/tests.test.js.map +1 -1
- package/x/tree/parts/branch.js +2 -2
- package/x/tree/parts/branch.js.map +1 -1
- package/x/tree/parts/trunk.js +2 -2
- package/x/tree/parts/trunk.js.map +1 -1
- package/x/tree/tree.test.js +1 -1
- package/x/tree/tree.test.js.map +1 -1
- package/s/signals/derive.ts +0 -37
- package/s/signals/fns.ts +0 -30
- package/s/signals/signal.ts +0 -50
- package/x/signals/derive.d.ts +0 -8
- package/x/signals/derive.js +0 -31
- package/x/signals/derive.js.map +0 -1
- package/x/signals/effect.js.map +0 -1
- package/x/signals/fns.d.ts +0 -11
- package/x/signals/fns.js +0 -15
- package/x/signals/fns.js.map +0 -1
- package/x/signals/lazy.js.map +0 -1
- package/x/signals/parts/reactive.js.map +0 -1
- package/x/signals/parts/readable.js.map +0 -1
- package/x/signals/signal.js +0 -42
- package/x/signals/signal.js.map +0 -1
- /package/s/signals/{parts → core/parts}/reactive.ts +0 -0
- /package/x/signals/{effect.d.ts → core/effect.d.ts} +0 -0
- /package/x/signals/{parts → core/parts}/reactive.d.ts +0 -0
- /package/x/signals/{parts → core/parts}/reactive.js +0 -0
- /package/x/signals/{parts → core/parts}/readable.d.ts +0 -0
|
@@ -1,269 +1,15 @@
|
|
|
1
1
|
|
|
2
|
-
import {Science
|
|
3
|
-
import {effect} from "./effect.js"
|
|
4
|
-
import {derive, lazy, signal} from "./fns.js"
|
|
2
|
+
import {Science} from "@e280/science"
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
count.value++
|
|
12
|
-
expect(count.value).is(1)
|
|
13
|
-
|
|
14
|
-
count.value = 5
|
|
15
|
-
expect(count.value).is(5)
|
|
16
|
-
}),
|
|
17
|
-
|
|
18
|
-
"signal set and publish returns value": test(async() => {
|
|
19
|
-
const count = signal(0)
|
|
20
|
-
expect(count.value).is(0)
|
|
21
|
-
expect(await count.set(1)).is(1)
|
|
22
|
-
expect(await count.publish(2)).is(2)
|
|
23
|
-
}),
|
|
24
|
-
|
|
25
|
-
"signal syntax interop": test(async() => {
|
|
26
|
-
const count = signal(0)
|
|
27
|
-
count.value = 1
|
|
28
|
-
expect(count.get()).is(1)
|
|
29
|
-
}),
|
|
30
|
-
|
|
31
|
-
"signal on is not debounced": test(async() => {
|
|
32
|
-
const count = signal(1)
|
|
33
|
-
let runs = 0
|
|
34
|
-
count.on(() => void runs++)
|
|
35
|
-
await count.set(2)
|
|
36
|
-
await count.set(3)
|
|
37
|
-
expect(runs).is(2)
|
|
38
|
-
}),
|
|
39
|
-
|
|
40
|
-
"signal on only fires on change": test(async() => {
|
|
41
|
-
const count = signal(1)
|
|
42
|
-
let runs = 0
|
|
43
|
-
count.on(() => void runs++)
|
|
44
|
-
await count.set(2)
|
|
45
|
-
await count.set(2)
|
|
46
|
-
expect(runs).is(1)
|
|
47
|
-
}),
|
|
48
|
-
|
|
49
|
-
"signal on circularity forbidden": test(async() => {
|
|
50
|
-
const count = signal(1)
|
|
51
|
-
let runs = 0
|
|
52
|
-
count.on(async() => {
|
|
53
|
-
await count.set(99)
|
|
54
|
-
runs++
|
|
55
|
-
})
|
|
56
|
-
expect(async() => {
|
|
57
|
-
await count.set(2)
|
|
58
|
-
}).throwsAsync()
|
|
59
|
-
expect(runs).is(0)
|
|
60
|
-
}),
|
|
61
|
-
|
|
62
|
-
"effect tracks signal changes": test(async() => {
|
|
63
|
-
const count = signal(1)
|
|
64
|
-
let doubled = 0
|
|
65
|
-
|
|
66
|
-
effect(() => doubled = count.value * 2)
|
|
67
|
-
expect(doubled).is(2)
|
|
68
|
-
|
|
69
|
-
await count.set(3)
|
|
70
|
-
expect(doubled).is(6)
|
|
71
|
-
}),
|
|
72
|
-
|
|
73
|
-
"effect is only called when signal actually changes": test(async() => {
|
|
74
|
-
const count = signal(1)
|
|
75
|
-
let runs = 0
|
|
76
|
-
effect(() => {
|
|
77
|
-
count.get()
|
|
78
|
-
runs++
|
|
79
|
-
})
|
|
80
|
-
expect(runs).is(1)
|
|
81
|
-
await count.set(999)
|
|
82
|
-
expect(runs).is(2)
|
|
83
|
-
await count.set(999)
|
|
84
|
-
expect(runs).is(2)
|
|
85
|
-
}),
|
|
86
|
-
|
|
87
|
-
"effects are debounced": test(async() => {
|
|
88
|
-
const count = signal(1)
|
|
89
|
-
let runs = 0
|
|
90
|
-
effect(() => {
|
|
91
|
-
count.get()
|
|
92
|
-
runs++
|
|
93
|
-
})
|
|
94
|
-
expect(runs).is(1)
|
|
95
|
-
count.value++
|
|
96
|
-
count.value++
|
|
97
|
-
await count.set(count.get() + 1)
|
|
98
|
-
expect(runs).is(2)
|
|
99
|
-
}),
|
|
100
|
-
|
|
101
|
-
"effects can be disposed": test(async() => {
|
|
102
|
-
const count = signal(1)
|
|
103
|
-
let doubled = 0
|
|
104
|
-
|
|
105
|
-
const dispose = effect(() => doubled = count.value * 2)
|
|
106
|
-
expect(doubled).is(2)
|
|
107
|
-
|
|
108
|
-
await count.set(3)
|
|
109
|
-
expect(doubled).is(6)
|
|
110
|
-
|
|
111
|
-
dispose()
|
|
112
|
-
await count.set(4)
|
|
113
|
-
expect(doubled).is(6) // old value
|
|
114
|
-
}),
|
|
115
|
-
|
|
116
|
-
"signal set promise waits for effects": test(async() => {
|
|
117
|
-
const count = signal(1)
|
|
118
|
-
let doubled = 0
|
|
119
|
-
|
|
120
|
-
effect(() => doubled = count.value * 2)
|
|
121
|
-
expect(doubled).is(2)
|
|
122
|
-
|
|
123
|
-
await count.set(3)
|
|
124
|
-
expect(doubled).is(6)
|
|
125
|
-
}),
|
|
126
|
-
|
|
127
|
-
"effect only runs on change": test(async() => {
|
|
128
|
-
const sig = signal("a")
|
|
129
|
-
let runs = 0
|
|
130
|
-
|
|
131
|
-
effect(() => {
|
|
132
|
-
sig.value
|
|
133
|
-
runs++
|
|
134
|
-
})
|
|
135
|
-
expect(runs).is(1)
|
|
136
|
-
|
|
137
|
-
await sig.set("a")
|
|
138
|
-
expect(runs).is(1)
|
|
139
|
-
|
|
140
|
-
await sig.set("b")
|
|
141
|
-
expect(runs).is(2)
|
|
142
|
-
}),
|
|
4
|
+
import effectTest from "./tests/effect.test.js"
|
|
5
|
+
import signalTest from "./tests/signal.test.js"
|
|
6
|
+
import derivedTest from "./tests/derived.test.js"
|
|
7
|
+
import lazyTest from "./tests/lazy.test.js"
|
|
143
8
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
await a.set(5)
|
|
151
|
-
expect(sum.value).is(8)
|
|
152
|
-
|
|
153
|
-
await b.set(7)
|
|
154
|
-
expect(sum.value).is(12)
|
|
155
|
-
}),
|
|
156
|
-
|
|
157
|
-
"effect reacts to derived changes": test(async() => {
|
|
158
|
-
const a = signal(1)
|
|
159
|
-
const b = signal(10)
|
|
160
|
-
const product = derive(() => a.value * b.value)
|
|
161
|
-
|
|
162
|
-
let mutations = 0
|
|
163
|
-
effect(() => {
|
|
164
|
-
void product.get()
|
|
165
|
-
mutations++
|
|
166
|
-
})
|
|
167
|
-
expect(product.value).is(10)
|
|
168
|
-
expect(mutations).is(1)
|
|
169
|
-
|
|
170
|
-
await a.set(2)
|
|
171
|
-
expect(product.value).is(20)
|
|
172
|
-
expect(mutations).is(2)
|
|
173
|
-
|
|
174
|
-
await a.set(3)
|
|
175
|
-
expect(product.value).is(30)
|
|
176
|
-
expect(mutations).is(3)
|
|
177
|
-
}),
|
|
178
|
-
|
|
179
|
-
"effect doesn't overreact to derived": test(async() => {
|
|
180
|
-
const a = signal(1)
|
|
181
|
-
const b = signal(10)
|
|
182
|
-
const product = signal.derive(() => a.value * b.value)
|
|
183
|
-
|
|
184
|
-
const derivedSpy = spy(() => {})
|
|
185
|
-
product.on(derivedSpy)
|
|
186
|
-
|
|
187
|
-
let mutations = 0
|
|
188
|
-
effect(() => {
|
|
189
|
-
a.get()
|
|
190
|
-
product.get()
|
|
191
|
-
mutations++
|
|
192
|
-
})
|
|
193
|
-
expect(product.value).is(10)
|
|
194
|
-
expect(mutations).is(1)
|
|
195
|
-
expect(derivedSpy.spy.calls.length).is(0)
|
|
196
|
-
|
|
197
|
-
await a.set(2)
|
|
198
|
-
expect(product.value).is(20)
|
|
199
|
-
expect(mutations).is(2)
|
|
200
|
-
expect(derivedSpy.spy.calls.length).is(1)
|
|
201
|
-
}),
|
|
202
|
-
|
|
203
|
-
"derived.on": test(async() => {
|
|
204
|
-
const a = signal(1)
|
|
205
|
-
const b = signal(10)
|
|
206
|
-
const product = signal.derive(() => a.value * b.value)
|
|
207
|
-
expect(product.value).is(10)
|
|
208
|
-
|
|
209
|
-
const mole = spy((_v: number) => {})
|
|
210
|
-
product.on(mole)
|
|
211
|
-
expect(mole.spy.calls.length).is(0)
|
|
212
|
-
|
|
213
|
-
await a.set(2)
|
|
214
|
-
expect(product.value).is(20)
|
|
215
|
-
expect(mole.spy.calls.length).is(1)
|
|
216
|
-
expect(mole.spy.calls[0].args[0]).is(20)
|
|
217
|
-
}),
|
|
218
|
-
|
|
219
|
-
"derived.on not called if result doesn't change": test(async() => {
|
|
220
|
-
const a = signal(1)
|
|
221
|
-
const b = signal(10)
|
|
222
|
-
const product = signal.derive(() => a.value * b.value)
|
|
223
|
-
expect(product.value).is(10)
|
|
224
|
-
|
|
225
|
-
const mole = spy((_v: number) => {})
|
|
226
|
-
product.on(mole)
|
|
227
|
-
expect(mole.spy.calls.length).is(0)
|
|
228
|
-
|
|
229
|
-
await a.set(2)
|
|
230
|
-
expect(product.value).is(20)
|
|
231
|
-
expect(mole.spy.calls.length).is(1)
|
|
232
|
-
expect(mole.spy.calls[0].args[0]).is(20)
|
|
233
|
-
|
|
234
|
-
await a.set(2)
|
|
235
|
-
expect(product.value).is(20)
|
|
236
|
-
expect(mole.spy.calls.length).is(1)
|
|
237
|
-
}),
|
|
238
|
-
|
|
239
|
-
"lazy is lazy": test(async() => {
|
|
240
|
-
const a = signal(1)
|
|
241
|
-
let runs = 0
|
|
242
|
-
|
|
243
|
-
const comp = lazy(() => {
|
|
244
|
-
runs++
|
|
245
|
-
return a.value * 10
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
expect(runs).is(0)
|
|
249
|
-
expect(comp.value).is(10)
|
|
250
|
-
expect(runs).is(1)
|
|
251
|
-
|
|
252
|
-
await a.set(2)
|
|
253
|
-
expect(runs).is(1)
|
|
254
|
-
expect(comp.value).is(20)
|
|
255
|
-
expect(runs).is(2)
|
|
256
|
-
}),
|
|
257
|
-
|
|
258
|
-
"lazy syntax": test(async() => {
|
|
259
|
-
const a = signal(2)
|
|
260
|
-
const b = signal(3)
|
|
261
|
-
const sum = lazy(() => a.value + b.value)
|
|
262
|
-
expect(sum.value).is(5)
|
|
263
|
-
|
|
264
|
-
await a.set(5)
|
|
265
|
-
expect(sum.value).is(8)
|
|
266
|
-
expect(sum.get()).is(8)
|
|
267
|
-
}),
|
|
9
|
+
export default Science.suite({
|
|
10
|
+
"effect": effectTest,
|
|
11
|
+
"signal": signalTest,
|
|
12
|
+
"derived": derivedTest,
|
|
13
|
+
"lazy": lazyTest,
|
|
268
14
|
})
|
|
269
15
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
|
|
2
|
+
import {Science, test, expect, spy} from "@e280/science"
|
|
3
|
+
import {effect} from "../core/effect.js"
|
|
4
|
+
import {derived, signal} from "../porcelain.js"
|
|
5
|
+
|
|
6
|
+
export default Science.suite({
|
|
7
|
+
"basic": test(async() => {
|
|
8
|
+
const a = signal(1)
|
|
9
|
+
const b = signal(10)
|
|
10
|
+
const product = derived(() => a.get() * b.get())
|
|
11
|
+
expect(product.get()).is(10)
|
|
12
|
+
|
|
13
|
+
await a.set(2)
|
|
14
|
+
expect(product.get()).is(20)
|
|
15
|
+
}),
|
|
16
|
+
|
|
17
|
+
"effect reacts to derived changes": test(async() => {
|
|
18
|
+
const a = signal(1)
|
|
19
|
+
const b = signal(10)
|
|
20
|
+
const product = derived(() => a.value * b.value)
|
|
21
|
+
|
|
22
|
+
let mutations = 0
|
|
23
|
+
effect(() => {
|
|
24
|
+
void product.get()
|
|
25
|
+
mutations++
|
|
26
|
+
})
|
|
27
|
+
expect(product.value).is(10)
|
|
28
|
+
expect(mutations).is(1)
|
|
29
|
+
|
|
30
|
+
await a.set(2)
|
|
31
|
+
expect(product.value).is(20)
|
|
32
|
+
expect(mutations).is(2)
|
|
33
|
+
|
|
34
|
+
await a.set(3)
|
|
35
|
+
expect(product.value).is(30)
|
|
36
|
+
expect(mutations).is(3)
|
|
37
|
+
}),
|
|
38
|
+
|
|
39
|
+
"effect doesn't overreact to derived": test(async() => {
|
|
40
|
+
const a = signal(1)
|
|
41
|
+
const b = signal(10)
|
|
42
|
+
const product = signal.derived(() => a.value * b.value)
|
|
43
|
+
|
|
44
|
+
const derivedSpy = spy(() => {})
|
|
45
|
+
product.on(derivedSpy)
|
|
46
|
+
|
|
47
|
+
let mutations = 0
|
|
48
|
+
effect(() => {
|
|
49
|
+
a.get()
|
|
50
|
+
product.get()
|
|
51
|
+
mutations++
|
|
52
|
+
})
|
|
53
|
+
expect(product.value).is(10)
|
|
54
|
+
expect(mutations).is(1)
|
|
55
|
+
expect(derivedSpy.spy.calls.length).is(0)
|
|
56
|
+
|
|
57
|
+
await a.set(2)
|
|
58
|
+
expect(product.value).is(20)
|
|
59
|
+
expect(mutations).is(2)
|
|
60
|
+
expect(derivedSpy.spy.calls.length).is(1)
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
"derived.on": test(async() => {
|
|
64
|
+
const a = signal(1)
|
|
65
|
+
const b = signal(10)
|
|
66
|
+
const product = signal.derived(() => a.value * b.value)
|
|
67
|
+
expect(product.value).is(10)
|
|
68
|
+
|
|
69
|
+
const mole = spy((_v: number) => {})
|
|
70
|
+
product.on(mole)
|
|
71
|
+
expect(mole.spy.calls.length).is(0)
|
|
72
|
+
|
|
73
|
+
await a.set(2)
|
|
74
|
+
expect(product.value).is(20)
|
|
75
|
+
expect(mole.spy.calls.length).is(1)
|
|
76
|
+
expect(mole.spy.calls[0].args[0]).is(20)
|
|
77
|
+
}),
|
|
78
|
+
|
|
79
|
+
"derived.on not called if result doesn't change": test(async() => {
|
|
80
|
+
const a = signal(1)
|
|
81
|
+
const b = signal(10)
|
|
82
|
+
const product = signal.derived(() => a.value * b.value)
|
|
83
|
+
expect(product.value).is(10)
|
|
84
|
+
|
|
85
|
+
const mole = spy((_v: number) => {})
|
|
86
|
+
product.on(mole)
|
|
87
|
+
expect(mole.spy.calls.length).is(0)
|
|
88
|
+
|
|
89
|
+
await a.set(2)
|
|
90
|
+
expect(product.value).is(20)
|
|
91
|
+
expect(mole.spy.calls.length).is(1)
|
|
92
|
+
expect(mole.spy.calls[0].args[0]).is(20)
|
|
93
|
+
|
|
94
|
+
await a.set(2)
|
|
95
|
+
expect(product.value).is(20)
|
|
96
|
+
expect(mole.spy.calls.length).is(1)
|
|
97
|
+
}),
|
|
98
|
+
|
|
99
|
+
"hipster fns": Science.suite({
|
|
100
|
+
"basic": test(async() => {
|
|
101
|
+
const a = signal(1)
|
|
102
|
+
const b = signal(10)
|
|
103
|
+
const product = derived(() => a() * b())
|
|
104
|
+
expect(product()).is(10)
|
|
105
|
+
|
|
106
|
+
await a(2)
|
|
107
|
+
expect(product()).is(20)
|
|
108
|
+
}),
|
|
109
|
+
}),
|
|
110
|
+
})
|
|
111
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
|
|
2
|
+
import {Science, test, expect} from "@e280/science"
|
|
3
|
+
import {signal} from "../porcelain.js"
|
|
4
|
+
import {effect} from "../core/effect.js"
|
|
5
|
+
|
|
6
|
+
export default Science.suite({
|
|
7
|
+
"tracks signal changes": test(async() => {
|
|
8
|
+
const count = signal(1)
|
|
9
|
+
let doubled = 0
|
|
10
|
+
|
|
11
|
+
effect(() => doubled = count.value * 2)
|
|
12
|
+
expect(doubled).is(2)
|
|
13
|
+
|
|
14
|
+
await count.set(3)
|
|
15
|
+
expect(doubled).is(6)
|
|
16
|
+
}),
|
|
17
|
+
|
|
18
|
+
"is only called when signal actually changes": test(async() => {
|
|
19
|
+
const count = signal(1)
|
|
20
|
+
let runs = 0
|
|
21
|
+
effect(() => {
|
|
22
|
+
count.get()
|
|
23
|
+
runs++
|
|
24
|
+
})
|
|
25
|
+
expect(runs).is(1)
|
|
26
|
+
await count.set(999)
|
|
27
|
+
expect(runs).is(2)
|
|
28
|
+
await count.set(999)
|
|
29
|
+
expect(runs).is(2)
|
|
30
|
+
}),
|
|
31
|
+
|
|
32
|
+
"debounced": test(async() => {
|
|
33
|
+
const count = signal(1)
|
|
34
|
+
let runs = 0
|
|
35
|
+
effect(() => {
|
|
36
|
+
count.get()
|
|
37
|
+
runs++
|
|
38
|
+
})
|
|
39
|
+
expect(runs).is(1)
|
|
40
|
+
count.value++
|
|
41
|
+
count.value++
|
|
42
|
+
await count.set(count.get() + 1)
|
|
43
|
+
expect(runs).is(2)
|
|
44
|
+
}),
|
|
45
|
+
|
|
46
|
+
"can be disposed": test(async() => {
|
|
47
|
+
const count = signal(1)
|
|
48
|
+
let doubled = 0
|
|
49
|
+
|
|
50
|
+
const dispose = effect(() => doubled = count.value * 2)
|
|
51
|
+
expect(doubled).is(2)
|
|
52
|
+
|
|
53
|
+
await count.set(3)
|
|
54
|
+
expect(doubled).is(6)
|
|
55
|
+
|
|
56
|
+
dispose()
|
|
57
|
+
await count.set(4)
|
|
58
|
+
expect(doubled).is(6) // old value
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
"signal set promise waits for effects": test(async() => {
|
|
62
|
+
const count = signal(1)
|
|
63
|
+
let doubled = 0
|
|
64
|
+
|
|
65
|
+
effect(() => doubled = count.value * 2)
|
|
66
|
+
expect(doubled).is(2)
|
|
67
|
+
|
|
68
|
+
await count.set(3)
|
|
69
|
+
expect(doubled).is(6)
|
|
70
|
+
}),
|
|
71
|
+
|
|
72
|
+
"only runs on change": test(async() => {
|
|
73
|
+
const sig = signal("a")
|
|
74
|
+
let runs = 0
|
|
75
|
+
|
|
76
|
+
effect(() => {
|
|
77
|
+
sig.value
|
|
78
|
+
runs++
|
|
79
|
+
})
|
|
80
|
+
expect(runs).is(1)
|
|
81
|
+
|
|
82
|
+
await sig.set("a")
|
|
83
|
+
expect(runs).is(1)
|
|
84
|
+
|
|
85
|
+
await sig.set("b")
|
|
86
|
+
expect(runs).is(2)
|
|
87
|
+
}),
|
|
88
|
+
})
|
|
89
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
|
|
2
|
+
import {Science, test, expect} from "@e280/science"
|
|
3
|
+
import {lazy, signal} from "../porcelain.js"
|
|
4
|
+
|
|
5
|
+
export default Science.suite({
|
|
6
|
+
"lazy values": test(async() => {
|
|
7
|
+
const a = signal(2)
|
|
8
|
+
const b = signal(3)
|
|
9
|
+
const sum = lazy(() => a.value + b.value)
|
|
10
|
+
expect(sum.value).is(5)
|
|
11
|
+
|
|
12
|
+
await a.set(5)
|
|
13
|
+
expect(sum.value).is(8)
|
|
14
|
+
|
|
15
|
+
await b.set(7)
|
|
16
|
+
expect(sum.value).is(12)
|
|
17
|
+
}),
|
|
18
|
+
|
|
19
|
+
"lazy is lazy": test(async() => {
|
|
20
|
+
const a = signal(1)
|
|
21
|
+
let runs = 0
|
|
22
|
+
|
|
23
|
+
const comp = lazy(() => {
|
|
24
|
+
runs++
|
|
25
|
+
return a.value * 10
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
expect(runs).is(0)
|
|
29
|
+
expect(comp.value).is(10)
|
|
30
|
+
expect(runs).is(1)
|
|
31
|
+
|
|
32
|
+
await a.set(2)
|
|
33
|
+
expect(runs).is(1)
|
|
34
|
+
expect(comp.value).is(20)
|
|
35
|
+
expect(runs).is(2)
|
|
36
|
+
}),
|
|
37
|
+
|
|
38
|
+
"lazy syntax": test(async() => {
|
|
39
|
+
const a = signal(2)
|
|
40
|
+
const b = signal(3)
|
|
41
|
+
const sum = lazy(() => a.value + b.value)
|
|
42
|
+
expect(sum.value).is(5)
|
|
43
|
+
|
|
44
|
+
await a.set(5)
|
|
45
|
+
expect(sum.value).is(8)
|
|
46
|
+
expect(sum.get()).is(8)
|
|
47
|
+
}),
|
|
48
|
+
|
|
49
|
+
"hipster fns": Science.suite({
|
|
50
|
+
"lazy values": test(async() => {
|
|
51
|
+
const a = signal(2)
|
|
52
|
+
const b = signal(3)
|
|
53
|
+
const sum = lazy(() => a() + b())
|
|
54
|
+
expect(sum()).is(5)
|
|
55
|
+
|
|
56
|
+
await a(5)
|
|
57
|
+
expect(sum()).is(8)
|
|
58
|
+
|
|
59
|
+
await b(7)
|
|
60
|
+
expect(sum()).is(12)
|
|
61
|
+
}),
|
|
62
|
+
}),
|
|
63
|
+
})
|
|
64
|
+
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
|
|
2
|
+
import {Science, test, expect} from "@e280/science"
|
|
3
|
+
import {signal} from "../porcelain.js"
|
|
4
|
+
|
|
5
|
+
export default Science.suite({
|
|
6
|
+
"get/set value": test(async() => {
|
|
7
|
+
const count = signal(0)
|
|
8
|
+
expect(count.value).is(0)
|
|
9
|
+
|
|
10
|
+
count.value++
|
|
11
|
+
expect(count.value).is(1)
|
|
12
|
+
|
|
13
|
+
count.value = 5
|
|
14
|
+
expect(count.value).is(5)
|
|
15
|
+
}),
|
|
16
|
+
|
|
17
|
+
"set and publish returns value": test(async() => {
|
|
18
|
+
const count = signal(0)
|
|
19
|
+
expect(count.value).is(0)
|
|
20
|
+
expect(await count.set(1)).is(1)
|
|
21
|
+
expect(await count.publish(2)).is(2)
|
|
22
|
+
}),
|
|
23
|
+
|
|
24
|
+
"syntax interop": test(async() => {
|
|
25
|
+
const count = signal(0)
|
|
26
|
+
count.value = 1
|
|
27
|
+
expect(count.get()).is(1)
|
|
28
|
+
}),
|
|
29
|
+
|
|
30
|
+
"on": Science.suite({
|
|
31
|
+
"on is not debounced": test(async() => {
|
|
32
|
+
const count = signal(1)
|
|
33
|
+
let runs = 0
|
|
34
|
+
count.on(() => void runs++)
|
|
35
|
+
await count.set(2)
|
|
36
|
+
await count.set(3)
|
|
37
|
+
expect(runs).is(2)
|
|
38
|
+
}),
|
|
39
|
+
|
|
40
|
+
"on only fires on change": test(async() => {
|
|
41
|
+
const count = signal(1)
|
|
42
|
+
let runs = 0
|
|
43
|
+
count.on(() => void runs++)
|
|
44
|
+
await count.set(2)
|
|
45
|
+
await count.set(2)
|
|
46
|
+
expect(runs).is(1)
|
|
47
|
+
}),
|
|
48
|
+
|
|
49
|
+
"on circularity forbidden": test(async() => {
|
|
50
|
+
const count = signal(1)
|
|
51
|
+
let runs = 0
|
|
52
|
+
count.on(async() => {
|
|
53
|
+
await count.set(99)
|
|
54
|
+
runs++
|
|
55
|
+
})
|
|
56
|
+
expect(async() => {
|
|
57
|
+
await count.set(2)
|
|
58
|
+
}).throwsAsync()
|
|
59
|
+
expect(runs).is(0)
|
|
60
|
+
}),
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
"hipster syntax": Science.suite({
|
|
64
|
+
"get and set": test(async() => {
|
|
65
|
+
const count = signal(0)
|
|
66
|
+
expect(count()).is(0)
|
|
67
|
+
|
|
68
|
+
count(count() + 1)
|
|
69
|
+
expect(count()).is(1)
|
|
70
|
+
}),
|
|
71
|
+
|
|
72
|
+
"old get and set still work": test(async() => {
|
|
73
|
+
const count = signal(0)
|
|
74
|
+
expect(count.get()).is(0)
|
|
75
|
+
|
|
76
|
+
count.set(count.get() + 1)
|
|
77
|
+
expect(count.get()).is(1)
|
|
78
|
+
}),
|
|
79
|
+
|
|
80
|
+
"interop": test(async() => {
|
|
81
|
+
const count = signal(0)
|
|
82
|
+
|
|
83
|
+
count(1)
|
|
84
|
+
expect(count()).is(1)
|
|
85
|
+
expect(count.get()).is(1)
|
|
86
|
+
expect(count.value).is(1)
|
|
87
|
+
|
|
88
|
+
count.set(2)
|
|
89
|
+
expect(count()).is(2)
|
|
90
|
+
expect(count.get()).is(2)
|
|
91
|
+
expect(count.value).is(2)
|
|
92
|
+
|
|
93
|
+
count.value = 3
|
|
94
|
+
expect(count()).is(3)
|
|
95
|
+
expect(count.get()).is(3)
|
|
96
|
+
expect(count.value).is(3)
|
|
97
|
+
}),
|
|
98
|
+
|
|
99
|
+
".on 'this' interrogation": test(async() => {
|
|
100
|
+
const count = signal(0)
|
|
101
|
+
expect(count()).is(0)
|
|
102
|
+
|
|
103
|
+
let reported = count()
|
|
104
|
+
count.on(x => {reported = x})
|
|
105
|
+
|
|
106
|
+
count(1)
|
|
107
|
+
expect(reported).is(1)
|
|
108
|
+
|
|
109
|
+
count.on.clear()
|
|
110
|
+
count(2)
|
|
111
|
+
expect(reported).is(1)
|
|
112
|
+
}),
|
|
113
|
+
}),
|
|
114
|
+
})
|
|
115
|
+
|
package/s/signals/types.ts
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
|
|
2
|
-
import {Lazy} from "./lazy.js"
|
|
3
|
-
import {Signal} from "./signal.js"
|
|
4
|
-
import {
|
|
2
|
+
import {Lazy} from "./core/lazy.js"
|
|
3
|
+
import {Signal} from "./core/signal.js"
|
|
4
|
+
import {Derived} from "./core/derived.js"
|
|
5
5
|
|
|
6
|
-
export type Signaly<V> = Signal<V> |
|
|
6
|
+
export type Signaly<V> = Signal<V> | Derived<V> | Lazy<V>
|
|
7
|
+
export type SignalyFn<V> = SignalFn<V> | DerivedFn<V> | LazyFn<V>
|
|
7
8
|
|
|
8
9
|
export type SignalOptions = {
|
|
9
10
|
compare: (a: any, b: any) => boolean
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
export type SignalFn<V> = {
|
|
14
|
+
(): V
|
|
15
|
+
(v: V): Promise<V>
|
|
16
|
+
(v?: V): V | Promise<V>
|
|
17
|
+
|
|
18
|
+
core: Signal<V>
|
|
19
|
+
} & Signal<V>
|
|
20
|
+
|
|
21
|
+
export type LazyFn<V> = {
|
|
22
|
+
(): V
|
|
23
|
+
core: Lazy<V>
|
|
24
|
+
} & Lazy<V>
|
|
25
|
+
|
|
26
|
+
export type DerivedFn<V> = {
|
|
27
|
+
(): V
|
|
28
|
+
core: Derived<V>
|
|
29
|
+
} & Derived<V>
|
|
30
|
+
|
package/s/tests.test.ts
CHANGED
|
@@ -5,8 +5,8 @@ import tree from "./tree/tree.test.js"
|
|
|
5
5
|
import signals from "./signals/signals.test.js"
|
|
6
6
|
import tracker from "./tracker/tracker.test.js"
|
|
7
7
|
|
|
8
|
-
import {signal} from "./signals/
|
|
9
|
-
import {effect} from "./signals/effect.js"
|
|
8
|
+
import {signal} from "./signals/porcelain.js"
|
|
9
|
+
import {effect} from "./signals/core/effect.js"
|
|
10
10
|
import {Trunk} from "./tree/parts/trunk.js"
|
|
11
11
|
|
|
12
12
|
await Science.run({
|