@praxisjs/store 0.2.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/dist/__tests__/create-store.test.js +51 -0
- package/dist/__tests__/create-store.test.js.map +1 -1
- package/dist/__tests__/decorators.test.js +18 -2
- package/dist/__tests__/decorators.test.js.map +1 -1
- package/dist/decorators.d.ts +2 -2
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +33 -20
- package/dist/decorators.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/create-store.test.ts +71 -0
- package/src/__tests__/decorators.test.ts +11 -0
- package/src/decorators.ts +47 -22
- package/src/index.ts +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# @praxisjs/store
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 3372878: Migrate all packages from functional APIs to a decorator-first design.
|
|
8
|
+
|
|
9
|
+
**`@praxisjs/core`**
|
|
10
|
+
|
|
11
|
+
- Added `Composable` abstract base class for building class-based composables
|
|
12
|
+
- Removed `resource`, `createResource`, `Resource`, `ResourceStatus`, `ResourceOptions` from public exports — use `@Resource` from `@praxisjs/decorators` instead
|
|
13
|
+
|
|
14
|
+
**`@praxisjs/motion`**
|
|
15
|
+
|
|
16
|
+
- Replaced `useMotion`, `tween`, `spring`, `createTransition`, `Animate`, `easings`, `resolveEasing` with `@Tween` and `@Spring` decorators
|
|
17
|
+
|
|
18
|
+
**`@praxisjs/di`**
|
|
19
|
+
|
|
20
|
+
- Replaced `useService` and `createScope` with a `@Scope` decorator
|
|
21
|
+
- Renamed exported type `Scope` to `ScopeType` to free the name for the new decorator
|
|
22
|
+
|
|
23
|
+
**`@praxisjs/fsm`**
|
|
24
|
+
|
|
25
|
+
- Removed `createMachine` — use the `@StateMachine` and `@Transition` decorators directly
|
|
26
|
+
|
|
27
|
+
**`@praxisjs/router`**
|
|
28
|
+
|
|
29
|
+
- Removed `createRouter`, `lazy`, `useRouter`, `useParams`, `useQuery`, `useLocation`
|
|
30
|
+
- Added `@RouterConfig`, `@Lazy`, `@InjectRouter`, `@Params`, `@Query`, `@Location` decorators
|
|
31
|
+
|
|
32
|
+
**`@praxisjs/store`**
|
|
33
|
+
|
|
34
|
+
- Removed `createStore` — use the `@Store` and `@UseStore` decorators directly
|
|
35
|
+
|
|
36
|
+
**`@praxisjs/composables`**
|
|
37
|
+
|
|
38
|
+
- Replaced all `use*` composable functions with class-based composables extending `Composable`:
|
|
39
|
+
`WindowSize`, `ScrollPosition`, `ElementSize`, `Intersection`, `Focus`, `MediaQuery`, `ColorScheme`, `Mouse`, `KeyCombo`, `Idle`, `Clipboard`, `Geolocation`, `TimeAgo`, `Pagination`
|
|
40
|
+
|
|
41
|
+
**`@praxisjs/concurrent`**
|
|
42
|
+
|
|
43
|
+
- Removed `task`, `queue`, `pool` and their instance types — use `@Task`, `@Queue`, `@Pool` decorators instead
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- Updated dependencies [3372878]
|
|
48
|
+
- Updated dependencies [feaa478]
|
|
49
|
+
- @praxisjs/core@1.0.0
|
|
50
|
+
- @praxisjs/decorators@0.5.0
|
|
51
|
+
|
|
52
|
+
## 0.2.3
|
|
53
|
+
|
|
54
|
+
### Patch Changes
|
|
55
|
+
|
|
56
|
+
- Updated dependencies [d11a10a]
|
|
57
|
+
- @praxisjs/core@0.4.2
|
|
58
|
+
|
|
3
59
|
## 0.2.2
|
|
4
60
|
|
|
5
61
|
### Patch Changes
|
|
@@ -78,5 +78,56 @@ describe("createStore", () => {
|
|
|
78
78
|
expect(() => { store.$patch({ unknownKey: 123 }); }).not.toThrow();
|
|
79
79
|
expect(store.count).toBe(0);
|
|
80
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("getting via a symbol key returns undefined", () => {
|
|
114
|
+
const store = makeCounter();
|
|
115
|
+
const sym = Symbol("test");
|
|
116
|
+
const val = Reflect.get(store, sym);
|
|
117
|
+
expect(val).toBeUndefined();
|
|
118
|
+
});
|
|
119
|
+
it("$state() snapshot includes getter values", () => {
|
|
120
|
+
const store = createStore({
|
|
121
|
+
a: 2,
|
|
122
|
+
b: 3,
|
|
123
|
+
get sum() {
|
|
124
|
+
return this.a + this.b;
|
|
125
|
+
},
|
|
126
|
+
})();
|
|
127
|
+
// $state returns only signal-backed fields (not getters)
|
|
128
|
+
const state = store.$state();
|
|
129
|
+
expect(state).toHaveProperty("a", 2);
|
|
130
|
+
expect(state).toHaveProperty("b", 3);
|
|
131
|
+
});
|
|
81
132
|
});
|
|
82
133
|
//# sourceMappingURL=create-store.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-store.test.js","sourceRoot":"","sources":["../../src/__tests__/create-store.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-store.test.js","sourceRoot":"","sources":["../../src/__tests__/create-store.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,15 +3,31 @@ import { Store, UseStore } from "../decorators";
|
|
|
3
3
|
describe("Store decorator", () => {
|
|
4
4
|
it("registers the class without throwing", () => {
|
|
5
5
|
class CounterStore {
|
|
6
|
-
|
|
6
|
+
constructor() {
|
|
7
|
+
this.value = 0;
|
|
8
|
+
}
|
|
7
9
|
}
|
|
8
10
|
expect(() => { Store()(CounterStore, {}); }).not.toThrow();
|
|
9
11
|
});
|
|
12
|
+
it("StoreBehavior.create() is invoked when an enhanced instance is constructed", () => {
|
|
13
|
+
class MyStore {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.value = 42;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
const Enhanced = Store()(MyStore, {});
|
|
20
|
+
// Creating an instance calls StoreBehavior.create() internally (returns {})
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
expect(() => new Enhanced()).not.toThrow();
|
|
23
|
+
});
|
|
10
24
|
});
|
|
11
25
|
describe("UseStore decorator", () => {
|
|
12
26
|
it("injects a singleton store instance via getter", () => {
|
|
13
27
|
class AppStore {
|
|
14
|
-
|
|
28
|
+
constructor() {
|
|
29
|
+
this.name = "app";
|
|
30
|
+
}
|
|
15
31
|
}
|
|
16
32
|
Store()(AppStore, {});
|
|
17
33
|
const initializers = [];
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"decorators.test.js","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":"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"}
|
package/dist/decorators.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare function Store(): (value: new (...args: unknown[]) => unknown,
|
|
2
|
-
export declare function UseStore(StoreConstructor: new () => unknown): (_value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
1
|
+
export declare function Store(): (value: new (...args: unknown[]) => unknown, context: ClassDecoratorContext) => new (...args: unknown[]) => unknown;
|
|
2
|
+
export declare function UseStore(StoreConstructor: new () => unknown): (_value: undefined, context: ClassFieldDecoratorContext<any>) => void;
|
|
3
3
|
//# sourceMappingURL=decorators.d.ts.map
|
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAwBA,wBAAgB,KAAK,IAIY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,qBAAqB,KAAK,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CACnJ;AAED,wBAAgB,QAAQ,CAAC,gBAAgB,EAAE,UAAU,OAAO,GAwBzC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,GAAG,CAAC,KAAK,IAAI,CACvF"}
|
package/dist/decorators.js
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
|
+
import { createClassDecorator, ClassBehavior, createFieldDecorator, } from "@praxisjs/decorators";
|
|
1
2
|
const storeRegistry = new Map();
|
|
3
|
+
class StoreBehavior extends ClassBehavior {
|
|
4
|
+
create(_instance) {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
initialize(Enhanced) {
|
|
9
|
+
storeRegistry.set(Enhanced, null);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const storeBehavior = new StoreBehavior();
|
|
2
13
|
export function Store() {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
14
|
+
const decorator = createClassDecorator(storeBehavior);
|
|
15
|
+
// Store decorators work on any class, not just RootComponent
|
|
16
|
+
return decorator;
|
|
6
17
|
}
|
|
7
18
|
export function UseStore(StoreConstructor) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!
|
|
15
|
-
storeRegistry.
|
|
16
|
-
|
|
19
|
+
const cache = new WeakMap();
|
|
20
|
+
return createFieldDecorator({
|
|
21
|
+
bind(_instance, _name, _initialValue) {
|
|
22
|
+
return {
|
|
23
|
+
descriptor: {
|
|
24
|
+
get() {
|
|
25
|
+
if (!cache.has(this)) {
|
|
26
|
+
if (!storeRegistry.has(StoreConstructor) ||
|
|
27
|
+
storeRegistry.get(StoreConstructor) === null) {
|
|
28
|
+
storeRegistry.set(StoreConstructor, new StoreConstructor());
|
|
29
|
+
}
|
|
30
|
+
cache.set(this, storeRegistry.get(StoreConstructor));
|
|
17
31
|
}
|
|
18
|
-
cache.
|
|
19
|
-
}
|
|
20
|
-
return cache.get(this);
|
|
32
|
+
return cache.get(this);
|
|
33
|
+
},
|
|
21
34
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
// Store decorators work on any class, not just StatefulComponent
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
});
|
|
27
40
|
}
|
|
28
41
|
//# sourceMappingURL=decorators.js.map
|
package/dist/decorators.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,aAAa,EAEb,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgD,CAAC;AAE9E,MAAM,aAAc,SAAQ,aAAa;IACvC,MAAM,CAAC,SAAwB;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8DAA8D;IAC9D,UAAU,CAAC,QAAyC;QAClD,aAAa,CAAC,GAAG,CAAC,QAA+C,EAAE,IAAI,CAAC,CAAC;IAC3E,CAAC;CACF;AAED,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;AAE1C,MAAM,UAAU,KAAK;IACnB,MAAM,SAAS,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;IACtD,6DAA6D;IAE7D,OAAO,SAA2I,CAAC;AACrJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,gBAAmC;IAC1D,MAAM,KAAK,GAAG,IAAI,OAAO,EAAmB,CAAC;IAE7C,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,aAAa;YAClC,OAAO;gBACL,UAAU,EAAE;oBACV,GAAG;wBACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;4BACrB,IACE,CAAC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC;gCACpC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,IAAI,EAC5C,CAAC;gCACD,aAAa,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,gBAAgB,EAAE,CAAC,CAAC;4BAC9D,CAAC;4BACD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;wBACvD,CAAC;wBACD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACzB,CAAC;iBACF;aACF,CAAC;QACJ,CAAC;QACH,iEAAiE;QACjE,8DAA8D;KAC7D,CAAqF,CAAC;AACzF,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/store",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"typescript": "^5.9.3"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@praxisjs/core": "0.
|
|
17
|
+
"@praxisjs/core": "1.0.0",
|
|
18
|
+
"@praxisjs/decorators": "0.5.0"
|
|
18
19
|
},
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "tsc",
|
|
@@ -95,4 +95,75 @@ describe("createStore", () => {
|
|
|
95
95
|
).not.toThrow();
|
|
96
96
|
expect(store.count).toBe(0);
|
|
97
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("getting via a symbol key returns undefined", () => {
|
|
149
|
+
const store = makeCounter();
|
|
150
|
+
const sym = Symbol("test");
|
|
151
|
+
const val = Reflect.get(store as object, sym);
|
|
152
|
+
expect(val).toBeUndefined();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("$state() snapshot includes getter values", () => {
|
|
156
|
+
const store = createStore({
|
|
157
|
+
a: 2,
|
|
158
|
+
b: 3,
|
|
159
|
+
get sum() {
|
|
160
|
+
return (this as unknown as { a: number; b: number }).a + (this as unknown as { a: number; b: number }).b;
|
|
161
|
+
},
|
|
162
|
+
})();
|
|
163
|
+
|
|
164
|
+
// $state returns only signal-backed fields (not getters)
|
|
165
|
+
const state = (store as unknown as { $state: () => Record<string, unknown> }).$state();
|
|
166
|
+
expect(state).toHaveProperty("a", 2);
|
|
167
|
+
expect(state).toHaveProperty("b", 3);
|
|
168
|
+
});
|
|
98
169
|
});
|
|
@@ -11,6 +11,17 @@ describe("Store decorator", () => {
|
|
|
11
11
|
{ Store()(CounterStore, {} as ClassDecoratorContext); },
|
|
12
12
|
).not.toThrow();
|
|
13
13
|
});
|
|
14
|
+
|
|
15
|
+
it("StoreBehavior.create() is invoked when an enhanced instance is constructed", () => {
|
|
16
|
+
class MyStore {
|
|
17
|
+
value = 42;
|
|
18
|
+
}
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
const Enhanced = Store()(MyStore as any, {} as ClassDecoratorContext);
|
|
21
|
+
// Creating an instance calls StoreBehavior.create() internally (returns {})
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
expect(() => new (Enhanced as any)()).not.toThrow();
|
|
24
|
+
});
|
|
14
25
|
});
|
|
15
26
|
|
|
16
27
|
describe("UseStore decorator", () => {
|
package/src/decorators.ts
CHANGED
|
@@ -1,32 +1,57 @@
|
|
|
1
|
+
import type { RootComponent } from "@praxisjs/core/internal";
|
|
2
|
+
import {
|
|
3
|
+
createClassDecorator,
|
|
4
|
+
ClassBehavior,
|
|
5
|
+
type ClassEnhancement,
|
|
6
|
+
createFieldDecorator,
|
|
7
|
+
type FieldBinding,
|
|
8
|
+
} from "@praxisjs/decorators";
|
|
9
|
+
|
|
1
10
|
const storeRegistry = new Map<new (...args: unknown[]) => unknown, unknown>();
|
|
2
11
|
|
|
12
|
+
class StoreBehavior extends ClassBehavior {
|
|
13
|
+
create(_instance: RootComponent): ClassEnhancement {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
initialize(Enhanced: new (...args: any[]) => unknown): void {
|
|
19
|
+
storeRegistry.set(Enhanced as new (...args: unknown[]) => unknown, null);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const storeBehavior = new StoreBehavior();
|
|
24
|
+
|
|
3
25
|
export function Store() {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
26
|
+
const decorator = createClassDecorator(storeBehavior);
|
|
27
|
+
// Store decorators work on any class, not just RootComponent
|
|
28
|
+
|
|
29
|
+
return decorator as unknown as (value: new (...args: unknown[]) => unknown, context: ClassDecoratorContext) => new (...args: unknown[]) => unknown;
|
|
7
30
|
}
|
|
8
31
|
|
|
9
32
|
export function UseStore(StoreConstructor: new () => unknown) {
|
|
10
|
-
|
|
11
|
-
const cache = new WeakMap<object, unknown>();
|
|
33
|
+
const cache = new WeakMap<object, unknown>();
|
|
12
34
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
return createFieldDecorator({
|
|
36
|
+
bind(_instance, _name, _initialValue): FieldBinding {
|
|
37
|
+
return {
|
|
38
|
+
descriptor: {
|
|
39
|
+
get(this: object): unknown {
|
|
40
|
+
if (!cache.has(this)) {
|
|
41
|
+
if (
|
|
42
|
+
!storeRegistry.has(StoreConstructor) ||
|
|
43
|
+
storeRegistry.get(StoreConstructor) === null
|
|
44
|
+
) {
|
|
45
|
+
storeRegistry.set(StoreConstructor, new StoreConstructor());
|
|
46
|
+
}
|
|
47
|
+
cache.set(this, storeRegistry.get(StoreConstructor));
|
|
22
48
|
}
|
|
23
|
-
cache.
|
|
24
|
-
}
|
|
25
|
-
return cache.get(this);
|
|
49
|
+
return cache.get(this);
|
|
50
|
+
},
|
|
26
51
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
// Store decorators work on any class, not just StatefulComponent
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
+
}) as unknown as (_value: undefined, context: ClassFieldDecoratorContext<any>) => void;
|
|
32
57
|
}
|
package/src/index.ts
CHANGED