@gez/class-state
Advanced tools
Comparing version 0.0.7 to 0.0.9
@@ -57,4 +57,4 @@ import { type State, type StateContext } from './create'; | ||
/** | ||
* 私有函数,外部调用不应该使用 | ||
*/ | ||
* 私有函数,外部调用不应该使用 | ||
*/ | ||
_setState(nextState: Record<string, any>): void; | ||
@@ -61,0 +61,0 @@ /** |
{ | ||
"name": "@gez/class-state", | ||
"version": "0.0.7", | ||
"type": "module", | ||
"license": "MIT", | ||
"keywords": [ | ||
"vuex", | ||
"mobx", | ||
"pinia", | ||
"redux" | ||
], | ||
"homepage": "https://github.com/dp-os/gez", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/dp-os/gez.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/dp-os/gez/issues" | ||
}, | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.cjs" | ||
} | ||
}, | ||
"main": "./dist/index.cjs", | ||
"types": "./dist/index.d.ts", | ||
"scripts": { | ||
"build": "tsc --noEmit && unbuild" | ||
}, | ||
"dependencies": { | ||
"immer": "^10.1.1" | ||
}, | ||
"devDependencies": { | ||
"unbuild": "^2.0.0", | ||
"vue": "^2.7.15" | ||
}, | ||
"gitHead": "44566aaf2b1057d6cdceeece888745e7dac8fc99" | ||
"name": "@gez/class-state", | ||
"template": "library", | ||
"scripts": { | ||
"lint:js": "eslint . --ext .js,.mjs,.cjs,.ts,.vue --fix", | ||
"lint:css": "stylelint '**/*.{css,vue}' --fix --aei", | ||
"lint:type": "tsc --noEmit", | ||
"test": "vitest --pass-with-no-tests", | ||
"coverage": "vitest run --coverage --pass-with-no-tests", | ||
"build": "unbuild" | ||
}, | ||
"dependencies": { | ||
"immer": "^10.1.1" | ||
}, | ||
"devDependencies": { | ||
"@gez/lint": "0.0.9", | ||
"@types/node": "20.12.12", | ||
"@vitest/coverage-v8": "1.6.0", | ||
"eslint": "8.57.0", | ||
"stylelint": "16.5.0", | ||
"typescript": "5.4.5", | ||
"unbuild": "2.0.0", | ||
"vitest": "1.6.0", | ||
"vue": "^3.4.27" | ||
}, | ||
"version": "0.0.9", | ||
"type": "module", | ||
"private": false, | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.cjs" | ||
} | ||
}, | ||
"main": "./dist/index.cjs", | ||
"module": "dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"src", | ||
"dist", | ||
"*.mjs", | ||
"template" | ||
], | ||
"gitHead": "5d769669f9d75cfbbae1c3df7e6c71fca8214634" | ||
} |
@@ -1,455 +0,456 @@ | ||
import { test, assert } from 'vitest' | ||
import { connectState, connectStore } from './connect' | ||
import { createState } from './create' | ||
import { assert, test } from 'vitest'; | ||
import { connectState, connectStore } from './connect'; | ||
import { createState } from './create'; | ||
test('Base', () => { | ||
const state = createState() | ||
const STORE_NAME = 'user' | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public age = 18 | ||
public text = '' | ||
public online = false | ||
public constructor () { | ||
Object.defineProperty(this, 'online', { | ||
enumerable: false | ||
}) | ||
} | ||
const state = createState(); | ||
const STORE_NAME = 'user'; | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public age = 18; | ||
public text = ''; | ||
public online = false; | ||
public constructor() { | ||
Object.defineProperty(this, 'online', { | ||
enumerable: false | ||
}); | ||
} | ||
public $setName (name: string) { | ||
this.name = name | ||
} | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
public $setAge (age: number) { | ||
this.age = age | ||
} | ||
public $setAge(age: number) { | ||
this.age = age; | ||
} | ||
public $buildText () { | ||
this.text = `${this.name} is ${this.age} years old.` | ||
} | ||
public $buildText() { | ||
this.text = `${this.name} is ${this.age} years old.`; | ||
} | ||
public $toggleOnline () { | ||
this.online = !this.online | ||
public $toggleOnline() { | ||
this.online = !this.online; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
const user = connectStore(User, STORE_NAME); | ||
assert.equal(user.name, '') | ||
assert.isUndefined(state.value.user) | ||
assert.equal(user.name, ''); | ||
assert.isUndefined(state.value.user); | ||
user.$setName('jack') | ||
assert.strictEqual(user.name, 'jack') | ||
// @ts-expect-error test | ||
assert.strictEqual(state.value.user.name, user.name) | ||
user.$setName('jack'); | ||
assert.strictEqual(user.name, 'jack'); | ||
// @ts-expect-error test | ||
assert.strictEqual(state.value.user.name, user.name); | ||
user.$setAge(20) | ||
assert.strictEqual(user.age, 20) | ||
// @ts-expect-error test | ||
assert.strictEqual(state.value.user.age, user.age) | ||
user.$setAge(20); | ||
assert.strictEqual(user.age, 20); | ||
// @ts-expect-error test | ||
assert.strictEqual(state.value.user.age, user.age); | ||
user.$buildText() | ||
assert.strictEqual(user.text, 'jack is 20 years old.') | ||
// @ts-expect-error test | ||
assert.strictEqual(state.value.user.text, user.text) | ||
// @ts-expect-error test | ||
assert.isUndefined(state.value.user.online) | ||
user.$buildText(); | ||
assert.strictEqual(user.text, 'jack is 20 years old.'); | ||
// @ts-expect-error test | ||
assert.strictEqual(state.value.user.text, user.text); | ||
// @ts-expect-error test | ||
assert.isUndefined(state.value.user.online); | ||
assert.strictEqual(user.online, false) | ||
user.$toggleOnline() | ||
assert.strictEqual(user.online, true) | ||
}) | ||
assert.strictEqual(user.online, false); | ||
user.$toggleOnline(); | ||
assert.strictEqual(user.online, true); | ||
}); | ||
test('Object type', () => { | ||
const state = createState() | ||
const STORE_NAME = 'user' | ||
const connectStore = connectState(state) | ||
class User { | ||
public data = { | ||
name: '', | ||
age: 18 | ||
} | ||
const state = createState(); | ||
const STORE_NAME = 'user'; | ||
const connectStore = connectState(state); | ||
class User { | ||
public data = { | ||
name: '', | ||
age: 18 | ||
}; | ||
public get text () { | ||
return `${this.data.name} is ${this.data.age} years old.` | ||
} | ||
public get text() { | ||
return `${this.data.name} is ${this.data.age} years old.`; | ||
} | ||
public $setName (name: string) { | ||
this.data.name = name | ||
} | ||
public $setName(name: string) { | ||
this.data.name = name; | ||
} | ||
public $setAge (age: number) { | ||
this.data.age = age | ||
public $setAge(age: number) { | ||
this.data.age = age; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
const user = connectStore(User, STORE_NAME); | ||
const preData = user.data | ||
user.$setName('jack') | ||
assert.strictEqual(user.data.name, 'jack') | ||
assert.strictEqual(user.data.age, 18) | ||
assert.notStrictEqual(user.data, preData) | ||
const preData = user.data; | ||
user.$setName('jack'); | ||
assert.strictEqual(user.data.name, 'jack'); | ||
assert.strictEqual(user.data.age, 18); | ||
assert.notStrictEqual(user.data, preData); | ||
assert.strictEqual(user.text, 'jack is 18 years old.') | ||
}) | ||
assert.strictEqual(user.text, 'jack is 18 years old.'); | ||
}); | ||
test('Commit function this bind', () => { | ||
const state = createState() | ||
const state = createState(); | ||
const STORE_NAME = 'user' | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
const STORE_NAME = 'user'; | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
const setName = user.$setName | ||
setName('jack') | ||
const user = connectStore(User, STORE_NAME); | ||
const setName = user.$setName; | ||
setName('jack'); | ||
assert.strictEqual(user.name, 'jack') | ||
}) | ||
assert.strictEqual(user.name, 'jack'); | ||
}); | ||
test('Commit function return value and args', () => { | ||
const state = createState() | ||
const state = createState(); | ||
const STORE_NAME = 'user' | ||
const connectStore = connectState(state) | ||
class User { | ||
public list: string[] = [] | ||
public $add (...list: string[]) { | ||
this.list.push(...list) | ||
return true | ||
const STORE_NAME = 'user'; | ||
const connectStore = connectState(state); | ||
class User { | ||
public list: string[] = []; | ||
public $add(...list: string[]) { | ||
this.list.push(...list); | ||
return true; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
assert.isTrue(user.$add('jack', 'tom')) | ||
assert.deepEqual(user.list, ['jack', 'tom']) | ||
}) | ||
const user = connectStore(User, STORE_NAME); | ||
assert.isTrue(user.$add('jack', 'tom')); | ||
assert.deepEqual(user.list, ['jack', 'tom']); | ||
}); | ||
test('Instance reference', () => { | ||
const state = createState() | ||
const state = createState(); | ||
const STORE_NAME = 'user' | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
const STORE_NAME = 'user'; | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
assert.strictEqual(user, connectStore(User, STORE_NAME)) | ||
const user = connectStore(User, STORE_NAME); | ||
assert.strictEqual(user, connectStore(User, STORE_NAME)); | ||
user.$setName('jack') | ||
user.$setName('jack'); | ||
assert.notStrictEqual(user, connectStore(User, STORE_NAME)) | ||
}) | ||
assert.notStrictEqual(user, connectStore(User, STORE_NAME)); | ||
}); | ||
test('Disconnect', () => { | ||
const state = createState() | ||
const STORE_NAME = 'user' | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
const state = createState(); | ||
const STORE_NAME = 'user'; | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
const user = connectStore(User, STORE_NAME); | ||
assert.isUndefined(state.value.user) | ||
assert.isUndefined(state.value.user); | ||
user.$setName('jack') | ||
assert.strictEqual(state.value.user, user.$.state) | ||
user.$setName('jack'); | ||
assert.strictEqual(state.value.user, user.$.state); | ||
user.$.dispose() | ||
assert.isUndefined(state.value.user) | ||
// @ts-expect-error need test | ||
assert.isNull(user.$._stateContext) | ||
}) | ||
user.$.dispose(); | ||
assert.isUndefined(state.value.user); | ||
// @ts-expect-error need test | ||
assert.isNull(user.$._stateContext); | ||
}); | ||
test('Preset state', () => { | ||
const STORE_NAME = 'user' | ||
const state = createState({ | ||
value: { | ||
[STORE_NAME]: { | ||
name: 'jack' | ||
} | ||
const STORE_NAME = 'user'; | ||
const state = createState({ | ||
value: { | ||
[STORE_NAME]: { | ||
name: 'jack' | ||
} | ||
} | ||
}); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public age = 18; | ||
} | ||
}) | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public age = 18 | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
const user = connectStore(User, STORE_NAME); | ||
assert.strictEqual(user.name, 'jack') | ||
assert.strictEqual(user.age, 18) | ||
assert.notStrictEqual(user.$.state, state.value.user) | ||
assert.deepEqual(state.value.user, { name: 'jack' }) | ||
}) | ||
assert.strictEqual(user.name, 'jack'); | ||
assert.strictEqual(user.age, 18); | ||
assert.notStrictEqual(user.$.state, state.value.user); | ||
assert.deepEqual(state.value.user, { name: 'jack' }); | ||
}); | ||
test('State modification delay', () => { | ||
const STORE_NAME = 'user' | ||
const state = createState() | ||
const connectStore = connectState(state) | ||
const STORE_NAME = 'user'; | ||
const state = createState(); | ||
const connectStore = connectState(state); | ||
class User { | ||
public static storeName = 'user' | ||
public name = '' | ||
public age = 0 | ||
class User { | ||
public static storeName = 'user'; | ||
public name = ''; | ||
public age = 0; | ||
public $setAge (age: number) { | ||
this.age = age | ||
} | ||
public $setAge(age: number) { | ||
this.age = age; | ||
} | ||
public $setName (name: string) { | ||
this.name = name | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, STORE_NAME) | ||
const setAge = user.$setAge.bind(user) | ||
const user = connectStore(User, STORE_NAME); | ||
const setAge = user.$setAge.bind(user); | ||
user.$setName('test') | ||
assert.equal(user.name, 'test') | ||
assert.equal(user.age, 0) | ||
user.$setName('test'); | ||
assert.equal(user.name, 'test'); | ||
assert.equal(user.age, 0); | ||
user.$setAge(100) | ||
assert.equal(user.name, 'test') | ||
assert.equal(user.age, 100) | ||
user.$setAge(100); | ||
assert.equal(user.name, 'test'); | ||
assert.equal(user.age, 100); | ||
setAge(200) | ||
assert.equal(user.name, 'test') | ||
assert.equal(user.age, 200) | ||
}) | ||
setAge(200); | ||
assert.equal(user.name, 'test'); | ||
assert.equal(user.age, 200); | ||
}); | ||
test('Multiple instances', () => { | ||
const state = createState() | ||
const _connectStore = connectState(state) | ||
const state = createState(); | ||
const _connectStore = connectState(state); | ||
class User { | ||
public name = '' | ||
public get blog () { | ||
return connectStore(Blog, 'blog') | ||
} | ||
class User { | ||
public name = ''; | ||
public get blog() { | ||
return connectStore(Blog, 'blog'); | ||
} | ||
public get log () { | ||
return `'${this.name}' published '${this.blog.text}'` | ||
} | ||
public get log() { | ||
return `'${this.name}' published '${this.blog.text}'`; | ||
} | ||
public $setName (name: string) { | ||
this.name = name | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
class Blog { | ||
public text = '' | ||
public $setText (text: string) { | ||
this.text = text | ||
class Blog { | ||
public text = ''; | ||
public $setText(text: string) { | ||
this.text = text; | ||
} | ||
} | ||
} | ||
const user = _connectStore(User, 'user') | ||
const user = _connectStore(User, 'user'); | ||
user.$setName('jack') | ||
user.blog.$setText('hello world.') | ||
user.$setName('jack'); | ||
user.blog.$setText('hello world.'); | ||
assert.strictEqual(user.name, 'jack') | ||
assert.equal(user.log, '\'jack\' published \'hello world.\'') | ||
}) | ||
assert.strictEqual(user.name, 'jack'); | ||
assert.equal(user.log, "'jack' published 'hello world.'"); | ||
}); | ||
test('Params', () => { | ||
const state = createState() | ||
const connectStore = connectState(state) | ||
const state = createState(); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = '' | ||
public uid: string | ||
public constructor (uid?: string) { | ||
this.uid = uid ?? '' | ||
} | ||
class User { | ||
public name = ''; | ||
public uid: string; | ||
public constructor(uid?: string) { | ||
this.uid = uid ?? ''; | ||
} | ||
public $setName (name: string) { | ||
this.name = name | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user100 = connectStore(User, 'user', '100') | ||
user100.$setName('jack') | ||
assert.strictEqual(user100.uid, '100') | ||
const user100 = connectStore(User, 'user', '100'); | ||
user100.$setName('jack'); | ||
assert.strictEqual(user100.uid, '100'); | ||
const user200 = connectStore(User, 'user', '200') | ||
user200.$setName('tom') | ||
assert.strictEqual(user100.uid, '100') | ||
assert.notStrictEqual(user100, user200) | ||
const user200 = connectStore(User, 'user', '200'); | ||
user200.$setName('tom'); | ||
assert.strictEqual(user100.uid, '100'); | ||
assert.notStrictEqual(user100, user200); | ||
assert.strictEqual(state.value['user/100'], user100.$.state) | ||
assert.strictEqual(state.value['user/200'], user200.$.state) | ||
assert.strictEqual(state.value['user/100'], user100.$.state); | ||
assert.strictEqual(state.value['user/200'], user200.$.state); | ||
assert.deepEqual(state.value['user/100'], { uid: '100', name: 'jack' }) | ||
assert.deepEqual(state.value['user/200'], { uid: '200', name: 'tom' }) | ||
}) | ||
assert.deepEqual(state.value['user/100'], { uid: '100', name: 'jack' }); | ||
assert.deepEqual(state.value['user/200'], { uid: '200', name: 'tom' }); | ||
}); | ||
test('Call commit multiple times', () => { | ||
const state = createState() | ||
const connectStore = connectState(state) | ||
const state = createState(); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = '' | ||
public age = 0 | ||
public text = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
return '1' | ||
} | ||
class User { | ||
public name = ''; | ||
public age = 0; | ||
public text = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
return '1'; | ||
} | ||
public $setAge (age: number) { | ||
this.age = age | ||
return '2' | ||
} | ||
public $setAge(age: number) { | ||
this.age = age; | ||
return '2'; | ||
} | ||
public $setUser (name: string, age: number) { | ||
const v1 = this.$setName(name) | ||
const v2 = this.$setAge(age) | ||
this.text = v1 + v2 | ||
public $setUser(name: string, age: number) { | ||
const v1 = this.$setName(name); | ||
const v2 = this.$setAge(age); | ||
this.text = v1 + v2; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
const user = connectStore(User, 'user'); | ||
user.$setUser('jack', 18) | ||
user.$setUser('jack', 18); | ||
assert.equal(user.name, 'jack') | ||
assert.equal(user.age, 18) | ||
assert.equal(user.text, '12') | ||
}) | ||
assert.equal(user.name, 'jack'); | ||
assert.equal(user.age, 18); | ||
assert.equal(user.text, '12'); | ||
}); | ||
test('No a submit function modification state', () => { | ||
const state = createState() | ||
const connectStore = connectState(state) | ||
const state = createState(); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = '' | ||
public setName (name: string) { | ||
this.name = name | ||
class User { | ||
public name = ''; | ||
public setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
assert.Throw(() => { | ||
user.setName('jack') | ||
}, 'Change the state in the agreed commit function, For example, $name(\'jack\')') | ||
}) | ||
const user = connectStore(User, 'user'); | ||
assert.Throw(() => { | ||
user.setName('jack'); | ||
}, "Change the state in the agreed commit function, For example, $name('jack')"); | ||
}); | ||
test('Equal submit function', () => { | ||
const state = createState() | ||
const connectStore = connectState(state) | ||
const state = createState(); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
const user = connectStore(User, 'user'); | ||
assert.equal(user.$setName, user.$setName) | ||
}) | ||
assert.equal(user.$setName, user.$setName); | ||
}); | ||
test('State Restore', () => { | ||
const state = createState({ | ||
value: { | ||
user: { | ||
name: 'jack' | ||
} | ||
} | ||
}) | ||
const connectStore = connectState(state) | ||
const state = createState({ | ||
value: { | ||
user: { | ||
name: 'jack' | ||
} | ||
} | ||
}); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
assert.equal(user.name, 'jack') | ||
}) | ||
const user = connectStore(User, 'user'); | ||
assert.equal(user.name, 'jack'); | ||
}); | ||
test('update value', () => { | ||
const state = createState() | ||
const connectStore = connectState(state) | ||
class Count { | ||
public value: number = 0 | ||
public text: string = '' | ||
public $inc () { | ||
this.value++ | ||
} | ||
const state = createState(); | ||
const connectStore = connectState(state); | ||
class Count { | ||
public value: number = 0; | ||
public text: string = ''; | ||
public $inc() { | ||
this.value++; | ||
} | ||
public $setText (text: string) { | ||
this.text = text | ||
public $setText(text: string) { | ||
this.text = text; | ||
} | ||
} | ||
} | ||
const count = connectStore(Count, 'count') | ||
const setText = count.$setText | ||
const count = connectStore(Count, 'count'); | ||
const setText = count.$setText; | ||
count.$inc() | ||
assert.equal(count.value, 1) | ||
count.$inc(); | ||
assert.equal(count.value, 1); | ||
count.$inc() | ||
assert.equal(count.value, 2) | ||
count.$inc(); | ||
assert.equal(count.value, 2); | ||
count.$inc() | ||
assert.equal(count.value, 3) | ||
count.$inc(); | ||
assert.equal(count.value, 3); | ||
setText('hello world') | ||
assert.equal(count.value, 3) | ||
assert.equal(count.text, 'hello world') | ||
setText('hello world'); | ||
assert.equal(count.value, 3); | ||
assert.equal(count.text, 'hello world'); | ||
setText('hello world2') | ||
assert.equal(count.value, 3) | ||
assert.equal(count.text, 'hello world2') | ||
}) | ||
setText('hello world2'); | ||
assert.equal(count.value, 3); | ||
assert.equal(count.text, 'hello world2'); | ||
}); | ||
test('default connecting', () => { | ||
const state = createState({ | ||
value: { | ||
count: { | ||
value: 100 | ||
} | ||
const state = createState({ | ||
value: { | ||
count: { | ||
value: 100 | ||
} | ||
} | ||
}); | ||
const connectStore = connectState(state); | ||
class Count { | ||
public value: number = 0; | ||
public $inc() { | ||
this.value++; | ||
} | ||
} | ||
}) | ||
const connectStore = connectState(state) | ||
class Count { | ||
public value: number = 0 | ||
public $inc () { | ||
this.value++ | ||
} | ||
} | ||
const count = connectStore(Count, 'count') | ||
assert.equal(count.value, 100) | ||
assert.equal(count.$.connecting, true) | ||
}) | ||
const count = connectStore(Count, 'count'); | ||
assert.equal(count.value, 100); | ||
assert.equal(count.$.connecting, true); | ||
}); | ||
test('update state', () => { | ||
const state = createState({ | ||
value: { | ||
count: { | ||
value: 100 | ||
} | ||
const state = createState({ | ||
value: { | ||
count: { | ||
value: 100 | ||
} | ||
} | ||
}); | ||
const connectStore = connectState(state); | ||
class Count { | ||
public value: number = 0; | ||
public $inc() { | ||
this.value++; | ||
} | ||
} | ||
}) | ||
const connectStore = connectState(state) | ||
class Count { | ||
public value: number = 0 | ||
public $inc () { | ||
this.value++ | ||
} | ||
} | ||
const count = connectStore(Count, 'count') | ||
const count = connectStore(Count, 'count'); | ||
count.$inc() | ||
const value = state.value | ||
count.$inc() | ||
assert.equal(value, state.value) | ||
}) | ||
count.$inc(); | ||
const value = state.value; | ||
count.$inc(); | ||
assert.equal(value, state.value); | ||
}); |
/* eslint-disable @typescript-eslint/no-this-alias */ | ||
import { produce } from 'immer' | ||
import { type State, getStateContext, type StateContext } from './create' | ||
export type StoreParams = Record<string, any> | ||
export type StoreConstructor = new (cacheKey?: string) => any | ||
import { produce } from 'immer'; | ||
export type StoreInstance<T extends {}> = T & { $: StoreContext<T> } | ||
import { getStateContext, type State, type StateContext } from './create'; | ||
export type StoreParams = Record<string, any>; | ||
export type StoreConstructor = new (cacheKey?: string) => any; | ||
let currentStateContext: StateContext | null = null | ||
export type StoreInstance<T extends {}> = T & { $: StoreContext<T> }; | ||
let currentStateContext: StateContext | null = null; | ||
/** | ||
* class created | ||
*/ | ||
export const LIFE_CYCLE_CREATED = Symbol('class created') | ||
export const LIFE_CYCLE_CREATED = Symbol('class created'); | ||
/** | ||
* class dispose | ||
*/ | ||
export const LIFE_CYCLE_DISPOSE = Symbol('class dispose') | ||
export const LIFE_CYCLE_DISPOSE = Symbol('class dispose'); | ||
export type StoreSubscribe = () => void | ||
export type StoreSubscribe = () => void; | ||
// 订阅的id | ||
let sid = 0 | ||
let sid = 0; | ||
function noon () {} | ||
function noon() {} | ||
export class StoreContext<T extends {}> { | ||
/** | ||
* 全局的状态上下文 | ||
*/ | ||
private _stateContext: StateContext | null | ||
/** | ||
* 原始实例 | ||
*/ | ||
private readonly _raw: T | ||
/** | ||
* 原始实例的代理,每次状态变化时,代理都会更新 | ||
*/ | ||
private _proxy: StoreInstance<T> | ||
/** | ||
* 当前的 state 是否是草稿状态 | ||
*/ | ||
private _drafting = false | ||
/** | ||
* $ 函数的缓存对象 | ||
*/ | ||
private readonly _cacheCommit = new Map<Function, Function>() | ||
/** | ||
* 当前的 store 的存储路径 | ||
*/ | ||
public readonly keyPath: string | ||
/** | ||
* 最新的状态 | ||
*/ | ||
public state: Record<string, any> | ||
/** | ||
* 当前的 store 的 state 是否已经连接到全局的 state 中 | ||
*/ | ||
public connecting: boolean | ||
private readonly _subs: Array<{ sid: number, cb: StoreSubscribe }> = [] | ||
/** | ||
* 全局的状态上下文 | ||
*/ | ||
private _stateContext: StateContext | null; | ||
/** | ||
* 原始实例 | ||
*/ | ||
private readonly _raw: T; | ||
/** | ||
* 原始实例的代理,每次状态变化时,代理都会更新 | ||
*/ | ||
private _proxy: StoreInstance<T>; | ||
/** | ||
* 当前的 state 是否是草稿状态 | ||
*/ | ||
private _drafting = false; | ||
/** | ||
* $ 函数的缓存对象 | ||
*/ | ||
private readonly _cacheCommit = new Map<Function, Function>(); | ||
/** | ||
* 当前的 store 的存储路径 | ||
*/ | ||
public readonly keyPath: string; | ||
/** | ||
* 最新的状态 | ||
*/ | ||
public state: Record<string, any>; | ||
/** | ||
* 当前的 store 的 state 是否已经连接到全局的 state 中 | ||
*/ | ||
public connecting: boolean; | ||
private readonly _subs: Array<{ sid: number; cb: StoreSubscribe }> = []; | ||
public constructor (stateContext: StateContext, raw: T, state: Record<string, any>, keyPath: string) { | ||
this._stateContext = stateContext | ||
stateContext.add(keyPath, this) | ||
public constructor( | ||
stateContext: StateContext, | ||
raw: T, | ||
state: Record<string, any>, | ||
keyPath: string | ||
) { | ||
this._stateContext = stateContext; | ||
stateContext.add(keyPath, this); | ||
this._raw = raw | ||
this._proxy = this._createProxyClass() | ||
this._raw = raw; | ||
this._proxy = this._createProxyClass(); | ||
this.state = state | ||
this.keyPath = keyPath | ||
this.connecting = stateContext.hasState(keyPath) | ||
this.state = state; | ||
this.keyPath = keyPath; | ||
this.connecting = stateContext.hasState(keyPath); | ||
this.get = this.get.bind(this) | ||
this.subscribe = this.subscribe.bind(this) | ||
this.dispose = this.dispose.bind(this) | ||
} | ||
/** | ||
* 获取当前代理实例,每次状态变化时,代理实例都会变化 | ||
* 已绑定 this | ||
*/ | ||
public get () { | ||
this._depend() | ||
return this._proxy | ||
} | ||
/** | ||
* 私有函数,外部调用不应该使用 | ||
*/ | ||
public _setState (nextState: Record<string, any>) { | ||
const { _stateContext, keyPath: fullPath, _subs } = this | ||
this.state = nextState | ||
if (_stateContext) { | ||
_stateContext.updateState(fullPath, nextState) | ||
this.get = this.get.bind(this); | ||
this.subscribe = this.subscribe.bind(this); | ||
this.dispose = this.dispose.bind(this); | ||
} | ||
this.connecting = !!_stateContext | ||
const store = this._createProxyClass() | ||
this._proxy = store | ||
if (_subs.length) { | ||
const subs = [..._subs] | ||
subs.forEach(item => { | ||
item.cb() | ||
}) | ||
/** | ||
* 获取当前代理实例,每次状态变化时,代理实例都会变化 | ||
* 已绑定 this | ||
*/ | ||
public get() { | ||
this._depend(); | ||
return this._proxy; | ||
} | ||
} | ||
/** | ||
* 销毁实例,释放内存 | ||
* 已绑定 this | ||
*/ | ||
public dispose () { | ||
const { _stateContext, _proxy } = this | ||
call(_proxy, LIFE_CYCLE_CREATED) | ||
if (_stateContext) { | ||
_stateContext.del(this.keyPath) | ||
this._stateContext = null | ||
/** | ||
* 私有函数,外部调用不应该使用 | ||
*/ | ||
public _setState(nextState: Record<string, any>) { | ||
const { _stateContext, keyPath: fullPath, _subs } = this; | ||
this.state = nextState; | ||
if (_stateContext) { | ||
_stateContext.updateState(fullPath, nextState); | ||
} | ||
this.connecting = !!_stateContext; | ||
const store = this._createProxyClass(); | ||
this._proxy = store; | ||
if (_subs.length) { | ||
const subs = [..._subs]; | ||
subs.forEach((item) => { | ||
item.cb(); | ||
}); | ||
} | ||
} | ||
this._subs.splice(0) | ||
this.dispose = noon | ||
} | ||
/** | ||
* 订阅状态变化 | ||
* @param cb 回调函数 | ||
* 已绑定 this | ||
* @returns | ||
*/ | ||
public subscribe (cb: StoreSubscribe) { | ||
const _sid = ++sid | ||
this._subs.push({ | ||
sid, | ||
cb | ||
}) | ||
return () => { | ||
const index = this._subs.findIndex(item => item.sid === _sid) | ||
if (index > -1) { | ||
this._subs.splice(index, 1) | ||
} | ||
/** | ||
* 销毁实例,释放内存 | ||
* 已绑定 this | ||
*/ | ||
public dispose() { | ||
const { _stateContext, _proxy } = this; | ||
call(_proxy, LIFE_CYCLE_CREATED); | ||
if (_stateContext) { | ||
_stateContext.del(this.keyPath); | ||
this._stateContext = null; | ||
} | ||
this._subs.splice(0); | ||
this.dispose = noon; | ||
} | ||
} | ||
private _depend () { | ||
const stateContext = this._stateContext | ||
if (stateContext) { | ||
if (this.connecting) { | ||
stateContext.depend(this.keyPath) | ||
} else { | ||
stateContext.depend() | ||
} | ||
/** | ||
* 订阅状态变化 | ||
* @param cb 回调函数 | ||
* 已绑定 this | ||
* @returns | ||
*/ | ||
public subscribe(cb: StoreSubscribe) { | ||
const _sid = ++sid; | ||
this._subs.push({ | ||
sid, | ||
cb | ||
}); | ||
return () => { | ||
const index = this._subs.findIndex((item) => item.sid === _sid); | ||
if (index > -1) { | ||
this._subs.splice(index, 1); | ||
} | ||
}; | ||
} | ||
} | ||
private _createProxyClass () { | ||
const storeContext = this | ||
return new Proxy(this._raw, { | ||
get (target, p, receiver) { | ||
if (p === '$') { | ||
return storeContext | ||
} else if (typeof p === 'string') { | ||
const state = storeContext.state | ||
if (p in state) { | ||
storeContext._depend() | ||
return state[p] | ||
} | ||
private _depend() { | ||
const stateContext = this._stateContext; | ||
if (stateContext) { | ||
if (this.connecting) { | ||
stateContext.depend(this.keyPath); | ||
} else { | ||
stateContext.depend(); | ||
} | ||
} | ||
currentStateContext = storeContext._stateContext | ||
const result = Reflect.get(target, p, receiver) | ||
currentStateContext = null | ||
if (typeof result === 'function' && typeof p === 'string' && p.startsWith('$')) { | ||
let func = storeContext._cacheCommit.get(result) | ||
if (!func) { | ||
func = storeContext._createProxyCommit(result) | ||
storeContext._cacheCommit.set(result, func) | ||
} | ||
return func | ||
} | ||
} | ||
return result | ||
}, | ||
set (target, p, newValue, receiver) { | ||
if (typeof p === 'string' && p in storeContext.state) { | ||
if (storeContext._drafting) { | ||
storeContext.state[p] = newValue | ||
return true | ||
} | ||
throw new Error(`Change the state in the agreed commit function, For example, $${p}('${String(newValue)}')`) | ||
} | ||
return Reflect.set(target, p, newValue, receiver) | ||
} | ||
}) as any | ||
} | ||
private _createProxyClass() { | ||
const storeContext = this; | ||
return new Proxy(this._raw, { | ||
get(target, p, receiver) { | ||
if (p === '$') { | ||
return storeContext; | ||
} else if (typeof p === 'string') { | ||
const state = storeContext.state; | ||
if (p in state) { | ||
storeContext._depend(); | ||
return state[p]; | ||
} | ||
} | ||
currentStateContext = storeContext._stateContext; | ||
const result = Reflect.get(target, p, receiver); | ||
currentStateContext = null; | ||
if ( | ||
typeof result === 'function' && | ||
typeof p === 'string' && | ||
p.startsWith('$') | ||
) { | ||
let func = storeContext._cacheCommit.get(result); | ||
if (!func) { | ||
func = storeContext._createProxyCommit(result); | ||
storeContext._cacheCommit.set(result, func); | ||
} | ||
return func; | ||
} | ||
private _createProxyCommit (commitFunc: Function) { | ||
const connectContext = this | ||
return function proxyCommit (...args: any) { | ||
if (connectContext._drafting) { | ||
return commitFunc.apply(connectContext._proxy, args) | ||
} | ||
return result; | ||
}, | ||
set(target, p, newValue, receiver) { | ||
if (typeof p === 'string' && p in storeContext.state) { | ||
if (storeContext._drafting) { | ||
storeContext.state[p] = newValue; | ||
return true; | ||
} | ||
throw new Error( | ||
`Change the state in the agreed commit function, For example, $${p}('${String(newValue)}')` | ||
); | ||
} | ||
return Reflect.set(target, p, newValue, receiver); | ||
} | ||
}) as any; | ||
} | ||
const prevState = connectContext.state | ||
let result | ||
const nextState = produce(prevState, (draft) => { | ||
connectContext._drafting = true | ||
connectContext.state = draft | ||
try { | ||
result = commitFunc.apply(connectContext._proxy, args) | ||
connectContext._drafting = false | ||
connectContext.state = prevState | ||
} catch (e) { | ||
connectContext._drafting = false | ||
connectContext.state = prevState | ||
throw e | ||
} | ||
}) | ||
connectContext._setState(nextState) | ||
return result | ||
private _createProxyCommit(commitFunc: Function) { | ||
const connectContext = this; | ||
return function proxyCommit(...args: any) { | ||
if (connectContext._drafting) { | ||
return commitFunc.apply(connectContext._proxy, args); | ||
} | ||
const prevState = connectContext.state; | ||
let result; | ||
const nextState = produce(prevState, (draft) => { | ||
connectContext._drafting = true; | ||
connectContext.state = draft; | ||
try { | ||
result = commitFunc.apply(connectContext._proxy, args); | ||
connectContext._drafting = false; | ||
connectContext.state = prevState; | ||
} catch (e) { | ||
connectContext._drafting = false; | ||
connectContext.state = prevState; | ||
throw e; | ||
} | ||
}); | ||
connectContext._setState(nextState); | ||
return result; | ||
}; | ||
} | ||
} | ||
} | ||
export function connectState (state: State) { | ||
const stateContext = getStateContext(state) | ||
return <T extends StoreConstructor>(Store: T, name: string, cacheKey?: string): StoreInstance<InstanceType<T>> => { | ||
const fullPath = typeof cacheKey === 'string' ? name + '/' + cacheKey : name | ||
let storeContext: StoreContext<InstanceType<T>> | null = stateContext.get(fullPath) | ||
if (!storeContext) { | ||
const store = new Store(cacheKey) | ||
let storeState | ||
if (fullPath in state.value) { | ||
storeState = { ...store, ...state.value[fullPath] } | ||
} else { | ||
storeState = { ...store } | ||
} | ||
storeContext = new StoreContext<InstanceType<T>>(stateContext, store, storeState, fullPath) | ||
call(storeContext.get(), LIFE_CYCLE_CREATED) | ||
} | ||
return storeContext.get() | ||
} | ||
export function connectState(state: State) { | ||
const stateContext = getStateContext(state); | ||
return <T extends StoreConstructor>( | ||
Store: T, | ||
name: string, | ||
cacheKey?: string | ||
): StoreInstance<InstanceType<T>> => { | ||
const fullPath = | ||
typeof cacheKey === 'string' ? name + '/' + cacheKey : name; | ||
let storeContext: StoreContext<InstanceType<T>> | null = | ||
stateContext.get(fullPath); | ||
if (!storeContext) { | ||
const store = new Store(cacheKey); | ||
let storeState; | ||
if (fullPath in state.value) { | ||
storeState = { ...store, ...state.value[fullPath] }; | ||
} else { | ||
storeState = { ...store }; | ||
} | ||
storeContext = new StoreContext<InstanceType<T>>( | ||
stateContext, | ||
store, | ||
storeState, | ||
fullPath | ||
); | ||
call(storeContext.get(), LIFE_CYCLE_CREATED); | ||
} | ||
return storeContext.get(); | ||
}; | ||
} | ||
export function connectStore<T extends StoreConstructor> (Store: T, name: string, ...params: ConstructorParameters<T>) { | ||
if (!currentStateContext) { | ||
throw new Error('No state context found') | ||
} | ||
return connectState(currentStateContext.state)(Store, name, ...params) | ||
export function connectStore<T extends StoreConstructor>( | ||
Store: T, | ||
name: string, | ||
...params: ConstructorParameters<T> | ||
) { | ||
if (!currentStateContext) { | ||
throw new Error('No state context found'); | ||
} | ||
return connectState(currentStateContext.state)(Store, name, ...params); | ||
} | ||
function call (obj: any, key: symbol) { | ||
if (typeof obj[key] === 'function') { | ||
return obj[key]() | ||
} | ||
function call(obj: any, key: symbol) { | ||
if (typeof obj[key] === 'function') { | ||
return obj[key](); | ||
} | ||
} |
@@ -1,77 +0,83 @@ | ||
import type { StoreContext } from './connect' | ||
import type { StoreContext } from './connect'; | ||
export interface State { | ||
value: Record<string, any> | ||
value: Record<string, any>; | ||
} | ||
const rootMap = new WeakMap<State, any>() | ||
const rootMap = new WeakMap<State, any>(); | ||
export class StateContext { | ||
public readonly state: State | ||
private readonly storeContext: Map<string, StoreContext<any>> = new Map<string, StoreContext<any>>() | ||
public constructor (state: State) { | ||
this.state = state | ||
} | ||
public readonly state: State; | ||
private readonly storeContext: Map<string, StoreContext<any>> = new Map< | ||
string, | ||
StoreContext<any> | ||
>(); | ||
public depend (fullPath?: string): unknown { | ||
if (fullPath) { | ||
return this.state.value[fullPath] | ||
public constructor(state: State) { | ||
this.state = state; | ||
} | ||
return this.state.value | ||
} | ||
public hasState (name: string): boolean { | ||
return name in this.state.value | ||
} | ||
public depend(fullPath?: string): unknown { | ||
if (fullPath) { | ||
return this.state.value[fullPath]; | ||
} | ||
return this.state.value; | ||
} | ||
public get (name: string): StoreContext<any> | null { | ||
return this.storeContext.get(name) ?? null | ||
} | ||
public hasState(name: string): boolean { | ||
return name in this.state.value; | ||
} | ||
public add (name: string, storeContext: StoreContext<any>) { | ||
this.storeContext.set(name, storeContext) | ||
} | ||
public get(name: string): StoreContext<any> | null { | ||
return this.storeContext.get(name) ?? null; | ||
} | ||
public updateState (name: string, nextState: any) { | ||
const { state } = this | ||
if (name in state.value) { | ||
state.value[name] = nextState | ||
} else { | ||
state.value = { | ||
...state.value, | ||
[name]: nextState | ||
} | ||
public add(name: string, storeContext: StoreContext<any>) { | ||
this.storeContext.set(name, storeContext); | ||
} | ||
} | ||
public del (name: string) { | ||
const { state } = this | ||
this.storeContext.delete(name) | ||
const newValue: Record<string, any> = {} | ||
Object.keys(state.value).forEach(key => { | ||
if (key !== name) { | ||
newValue[key] = state.value[key] | ||
} | ||
}) | ||
state.value = newValue | ||
} | ||
public updateState(name: string, nextState: any) { | ||
const { state } = this; | ||
if (name in state.value) { | ||
state.value[name] = nextState; | ||
} else { | ||
state.value = { | ||
...state.value, | ||
[name]: nextState | ||
}; | ||
} | ||
} | ||
public del(name: string) { | ||
const { state } = this; | ||
this.storeContext.delete(name); | ||
const newValue: Record<string, any> = {}; | ||
Object.keys(state.value).forEach((key) => { | ||
if (key !== name) { | ||
newValue[key] = state.value[key]; | ||
} | ||
}); | ||
state.value = newValue; | ||
} | ||
} | ||
function setStateContext (state: State, stateContext: StateContext) { | ||
rootMap.set(state, stateContext) | ||
function setStateContext(state: State, stateContext: StateContext) { | ||
rootMap.set(state, stateContext); | ||
} | ||
export function getStateContext (state: State): StateContext { | ||
let stateContext = rootMap.get(state) | ||
if (stateContext) { | ||
return stateContext | ||
} else { | ||
stateContext = new StateContext(state) | ||
setStateContext(state, stateContext) | ||
} | ||
export function getStateContext(state: State): StateContext { | ||
let stateContext = rootMap.get(state); | ||
if (stateContext) { | ||
return stateContext; | ||
} else { | ||
stateContext = new StateContext(state); | ||
setStateContext(state, stateContext); | ||
} | ||
return stateContext | ||
return stateContext; | ||
} | ||
export function createState (state?: State): State { | ||
return getStateContext(state?.value && typeof state.value === 'object' ? state : { value: {} }).state | ||
export function createState(state?: State): State { | ||
return getStateContext( | ||
state?.value && typeof state.value === 'object' ? state : { value: {} } | ||
).state; | ||
} |
@@ -1,2 +0,11 @@ | ||
export { createState, type State } from './create' | ||
export { connectState, connectStore, type StoreConstructor, type StoreContext, type StoreInstance, type StoreParams, LIFE_CYCLE_CREATED, LIFE_CYCLE_DISPOSE } from './connect' | ||
export { createState, type State } from './create'; | ||
export { | ||
connectState, | ||
connectStore, | ||
type StoreConstructor, | ||
type StoreContext, | ||
type StoreInstance, | ||
type StoreParams, | ||
LIFE_CYCLE_CREATED, | ||
LIFE_CYCLE_DISPOSE | ||
} from './connect'; |
@@ -1,73 +0,83 @@ | ||
import { reactive, watch, nextTick } from 'vue' | ||
import { test, assert } from 'vitest' | ||
import { connectState } from './connect' | ||
import { createState } from './create' | ||
import { assert, test } from 'vitest'; | ||
import { nextTick, reactive, watch } from 'vue'; | ||
import { connectState } from './connect'; | ||
import { createState } from './create'; | ||
test('base', async () => { | ||
const state = createState(reactive({ value: {} })) | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
const state = createState(reactive({ value: {} })); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
let updateValue | ||
watch(() => { | ||
return user.name | ||
}, (name) => { | ||
updateValue = name | ||
}) | ||
user.$setName('test') | ||
await nextTick() | ||
assert.equal(updateValue, 'test') | ||
const user = connectStore(User, 'user'); | ||
let updateValue; | ||
watch( | ||
() => { | ||
return user.name; | ||
}, | ||
(name) => { | ||
updateValue = name; | ||
} | ||
); | ||
user.$setName('test'); | ||
await nextTick(); | ||
assert.equal(updateValue, 'test'); | ||
user.$setName('test2') | ||
await nextTick() | ||
assert.equal(updateValue, 'test2') | ||
}) | ||
user.$setName('test2'); | ||
await nextTick(); | ||
assert.equal(updateValue, 'test2'); | ||
}); | ||
test('base2', async () => { | ||
const state = createState(reactive({ value: {} })) | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
const state = createState(reactive({ value: {} })); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
user.$setName('test') | ||
let updateValue | ||
watch(() => { | ||
return user.name | ||
}, (name) => { | ||
updateValue = name | ||
}) | ||
user.$setName('test2') | ||
await nextTick() | ||
assert.equal(updateValue, 'test2') | ||
}) | ||
const user = connectStore(User, 'user'); | ||
user.$setName('test'); | ||
let updateValue; | ||
watch( | ||
() => { | ||
return user.name; | ||
}, | ||
(name) => { | ||
updateValue = name; | ||
} | ||
); | ||
user.$setName('test2'); | ||
await nextTick(); | ||
assert.equal(updateValue, 'test2'); | ||
}); | ||
test('watch root', async () => { | ||
const state = createState(reactive({ value: {} })) | ||
const connectStore = connectState(state) | ||
class User { | ||
public name = '' | ||
public $setName (name: string) { | ||
this.name = name | ||
const state = createState(reactive({ value: {} })); | ||
const connectStore = connectState(state); | ||
class User { | ||
public name = ''; | ||
public $setName(name: string) { | ||
this.name = name; | ||
} | ||
} | ||
} | ||
const user = connectStore(User, 'user') | ||
let updateCount = 0 | ||
watch(() => { | ||
return connectStore(User, 'user') | ||
}, () => { | ||
updateCount++ | ||
}) | ||
assert.equal(user.$.connecting, false) | ||
user.$setName('test2') | ||
await nextTick() | ||
assert.equal(updateCount, 1) | ||
}) | ||
const user = connectStore(User, 'user'); | ||
let updateCount = 0; | ||
watch( | ||
() => { | ||
return connectStore(User, 'user'); | ||
}, | ||
() => { | ||
updateCount++; | ||
} | ||
); | ||
assert.equal(user.$.connecting, false); | ||
user.$setName('test2'); | ||
await nextTick(); | ||
assert.equal(updateCount, 1); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
80333
2711
9
23
2
2
2
0
1