@e7w/easy-model 0.0.1

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/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # 简单模型(easy-model)
2
+
3
+ > 一个简单的状态管理包.\
4
+ > A simple state management lib for Typescript
5
+
6
+ ## 例子(Example)
7
+
8
+ ```ts
9
+ import { provide, subscribe } from "@e7w/easy-model";
10
+
11
+ const A = provide(
12
+ class A {
13
+ msg = "1";
14
+
15
+ constructor(private id: number) {}
16
+
17
+ random() {
18
+ this.msg = `${Math.random()}`;
19
+ }
20
+ }
21
+ );
22
+
23
+ A(1) === A(1); // true
24
+ subscribe(A(1), console.log.bind(console, "Path of changed value:"));
25
+ A(1).msg = "123"; // Path of changed value: ["msg"]
26
+ ```
@@ -0,0 +1,6 @@
1
+ export type Ctor = new (...args: any[]) => any;
2
+ export type Obj = Record<string | symbol | number, any>;
3
+ export declare function safeGet(target: Obj, p: string | symbol): any;
4
+ export declare function track(target: Obj, handler: (path: (string | symbol)[]) => void): void;
5
+ export declare function subscribe(target: Obj, handler: (path: (string | symbol)[]) => void): () => void;
6
+ export declare function trigger(target: Obj, path: (string | symbol)[]): void;
@@ -0,0 +1,2 @@
1
+ export { subscribe } from "./helpers";
2
+ export { provide } from "./provide";
@@ -0,0 +1,126 @@
1
+ var O = Object.defineProperty;
2
+ var _ = (n, t, e) => t in n ? O(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
+ var c = (n, t, e) => (_(n, typeof t != "symbol" ? t + "" : t, e), e);
4
+ const h = /* @__PURE__ */ new WeakMap(), g = Symbol("origin");
5
+ function i(n) {
6
+ if (n = f(n), h.has(n))
7
+ return h.get(n);
8
+ const t = new Proxy(n, new j(n));
9
+ return h.set(n, t), t;
10
+ }
11
+ function f(n) {
12
+ return n[g] || n;
13
+ }
14
+ class j {
15
+ constructor(t) {
16
+ c(this, "triggers", {});
17
+ this.obj = t;
18
+ }
19
+ get(t, e, r) {
20
+ if (e === g)
21
+ return this.obj;
22
+ let s = k(t, e) || Reflect.get(t, e, r);
23
+ return typeof s == "function" ? s.bind(i(t)) : (typeof s == "object" && (s = i(s), p(s, this.getTrigger(e))), s);
24
+ }
25
+ set(t, e, r, s) {
26
+ const o = Reflect.set(t, e, r, s);
27
+ return y(this.obj, [e]), o;
28
+ }
29
+ getTrigger(t) {
30
+ return t in this.triggers || (this.triggers[t] = (e) => y(this.obj, [t, ...e])), this.triggers[t];
31
+ }
32
+ }
33
+ const l = ["push", "pop", "shift", "unshift", "splice"];
34
+ function k(n, t) {
35
+ return t === "hasOwnProperty" ? function(e) {
36
+ return f(this).hasOwnProperty(e);
37
+ } : Array.isArray(n) && typeof l[t] == "function" ? function(...e) {
38
+ const r = l[t].apply(f(this), e);
39
+ return l.includes(t) && y(this, [t]), r;
40
+ } : null;
41
+ }
42
+ const a = /* @__PURE__ */ new WeakMap();
43
+ function d(n) {
44
+ return n = f(n), a.has(n) || a.set(n, /* @__PURE__ */ new Set()), a.get(n);
45
+ }
46
+ function p(n, t) {
47
+ d(n).add(t);
48
+ }
49
+ function R(n, t) {
50
+ const e = (s) => {
51
+ t(s), p(n, e);
52
+ }, r = () => {
53
+ d(n).delete(e);
54
+ };
55
+ return p(n, e), r;
56
+ }
57
+ function y(n, t) {
58
+ const e = d(n), r = [...e];
59
+ return e.clear(), r.forEach((s) => s(t));
60
+ }
61
+ function C(n) {
62
+ return new Proxy(n, new u(n));
63
+ }
64
+ const b = class {
65
+ constructor(t) {
66
+ c(this, "fakeCtor");
67
+ c(this, "caches", /* @__PURE__ */ new Map());
68
+ this.Ctor = t;
69
+ const e = function() {
70
+ };
71
+ e.prototype = new Proxy(
72
+ {
73
+ constructor: t,
74
+ __proto__: t.prototype
75
+ },
76
+ b.prototypeHandlers
77
+ ), this.fakeCtor = e;
78
+ }
79
+ apply(t, e, r) {
80
+ return this.getInstance(r) || this.register(
81
+ r,
82
+ Reflect.construct(this.Ctor, r, this.fakeCtor)
83
+ );
84
+ }
85
+ construct(t, e, r) {
86
+ return Reflect.construct(
87
+ t,
88
+ e,
89
+ r === this.Ctor ? this.fakeCtor : r
90
+ );
91
+ }
92
+ getInstance(t) {
93
+ for (const e of this.caches.keys()) {
94
+ if (!e.every(
95
+ (s, o) => s === t[o] ? !0 : typeof s == "object" && typeof t[o] == "object" ? this.isShallowEqualObj(s, t[o]) : !1
96
+ ))
97
+ continue;
98
+ const r = this.caches.get(e);
99
+ return r.deref() ? i(r.deref()) : (this.caches.delete(e), null);
100
+ }
101
+ return null;
102
+ }
103
+ register(t, e) {
104
+ return this.caches.set(t, new WeakRef(e)), i(e);
105
+ }
106
+ isShallowEqualObj(t, e) {
107
+ const r = Object.keys(t), s = e.keys(e);
108
+ return r.length === s.length && r.every((o) => t[o] === e[o]);
109
+ }
110
+ };
111
+ let u = b;
112
+ c(u, "prototypeHandlers", {
113
+ get(t, e, r) {
114
+ const s = k(t, e);
115
+ if (s)
116
+ return s;
117
+ const o = Reflect.get(t, e, r);
118
+ return typeof e == "symbol" || ["constructor", "__proto__"].includes(e) || typeof o != "function" ? o : function(...w) {
119
+ return o.apply(i(this), w);
120
+ };
121
+ }
122
+ });
123
+ export {
124
+ C as provide,
125
+ R as subscribe
126
+ };
@@ -0,0 +1 @@
1
+ (function(i,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(i=typeof globalThis<"u"?globalThis:i||self,o(i["@e7w/easy-model"]={}))})(this,function(i){"use strict";var v=Object.defineProperty;var H=(i,o,u)=>o in i?v(i,o,{enumerable:!0,configurable:!0,writable:!0,value:u}):i[o]=u;var h=(i,o,u)=>(H(i,typeof o!="symbol"?o+"":o,u),u);const o=new WeakMap,u=Symbol("origin");function f(n){if(n=l(n),o.has(n))return o.get(n);const e=new Proxy(n,new O(n));return o.set(n,e),e}function l(n){return n[u]||n}class O{constructor(e){h(this,"triggers",{});this.obj=e}get(e,t,r){if(t===u)return this.obj;let s=k(e,t)||Reflect.get(e,t,r);return typeof s=="function"?s.bind(f(e)):(typeof s=="object"&&(s=f(s),b(s,this.getTrigger(t))),s)}set(e,t,r,s){const c=Reflect.set(e,t,r,s);return g(this.obj,[t]),c}getTrigger(e){return e in this.triggers||(this.triggers[e]=t=>g(this.obj,[e,...t])),this.triggers[e]}}const d=["push","pop","shift","unshift","splice"];function k(n,e){return e==="hasOwnProperty"?function(t){return l(this).hasOwnProperty(t)}:Array.isArray(n)&&typeof d[e]=="function"?function(...t){const r=d[e].apply(l(this),t);return d.includes(e)&&g(this,[e]),r}:null}const p=new WeakMap;function y(n){return n=l(n),p.has(n)||p.set(n,new Set),p.get(n)}function b(n,e){y(n).add(e)}function j(n,e){const t=s=>{e(s),b(n,t)},r=()=>{y(n).delete(t)};return b(n,t),r}function g(n,e){const t=y(n),r=[...t];return t.clear(),r.forEach(s=>s(e))}function _(n){return new Proxy(n,new a(n))}const w=class{constructor(e){h(this,"fakeCtor");h(this,"caches",new Map);this.Ctor=e;const t=function(){};t.prototype=new Proxy({constructor:e,__proto__:e.prototype},w.prototypeHandlers),this.fakeCtor=t}apply(e,t,r){return this.getInstance(r)||this.register(r,Reflect.construct(this.Ctor,r,this.fakeCtor))}construct(e,t,r){return Reflect.construct(e,t,r===this.Ctor?this.fakeCtor:r)}getInstance(e){for(const t of this.caches.keys()){if(!t.every((s,c)=>s===e[c]?!0:typeof s=="object"&&typeof e[c]=="object"?this.isShallowEqualObj(s,e[c]):!1))continue;const r=this.caches.get(t);return r.deref()?f(r.deref()):(this.caches.delete(t),null)}return null}register(e,t){return this.caches.set(e,new WeakRef(t)),f(t)}isShallowEqualObj(e,t){const r=Object.keys(e),s=t.keys(t);return r.length===s.length&&r.every(c=>e[c]===t[c])}};let a=w;h(a,"prototypeHandlers",{get(e,t,r){const s=k(e,t);if(s)return s;const c=Reflect.get(e,t,r);return typeof t=="symbol"||["constructor","__proto__"].includes(t)||typeof c!="function"?c:function(...m){return c.apply(f(this),m)}}}),i.provide=_,i.subscribe=j,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,3 @@
1
+ import { type Obj } from "./helpers";
2
+ export declare function observe<T extends Obj>(target: T): T;
3
+ export declare function getOrigin<T extends Obj>(target: T): T;
@@ -0,0 +1,2 @@
1
+ import { type Ctor } from "./helpers";
2
+ export declare function provide<T extends Ctor>(Ctor: T): T & ((...args: ConstructorParameters<T>) => InstanceType<T>);
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@e7w/easy-model",
3
+ "version": "0.0.1",
4
+ "description": "一个简单的状态管理包, A simple state management lib for Typescript",
5
+ "main": "./dist/index.es.js",
6
+ "module": "./dist/index.es.js",
7
+ "types": "./src/index.d.ts",
8
+ "typings": "./dist/index.d.ts",
9
+ "exports": {
10
+ "import": "./dist/index.es.js",
11
+ "require": "./dist/index.umd.js"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org/"
16
+ },
17
+ "type": "module",
18
+ "keywords": [
19
+ "model",
20
+ "provide",
21
+ "observe"
22
+ ],
23
+ "author": "张一凡<344275632@qq.com>",
24
+ "license": "ISC",
25
+ "files": [
26
+ "package.json",
27
+ "src",
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "scripts": {
32
+ "build": "vite build"
33
+ }
34
+ }
package/src/helpers.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { getOrigin } from "./observe";
2
+
3
+ export type Ctor = new (...args: any[]) => any;
4
+ export type Obj = Record<string | symbol | number, any>;
5
+ const fakeArr: any = ["push", "pop", "shift", "unshift", "splice"];
6
+ export function safeGet(target: Obj, p: string | symbol): any {
7
+ if (p === "hasOwnProperty") {
8
+ return function (this: Obj, key: string) {
9
+ return getOrigin(this).hasOwnProperty(key);
10
+ };
11
+ }
12
+ if (Array.isArray(target) && typeof fakeArr[p] === "function") {
13
+ return function (this: Obj, ...args: any) {
14
+ const ret = fakeArr[p].apply(getOrigin(this), args);
15
+ if (fakeArr.includes(p)) trigger(this, [p]);
16
+ return ret;
17
+ };
18
+ }
19
+ return null;
20
+ }
21
+
22
+ const updateHandlersMap = new WeakMap();
23
+
24
+ function getUpdateHandlers(
25
+ target: Obj
26
+ ): Set<(path: (string | symbol)[]) => void> {
27
+ target = getOrigin(target);
28
+ if (!updateHandlersMap.has(target)) updateHandlersMap.set(target, new Set());
29
+ return updateHandlersMap.get(target);
30
+ }
31
+
32
+ export function track(
33
+ target: Obj,
34
+ handler: (path: (string | symbol)[]) => void
35
+ ): void {
36
+ const handlers = getUpdateHandlers(target);
37
+ handlers.add(handler);
38
+ }
39
+
40
+ export function subscribe(
41
+ target: Obj,
42
+ handler: (path: (string | symbol)[]) => void
43
+ ): () => void {
44
+ const wrappedHandler: typeof handler = (path) => {
45
+ handler(path);
46
+ track(target, wrappedHandler);
47
+ };
48
+ const unsubscribe = () => {
49
+ getUpdateHandlers(target).delete(wrappedHandler);
50
+ };
51
+ track(target, wrappedHandler);
52
+ return unsubscribe;
53
+ }
54
+
55
+ export function trigger(target: Obj, path: (string | symbol)[]): void {
56
+ const handlers = getUpdateHandlers(target);
57
+ const cbs = [...handlers];
58
+ handlers.clear();
59
+
60
+ return cbs.forEach((fn) => fn(path));
61
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { subscribe } from "./helpers";
2
+ export { provide } from "./provide";
package/src/observe.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { type Obj, safeGet, track, trigger } from "./helpers";
2
+
3
+ const observedMap = new WeakMap();
4
+ const origin = Symbol("origin");
5
+ export function observe<T extends Obj>(target: T): T {
6
+ target = getOrigin(target);
7
+ if (observedMap.has(target)) return observedMap.get(target);
8
+ const ret = new Proxy(target, new ObserveHandler(target));
9
+ observedMap.set(target, ret);
10
+ return ret;
11
+ }
12
+
13
+ export function getOrigin<T extends Obj>(target: T): T {
14
+ return target[origin] || target;
15
+ }
16
+
17
+ class ObserveHandler<T extends Obj> implements ProxyHandler<T> {
18
+ private triggers: Record<
19
+ string | symbol,
20
+ (path: (string | symbol)[]) => void
21
+ > = {};
22
+
23
+ public constructor(private obj: T) {}
24
+
25
+ public get(target: T, p: string | symbol, receiver: any): any {
26
+ if (p === origin) return this.obj;
27
+ let ret = safeGet(target, p) || Reflect.get(target, p, receiver);
28
+ if (typeof ret === "function") return ret.bind(observe(target));
29
+ if (typeof ret === "object") {
30
+ ret = observe(ret);
31
+ track(ret, this.getTrigger(p));
32
+ }
33
+ return ret;
34
+ }
35
+
36
+ public set(
37
+ target: T,
38
+ p: string | symbol,
39
+ newValue: any,
40
+ receiver: any
41
+ ): boolean {
42
+ const ret = Reflect.set(target, p, newValue, receiver);
43
+ trigger(this.obj, [p]);
44
+ return ret;
45
+ }
46
+
47
+ private getTrigger(p: string | symbol): (path: (string | symbol)[]) => void {
48
+ if (!(p in this.triggers)) {
49
+ this.triggers[p] = (path: (typeof p)[]) =>
50
+ trigger(this.obj, [p, ...path]);
51
+ }
52
+ return this.triggers[p];
53
+ }
54
+ }
package/src/provide.ts ADDED
@@ -0,0 +1,111 @@
1
+ import { type Ctor, type Obj, safeGet } from "./helpers";
2
+ import { observe } from "./observe";
3
+
4
+ export function provide<T extends Ctor>(
5
+ Ctor: T
6
+ ): T & ((...args: ConstructorParameters<T>) => InstanceType<T>) {
7
+ return new Proxy(Ctor, new Provider(Ctor)) as any;
8
+ }
9
+
10
+ class Provider<T extends Ctor> implements ProxyHandler<T> {
11
+ private static prototypeHandlers: ProxyHandler<Obj> = {
12
+ get(target, p, receiver) {
13
+ const safeVal = safeGet(target, p);
14
+ if (safeVal) return safeVal;
15
+ const ret = Reflect.get(target, p, receiver);
16
+
17
+ if (
18
+ typeof p === "symbol" ||
19
+ ["constructor", "__proto__"].includes(p) ||
20
+ typeof ret !== "function"
21
+ )
22
+ return ret;
23
+ return function (this: Obj, ...args: any[]) {
24
+ return ret.apply(observe(this), args);
25
+ };
26
+ },
27
+ };
28
+
29
+ public fakeCtor: T;
30
+ private caches = new Map<
31
+ ConstructorParameters<T>,
32
+ WeakRef<InstanceType<T>>
33
+ >();
34
+
35
+ public constructor(private Ctor: T) {
36
+ const fakeCtor: any = function () {};
37
+ fakeCtor.prototype = new Proxy(
38
+ {
39
+ constructor: Ctor,
40
+ __proto__: Ctor.prototype,
41
+ },
42
+ Provider.prototypeHandlers
43
+ );
44
+ this.fakeCtor = fakeCtor;
45
+ }
46
+
47
+ public apply(
48
+ _target: T,
49
+ _thisArg: any,
50
+ argArray: ConstructorParameters<T>
51
+ ): InstanceType<T> {
52
+ // todo: 循环引用创建时抛出错误
53
+ return (
54
+ this.getInstance(argArray) ||
55
+ this.register(
56
+ argArray,
57
+ Reflect.construct(this.Ctor, argArray, this.fakeCtor)
58
+ )
59
+ );
60
+ }
61
+
62
+ public construct(
63
+ target: T,
64
+ argArray: any[],
65
+ newTarget: any
66
+ ): InstanceType<T> {
67
+ return Reflect.construct(
68
+ target,
69
+ argArray,
70
+ newTarget === this.Ctor ? this.fakeCtor : newTarget
71
+ );
72
+ }
73
+
74
+ public getInstance(args: ConstructorParameters<T>): InstanceType<T> | null {
75
+ for (const cachedArgs of this.caches.keys()) {
76
+ if (
77
+ !cachedArgs.every((arg, index) =>
78
+ arg === args[index]
79
+ ? true
80
+ : typeof arg === "object" && typeof args[index] === "object"
81
+ ? this.isShallowEqualObj(arg, args[index]) // 只考虑 array 和 object 的浅比较, 其他奇怪的对象不应该出现在入参里.
82
+ : false
83
+ )
84
+ )
85
+ continue;
86
+
87
+ const instance = this.caches.get(cachedArgs)!;
88
+ if (instance.deref()) return observe(instance.deref()!);
89
+ this.caches.delete(cachedArgs);
90
+ return null;
91
+ }
92
+ return null;
93
+ }
94
+
95
+ public register(
96
+ args: ConstructorParameters<T>,
97
+ instance: InstanceType<T>
98
+ ): InstanceType<T> {
99
+ this.caches.set(args, new WeakRef(instance));
100
+ return observe(instance);
101
+ }
102
+
103
+ private isShallowEqualObj(objectA: Obj, objectB: Obj): Boolean {
104
+ const kOfA = Object.keys(objectA);
105
+ const kOfB = objectB.keys(objectB);
106
+ return (
107
+ kOfA.length === kOfB.length &&
108
+ kOfA.every((key) => objectA[key] === objectB[key])
109
+ );
110
+ }
111
+ }