fix vue useDeepSignal for sets as base

feat/orm-diffs
Laurin Weger 1 day ago
parent 294ad71b7c
commit 0df0b10109
No known key found for this signature in database
GPG Key ID: 9B372BB0B792770F
  1. 1
      sdk/js/signals/src/connector/ormConnectionHandler.ts
  2. 111
      sdk/js/signals/src/frontendAdapters/vue/useDeepSignal.ts

@ -71,7 +71,6 @@ export class OrmConnection<T extends BaseType> {
ngSession.then(async ({ ng, session }) => { ngSession.then(async ({ ng, session }) => {
console.log("Creating orm connection. ng and session", ng, session); console.log("Creating orm connection. ng and session", ng, session);
await new Promise((resolve) => setTimeout(resolve, 2000));
try { try {
ng.orm_start( ng.orm_start(
(scope.length == 0 (scope.length == 0

@ -2,97 +2,41 @@ import { ref, onBeforeUnmount } from "vue";
import { watch } from "@ng-org/alien-deepsignals"; import { watch } from "@ng-org/alien-deepsignals";
/** /**
* Bridge a deepSignal root into Vue with per top-level property granularity. * Bridge a deepSignal root into Vue with reactivity.
* Uses a single version counter that increments on any deep mutation,
* causing Vue to re-render when the deepSignal changes.
*/ */
export function useDeepSignal<T extends Record<string | number | symbol, any>>( export function useDeepSignal<T>(deepProxy: T): T {
deepProxy: T const version = ref(0);
): T {
// Version per top-level key
const versionRefs = new Map<PropertyKey, ReturnType<typeof ref<number>>>();
// Version for the set of top-level keys (enumeration/in-operator)
const keysVersion = ref(0);
const ensureVersion = (key: PropertyKey) => {
if (!versionRefs.has(key)) versionRefs.set(key, ref(0));
return versionRefs.get(key)!;
};
const bump = (key: PropertyKey) => {
const vr = ensureVersion(key);
vr.value = (vr.value || 0) + 1;
};
const bumpAllTopKeys = () => {
for (const k of Reflect.ownKeys(deepProxy as object)) bump(k);
};
// Seed existing string keys (symbols will be created on demand)
for (const k of Object.keys(deepProxy as object)) ensureVersion(k);
// Normalize first path element to a JS property key compatible with Proxy traps
const normalizeTopKey = (k: unknown): PropertyKey =>
typeof k === "number" ? String(k) : (k as PropertyKey);
// Subscribe to deep patches (coalesced per batch to avoid redundant triggers)
const stopHandle = watch(deepProxy, ({ patches }) => { const stopHandle = watch(deepProxy, ({ patches }) => {
let sawRoot = false; if (patches.length > 0) {
let keysChanged = false; version.value++;
const touched = new Set<PropertyKey>();
for (const p of patches) {
if (!p || !Array.isArray(p.path)) continue;
if (p.path.length === 0) {
sawRoot = true;
break; // full invalidation; no need to examine the rest
}
touched.add(normalizeTopKey(p.path[0]));
const op = p.op as string | undefined;
if (p.path.length === 1 && (op === "add" || op === "remove")) {
keysChanged = true;
}
}
if (sawRoot) {
keysVersion.value++;
bumpAllTopKeys();
return;
} }
if (keysChanged) keysVersion.value++;
for (const k of touched) bump(k);
}); });
const proxy = new Proxy({} as T, { // Proxy that creates Vue dependency on version for any access
get(_t, key: PropertyKey) { const proxy = new Proxy(deepProxy as any, {
if (key === "__raw") return deepProxy; get(target, key: PropertyKey) {
// Track per-key dependence if (key === "__raw") return target;
ensureVersion(key).value; // Track version to create reactive dependency
return deepProxy[key]; version.value;
}, const value = target[key];
set(_t, key: PropertyKey, value: any) { // Bind methods to maintain correct `this` context
deepProxy[key] = value; return typeof value === "function" ? value.bind(target) : value;
return true;
},
deleteProperty(_t, key: PropertyKey) {
return delete deepProxy[key];
}, },
has(_t, key: PropertyKey) { has(target, key: PropertyKey) {
// Make `'foo' in proxy` reactive to key set changes version.value;
keysVersion.value; return key in target;
return key in deepProxy;
}, },
ownKeys() { ownKeys(target) {
// Make Object.keys/for...in/v-for over keys reactive version.value;
keysVersion.value; return Reflect.ownKeys(target);
return Reflect.ownKeys(deepProxy as object);
}, },
getOwnPropertyDescriptor(_t, key: PropertyKey) { getOwnPropertyDescriptor(target, key: PropertyKey) {
// Keep enumeration reactive; report a configurable, enumerable prop version.value;
keysVersion.value; const desc = Object.getOwnPropertyDescriptor(target, key);
return { configurable: true, enumerable: true }; return desc ? { ...desc, configurable: true } : undefined;
}, },
}); });
@ -102,10 +46,9 @@ export function useDeepSignal<T extends Record<string | number | symbol, any>>(
} catch { } catch {
// ignore // ignore
} }
versionRefs.clear();
}); });
return proxy; return proxy as T;
} }
export default useDeepSignal; export default useDeepSignal;

Loading…
Cancel
Save