/** * A listener notified when something changes inside a reactive subtree. * Receives the full source path of the changed property (e.g. "items[0].name"). */ type ReactiveListener = (changedPath?: string) => void; /** * A dispatcher owns the set of listeners attached to a given proxy subtree. * The same dispatcher instance is shared by every nested proxy reached * through a single outermost create() call, so changes at any depth fan out * to every subscriber once. */ type ReactiveDispatcher = { listeners: Set; }; /** * Utility class for creating reactive proxies that automatically track changes. */ export declare class ReactiveProxy { /** * A WeakMap to store the proxy for each target object and path combination. * This prevents creating multiple proxies for the same object accessed from different paths. */ private static proxyCache; /** * A WeakMap to track which objects are proxies, mapping proxy -> original target. * This prevents double-wrapping of already proxied objects. */ private static proxyToTarget; /** * A WeakSet to track objects marked as "raw" (non-reactive). * These objects will not be wrapped with Proxy. */ private static rawObjects; /** * A WeakMap to store the path for each proxy object. * This allows retrieving the source path of an object for computed property mapping. */ private static proxyPaths; /** * Dispatchers per (target, path). Every target reached while walking a proxy * subtree registers an entry pointing at the same dispatcher as the outermost * proxy of that subtree, so callers can look up the dispatcher from any * intermediate proxy when subscribing. */ private static dispatchers; /** * A Map to store path aliases. * Key: alias path (e.g., "editingNestedStep.steps") * Value: source path (e.g., "routes[0].steps[0].steps") * This allows mapping variable names to their actual source paths for dependency tracking. */ private static pathAliases; /** * Creates a reactive proxy for the given object. * The proxy will call the onChange callback whenever a property is modified. * * @param target The object to make reactive. * @param onChange Callback function to call when the object changes. Receives the full path of the changed property. * @param path The current path in the object tree (used internally for nested objects). * @param inheritedDispatcher Internal: the dispatcher inherited from an enclosing create() call when wrapping a nested target. External callers must omit this. * @returns A reactive proxy of the target object. */ static create(target: T, onChange?: (changedPath?: string) => void, path?: string, inheritedDispatcher?: ReactiveDispatcher): T; /** * Looks up the dispatcher associated with (target, path), or installs a new one. * When called for a nested target during proxy walking, the enclosing dispatcher * is reused so a single subtree fans out changes through one notification path. */ private static resolveDispatcher; /** * Invokes every listener attached to the dispatcher. * Iterates a snapshot of the listener set so unsubscribing during dispatch is safe. */ private static dispatch; /** * Subscribes a listener to changes inside the subtree of an existing reactive proxy. * * The listener is scoped by the proxy's source path: only changes at or below that * path are delivered, which lets a child component receive notifications when the * nested contents of a prop change even though the prop reference itself is unchanged. * * @param proxyOrTarget A proxy returned from create(), or the underlying target object. * @param listener Called with the full source path of every relevant change. * @returns A function that removes the subscription. */ static subscribe(proxyOrTarget: object, listener: ReactiveListener): () => void; /** * Checks if the given object is a reactive proxy. * * @param obj The object to check. * @returns True if the object is a reactive proxy, false otherwise. */ static isReactive(obj: any): boolean; /** * Unwraps a reactive proxy to get the original object. * If the object is not a proxy, returns it as-is. * * @param obj The object to unwrap. * @returns The original object. */ static unwrap(obj: T): T; /** * Marks an object as "raw" (non-reactive). * Objects marked as raw will not be wrapped with Proxy when accessed from reactive objects. * This is useful for objects that should not be reactive, such as: * - Objects with private fields (class instances with # fields) * - Third-party library instances * - Objects used only for method calls * * @param obj The object to mark as raw. * @returns The same object (for chaining). */ static markRaw(obj: T): T; /** * Checks if an object is marked as raw (non-reactive). * * @param obj The object to check. * @returns True if the object is marked as raw, false otherwise. */ static isRaw(obj: any): boolean; /** * Gets the source path for a proxy object. * This is used to map computed property values back to their source paths. * For example, if a computed property returns `model.elements[0]`, * this method returns "model.elements[0]" for that object. * * @param obj The proxy object to get the path for. * @returns The source path, or undefined if not found. */ static getPath(obj: any): string | undefined; /** * Registers a path alias. * This is used when a variable is assigned to reference an existing reactive object. * For example, when `editingNestedStep = routes[0].steps[0]`, this creates an alias * so that changes to "routes[0].steps[0].steps" also match "editingNestedStep.steps". * * @param aliasPath The alias path (e.g., "editingNestedStep") * @param sourcePath The source path (e.g., "routes[0].steps[0]") */ static registerPathAlias(aliasPath: string, sourcePath: string): void; /** * Unregisters a path alias. * * @param aliasPath The alias path to remove */ static unregisterPathAlias(aliasPath: string): void; /** * Resolves an alias path to its source path. * Also handles nested paths (e.g., "editingNestedStep.steps" -> "routes[0].steps[0].steps"). * * @param aliasPath The alias path to resolve * @returns The source path, or undefined if no alias exists */ static resolvePathAlias(aliasPath: string): string | undefined; /** * Checks if a change path matches an identifier, considering path aliases. * For example, if "editingNestedStep" is aliased to "routes[0].steps[0]", * then a change to "routes[0].steps[0].steps" should match "editingNestedStep.steps". * * @param changePath The path that was changed (e.g., "routes[0].steps[0].steps") * @param identifier The identifier to check (e.g., "editingNestedStep.steps") * @returns True if the change path matches the identifier */ static doesChangeMatchIdentifier(changePath: string, identifier: string): boolean; } export {};