@e280/strata 0.1.0 → 0.2.0-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/README.md +7 -13
- package/package.json +3 -3
- package/s/signals/derive.ts +37 -0
- package/s/signals/effect.ts +10 -2
- package/s/signals/fns.ts +30 -0
- package/s/signals/index.ts +6 -2
- package/s/signals/lazy.ts +47 -0
- package/s/signals/parts/reactive.ts +12 -0
- package/s/signals/parts/readable.ts +16 -0
- package/s/signals/signal.ts +43 -37
- package/s/signals/signals.test.ts +6 -22
- package/s/signals/types.ts +3 -3
- package/s/signals/utils/default-compare.ts +5 -0
- package/s/tests.test.ts +2 -2
- package/s/tree/parts/branch.ts +4 -4
- package/s/tree/parts/trunk.ts +7 -5
- package/x/signals/derive.d.ts +8 -0
- package/x/signals/derive.js +31 -0
- package/x/signals/derive.js.map +1 -0
- package/x/signals/effect.js.map +1 -1
- package/x/signals/fns.d.ts +11 -0
- package/x/signals/fns.js +15 -0
- package/x/signals/fns.js.map +1 -0
- package/x/signals/index.d.ts +5 -2
- package/x/signals/index.js +5 -2
- package/x/signals/index.js.map +1 -1
- package/x/signals/lazy.d.ts +8 -0
- package/x/signals/lazy.js +37 -0
- package/x/signals/lazy.js.map +1 -0
- package/x/signals/parts/reactive.d.ts +5 -0
- package/x/signals/parts/reactive.js +9 -0
- package/x/signals/parts/reactive.js.map +1 -0
- package/x/signals/parts/readable.d.ts +6 -0
- package/x/signals/parts/readable.js +15 -0
- package/x/signals/parts/readable.js.map +1 -0
- package/x/signals/signal.d.ts +6 -17
- package/x/signals/signal.js +39 -15
- package/x/signals/signal.js.map +1 -1
- package/x/signals/signals.test.d.ts +1 -2
- package/x/signals/signals.test.js +6 -16
- package/x/signals/signals.test.js.map +1 -1
- package/x/signals/types.d.ts +3 -3
- package/x/signals/utils/default-compare.d.ts +1 -0
- package/x/signals/utils/default-compare.js +4 -0
- package/x/signals/utils/default-compare.js.map +1 -0
- 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 +4 -3
- package/x/tree/parts/trunk.js.map +1 -1
- package/s/signals/parts/derive.ts +0 -29
- package/s/signals/parts/lazy.ts +0 -27
- package/s/signals/parts/units.ts +0 -152
- package/x/signals/parts/derive.d.ts +0 -12
- package/x/signals/parts/derive.js +0 -12
- package/x/signals/parts/derive.js.map +0 -1
- package/x/signals/parts/lazy.d.ts +0 -10
- package/x/signals/parts/lazy.js +0 -12
- package/x/signals/parts/lazy.js.map +0 -1
- package/x/signals/parts/units.d.ts +0 -43
- package/x/signals/parts/units.js +0 -133
- package/x/signals/parts/units.js.map +0 -1
package/README.md
CHANGED
|
@@ -32,24 +32,18 @@ import {signal, effect} from "@e280/strata"
|
|
|
32
32
|
```
|
|
33
33
|
- **read a signal**
|
|
34
34
|
```ts
|
|
35
|
-
count() // 0
|
|
35
|
+
count.get() // 0
|
|
36
36
|
```
|
|
37
37
|
- **set a signal**
|
|
38
38
|
```ts
|
|
39
|
-
count(1)
|
|
39
|
+
count.set(1)
|
|
40
40
|
```
|
|
41
41
|
- **set a signal, and await effect propagation**
|
|
42
42
|
```ts
|
|
43
|
-
await count(2)
|
|
43
|
+
await count.set(2)
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
### 🚦 pick your poison
|
|
47
|
-
- **signal hipster fn syntax**
|
|
48
|
-
```ts
|
|
49
|
-
count() // get
|
|
50
|
-
await count(2) // set
|
|
51
|
-
```
|
|
52
|
-
> see the [discussion](https://github.com/e280/strata/discussions/1) about this controversial hipster-syntax
|
|
53
47
|
- **signal get/set syntax**
|
|
54
48
|
```ts
|
|
55
49
|
count.get() // get
|
|
@@ -69,7 +63,7 @@ import {signal, effect} from "@e280/strata"
|
|
|
69
63
|
### 🚦 effects
|
|
70
64
|
- **effects run when the relevant signals change**
|
|
71
65
|
```ts
|
|
72
|
-
effect(() => console.log(count()))
|
|
66
|
+
effect(() => console.log(count.get()))
|
|
73
67
|
// 1
|
|
74
68
|
// the system detects 'count' is relevant
|
|
75
69
|
|
|
@@ -84,15 +78,15 @@ import {signal, effect} from "@e280/strata"
|
|
|
84
78
|
```ts
|
|
85
79
|
const a = signal(1)
|
|
86
80
|
const b = signal(10)
|
|
87
|
-
const product = signal.derive(() => a() * b())
|
|
81
|
+
const product = signal.derive(() => a.get() * b.get())
|
|
88
82
|
|
|
89
|
-
product() // 10
|
|
83
|
+
product.get() // 10
|
|
90
84
|
|
|
91
85
|
// change a dependency,
|
|
92
86
|
// and the derived signal is automatically updated
|
|
93
87
|
await a.set(2)
|
|
94
88
|
|
|
95
|
-
product() // 20
|
|
89
|
+
product.get() // 20
|
|
96
90
|
```
|
|
97
91
|
- **signal.lazy**
|
|
98
92
|
is for making special optimizations.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/strata",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-0",
|
|
4
4
|
"description": "state management",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"_tscw": "tsc -w"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@e280/stz": "^0.
|
|
32
|
+
"@e280/stz": "^0.2.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@e280/science": "^0.1.
|
|
35
|
+
"@e280/science": "^0.1.1",
|
|
36
36
|
"@types/node": "^24.3.0",
|
|
37
37
|
"npm-run-all": "^4.1.5",
|
|
38
38
|
"typescript": "^5.9.2"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
import {SignalOptions} from "./types.js"
|
|
3
|
+
import {collectorEffect} from "./effect.js"
|
|
4
|
+
import {Reactive} from "./parts/reactive.js"
|
|
5
|
+
import {tracker} from "../tracker/tracker.js"
|
|
6
|
+
import {defaultCompare} from "./utils/default-compare.js"
|
|
7
|
+
|
|
8
|
+
export class Derive<V> extends Reactive<V> {
|
|
9
|
+
#dispose: () => void
|
|
10
|
+
|
|
11
|
+
constructor(formula: () => V, options?: Partial<SignalOptions>) {
|
|
12
|
+
const compare = options?.compare ?? defaultCompare
|
|
13
|
+
const {result, dispose} = collectorEffect(formula, async() => {
|
|
14
|
+
const value = formula()
|
|
15
|
+
const isChanged = !compare(this.sneak, value)
|
|
16
|
+
if (isChanged) {
|
|
17
|
+
this.sneak = value
|
|
18
|
+
await Promise.all([
|
|
19
|
+
tracker.notifyWrite(this),
|
|
20
|
+
this.on.pub(value),
|
|
21
|
+
])
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
super(result)
|
|
25
|
+
this.#dispose = dispose
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get value() {
|
|
29
|
+
return this.get()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
dispose() {
|
|
33
|
+
super.dispose()
|
|
34
|
+
this.#dispose()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
package/s/signals/effect.ts
CHANGED
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
import {debounce} from "@e280/stz"
|
|
3
3
|
import {tracker} from "../tracker/tracker.js"
|
|
4
4
|
|
|
5
|
-
export function effect(
|
|
5
|
+
export function effect(
|
|
6
|
+
collector: () => void,
|
|
7
|
+
responder: () => void = collector,
|
|
8
|
+
) {
|
|
9
|
+
|
|
6
10
|
return collectorEffect(collector, responder).dispose
|
|
7
11
|
}
|
|
8
12
|
|
|
9
|
-
export function collectorEffect<C = void>(
|
|
13
|
+
export function collectorEffect<C = void>(
|
|
14
|
+
collector: () => C,
|
|
15
|
+
responder: () => void = collector,
|
|
16
|
+
) {
|
|
17
|
+
|
|
10
18
|
const {seen, result} = tracker.observe(collector)
|
|
11
19
|
const fn = debounce(0, responder)
|
|
12
20
|
|
package/s/signals/fns.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import {Lazy} from "./lazy.js"
|
|
3
|
+
import {Signal} from "./signal.js"
|
|
4
|
+
import {Derive} from "./derive.js"
|
|
5
|
+
import {SignalOptions} from "./types.js"
|
|
6
|
+
|
|
7
|
+
export function lazy<V>(
|
|
8
|
+
formula: () => V,
|
|
9
|
+
options?: Partial<SignalOptions>,
|
|
10
|
+
) {
|
|
11
|
+
return new Lazy<V>(formula, options)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function derive<V>(
|
|
15
|
+
formula: () => V,
|
|
16
|
+
options?: Partial<SignalOptions>,
|
|
17
|
+
) {
|
|
18
|
+
return new Derive<V>(formula, options)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function signal<V>(
|
|
22
|
+
value: V,
|
|
23
|
+
options?: Partial<SignalOptions>,
|
|
24
|
+
) {
|
|
25
|
+
return new Signal<V>(value, options)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
signal.lazy = lazy
|
|
29
|
+
signal.derive = derive
|
|
30
|
+
|
package/s/signals/index.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
|
|
2
|
-
export * from "./parts/
|
|
3
|
-
export * from "./parts/
|
|
2
|
+
export * from "./parts/reactive.js"
|
|
3
|
+
export * from "./parts/readable.js"
|
|
4
|
+
|
|
5
|
+
export * from "./derive.js"
|
|
4
6
|
export * from "./effect.js"
|
|
7
|
+
export * from "./fns.js"
|
|
8
|
+
export * from "./lazy.js"
|
|
5
9
|
export * from "./signal.js"
|
|
6
10
|
export * from "./types.js"
|
|
7
11
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
import {SignalOptions} from "./types.js"
|
|
3
|
+
import {collectorEffect} from "./effect.js"
|
|
4
|
+
import {Readable} from "./parts/readable.js"
|
|
5
|
+
import {tracker} from "../tracker/tracker.js"
|
|
6
|
+
import {defaultCompare} from "./utils/default-compare.js"
|
|
7
|
+
|
|
8
|
+
export class Lazy<V> extends Readable<V> {
|
|
9
|
+
#formula: () => V
|
|
10
|
+
#compare: (a: any, b: any) => boolean
|
|
11
|
+
#dirty = false
|
|
12
|
+
#effect: (() => void) | undefined
|
|
13
|
+
|
|
14
|
+
constructor(formula: () => V, options?: Partial<SignalOptions>) {
|
|
15
|
+
super(undefined as any)
|
|
16
|
+
this.#formula = formula
|
|
17
|
+
this.#compare = options?.compare ?? defaultCompare
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get() {
|
|
21
|
+
if (!this.#effect) {
|
|
22
|
+
const {result, dispose} = collectorEffect(
|
|
23
|
+
this.#formula,
|
|
24
|
+
() => this.#dirty = true,
|
|
25
|
+
)
|
|
26
|
+
this.#effect = dispose
|
|
27
|
+
this.sneak = result
|
|
28
|
+
}
|
|
29
|
+
if (this.#dirty) {
|
|
30
|
+
this.#dirty = false
|
|
31
|
+
|
|
32
|
+
const v = this.#formula()
|
|
33
|
+
const isChanged = !this.#compare(this.sneak, v)
|
|
34
|
+
if (isChanged) {
|
|
35
|
+
this.sneak = v
|
|
36
|
+
tracker.notifyWrite(this)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return super.get()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
dispose() {
|
|
43
|
+
if (this.#effect)
|
|
44
|
+
this.#effect()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
package/s/signals/signal.ts
CHANGED
|
@@ -1,44 +1,50 @@
|
|
|
1
1
|
|
|
2
|
-
import {Sub} from "@e280/stz"
|
|
3
|
-
|
|
4
|
-
import {lazy} from "./parts/lazy.js"
|
|
5
|
-
import {derive} from "./parts/derive.js"
|
|
6
2
|
import {SignalOptions} from "./types.js"
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
on: Sub<[V]>
|
|
19
|
-
get(): V
|
|
20
|
-
set(v: V): Promise<V>
|
|
21
|
-
publish(v?: V): Promise<V>
|
|
22
|
-
dispose(): void
|
|
23
|
-
} & SignalCore<V>
|
|
24
|
-
|
|
25
|
-
export function signal<V>(value: V, options: Partial<SignalOptions> = {}) {
|
|
26
|
-
function fn(): V
|
|
27
|
-
function fn(v: V): Promise<void>
|
|
28
|
-
function fn(v?: V): V | Promise<void> {
|
|
29
|
-
return v !== undefined
|
|
30
|
-
? (fn as any).set(v)
|
|
31
|
-
: (fn as any).get()
|
|
3
|
+
import {Reactive} from "./parts/reactive.js"
|
|
4
|
+
import {tracker} from "../tracker/tracker.js"
|
|
5
|
+
import {defaultCompare} from "./utils/default-compare.js"
|
|
6
|
+
|
|
7
|
+
export class Signal<V> extends Reactive<V> {
|
|
8
|
+
#lock = false
|
|
9
|
+
#compare: (a: any, b: any) => boolean
|
|
10
|
+
|
|
11
|
+
constructor(sneak: V, options?: Partial<SignalOptions>) {
|
|
12
|
+
super(sneak)
|
|
13
|
+
this.#compare = options?.compare ?? defaultCompare
|
|
32
14
|
}
|
|
33
15
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
16
|
+
async set(v: V) {
|
|
17
|
+
const isChanged = !this.#compare(this.sneak, v)
|
|
18
|
+
if (isChanged) await this.publish(v)
|
|
19
|
+
return v
|
|
20
|
+
}
|
|
38
21
|
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
get value() {
|
|
23
|
+
return this.get()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
set value(v: V) {
|
|
27
|
+
this.set(v)
|
|
28
|
+
}
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
30
|
+
async publish(v = this.get()) {
|
|
31
|
+
if (this.#lock) throw new Error("forbid circularity")
|
|
32
|
+
let promise = Promise.resolve()
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
this.#lock = true
|
|
36
|
+
this.sneak = v
|
|
37
|
+
promise = Promise.all([
|
|
38
|
+
tracker.notifyWrite(this),
|
|
39
|
+
this.on.pub(v),
|
|
40
|
+
]) as any
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
this.#lock = false
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await promise
|
|
47
|
+
return v
|
|
48
|
+
}
|
|
49
|
+
}
|
|
44
50
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import {Science, test, expect, spy} from "@e280/science"
|
|
3
|
-
|
|
4
|
-
import {lazy} from "./parts/lazy.js"
|
|
5
3
|
import {effect} from "./effect.js"
|
|
6
|
-
import {signal} from "./
|
|
4
|
+
import {derive, lazy, signal} from "./fns.js"
|
|
7
5
|
|
|
8
6
|
export default Science.suite({
|
|
9
7
|
"signal get/set value": test(async() => {
|
|
@@ -17,31 +15,17 @@ export default Science.suite({
|
|
|
17
15
|
expect(count.value).is(5)
|
|
18
16
|
}),
|
|
19
17
|
|
|
20
|
-
"signal fn syntax": test(async() => {
|
|
21
|
-
const count = signal(0)
|
|
22
|
-
expect(count()).is(0)
|
|
23
|
-
|
|
24
|
-
count(count() + 1)
|
|
25
|
-
expect(count()).is(1)
|
|
26
|
-
|
|
27
|
-
count(5)
|
|
28
|
-
expect(count()).is(5)
|
|
29
|
-
}),
|
|
30
|
-
|
|
31
18
|
"signal set and publish returns value": test(async() => {
|
|
32
19
|
const count = signal(0)
|
|
33
20
|
expect(count.value).is(0)
|
|
34
|
-
|
|
35
21
|
expect(await count.set(1)).is(1)
|
|
36
|
-
expect(await count(2)).is(2)
|
|
37
|
-
expect(await count.publish(3)).is(3)
|
|
22
|
+
expect(await count.publish(2)).is(2)
|
|
38
23
|
}),
|
|
39
24
|
|
|
40
25
|
"signal syntax interop": test(async() => {
|
|
41
26
|
const count = signal(0)
|
|
42
|
-
|
|
43
27
|
count.value = 1
|
|
44
|
-
expect(count()).is(1)
|
|
28
|
+
expect(count.get()).is(1)
|
|
45
29
|
}),
|
|
46
30
|
|
|
47
31
|
"signal on is not debounced": test(async() => {
|
|
@@ -173,7 +157,7 @@ export default Science.suite({
|
|
|
173
157
|
"effect reacts to derived changes": test(async() => {
|
|
174
158
|
const a = signal(1)
|
|
175
159
|
const b = signal(10)
|
|
176
|
-
const product =
|
|
160
|
+
const product = derive(() => a.value * b.value)
|
|
177
161
|
|
|
178
162
|
let mutations = 0
|
|
179
163
|
effect(() => {
|
|
@@ -271,7 +255,7 @@ export default Science.suite({
|
|
|
271
255
|
expect(runs).is(2)
|
|
272
256
|
}),
|
|
273
257
|
|
|
274
|
-
"lazy
|
|
258
|
+
"lazy syntax": test(async() => {
|
|
275
259
|
const a = signal(2)
|
|
276
260
|
const b = signal(3)
|
|
277
261
|
const sum = lazy(() => a.value + b.value)
|
|
@@ -279,7 +263,7 @@ export default Science.suite({
|
|
|
279
263
|
|
|
280
264
|
await a.set(5)
|
|
281
265
|
expect(sum.value).is(8)
|
|
282
|
-
expect(sum()).is(8)
|
|
266
|
+
expect(sum.get()).is(8)
|
|
283
267
|
}),
|
|
284
268
|
})
|
|
285
269
|
|
package/s/signals/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
+
import {Lazy} from "./lazy.js"
|
|
2
3
|
import {Signal} from "./signal.js"
|
|
3
|
-
import {
|
|
4
|
-
import {DerivedSignal} from "./parts/derive.js"
|
|
4
|
+
import {Derive} from "./derive.js"
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type Signaly<V> = Signal<V> | Derive<V> | Lazy<V>
|
|
7
7
|
|
|
8
8
|
export type SignalOptions = {
|
|
9
9
|
compare: (a: any, b: any) => boolean
|
package/s/tests.test.ts
CHANGED
|
@@ -5,9 +5,9 @@ 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 {
|
|
8
|
+
import {signal} from "./signals/fns.js"
|
|
9
9
|
import {effect} from "./signals/effect.js"
|
|
10
|
-
import {
|
|
10
|
+
import {Trunk} from "./tree/parts/trunk.js"
|
|
11
11
|
|
|
12
12
|
await Science.run({
|
|
13
13
|
tree,
|
package/s/tree/parts/branch.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
import {deep} from "@e280/stz"
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import {derive} from "../../signals/fns.js"
|
|
4
|
+
import {Derive} from "../../signals/derive.js"
|
|
5
5
|
import {Branchstate, Immutable, Mutator, Options, Selector, Tree} from "./types.js"
|
|
6
6
|
|
|
7
7
|
export class Branch<S extends Branchstate, ParentState extends Branchstate = any> implements Tree<S> {
|
|
8
|
-
#immutable:
|
|
8
|
+
#immutable: Derive<Immutable<S>>
|
|
9
9
|
|
|
10
10
|
constructor(
|
|
11
11
|
private parent: Tree<ParentState>,
|
|
@@ -13,7 +13,7 @@ export class Branch<S extends Branchstate, ParentState extends Branchstate = any
|
|
|
13
13
|
private options: Options,
|
|
14
14
|
) {
|
|
15
15
|
|
|
16
|
-
this.#immutable =
|
|
16
|
+
this.#immutable = derive(() => {
|
|
17
17
|
const state = selector(parent.state as any)
|
|
18
18
|
return deep.freeze(options.clone(state)) as Immutable<S>
|
|
19
19
|
}, {compare: deep.equal})
|
package/s/tree/parts/trunk.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
import {deep} from "@e280/stz"
|
|
3
3
|
import {Branch} from "./branch.js"
|
|
4
|
+
import {signal} from "../../signals/fns.js"
|
|
4
5
|
import {trunkSetup} from "./utils/setup.js"
|
|
6
|
+
import {Derive} from "../../signals/derive.js"
|
|
7
|
+
import {Signal} from "../../signals/signal.js"
|
|
5
8
|
import {Chronobranch} from "./chronobranch.js"
|
|
6
9
|
import {processOptions} from "./utils/process-options.js"
|
|
7
|
-
import {DerivedSignal} from "../../signals/parts/derive.js"
|
|
8
|
-
import {signal, Signal} from "../../signals/signal.js"
|
|
9
10
|
import {Branchstate, Chronicle, Immutable, Mutator, Options, Selector, Tree, Trunkstate} from "./types.js"
|
|
10
11
|
|
|
11
12
|
export class Trunk<S extends Trunkstate> implements Tree<S> {
|
|
@@ -18,7 +19,7 @@ export class Trunk<S extends Trunkstate> implements Tree<S> {
|
|
|
18
19
|
|
|
19
20
|
options: Options
|
|
20
21
|
|
|
21
|
-
#immutable:
|
|
22
|
+
#immutable: Derive<Immutable<S>>
|
|
22
23
|
#mutable: Signal<S>
|
|
23
24
|
#mutationLock = 0
|
|
24
25
|
|
|
@@ -44,8 +45,9 @@ export class Trunk<S extends Trunkstate> implements Tree<S> {
|
|
|
44
45
|
throw new Error("nested mutations are forbidden")
|
|
45
46
|
try {
|
|
46
47
|
this.#mutationLock++
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
const value = this.#mutable.get()
|
|
49
|
+
mutator(value)
|
|
50
|
+
const newState = value
|
|
49
51
|
const isChanged = !deep.equal(newState, oldState)
|
|
50
52
|
if (isChanged)
|
|
51
53
|
await this.overwrite(newState)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SignalOptions } from "./types.js";
|
|
2
|
+
import { Reactive } from "./parts/reactive.js";
|
|
3
|
+
export declare class Derive<V> extends Reactive<V> {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(formula: () => V, options?: Partial<SignalOptions>);
|
|
6
|
+
get value(): V;
|
|
7
|
+
dispose(): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { collectorEffect } from "./effect.js";
|
|
2
|
+
import { Reactive } from "./parts/reactive.js";
|
|
3
|
+
import { tracker } from "../tracker/tracker.js";
|
|
4
|
+
import { defaultCompare } from "./utils/default-compare.js";
|
|
5
|
+
export class Derive extends Reactive {
|
|
6
|
+
#dispose;
|
|
7
|
+
constructor(formula, options) {
|
|
8
|
+
const compare = options?.compare ?? defaultCompare;
|
|
9
|
+
const { result, dispose } = collectorEffect(formula, async () => {
|
|
10
|
+
const value = formula();
|
|
11
|
+
const isChanged = !compare(this.sneak, value);
|
|
12
|
+
if (isChanged) {
|
|
13
|
+
this.sneak = value;
|
|
14
|
+
await Promise.all([
|
|
15
|
+
tracker.notifyWrite(this),
|
|
16
|
+
this.on.pub(value),
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
super(result);
|
|
21
|
+
this.#dispose = dispose;
|
|
22
|
+
}
|
|
23
|
+
get value() {
|
|
24
|
+
return this.get();
|
|
25
|
+
}
|
|
26
|
+
dispose() {
|
|
27
|
+
super.dispose();
|
|
28
|
+
this.#dispose();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../s/signals/derive.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,eAAe,EAAC,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAC,QAAQ,EAAC,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAA;AAC7C,OAAO,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAA;AAEzD,MAAM,OAAO,MAAU,SAAQ,QAAW;IACzC,QAAQ,CAAY;IAEpB,YAAY,OAAgB,EAAE,OAAgC;QAC7D,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,cAAc,CAAA;QAClD,MAAM,EAAC,MAAM,EAAE,OAAO,EAAC,GAAG,eAAe,CAAC,OAAO,EAAE,KAAK,IAAG,EAAE;YAC5D,MAAM,KAAK,GAAG,OAAO,EAAE,CAAA;YACvB,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YAC7C,IAAI,SAAS,EAAE,CAAC;gBACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;gBAClB,MAAM,OAAO,CAAC,GAAG,CAAC;oBACjB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;oBACzB,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;iBAClB,CAAC,CAAA;YACH,CAAC;QACF,CAAC,CAAC,CAAA;QACF,KAAK,CAAC,MAAM,CAAC,CAAA;QACb,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,GAAG,EAAE,CAAA;IAClB,CAAC;IAED,OAAO;QACN,KAAK,CAAC,OAAO,EAAE,CAAA;QACf,IAAI,CAAC,QAAQ,EAAE,CAAA;IAChB,CAAC;CACD"}
|
package/x/signals/effect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../s/signals/effect.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAA;AAClC,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAA;AAE7C,MAAM,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../s/signals/effect.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAA;AAClC,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAA;AAE7C,MAAM,UAAU,MAAM,CACpB,SAAqB,EACrB,YAAwB,SAAS;IAGlC,OAAO,eAAe,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,OAAO,CAAA;AACrD,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAAkB,EAClB,YAAwB,SAAS;IAGlC,MAAM,EAAC,IAAI,EAAE,MAAM,EAAC,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACjD,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;IAEjC,MAAM,SAAS,GAAmB,EAAE,CAAA;IACpC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;IAEjD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QAC1C,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC;IAED,OAAO,EAAC,MAAM,EAAE,OAAO,EAAC,CAAA;AACzB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Lazy } from "./lazy.js";
|
|
2
|
+
import { Signal } from "./signal.js";
|
|
3
|
+
import { Derive } from "./derive.js";
|
|
4
|
+
import { SignalOptions } from "./types.js";
|
|
5
|
+
export declare function lazy<V>(formula: () => V, options?: Partial<SignalOptions>): Lazy<V>;
|
|
6
|
+
export declare function derive<V>(formula: () => V, options?: Partial<SignalOptions>): Derive<V>;
|
|
7
|
+
export declare function signal<V>(value: V, options?: Partial<SignalOptions>): Signal<V>;
|
|
8
|
+
export declare namespace signal {
|
|
9
|
+
var lazy: typeof import("./fns.js").lazy;
|
|
10
|
+
var derive: typeof import("./fns.js").derive;
|
|
11
|
+
}
|
package/x/signals/fns.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Lazy } from "./lazy.js";
|
|
2
|
+
import { Signal } from "./signal.js";
|
|
3
|
+
import { Derive } from "./derive.js";
|
|
4
|
+
export function lazy(formula, options) {
|
|
5
|
+
return new Lazy(formula, options);
|
|
6
|
+
}
|
|
7
|
+
export function derive(formula, options) {
|
|
8
|
+
return new Derive(formula, options);
|
|
9
|
+
}
|
|
10
|
+
export function signal(value, options) {
|
|
11
|
+
return new Signal(value, options);
|
|
12
|
+
}
|
|
13
|
+
signal.lazy = lazy;
|
|
14
|
+
signal.derive = derive;
|
|
15
|
+
//# sourceMappingURL=fns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fns.js","sourceRoot":"","sources":["../../s/signals/fns.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAA;AAClC,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAA;AAGlC,MAAM,UAAU,IAAI,CAClB,OAAgB,EAChB,OAAgC;IAEjC,OAAO,IAAI,IAAI,CAAI,OAAO,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,OAAgB,EAChB,OAAgC;IAEjC,OAAO,IAAI,MAAM,CAAI,OAAO,EAAE,OAAO,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,KAAQ,EACR,OAAgC;IAEjC,OAAO,IAAI,MAAM,CAAI,KAAK,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,CAAC,IAAI,GAAG,IAAI,CAAA;AAClB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAA"}
|
package/x/signals/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export * from "./parts/
|
|
2
|
-
export * from "./parts/
|
|
1
|
+
export * from "./parts/reactive.js";
|
|
2
|
+
export * from "./parts/readable.js";
|
|
3
|
+
export * from "./derive.js";
|
|
3
4
|
export * from "./effect.js";
|
|
5
|
+
export * from "./fns.js";
|
|
6
|
+
export * from "./lazy.js";
|
|
4
7
|
export * from "./signal.js";
|
|
5
8
|
export * from "./types.js";
|
package/x/signals/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export * from "./parts/
|
|
2
|
-
export * from "./parts/
|
|
1
|
+
export * from "./parts/reactive.js";
|
|
2
|
+
export * from "./parts/readable.js";
|
|
3
|
+
export * from "./derive.js";
|
|
3
4
|
export * from "./effect.js";
|
|
5
|
+
export * from "./fns.js";
|
|
6
|
+
export * from "./lazy.js";
|
|
4
7
|
export * from "./signal.js";
|
|
5
8
|
export * from "./types.js";
|
|
6
9
|
//# sourceMappingURL=index.js.map
|
package/x/signals/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../s/signals/index.ts"],"names":[],"mappings":"AACA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../s/signals/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA"}
|