@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.
- package/dist/connect.d.ts +80 -0
- package/dist/connect.mjs +244 -0
- package/dist/connect.test.d.ts +1 -0
- package/dist/connect.test.mjs +365 -0
- package/dist/create.d.ts +17 -0
- package/dist/create.mjs +63 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.mjs +7 -0
- package/dist/vue.test.d.ts +1 -0
- package/dist/vue.test.mjs +78 -0
- package/package.json +48 -0
- package/src/connect.test.ts +452 -0
- package/src/connect.ts +306 -0
- package/src/create.ts +83 -0
- package/src/index.ts +11 -0
- package/src/vue.test.ts +83 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type State, type StateContext } from './create';
|
|
2
|
+
export type StoreParams = Record<string, any>;
|
|
3
|
+
export type StoreConstructor = new (cacheKey?: string) => any;
|
|
4
|
+
export type StoreInstance<T extends {}> = T & {
|
|
5
|
+
$: StoreContext<T>;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* class created
|
|
9
|
+
*/
|
|
10
|
+
export declare const LIFE_CYCLE_CREATED: unique symbol;
|
|
11
|
+
/**
|
|
12
|
+
* class dispose
|
|
13
|
+
*/
|
|
14
|
+
export declare const LIFE_CYCLE_DISPOSE: unique symbol;
|
|
15
|
+
export type StoreSubscribe = () => void;
|
|
16
|
+
export declare class StoreContext<T extends {}> {
|
|
17
|
+
/**
|
|
18
|
+
* 全局的状态上下文
|
|
19
|
+
*/
|
|
20
|
+
private _stateContext;
|
|
21
|
+
/**
|
|
22
|
+
* 原始实例
|
|
23
|
+
*/
|
|
24
|
+
private readonly _raw;
|
|
25
|
+
/**
|
|
26
|
+
* 原始实例的代理,每次状态变化时,代理都会更新
|
|
27
|
+
*/
|
|
28
|
+
private _proxy;
|
|
29
|
+
/**
|
|
30
|
+
* 当前的 state 是否是草稿状态
|
|
31
|
+
*/
|
|
32
|
+
private _drafting;
|
|
33
|
+
/**
|
|
34
|
+
* $ 函数的缓存对象
|
|
35
|
+
*/
|
|
36
|
+
private readonly _cacheCommit;
|
|
37
|
+
/**
|
|
38
|
+
* 当前的 store 的存储路径
|
|
39
|
+
*/
|
|
40
|
+
readonly keyPath: string;
|
|
41
|
+
/**
|
|
42
|
+
* 最新的状态
|
|
43
|
+
*/
|
|
44
|
+
state: Record<string, any>;
|
|
45
|
+
/**
|
|
46
|
+
* 当前的 store 的 state 是否已经连接到全局的 state 中
|
|
47
|
+
*/
|
|
48
|
+
connecting: boolean;
|
|
49
|
+
private readonly _subs;
|
|
50
|
+
constructor(stateContext: StateContext, raw: T, state: Record<string, any>, keyPath: string);
|
|
51
|
+
/**
|
|
52
|
+
* 获取当前代理实例,每次状态变化时,代理实例都会变化
|
|
53
|
+
* 已绑定 this
|
|
54
|
+
*/
|
|
55
|
+
get(): StoreInstance<T>;
|
|
56
|
+
/**
|
|
57
|
+
* 私有函数,外部调用不应该使用
|
|
58
|
+
*/
|
|
59
|
+
_setState(nextState: Record<string, any>): void;
|
|
60
|
+
/**
|
|
61
|
+
* 销毁实例,释放内存
|
|
62
|
+
* 已绑定 this
|
|
63
|
+
*/
|
|
64
|
+
dispose(): void;
|
|
65
|
+
/**
|
|
66
|
+
* 订阅状态变化
|
|
67
|
+
* @param cb 回调函数
|
|
68
|
+
* 已绑定 this
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
71
|
+
subscribe(cb: StoreSubscribe): () => void;
|
|
72
|
+
private _depend;
|
|
73
|
+
private _createProxyClass;
|
|
74
|
+
private _createProxyCommit;
|
|
75
|
+
}
|
|
76
|
+
export declare function connectState(state: State): <T extends StoreConstructor>(Store: T, name: string, cacheKey?: string) => StoreInstance<InstanceType<T>>;
|
|
77
|
+
/**
|
|
78
|
+
* 查找外部的 store。如果没有找到则返回 null
|
|
79
|
+
*/
|
|
80
|
+
export declare function foreignStore<T extends StoreConstructor>(Store: T, name: string, cacheKey?: string): InstanceType<T> | null;
|
package/dist/connect.mjs
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { produce } from "immer";
|
|
2
|
+
import { getStateContext } from "./create.mjs";
|
|
3
|
+
let currentStateContext = null;
|
|
4
|
+
export const LIFE_CYCLE_CREATED = Symbol("class created");
|
|
5
|
+
export const LIFE_CYCLE_DISPOSE = Symbol("class dispose");
|
|
6
|
+
let sid = 0;
|
|
7
|
+
function noon() {
|
|
8
|
+
}
|
|
9
|
+
export class StoreContext {
|
|
10
|
+
/**
|
|
11
|
+
* 全局的状态上下文
|
|
12
|
+
*/
|
|
13
|
+
_stateContext;
|
|
14
|
+
/**
|
|
15
|
+
* 原始实例
|
|
16
|
+
*/
|
|
17
|
+
_raw;
|
|
18
|
+
/**
|
|
19
|
+
* 原始实例的代理,每次状态变化时,代理都会更新
|
|
20
|
+
*/
|
|
21
|
+
_proxy;
|
|
22
|
+
/**
|
|
23
|
+
* 当前的 state 是否是草稿状态
|
|
24
|
+
*/
|
|
25
|
+
_drafting = false;
|
|
26
|
+
/**
|
|
27
|
+
* $ 函数的缓存对象
|
|
28
|
+
*/
|
|
29
|
+
_cacheCommit = /* @__PURE__ */ new Map();
|
|
30
|
+
/**
|
|
31
|
+
* 当前的 store 的存储路径
|
|
32
|
+
*/
|
|
33
|
+
keyPath;
|
|
34
|
+
/**
|
|
35
|
+
* 最新的状态
|
|
36
|
+
*/
|
|
37
|
+
state;
|
|
38
|
+
/**
|
|
39
|
+
* 当前的 store 的 state 是否已经连接到全局的 state 中
|
|
40
|
+
*/
|
|
41
|
+
connecting;
|
|
42
|
+
_subs = [];
|
|
43
|
+
constructor(stateContext, raw, state, keyPath) {
|
|
44
|
+
this._stateContext = stateContext;
|
|
45
|
+
stateContext.add(keyPath, this);
|
|
46
|
+
this._raw = raw;
|
|
47
|
+
this._proxy = this._createProxyClass();
|
|
48
|
+
this.state = state;
|
|
49
|
+
this.keyPath = keyPath;
|
|
50
|
+
this.connecting = stateContext.hasState(keyPath);
|
|
51
|
+
this.get = this.get.bind(this);
|
|
52
|
+
this.subscribe = this.subscribe.bind(this);
|
|
53
|
+
this.dispose = this.dispose.bind(this);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 获取当前代理实例,每次状态变化时,代理实例都会变化
|
|
57
|
+
* 已绑定 this
|
|
58
|
+
*/
|
|
59
|
+
get() {
|
|
60
|
+
this._depend();
|
|
61
|
+
return this._proxy;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 私有函数,外部调用不应该使用
|
|
65
|
+
*/
|
|
66
|
+
_setState(nextState) {
|
|
67
|
+
const { _stateContext, keyPath: fullPath, _subs } = this;
|
|
68
|
+
this.state = nextState;
|
|
69
|
+
if (_stateContext) {
|
|
70
|
+
_stateContext.updateState(fullPath, nextState);
|
|
71
|
+
}
|
|
72
|
+
this.connecting = !!_stateContext;
|
|
73
|
+
const store = this._createProxyClass();
|
|
74
|
+
this._proxy = store;
|
|
75
|
+
if (_subs.length) {
|
|
76
|
+
const subs = [..._subs];
|
|
77
|
+
subs.forEach((item) => {
|
|
78
|
+
item.cb();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 销毁实例,释放内存
|
|
84
|
+
* 已绑定 this
|
|
85
|
+
*/
|
|
86
|
+
dispose() {
|
|
87
|
+
const { _stateContext, _proxy } = this;
|
|
88
|
+
call(_proxy, LIFE_CYCLE_DISPOSE);
|
|
89
|
+
if (_stateContext) {
|
|
90
|
+
_stateContext.del(this.keyPath);
|
|
91
|
+
this._stateContext = null;
|
|
92
|
+
}
|
|
93
|
+
this._subs.splice(0);
|
|
94
|
+
this.dispose = noon;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 订阅状态变化
|
|
98
|
+
* @param cb 回调函数
|
|
99
|
+
* 已绑定 this
|
|
100
|
+
* @returns
|
|
101
|
+
*/
|
|
102
|
+
subscribe(cb) {
|
|
103
|
+
const _sid = ++sid;
|
|
104
|
+
this._subs.push({
|
|
105
|
+
sid,
|
|
106
|
+
cb
|
|
107
|
+
});
|
|
108
|
+
return () => {
|
|
109
|
+
const index = this._subs.findIndex((item) => item.sid === _sid);
|
|
110
|
+
if (index > -1) {
|
|
111
|
+
this._subs.splice(index, 1);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
_depend() {
|
|
116
|
+
const stateContext = this._stateContext;
|
|
117
|
+
if (stateContext) {
|
|
118
|
+
if (this.connecting) {
|
|
119
|
+
stateContext.depend(this.keyPath);
|
|
120
|
+
} else {
|
|
121
|
+
stateContext.depend();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
_createProxyClass() {
|
|
126
|
+
const storeContext = this;
|
|
127
|
+
return new Proxy(this._raw, {
|
|
128
|
+
get(target, p, receiver) {
|
|
129
|
+
if (p === "$") {
|
|
130
|
+
return storeContext;
|
|
131
|
+
} else if (typeof p === "string") {
|
|
132
|
+
const state = storeContext.state;
|
|
133
|
+
if (p in state) {
|
|
134
|
+
storeContext._depend();
|
|
135
|
+
return state[p];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const result = applyStateContext(
|
|
139
|
+
storeContext._stateContext,
|
|
140
|
+
() => Reflect.get(target, p, receiver)
|
|
141
|
+
);
|
|
142
|
+
if (typeof result === "function" && typeof p === "string" && p.startsWith("$")) {
|
|
143
|
+
let func = storeContext._cacheCommit.get(result);
|
|
144
|
+
if (!func) {
|
|
145
|
+
func = storeContext._createProxyCommit(result);
|
|
146
|
+
storeContext._cacheCommit.set(result, func);
|
|
147
|
+
}
|
|
148
|
+
return func;
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
},
|
|
152
|
+
set(target, p, newValue, receiver) {
|
|
153
|
+
if (typeof p === "string" && p in storeContext.state) {
|
|
154
|
+
if (storeContext._drafting) {
|
|
155
|
+
storeContext.state[p] = newValue;
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Change the state in the agreed commit function, For example, $${p}('${String(newValue)}')`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return Reflect.set(target, p, newValue, receiver);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
_createProxyCommit(commitFunc) {
|
|
167
|
+
const connectContext = this;
|
|
168
|
+
return function proxyCommit(...args) {
|
|
169
|
+
if (connectContext._drafting) {
|
|
170
|
+
return commitFunc.apply(connectContext._proxy, args);
|
|
171
|
+
}
|
|
172
|
+
const prevState = connectContext.state;
|
|
173
|
+
let result;
|
|
174
|
+
const nextState = produce(prevState, (draft) => {
|
|
175
|
+
connectContext._drafting = true;
|
|
176
|
+
connectContext.state = draft;
|
|
177
|
+
try {
|
|
178
|
+
result = commitFunc.apply(connectContext._proxy, args);
|
|
179
|
+
connectContext._drafting = false;
|
|
180
|
+
connectContext.state = prevState;
|
|
181
|
+
} catch (e) {
|
|
182
|
+
connectContext._drafting = false;
|
|
183
|
+
connectContext.state = prevState;
|
|
184
|
+
throw e;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
connectContext._setState(nextState);
|
|
188
|
+
return result;
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function getFullPath(name, cacheKey) {
|
|
193
|
+
return typeof cacheKey === "string" ? name + "/" + cacheKey : name;
|
|
194
|
+
}
|
|
195
|
+
export function connectState(state) {
|
|
196
|
+
const stateContext = getStateContext(state);
|
|
197
|
+
return (Store, name, cacheKey) => {
|
|
198
|
+
const fullPath = getFullPath(name, cacheKey);
|
|
199
|
+
let storeContext = stateContext.get(fullPath);
|
|
200
|
+
if (!storeContext) {
|
|
201
|
+
const store = applyStateContext(
|
|
202
|
+
stateContext,
|
|
203
|
+
() => new Store(cacheKey)
|
|
204
|
+
);
|
|
205
|
+
let storeState;
|
|
206
|
+
if (fullPath in state.value) {
|
|
207
|
+
storeState = { ...store, ...state.value[fullPath] };
|
|
208
|
+
} else {
|
|
209
|
+
storeState = { ...store };
|
|
210
|
+
}
|
|
211
|
+
storeContext = new StoreContext(
|
|
212
|
+
stateContext,
|
|
213
|
+
store,
|
|
214
|
+
storeState,
|
|
215
|
+
fullPath
|
|
216
|
+
);
|
|
217
|
+
call(storeContext.get(), LIFE_CYCLE_CREATED);
|
|
218
|
+
}
|
|
219
|
+
return storeContext.get();
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
export function foreignStore(Store, name, cacheKey) {
|
|
223
|
+
if (!currentStateContext) {
|
|
224
|
+
throw new Error("No state context found");
|
|
225
|
+
}
|
|
226
|
+
const fullPath = getFullPath(name, cacheKey);
|
|
227
|
+
const storeContext = currentStateContext.get(fullPath);
|
|
228
|
+
if (storeContext) {
|
|
229
|
+
return storeContext.get();
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
function call(obj, key) {
|
|
234
|
+
if (typeof obj[key] === "function") {
|
|
235
|
+
return obj[key]();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function applyStateContext(stateContext, cb) {
|
|
239
|
+
const prev = currentStateContext;
|
|
240
|
+
currentStateContext = stateContext;
|
|
241
|
+
const value = cb();
|
|
242
|
+
currentStateContext = prev;
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { assert, test } from "vitest";
|
|
5
|
+
import { connectState, foreignStore } from "./connect.mjs";
|
|
6
|
+
import { createState } from "./create.mjs";
|
|
7
|
+
test("Base", () => {
|
|
8
|
+
const state = createState();
|
|
9
|
+
const STORE_NAME = "user";
|
|
10
|
+
const connectStore = connectState(state);
|
|
11
|
+
class User {
|
|
12
|
+
name = "";
|
|
13
|
+
age = 18;
|
|
14
|
+
text = "";
|
|
15
|
+
online = false;
|
|
16
|
+
constructor() {
|
|
17
|
+
Object.defineProperty(this, "online", {
|
|
18
|
+
enumerable: false
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
$setName(name) {
|
|
22
|
+
this.name = name;
|
|
23
|
+
}
|
|
24
|
+
$setAge(age) {
|
|
25
|
+
this.age = age;
|
|
26
|
+
}
|
|
27
|
+
$buildText() {
|
|
28
|
+
this.text = `${this.name} is ${this.age} years old.`;
|
|
29
|
+
}
|
|
30
|
+
$toggleOnline() {
|
|
31
|
+
this.online = !this.online;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const user = connectStore(User, STORE_NAME);
|
|
35
|
+
assert.equal(user.name, "");
|
|
36
|
+
assert.isUndefined(state.value.user);
|
|
37
|
+
});
|
|
38
|
+
test("Object type", () => {
|
|
39
|
+
const state = createState();
|
|
40
|
+
const STORE_NAME = "user";
|
|
41
|
+
const connectStore = connectState(state);
|
|
42
|
+
class User {
|
|
43
|
+
data = {
|
|
44
|
+
name: "",
|
|
45
|
+
age: 18
|
|
46
|
+
};
|
|
47
|
+
get text() {
|
|
48
|
+
return `${this.data.name} is ${this.data.age} years old.`;
|
|
49
|
+
}
|
|
50
|
+
$setName(name) {
|
|
51
|
+
this.data.name = name;
|
|
52
|
+
}
|
|
53
|
+
$setAge(age) {
|
|
54
|
+
this.data.age = age;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const user = connectStore(User, STORE_NAME);
|
|
58
|
+
const preData = user.data;
|
|
59
|
+
user.$setName("jack");
|
|
60
|
+
assert.strictEqual(user.data.name, "jack");
|
|
61
|
+
assert.strictEqual(user.data.age, 18);
|
|
62
|
+
assert.notStrictEqual(user.data, preData);
|
|
63
|
+
assert.strictEqual(user.text, "jack is 18 years old.");
|
|
64
|
+
});
|
|
65
|
+
test("Commit function this bind", () => {
|
|
66
|
+
const state = createState();
|
|
67
|
+
const STORE_NAME = "user";
|
|
68
|
+
const connectStore = connectState(state);
|
|
69
|
+
class User {
|
|
70
|
+
name = "";
|
|
71
|
+
$setName(name) {
|
|
72
|
+
this.name = name;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const user = connectStore(User, STORE_NAME);
|
|
76
|
+
const setName = user.$setName;
|
|
77
|
+
setName("jack");
|
|
78
|
+
assert.strictEqual(user.name, "jack");
|
|
79
|
+
});
|
|
80
|
+
test("Commit function return value and args", () => {
|
|
81
|
+
const state = createState();
|
|
82
|
+
const STORE_NAME = "user";
|
|
83
|
+
const connectStore = connectState(state);
|
|
84
|
+
class User {
|
|
85
|
+
list = [];
|
|
86
|
+
$add(...list) {
|
|
87
|
+
this.list.push(...list);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const user = connectStore(User, STORE_NAME);
|
|
92
|
+
assert.isTrue(user.$add("jack", "tom"));
|
|
93
|
+
assert.deepEqual(user.list, ["jack", "tom"]);
|
|
94
|
+
});
|
|
95
|
+
test("Instance reference", () => {
|
|
96
|
+
const state = createState();
|
|
97
|
+
const STORE_NAME = "user";
|
|
98
|
+
const connectStore = connectState(state);
|
|
99
|
+
class User {
|
|
100
|
+
name = "";
|
|
101
|
+
$setName(name) {
|
|
102
|
+
this.name = name;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const user = connectStore(User, STORE_NAME);
|
|
106
|
+
assert.strictEqual(user, connectStore(User, STORE_NAME));
|
|
107
|
+
user.$setName("jack");
|
|
108
|
+
assert.notStrictEqual(user, connectStore(User, STORE_NAME));
|
|
109
|
+
});
|
|
110
|
+
test("Disconnect", () => {
|
|
111
|
+
const state = createState();
|
|
112
|
+
const STORE_NAME = "user";
|
|
113
|
+
const connectStore = connectState(state);
|
|
114
|
+
class User {
|
|
115
|
+
name = "";
|
|
116
|
+
$setName(name) {
|
|
117
|
+
this.name = name;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const user = connectStore(User, STORE_NAME);
|
|
121
|
+
assert.isUndefined(state.value.user);
|
|
122
|
+
user.$setName("jack");
|
|
123
|
+
assert.strictEqual(state.value.user, user.$.state);
|
|
124
|
+
user.$.dispose();
|
|
125
|
+
assert.isUndefined(state.value.user);
|
|
126
|
+
assert.isNull(user.$._stateContext);
|
|
127
|
+
});
|
|
128
|
+
test("Preset state", () => {
|
|
129
|
+
const STORE_NAME = "user";
|
|
130
|
+
const state = createState({
|
|
131
|
+
value: {
|
|
132
|
+
[STORE_NAME]: {
|
|
133
|
+
name: "jack"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
const connectStore = connectState(state);
|
|
138
|
+
class User {
|
|
139
|
+
name = "";
|
|
140
|
+
age = 18;
|
|
141
|
+
}
|
|
142
|
+
const user = connectStore(User, STORE_NAME);
|
|
143
|
+
assert.strictEqual(user.name, "jack");
|
|
144
|
+
assert.strictEqual(user.age, 18);
|
|
145
|
+
assert.notStrictEqual(user.$.state, state.value.user);
|
|
146
|
+
assert.deepEqual(state.value.user, { name: "jack" });
|
|
147
|
+
});
|
|
148
|
+
test("State modification delay", () => {
|
|
149
|
+
const STORE_NAME = "user";
|
|
150
|
+
const state = createState();
|
|
151
|
+
const connectStore = connectState(state);
|
|
152
|
+
class User {
|
|
153
|
+
name = "";
|
|
154
|
+
age = 0;
|
|
155
|
+
$setAge(age) {
|
|
156
|
+
this.age = age;
|
|
157
|
+
}
|
|
158
|
+
$setName(name) {
|
|
159
|
+
this.name = name;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
__publicField(User, "storeName", "user");
|
|
163
|
+
const user = connectStore(User, STORE_NAME);
|
|
164
|
+
const setAge = user.$setAge.bind(user);
|
|
165
|
+
user.$setName("test");
|
|
166
|
+
assert.equal(user.name, "test");
|
|
167
|
+
assert.equal(user.age, 0);
|
|
168
|
+
user.$setAge(100);
|
|
169
|
+
assert.equal(user.name, "test");
|
|
170
|
+
assert.equal(user.age, 100);
|
|
171
|
+
setAge(200);
|
|
172
|
+
assert.equal(user.name, "test");
|
|
173
|
+
assert.equal(user.age, 200);
|
|
174
|
+
});
|
|
175
|
+
test("Multiple instances", () => {
|
|
176
|
+
const state = createState();
|
|
177
|
+
const _connectStore = connectState(state);
|
|
178
|
+
class User {
|
|
179
|
+
name = "";
|
|
180
|
+
get blog() {
|
|
181
|
+
return foreignStore(Blog, "blog");
|
|
182
|
+
}
|
|
183
|
+
get log() {
|
|
184
|
+
return `'${this.name}' published '${this.blog.text}'`;
|
|
185
|
+
}
|
|
186
|
+
$setName(name) {
|
|
187
|
+
this.name = name;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
class Blog {
|
|
191
|
+
text = "";
|
|
192
|
+
$setText(text) {
|
|
193
|
+
this.text = text;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const user = _connectStore(User, "user");
|
|
197
|
+
user.$setName("jack");
|
|
198
|
+
user.blog.$setText("hello world.");
|
|
199
|
+
assert.strictEqual(user.name, "jack");
|
|
200
|
+
assert.equal(user.log, "'jack' published 'hello world.'");
|
|
201
|
+
});
|
|
202
|
+
test("Params", () => {
|
|
203
|
+
const state = createState();
|
|
204
|
+
const connectStore = connectState(state);
|
|
205
|
+
class User {
|
|
206
|
+
name = "";
|
|
207
|
+
uid;
|
|
208
|
+
constructor(uid) {
|
|
209
|
+
this.uid = uid ?? "";
|
|
210
|
+
}
|
|
211
|
+
$setName(name) {
|
|
212
|
+
this.name = name;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const user100 = connectStore(User, "user", "100");
|
|
216
|
+
user100.$setName("jack");
|
|
217
|
+
assert.strictEqual(user100.uid, "100");
|
|
218
|
+
const user200 = connectStore(User, "user", "200");
|
|
219
|
+
user200.$setName("tom");
|
|
220
|
+
assert.strictEqual(user100.uid, "100");
|
|
221
|
+
assert.notStrictEqual(user100, user200);
|
|
222
|
+
assert.strictEqual(state.value["user/100"], user100.$.state);
|
|
223
|
+
assert.strictEqual(state.value["user/200"], user200.$.state);
|
|
224
|
+
assert.deepEqual(state.value["user/100"], { uid: "100", name: "jack" });
|
|
225
|
+
assert.deepEqual(state.value["user/200"], { uid: "200", name: "tom" });
|
|
226
|
+
});
|
|
227
|
+
test("Call commit multiple times", () => {
|
|
228
|
+
const state = createState();
|
|
229
|
+
const connectStore = connectState(state);
|
|
230
|
+
class User {
|
|
231
|
+
name = "";
|
|
232
|
+
age = 0;
|
|
233
|
+
text = "";
|
|
234
|
+
$setName(name) {
|
|
235
|
+
this.name = name;
|
|
236
|
+
return "1";
|
|
237
|
+
}
|
|
238
|
+
$setAge(age) {
|
|
239
|
+
this.age = age;
|
|
240
|
+
return "2";
|
|
241
|
+
}
|
|
242
|
+
$setUser(name, age) {
|
|
243
|
+
const v1 = this.$setName(name);
|
|
244
|
+
const v2 = this.$setAge(age);
|
|
245
|
+
this.text = v1 + v2;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const user = connectStore(User, "user");
|
|
249
|
+
user.$setUser("jack", 18);
|
|
250
|
+
assert.equal(user.name, "jack");
|
|
251
|
+
assert.equal(user.age, 18);
|
|
252
|
+
assert.equal(user.text, "12");
|
|
253
|
+
});
|
|
254
|
+
test("No a submit function modification state", () => {
|
|
255
|
+
const state = createState();
|
|
256
|
+
const connectStore = connectState(state);
|
|
257
|
+
class User {
|
|
258
|
+
name = "";
|
|
259
|
+
setName(name) {
|
|
260
|
+
this.name = name;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const user = connectStore(User, "user");
|
|
264
|
+
assert.Throw(() => {
|
|
265
|
+
user.setName("jack");
|
|
266
|
+
}, "Change the state in the agreed commit function, For example, $name('jack')");
|
|
267
|
+
});
|
|
268
|
+
test("Equal submit function", () => {
|
|
269
|
+
const state = createState();
|
|
270
|
+
const connectStore = connectState(state);
|
|
271
|
+
class User {
|
|
272
|
+
name = "";
|
|
273
|
+
$setName(name) {
|
|
274
|
+
this.name = name;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const user = connectStore(User, "user");
|
|
278
|
+
assert.equal(user.$setName, user.$setName);
|
|
279
|
+
});
|
|
280
|
+
test("State Restore", () => {
|
|
281
|
+
const state = createState({
|
|
282
|
+
value: {
|
|
283
|
+
user: {
|
|
284
|
+
name: "jack"
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
const connectStore = connectState(state);
|
|
289
|
+
class User {
|
|
290
|
+
name = "";
|
|
291
|
+
$setName(name) {
|
|
292
|
+
this.name = name;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const user = connectStore(User, "user");
|
|
296
|
+
assert.equal(user.name, "jack");
|
|
297
|
+
});
|
|
298
|
+
test("update value", () => {
|
|
299
|
+
const state = createState();
|
|
300
|
+
const connectStore = connectState(state);
|
|
301
|
+
class Count {
|
|
302
|
+
value = 0;
|
|
303
|
+
text = "";
|
|
304
|
+
$inc() {
|
|
305
|
+
this.value++;
|
|
306
|
+
}
|
|
307
|
+
$setText(text) {
|
|
308
|
+
this.text = text;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const count = connectStore(Count, "count");
|
|
312
|
+
const setText = count.$setText;
|
|
313
|
+
count.$inc();
|
|
314
|
+
assert.equal(count.value, 1);
|
|
315
|
+
count.$inc();
|
|
316
|
+
assert.equal(count.value, 2);
|
|
317
|
+
count.$inc();
|
|
318
|
+
assert.equal(count.value, 3);
|
|
319
|
+
setText("hello world");
|
|
320
|
+
assert.equal(count.value, 3);
|
|
321
|
+
assert.equal(count.text, "hello world");
|
|
322
|
+
setText("hello world2");
|
|
323
|
+
assert.equal(count.value, 3);
|
|
324
|
+
assert.equal(count.text, "hello world2");
|
|
325
|
+
});
|
|
326
|
+
test("default connecting", () => {
|
|
327
|
+
const state = createState({
|
|
328
|
+
value: {
|
|
329
|
+
count: {
|
|
330
|
+
value: 100
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
const connectStore = connectState(state);
|
|
335
|
+
class Count {
|
|
336
|
+
value = 0;
|
|
337
|
+
$inc() {
|
|
338
|
+
this.value++;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const count = connectStore(Count, "count");
|
|
342
|
+
assert.equal(count.value, 100);
|
|
343
|
+
assert.equal(count.$.connecting, true);
|
|
344
|
+
});
|
|
345
|
+
test("update state", () => {
|
|
346
|
+
const state = createState({
|
|
347
|
+
value: {
|
|
348
|
+
count: {
|
|
349
|
+
value: 100
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
const connectStore = connectState(state);
|
|
354
|
+
class Count {
|
|
355
|
+
value = 0;
|
|
356
|
+
$inc() {
|
|
357
|
+
this.value++;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const count = connectStore(Count, "count");
|
|
361
|
+
count.$inc();
|
|
362
|
+
const value = state.value;
|
|
363
|
+
count.$inc();
|
|
364
|
+
assert.equal(value, state.value);
|
|
365
|
+
});
|
package/dist/create.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { StoreContext } from './connect';
|
|
2
|
+
export interface State {
|
|
3
|
+
value: Record<string, any>;
|
|
4
|
+
}
|
|
5
|
+
export declare class StateContext {
|
|
6
|
+
readonly state: State;
|
|
7
|
+
private readonly storeContext;
|
|
8
|
+
constructor(state: State);
|
|
9
|
+
depend(fullPath?: string): unknown;
|
|
10
|
+
hasState(name: string): boolean;
|
|
11
|
+
get(name: string): StoreContext<any> | null;
|
|
12
|
+
add(name: string, storeContext: StoreContext<any>): void;
|
|
13
|
+
updateState(name: string, nextState: any): void;
|
|
14
|
+
del(name: string): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function getStateContext(state: State): StateContext;
|
|
17
|
+
export declare function createState(state?: State): State;
|