(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('proxy-compare')) : typeof define === 'function' && define.amd ? define(['exports', 'proxy-compare'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.valtioVanilla = {}, global.proxyCompare)); })(this, (function (exports, proxyCompare) { 'use strict'; var isObject = function isObject(x) { return typeof x === 'object' && x !== null; }; var proxyStateMap = new WeakMap(); var refSet = new WeakSet(); var buildProxyFunction = function buildProxyFunction(objectIs, newProxy, canProxy, defaultHandlePromise, snapCache, createSnapshot, proxyCache, versionHolder, _proxyFunction) { if (objectIs === void 0) { objectIs = Object.is; } if (newProxy === void 0) { newProxy = function newProxy(target, handler) { return new Proxy(target, handler); }; } if (canProxy === void 0) { canProxy = function canProxy(x) { return isObject(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer); }; } if (defaultHandlePromise === void 0) { defaultHandlePromise = function defaultHandlePromise(promise) { switch (promise.status) { case 'fulfilled': return promise.value; case 'rejected': throw promise.reason; default: throw promise; } }; } if (snapCache === void 0) { snapCache = new WeakMap(); } if (createSnapshot === void 0) { createSnapshot = function (_createSnapshot) { function createSnapshot(_x, _x2, _x3) { return _createSnapshot.apply(this, arguments); } createSnapshot.toString = function () { return _createSnapshot.toString(); }; return createSnapshot; }(function (target, version, handlePromise) { if (handlePromise === void 0) { handlePromise = defaultHandlePromise; } var cache = snapCache.get(target); if ((cache == null ? void 0 : cache[0]) === version) { return cache[1]; } var snap = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target)); proxyCompare.markToTrack(snap, true); snapCache.set(target, [version, snap]); Reflect.ownKeys(target).forEach(function (key) { if (Object.getOwnPropertyDescriptor(snap, key)) { return; } var value = Reflect.get(target, key); var _ref = Reflect.getOwnPropertyDescriptor(target, key), enumerable = _ref.enumerable; var desc = { value: value, enumerable: enumerable, configurable: true }; if (refSet.has(value)) { proxyCompare.markToTrack(value, false); } else if (value instanceof Promise) { delete desc.value; desc.get = function () { return handlePromise(value); }; } else if (proxyStateMap.has(value)) { var _ref2 = proxyStateMap.get(value), _target = _ref2[0], _ensureVersion = _ref2[1]; desc.value = createSnapshot(_target, _ensureVersion(), handlePromise); } Object.defineProperty(snap, key, desc); }); return Object.preventExtensions(snap); }); } if (proxyCache === void 0) { proxyCache = new WeakMap(); } if (versionHolder === void 0) { versionHolder = [1, 1]; } if (_proxyFunction === void 0) { _proxyFunction = function proxyFunction(initialObject) { if (!isObject(initialObject)) { throw new Error('object required'); } var found = proxyCache.get(initialObject); if (found) { return found; } var version = versionHolder[0]; var listeners = new Set(); var notifyUpdate = function notifyUpdate(op, nextVersion) { if (nextVersion === void 0) { nextVersion = ++versionHolder[0]; } if (version !== nextVersion) { version = nextVersion; listeners.forEach(function (listener) { return listener(op, nextVersion); }); } }; var checkVersion = versionHolder[1]; var ensureVersion = function ensureVersion(nextCheckVersion) { if (nextCheckVersion === void 0) { nextCheckVersion = ++versionHolder[1]; } if (checkVersion !== nextCheckVersion && !listeners.size) { checkVersion = nextCheckVersion; propProxyStates.forEach(function (_ref3) { var propProxyState = _ref3[0]; var propVersion = propProxyState[1](nextCheckVersion); if (propVersion > version) { version = propVersion; } }); } return version; }; var createPropListener = function createPropListener(prop) { return function (op, nextVersion) { var newOp = [].concat(op); newOp[1] = [prop].concat(newOp[1]); notifyUpdate(newOp, nextVersion); }; }; var propProxyStates = new Map(); var addPropListener = function addPropListener(prop, propProxyState) { if (propProxyStates.has(prop)) { throw new Error('prop listener already exists'); } if (listeners.size) { var remove = propProxyState[3](createPropListener(prop)); propProxyStates.set(prop, [propProxyState, remove]); } else { propProxyStates.set(prop, [propProxyState]); } }; var removePropListener = function removePropListener(prop) { var entry = propProxyStates.get(prop); if (entry) { var _entry$; propProxyStates.delete(prop); (_entry$ = entry[1]) == null || _entry$.call(entry); } }; var addListener = function addListener(listener) { listeners.add(listener); if (listeners.size === 1) { propProxyStates.forEach(function (_ref4, prop) { var propProxyState = _ref4[0], prevRemove = _ref4[1]; if (prevRemove) { throw new Error('remove already exists'); } var remove = propProxyState[3](createPropListener(prop)); propProxyStates.set(prop, [propProxyState, remove]); }); } var removeListener = function removeListener() { listeners.delete(listener); if (listeners.size === 0) { propProxyStates.forEach(function (_ref5, prop) { var propProxyState = _ref5[0], remove = _ref5[1]; if (remove) { remove(); propProxyStates.set(prop, [propProxyState]); } }); } }; return removeListener; }; var baseObject = Array.isArray(initialObject) ? [] : Object.create(Object.getPrototypeOf(initialObject)); var handler = { deleteProperty: function deleteProperty(target, prop) { var prevValue = Reflect.get(target, prop); removePropListener(prop); var deleted = Reflect.deleteProperty(target, prop); if (deleted) { notifyUpdate(['delete', [prop], prevValue]); } return deleted; }, set: function set(target, prop, value, receiver) { var hasPrevValue = Reflect.has(target, prop); var prevValue = Reflect.get(target, prop, receiver); if (hasPrevValue && (objectIs(prevValue, value) || proxyCache.has(value) && objectIs(prevValue, proxyCache.get(value)))) { return true; } removePropListener(prop); if (isObject(value)) { value = proxyCompare.getUntracked(value) || value; } var nextValue = value; if (value instanceof Promise) { value.then(function (v) { value.status = 'fulfilled'; value.value = v; notifyUpdate(['resolve', [prop], v]); }).catch(function (e) { value.status = 'rejected'; value.reason = e; notifyUpdate(['reject', [prop], e]); }); } else { if (!proxyStateMap.has(value) && canProxy(value)) { nextValue = _proxyFunction(value); } var childProxyState = !refSet.has(nextValue) && proxyStateMap.get(nextValue); if (childProxyState) { addPropListener(prop, childProxyState); } } Reflect.set(target, prop, nextValue, receiver); notifyUpdate(['set', [prop], value, prevValue]); return true; } }; var proxyObject = newProxy(baseObject, handler); proxyCache.set(initialObject, proxyObject); var proxyState = [baseObject, ensureVersion, createSnapshot, addListener]; proxyStateMap.set(proxyObject, proxyState); Reflect.ownKeys(initialObject).forEach(function (key) { var desc = Object.getOwnPropertyDescriptor(initialObject, key); if ('value' in desc) { proxyObject[key] = initialObject[key]; delete desc.value; delete desc.writable; } Object.defineProperty(baseObject, key, desc); }); return proxyObject; }; } return [_proxyFunction, proxyStateMap, refSet, objectIs, newProxy, canProxy, defaultHandlePromise, snapCache, createSnapshot, proxyCache, versionHolder]; }; var _buildProxyFunction = buildProxyFunction(), defaultProxyFunction = _buildProxyFunction[0]; function proxy(initialObject) { if (initialObject === void 0) { initialObject = {}; } return defaultProxyFunction(initialObject); } function getVersion(proxyObject) { var proxyState = proxyStateMap.get(proxyObject); return proxyState == null ? void 0 : proxyState[1](); } function subscribe(proxyObject, callback, notifyInSync) { var proxyState = proxyStateMap.get(proxyObject); if (!proxyState) { console.warn('Please use proxy object'); } var promise; var ops = []; var addListener = proxyState[3]; var isListenerActive = false; var listener = function listener(op) { ops.push(op); if (notifyInSync) { callback(ops.splice(0)); return; } if (!promise) { promise = Promise.resolve().then(function () { promise = undefined; if (isListenerActive) { callback(ops.splice(0)); } }); } }; var removeListener = addListener(listener); isListenerActive = true; return function () { isListenerActive = false; removeListener(); }; } function snapshot(proxyObject, handlePromise) { var proxyState = proxyStateMap.get(proxyObject); if (!proxyState) { console.warn('Please use proxy object'); } var _ref6 = proxyState, target = _ref6[0], ensureVersion = _ref6[1], createSnapshot = _ref6[2]; return createSnapshot(target, ensureVersion(), handlePromise); } function ref(obj) { refSet.add(obj); return obj; } var unstable_buildProxyFunction = buildProxyFunction; exports.getVersion = getVersion; exports.proxy = proxy; exports.ref = ref; exports.snapshot = snapshot; exports.subscribe = subscribe; exports.unstable_buildProxyFunction = unstable_buildProxyFunction; }));