@praxisjs/core 2.2.0 → 2.3.1
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/CHANGELOG.md +24 -0
- package/dist/component/internals.d.ts +12 -2
- package/dist/component/internals.d.ts.map +1 -1
- package/dist/component/internals.js +25 -7
- package/dist/component/internals.js.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -2
- package/dist/internal.js.map +1 -1
- package/dist/signal/batch.d.ts +1 -3
- package/dist/signal/batch.d.ts.map +1 -1
- package/dist/signal/batch.js +4 -30
- package/dist/signal/batch.js.map +1 -1
- package/dist/signal/computed.d.ts.map +1 -1
- package/dist/signal/computed.js +13 -66
- package/dist/signal/computed.js.map +1 -1
- package/dist/signal/effect.d.ts +6 -14
- package/dist/signal/effect.d.ts.map +1 -1
- package/dist/signal/effect.js +11 -83
- package/dist/signal/effect.js.map +1 -1
- package/dist/signal/graph.d.ts +111 -0
- package/dist/signal/graph.d.ts.map +1 -0
- package/dist/signal/graph.js +513 -0
- package/dist/signal/graph.js.map +1 -0
- package/dist/signal/index.d.ts +1 -0
- package/dist/signal/index.d.ts.map +1 -1
- package/dist/signal/index.js +1 -0
- package/dist/signal/index.js.map +1 -1
- package/dist/signal/peek.d.ts.map +1 -1
- package/dist/signal/peek.js +2 -9
- package/dist/signal/peek.js.map +1 -1
- package/dist/signal/selector.d.ts +5 -0
- package/dist/signal/selector.d.ts.map +1 -0
- package/dist/signal/selector.js +128 -0
- package/dist/signal/selector.js.map +1 -0
- package/dist/signal/signal.d.ts +0 -5
- package/dist/signal/signal.d.ts.map +1 -1
- package/dist/signal/signal.js +11 -70
- package/dist/signal/signal.js.map +1 -1
- package/package.json +13 -4
- package/src/component/internals.ts +35 -10
- package/src/internal.ts +26 -0
- package/src/signal/batch.ts +5 -33
- package/src/signal/computed.ts +13 -66
- package/src/signal/effect.ts +12 -92
- package/src/signal/graph.ts +562 -0
- package/src/signal/index.ts +1 -0
- package/src/signal/peek.ts +2 -8
- package/src/signal/selector.ts +140 -0
- package/src/signal/signal.ts +11 -74
- package/dist/__tests__/batch.test.d.ts +0 -2
- package/dist/__tests__/batch.test.d.ts.map +0 -1
- package/dist/__tests__/batch.test.js +0 -124
- package/dist/__tests__/batch.test.js.map +0 -1
- package/dist/__tests__/component.test.d.ts +0 -2
- package/dist/__tests__/component.test.d.ts.map +0 -1
- package/dist/__tests__/component.test.js +0 -124
- package/dist/__tests__/component.test.js.map +0 -1
- package/dist/__tests__/computed.test.d.ts +0 -2
- package/dist/__tests__/computed.test.d.ts.map +0 -1
- package/dist/__tests__/computed.test.js +0 -289
- package/dist/__tests__/computed.test.js.map +0 -1
- package/dist/__tests__/effect.test.d.ts +0 -2
- package/dist/__tests__/effect.test.d.ts.map +0 -1
- package/dist/__tests__/effect.test.js +0 -200
- package/dist/__tests__/effect.test.js.map +0 -1
- package/dist/__tests__/peek.test.d.ts +0 -2
- package/dist/__tests__/peek.test.d.ts.map +0 -1
- package/dist/__tests__/peek.test.js +0 -26
- package/dist/__tests__/peek.test.js.map +0 -1
- package/dist/__tests__/persisted-signal.test.d.ts +0 -2
- package/dist/__tests__/persisted-signal.test.d.ts.map +0 -1
- package/dist/__tests__/persisted-signal.test.js +0 -252
- package/dist/__tests__/persisted-signal.test.js.map +0 -1
- package/dist/__tests__/reactive.test.d.ts +0 -2
- package/dist/__tests__/reactive.test.d.ts.map +0 -1
- package/dist/__tests__/reactive.test.js +0 -299
- package/dist/__tests__/reactive.test.js.map +0 -1
- package/dist/__tests__/resource-focus.test.d.ts +0 -2
- package/dist/__tests__/resource-focus.test.d.ts.map +0 -1
- package/dist/__tests__/resource-focus.test.js +0 -50
- package/dist/__tests__/resource-focus.test.js.map +0 -1
- package/dist/__tests__/resource-server-pass.test.d.ts +0 -2
- package/dist/__tests__/resource-server-pass.test.d.ts.map +0 -1
- package/dist/__tests__/resource-server-pass.test.js +0 -78
- package/dist/__tests__/resource-server-pass.test.js.map +0 -1
- package/dist/__tests__/resource.test.d.ts +0 -2
- package/dist/__tests__/resource.test.d.ts.map +0 -1
- package/dist/__tests__/resource.test.js +0 -336
- package/dist/__tests__/resource.test.js.map +0 -1
- package/dist/__tests__/signal.test.d.ts +0 -2
- package/dist/__tests__/signal.test.d.ts.map +0 -1
- package/dist/__tests__/signal.test.js +0 -254
- package/dist/__tests__/signal.test.js.map +0 -1
- package/dist/__tests__/synced.test.d.ts +0 -2
- package/dist/__tests__/synced.test.d.ts.map +0 -1
- package/dist/__tests__/synced.test.js +0 -142
- package/dist/__tests__/synced.test.js.map +0 -1
- package/dist/__tests__/track.test.d.ts +0 -2
- package/dist/__tests__/track.test.d.ts.map +0 -1
- package/dist/__tests__/track.test.js +0 -54
- package/dist/__tests__/track.test.js.map +0 -1
- package/src/__tests__/batch.test.ts +0 -138
- package/src/__tests__/component.test.ts +0 -165
- package/src/__tests__/computed.test.ts +0 -333
- package/src/__tests__/effect.test.ts +0 -241
- package/src/__tests__/peek.test.ts +0 -31
- package/src/__tests__/persisted-signal.test.ts +0 -305
- package/src/__tests__/reactive.test.ts +0 -343
- package/src/__tests__/resource-focus.test.ts +0 -61
- package/src/__tests__/resource-server-pass.test.ts +0 -90
- package/src/__tests__/resource.test.ts +0 -421
- package/src/__tests__/signal.test.ts +0 -291
- package/src/__tests__/synced.test.ts +0 -173
- package/src/__tests__/track.test.ts +0 -61
- package/tsconfig.json +0 -8
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { batch } from "../signal/batch";
|
|
3
|
-
import { SUBS_SET_THRESHOLD } from "../signal/effect";
|
|
4
|
-
import { effect } from "../signal/effect";
|
|
5
|
-
import { signal, addSub, removeSub } from "../signal/signal";
|
|
6
|
-
describe("signal", () => {
|
|
7
|
-
it("returns initial value", () => {
|
|
8
|
-
const s = signal(42);
|
|
9
|
-
expect(s()).toBe(42);
|
|
10
|
-
});
|
|
11
|
-
it("updates value with set", () => {
|
|
12
|
-
const s = signal(0);
|
|
13
|
-
s.set(10);
|
|
14
|
-
expect(s()).toBe(10);
|
|
15
|
-
});
|
|
16
|
-
it("updates value with update fn", () => {
|
|
17
|
-
const s = signal(5);
|
|
18
|
-
s.update((v) => v * 2);
|
|
19
|
-
expect(s()).toBe(10);
|
|
20
|
-
});
|
|
21
|
-
it("skips update when value is identical", () => {
|
|
22
|
-
const s = signal(1);
|
|
23
|
-
const calls = [];
|
|
24
|
-
s.subscribe((v) => calls.push(v));
|
|
25
|
-
const before = calls.length;
|
|
26
|
-
s.set(1); // same value
|
|
27
|
-
expect(calls.length).toBe(before);
|
|
28
|
-
});
|
|
29
|
-
it("subscribe fires immediately with current value", () => {
|
|
30
|
-
const s = signal("hello");
|
|
31
|
-
const received = [];
|
|
32
|
-
s.subscribe((v) => received.push(v));
|
|
33
|
-
expect(received).toEqual(["hello"]);
|
|
34
|
-
});
|
|
35
|
-
it("subscribe fires on subsequent updates", () => {
|
|
36
|
-
const s = signal(0);
|
|
37
|
-
const received = [];
|
|
38
|
-
s.subscribe((v) => received.push(v));
|
|
39
|
-
s.set(1);
|
|
40
|
-
s.set(2);
|
|
41
|
-
expect(received).toEqual([0, 1, 2]);
|
|
42
|
-
});
|
|
43
|
-
it("unsubscribe stops receiving updates", () => {
|
|
44
|
-
const s = signal(0);
|
|
45
|
-
const received = [];
|
|
46
|
-
const unsub = s.subscribe((v) => received.push(v));
|
|
47
|
-
unsub();
|
|
48
|
-
s.set(99);
|
|
49
|
-
expect(received).toEqual([0]);
|
|
50
|
-
});
|
|
51
|
-
it("marks __isSignal = true", () => {
|
|
52
|
-
const s = signal(0);
|
|
53
|
-
expect(s.__isSignal).toBe(true);
|
|
54
|
-
});
|
|
55
|
-
it("supports object values", () => {
|
|
56
|
-
const s = signal({ name: "Alice" });
|
|
57
|
-
s.set({ name: "Bob" });
|
|
58
|
-
expect(s().name).toBe("Bob");
|
|
59
|
-
});
|
|
60
|
-
it("supports null and undefined", () => {
|
|
61
|
-
const s = signal(null);
|
|
62
|
-
expect(s()).toBeNull();
|
|
63
|
-
s.set(5);
|
|
64
|
-
expect(s()).toBe(5);
|
|
65
|
-
});
|
|
66
|
-
it("NaN is considered equal to NaN — no notification", () => {
|
|
67
|
-
const s = signal(NaN);
|
|
68
|
-
const calls = [];
|
|
69
|
-
s.subscribe((v) => calls.push(v));
|
|
70
|
-
const before = calls.length;
|
|
71
|
-
s.set(NaN);
|
|
72
|
-
expect(calls.length).toBe(before);
|
|
73
|
-
});
|
|
74
|
-
it("-0 and +0 are considered different — notification fires", () => {
|
|
75
|
-
const s = signal(-0);
|
|
76
|
-
const calls = [];
|
|
77
|
-
s.subscribe((v) => calls.push(v));
|
|
78
|
-
const before = calls.length;
|
|
79
|
-
s.set(+0);
|
|
80
|
-
expect(calls.length).toBe(before + 1);
|
|
81
|
-
});
|
|
82
|
-
it("update() fn that throws does not update the value", () => {
|
|
83
|
-
const s = signal(5);
|
|
84
|
-
expect(() => s.update(() => { throw new Error("fn error"); })).toThrow("fn error");
|
|
85
|
-
expect(s()).toBe(5);
|
|
86
|
-
});
|
|
87
|
-
it("multiple subscribers all receive the update", () => {
|
|
88
|
-
const s = signal(0);
|
|
89
|
-
const a = [];
|
|
90
|
-
const b = [];
|
|
91
|
-
s.subscribe((v) => a.push(v));
|
|
92
|
-
s.subscribe((v) => b.push(v));
|
|
93
|
-
s.set(7);
|
|
94
|
-
expect(a).toContain(7);
|
|
95
|
-
expect(b).toContain(7);
|
|
96
|
-
});
|
|
97
|
-
it("subscriber B still fires when subscriber A throws", () => {
|
|
98
|
-
const s = signal(0);
|
|
99
|
-
const received = [];
|
|
100
|
-
s.subscribe((v) => { if (v !== 0)
|
|
101
|
-
throw new Error("sub A throws"); });
|
|
102
|
-
s.subscribe((v) => received.push(v));
|
|
103
|
-
expect(() => s.set(1)).toThrow("sub A throws");
|
|
104
|
-
expect(received).toContain(1);
|
|
105
|
-
});
|
|
106
|
-
it("unsubscribe during notification does not crash", () => {
|
|
107
|
-
const s = signal(0);
|
|
108
|
-
let unsub;
|
|
109
|
-
unsub = s.subscribe(() => {
|
|
110
|
-
unsub?.();
|
|
111
|
-
});
|
|
112
|
-
expect(() => s.set(1)).not.toThrow();
|
|
113
|
-
});
|
|
114
|
-
it("unsubscribing one of multiple subscribers removes only that subscriber", () => {
|
|
115
|
-
const s = signal(0);
|
|
116
|
-
const a = [];
|
|
117
|
-
const b = [];
|
|
118
|
-
const unsubA = s.subscribe((v) => a.push(v));
|
|
119
|
-
s.subscribe((v) => b.push(v));
|
|
120
|
-
// subs is now an array — hits removeSub else branch
|
|
121
|
-
unsubA();
|
|
122
|
-
s.set(1);
|
|
123
|
-
expect(a).toEqual([0]); // A stopped after initial fire
|
|
124
|
-
expect(b).toEqual([0, 1]); // B still receives
|
|
125
|
-
});
|
|
126
|
-
it("unsubscribing a non-existent subscriber from array subs is a no-op", () => {
|
|
127
|
-
const s = signal(0);
|
|
128
|
-
const a = [];
|
|
129
|
-
const b = [];
|
|
130
|
-
s.subscribe((v) => a.push(v));
|
|
131
|
-
const unsubB = s.subscribe((v) => b.push(v));
|
|
132
|
-
unsubB(); // remove B, subs becomes array without B
|
|
133
|
-
unsubB(); // call again — idx will be -1, splice not called
|
|
134
|
-
expect(() => s.set(1)).not.toThrow();
|
|
135
|
-
expect(a).toContain(1);
|
|
136
|
-
});
|
|
137
|
-
it("batch defers notifications for multiple array subscribers", () => {
|
|
138
|
-
const s = signal(0);
|
|
139
|
-
const a = [];
|
|
140
|
-
const b = [];
|
|
141
|
-
s.subscribe((v) => a.push(v));
|
|
142
|
-
s.subscribe((v) => b.push(v));
|
|
143
|
-
// subs is an array; inside batch, notifySubs hits the batching=true array path
|
|
144
|
-
batch(() => {
|
|
145
|
-
s.set(1);
|
|
146
|
-
expect(a).toEqual([0]); // not yet fired
|
|
147
|
-
expect(b).toEqual([0]);
|
|
148
|
-
});
|
|
149
|
-
expect(a).toContain(1);
|
|
150
|
-
expect(b).toContain(1);
|
|
151
|
-
});
|
|
152
|
-
it("removeSub with non-matching single-function subscriber is a no-op", () => {
|
|
153
|
-
// When subs is a single function and we try to remove a different function,
|
|
154
|
-
// the holder must remain unchanged (subs !== eff → false branch).
|
|
155
|
-
const holder = { subs: null };
|
|
156
|
-
const fn1 = () => { };
|
|
157
|
-
const fn2 = () => { };
|
|
158
|
-
addSub(holder, fn1); // subs = fn1 (single function)
|
|
159
|
-
removeSub(holder, fn2); // fn2 !== fn1 → no-op
|
|
160
|
-
expect(holder.subs).toBe(fn1);
|
|
161
|
-
});
|
|
162
|
-
it("addSub does not add a duplicate subscriber to an array holder", () => {
|
|
163
|
-
const fn1 = () => { };
|
|
164
|
-
const fn2 = () => { };
|
|
165
|
-
const holder = { subs: [fn1, fn2] };
|
|
166
|
-
addSub(holder, fn2);
|
|
167
|
-
expect(holder.subs).toEqual([fn1, fn2]);
|
|
168
|
-
});
|
|
169
|
-
it("removeSub normalizes an emptied array holder back to null", () => {
|
|
170
|
-
const fn = () => { };
|
|
171
|
-
const holder = { subs: [fn] };
|
|
172
|
-
removeSub(holder, fn);
|
|
173
|
-
expect(holder.subs).toBeNull();
|
|
174
|
-
});
|
|
175
|
-
it("set() with mutated object reference (same ref) does NOT notify — Object.is semantics", () => {
|
|
176
|
-
const obj = { count: 0 };
|
|
177
|
-
const s = signal(obj);
|
|
178
|
-
const calls = [];
|
|
179
|
-
s.subscribe((v) => calls.push(v));
|
|
180
|
-
const before = calls.length;
|
|
181
|
-
// Mutate the object in-place and set the same reference
|
|
182
|
-
obj.count = 99;
|
|
183
|
-
s.set(obj);
|
|
184
|
-
// Object.is(obj, obj) === true, so no notification
|
|
185
|
-
expect(calls.length).toBe(before);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
describe("large subscriber lists", () => {
|
|
189
|
-
function fns(count) {
|
|
190
|
-
return Array.from({ length: count }, () => () => { });
|
|
191
|
-
}
|
|
192
|
-
it("keeps an array up to the threshold and promotes to a Set past it, preserving order", () => {
|
|
193
|
-
const holder = { subs: null };
|
|
194
|
-
const list = fns(SUBS_SET_THRESHOLD);
|
|
195
|
-
for (const fn of list)
|
|
196
|
-
addSub(holder, fn);
|
|
197
|
-
expect(Array.isArray(holder.subs)).toBe(true);
|
|
198
|
-
const extra = () => { };
|
|
199
|
-
addSub(holder, extra);
|
|
200
|
-
expect(holder.subs).toBeInstanceOf(Set);
|
|
201
|
-
expect([...holder.subs]).toEqual([...list, extra]);
|
|
202
|
-
});
|
|
203
|
-
it("addSub on a Set holder adds new subscribers and ignores duplicates", () => {
|
|
204
|
-
const list = fns(SUBS_SET_THRESHOLD + 1);
|
|
205
|
-
const holder = { subs: new Set(list) };
|
|
206
|
-
addSub(holder, list[0]);
|
|
207
|
-
expect(holder.subs.size).toBe(list.length);
|
|
208
|
-
const extra = () => { };
|
|
209
|
-
addSub(holder, extra);
|
|
210
|
-
expect(holder.subs.size).toBe(list.length + 1);
|
|
211
|
-
});
|
|
212
|
-
it("removeSub on a Set holder removes one subscriber, ignores unknown ones, and normalizes to null when emptied", () => {
|
|
213
|
-
const [a, b, stranger] = fns(3);
|
|
214
|
-
const holder = { subs: new Set([a, b]) };
|
|
215
|
-
removeSub(holder, stranger);
|
|
216
|
-
expect(holder.subs.size).toBe(2);
|
|
217
|
-
removeSub(holder, a);
|
|
218
|
-
expect([...holder.subs]).toEqual([b]);
|
|
219
|
-
removeSub(holder, b);
|
|
220
|
-
expect(holder.subs).toBeNull();
|
|
221
|
-
});
|
|
222
|
-
it("many effects on one signal all re-run once per change, in subscription order", () => {
|
|
223
|
-
const count = SUBS_SET_THRESHOLD * 3;
|
|
224
|
-
const s = signal(0);
|
|
225
|
-
const order = [];
|
|
226
|
-
const stops = Array.from({ length: count }, (_, i) => effect(() => {
|
|
227
|
-
void s();
|
|
228
|
-
order.push(i);
|
|
229
|
-
}));
|
|
230
|
-
order.length = 0;
|
|
231
|
-
s.set(1);
|
|
232
|
-
expect(order).toEqual(Array.from({ length: count }, (_, i) => i));
|
|
233
|
-
order.length = 0;
|
|
234
|
-
s.set(2);
|
|
235
|
-
expect(order).toEqual(Array.from({ length: count }, (_, i) => i));
|
|
236
|
-
stops.forEach((stop) => { stop(); });
|
|
237
|
-
order.length = 0;
|
|
238
|
-
s.set(3);
|
|
239
|
-
expect(order).toEqual([]);
|
|
240
|
-
});
|
|
241
|
-
it("an effect stopped while the signal holds a Set no longer runs, the others still do", () => {
|
|
242
|
-
const s = signal(0);
|
|
243
|
-
const runs = new Map();
|
|
244
|
-
const stops = Array.from({ length: SUBS_SET_THRESHOLD + 4 }, (_, i) => effect(() => {
|
|
245
|
-
void s();
|
|
246
|
-
runs.set(i, (runs.get(i) ?? 0) + 1);
|
|
247
|
-
}));
|
|
248
|
-
stops[2]();
|
|
249
|
-
s.set(1);
|
|
250
|
-
expect(runs.get(2)).toBe(1);
|
|
251
|
-
expect(runs.get(3)).toBe(2);
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
//# sourceMappingURL=signal.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signal.test.js","sourceRoot":"","sources":["../../src/__tests__/signal.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"synced.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/synced.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
import { syncedSignal } from "../signal/synced";
|
|
3
|
-
import { effect } from "../signal/effect";
|
|
4
|
-
// BroadcastChannel mock
|
|
5
|
-
class MockBroadcastChannel {
|
|
6
|
-
static instances = [];
|
|
7
|
-
static byChannel = new Map();
|
|
8
|
-
onmessage = null;
|
|
9
|
-
name;
|
|
10
|
-
closed = false;
|
|
11
|
-
constructor(name) {
|
|
12
|
-
this.name = name;
|
|
13
|
-
MockBroadcastChannel.instances.push(this);
|
|
14
|
-
if (!MockBroadcastChannel.byChannel.has(name)) {
|
|
15
|
-
MockBroadcastChannel.byChannel.set(name, []);
|
|
16
|
-
}
|
|
17
|
-
MockBroadcastChannel.byChannel.get(name).push(this);
|
|
18
|
-
}
|
|
19
|
-
postMessage(data) {
|
|
20
|
-
// Deliver to all OTHER instances on same channel
|
|
21
|
-
MockBroadcastChannel.byChannel.get(this.name)?.forEach((ch) => {
|
|
22
|
-
if (ch !== this && ch.onmessage) {
|
|
23
|
-
ch.onmessage(new MessageEvent("message", { data }));
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
close() {
|
|
28
|
-
this.closed = true;
|
|
29
|
-
const list = MockBroadcastChannel.byChannel.get(this.name);
|
|
30
|
-
if (list) {
|
|
31
|
-
const idx = list.indexOf(this);
|
|
32
|
-
if (idx !== -1)
|
|
33
|
-
list.splice(idx, 1);
|
|
34
|
-
}
|
|
35
|
-
MockBroadcastChannel.instances.splice(MockBroadcastChannel.instances.indexOf(this), 1);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
MockBroadcastChannel.instances = [];
|
|
40
|
-
MockBroadcastChannel.byChannel = new Map();
|
|
41
|
-
vi.stubGlobal("BroadcastChannel", MockBroadcastChannel);
|
|
42
|
-
});
|
|
43
|
-
describe("syncedSignal", () => {
|
|
44
|
-
it("reads initial value", () => {
|
|
45
|
-
const s = syncedSignal("ch", 42);
|
|
46
|
-
expect(s()).toBe(42);
|
|
47
|
-
s.close();
|
|
48
|
-
});
|
|
49
|
-
it("set() updates the signal value", () => {
|
|
50
|
-
const s = syncedSignal("ch", 0);
|
|
51
|
-
s.set(10);
|
|
52
|
-
expect(s()).toBe(10);
|
|
53
|
-
s.close();
|
|
54
|
-
});
|
|
55
|
-
it("update() applies a transform", () => {
|
|
56
|
-
const s = syncedSignal("ch", 5);
|
|
57
|
-
s.update((v) => v * 2);
|
|
58
|
-
expect(s()).toBe(10);
|
|
59
|
-
s.close();
|
|
60
|
-
});
|
|
61
|
-
it("set() posts a JSON message to the channel", () => {
|
|
62
|
-
const s = syncedSignal("ch", 0);
|
|
63
|
-
const postSpy = vi.spyOn(MockBroadcastChannel.instances[0], "postMessage");
|
|
64
|
-
s.set(99);
|
|
65
|
-
expect(postSpy).toHaveBeenCalledWith(JSON.stringify(99));
|
|
66
|
-
s.close();
|
|
67
|
-
});
|
|
68
|
-
it("receiving a message from another tab updates the signal", () => {
|
|
69
|
-
const s = syncedSignal("ch", 0);
|
|
70
|
-
const channel = MockBroadcastChannel.instances[0];
|
|
71
|
-
channel.onmessage(new MessageEvent("message", { data: JSON.stringify(7) }));
|
|
72
|
-
expect(s()).toBe(7);
|
|
73
|
-
s.close();
|
|
74
|
-
});
|
|
75
|
-
it("does not echo own set() back to itself", () => {
|
|
76
|
-
const s = syncedSignal("ch", 0);
|
|
77
|
-
// Simulate two instances on the same channel
|
|
78
|
-
const s2 = syncedSignal("ch", 0);
|
|
79
|
-
const received = [];
|
|
80
|
-
effect(() => { received.push(s2()); });
|
|
81
|
-
s.set(5);
|
|
82
|
-
// s2 should receive the message because it came from a different instance
|
|
83
|
-
expect(s2()).toBe(5);
|
|
84
|
-
// s itself should NOT trigger its own onmessage handler (no echo)
|
|
85
|
-
const channel = MockBroadcastChannel.instances[0];
|
|
86
|
-
const receivedBySelf = [];
|
|
87
|
-
effect(() => { receivedBySelf.push(s()); });
|
|
88
|
-
const beforeCount = receivedBySelf.length;
|
|
89
|
-
// Manually simulate echo — should be ignored because posting=false after set
|
|
90
|
-
channel.onmessage(new MessageEvent("message", { data: JSON.stringify(5) }));
|
|
91
|
-
// The value stays 5 (no spurious extra notification tested via subscribe count)
|
|
92
|
-
expect(s()).toBe(5);
|
|
93
|
-
expect(receivedBySelf.length).toBe(beforeCount); // no extra effect run (Object.is equality)
|
|
94
|
-
s.close();
|
|
95
|
-
s2.close();
|
|
96
|
-
});
|
|
97
|
-
it("subscribe fires immediately then on each remote change", () => {
|
|
98
|
-
const s = syncedSignal("ch", 0);
|
|
99
|
-
const channel = MockBroadcastChannel.instances[0];
|
|
100
|
-
const received = [];
|
|
101
|
-
s.subscribe((v) => received.push(v));
|
|
102
|
-
expect(received).toEqual([0]);
|
|
103
|
-
channel.onmessage(new MessageEvent("message", { data: JSON.stringify(3) }));
|
|
104
|
-
expect(received).toEqual([0, 3]);
|
|
105
|
-
s.close();
|
|
106
|
-
});
|
|
107
|
-
it("close() shuts down the BroadcastChannel", () => {
|
|
108
|
-
const s = syncedSignal("ch", 0);
|
|
109
|
-
const channel = MockBroadcastChannel.instances[0];
|
|
110
|
-
expect(channel.closed).toBe(false);
|
|
111
|
-
s.close();
|
|
112
|
-
expect(channel.closed).toBe(true);
|
|
113
|
-
});
|
|
114
|
-
it("has __isSignal marker", () => {
|
|
115
|
-
const s = syncedSignal("ch", 0);
|
|
116
|
-
expect(s.__isSignal).toBe(true);
|
|
117
|
-
s.close();
|
|
118
|
-
});
|
|
119
|
-
it("does not update value when onmessage fires while posting (posting guard)", () => {
|
|
120
|
-
// Use a self-delivering channel that echoes to itself during postMessage.
|
|
121
|
-
// This covers the `if (posting) return;` branch in synced.ts.
|
|
122
|
-
class SelfEchoChannel {
|
|
123
|
-
onmessage = null;
|
|
124
|
-
postMessage(data) {
|
|
125
|
-
this.onmessage?.(new MessageEvent("message", { data }));
|
|
126
|
-
}
|
|
127
|
-
close() { }
|
|
128
|
-
}
|
|
129
|
-
vi.stubGlobal("BroadcastChannel", SelfEchoChannel);
|
|
130
|
-
const s = syncedSignal("echo-ch", 0);
|
|
131
|
-
const received = [];
|
|
132
|
-
s.subscribe((v) => received.push(v));
|
|
133
|
-
// set() triggers postMessage → onmessage fires → posting=true → early return
|
|
134
|
-
// Inner value should not be double-set
|
|
135
|
-
s.set(42);
|
|
136
|
-
expect(s()).toBe(42);
|
|
137
|
-
// Only two notifications: initial (0) + the set (42), no echo re-set
|
|
138
|
-
expect(received).toEqual([0, 42]);
|
|
139
|
-
s.close();
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
//# sourceMappingURL=synced.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"synced.test.js","sourceRoot":"","sources":["../../src/__tests__/synced.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"track.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/track.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { track, runEffect, activeEffect } from "../signal/effect";
|
|
3
|
-
import { signal } from "../signal/signal";
|
|
4
|
-
describe("track", () => {
|
|
5
|
-
it("runs the effect immediately", () => {
|
|
6
|
-
const fn = vi.fn();
|
|
7
|
-
track(fn);
|
|
8
|
-
expect(fn).toHaveBeenCalledOnce();
|
|
9
|
-
});
|
|
10
|
-
it("sets activeEffect during execution, resets after", () => {
|
|
11
|
-
let during = "not-set";
|
|
12
|
-
track(() => {
|
|
13
|
-
during = activeEffect;
|
|
14
|
-
});
|
|
15
|
-
expect(during).toBeTypeOf("function");
|
|
16
|
-
expect(activeEffect).toBeNull();
|
|
17
|
-
});
|
|
18
|
-
it("supports nested track calls — restores outer effect", () => {
|
|
19
|
-
const outer = vi.fn();
|
|
20
|
-
const inner = vi.fn();
|
|
21
|
-
let outerActive;
|
|
22
|
-
let innerActive;
|
|
23
|
-
track(() => {
|
|
24
|
-
outer();
|
|
25
|
-
outerActive = activeEffect;
|
|
26
|
-
track(() => {
|
|
27
|
-
inner();
|
|
28
|
-
innerActive = activeEffect;
|
|
29
|
-
});
|
|
30
|
-
// after inner track, activeEffect should be back to outer
|
|
31
|
-
expect(activeEffect).toBe(outerActive);
|
|
32
|
-
});
|
|
33
|
-
expect(outer).toHaveBeenCalledOnce();
|
|
34
|
-
expect(inner).toHaveBeenCalledOnce();
|
|
35
|
-
expect(innerActive).not.toBe(outerActive);
|
|
36
|
-
});
|
|
37
|
-
it("subscribes the tracked effect to signals read inside it", () => {
|
|
38
|
-
const s = signal(1);
|
|
39
|
-
const values = [];
|
|
40
|
-
track(() => values.push(s()));
|
|
41
|
-
s.set(2);
|
|
42
|
-
expect(values).toEqual([1, 2]);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
describe("runEffect", () => {
|
|
46
|
-
it("sets activeEffect to the given value", () => {
|
|
47
|
-
const fn = () => { };
|
|
48
|
-
runEffect(fn);
|
|
49
|
-
expect(activeEffect).toBe(fn);
|
|
50
|
-
runEffect(null);
|
|
51
|
-
expect(activeEffect).toBeNull();
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
//# sourceMappingURL=track.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"track.test.js","sourceRoot":"","sources":["../../src/__tests__/track.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACnB,KAAK,CAAC,EAAE,CAAC,CAAC;QACV,MAAM,CAAC,EAAE,CAAC,CAAC,oBAAoB,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,IAAI,MAAM,GAAY,SAAS,CAAC;QAChC,KAAK,CAAC,GAAG,EAAE;YACT,MAAM,GAAG,YAAY,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACtB,IAAI,WAAoB,CAAC;QACzB,IAAI,WAAoB,CAAC;QAEzB,KAAK,CAAC,GAAG,EAAE;YACT,KAAK,EAAE,CAAC;YACR,WAAW,GAAG,YAAY,CAAC;YAC3B,KAAK,CAAC,GAAG,EAAE;gBACT,KAAK,EAAE,CAAC;gBACR,WAAW,GAAG,YAAY,CAAC;YAC7B,CAAC,CAAC,CAAC;YACH,0DAA0D;YAC1D,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,EAAE,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,EAAE,CAAC;QACrC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACT,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,EAAE,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QACpB,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { batch } from "../signal/batch";
|
|
4
|
-
import { effect } from "../signal/effect";
|
|
5
|
-
import { signal } from "../signal/signal";
|
|
6
|
-
|
|
7
|
-
describe("batch", () => {
|
|
8
|
-
it("executes the wrapped function", () => {
|
|
9
|
-
const s = signal(0);
|
|
10
|
-
batch(() => {
|
|
11
|
-
s.set(5);
|
|
12
|
-
s.set(10);
|
|
13
|
-
});
|
|
14
|
-
expect(s()).toBe(10);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("does not throw when no effects are tracking", () => {
|
|
18
|
-
const s = signal(0);
|
|
19
|
-
expect(() => { batch(() => { s.set(1); }); }).not.toThrow();
|
|
20
|
-
expect(s()).toBe(1);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("propagates errors thrown inside the batch", () => {
|
|
24
|
-
expect(() =>
|
|
25
|
-
{ batch(() => {
|
|
26
|
-
throw new Error("inside batch");
|
|
27
|
-
}); },
|
|
28
|
-
).toThrow("inside batch");
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("nested batch() — effects run exactly once after outer batch completes", () => {
|
|
32
|
-
const s = signal(0);
|
|
33
|
-
const runs: number[] = [];
|
|
34
|
-
effect(() => { runs.push(s()); });
|
|
35
|
-
// initial run captured
|
|
36
|
-
const before = runs.length;
|
|
37
|
-
|
|
38
|
-
batch(() => {
|
|
39
|
-
batch(() => {
|
|
40
|
-
s.set(1);
|
|
41
|
-
s.set(2);
|
|
42
|
-
});
|
|
43
|
-
s.set(3);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// effect should have run exactly once for the final value
|
|
47
|
-
expect(runs.length).toBe(before + 1);
|
|
48
|
-
expect(runs[runs.length - 1]).toBe(3);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("batch() that throws still cleans up state (no stuck batchQueue)", () => {
|
|
52
|
-
const s = signal(0);
|
|
53
|
-
const runs: number[] = [];
|
|
54
|
-
effect(() => { runs.push(s()); });
|
|
55
|
-
|
|
56
|
-
expect(() =>
|
|
57
|
-
batch(() => {
|
|
58
|
-
s.set(1);
|
|
59
|
-
throw new Error("batch boom");
|
|
60
|
-
}),
|
|
61
|
-
).toThrow("batch boom");
|
|
62
|
-
|
|
63
|
-
// After the failed batch, the queue must be cleared so subsequent
|
|
64
|
-
// signal changes work normally (not deferred indefinitely).
|
|
65
|
-
const countBefore = runs.length;
|
|
66
|
-
s.set(99);
|
|
67
|
-
expect(runs.length).toBe(countBefore + 1);
|
|
68
|
-
expect(runs[runs.length - 1]).toBe(99);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("effect added inside a running batch is included in the drain", () => {
|
|
72
|
-
const s = signal(0);
|
|
73
|
-
const seen: number[] = [];
|
|
74
|
-
|
|
75
|
-
batch(() => {
|
|
76
|
-
// Create an effect inside the batch — it runs immediately (initial run)
|
|
77
|
-
// and registers itself as a subscriber. Then we set the signal so it
|
|
78
|
-
// gets enqueued into the batch queue.
|
|
79
|
-
effect(() => { seen.push(s()); });
|
|
80
|
-
s.set(5);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// The effect should have captured both the initial value and the batched value
|
|
84
|
-
expect(seen).toContain(0);
|
|
85
|
-
expect(seen).toContain(5);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("an effect fed by several signals runs once per batch", () => {
|
|
89
|
-
const a = signal(0);
|
|
90
|
-
const b = signal(0);
|
|
91
|
-
const runs = vi.fn();
|
|
92
|
-
effect(() => {
|
|
93
|
-
void a();
|
|
94
|
-
void b();
|
|
95
|
-
runs();
|
|
96
|
-
});
|
|
97
|
-
runs.mockClear();
|
|
98
|
-
batch(() => {
|
|
99
|
-
a.set(1);
|
|
100
|
-
b.set(1);
|
|
101
|
-
a.set(2);
|
|
102
|
-
});
|
|
103
|
-
expect(runs).toHaveBeenCalledOnce();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it("a throwing effect does not stop the others and the error is rethrown after the flush", () => {
|
|
107
|
-
const s = signal(0);
|
|
108
|
-
const after = vi.fn();
|
|
109
|
-
let armed = false;
|
|
110
|
-
effect(() => {
|
|
111
|
-
void s();
|
|
112
|
-
if (armed) throw new Error("effect boom");
|
|
113
|
-
});
|
|
114
|
-
effect(() => {
|
|
115
|
-
void s();
|
|
116
|
-
if (armed) after();
|
|
117
|
-
});
|
|
118
|
-
armed = true;
|
|
119
|
-
expect(() => { batch(() => { s.set(1); }); }).toThrow("effect boom");
|
|
120
|
-
expect(after).toHaveBeenCalledOnce();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("a failed flush leaves no stale entries for the next batch", () => {
|
|
124
|
-
const s = signal(0);
|
|
125
|
-
const runs = vi.fn();
|
|
126
|
-
let throws = true;
|
|
127
|
-
effect(() => {
|
|
128
|
-
void s();
|
|
129
|
-
runs();
|
|
130
|
-
if (throws && s() === 1) throw new Error("once");
|
|
131
|
-
});
|
|
132
|
-
expect(() => { batch(() => { s.set(1); }); }).toThrow("once");
|
|
133
|
-
throws = false;
|
|
134
|
-
runs.mockClear();
|
|
135
|
-
batch(() => { s.set(2); });
|
|
136
|
-
expect(runs).toHaveBeenCalledOnce();
|
|
137
|
-
});
|
|
138
|
-
});
|