@praxisjs/core 0.4.0 → 0.4.2

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/__tests__/batch.test.d.ts +2 -0
  3. package/dist/__tests__/batch.test.d.ts.map +1 -0
  4. package/dist/__tests__/batch.test.js +26 -0
  5. package/dist/__tests__/batch.test.js.map +1 -0
  6. package/dist/__tests__/component.test.d.ts +2 -0
  7. package/dist/__tests__/component.test.d.ts.map +1 -0
  8. package/dist/__tests__/component.test.js +68 -0
  9. package/dist/__tests__/component.test.js.map +1 -0
  10. package/dist/__tests__/computed.test.d.ts +2 -0
  11. package/dist/__tests__/computed.test.d.ts.map +1 -0
  12. package/dist/__tests__/computed.test.js +112 -0
  13. package/dist/__tests__/computed.test.js.map +1 -0
  14. package/dist/__tests__/effect.test.d.ts +2 -0
  15. package/dist/__tests__/effect.test.d.ts.map +1 -0
  16. package/dist/__tests__/effect.test.js +84 -0
  17. package/dist/__tests__/effect.test.js.map +1 -0
  18. package/dist/__tests__/peek.test.d.ts +2 -0
  19. package/dist/__tests__/peek.test.d.ts.map +1 -0
  20. package/dist/__tests__/peek.test.js +26 -0
  21. package/dist/__tests__/peek.test.js.map +1 -0
  22. package/dist/__tests__/persisted-signal.test.d.ts +2 -0
  23. package/dist/__tests__/persisted-signal.test.d.ts.map +1 -0
  24. package/dist/__tests__/persisted-signal.test.js +122 -0
  25. package/dist/__tests__/persisted-signal.test.js.map +1 -0
  26. package/dist/__tests__/reactive.test.d.ts +2 -0
  27. package/dist/__tests__/reactive.test.d.ts.map +1 -0
  28. package/dist/__tests__/reactive.test.js +212 -0
  29. package/dist/__tests__/reactive.test.js.map +1 -0
  30. package/dist/__tests__/resource.test.d.ts +2 -0
  31. package/dist/__tests__/resource.test.d.ts.map +1 -0
  32. package/dist/__tests__/resource.test.js +84 -0
  33. package/dist/__tests__/resource.test.js.map +1 -0
  34. package/dist/__tests__/signal.test.d.ts +2 -0
  35. package/dist/__tests__/signal.test.d.ts.map +1 -0
  36. package/dist/__tests__/signal.test.js +95 -0
  37. package/dist/__tests__/signal.test.js.map +1 -0
  38. package/dist/__tests__/track.test.d.ts +2 -0
  39. package/dist/__tests__/track.test.d.ts.map +1 -0
  40. package/dist/__tests__/track.test.js +54 -0
  41. package/dist/__tests__/track.test.js.map +1 -0
  42. package/dist/reactive/reactive.d.ts.map +1 -1
  43. package/dist/reactive/reactive.js +8 -1
  44. package/dist/reactive/reactive.js.map +1 -1
  45. package/dist/signal/effect.d.ts.map +1 -1
  46. package/dist/signal/effect.js +5 -0
  47. package/dist/signal/effect.js.map +1 -1
  48. package/dist/signal/persisted.d.ts.map +1 -1
  49. package/dist/signal/persisted.js +10 -12
  50. package/dist/signal/persisted.js.map +1 -1
  51. package/package.json +1 -1
  52. package/src/__tests__/batch.test.ts +29 -0
  53. package/src/__tests__/component.test.ts +82 -0
  54. package/src/__tests__/computed.test.ts +128 -0
  55. package/src/__tests__/effect.test.ts +93 -0
  56. package/src/__tests__/peek.test.ts +31 -0
  57. package/src/__tests__/persisted-signal.test.ts +151 -0
  58. package/src/__tests__/reactive.test.ts +245 -0
  59. package/src/__tests__/resource.test.ts +97 -0
  60. package/src/__tests__/signal.test.ts +109 -0
  61. package/src/__tests__/track.test.ts +61 -0
  62. package/src/reactive/reactive.ts +9 -1
  63. package/src/signal/effect.ts +4 -0
  64. package/src/signal/persisted.ts +12 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @praxisjs/core
