@esmx/class-state 3.0.0-rc.10

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.
@@ -0,0 +1,63 @@
1
+ const rootMap = /* @__PURE__ */ new WeakMap();
2
+ export class StateContext {
3
+ state;
4
+ storeContext = /* @__PURE__ */ new Map();
5
+ constructor(state) {
6
+ this.state = state;
7
+ }
8
+ depend(fullPath) {
9
+ if (fullPath) {
10
+ return this.state.value[fullPath];
11
+ }
12
+ return this.state.value;
13
+ }
14
+ hasState(name) {
15
+ return name in this.state.value;
16
+ }
17
+ get(name) {
18
+ return this.storeContext.get(name) ?? null;
19
+ }
20
+ add(name, storeContext) {
21
+ this.storeContext.set(name, storeContext);
22
+ }
23
+ updateState(name, nextState) {
24
+ const { state } = this;
25
+ if (name in state.value) {
26
+ state.value[name] = nextState;
27
+ } else {
28
+ state.value = {
29
+ ...state.value,
30
+ [name]: nextState
31
+ };
32
+ }
33
+ }
34
+ del(name) {
35
+ const { state } = this;
36
+ this.storeContext.delete(name);
37
+ const newValue = {};
38
+ Object.keys(state.value).forEach((key) => {
39
+ if (key !== name) {
40
+ newValue[key] = state.value[key];
41
+ }
42
+ });
43
+ state.value = newValue;
44
+ }
45
+ }
46
+ function setStateContext(state, stateContext) {
47
+ rootMap.set(state, stateContext);
48
+ }
49
+ export function getStateContext(state) {
50
+ let stateContext = rootMap.get(state);
51
+ if (stateContext) {
52
+ return stateContext;
53
+ } else {
54
+ stateContext = new StateContext(state);
55
+ setStateContext(state, stateContext);
56
+ }
57
+ return stateContext;
58
+ }
59
+ export function createState(state) {
60
+ return getStateContext(
61
+ (state == null ? void 0 : state.value) && typeof state.value === "object" ? state : { value: {} }
62
+ ).state;
63
+ }
@@ -0,0 +1,2 @@
1
+ export { createState, type State } from './create';
2
+ export { connectState, foreignStore, type StoreConstructor, type StoreContext, type StoreInstance, type StoreParams, LIFE_CYCLE_CREATED, LIFE_CYCLE_DISPOSE } from './connect';
package/dist/index.mjs ADDED
@@ -0,0 +1,7 @@
1
+ export { createState } from "./create.mjs";
2
+ export {
3
+ connectState,
4
+ foreignStore,
5
+ LIFE_CYCLE_CREATED,
6
+ LIFE_CYCLE_DISPOSE
7
+ } from "./connect.mjs";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,78 @@
1
+ import { assert, test } from "vitest";
2
+ import { nextTick, reactive, watch } from "vue";
3
+ import { connectState } from "./connect.mjs";
4
+ import { createState } from "./create.mjs";
5
+ test("base", async () => {
6
+ const state = createState(reactive({ value: {} }));
7
+ const connectStore = connectState(state);
8
+ class User {
9
+ name = "";
10
+ $setName(name) {
11
+ this.name = name;
12
+ }
13
+ }
14
+ const user = connectStore(User, "user");
15
+ let updateValue;
16
+ watch(
17
+ () => {
18
+ return user.name;
19
+ },
20
+ (name) => {
21
+ updateValue = name;
22
+ }
23
+ );
24
+ user.$setName("test");
25
+ await nextTick();
26
+ assert.equal(updateValue, "test");
27
+ user.$setName("test2");
28
+ await nextTick();
29
+ assert.equal(updateValue, "test2");
30
+ });
31
+ test("base2", async () => {
32
+ const state = createState(reactive({ value: {} }));
33
+ const connectStore = connectState(state);
34
+ class User {
35
+ name = "";
36
+ $setName(name) {
37
+ this.name = name;
38
+ }
39
+ }
40
+ const user = connectStore(User, "user");
41
+ user.$setName("test");
42
+ let updateValue;
43
+ watch(
44
+ () => {
45
+ return user.name;
46
+ },
47
+ (name) => {
48
+ updateValue = name;
49
+ }
50
+ );
51
+ user.$setName("test2");
52
+ await nextTick();
53
+ assert.equal(updateValue, "test2");
54
+ });
55
+ test("watch root", async () => {
56
+ const state = createState(reactive({ value: {} }));
57
+ const connectStore = connectState(state);
58
+ class User {
59
+ name = "";
60
+ $setName(name) {
61
+ this.name = name;
62
+ }
63
+ }
64
+ const user = connectStore(User, "user");
65
+ let updateCount = 0;
66
+ watch(
67
+ () => {
68
+ return connectStore(User, "user");
69
+ },
70
+ () => {
71
+ updateCount++;
72
+ }
73
+ );
74
+ assert.equal(user.$.connecting, false);
75
+ user.$setName("test2");
76
+ await nextTick();
77
+ assert.equal(updateCount, 1);
78
+ });
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@esmx/class-state",
3
+ "template": "library",
4
+ "license": "MIT",
5
+ "scripts": {
6
+ "lint:js": "biome check --write --no-errors-on-unmatched",
7
+ "lint:css": "stylelint '**/*.{css,vue}' --fix --aei",
8
+ "lint:type": "tsc --noEmit",
9
+ "test": "vitest run --pass-with-no-tests",
10
+ "coverage": "vitest run --coverage --pass-with-no-tests",
11
+ "build": "unbuild"
12
+ },
13
+ "dependencies": {
14
+ "immer": "^10.1.1"
15
+ },
16
+ "devDependencies": {
17
+ "@biomejs/biome": "1.9.4",
18
+ "@esmx/lint": "3.0.0-rc.10",
19
+ "@types/node": "22.13.10",
20
+ "@vitest/coverage-v8": "3.0.8",
21
+ "@vue/compiler-dom": "^3.5.13",
22
+ "stylelint": "16.15.0",
23
+ "typescript": "5.8.2",
24
+ "unbuild": "2.0.0",
25
+ "vitest": "3.0.8",
26
+ "vue": "^3.5.13"
27
+ },
28
+ "version": "3.0.0-rc.10",
29
+ "type": "module",
30
+ "private": false,
31
+ "exports": {
32
+ ".": {
33
+ "import": "./dist/index.mjs",
34
+ "types": "./dist/index.d.ts"
35
+ }
36
+ },
37
+ "module": "dist/index.mjs",
38
+ "types": "./dist/index.d.ts",
39
+ "files": [
40
+ "lib",
41
+ "src",
42
+ "dist",
43
+ "*.mjs",
44
+ "template",
45
+ "public"
46
+ ],
47
+ "gitHead": "4a528ffecfdc6f2c6e7d97bc952427745f467691"
48
+ }
@@ -0,0 +1,452 @@
1
+ import { assert, test } from 'vitest';
2
+
3
+ import { connectState, foreignStore } from './connect';
4
+ import { createState } from './create';
5
+
6
+ test('Base', () => {
7
+ const state = createState();
8
+ const STORE_NAME = 'user';
9
+ const connectStore = connectState(state);
10
+ class User {
11
+ public name = '';
12
+ public age = 18;
13
+ public text = '';
14
+ public online = false;
15
+ public constructor() {
16
+ Object.defineProperty(this, 'online', {
17
+ enumerable: false
18
+ });
19
+ }
20
+
21
+ public $setName(name: string) {
22
+ this.name = name;
23
+ }
24
+
25
+ public $setAge(age: number) {
26
+ this.age = age;
27
+ }
28
+
29
+ public $buildText() {
30
+ this.text = `${this.name} is ${this.age} years old.`;
31
+ }
32
+
33
+ public $toggleOnline() {
34
+ this.online = !this.online;
35
+ }
36
+ }
37
+ const user = connectStore(User, STORE_NAME);
38
+
39
+ assert.equal(user.name, '');
40
+ assert.isUndefined(state.value.user);
41
+
42
+ // user.$setName('jack');
43
+ // assert.strictEqual(user.name, 'jack');
44
+ // assert.strictEqual(state.value.user.name, user.name);
45
+
46
+ // user.$setAge(20);
47
+ // assert.strictEqual(user.age, 20);
48
+ // assert.strictEqual(state.value.user.age, user.age);
49
+
50
+ // user.$buildText();
51
+ // assert.strictEqual(user.text, 'jack is 20 years old.');
52
+ // assert.strictEqual(state.value.user.text, user.text);
53
+ // assert.isUndefined(state.value.user.online);
54
+
55
+ // assert.strictEqual(user.online, false);
56
+ // user.$toggleOnline();
57
+ // assert.strictEqual(user.online, true);
58
+ });
59
+
60
+ test('Object type', () => {
61
+ const state = createState();
62
+ const STORE_NAME = 'user';
63
+ const connectStore = connectState(state);
64
+ class User {
65
+ public data = {
66
+ name: '',
67
+ age: 18
68
+ };
69
+
70
+ public get text() {
71
+ return `${this.data.name} is ${this.data.age} years old.`;
72
+ }
73
+
74
+ public $setName(name: string) {
75
+ this.data.name = name;
76
+ }
77
+
78
+ public $setAge(age: number) {
79
+ this.data.age = age;
80
+ }
81
+ }
82
+ const user = connectStore(User, STORE_NAME);
83
+
84
+ const preData = user.data;
85
+ user.$setName('jack');
86
+ assert.strictEqual(user.data.name, 'jack');
87
+ assert.strictEqual(user.data.age, 18);
88
+ assert.notStrictEqual(user.data, preData);
89
+
90
+ assert.strictEqual(user.text, 'jack is 18 years old.');
91
+ });
92
+
93
+ test('Commit function this bind', () => {
94
+ const state = createState();
95
+
96
+ const STORE_NAME = 'user';
97
+ const connectStore = connectState(state);
98
+ class User {
99
+ public name = '';
100
+ public $setName(name: string) {
101
+ this.name = name;
102
+ }
103
+ }
104
+ const user = connectStore(User, STORE_NAME);
105
+ const setName = user.$setName;
106
+ setName('jack');
107
+
108
+ assert.strictEqual(user.name, 'jack');
109
+ });
110
+
111
+ test('Commit function return value and args', () => {
112
+ const state = createState();
113
+
114
+ const STORE_NAME = 'user';
115
+ const connectStore = connectState(state);
116
+ class User {
117
+ public list: string[] = [];
118
+ public $add(...list: string[]) {
119
+ this.list.push(...list);
120
+ return true;
121
+ }
122
+ }
123
+
124
+ const user = connectStore(User, STORE_NAME);
125
+ assert.isTrue(user.$add('jack', 'tom'));
126
+ assert.deepEqual(user.list, ['jack', 'tom']);
127
+ });
128
+
129
+ test('Instance reference', () => {
130
+ const state = createState();
131
+
132
+ const STORE_NAME = 'user';
133
+ const connectStore = connectState(state);
134
+ class User {
135
+ public name = '';
136
+ public $setName(name: string) {
137
+ this.name = name;
138
+ }
139
+ }
140
+ const user = connectStore(User, STORE_NAME);
141
+ assert.strictEqual(user, connectStore(User, STORE_NAME));
142
+
143
+ user.$setName('jack');
144
+
145
+ assert.notStrictEqual(user, connectStore(User, STORE_NAME));
146
+ });
147
+
148
+ test('Disconnect', () => {
149
+ const state = createState();
150
+ const STORE_NAME = 'user';
151
+ const connectStore = connectState(state);
152
+ class User {
153
+ public name = '';
154
+ public $setName(name: string) {
155
+ this.name = name;
156
+ }
157
+ }
158
+ const user = connectStore(User, STORE_NAME);
159
+
160
+ assert.isUndefined(state.value.user);
161
+
162
+ user.$setName('jack');
163
+ assert.strictEqual(state.value.user, user.$.state);
164
+
165
+ user.$.dispose();
166
+ assert.isUndefined(state.value.user);
167
+ // @ts-expect-error need test
168
+ assert.isNull(user.$._stateContext);
169
+ });
170
+ test('Preset state', () => {
171
+ const STORE_NAME = 'user';
172
+ const state = createState({
173
+ value: {
174
+ [STORE_NAME]: {
175
+ name: 'jack'
176
+ }
177
+ }
178
+ });
179
+ const connectStore = connectState(state);
180
+ class User {
181
+ public name = '';
182
+ public age = 18;
183
+ }
184
+ const user = connectStore(User, STORE_NAME);
185
+
186
+ assert.strictEqual(user.name, 'jack');
187
+ assert.strictEqual(user.age, 18);
188
+ assert.notStrictEqual(user.$.state, state.value.user);
189
+ assert.deepEqual(state.value.user, { name: 'jack' });
190
+ });
191
+
192
+ test('State modification delay', () => {
193
+ const STORE_NAME = 'user';
194
+ const state = createState();
195
+ const connectStore = connectState(state);
196
+
197
+ class User {
198
+ public static storeName = 'user';
199
+ public name = '';
200
+ public age = 0;
201
+
202
+ public $setAge(age: number) {
203
+ this.age = age;
204
+ }
205
+
206
+ public $setName(name: string) {
207
+ this.name = name;
208
+ }
209
+ }
210
+ const user = connectStore(User, STORE_NAME);
211
+ const setAge = user.$setAge.bind(user);
212
+
213
+ user.$setName('test');
214
+ assert.equal(user.name, 'test');
215
+ assert.equal(user.age, 0);
216
+
217
+ user.$setAge(100);
218
+ assert.equal(user.name, 'test');
219
+ assert.equal(user.age, 100);
220
+
221
+ setAge(200);
222
+ assert.equal(user.name, 'test');
223
+ assert.equal(user.age, 200);
224
+ });
225
+
226
+ test('Multiple instances', () => {
227
+ const state = createState();
228
+ const _connectStore = connectState(state);
229
+
230
+ class User {
231
+ public name = '';
232
+ public get blog() {
233
+ return foreignStore(Blog, 'blog')!;
234
+ }
235
+
236
+ public get log() {
237
+ return `'${this.name}' published '${this.blog.text}'`;
238
+ }
239
+
240
+ public $setName(name: string) {
241
+ this.name = name;
242
+ }
243
+ }
244
+
245
+ class Blog {
246
+ public text = '';
247
+ public $setText(text: string) {
248
+ this.text = text;
249
+ }
250
+ }
251
+
252
+ const user = _connectStore(User, 'user');
253
+
254
+ user.$setName('jack');
255
+ user.blog.$setText('hello world.');
256
+
257
+ assert.strictEqual(user.name, 'jack');
258
+ assert.equal(user.log, "'jack' published 'hello world.'");
259
+ });
260
+
261
+ test('Params', () => {
262
+ const state = createState();
263
+ const connectStore = connectState(state);
264
+
265
+ class User {
266
+ public name = '';
267
+ public uid: string;
268
+ public constructor(uid?: string) {
269
+ this.uid = uid ?? '';
270
+ }
271
+
272
+ public $setName(name: string) {
273
+ this.name = name;
274
+ }
275
+ }
276
+ const user100 = connectStore(User, 'user', '100');
277
+ user100.$setName('jack');
278
+ assert.strictEqual(user100.uid, '100');
279
+
280
+ const user200 = connectStore(User, 'user', '200');
281
+ user200.$setName('tom');
282
+ assert.strictEqual(user100.uid, '100');
283
+ assert.notStrictEqual(user100, user200);
284
+
285
+ assert.strictEqual(state.value['user/100'], user100.$.state);
286
+ assert.strictEqual(state.value['user/200'], user200.$.state);
287
+
288
+ assert.deepEqual(state.value['user/100'], { uid: '100', name: 'jack' });
289
+ assert.deepEqual(state.value['user/200'], { uid: '200', name: 'tom' });
290
+ });
291
+
292
+ test('Call commit multiple times', () => {
293
+ const state = createState();
294
+ const connectStore = connectState(state);
295
+
296
+ class User {
297
+ public name = '';
298
+ public age = 0;
299
+ public text = '';
300
+ public $setName(name: string) {
301
+ this.name = name;
302
+ return '1';
303
+ }
304
+
305
+ public $setAge(age: number) {
306
+ this.age = age;
307
+ return '2';
308
+ }
309
+
310
+ public $setUser(name: string, age: number) {
311
+ const v1 = this.$setName(name);
312
+ const v2 = this.$setAge(age);
313
+ this.text = v1 + v2;
314
+ }
315
+ }
316
+ const user = connectStore(User, 'user');
317
+
318
+ user.$setUser('jack', 18);
319
+
320
+ assert.equal(user.name, 'jack');
321
+ assert.equal(user.age, 18);
322
+ assert.equal(user.text, '12');
323
+ });
324
+
325
+ test('No a submit function modification state', () => {
326
+ const state = createState();
327
+ const connectStore = connectState(state);
328
+
329
+ class User {
330
+ public name = '';
331
+ public setName(name: string) {
332
+ this.name = name;
333
+ }
334
+ }
335
+ const user = connectStore(User, 'user');
336
+ assert.Throw(() => {
337
+ user.setName('jack');
338
+ }, "Change the state in the agreed commit function, For example, $name('jack')");
339
+ });
340
+
341
+ test('Equal submit function', () => {
342
+ const state = createState();
343
+ const connectStore = connectState(state);
344
+
345
+ class User {
346
+ public name = '';
347
+ public $setName(name: string) {
348
+ this.name = name;
349
+ }
350
+ }
351
+ const user = connectStore(User, 'user');
352
+
353
+ assert.equal(user.$setName, user.$setName);
354
+ });
355
+
356
+ test('State Restore', () => {
357
+ const state = createState({
358
+ value: {
359
+ user: {
360
+ name: 'jack'
361
+ }
362
+ }
363
+ });
364
+ const connectStore = connectState(state);
365
+
366
+ class User {
367
+ public name = '';
368
+ public $setName(name: string) {
369
+ this.name = name;
370
+ }
371
+ }
372
+ const user = connectStore(User, 'user');
373
+ assert.equal(user.name, 'jack');
374
+ });
375
+
376
+ test('update value', () => {
377
+ const state = createState();
378
+ const connectStore = connectState(state);
379
+ class Count {
380
+ public value = 0;
381
+ public text = '';
382
+ public $inc() {
383
+ this.value++;
384
+ }
385
+
386
+ public $setText(text: string) {
387
+ this.text = text;
388
+ }
389
+ }
390
+ const count = connectStore(Count, 'count');
391
+ const setText = count.$setText;
392
+
393
+ count.$inc();
394
+ assert.equal(count.value, 1);
395
+
396
+ count.$inc();
397
+ assert.equal(count.value, 2);
398
+
399
+ count.$inc();
400
+ assert.equal(count.value, 3);
401
+
402
+ setText('hello world');
403
+ assert.equal(count.value, 3);
404
+ assert.equal(count.text, 'hello world');
405
+
406
+ setText('hello world2');
407
+ assert.equal(count.value, 3);
408
+ assert.equal(count.text, 'hello world2');
409
+ });
410
+
411
+ test('default connecting', () => {
412
+ const state = createState({
413
+ value: {
414
+ count: {
415
+ value: 100
416
+ }
417
+ }
418
+ });
419
+ const connectStore = connectState(state);
420
+ class Count {
421
+ public value = 0;
422
+ public $inc() {
423
+ this.value++;
424
+ }
425
+ }
426
+ const count = connectStore(Count, 'count');
427
+ assert.equal(count.value, 100);
428
+ assert.equal(count.$.connecting, true);
429
+ });
430
+
431
+ test('update state', () => {
432
+ const state = createState({
433
+ value: {
434
+ count: {
435
+ value: 100
436
+ }
437
+ }
438
+ });
439
+ const connectStore = connectState(state);
440
+ class Count {
441
+ public value = 0;
442
+ public $inc() {
443
+ this.value++;
444
+ }
445
+ }
446
+ const count = connectStore(Count, 'count');
447
+
448
+ count.$inc();
449
+ const value = state.value;
450
+ count.$inc();
451
+ assert.equal(value, state.value);
452
+ });