Rewrite settings proxy to proper store

This commit is contained in:
Vendicated
2023-04-10 01:04:41 +02:00
parent ddebb6563a
commit c2eaa9d35a
8 changed files with 90 additions and 58 deletions

View File

@@ -4,23 +4,67 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
export function makeChangeListenerProxy<T extends object>(object: T, onChange: (object: T) => void, _root = object): T {
return new Proxy(object, {
get(target, key) {
const v = target[key];
if (typeof v === "object" && !Array.isArray(v) && v !== null)
return makeChangeListenerProxy(v, onChange, _root);
export class SettingsStore<T extends object> {
public declare store: T;
private globalListeners = new Set<(newData: T) => void>();
private pathListeners = new Map<string, Set<(newData: unknown) => void>>();
return v;
},
public constructor(public plain: T) {
this.store = this.makeProxy(plain);
}
set(target, key, value) {
if (target[key] === value) return true;
private makeProxy(object: any, root: T = object, path: string = "") {
const self = this;
Reflect.set(target, key, value);
onChange(_root);
return new Proxy(object, {
get(target, key: string) {
const v = target[key];
return true;
}
});
if (typeof v === "object" && v !== null && !Array.isArray(v))
return self.makeProxy(v, root, `${path}${path && "."}${key}`);
return v;
},
set(target, key: string, value) {
if (target[key] === value) return true;
Reflect.set(target, key, value);
const setPath = `${path}${path && "."}${key}`;
self.globalListeners.forEach(cb => cb(root));
self.pathListeners.get(setPath)?.forEach(cb => cb(value));
return true;
}
});
}
public setData(value: T) {
this.plain = value;
this.store = this.makeProxy(value);
this.globalListeners.forEach(cb => cb(value));
}
public addGlobalChangeListener(cb: (store: T) => void) {
this.globalListeners.add(cb);
}
public addChangeListener(path: string, cb: (data: any) => void) {
const listeners = this.pathListeners.get(path) ?? new Set();
listeners.add(cb);
this.pathListeners.set(path, listeners);
}
public removeGlobalChangeListener(cb: (store: T) => void) {
this.globalListeners.delete(cb);
}
public removeChangeListener(path: string, cb: (data: any) => void) {
const listeners = this.pathListeners.get(path);
if (!listeners) return;
listeners.delete(cb);
if (!listeners.size) this.pathListeners.delete(path);
}
}