2
2
 
3
+ ## 0.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d11a10a: Fix `effect()` stop function not preventing re-runs
8
+
9
+ The function returned by `effect()` was only calling the cleanup callback but leaving the effect subscribed to all tracked signals, so it would keep re-running after being stopped. The stop function now sets a `stopped` flag that makes future invocations of the wrapped effect a no-op, and nullifies the cleanup reference to ensure idempotent behaviour.
10
+
11
+ This also fixes `$subscribe` unsubscription in `@praxisjs/store`, which relied on this mechanism to detach listeners.
12
+
13
+ ## 0.4.1
14
+
15
+ ### Patch Changes
16
+
17
+ - fe39901: fix(core): fix effect subscription leak in `when()` when source is immediately truthy
18
+
19
+ When `source()` returned a truthy value on the first synchronous effect run, `stop` was still `undefined` at that point. The `stop?.()` call inside the callback was a no-op, leaving the effect subscribed forever — any future change to the source kept triggering the effect (which returned early via `disposed`, but still maintained its reactive tracking).
20
+
21
+ The implementation was refactored to use a `ref` object (`{ cancel }`) to hold the cancellation function. This allows `stop` to be declared as `const`, removes the optional chain on a non-nullable type, and ensures the effect is properly cancelled via `if (disposed) stop()` after the first synchronous run.
22
+
3
23
  ## 0.4.0
4
24
 
