-
Notifications
You must be signed in to change notification settings - Fork 0
/
Settable.ts
80 lines (74 loc) · 1.93 KB
/
Settable.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
interface Settable<T> {
__original__: T;
__on__(cb: () => void): void;
__emit__(): void;
__cb__: Array<() => void>;
}
export function wrap<T extends {}>(obj: T): T & Settable<T> {
if (obj == null || typeof obj !== "object") {
return obj as any;
}
const settable: Settable<T> = {
__cb__: [],
__emit__() {
this.__cb__.forEach((it) => it());
},
__on__(cb) {
this.__cb__.push(cb);
},
__original__: obj,
};
Object.keys(obj).forEach((key) => {
const wrapped = wrap((obj as any)[key]);
(obj as any)[key] = wrapped;
wrapped?.__on__?.(() => settable.__emit__());
});
function set(_: any, key: string, value: any) {
const wrapped = wrap<{}>(value);
(obj as any)[key as any] = wrapped;
wrapped?.__on__?.(() => settable.__emit__());
settable.__emit__();
return true;
}
if (Array.isArray(obj)) {
return new Proxy(settable, {
get(target, key) {
if (
["__cb__", "__emit__", "__on__", "__original__"].includes(
key.toString(),
)
) {
return (target as any)[key as any];
}
if (["push", "pop", "shift", "unshift"].includes(key.toString())) {
return (...args: any[]) => {
const result = (obj as any)[key](...args);
settable.__emit__();
return result;
};
} else if (
["map", "forEach", "reduce", "filter", "find", "concat"].includes(
key.toString(),
)
) {
return (...args: any[]) => (obj as any)[key](...args);
}
return (obj as any)[key];
},
set,
}) as any;
}
return new Proxy(settable, {
get(target, key) {
if (
["__cb__", "__emit__", "__on__", "__original__"].includes(
key.toString(),
)
) {
return (target as any)[key as any];
}
return (obj as any)[key as any];
},
set,
}) as any;
}