Skip to content

Commit 4ca63a7

Browse files
committed
[debugging] add mutation detector proxy class
1 parent 91c665a commit 4ca63a7

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* mutation-detector-proxy
3+
*
4+
* Copyright (C) 2025 Posit Software, PBC
5+
*/
6+
7+
export type DeepProxyChange = {
8+
type: "update" | "delete";
9+
path: (string | symbol)[];
10+
oldValue: unknown;
11+
newValue?: unknown;
12+
};
13+
14+
export type OnChangeCallback = (change: DeepProxyChange) => void;
15+
16+
export function mutationDetectorProxy<T extends object>(
17+
obj: T,
18+
onChange: OnChangeCallback,
19+
path: (string | symbol)[] = [],
20+
): T {
21+
return new Proxy(obj, {
22+
get(target: T, property: string | symbol): any {
23+
const value = Reflect.get(target, property);
24+
if (value && typeof value === "object") {
25+
return mutationDetectorProxy(
26+
value,
27+
onChange,
28+
[...path, property],
29+
);
30+
}
31+
return value;
32+
},
33+
34+
set(target: T, property: string | symbol, value: any): boolean {
35+
const oldValue = Reflect.get(target, property);
36+
const result = Reflect.set(target, property, value);
37+
38+
if (result) {
39+
onChange({
40+
type: "update",
41+
path: [...path, property],
42+
oldValue,
43+
newValue: value,
44+
});
45+
}
46+
47+
return result;
48+
},
49+
50+
deleteProperty(target: T, property: string | symbol): boolean {
51+
const oldValue = Reflect.get(target, property);
52+
const result = Reflect.deleteProperty(target, property);
53+
54+
if (result) {
55+
onChange({
56+
type: "delete",
57+
path: [...path, property],
58+
oldValue,
59+
});
60+
}
61+
62+
return result;
63+
},
64+
});
65+
}

0 commit comments

Comments
 (0)