From 4ca63a77b9f4b89621c7ed822a6612c6f298c9d2 Mon Sep 17 00:00:00 2001 From: Carlos Scheidegger Date: Thu, 6 Mar 2025 12:30:23 -0500 Subject: [PATCH] [debugging] add mutation detector proxy class --- src/core/debug/mutation-detector-proxy.ts | 65 +++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/core/debug/mutation-detector-proxy.ts diff --git a/src/core/debug/mutation-detector-proxy.ts b/src/core/debug/mutation-detector-proxy.ts new file mode 100644 index 0000000000..a92b9926a3 --- /dev/null +++ b/src/core/debug/mutation-detector-proxy.ts @@ -0,0 +1,65 @@ +/* + * mutation-detector-proxy + * + * Copyright (C) 2025 Posit Software, PBC + */ + +export type DeepProxyChange = { + type: "update" | "delete"; + path: (string | symbol)[]; + oldValue: unknown; + newValue?: unknown; +}; + +export type OnChangeCallback = (change: DeepProxyChange) => void; + +export function mutationDetectorProxy( + obj: T, + onChange: OnChangeCallback, + path: (string | symbol)[] = [], +): T { + return new Proxy(obj, { + get(target: T, property: string | symbol): any { + const value = Reflect.get(target, property); + if (value && typeof value === "object") { + return mutationDetectorProxy( + value, + onChange, + [...path, property], + ); + } + return value; + }, + + set(target: T, property: string | symbol, value: any): boolean { + const oldValue = Reflect.get(target, property); + const result = Reflect.set(target, property, value); + + if (result) { + onChange({ + type: "update", + path: [...path, property], + oldValue, + newValue: value, + }); + } + + return result; + }, + + deleteProperty(target: T, property: string | symbol): boolean { + const oldValue = Reflect.get(target, property); + const result = Reflect.deleteProperty(target, property); + + if (result) { + onChange({ + type: "delete", + path: [...path, property], + oldValue, + }); + } + + return result; + }, + }); +}