@e280/strata 0.2.0-1 → 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 -57
- 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 +5 -6
- package/s/signals/tests/{derive.test.ts → derived.test.ts} +28 -6
- package/s/signals/tests/effect.test.ts +2 -2
- package/s/signals/tests/lazy.test.ts +16 -1
- package/s/signals/tests/signal.test.ts +53 -1
- package/s/signals/types.ts +16 -5
- 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} +4 -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 +26 -17
- package/x/signals/signals.test.js +4 -6
- package/x/signals/signals.test.js.map +1 -1
- package/x/signals/tests/{derive.test.d.ts → derived.test.d.ts} +4 -0
- package/x/signals/tests/{derive.test.js → derived.test.js} +25 -7
- package/x/signals/tests/derived.test.js.map +1 -0
- package/x/signals/tests/effect.test.js +2 -2
- package/x/signals/tests/effect.test.js.map +1 -1
- package/x/signals/tests/lazy.test.d.ts +3 -0
- package/x/signals/tests/lazy.test.js +13 -1
- package/x/signals/tests/lazy.test.js.map +1 -1
- package/x/signals/tests/signal.test.d.ts +6 -0
- package/x/signals/tests/signal.test.js +41 -1
- package/x/signals/tests/signal.test.js.map +1 -1
- package/x/signals/types.d.ts +14 -5
- 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 -33
- package/s/signals/fns.ts +0 -31
- package/s/signals/signal.ts +0 -55
- package/s/signals/tests/signal-fn.test.ts +0 -28
- package/s/signals/utils/hipster.ts +0 -40
- package/x/signals/derive.d.ts +0 -7
- package/x/signals/derive.js +0 -28
- package/x/signals/derive.js.map +0 -1
- package/x/signals/effect.js.map +0 -1
- package/x/signals/fns.d.ts +0 -12
- package/x/signals/fns.js +0 -16
- 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 -46
- package/x/signals/signal.js.map +0 -1
- package/x/signals/tests/derive.test.js.map +0 -1
- package/x/signals/tests/signal-fn.test.d.ts +0 -6
- package/x/signals/tests/signal-fn.test.js +0 -22
- package/x/signals/tests/signal-fn.test.js.map +0 -1
- package/x/signals/utils/hipster.d.ts +0 -3
- package/x/signals/utils/hipster.js +0 -28
- package/x/signals/utils/hipster.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
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|

