@manyducks.co/dolla 2.0.0-alpha.8 → 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 +222 -512
- package/dist/core/app.d.ts +24 -0
- package/dist/core/context.d.ts +147 -0
- package/dist/core/env.d.ts +3 -0
- package/dist/core/hooks.d.ts +70 -0
- package/dist/core/hooks.test.d.ts +1 -0
- package/dist/core/index.d.ts +25 -0
- package/dist/core/logger.d.ts +42 -0
- package/dist/core/logger.test.d.ts +0 -0
- package/dist/core/markup.d.ts +82 -0
- package/dist/core/markup.test.d.ts +0 -0
- package/dist/core/nodes/_markup.d.ts +36 -0
- package/dist/core/nodes/dom.d.ts +13 -0
- package/dist/core/nodes/dynamic.d.ts +22 -0
- package/dist/core/nodes/element.d.ts +27 -0
- package/dist/core/nodes/portal.d.ts +18 -0
- package/dist/core/nodes/repeat.d.ts +27 -0
- package/dist/core/nodes/view.d.ts +25 -0
- package/dist/core/ref.d.ts +19 -0
- package/dist/core/ref.test.d.ts +1 -0
- package/dist/core/signals.d.ts +100 -0
- package/dist/core/signals.test.d.ts +1 -0
- package/dist/{views → core/views}/default-crash-view.d.ts +11 -4
- package/dist/core/views/for.d.ts +21 -0
- package/dist/core/views/fragment.d.ts +7 -0
- package/dist/core/views/portal.d.ts +16 -0
- package/dist/core/views/show.d.ts +25 -0
- package/dist/fragment-BahD_BJA.js +7 -0
- package/dist/fragment-BahD_BJA.js.map +1 -0
- package/dist/{modules/http.d.ts → http/index.d.ts} +3 -5
- package/dist/http.js +150 -0
- package/dist/http.js.map +1 -0
- package/dist/i18n/index.d.ts +134 -0
- package/dist/i18n.js +309 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index-DRJlxs-Q.js +535 -0
- package/dist/index-DRJlxs-Q.js.map +1 -0
- package/dist/index.js +160 -1386
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +3 -2
- package/dist/jsx-dev-runtime.js +5 -12
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +4 -3
- package/dist/jsx-runtime.js +9 -15
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/logger-Aqi9m1CF.js +565 -0
- package/dist/logger-Aqi9m1CF.js.map +1 -0
- package/dist/markup-8jNhoqDe.js +1089 -0
- package/dist/markup-8jNhoqDe.js.map +1 -0
- package/dist/router/hooks.d.ts +2 -0
- package/dist/router/index.d.ts +3 -0
- package/dist/router/router.d.ts +166 -0
- package/dist/{routing.d.ts → router/router.utils.d.ts} +17 -3
- package/dist/router/router.utils.test.d.ts +1 -0
- package/dist/router.js +6 -0
- package/dist/router.js.map +1 -0
- package/dist/typeChecking-5kmX0ulW.js +65 -0
- package/dist/typeChecking-5kmX0ulW.js.map +1 -0
- package/dist/typeChecking.d.ts +2 -98
- package/dist/typeChecking.test.d.ts +1 -0
- package/dist/types.d.ts +97 -25
- package/dist/utils.d.ts +25 -3
- package/docs/buildless.md +132 -0
- package/docs/components.md +238 -0
- package/docs/hooks.md +356 -0
- package/docs/http.md +178 -0
- package/docs/i18n.md +220 -0
- package/docs/index.md +10 -0
- package/docs/markup.md +136 -0
- package/docs/mixins.md +176 -0
- package/docs/ref.md +77 -0
- package/docs/router.md +281 -0
- package/docs/setup.md +137 -0
- package/docs/signals.md +262 -0
- package/docs/stores.md +113 -0
- package/docs/views.md +356 -0
- package/index.d.ts +2 -2
- package/notes/atomic.md +452 -0
- package/notes/elimination.md +33 -0
- package/notes/observable.md +180 -0
- package/notes/scratch.md +350 -18
- package/notes/splitting.md +5 -0
- package/package.json +29 -15
- package/vite.config.js +5 -11
- package/build.js +0 -34
- package/dist/index.d.ts +0 -21
- package/dist/markup.d.ts +0 -108
- package/dist/modules/dolla.d.ts +0 -111
- package/dist/modules/language.d.ts +0 -41
- package/dist/modules/render.d.ts +0 -17
- package/dist/modules/router.d.ts +0 -152
- package/dist/nodes/cond.d.ts +0 -26
- package/dist/nodes/html.d.ts +0 -31
- package/dist/nodes/observer.d.ts +0 -29
- package/dist/nodes/outlet.d.ts +0 -22
- package/dist/nodes/portal.d.ts +0 -19
- package/dist/nodes/repeat.d.ts +0 -34
- package/dist/nodes/text.d.ts +0 -19
- package/dist/passthrough-9kwwjgWk.js +0 -1279
- package/dist/passthrough-9kwwjgWk.js.map +0 -1
- package/dist/state.d.ts +0 -101
- package/dist/view.d.ts +0 -65
- package/dist/views/passthrough.d.ts +0 -5
- package/notes/context-vars.md +0 -21
- package/notes/readme-scratch.md +0 -222
- package/notes/route-middleware.md +0 -42
- package/tests/state.test.js +0 -135
- /package/dist/{routing.test.d.ts → core/context.test.d.ts} +0 -0
package/notes/readme-scratch.md
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
# README
|
|
2
|
-
|
|
3
|
-
> This note will eventually become the new README. Here I'm laying out my ideal framework API.
|
|
4
|
-
|
|
5
|
-
A basic component.
|
|
6
|
-
|
|
7
|
-
```jsx
|
|
8
|
-
import Dolla, { createState, derive } from "@manyducks.co/dolla";
|
|
9
|
-
|
|
10
|
-
function ExampleView(props, ctx) {
|
|
11
|
-
const [$count, setCount] = createState(5);
|
|
12
|
-
const $doubled = derive([$count], (n) => n * 2);
|
|
13
|
-
|
|
14
|
-
ctx.watch([$count], (count) => {
|
|
15
|
-
ctx.log("value of count is now %n", count);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
return <p>{$count}</p>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
Dolla.mount(document.body, ExampleView);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
<details open>
|
|
25
|
-
<summary>
|
|
26
|
-
<h2>Signals API</h2>
|
|
27
|
-
</summary>
|
|
28
|
-
|
|
29
|
-
The signals API. Dolla's signals use explicit tracking, meaning any function where signal values are tracked take an array of the signals you want to track. This way you know exactly what depends on what at a glance without any kind of hidden tracking logic behind the scenes. You are free to `.get()` the value of a signal without worrying about untracking it first.
|
|
30
|
-
|
|
31
|
-
```jsx
|
|
32
|
-
import { createState } from "@manyducks.co/dolla";
|
|
33
|
-
|
|
34
|
-
const [$count, setCount] = createState(256);
|
|
35
|
-
|
|
36
|
-
$count.get(); // 256; returns the current value
|
|
37
|
-
|
|
38
|
-
const stop = $count.watch((value) => {
|
|
39
|
-
// Runs once immediately, then again whenever the value changes.
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
setCount(512); // Update the value of $count. The new value is set and all watchers run synchronously.
|
|
43
|
-
|
|
44
|
-
stop(); // Stop watching for changes.
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
That is the basic signal API. Signals are all about composability. Here are some more advanced ways of working with them:
|
|
48
|
-
|
|
49
|
-
```jsx
|
|
50
|
-
import { createState, toState, valueOf, derive } from "@manyducks.co/dolla";
|
|
51
|
-
|
|
52
|
-
const [$count, setCount] = createState(72);
|
|
53
|
-
|
|
54
|
-
// Returns the value of the signal passed in. If the value is not a signal it is returned as is.
|
|
55
|
-
const count = valueOf($count);
|
|
56
|
-
const bool = valueOf(true);
|
|
57
|
-
|
|
58
|
-
// Creates a signal containing the value passed in. If the value is already a signal it is returned as is.
|
|
59
|
-
const $bool = toState(true);
|
|
60
|
-
const $anotherCount = toState($count);
|
|
61
|
-
|
|
62
|
-
// Derive a new signal from the value of another. Whenever $count changes, $doubled will follow.
|
|
63
|
-
const $doubled = derive([$count], (count) => count * 2);
|
|
64
|
-
|
|
65
|
-
// Derive a new signal from the values of several others. When any value in the list changes, $sum will be recomputed.
|
|
66
|
-
const $sum = derive([$count, $doubled], (count, doubled) => count + doubled);
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
The API if we call it State instead of Signal to distance from the Signal object in standardization process.
|
|
70
|
-
|
|
71
|
-
```jsx
|
|
72
|
-
import { createState, toState, valueOf, derive } from "@manyducks.co/dolla";
|
|
73
|
-
|
|
74
|
-
const [$count, setCount] = createState(72);
|
|
75
|
-
|
|
76
|
-
// Returns the value of the signal passed in. If the value is not a signal it is returned as is.
|
|
77
|
-
const count = valueOf($count);
|
|
78
|
-
const bool = valueOf(true);
|
|
79
|
-
|
|
80
|
-
// Creates a signal containing the value passed in. If the value is already a signal it is returned as is.
|
|
81
|
-
const $bool = toState(true);
|
|
82
|
-
const $anotherCount = toState($count);
|
|
83
|
-
|
|
84
|
-
// Derive a new signal from the value of another. Whenever $count changes, $doubled will follow.
|
|
85
|
-
const $doubled = derive([$count], (count) => count * 2);
|
|
86
|
-
|
|
87
|
-
// Derive a new signal from the values of several others. When any value in the list changes, $sum will be recomputed.
|
|
88
|
-
const $sum = derive([$count, $doubled], (count, doubled) => count + doubled);
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
States also come in a settable variety, with the setter included on the same object. Sometimes you want to pass around a two-way binding and this is what SettableState is for.
|
|
92
|
-
|
|
93
|
-
```jsx
|
|
94
|
-
import { createSettableState, fromSettable, toSettable } from "@manyducks.co/dolla";
|
|
95
|
-
|
|
96
|
-
// Settable states have their setter included.
|
|
97
|
-
const $$value = createSettableState("Test");
|
|
98
|
-
$$value.set("New Value");
|
|
99
|
-
|
|
100
|
-
// They can also be split into a State and Setter
|
|
101
|
-
const [$value, setValue] = fromSettableState($$value);
|
|
102
|
-
|
|
103
|
-
// And a State and Setter can be combined into a SettableState.
|
|
104
|
-
const $$otherValue = toSettableState($value, setValue);
|
|
105
|
-
|
|
106
|
-
// Or discard the setter and make it read-only using the good old toState function:
|
|
107
|
-
const $value = toState($$value);
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Alternative API
|
|
111
|
-
|
|
112
|
-
```jsx
|
|
113
|
-
import { State } from "@manyducks.co/dolla";
|
|
114
|
-
|
|
115
|
-
const [$count, setCount] = State(72);
|
|
116
|
-
|
|
117
|
-
const count = State.unwrap($count);
|
|
118
|
-
const bool = State.unwrap(true);
|
|
119
|
-
|
|
120
|
-
const $bool = State.wrap(true);
|
|
121
|
-
const $sameCount = State.wrap($count);
|
|
122
|
-
|
|
123
|
-
const $doubled = State.from([$count], (count) => count * 2);
|
|
124
|
-
|
|
125
|
-
const $sum = State.from([$count, $doubled], (count, doubled) => count + doubled);
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Yet another
|
|
129
|
-
|
|
130
|
-
```jsx
|
|
131
|
-
import Dolla from "@manyducks.co/dolla";
|
|
132
|
-
|
|
133
|
-
const [$count, setCount] = Dolla.state(72);
|
|
134
|
-
|
|
135
|
-
const count = Dolla.get($count);
|
|
136
|
-
const bool = Dolla.get(true);
|
|
137
|
-
|
|
138
|
-
const $bool = Dolla.toState(true);
|
|
139
|
-
const $sameCount = Dolla.toState($count);
|
|
140
|
-
|
|
141
|
-
const $doubled = Dolla.computed([$count], (count) => count * 2);
|
|
142
|
-
const $sum = Dolla.computed([$count, $doubled], (count, doubled) => count + doubled);
|
|
143
|
-
|
|
144
|
-
// or
|
|
145
|
-
|
|
146
|
-
import { state, computed, get, toState } from "@manyducks.co/dolla";
|
|
147
|
-
|
|
148
|
-
const [$count, setCount] = state(72);
|
|
149
|
-
|
|
150
|
-
const count = get($count);
|
|
151
|
-
const bool = get(true);
|
|
152
|
-
|
|
153
|
-
const $bool = toState(true);
|
|
154
|
-
const $sameCount = toState($count);
|
|
155
|
-
|
|
156
|
-
const $doubled = computed([$count], (count) => count * 2);
|
|
157
|
-
const $sum = computed([$count, $doubled], (count, doubled) => count + doubled);
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Settable signals:
|
|
161
|
-
|
|
162
|
-
```jsx
|
|
163
|
-
import { createSettableState, createSetter, toSettableSignal, fromSettableSignal } from "@manyducks.co/dolla";
|
|
164
|
-
|
|
165
|
-
// Create a SettableSignal, which is basically a signal and its setter combined into a single object.
|
|
166
|
-
const $$settable = createSettableState("Example");
|
|
167
|
-
|
|
168
|
-
// The basic API is identical...
|
|
169
|
-
$$settable.get();
|
|
170
|
-
const stop = $$settable.watch((value) => {
|
|
171
|
-
// ...
|
|
172
|
-
});
|
|
173
|
-
stop();
|
|
174
|
-
|
|
175
|
-
// ... except for the addition of a setter.
|
|
176
|
-
$$settable.set("Set me directly");
|
|
177
|
-
|
|
178
|
-
// When you already have a signal and a setter, they can be combined into one.
|
|
179
|
-
const $$count = toSettableSignal($count, setCount);
|
|
180
|
-
|
|
181
|
-
// This updates the original $signal value.
|
|
182
|
-
$$count.set(386);
|
|
183
|
-
|
|
184
|
-
// TODO: You can also split a SettableSignal into a signal and its setter.
|
|
185
|
-
const [$readable, setReadable] = fromSettableSignal($$settable);
|
|
186
|
-
|
|
187
|
-
// Create a custom setter. Calling this will cap the value to 100.
|
|
188
|
-
const setCountBounded = createSetter($count, (next, current) => {
|
|
189
|
-
return Math.min(100, next);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
setCountBounded((current) => {
|
|
193
|
-
return current + 1;
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Or make a proxy $$doubled -- but would you actually want to proxy things like this?
|
|
197
|
-
const [$count, setCount] = createState(5);
|
|
198
|
-
const $doubled = derive([$count], (count) => count * 2);
|
|
199
|
-
const $$doubled = toSettableSignal(
|
|
200
|
-
$doubled,
|
|
201
|
-
createSetter($doubled, (next, current) => {
|
|
202
|
-
setCount(next * 2);
|
|
203
|
-
}),
|
|
204
|
-
);
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
I'm not really sure we need all of this. On the chopping block:
|
|
208
|
-
|
|
209
|
-
- The entire concept of settable signals
|
|
210
|
-
- `createSettableState`
|
|
211
|
-
- `toSettableSignal`
|
|
212
|
-
- `fromSettableSignal`
|
|
213
|
-
- `createSetter`
|
|
214
|
-
|
|
215
|
-
This makes the entire API just four functions:
|
|
216
|
-
|
|
217
|
-
- `createState`
|
|
218
|
-
- `derive`
|
|
219
|
-
- `toState`
|
|
220
|
-
- `valueOf`
|
|
221
|
-
|
|
222
|
-
</details>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Router Middleware
|
|
2
|
-
|
|
3
|
-
Allow handling route guards, preloading, etc with per-route middleware. When a route is matched, all middleware from higher layers are run again.
|
|
4
|
-
|
|
5
|
-
```js
|
|
6
|
-
Dolla.router.setup({
|
|
7
|
-
middleware: [/* does it make sense to have global middleware? */]
|
|
8
|
-
routes: [
|
|
9
|
-
{ path: "/login", middleware: [auth] },
|
|
10
|
-
{ path: "/", middleware: [auth], routes: [{ path: "/example", view: ExampleView }] }
|
|
11
|
-
]
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
async function auth(ctx) {
|
|
15
|
-
// This check can be implemented however it needs to be for the app.
|
|
16
|
-
const authed = await isAuthorized();
|
|
17
|
-
|
|
18
|
-
if (ctx.path === "/login") {
|
|
19
|
-
if (authed) {
|
|
20
|
-
ctx.redirect("/");
|
|
21
|
-
}
|
|
22
|
-
} else {
|
|
23
|
-
if (!authed) {
|
|
24
|
-
ctx.redirect("/login");
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
// If no redirect has happened and nothing has been returned then we're clear to proceed.
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// A middleware can also return Markup to stay on the URL but show something different.
|
|
31
|
-
async function randomVisitor(ctx) {
|
|
32
|
-
if (Math.random() > 0.99) {
|
|
33
|
-
return <LuckyVisitorView />
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Or preload async data and set a context variable before navigating.
|
|
38
|
-
async function preload(ctx) {
|
|
39
|
-
const data = await fetchData();
|
|
40
|
-
ctx.set("data", data);
|
|
41
|
-
}
|
|
42
|
-
```
|
package/tests/state.test.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
3
|
-
|
|
4
|
-
import { createState, derive } from "../dist/index.js";
|
|
5
|
-
|
|
6
|
-
test("signal", (t) => {
|
|
7
|
-
const [$count, setCount] = createState(5);
|
|
8
|
-
|
|
9
|
-
const defaultWatcher = t.mock.fn();
|
|
10
|
-
const stopDefault = $count.watch(defaultWatcher);
|
|
11
|
-
|
|
12
|
-
const lazyWatcher = t.mock.fn();
|
|
13
|
-
const stopLazy = $count.watch(lazyWatcher, { lazy: true });
|
|
14
|
-
|
|
15
|
-
assert.equal(defaultWatcher.mock.callCount(), 1, "watcher is called immediately by default");
|
|
16
|
-
assert.equal(lazyWatcher.mock.callCount(), 0, "lazy watcher is not called immediately");
|
|
17
|
-
|
|
18
|
-
assert.equal($count.get(), 5, "get returns the initial value");
|
|
19
|
-
|
|
20
|
-
setCount(12);
|
|
21
|
-
|
|
22
|
-
assert.equal($count.get(), 12, "setter updates the signal value");
|
|
23
|
-
|
|
24
|
-
assert.equal(defaultWatcher.mock.callCount(), 2, "default watcher is called");
|
|
25
|
-
assert.equal(lazyWatcher.mock.callCount(), 1, "lazy watcher is called");
|
|
26
|
-
|
|
27
|
-
assert.deepStrictEqual(defaultWatcher.mock.calls[1].arguments, [12], "default watcher is called with new value");
|
|
28
|
-
assert.deepStrictEqual(lazyWatcher.mock.calls[0].arguments, [12], "lazy watcher is called with new value");
|
|
29
|
-
|
|
30
|
-
setCount(12);
|
|
31
|
-
|
|
32
|
-
assert.equal(defaultWatcher.mock.callCount(), 2, "default watcher was not called with same value");
|
|
33
|
-
assert.equal(lazyWatcher.mock.callCount(), 1, "lazy watcher was not called with same value");
|
|
34
|
-
|
|
35
|
-
stopDefault();
|
|
36
|
-
stopLazy();
|
|
37
|
-
|
|
38
|
-
setCount(51);
|
|
39
|
-
|
|
40
|
-
assert.equal(defaultWatcher.mock.callCount(), 2, "default watcher has not been called again");
|
|
41
|
-
assert.equal(lazyWatcher.mock.callCount(), 1, "lazy watcher has not been called again");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("derive", (t) => {
|
|
45
|
-
const [$one, setOne] = createState(5);
|
|
46
|
-
const [$two, setTwo] = createState(20);
|
|
47
|
-
|
|
48
|
-
const deriveSum = t.mock.fn((one, two) => one + two);
|
|
49
|
-
const deriveProduct = t.mock.fn((one, two) => one * two);
|
|
50
|
-
|
|
51
|
-
const $sum = derive([$one, $two], deriveSum);
|
|
52
|
-
const $product = derive([$one, $two], deriveProduct);
|
|
53
|
-
|
|
54
|
-
assert.equal($sum.get(), 25, "sum is calculated correctly");
|
|
55
|
-
assert.equal($product.get(), 100, "product is calculated correctly");
|
|
56
|
-
|
|
57
|
-
assert.equal(deriveSum.mock.callCount(), 1, "derive function has only been called once");
|
|
58
|
-
|
|
59
|
-
$sum.get();
|
|
60
|
-
$sum.get();
|
|
61
|
-
$sum.get();
|
|
62
|
-
|
|
63
|
-
assert.equal(deriveSum.mock.callCount(), 1, "derive function still only called once as dependencies haven't changed");
|
|
64
|
-
|
|
65
|
-
const defaultWatcher = t.mock.fn();
|
|
66
|
-
const stopDefault = $sum.watch(defaultWatcher);
|
|
67
|
-
|
|
68
|
-
const lazyWatcher = t.mock.fn();
|
|
69
|
-
const stopLazy = $product.watch(lazyWatcher, { lazy: true });
|
|
70
|
-
|
|
71
|
-
assert.equal(defaultWatcher.mock.callCount(), 1, "default watcher has been called");
|
|
72
|
-
assert.equal(lazyWatcher.mock.callCount(), 0, "lazy watcher has not been called yet");
|
|
73
|
-
|
|
74
|
-
assert.deepStrictEqual(defaultWatcher.mock.calls[0].arguments, [25], "default watcher was called with initial value");
|
|
75
|
-
|
|
76
|
-
setOne(6);
|
|
77
|
-
|
|
78
|
-
assert.equal(defaultWatcher.mock.callCount(), 2, "default watcher has been called");
|
|
79
|
-
assert.equal(lazyWatcher.mock.callCount(), 1, "lazy watcher has been called");
|
|
80
|
-
|
|
81
|
-
assert.deepStrictEqual(defaultWatcher.mock.calls[1].arguments, [26], "default watcher was called with new value");
|
|
82
|
-
assert.deepStrictEqual(lazyWatcher.mock.calls[0].arguments, [120], "lazy watcher was called with new value");
|
|
83
|
-
|
|
84
|
-
setTwo(20);
|
|
85
|
-
|
|
86
|
-
assert.equal(defaultWatcher.mock.callCount(), 2, "default watcher was not called with same value");
|
|
87
|
-
assert.equal(lazyWatcher.mock.callCount(), 1, "lazy watcher was not called with same value");
|
|
88
|
-
|
|
89
|
-
stopDefault();
|
|
90
|
-
stopLazy();
|
|
91
|
-
|
|
92
|
-
setOne(4);
|
|
93
|
-
|
|
94
|
-
assert.equal(defaultWatcher.mock.callCount(), 2, "default watcher was not called after stop");
|
|
95
|
-
assert.equal(lazyWatcher.mock.callCount(), 1, "lazy watcher was not called after stop");
|
|
96
|
-
|
|
97
|
-
assert.equal($sum.get(), 24, "sum is derived correctly");
|
|
98
|
-
assert.equal($product.get(), 80, "product is derived correctly");
|
|
99
|
-
|
|
100
|
-
assert.equal(deriveSum.mock.callCount(), 3, "sum has only been derived three times");
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("derive nested signals", (t) => {
|
|
104
|
-
const [$value, setValue] = createState(5);
|
|
105
|
-
|
|
106
|
-
const [$object, setObject] = createState({
|
|
107
|
-
href: derive([$value], (value) => `/projects/${value}/test`),
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// o.href here is itself a derived value
|
|
111
|
-
const $href = derive([$object], (o) => o.href);
|
|
112
|
-
|
|
113
|
-
const watcher = t.mock.fn();
|
|
114
|
-
const stop = $href.watch(watcher);
|
|
115
|
-
|
|
116
|
-
assert.equal(watcher.mock.callCount(), 1);
|
|
117
|
-
assert.deepStrictEqual(watcher.mock.calls[0].arguments, ["/projects/5/test"]);
|
|
118
|
-
|
|
119
|
-
// Update value which href depends on.
|
|
120
|
-
setValue(12);
|
|
121
|
-
|
|
122
|
-
assert.equal(watcher.mock.callCount(), 2);
|
|
123
|
-
assert.deepStrictEqual(watcher.mock.calls[1].arguments, ["/projects/12/test"]);
|
|
124
|
-
|
|
125
|
-
// Now set the original object and replace the derived href.
|
|
126
|
-
// See that watcher still receives the latest value.
|
|
127
|
-
setObject({
|
|
128
|
-
href: derive([$value], (value) => `/projects/${value}/changed`),
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
assert.equal(watcher.mock.callCount(), 3);
|
|
132
|
-
assert.deepStrictEqual(watcher.mock.calls[2].arguments, ["/projects/12/changed"]);
|
|
133
|
-
|
|
134
|
-
stop();
|
|
135
|
-
});
|
|
File without changes
|