5
25
  ### Minor Changes
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=batch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/batch.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { batch } from "../signal/batch";
3
+ import { signal } from "../signal/signal";
4
+ describe("batch", () => {
5
+ it("executes the wrapped function", () => {
6
+ const s = signal(0);
7
+ batch(() => {
8
+ s.set(5);
9
+ s.set(10);
10
+ });
11
+ expect(s()).toBe(10);
12
+ });
13
+ it("does not throw when no effects are tracking", () => {
14
+ const s = signal(0);
15
+ expect(() => { batch(() => { s.set(1); }); }).not.toThrow();
16
+ expect(s()).toBe(1);
17
+ });
18
+ it("propagates errors thrown inside the batch", () => {
19
+ expect(() => {
20
+ batch(() => {
21
+ throw new Error("inside batch");
22
+ });
23
+ }).toThrow("inside batch");
24
+ });
25
+ });
26
+ //# sourceMappingURL=batch.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.test.js","sourceRoot":"","sources":["../../src/__tests__/batch.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,KAAK,CAAC,GAAG,EAAE;YACT,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACT,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC5D,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,GAAG,EAAE;YACR,KAAK,CAAC,GAAG,EAAE;gBACX,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;QAAC,CAAC,CACN,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=component.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/component.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { RootComponent } from "../component/base";
3
+ import { StatefulComponent } from "../component/stateful";
4
+ import { StatelessComponent } from "../component/stateless";
5
+ class ConcreteRoot extends RootComponent {
6
+ render() { return null; }
7
+ }
8
+ class ConcreteStateful extends StatefulComponent {
9
+ render() { return null; }
10
+ }
11
+ describe("RootComponent", () => {
12
+ it("stores props on _rawProps", () => {
13
+ const c = new ConcreteRoot({ name: "Alice" });
14
+ expect(c._rawProps.name).toBe("Alice");
15
+ });
16
+ it("exposes props via .props getter", () => {
17
+ const c = new ConcreteRoot({ name: "Bob" });
18
+ expect(c.props.name).toBe("Bob");
19
+ });
20
+ it("_mounted starts as false", () => {
21
+ const c = new ConcreteRoot({ name: "" });
22
+ expect(c._mounted).toBe(false);
23
+ });
24
+ it("_anchor starts as undefined", () => {
25
+ const c = new ConcreteRoot({ name: "" });
26
+ expect(c._anchor).toBeUndefined();
27
+ });
28
+ it("defaults to empty object when no props given", () => {
29
+ const c = new ConcreteRoot();
30
+ expect(c._rawProps).toEqual({});
31
+ });
32
+ });
33
+ describe("StatefulComponent", () => {
34
+ it("_defaults starts as empty object", () => {
35
+ const c = new ConcreteStateful();
36
+ expect(c._defaults).toEqual({});
37
+ });
38
+ it("_stateDirty starts as false", () => {
39
+ const c = new ConcreteStateful();
40
+ expect(c._stateDirty).toBe(false);
41
+ });
42
+ it("_setProps replaces _rawProps contents", () => {
43
+ const c = new ConcreteStateful({ x: 1 });
44
+ c._setProps({ y: 2 });
45
+ expect((c._rawProps).x).toBeUndefined();
46
+ expect((c._rawProps).y).toBe(2);
47
+ });
48
+ });
49
+ class ConcreteStateless extends StatelessComponent {
50
+ render() { return null; }
51
+ }
52
+ describe("StatelessComponent", () => {
53
+ it("stores props on _rawProps", () => {
54
+ const c = new ConcreteStateless({ name: "Alice" });
55
+ expect(c._rawProps.name).toBe("Alice");
56
+ });
57
+ it("_setProps replaces _rawProps contents", () => {
58
+ const c = new ConcreteStateless({ name: "Alice" });
59
+ c._setProps({ name: "Bob" });
60
+ expect(c._rawProps.name).toBe("Bob");
61
+ });
62
+ it("_setProps removes old keys", () => {
63
+ const c = new ConcreteStateless({ name: "Alice" });
64
+ c._setProps({});
65
+ expect(c._rawProps.name).toBeUndefined();
66
+ });
67
+ });
68
+ //# sourceMappingURL=component.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component.test.js","sourceRoot":"","sources":["../../src/__tests__/component.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=computed.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/computed.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,112 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { computed } from "../signal/computed";
3
+ import { signal } from "../signal/signal";
4
+ describe("computed", () => {
5
+ it("derives value from signal", () => {
6
+ const s = signal(4);
7
+ const doubled = computed(() => s() * 2);
8
+ expect(doubled()).toBe(8);
9
+ });
10
+ it("updates when source signal changes", () => {
11
+ const s = signal(3);
12
+ const triple = computed(() => s() * 3);
13
+ s.set(5);
14
+ expect(triple()).toBe(15);
15
+ });
16
+ it("is lazy — does not recompute until accessed", () => {
17
+ const s = signal(1);
18
+ const fn = vi.fn(() => s() + 1);
19
+ const c = computed(fn);
20
+ expect(fn).not.toHaveBeenCalled();
21
+ c();
22
+ expect(fn).toHaveBeenCalledOnce();
23
+ });
24
+ it("caches value between reads when source has not changed", () => {
25
+ const s = signal(2);
26
+ const fn = vi.fn(() => s() * 10);
27
+ const c = computed(fn);
28
+ c();
29
+ c();
30
+ expect(fn).toHaveBeenCalledOnce();
31
+ });
32
+ it("recomputes after source change", () => {
33
+ const s = signal(1);
34
+ const fn = vi.fn(() => s() + 100);
35
+ const c = computed(fn);
36
+ c();
37
+ s.set(2);
38
+ c();
39
+ expect(fn).toHaveBeenCalledTimes(2);
40
+ });
41
+ it("marks __isComputed = true", () => {
42
+ const c = computed(() => 42);
43
+ expect(c.__isComputed).toBe(true);
44
+ });
45
+ it("chained computed values update correctly", () => {
46
+ const s = signal(1);
47
+ const doubled = computed(() => s() * 2);
48
+ const quadrupled = computed(() => doubled() * 2);
49
+ expect(quadrupled()).toBe(4);
50
+ s.set(3);
51
+ expect(quadrupled()).toBe(12);
52
+ });
53
+ it("subscribe fires immediately with computed value", () => {
54
+ const s = signal(5);
55
+ const c = computed(() => s() + 1);
56
+ const received = [];
57
+ c.subscribe((v) => received.push(v));
58
+ expect(received).toEqual([6]);
59
+ });
60
+ it("subscribe fires when source changes", () => {
61
+ const s = signal(0);
62
+ const c = computed(() => s() * 3);
63
+ const received = [];
64
+ c.subscribe((v) => received.push(v));
65
+ s.set(2);
66
+ s.set(4);
67
+ expect(received).toEqual([0, 6, 12]);
68
+ });
69
+ it("unsubscribe stops receiving updates", () => {
70
+ const s = signal(0);
71
+ const c = computed(() => s() + 1);
72
+ const received = [];
73
+ const unsub = c.subscribe((v) => received.push(v));
74
+ unsub();
75
+ s.set(10);
76
+ expect(received).toEqual([1]);
77
+ });
78
+ it("computeFn that throws propagates the error on read", () => {
79
+ const s = signal(true);
80
+ const c = computed(() => {
81
+ if (s())
82
+ throw new Error("compute error");
83
+ return 0;
84
+ });
85
+ expect(() => c()).toThrow("compute error");
86
+ });
87
+ it("dynamic dependency: switches tracked signal based on condition", () => {
88
+ const toggle = signal(true);
89
+ const a = signal(10);
90
+ const b = signal(20);
91
+ const c = computed(() => (toggle() ? a() : b()));
92
+ expect(c()).toBe(10);
93
+ a.set(11);
94
+ expect(c()).toBe(11);
95
+ toggle.set(false);
96
+ expect(c()).toBe(20);
97
+ b.set(21);
98
+ expect(c()).toBe(21);
99
+ });
100
+ it("unsubscribe then re-subscribe works correctly", () => {
101
+ const s = signal(1);
102
+ const c = computed(() => s() * 3);
103
+ const received = [];
104
+ const unsub = c.subscribe((v) => received.push(v));
105
+ unsub();
106
+ // Re-subscribe
107
+ c.subscribe((v) => received.push(v));
108
+ s.set(2);
109
+ expect(received).toContain(6);
110
+ });
111
+ });
112
+ //# sourceMappingURL=computed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.test.js","sourceRoot":"","sources":["../../src/__tests__/computed.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=effect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/effect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,84 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { effect } from "../signal/effect";
3
+ import { signal } from "../signal/signal";
4
+ describe("effect", () => {
5
+ it("runs immediately on creation", () => {
6
+ const ran = vi.fn();
7
+ effect(ran);
8
+ expect(ran).toHaveBeenCalledOnce();
9
+ });
10
+ it("re-runs when a tracked signal changes", () => {
11
+ const s = signal(1);
12
+ const values = [];
13
+ effect(() => {
14
+ values.push(s());
15
+ });
16
+ s.set(2);
17
+ s.set(3);
18
+ expect(values).toEqual([1, 2, 3]);
19
+ });
20
+ it("stop() calls the cleanup function", () => {
21
+ const cleanupFn = vi.fn();
22
+ const stop = effect(() => cleanupFn);
23
+ stop();
24
+ expect(cleanupFn).toHaveBeenCalledOnce();
25
+ });
26
+ it("calls cleanup function before re-run", () => {
27
+ const s = signal(0);
28
+ const order = [];
29
+ effect(() => {
30
+ const v = s();
31
+ order.push(`run:${v}`);
32
+ return () => order.push(`cleanup`);
33
+ });
34
+ s.set(1);
35
+ expect(order).toEqual(["run:0", "cleanup", "run:1"]);
36
+ });
37
+ it("tracks multiple signals", () => {
38
+ const a = signal(1);
39
+ const b = signal(10);
40
+ const sums = [];
41
+ effect(() => {
42
+ sums.push(a() + b());
43
+ });
44
+ a.set(2);
45
+ b.set(20);
46
+ expect(sums).toEqual([11, 12, 22]);
47
+ });
48
+ it("stop() prevents future re-runs", () => {
49
+ const s = signal(0);
50
+ const values = [];
51
+ const stop = effect(() => {
52
+ values.push(s());
53
+ });
54
+ stop();
55
+ s.set(99);
56
+ expect(values).toEqual([0]); // only initial run
57
+ });
58
+ it("effect with no reactive dependencies runs once only", () => {
59
+ const ran = vi.fn();
60
+ effect(() => {
61
+ ran(); // no signal reads
62
+ });
63
+ expect(ran).toHaveBeenCalledTimes(1);
64
+ // No signal changes possible — just verify it doesn't re-run spontaneously
65
+ expect(ran).toHaveBeenCalledTimes(1);
66
+ });
67
+ it("stop() with no cleanup function does not throw", () => {
68
+ const stop = effect(() => { });
69
+ expect(() => stop()).not.toThrow();
70
+ });
71
+ it("cleanup is re-invoked before each re-run", () => {
72
+ const s = signal(0);
73
+ const cleanupCount = { n: 0 };
74
+ effect(() => {
75
+ s(); // track
76
+ return () => { cleanupCount.n++; };
77
+ });
78
+ s.set(1);
79
+ s.set(2);
80
+ // cleanup called once before second run, once before third run
81
+ expect(cleanupCount.n).toBe(2);
82
+ });
83
+ });
84
+ //# sourceMappingURL=effect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.test.js","sourceRoot":"","sources":["../../src/__tests__/effect.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=peek.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peek.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/peek.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { computed } from "../signal/computed";
3
+ import { effect } from "../signal/effect";
4
+ import { peek } from "../signal/peek";
5
+ import { signal } from "../signal/signal";
6
+ describe("peek", () => {
7
+ it("returns the current value without tracking", () => {
8
+ const s = signal(42);
9
+ expect(peek(s)).toBe(42);
10
+ });
11
+ it("does not subscribe the active effect when peeked", () => {
12
+ const s = signal(1);
13
+ const runs = [];
14
+ effect(() => {
15
+ runs.push(peek(s)); // peek — should not subscribe
16
+ });
17
+ s.set(99); // should NOT trigger re-run
18
+ expect(runs).toEqual([1]);
19
+ });
20
+ it("works with computed values", () => {
21
+ const s = signal(5);
22
+ const c = computed(() => s() * 2);
23
+ expect(peek(c)).toBe(10);
24
+ });
25
+ });
26
+ //# sourceMappingURL=peek.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peek.test.js","sourceRoot":"","sources":["../../src/__tests__/peek.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;IACpB,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,8BAA8B;QACpD,CAAC,CAAC,CAAC;QAEH,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,4BAA4B;QACvC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=persisted-signal.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persisted-signal.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/persisted-signal.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,122 @@
1
+ // @vitest-environment jsdom
2
+ import { describe, it, expect, beforeEach, vi } from "vitest";
3
+ import { persistedSignal } from "../signal/persisted";
4
+ beforeEach(() => {
5
+ localStorage.clear();
6
+ });
7
+ describe("persistedSignal", () => {
8
+ it("returns initialValue when nothing is stored", () => {
9
+ const s = persistedSignal("key1", 42);
10
+ expect(s()).toBe(42);
11
+ });
12
+ it("reads existing value from localStorage", () => {
13
+ localStorage.setItem("key2", "99");
14
+ const s = persistedSignal("key2", 0);
15
+ expect(s()).toBe(99);
16
+ });
17
+ it("persists set() to localStorage", () => {
18
+ const s = persistedSignal("key3", 0);
19
+ s.set(7);
20
+ expect(localStorage.getItem("key3")).toBe("7");
21
+ expect(s()).toBe(7);
22
+ });
23
+ it("persists update() to localStorage", () => {
24
+ const s = persistedSignal("key4", 10);
25
+ s.update((v) => v + 5);
26
+ expect(localStorage.getItem("key4")).toBe("15");
27
+ expect(s()).toBe(15);
28
+ });
29
+ it("removes the key when set to null", () => {
30
+ const s = persistedSignal("key5", "hello");
31
+ s.set(null);
32
+ expect(localStorage.getItem("key5")).toBeNull();
33
+ });
34
+ it("marks __isSignal = true", () => {
35
+ const s = persistedSignal("key6", 0);
36
+ expect(s.__isSignal).toBe(true);
37
+ });
38
+ it("supports custom serialize/deserialize", () => {
39
+ const s = persistedSignal("key7", { x: 1 }, {
40
+ serialize: (v) => JSON.stringify(v),
41
+ deserialize: (raw) => JSON.parse(raw),
42
+ });
43
+ s.set({ x: 99 });
44
+ expect(localStorage.getItem("key7")).toBe('{"x":99}');
45
+ const s2 = persistedSignal("key7", { x: 0 }, {
46
+ serialize: JSON.stringify,
47
+ deserialize: (raw) => JSON.parse(raw),
48
+ });
49
+ expect(s2().x).toBe(99);
50
+ });
51
+ it("falls back to initialValue when deserialization fails", () => {
52
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
53
+ localStorage.setItem("key8", "{ bad json");
54
+ const s = persistedSignal("key8", 42);
55
+ expect(s()).toBe(42);
56
+ warn.mockRestore();
57
+ });
58
+ it("syncs from storage event on other tab", () => {
59
+ const s = persistedSignal("key9", 1);
60
+ window.dispatchEvent(new StorageEvent("storage", {
61
+ key: "key9",
62
+ newValue: "55",
63
+ storageArea: localStorage,
64
+ }));
65
+ expect(s()).toBe(55);
66
+ });
67
+ it("syncTabs=false does not add storage listener", () => {
68
+ const s = persistedSignal("key10", 1, { syncTabs: false });
69
+ s.set(5);
70
+ // Just verify it works without errors
71
+ expect(s()).toBe(5);
72
+ });
73
+ it("warns and falls back to initialValue when serialize throws on set", () => {
74
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
75
+ const s = persistedSignal("key11", { x: 1 }, {
76
+ serialize: () => { throw new Error("serialize fail"); },
77
+ deserialize: JSON.parse,
78
+ });
79
+ expect(() => s.set({ x: 2 })).not.toThrow();
80
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("Failed to serialize"), expect.any(Error));
81
+ warn.mockRestore();
82
+ });
83
+ it("syncs to initialValue when storage event has newValue=null (key removed)", () => {
84
+ const s = persistedSignal("key12", 42);
85
+ s.set(99);
86
+ window.dispatchEvent(new StorageEvent("storage", {
87
+ key: "key12",
88
+ newValue: null, // key removed in another tab
89
+ storageArea: localStorage,
90
+ }));
91
+ expect(s()).toBe(42); // falls back to initialValue
92
+ });
93
+ it("warns and falls back to initialValue when storage event deserialization fails", () => {
94
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
95
+ const s = persistedSignal("key13", 0, {
96
+ deserialize: () => { throw new Error("bad"); },
97
+ });
98
+ window.dispatchEvent(new StorageEvent("storage", {
99
+ key: "key13",
100
+ newValue: "invalid",
101
+ storageArea: localStorage,
102
+ }));
103
+ expect(s()).toBe(0);
104
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("Failed to deserialize"), expect.any(Error));
105
+ warn.mockRestore();
106
+ });
107
+ it("ignores storage events from other keys", () => {
108
+ const s = persistedSignal("key14", 1);
109
+ window.dispatchEvent(new StorageEvent("storage", {
110
+ key: "other-key",
111
+ newValue: "999",
112
+ storageArea: localStorage,
113
+ }));
114
+ expect(s()).toBe(1);
115
+ });
116
+ it("set(undefined) removes the key from localStorage", () => {
117
+ const s = persistedSignal("key15", 5);
118
+ s.set(undefined);
119
+ expect(localStorage.getItem("key15")).toBeNull();
120
+ });
121
+ });
122
+ //# sourceMappingURL=persisted-signal.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persisted-signal.test.js","sourceRoot":"","sources":["../../src/__tests__/persisted-signal.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=reactive.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactive.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/reactive.test.ts"],"names":[],"mappings":""}