@esportsplus/reactivity 0.31.2 → 0.32.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/.claude/CHANGELOG.md +43 -0
- package/README.md +13 -6
- package/bench/cellx.bench.ts +61 -0
- package/bench/dynamic.bench.ts +103 -0
- package/bench/kairo.bench.ts +368 -0
- package/bench/lib/reactive-adapter.ts +51 -0
- package/bench/molbench.bench.ts +75 -0
- package/{tests/bench/system.ts → bench/system.bench.ts} +3 -3
- package/build/compiler/array.d.ts +1 -1
- package/build/compiler/constants.d.ts +7 -6
- package/build/compiler/constants.js +6 -7
- package/build/compiler/object.d.ts +1 -1
- package/build/compiler/object.js +1 -2
- package/build/compiler/primitives.d.ts +1 -1
- package/build/constants.d.ts +3 -1
- package/build/constants.js +3 -1
- package/build/reactive/array.d.ts +8 -5
- package/build/reactive/array.js +14 -14
- package/build/reactive/index.d.ts +2 -2
- package/build/reactive/index.js +1 -1
- package/build/reactive/object.d.ts +4 -4
- package/build/reactive/object.js +8 -23
- package/build/system.d.ts +15 -6
- package/build/system.js +415 -69
- package/build/types.d.ts +16 -4
- package/package.json +5 -2
- package/pnpm-workspace.yaml +2 -0
- package/src/compiler/array.ts +1 -1
- package/src/compiler/constants.ts +8 -6
- package/src/compiler/index.ts +2 -1
- package/src/compiler/object.ts +2 -2
- package/src/compiler/plugins/vite.ts +1 -0
- package/src/compiler/primitives.ts +1 -1
- package/src/constants.ts +6 -2
- package/src/reactive/array.ts +26 -23
- package/src/reactive/index.ts +6 -6
- package/src/reactive/object.ts +16 -41
- package/src/system.ts +612 -80
- package/src/types.ts +29 -9
- package/test/async-computed.test.ts +323 -0
- package/test/async-errors.test.ts +146 -0
- package/test/async-hardening.test.ts +73 -0
- package/test/async-iterable.test.ts +221 -0
- package/test/async-nested.test.ts +19 -0
- package/test/deep-graphs.test.ts +215 -0
- package/{tests/effects.ts → test/effects.test.ts} +60 -0
- package/test/equals.test.ts +142 -0
- package/test/errors.test.ts +201 -0
- package/test/flush.test.ts +185 -0
- package/test/glitch-freedom.test.ts +115 -0
- package/test/invalidate.test.ts +147 -0
- package/test/lib/wait-for.ts +28 -0
- package/test/pending-writes.test.ts +139 -0
- package/{tests/reactive.ts → test/reactive/reactive.test.ts} +20 -19
- package/test/read-dedup.test.ts +120 -0
- package/test/signal-selector.test.ts +187 -0
- package/{tests/system.ts → test/system.test.ts} +214 -23
- package/test/tsconfig.json +16 -0
- package/test/untrack.test.ts +146 -0
- package/vitest.config.ts +2 -2
- package/tests/async-computed.ts +0 -239
- /package/{tests/bench/array.ts → bench/reactive/array.bench.ts} +0 -0
- /package/{tests/bench/reactive-object.ts → bench/reactive/reactive-object.bench.ts} +0 -0
- /package/{tests → bench}/tsconfig.json +0 -0
- /package/{tests/compiler.ts → test/compiler/compiler.test.ts} +0 -0
- /package/{tests/primitives.ts → test/primitives.test.ts} +0 -0
- /package/{tests/array.ts → test/reactive/array.test.ts} +0 -0
- /package/{tests/nested.ts → test/reactive/nested.test.ts} +0 -0
- /package/{tests/objects.ts → test/reactive/objects.test.ts} +0 -0
package/tests/async-computed.ts
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { asyncComputed, effect, read, root, signal, write } from '~/system';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
describe('asyncComputed', () => {
|
|
6
|
-
it('initial value is undefined', () => {
|
|
7
|
-
root(() => {
|
|
8
|
-
let node = asyncComputed(() => Promise.resolve(42));
|
|
9
|
-
|
|
10
|
-
expect(read(node)).toBeUndefined();
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('resolves to correct value', async () => {
|
|
15
|
-
let node!: ReturnType<typeof asyncComputed<number>>;
|
|
16
|
-
|
|
17
|
-
root(() => {
|
|
18
|
-
node = asyncComputed(() => Promise.resolve(42));
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
22
|
-
|
|
23
|
-
expect(read(node)).toBe(42);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('updates when dependency changes', async () => {
|
|
27
|
-
let node!: ReturnType<typeof asyncComputed<string>>,
|
|
28
|
-
s = signal('hello');
|
|
29
|
-
|
|
30
|
-
root(() => {
|
|
31
|
-
node = asyncComputed(() => Promise.resolve(read(s)));
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
35
|
-
|
|
36
|
-
expect(read(node)).toBe('hello');
|
|
37
|
-
|
|
38
|
-
write(s, 'world');
|
|
39
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
40
|
-
|
|
41
|
-
expect(read(node)).toBe('world');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('race condition — rapid changes, only latest promise writes', async () => {
|
|
45
|
-
let node!: ReturnType<typeof asyncComputed<number>>,
|
|
46
|
-
resolvers: ((v: number) => void)[] = [],
|
|
47
|
-
s = signal(1);
|
|
48
|
-
|
|
49
|
-
root(() => {
|
|
50
|
-
node = asyncComputed(() => {
|
|
51
|
-
read(s);
|
|
52
|
-
return new Promise<number>((resolve) => {
|
|
53
|
-
resolvers.push(resolve);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
expect(read(node)).toBeUndefined();
|
|
59
|
-
|
|
60
|
-
write(s, 2);
|
|
61
|
-
await Promise.resolve();
|
|
62
|
-
await Promise.resolve();
|
|
63
|
-
|
|
64
|
-
write(s, 3);
|
|
65
|
-
await Promise.resolve();
|
|
66
|
-
await Promise.resolve();
|
|
67
|
-
|
|
68
|
-
// Resolve first (stale)
|
|
69
|
-
resolvers[0](100);
|
|
70
|
-
await Promise.resolve();
|
|
71
|
-
|
|
72
|
-
expect(read(node)).toBeUndefined();
|
|
73
|
-
|
|
74
|
-
// Resolve second (stale)
|
|
75
|
-
resolvers[1](200);
|
|
76
|
-
await Promise.resolve();
|
|
77
|
-
|
|
78
|
-
expect(read(node)).toBeUndefined();
|
|
79
|
-
|
|
80
|
-
// Resolve latest
|
|
81
|
-
resolvers[2](300);
|
|
82
|
-
await Promise.resolve();
|
|
83
|
-
|
|
84
|
-
expect(read(node)).toBe(300);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('onCleanup works for abort controller', async () => {
|
|
88
|
-
let aborted = false,
|
|
89
|
-
s = signal(1);
|
|
90
|
-
|
|
91
|
-
root(() => {
|
|
92
|
-
asyncComputed((onCleanup) => {
|
|
93
|
-
let controller = new AbortController();
|
|
94
|
-
|
|
95
|
-
controller.signal.addEventListener('abort', () => {
|
|
96
|
-
aborted = true;
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
onCleanup(() => controller.abort());
|
|
100
|
-
|
|
101
|
-
return Promise.resolve(read(s));
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
106
|
-
|
|
107
|
-
expect(aborted).toBe(false);
|
|
108
|
-
|
|
109
|
-
write(s, 2);
|
|
110
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
111
|
-
|
|
112
|
-
expect(aborted).toBe(true);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('effect tracks async computed', async () => {
|
|
116
|
-
let node!: ReturnType<typeof asyncComputed<number>>,
|
|
117
|
-
s = signal(10),
|
|
118
|
-
values: (number | undefined)[] = [];
|
|
119
|
-
|
|
120
|
-
root(() => {
|
|
121
|
-
node = asyncComputed(() => Promise.resolve(read(s)));
|
|
122
|
-
|
|
123
|
-
effect(() => {
|
|
124
|
-
values.push(read(node));
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
expect(values).toEqual([undefined]);
|
|
129
|
-
|
|
130
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
131
|
-
|
|
132
|
-
expect(values).toEqual([undefined, 10]);
|
|
133
|
-
|
|
134
|
-
write(s, 20);
|
|
135
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
136
|
-
|
|
137
|
-
expect(values).toEqual([undefined, 10, 20]);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('dispose stops updates', async () => {
|
|
141
|
-
let node!: ReturnType<typeof asyncComputed<number>>,
|
|
142
|
-
s = signal(1);
|
|
143
|
-
|
|
144
|
-
let disposeRoot!: VoidFunction;
|
|
145
|
-
|
|
146
|
-
root((dispose) => {
|
|
147
|
-
disposeRoot = dispose;
|
|
148
|
-
node = asyncComputed(() => Promise.resolve(read(s)));
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
152
|
-
|
|
153
|
-
expect(read(node)).toBe(1);
|
|
154
|
-
|
|
155
|
-
disposeRoot();
|
|
156
|
-
|
|
157
|
-
write(s, 2);
|
|
158
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
159
|
-
|
|
160
|
-
expect(read(node)).toBe(1);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('nested asyncComputed — B depends on A', async () => {
|
|
164
|
-
let s = signal(5),
|
|
165
|
-
nodeA!: ReturnType<typeof asyncComputed<number>>,
|
|
166
|
-
nodeB!: ReturnType<typeof asyncComputed<number>>;
|
|
167
|
-
|
|
168
|
-
root(() => {
|
|
169
|
-
nodeA = asyncComputed(() => Promise.resolve(read(s) * 2));
|
|
170
|
-
|
|
171
|
-
nodeB = asyncComputed(() => {
|
|
172
|
-
let a = read(nodeA);
|
|
173
|
-
|
|
174
|
-
if (a === undefined) {
|
|
175
|
-
return Promise.resolve(0);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return Promise.resolve(a + 100);
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// Initially both undefined
|
|
183
|
-
expect(read(nodeA)).toBeUndefined();
|
|
184
|
-
expect(read(nodeB)).toBeUndefined();
|
|
185
|
-
|
|
186
|
-
// Wait for A to resolve
|
|
187
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
188
|
-
|
|
189
|
-
expect(read(nodeA)).toBe(10);
|
|
190
|
-
|
|
191
|
-
// Wait for B to react to A's resolved value
|
|
192
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
193
|
-
|
|
194
|
-
expect(read(nodeB)).toBe(110);
|
|
195
|
-
|
|
196
|
-
// Update source signal — A and B should both update
|
|
197
|
-
write(s, 20);
|
|
198
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
199
|
-
|
|
200
|
-
expect(read(nodeA)).toBe(40);
|
|
201
|
-
|
|
202
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
203
|
-
|
|
204
|
-
expect(read(nodeB)).toBe(140);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('rejected promise does not crash and retains previous value', async () => {
|
|
208
|
-
let node!: ReturnType<typeof asyncComputed<number>>,
|
|
209
|
-
s = signal(1);
|
|
210
|
-
|
|
211
|
-
root(() => {
|
|
212
|
-
node = asyncComputed(() => {
|
|
213
|
-
let v = read(s);
|
|
214
|
-
|
|
215
|
-
if (v === 2) {
|
|
216
|
-
return Promise.reject(new Error('fail'));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return Promise.resolve(v);
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
224
|
-
|
|
225
|
-
expect(read(node)).toBe(1);
|
|
226
|
-
|
|
227
|
-
write(s, 2);
|
|
228
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
229
|
-
|
|
230
|
-
// Value should remain 1 after rejection
|
|
231
|
-
expect(read(node)).toBe(1);
|
|
232
|
-
|
|
233
|
-
write(s, 3);
|
|
234
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
235
|
-
|
|
236
|
-
// Resumes after non-rejected promise
|
|
237
|
-
expect(read(node)).toBe(3);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|