{"version":3,"file":"index.umd.js","sources":["../src/derive.ts"],"sourcesContent":["import { getVersion, proxy, subscribe } from 'valtio/vanilla'\n\ntype DeriveGet = (proxyObject: T) => T\n\ntype Subscription = {\n s: object // \"s\"ourceObject\n d: object // \"d\"erivedObject\n k: string // derived \"k\"ey\n c: () => void // \"c\"allback\n n: boolean // \"n\"otifyInSync\n i: string[] // \"i\"goringKeys\n p?: Promise // \"p\"romise\n}\n\ntype SourceObjectEntry = [\n subscriptions: Set,\n unsubscribe: () => void,\n pendingCount: number,\n pendingCallbacks: Set<() => void>,\n]\n\ntype DerivedObjectEntry = [subscriptions: Set]\n\nconst sourceObjectMap = new WeakMap()\nconst derivedObjectMap = new WeakMap()\n\nconst markPending = (sourceObject: object, callback?: () => void) => {\n const sourceObjectEntry = sourceObjectMap.get(sourceObject)\n if (sourceObjectEntry) {\n sourceObjectEntry[0].forEach((subscription) => {\n const { d: derivedObject } = subscription\n if (sourceObject !== derivedObject) {\n markPending(derivedObject)\n }\n })\n ++sourceObjectEntry[2] // pendingCount\n if (callback) {\n sourceObjectEntry[3].add(callback) // pendingCallbacks\n }\n }\n}\n\n// has side effect (even though used in Array.map)\nconst checkPending = (sourceObject: object, callback: () => void) => {\n const sourceObjectEntry = sourceObjectMap.get(sourceObject)\n if (sourceObjectEntry?.[2]) {\n sourceObjectEntry[3].add(callback) // pendingCallbacks\n return true\n }\n return false\n}\n\nconst unmarkPending = (sourceObject: object) => {\n const sourceObjectEntry = sourceObjectMap.get(sourceObject)\n if (sourceObjectEntry) {\n --sourceObjectEntry[2] // pendingCount\n if (!sourceObjectEntry[2]) {\n sourceObjectEntry[3].forEach((callback) => callback())\n sourceObjectEntry[3].clear() // pendingCallbacks\n }\n sourceObjectEntry[0].forEach((subscription) => {\n const { d: derivedObject } = subscription\n if (sourceObject !== derivedObject) {\n unmarkPending(derivedObject)\n }\n })\n }\n}\n\nconst addSubscription = (subscription: Subscription) => {\n const { s: sourceObject, d: derivedObject } = subscription\n let derivedObjectEntry = derivedObjectMap.get(derivedObject)\n if (!derivedObjectEntry) {\n derivedObjectEntry = [new Set()]\n derivedObjectMap.set(subscription.d, derivedObjectEntry)\n }\n derivedObjectEntry[0].add(subscription)\n let sourceObjectEntry = sourceObjectMap.get(sourceObject)\n if (!sourceObjectEntry) {\n const subscriptions = new Set()\n const unsubscribe = subscribe(\n sourceObject,\n (ops) => {\n subscriptions.forEach((subscription) => {\n const {\n d: derivedObject,\n c: callback,\n n: notifyInSync,\n i: ignoreKeys,\n } = subscription\n if (\n sourceObject === derivedObject &&\n ops.every(\n (op) =>\n op[1].length === 1 && ignoreKeys.includes(op[1][0] as string)\n )\n ) {\n // only setting derived properties\n return\n }\n if (subscription.p) {\n // already scheduled\n return\n }\n markPending(sourceObject, callback)\n if (notifyInSync) {\n unmarkPending(sourceObject)\n } else {\n subscription.p = Promise.resolve().then(() => {\n delete subscription.p // promise\n unmarkPending(sourceObject)\n })\n }\n })\n },\n true\n )\n sourceObjectEntry = [subscriptions, unsubscribe, 0, new Set()]\n sourceObjectMap.set(sourceObject, sourceObjectEntry)\n }\n sourceObjectEntry[0].add(subscription)\n}\n\nconst removeSubscription = (subscription: Subscription) => {\n const { s: sourceObject, d: derivedObject } = subscription\n const derivedObjectEntry = derivedObjectMap.get(derivedObject)\n derivedObjectEntry?.[0].delete(subscription)\n if (derivedObjectEntry?.[0].size === 0) {\n derivedObjectMap.delete(derivedObject)\n }\n const sourceObjectEntry = sourceObjectMap.get(sourceObject)\n if (sourceObjectEntry) {\n const [subscriptions, unsubscribe] = sourceObjectEntry\n subscriptions.delete(subscription)\n if (!subscriptions.size) {\n unsubscribe()\n sourceObjectMap.delete(sourceObject)\n }\n }\n}\n\nconst listSubscriptions = (derivedObject: object) => {\n const derivedObjectEntry = derivedObjectMap.get(derivedObject)\n if (derivedObjectEntry) {\n return Array.from(derivedObjectEntry[0]) // NOTE do we need to copy?\n }\n return []\n}\n\n// NOTE This is experimentally exported.\n// The availability is not guaranteed, and it will be renamed,\n// changed or removed without any notice in future versions.\n// It's not expected to use this in production.\nexport const unstable_deriveSubscriptions = {\n add: addSubscription,\n remove: removeSubscription,\n list: listSubscriptions,\n}\n\n/**\n * derive\n *\n * This creates derived properties and attaches them\n * to a new proxy object or an existing proxy object.\n *\n * @example\n * import { proxy } from 'valtio'\n * import { derive } from 'valtio/utils'\n *\n * const state = proxy({\n * count: 1,\n * })\n *\n * const derivedState = derive({\n * doubled: (get) => get(state).count * 2,\n * })\n *\n * derive({\n * tripled: (get) => get(state).count * 3,\n * }, {\n * proxy: state,\n * })\n */\nexport function derive(\n derivedFns: {\n [K in keyof U]: (get: DeriveGet) => U[K]\n },\n options?: {\n proxy?: T\n sync?: boolean\n }\n) {\n const proxyObject = (options?.proxy || proxy({})) as U\n const notifyInSync = !!options?.sync\n const derivedKeys = Object.keys(derivedFns)\n derivedKeys.forEach((key) => {\n if (Object.getOwnPropertyDescriptor(proxyObject, key)) {\n throw new Error('object property already defined')\n }\n const fn = derivedFns[key as keyof U]\n type DependencyEntry = {\n v: number // \"v\"ersion\n s?: Subscription // \"s\"ubscription\n }\n let lastDependencies: Map | null = null\n const evaluate = () => {\n if (lastDependencies) {\n if (\n Array.from(lastDependencies)\n .map(([p]) => checkPending(p, evaluate))\n .some((isPending) => isPending)\n ) {\n // some dependencies are pending\n return\n }\n if (\n Array.from(lastDependencies).every(\n ([p, entry]) => getVersion(p) === entry.v\n )\n ) {\n // no dependencies are changed\n return\n }\n }\n const dependencies = new Map()\n const get =

(p: P) => {\n dependencies.set(p, { v: getVersion(p) as number })\n return p\n }\n const value = fn(get)\n const subscribeToDependencies = () => {\n dependencies.forEach((entry, p) => {\n const lastSubscription = lastDependencies?.get(p)?.s\n if (lastSubscription) {\n entry.s = lastSubscription\n } else {\n const subscription: Subscription = {\n s: p, // sourceObject\n d: proxyObject, // derivedObject\n k: key, // derived key\n c: evaluate, // callback\n n: notifyInSync,\n i: derivedKeys, // ignoringKeys\n }\n addSubscription(subscription)\n entry.s = subscription\n }\n })\n lastDependencies?.forEach((entry, p) => {\n if (!dependencies.has(p) && entry.s) {\n removeSubscription(entry.s)\n }\n })\n lastDependencies = dependencies\n }\n if ((value as unknown) instanceof Promise) {\n ;(value as Promise).finally(subscribeToDependencies)\n } else {\n subscribeToDependencies()\n }\n proxyObject[key as keyof U] = value\n }\n evaluate()\n })\n return proxyObject as T & U\n}\n\n/**\n * underive\n *\n * This stops derived properties to evaluate.\n * It will stop all (or specified by `keys` option) subscriptions.\n * If you specify `delete` option, it will delete the properties\n * and you can attach new derived properties.\n *\n * @example\n * import { proxy } from 'valtio'\n * import { derive, underive } from 'valtio/utils'\n *\n * const state = proxy({\n * count: 1,\n * })\n *\n * const derivedState = derive({\n * doubled: (get) => get(state).count * 2,\n * })\n *\n * underive(derivedState)\n */\nexport function underive(\n proxyObject: T & U,\n options?: {\n delete?: boolean\n keys?: (keyof U)[]\n }\n) {\n const keysToDelete = options?.delete ? new Set() : null\n listSubscriptions(proxyObject).forEach((subscription) => {\n const { k: key } = subscription\n if (!options?.keys || options.keys.includes(key as keyof U)) {\n removeSubscription(subscription)\n if (keysToDelete) {\n keysToDelete.add(key as keyof U)\n }\n }\n })\n if (keysToDelete) {\n keysToDelete.forEach((key) => {\n delete proxyObject[key]\n })\n }\n}\n"],"names":["sourceObjectMap","WeakMap","derivedObjectMap","markPending","sourceObject","callback","sourceObjectEntry","get","forEach","subscription","derivedObject","d","add","unmarkPending","clear","addSubscription","s","derivedObjectEntry","Set","set","subscriptions","unsubscribe","subscribe","ops","c","notifyInSync","n","ignoreKeys","i","every","op","length","includes","p","Promise","resolve","then","removeSubscription","size","listSubscriptions","Array","from","unstable_deriveSubscriptions","remove","list","derivedFns","options","proxyObject","proxy","sync","derivedKeys","Object","keys","key","getOwnPropertyDescriptor","Error","fn","lastDependencies","evaluate","map","_ref","some","isPending","_ref2","entry","getVersion","v","dependencies","Map","value","subscribeToDependencies","_lastDependencies2","_lastDependencies","lastSubscription","k","has","keysToDelete"],"mappings":"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"}