|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
<br/><br/>
|
|
5
7
|
|
|
6
8
|
# ⛏️ strata
|
|
7
9
|
|
|
@@ -9,14 +11,16 @@
|
|
|
9
11
|
📦 `npm install @e280/strata`
|
|
10
12
|
🧙♂️ probably my tenth state management library, lol
|
|
11
13
|
💁 it's all about rerendering ui when data changes
|
|
12
|
-
🦝
|
|
14
|
+
🦝 powers reactivity in our view library [@e280/sly](https://github.com/e280/sly)
|
|
13
15
|
🧑💻 a project by https://e280.org/
|
|
14
16
|
|
|
15
17
|
🚦 **signals** — ephemeral view-level state
|
|
16
18
|
🌳 **tree** — persistent app-level state
|
|
17
19
|
🪄 **tracker** — reactivity integration hub
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
<br/><br/>
|
|
20
24
|
|
|
21
25
|
## 🚦 strata signals
|
|
22
26
|
> *ephemeral view-level state*
|
|
@@ -26,95 +30,125 @@ import {signal, effect} from "@e280/strata"
|
|
|
26
30
|
```
|
|
27
31
|
|
|
28
32
|
### 🚦 each signal holds a value
|
|
29
|
-
- **
|
|
33
|
+
- **make signal**
|
|
30
34
|
```ts
|
|
31
|
-
const count = signal(0)
|
|
35
|
+
const $count = signal(0)
|
|
32
36
|
```
|
|
33
|
-
|
|
37
|
+
> *maybe you like the `$` prefix convention for signals?*
|
|
38
|
+
- **read signal**
|
|
34
39
|
```ts
|
|
35
|
-
count
|
|
40
|
+
$count() // 0
|
|
36
41
|
```
|
|
37
|
-
- **
|
|
42
|
+
- **write signal**
|
|
38
43
|
```ts
|
|
39
|
-
count
|
|
44
|
+
$count(1)
|
|
40
45
|
```
|
|
41
|
-
- **
|
|
46
|
+
- **write signal *(and await all downstream effects)***
|
|
42
47
|
```ts
|
|
43
|
-
await count
|
|
48
|
+
await $count(2)
|
|
44
49
|
```
|
|
50
|
+
> *this is supposed to impress you*
|
|
45
51
|
|
|
46
52
|
### 🚦 pick your poison
|
|
53
|
+
- **signal hipster-fn syntax**
|
|
54
|
+
```ts
|
|
55
|
+
$count() // read
|
|
56
|
+
await $count(2) // write
|
|
57
|
+
```
|
|
47
58
|
- **signal get/set syntax**
|
|
48
59
|
```ts
|
|
49
|
-
count.get()
|
|
50
|
-
await count.set(2) //
|
|
60
|
+
$count.get() // read
|
|
61
|
+
await $count.set(2) // write
|
|
51
62
|
```
|
|
52
63
|
- **signal .value accessor syntax**
|
|
53
64
|
```ts
|
|
54
|
-
count.value
|
|
55
|
-
count.value = 2 //
|
|
65
|
+
$count.value // read
|
|
66
|
+
$count.value = 2 // write
|
|
56
67
|
```
|
|
57
|
-
value pattern is nice for these vibes
|
|
68
|
+
value pattern is super nice for these vibes
|
|
58
69
|
```ts
|
|
59
|
-
count.value++
|
|
60
|
-
count.value += 1
|
|
70
|
+
$count.value++
|
|
71
|
+
$count.value += 1
|
|
61
72
|
```
|
|
62
|
-
- **signal hipster fn syntax**
|
|
63
|
-
- turn a signal into a hipster fn
|
|
64
|
-
```ts
|
|
65
|
-
const count = signal.fn(1)
|
|
66
|
-
```
|
|
67
|
-
- now you can directly invoke it
|
|
68
|
-
```ts
|
|
69
|
-
count() // get
|
|
70
|
-
await count(2) // set
|
|
71
|
-
```
|
|
72
|
-
- it has all the stuff that a signal has
|
|
73
|
-
```ts
|
|
74
|
-
count.get()
|
|
75
|
-
await count.publish(5)
|
|
76
|
-
count.on(x => console.log(x))
|
|
77
|
-
```
|
|
78
|
-
- mint a fresh new signal fn
|
|
79
|
-
```ts
|
|
80
|
-
const count = signal.fn(1)
|
|
81
|
-
```
|
|
82
73
|
|
|
83
74
|
### 🚦 effects
|
|
84
75
|
- **effects run when the relevant signals change**
|
|
85
76
|
```ts
|
|
86
|
-
effect(() => console.log(count
|
|
77
|
+
effect(() => console.log($count()))
|
|
87
78
|
// 1
|
|
88
|
-
// the system detects 'count' is relevant
|
|
79
|
+
// the system detects '$count' is relevant
|
|
89
80
|
|
|
90
|
-
count.value++
|
|
81
|
+
$count.value++
|
|
91
82
|
// 2
|
|
92
|
-
// when count is changed, the effect fn is run
|
|
83
|
+
// when $count is changed, the effect fn is run
|
|
93
84
|
```
|
|
94
85
|
|
|
95
|
-
### 🚦 `signal.
|
|
96
|
-
- **signal.
|
|
97
|
-
is for combining signals
|
|
86
|
+
### 🚦 `signal.derived` and `signal.lazy` are computed signals
|
|
87
|
+
- **signal.derived**
|
|
88
|
+
is for combining signals, like a formula
|
|
98
89
|
```ts
|
|
99
|
-
const a = signal(1)
|
|
100
|
-
const b = signal(10)
|
|
101
|
-
const product = signal.
|
|
90
|
+
const $a = signal(1)
|
|
91
|
+
const $b = signal(10)
|
|
92
|
+
const $product = signal.derived(() => $a() * $b())
|
|
102
93
|
|
|
103
|
-
product
|
|
94
|
+
$product() // 10
|
|
104
95
|
|
|
105
96
|
// change a dependency,
|
|
106
97
|
// and the derived signal is automatically updated
|
|
107
|
-
await a
|
|
98
|
+
await $a(2)
|
|
108
99
|
|
|
109
|
-
product
|
|
100
|
+
$product() // 20
|
|
110
101
|
```
|
|
111
102
|
- **signal.lazy**
|
|
112
103
|
is for making special optimizations.
|
|
113
|
-
it's like
|
|
114
|
-
because it's so lazy it only computes the value on read, and only when necessary.
|
|
104
|
+
it's like derived, except it cannot trigger effects,
|
|
105
|
+
because it's so damned lazy, it only computes the value on read, and only when necessary.
|
|
115
106
|
> *i repeat: lazy signals cannot trigger effects!*
|
|
116
107
|
|
|
117
|
-
|
|
108
|
+
### 🚦 core primitive classes
|
|
109
|
+
- **the hipster-fn syntax has a slight performance cost**
|
|
110
|
+
- **you can instead use the core primitive classes**
|
|
111
|
+
```ts
|
|
112
|
+
const $count = new Signal(1)
|
|
113
|
+
```
|
|
114
|
+
core signals work mostly the same
|
|
115
|
+
```ts
|
|
116
|
+
// ✅ legal
|
|
117
|
+
$count.get()
|
|
118
|
+
$count.set(2)
|
|
119
|
+
```
|
|
120
|
+
except you cannot directly invoke them
|
|
121
|
+
```ts
|
|
122
|
+
// ⛔ illegal on core primitives
|
|
123
|
+
$count()
|
|
124
|
+
$count(2)
|
|
125
|
+
```
|
|
126
|
+
- **same thing for derived/lazy**
|
|
127
|
+
```ts
|
|
128
|
+
const $product = new Derived(() => $a() * $b())
|
|
129
|
+
```
|
|
130
|
+
```ts
|
|
131
|
+
const $product = new Lazy(() => $a() * $b())
|
|
132
|
+
```
|
|
133
|
+
- **conversions**
|
|
134
|
+
- all core primitives (signal/derived/lazy) have a convert-to-hipster-fn method
|
|
135
|
+
```ts
|
|
136
|
+
new Signal(1).fn() // SignalFn<number>, hipster-fn
|
|
137
|
+
```
|
|
138
|
+
- and all hipster fns (signal/derived/lazy) have a `.core` property to get the primitive
|
|
139
|
+
```ts
|
|
140
|
+
signal(0).core // Signal<number>, primitive instance
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 🚦 types
|
|
144
|
+
- **`Signaly<V>`** — can be `Signal<V>` or `Derived<V>` or `Lazy<V>`
|
|
145
|
+
- these are types for the core primitive classes
|
|
146
|
+
- **`SignalyFn<V>`** — can be `SignalFn<V>` or `DerivedFn<V>` or `LazyFn<V>`
|
|
147
|
+
- these `*Fn` types are for the hipster-fn-syntax enabled variants
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
<br/><br/>
|
|
118
152
|
|
|
119
153
|
## 🌳 strata trees
|
|
120
154
|
> *persistent app-level state*
|
|
@@ -249,7 +283,9 @@ import {Trunk} from "@e280/strata"
|
|
|
249
283
|
- chronobranch can have its own branches — all their mutations advance history
|
|
250
284
|
- plz pinky-swear right now, that you won't create a chronobranch under a branch under another chronobranch 💀
|
|
251
285
|
|
|
252
|
-
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
<br/><br/>
|
|
253
289
|
|
|
254
290
|
## 🪄 strata tracker
|
|
255
291
|
> *reactivity integration hub*
|
|
@@ -324,9 +360,11 @@ note, the *items* that the tracker tracks can be any object, or symbol.. the tra
|
|
|
324
360
|
}
|
|
325
361
|
```
|
|
326
362
|
|
|
327
|
-
<br/>
|
|
328
363
|
|
|
329
|
-
|
|
364
|
+
|
|
365
|
+
<br/><br/>
|
|
366
|
+
|
|
367
|
+
## 🧑💻 strata is by e280
|
|
330
368
|
free and open source by https://e280.org/
|
|
331
369
|
join us if you're cool and good at dev
|
|
332
370
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/strata",
|
|
3
|
-
"version": "0.2.0-
|
|
3
|
+
"version": "0.2.0-10",
|
|
4
4
|
"description": "state management",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"_tscw": "tsc -w"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@e280/stz": "^0.2.
|
|
32
|
+
"@e280/stz": "^0.2.2"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@e280/science": "^0.1.
|
|
36
|
-
"@types/node": "^24.3.
|
|
35
|
+
"@e280/science": "^0.1.2",
|
|
36
|
+
"@types/node": "^24.3.1",
|
|
37
37
|
"npm-run-all": "^4.1.5",
|
|
38
38
|
"typescript": "^5.9.2"
|
|
39
39
|
},
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
|
|
2
|
+
import {collectorEffect} from "./effect.js"
|
|
3
|
+
import {Reactive} from "./parts/reactive.js"
|
|
4
|
+
import {tracker} from "../../tracker/tracker.js"
|
|
5
|
+
import {DerivedFn, SignalOptions} from "../types.js"
|
|
6
|
+
import {defaultCompare} from "../utils/default-compare.js"
|
|
7
|
+
|
|
8
|
+
export class Derived<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
|
+
toString() {
|
|
29
|
+
return `(derived "${String(this.get())}")`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
dispose() {
|
|
33
|
+
super.dispose()
|
|
34
|
+
this.#dispose()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get core() {
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn() {
|
|
42
|
+
const that = this as Derived<V>
|
|
43
|
+
|
|
44
|
+
function f(): V {
|
|
45
|
+
return that.get()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
f.core = that
|
|
49
|
+
f.get = that.get.bind(that)
|
|
50
|
+
f.on = that.on
|
|
51
|
+
f.dispose = that.dispose.bind(that)
|
|
52
|
+
f.fn = that.fn.bind(that)
|
|
53
|
+
|
|
54
|
+
Object.defineProperty(f, "value", {
|
|
55
|
+
get: () => that.value,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
Object.defineProperty(f, "sneak", {
|
|
59
|
+
get: () => that.sneak,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return f as DerivedFn<V>
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
import {SignalOptions} from "./types.js"
|
|
3
2
|
import {collectorEffect} from "./effect.js"
|
|
4
3
|
import {Readable} from "./parts/readable.js"
|
|
5
|
-
import {tracker} from "
|
|
6
|
-
import {
|
|
4
|
+
import {tracker} from "../../tracker/tracker.js"
|
|
5
|
+
import {LazyFn, SignalOptions} from "../types.js"
|
|
6
|
+
import {defaultCompare} from "../utils/default-compare.js"
|
|
7
7
|
|
|
8
8
|
export class Lazy<V> extends Readable<V> {
|
|
9
9
|
#formula: () => V
|
|
@@ -17,6 +17,10 @@ export class Lazy<V> extends Readable<V> {
|
|
|
17
17
|
this.#compare = options?.compare ?? defaultCompare
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
toString() {
|
|
21
|
+
return `($lazy "${String(this.get())}")`
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
get() {
|
|
21
25
|
if (!this.#effect) {
|
|
22
26
|
const {result, dispose} = collectorEffect(
|
|
@@ -43,5 +47,32 @@ export class Lazy<V> extends Readable<V> {
|
|
|
43
47
|
if (this.#effect)
|
|
44
48
|
this.#effect()
|
|
45
49
|
}
|
|
50
|
+
|
|
51
|
+
get core() {
|
|
52
|
+
return this
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fn() {
|
|
56
|
+
const that = this as Lazy<V>
|
|
57
|
+
|
|
58
|
+
function f(): V {
|
|
59
|
+
return that.get()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
f.core = that
|
|
63
|
+
f.get = that.get.bind(that)
|
|
64
|
+
f.dispose = that.dispose.bind(that)
|
|
65
|
+
f.fn = that.fn.bind(that)
|
|
66
|
+
|
|
67
|
+
Object.defineProperty(f, "value", {
|
|
68
|
+
get: () => that.value,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
Object.defineProperty(f, "sneak", {
|
|
72
|
+
get: () => that.sneak,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return f as LazyFn<V>
|
|
76
|
+
}
|
|
46
77
|
}
|
|
47
78
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
|
|
2
|
+
import {Reactive} from "./parts/reactive.js"
|
|
3
|
+
import {tracker} from "../../tracker/tracker.js"
|
|
4
|
+
import {SignalFn, SignalOptions} from "../types.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(value: V, options?: Partial<SignalOptions>) {
|
|
12
|
+
super(value)
|
|
13
|
+
this.#compare = options?.compare ?? defaultCompare
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
toString() {
|
|
17
|
+
return `($signal "${String(this.get())}")`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async set(v: V) {
|
|
21
|
+
const isChanged = !this.#compare(this.sneak, v)
|
|
22
|
+
if (isChanged) await this.publish(v)
|
|
23
|
+
return v
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get value() {
|
|
27
|
+
return this.get()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
set value(v: V) {
|
|
31
|
+
void this.set(v)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async publish(v = this.sneak) {
|
|
35
|
+
// only wizards are allowed beyond this point.
|
|
36
|
+
// - the implementation is subtle
|
|
37
|
+
// - it looks wrong, but it's right
|
|
38
|
+
// - tarnished alchemists, take heed: lock engages only for sync activity of the async fns (think of the value setter!)
|
|
39
|
+
|
|
40
|
+
if (this.#lock)
|
|
41
|
+
throw new Error("forbid circularity")
|
|
42
|
+
|
|
43
|
+
let promise: Promise<any> = Promise.resolve()
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
this.#lock = true
|
|
47
|
+
this.sneak = v
|
|
48
|
+
promise = Promise.all([
|
|
49
|
+
tracker.notifyWrite(this),
|
|
50
|
+
this.on.publish(v),
|
|
51
|
+
])
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
this.#lock = false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await promise
|
|
58
|
+
return v
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get core() {
|
|
62
|
+
return this
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn() {
|
|
66
|
+
const that = this as Signal<V>
|
|
67
|
+
|
|
68
|
+
function f(): V
|
|
69
|
+
function f(v: V): Promise<V>
|
|
70
|
+
function f(_v?: V): V | Promise<V> {
|
|
71
|
+
return (arguments.length === 0)
|
|
72
|
+
? that.get()
|
|
73
|
+
: that.set(arguments[0])
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
f.core = that
|
|
77
|
+
f.get = that.get.bind(that)
|
|
78
|
+
f.set = that.set.bind(that)
|
|
79
|
+
f.on = that.on
|
|
80
|
+
f.dispose = that.dispose.bind(that)
|
|
81
|
+
f.publish = that.publish.bind(that)
|
|
82
|
+
f.fn = that.fn.bind(that)
|
|
83
|
+
|
|
84
|
+
Object.defineProperty(f, "value", {
|
|
85
|
+
get: () => that.value,
|
|
86
|
+
set: (v) => that.value = v,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
Object.defineProperty(f, "sneak", {
|
|
90
|
+
get: () => that.sneak,
|
|
91
|
+
set: (v) => that.sneak = v,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
return f as SignalFn<V>
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
package/s/signals/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
export * from "./parts/reactive.js"
|
|
3
|
-
export * from "./parts/readable.js"
|
|
4
|
-
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
export * from "./
|
|
8
|
-
|
|
9
|
-
export * from "./
|
|
2
|
+
export * from "./core/parts/reactive.js"
|
|
3
|
+
export * from "./core/parts/readable.js"
|
|
4
|
+
export * from "./core/derived.js"
|
|
5
|
+
export * from "./core/effect.js"
|
|
6
|
+
export * from "./core/lazy.js"
|
|
7
|
+
export * from "./core/signal.js"
|
|
8
|
+
|
|
9
|
+
export * from "./r/map.js"
|
|
10
|
+
export * from "./r/set.js"
|
|
11
|
+
|
|
12
|
+
export * from "./porcelain.js"
|
|
10
13
|
export * from "./types.js"
|
|
11
14
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import {SignalOptions} from "./types.js"
|
|
3
|
+
import {Lazy} from "./core/lazy.js"
|
|
4
|
+
import {Signal} from "./core/signal.js"
|
|
5
|
+
import {Derived} from "./core/derived.js"
|
|
6
|
+
|
|
7
|
+
export function lazy<V>(
|
|
8
|
+
formula: () => V,
|
|
9
|
+
options?: Partial<SignalOptions>,
|
|
10
|
+
) {
|
|
11
|
+
return new Lazy<V>(formula, options).fn()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function derived<V>(
|
|
15
|
+
formula: () => V,
|
|
16
|
+
options?: Partial<SignalOptions>,
|
|
17
|
+
) {
|
|
18
|
+
return new Derived<V>(formula, options).fn()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function signal<V>(
|
|
22
|
+
value: V,
|
|
23
|
+
options?: Partial<SignalOptions>,
|
|
24
|
+
) {
|
|
25
|
+
return new Signal<V>(value, options).fn()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
signal.lazy = lazy
|
|
29
|
+
signal.derived = derived
|
|
30
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
import {MapG} from "@e280/stz"
|
|
3
|
+
import {tracker} from "../../tracker/tracker.js"
|
|
4
|
+
|
|
5
|
+
export class RMap<K, V> extends MapG<K, V> {
|
|
6
|
+
get size() {
|
|
7
|
+
tracker.notifyRead(this)
|
|
8
|
+
return super.size
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
;[Symbol.iterator]() {
|
|
12
|
+
tracker.notifyRead(this)
|
|
13
|
+
return super[Symbol.iterator]()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
keys() {
|
|
17
|
+
tracker.notifyRead(this)
|
|
18
|
+
return super.keys()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
values() {
|
|
22
|
+
tracker.notifyRead(this)
|
|
23
|
+
return super.values()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
entries() {
|
|
27
|
+
tracker.notifyRead(this)
|
|
28
|
+
return super.entries()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
forEach(callbackFn: (value: V, key: K, map: Map<K, V>) => void) {
|
|
32
|
+
tracker.notifyRead(this)
|
|
33
|
+
return super.forEach(callbackFn)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
has(key: K) {
|
|
37
|
+
tracker.notifyRead(this)
|
|
38
|
+
return super.has(key)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get(key: K) {
|
|
42
|
+
tracker.notifyRead(this)
|
|
43
|
+
return super.get(key)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
set(key: K, value: V) {
|
|
47
|
+
const r = super.set(key, value)
|
|
48
|
+
tracker.notifyWrite(this)
|
|
49
|
+
return r
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
delete(key: K) {
|
|
53
|
+
const r = super.delete(key)
|
|
54
|
+
tracker.notifyWrite(this)
|
|
55
|
+
return r
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
clear() {
|
|
59
|
+
super.clear()
|
|
60
|
+
tracker.notifyWrite(this)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
import {SetG} from "@e280/stz"
|
|
3
|
+
import {tracker} from "../../tracker/tracker.js"
|
|
4
|
+
|
|
5
|
+
export class RSet<T> extends SetG<T> {
|
|
6
|
+
get size() {
|
|
7
|
+
tracker.notifyRead(this)
|
|
8
|
+
return super.size
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
;[Symbol.iterator]() {
|
|
12
|
+
tracker.notifyRead(this)
|
|
13
|
+
return super[Symbol.iterator]()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
values() {
|
|
17
|
+
tracker.notifyRead(this)
|
|
18
|
+
return super.values()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
has(item: T) {
|
|
22
|
+
tracker.notifyRead(this)
|
|
23
|
+
return super.has(item)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
add(item: T) {
|
|
27
|
+
super.add(item)
|
|
28
|
+
tracker.notifyWrite(this)
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
delete(item: T) {
|
|
33
|
+
const r = super.delete(item)
|
|
34
|
+
tracker.notifyWrite(this)
|
|
35
|
+
return r
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
clear() {
|
|
39
|
+
super.clear()
|
|
40
|
+
tracker.notifyWrite(this)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
import {Science} from "@e280/science"
|
|
3
|
-
|
|
4
|
-
import signalFnTest from "./tests/signal-fn.test.js"
|
|
3
|
+
|
|
5
4
|
import effectTest from "./tests/effect.test.js"
|
|
5
|
+
import signalTest from "./tests/signal.test.js"
|
|
6
|
+
import derivedTest from "./tests/derived.test.js"
|
|
6
7
|
import lazyTest from "./tests/lazy.test.js"
|
|
7
|
-
import deriveTest from "./tests/derive.test.js"
|
|
8
8
|
|
|
9
9
|
export default Science.suite({
|
|
10
|
-
"signal": signalTest,
|
|
11
|
-
"signal.fn": signalFnTest,
|
|
12
10
|
"effect": effectTest,
|
|
11
|
+
"signal": signalTest,
|
|
12
|
+
"derived": derivedTest,
|
|
13
13
|
"lazy": lazyTest,
|
|
14
|
-
"derive": deriveTest,
|
|
15
14
|
})
|
|
16
15
|
|