event-emission 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -24
- package/dist/event-emission.d.ts +13 -14
- package/dist/event-emission.d.ts.map +1 -1
- package/dist/factory.d.ts +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/index.cjs +474 -285
- package/dist/index.cjs.map +8 -9
- package/dist/index.d.ts +1 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +449 -278
- package/dist/index.js.map +8 -9
- package/dist/interoperability.cjs +1605 -0
- package/dist/interoperability.cjs.map +15 -0
- package/dist/{interop.d.ts → interoperability.d.ts} +2 -1
- package/dist/interoperability.d.ts.map +1 -0
- package/dist/interoperability.js +1555 -0
- package/dist/interoperability.js.map +15 -0
- package/dist/observable.cjs +286 -0
- package/dist/observable.cjs.map +11 -0
- package/dist/observable.js +253 -0
- package/dist/observable.js.map +11 -0
- package/dist/observe.cjs +344 -0
- package/dist/observe.cjs.map +10 -0
- package/dist/observe.d.ts +6 -1
- package/dist/observe.d.ts.map +1 -1
- package/dist/observe.js +313 -0
- package/dist/observe.js.map +10 -0
- package/dist/symbols.d.ts +1 -1
- package/dist/types.cjs +35 -0
- package/dist/types.cjs.map +9 -0
- package/dist/types.d.ts +60 -25
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +9 -0
- package/package.json +25 -1
- package/src/event-emission.ts +26 -20
- package/src/factory.ts +538 -218
- package/src/index.ts +4 -33
- package/src/{interop.ts → interoperability.ts} +24 -6
- package/src/observe.ts +54 -17
- package/src/symbols.ts +1 -1
- package/src/types.ts +75 -30
- package/dist/interop.d.ts.map +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/observe.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/* eslint-disable @typescript-eslint/no-unsafe-assignment -- Proxy handlers require any spreads */\n/* eslint-disable @typescript-eslint/no-redundant-type-constituents -- Type unions are intentional for flexibility */\n\nimport type { EmissionEvent, EventTargetLike } from './types';\n\n// =============================================================================\n// DOM Type Stubs (for DOM-free environments)\n// =============================================================================\n\n/** Minimal EventTarget interface for duck-typing */\ninterface MinimalEventTarget {\n addEventListener(type: string, listener: (event: unknown) => void): void;\n removeEventListener(type: string, listener: (event: unknown) => void): void;\n dispatchEvent(event: unknown): boolean;\n}\n\n/** Minimal Event interface for forwarding */\ninterface MinimalEvent {\n type: string;\n}\n\n/** Minimal CustomEvent interface for forwarding */\ninterface MinimalCustomEvent extends MinimalEvent {\n detail?: unknown;\n}\n\n/** Type declaration for structuredClone (available in modern runtimes) */\ndeclare function structuredClone<T>(value: T): T;\n\n// =============================================================================\n// Symbols\n// =============================================================================\n\n/** Symbol marking an object as proxied */\nexport const PROXY_MARKER = Symbol.for('@lasercat/event-emission/proxy');\n\n/** Symbol to access the original unproxied target */\nexport const ORIGINAL_TARGET = Symbol.for('@lasercat/event-emission/original');\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Options for observable proxy creation */\nexport interface ObserveOptions {\n /** Enable deep observation of nested objects (default: true) */\n deep?: boolean;\n /** Clone strategy for previous state (default: 'path'); 'deep' uses structuredClone or deepClone */\n cloneStrategy?: 'shallow' | 'deep' | 'path';\n /** Optional deep clone fallback for runtimes without structuredClone */\n deepClone?: <T>(value: T) => T;\n}\n\n/** Event detail for property changes */\nexport interface PropertyChangeDetail<T = unknown> {\n /** The new value */\n value: T;\n /** Current state of the root object (after change) */\n current: unknown;\n /** Previous state of the root object (before change) */\n previous: unknown;\n}\n\n/** Array methods that mutate the array */\nexport type ArrayMutationMethod =\n | 'push'\n | 'pop'\n | 'shift'\n | 'unshift'\n | 'splice'\n | 'sort'\n | 'reverse'\n | 'fill'\n | 'copyWithin';\n\n/** Event detail for array mutations */\nexport interface ArrayMutationDetail<T = unknown> {\n /** The array method that was called */\n method: ArrayMutationMethod;\n /** Arguments passed to the method */\n args: unknown[];\n /** Return value of the method */\n result: unknown;\n /** Items that were added (if applicable) */\n added?: T[];\n /** Items that were removed (if applicable) */\n removed?: T[];\n /** Current state of the root object (after change) */\n current: unknown;\n /** Previous state of the root object (before change) */\n previous: unknown;\n}\n\n/** Event map for observable objects */\nexport type ObservableEventMap<_T extends object> = {\n update: PropertyChangeDetail;\n [key: `update:${string}`]: PropertyChangeDetail | ArrayMutationDetail;\n};\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst ARRAY_MUTATORS = new Set<ArrayMutationMethod>([\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse',\n 'fill',\n 'copyWithin',\n]);\n\n// =============================================================================\n// Internal Types\n// =============================================================================\n\ntype ResolvedObserveOptions = {\n deep: boolean;\n cloneStrategy: 'shallow' | 'deep' | 'path';\n deepClone?: ObserveOptions['deepClone'];\n};\n\ninterface ProxyContext<T extends object> {\n eventTarget: EventTargetLike<ObservableEventMap<T>>;\n /** Reference to the original (unproxied) root object for cloning */\n originalRoot: T;\n options: ResolvedObserveOptions;\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/** Check if a value can be proxied */\nfunction isProxyable(value: unknown): value is object {\n return (\n value !== null &&\n typeof value === 'object' &&\n !isProxied(value) &&\n !(value instanceof Date) &&\n !(value instanceof RegExp) &&\n !(value instanceof Map) &&\n !(value instanceof Set) &&\n !(value instanceof WeakMap) &&\n !(value instanceof WeakSet) &&\n !(value instanceof Promise) &&\n !(value instanceof Error) &&\n !(value instanceof ArrayBuffer) &&\n !ArrayBuffer.isView(value)\n );\n}\n\n/** Check if already proxied */\nfunction isProxied(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[PROXY_MARKER] === true\n );\n}\n\n/** Check if property is an array mutator */\nfunction isArrayMutator(prop: string | symbol): prop is ArrayMutationMethod {\n return typeof prop === 'string' && ARRAY_MUTATORS.has(prop as ArrayMutationMethod);\n}\n\n/** Clone along changed path for efficiency */\nfunction cloneAlongPath(obj: unknown, path?: string): unknown {\n const isArray = Array.isArray(obj);\n const rootClone = isArray\n ? [...(obj as unknown[])]\n : { ...(obj as Record<string, unknown>) };\n\n if (!path || isArray) {\n return rootClone;\n }\n\n const parts = path.split('.');\n\n const result = rootClone as Record<string, unknown>;\n\n let current: Record<string, unknown> = result;\n // Clone all objects along the path, INCLUDING the leaf\n for (let i = 0; i < parts.length; i++) {\n const key = parts[i];\n const value = current[key];\n if (value !== null && typeof value === 'object') {\n current[key] = Array.isArray(value) ? [...value] : { ...value };\n // Only traverse deeper if not the last element\n if (i < parts.length - 1) {\n current = current[key] as Record<string, unknown>;\n }\n } else {\n break;\n }\n }\n\n return result;\n}\n\n/** Clone for comparison based on strategy */\nfunction cloneForComparison(\n obj: unknown,\n strategy: 'shallow' | 'deep' | 'path',\n changedPath?: string,\n deepClone?: ObserveOptions['deepClone'],\n): unknown {\n if (obj === null || typeof obj !== 'object') return obj;\n\n switch (strategy) {\n case 'shallow':\n return Array.isArray(obj) ? [...obj] : { ...obj };\n\n case 'deep':\n if (deepClone) {\n return deepClone(obj);\n }\n if (typeof structuredClone !== 'function') {\n throw new Error(\n \"structuredClone is not available in this runtime; provide observe.deepClone, or use cloneStrategy 'path' or 'shallow'.\",\n );\n }\n return structuredClone(obj);\n\n case 'path':\n return cloneAlongPath(obj, changedPath);\n\n default:\n return obj;\n }\n}\n\n/** Compute array diff for mutation events */\nfunction computeArrayDiff(\n method: ArrayMutationMethod,\n before: unknown[],\n _after: unknown[],\n args: unknown[],\n): { added?: unknown[]; removed?: unknown[] } {\n switch (method) {\n case 'push':\n return { added: args };\n case 'pop':\n return { removed: before.length > 0 ? [before[before.length - 1]] : [] };\n case 'shift':\n return { removed: before.length > 0 ? [before[0]] : [] };\n case 'unshift':\n return { added: args };\n case 'splice': {\n const [start, deleteCount, ...items] = args as [number, number?, ...unknown[]];\n const actualStart =\n start < 0 ? Math.max(before.length + start, 0) : Math.min(start, before.length);\n const actualDeleteCount = Math.min(\n deleteCount ?? before.length - actualStart,\n before.length - actualStart,\n );\n return {\n removed: before.slice(actualStart, actualStart + actualDeleteCount),\n added: items,\n };\n }\n case 'sort':\n case 'reverse':\n case 'fill':\n case 'copyWithin':\n return {};\n default:\n return {};\n }\n}\n\n// =============================================================================\n// Proxy Registry (prevents duplicate proxying)\n// =============================================================================\n\n// Registry key combines target object with context to allow same object\n// to be observed in different contexts\nconst proxyRegistry = new WeakMap<\n object,\n WeakMap<ProxyContext<object>, { proxy: object; path: string }>\n>();\n\n/** Get or create proxy registry entry for a context */\nfunction getContextRegistry(\n target: object,\n): WeakMap<ProxyContext<object>, { proxy: object; path: string }> {\n let contextMap = proxyRegistry.get(target);\n if (!contextMap) {\n contextMap = new WeakMap();\n proxyRegistry.set(target, contextMap);\n }\n return contextMap;\n}\n\n// =============================================================================\n// Array Method Interceptor\n// =============================================================================\n\nfunction createArrayMethodInterceptor<T extends object>(\n array: unknown[],\n method: ArrayMutationMethod,\n path: string,\n context: ProxyContext<T>,\n): (...args: unknown[]) => unknown {\n const original = array[method as keyof typeof array] as (...args: unknown[]) => unknown;\n\n return function (this: unknown[], ...args: unknown[]): unknown {\n // Clone from original (unproxied) root BEFORE mutation\n const previousState = cloneForComparison(\n context.originalRoot,\n context.options.cloneStrategy,\n path,\n context.options.deepClone,\n );\n const previousItems = [...array];\n\n const result = original.apply(this, args);\n\n const { added, removed } = computeArrayDiff(method, previousItems, array, args);\n\n // Determine event path - for root arrays, avoid leading dot\n const methodEventPath = path ? `update:${path}.${method}` : `update:${method}`;\n const arrayEventPath = path ? `update:${path}` : 'update:';\n\n // Dispatch method-specific event\n context.eventTarget.dispatchEvent({\n type: methodEventPath as keyof ObservableEventMap<T> & string,\n detail: {\n method,\n args,\n result,\n added,\n removed,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n // Dispatch path event for the array itself (only if path is non-empty)\n if (path) {\n context.eventTarget.dispatchEvent({\n type: arrayEventPath as keyof ObservableEventMap<T> & string,\n detail: {\n value: array,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n }\n\n // Dispatch top-level update\n context.eventTarget.dispatchEvent({\n type: 'update' as keyof ObservableEventMap<T> & string,\n detail: {\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n return result;\n };\n}\n\n// =============================================================================\n// Core Proxy Creation\n// =============================================================================\n\nfunction createObservableProxyInternal<T extends object>(\n target: T,\n path: string,\n context: ProxyContext<T>,\n): T {\n // Check if this exact object is already proxied for this context\n const contextRegistry = getContextRegistry(target);\n const existing = contextRegistry.get(context as unknown as ProxyContext<object>);\n if (existing) {\n // Return existing proxy - note: shared objects will use the first path they were accessed from\n // This is intentional to avoid duplicate event dispatching\n return existing.proxy as T;\n }\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n // Handle internal markers\n if (prop === PROXY_MARKER) return true;\n if (prop === ORIGINAL_TARGET) return obj;\n\n // Pass through symbols\n if (typeof prop === 'symbol') {\n return Reflect.get(obj, prop, receiver);\n }\n\n const value = Reflect.get(obj, prop, receiver);\n\n // Intercept array mutating methods\n if (Array.isArray(obj) && isArrayMutator(prop)) {\n return createArrayMethodInterceptor(obj, prop, path, context);\n }\n\n // Lazy proxy nested objects/arrays\n if (context.options.deep && isProxyable(value)) {\n const nestedPath = path ? `${path}.${prop}` : prop;\n return createObservableProxyInternal(\n value as object,\n nestedPath,\n context as ProxyContext<object>,\n );\n }\n\n return value;\n },\n\n set(obj, prop, value, receiver) {\n // Pass through symbols\n if (typeof prop === 'symbol') {\n return Reflect.set(obj, prop, value, receiver);\n }\n\n const oldValue = Reflect.get(obj, prop, receiver);\n\n // Skip if value unchanged (shallow equality)\n if (Object.is(oldValue, value)) {\n return true;\n }\n\n // Capture previous state before mutation (from original, not proxy)\n const propPath = path ? `${path}.${prop}` : prop;\n const previousState = cloneForComparison(\n context.originalRoot,\n context.options.cloneStrategy,\n propPath,\n context.options.deepClone,\n );\n\n const success = Reflect.set(obj, prop, value, receiver);\n\n if (success) {\n // Dispatch path-specific event\n context.eventTarget.dispatchEvent({\n type: `update:${propPath}` as keyof ObservableEventMap<T> & string,\n detail: {\n value,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n // Dispatch top-level update event\n context.eventTarget.dispatchEvent({\n type: 'update' as keyof ObservableEventMap<T> & string,\n detail: {\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n }\n\n return success;\n },\n\n deleteProperty(obj, prop) {\n // Pass through symbols\n if (typeof prop === 'symbol') {\n return Reflect.deleteProperty(obj, prop);\n }\n\n const propPath = path ? `${path}.${String(prop)}` : String(prop);\n const previousState = cloneForComparison(\n context.originalRoot,\n context.options.cloneStrategy,\n propPath,\n context.options.deepClone,\n );\n\n const success = Reflect.deleteProperty(obj, prop);\n\n if (success) {\n // Dispatch path-specific event\n context.eventTarget.dispatchEvent({\n type: `update:${propPath}` as keyof ObservableEventMap<T> & string,\n detail: {\n value: undefined,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n // Dispatch top-level update event\n context.eventTarget.dispatchEvent({\n type: 'update' as keyof ObservableEventMap<T> & string,\n detail: {\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n }\n\n return success;\n },\n });\n\n // Register the proxy\n contextRegistry.set(context as unknown as ProxyContext<object>, {\n proxy,\n path,\n });\n\n return proxy;\n}\n\n// =============================================================================\n// EventTarget Forwarding\n// =============================================================================\n\n/** Duck-type check for EventTarget */\nfunction isEventTarget(obj: unknown): obj is MinimalEventTarget {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n typeof (obj as MinimalEventTarget).addEventListener === 'function' &&\n typeof (obj as MinimalEventTarget).removeEventListener === 'function' &&\n typeof (obj as MinimalEventTarget).dispatchEvent === 'function'\n );\n}\n\n/**\n * Sets up event forwarding from a source EventTarget to an EventEmission target.\n *\n * This function enables integration between DOM EventTargets and EventEmission targets.\n * When listeners are added to the target, corresponding forwarding handlers are\n * automatically registered on the source. Update events are not forwarded to\n * prevent circular event loops.\n *\n * @template T - The object type whose events are being forwarded.\n * @param source - The DOM EventTarget to forward events from.\n * @param target - The EventEmission target to forward events to.\n * @returns A cleanup function that removes all forwarding handlers when called.\n *\n * @example\n * ```typescript\n * const domElement = document.getElementById('my-element');\n * const events = createEventTarget<{ click: MouseEvent; focus: FocusEvent }>();\n *\n * const cleanup = setupEventForwarding(domElement, events);\n *\n * // When you add listeners to events, they will receive events from domElement\n * events.addEventListener('click', (event) => {\n * console.log('Click received via forwarding');\n * });\n *\n * // Stop forwarding when done\n * cleanup();\n * ```\n */\nexport function setupEventForwarding<T extends object>(\n source: MinimalEventTarget,\n target: EventTargetLike<ObservableEventMap<T>>,\n): () => void {\n const handlers = new Map<string, (event: unknown) => void>();\n const sourceAddEventListener = source.addEventListener.bind(source);\n const sourceRemoveEventListener = source.removeEventListener.bind(source);\n\n const forwardHandler = (type: string) => (event: unknown) => {\n const detail = (event as MinimalCustomEvent).detail ?? event;\n target.dispatchEvent({\n type: type as keyof ObservableEventMap<T> & string,\n detail,\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n };\n\n // Save original method reference without mutating target\n const originalAddEventListener = target.addEventListener.bind(target);\n\n // Create a wrapped addEventListener that also sets up forwarding\n const wrappedAddEventListener = ((\n type: string,\n listener: (event: EmissionEvent<unknown>) => void | Promise<void>,\n options?: unknown,\n ) => {\n // Forward non-update events from source (lazily, once per type)\n if (!handlers.has(type) && type !== 'update' && !type.startsWith('update:')) {\n const handler = forwardHandler(type);\n handlers.set(type, handler);\n sourceAddEventListener(type, handler);\n }\n return originalAddEventListener(\n type as keyof ObservableEventMap<T> & string,\n listener as (\n event: EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>,\n ) => void,\n options as Parameters<typeof originalAddEventListener>[2],\n );\n }) as typeof target.addEventListener;\n\n // Replace the addEventListener method\n (target as { addEventListener: typeof wrappedAddEventListener }).addEventListener =\n wrappedAddEventListener;\n\n return () => {\n // Restore original addEventListener\n (target as { addEventListener: typeof originalAddEventListener }).addEventListener =\n originalAddEventListener;\n // Clean up all forwarding handlers\n for (const [type, handler] of handlers) {\n sourceRemoveEventListener(type, handler);\n }\n handlers.clear();\n };\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Checks if an object is an observed proxy created by createObservableProxy.\n *\n * Use this to determine whether an object is being tracked for changes.\n * Useful for conditional logic or debugging.\n *\n * @param obj - The object to check.\n * @returns True if the object is an observed proxy, false otherwise.\n *\n * @example\n * ```typescript\n * const original = { count: 0 };\n * const state = createEventTarget(original, { observe: true });\n *\n * console.log(isObserved(original)); // false\n * console.log(isObserved(state)); // true\n * ```\n */\nexport function isObserved(obj: unknown): boolean {\n return isProxied(obj);\n}\n\n/**\n * Retrieves the original unproxied object from an observed proxy.\n *\n * When you pass an object to createEventTarget with observe: true, a Proxy\n * wrapper is created. This function returns the underlying original object,\n * which is useful when you need direct access without triggering events.\n *\n * @template T - The object type.\n * @param proxy - The observed proxy (or any object).\n * @returns The original unproxied object. If the input is not a proxy, returns it unchanged.\n *\n * @example\n * ```typescript\n * const original = { count: 0 };\n * const state = createEventTarget(original, { observe: true });\n *\n * // state is a Proxy wrapping original\n * const unwrapped = getOriginal(state);\n *\n * console.log(unwrapped === original); // true\n * console.log(unwrapped === state); // false\n * ```\n *\n * @example Passing to external APIs that don't work with Proxies\n * ```typescript\n * const data = createEventTarget({ items: [] }, { observe: true });\n *\n * // Some serialization libraries have issues with Proxies\n * const json = JSON.stringify(getOriginal(data));\n * ```\n */\nexport function getOriginal<T extends object>(proxy: T): T {\n if (!isProxied(proxy)) {\n return proxy;\n }\n return (proxy as Record<symbol, T>)[ORIGINAL_TARGET] ?? proxy;\n}\n\n/**\n * Creates an observable proxy that dispatches events when properties change.\n *\n * This function wraps an object in a Proxy that tracks all property modifications,\n * including nested objects and array mutations. Events are dispatched to the\n * provided event target for each change.\n *\n * If the target is an EventTarget, event forwarding is set up automatically and\n * cleaned up when the event target completes.\n *\n * Note: This is typically called internally by createEventTarget with observe: true.\n * You usually don't need to call this directly.\n *\n * @template T - The object type being observed.\n * @param target - The object to observe.\n * @param eventTarget - The event target to dispatch change events to.\n * @param options - Optional configuration for observation behavior.\n * @returns A proxied version of the target that dispatches events on changes.\n *\n * @example Direct usage (advanced)\n * ```typescript\n * import { createEventTarget, createObservableProxy } from 'event-emission';\n *\n * type State = { count: number };\n * const eventTarget = createEventTarget<ObservableEventMap<State>>();\n * const original = { count: 0 };\n *\n * const state = createObservableProxy(original, eventTarget, {\n * deep: true,\n * cloneStrategy: 'path',\n * });\n *\n * eventTarget.addEventListener('update', (event) => {\n * console.log('State changed:', event.detail);\n * });\n *\n * state.count = 1; // Triggers 'update' and 'update:count' events\n * ```\n *\n * @example Typical usage via createEventTarget\n * ```typescript\n * const state = createEventTarget({ count: 0 }, { observe: true });\n *\n * state.addEventListener('update:count', (event) => {\n * console.log('Count changed to:', event.detail.value);\n * });\n *\n * state.count = 1; // Triggers the event\n * ```\n */\nexport function createObservableProxy<T extends object>(\n target: T,\n eventTarget: EventTargetLike<ObservableEventMap<T>>,\n options?: ObserveOptions,\n): T {\n const resolvedOptions: ResolvedObserveOptions = {\n deep: options?.deep ?? true,\n cloneStrategy: options?.cloneStrategy ?? 'path',\n deepClone: options?.deepClone,\n };\n\n const context: ProxyContext<T> = {\n eventTarget,\n originalRoot: target, // Keep reference to original, never the proxy\n options: resolvedOptions,\n };\n\n const proxy = createObservableProxyInternal(target, '', context);\n\n // Set up event forwarding if target is already an EventTarget\n if (isEventTarget(target)) {\n const cleanupForwarding = setupEventForwarding(\n target as unknown as MinimalEventTarget,\n eventTarget,\n );\n const maybeComplete = (eventTarget as { complete?: () => void }).complete;\n if (typeof maybeComplete === 'function') {\n const originalComplete = maybeComplete.bind(eventTarget);\n let cleaned = false;\n (eventTarget as { complete: () => void }).complete = () => {\n if (!cleaned) {\n cleaned = true;\n cleanupForwarding();\n }\n return originalComplete();\n };\n }\n }\n\n return proxy;\n}\n\n/* eslint-enable @typescript-eslint/no-unsafe-assignment */\n/* eslint-enable @typescript-eslint/no-redundant-type-constituents */\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "A44AD03CF1F776F164756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/observe.d.ts
CHANGED
|
@@ -13,8 +13,10 @@ export declare const ORIGINAL_TARGET: unique symbol;
|
|
|
13
13
|
export interface ObserveOptions {
|
|
14
14
|
/** Enable deep observation of nested objects (default: true) */
|
|
15
15
|
deep?: boolean;
|
|
16
|
-
/** Clone strategy for previous state (default: 'path') */
|
|
16
|
+
/** Clone strategy for previous state (default: 'path'); 'deep' uses structuredClone or deepClone */
|
|
17
17
|
cloneStrategy?: 'shallow' | 'deep' | 'path';
|
|
18
|
+
/** Optional deep clone fallback for runtimes without structuredClone */
|
|
19
|
+
deepClone?: <T>(value: T) => T;
|
|
18
20
|
}
|
|
19
21
|
/** Event detail for property changes */
|
|
20
22
|
export interface PropertyChangeDetail<T = unknown> {
|
|
@@ -137,6 +139,9 @@ export declare function getOriginal<T extends object>(proxy: T): T;
|
|
|
137
139
|
* including nested objects and array mutations. Events are dispatched to the
|
|
138
140
|
* provided event target for each change.
|
|
139
141
|
*
|
|
142
|
+
* If the target is an EventTarget, event forwarding is set up automatically and
|
|
143
|
+
* cleaned up when the event target completes.
|
|
144
|
+
*
|
|
140
145
|
* Note: This is typically called internally by createEventTarget with observe: true.
|
|
141
146
|
* You usually don't need to call this directly.
|
|
142
147
|
*
|
package/dist/observe.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,SAAS,CAAC;AAM9D,oDAAoD;AACpD,UAAU,kBAAkB;IAC1B,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACzE,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5E,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACxC;AAmBD,0CAA0C;AAC1C,eAAO,MAAM,YAAY,eAA+C,CAAC;AAEzE,qDAAqD;AACrD,eAAO,MAAM,eAAe,eAAkD,CAAC;AAM/E,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"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"}
|
package/dist/observe.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/observe.ts
|
|
3
|
+
var PROXY_MARKER = Symbol.for("@lasercat/event-emission/proxy");
|
|
4
|
+
var ORIGINAL_TARGET = Symbol.for("@lasercat/event-emission/original");
|
|
5
|
+
var ARRAY_MUTATORS = new Set([
|
|
6
|
+
"push",
|
|
7
|
+
"pop",
|
|
8
|
+
"shift",
|
|
9
|
+
"unshift",
|
|
10
|
+
"splice",
|
|
11
|
+
"sort",
|
|
12
|
+
"reverse",
|
|
13
|
+
"fill",
|
|
14
|
+
"copyWithin"
|
|
15
|
+
]);
|
|
16
|
+
function isProxyable(value) {
|
|
17
|
+
return value !== null && typeof value === "object" && !isProxied(value) && !(value instanceof Date) && !(value instanceof RegExp) && !(value instanceof Map) && !(value instanceof Set) && !(value instanceof WeakMap) && !(value instanceof WeakSet) && !(value instanceof Promise) && !(value instanceof Error) && !(value instanceof ArrayBuffer) && !ArrayBuffer.isView(value);
|
|
18
|
+
}
|
|
19
|
+
function isProxied(value) {
|
|
20
|
+
return typeof value === "object" && value !== null && value[PROXY_MARKER] === true;
|
|
21
|
+
}
|
|
22
|
+
function isArrayMutator(prop) {
|
|
23
|
+
return typeof prop === "string" && ARRAY_MUTATORS.has(prop);
|
|
24
|
+
}
|
|
25
|
+
function cloneAlongPath(obj, path) {
|
|
26
|
+
const isArray = Array.isArray(obj);
|
|
27
|
+
const rootClone = isArray ? [...obj] : { ...obj };
|
|
28
|
+
if (!path || isArray) {
|
|
29
|
+
return rootClone;
|
|
30
|
+
}
|
|
31
|
+
const parts = path.split(".");
|
|
32
|
+
const result = rootClone;
|
|
33
|
+
let current = result;
|
|
34
|
+
for (let i = 0;i < parts.length; i++) {
|
|
35
|
+
const key = parts[i];
|
|
36
|
+
const value = current[key];
|
|
37
|
+
if (value !== null && typeof value === "object") {
|
|
38
|
+
current[key] = Array.isArray(value) ? [...value] : { ...value };
|
|
39
|
+
if (i < parts.length - 1) {
|
|
40
|
+
current = current[key];
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
function cloneForComparison(obj, strategy, changedPath, deepClone) {
|
|
49
|
+
if (obj === null || typeof obj !== "object")
|
|
50
|
+
return obj;
|
|
51
|
+
switch (strategy) {
|
|
52
|
+
case "shallow":
|
|
53
|
+
return Array.isArray(obj) ? [...obj] : { ...obj };
|
|
54
|
+
case "deep":
|
|
55
|
+
if (deepClone) {
|
|
56
|
+
return deepClone(obj);
|
|
57
|
+
}
|
|
58
|
+
if (typeof structuredClone !== "function") {
|
|
59
|
+
throw new Error("structuredClone is not available in this runtime; provide observe.deepClone, or use cloneStrategy 'path' or 'shallow'.");
|
|
60
|
+
}
|
|
61
|
+
return structuredClone(obj);
|
|
62
|
+
case "path":
|
|
63
|
+
return cloneAlongPath(obj, changedPath);
|
|
64
|
+
default:
|
|
65
|
+
return obj;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function computeArrayDiff(method, before, _after, args) {
|
|
69
|
+
switch (method) {
|
|
70
|
+
case "push":
|
|
71
|
+
return { added: args };
|
|
72
|
+
case "pop":
|
|
73
|
+
return { removed: before.length > 0 ? [before[before.length - 1]] : [] };
|
|
74
|
+
case "shift":
|
|
75
|
+
return { removed: before.length > 0 ? [before[0]] : [] };
|
|
76
|
+
case "unshift":
|
|
77
|
+
return { added: args };
|
|
78
|
+
case "splice": {
|
|
79
|
+
const [start, deleteCount, ...items] = args;
|
|
80
|
+
const actualStart = start < 0 ? Math.max(before.length + start, 0) : Math.min(start, before.length);
|
|
81
|
+
const actualDeleteCount = Math.min(deleteCount ?? before.length - actualStart, before.length - actualStart);
|
|
82
|
+
return {
|
|
83
|
+
removed: before.slice(actualStart, actualStart + actualDeleteCount),
|
|
84
|
+
added: items
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
case "sort":
|
|
88
|
+
case "reverse":
|
|
89
|
+
case "fill":
|
|
90
|
+
case "copyWithin":
|
|
91
|
+
return {};
|
|
92
|
+
default:
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
var proxyRegistry = new WeakMap;
|
|
97
|
+
function getContextRegistry(target) {
|
|
98
|
+
let contextMap = proxyRegistry.get(target);
|
|
99
|
+
if (!contextMap) {
|
|
100
|
+
contextMap = new WeakMap;
|
|
101
|
+
proxyRegistry.set(target, contextMap);
|
|
102
|
+
}
|
|
103
|
+
return contextMap;
|
|
104
|
+
}
|
|
105
|
+
function createArrayMethodInterceptor(array, method, path, context) {
|
|
106
|
+
const original = array[method];
|
|
107
|
+
return function(...args) {
|
|
108
|
+
const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, path, context.options.deepClone);
|
|
109
|
+
const previousItems = [...array];
|
|
110
|
+
const result = original.apply(this, args);
|
|
111
|
+
const { added, removed } = computeArrayDiff(method, previousItems, array, args);
|
|
112
|
+
const methodEventPath = path ? `update:${path}.${method}` : `update:${method}`;
|
|
113
|
+
const arrayEventPath = path ? `update:${path}` : "update:";
|
|
114
|
+
context.eventTarget.dispatchEvent({
|
|
115
|
+
type: methodEventPath,
|
|
116
|
+
detail: {
|
|
117
|
+
method,
|
|
118
|
+
args,
|
|
119
|
+
result,
|
|
120
|
+
added,
|
|
121
|
+
removed,
|
|
122
|
+
current: context.originalRoot,
|
|
123
|
+
previous: previousState
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
if (path) {
|
|
127
|
+
context.eventTarget.dispatchEvent({
|
|
128
|
+
type: arrayEventPath,
|
|
129
|
+
detail: {
|
|
130
|
+
value: array,
|
|
131
|
+
current: context.originalRoot,
|
|
132
|
+
previous: previousState
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
context.eventTarget.dispatchEvent({
|
|
137
|
+
type: "update",
|
|
138
|
+
detail: {
|
|
139
|
+
current: context.originalRoot,
|
|
140
|
+
previous: previousState
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return result;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function createObservableProxyInternal(target, path, context) {
|
|
147
|
+
const contextRegistry = getContextRegistry(target);
|
|
148
|
+
const existing = contextRegistry.get(context);
|
|
149
|
+
if (existing) {
|
|
150
|
+
return existing.proxy;
|
|
151
|
+
}
|
|
152
|
+
const proxy = new Proxy(target, {
|
|
153
|
+
get(obj, prop, receiver) {
|
|
154
|
+
if (prop === PROXY_MARKER)
|
|
155
|
+
return true;
|
|
156
|
+
if (prop === ORIGINAL_TARGET)
|
|
157
|
+
return obj;
|
|
158
|
+
if (typeof prop === "symbol") {
|
|
159
|
+
return Reflect.get(obj, prop, receiver);
|
|
160
|
+
}
|
|
161
|
+
const value = Reflect.get(obj, prop, receiver);
|
|
162
|
+
if (Array.isArray(obj) && isArrayMutator(prop)) {
|
|
163
|
+
return createArrayMethodInterceptor(obj, prop, path, context);
|
|
164
|
+
}
|
|
165
|
+
if (context.options.deep && isProxyable(value)) {
|
|
166
|
+
const nestedPath = path ? `${path}.${prop}` : prop;
|
|
167
|
+
return createObservableProxyInternal(value, nestedPath, context);
|
|
168
|
+
}
|
|
169
|
+
return value;
|
|
170
|
+
},
|
|
171
|
+
set(obj, prop, value, receiver) {
|
|
172
|
+
if (typeof prop === "symbol") {
|
|
173
|
+
return Reflect.set(obj, prop, value, receiver);
|
|
174
|
+
}
|
|
175
|
+
const oldValue = Reflect.get(obj, prop, receiver);
|
|
176
|
+
if (Object.is(oldValue, value)) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
const propPath = path ? `${path}.${prop}` : prop;
|
|
180
|
+
const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, propPath, context.options.deepClone);
|
|
181
|
+
const success = Reflect.set(obj, prop, value, receiver);
|
|
182
|
+
if (success) {
|
|
183
|
+
context.eventTarget.dispatchEvent({
|
|
184
|
+
type: `update:${propPath}`,
|
|
185
|
+
detail: {
|
|
186
|
+
value,
|
|
187
|
+
current: context.originalRoot,
|
|
188
|
+
previous: previousState
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
context.eventTarget.dispatchEvent({
|
|
192
|
+
type: "update",
|
|
193
|
+
detail: {
|
|
194
|
+
current: context.originalRoot,
|
|
195
|
+
previous: previousState
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return success;
|
|
200
|
+
},
|
|
201
|
+
deleteProperty(obj, prop) {
|
|
202
|
+
if (typeof prop === "symbol") {
|
|
203
|
+
return Reflect.deleteProperty(obj, prop);
|
|
204
|
+
}
|
|
205
|
+
const propPath = path ? `${path}.${String(prop)}` : String(prop);
|
|
206
|
+
const previousState = cloneForComparison(context.originalRoot, context.options.cloneStrategy, propPath, context.options.deepClone);
|
|
207
|
+
const success = Reflect.deleteProperty(obj, prop);
|
|
208
|
+
if (success) {
|
|
209
|
+
context.eventTarget.dispatchEvent({
|
|
210
|
+
type: `update:${propPath}`,
|
|
211
|
+
detail: {
|
|
212
|
+
value: undefined,
|
|
213
|
+
current: context.originalRoot,
|
|
214
|
+
previous: previousState
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
context.eventTarget.dispatchEvent({
|
|
218
|
+
type: "update",
|
|
219
|
+
detail: {
|
|
220
|
+
current: context.originalRoot,
|
|
221
|
+
previous: previousState
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return success;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
contextRegistry.set(context, {
|
|
229
|
+
proxy,
|
|
230
|
+
path
|
|
231
|
+
});
|
|
232
|
+
return proxy;
|
|
233
|
+
}
|
|
234
|
+
function isEventTarget(obj) {
|
|
235
|
+
return typeof obj === "object" && obj !== null && typeof obj.addEventListener === "function" && typeof obj.removeEventListener === "function" && typeof obj.dispatchEvent === "function";
|
|
236
|
+
}
|
|
237
|
+
function setupEventForwarding(source, target) {
|
|
238
|
+
const handlers = new Map;
|
|
239
|
+
const sourceAddEventListener = source.addEventListener.bind(source);
|
|
240
|
+
const sourceRemoveEventListener = source.removeEventListener.bind(source);
|
|
241
|
+
const forwardHandler = (type) => (event) => {
|
|
242
|
+
const detail = event.detail ?? event;
|
|
243
|
+
target.dispatchEvent({
|
|
244
|
+
type,
|
|
245
|
+
detail
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
const originalAddEventListener = target.addEventListener.bind(target);
|
|
249
|
+
const wrappedAddEventListener = (type, listener, options) => {
|
|
250
|
+
if (!handlers.has(type) && type !== "update" && !type.startsWith("update:")) {
|
|
251
|
+
const handler = forwardHandler(type);
|
|
252
|
+
handlers.set(type, handler);
|
|
253
|
+
sourceAddEventListener(type, handler);
|
|
254
|
+
}
|
|
255
|
+
return originalAddEventListener(type, listener, options);
|
|
256
|
+
};
|
|
257
|
+
target.addEventListener = wrappedAddEventListener;
|
|
258
|
+
return () => {
|
|
259
|
+
target.addEventListener = originalAddEventListener;
|
|
260
|
+
for (const [type, handler] of handlers) {
|
|
261
|
+
sourceRemoveEventListener(type, handler);
|
|
262
|
+
}
|
|
263
|
+
handlers.clear();
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function isObserved(obj) {
|
|
267
|
+
return isProxied(obj);
|
|
268
|
+
}
|
|
269
|
+
function getOriginal(proxy) {
|
|
270
|
+
if (!isProxied(proxy)) {
|
|
271
|
+
return proxy;
|
|
272
|
+
}
|
|
273
|
+
return proxy[ORIGINAL_TARGET] ?? proxy;
|
|
274
|
+
}
|
|
275
|
+
function createObservableProxy(target, eventTarget, options) {
|
|
276
|
+
const resolvedOptions = {
|
|
277
|
+
deep: options?.deep ?? true,
|
|
278
|
+
cloneStrategy: options?.cloneStrategy ?? "path",
|
|
279
|
+
deepClone: options?.deepClone
|
|
280
|
+
};
|
|
281
|
+
const context = {
|
|
282
|
+
eventTarget,
|
|
283
|
+
originalRoot: target,
|
|
284
|
+
options: resolvedOptions
|
|
285
|
+
};
|
|
286
|
+
const proxy = createObservableProxyInternal(target, "", context);
|
|
287
|
+
if (isEventTarget(target)) {
|
|
288
|
+
const cleanupForwarding = setupEventForwarding(target, eventTarget);
|
|
289
|
+
const maybeComplete = eventTarget.complete;
|
|
290
|
+
if (typeof maybeComplete === "function") {
|
|
291
|
+
const originalComplete = maybeComplete.bind(eventTarget);
|
|
292
|
+
let cleaned = false;
|
|
293
|
+
eventTarget.complete = () => {
|
|
294
|
+
if (!cleaned) {
|
|
295
|
+
cleaned = true;
|
|
296
|
+
cleanupForwarding();
|
|
297
|
+
}
|
|
298
|
+
return originalComplete();
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return proxy;
|
|
303
|
+
}
|
|
304
|
+
export {
|
|
305
|
+
setupEventForwarding,
|
|
306
|
+
isObserved,
|
|
307
|
+
getOriginal,
|
|
308
|
+
createObservableProxy,
|
|
309
|
+
PROXY_MARKER,
|
|
310
|
+
ORIGINAL_TARGET
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
//# debugId=54B6DC0E6217D6F464756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/observe.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/* eslint-disable @typescript-eslint/no-unsafe-assignment -- Proxy handlers require any spreads */\n/* eslint-disable @typescript-eslint/no-redundant-type-constituents -- Type unions are intentional for flexibility */\n\nimport type { EmissionEvent, EventTargetLike } from './types';\n\n// =============================================================================\n// DOM Type Stubs (for DOM-free environments)\n// =============================================================================\n\n/** Minimal EventTarget interface for duck-typing */\ninterface MinimalEventTarget {\n addEventListener(type: string, listener: (event: unknown) => void): void;\n removeEventListener(type: string, listener: (event: unknown) => void): void;\n dispatchEvent(event: unknown): boolean;\n}\n\n/** Minimal Event interface for forwarding */\ninterface MinimalEvent {\n type: string;\n}\n\n/** Minimal CustomEvent interface for forwarding */\ninterface MinimalCustomEvent extends MinimalEvent {\n detail?: unknown;\n}\n\n/** Type declaration for structuredClone (available in modern runtimes) */\ndeclare function structuredClone<T>(value: T): T;\n\n// =============================================================================\n// Symbols\n// =============================================================================\n\n/** Symbol marking an object as proxied */\nexport const PROXY_MARKER = Symbol.for('@lasercat/event-emission/proxy');\n\n/** Symbol to access the original unproxied target */\nexport const ORIGINAL_TARGET = Symbol.for('@lasercat/event-emission/original');\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Options for observable proxy creation */\nexport interface ObserveOptions {\n /** Enable deep observation of nested objects (default: true) */\n deep?: boolean;\n /** Clone strategy for previous state (default: 'path'); 'deep' uses structuredClone or deepClone */\n cloneStrategy?: 'shallow' | 'deep' | 'path';\n /** Optional deep clone fallback for runtimes without structuredClone */\n deepClone?: <T>(value: T) => T;\n}\n\n/** Event detail for property changes */\nexport interface PropertyChangeDetail<T = unknown> {\n /** The new value */\n value: T;\n /** Current state of the root object (after change) */\n current: unknown;\n /** Previous state of the root object (before change) */\n previous: unknown;\n}\n\n/** Array methods that mutate the array */\nexport type ArrayMutationMethod =\n | 'push'\n | 'pop'\n | 'shift'\n | 'unshift'\n | 'splice'\n | 'sort'\n | 'reverse'\n | 'fill'\n | 'copyWithin';\n\n/** Event detail for array mutations */\nexport interface ArrayMutationDetail<T = unknown> {\n /** The array method that was called */\n method: ArrayMutationMethod;\n /** Arguments passed to the method */\n args: unknown[];\n /** Return value of the method */\n result: unknown;\n /** Items that were added (if applicable) */\n added?: T[];\n /** Items that were removed (if applicable) */\n removed?: T[];\n /** Current state of the root object (after change) */\n current: unknown;\n /** Previous state of the root object (before change) */\n previous: unknown;\n}\n\n/** Event map for observable objects */\nexport type ObservableEventMap<_T extends object> = {\n update: PropertyChangeDetail;\n [key: `update:${string}`]: PropertyChangeDetail | ArrayMutationDetail;\n};\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst ARRAY_MUTATORS = new Set<ArrayMutationMethod>([\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse',\n 'fill',\n 'copyWithin',\n]);\n\n// =============================================================================\n// Internal Types\n// =============================================================================\n\ntype ResolvedObserveOptions = {\n deep: boolean;\n cloneStrategy: 'shallow' | 'deep' | 'path';\n deepClone?: ObserveOptions['deepClone'];\n};\n\ninterface ProxyContext<T extends object> {\n eventTarget: EventTargetLike<ObservableEventMap<T>>;\n /** Reference to the original (unproxied) root object for cloning */\n originalRoot: T;\n options: ResolvedObserveOptions;\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/** Check if a value can be proxied */\nfunction isProxyable(value: unknown): value is object {\n return (\n value !== null &&\n typeof value === 'object' &&\n !isProxied(value) &&\n !(value instanceof Date) &&\n !(value instanceof RegExp) &&\n !(value instanceof Map) &&\n !(value instanceof Set) &&\n !(value instanceof WeakMap) &&\n !(value instanceof WeakSet) &&\n !(value instanceof Promise) &&\n !(value instanceof Error) &&\n !(value instanceof ArrayBuffer) &&\n !ArrayBuffer.isView(value)\n );\n}\n\n/** Check if already proxied */\nfunction isProxied(value: unknown): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<symbol, unknown>)[PROXY_MARKER] === true\n );\n}\n\n/** Check if property is an array mutator */\nfunction isArrayMutator(prop: string | symbol): prop is ArrayMutationMethod {\n return typeof prop === 'string' && ARRAY_MUTATORS.has(prop as ArrayMutationMethod);\n}\n\n/** Clone along changed path for efficiency */\nfunction cloneAlongPath(obj: unknown, path?: string): unknown {\n const isArray = Array.isArray(obj);\n const rootClone = isArray\n ? [...(obj as unknown[])]\n : { ...(obj as Record<string, unknown>) };\n\n if (!path || isArray) {\n return rootClone;\n }\n\n const parts = path.split('.');\n\n const result = rootClone as Record<string, unknown>;\n\n let current: Record<string, unknown> = result;\n // Clone all objects along the path, INCLUDING the leaf\n for (let i = 0; i < parts.length; i++) {\n const key = parts[i];\n const value = current[key];\n if (value !== null && typeof value === 'object') {\n current[key] = Array.isArray(value) ? [...value] : { ...value };\n // Only traverse deeper if not the last element\n if (i < parts.length - 1) {\n current = current[key] as Record<string, unknown>;\n }\n } else {\n break;\n }\n }\n\n return result;\n}\n\n/** Clone for comparison based on strategy */\nfunction cloneForComparison(\n obj: unknown,\n strategy: 'shallow' | 'deep' | 'path',\n changedPath?: string,\n deepClone?: ObserveOptions['deepClone'],\n): unknown {\n if (obj === null || typeof obj !== 'object') return obj;\n\n switch (strategy) {\n case 'shallow':\n return Array.isArray(obj) ? [...obj] : { ...obj };\n\n case 'deep':\n if (deepClone) {\n return deepClone(obj);\n }\n if (typeof structuredClone !== 'function') {\n throw new Error(\n \"structuredClone is not available in this runtime; provide observe.deepClone, or use cloneStrategy 'path' or 'shallow'.\",\n );\n }\n return structuredClone(obj);\n\n case 'path':\n return cloneAlongPath(obj, changedPath);\n\n default:\n return obj;\n }\n}\n\n/** Compute array diff for mutation events */\nfunction computeArrayDiff(\n method: ArrayMutationMethod,\n before: unknown[],\n _after: unknown[],\n args: unknown[],\n): { added?: unknown[]; removed?: unknown[] } {\n switch (method) {\n case 'push':\n return { added: args };\n case 'pop':\n return { removed: before.length > 0 ? [before[before.length - 1]] : [] };\n case 'shift':\n return { removed: before.length > 0 ? [before[0]] : [] };\n case 'unshift':\n return { added: args };\n case 'splice': {\n const [start, deleteCount, ...items] = args as [number, number?, ...unknown[]];\n const actualStart =\n start < 0 ? Math.max(before.length + start, 0) : Math.min(start, before.length);\n const actualDeleteCount = Math.min(\n deleteCount ?? before.length - actualStart,\n before.length - actualStart,\n );\n return {\n removed: before.slice(actualStart, actualStart + actualDeleteCount),\n added: items,\n };\n }\n case 'sort':\n case 'reverse':\n case 'fill':\n case 'copyWithin':\n return {};\n default:\n return {};\n }\n}\n\n// =============================================================================\n// Proxy Registry (prevents duplicate proxying)\n// =============================================================================\n\n// Registry key combines target object with context to allow same object\n// to be observed in different contexts\nconst proxyRegistry = new WeakMap<\n object,\n WeakMap<ProxyContext<object>, { proxy: object; path: string }>\n>();\n\n/** Get or create proxy registry entry for a context */\nfunction getContextRegistry(\n target: object,\n): WeakMap<ProxyContext<object>, { proxy: object; path: string }> {\n let contextMap = proxyRegistry.get(target);\n if (!contextMap) {\n contextMap = new WeakMap();\n proxyRegistry.set(target, contextMap);\n }\n return contextMap;\n}\n\n// =============================================================================\n// Array Method Interceptor\n// =============================================================================\n\nfunction createArrayMethodInterceptor<T extends object>(\n array: unknown[],\n method: ArrayMutationMethod,\n path: string,\n context: ProxyContext<T>,\n): (...args: unknown[]) => unknown {\n const original = array[method as keyof typeof array] as (...args: unknown[]) => unknown;\n\n return function (this: unknown[], ...args: unknown[]): unknown {\n // Clone from original (unproxied) root BEFORE mutation\n const previousState = cloneForComparison(\n context.originalRoot,\n context.options.cloneStrategy,\n path,\n context.options.deepClone,\n );\n const previousItems = [...array];\n\n const result = original.apply(this, args);\n\n const { added, removed } = computeArrayDiff(method, previousItems, array, args);\n\n // Determine event path - for root arrays, avoid leading dot\n const methodEventPath = path ? `update:${path}.${method}` : `update:${method}`;\n const arrayEventPath = path ? `update:${path}` : 'update:';\n\n // Dispatch method-specific event\n context.eventTarget.dispatchEvent({\n type: methodEventPath as keyof ObservableEventMap<T> & string,\n detail: {\n method,\n args,\n result,\n added,\n removed,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n // Dispatch path event for the array itself (only if path is non-empty)\n if (path) {\n context.eventTarget.dispatchEvent({\n type: arrayEventPath as keyof ObservableEventMap<T> & string,\n detail: {\n value: array,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n }\n\n // Dispatch top-level update\n context.eventTarget.dispatchEvent({\n type: 'update' as keyof ObservableEventMap<T> & string,\n detail: {\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n return result;\n };\n}\n\n// =============================================================================\n// Core Proxy Creation\n// =============================================================================\n\nfunction createObservableProxyInternal<T extends object>(\n target: T,\n path: string,\n context: ProxyContext<T>,\n): T {\n // Check if this exact object is already proxied for this context\n const contextRegistry = getContextRegistry(target);\n const existing = contextRegistry.get(context as unknown as ProxyContext<object>);\n if (existing) {\n // Return existing proxy - note: shared objects will use the first path they were accessed from\n // This is intentional to avoid duplicate event dispatching\n return existing.proxy as T;\n }\n\n const proxy = new Proxy(target, {\n get(obj, prop, receiver) {\n // Handle internal markers\n if (prop === PROXY_MARKER) return true;\n if (prop === ORIGINAL_TARGET) return obj;\n\n // Pass through symbols\n if (typeof prop === 'symbol') {\n return Reflect.get(obj, prop, receiver);\n }\n\n const value = Reflect.get(obj, prop, receiver);\n\n // Intercept array mutating methods\n if (Array.isArray(obj) && isArrayMutator(prop)) {\n return createArrayMethodInterceptor(obj, prop, path, context);\n }\n\n // Lazy proxy nested objects/arrays\n if (context.options.deep && isProxyable(value)) {\n const nestedPath = path ? `${path}.${prop}` : prop;\n return createObservableProxyInternal(\n value as object,\n nestedPath,\n context as ProxyContext<object>,\n );\n }\n\n return value;\n },\n\n set(obj, prop, value, receiver) {\n // Pass through symbols\n if (typeof prop === 'symbol') {\n return Reflect.set(obj, prop, value, receiver);\n }\n\n const oldValue = Reflect.get(obj, prop, receiver);\n\n // Skip if value unchanged (shallow equality)\n if (Object.is(oldValue, value)) {\n return true;\n }\n\n // Capture previous state before mutation (from original, not proxy)\n const propPath = path ? `${path}.${prop}` : prop;\n const previousState = cloneForComparison(\n context.originalRoot,\n context.options.cloneStrategy,\n propPath,\n context.options.deepClone,\n );\n\n const success = Reflect.set(obj, prop, value, receiver);\n\n if (success) {\n // Dispatch path-specific event\n context.eventTarget.dispatchEvent({\n type: `update:${propPath}` as keyof ObservableEventMap<T> & string,\n detail: {\n value,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n // Dispatch top-level update event\n context.eventTarget.dispatchEvent({\n type: 'update' as keyof ObservableEventMap<T> & string,\n detail: {\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n }\n\n return success;\n },\n\n deleteProperty(obj, prop) {\n // Pass through symbols\n if (typeof prop === 'symbol') {\n return Reflect.deleteProperty(obj, prop);\n }\n\n const propPath = path ? `${path}.${String(prop)}` : String(prop);\n const previousState = cloneForComparison(\n context.originalRoot,\n context.options.cloneStrategy,\n propPath,\n context.options.deepClone,\n );\n\n const success = Reflect.deleteProperty(obj, prop);\n\n if (success) {\n // Dispatch path-specific event\n context.eventTarget.dispatchEvent({\n type: `update:${propPath}` as keyof ObservableEventMap<T> & string,\n detail: {\n value: undefined,\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n\n // Dispatch top-level update event\n context.eventTarget.dispatchEvent({\n type: 'update' as keyof ObservableEventMap<T> & string,\n detail: {\n current: context.originalRoot,\n previous: previousState,\n },\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n }\n\n return success;\n },\n });\n\n // Register the proxy\n contextRegistry.set(context as unknown as ProxyContext<object>, {\n proxy,\n path,\n });\n\n return proxy;\n}\n\n// =============================================================================\n// EventTarget Forwarding\n// =============================================================================\n\n/** Duck-type check for EventTarget */\nfunction isEventTarget(obj: unknown): obj is MinimalEventTarget {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n typeof (obj as MinimalEventTarget).addEventListener === 'function' &&\n typeof (obj as MinimalEventTarget).removeEventListener === 'function' &&\n typeof (obj as MinimalEventTarget).dispatchEvent === 'function'\n );\n}\n\n/**\n * Sets up event forwarding from a source EventTarget to an EventEmission target.\n *\n * This function enables integration between DOM EventTargets and EventEmission targets.\n * When listeners are added to the target, corresponding forwarding handlers are\n * automatically registered on the source. Update events are not forwarded to\n * prevent circular event loops.\n *\n * @template T - The object type whose events are being forwarded.\n * @param source - The DOM EventTarget to forward events from.\n * @param target - The EventEmission target to forward events to.\n * @returns A cleanup function that removes all forwarding handlers when called.\n *\n * @example\n * ```typescript\n * const domElement = document.getElementById('my-element');\n * const events = createEventTarget<{ click: MouseEvent; focus: FocusEvent }>();\n *\n * const cleanup = setupEventForwarding(domElement, events);\n *\n * // When you add listeners to events, they will receive events from domElement\n * events.addEventListener('click', (event) => {\n * console.log('Click received via forwarding');\n * });\n *\n * // Stop forwarding when done\n * cleanup();\n * ```\n */\nexport function setupEventForwarding<T extends object>(\n source: MinimalEventTarget,\n target: EventTargetLike<ObservableEventMap<T>>,\n): () => void {\n const handlers = new Map<string, (event: unknown) => void>();\n const sourceAddEventListener = source.addEventListener.bind(source);\n const sourceRemoveEventListener = source.removeEventListener.bind(source);\n\n const forwardHandler = (type: string) => (event: unknown) => {\n const detail = (event as MinimalCustomEvent).detail ?? event;\n target.dispatchEvent({\n type: type as keyof ObservableEventMap<T> & string,\n detail,\n } as EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>);\n };\n\n // Save original method reference without mutating target\n const originalAddEventListener = target.addEventListener.bind(target);\n\n // Create a wrapped addEventListener that also sets up forwarding\n const wrappedAddEventListener = ((\n type: string,\n listener: (event: EmissionEvent<unknown>) => void | Promise<void>,\n options?: unknown,\n ) => {\n // Forward non-update events from source (lazily, once per type)\n if (!handlers.has(type) && type !== 'update' && !type.startsWith('update:')) {\n const handler = forwardHandler(type);\n handlers.set(type, handler);\n sourceAddEventListener(type, handler);\n }\n return originalAddEventListener(\n type as keyof ObservableEventMap<T> & string,\n listener as (\n event: EmissionEvent<ObservableEventMap<T>[keyof ObservableEventMap<T>]>,\n ) => void,\n options as Parameters<typeof originalAddEventListener>[2],\n );\n }) as typeof target.addEventListener;\n\n // Replace the addEventListener method\n (target as { addEventListener: typeof wrappedAddEventListener }).addEventListener =\n wrappedAddEventListener;\n\n return () => {\n // Restore original addEventListener\n (target as { addEventListener: typeof originalAddEventListener }).addEventListener =\n originalAddEventListener;\n // Clean up all forwarding handlers\n for (const [type, handler] of handlers) {\n sourceRemoveEventListener(type, handler);\n }\n handlers.clear();\n };\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Checks if an object is an observed proxy created by createObservableProxy.\n *\n * Use this to determine whether an object is being tracked for changes.\n * Useful for conditional logic or debugging.\n *\n * @param obj - The object to check.\n * @returns True if the object is an observed proxy, false otherwise.\n *\n * @example\n * ```typescript\n * const original = { count: 0 };\n * const state = createEventTarget(original, { observe: true });\n *\n * console.log(isObserved(original)); // false\n * console.log(isObserved(state)); // true\n * ```\n */\nexport function isObserved(obj: unknown): boolean {\n return isProxied(obj);\n}\n\n/**\n * Retrieves the original unproxied object from an observed proxy.\n *\n * When you pass an object to createEventTarget with observe: true, a Proxy\n * wrapper is created. This function returns the underlying original object,\n * which is useful when you need direct access without triggering events.\n *\n * @template T - The object type.\n * @param proxy - The observed proxy (or any object).\n * @returns The original unproxied object. If the input is not a proxy, returns it unchanged.\n *\n * @example\n * ```typescript\n * const original = { count: 0 };\n * const state = createEventTarget(original, { observe: true });\n *\n * // state is a Proxy wrapping original\n * const unwrapped = getOriginal(state);\n *\n * console.log(unwrapped === original); // true\n * console.log(unwrapped === state); // false\n * ```\n *\n * @example Passing to external APIs that don't work with Proxies\n * ```typescript\n * const data = createEventTarget({ items: [] }, { observe: true });\n *\n * // Some serialization libraries have issues with Proxies\n * const json = JSON.stringify(getOriginal(data));\n * ```\n */\nexport function getOriginal<T extends object>(proxy: T): T {\n if (!isProxied(proxy)) {\n return proxy;\n }\n return (proxy as Record<symbol, T>)[ORIGINAL_TARGET] ?? proxy;\n}\n\n/**\n * Creates an observable proxy that dispatches events when properties change.\n *\n * This function wraps an object in a Proxy that tracks all property modifications,\n * including nested objects and array mutations. Events are dispatched to the\n * provided event target for each change.\n *\n * If the target is an EventTarget, event forwarding is set up automatically and\n * cleaned up when the event target completes.\n *\n * Note: This is typically called internally by createEventTarget with observe: true.\n * You usually don't need to call this directly.\n *\n * @template T - The object type being observed.\n * @param target - The object to observe.\n * @param eventTarget - The event target to dispatch change events to.\n * @param options - Optional configuration for observation behavior.\n * @returns A proxied version of the target that dispatches events on changes.\n *\n * @example Direct usage (advanced)\n * ```typescript\n * import { createEventTarget, createObservableProxy } from 'event-emission';\n *\n * type State = { count: number };\n * const eventTarget = createEventTarget<ObservableEventMap<State>>();\n * const original = { count: 0 };\n *\n * const state = createObservableProxy(original, eventTarget, {\n * deep: true,\n * cloneStrategy: 'path',\n * });\n *\n * eventTarget.addEventListener('update', (event) => {\n * console.log('State changed:', event.detail);\n * });\n *\n * state.count = 1; // Triggers 'update' and 'update:count' events\n * ```\n *\n * @example Typical usage via createEventTarget\n * ```typescript\n * const state = createEventTarget({ count: 0 }, { observe: true });\n *\n * state.addEventListener('update:count', (event) => {\n * console.log('Count changed to:', event.detail.value);\n * });\n *\n * state.count = 1; // Triggers the event\n * ```\n */\nexport function createObservableProxy<T extends object>(\n target: T,\n eventTarget: EventTargetLike<ObservableEventMap<T>>,\n options?: ObserveOptions,\n): T {\n const resolvedOptions: ResolvedObserveOptions = {\n deep: options?.deep ?? true,\n cloneStrategy: options?.cloneStrategy ?? 'path',\n deepClone: options?.deepClone,\n };\n\n const context: ProxyContext<T> = {\n eventTarget,\n originalRoot: target, // Keep reference to original, never the proxy\n options: resolvedOptions,\n };\n\n const proxy = createObservableProxyInternal(target, '', context);\n\n // Set up event forwarding if target is already an EventTarget\n if (isEventTarget(target)) {\n const cleanupForwarding = setupEventForwarding(\n target as unknown as MinimalEventTarget,\n eventTarget,\n );\n const maybeComplete = (eventTarget as { complete?: () => void }).complete;\n if (typeof maybeComplete === 'function') {\n const originalComplete = maybeComplete.bind(eventTarget);\n let cleaned = false;\n (eventTarget as { complete: () => void }).complete = () => {\n if (!cleaned) {\n cleaned = true;\n cleanupForwarding();\n }\n return originalComplete();\n };\n }\n }\n\n return proxy;\n}\n\n/* eslint-enable @typescript-eslint/no-unsafe-assignment */\n/* eslint-enable @typescript-eslint/no-redundant-type-constituents */\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "54B6DC0E6217D6F464756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/symbols.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Symbol.observable polyfill for TC39 Observable
|
|
2
|
+
* Symbol.observable polyfill for TC39 Observable interoperability.
|
|
3
3
|
* This ensures the symbol exists even in environments that don't support it natively.
|
|
4
4
|
*/
|
|
5
5
|
export declare const SymbolObservable: symbol;
|
package/dist/types.cjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// src/types.ts
|
|
31
|
+
var exports_types = {};
|
|
32
|
+
module.exports = __toCommonJS(exports_types);
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
//# debugId=23C407FF9687AF9A64756E2164756E21
|