New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@gez/class-state

Package Overview
Dependencies
Maintainers
2
Versions
185
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@gez/class-state - npm Package Compare versions

Comparing version 0.0.7 to 0.0.9

./dist/index.cjs

4

dist/connect.d.ts

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc