@praxisjs/store 0.2.1 → 0.2.3
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 +20 -0
- package/dist/__tests__/create-store.test.d.ts +2 -0
- package/dist/__tests__/create-store.test.d.ts.map +1 -0
- package/dist/__tests__/create-store.test.js +127 -0
- package/dist/__tests__/create-store.test.js.map +1 -0
- package/dist/__tests__/decorators.test.d.ts +2 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +47 -0
- package/dist/__tests__/decorators.test.js.map +1 -0
- package/dist/create-store.js +1 -1
- package/dist/create-store.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/create-store.test.ts +162 -0
- package/src/__tests__/decorators.test.ts +59 -0
- package/src/create-store.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @praxisjs/store
|
|
2
2
|
|
|
3
|
+
## 0.2.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [d11a10a]
|
|
8
|
+
- @praxisjs/core@0.4.2
|
|
9
|
+
|
|
10
|
+
## 0.2.2
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- fe39901: fix(store): fix `TypeError` when assigning symbol keys on the store Proxy
|
|
15
|
+
|
|
16
|
+
The Proxy `set` trap returned `false` for non-string keys (symbols). In ES modules with strict mode, returning `false` from a `set` trap throws `TypeError: 'set' on proxy: trap returned falsish`. This broke internal JavaScript operations that use symbol keys (e.g. `Symbol.toPrimitive`, `Symbol.iterator`).
|
|
17
|
+
|
|
18
|
+
The fix returns `true` in those cases, silently ignoring the assignment — the correct behaviour, since the store only manages string keys.
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [fe39901]
|
|
21
|
+
- @praxisjs/core@0.4.1
|
|
22
|
+
|
|
3
23
|
## 0.2.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-store.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/create-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { createStore } from "../create-store";
|
|
3
|
+
function makeCounter() {
|
|
4
|
+
return createStore({
|
|
5
|
+
count: 0,
|
|
6
|
+
step: 1,
|
|
7
|
+
increment() {
|
|
8
|
+
this.count +=
|
|
9
|
+
this.step;
|
|
10
|
+
},
|
|
11
|
+
decrement() {
|
|
12
|
+
this.count--;
|
|
13
|
+
},
|
|
14
|
+
})();
|
|
15
|
+
}
|
|
16
|
+
describe("createStore", () => {
|
|
17
|
+
it("returns a factory that provides the store proxy", () => {
|
|
18
|
+
const store = makeCounter();
|
|
19
|
+
expect(store).toBeDefined();
|
|
20
|
+
});
|
|
21
|
+
it("reads signal state via property access", () => {
|
|
22
|
+
const store = makeCounter();
|
|
23
|
+
expect(store.count).toBe(0);
|
|
24
|
+
});
|
|
25
|
+
it("sets signal state via property assignment", () => {
|
|
26
|
+
const store = makeCounter();
|
|
27
|
+
store.count = 5;
|
|
28
|
+
expect(store.count).toBe(5);
|
|
29
|
+
});
|
|
30
|
+
it("calls methods bound to the store proxy", () => {
|
|
31
|
+
const store = makeCounter();
|
|
32
|
+
store.increment();
|
|
33
|
+
expect(store.count).toBe(1);
|
|
34
|
+
});
|
|
35
|
+
it("$state returns a plain snapshot of all state", () => {
|
|
36
|
+
const store = makeCounter();
|
|
37
|
+
const state = store.$state();
|
|
38
|
+
expect(state).toEqual({ count: 0, step: 1 });
|
|
39
|
+
});
|
|
40
|
+
it("$patch updates multiple keys at once", () => {
|
|
41
|
+
const store = makeCounter();
|
|
42
|
+
store.$patch({ count: 10, step: 5 });
|
|
43
|
+
expect(store.count).toBe(10);
|
|
44
|
+
expect(store.step).toBe(5);
|
|
45
|
+
});
|
|
46
|
+
it("$reset restores initial values", () => {
|
|
47
|
+
const store = makeCounter();
|
|
48
|
+
store.count = 99;
|
|
49
|
+
store.$reset();
|
|
50
|
+
expect(store.count).toBe(0);
|
|
51
|
+
});
|
|
52
|
+
it("$subscribe calls listener with state snapshot on each change", () => {
|
|
53
|
+
const store = makeCounter();
|
|
54
|
+
const snapshots = [];
|
|
55
|
+
store.$subscribe((s) => snapshots.push(s.count));
|
|
56
|
+
store.count = 42;
|
|
57
|
+
store.count = 99;
|
|
58
|
+
expect(snapshots).toEqual([0, 42, 99]);
|
|
59
|
+
});
|
|
60
|
+
it("definition getters are exposed on the store proxy", () => {
|
|
61
|
+
const definition = {
|
|
62
|
+
a: 2,
|
|
63
|
+
b: 3,
|
|
64
|
+
get sum() { return this.a + this.b; },
|
|
65
|
+
};
|
|
66
|
+
const store = createStore(definition)();
|
|
67
|
+
expect(store.sum).toBe(5);
|
|
68
|
+
});
|
|
69
|
+
it("setting a non-signal key via proxy returns false silently", () => {
|
|
70
|
+
const store = makeCounter();
|
|
71
|
+
// symbol keys are skipped — should not throw
|
|
72
|
+
expect(() => {
|
|
73
|
+
store[Symbol("noop")] = 1;
|
|
74
|
+
}).not.toThrow();
|
|
75
|
+
});
|
|
76
|
+
it("$patch ignores unknown keys", () => {
|
|
77
|
+
const store = makeCounter();
|
|
78
|
+
expect(() => { store.$patch({ unknownKey: 123 }); }).not.toThrow();
|
|
79
|
+
expect(store.count).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
it("setting a non-signal string key via proxy returns false", () => {
|
|
82
|
+
const store = makeCounter();
|
|
83
|
+
// "nonExistent" is a string key but is not a signal — set returns false
|
|
84
|
+
const result = Reflect.set(store, "nonExistent", 42);
|
|
85
|
+
expect(result).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it("getting an unknown key returns undefined", () => {
|
|
88
|
+
const store = makeCounter();
|
|
89
|
+
const val = store.doesNotExist;
|
|
90
|
+
expect(val).toBeUndefined();
|
|
91
|
+
});
|
|
92
|
+
it("multiple $subscribe listeners all receive updates", () => {
|
|
93
|
+
const store = makeCounter();
|
|
94
|
+
const snapshotsA = [];
|
|
95
|
+
const snapshotsB = [];
|
|
96
|
+
store.$subscribe((s) => snapshotsA.push(s.count));
|
|
97
|
+
store.$subscribe((s) => snapshotsB.push(s.count));
|
|
98
|
+
store.count = 5;
|
|
99
|
+
expect(snapshotsA).toContain(5);
|
|
100
|
+
expect(snapshotsB).toContain(5);
|
|
101
|
+
});
|
|
102
|
+
it("$subscribe unsubscribe stops delivery to that listener", () => {
|
|
103
|
+
const store = makeCounter();
|
|
104
|
+
const snapshots = [];
|
|
105
|
+
const unsub = store.$subscribe((s) => snapshots.push(s.count));
|
|
106
|
+
store.count = 1;
|
|
107
|
+
unsub();
|
|
108
|
+
store.count = 2;
|
|
109
|
+
// After unsub, count=2 should NOT be in snapshots
|
|
110
|
+
expect(snapshots).toContain(1);
|
|
111
|
+
expect(snapshots).not.toContain(2);
|
|
112
|
+
});
|
|
113
|
+
it("$state() snapshot includes getter values", () => {
|
|
114
|
+
const store = createStore({
|
|
115
|
+
a: 2,
|
|
116
|
+
b: 3,
|
|
117
|
+
get sum() {
|
|
118
|
+
return this.a + this.b;
|
|
119
|
+
},
|
|
120
|
+
})();
|
|
121
|
+
// $state returns only signal-backed fields (not getters)
|
|
122
|
+
const state = store.$state();
|
|
123
|
+
expect(state).toHaveProperty("a", 2);
|
|
124
|
+
expect(state).toHaveProperty("b", 3);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=create-store.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-store.test.js","sourceRoot":"","sources":["../../src/__tests__/create-store.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,SAAS,WAAW;IAClB,OAAO,WAAW,CAAC;QACjB,KAAK,EAAE,CAAC;QACR,IAAI,EAAE,CAAC;QACP,SAAS;YACN,IAAmD,CAAC,KAAK;gBACvD,IAAmD,CAAC,IAAI,CAAC;QAC9D,CAAC;QACD,SAAS;YACN,IAAqC,CAAC,KAAK,EAAE,CAAC;QACjD,CAAC;KACF,CAAC,EAAE,CAAC;AACP,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC3B,KAAsC,CAAC,KAAK,GAAG,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC3B,KAA8C,CAAC,SAAS,EAAE,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAI,KAA8D,CAAC,MAAM,EAAE,CAAC;QACvF,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC3B,KAAqE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACtG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC3B,KAAsC,CAAC,KAAK,GAAG,EAAE,CAAC;QAClD,KAA2C,CAAC,MAAM,EAAE,CAAC;QACtD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAa,EAAE,CAAC;QAC9B,KAA6F,CAAC,UAAU,CACvG,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAe,CAAC,CACzC,CAAC;QACD,KAAsC,CAAC,KAAK,GAAG,EAAE,CAAC;QAClD,KAAsC,CAAC,KAAK,GAAG,EAAE,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,UAAU,GAAG;YACjB,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;YACJ,IAAI,GAAG,KAAK,OAAQ,IAA4C,CAAC,CAAC,GAAI,IAA4C,CAAC,CAAC,CAAC,CAAC,CAAC;SACxH,CAAC;QACF,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QACxC,MAAM,CAAE,KAAoC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,6CAA6C;QAC7C,MAAM,CAAC,GAAG,EAAE;YACT,KAA4C,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,EAAE,GACP,KAAqE,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CACxG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,wEAAwE;QACxE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CACxB,KAAe,EACf,aAAa,EACb,EAAE,CACH,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAI,KAA4C,CAAC,YAAY,CAAC;QACvE,MAAM,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,UAAU,GAAa,EAAE,CAAC;QAG/B,KAA8B,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,KAAe,CAAC,CAAC,CAAC;QACrF,KAA8B,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,KAAe,CAAC,CAAC,CAAC;QAErF,KAAsC,CAAC,KAAK,GAAG,CAAC,CAAC;QAClD,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAa,EAAE,CAAC;QAG/B,MAAM,KAAK,GAAI,KAA8B,CAAC,UAAU,CACtD,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAe,CAAC,CACzC,CAAC;QAED,KAAsC,CAAC,KAAK,GAAG,CAAC,CAAC;QAClD,KAAK,EAAE,CAAC;QACP,KAAsC,CAAC,KAAK,GAAG,CAAC,CAAC;QAElD,kDAAkD;QAClD,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,KAAK,GAAG,WAAW,CAAC;YACxB,CAAC,EAAE,CAAC;YACJ,CAAC,EAAE,CAAC;YACJ,IAAI,GAAG;gBACL,OAAQ,IAA4C,CAAC,CAAC,GAAI,IAA4C,CAAC,CAAC,CAAC;YAC3G,CAAC;SACF,CAAC,EAAE,CAAC;QAEL,yDAAyD;QACzD,MAAM,KAAK,GAAI,KAA8D,CAAC,MAAM,EAAE,CAAC;QACvF,MAAM,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { Store, UseStore } from "../decorators";
|
|
3
|
+
describe("Store decorator", () => {
|
|
4
|
+
it("registers the class without throwing", () => {
|
|
5
|
+
class CounterStore {
|
|
6
|
+
value = 0;
|
|
7
|
+
}
|
|
8
|
+
expect(() => { Store()(CounterStore, {}); }).not.toThrow();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
describe("UseStore decorator", () => {
|
|
12
|
+
it("injects a singleton store instance via getter", () => {
|
|
13
|
+
class AppStore {
|
|
14
|
+
name = "app";
|
|
15
|
+
}
|
|
16
|
+
Store()(AppStore, {});
|
|
17
|
+
const initializers = [];
|
|
18
|
+
const ctx = {
|
|
19
|
+
name: "store",
|
|
20
|
+
kind: "field",
|
|
21
|
+
addInitializer(fn) { initializers.push(fn); },
|
|
22
|
+
};
|
|
23
|
+
UseStore(AppStore)(undefined, ctx);
|
|
24
|
+
const instance = {};
|
|
25
|
+
initializers.forEach((fn) => { fn.call(instance); });
|
|
26
|
+
expect(instance.store).toBeInstanceOf(AppStore);
|
|
27
|
+
expect(instance.store.name).toBe("app");
|
|
28
|
+
});
|
|
29
|
+
it("returns the same instance on repeated access (singleton)", () => {
|
|
30
|
+
class SharedStore {
|
|
31
|
+
}
|
|
32
|
+
Store()(SharedStore, {});
|
|
33
|
+
const initializers = [];
|
|
34
|
+
const ctx = {
|
|
35
|
+
name: "sharedStore",
|
|
36
|
+
kind: "field",
|
|
37
|
+
addInitializer(fn) { initializers.push(fn); },
|
|
38
|
+
};
|
|
39
|
+
UseStore(SharedStore)(undefined, ctx);
|
|
40
|
+
const a = {};
|
|
41
|
+
const b = {};
|
|
42
|
+
initializers.forEach((fn) => { fn.call(a); });
|
|
43
|
+
initializers.forEach((fn) => { fn.call(b); });
|
|
44
|
+
expect(a.sharedStore).toBe(b.sharedStore);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=decorators.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.test.js","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEhD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,YAAY;YAChB,KAAK,GAAG,CAAC,CAAC;SACX;QACD,MAAM,CAAC,GAAG,EAAE,GACR,KAAK,EAAE,CAAC,YAAY,EAAE,EAA2B,CAAC,CAAC,CAAC,CAAC,CACxD,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,QAAQ;YACZ,IAAI,GAAG,KAAK,CAAC;SACd;QACD,KAAK,EAAE,CAAC,QAAQ,EAAE,EAA2B,CAAC,CAAC;QAE/C,MAAM,YAAY,GAAmC,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG;YACV,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,OAAgB;YACtB,cAAc,CAAC,EAA2B,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;SACzC,CAAC;QAEhC,QAAQ,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAEnC,MAAM,QAAQ,GAA4B,EAAE,CAAC;QAC7C,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAErD,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAE,QAAQ,CAAC,KAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,WAAW;SAAG;QACpB,KAAK,EAAE,CAAC,WAAW,EAAE,EAA2B,CAAC,CAAC;QAElD,MAAM,YAAY,GAAmC,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG;YACV,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,OAAgB;YACtB,cAAc,CAAC,EAA2B,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;SACzC,CAAC;QAEhC,QAAQ,CAAC,WAAW,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAEtC,MAAM,CAAC,GAA4B,EAAE,CAAC;QACtC,MAAM,CAAC,GAA4B,EAAE,CAAC;QACtC,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9C,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/create-store.js
CHANGED
package/dist/create-store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-store.js","sourceRoot":"","sources":["../src/create-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,UAAU,WAAW,CACzB,UAA2B;IAE3B,MAAM,YAAY,GAA4B,EAAE,CAAC;IACjD,MAAM,OAAO,GAAoD,EAAE,CAAC;IAEpE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,IAAI,OAAO,KAAK,KAAK,UAAU;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,KAAwC,CAAC;;YACrD,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACjC,CAAC;IAED,MAAM,OAAO,GAA8C,EAAE,CAAC;IAC9D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAO,EAAE;QAC/B,GAAG,CAAC,EAAE,EAAE,GAAoB;YAC1B,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAC9C,IAAI,GAAG,IAAI,OAAO;gBAChB,OAAO,CAAC,GAAG,IAAe,EAAW,EAAE,CACrC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;YACtC,IAAI,GAAG,KAAK,YAAY;gBAAE,OAAO,SAAS,CAAC;YAC3C,IAAI,GAAG,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC;YACnC,IAAI,GAAG,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC;YACnC,IAAI,GAAG,KAAK,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YACtC,IAAI,GAAG,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,wBAAwB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAC9D,IAAI,IAAI,EAAE,GAAG;gBAAE,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAY,CAAC;YACtD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,GAAG,CAAC,EAAE,EAAE,GAAoB,EAAE,KAAc;YAC1C,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"create-store.js","sourceRoot":"","sources":["../src/create-store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/store",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"typescript": "^5.9.3"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@praxisjs/core": "0.4.
|
|
17
|
+
"@praxisjs/core": "0.4.2"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsc",
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { createStore } from "../create-store";
|
|
4
|
+
|
|
5
|
+
function makeCounter() {
|
|
6
|
+
return createStore({
|
|
7
|
+
count: 0,
|
|
8
|
+
step: 1,
|
|
9
|
+
increment() {
|
|
10
|
+
(this as unknown as { count: number; step: number }).count +=
|
|
11
|
+
(this as unknown as { count: number; step: number }).step;
|
|
12
|
+
},
|
|
13
|
+
decrement() {
|
|
14
|
+
(this as unknown as { count: number }).count--;
|
|
15
|
+
},
|
|
16
|
+
})();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("createStore", () => {
|
|
20
|
+
it("returns a factory that provides the store proxy", () => {
|
|
21
|
+
const store = makeCounter();
|
|
22
|
+
expect(store).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("reads signal state via property access", () => {
|
|
26
|
+
const store = makeCounter();
|
|
27
|
+
expect(store.count).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("sets signal state via property assignment", () => {
|
|
31
|
+
const store = makeCounter();
|
|
32
|
+
(store as unknown as { count: number }).count = 5;
|
|
33
|
+
expect(store.count).toBe(5);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("calls methods bound to the store proxy", () => {
|
|
37
|
+
const store = makeCounter();
|
|
38
|
+
(store as unknown as { increment: () => void }).increment();
|
|
39
|
+
expect(store.count).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("$state returns a plain snapshot of all state", () => {
|
|
43
|
+
const store = makeCounter();
|
|
44
|
+
const state = (store as unknown as { $state: () => Record<string, unknown> }).$state();
|
|
45
|
+
expect(state).toEqual({ count: 0, step: 1 });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("$patch updates multiple keys at once", () => {
|
|
49
|
+
const store = makeCounter();
|
|
50
|
+
(store as unknown as { $patch: (p: Record<string, unknown>) => void }).$patch({ count: 10, step: 5 });
|
|
51
|
+
expect(store.count).toBe(10);
|
|
52
|
+
expect(store.step).toBe(5);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("$reset restores initial values", () => {
|
|
56
|
+
const store = makeCounter();
|
|
57
|
+
(store as unknown as { count: number }).count = 99;
|
|
58
|
+
(store as unknown as { $reset: () => void }).$reset();
|
|
59
|
+
expect(store.count).toBe(0);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("$subscribe calls listener with state snapshot on each change", () => {
|
|
63
|
+
const store = makeCounter();
|
|
64
|
+
const snapshots: number[] = [];
|
|
65
|
+
(store as unknown as { $subscribe: (fn: (s: Record<string, unknown>) => void) => () => void }).$subscribe(
|
|
66
|
+
(s) => snapshots.push(s.count as number),
|
|
67
|
+
);
|
|
68
|
+
(store as unknown as { count: number }).count = 42;
|
|
69
|
+
(store as unknown as { count: number }).count = 99;
|
|
70
|
+
expect(snapshots).toEqual([0, 42, 99]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("definition getters are exposed on the store proxy", () => {
|
|
74
|
+
const definition = {
|
|
75
|
+
a: 2,
|
|
76
|
+
b: 3,
|
|
77
|
+
get sum() { return (this as unknown as { a: number; b: number }).a + (this as unknown as { a: number; b: number }).b; },
|
|
78
|
+
};
|
|
79
|
+
const store = createStore(definition)();
|
|
80
|
+
expect((store as unknown as { sum: number }).sum).toBe(5);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("setting a non-signal key via proxy returns false silently", () => {
|
|
84
|
+
const store = makeCounter();
|
|
85
|
+
// symbol keys are skipped — should not throw
|
|
86
|
+
expect(() => {
|
|
87
|
+
(store as unknown as Record<symbol, unknown>)[Symbol("noop")] = 1;
|
|
88
|
+
}).not.toThrow();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("$patch ignores unknown keys", () => {
|
|
92
|
+
const store = makeCounter();
|
|
93
|
+
expect(() =>
|
|
94
|
+
{ (store as unknown as { $patch: (p: Record<string, unknown>) => void }).$patch({ unknownKey: 123 }); },
|
|
95
|
+
).not.toThrow();
|
|
96
|
+
expect(store.count).toBe(0);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("setting a non-signal string key via proxy returns false", () => {
|
|
100
|
+
const store = makeCounter();
|
|
101
|
+
// "nonExistent" is a string key but is not a signal — set returns false
|
|
102
|
+
const result = Reflect.set(
|
|
103
|
+
store as object,
|
|
104
|
+
"nonExistent",
|
|
105
|
+
42,
|
|
106
|
+
);
|
|
107
|
+
expect(result).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("getting an unknown key returns undefined", () => {
|
|
111
|
+
const store = makeCounter();
|
|
112
|
+
const val = (store as unknown as Record<string, unknown>).doesNotExist;
|
|
113
|
+
expect(val).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("multiple $subscribe listeners all receive updates", () => {
|
|
117
|
+
const store = makeCounter();
|
|
118
|
+
const snapshotsA: number[] = [];
|
|
119
|
+
const snapshotsB: number[] = [];
|
|
120
|
+
|
|
121
|
+
type StoreType = { $subscribe: (fn: (s: Record<string, unknown>) => void) => () => void };
|
|
122
|
+
(store as unknown as StoreType).$subscribe((s) => snapshotsA.push(s.count as number));
|
|
123
|
+
(store as unknown as StoreType).$subscribe((s) => snapshotsB.push(s.count as number));
|
|
124
|
+
|
|
125
|
+
(store as unknown as { count: number }).count = 5;
|
|
126
|
+
expect(snapshotsA).toContain(5);
|
|
127
|
+
expect(snapshotsB).toContain(5);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("$subscribe unsubscribe stops delivery to that listener", () => {
|
|
131
|
+
const store = makeCounter();
|
|
132
|
+
const snapshots: number[] = [];
|
|
133
|
+
|
|
134
|
+
type StoreType = { $subscribe: (fn: (s: Record<string, unknown>) => void) => () => void };
|
|
135
|
+
const unsub = (store as unknown as StoreType).$subscribe(
|
|
136
|
+
(s) => snapshots.push(s.count as number),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
(store as unknown as { count: number }).count = 1;
|
|
140
|
+
unsub();
|
|
141
|
+
(store as unknown as { count: number }).count = 2;
|
|
142
|
+
|
|
143
|
+
// After unsub, count=2 should NOT be in snapshots
|
|
144
|
+
expect(snapshots).toContain(1);
|
|
145
|
+
expect(snapshots).not.toContain(2);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("$state() snapshot includes getter values", () => {
|
|
149
|
+
const store = createStore({
|
|
150
|
+
a: 2,
|
|
151
|
+
b: 3,
|
|
152
|
+
get sum() {
|
|
153
|
+
return (this as unknown as { a: number; b: number }).a + (this as unknown as { a: number; b: number }).b;
|
|
154
|
+
},
|
|
155
|
+
})();
|
|
156
|
+
|
|
157
|
+
// $state returns only signal-backed fields (not getters)
|
|
158
|
+
const state = (store as unknown as { $state: () => Record<string, unknown> }).$state();
|
|
159
|
+
expect(state).toHaveProperty("a", 2);
|
|
160
|
+
expect(state).toHaveProperty("b", 3);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { Store, UseStore } from "../decorators";
|
|
4
|
+
|
|
5
|
+
describe("Store decorator", () => {
|
|
6
|
+
it("registers the class without throwing", () => {
|
|
7
|
+
class CounterStore {
|
|
8
|
+
value = 0;
|
|
9
|
+
}
|
|
10
|
+
expect(() =>
|
|
11
|
+
{ Store()(CounterStore, {} as ClassDecoratorContext); },
|
|
12
|
+
).not.toThrow();
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("UseStore decorator", () => {
|
|
17
|
+
it("injects a singleton store instance via getter", () => {
|
|
18
|
+
class AppStore {
|
|
19
|
+
name = "app";
|
|
20
|
+
}
|
|
21
|
+
Store()(AppStore, {} as ClassDecoratorContext);
|
|
22
|
+
|
|
23
|
+
const initializers: Array<(this: unknown) => void> = [];
|
|
24
|
+
const ctx = {
|
|
25
|
+
name: "store",
|
|
26
|
+
kind: "field" as const,
|
|
27
|
+
addInitializer(fn: (this: unknown) => void) { initializers.push(fn); },
|
|
28
|
+
} as ClassFieldDecoratorContext;
|
|
29
|
+
|
|
30
|
+
UseStore(AppStore)(undefined, ctx);
|
|
31
|
+
|
|
32
|
+
const instance: Record<string, unknown> = {};
|
|
33
|
+
initializers.forEach((fn) => { fn.call(instance); });
|
|
34
|
+
|
|
35
|
+
expect(instance.store).toBeInstanceOf(AppStore);
|
|
36
|
+
expect((instance.store as AppStore).name).toBe("app");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("returns the same instance on repeated access (singleton)", () => {
|
|
40
|
+
class SharedStore {}
|
|
41
|
+
Store()(SharedStore, {} as ClassDecoratorContext);
|
|
42
|
+
|
|
43
|
+
const initializers: Array<(this: unknown) => void> = [];
|
|
44
|
+
const ctx = {
|
|
45
|
+
name: "sharedStore",
|
|
46
|
+
kind: "field" as const,
|
|
47
|
+
addInitializer(fn: (this: unknown) => void) { initializers.push(fn); },
|
|
48
|
+
} as ClassFieldDecoratorContext;
|
|
49
|
+
|
|
50
|
+
UseStore(SharedStore)(undefined, ctx);
|
|
51
|
+
|
|
52
|
+
const a: Record<string, unknown> = {};
|
|
53
|
+
const b: Record<string, unknown> = {};
|
|
54
|
+
initializers.forEach((fn) => { fn.call(a); });
|
|
55
|
+
initializers.forEach((fn) => { fn.call(b); });
|
|
56
|
+
|
|
57
|
+
expect(a.sharedStore).toBe(b.sharedStore);
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/create-store.ts
CHANGED
|
@@ -33,7 +33,7 @@ export function createStore<T extends Record<string, unknown>>(
|
|
|
33
33
|
return undefined;
|
|
34
34
|
},
|
|
35
35
|
set(_t, key: string | symbol, value: unknown) {
|
|
36
|
-
if (typeof key !== "string") return
|
|
36
|
+
if (typeof key !== "string") return true;
|
|
37
37
|
if (key in signals) {
|
|
38
38
|
signals[key].set(value);
|
|
39
39
|
return true;
|