@tanstack/store
Advanced tools
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| var ReactiveFlags = /* @__PURE__ */ ((ReactiveFlags2) => { | ||
| ReactiveFlags2[ReactiveFlags2["None"] = 0] = "None"; | ||
| ReactiveFlags2[ReactiveFlags2["Mutable"] = 1] = "Mutable"; | ||
| ReactiveFlags2[ReactiveFlags2["Watching"] = 2] = "Watching"; | ||
| ReactiveFlags2[ReactiveFlags2["RecursedCheck"] = 4] = "RecursedCheck"; | ||
| ReactiveFlags2[ReactiveFlags2["Recursed"] = 8] = "Recursed"; | ||
| ReactiveFlags2[ReactiveFlags2["Dirty"] = 16] = "Dirty"; | ||
| ReactiveFlags2[ReactiveFlags2["Pending"] = 32] = "Pending"; | ||
| return ReactiveFlags2; | ||
| })(ReactiveFlags || {}); | ||
| function createReactiveSystem({ | ||
| update, | ||
| notify, | ||
| unwatched | ||
| }) { | ||
| return { | ||
| link: link2, | ||
| unlink: unlink2, | ||
| propagate: propagate2, | ||
| checkDirty: checkDirty2, | ||
| shallowPropagate: shallowPropagate2 | ||
| }; | ||
| function link2(dep, sub, version) { | ||
| const prevDep = sub.depsTail; | ||
| if (prevDep !== void 0 && prevDep.dep === dep) { | ||
| return; | ||
| } | ||
| const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps; | ||
| if (nextDep !== void 0 && nextDep.dep === dep) { | ||
| nextDep.version = version; | ||
| sub.depsTail = nextDep; | ||
| return; | ||
| } | ||
| const prevSub = dep.subsTail; | ||
| if (prevSub !== void 0 && prevSub.version === version && prevSub.sub === sub) { | ||
| return; | ||
| } | ||
| const newLink = sub.depsTail = dep.subsTail = { | ||
| version, | ||
| dep, | ||
| sub, | ||
| prevDep, | ||
| nextDep, | ||
| prevSub, | ||
| nextSub: void 0 | ||
| }; | ||
| if (nextDep !== void 0) { | ||
| nextDep.prevDep = newLink; | ||
| } | ||
| if (prevDep !== void 0) { | ||
| prevDep.nextDep = newLink; | ||
| } else { | ||
| sub.deps = newLink; | ||
| } | ||
| if (prevSub !== void 0) { | ||
| prevSub.nextSub = newLink; | ||
| } else { | ||
| dep.subs = newLink; | ||
| } | ||
| } | ||
| function unlink2(link3, sub = link3.sub) { | ||
| const dep = link3.dep; | ||
| const prevDep = link3.prevDep; | ||
| const nextDep = link3.nextDep; | ||
| const nextSub = link3.nextSub; | ||
| const prevSub = link3.prevSub; | ||
| if (nextDep !== void 0) { | ||
| nextDep.prevDep = prevDep; | ||
| } else { | ||
| sub.depsTail = prevDep; | ||
| } | ||
| if (prevDep !== void 0) { | ||
| prevDep.nextDep = nextDep; | ||
| } else { | ||
| sub.deps = nextDep; | ||
| } | ||
| if (nextSub !== void 0) { | ||
| nextSub.prevSub = prevSub; | ||
| } else { | ||
| dep.subsTail = prevSub; | ||
| } | ||
| if (prevSub !== void 0) { | ||
| prevSub.nextSub = nextSub; | ||
| } else if ((dep.subs = nextSub) === void 0) { | ||
| unwatched(dep); | ||
| } | ||
| return nextDep; | ||
| } | ||
| function propagate2(link3) { | ||
| let next = link3.nextSub; | ||
| let stack; | ||
| top: do { | ||
| const sub = link3.sub; | ||
| let flags = sub.flags; | ||
| if (!(flags & (4 | 8 | 16 | 32))) { | ||
| sub.flags = flags | 32; | ||
| } else if (!(flags & (4 | 8))) { | ||
| flags = 0; | ||
| } else if (!(flags & 4)) { | ||
| sub.flags = flags & -9 | 32; | ||
| } else if (!(flags & (16 | 32)) && isValidLink(link3, sub)) { | ||
| sub.flags = flags | (8 | 32); | ||
| flags &= 1; | ||
| } else { | ||
| flags = 0; | ||
| } | ||
| if (flags & 2) { | ||
| notify(sub); | ||
| } | ||
| if (flags & 1) { | ||
| const subSubs = sub.subs; | ||
| if (subSubs !== void 0) { | ||
| const nextSub = (link3 = subSubs).nextSub; | ||
| if (nextSub !== void 0) { | ||
| stack = { value: next, prev: stack }; | ||
| next = nextSub; | ||
| } | ||
| continue; | ||
| } | ||
| } | ||
| if ((link3 = next) !== void 0) { | ||
| next = link3.nextSub; | ||
| continue; | ||
| } | ||
| while (stack !== void 0) { | ||
| link3 = stack.value; | ||
| stack = stack.prev; | ||
| if (link3 !== void 0) { | ||
| next = link3.nextSub; | ||
| continue top; | ||
| } | ||
| } | ||
| break; | ||
| } while (true); | ||
| } | ||
| function checkDirty2(link3, sub) { | ||
| let stack; | ||
| let checkDepth = 0; | ||
| let dirty = false; | ||
| top: do { | ||
| const dep = link3.dep; | ||
| const flags = dep.flags; | ||
| if (sub.flags & 16) { | ||
| dirty = true; | ||
| } else if ((flags & (1 | 16)) === (1 | 16)) { | ||
| if (update(dep)) { | ||
| const subs = dep.subs; | ||
| if (subs.nextSub !== void 0) { | ||
| shallowPropagate2(subs); | ||
| } | ||
| dirty = true; | ||
| } | ||
| } else if ((flags & (1 | 32)) === (1 | 32)) { | ||
| if (link3.nextSub !== void 0 || link3.prevSub !== void 0) { | ||
| stack = { value: link3, prev: stack }; | ||
| } | ||
| link3 = dep.deps; | ||
| sub = dep; | ||
| ++checkDepth; | ||
| continue; | ||
| } | ||
| if (!dirty) { | ||
| const nextDep = link3.nextDep; | ||
| if (nextDep !== void 0) { | ||
| link3 = nextDep; | ||
| continue; | ||
| } | ||
| } | ||
| while (checkDepth--) { | ||
| const firstSub = sub.subs; | ||
| const hasMultipleSubs = firstSub.nextSub !== void 0; | ||
| if (hasMultipleSubs) { | ||
| link3 = stack.value; | ||
| stack = stack.prev; | ||
| } else { | ||
| link3 = firstSub; | ||
| } | ||
| if (dirty) { | ||
| if (update(sub)) { | ||
| if (hasMultipleSubs) { | ||
| shallowPropagate2(firstSub); | ||
| } | ||
| sub = link3.sub; | ||
| continue; | ||
| } | ||
| dirty = false; | ||
| } else { | ||
| sub.flags &= -33; | ||
| } | ||
| sub = link3.sub; | ||
| const nextDep = link3.nextDep; | ||
| if (nextDep !== void 0) { | ||
| link3 = nextDep; | ||
| continue top; | ||
| } | ||
| } | ||
| return dirty; | ||
| } while (true); | ||
| } | ||
| function shallowPropagate2(link3) { | ||
| do { | ||
| const sub = link3.sub; | ||
| const flags = sub.flags; | ||
| if ((flags & (32 | 16)) === 32) { | ||
| sub.flags = flags | 16; | ||
| if ((flags & (2 | 4)) === 2) { | ||
| notify(sub); | ||
| } | ||
| } | ||
| } while ((link3 = link3.nextSub) !== void 0); | ||
| } | ||
| function isValidLink(checkLink, sub) { | ||
| let link3 = sub.depsTail; | ||
| while (link3 !== void 0) { | ||
| if (link3 === checkLink) { | ||
| return true; | ||
| } | ||
| link3 = link3.prevDep; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| let batchDepth = 0; | ||
| let notifyIndex = 0; | ||
| let queuedLength = 0; | ||
| const queued = []; | ||
| const { link, unlink, propagate, checkDirty, shallowPropagate } = createReactiveSystem({ | ||
| update(node) { | ||
| if (node.depsTail !== void 0) { | ||
| return updateComputed(node); | ||
| } else { | ||
| return updateSignal(node); | ||
| } | ||
| }, | ||
| notify(effect2) { | ||
| let insertIndex = queuedLength; | ||
| let firstInsertedIndex = insertIndex; | ||
| do { | ||
| queued[insertIndex++] = effect2; | ||
| effect2.flags &= -3; | ||
| effect2 = effect2.subs?.sub; | ||
| if (effect2 === void 0 || !(effect2.flags & 2)) { | ||
| break; | ||
| } | ||
| } while (true); | ||
| queuedLength = insertIndex; | ||
| while (firstInsertedIndex < --insertIndex) { | ||
| const left = queued[firstInsertedIndex]; | ||
| queued[firstInsertedIndex++] = queued[insertIndex]; | ||
| queued[insertIndex] = left; | ||
| } | ||
| }, | ||
| unwatched(node) { | ||
| if (!(node.flags & 1)) { | ||
| effectScopeOper.call(node); | ||
| } else if (node.depsTail !== void 0) { | ||
| node.depsTail = void 0; | ||
| node.flags = 1 | 16; | ||
| purgeDeps(node); | ||
| } | ||
| } | ||
| }); | ||
| function getBatchDepth() { | ||
| return batchDepth; | ||
| } | ||
| function startBatch() { | ||
| ++batchDepth; | ||
| } | ||
| function endBatch() { | ||
| if (!--batchDepth) { | ||
| flush(); | ||
| } | ||
| } | ||
| function updateComputed(c) { | ||
| c.depsTail = void 0; | ||
| c.flags = 1 | 4; | ||
| try { | ||
| const oldValue = c.value; | ||
| return oldValue !== (c.value = c.getter(oldValue)); | ||
| } finally { | ||
| c.flags &= -5; | ||
| purgeDeps(c); | ||
| } | ||
| } | ||
| function updateSignal(s) { | ||
| s.flags = 1; | ||
| return s.currentValue !== (s.currentValue = s.pendingValue); | ||
| } | ||
| function run(e) { | ||
| const flags = e.flags; | ||
| if (flags & 16 || flags & 32 && checkDirty(e.deps, e)) { | ||
| e.depsTail = void 0; | ||
| e.flags = 2 | 4; | ||
| try { | ||
| ; | ||
| e.fn(); | ||
| } finally { | ||
| e.flags &= -5; | ||
| purgeDeps(e); | ||
| } | ||
| } else { | ||
| e.flags = 2; | ||
| } | ||
| } | ||
| function flush() { | ||
| try { | ||
| while (notifyIndex < queuedLength) { | ||
| const effect2 = queued[notifyIndex]; | ||
| queued[notifyIndex++] = void 0; | ||
| run(effect2); | ||
| } | ||
| } finally { | ||
| while (notifyIndex < queuedLength) { | ||
| const effect2 = queued[notifyIndex]; | ||
| queued[notifyIndex++] = void 0; | ||
| effect2.flags |= 2 | 8; | ||
| } | ||
| notifyIndex = 0; | ||
| queuedLength = 0; | ||
| } | ||
| } | ||
| function effectScopeOper() { | ||
| this.depsTail = void 0; | ||
| this.flags = 0; | ||
| purgeDeps(this); | ||
| const sub = this.subs; | ||
| if (sub !== void 0) { | ||
| unlink(sub); | ||
| } | ||
| } | ||
| function purgeDeps(sub) { | ||
| const depsTail = sub.depsTail; | ||
| let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps; | ||
| while (dep !== void 0) { | ||
| dep = unlink(dep, sub); | ||
| } | ||
| } | ||
| exports.ReactiveFlags = ReactiveFlags; | ||
| exports.createReactiveSystem = createReactiveSystem; | ||
| exports.endBatch = endBatch; | ||
| exports.getBatchDepth = getBatchDepth; | ||
| exports.startBatch = startBatch; | ||
| //# sourceMappingURL=alien.cjs.map |
| {"version":3,"file":"alien.cjs","sources":["../../src/alien.ts"],"sourcesContent":["/* eslint-disable */\n// Adapted from Alien Signals\n// https://github.com/stackblitz/alien-signals/\n\nexport interface ReactiveNode {\n deps?: Link\n depsTail?: Link\n subs?: Link\n subsTail?: Link\n flags: ReactiveFlags\n}\n\nexport interface Link {\n version: number\n dep: ReactiveNode\n sub: ReactiveNode\n prevSub: Link | undefined\n nextSub: Link | undefined\n prevDep: Link | undefined\n nextDep: Link | undefined\n}\n\ninterface Stack<T> {\n value: T\n prev: Stack<T> | undefined\n}\n\nexport const enum ReactiveFlags {\n None = 0,\n Mutable = 1,\n Watching = 2,\n RecursedCheck = 4,\n Recursed = 8,\n Dirty = 16,\n Pending = 32,\n}\n\nexport function createReactiveSystem({\n update,\n notify,\n unwatched,\n}: {\n update(sub: ReactiveNode): boolean\n notify(sub: ReactiveNode): void\n unwatched(sub: ReactiveNode): void\n}) {\n return {\n link,\n unlink,\n propagate,\n checkDirty,\n shallowPropagate,\n }\n\n function link(dep: ReactiveNode, sub: ReactiveNode, version: number): void {\n const prevDep = sub.depsTail\n if (prevDep !== undefined && prevDep.dep === dep) {\n return\n }\n const nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps\n if (nextDep !== undefined && nextDep.dep === dep) {\n nextDep.version = version\n sub.depsTail = nextDep\n return\n }\n const prevSub = dep.subsTail\n if (\n prevSub !== undefined &&\n prevSub.version === version &&\n prevSub.sub === sub\n ) {\n return\n }\n const newLink =\n (sub.depsTail =\n dep.subsTail =\n {\n version,\n dep,\n sub,\n prevDep,\n nextDep,\n prevSub,\n nextSub: undefined,\n })\n if (nextDep !== undefined) {\n nextDep.prevDep = newLink\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = newLink\n } else {\n sub.deps = newLink\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = newLink\n } else {\n dep.subs = newLink\n }\n }\n\n function unlink(link: Link, sub = link.sub): Link | undefined {\n const dep = link.dep\n const prevDep = link.prevDep\n const nextDep = link.nextDep\n const nextSub = link.nextSub\n const prevSub = link.prevSub\n if (nextDep !== undefined) {\n nextDep.prevDep = prevDep\n } else {\n sub.depsTail = prevDep\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = nextDep\n } else {\n sub.deps = nextDep\n }\n if (nextSub !== undefined) {\n nextSub.prevSub = prevSub\n } else {\n dep.subsTail = prevSub\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = nextSub\n } else if ((dep.subs = nextSub) === undefined) {\n unwatched(dep)\n }\n return nextDep\n }\n\n function propagate(link: Link): void {\n let next = link.nextSub\n let stack: Stack<Link | undefined> | undefined\n\n top: do {\n const sub = link.sub\n let flags = sub.flags\n\n if (\n !(\n flags &\n (ReactiveFlags.RecursedCheck |\n ReactiveFlags.Recursed |\n ReactiveFlags.Dirty |\n ReactiveFlags.Pending)\n )\n ) {\n sub.flags = flags | ReactiveFlags.Pending\n } else if (\n !(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed))\n ) {\n flags = ReactiveFlags.None\n } else if (!(flags & ReactiveFlags.RecursedCheck)) {\n sub.flags = (flags & ~ReactiveFlags.Recursed) | ReactiveFlags.Pending\n } else if (\n !(flags & (ReactiveFlags.Dirty | ReactiveFlags.Pending)) &&\n isValidLink(link, sub)\n ) {\n sub.flags = flags | (ReactiveFlags.Recursed | ReactiveFlags.Pending)\n flags &= ReactiveFlags.Mutable\n } else {\n flags = ReactiveFlags.None\n }\n\n if (flags & ReactiveFlags.Watching) {\n notify(sub)\n }\n\n if (flags & ReactiveFlags.Mutable) {\n const subSubs = sub.subs\n if (subSubs !== undefined) {\n const nextSub = (link = subSubs).nextSub\n if (nextSub !== undefined) {\n stack = { value: next, prev: stack }\n next = nextSub\n }\n continue\n }\n }\n\n if ((link = next!) !== undefined) {\n next = link.nextSub\n continue\n }\n\n while (stack !== undefined) {\n link = stack.value!\n stack = stack.prev\n if (link !== undefined) {\n next = link.nextSub\n continue top\n }\n }\n\n break\n } while (true)\n }\n\n function checkDirty(link: Link, sub: ReactiveNode): boolean {\n let stack: Stack<Link> | undefined\n let checkDepth = 0\n let dirty = false\n\n top: do {\n const dep = link.dep\n const flags = dep.flags\n\n if (sub.flags & ReactiveFlags.Dirty) {\n dirty = true\n } else if (\n (flags & (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) ===\n (ReactiveFlags.Mutable | ReactiveFlags.Dirty)\n ) {\n if (update(dep)) {\n const subs = dep.subs!\n if (subs.nextSub !== undefined) {\n shallowPropagate(subs)\n }\n dirty = true\n }\n } else if (\n (flags & (ReactiveFlags.Mutable | ReactiveFlags.Pending)) ===\n (ReactiveFlags.Mutable | ReactiveFlags.Pending)\n ) {\n if (link.nextSub !== undefined || link.prevSub !== undefined) {\n stack = { value: link, prev: stack }\n }\n link = dep.deps!\n sub = dep\n ++checkDepth\n continue\n }\n\n if (!dirty) {\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue\n }\n }\n\n while (checkDepth--) {\n const firstSub = sub.subs!\n const hasMultipleSubs = firstSub.nextSub !== undefined\n if (hasMultipleSubs) {\n link = stack!.value\n stack = stack!.prev\n } else {\n link = firstSub\n }\n if (dirty) {\n if (update(sub)) {\n if (hasMultipleSubs) {\n shallowPropagate(firstSub)\n }\n sub = link.sub\n continue\n }\n dirty = false\n } else {\n sub.flags &= ~ReactiveFlags.Pending\n }\n sub = link.sub\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue top\n }\n }\n\n return dirty\n } while (true)\n }\n\n function shallowPropagate(link: Link): void {\n do {\n const sub = link.sub\n const flags = sub.flags\n if (\n (flags & (ReactiveFlags.Pending | ReactiveFlags.Dirty)) ===\n ReactiveFlags.Pending\n ) {\n sub.flags = flags | ReactiveFlags.Dirty\n if (\n (flags & (ReactiveFlags.Watching | ReactiveFlags.RecursedCheck)) ===\n ReactiveFlags.Watching\n ) {\n notify(sub)\n }\n }\n } while ((link = link.nextSub!) !== undefined)\n }\n\n function isValidLink(checkLink: Link, sub: ReactiveNode): boolean {\n let link = sub.depsTail\n while (link !== undefined) {\n if (link === checkLink) {\n return true\n }\n link = link.prevDep\n }\n return false\n }\n}\n\ninterface EffectNode extends ReactiveNode {\n fn(): void\n}\n\ninterface ComputedNode<T = any> extends ReactiveNode {\n value: T | undefined\n getter: (previousValue?: T) => T\n}\n\ninterface SignalNode<T = any> extends ReactiveNode {\n currentValue: T\n pendingValue: T\n}\n\nlet cycle = 0\nlet batchDepth = 0\nlet notifyIndex = 0\nlet queuedLength = 0\nlet activeSub: ReactiveNode | undefined\n\nconst queued: (EffectNode | undefined)[] = []\nconst { link, unlink, propagate, checkDirty, shallowPropagate } =\n createReactiveSystem({\n update(node: SignalNode | ComputedNode): boolean {\n if (node.depsTail !== undefined) {\n return updateComputed(node as ComputedNode)\n } else {\n return updateSignal(node as SignalNode)\n }\n },\n notify(effect: EffectNode) {\n let insertIndex = queuedLength\n let firstInsertedIndex = insertIndex\n\n do {\n queued[insertIndex++] = effect\n effect.flags &= ~ReactiveFlags.Watching\n effect = effect.subs?.sub as EffectNode\n if (effect === undefined || !(effect.flags & ReactiveFlags.Watching)) {\n break\n }\n } while (true)\n\n queuedLength = insertIndex\n\n while (firstInsertedIndex < --insertIndex) {\n const left = queued[firstInsertedIndex]\n queued[firstInsertedIndex++] = queued[insertIndex]\n queued[insertIndex] = left\n }\n },\n unwatched(node) {\n if (!(node.flags & ReactiveFlags.Mutable)) {\n effectScopeOper.call(node)\n } else if (node.depsTail !== undefined) {\n node.depsTail = undefined\n node.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n purgeDeps(node)\n }\n },\n })\n\nexport function getActiveSub(): ReactiveNode | undefined {\n return activeSub\n}\n\nexport function setActiveSub(sub?: ReactiveNode) {\n const prevSub = activeSub\n activeSub = sub\n return prevSub\n}\n\nexport function getBatchDepth(): number {\n return batchDepth\n}\n\nexport function startBatch() {\n ++batchDepth\n}\n\nexport function endBatch() {\n if (!--batchDepth) {\n flush()\n }\n}\n\nexport function isSignal(fn: () => void): boolean {\n return fn.name === 'bound ' + signalOper.name\n}\n\nexport function isComputed(fn: () => void): boolean {\n return fn.name === 'bound ' + computedOper.name\n}\n\nexport function isEffect(fn: () => void): boolean {\n return fn.name === 'bound ' + effectOper.name\n}\n\nexport function isEffectScope(fn: () => void): boolean {\n return fn.name === 'bound ' + effectScopeOper.name\n}\n\nexport function signal<T>(): {\n (): T | undefined\n (value: T | undefined): void\n}\nexport function signal<T>(initialValue: T): {\n (): T\n (value: T): void\n}\nexport function signal<T>(initialValue?: T): {\n (): T | undefined\n (value: T | undefined): void\n} {\n return signalOper.bind({\n currentValue: initialValue,\n pendingValue: initialValue,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.Mutable,\n }) as () => T | undefined\n}\n\nexport function computed<T>(getter: (previousValue?: T) => T): () => T {\n return computedOper.bind({\n value: undefined,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: ReactiveFlags.None,\n getter: getter as (previousValue?: unknown) => unknown,\n }) as () => T\n}\n\nexport function effect(fn: () => void): () => void {\n const e: EffectNode = {\n fn,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,\n }\n const prevSub = setActiveSub(e)\n if (prevSub !== undefined) {\n link(e, prevSub, 0)\n }\n try {\n e.fn()\n } finally {\n activeSub = prevSub\n e.flags &= ~ReactiveFlags.RecursedCheck\n }\n return effectOper.bind(e)\n}\n\nexport function effectScope(fn: () => void): () => void {\n const e: ReactiveNode = {\n deps: undefined,\n depsTail: undefined,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.None,\n }\n const prevSub = setActiveSub(e)\n if (prevSub !== undefined) {\n link(e, prevSub, 0)\n }\n try {\n fn()\n } finally {\n activeSub = prevSub\n }\n return effectScopeOper.bind(e)\n}\n\nexport function trigger(fn: () => void) {\n const sub: ReactiveNode = {\n deps: undefined,\n depsTail: undefined,\n flags: ReactiveFlags.Watching,\n }\n const prevSub = setActiveSub(sub)\n try {\n fn()\n } finally {\n activeSub = prevSub\n let link = sub.deps\n while (link !== undefined) {\n const dep = link.dep\n link = unlink(link, sub)\n const subs = dep.subs\n if (subs !== undefined) {\n sub.flags = ReactiveFlags.None\n propagate(subs)\n shallowPropagate(subs)\n }\n }\n if (!batchDepth) {\n flush()\n }\n }\n}\n\nfunction updateComputed(c: ComputedNode): boolean {\n ++cycle\n c.depsTail = undefined\n c.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n const prevSub = setActiveSub(c)\n try {\n const oldValue = c.value\n return oldValue !== (c.value = c.getter(oldValue))\n } finally {\n activeSub = prevSub\n c.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(c)\n }\n}\n\nfunction updateSignal(s: SignalNode): boolean {\n s.flags = ReactiveFlags.Mutable\n return s.currentValue !== (s.currentValue = s.pendingValue)\n}\n\nfunction run(e: EffectNode): void {\n const flags = e.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(e.deps!, e))\n ) {\n ++cycle\n e.depsTail = undefined\n e.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck\n const prevSub = setActiveSub(e)\n try {\n ;(e as EffectNode).fn()\n } finally {\n activeSub = prevSub\n e.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(e)\n }\n } else {\n e.flags = ReactiveFlags.Watching\n }\n}\n\nfunction flush(): void {\n try {\n while (notifyIndex < queuedLength) {\n const effect = queued[notifyIndex]!\n queued[notifyIndex++] = undefined\n run(effect)\n }\n } finally {\n while (notifyIndex < queuedLength) {\n const effect = queued[notifyIndex]!\n queued[notifyIndex++] = undefined\n effect.flags |= ReactiveFlags.Watching | ReactiveFlags.Recursed\n }\n notifyIndex = 0\n queuedLength = 0\n }\n}\n\nfunction computedOper<T>(this: ComputedNode<T>): T {\n const flags = this.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending &&\n (checkDirty(this.deps!, this) ||\n ((this.flags = flags & ~ReactiveFlags.Pending), false)))\n ) {\n if (updateComputed(this)) {\n const subs = this.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n } else if (!flags) {\n this.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n const prevSub = setActiveSub(this)\n try {\n this.value = this.getter()\n } finally {\n activeSub = prevSub\n this.flags &= ~ReactiveFlags.RecursedCheck\n }\n }\n const sub = activeSub\n if (sub !== undefined) {\n link(this, sub, cycle)\n }\n return this.value!\n}\n\nfunction signalOper<T>(this: SignalNode<T>, ...value: [T]): T | void {\n if (value.length) {\n if (this.pendingValue !== (this.pendingValue = value[0])) {\n this.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n const subs = this.subs\n if (subs !== undefined) {\n propagate(subs)\n if (!batchDepth) {\n flush()\n }\n }\n }\n } else {\n if (this.flags & ReactiveFlags.Dirty) {\n if (updateSignal(this)) {\n const subs = this.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n }\n let sub = activeSub\n while (sub !== undefined) {\n if (sub.flags & (ReactiveFlags.Mutable | ReactiveFlags.Watching)) {\n link(this, sub, cycle)\n break\n }\n sub = sub.subs?.sub\n }\n return this.currentValue\n }\n}\n\nfunction effectOper(this: EffectNode): void {\n effectScopeOper.call(this)\n}\n\nfunction effectScopeOper(this: ReactiveNode): void {\n this.depsTail = undefined\n this.flags = ReactiveFlags.None\n purgeDeps(this)\n const sub = this.subs\n if (sub !== undefined) {\n unlink(sub)\n }\n}\n\nfunction purgeDeps(sub: ReactiveNode) {\n const depsTail = sub.depsTail\n let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps\n while (dep !== undefined) {\n dep = unlink(dep, sub)\n }\n}\n"],"names":["ReactiveFlags","link","unlink","propagate","checkDirty","shallowPropagate","effect"],"mappings":"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"} |
| export interface ReactiveNode { | ||
| deps?: Link; | ||
| depsTail?: Link; | ||
| subs?: Link; | ||
| subsTail?: Link; | ||
| flags: ReactiveFlags; | ||
| } | ||
| export interface Link { | ||
| version: number; | ||
| dep: ReactiveNode; | ||
| sub: ReactiveNode; | ||
| prevSub: Link | undefined; | ||
| nextSub: Link | undefined; | ||
| prevDep: Link | undefined; | ||
| nextDep: Link | undefined; | ||
| } | ||
| export declare const enum ReactiveFlags { | ||
| None = 0, | ||
| Mutable = 1, | ||
| Watching = 2, | ||
| RecursedCheck = 4, | ||
| Recursed = 8, | ||
| Dirty = 16, | ||
| Pending = 32 | ||
| } | ||
| export declare function createReactiveSystem({ update, notify, unwatched, }: { | ||
| update(sub: ReactiveNode): boolean; | ||
| notify(sub: ReactiveNode): void; | ||
| unwatched(sub: ReactiveNode): void; | ||
| }): { | ||
| link: (dep: ReactiveNode, sub: ReactiveNode, version: number) => void; | ||
| unlink: (link: Link, sub?: ReactiveNode) => Link | undefined; | ||
| propagate: (link: Link) => void; | ||
| checkDirty: (link: Link, sub: ReactiveNode) => boolean; | ||
| shallowPropagate: (link: Link) => void; | ||
| }; | ||
| export declare function getActiveSub(): ReactiveNode | undefined; | ||
| export declare function setActiveSub(sub?: ReactiveNode): ReactiveNode | undefined; | ||
| export declare function getBatchDepth(): number; | ||
| export declare function startBatch(): void; | ||
| export declare function endBatch(): void; | ||
| export declare function isSignal(fn: () => void): boolean; | ||
| export declare function isComputed(fn: () => void): boolean; | ||
| export declare function isEffect(fn: () => void): boolean; | ||
| export declare function isEffectScope(fn: () => void): boolean; | ||
| export declare function signal<T>(): { | ||
| (): T | undefined; | ||
| (value: T | undefined): void; | ||
| }; | ||
| export declare function signal<T>(initialValue: T): { | ||
| (): T; | ||
| (value: T): void; | ||
| }; | ||
| export declare function computed<T>(getter: (previousValue?: T) => T): () => T; | ||
| export declare function effect(fn: () => void): () => void; | ||
| export declare function effectScope(fn: () => void): () => void; | ||
| export declare function trigger(fn: () => void): void; |
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const alien = require("./alien.cjs"); | ||
| function toObserver(nextHandler, errorHandler, completionHandler) { | ||
| const isObserver = typeof nextHandler === "object"; | ||
| const self = isObserver ? nextHandler : void 0; | ||
| return { | ||
| next: (isObserver ? nextHandler.next : nextHandler)?.bind(self), | ||
| error: (isObserver ? nextHandler.error : errorHandler)?.bind(self), | ||
| complete: (isObserver ? nextHandler.complete : completionHandler)?.bind( | ||
| self | ||
| ) | ||
| }; | ||
| } | ||
| const queuedEffects = []; | ||
| let cycle = 0; | ||
| const { link, unlink, propagate, checkDirty, shallowPropagate } = alien.createReactiveSystem({ | ||
| update(atom) { | ||
| return atom._update(); | ||
| }, | ||
| // eslint-disable-next-line no-shadow | ||
| notify(effect2) { | ||
| queuedEffects[queuedEffectsLength++] = effect2; | ||
| effect2.flags &= ~alien.ReactiveFlags.Watching; | ||
| }, | ||
| unwatched(atom) { | ||
| if (atom.depsTail !== void 0) { | ||
| atom.depsTail = void 0; | ||
| atom.flags = alien.ReactiveFlags.Mutable | alien.ReactiveFlags.Dirty; | ||
| purgeDeps(atom); | ||
| } | ||
| } | ||
| }); | ||
| let notifyIndex = 0; | ||
| let queuedEffectsLength = 0; | ||
| let activeSub; | ||
| function purgeDeps(sub) { | ||
| const depsTail = sub.depsTail; | ||
| let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps; | ||
| while (dep !== void 0) { | ||
| dep = unlink(dep, sub); | ||
| } | ||
| } | ||
| function flush() { | ||
| if (alien.getBatchDepth() > 0) { | ||
| return; | ||
| } | ||
| while (notifyIndex < queuedEffectsLength) { | ||
| const effect2 = queuedEffects[notifyIndex]; | ||
| queuedEffects[notifyIndex++] = void 0; | ||
| effect2.notify(); | ||
| } | ||
| notifyIndex = 0; | ||
| queuedEffectsLength = 0; | ||
| } | ||
| function createAsyncAtom(getValue, options) { | ||
| const ref = {}; | ||
| const atom = createAtom(() => { | ||
| getValue().then( | ||
| (data) => { | ||
| const internalAtom = ref.current; | ||
| if (internalAtom._update({ status: "done", data })) { | ||
| const subs = internalAtom.subs; | ||
| if (subs !== void 0) { | ||
| propagate(subs); | ||
| shallowPropagate(subs); | ||
| flush(); | ||
| } | ||
| } | ||
| }, | ||
| (error) => { | ||
| const internalAtom = ref.current; | ||
| if (internalAtom._update({ status: "error", error })) { | ||
| const subs = internalAtom.subs; | ||
| if (subs !== void 0) { | ||
| propagate(subs); | ||
| shallowPropagate(subs); | ||
| flush(); | ||
| } | ||
| } | ||
| } | ||
| ); | ||
| return { status: "pending" }; | ||
| }, options); | ||
| ref.current = atom; | ||
| return atom; | ||
| } | ||
| function createAtom(valueOrFn, options) { | ||
| const isComputed = typeof valueOrFn === "function"; | ||
| const getter = valueOrFn; | ||
| const atom = { | ||
| _snapshot: isComputed ? void 0 : valueOrFn, | ||
| subs: void 0, | ||
| subsTail: void 0, | ||
| deps: void 0, | ||
| depsTail: void 0, | ||
| flags: isComputed ? alien.ReactiveFlags.None : alien.ReactiveFlags.Mutable, | ||
| get() { | ||
| if (activeSub !== void 0) { | ||
| link(atom, activeSub, cycle); | ||
| } | ||
| return atom._snapshot; | ||
| }, | ||
| subscribe(observerOrFn) { | ||
| const obs = toObserver(observerOrFn); | ||
| const observed = { current: false }; | ||
| const e = effect(() => { | ||
| atom.get(); | ||
| if (!observed.current) { | ||
| observed.current = true; | ||
| } else { | ||
| obs.next?.(atom._snapshot); | ||
| } | ||
| }); | ||
| return { | ||
| unsubscribe: () => { | ||
| e.stop(); | ||
| } | ||
| }; | ||
| }, | ||
| _update(getValue) { | ||
| const prevSub = activeSub; | ||
| const compare = options?.compare ?? Object.is; | ||
| activeSub = atom; | ||
| ++cycle; | ||
| atom.depsTail = void 0; | ||
| if (isComputed) { | ||
| atom.flags = alien.ReactiveFlags.Mutable | alien.ReactiveFlags.RecursedCheck; | ||
| } | ||
| try { | ||
| const oldValue = atom._snapshot; | ||
| const newValue = typeof getValue === "function" ? getValue(oldValue) : getValue === void 0 && isComputed ? getter(oldValue) : getValue; | ||
| if (oldValue === void 0 || !compare(oldValue, newValue)) { | ||
| atom._snapshot = newValue; | ||
| return true; | ||
| } | ||
| return false; | ||
| } finally { | ||
| activeSub = prevSub; | ||
| if (isComputed) { | ||
| atom.flags &= ~alien.ReactiveFlags.RecursedCheck; | ||
| } | ||
| purgeDeps(atom); | ||
| } | ||
| } | ||
| }; | ||
| if (isComputed) { | ||
| atom.flags = alien.ReactiveFlags.Mutable | alien.ReactiveFlags.Dirty; | ||
| atom.get = function() { | ||
| const flags = atom.flags; | ||
| if (flags & alien.ReactiveFlags.Dirty || flags & alien.ReactiveFlags.Pending && checkDirty(atom.deps, atom)) { | ||
| if (atom._update()) { | ||
| const subs = atom.subs; | ||
| if (subs !== void 0) { | ||
| shallowPropagate(subs); | ||
| } | ||
| } | ||
| } else if (flags & alien.ReactiveFlags.Pending) { | ||
| atom.flags = flags & ~alien.ReactiveFlags.Pending; | ||
| } | ||
| if (activeSub !== void 0) { | ||
| link(atom, activeSub, cycle); | ||
| } | ||
| return atom._snapshot; | ||
| }; | ||
| } else { | ||
| atom.set = function(valueOrFn2) { | ||
| if (atom._update(valueOrFn2)) { | ||
| const subs = atom.subs; | ||
| if (subs !== void 0) { | ||
| propagate(subs); | ||
| shallowPropagate(subs); | ||
| flush(); | ||
| } | ||
| } | ||
| }; | ||
| } | ||
| return atom; | ||
| } | ||
| function effect(fn) { | ||
| const run = () => { | ||
| const prevSub = activeSub; | ||
| activeSub = effectObj; | ||
| ++cycle; | ||
| effectObj.depsTail = void 0; | ||
| effectObj.flags = alien.ReactiveFlags.Watching | alien.ReactiveFlags.RecursedCheck; | ||
| try { | ||
| return fn(); | ||
| } finally { | ||
| activeSub = prevSub; | ||
| effectObj.flags &= ~alien.ReactiveFlags.RecursedCheck; | ||
| purgeDeps(effectObj); | ||
| } | ||
| }; | ||
| const effectObj = { | ||
| deps: void 0, | ||
| depsTail: void 0, | ||
| subs: void 0, | ||
| subsTail: void 0, | ||
| flags: alien.ReactiveFlags.Watching | alien.ReactiveFlags.RecursedCheck, | ||
| notify() { | ||
| const flags = this.flags; | ||
| if (flags & alien.ReactiveFlags.Dirty || flags & alien.ReactiveFlags.Pending && checkDirty(this.deps, this)) { | ||
| run(); | ||
| } else { | ||
| this.flags = alien.ReactiveFlags.Watching; | ||
| } | ||
| }, | ||
| stop() { | ||
| this.flags = alien.ReactiveFlags.None; | ||
| this.depsTail = void 0; | ||
| purgeDeps(this); | ||
| } | ||
| }; | ||
| run(); | ||
| return effectObj; | ||
| } | ||
| exports.createAsyncAtom = createAsyncAtom; | ||
| exports.createAtom = createAtom; | ||
| exports.flush = flush; | ||
| exports.toObserver = toObserver; | ||
| //# sourceMappingURL=atom.cjs.map |
| {"version":3,"file":"atom.cjs","sources":["../../src/atom.ts"],"sourcesContent":["import { ReactiveFlags, createReactiveSystem, getBatchDepth } from './alien'\n\nimport type { ReactiveNode } from './alien'\nimport type {\n Atom,\n AtomOptions,\n Observer,\n ReadonlyAtom,\n Subscription,\n} from './types'\n\nexport function toObserver<T>(\n nextHandler?: Observer<T> | ((value: T) => void),\n errorHandler?: (error: any) => void,\n completionHandler?: () => void,\n): Observer<T> {\n const isObserver = typeof nextHandler === 'object'\n const self = isObserver ? nextHandler : undefined\n\n return {\n next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),\n error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),\n complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(\n self,\n ),\n }\n}\n\ninterface InternalAtom<T> extends ReactiveNode {\n _snapshot: T\n _update: (getValue?: T | ((snapshot: T) => T)) => boolean\n get: () => T\n subscribe: (observerOrFn: Observer<T> | ((value: T) => void)) => Subscription\n}\n\nconst queuedEffects: Array<Effect | undefined> = []\nlet cycle = 0\nconst { link, unlink, propagate, checkDirty, shallowPropagate } =\n createReactiveSystem({\n update(atom: InternalAtom<any>): boolean {\n return atom._update()\n },\n // eslint-disable-next-line no-shadow\n notify(effect: Effect): void {\n queuedEffects[queuedEffectsLength++] = effect\n effect.flags &= ~ReactiveFlags.Watching\n },\n unwatched(atom: InternalAtom<any>): void {\n if (atom.depsTail !== undefined) {\n atom.depsTail = undefined\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n purgeDeps(atom)\n }\n },\n })\n\nlet notifyIndex = 0\nlet queuedEffectsLength = 0\nlet activeSub: ReactiveNode | undefined\n\nfunction purgeDeps(sub: ReactiveNode) {\n const depsTail = sub.depsTail\n let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps\n while (dep !== undefined) {\n dep = unlink(dep, sub)\n }\n}\n\nexport function flush(): void {\n if (getBatchDepth() > 0) {\n return\n }\n while (notifyIndex < queuedEffectsLength) {\n // eslint-disable-next-line no-shadow\n const effect = queuedEffects[notifyIndex]!\n queuedEffects[notifyIndex++] = undefined\n effect.notify()\n }\n notifyIndex = 0\n queuedEffectsLength = 0\n}\n\ntype AsyncAtomState<TData, TError = unknown> =\n | { status: 'pending' }\n | { status: 'done'; data: TData }\n | { status: 'error'; error: TError }\n\nexport function createAsyncAtom<T>(\n getValue: () => Promise<T>,\n options?: AtomOptions<AsyncAtomState<T>>,\n): ReadonlyAtom<AsyncAtomState<T>> {\n const ref: { current?: InternalAtom<AsyncAtomState<T>> } = {}\n const atom = createAtom<AsyncAtomState<T>>(() => {\n getValue().then(\n (data) => {\n const internalAtom = ref.current!\n if (internalAtom._update({ status: 'done', data })) {\n const subs = internalAtom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n },\n (error) => {\n const internalAtom = ref.current!\n if (internalAtom._update({ status: 'error', error })) {\n const subs = internalAtom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n },\n )\n\n return { status: 'pending' }\n }, options)\n ref.current = atom as unknown as InternalAtom<AsyncAtomState<T>>\n\n return atom\n}\n\nexport function createAtom<T>(\n getValue: (prev?: NoInfer<T>) => T,\n options?: AtomOptions<T>,\n): ReadonlyAtom<T>\nexport function createAtom<T>(\n initialValue: T,\n options?: AtomOptions<T>,\n): Atom<T>\nexport function createAtom<T>(\n valueOrFn: T | ((prev?: T) => T),\n options?: AtomOptions<T>,\n): Atom<T> | ReadonlyAtom<T> {\n const isComputed = typeof valueOrFn === 'function'\n const getter = valueOrFn as (prev?: T) => T\n\n // Create plain object atom\n const atom: InternalAtom<T> = {\n _snapshot: isComputed ? undefined! : valueOrFn,\n\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable,\n\n get(): T {\n if (activeSub !== undefined) {\n link(atom, activeSub, cycle)\n }\n return atom._snapshot\n },\n\n subscribe(observerOrFn: Observer<T> | ((value: T) => void)) {\n const obs = toObserver(observerOrFn)\n const observed = { current: false }\n const e = effect(() => {\n atom.get()\n if (!observed.current) {\n observed.current = true\n } else {\n obs.next?.(atom._snapshot)\n }\n })\n\n return {\n unsubscribe: () => {\n e.stop()\n },\n }\n },\n _update(getValue?: T | ((snapshot: T) => T)): boolean {\n const prevSub = activeSub\n const compare = options?.compare ?? Object.is\n activeSub = atom\n ++cycle\n atom.depsTail = undefined\n if (isComputed) {\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n }\n try {\n const oldValue = atom._snapshot\n const newValue =\n typeof getValue === 'function'\n ? (getValue as (snapshot: T) => T)(oldValue)\n : getValue === undefined && isComputed\n ? getter(oldValue)\n : getValue!\n if (oldValue === undefined || !compare(oldValue, newValue)) {\n atom._snapshot = newValue\n return true\n }\n return false\n } finally {\n activeSub = prevSub\n if (isComputed) {\n atom.flags &= ~ReactiveFlags.RecursedCheck\n }\n purgeDeps(atom)\n }\n },\n }\n\n if (isComputed) {\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n atom.get = function (): T {\n const flags = atom.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(atom.deps!, atom))\n ) {\n if (atom._update()) {\n const subs = atom.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n } else if (flags & ReactiveFlags.Pending) {\n atom.flags = flags & ~ReactiveFlags.Pending\n }\n if (activeSub !== undefined) {\n link(atom, activeSub, cycle)\n }\n return atom._snapshot\n }\n } else {\n ;(atom as unknown as Atom<T>).set = function (\n // eslint-disable-next-line no-shadow\n valueOrFn: T | ((prev: T) => T),\n ): void {\n if (atom._update(valueOrFn)) {\n const subs = atom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n }\n }\n\n return atom as unknown as Atom<T> | ReadonlyAtom<T>\n}\n\ninterface Effect extends ReactiveNode {\n notify: () => void\n stop: () => void\n}\n\nfunction effect<T>(fn: () => T): Effect {\n const run = (): T => {\n const prevSub = activeSub\n activeSub = effectObj\n ++cycle\n effectObj.depsTail = undefined\n effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck\n try {\n return fn()\n } finally {\n activeSub = prevSub\n effectObj.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(effectObj)\n }\n }\n const effectObj: Effect = {\n deps: undefined,\n depsTail: undefined,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,\n\n notify(): void {\n const flags = this.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(this.deps!, this))\n ) {\n run()\n } else {\n this.flags = ReactiveFlags.Watching\n }\n },\n\n stop(): void {\n this.flags = ReactiveFlags.None\n this.depsTail = undefined\n purgeDeps(this)\n },\n }\n\n run()\n\n return effectObj\n}\n"],"names":["createReactiveSystem","effect","ReactiveFlags","getBatchDepth","valueOrFn"],"mappings":"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"} |
| import { Atom, AtomOptions, Observer, ReadonlyAtom } from './types.cjs'; | ||
| export declare function toObserver<T>(nextHandler?: Observer<T> | ((value: T) => void), errorHandler?: (error: any) => void, completionHandler?: () => void): Observer<T>; | ||
| export declare function flush(): void; | ||
| type AsyncAtomState<TData, TError = unknown> = { | ||
| status: 'pending'; | ||
| } | { | ||
| status: 'done'; | ||
| data: TData; | ||
| } | { | ||
| status: 'error'; | ||
| error: TError; | ||
| }; | ||
| export declare function createAsyncAtom<T>(getValue: () => Promise<T>, options?: AtomOptions<AsyncAtomState<T>>): ReadonlyAtom<AsyncAtomState<T>>; | ||
| export declare function createAtom<T>(getValue: (prev?: NoInfer<T>) => T, options?: AtomOptions<T>): ReadonlyAtom<T>; | ||
| export declare function createAtom<T>(initialValue: T, options?: AtomOptions<T>): Atom<T>; | ||
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const alien = require("./alien.cjs"); | ||
| const atom = require("./atom.cjs"); | ||
| function batch(fn) { | ||
| try { | ||
| alien.startBatch(); | ||
| fn(); | ||
| } finally { | ||
| alien.endBatch(); | ||
| atom.flush(); | ||
| } | ||
| } | ||
| exports.batch = batch; | ||
| //# sourceMappingURL=batch.cjs.map |
| {"version":3,"file":"batch.cjs","sources":["../../src/batch.ts"],"sourcesContent":["import { endBatch, startBatch } from './alien'\nimport { flush } from './atom'\n\nexport function batch(fn: () => void) {\n try {\n startBatch()\n fn()\n } finally {\n endBatch()\n flush()\n }\n}\n"],"names":["startBatch","endBatch","flush"],"mappings":";;;;AAGO,SAAS,MAAM,IAAgB;AACpC,MAAI;AACFA,qBAAA;AACA,OAAA;AAAA,EACF,UAAA;AACEC,mBAAA;AACAC,eAAA;AAAA,EACF;AACF;;"} |
| export declare function batch(fn: () => void): void; |
| export interface ReactiveNode { | ||
| deps?: Link; | ||
| depsTail?: Link; | ||
| subs?: Link; | ||
| subsTail?: Link; | ||
| flags: ReactiveFlags; | ||
| } | ||
| export interface Link { | ||
| version: number; | ||
| dep: ReactiveNode; | ||
| sub: ReactiveNode; | ||
| prevSub: Link | undefined; | ||
| nextSub: Link | undefined; | ||
| prevDep: Link | undefined; | ||
| nextDep: Link | undefined; | ||
| } | ||
| export declare const enum ReactiveFlags { | ||
| None = 0, | ||
| Mutable = 1, | ||
| Watching = 2, | ||
| RecursedCheck = 4, | ||
| Recursed = 8, | ||
| Dirty = 16, | ||
| Pending = 32 | ||
| } | ||
| export declare function createReactiveSystem({ update, notify, unwatched, }: { | ||
| update(sub: ReactiveNode): boolean; | ||
| notify(sub: ReactiveNode): void; | ||
| unwatched(sub: ReactiveNode): void; | ||
| }): { | ||
| link: (dep: ReactiveNode, sub: ReactiveNode, version: number) => void; | ||
| unlink: (link: Link, sub?: ReactiveNode) => Link | undefined; | ||
| propagate: (link: Link) => void; | ||
| checkDirty: (link: Link, sub: ReactiveNode) => boolean; | ||
| shallowPropagate: (link: Link) => void; | ||
| }; | ||
| export declare function getActiveSub(): ReactiveNode | undefined; | ||
| export declare function setActiveSub(sub?: ReactiveNode): ReactiveNode | undefined; | ||
| export declare function getBatchDepth(): number; | ||
| export declare function startBatch(): void; | ||
| export declare function endBatch(): void; | ||
| export declare function isSignal(fn: () => void): boolean; | ||
| export declare function isComputed(fn: () => void): boolean; | ||
| export declare function isEffect(fn: () => void): boolean; | ||
| export declare function isEffectScope(fn: () => void): boolean; | ||
| export declare function signal<T>(): { | ||
| (): T | undefined; | ||
| (value: T | undefined): void; | ||
| }; | ||
| export declare function signal<T>(initialValue: T): { | ||
| (): T; | ||
| (value: T): void; | ||
| }; | ||
| export declare function computed<T>(getter: (previousValue?: T) => T): () => T; | ||
| export declare function effect(fn: () => void): () => void; | ||
| export declare function effectScope(fn: () => void): () => void; | ||
| export declare function trigger(fn: () => void): void; |
| var ReactiveFlags = /* @__PURE__ */ ((ReactiveFlags2) => { | ||
| ReactiveFlags2[ReactiveFlags2["None"] = 0] = "None"; | ||
| ReactiveFlags2[ReactiveFlags2["Mutable"] = 1] = "Mutable"; | ||
| ReactiveFlags2[ReactiveFlags2["Watching"] = 2] = "Watching"; | ||
| ReactiveFlags2[ReactiveFlags2["RecursedCheck"] = 4] = "RecursedCheck"; | ||
| ReactiveFlags2[ReactiveFlags2["Recursed"] = 8] = "Recursed"; | ||
| ReactiveFlags2[ReactiveFlags2["Dirty"] = 16] = "Dirty"; | ||
| ReactiveFlags2[ReactiveFlags2["Pending"] = 32] = "Pending"; | ||
| return ReactiveFlags2; | ||
| })(ReactiveFlags || {}); | ||
| function createReactiveSystem({ | ||
| update, | ||
| notify, | ||
| unwatched | ||
| }) { | ||
| return { | ||
| link: link2, | ||
| unlink: unlink2, | ||
| propagate: propagate2, | ||
| checkDirty: checkDirty2, | ||
| shallowPropagate: shallowPropagate2 | ||
| }; | ||
| function link2(dep, sub, version) { | ||
| const prevDep = sub.depsTail; | ||
| if (prevDep !== void 0 && prevDep.dep === dep) { | ||
| return; | ||
| } | ||
| const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps; | ||
| if (nextDep !== void 0 && nextDep.dep === dep) { | ||
| nextDep.version = version; | ||
| sub.depsTail = nextDep; | ||
| return; | ||
| } | ||
| const prevSub = dep.subsTail; | ||
| if (prevSub !== void 0 && prevSub.version === version && prevSub.sub === sub) { | ||
| return; | ||
| } | ||
| const newLink = sub.depsTail = dep.subsTail = { | ||
| version, | ||
| dep, | ||
| sub, | ||
| prevDep, | ||
| nextDep, | ||
| prevSub, | ||
| nextSub: void 0 | ||
| }; | ||
| if (nextDep !== void 0) { | ||
| nextDep.prevDep = newLink; | ||
| } | ||
| if (prevDep !== void 0) { | ||
| prevDep.nextDep = newLink; | ||
| } else { | ||
| sub.deps = newLink; | ||
| } | ||
| if (prevSub !== void 0) { | ||
| prevSub.nextSub = newLink; | ||
| } else { | ||
| dep.subs = newLink; | ||
| } | ||
| } | ||
| function unlink2(link3, sub = link3.sub) { | ||
| const dep = link3.dep; | ||
| const prevDep = link3.prevDep; | ||
| const nextDep = link3.nextDep; | ||
| const nextSub = link3.nextSub; | ||
| const prevSub = link3.prevSub; | ||
| if (nextDep !== void 0) { | ||
| nextDep.prevDep = prevDep; | ||
| } else { | ||
| sub.depsTail = prevDep; | ||
| } | ||
| if (prevDep !== void 0) { | ||
| prevDep.nextDep = nextDep; | ||
| } else { | ||
| sub.deps = nextDep; | ||
| } | ||
| if (nextSub !== void 0) { | ||
| nextSub.prevSub = prevSub; | ||
| } else { | ||
| dep.subsTail = prevSub; | ||
| } | ||
| if (prevSub !== void 0) { | ||
| prevSub.nextSub = nextSub; | ||
| } else if ((dep.subs = nextSub) === void 0) { | ||
| unwatched(dep); | ||
| } | ||
| return nextDep; | ||
| } | ||
| function propagate2(link3) { | ||
| let next = link3.nextSub; | ||
| let stack; | ||
| top: do { | ||
| const sub = link3.sub; | ||
| let flags = sub.flags; | ||
| if (!(flags & (4 | 8 | 16 | 32))) { | ||
| sub.flags = flags | 32; | ||
| } else if (!(flags & (4 | 8))) { | ||
| flags = 0; | ||
| } else if (!(flags & 4)) { | ||
| sub.flags = flags & -9 | 32; | ||
| } else if (!(flags & (16 | 32)) && isValidLink(link3, sub)) { | ||
| sub.flags = flags | (8 | 32); | ||
| flags &= 1; | ||
| } else { | ||
| flags = 0; | ||
| } | ||
| if (flags & 2) { | ||
| notify(sub); | ||
| } | ||
| if (flags & 1) { | ||
| const subSubs = sub.subs; | ||
| if (subSubs !== void 0) { | ||
| const nextSub = (link3 = subSubs).nextSub; | ||
| if (nextSub !== void 0) { | ||
| stack = { value: next, prev: stack }; | ||
| next = nextSub; | ||
| } | ||
| continue; | ||
| } | ||
| } | ||
| if ((link3 = next) !== void 0) { | ||
| next = link3.nextSub; | ||
| continue; | ||
| } | ||
| while (stack !== void 0) { | ||
| link3 = stack.value; | ||
| stack = stack.prev; | ||
| if (link3 !== void 0) { | ||
| next = link3.nextSub; | ||
| continue top; | ||
| } | ||
| } | ||
| break; | ||
| } while (true); | ||
| } | ||
| function checkDirty2(link3, sub) { | ||
| let stack; | ||
| let checkDepth = 0; | ||
| let dirty = false; | ||
| top: do { | ||
| const dep = link3.dep; | ||
| const flags = dep.flags; | ||
| if (sub.flags & 16) { | ||
| dirty = true; | ||
| } else if ((flags & (1 | 16)) === (1 | 16)) { | ||
| if (update(dep)) { | ||
| const subs = dep.subs; | ||
| if (subs.nextSub !== void 0) { | ||
| shallowPropagate2(subs); | ||
| } | ||
| dirty = true; | ||
| } | ||
| } else if ((flags & (1 | 32)) === (1 | 32)) { | ||
| if (link3.nextSub !== void 0 || link3.prevSub !== void 0) { | ||
| stack = { value: link3, prev: stack }; | ||
| } | ||
| link3 = dep.deps; | ||
| sub = dep; | ||
| ++checkDepth; | ||
| continue; | ||
| } | ||
| if (!dirty) { | ||
| const nextDep = link3.nextDep; | ||
| if (nextDep !== void 0) { | ||
| link3 = nextDep; | ||
| continue; | ||
| } | ||
| } | ||
| while (checkDepth--) { | ||
| const firstSub = sub.subs; | ||
| const hasMultipleSubs = firstSub.nextSub !== void 0; | ||
| if (hasMultipleSubs) { | ||
| link3 = stack.value; | ||
| stack = stack.prev; | ||
| } else { | ||
| link3 = firstSub; | ||
| } | ||
| if (dirty) { | ||
| if (update(sub)) { | ||
| if (hasMultipleSubs) { | ||
| shallowPropagate2(firstSub); | ||
| } | ||
| sub = link3.sub; | ||
| continue; | ||
| } | ||
| dirty = false; | ||
| } else { | ||
| sub.flags &= -33; | ||
| } | ||
| sub = link3.sub; | ||
| const nextDep = link3.nextDep; | ||
| if (nextDep !== void 0) { | ||
| link3 = nextDep; | ||
| continue top; | ||
| } | ||
| } | ||
| return dirty; | ||
| } while (true); | ||
| } | ||
| function shallowPropagate2(link3) { | ||
| do { | ||
| const sub = link3.sub; | ||
| const flags = sub.flags; | ||
| if ((flags & (32 | 16)) === 32) { | ||
| sub.flags = flags | 16; | ||
| if ((flags & (2 | 4)) === 2) { | ||
| notify(sub); | ||
| } | ||
| } | ||
| } while ((link3 = link3.nextSub) !== void 0); | ||
| } | ||
| function isValidLink(checkLink, sub) { | ||
| let link3 = sub.depsTail; | ||
| while (link3 !== void 0) { | ||
| if (link3 === checkLink) { | ||
| return true; | ||
| } | ||
| link3 = link3.prevDep; | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| let batchDepth = 0; | ||
| let notifyIndex = 0; | ||
| let queuedLength = 0; | ||
| const queued = []; | ||
| const { link, unlink, propagate, checkDirty, shallowPropagate } = createReactiveSystem({ | ||
| update(node) { | ||
| if (node.depsTail !== void 0) { | ||
| return updateComputed(node); | ||
| } else { | ||
| return updateSignal(node); | ||
| } | ||
| }, | ||
| notify(effect2) { | ||
| let insertIndex = queuedLength; | ||
| let firstInsertedIndex = insertIndex; | ||
| do { | ||
| queued[insertIndex++] = effect2; | ||
| effect2.flags &= -3; | ||
| effect2 = effect2.subs?.sub; | ||
| if (effect2 === void 0 || !(effect2.flags & 2)) { | ||
| break; | ||
| } | ||
| } while (true); | ||
| queuedLength = insertIndex; | ||
| while (firstInsertedIndex < --insertIndex) { | ||
| const left = queued[firstInsertedIndex]; | ||
| queued[firstInsertedIndex++] = queued[insertIndex]; | ||
| queued[insertIndex] = left; | ||
| } | ||
| }, | ||
| unwatched(node) { | ||
| if (!(node.flags & 1)) { | ||
| effectScopeOper.call(node); | ||
| } else if (node.depsTail !== void 0) { | ||
| node.depsTail = void 0; | ||
| node.flags = 1 | 16; | ||
| purgeDeps(node); | ||
| } | ||
| } | ||
| }); | ||
| function getBatchDepth() { | ||
| return batchDepth; | ||
| } | ||
| function startBatch() { | ||
| ++batchDepth; | ||
| } | ||
| function endBatch() { | ||
| if (!--batchDepth) { | ||
| flush(); | ||
| } | ||
| } | ||
| function updateComputed(c) { | ||
| c.depsTail = void 0; | ||
| c.flags = 1 | 4; | ||
| try { | ||
| const oldValue = c.value; | ||
| return oldValue !== (c.value = c.getter(oldValue)); | ||
| } finally { | ||
| c.flags &= -5; | ||
| purgeDeps(c); | ||
| } | ||
| } | ||
| function updateSignal(s) { | ||
| s.flags = 1; | ||
| return s.currentValue !== (s.currentValue = s.pendingValue); | ||
| } | ||
| function run(e) { | ||
| const flags = e.flags; | ||
| if (flags & 16 || flags & 32 && checkDirty(e.deps, e)) { | ||
| e.depsTail = void 0; | ||
| e.flags = 2 | 4; | ||
| try { | ||
| ; | ||
| e.fn(); | ||
| } finally { | ||
| e.flags &= -5; | ||
| purgeDeps(e); | ||
| } | ||
| } else { | ||
| e.flags = 2; | ||
| } | ||
| } | ||
| function flush() { | ||
| try { | ||
| while (notifyIndex < queuedLength) { | ||
| const effect2 = queued[notifyIndex]; | ||
| queued[notifyIndex++] = void 0; | ||
| run(effect2); | ||
| } | ||
| } finally { | ||
| while (notifyIndex < queuedLength) { | ||
| const effect2 = queued[notifyIndex]; | ||
| queued[notifyIndex++] = void 0; | ||
| effect2.flags |= 2 | 8; | ||
| } | ||
| notifyIndex = 0; | ||
| queuedLength = 0; | ||
| } | ||
| } | ||
| function effectScopeOper() { | ||
| this.depsTail = void 0; | ||
| this.flags = 0; | ||
| purgeDeps(this); | ||
| const sub = this.subs; | ||
| if (sub !== void 0) { | ||
| unlink(sub); | ||
| } | ||
| } | ||
| function purgeDeps(sub) { | ||
| const depsTail = sub.depsTail; | ||
| let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps; | ||
| while (dep !== void 0) { | ||
| dep = unlink(dep, sub); | ||
| } | ||
| } | ||
| export { | ||
| ReactiveFlags, | ||
| createReactiveSystem, | ||
| endBatch, | ||
| getBatchDepth, | ||
| startBatch | ||
| }; | ||
| //# sourceMappingURL=alien.js.map |
| {"version":3,"file":"alien.js","sources":["../../src/alien.ts"],"sourcesContent":["/* eslint-disable */\n// Adapted from Alien Signals\n// https://github.com/stackblitz/alien-signals/\n\nexport interface ReactiveNode {\n deps?: Link\n depsTail?: Link\n subs?: Link\n subsTail?: Link\n flags: ReactiveFlags\n}\n\nexport interface Link {\n version: number\n dep: ReactiveNode\n sub: ReactiveNode\n prevSub: Link | undefined\n nextSub: Link | undefined\n prevDep: Link | undefined\n nextDep: Link | undefined\n}\n\ninterface Stack<T> {\n value: T\n prev: Stack<T> | undefined\n}\n\nexport const enum ReactiveFlags {\n None = 0,\n Mutable = 1,\n Watching = 2,\n RecursedCheck = 4,\n Recursed = 8,\n Dirty = 16,\n Pending = 32,\n}\n\nexport function createReactiveSystem({\n update,\n notify,\n unwatched,\n}: {\n update(sub: ReactiveNode): boolean\n notify(sub: ReactiveNode): void\n unwatched(sub: ReactiveNode): void\n}) {\n return {\n link,\n unlink,\n propagate,\n checkDirty,\n shallowPropagate,\n }\n\n function link(dep: ReactiveNode, sub: ReactiveNode, version: number): void {\n const prevDep = sub.depsTail\n if (prevDep !== undefined && prevDep.dep === dep) {\n return\n }\n const nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps\n if (nextDep !== undefined && nextDep.dep === dep) {\n nextDep.version = version\n sub.depsTail = nextDep\n return\n }\n const prevSub = dep.subsTail\n if (\n prevSub !== undefined &&\n prevSub.version === version &&\n prevSub.sub === sub\n ) {\n return\n }\n const newLink =\n (sub.depsTail =\n dep.subsTail =\n {\n version,\n dep,\n sub,\n prevDep,\n nextDep,\n prevSub,\n nextSub: undefined,\n })\n if (nextDep !== undefined) {\n nextDep.prevDep = newLink\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = newLink\n } else {\n sub.deps = newLink\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = newLink\n } else {\n dep.subs = newLink\n }\n }\n\n function unlink(link: Link, sub = link.sub): Link | undefined {\n const dep = link.dep\n const prevDep = link.prevDep\n const nextDep = link.nextDep\n const nextSub = link.nextSub\n const prevSub = link.prevSub\n if (nextDep !== undefined) {\n nextDep.prevDep = prevDep\n } else {\n sub.depsTail = prevDep\n }\n if (prevDep !== undefined) {\n prevDep.nextDep = nextDep\n } else {\n sub.deps = nextDep\n }\n if (nextSub !== undefined) {\n nextSub.prevSub = prevSub\n } else {\n dep.subsTail = prevSub\n }\n if (prevSub !== undefined) {\n prevSub.nextSub = nextSub\n } else if ((dep.subs = nextSub) === undefined) {\n unwatched(dep)\n }\n return nextDep\n }\n\n function propagate(link: Link): void {\n let next = link.nextSub\n let stack: Stack<Link | undefined> | undefined\n\n top: do {\n const sub = link.sub\n let flags = sub.flags\n\n if (\n !(\n flags &\n (ReactiveFlags.RecursedCheck |\n ReactiveFlags.Recursed |\n ReactiveFlags.Dirty |\n ReactiveFlags.Pending)\n )\n ) {\n sub.flags = flags | ReactiveFlags.Pending\n } else if (\n !(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed))\n ) {\n flags = ReactiveFlags.None\n } else if (!(flags & ReactiveFlags.RecursedCheck)) {\n sub.flags = (flags & ~ReactiveFlags.Recursed) | ReactiveFlags.Pending\n } else if (\n !(flags & (ReactiveFlags.Dirty | ReactiveFlags.Pending)) &&\n isValidLink(link, sub)\n ) {\n sub.flags = flags | (ReactiveFlags.Recursed | ReactiveFlags.Pending)\n flags &= ReactiveFlags.Mutable\n } else {\n flags = ReactiveFlags.None\n }\n\n if (flags & ReactiveFlags.Watching) {\n notify(sub)\n }\n\n if (flags & ReactiveFlags.Mutable) {\n const subSubs = sub.subs\n if (subSubs !== undefined) {\n const nextSub = (link = subSubs).nextSub\n if (nextSub !== undefined) {\n stack = { value: next, prev: stack }\n next = nextSub\n }\n continue\n }\n }\n\n if ((link = next!) !== undefined) {\n next = link.nextSub\n continue\n }\n\n while (stack !== undefined) {\n link = stack.value!\n stack = stack.prev\n if (link !== undefined) {\n next = link.nextSub\n continue top\n }\n }\n\n break\n } while (true)\n }\n\n function checkDirty(link: Link, sub: ReactiveNode): boolean {\n let stack: Stack<Link> | undefined\n let checkDepth = 0\n let dirty = false\n\n top: do {\n const dep = link.dep\n const flags = dep.flags\n\n if (sub.flags & ReactiveFlags.Dirty) {\n dirty = true\n } else if (\n (flags & (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) ===\n (ReactiveFlags.Mutable | ReactiveFlags.Dirty)\n ) {\n if (update(dep)) {\n const subs = dep.subs!\n if (subs.nextSub !== undefined) {\n shallowPropagate(subs)\n }\n dirty = true\n }\n } else if (\n (flags & (ReactiveFlags.Mutable | ReactiveFlags.Pending)) ===\n (ReactiveFlags.Mutable | ReactiveFlags.Pending)\n ) {\n if (link.nextSub !== undefined || link.prevSub !== undefined) {\n stack = { value: link, prev: stack }\n }\n link = dep.deps!\n sub = dep\n ++checkDepth\n continue\n }\n\n if (!dirty) {\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue\n }\n }\n\n while (checkDepth--) {\n const firstSub = sub.subs!\n const hasMultipleSubs = firstSub.nextSub !== undefined\n if (hasMultipleSubs) {\n link = stack!.value\n stack = stack!.prev\n } else {\n link = firstSub\n }\n if (dirty) {\n if (update(sub)) {\n if (hasMultipleSubs) {\n shallowPropagate(firstSub)\n }\n sub = link.sub\n continue\n }\n dirty = false\n } else {\n sub.flags &= ~ReactiveFlags.Pending\n }\n sub = link.sub\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue top\n }\n }\n\n return dirty\n } while (true)\n }\n\n function shallowPropagate(link: Link): void {\n do {\n const sub = link.sub\n const flags = sub.flags\n if (\n (flags & (ReactiveFlags.Pending | ReactiveFlags.Dirty)) ===\n ReactiveFlags.Pending\n ) {\n sub.flags = flags | ReactiveFlags.Dirty\n if (\n (flags & (ReactiveFlags.Watching | ReactiveFlags.RecursedCheck)) ===\n ReactiveFlags.Watching\n ) {\n notify(sub)\n }\n }\n } while ((link = link.nextSub!) !== undefined)\n }\n\n function isValidLink(checkLink: Link, sub: ReactiveNode): boolean {\n let link = sub.depsTail\n while (link !== undefined) {\n if (link === checkLink) {\n return true\n }\n link = link.prevDep\n }\n return false\n }\n}\n\ninterface EffectNode extends ReactiveNode {\n fn(): void\n}\n\ninterface ComputedNode<T = any> extends ReactiveNode {\n value: T | undefined\n getter: (previousValue?: T) => T\n}\n\ninterface SignalNode<T = any> extends ReactiveNode {\n currentValue: T\n pendingValue: T\n}\n\nlet cycle = 0\nlet batchDepth = 0\nlet notifyIndex = 0\nlet queuedLength = 0\nlet activeSub: ReactiveNode | undefined\n\nconst queued: (EffectNode | undefined)[] = []\nconst { link, unlink, propagate, checkDirty, shallowPropagate } =\n createReactiveSystem({\n update(node: SignalNode | ComputedNode): boolean {\n if (node.depsTail !== undefined) {\n return updateComputed(node as ComputedNode)\n } else {\n return updateSignal(node as SignalNode)\n }\n },\n notify(effect: EffectNode) {\n let insertIndex = queuedLength\n let firstInsertedIndex = insertIndex\n\n do {\n queued[insertIndex++] = effect\n effect.flags &= ~ReactiveFlags.Watching\n effect = effect.subs?.sub as EffectNode\n if (effect === undefined || !(effect.flags & ReactiveFlags.Watching)) {\n break\n }\n } while (true)\n\n queuedLength = insertIndex\n\n while (firstInsertedIndex < --insertIndex) {\n const left = queued[firstInsertedIndex]\n queued[firstInsertedIndex++] = queued[insertIndex]\n queued[insertIndex] = left\n }\n },\n unwatched(node) {\n if (!(node.flags & ReactiveFlags.Mutable)) {\n effectScopeOper.call(node)\n } else if (node.depsTail !== undefined) {\n node.depsTail = undefined\n node.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n purgeDeps(node)\n }\n },\n })\n\nexport function getActiveSub(): ReactiveNode | undefined {\n return activeSub\n}\n\nexport function setActiveSub(sub?: ReactiveNode) {\n const prevSub = activeSub\n activeSub = sub\n return prevSub\n}\n\nexport function getBatchDepth(): number {\n return batchDepth\n}\n\nexport function startBatch() {\n ++batchDepth\n}\n\nexport function endBatch() {\n if (!--batchDepth) {\n flush()\n }\n}\n\nexport function isSignal(fn: () => void): boolean {\n return fn.name === 'bound ' + signalOper.name\n}\n\nexport function isComputed(fn: () => void): boolean {\n return fn.name === 'bound ' + computedOper.name\n}\n\nexport function isEffect(fn: () => void): boolean {\n return fn.name === 'bound ' + effectOper.name\n}\n\nexport function isEffectScope(fn: () => void): boolean {\n return fn.name === 'bound ' + effectScopeOper.name\n}\n\nexport function signal<T>(): {\n (): T | undefined\n (value: T | undefined): void\n}\nexport function signal<T>(initialValue: T): {\n (): T\n (value: T): void\n}\nexport function signal<T>(initialValue?: T): {\n (): T | undefined\n (value: T | undefined): void\n} {\n return signalOper.bind({\n currentValue: initialValue,\n pendingValue: initialValue,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.Mutable,\n }) as () => T | undefined\n}\n\nexport function computed<T>(getter: (previousValue?: T) => T): () => T {\n return computedOper.bind({\n value: undefined,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: ReactiveFlags.None,\n getter: getter as (previousValue?: unknown) => unknown,\n }) as () => T\n}\n\nexport function effect(fn: () => void): () => void {\n const e: EffectNode = {\n fn,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,\n }\n const prevSub = setActiveSub(e)\n if (prevSub !== undefined) {\n link(e, prevSub, 0)\n }\n try {\n e.fn()\n } finally {\n activeSub = prevSub\n e.flags &= ~ReactiveFlags.RecursedCheck\n }\n return effectOper.bind(e)\n}\n\nexport function effectScope(fn: () => void): () => void {\n const e: ReactiveNode = {\n deps: undefined,\n depsTail: undefined,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.None,\n }\n const prevSub = setActiveSub(e)\n if (prevSub !== undefined) {\n link(e, prevSub, 0)\n }\n try {\n fn()\n } finally {\n activeSub = prevSub\n }\n return effectScopeOper.bind(e)\n}\n\nexport function trigger(fn: () => void) {\n const sub: ReactiveNode = {\n deps: undefined,\n depsTail: undefined,\n flags: ReactiveFlags.Watching,\n }\n const prevSub = setActiveSub(sub)\n try {\n fn()\n } finally {\n activeSub = prevSub\n let link = sub.deps\n while (link !== undefined) {\n const dep = link.dep\n link = unlink(link, sub)\n const subs = dep.subs\n if (subs !== undefined) {\n sub.flags = ReactiveFlags.None\n propagate(subs)\n shallowPropagate(subs)\n }\n }\n if (!batchDepth) {\n flush()\n }\n }\n}\n\nfunction updateComputed(c: ComputedNode): boolean {\n ++cycle\n c.depsTail = undefined\n c.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n const prevSub = setActiveSub(c)\n try {\n const oldValue = c.value\n return oldValue !== (c.value = c.getter(oldValue))\n } finally {\n activeSub = prevSub\n c.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(c)\n }\n}\n\nfunction updateSignal(s: SignalNode): boolean {\n s.flags = ReactiveFlags.Mutable\n return s.currentValue !== (s.currentValue = s.pendingValue)\n}\n\nfunction run(e: EffectNode): void {\n const flags = e.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(e.deps!, e))\n ) {\n ++cycle\n e.depsTail = undefined\n e.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck\n const prevSub = setActiveSub(e)\n try {\n ;(e as EffectNode).fn()\n } finally {\n activeSub = prevSub\n e.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(e)\n }\n } else {\n e.flags = ReactiveFlags.Watching\n }\n}\n\nfunction flush(): void {\n try {\n while (notifyIndex < queuedLength) {\n const effect = queued[notifyIndex]!\n queued[notifyIndex++] = undefined\n run(effect)\n }\n } finally {\n while (notifyIndex < queuedLength) {\n const effect = queued[notifyIndex]!\n queued[notifyIndex++] = undefined\n effect.flags |= ReactiveFlags.Watching | ReactiveFlags.Recursed\n }\n notifyIndex = 0\n queuedLength = 0\n }\n}\n\nfunction computedOper<T>(this: ComputedNode<T>): T {\n const flags = this.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending &&\n (checkDirty(this.deps!, this) ||\n ((this.flags = flags & ~ReactiveFlags.Pending), false)))\n ) {\n if (updateComputed(this)) {\n const subs = this.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n } else if (!flags) {\n this.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n const prevSub = setActiveSub(this)\n try {\n this.value = this.getter()\n } finally {\n activeSub = prevSub\n this.flags &= ~ReactiveFlags.RecursedCheck\n }\n }\n const sub = activeSub\n if (sub !== undefined) {\n link(this, sub, cycle)\n }\n return this.value!\n}\n\nfunction signalOper<T>(this: SignalNode<T>, ...value: [T]): T | void {\n if (value.length) {\n if (this.pendingValue !== (this.pendingValue = value[0])) {\n this.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n const subs = this.subs\n if (subs !== undefined) {\n propagate(subs)\n if (!batchDepth) {\n flush()\n }\n }\n }\n } else {\n if (this.flags & ReactiveFlags.Dirty) {\n if (updateSignal(this)) {\n const subs = this.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n }\n let sub = activeSub\n while (sub !== undefined) {\n if (sub.flags & (ReactiveFlags.Mutable | ReactiveFlags.Watching)) {\n link(this, sub, cycle)\n break\n }\n sub = sub.subs?.sub\n }\n return this.currentValue\n }\n}\n\nfunction effectOper(this: EffectNode): void {\n effectScopeOper.call(this)\n}\n\nfunction effectScopeOper(this: ReactiveNode): void {\n this.depsTail = undefined\n this.flags = ReactiveFlags.None\n purgeDeps(this)\n const sub = this.subs\n if (sub !== undefined) {\n unlink(sub)\n }\n}\n\nfunction purgeDeps(sub: ReactiveNode) {\n const depsTail = sub.depsTail\n let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps\n while (dep !== undefined) {\n dep = unlink(dep, sub)\n }\n}\n"],"names":["ReactiveFlags","link","unlink","propagate","checkDirty","shallowPropagate","effect"],"mappings":"AA2BO,IAAW,kCAAAA,mBAAX;AACLA,iBAAAA,eAAA,UAAO,CAAA,IAAP;AACAA,iBAAAA,eAAA,aAAU,CAAA,IAAV;AACAA,iBAAAA,eAAA,cAAW,CAAA,IAAX;AACAA,iBAAAA,eAAA,mBAAgB,CAAA,IAAhB;AACAA,iBAAAA,eAAA,cAAW,CAAA,IAAX;AACAA,iBAAAA,eAAA,WAAQ,EAAA,IAAR;AACAA,iBAAAA,eAAA,aAAU,EAAA,IAAV;AAPgB,SAAAA;AAAA,GAAA,iBAAA,CAAA,CAAA;AAUX,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SAAO;AAAA,IACL,MAAAC;AAAAA,IACA,QAAAC;AAAAA,IACA,WAAAC;AAAAA,IACA,YAAAC;AAAAA,IACA,kBAAAC;AAAAA,EAAA;AAGF,WAASJ,MAAK,KAAmB,KAAmB,SAAuB;AACzE,UAAM,UAAU,IAAI;AACpB,QAAI,YAAY,UAAa,QAAQ,QAAQ,KAAK;AAChD;AAAA,IACF;AACA,UAAM,UAAU,YAAY,SAAY,QAAQ,UAAU,IAAI;AAC9D,QAAI,YAAY,UAAa,QAAQ,QAAQ,KAAK;AAChD,cAAQ,UAAU;AAClB,UAAI,WAAW;AACf;AAAA,IACF;AACA,UAAM,UAAU,IAAI;AACpB,QACE,YAAY,UACZ,QAAQ,YAAY,WACpB,QAAQ,QAAQ,KAChB;AACA;AAAA,IACF;AACA,UAAM,UACH,IAAI,WACL,IAAI,WACF;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IAAA;AAEf,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB;AACA,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB,OAAO;AACL,UAAI,OAAO;AAAA,IACb;AACA,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB,OAAO;AACL,UAAI,OAAO;AAAA,IACb;AAAA,EACF;AAEA,WAASC,QAAOD,OAAY,MAAMA,MAAK,KAAuB;AAC5D,UAAM,MAAMA,MAAK;AACjB,UAAM,UAAUA,MAAK;AACrB,UAAM,UAAUA,MAAK;AACrB,UAAM,UAAUA,MAAK;AACrB,UAAM,UAAUA,MAAK;AACrB,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB,OAAO;AACL,UAAI,WAAW;AAAA,IACjB;AACA,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB,OAAO;AACL,UAAI,OAAO;AAAA,IACb;AACA,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB,OAAO;AACL,UAAI,WAAW;AAAA,IACjB;AACA,QAAI,YAAY,QAAW;AACzB,cAAQ,UAAU;AAAA,IACpB,YAAY,IAAI,OAAO,aAAa,QAAW;AAC7C,gBAAU,GAAG;AAAA,IACf;AACA,WAAO;AAAA,EACT;AAEA,WAASE,WAAUF,OAAkB;AACnC,QAAI,OAAOA,MAAK;AAChB,QAAI;AAEJ,QAAK,IAAG;AACN,YAAM,MAAMA,MAAK;AACjB,UAAI,QAAQ,IAAI;AAEhB,UACE,EACE,SACC,IACC,IACA,KACA,MAEJ;AACA,YAAI,QAAQ,QAAQ;AAAA,MACtB,WACE,EAAE,SAAS,IAA8B,KACzC;AACA,gBAAQ;AAAA,MACV,WAAW,EAAE,QAAQ,IAA8B;AACjD,YAAI,QAAS,QAAQ,KAA2B;AAAA,MAClD,WACE,EAAE,SAAS,KAAsB,QACjC,YAAYA,OAAM,GAAG,GACrB;AACA,YAAI,QAAQ,SAAS,IAAyB;AAC9C,iBAAS;AAAA,MACX,OAAO;AACL,gBAAQ;AAAA,MACV;AAEA,UAAI,QAAQ,GAAwB;AAClC,eAAO,GAAG;AAAA,MACZ;AAEA,UAAI,QAAQ,GAAuB;AACjC,cAAM,UAAU,IAAI;AACpB,YAAI,YAAY,QAAW;AACzB,gBAAM,WAAWA,QAAO,SAAS;AACjC,cAAI,YAAY,QAAW;AACzB,oBAAQ,EAAE,OAAO,MAAM,MAAM,MAAA;AAC7B,mBAAO;AAAA,UACT;AACA;AAAA,QACF;AAAA,MACF;AAEA,WAAKA,QAAO,UAAW,QAAW;AAChC,eAAOA,MAAK;AACZ;AAAA,MACF;AAEA,aAAO,UAAU,QAAW;AAC1BA,gBAAO,MAAM;AACb,gBAAQ,MAAM;AACd,YAAIA,UAAS,QAAW;AACtB,iBAAOA,MAAK;AACZ,mBAAS;AAAA,QACX;AAAA,MACF;AAEA;AAAA,IACF,SAAS;AAAA,EACX;AAEA,WAASG,YAAWH,OAAY,KAA4B;AAC1D,QAAI;AACJ,QAAI,aAAa;AACjB,QAAI,QAAQ;AAEZ,QAAK,IAAG;AACN,YAAM,MAAMA,MAAK;AACjB,YAAM,QAAQ,IAAI;AAElB,UAAI,IAAI,QAAQ,IAAqB;AACnC,gBAAQ;AAAA,MACV,YACG,SAAS,IAAwB,UACjC,IAAwB,KACzB;AACA,YAAI,OAAO,GAAG,GAAG;AACf,gBAAM,OAAO,IAAI;AACjB,cAAI,KAAK,YAAY,QAAW;AAC9BI,8BAAiB,IAAI;AAAA,UACvB;AACA,kBAAQ;AAAA,QACV;AAAA,MACF,YACG,SAAS,IAAwB,UACjC,IAAwB,KACzB;AACA,YAAIJ,MAAK,YAAY,UAAaA,MAAK,YAAY,QAAW;AAC5D,kBAAQ,EAAE,OAAOA,OAAM,MAAM,MAAA;AAAA,QAC/B;AACAA,gBAAO,IAAI;AACX,cAAM;AACN,UAAE;AACF;AAAA,MACF;AAEA,UAAI,CAAC,OAAO;AACV,cAAM,UAAUA,MAAK;AACrB,YAAI,YAAY,QAAW;AACzBA,kBAAO;AACP;AAAA,QACF;AAAA,MACF;AAEA,aAAO,cAAc;AACnB,cAAM,WAAW,IAAI;AACrB,cAAM,kBAAkB,SAAS,YAAY;AAC7C,YAAI,iBAAiB;AACnBA,kBAAO,MAAO;AACd,kBAAQ,MAAO;AAAA,QACjB,OAAO;AACLA,kBAAO;AAAA,QACT;AACA,YAAI,OAAO;AACT,cAAI,OAAO,GAAG,GAAG;AACf,gBAAI,iBAAiB;AACnBI,gCAAiB,QAAQ;AAAA,YAC3B;AACA,kBAAMJ,MAAK;AACX;AAAA,UACF;AACA,kBAAQ;AAAA,QACV,OAAO;AACL,cAAI,SAAS;AAAA,QACf;AACA,cAAMA,MAAK;AACX,cAAM,UAAUA,MAAK;AACrB,YAAI,YAAY,QAAW;AACzBA,kBAAO;AACP,mBAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS;AAAA,EACX;AAEA,WAASI,kBAAiBJ,OAAkB;AAC1C,OAAG;AACD,YAAM,MAAMA,MAAK;AACjB,YAAM,QAAQ,IAAI;AAClB,WACG,SAAS,KAAwB,SAClC,IACA;AACA,YAAI,QAAQ,QAAQ;AACpB,aACG,SAAS,IAAyB,QACnC,GACA;AACA,iBAAO,GAAG;AAAA,QACZ;AAAA,MACF;AAAA,IACF,UAAUA,QAAOA,MAAK,aAAc;AAAA,EACtC;AAEA,WAAS,YAAY,WAAiB,KAA4B;AAChE,QAAIA,QAAO,IAAI;AACf,WAAOA,UAAS,QAAW;AACzB,UAAIA,UAAS,WAAW;AACtB,eAAO;AAAA,MACT;AACAA,cAAOA,MAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AACF;AAiBA,IAAI,aAAa;AACjB,IAAI,cAAc;AAClB,IAAI,eAAe;AAGnB,MAAM,SAAqC,CAAA;AAC3C,MAAM,EAAE,MAAM,QAAQ,WAAW,YAAY,iBAAA,IAC3C,qBAAqB;AAAA,EACnB,OAAO,MAA0C;AAC/C,QAAI,KAAK,aAAa,QAAW;AAC/B,aAAO,eAAe,IAAoB;AAAA,IAC5C,OAAO;AACL,aAAO,aAAa,IAAkB;AAAA,IACxC;AAAA,EACF;AAAA,EACA,OAAOK,SAAoB;AACzB,QAAI,cAAc;AAClB,QAAI,qBAAqB;AAEzB,OAAG;AACD,aAAO,aAAa,IAAIA;AACxBA,cAAO,SAAS;AAChBA,gBAASA,QAAO,MAAM;AACtB,UAAIA,YAAW,UAAa,EAAEA,QAAO,QAAQ,IAAyB;AACpE;AAAA,MACF;AAAA,IACF,SAAS;AAET,mBAAe;AAEf,WAAO,qBAAqB,EAAE,aAAa;AACzC,YAAM,OAAO,OAAO,kBAAkB;AACtC,aAAO,oBAAoB,IAAI,OAAO,WAAW;AACjD,aAAO,WAAW,IAAI;AAAA,IACxB;AAAA,EACF;AAAA,EACA,UAAU,MAAM;AACd,QAAI,EAAE,KAAK,QAAQ,IAAwB;AACzC,sBAAgB,KAAK,IAAI;AAAA,IAC3B,WAAW,KAAK,aAAa,QAAW;AACtC,WAAK,WAAW;AAChB,WAAK,QAAQ,IAAwB;AACrC,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF;AACF,CAAC;AAYI,SAAS,gBAAwB;AACtC,SAAO;AACT;AAEO,SAAS,aAAa;AAC3B,IAAE;AACJ;AAEO,SAAS,WAAW;AACzB,MAAI,CAAC,EAAE,YAAY;AACjB,UAAA;AAAA,EACF;AACF;AAyHA,SAAS,eAAe,GAA0B;AAEhD,IAAE,WAAW;AACb,IAAE,QAAQ,IAAwB;AAElC,MAAI;AACF,UAAM,WAAW,EAAE;AACnB,WAAO,cAAc,EAAE,QAAQ,EAAE,OAAO,QAAQ;AAAA,EAClD,UAAA;AAEE,MAAE,SAAS;AACX,cAAU,CAAC;AAAA,EACb;AACF;AAEA,SAAS,aAAa,GAAwB;AAC5C,IAAE,QAAQ;AACV,SAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE;AAChD;AAEA,SAAS,IAAI,GAAqB;AAChC,QAAM,QAAQ,EAAE;AAChB,MACE,QAAQ,MACP,QAAQ,MAAyB,WAAW,EAAE,MAAO,CAAC,GACvD;AAEA,MAAE,WAAW;AACb,MAAE,QAAQ,IAAyB;AAEnC,QAAI;AACF;AAAE,QAAiB,GAAA;AAAA,IACrB,UAAA;AAEE,QAAE,SAAS;AACX,gBAAU,CAAC;AAAA,IACb;AAAA,EACF,OAAO;AACL,MAAE,QAAQ;AAAA,EACZ;AACF;AAEA,SAAS,QAAc;AACrB,MAAI;AACF,WAAO,cAAc,cAAc;AACjC,YAAMA,UAAS,OAAO,WAAW;AACjC,aAAO,aAAa,IAAI;AACxB,UAAIA,OAAM;AAAA,IACZ;AAAA,EACF,UAAA;AACE,WAAO,cAAc,cAAc;AACjC,YAAMA,UAAS,OAAO,WAAW;AACjC,aAAO,aAAa,IAAI;AACxBA,cAAO,SAAS,IAAyB;AAAA,IAC3C;AACA,kBAAc;AACd,mBAAe;AAAA,EACjB;AACF;AAsEA,SAAS,kBAA0C;AACjD,OAAK,WAAW;AAChB,OAAK,QAAQ;AACb,YAAU,IAAI;AACd,QAAM,MAAM,KAAK;AACjB,MAAI,QAAQ,QAAW;AACrB,WAAO,GAAG;AAAA,EACZ;AACF;AAEA,SAAS,UAAU,KAAmB;AACpC,QAAM,WAAW,IAAI;AACrB,MAAI,MAAM,aAAa,SAAY,SAAS,UAAU,IAAI;AAC1D,SAAO,QAAQ,QAAW;AACxB,UAAM,OAAO,KAAK,GAAG;AAAA,EACvB;AACF;"} |
| import { Atom, AtomOptions, Observer, ReadonlyAtom } from './types.js'; | ||
| export declare function toObserver<T>(nextHandler?: Observer<T> | ((value: T) => void), errorHandler?: (error: any) => void, completionHandler?: () => void): Observer<T>; | ||
| export declare function flush(): void; | ||
| type AsyncAtomState<TData, TError = unknown> = { | ||
| status: 'pending'; | ||
| } | { | ||
| status: 'done'; | ||
| data: TData; | ||
| } | { | ||
| status: 'error'; | ||
| error: TError; | ||
| }; | ||
| export declare function createAsyncAtom<T>(getValue: () => Promise<T>, options?: AtomOptions<AsyncAtomState<T>>): ReadonlyAtom<AsyncAtomState<T>>; | ||
| export declare function createAtom<T>(getValue: (prev?: NoInfer<T>) => T, options?: AtomOptions<T>): ReadonlyAtom<T>; | ||
| export declare function createAtom<T>(initialValue: T, options?: AtomOptions<T>): Atom<T>; | ||
| export {}; |
+222
| import { createReactiveSystem, ReactiveFlags, getBatchDepth } from "./alien.js"; | ||
| function toObserver(nextHandler, errorHandler, completionHandler) { | ||
| const isObserver = typeof nextHandler === "object"; | ||
| const self = isObserver ? nextHandler : void 0; | ||
| return { | ||
| next: (isObserver ? nextHandler.next : nextHandler)?.bind(self), | ||
| error: (isObserver ? nextHandler.error : errorHandler)?.bind(self), | ||
| complete: (isObserver ? nextHandler.complete : completionHandler)?.bind( | ||
| self | ||
| ) | ||
| }; | ||
| } | ||
| const queuedEffects = []; | ||
| let cycle = 0; | ||
| const { link, unlink, propagate, checkDirty, shallowPropagate } = createReactiveSystem({ | ||
| update(atom) { | ||
| return atom._update(); | ||
| }, | ||
| // eslint-disable-next-line no-shadow | ||
| notify(effect2) { | ||
| queuedEffects[queuedEffectsLength++] = effect2; | ||
| effect2.flags &= ~ReactiveFlags.Watching; | ||
| }, | ||
| unwatched(atom) { | ||
| if (atom.depsTail !== void 0) { | ||
| atom.depsTail = void 0; | ||
| atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty; | ||
| purgeDeps(atom); | ||
| } | ||
| } | ||
| }); | ||
| let notifyIndex = 0; | ||
| let queuedEffectsLength = 0; | ||
| let activeSub; | ||
| function purgeDeps(sub) { | ||
| const depsTail = sub.depsTail; | ||
| let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps; | ||
| while (dep !== void 0) { | ||
| dep = unlink(dep, sub); | ||
| } | ||
| } | ||
| function flush() { | ||
| if (getBatchDepth() > 0) { | ||
| return; | ||
| } | ||
| while (notifyIndex < queuedEffectsLength) { | ||
| const effect2 = queuedEffects[notifyIndex]; | ||
| queuedEffects[notifyIndex++] = void 0; | ||
| effect2.notify(); | ||
| } | ||
| notifyIndex = 0; | ||
| queuedEffectsLength = 0; | ||
| } | ||
| function createAsyncAtom(getValue, options) { | ||
| const ref = {}; | ||
| const atom = createAtom(() => { | ||
| getValue().then( | ||
| (data) => { | ||
| const internalAtom = ref.current; | ||
| if (internalAtom._update({ status: "done", data })) { | ||
| const subs = internalAtom.subs; | ||
| if (subs !== void 0) { | ||
| propagate(subs); | ||
| shallowPropagate(subs); | ||
| flush(); | ||
| } | ||
| } | ||
| }, | ||
| (error) => { | ||
| const internalAtom = ref.current; | ||
| if (internalAtom._update({ status: "error", error })) { | ||
| const subs = internalAtom.subs; | ||
| if (subs !== void 0) { | ||
| propagate(subs); | ||
| shallowPropagate(subs); | ||
| flush(); | ||
| } | ||
| } | ||
| } | ||
| ); | ||
| return { status: "pending" }; | ||
| }, options); | ||
| ref.current = atom; | ||
| return atom; | ||
| } | ||
| function createAtom(valueOrFn, options) { | ||
| const isComputed = typeof valueOrFn === "function"; | ||
| const getter = valueOrFn; | ||
| const atom = { | ||
| _snapshot: isComputed ? void 0 : valueOrFn, | ||
| subs: void 0, | ||
| subsTail: void 0, | ||
| deps: void 0, | ||
| depsTail: void 0, | ||
| flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable, | ||
| get() { | ||
| if (activeSub !== void 0) { | ||
| link(atom, activeSub, cycle); | ||
| } | ||
| return atom._snapshot; | ||
| }, | ||
| subscribe(observerOrFn) { | ||
| const obs = toObserver(observerOrFn); | ||
| const observed = { current: false }; | ||
| const e = effect(() => { | ||
| atom.get(); | ||
| if (!observed.current) { | ||
| observed.current = true; | ||
| } else { | ||
| obs.next?.(atom._snapshot); | ||
| } | ||
| }); | ||
| return { | ||
| unsubscribe: () => { | ||
| e.stop(); | ||
| } | ||
| }; | ||
| }, | ||
| _update(getValue) { | ||
| const prevSub = activeSub; | ||
| const compare = options?.compare ?? Object.is; | ||
| activeSub = atom; | ||
| ++cycle; | ||
| atom.depsTail = void 0; | ||
| if (isComputed) { | ||
| atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck; | ||
| } | ||
| try { | ||
| const oldValue = atom._snapshot; | ||
| const newValue = typeof getValue === "function" ? getValue(oldValue) : getValue === void 0 && isComputed ? getter(oldValue) : getValue; | ||
| if (oldValue === void 0 || !compare(oldValue, newValue)) { | ||
| atom._snapshot = newValue; | ||
| return true; | ||
| } | ||
| return false; | ||
| } finally { | ||
| activeSub = prevSub; | ||
| if (isComputed) { | ||
| atom.flags &= ~ReactiveFlags.RecursedCheck; | ||
| } | ||
| purgeDeps(atom); | ||
| } | ||
| } | ||
| }; | ||
| if (isComputed) { | ||
| atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty; | ||
| atom.get = function() { | ||
| const flags = atom.flags; | ||
| if (flags & ReactiveFlags.Dirty || flags & ReactiveFlags.Pending && checkDirty(atom.deps, atom)) { | ||
| if (atom._update()) { | ||
| const subs = atom.subs; | ||
| if (subs !== void 0) { | ||
| shallowPropagate(subs); | ||
| } | ||
| } | ||
| } else if (flags & ReactiveFlags.Pending) { | ||
| atom.flags = flags & ~ReactiveFlags.Pending; | ||
| } | ||
| if (activeSub !== void 0) { | ||
| link(atom, activeSub, cycle); | ||
| } | ||
| return atom._snapshot; | ||
| }; | ||
| } else { | ||
| atom.set = function(valueOrFn2) { | ||
| if (atom._update(valueOrFn2)) { | ||
| const subs = atom.subs; | ||
| if (subs !== void 0) { | ||
| propagate(subs); | ||
| shallowPropagate(subs); | ||
| flush(); | ||
| } | ||
| } | ||
| }; | ||
| } | ||
| return atom; | ||
| } | ||
| function effect(fn) { | ||
| const run = () => { | ||
| const prevSub = activeSub; | ||
| activeSub = effectObj; | ||
| ++cycle; | ||
| effectObj.depsTail = void 0; | ||
| effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck; | ||
| try { | ||
| return fn(); | ||
| } finally { | ||
| activeSub = prevSub; | ||
| effectObj.flags &= ~ReactiveFlags.RecursedCheck; | ||
| purgeDeps(effectObj); | ||
| } | ||
| }; | ||
| const effectObj = { | ||
| deps: void 0, | ||
| depsTail: void 0, | ||
| subs: void 0, | ||
| subsTail: void 0, | ||
| flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck, | ||
| notify() { | ||
| const flags = this.flags; | ||
| if (flags & ReactiveFlags.Dirty || flags & ReactiveFlags.Pending && checkDirty(this.deps, this)) { | ||
| run(); | ||
| } else { | ||
| this.flags = ReactiveFlags.Watching; | ||
| } | ||
| }, | ||
| stop() { | ||
| this.flags = ReactiveFlags.None; | ||
| this.depsTail = void 0; | ||
| purgeDeps(this); | ||
| } | ||
| }; | ||
| run(); | ||
| return effectObj; | ||
| } | ||
| export { | ||
| createAsyncAtom, | ||
| createAtom, | ||
| flush, | ||
| toObserver | ||
| }; | ||
| //# sourceMappingURL=atom.js.map |
| {"version":3,"file":"atom.js","sources":["../../src/atom.ts"],"sourcesContent":["import { ReactiveFlags, createReactiveSystem, getBatchDepth } from './alien'\n\nimport type { ReactiveNode } from './alien'\nimport type {\n Atom,\n AtomOptions,\n Observer,\n ReadonlyAtom,\n Subscription,\n} from './types'\n\nexport function toObserver<T>(\n nextHandler?: Observer<T> | ((value: T) => void),\n errorHandler?: (error: any) => void,\n completionHandler?: () => void,\n): Observer<T> {\n const isObserver = typeof nextHandler === 'object'\n const self = isObserver ? nextHandler : undefined\n\n return {\n next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),\n error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),\n complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(\n self,\n ),\n }\n}\n\ninterface InternalAtom<T> extends ReactiveNode {\n _snapshot: T\n _update: (getValue?: T | ((snapshot: T) => T)) => boolean\n get: () => T\n subscribe: (observerOrFn: Observer<T> | ((value: T) => void)) => Subscription\n}\n\nconst queuedEffects: Array<Effect | undefined> = []\nlet cycle = 0\nconst { link, unlink, propagate, checkDirty, shallowPropagate } =\n createReactiveSystem({\n update(atom: InternalAtom<any>): boolean {\n return atom._update()\n },\n // eslint-disable-next-line no-shadow\n notify(effect: Effect): void {\n queuedEffects[queuedEffectsLength++] = effect\n effect.flags &= ~ReactiveFlags.Watching\n },\n unwatched(atom: InternalAtom<any>): void {\n if (atom.depsTail !== undefined) {\n atom.depsTail = undefined\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n purgeDeps(atom)\n }\n },\n })\n\nlet notifyIndex = 0\nlet queuedEffectsLength = 0\nlet activeSub: ReactiveNode | undefined\n\nfunction purgeDeps(sub: ReactiveNode) {\n const depsTail = sub.depsTail\n let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps\n while (dep !== undefined) {\n dep = unlink(dep, sub)\n }\n}\n\nexport function flush(): void {\n if (getBatchDepth() > 0) {\n return\n }\n while (notifyIndex < queuedEffectsLength) {\n // eslint-disable-next-line no-shadow\n const effect = queuedEffects[notifyIndex]!\n queuedEffects[notifyIndex++] = undefined\n effect.notify()\n }\n notifyIndex = 0\n queuedEffectsLength = 0\n}\n\ntype AsyncAtomState<TData, TError = unknown> =\n | { status: 'pending' }\n | { status: 'done'; data: TData }\n | { status: 'error'; error: TError }\n\nexport function createAsyncAtom<T>(\n getValue: () => Promise<T>,\n options?: AtomOptions<AsyncAtomState<T>>,\n): ReadonlyAtom<AsyncAtomState<T>> {\n const ref: { current?: InternalAtom<AsyncAtomState<T>> } = {}\n const atom = createAtom<AsyncAtomState<T>>(() => {\n getValue().then(\n (data) => {\n const internalAtom = ref.current!\n if (internalAtom._update({ status: 'done', data })) {\n const subs = internalAtom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n },\n (error) => {\n const internalAtom = ref.current!\n if (internalAtom._update({ status: 'error', error })) {\n const subs = internalAtom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n },\n )\n\n return { status: 'pending' }\n }, options)\n ref.current = atom as unknown as InternalAtom<AsyncAtomState<T>>\n\n return atom\n}\n\nexport function createAtom<T>(\n getValue: (prev?: NoInfer<T>) => T,\n options?: AtomOptions<T>,\n): ReadonlyAtom<T>\nexport function createAtom<T>(\n initialValue: T,\n options?: AtomOptions<T>,\n): Atom<T>\nexport function createAtom<T>(\n valueOrFn: T | ((prev?: T) => T),\n options?: AtomOptions<T>,\n): Atom<T> | ReadonlyAtom<T> {\n const isComputed = typeof valueOrFn === 'function'\n const getter = valueOrFn as (prev?: T) => T\n\n // Create plain object atom\n const atom: InternalAtom<T> = {\n _snapshot: isComputed ? undefined! : valueOrFn,\n\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable,\n\n get(): T {\n if (activeSub !== undefined) {\n link(atom, activeSub, cycle)\n }\n return atom._snapshot\n },\n\n subscribe(observerOrFn: Observer<T> | ((value: T) => void)) {\n const obs = toObserver(observerOrFn)\n const observed = { current: false }\n const e = effect(() => {\n atom.get()\n if (!observed.current) {\n observed.current = true\n } else {\n obs.next?.(atom._snapshot)\n }\n })\n\n return {\n unsubscribe: () => {\n e.stop()\n },\n }\n },\n _update(getValue?: T | ((snapshot: T) => T)): boolean {\n const prevSub = activeSub\n const compare = options?.compare ?? Object.is\n activeSub = atom\n ++cycle\n atom.depsTail = undefined\n if (isComputed) {\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck\n }\n try {\n const oldValue = atom._snapshot\n const newValue =\n typeof getValue === 'function'\n ? (getValue as (snapshot: T) => T)(oldValue)\n : getValue === undefined && isComputed\n ? getter(oldValue)\n : getValue!\n if (oldValue === undefined || !compare(oldValue, newValue)) {\n atom._snapshot = newValue\n return true\n }\n return false\n } finally {\n activeSub = prevSub\n if (isComputed) {\n atom.flags &= ~ReactiveFlags.RecursedCheck\n }\n purgeDeps(atom)\n }\n },\n }\n\n if (isComputed) {\n atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty\n atom.get = function (): T {\n const flags = atom.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(atom.deps!, atom))\n ) {\n if (atom._update()) {\n const subs = atom.subs\n if (subs !== undefined) {\n shallowPropagate(subs)\n }\n }\n } else if (flags & ReactiveFlags.Pending) {\n atom.flags = flags & ~ReactiveFlags.Pending\n }\n if (activeSub !== undefined) {\n link(atom, activeSub, cycle)\n }\n return atom._snapshot\n }\n } else {\n ;(atom as unknown as Atom<T>).set = function (\n // eslint-disable-next-line no-shadow\n valueOrFn: T | ((prev: T) => T),\n ): void {\n if (atom._update(valueOrFn)) {\n const subs = atom.subs\n if (subs !== undefined) {\n propagate(subs)\n shallowPropagate(subs)\n flush()\n }\n }\n }\n }\n\n return atom as unknown as Atom<T> | ReadonlyAtom<T>\n}\n\ninterface Effect extends ReactiveNode {\n notify: () => void\n stop: () => void\n}\n\nfunction effect<T>(fn: () => T): Effect {\n const run = (): T => {\n const prevSub = activeSub\n activeSub = effectObj\n ++cycle\n effectObj.depsTail = undefined\n effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck\n try {\n return fn()\n } finally {\n activeSub = prevSub\n effectObj.flags &= ~ReactiveFlags.RecursedCheck\n purgeDeps(effectObj)\n }\n }\n const effectObj: Effect = {\n deps: undefined,\n depsTail: undefined,\n subs: undefined,\n subsTail: undefined,\n flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,\n\n notify(): void {\n const flags = this.flags\n if (\n flags & ReactiveFlags.Dirty ||\n (flags & ReactiveFlags.Pending && checkDirty(this.deps!, this))\n ) {\n run()\n } else {\n this.flags = ReactiveFlags.Watching\n }\n },\n\n stop(): void {\n this.flags = ReactiveFlags.None\n this.depsTail = undefined\n purgeDeps(this)\n },\n }\n\n run()\n\n return effectObj\n}\n"],"names":["effect","valueOrFn"],"mappings":"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"} |
| export declare function batch(fn: () => void): void; |
| import { startBatch, endBatch } from "./alien.js"; | ||
| import { flush } from "./atom.js"; | ||
| function batch(fn) { | ||
| try { | ||
| startBatch(); | ||
| fn(); | ||
| } finally { | ||
| endBatch(); | ||
| flush(); | ||
| } | ||
| } | ||
| export { | ||
| batch | ||
| }; | ||
| //# sourceMappingURL=batch.js.map |
| {"version":3,"file":"batch.js","sources":["../../src/batch.ts"],"sourcesContent":["import { endBatch, startBatch } from './alien'\nimport { flush } from './atom'\n\nexport function batch(fn: () => void) {\n try {\n startBatch()\n fn()\n } finally {\n endBatch()\n flush()\n }\n}\n"],"names":[],"mappings":";;AAGO,SAAS,MAAM,IAAgB;AACpC,MAAI;AACF,eAAA;AACA,OAAA;AAAA,EACF,UAAA;AACE,aAAA;AACA,UAAA;AAAA,EACF;AACF;"} |
+654
| /* eslint-disable */ | ||
| // Adapted from Alien Signals | ||
| // https://github.com/stackblitz/alien-signals/ | ||
| export interface ReactiveNode { | ||
| deps?: Link | ||
| depsTail?: Link | ||
| subs?: Link | ||
| subsTail?: Link | ||
| flags: ReactiveFlags | ||
| } | ||
| export interface Link { | ||
| version: number | ||
| dep: ReactiveNode | ||
| sub: ReactiveNode | ||
| prevSub: Link | undefined | ||
| nextSub: Link | undefined | ||
| prevDep: Link | undefined | ||
| nextDep: Link | undefined | ||
| } | ||
| interface Stack<T> { | ||
| value: T | ||
| prev: Stack<T> | undefined | ||
| } | ||
| export const enum ReactiveFlags { | ||
| None = 0, | ||
| Mutable = 1, | ||
| Watching = 2, | ||
| RecursedCheck = 4, | ||
| Recursed = 8, | ||
| Dirty = 16, | ||
| Pending = 32, | ||
| } | ||
| export function createReactiveSystem({ | ||
| update, | ||
| notify, | ||
| unwatched, | ||
| }: { | ||
| update(sub: ReactiveNode): boolean | ||
| notify(sub: ReactiveNode): void | ||
| unwatched(sub: ReactiveNode): void | ||
| }) { | ||
| return { | ||
| link, | ||
| unlink, | ||
| propagate, | ||
| checkDirty, | ||
| shallowPropagate, | ||
| } | ||
| function link(dep: ReactiveNode, sub: ReactiveNode, version: number): void { | ||
| const prevDep = sub.depsTail | ||
| if (prevDep !== undefined && prevDep.dep === dep) { | ||
| return | ||
| } | ||
| const nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps | ||
| if (nextDep !== undefined && nextDep.dep === dep) { | ||
| nextDep.version = version | ||
| sub.depsTail = nextDep | ||
| return | ||
| } | ||
| const prevSub = dep.subsTail | ||
| if ( | ||
| prevSub !== undefined && | ||
| prevSub.version === version && | ||
| prevSub.sub === sub | ||
| ) { | ||
| return | ||
| } | ||
| const newLink = | ||
| (sub.depsTail = | ||
| dep.subsTail = | ||
| { | ||
| version, | ||
| dep, | ||
| sub, | ||
| prevDep, | ||
| nextDep, | ||
| prevSub, | ||
| nextSub: undefined, | ||
| }) | ||
| if (nextDep !== undefined) { | ||
| nextDep.prevDep = newLink | ||
| } | ||
| if (prevDep !== undefined) { | ||
| prevDep.nextDep = newLink | ||
| } else { | ||
| sub.deps = newLink | ||
| } | ||
| if (prevSub !== undefined) { | ||
| prevSub.nextSub = newLink | ||
| } else { | ||
| dep.subs = newLink | ||
| } | ||
| } | ||
| function unlink(link: Link, sub = link.sub): Link | undefined { | ||
| const dep = link.dep | ||
| const prevDep = link.prevDep | ||
| const nextDep = link.nextDep | ||
| const nextSub = link.nextSub | ||
| const prevSub = link.prevSub | ||
| if (nextDep !== undefined) { | ||
| nextDep.prevDep = prevDep | ||
| } else { | ||
| sub.depsTail = prevDep | ||
| } | ||
| if (prevDep !== undefined) { | ||
| prevDep.nextDep = nextDep | ||
| } else { | ||
| sub.deps = nextDep | ||
| } | ||
| if (nextSub !== undefined) { | ||
| nextSub.prevSub = prevSub | ||
| } else { | ||
| dep.subsTail = prevSub | ||
| } | ||
| if (prevSub !== undefined) { | ||
| prevSub.nextSub = nextSub | ||
| } else if ((dep.subs = nextSub) === undefined) { | ||
| unwatched(dep) | ||
| } | ||
| return nextDep | ||
| } | ||
| function propagate(link: Link): void { | ||
| let next = link.nextSub | ||
| let stack: Stack<Link | undefined> | undefined | ||
| top: do { | ||
| const sub = link.sub | ||
| let flags = sub.flags | ||
| if ( | ||
| !( | ||
| flags & | ||
| (ReactiveFlags.RecursedCheck | | ||
| ReactiveFlags.Recursed | | ||
| ReactiveFlags.Dirty | | ||
| ReactiveFlags.Pending) | ||
| ) | ||
| ) { | ||
| sub.flags = flags | ReactiveFlags.Pending | ||
| } else if ( | ||
| !(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed)) | ||
| ) { | ||
| flags = ReactiveFlags.None | ||
| } else if (!(flags & ReactiveFlags.RecursedCheck)) { | ||
| sub.flags = (flags & ~ReactiveFlags.Recursed) | ReactiveFlags.Pending | ||
| } else if ( | ||
| !(flags & (ReactiveFlags.Dirty | ReactiveFlags.Pending)) && | ||
| isValidLink(link, sub) | ||
| ) { | ||
| sub.flags = flags | (ReactiveFlags.Recursed | ReactiveFlags.Pending) | ||
| flags &= ReactiveFlags.Mutable | ||
| } else { | ||
| flags = ReactiveFlags.None | ||
| } | ||
| if (flags & ReactiveFlags.Watching) { | ||
| notify(sub) | ||
| } | ||
| if (flags & ReactiveFlags.Mutable) { | ||
| const subSubs = sub.subs | ||
| if (subSubs !== undefined) { | ||
| const nextSub = (link = subSubs).nextSub | ||
| if (nextSub !== undefined) { | ||
| stack = { value: next, prev: stack } | ||
| next = nextSub | ||
| } | ||
| continue | ||
| } | ||
| } | ||
| if ((link = next!) !== undefined) { | ||
| next = link.nextSub | ||
| continue | ||
| } | ||
| while (stack !== undefined) { | ||
| link = stack.value! | ||
| stack = stack.prev | ||
| if (link !== undefined) { | ||
| next = link.nextSub | ||
| continue top | ||
| } | ||
| } | ||
| break | ||
| } while (true) | ||
| } | ||
| function checkDirty(link: Link, sub: ReactiveNode): boolean { | ||
| let stack: Stack<Link> | undefined | ||
| let checkDepth = 0 | ||
| let dirty = false | ||
| top: do { | ||
| const dep = link.dep | ||
| const flags = dep.flags | ||
| if (sub.flags & ReactiveFlags.Dirty) { | ||
| dirty = true | ||
| } else if ( | ||
| (flags & (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) === | ||
| (ReactiveFlags.Mutable | ReactiveFlags.Dirty) | ||
| ) { | ||
| if (update(dep)) { | ||
| const subs = dep.subs! | ||
| if (subs.nextSub !== undefined) { | ||
| shallowPropagate(subs) | ||
| } | ||
| dirty = true | ||
| } | ||
| } else if ( | ||
| (flags & (ReactiveFlags.Mutable | ReactiveFlags.Pending)) === | ||
| (ReactiveFlags.Mutable | ReactiveFlags.Pending) | ||
| ) { | ||
| if (link.nextSub !== undefined || link.prevSub !== undefined) { | ||
| stack = { value: link, prev: stack } | ||
| } | ||
| link = dep.deps! | ||
| sub = dep | ||
| ++checkDepth | ||
| continue | ||
| } | ||
| if (!dirty) { | ||
| const nextDep = link.nextDep | ||
| if (nextDep !== undefined) { | ||
| link = nextDep | ||
| continue | ||
| } | ||
| } | ||
| while (checkDepth--) { | ||
| const firstSub = sub.subs! | ||
| const hasMultipleSubs = firstSub.nextSub !== undefined | ||
| if (hasMultipleSubs) { | ||
| link = stack!.value | ||
| stack = stack!.prev | ||
| } else { | ||
| link = firstSub | ||
| } | ||
| if (dirty) { | ||
| if (update(sub)) { | ||
| if (hasMultipleSubs) { | ||
| shallowPropagate(firstSub) | ||
| } | ||
| sub = link.sub | ||
| continue | ||
| } | ||
| dirty = false | ||
| } else { | ||
| sub.flags &= ~ReactiveFlags.Pending | ||
| } | ||
| sub = link.sub | ||
| const nextDep = link.nextDep | ||
| if (nextDep !== undefined) { | ||
| link = nextDep | ||
| continue top | ||
| } | ||
| } | ||
| return dirty | ||
| } while (true) | ||
| } | ||
| function shallowPropagate(link: Link): void { | ||
| do { | ||
| const sub = link.sub | ||
| const flags = sub.flags | ||
| if ( | ||
| (flags & (ReactiveFlags.Pending | ReactiveFlags.Dirty)) === | ||
| ReactiveFlags.Pending | ||
| ) { | ||
| sub.flags = flags | ReactiveFlags.Dirty | ||
| if ( | ||
| (flags & (ReactiveFlags.Watching | ReactiveFlags.RecursedCheck)) === | ||
| ReactiveFlags.Watching | ||
| ) { | ||
| notify(sub) | ||
| } | ||
| } | ||
| } while ((link = link.nextSub!) !== undefined) | ||
| } | ||
| function isValidLink(checkLink: Link, sub: ReactiveNode): boolean { | ||
| let link = sub.depsTail | ||
| while (link !== undefined) { | ||
| if (link === checkLink) { | ||
| return true | ||
| } | ||
| link = link.prevDep | ||
| } | ||
| return false | ||
| } | ||
| } | ||
| interface EffectNode extends ReactiveNode { | ||
| fn(): void | ||
| } | ||
| interface ComputedNode<T = any> extends ReactiveNode { | ||
| value: T | undefined | ||
| getter: (previousValue?: T) => T | ||
| } | ||
| interface SignalNode<T = any> extends ReactiveNode { | ||
| currentValue: T | ||
| pendingValue: T | ||
| } | ||
| let cycle = 0 | ||
| let batchDepth = 0 | ||
| let notifyIndex = 0 | ||
| let queuedLength = 0 | ||
| let activeSub: ReactiveNode | undefined | ||
| const queued: (EffectNode | undefined)[] = [] | ||
| const { link, unlink, propagate, checkDirty, shallowPropagate } = | ||
| createReactiveSystem({ | ||
| update(node: SignalNode | ComputedNode): boolean { | ||
| if (node.depsTail !== undefined) { | ||
| return updateComputed(node as ComputedNode) | ||
| } else { | ||
| return updateSignal(node as SignalNode) | ||
| } | ||
| }, | ||
| notify(effect: EffectNode) { | ||
| let insertIndex = queuedLength | ||
| let firstInsertedIndex = insertIndex | ||
| do { | ||
| queued[insertIndex++] = effect | ||
| effect.flags &= ~ReactiveFlags.Watching | ||
| effect = effect.subs?.sub as EffectNode | ||
| if (effect === undefined || !(effect.flags & ReactiveFlags.Watching)) { | ||
| break | ||
| } | ||
| } while (true) | ||
| queuedLength = insertIndex | ||
| while (firstInsertedIndex < --insertIndex) { | ||
| const left = queued[firstInsertedIndex] | ||
| queued[firstInsertedIndex++] = queued[insertIndex] | ||
| queued[insertIndex] = left | ||
| } | ||
| }, | ||
| unwatched(node) { | ||
| if (!(node.flags & ReactiveFlags.Mutable)) { | ||
| effectScopeOper.call(node) | ||
| } else if (node.depsTail !== undefined) { | ||
| node.depsTail = undefined | ||
| node.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty | ||
| purgeDeps(node) | ||
| } | ||
| }, | ||
| }) | ||
| export function getActiveSub(): ReactiveNode | undefined { | ||
| return activeSub | ||
| } | ||
| export function setActiveSub(sub?: ReactiveNode) { | ||
| const prevSub = activeSub | ||
| activeSub = sub | ||
| return prevSub | ||
| } | ||
| export function getBatchDepth(): number { | ||
| return batchDepth | ||
| } | ||
| export function startBatch() { | ||
| ++batchDepth | ||
| } | ||
| export function endBatch() { | ||
| if (!--batchDepth) { | ||
| flush() | ||
| } | ||
| } | ||
| export function isSignal(fn: () => void): boolean { | ||
| return fn.name === 'bound ' + signalOper.name | ||
| } | ||
| export function isComputed(fn: () => void): boolean { | ||
| return fn.name === 'bound ' + computedOper.name | ||
| } | ||
| export function isEffect(fn: () => void): boolean { | ||
| return fn.name === 'bound ' + effectOper.name | ||
| } | ||
| export function isEffectScope(fn: () => void): boolean { | ||
| return fn.name === 'bound ' + effectScopeOper.name | ||
| } | ||
| export function signal<T>(): { | ||
| (): T | undefined | ||
| (value: T | undefined): void | ||
| } | ||
| export function signal<T>(initialValue: T): { | ||
| (): T | ||
| (value: T): void | ||
| } | ||
| export function signal<T>(initialValue?: T): { | ||
| (): T | undefined | ||
| (value: T | undefined): void | ||
| } { | ||
| return signalOper.bind({ | ||
| currentValue: initialValue, | ||
| pendingValue: initialValue, | ||
| subs: undefined, | ||
| subsTail: undefined, | ||
| flags: ReactiveFlags.Mutable, | ||
| }) as () => T | undefined | ||
| } | ||
| export function computed<T>(getter: (previousValue?: T) => T): () => T { | ||
| return computedOper.bind({ | ||
| value: undefined, | ||
| subs: undefined, | ||
| subsTail: undefined, | ||
| deps: undefined, | ||
| depsTail: undefined, | ||
| flags: ReactiveFlags.None, | ||
| getter: getter as (previousValue?: unknown) => unknown, | ||
| }) as () => T | ||
| } | ||
| export function effect(fn: () => void): () => void { | ||
| const e: EffectNode = { | ||
| fn, | ||
| subs: undefined, | ||
| subsTail: undefined, | ||
| deps: undefined, | ||
| depsTail: undefined, | ||
| flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck, | ||
| } | ||
| const prevSub = setActiveSub(e) | ||
| if (prevSub !== undefined) { | ||
| link(e, prevSub, 0) | ||
| } | ||
| try { | ||
| e.fn() | ||
| } finally { | ||
| activeSub = prevSub | ||
| e.flags &= ~ReactiveFlags.RecursedCheck | ||
| } | ||
| return effectOper.bind(e) | ||
| } | ||
| export function effectScope(fn: () => void): () => void { | ||
| const e: ReactiveNode = { | ||
| deps: undefined, | ||
| depsTail: undefined, | ||
| subs: undefined, | ||
| subsTail: undefined, | ||
| flags: ReactiveFlags.None, | ||
| } | ||
| const prevSub = setActiveSub(e) | ||
| if (prevSub !== undefined) { | ||
| link(e, prevSub, 0) | ||
| } | ||
| try { | ||
| fn() | ||
| } finally { | ||
| activeSub = prevSub | ||
| } | ||
| return effectScopeOper.bind(e) | ||
| } | ||
| export function trigger(fn: () => void) { | ||
| const sub: ReactiveNode = { | ||
| deps: undefined, | ||
| depsTail: undefined, | ||
| flags: ReactiveFlags.Watching, | ||
| } | ||
| const prevSub = setActiveSub(sub) | ||
| try { | ||
| fn() | ||
| } finally { | ||
| activeSub = prevSub | ||
| let link = sub.deps | ||
| while (link !== undefined) { | ||
| const dep = link.dep | ||
| link = unlink(link, sub) | ||
| const subs = dep.subs | ||
| if (subs !== undefined) { | ||
| sub.flags = ReactiveFlags.None | ||
| propagate(subs) | ||
| shallowPropagate(subs) | ||
| } | ||
| } | ||
| if (!batchDepth) { | ||
| flush() | ||
| } | ||
| } | ||
| } | ||
| function updateComputed(c: ComputedNode): boolean { | ||
| ++cycle | ||
| c.depsTail = undefined | ||
| c.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck | ||
| const prevSub = setActiveSub(c) | ||
| try { | ||
| const oldValue = c.value | ||
| return oldValue !== (c.value = c.getter(oldValue)) | ||
| } finally { | ||
| activeSub = prevSub | ||
| c.flags &= ~ReactiveFlags.RecursedCheck | ||
| purgeDeps(c) | ||
| } | ||
| } | ||
| function updateSignal(s: SignalNode): boolean { | ||
| s.flags = ReactiveFlags.Mutable | ||
| return s.currentValue !== (s.currentValue = s.pendingValue) | ||
| } | ||
| function run(e: EffectNode): void { | ||
| const flags = e.flags | ||
| if ( | ||
| flags & ReactiveFlags.Dirty || | ||
| (flags & ReactiveFlags.Pending && checkDirty(e.deps!, e)) | ||
| ) { | ||
| ++cycle | ||
| e.depsTail = undefined | ||
| e.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck | ||
| const prevSub = setActiveSub(e) | ||
| try { | ||
| ;(e as EffectNode).fn() | ||
| } finally { | ||
| activeSub = prevSub | ||
| e.flags &= ~ReactiveFlags.RecursedCheck | ||
| purgeDeps(e) | ||
| } | ||
| } else { | ||
| e.flags = ReactiveFlags.Watching | ||
| } | ||
| } | ||
| function flush(): void { | ||
| try { | ||
| while (notifyIndex < queuedLength) { | ||
| const effect = queued[notifyIndex]! | ||
| queued[notifyIndex++] = undefined | ||
| run(effect) | ||
| } | ||
| } finally { | ||
| while (notifyIndex < queuedLength) { | ||
| const effect = queued[notifyIndex]! | ||
| queued[notifyIndex++] = undefined | ||
| effect.flags |= ReactiveFlags.Watching | ReactiveFlags.Recursed | ||
| } | ||
| notifyIndex = 0 | ||
| queuedLength = 0 | ||
| } | ||
| } | ||
| function computedOper<T>(this: ComputedNode<T>): T { | ||
| const flags = this.flags | ||
| if ( | ||
| flags & ReactiveFlags.Dirty || | ||
| (flags & ReactiveFlags.Pending && | ||
| (checkDirty(this.deps!, this) || | ||
| ((this.flags = flags & ~ReactiveFlags.Pending), false))) | ||
| ) { | ||
| if (updateComputed(this)) { | ||
| const subs = this.subs | ||
| if (subs !== undefined) { | ||
| shallowPropagate(subs) | ||
| } | ||
| } | ||
| } else if (!flags) { | ||
| this.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck | ||
| const prevSub = setActiveSub(this) | ||
| try { | ||
| this.value = this.getter() | ||
| } finally { | ||
| activeSub = prevSub | ||
| this.flags &= ~ReactiveFlags.RecursedCheck | ||
| } | ||
| } | ||
| const sub = activeSub | ||
| if (sub !== undefined) { | ||
| link(this, sub, cycle) | ||
| } | ||
| return this.value! | ||
| } | ||
| function signalOper<T>(this: SignalNode<T>, ...value: [T]): T | void { | ||
| if (value.length) { | ||
| if (this.pendingValue !== (this.pendingValue = value[0])) { | ||
| this.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty | ||
| const subs = this.subs | ||
| if (subs !== undefined) { | ||
| propagate(subs) | ||
| if (!batchDepth) { | ||
| flush() | ||
| } | ||
| } | ||
| } | ||
| } else { | ||
| if (this.flags & ReactiveFlags.Dirty) { | ||
| if (updateSignal(this)) { | ||
| const subs = this.subs | ||
| if (subs !== undefined) { | ||
| shallowPropagate(subs) | ||
| } | ||
| } | ||
| } | ||
| let sub = activeSub | ||
| while (sub !== undefined) { | ||
| if (sub.flags & (ReactiveFlags.Mutable | ReactiveFlags.Watching)) { | ||
| link(this, sub, cycle) | ||
| break | ||
| } | ||
| sub = sub.subs?.sub | ||
| } | ||
| return this.currentValue | ||
| } | ||
| } | ||
| function effectOper(this: EffectNode): void { | ||
| effectScopeOper.call(this) | ||
| } | ||
| function effectScopeOper(this: ReactiveNode): void { | ||
| this.depsTail = undefined | ||
| this.flags = ReactiveFlags.None | ||
| purgeDeps(this) | ||
| const sub = this.subs | ||
| if (sub !== undefined) { | ||
| unlink(sub) | ||
| } | ||
| } | ||
| function purgeDeps(sub: ReactiveNode) { | ||
| const depsTail = sub.depsTail | ||
| let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps | ||
| while (dep !== undefined) { | ||
| dep = unlink(dep, sub) | ||
| } | ||
| } |
+298
| import { ReactiveFlags, createReactiveSystem, getBatchDepth } from './alien' | ||
| import type { ReactiveNode } from './alien' | ||
| import type { | ||
| Atom, | ||
| AtomOptions, | ||
| Observer, | ||
| ReadonlyAtom, | ||
| Subscription, | ||
| } from './types' | ||
| export function toObserver<T>( | ||
| nextHandler?: Observer<T> | ((value: T) => void), | ||
| errorHandler?: (error: any) => void, | ||
| completionHandler?: () => void, | ||
| ): Observer<T> { | ||
| const isObserver = typeof nextHandler === 'object' | ||
| const self = isObserver ? nextHandler : undefined | ||
| return { | ||
| next: (isObserver ? nextHandler.next : nextHandler)?.bind(self), | ||
| error: (isObserver ? nextHandler.error : errorHandler)?.bind(self), | ||
| complete: (isObserver ? nextHandler.complete : completionHandler)?.bind( | ||
| self, | ||
| ), | ||
| } | ||
| } | ||
| interface InternalAtom<T> extends ReactiveNode { | ||
| _snapshot: T | ||
| _update: (getValue?: T | ((snapshot: T) => T)) => boolean | ||
| get: () => T | ||
| subscribe: (observerOrFn: Observer<T> | ((value: T) => void)) => Subscription | ||
| } | ||
| const queuedEffects: Array<Effect | undefined> = [] | ||
| let cycle = 0 | ||
| const { link, unlink, propagate, checkDirty, shallowPropagate } = | ||
| createReactiveSystem({ | ||
| update(atom: InternalAtom<any>): boolean { | ||
| return atom._update() | ||
| }, | ||
| // eslint-disable-next-line no-shadow | ||
| notify(effect: Effect): void { | ||
| queuedEffects[queuedEffectsLength++] = effect | ||
| effect.flags &= ~ReactiveFlags.Watching | ||
| }, | ||
| unwatched(atom: InternalAtom<any>): void { | ||
| if (atom.depsTail !== undefined) { | ||
| atom.depsTail = undefined | ||
| atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty | ||
| purgeDeps(atom) | ||
| } | ||
| }, | ||
| }) | ||
| let notifyIndex = 0 | ||
| let queuedEffectsLength = 0 | ||
| let activeSub: ReactiveNode | undefined | ||
| function purgeDeps(sub: ReactiveNode) { | ||
| const depsTail = sub.depsTail | ||
| let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps | ||
| while (dep !== undefined) { | ||
| dep = unlink(dep, sub) | ||
| } | ||
| } | ||
| export function flush(): void { | ||
| if (getBatchDepth() > 0) { | ||
| return | ||
| } | ||
| while (notifyIndex < queuedEffectsLength) { | ||
| // eslint-disable-next-line no-shadow | ||
| const effect = queuedEffects[notifyIndex]! | ||
| queuedEffects[notifyIndex++] = undefined | ||
| effect.notify() | ||
| } | ||
| notifyIndex = 0 | ||
| queuedEffectsLength = 0 | ||
| } | ||
| type AsyncAtomState<TData, TError = unknown> = | ||
| | { status: 'pending' } | ||
| | { status: 'done'; data: TData } | ||
| | { status: 'error'; error: TError } | ||
| export function createAsyncAtom<T>( | ||
| getValue: () => Promise<T>, | ||
| options?: AtomOptions<AsyncAtomState<T>>, | ||
| ): ReadonlyAtom<AsyncAtomState<T>> { | ||
| const ref: { current?: InternalAtom<AsyncAtomState<T>> } = {} | ||
| const atom = createAtom<AsyncAtomState<T>>(() => { | ||
| getValue().then( | ||
| (data) => { | ||
| const internalAtom = ref.current! | ||
| if (internalAtom._update({ status: 'done', data })) { | ||
| const subs = internalAtom.subs | ||
| if (subs !== undefined) { | ||
| propagate(subs) | ||
| shallowPropagate(subs) | ||
| flush() | ||
| } | ||
| } | ||
| }, | ||
| (error) => { | ||
| const internalAtom = ref.current! | ||
| if (internalAtom._update({ status: 'error', error })) { | ||
| const subs = internalAtom.subs | ||
| if (subs !== undefined) { | ||
| propagate(subs) | ||
| shallowPropagate(subs) | ||
| flush() | ||
| } | ||
| } | ||
| }, | ||
| ) | ||
| return { status: 'pending' } | ||
| }, options) | ||
| ref.current = atom as unknown as InternalAtom<AsyncAtomState<T>> | ||
| return atom | ||
| } | ||
| export function createAtom<T>( | ||
| getValue: (prev?: NoInfer<T>) => T, | ||
| options?: AtomOptions<T>, | ||
| ): ReadonlyAtom<T> | ||
| export function createAtom<T>( | ||
| initialValue: T, | ||
| options?: AtomOptions<T>, | ||
| ): Atom<T> | ||
| export function createAtom<T>( | ||
| valueOrFn: T | ((prev?: T) => T), | ||
| options?: AtomOptions<T>, | ||
| ): Atom<T> | ReadonlyAtom<T> { | ||
| const isComputed = typeof valueOrFn === 'function' | ||
| const getter = valueOrFn as (prev?: T) => T | ||
| // Create plain object atom | ||
| const atom: InternalAtom<T> = { | ||
| _snapshot: isComputed ? undefined! : valueOrFn, | ||
| subs: undefined, | ||
| subsTail: undefined, | ||
| deps: undefined, | ||
| depsTail: undefined, | ||
| flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable, | ||
| get(): T { | ||
| if (activeSub !== undefined) { | ||
| link(atom, activeSub, cycle) | ||
| } | ||
| return atom._snapshot | ||
| }, | ||
| subscribe(observerOrFn: Observer<T> | ((value: T) => void)) { | ||
| const obs = toObserver(observerOrFn) | ||
| const observed = { current: false } | ||
| const e = effect(() => { | ||
| atom.get() | ||
| if (!observed.current) { | ||
| observed.current = true | ||
| } else { | ||
| obs.next?.(atom._snapshot) | ||
| } | ||
| }) | ||
| return { | ||
| unsubscribe: () => { | ||
| e.stop() | ||
| }, | ||
| } | ||
| }, | ||
| _update(getValue?: T | ((snapshot: T) => T)): boolean { | ||
| const prevSub = activeSub | ||
| const compare = options?.compare ?? Object.is | ||
| activeSub = atom | ||
| ++cycle | ||
| atom.depsTail = undefined | ||
| if (isComputed) { | ||
| atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck | ||
| } | ||
| try { | ||
| const oldValue = atom._snapshot | ||
| const newValue = | ||
| typeof getValue === 'function' | ||
| ? (getValue as (snapshot: T) => T)(oldValue) | ||
| : getValue === undefined && isComputed | ||
| ? getter(oldValue) | ||
| : getValue! | ||
| if (oldValue === undefined || !compare(oldValue, newValue)) { | ||
| atom._snapshot = newValue | ||
| return true | ||
| } | ||
| return false | ||
| } finally { | ||
| activeSub = prevSub | ||
| if (isComputed) { | ||
| atom.flags &= ~ReactiveFlags.RecursedCheck | ||
| } | ||
| purgeDeps(atom) | ||
| } | ||
| }, | ||
| } | ||
| if (isComputed) { | ||
| atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty | ||
| atom.get = function (): T { | ||
| const flags = atom.flags | ||
| if ( | ||
| flags & ReactiveFlags.Dirty || | ||
| (flags & ReactiveFlags.Pending && checkDirty(atom.deps!, atom)) | ||
| ) { | ||
| if (atom._update()) { | ||
| const subs = atom.subs | ||
| if (subs !== undefined) { | ||
| shallowPropagate(subs) | ||
| } | ||
| } | ||
| } else if (flags & ReactiveFlags.Pending) { | ||
| atom.flags = flags & ~ReactiveFlags.Pending | ||
| } | ||
| if (activeSub !== undefined) { | ||
| link(atom, activeSub, cycle) | ||
| } | ||
| return atom._snapshot | ||
| } | ||
| } else { | ||
| ;(atom as unknown as Atom<T>).set = function ( | ||
| // eslint-disable-next-line no-shadow | ||
| valueOrFn: T | ((prev: T) => T), | ||
| ): void { | ||
| if (atom._update(valueOrFn)) { | ||
| const subs = atom.subs | ||
| if (subs !== undefined) { | ||
| propagate(subs) | ||
| shallowPropagate(subs) | ||
| flush() | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return atom as unknown as Atom<T> | ReadonlyAtom<T> | ||
| } | ||
| interface Effect extends ReactiveNode { | ||
| notify: () => void | ||
| stop: () => void | ||
| } | ||
| function effect<T>(fn: () => T): Effect { | ||
| const run = (): T => { | ||
| const prevSub = activeSub | ||
| activeSub = effectObj | ||
| ++cycle | ||
| effectObj.depsTail = undefined | ||
| effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck | ||
| try { | ||
| return fn() | ||
| } finally { | ||
| activeSub = prevSub | ||
| effectObj.flags &= ~ReactiveFlags.RecursedCheck | ||
| purgeDeps(effectObj) | ||
| } | ||
| } | ||
| const effectObj: Effect = { | ||
| deps: undefined, | ||
| depsTail: undefined, | ||
| subs: undefined, | ||
| subsTail: undefined, | ||
| flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck, | ||
| notify(): void { | ||
| const flags = this.flags | ||
| if ( | ||
| flags & ReactiveFlags.Dirty || | ||
| (flags & ReactiveFlags.Pending && checkDirty(this.deps!, this)) | ||
| ) { | ||
| run() | ||
| } else { | ||
| this.flags = ReactiveFlags.Watching | ||
| } | ||
| }, | ||
| stop(): void { | ||
| this.flags = ReactiveFlags.None | ||
| this.depsTail = undefined | ||
| purgeDeps(this) | ||
| }, | ||
| } | ||
| run() | ||
| return effectObj | ||
| } |
+12
| import { endBatch, startBatch } from './alien' | ||
| import { flush } from './atom' | ||
| export function batch(fn: () => void) { | ||
| try { | ||
| startBatch() | ||
| fn() | ||
| } finally { | ||
| endBatch() | ||
| flush() | ||
| } | ||
| } |
+8
-12
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const derived = require("./derived.cjs"); | ||
| const effect = require("./effect.cjs"); | ||
| const atom = require("./atom.cjs"); | ||
| const store = require("./store.cjs"); | ||
| const types = require("./types.cjs"); | ||
| const scheduler = require("./scheduler.cjs"); | ||
| exports.Derived = derived.Derived; | ||
| exports.Effect = effect.Effect; | ||
| const batch = require("./batch.cjs"); | ||
| exports.createAsyncAtom = atom.createAsyncAtom; | ||
| exports.createAtom = atom.createAtom; | ||
| exports.flush = atom.flush; | ||
| exports.toObserver = atom.toObserver; | ||
| exports.Store = store.Store; | ||
| exports.isUpdaterFunction = types.isUpdaterFunction; | ||
| exports.__depsThatHaveWrittenThisTick = scheduler.__depsThatHaveWrittenThisTick; | ||
| exports.__derivedToStore = scheduler.__derivedToStore; | ||
| exports.__flush = scheduler.__flush; | ||
| exports.__storeToDerived = scheduler.__storeToDerived; | ||
| exports.batch = scheduler.batch; | ||
| exports.createStore = store.createStore; | ||
| exports.batch = batch.batch; | ||
| //# sourceMappingURL=index.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"} | ||
| {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"} |
@@ -1,5 +0,4 @@ | ||
| export * from './derived.cjs'; | ||
| export * from './effect.cjs'; | ||
| export * from './types.cjs'; | ||
| export * from './atom.cjs'; | ||
| export * from './store.cjs'; | ||
| export * from './types.cjs'; | ||
| export * from './scheduler.cjs'; | ||
| export * from './batch.cjs'; |
+22
-29
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const scheduler = require("./scheduler.cjs"); | ||
| const types = require("./types.cjs"); | ||
| const atom = require("./atom.cjs"); | ||
| class Store { | ||
| constructor(initialState, options) { | ||
| this.listeners = /* @__PURE__ */ new Set(); | ||
| this.subscribe = (listener) => { | ||
| var _a, _b; | ||
| this.listeners.add(listener); | ||
| const unsub = (_b = (_a = this.options) == null ? void 0 : _a.onSubscribe) == null ? void 0 : _b.call(_a, listener, this); | ||
| return () => { | ||
| this.listeners.delete(listener); | ||
| unsub == null ? void 0 : unsub(); | ||
| }; | ||
| }; | ||
| this.prevState = initialState; | ||
| this.state = initialState; | ||
| this.options = options; | ||
| constructor(valueOrFn) { | ||
| this.atom = atom.createAtom( | ||
| valueOrFn | ||
| ); | ||
| } | ||
| setState(updater) { | ||
| var _a, _b, _c; | ||
| this.prevState = this.state; | ||
| if ((_a = this.options) == null ? void 0 : _a.updateFn) { | ||
| this.state = this.options.updateFn(this.prevState)(updater); | ||
| } else { | ||
| if (types.isUpdaterFunction(updater)) { | ||
| this.state = updater(this.prevState); | ||
| } else { | ||
| this.state = updater; | ||
| } | ||
| } | ||
| (_c = (_b = this.options) == null ? void 0 : _b.onUpdate) == null ? void 0 : _c.call(_b); | ||
| scheduler.__flush(this); | ||
| this.atom.set(updater); | ||
| } | ||
| get state() { | ||
| return this.atom.get(); | ||
| } | ||
| get() { | ||
| return this.state; | ||
| } | ||
| subscribe(observerOrFn) { | ||
| return this.atom.subscribe(atom.toObserver(observerOrFn)); | ||
| } | ||
| } | ||
| function createStore(valueOrFn) { | ||
| if (typeof valueOrFn === "function") { | ||
| return new Store(valueOrFn); | ||
| } | ||
| return new Store(valueOrFn); | ||
| } | ||
| exports.Store = Store; | ||
| exports.createStore = createStore; | ||
| //# sourceMappingURL=store.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"store.cjs","sources":["../../src/store.ts"],"sourcesContent":["import { __flush } from './scheduler'\nimport { isUpdaterFunction } from './types'\nimport type { AnyUpdater, Listener, Updater } from './types'\n\nexport interface StoreOptions<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n /**\n * Replace the default update function with a custom one.\n */\n updateFn?: (previous: TState) => (updater: TUpdater) => TState\n /**\n * Called when a listener subscribes to the store.\n *\n * @return a function to unsubscribe the listener\n */\n onSubscribe?: (\n listener: Listener<TState>,\n store: Store<TState, TUpdater>,\n ) => () => void\n /**\n * Called after the state has been updated, used to derive other state.\n */\n onUpdate?: () => void\n}\n\nexport class Store<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState\n options?: StoreOptions<TState, TUpdater>\n\n constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) {\n this.prevState = initialState\n this.state = initialState\n this.options = options\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options?.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n\n /**\n * Update the store state safely with improved type checking\n */\n setState(updater: (prevState: TState) => TState): void\n setState(updater: TState): void\n setState(updater: TUpdater): void\n setState(updater: Updater<TState> | TUpdater): void {\n this.prevState = this.state\n\n if (this.options?.updateFn) {\n this.state = this.options.updateFn(this.prevState)(updater as TUpdater)\n } else {\n if (isUpdaterFunction(updater)) {\n this.state = updater(this.prevState)\n } else {\n this.state = updater as TState\n }\n }\n\n // Always run onUpdate, regardless of batching\n this.options?.onUpdate?.()\n\n // Attempt to flush\n __flush(this as never)\n }\n}\n"],"names":["isUpdaterFunction","__flush"],"mappings":";;;;AA2BO,MAAM,MAGX;AAAA,EAMA,YAAY,cAAsB,SAA0C;AAL5E,SAAA,gCAAgB,IAAA;AAWhB,SAAA,YAAY,CAAC,aAA+B;;AAC1C,WAAK,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,YAAL,mBAAc,gBAAd,4BAA4B,UAAU;AACpD,aAAO,MAAM;AACX,aAAK,UAAU,OAAO,QAAQ;AAC9B;AAAA,MACF;AAAA,IACF;AAZE,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAiBA,SAAS,SAA2C;;AAClD,SAAK,YAAY,KAAK;AAEtB,SAAI,UAAK,YAAL,mBAAc,UAAU;AAC1B,WAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,OAAmB;AAAA,IACxE,OAAO;AACL,UAAIA,MAAAA,kBAAkB,OAAO,GAAG;AAC9B,aAAK,QAAQ,QAAQ,KAAK,SAAS;AAAA,MACrC,OAAO;AACL,aAAK,QAAQ;AAAA,MACf;AAAA,IACF;AAGA,qBAAK,YAAL,mBAAc,aAAd;AAGAC,cAAAA,QAAQ,IAAa;AAAA,EACvB;AACF;;"} | ||
| {"version":3,"file":"store.cjs","sources":["../../src/store.ts"],"sourcesContent":["import { createAtom, toObserver } from './atom'\nimport type { Atom, Observer, Subscription } from './types'\n\nexport class Store<T> {\n private atom: Atom<T>\n constructor(getValue: (prev?: NoInfer<T>) => T)\n constructor(initialValue: T)\n constructor(valueOrFn: T | ((prev?: T) => T)) {\n // createAtom has overloads that return ReadonlyAtom<T> for functions and Atom<T> for values\n // Store always needs Atom<T> for setState, so we assert the return type\n this.atom = createAtom(\n valueOrFn as T | ((prev?: NoInfer<T>) => T),\n ) as Atom<T>\n }\n public setState(updater: (prev: T) => T) {\n this.atom.set(updater)\n }\n public get state() {\n return this.atom.get()\n }\n public get() {\n return this.state\n }\n public subscribe(\n observerOrFn: Observer<T> | ((value: T) => void),\n ): Subscription {\n return this.atom.subscribe(toObserver(observerOrFn))\n }\n}\n\nexport function createStore<T>(getValue: (prev?: NoInfer<T>) => T): Store<T>\nexport function createStore<T>(initialValue: T): Store<T>\nexport function createStore<T>(valueOrFn: T | ((prev?: T) => T)): Store<T> {\n if (typeof valueOrFn === 'function') {\n return new Store(valueOrFn as (prev?: NoInfer<T>) => T)\n }\n return new Store(valueOrFn)\n}\n"],"names":["createAtom","toObserver"],"mappings":";;;AAGO,MAAM,MAAS;AAAA,EAIpB,YAAY,WAAkC;AAG5C,SAAK,OAAOA,KAAAA;AAAAA,MACV;AAAA,IAAA;AAAA,EAEJ;AAAA,EACO,SAAS,SAAyB;AACvC,SAAK,KAAK,IAAI,OAAO;AAAA,EACvB;AAAA,EACA,IAAW,QAAQ;AACjB,WAAO,KAAK,KAAK,IAAA;AAAA,EACnB;AAAA,EACO,MAAM;AACX,WAAO,KAAK;AAAA,EACd;AAAA,EACO,UACL,cACc;AACd,WAAO,KAAK,KAAK,UAAUC,KAAAA,WAAW,YAAY,CAAC;AAAA,EACrD;AACF;AAIO,SAAS,YAAe,WAA4C;AACzE,MAAI,OAAO,cAAc,YAAY;AACnC,WAAO,IAAI,MAAM,SAAqC;AAAA,EACxD;AACA,SAAO,IAAI,MAAM,SAAS;AAC5B;;;"} |
+11
-30
@@ -1,31 +0,12 @@ | ||
| import { AnyUpdater, Listener } from './types.cjs'; | ||
| export interface StoreOptions<TState, TUpdater extends AnyUpdater = (cb: TState) => TState> { | ||
| /** | ||
| * Replace the default update function with a custom one. | ||
| */ | ||
| updateFn?: (previous: TState) => (updater: TUpdater) => TState; | ||
| /** | ||
| * Called when a listener subscribes to the store. | ||
| * | ||
| * @return a function to unsubscribe the listener | ||
| */ | ||
| onSubscribe?: (listener: Listener<TState>, store: Store<TState, TUpdater>) => () => void; | ||
| /** | ||
| * Called after the state has been updated, used to derive other state. | ||
| */ | ||
| onUpdate?: () => void; | ||
| import { Observer, Subscription } from './types.cjs'; | ||
| export declare class Store<T> { | ||
| private atom; | ||
| constructor(getValue: (prev?: NoInfer<T>) => T); | ||
| constructor(initialValue: T); | ||
| setState(updater: (prev: T) => T): void; | ||
| get state(): T; | ||
| get(): T; | ||
| subscribe(observerOrFn: Observer<T> | ((value: T) => void)): Subscription; | ||
| } | ||
| export declare class Store<TState, TUpdater extends AnyUpdater = (cb: TState) => TState> { | ||
| listeners: Set<Listener<TState>>; | ||
| state: TState; | ||
| prevState: TState; | ||
| options?: StoreOptions<TState, TUpdater>; | ||
| constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>); | ||
| subscribe: (listener: Listener<TState>) => () => void; | ||
| /** | ||
| * Update the store state safely with improved type checking | ||
| */ | ||
| setState(updater: (prevState: TState) => TState): void; | ||
| setState(updater: TState): void; | ||
| setState(updater: TUpdater): void; | ||
| } | ||
| export declare function createStore<T>(getValue: (prev?: NoInfer<T>) => T): Store<T>; | ||
| export declare function createStore<T>(initialValue: T): Store<T>; |
+47
-20
@@ -0,23 +1,50 @@ | ||
| import { ReactiveNode } from './alien.cjs'; | ||
| export type Selection<TSelected> = Readable<TSelected>; | ||
| export interface InteropSubscribable<T> { | ||
| subscribe: (observer: Observer<T>) => Subscription; | ||
| } | ||
| export type Observer<T> = { | ||
| next?: (value: T) => void; | ||
| error?: (err: unknown) => void; | ||
| complete?: () => void; | ||
| }; | ||
| export interface Subscription { | ||
| unsubscribe: () => void; | ||
| } | ||
| export interface Subscribable<T> extends InteropSubscribable<T> { | ||
| subscribe: ((observer: Observer<T>) => Subscription) & ((next: (value: T) => void, error?: (error: any) => void, complete?: () => void) => Subscription); | ||
| } | ||
| export interface Readable<T> extends Subscribable<T> { | ||
| get: () => T; | ||
| } | ||
| export interface BaseAtom<T> extends Subscribable<T>, Readable<T> { | ||
| } | ||
| export interface InternalBaseAtom<T> extends Subscribable<T>, Readable<T> { | ||
| /** @internal */ | ||
| _snapshot: T; | ||
| /** @internal */ | ||
| _update: (getValue?: T | ((snapshot: T) => T)) => boolean; | ||
| } | ||
| export interface Atom<T> extends BaseAtom<T> { | ||
| /** Sets the value of the atom using a function. */ | ||
| set: ((fn: (prevVal: T) => T) => void) & ((value: T) => void); | ||
| } | ||
| export interface AtomOptions<T> { | ||
| compare?: (prev: T, next: T) => boolean; | ||
| } | ||
| export type AnyAtom = BaseAtom<any>; | ||
| export interface InternalReadonlyAtom<T> extends InternalBaseAtom<T>, ReactiveNode { | ||
| } | ||
| /** | ||
| * @private | ||
| * An atom that is read-only and cannot be set. | ||
| * | ||
| * @example | ||
| * | ||
| * ```ts | ||
| * const atom = createAtom(() => 42); | ||
| * // @ts-expect-error - Cannot set a readonly atom | ||
| * atom.set(43); | ||
| * ``` | ||
| */ | ||
| export type AnyUpdater = (prev: any) => any; | ||
| /** | ||
| * Type-safe updater that can be either a function or direct value | ||
| */ | ||
| export type Updater<T> = ((prev: T) => T) | T; | ||
| /** | ||
| * @private | ||
| */ | ||
| export interface ListenerValue<T> { | ||
| readonly prevVal: T; | ||
| readonly currentVal: T; | ||
| export interface ReadonlyAtom<T> extends BaseAtom<T> { | ||
| } | ||
| /** | ||
| * @private | ||
| */ | ||
| export type Listener<T> = (value: ListenerValue<T>) => void; | ||
| /** | ||
| * Type guard to check if updater is a function | ||
| */ | ||
| export declare function isUpdaterFunction<T>(updater: Updater<T>): updater is (prev: T) => T; |
@@ -1,5 +0,4 @@ | ||
| export * from './derived.js'; | ||
| export * from './effect.js'; | ||
| export * from './types.js'; | ||
| export * from './atom.js'; | ||
| export * from './store.js'; | ||
| export * from './types.js'; | ||
| export * from './scheduler.js'; | ||
| export * from './batch.js'; |
+8
-12
@@ -1,17 +0,13 @@ | ||
| import { Derived } from "./derived.js"; | ||
| import { Effect } from "./effect.js"; | ||
| import { Store } from "./store.js"; | ||
| import { isUpdaterFunction } from "./types.js"; | ||
| import { __depsThatHaveWrittenThisTick, __derivedToStore, __flush, __storeToDerived, batch } from "./scheduler.js"; | ||
| import { createAsyncAtom, createAtom, flush, toObserver } from "./atom.js"; | ||
| import { Store, createStore } from "./store.js"; | ||
| import { batch } from "./batch.js"; | ||
| export { | ||
| Derived, | ||
| Effect, | ||
| Store, | ||
| __depsThatHaveWrittenThisTick, | ||
| __derivedToStore, | ||
| __flush, | ||
| __storeToDerived, | ||
| batch, | ||
| isUpdaterFunction | ||
| createAsyncAtom, | ||
| createAtom, | ||
| createStore, | ||
| flush, | ||
| toObserver | ||
| }; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"} |
+11
-30
@@ -1,31 +0,12 @@ | ||
| import { AnyUpdater, Listener } from './types.js'; | ||
| export interface StoreOptions<TState, TUpdater extends AnyUpdater = (cb: TState) => TState> { | ||
| /** | ||
| * Replace the default update function with a custom one. | ||
| */ | ||
| updateFn?: (previous: TState) => (updater: TUpdater) => TState; | ||
| /** | ||
| * Called when a listener subscribes to the store. | ||
| * | ||
| * @return a function to unsubscribe the listener | ||
| */ | ||
| onSubscribe?: (listener: Listener<TState>, store: Store<TState, TUpdater>) => () => void; | ||
| /** | ||
| * Called after the state has been updated, used to derive other state. | ||
| */ | ||
| onUpdate?: () => void; | ||
| import { Observer, Subscription } from './types.js'; | ||
| export declare class Store<T> { | ||
| private atom; | ||
| constructor(getValue: (prev?: NoInfer<T>) => T); | ||
| constructor(initialValue: T); | ||
| setState(updater: (prev: T) => T): void; | ||
| get state(): T; | ||
| get(): T; | ||
| subscribe(observerOrFn: Observer<T> | ((value: T) => void)): Subscription; | ||
| } | ||
| export declare class Store<TState, TUpdater extends AnyUpdater = (cb: TState) => TState> { | ||
| listeners: Set<Listener<TState>>; | ||
| state: TState; | ||
| prevState: TState; | ||
| options?: StoreOptions<TState, TUpdater>; | ||
| constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>); | ||
| subscribe: (listener: Listener<TState>) => () => void; | ||
| /** | ||
| * Update the store state safely with improved type checking | ||
| */ | ||
| setState(updater: (prevState: TState) => TState): void; | ||
| setState(updater: TState): void; | ||
| setState(updater: TUpdater): void; | ||
| } | ||
| export declare function createStore<T>(getValue: (prev?: NoInfer<T>) => T): Store<T>; | ||
| export declare function createStore<T>(initialValue: T): Store<T>; |
+23
-30
@@ -1,38 +0,31 @@ | ||
| import { __flush } from "./scheduler.js"; | ||
| import { isUpdaterFunction } from "./types.js"; | ||
| import { createAtom, toObserver } from "./atom.js"; | ||
| class Store { | ||
| constructor(initialState, options) { | ||
| this.listeners = /* @__PURE__ */ new Set(); | ||
| this.subscribe = (listener) => { | ||
| var _a, _b; | ||
| this.listeners.add(listener); | ||
| const unsub = (_b = (_a = this.options) == null ? void 0 : _a.onSubscribe) == null ? void 0 : _b.call(_a, listener, this); | ||
| return () => { | ||
| this.listeners.delete(listener); | ||
| unsub == null ? void 0 : unsub(); | ||
| }; | ||
| }; | ||
| this.prevState = initialState; | ||
| this.state = initialState; | ||
| this.options = options; | ||
| constructor(valueOrFn) { | ||
| this.atom = createAtom( | ||
| valueOrFn | ||
| ); | ||
| } | ||
| setState(updater) { | ||
| var _a, _b, _c; | ||
| this.prevState = this.state; | ||
| if ((_a = this.options) == null ? void 0 : _a.updateFn) { | ||
| this.state = this.options.updateFn(this.prevState)(updater); | ||
| } else { | ||
| if (isUpdaterFunction(updater)) { | ||
| this.state = updater(this.prevState); | ||
| } else { | ||
| this.state = updater; | ||
| } | ||
| } | ||
| (_c = (_b = this.options) == null ? void 0 : _b.onUpdate) == null ? void 0 : _c.call(_b); | ||
| __flush(this); | ||
| this.atom.set(updater); | ||
| } | ||
| get state() { | ||
| return this.atom.get(); | ||
| } | ||
| get() { | ||
| return this.state; | ||
| } | ||
| subscribe(observerOrFn) { | ||
| return this.atom.subscribe(toObserver(observerOrFn)); | ||
| } | ||
| } | ||
| function createStore(valueOrFn) { | ||
| if (typeof valueOrFn === "function") { | ||
| return new Store(valueOrFn); | ||
| } | ||
| return new Store(valueOrFn); | ||
| } | ||
| export { | ||
| Store | ||
| Store, | ||
| createStore | ||
| }; | ||
| //# sourceMappingURL=store.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"store.js","sources":["../../src/store.ts"],"sourcesContent":["import { __flush } from './scheduler'\nimport { isUpdaterFunction } from './types'\nimport type { AnyUpdater, Listener, Updater } from './types'\n\nexport interface StoreOptions<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n /**\n * Replace the default update function with a custom one.\n */\n updateFn?: (previous: TState) => (updater: TUpdater) => TState\n /**\n * Called when a listener subscribes to the store.\n *\n * @return a function to unsubscribe the listener\n */\n onSubscribe?: (\n listener: Listener<TState>,\n store: Store<TState, TUpdater>,\n ) => () => void\n /**\n * Called after the state has been updated, used to derive other state.\n */\n onUpdate?: () => void\n}\n\nexport class Store<\n TState,\n TUpdater extends AnyUpdater = (cb: TState) => TState,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState\n options?: StoreOptions<TState, TUpdater>\n\n constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) {\n this.prevState = initialState\n this.state = initialState\n this.options = options\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options?.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n\n /**\n * Update the store state safely with improved type checking\n */\n setState(updater: (prevState: TState) => TState): void\n setState(updater: TState): void\n setState(updater: TUpdater): void\n setState(updater: Updater<TState> | TUpdater): void {\n this.prevState = this.state\n\n if (this.options?.updateFn) {\n this.state = this.options.updateFn(this.prevState)(updater as TUpdater)\n } else {\n if (isUpdaterFunction(updater)) {\n this.state = updater(this.prevState)\n } else {\n this.state = updater as TState\n }\n }\n\n // Always run onUpdate, regardless of batching\n this.options?.onUpdate?.()\n\n // Attempt to flush\n __flush(this as never)\n }\n}\n"],"names":[],"mappings":";;AA2BO,MAAM,MAGX;AAAA,EAMA,YAAY,cAAsB,SAA0C;AAL5E,SAAA,gCAAgB,IAAA;AAWhB,SAAA,YAAY,CAAC,aAA+B;;AAC1C,WAAK,UAAU,IAAI,QAAQ;AAC3B,YAAM,SAAQ,gBAAK,YAAL,mBAAc,gBAAd,4BAA4B,UAAU;AACpD,aAAO,MAAM;AACX,aAAK,UAAU,OAAO,QAAQ;AAC9B;AAAA,MACF;AAAA,IACF;AAZE,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAiBA,SAAS,SAA2C;;AAClD,SAAK,YAAY,KAAK;AAEtB,SAAI,UAAK,YAAL,mBAAc,UAAU;AAC1B,WAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,EAAE,OAAmB;AAAA,IACxE,OAAO;AACL,UAAI,kBAAkB,OAAO,GAAG;AAC9B,aAAK,QAAQ,QAAQ,KAAK,SAAS;AAAA,MACrC,OAAO;AACL,aAAK,QAAQ;AAAA,MACf;AAAA,IACF;AAGA,qBAAK,YAAL,mBAAc,aAAd;AAGA,YAAQ,IAAa;AAAA,EACvB;AACF;"} | ||
| {"version":3,"file":"store.js","sources":["../../src/store.ts"],"sourcesContent":["import { createAtom, toObserver } from './atom'\nimport type { Atom, Observer, Subscription } from './types'\n\nexport class Store<T> {\n private atom: Atom<T>\n constructor(getValue: (prev?: NoInfer<T>) => T)\n constructor(initialValue: T)\n constructor(valueOrFn: T | ((prev?: T) => T)) {\n // createAtom has overloads that return ReadonlyAtom<T> for functions and Atom<T> for values\n // Store always needs Atom<T> for setState, so we assert the return type\n this.atom = createAtom(\n valueOrFn as T | ((prev?: NoInfer<T>) => T),\n ) as Atom<T>\n }\n public setState(updater: (prev: T) => T) {\n this.atom.set(updater)\n }\n public get state() {\n return this.atom.get()\n }\n public get() {\n return this.state\n }\n public subscribe(\n observerOrFn: Observer<T> | ((value: T) => void),\n ): Subscription {\n return this.atom.subscribe(toObserver(observerOrFn))\n }\n}\n\nexport function createStore<T>(getValue: (prev?: NoInfer<T>) => T): Store<T>\nexport function createStore<T>(initialValue: T): Store<T>\nexport function createStore<T>(valueOrFn: T | ((prev?: T) => T)): Store<T> {\n if (typeof valueOrFn === 'function') {\n return new Store(valueOrFn as (prev?: NoInfer<T>) => T)\n }\n return new Store(valueOrFn)\n}\n"],"names":[],"mappings":";AAGO,MAAM,MAAS;AAAA,EAIpB,YAAY,WAAkC;AAG5C,SAAK,OAAO;AAAA,MACV;AAAA,IAAA;AAAA,EAEJ;AAAA,EACO,SAAS,SAAyB;AACvC,SAAK,KAAK,IAAI,OAAO;AAAA,EACvB;AAAA,EACA,IAAW,QAAQ;AACjB,WAAO,KAAK,KAAK,IAAA;AAAA,EACnB;AAAA,EACO,MAAM;AACX,WAAO,KAAK;AAAA,EACd;AAAA,EACO,UACL,cACc;AACd,WAAO,KAAK,KAAK,UAAU,WAAW,YAAY,CAAC;AAAA,EACrD;AACF;AAIO,SAAS,YAAe,WAA4C;AACzE,MAAI,OAAO,cAAc,YAAY;AACnC,WAAO,IAAI,MAAM,SAAqC;AAAA,EACxD;AACA,SAAO,IAAI,MAAM,SAAS;AAC5B;"} |
+47
-20
@@ -0,23 +1,50 @@ | ||
| import { ReactiveNode } from './alien.js'; | ||
| export type Selection<TSelected> = Readable<TSelected>; | ||
| export interface InteropSubscribable<T> { | ||
| subscribe: (observer: Observer<T>) => Subscription; | ||
| } | ||
| export type Observer<T> = { | ||
| next?: (value: T) => void; | ||
| error?: (err: unknown) => void; | ||
| complete?: () => void; | ||
| }; | ||
| export interface Subscription { | ||
| unsubscribe: () => void; | ||
| } | ||
| export interface Subscribable<T> extends InteropSubscribable<T> { | ||
| subscribe: ((observer: Observer<T>) => Subscription) & ((next: (value: T) => void, error?: (error: any) => void, complete?: () => void) => Subscription); | ||
| } | ||
| export interface Readable<T> extends Subscribable<T> { | ||
| get: () => T; | ||
| } | ||
| export interface BaseAtom<T> extends Subscribable<T>, Readable<T> { | ||
| } | ||
| export interface InternalBaseAtom<T> extends Subscribable<T>, Readable<T> { | ||
| /** @internal */ | ||
| _snapshot: T; | ||
| /** @internal */ | ||
| _update: (getValue?: T | ((snapshot: T) => T)) => boolean; | ||
| } | ||
| export interface Atom<T> extends BaseAtom<T> { | ||
| /** Sets the value of the atom using a function. */ | ||
| set: ((fn: (prevVal: T) => T) => void) & ((value: T) => void); | ||
| } | ||
| export interface AtomOptions<T> { | ||
| compare?: (prev: T, next: T) => boolean; | ||
| } | ||
| export type AnyAtom = BaseAtom<any>; | ||
| export interface InternalReadonlyAtom<T> extends InternalBaseAtom<T>, ReactiveNode { | ||
| } | ||
| /** | ||
| * @private | ||
| * An atom that is read-only and cannot be set. | ||
| * | ||
| * @example | ||
| * | ||
| * ```ts | ||
| * const atom = createAtom(() => 42); | ||
| * // @ts-expect-error - Cannot set a readonly atom | ||
| * atom.set(43); | ||
| * ``` | ||
| */ | ||
| export type AnyUpdater = (prev: any) => any; | ||
| /** | ||
| * Type-safe updater that can be either a function or direct value | ||
| */ | ||
| export type Updater<T> = ((prev: T) => T) | T; | ||
| /** | ||
| * @private | ||
| */ | ||
| export interface ListenerValue<T> { | ||
| readonly prevVal: T; | ||
| readonly currentVal: T; | ||
| export interface ReadonlyAtom<T> extends BaseAtom<T> { | ||
| } | ||
| /** | ||
| * @private | ||
| */ | ||
| export type Listener<T> = (value: ListenerValue<T>) => void; | ||
| /** | ||
| * Type guard to check if updater is a function | ||
| */ | ||
| export declare function isUpdaterFunction<T>(updater: Updater<T>): updater is (prev: T) => T; |
+6
-7
| { | ||
| "name": "@tanstack/store", | ||
| "version": "0.8.1", | ||
| "version": "0.9.0", | ||
| "description": "Framework agnostic type-safe store w/ reactive framework adapters", | ||
@@ -44,3 +44,3 @@ "author": "Tanner Linsley", | ||
| "devDependencies": { | ||
| "@angular/core": "^19.2.15", | ||
| "@angular/core": "^21.1.2", | ||
| "@preact/signals": "^1.3.2", | ||
@@ -54,7 +54,6 @@ "solid-js": "^1.9.9", | ||
| "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", | ||
| "test:types:ts50": "node ../../node_modules/typescript50/lib/tsc.js", | ||
| "test:types:ts51": "node ../../node_modules/typescript51/lib/tsc.js", | ||
| "test:types:ts52": "node ../../node_modules/typescript52/lib/tsc.js", | ||
| "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", | ||
| "test:types:ts54": "tsc", | ||
| "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", | ||
| "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", | ||
| "test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js", | ||
| "test:types:ts59": "tsc", | ||
| "test:lib": "vitest", | ||
@@ -61,0 +60,0 @@ "test:bench": "vitest bench", |
+3
-4
@@ -1,5 +0,4 @@ | ||
| export * from './derived' | ||
| export * from './effect' | ||
| export * from './types' | ||
| export * from './atom' | ||
| export * from './store' | ||
| export * from './types' | ||
| export * from './scheduler' | ||
| export * from './batch' |
+32
-71
@@ -1,77 +0,38 @@ | ||
| import { __flush } from './scheduler' | ||
| import { isUpdaterFunction } from './types' | ||
| import type { AnyUpdater, Listener, Updater } from './types' | ||
| import { createAtom, toObserver } from './atom' | ||
| import type { Atom, Observer, Subscription } from './types' | ||
| export interface StoreOptions< | ||
| TState, | ||
| TUpdater extends AnyUpdater = (cb: TState) => TState, | ||
| > { | ||
| /** | ||
| * Replace the default update function with a custom one. | ||
| */ | ||
| updateFn?: (previous: TState) => (updater: TUpdater) => TState | ||
| /** | ||
| * Called when a listener subscribes to the store. | ||
| * | ||
| * @return a function to unsubscribe the listener | ||
| */ | ||
| onSubscribe?: ( | ||
| listener: Listener<TState>, | ||
| store: Store<TState, TUpdater>, | ||
| ) => () => void | ||
| /** | ||
| * Called after the state has been updated, used to derive other state. | ||
| */ | ||
| onUpdate?: () => void | ||
| } | ||
| export class Store< | ||
| TState, | ||
| TUpdater extends AnyUpdater = (cb: TState) => TState, | ||
| > { | ||
| listeners = new Set<Listener<TState>>() | ||
| state: TState | ||
| prevState: TState | ||
| options?: StoreOptions<TState, TUpdater> | ||
| constructor(initialState: TState, options?: StoreOptions<TState, TUpdater>) { | ||
| this.prevState = initialState | ||
| this.state = initialState | ||
| this.options = options | ||
| export class Store<T> { | ||
| private atom: Atom<T> | ||
| constructor(getValue: (prev?: NoInfer<T>) => T) | ||
| constructor(initialValue: T) | ||
| constructor(valueOrFn: T | ((prev?: T) => T)) { | ||
| // createAtom has overloads that return ReadonlyAtom<T> for functions and Atom<T> for values | ||
| // Store always needs Atom<T> for setState, so we assert the return type | ||
| this.atom = createAtom( | ||
| valueOrFn as T | ((prev?: NoInfer<T>) => T), | ||
| ) as Atom<T> | ||
| } | ||
| subscribe = (listener: Listener<TState>) => { | ||
| this.listeners.add(listener) | ||
| const unsub = this.options?.onSubscribe?.(listener, this) | ||
| return () => { | ||
| this.listeners.delete(listener) | ||
| unsub?.() | ||
| } | ||
| public setState(updater: (prev: T) => T) { | ||
| this.atom.set(updater) | ||
| } | ||
| public get state() { | ||
| return this.atom.get() | ||
| } | ||
| public get() { | ||
| return this.state | ||
| } | ||
| public subscribe( | ||
| observerOrFn: Observer<T> | ((value: T) => void), | ||
| ): Subscription { | ||
| return this.atom.subscribe(toObserver(observerOrFn)) | ||
| } | ||
| } | ||
| /** | ||
| * Update the store state safely with improved type checking | ||
| */ | ||
| setState(updater: (prevState: TState) => TState): void | ||
| setState(updater: TState): void | ||
| setState(updater: TUpdater): void | ||
| setState(updater: Updater<TState> | TUpdater): void { | ||
| this.prevState = this.state | ||
| if (this.options?.updateFn) { | ||
| this.state = this.options.updateFn(this.prevState)(updater as TUpdater) | ||
| } else { | ||
| if (isUpdaterFunction(updater)) { | ||
| this.state = updater(this.prevState) | ||
| } else { | ||
| this.state = updater as TState | ||
| } | ||
| } | ||
| // Always run onUpdate, regardless of batching | ||
| this.options?.onUpdate?.() | ||
| // Attempt to flush | ||
| __flush(this as never) | ||
| export function createStore<T>(getValue: (prev?: NoInfer<T>) => T): Store<T> | ||
| export function createStore<T>(initialValue: T): Store<T> | ||
| export function createStore<T>(valueOrFn: T | ((prev?: T) => T)): Store<T> { | ||
| if (typeof valueOrFn === 'function') { | ||
| return new Store(valueOrFn as (prev?: NoInfer<T>) => T) | ||
| } | ||
| return new Store(valueOrFn) | ||
| } |
+60
-24
@@ -1,31 +0,67 @@ | ||
| /** | ||
| * @private | ||
| */ | ||
| export type AnyUpdater = (prev: any) => any | ||
| import type { ReactiveNode } from './alien' | ||
| /** | ||
| * Type-safe updater that can be either a function or direct value | ||
| */ | ||
| export type Updater<T> = ((prev: T) => T) | T | ||
| export type Selection<TSelected> = Readable<TSelected> | ||
| /** | ||
| * @private | ||
| */ | ||
| export interface ListenerValue<T> { | ||
| readonly prevVal: T | ||
| readonly currentVal: T | ||
| export interface InteropSubscribable<T> { | ||
| subscribe: (observer: Observer<T>) => Subscription | ||
| } | ||
| /** | ||
| * @private | ||
| */ | ||
| export type Listener<T> = (value: ListenerValue<T>) => void | ||
| // Based on RxJS types | ||
| export type Observer<T> = { | ||
| next?: (value: T) => void | ||
| error?: (err: unknown) => void | ||
| complete?: () => void | ||
| } | ||
| export interface Subscription { | ||
| unsubscribe: () => void | ||
| } | ||
| export interface Subscribable<T> extends InteropSubscribable<T> { | ||
| subscribe: ((observer: Observer<T>) => Subscription) & | ||
| (( | ||
| next: (value: T) => void, | ||
| error?: (error: any) => void, | ||
| complete?: () => void, | ||
| ) => Subscription) | ||
| } | ||
| export interface Readable<T> extends Subscribable<T> { | ||
| get: () => T | ||
| } | ||
| export interface BaseAtom<T> extends Subscribable<T>, Readable<T> {} | ||
| export interface InternalBaseAtom<T> extends Subscribable<T>, Readable<T> { | ||
| /** @internal */ | ||
| _snapshot: T | ||
| /** @internal */ | ||
| _update: (getValue?: T | ((snapshot: T) => T)) => boolean | ||
| } | ||
| export interface Atom<T> extends BaseAtom<T> { | ||
| /** Sets the value of the atom using a function. */ | ||
| set: ((fn: (prevVal: T) => T) => void) & ((value: T) => void) | ||
| } | ||
| export interface AtomOptions<T> { | ||
| compare?: (prev: T, next: T) => boolean | ||
| } | ||
| export type AnyAtom = BaseAtom<any> | ||
| export interface InternalReadonlyAtom<T> | ||
| extends InternalBaseAtom<T>, ReactiveNode {} | ||
| /** | ||
| * Type guard to check if updater is a function | ||
| * An atom that is read-only and cannot be set. | ||
| * | ||
| * @example | ||
| * | ||
| * ```ts | ||
| * const atom = createAtom(() => 42); | ||
| * // @ts-expect-error - Cannot set a readonly atom | ||
| * atom.set(43); | ||
| * ``` | ||
| */ | ||
| export function isUpdaterFunction<T>( | ||
| updater: Updater<T>, | ||
| ): updater is (prev: T) => T { | ||
| return typeof updater === 'function' | ||
| } | ||
| export interface ReadonlyAtom<T> extends BaseAtom<T> {} |
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const store = require("./store.cjs"); | ||
| const scheduler = require("./scheduler.cjs"); | ||
| class Derived { | ||
| constructor(options) { | ||
| this.listeners = /* @__PURE__ */ new Set(); | ||
| this._subscriptions = []; | ||
| this.lastSeenDepValues = []; | ||
| this.getDepVals = () => { | ||
| const l = this.options.deps.length; | ||
| const prevDepVals = new Array(l); | ||
| const currDepVals = new Array(l); | ||
| for (let i = 0; i < l; i++) { | ||
| const dep = this.options.deps[i]; | ||
| prevDepVals[i] = dep.prevState; | ||
| currDepVals[i] = dep.state; | ||
| } | ||
| this.lastSeenDepValues = currDepVals; | ||
| return { | ||
| prevDepVals, | ||
| currDepVals, | ||
| prevVal: this.prevState ?? void 0 | ||
| }; | ||
| }; | ||
| this.recompute = () => { | ||
| var _a, _b; | ||
| this.prevState = this.state; | ||
| const depVals = this.getDepVals(); | ||
| this.state = this.options.fn(depVals); | ||
| (_b = (_a = this.options).onUpdate) == null ? void 0 : _b.call(_a); | ||
| }; | ||
| this.checkIfRecalculationNeededDeeply = () => { | ||
| for (const dep of this.options.deps) { | ||
| if (dep instanceof Derived) { | ||
| dep.checkIfRecalculationNeededDeeply(); | ||
| } | ||
| } | ||
| let shouldRecompute = false; | ||
| const lastSeenDepValues = this.lastSeenDepValues; | ||
| const { currDepVals } = this.getDepVals(); | ||
| for (let i = 0; i < currDepVals.length; i++) { | ||
| if (currDepVals[i] !== lastSeenDepValues[i]) { | ||
| shouldRecompute = true; | ||
| break; | ||
| } | ||
| } | ||
| if (shouldRecompute) { | ||
| this.recompute(); | ||
| } | ||
| }; | ||
| this.mount = () => { | ||
| this.registerOnGraph(); | ||
| this.checkIfRecalculationNeededDeeply(); | ||
| return () => { | ||
| this.unregisterFromGraph(); | ||
| for (const cleanup of this._subscriptions) { | ||
| cleanup(); | ||
| } | ||
| }; | ||
| }; | ||
| this.subscribe = (listener) => { | ||
| var _a, _b; | ||
| this.listeners.add(listener); | ||
| const unsub = (_b = (_a = this.options).onSubscribe) == null ? void 0 : _b.call(_a, listener, this); | ||
| return () => { | ||
| this.listeners.delete(listener); | ||
| unsub == null ? void 0 : unsub(); | ||
| }; | ||
| }; | ||
| this.options = options; | ||
| this.state = options.fn({ | ||
| prevDepVals: void 0, | ||
| prevVal: void 0, | ||
| currDepVals: this.getDepVals().currDepVals | ||
| }); | ||
| } | ||
| registerOnGraph(deps = this.options.deps) { | ||
| for (const dep of deps) { | ||
| if (dep instanceof Derived) { | ||
| dep.registerOnGraph(); | ||
| this.registerOnGraph(dep.options.deps); | ||
| } else if (dep instanceof store.Store) { | ||
| let relatedLinkedDerivedVals = scheduler.__storeToDerived.get(dep); | ||
| if (!relatedLinkedDerivedVals) { | ||
| relatedLinkedDerivedVals = /* @__PURE__ */ new Set(); | ||
| scheduler.__storeToDerived.set(dep, relatedLinkedDerivedVals); | ||
| } | ||
| relatedLinkedDerivedVals.add(this); | ||
| let relatedStores = scheduler.__derivedToStore.get(this); | ||
| if (!relatedStores) { | ||
| relatedStores = /* @__PURE__ */ new Set(); | ||
| scheduler.__derivedToStore.set(this, relatedStores); | ||
| } | ||
| relatedStores.add(dep); | ||
| } | ||
| } | ||
| } | ||
| unregisterFromGraph(deps = this.options.deps) { | ||
| for (const dep of deps) { | ||
| if (dep instanceof Derived) { | ||
| this.unregisterFromGraph(dep.options.deps); | ||
| } else if (dep instanceof store.Store) { | ||
| const relatedLinkedDerivedVals = scheduler.__storeToDerived.get(dep); | ||
| if (relatedLinkedDerivedVals) { | ||
| relatedLinkedDerivedVals.delete(this); | ||
| } | ||
| const relatedStores = scheduler.__derivedToStore.get(this); | ||
| if (relatedStores) { | ||
| relatedStores.delete(dep); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| exports.Derived = Derived; | ||
| //# sourceMappingURL=derived.cjs.map |
| {"version":3,"file":"derived.cjs","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n T extends Derived<infer InnerD>\n ? InnerD\n : T extends Store<infer InnerS>\n ? InnerS\n : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly []\n ? []\n : TArr extends readonly [infer Head, ...infer Tail]\n ? Head extends Derived<any> | Store<any>\n ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n ? [\n UnwrapDerivedOrStore<Head>,\n ...UnwrapReadonlyDerivedOrStoreArray<Tail>,\n ]\n : [UnwrapDerivedOrStore<Head>]\n : []\n : TArr extends ReadonlyArray<Derived<any> | Store<any>>\n ? Array<UnwrapDerivedOrStore<TArr[number]>>\n : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n TUnwrappedArr extends\n UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n // `undefined` if it's the first run\n /**\n * `undefined` if it's the first run\n * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n */\n prevVal: unknown | undefined\n prevDepVals: TUnwrappedArr | undefined\n currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n TState,\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n onSubscribe?: (\n listener: Listener<TState>,\n derived: Derived<TState>,\n ) => () => void\n onUpdate?: () => void\n deps: TArr\n /**\n * Values of the `deps` from before and after the current invocation of `fn`\n */\n fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n TState,\n const TArr extends ReadonlyArray<\n Derived<any> | Store<any>\n > = ReadonlyArray<any>,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState | undefined\n options: DerivedOptions<TState, TArr>\n\n /**\n * Functions representing the subscriptions. Call a function to cleanup\n * @private\n */\n _subscriptions: Array<() => void> = []\n\n lastSeenDepValues: Array<unknown> = []\n getDepVals = () => {\n const l = this.options.deps.length\n const prevDepVals = new Array<unknown>(l)\n const currDepVals = new Array<unknown>(l)\n for (let i = 0; i < l; i++) {\n const dep = this.options.deps[i]!\n prevDepVals[i] = dep.prevState\n currDepVals[i] = dep.state\n }\n this.lastSeenDepValues = currDepVals\n return {\n prevDepVals,\n currDepVals,\n prevVal: this.prevState ?? undefined,\n }\n }\n\n constructor(options: DerivedOptions<TState, TArr>) {\n this.options = options\n this.state = options.fn({\n prevDepVals: undefined,\n prevVal: undefined,\n currDepVals: this.getDepVals().currDepVals as never,\n })\n }\n\n registerOnGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n // First register the intermediate derived value if it's not already registered\n dep.registerOnGraph()\n // Then register this derived with the dep's underlying stores\n this.registerOnGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n // Register the derived as related derived to the store\n let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (!relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals = new Set()\n __storeToDerived.set(dep, relatedLinkedDerivedVals)\n }\n relatedLinkedDerivedVals.add(this as never)\n\n // Register the store as a related store to this derived\n let relatedStores = __derivedToStore.get(this as never)\n if (!relatedStores) {\n relatedStores = new Set()\n __derivedToStore.set(this as never, relatedStores)\n }\n relatedStores.add(dep)\n }\n }\n }\n\n unregisterFromGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n this.unregisterFromGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals.delete(this as never)\n }\n\n const relatedStores = __derivedToStore.get(this as never)\n if (relatedStores) {\n relatedStores.delete(dep)\n }\n }\n }\n }\n\n recompute = () => {\n this.prevState = this.state\n const depVals = this.getDepVals()\n this.state = this.options.fn(depVals as never)\n\n this.options.onUpdate?.()\n }\n\n checkIfRecalculationNeededDeeply = () => {\n for (const dep of this.options.deps) {\n if (dep instanceof Derived) {\n dep.checkIfRecalculationNeededDeeply()\n }\n }\n let shouldRecompute = false\n const lastSeenDepValues = this.lastSeenDepValues\n const { currDepVals } = this.getDepVals()\n for (let i = 0; i < currDepVals.length; i++) {\n if (currDepVals[i] !== lastSeenDepValues[i]) {\n shouldRecompute = true\n break\n }\n }\n\n if (shouldRecompute) {\n this.recompute()\n }\n }\n\n mount = () => {\n this.registerOnGraph()\n this.checkIfRecalculationNeededDeeply()\n\n return () => {\n this.unregisterFromGraph()\n for (const cleanup of this._subscriptions) {\n cleanup()\n }\n }\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n}\n"],"names":["Store","__storeToDerived","__derivedToStore"],"mappings":"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"} |
| import { Store } from './store.cjs'; | ||
| import { Listener } from './types.cjs'; | ||
| export type UnwrapDerivedOrStore<T> = T extends Derived<infer InnerD> ? InnerD : T extends Store<infer InnerS> ? InnerS : never; | ||
| type UnwrapReadonlyDerivedOrStoreArray<TArr extends ReadonlyArray<Derived<any> | Store<any>>> = TArr extends readonly [] ? [] : TArr extends readonly [infer Head, ...infer Tail] ? Head extends Derived<any> | Store<any> ? Tail extends ReadonlyArray<Derived<any> | Store<any>> ? [ | ||
| UnwrapDerivedOrStore<Head>, | ||
| ...UnwrapReadonlyDerivedOrStoreArray<Tail> | ||
| ] : [UnwrapDerivedOrStore<Head>] : [] : TArr extends ReadonlyArray<Derived<any> | Store<any>> ? Array<UnwrapDerivedOrStore<TArr[number]>> : []; | ||
| export interface DerivedFnProps<TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>, TUnwrappedArr extends UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>> { | ||
| /** | ||
| * `undefined` if it's the first run | ||
| * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage | ||
| */ | ||
| prevVal: unknown | undefined; | ||
| prevDepVals: TUnwrappedArr | undefined; | ||
| currDepVals: TUnwrappedArr; | ||
| } | ||
| export interface DerivedOptions<TState, TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>> { | ||
| onSubscribe?: (listener: Listener<TState>, derived: Derived<TState>) => () => void; | ||
| onUpdate?: () => void; | ||
| deps: TArr; | ||
| /** | ||
| * Values of the `deps` from before and after the current invocation of `fn` | ||
| */ | ||
| fn: (props: DerivedFnProps<TArr>) => TState; | ||
| } | ||
| export declare class Derived<TState, const TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>> { | ||
| listeners: Set<Listener<TState>>; | ||
| state: TState; | ||
| prevState: TState | undefined; | ||
| options: DerivedOptions<TState, TArr>; | ||
| /** | ||
| * Functions representing the subscriptions. Call a function to cleanup | ||
| * @private | ||
| */ | ||
| _subscriptions: Array<() => void>; | ||
| lastSeenDepValues: Array<unknown>; | ||
| getDepVals: () => { | ||
| prevDepVals: unknown[]; | ||
| currDepVals: unknown[]; | ||
| prevVal: NonNullable<TState> | undefined; | ||
| }; | ||
| constructor(options: DerivedOptions<TState, TArr>); | ||
| registerOnGraph(deps?: ReadonlyArray<Derived<any> | Store<any>>): void; | ||
| unregisterFromGraph(deps?: ReadonlyArray<Derived<any> | Store<any>>): void; | ||
| recompute: () => void; | ||
| checkIfRecalculationNeededDeeply: () => void; | ||
| mount: () => () => void; | ||
| subscribe: (listener: Listener<TState>) => () => void; | ||
| } | ||
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const derived = require("./derived.cjs"); | ||
| class Effect { | ||
| constructor(opts) { | ||
| const { eager, fn, ...derivedProps } = opts; | ||
| this._derived = new derived.Derived({ | ||
| ...derivedProps, | ||
| fn: () => { | ||
| }, | ||
| onUpdate() { | ||
| fn(); | ||
| } | ||
| }); | ||
| if (eager) { | ||
| fn(); | ||
| } | ||
| } | ||
| mount() { | ||
| return this._derived.mount(); | ||
| } | ||
| } | ||
| exports.Effect = Effect; | ||
| //# sourceMappingURL=effect.cjs.map |
| {"version":3,"file":"effect.cjs","sources":["../../src/effect.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { DerivedOptions } from './derived'\n\ninterface EffectOptions\n extends Omit<\n DerivedOptions<unknown>,\n 'onUpdate' | 'onSubscribe' | 'lazy' | 'fn'\n > {\n /**\n * Should the effect trigger immediately?\n * @default false\n */\n eager?: boolean\n fn: () => void\n}\n\nexport class Effect {\n /**\n * @private\n */\n _derived: Derived<void>\n\n constructor(opts: EffectOptions) {\n const { eager, fn, ...derivedProps } = opts\n\n this._derived = new Derived({\n ...derivedProps,\n fn: () => {},\n onUpdate() {\n fn()\n },\n })\n\n if (eager) {\n fn()\n }\n }\n\n mount() {\n return this._derived.mount()\n }\n}\n"],"names":["Derived"],"mappings":";;;AAgBO,MAAM,OAAO;AAAA,EAMlB,YAAY,MAAqB;AAC/B,UAAM,EAAE,OAAO,IAAI,GAAG,iBAAiB;AAEvC,SAAK,WAAW,IAAIA,gBAAQ;AAAA,MAC1B,GAAG;AAAA,MACH,IAAI,MAAM;AAAA,MAAC;AAAA,MACX,WAAW;AACT,WAAA;AAAA,MACF;AAAA,IAAA,CACD;AAED,QAAI,OAAO;AACT,SAAA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,WAAO,KAAK,SAAS,MAAA;AAAA,EACvB;AACF;;"} |
| import { Derived, DerivedOptions } from './derived.cjs'; | ||
| interface EffectOptions extends Omit<DerivedOptions<unknown>, 'onUpdate' | 'onSubscribe' | 'lazy' | 'fn'> { | ||
| /** | ||
| * Should the effect trigger immediately? | ||
| * @default false | ||
| */ | ||
| eager?: boolean; | ||
| fn: () => void; | ||
| } | ||
| export declare class Effect { | ||
| /** | ||
| * @private | ||
| */ | ||
| _derived: Derived<void>; | ||
| constructor(opts: EffectOptions); | ||
| mount(): () => void; | ||
| } | ||
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const derived = require("./derived.cjs"); | ||
| const __storeToDerived = /* @__PURE__ */ new WeakMap(); | ||
| const __derivedToStore = /* @__PURE__ */ new WeakMap(); | ||
| const __depsThatHaveWrittenThisTick = { | ||
| current: [] | ||
| }; | ||
| let __isFlushing = false; | ||
| let __batchDepth = 0; | ||
| const __pendingUpdates = /* @__PURE__ */ new Set(); | ||
| const __initialBatchValues = /* @__PURE__ */ new Map(); | ||
| function __flush_internals(relatedVals) { | ||
| const sorted = Array.from(relatedVals).sort((a, b) => { | ||
| if (a instanceof derived.Derived && a.options.deps.includes(b)) return 1; | ||
| if (b instanceof derived.Derived && b.options.deps.includes(a)) return -1; | ||
| return 0; | ||
| }); | ||
| for (const derived2 of sorted) { | ||
| if (__depsThatHaveWrittenThisTick.current.includes(derived2)) { | ||
| continue; | ||
| } | ||
| __depsThatHaveWrittenThisTick.current.push(derived2); | ||
| derived2.recompute(); | ||
| const stores = __derivedToStore.get(derived2); | ||
| if (stores) { | ||
| for (const store of stores) { | ||
| const relatedLinkedDerivedVals = __storeToDerived.get(store); | ||
| if (!relatedLinkedDerivedVals) continue; | ||
| __flush_internals(relatedLinkedDerivedVals); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function __notifyListeners(store) { | ||
| const value = { | ||
| prevVal: store.prevState, | ||
| currentVal: store.state | ||
| }; | ||
| for (const listener of store.listeners) { | ||
| listener(value); | ||
| } | ||
| } | ||
| function __notifyDerivedListeners(derived2) { | ||
| const value = { | ||
| prevVal: derived2.prevState, | ||
| currentVal: derived2.state | ||
| }; | ||
| for (const listener of derived2.listeners) { | ||
| listener(value); | ||
| } | ||
| } | ||
| function __flush(store) { | ||
| if (__batchDepth > 0 && !__initialBatchValues.has(store)) { | ||
| __initialBatchValues.set(store, store.prevState); | ||
| } | ||
| __pendingUpdates.add(store); | ||
| if (__batchDepth > 0) return; | ||
| if (__isFlushing) return; | ||
| try { | ||
| __isFlushing = true; | ||
| while (__pendingUpdates.size > 0) { | ||
| const stores = Array.from(__pendingUpdates); | ||
| __pendingUpdates.clear(); | ||
| for (const store2 of stores) { | ||
| const prevState = __initialBatchValues.get(store2) ?? store2.prevState; | ||
| store2.prevState = prevState; | ||
| __notifyListeners(store2); | ||
| } | ||
| for (const store2 of stores) { | ||
| const derivedVals = __storeToDerived.get(store2); | ||
| if (!derivedVals) continue; | ||
| __depsThatHaveWrittenThisTick.current.push(store2); | ||
| __flush_internals(derivedVals); | ||
| } | ||
| for (const store2 of stores) { | ||
| const derivedVals = __storeToDerived.get(store2); | ||
| if (!derivedVals) continue; | ||
| for (const derived2 of derivedVals) { | ||
| __notifyDerivedListeners(derived2); | ||
| } | ||
| } | ||
| } | ||
| } finally { | ||
| __isFlushing = false; | ||
| __depsThatHaveWrittenThisTick.current = []; | ||
| __initialBatchValues.clear(); | ||
| } | ||
| } | ||
| function batch(fn) { | ||
| __batchDepth++; | ||
| try { | ||
| fn(); | ||
| } finally { | ||
| __batchDepth--; | ||
| if (__batchDepth === 0) { | ||
| const pendingUpdateToFlush = __pendingUpdates.values().next().value; | ||
| if (pendingUpdateToFlush) { | ||
| __flush(pendingUpdateToFlush); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| exports.__depsThatHaveWrittenThisTick = __depsThatHaveWrittenThisTick; | ||
| exports.__derivedToStore = __derivedToStore; | ||
| exports.__flush = __flush; | ||
| exports.__storeToDerived = __storeToDerived; | ||
| exports.batch = batch; | ||
| //# sourceMappingURL=scheduler.cjs.map |
| {"version":3,"file":"scheduler.cjs","sources":["../../src/scheduler.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Set<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: Set<Derived<unknown>>) {\n // First sort deriveds by dependency order\n const sorted = Array.from(relatedVals).sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n\n for (const derived of sorted) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n const value = {\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }\n for (const listener of store.listeners) {\n listener(value)\n }\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n const value = {\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }\n for (const listener of derived.listeners) {\n listener(value)\n }\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = __pendingUpdates.values().next().value\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["Derived","derived","store"],"mappings":";;;AAkBO,MAAM,uCAAuB,QAAA;AAI7B,MAAM,uCAAuB,QAAA;AAK7B,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAA;AAE7B,MAAM,2CAA2B,IAAA;AAEjC,SAAS,kBAAkB,aAAoC;AAE7D,QAAM,SAAS,MAAM,KAAK,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM;AAEpD,QAAI,aAAaA,QAAAA,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAE/D,QAAI,aAAaA,QAAAA,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAC/D,WAAO;AAAA,EACT,CAAC;AAED,aAAWC,YAAW,QAAQ;AAC5B,QAAI,8BAA8B,QAAQ,SAASA,QAAO,GAAG;AAC3D;AAAA,IACF;AAEA,kCAA8B,QAAQ,KAAKA,QAAO;AAClD,IAAAA,SAAQ,UAAA;AAER,UAAM,SAAS,iBAAiB,IAAIA,QAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AAC1B,cAAM,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,CAAC,yBAA0B;AAC/B,0BAAkB,wBAAwB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,EAAA;AAEpB,aAAW,YAAY,MAAM,WAAW;AACtC,aAAS,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,yBAAyBA,UAA2B;AAC3D,QAAM,QAAQ;AAAA,IACZ,SAASA,SAAQ;AAAA,IACjB,YAAYA,SAAQ;AAAA,EAAA;AAEtB,aAAW,YAAYA,SAAQ,WAAW;AACxC,aAAS,KAAK;AAAA,EAChB;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACxD,yBAAqB,IAAI,OAAO,MAAM,SAAS;AAAA,EACjD;AAEA,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAElB,MAAI;AACF,mBAAe;AAEf,WAAO,iBAAiB,OAAO,GAAG;AAChC,YAAM,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAA;AAGjB,iBAAWC,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MACzB;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,sCAA8B,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAC/B;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAWD,YAAW,aAAa;AACjC,mCAAyBA,QAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,mBAAe;AACf,kCAA8B,UAAU,CAAA;AACxC,yBAAqB,MAAA;AAAA,EACvB;AACF;AAEO,SAAS,MAAM,IAAgB;AACpC;AACA,MAAI;AACF,OAAA;AAAA,EACF,UAAA;AACE;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,iBAAiB,OAAA,EAAS,OAAO;AAC9D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;;;;;;"} |
| import { Derived } from './derived.cjs'; | ||
| import { Store } from './store.cjs'; | ||
| /** | ||
| * This is here to solve the pyramid dependency problem where: | ||
| * A | ||
| * / \ | ||
| * B C | ||
| * \ / | ||
| * D | ||
| * | ||
| * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is. | ||
| * | ||
| * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been | ||
| * resolved. | ||
| * | ||
| * This is a record of stores, because derived stores are not able to write values to, but stores are | ||
| */ | ||
| export declare const __storeToDerived: WeakMap<Store<unknown, (cb: unknown) => unknown>, Set<Derived<unknown, readonly any[]>>>; | ||
| export declare const __derivedToStore: WeakMap<Derived<unknown, readonly any[]>, Set<Store<unknown, (cb: unknown) => unknown>>>; | ||
| export declare const __depsThatHaveWrittenThisTick: { | ||
| current: Array<Derived<unknown> | Store<unknown>>; | ||
| }; | ||
| /** | ||
| * @private only to be called from `Store` on write | ||
| */ | ||
| export declare function __flush(store: Store<unknown>): void; | ||
| export declare function batch(fn: () => void): void; |
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| function isUpdaterFunction(updater) { | ||
| return typeof updater === "function"; | ||
| } | ||
| exports.isUpdaterFunction = isUpdaterFunction; | ||
| //# sourceMappingURL=types.cjs.map |
| {"version":3,"file":"types.cjs","sources":["../../src/types.ts"],"sourcesContent":["/**\n * @private\n */\nexport type AnyUpdater = (prev: any) => any\n\n/**\n * Type-safe updater that can be either a function or direct value\n */\nexport type Updater<T> = ((prev: T) => T) | T\n\n/**\n * @private\n */\nexport interface ListenerValue<T> {\n readonly prevVal: T\n readonly currentVal: T\n}\n\n/**\n * @private\n */\nexport type Listener<T> = (value: ListenerValue<T>) => void\n\n/**\n * Type guard to check if updater is a function\n */\nexport function isUpdaterFunction<T>(\n updater: Updater<T>,\n): updater is (prev: T) => T {\n return typeof updater === 'function'\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,kBACd,SAC2B;AAC3B,SAAO,OAAO,YAAY;AAC5B;;"} |
| import { Store } from './store.js'; | ||
| import { Listener } from './types.js'; | ||
| export type UnwrapDerivedOrStore<T> = T extends Derived<infer InnerD> ? InnerD : T extends Store<infer InnerS> ? InnerS : never; | ||
| type UnwrapReadonlyDerivedOrStoreArray<TArr extends ReadonlyArray<Derived<any> | Store<any>>> = TArr extends readonly [] ? [] : TArr extends readonly [infer Head, ...infer Tail] ? Head extends Derived<any> | Store<any> ? Tail extends ReadonlyArray<Derived<any> | Store<any>> ? [ | ||
| UnwrapDerivedOrStore<Head>, | ||
| ...UnwrapReadonlyDerivedOrStoreArray<Tail> | ||
| ] : [UnwrapDerivedOrStore<Head>] : [] : TArr extends ReadonlyArray<Derived<any> | Store<any>> ? Array<UnwrapDerivedOrStore<TArr[number]>> : []; | ||
| export interface DerivedFnProps<TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>, TUnwrappedArr extends UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>> { | ||
| /** | ||
| * `undefined` if it's the first run | ||
| * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage | ||
| */ | ||
| prevVal: unknown | undefined; | ||
| prevDepVals: TUnwrappedArr | undefined; | ||
| currDepVals: TUnwrappedArr; | ||
| } | ||
| export interface DerivedOptions<TState, TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>> { | ||
| onSubscribe?: (listener: Listener<TState>, derived: Derived<TState>) => () => void; | ||
| onUpdate?: () => void; | ||
| deps: TArr; | ||
| /** | ||
| * Values of the `deps` from before and after the current invocation of `fn` | ||
| */ | ||
| fn: (props: DerivedFnProps<TArr>) => TState; | ||
| } | ||
| export declare class Derived<TState, const TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>> { | ||
| listeners: Set<Listener<TState>>; | ||
| state: TState; | ||
| prevState: TState | undefined; | ||
| options: DerivedOptions<TState, TArr>; | ||
| /** | ||
| * Functions representing the subscriptions. Call a function to cleanup | ||
| * @private | ||
| */ | ||
| _subscriptions: Array<() => void>; | ||
| lastSeenDepValues: Array<unknown>; | ||
| getDepVals: () => { | ||
| prevDepVals: unknown[]; | ||
| currDepVals: unknown[]; | ||
| prevVal: NonNullable<TState> | undefined; | ||
| }; | ||
| constructor(options: DerivedOptions<TState, TArr>); | ||
| registerOnGraph(deps?: ReadonlyArray<Derived<any> | Store<any>>): void; | ||
| unregisterFromGraph(deps?: ReadonlyArray<Derived<any> | Store<any>>): void; | ||
| recompute: () => void; | ||
| checkIfRecalculationNeededDeeply: () => void; | ||
| mount: () => () => void; | ||
| subscribe: (listener: Listener<TState>) => () => void; | ||
| } | ||
| export {}; |
| import { Store } from "./store.js"; | ||
| import { __storeToDerived, __derivedToStore } from "./scheduler.js"; | ||
| class Derived { | ||
| constructor(options) { | ||
| this.listeners = /* @__PURE__ */ new Set(); | ||
| this._subscriptions = []; | ||
| this.lastSeenDepValues = []; | ||
| this.getDepVals = () => { | ||
| const l = this.options.deps.length; | ||
| const prevDepVals = new Array(l); | ||
| const currDepVals = new Array(l); | ||
| for (let i = 0; i < l; i++) { | ||
| const dep = this.options.deps[i]; | ||
| prevDepVals[i] = dep.prevState; | ||
| currDepVals[i] = dep.state; | ||
| } | ||
| this.lastSeenDepValues = currDepVals; | ||
| return { | ||
| prevDepVals, | ||
| currDepVals, | ||
| prevVal: this.prevState ?? void 0 | ||
| }; | ||
| }; | ||
| this.recompute = () => { | ||
| var _a, _b; | ||
| this.prevState = this.state; | ||
| const depVals = this.getDepVals(); | ||
| this.state = this.options.fn(depVals); | ||
| (_b = (_a = this.options).onUpdate) == null ? void 0 : _b.call(_a); | ||
| }; | ||
| this.checkIfRecalculationNeededDeeply = () => { | ||
| for (const dep of this.options.deps) { | ||
| if (dep instanceof Derived) { | ||
| dep.checkIfRecalculationNeededDeeply(); | ||
| } | ||
| } | ||
| let shouldRecompute = false; | ||
| const lastSeenDepValues = this.lastSeenDepValues; | ||
| const { currDepVals } = this.getDepVals(); | ||
| for (let i = 0; i < currDepVals.length; i++) { | ||
| if (currDepVals[i] !== lastSeenDepValues[i]) { | ||
| shouldRecompute = true; | ||
| break; | ||
| } | ||
| } | ||
| if (shouldRecompute) { | ||
| this.recompute(); | ||
| } | ||
| }; | ||
| this.mount = () => { | ||
| this.registerOnGraph(); | ||
| this.checkIfRecalculationNeededDeeply(); | ||
| return () => { | ||
| this.unregisterFromGraph(); | ||
| for (const cleanup of this._subscriptions) { | ||
| cleanup(); | ||
| } | ||
| }; | ||
| }; | ||
| this.subscribe = (listener) => { | ||
| var _a, _b; | ||
| this.listeners.add(listener); | ||
| const unsub = (_b = (_a = this.options).onSubscribe) == null ? void 0 : _b.call(_a, listener, this); | ||
| return () => { | ||
| this.listeners.delete(listener); | ||
| unsub == null ? void 0 : unsub(); | ||
| }; | ||
| }; | ||
| this.options = options; | ||
| this.state = options.fn({ | ||
| prevDepVals: void 0, | ||
| prevVal: void 0, | ||
| currDepVals: this.getDepVals().currDepVals | ||
| }); | ||
| } | ||
| registerOnGraph(deps = this.options.deps) { | ||
| for (const dep of deps) { | ||
| if (dep instanceof Derived) { | ||
| dep.registerOnGraph(); | ||
| this.registerOnGraph(dep.options.deps); | ||
| } else if (dep instanceof Store) { | ||
| let relatedLinkedDerivedVals = __storeToDerived.get(dep); | ||
| if (!relatedLinkedDerivedVals) { | ||
| relatedLinkedDerivedVals = /* @__PURE__ */ new Set(); | ||
| __storeToDerived.set(dep, relatedLinkedDerivedVals); | ||
| } | ||
| relatedLinkedDerivedVals.add(this); | ||
| let relatedStores = __derivedToStore.get(this); | ||
| if (!relatedStores) { | ||
| relatedStores = /* @__PURE__ */ new Set(); | ||
| __derivedToStore.set(this, relatedStores); | ||
| } | ||
| relatedStores.add(dep); | ||
| } | ||
| } | ||
| } | ||
| unregisterFromGraph(deps = this.options.deps) { | ||
| for (const dep of deps) { | ||
| if (dep instanceof Derived) { | ||
| this.unregisterFromGraph(dep.options.deps); | ||
| } else if (dep instanceof Store) { | ||
| const relatedLinkedDerivedVals = __storeToDerived.get(dep); | ||
| if (relatedLinkedDerivedVals) { | ||
| relatedLinkedDerivedVals.delete(this); | ||
| } | ||
| const relatedStores = __derivedToStore.get(this); | ||
| if (relatedStores) { | ||
| relatedStores.delete(dep); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| export { | ||
| Derived | ||
| }; | ||
| //# sourceMappingURL=derived.js.map |
| {"version":3,"file":"derived.js","sources":["../../src/derived.ts"],"sourcesContent":["import { Store } from './store'\nimport { __derivedToStore, __storeToDerived } from './scheduler'\nimport type { Listener } from './types'\n\nexport type UnwrapDerivedOrStore<T> =\n T extends Derived<infer InnerD>\n ? InnerD\n : T extends Store<infer InnerS>\n ? InnerS\n : never\n\ntype UnwrapReadonlyDerivedOrStoreArray<\n TArr extends ReadonlyArray<Derived<any> | Store<any>>,\n> = TArr extends readonly []\n ? []\n : TArr extends readonly [infer Head, ...infer Tail]\n ? Head extends Derived<any> | Store<any>\n ? Tail extends ReadonlyArray<Derived<any> | Store<any>>\n ? [\n UnwrapDerivedOrStore<Head>,\n ...UnwrapReadonlyDerivedOrStoreArray<Tail>,\n ]\n : [UnwrapDerivedOrStore<Head>]\n : []\n : TArr extends ReadonlyArray<Derived<any> | Store<any>>\n ? Array<UnwrapDerivedOrStore<TArr[number]>>\n : []\n\n// Can't have currVal, as it's being evaluated from the current derived fn\nexport interface DerivedFnProps<\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n TUnwrappedArr extends\n UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>,\n> {\n // `undefined` if it's the first run\n /**\n * `undefined` if it's the first run\n * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage\n */\n prevVal: unknown | undefined\n prevDepVals: TUnwrappedArr | undefined\n currDepVals: TUnwrappedArr\n}\n\nexport interface DerivedOptions<\n TState,\n TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>,\n> {\n onSubscribe?: (\n listener: Listener<TState>,\n derived: Derived<TState>,\n ) => () => void\n onUpdate?: () => void\n deps: TArr\n /**\n * Values of the `deps` from before and after the current invocation of `fn`\n */\n fn: (props: DerivedFnProps<TArr>) => TState\n}\n\nexport class Derived<\n TState,\n const TArr extends ReadonlyArray<\n Derived<any> | Store<any>\n > = ReadonlyArray<any>,\n> {\n listeners = new Set<Listener<TState>>()\n state: TState\n prevState: TState | undefined\n options: DerivedOptions<TState, TArr>\n\n /**\n * Functions representing the subscriptions. Call a function to cleanup\n * @private\n */\n _subscriptions: Array<() => void> = []\n\n lastSeenDepValues: Array<unknown> = []\n getDepVals = () => {\n const l = this.options.deps.length\n const prevDepVals = new Array<unknown>(l)\n const currDepVals = new Array<unknown>(l)\n for (let i = 0; i < l; i++) {\n const dep = this.options.deps[i]!\n prevDepVals[i] = dep.prevState\n currDepVals[i] = dep.state\n }\n this.lastSeenDepValues = currDepVals\n return {\n prevDepVals,\n currDepVals,\n prevVal: this.prevState ?? undefined,\n }\n }\n\n constructor(options: DerivedOptions<TState, TArr>) {\n this.options = options\n this.state = options.fn({\n prevDepVals: undefined,\n prevVal: undefined,\n currDepVals: this.getDepVals().currDepVals as never,\n })\n }\n\n registerOnGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n // First register the intermediate derived value if it's not already registered\n dep.registerOnGraph()\n // Then register this derived with the dep's underlying stores\n this.registerOnGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n // Register the derived as related derived to the store\n let relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (!relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals = new Set()\n __storeToDerived.set(dep, relatedLinkedDerivedVals)\n }\n relatedLinkedDerivedVals.add(this as never)\n\n // Register the store as a related store to this derived\n let relatedStores = __derivedToStore.get(this as never)\n if (!relatedStores) {\n relatedStores = new Set()\n __derivedToStore.set(this as never, relatedStores)\n }\n relatedStores.add(dep)\n }\n }\n }\n\n unregisterFromGraph(\n deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps,\n ) {\n for (const dep of deps) {\n if (dep instanceof Derived) {\n this.unregisterFromGraph(dep.options.deps)\n } else if (dep instanceof Store) {\n const relatedLinkedDerivedVals = __storeToDerived.get(dep)\n if (relatedLinkedDerivedVals) {\n relatedLinkedDerivedVals.delete(this as never)\n }\n\n const relatedStores = __derivedToStore.get(this as never)\n if (relatedStores) {\n relatedStores.delete(dep)\n }\n }\n }\n }\n\n recompute = () => {\n this.prevState = this.state\n const depVals = this.getDepVals()\n this.state = this.options.fn(depVals as never)\n\n this.options.onUpdate?.()\n }\n\n checkIfRecalculationNeededDeeply = () => {\n for (const dep of this.options.deps) {\n if (dep instanceof Derived) {\n dep.checkIfRecalculationNeededDeeply()\n }\n }\n let shouldRecompute = false\n const lastSeenDepValues = this.lastSeenDepValues\n const { currDepVals } = this.getDepVals()\n for (let i = 0; i < currDepVals.length; i++) {\n if (currDepVals[i] !== lastSeenDepValues[i]) {\n shouldRecompute = true\n break\n }\n }\n\n if (shouldRecompute) {\n this.recompute()\n }\n }\n\n mount = () => {\n this.registerOnGraph()\n this.checkIfRecalculationNeededDeeply()\n\n return () => {\n this.unregisterFromGraph()\n for (const cleanup of this._subscriptions) {\n cleanup()\n }\n }\n }\n\n subscribe = (listener: Listener<TState>) => {\n this.listeners.add(listener)\n const unsub = this.options.onSubscribe?.(listener, this)\n return () => {\n this.listeners.delete(listener)\n unsub?.()\n }\n }\n}\n"],"names":[],"mappings":"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"} |
| import { Derived, DerivedOptions } from './derived.js'; | ||
| interface EffectOptions extends Omit<DerivedOptions<unknown>, 'onUpdate' | 'onSubscribe' | 'lazy' | 'fn'> { | ||
| /** | ||
| * Should the effect trigger immediately? | ||
| * @default false | ||
| */ | ||
| eager?: boolean; | ||
| fn: () => void; | ||
| } | ||
| export declare class Effect { | ||
| /** | ||
| * @private | ||
| */ | ||
| _derived: Derived<void>; | ||
| constructor(opts: EffectOptions); | ||
| mount(): () => void; | ||
| } | ||
| export {}; |
| import { Derived } from "./derived.js"; | ||
| class Effect { | ||
| constructor(opts) { | ||
| const { eager, fn, ...derivedProps } = opts; | ||
| this._derived = new Derived({ | ||
| ...derivedProps, | ||
| fn: () => { | ||
| }, | ||
| onUpdate() { | ||
| fn(); | ||
| } | ||
| }); | ||
| if (eager) { | ||
| fn(); | ||
| } | ||
| } | ||
| mount() { | ||
| return this._derived.mount(); | ||
| } | ||
| } | ||
| export { | ||
| Effect | ||
| }; | ||
| //# sourceMappingURL=effect.js.map |
| {"version":3,"file":"effect.js","sources":["../../src/effect.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { DerivedOptions } from './derived'\n\ninterface EffectOptions\n extends Omit<\n DerivedOptions<unknown>,\n 'onUpdate' | 'onSubscribe' | 'lazy' | 'fn'\n > {\n /**\n * Should the effect trigger immediately?\n * @default false\n */\n eager?: boolean\n fn: () => void\n}\n\nexport class Effect {\n /**\n * @private\n */\n _derived: Derived<void>\n\n constructor(opts: EffectOptions) {\n const { eager, fn, ...derivedProps } = opts\n\n this._derived = new Derived({\n ...derivedProps,\n fn: () => {},\n onUpdate() {\n fn()\n },\n })\n\n if (eager) {\n fn()\n }\n }\n\n mount() {\n return this._derived.mount()\n }\n}\n"],"names":[],"mappings":";AAgBO,MAAM,OAAO;AAAA,EAMlB,YAAY,MAAqB;AAC/B,UAAM,EAAE,OAAO,IAAI,GAAG,iBAAiB;AAEvC,SAAK,WAAW,IAAI,QAAQ;AAAA,MAC1B,GAAG;AAAA,MACH,IAAI,MAAM;AAAA,MAAC;AAAA,MACX,WAAW;AACT,WAAA;AAAA,MACF;AAAA,IAAA,CACD;AAED,QAAI,OAAO;AACT,SAAA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,WAAO,KAAK,SAAS,MAAA;AAAA,EACvB;AACF;"} |
| import { Derived } from './derived.js'; | ||
| import { Store } from './store.js'; | ||
| /** | ||
| * This is here to solve the pyramid dependency problem where: | ||
| * A | ||
| * / \ | ||
| * B C | ||
| * \ / | ||
| * D | ||
| * | ||
| * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is. | ||
| * | ||
| * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been | ||
| * resolved. | ||
| * | ||
| * This is a record of stores, because derived stores are not able to write values to, but stores are | ||
| */ | ||
| export declare const __storeToDerived: WeakMap<Store<unknown, (cb: unknown) => unknown>, Set<Derived<unknown, readonly any[]>>>; | ||
| export declare const __derivedToStore: WeakMap<Derived<unknown, readonly any[]>, Set<Store<unknown, (cb: unknown) => unknown>>>; | ||
| export declare const __depsThatHaveWrittenThisTick: { | ||
| current: Array<Derived<unknown> | Store<unknown>>; | ||
| }; | ||
| /** | ||
| * @private only to be called from `Store` on write | ||
| */ | ||
| export declare function __flush(store: Store<unknown>): void; | ||
| export declare function batch(fn: () => void): void; |
| import { Derived } from "./derived.js"; | ||
| const __storeToDerived = /* @__PURE__ */ new WeakMap(); | ||
| const __derivedToStore = /* @__PURE__ */ new WeakMap(); | ||
| const __depsThatHaveWrittenThisTick = { | ||
| current: [] | ||
| }; | ||
| let __isFlushing = false; | ||
| let __batchDepth = 0; | ||
| const __pendingUpdates = /* @__PURE__ */ new Set(); | ||
| const __initialBatchValues = /* @__PURE__ */ new Map(); | ||
| function __flush_internals(relatedVals) { | ||
| const sorted = Array.from(relatedVals).sort((a, b) => { | ||
| if (a instanceof Derived && a.options.deps.includes(b)) return 1; | ||
| if (b instanceof Derived && b.options.deps.includes(a)) return -1; | ||
| return 0; | ||
| }); | ||
| for (const derived of sorted) { | ||
| if (__depsThatHaveWrittenThisTick.current.includes(derived)) { | ||
| continue; | ||
| } | ||
| __depsThatHaveWrittenThisTick.current.push(derived); | ||
| derived.recompute(); | ||
| const stores = __derivedToStore.get(derived); | ||
| if (stores) { | ||
| for (const store of stores) { | ||
| const relatedLinkedDerivedVals = __storeToDerived.get(store); | ||
| if (!relatedLinkedDerivedVals) continue; | ||
| __flush_internals(relatedLinkedDerivedVals); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function __notifyListeners(store) { | ||
| const value = { | ||
| prevVal: store.prevState, | ||
| currentVal: store.state | ||
| }; | ||
| for (const listener of store.listeners) { | ||
| listener(value); | ||
| } | ||
| } | ||
| function __notifyDerivedListeners(derived) { | ||
| const value = { | ||
| prevVal: derived.prevState, | ||
| currentVal: derived.state | ||
| }; | ||
| for (const listener of derived.listeners) { | ||
| listener(value); | ||
| } | ||
| } | ||
| function __flush(store) { | ||
| if (__batchDepth > 0 && !__initialBatchValues.has(store)) { | ||
| __initialBatchValues.set(store, store.prevState); | ||
| } | ||
| __pendingUpdates.add(store); | ||
| if (__batchDepth > 0) return; | ||
| if (__isFlushing) return; | ||
| try { | ||
| __isFlushing = true; | ||
| while (__pendingUpdates.size > 0) { | ||
| const stores = Array.from(__pendingUpdates); | ||
| __pendingUpdates.clear(); | ||
| for (const store2 of stores) { | ||
| const prevState = __initialBatchValues.get(store2) ?? store2.prevState; | ||
| store2.prevState = prevState; | ||
| __notifyListeners(store2); | ||
| } | ||
| for (const store2 of stores) { | ||
| const derivedVals = __storeToDerived.get(store2); | ||
| if (!derivedVals) continue; | ||
| __depsThatHaveWrittenThisTick.current.push(store2); | ||
| __flush_internals(derivedVals); | ||
| } | ||
| for (const store2 of stores) { | ||
| const derivedVals = __storeToDerived.get(store2); | ||
| if (!derivedVals) continue; | ||
| for (const derived of derivedVals) { | ||
| __notifyDerivedListeners(derived); | ||
| } | ||
| } | ||
| } | ||
| } finally { | ||
| __isFlushing = false; | ||
| __depsThatHaveWrittenThisTick.current = []; | ||
| __initialBatchValues.clear(); | ||
| } | ||
| } | ||
| function batch(fn) { | ||
| __batchDepth++; | ||
| try { | ||
| fn(); | ||
| } finally { | ||
| __batchDepth--; | ||
| if (__batchDepth === 0) { | ||
| const pendingUpdateToFlush = __pendingUpdates.values().next().value; | ||
| if (pendingUpdateToFlush) { | ||
| __flush(pendingUpdateToFlush); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| export { | ||
| __depsThatHaveWrittenThisTick, | ||
| __derivedToStore, | ||
| __flush, | ||
| __storeToDerived, | ||
| batch | ||
| }; | ||
| //# sourceMappingURL=scheduler.js.map |
| {"version":3,"file":"scheduler.js","sources":["../../src/scheduler.ts"],"sourcesContent":["import { Derived } from './derived'\nimport type { Store } from './store'\n\n/**\n * This is here to solve the pyramid dependency problem where:\n * A\n * / \\\n * B C\n * \\ /\n * D\n *\n * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is.\n *\n * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been\n * resolved.\n *\n * This is a record of stores, because derived stores are not able to write values to, but stores are\n */\nexport const __storeToDerived = new WeakMap<\n Store<unknown>,\n Set<Derived<unknown>>\n>()\nexport const __derivedToStore = new WeakMap<\n Derived<unknown>,\n Set<Store<unknown>>\n>()\n\nexport const __depsThatHaveWrittenThisTick = {\n current: [] as Array<Derived<unknown> | Store<unknown>>,\n}\n\nlet __isFlushing = false\nlet __batchDepth = 0\nconst __pendingUpdates = new Set<Store<unknown>>()\n// Add a map to store initial values before batch\nconst __initialBatchValues = new Map<Store<unknown>, unknown>()\n\nfunction __flush_internals(relatedVals: Set<Derived<unknown>>) {\n // First sort deriveds by dependency order\n const sorted = Array.from(relatedVals).sort((a, b) => {\n // If a depends on b, b should go first\n if (a instanceof Derived && a.options.deps.includes(b)) return 1\n // If b depends on a, a should go first\n if (b instanceof Derived && b.options.deps.includes(a)) return -1\n return 0\n })\n\n for (const derived of sorted) {\n if (__depsThatHaveWrittenThisTick.current.includes(derived)) {\n continue\n }\n\n __depsThatHaveWrittenThisTick.current.push(derived)\n derived.recompute()\n\n const stores = __derivedToStore.get(derived)\n if (stores) {\n for (const store of stores) {\n const relatedLinkedDerivedVals = __storeToDerived.get(store)\n if (!relatedLinkedDerivedVals) continue\n __flush_internals(relatedLinkedDerivedVals)\n }\n }\n }\n}\n\nfunction __notifyListeners(store: Store<unknown>) {\n const value = {\n prevVal: store.prevState as never,\n currentVal: store.state as never,\n }\n for (const listener of store.listeners) {\n listener(value)\n }\n}\n\nfunction __notifyDerivedListeners(derived: Derived<unknown>) {\n const value = {\n prevVal: derived.prevState as never,\n currentVal: derived.state as never,\n }\n for (const listener of derived.listeners) {\n listener(value)\n }\n}\n\n/**\n * @private only to be called from `Store` on write\n */\nexport function __flush(store: Store<unknown>) {\n // If we're starting a batch, store the initial values\n if (__batchDepth > 0 && !__initialBatchValues.has(store)) {\n __initialBatchValues.set(store, store.prevState)\n }\n\n __pendingUpdates.add(store)\n\n if (__batchDepth > 0) return\n if (__isFlushing) return\n\n try {\n __isFlushing = true\n\n while (__pendingUpdates.size > 0) {\n const stores = Array.from(__pendingUpdates)\n __pendingUpdates.clear()\n\n // First notify listeners with updated values\n for (const store of stores) {\n // Use initial batch values for prevState if we have them\n const prevState = __initialBatchValues.get(store) ?? store.prevState\n store.prevState = prevState\n __notifyListeners(store)\n }\n\n // Then update all derived values\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n __depsThatHaveWrittenThisTick.current.push(store)\n __flush_internals(derivedVals)\n }\n\n // Notify derived listeners after recomputing\n for (const store of stores) {\n const derivedVals = __storeToDerived.get(store)\n if (!derivedVals) continue\n\n for (const derived of derivedVals) {\n __notifyDerivedListeners(derived)\n }\n }\n }\n } finally {\n __isFlushing = false\n __depsThatHaveWrittenThisTick.current = []\n __initialBatchValues.clear()\n }\n}\n\nexport function batch(fn: () => void) {\n __batchDepth++\n try {\n fn()\n } finally {\n __batchDepth--\n if (__batchDepth === 0) {\n const pendingUpdateToFlush = __pendingUpdates.values().next().value\n if (pendingUpdateToFlush) {\n __flush(pendingUpdateToFlush) // Trigger flush of all pending updates\n }\n }\n }\n}\n"],"names":["store"],"mappings":";AAkBO,MAAM,uCAAuB,QAAA;AAI7B,MAAM,uCAAuB,QAAA;AAK7B,MAAM,gCAAgC;AAAA,EAC3C,SAAS,CAAA;AACX;AAEA,IAAI,eAAe;AACnB,IAAI,eAAe;AACnB,MAAM,uCAAuB,IAAA;AAE7B,MAAM,2CAA2B,IAAA;AAEjC,SAAS,kBAAkB,aAAoC;AAE7D,QAAM,SAAS,MAAM,KAAK,WAAW,EAAE,KAAK,CAAC,GAAG,MAAM;AAEpD,QAAI,aAAa,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAE/D,QAAI,aAAa,WAAW,EAAE,QAAQ,KAAK,SAAS,CAAC,EAAG,QAAO;AAC/D,WAAO;AAAA,EACT,CAAC;AAED,aAAW,WAAW,QAAQ;AAC5B,QAAI,8BAA8B,QAAQ,SAAS,OAAO,GAAG;AAC3D;AAAA,IACF;AAEA,kCAA8B,QAAQ,KAAK,OAAO;AAClD,YAAQ,UAAA;AAER,UAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,QAAI,QAAQ;AACV,iBAAW,SAAS,QAAQ;AAC1B,cAAM,2BAA2B,iBAAiB,IAAI,KAAK;AAC3D,YAAI,CAAC,yBAA0B;AAC/B,0BAAkB,wBAAwB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,EAAA;AAEpB,aAAW,YAAY,MAAM,WAAW;AACtC,aAAS,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,yBAAyB,SAA2B;AAC3D,QAAM,QAAQ;AAAA,IACZ,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ;AAAA,EAAA;AAEtB,aAAW,YAAY,QAAQ,WAAW;AACxC,aAAS,KAAK;AAAA,EAChB;AACF;AAKO,SAAS,QAAQ,OAAuB;AAE7C,MAAI,eAAe,KAAK,CAAC,qBAAqB,IAAI,KAAK,GAAG;AACxD,yBAAqB,IAAI,OAAO,MAAM,SAAS;AAAA,EACjD;AAEA,mBAAiB,IAAI,KAAK;AAE1B,MAAI,eAAe,EAAG;AACtB,MAAI,aAAc;AAElB,MAAI;AACF,mBAAe;AAEf,WAAO,iBAAiB,OAAO,GAAG;AAChC,YAAM,SAAS,MAAM,KAAK,gBAAgB;AAC1C,uBAAiB,MAAA;AAGjB,iBAAWA,UAAS,QAAQ;AAE1B,cAAM,YAAY,qBAAqB,IAAIA,MAAK,KAAKA,OAAM;AAC3DA,eAAM,YAAY;AAClB,0BAAkBA,MAAK;AAAA,MACzB;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,sCAA8B,QAAQ,KAAKA,MAAK;AAChD,0BAAkB,WAAW;AAAA,MAC/B;AAGA,iBAAWA,UAAS,QAAQ;AAC1B,cAAM,cAAc,iBAAiB,IAAIA,MAAK;AAC9C,YAAI,CAAC,YAAa;AAElB,mBAAW,WAAW,aAAa;AACjC,mCAAyB,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAA;AACE,mBAAe;AACf,kCAA8B,UAAU,CAAA;AACxC,yBAAqB,MAAA;AAAA,EACvB;AACF;AAEO,SAAS,MAAM,IAAgB;AACpC;AACA,MAAI;AACF,OAAA;AAAA,EACF,UAAA;AACE;AACA,QAAI,iBAAiB,GAAG;AACtB,YAAM,uBAAuB,iBAAiB,OAAA,EAAS,OAAO;AAC9D,UAAI,sBAAsB;AACxB,gBAAQ,oBAAoB;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;"} |
| function isUpdaterFunction(updater) { | ||
| return typeof updater === "function"; | ||
| } | ||
| export { | ||
| isUpdaterFunction | ||
| }; | ||
| //# sourceMappingURL=types.js.map |
| {"version":3,"file":"types.js","sources":["../../src/types.ts"],"sourcesContent":["/**\n * @private\n */\nexport type AnyUpdater = (prev: any) => any\n\n/**\n * Type-safe updater that can be either a function or direct value\n */\nexport type Updater<T> = ((prev: T) => T) | T\n\n/**\n * @private\n */\nexport interface ListenerValue<T> {\n readonly prevVal: T\n readonly currentVal: T\n}\n\n/**\n * @private\n */\nexport type Listener<T> = (value: ListenerValue<T>) => void\n\n/**\n * Type guard to check if updater is a function\n */\nexport function isUpdaterFunction<T>(\n updater: Updater<T>,\n): updater is (prev: T) => T {\n return typeof updater === 'function'\n}\n"],"names":[],"mappings":"AA0BO,SAAS,kBACd,SAC2B;AAC3B,SAAO,OAAO,YAAY;AAC5B;"} |
-203
| import { Store } from './store' | ||
| import { __derivedToStore, __storeToDerived } from './scheduler' | ||
| import type { Listener } from './types' | ||
| export type UnwrapDerivedOrStore<T> = | ||
| T extends Derived<infer InnerD> | ||
| ? InnerD | ||
| : T extends Store<infer InnerS> | ||
| ? InnerS | ||
| : never | ||
| type UnwrapReadonlyDerivedOrStoreArray< | ||
| TArr extends ReadonlyArray<Derived<any> | Store<any>>, | ||
| > = TArr extends readonly [] | ||
| ? [] | ||
| : TArr extends readonly [infer Head, ...infer Tail] | ||
| ? Head extends Derived<any> | Store<any> | ||
| ? Tail extends ReadonlyArray<Derived<any> | Store<any>> | ||
| ? [ | ||
| UnwrapDerivedOrStore<Head>, | ||
| ...UnwrapReadonlyDerivedOrStoreArray<Tail>, | ||
| ] | ||
| : [UnwrapDerivedOrStore<Head>] | ||
| : [] | ||
| : TArr extends ReadonlyArray<Derived<any> | Store<any>> | ||
| ? Array<UnwrapDerivedOrStore<TArr[number]>> | ||
| : [] | ||
| // Can't have currVal, as it's being evaluated from the current derived fn | ||
| export interface DerivedFnProps< | ||
| TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>, | ||
| TUnwrappedArr extends | ||
| UnwrapReadonlyDerivedOrStoreArray<TArr> = UnwrapReadonlyDerivedOrStoreArray<TArr>, | ||
| > { | ||
| // `undefined` if it's the first run | ||
| /** | ||
| * `undefined` if it's the first run | ||
| * @privateRemarks this also cannot be typed as TState, as it breaks the inferencing of the function's return type when an argument is used - even with `NoInfer` usage | ||
| */ | ||
| prevVal: unknown | undefined | ||
| prevDepVals: TUnwrappedArr | undefined | ||
| currDepVals: TUnwrappedArr | ||
| } | ||
| export interface DerivedOptions< | ||
| TState, | ||
| TArr extends ReadonlyArray<Derived<any> | Store<any>> = ReadonlyArray<any>, | ||
| > { | ||
| onSubscribe?: ( | ||
| listener: Listener<TState>, | ||
| derived: Derived<TState>, | ||
| ) => () => void | ||
| onUpdate?: () => void | ||
| deps: TArr | ||
| /** | ||
| * Values of the `deps` from before and after the current invocation of `fn` | ||
| */ | ||
| fn: (props: DerivedFnProps<TArr>) => TState | ||
| } | ||
| export class Derived< | ||
| TState, | ||
| const TArr extends ReadonlyArray< | ||
| Derived<any> | Store<any> | ||
| > = ReadonlyArray<any>, | ||
| > { | ||
| listeners = new Set<Listener<TState>>() | ||
| state: TState | ||
| prevState: TState | undefined | ||
| options: DerivedOptions<TState, TArr> | ||
| /** | ||
| * Functions representing the subscriptions. Call a function to cleanup | ||
| * @private | ||
| */ | ||
| _subscriptions: Array<() => void> = [] | ||
| lastSeenDepValues: Array<unknown> = [] | ||
| getDepVals = () => { | ||
| const l = this.options.deps.length | ||
| const prevDepVals = new Array<unknown>(l) | ||
| const currDepVals = new Array<unknown>(l) | ||
| for (let i = 0; i < l; i++) { | ||
| const dep = this.options.deps[i]! | ||
| prevDepVals[i] = dep.prevState | ||
| currDepVals[i] = dep.state | ||
| } | ||
| this.lastSeenDepValues = currDepVals | ||
| return { | ||
| prevDepVals, | ||
| currDepVals, | ||
| prevVal: this.prevState ?? undefined, | ||
| } | ||
| } | ||
| constructor(options: DerivedOptions<TState, TArr>) { | ||
| this.options = options | ||
| this.state = options.fn({ | ||
| prevDepVals: undefined, | ||
| prevVal: undefined, | ||
| currDepVals: this.getDepVals().currDepVals as never, | ||
| }) | ||
| } | ||
| registerOnGraph( | ||
| deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps, | ||
| ) { | ||
| for (const dep of deps) { | ||
| if (dep instanceof Derived) { | ||
| // First register the intermediate derived value if it's not already registered | ||
| dep.registerOnGraph() | ||
| // Then register this derived with the dep's underlying stores | ||
| this.registerOnGraph(dep.options.deps) | ||
| } else if (dep instanceof Store) { | ||
| // Register the derived as related derived to the store | ||
| let relatedLinkedDerivedVals = __storeToDerived.get(dep) | ||
| if (!relatedLinkedDerivedVals) { | ||
| relatedLinkedDerivedVals = new Set() | ||
| __storeToDerived.set(dep, relatedLinkedDerivedVals) | ||
| } | ||
| relatedLinkedDerivedVals.add(this as never) | ||
| // Register the store as a related store to this derived | ||
| let relatedStores = __derivedToStore.get(this as never) | ||
| if (!relatedStores) { | ||
| relatedStores = new Set() | ||
| __derivedToStore.set(this as never, relatedStores) | ||
| } | ||
| relatedStores.add(dep) | ||
| } | ||
| } | ||
| } | ||
| unregisterFromGraph( | ||
| deps: ReadonlyArray<Derived<any> | Store<any>> = this.options.deps, | ||
| ) { | ||
| for (const dep of deps) { | ||
| if (dep instanceof Derived) { | ||
| this.unregisterFromGraph(dep.options.deps) | ||
| } else if (dep instanceof Store) { | ||
| const relatedLinkedDerivedVals = __storeToDerived.get(dep) | ||
| if (relatedLinkedDerivedVals) { | ||
| relatedLinkedDerivedVals.delete(this as never) | ||
| } | ||
| const relatedStores = __derivedToStore.get(this as never) | ||
| if (relatedStores) { | ||
| relatedStores.delete(dep) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| recompute = () => { | ||
| this.prevState = this.state | ||
| const depVals = this.getDepVals() | ||
| this.state = this.options.fn(depVals as never) | ||
| this.options.onUpdate?.() | ||
| } | ||
| checkIfRecalculationNeededDeeply = () => { | ||
| for (const dep of this.options.deps) { | ||
| if (dep instanceof Derived) { | ||
| dep.checkIfRecalculationNeededDeeply() | ||
| } | ||
| } | ||
| let shouldRecompute = false | ||
| const lastSeenDepValues = this.lastSeenDepValues | ||
| const { currDepVals } = this.getDepVals() | ||
| for (let i = 0; i < currDepVals.length; i++) { | ||
| if (currDepVals[i] !== lastSeenDepValues[i]) { | ||
| shouldRecompute = true | ||
| break | ||
| } | ||
| } | ||
| if (shouldRecompute) { | ||
| this.recompute() | ||
| } | ||
| } | ||
| mount = () => { | ||
| this.registerOnGraph() | ||
| this.checkIfRecalculationNeededDeeply() | ||
| return () => { | ||
| this.unregisterFromGraph() | ||
| for (const cleanup of this._subscriptions) { | ||
| cleanup() | ||
| } | ||
| } | ||
| } | ||
| subscribe = (listener: Listener<TState>) => { | ||
| this.listeners.add(listener) | ||
| const unsub = this.options.onSubscribe?.(listener, this) | ||
| return () => { | ||
| this.listeners.delete(listener) | ||
| unsub?.() | ||
| } | ||
| } | ||
| } |
| import { Derived } from './derived' | ||
| import type { DerivedOptions } from './derived' | ||
| interface EffectOptions | ||
| extends Omit< | ||
| DerivedOptions<unknown>, | ||
| 'onUpdate' | 'onSubscribe' | 'lazy' | 'fn' | ||
| > { | ||
| /** | ||
| * Should the effect trigger immediately? | ||
| * @default false | ||
| */ | ||
| eager?: boolean | ||
| fn: () => void | ||
| } | ||
| export class Effect { | ||
| /** | ||
| * @private | ||
| */ | ||
| _derived: Derived<void> | ||
| constructor(opts: EffectOptions) { | ||
| const { eager, fn, ...derivedProps } = opts | ||
| this._derived = new Derived({ | ||
| ...derivedProps, | ||
| fn: () => {}, | ||
| onUpdate() { | ||
| fn() | ||
| }, | ||
| }) | ||
| if (eager) { | ||
| fn() | ||
| } | ||
| } | ||
| mount() { | ||
| return this._derived.mount() | ||
| } | ||
| } |
-155
| import { Derived } from './derived' | ||
| import type { Store } from './store' | ||
| /** | ||
| * This is here to solve the pyramid dependency problem where: | ||
| * A | ||
| * / \ | ||
| * B C | ||
| * \ / | ||
| * D | ||
| * | ||
| * Where we deeply traverse this tree, how do we avoid D being recomputed twice; once when B is updated, once when C is. | ||
| * | ||
| * To solve this, we create linkedDeps that allows us to sync avoid writes to the state until all of the deps have been | ||
| * resolved. | ||
| * | ||
| * This is a record of stores, because derived stores are not able to write values to, but stores are | ||
| */ | ||
| export const __storeToDerived = new WeakMap< | ||
| Store<unknown>, | ||
| Set<Derived<unknown>> | ||
| >() | ||
| export const __derivedToStore = new WeakMap< | ||
| Derived<unknown>, | ||
| Set<Store<unknown>> | ||
| >() | ||
| export const __depsThatHaveWrittenThisTick = { | ||
| current: [] as Array<Derived<unknown> | Store<unknown>>, | ||
| } | ||
| let __isFlushing = false | ||
| let __batchDepth = 0 | ||
| const __pendingUpdates = new Set<Store<unknown>>() | ||
| // Add a map to store initial values before batch | ||
| const __initialBatchValues = new Map<Store<unknown>, unknown>() | ||
| function __flush_internals(relatedVals: Set<Derived<unknown>>) { | ||
| // First sort deriveds by dependency order | ||
| const sorted = Array.from(relatedVals).sort((a, b) => { | ||
| // If a depends on b, b should go first | ||
| if (a instanceof Derived && a.options.deps.includes(b)) return 1 | ||
| // If b depends on a, a should go first | ||
| if (b instanceof Derived && b.options.deps.includes(a)) return -1 | ||
| return 0 | ||
| }) | ||
| for (const derived of sorted) { | ||
| if (__depsThatHaveWrittenThisTick.current.includes(derived)) { | ||
| continue | ||
| } | ||
| __depsThatHaveWrittenThisTick.current.push(derived) | ||
| derived.recompute() | ||
| const stores = __derivedToStore.get(derived) | ||
| if (stores) { | ||
| for (const store of stores) { | ||
| const relatedLinkedDerivedVals = __storeToDerived.get(store) | ||
| if (!relatedLinkedDerivedVals) continue | ||
| __flush_internals(relatedLinkedDerivedVals) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| function __notifyListeners(store: Store<unknown>) { | ||
| const value = { | ||
| prevVal: store.prevState as never, | ||
| currentVal: store.state as never, | ||
| } | ||
| for (const listener of store.listeners) { | ||
| listener(value) | ||
| } | ||
| } | ||
| function __notifyDerivedListeners(derived: Derived<unknown>) { | ||
| const value = { | ||
| prevVal: derived.prevState as never, | ||
| currentVal: derived.state as never, | ||
| } | ||
| for (const listener of derived.listeners) { | ||
| listener(value) | ||
| } | ||
| } | ||
| /** | ||
| * @private only to be called from `Store` on write | ||
| */ | ||
| export function __flush(store: Store<unknown>) { | ||
| // If we're starting a batch, store the initial values | ||
| if (__batchDepth > 0 && !__initialBatchValues.has(store)) { | ||
| __initialBatchValues.set(store, store.prevState) | ||
| } | ||
| __pendingUpdates.add(store) | ||
| if (__batchDepth > 0) return | ||
| if (__isFlushing) return | ||
| try { | ||
| __isFlushing = true | ||
| while (__pendingUpdates.size > 0) { | ||
| const stores = Array.from(__pendingUpdates) | ||
| __pendingUpdates.clear() | ||
| // First notify listeners with updated values | ||
| for (const store of stores) { | ||
| // Use initial batch values for prevState if we have them | ||
| const prevState = __initialBatchValues.get(store) ?? store.prevState | ||
| store.prevState = prevState | ||
| __notifyListeners(store) | ||
| } | ||
| // Then update all derived values | ||
| for (const store of stores) { | ||
| const derivedVals = __storeToDerived.get(store) | ||
| if (!derivedVals) continue | ||
| __depsThatHaveWrittenThisTick.current.push(store) | ||
| __flush_internals(derivedVals) | ||
| } | ||
| // Notify derived listeners after recomputing | ||
| for (const store of stores) { | ||
| const derivedVals = __storeToDerived.get(store) | ||
| if (!derivedVals) continue | ||
| for (const derived of derivedVals) { | ||
| __notifyDerivedListeners(derived) | ||
| } | ||
| } | ||
| } | ||
| } finally { | ||
| __isFlushing = false | ||
| __depsThatHaveWrittenThisTick.current = [] | ||
| __initialBatchValues.clear() | ||
| } | ||
| } | ||
| export function batch(fn: () => void) { | ||
| __batchDepth++ | ||
| try { | ||
| fn() | ||
| } finally { | ||
| __batchDepth-- | ||
| if (__batchDepth === 0) { | ||
| const pendingUpdateToFlush = __pendingUpdates.values().next().value | ||
| if (pendingUpdateToFlush) { | ||
| __flush(pendingUpdateToFlush) // Trigger flush of all pending updates | ||
| } | ||
| } | ||
| } | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
145769
66.32%2369
91.98%0
-100%40
-9.09%1
Infinity%