You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@tanstack/store

Package Overview
Dependencies
Maintainers
6
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tanstack/store - npm Package Compare versions

Comparing version
0.8.1
to
0.9.0
+345
dist/cjs/alien.cjs
"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":"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"}
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 {};
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;"}
/* 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)
}
}
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
}
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

@@ -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';
"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;;;"}

@@ -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>;

@@ -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';

@@ -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":";;;"}

@@ -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>;

@@ -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;"}

@@ -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;
{
"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",

@@ -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'

@@ -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)
}

@@ -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;"}
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()
}
}
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
}
}
}
}