alien-signals
Advanced tools
+172
-183
@@ -42,14 +42,18 @@ "use strict"; | ||
| SubscriberFlags2[SubscriberFlags2["Tracking"] = 4] = "Tracking"; | ||
| SubscriberFlags2[SubscriberFlags2["Notified"] = 8] = "Notified"; | ||
| SubscriberFlags2[SubscriberFlags2["Recursed"] = 16] = "Recursed"; | ||
| SubscriberFlags2[SubscriberFlags2["Dirty"] = 32] = "Dirty"; | ||
| SubscriberFlags2[SubscriberFlags2["PendingComputed"] = 64] = "PendingComputed"; | ||
| SubscriberFlags2[SubscriberFlags2["PendingEffect"] = 128] = "PendingEffect"; | ||
| SubscriberFlags2[SubscriberFlags2["Cold"] = 256] = "Cold"; | ||
| SubscriberFlags2[SubscriberFlags2["Propagated"] = 224] = "Propagated"; | ||
| SubscriberFlags2[SubscriberFlags2["Recursed"] = 8] = "Recursed"; | ||
| SubscriberFlags2[SubscriberFlags2["Dirty"] = 16] = "Dirty"; | ||
| SubscriberFlags2[SubscriberFlags2["Pending"] = 32] = "Pending"; | ||
| SubscriberFlags2[SubscriberFlags2["Cold"] = 64] = "Cold"; | ||
| SubscriberFlags2[SubscriberFlags2["Propagated"] = 48] = "Propagated"; | ||
| return SubscriberFlags2; | ||
| })(SubscriberFlags || {}); | ||
| function createReactiveSystem({ | ||
| updateComputed, | ||
| notifyEffect: notifyEffect2 | ||
| computed: { | ||
| update: updateComputed2, | ||
| onUnwatched: onUnwatchedComputed = () => { | ||
| } | ||
| }, | ||
| effect: { | ||
| notify: notifyEffect2 | ||
| } | ||
| }) { | ||
@@ -93,3 +97,3 @@ let queuedEffects; | ||
| propagate(link2) { | ||
| let targetFlag = 32 /* Dirty */; | ||
| let targetFlag = 16 /* Dirty */ | 32 /* Pending */; | ||
| let subs = link2; | ||
@@ -100,3 +104,3 @@ let stack = 0; | ||
| const subFlags = sub.flags; | ||
| if (!(subFlags & (4 /* Tracking */ | 16 /* Recursed */ | 224 /* Propagated */)) && (sub.flags = subFlags | targetFlag | 8 /* Notified */, true) || subFlags & 16 /* Recursed */ && !(subFlags & 4 /* Tracking */) && (sub.flags = subFlags & ~16 /* Recursed */ | targetFlag | 8 /* Notified */, true) || !(subFlags & 224 /* Propagated */) && isValidLink(link2, sub) && (sub.flags = subFlags | 16 /* Recursed */ | targetFlag | 8 /* Notified */, sub.subs !== void 0)) { | ||
| if (!(subFlags & (4 /* Tracking */ | 8 /* Recursed */ | 48 /* Propagated */)) && (sub.flags = subFlags | targetFlag, true) || subFlags & 8 /* Recursed */ && !(subFlags & 4 /* Tracking */) && (sub.flags = subFlags & ~8 /* Recursed */ | targetFlag, true) || !(subFlags & 48 /* Propagated */) && isValidLink(link2, sub) && (sub.flags = subFlags | 8 /* Recursed */ | targetFlag, sub.subs !== void 0)) { | ||
| const subSubs = sub.subs; | ||
@@ -107,8 +111,7 @@ if (subSubs !== void 0) { | ||
| link2 = subs = subSubs; | ||
| targetFlag = 64 /* PendingComputed */; | ||
| ++stack; | ||
| } else { | ||
| link2 = subSubs; | ||
| targetFlag = subFlags & 2 /* Effect */ ? 128 /* PendingEffect */ : 64 /* PendingComputed */; | ||
| } | ||
| targetFlag = 32 /* Pending */; | ||
| continue; | ||
@@ -125,4 +128,4 @@ } | ||
| } else if (!(subFlags & (4 /* Tracking */ | targetFlag))) { | ||
| sub.flags = subFlags | targetFlag | 8 /* Notified */; | ||
| if ((subFlags & (2 /* Effect */ | 8 /* Notified */)) === 2 /* Effect */) { | ||
| sub.flags = subFlags | targetFlag; | ||
| if (subFlags & 2 /* Effect */ && !isQueued(sub)) { | ||
| if (queuedEffectsTail !== void 0) { | ||
@@ -135,3 +138,3 @@ queuedEffectsTail.depsTail.nextDep = sub.deps; | ||
| } | ||
| } else if (!(subFlags & targetFlag) && subFlags & 224 /* Propagated */ && isValidLink(link2, sub)) { | ||
| } else if (!(subFlags & targetFlag) && subFlags & 48 /* Propagated */ && isValidLink(link2, sub)) { | ||
| sub.flags = subFlags | targetFlag; | ||
@@ -141,3 +144,3 @@ } | ||
| subs = link2; | ||
| targetFlag = stack ? 64 /* PendingComputed */ : 32 /* Dirty */; | ||
| targetFlag = stack ? 32 /* Pending */ : 16 /* Dirty */ | 32 /* Pending */; | ||
| continue; | ||
@@ -153,3 +156,3 @@ } | ||
| subs = link2; | ||
| targetFlag = stack ? 64 /* PendingComputed */ : 32 /* Dirty */; | ||
| targetFlag = stack ? 32 /* Pending */ : 16 /* Dirty */ | 32 /* Pending */; | ||
| continue top; | ||
@@ -171,3 +174,3 @@ } | ||
| sub.depsTail = void 0; | ||
| sub.flags = sub.flags & ~(8 /* Notified */ | 16 /* Recursed */ | 224 /* Propagated */) | 4 /* Tracking */; | ||
| sub.flags = sub.flags & ~(8 /* Recursed */ | 48 /* Propagated */) | 4 /* Tracking */; | ||
| }, | ||
@@ -197,44 +200,77 @@ /** | ||
| /** | ||
| * Updates the dirty flag for the given subscriber based on its dependencies. | ||
| * Recursively checks and updates all computed subscribers marked as pending. | ||
| * | ||
| * If the subscriber has any pending computeds, this function sets the Dirty flag | ||
| * and returns `true`. Otherwise, it clears the PendingComputed flag and returns `false`. | ||
| * It traverses the linked structure using a stack mechanism. For each computed | ||
| * subscriber in a pending state, updateComputed is called and shallowPropagate | ||
| * is triggered if a value changes. Returns whether any updates occurred. | ||
| * | ||
| * @param sub - The subscriber to update. | ||
| * @param flags - The current flag set for this subscriber. | ||
| * @returns `true` if the subscriber is marked as Dirty; otherwise `false`. | ||
| * @param link - The starting link representing a sequence of pending computeds. | ||
| * @returns `true` if a computed was updated, otherwise `false`. | ||
| */ | ||
| updateDirtyFlag(sub, flags) { | ||
| if (checkDirty(sub.deps)) { | ||
| sub.flags = flags | 32 /* Dirty */; | ||
| return true; | ||
| } else { | ||
| sub.flags = flags & ~64 /* PendingComputed */; | ||
| return false; | ||
| } | ||
| checkDirty(link2) { | ||
| let stack = 0; | ||
| let dirty; | ||
| top: do { | ||
| dirty = false; | ||
| const dep = link2.dep; | ||
| if (dep.version !== link2.version) { | ||
| dirty = true; | ||
| } else if ("flags" in dep) { | ||
| const depFlags = dep.flags; | ||
| if ((depFlags & (1 /* Computed */ | 16 /* Dirty */)) === (1 /* Computed */ | 16 /* Dirty */)) { | ||
| if (updateComputed2(dep)) { | ||
| dirty = true; | ||
| } | ||
| } else if ((depFlags & (1 /* Computed */ | 32 /* Pending */)) === (1 /* Computed */ | 32 /* Pending */)) { | ||
| const depSubs = dep.subs; | ||
| if (depSubs.nextSub !== void 0) { | ||
| depSubs.prevSub = link2; | ||
| } | ||
| link2 = dep.deps; | ||
| ++stack; | ||
| continue; | ||
| } | ||
| } | ||
| if (!dirty && link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue; | ||
| } | ||
| if (stack) { | ||
| let sub = link2.sub; | ||
| do { | ||
| --stack; | ||
| const subSubs = sub.subs; | ||
| if (dirty) { | ||
| if (updateComputed2(sub)) { | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| sub = link2.sub; | ||
| } else { | ||
| sub = subSubs.sub; | ||
| } | ||
| continue; | ||
| } | ||
| } else { | ||
| sub.flags &= ~32 /* Pending */; | ||
| } | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| if (link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue top; | ||
| } | ||
| sub = link2.sub; | ||
| } else { | ||
| if ((link2 = subSubs.nextDep) !== void 0) { | ||
| continue top; | ||
| } | ||
| sub = subSubs.sub; | ||
| } | ||
| dirty = false; | ||
| } while (stack); | ||
| } | ||
| return dirty; | ||
| } while (true); | ||
| }, | ||
| /** | ||
| * Updates the computed subscriber if necessary before its value is accessed. | ||
| * | ||
| * If the subscriber is marked Dirty or PendingComputed, this function runs | ||
| * the provided updateComputed logic and triggers a shallowPropagate for any | ||
| * downstream subscribers if an actual update occurs. | ||
| * | ||
| * @param computed - The computed subscriber to update. | ||
| * @param flags - The current flag set for this subscriber. | ||
| */ | ||
| processComputedUpdate(computed2, flags) { | ||
| if (flags & 256 /* Cold */) { | ||
| warming(computed2, flags, computed2.deps); | ||
| flags = computed2.flags; | ||
| } | ||
| if (flags & 32 /* Dirty */) { | ||
| updateComputed(computed2); | ||
| } else if (checkDirty(computed2.deps)) { | ||
| updateComputed(computed2); | ||
| } else { | ||
| computed2.flags = flags & ~64 /* PendingComputed */; | ||
| } | ||
| }, | ||
| /** | ||
| * Ensures all pending internal effects for the given subscriber are processed. | ||
@@ -250,14 +286,11 @@ * | ||
| */ | ||
| processPendingInnerEffects(sub, flags) { | ||
| if (flags & 128 /* PendingEffect */) { | ||
| sub.flags = flags & ~128 /* PendingEffect */; | ||
| let link2 = sub.deps; | ||
| do { | ||
| const dep = link2.dep; | ||
| if ("flags" in dep && dep.flags & 2 /* Effect */ && dep.flags & 224 /* Propagated */) { | ||
| notifyEffect2(dep); | ||
| } | ||
| link2 = link2.nextDep; | ||
| } while (link2 !== void 0); | ||
| } | ||
| processPendingInnerEffects(sub) { | ||
| let link2 = sub.deps; | ||
| do { | ||
| const dep = link2.dep; | ||
| if ("flags" in dep && dep.flags & 2 /* Effect */ && dep.flags & 48 /* Propagated */) { | ||
| notifyEffect2(dep); | ||
| } | ||
| link2 = link2.nextDep; | ||
| } while (link2 !== void 0); | ||
| }, | ||
@@ -283,8 +316,18 @@ /** | ||
| } | ||
| if (!notifyEffect2(effect2)) { | ||
| effect2.flags &= ~8 /* Notified */; | ||
| } | ||
| notifyEffect2(effect2); | ||
| } | ||
| }, | ||
| warming: warming2, | ||
| cooling: cooling2 | ||
| }; | ||
| function isQueued(effect2) { | ||
| let queuedEffect = queuedEffects; | ||
| while (queuedEffect !== void 0) { | ||
| if (queuedEffect === effect2) { | ||
| return true; | ||
| } | ||
| queuedEffect = queuedEffect.depsTail.nextDep?.sub; | ||
| } | ||
| }; | ||
| return false; | ||
| } | ||
| function linkNewDep(dep, sub, nextDep, depsTail) { | ||
@@ -315,67 +358,2 @@ const newLink = { | ||
| } | ||
| function checkDirty(link2) { | ||
| let stack = 0; | ||
| let dirty; | ||
| top: do { | ||
| dirty = false; | ||
| const dep = link2.dep; | ||
| if (dep.version !== link2.version) { | ||
| dirty = true; | ||
| } else if ("flags" in dep) { | ||
| const depFlags = dep.flags; | ||
| if ((depFlags & (1 /* Computed */ | 32 /* Dirty */)) === (1 /* Computed */ | 32 /* Dirty */)) { | ||
| if (updateComputed(dep)) { | ||
| dirty = true; | ||
| } | ||
| } else if ((depFlags & (1 /* Computed */ | 64 /* PendingComputed */)) === (1 /* Computed */ | 64 /* PendingComputed */)) { | ||
| const depSubs = dep.subs; | ||
| if (depSubs.nextSub !== void 0) { | ||
| depSubs.prevSub = link2; | ||
| } | ||
| link2 = dep.deps; | ||
| ++stack; | ||
| continue; | ||
| } | ||
| } | ||
| if (!dirty && link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue; | ||
| } | ||
| if (stack) { | ||
| let sub = link2.sub; | ||
| do { | ||
| --stack; | ||
| const subSubs = sub.subs; | ||
| if (dirty) { | ||
| if (updateComputed(sub)) { | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| sub = link2.sub; | ||
| } else { | ||
| sub = subSubs.sub; | ||
| } | ||
| continue; | ||
| } | ||
| } else { | ||
| sub.flags &= ~64 /* PendingComputed */; | ||
| } | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| if (link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue top; | ||
| } | ||
| sub = link2.sub; | ||
| } else { | ||
| if ((link2 = subSubs.nextDep) !== void 0) { | ||
| continue top; | ||
| } | ||
| sub = subSubs.sub; | ||
| } | ||
| dirty = false; | ||
| } while (stack); | ||
| } | ||
| return dirty; | ||
| } while (true); | ||
| } | ||
| function isValidLink(checkLink, sub) { | ||
@@ -421,3 +399,3 @@ const depsTail = sub.depsTail; | ||
| } else if (depFlags & 1 /* Computed */) { | ||
| cooling(dep, depFlags, depDeps); | ||
| onUnwatchedComputed(dep); | ||
| } | ||
@@ -428,4 +406,5 @@ } | ||
| } | ||
| function warming(sub, flags, link2) { | ||
| sub.flags = flags & ~256 /* Cold */; | ||
| function warming2(sub) { | ||
| sub.flags &= ~64 /* Cold */; | ||
| let link2 = sub.deps; | ||
| do { | ||
@@ -444,4 +423,4 @@ const dep = link2.dep; | ||
| const depFlags = dep.flags; | ||
| if (depFlags & 256 /* Cold */) { | ||
| warming(dep, depFlags, dep.deps); | ||
| if (depFlags & 64 /* Cold */) { | ||
| warming2(dep); | ||
| } | ||
@@ -451,4 +430,5 @@ } | ||
| } | ||
| function cooling(sub, flags, link2) { | ||
| sub.flags = flags | 256 /* Cold */ | 64 /* PendingComputed */; | ||
| function cooling2(sub) { | ||
| sub.flags |= 64 /* Cold */; | ||
| let link2 = sub.deps; | ||
| do { | ||
@@ -470,7 +450,4 @@ const dep = link2.dep; | ||
| } | ||
| if (dep.subs === void 0 && "deps" in dep) { | ||
| const depDeps = dep.deps; | ||
| if (depDeps !== void 0) { | ||
| cooling(dep, dep.flags, depDeps); | ||
| } | ||
| if (dep.subs === void 0 && "flags" in dep && dep.flags & 1 /* Computed */ && dep.deps !== void 0) { | ||
| cooling2(dep); | ||
| } | ||
@@ -484,33 +461,24 @@ } while ((link2 = link2.nextDep) !== void 0); | ||
| link, | ||
| warming, | ||
| cooling, | ||
| propagate, | ||
| updateDirtyFlag, | ||
| checkDirty, | ||
| endTracking, | ||
| startTracking, | ||
| endTracking, | ||
| processEffectNotifications, | ||
| processComputedUpdate, | ||
| processPendingInnerEffects | ||
| } = createReactiveSystem({ | ||
| updateComputed(computed2) { | ||
| const prevSub = activeSub; | ||
| activeSub = computed2; | ||
| startTracking(computed2); | ||
| try { | ||
| const oldValue = computed2.currentValue; | ||
| const newValue = computed2.getter(oldValue); | ||
| if (oldValue !== newValue) { | ||
| computed2.currentValue = newValue; | ||
| computed2.version++; | ||
| return true; | ||
| } | ||
| return false; | ||
| } finally { | ||
| activeSub = prevSub; | ||
| endTracking(computed2); | ||
| computed: { | ||
| update: updateComputed, | ||
| onUnwatched(computed2) { | ||
| cooling(computed2); | ||
| } | ||
| }, | ||
| notifyEffect(e) { | ||
| if ("isScope" in e) { | ||
| return notifyEffectScope(e); | ||
| } else { | ||
| return notifyEffect(e); | ||
| effect: { | ||
| notify(e) { | ||
| if ("isScope" in e) { | ||
| notifyEffectScope(e); | ||
| } else { | ||
| notifyEffect(e); | ||
| } | ||
| } | ||
@@ -560,3 +528,3 @@ } | ||
| depsTail: void 0, | ||
| flags: 1 /* Computed */ | 32 /* Dirty */, | ||
| flags: 1 /* Computed */ | 16 /* Dirty */, | ||
| getter | ||
@@ -592,2 +560,20 @@ }); | ||
| } | ||
| function updateComputed(computed2) { | ||
| const prevSub = activeSub; | ||
| activeSub = computed2; | ||
| startTracking(computed2); | ||
| try { | ||
| const oldValue = computed2.currentValue; | ||
| const newValue = computed2.getter(oldValue); | ||
| if (oldValue !== newValue) { | ||
| computed2.currentValue = newValue; | ||
| computed2.version++; | ||
| return true; | ||
| } | ||
| return false; | ||
| } finally { | ||
| activeSub = prevSub; | ||
| endTracking(computed2); | ||
| } | ||
| } | ||
| function runEffect(e) { | ||
@@ -617,21 +603,24 @@ const prevSub = activeSub; | ||
| const flags = e.flags; | ||
| if (flags & 32 /* Dirty */ || flags & 64 /* PendingComputed */ && updateDirtyFlag(e, flags)) { | ||
| if (flags & 16 /* Dirty */ || checkDirty(e.deps)) { | ||
| runEffect(e); | ||
| } else { | ||
| processPendingInnerEffects(e, e.flags); | ||
| e.flags = flags & ~32 /* Pending */; | ||
| processPendingInnerEffects(e); | ||
| } | ||
| return true; | ||
| } | ||
| function notifyEffectScope(e) { | ||
| const flags = e.flags; | ||
| if (flags & 128 /* PendingEffect */) { | ||
| processPendingInnerEffects(e, e.flags); | ||
| return true; | ||
| if (flags & 32 /* Pending */) { | ||
| e.flags = flags & ~32 /* Pending */; | ||
| processPendingInnerEffects(e); | ||
| } | ||
| return false; | ||
| } | ||
| function computedGetter() { | ||
| const flags = this.flags; | ||
| if (flags & (32 /* Dirty */ | 64 /* PendingComputed */)) { | ||
| processComputedUpdate(this, flags); | ||
| if (flags & 64 /* Cold */ && (warming(this), true) || flags & (16 /* Dirty */ | 32 /* Pending */)) { | ||
| if (flags & 16 /* Dirty */ || checkDirty(this.deps)) { | ||
| updateComputed(this); | ||
| } else { | ||
| this.flags &= ~32 /* Pending */; | ||
| } | ||
| } | ||
@@ -638,0 +627,0 @@ if (activeSub !== void 0) { |
+172
-183
@@ -7,14 +7,18 @@ // src/system.ts | ||
| SubscriberFlags2[SubscriberFlags2["Tracking"] = 4] = "Tracking"; | ||
| SubscriberFlags2[SubscriberFlags2["Notified"] = 8] = "Notified"; | ||
| SubscriberFlags2[SubscriberFlags2["Recursed"] = 16] = "Recursed"; | ||
| SubscriberFlags2[SubscriberFlags2["Dirty"] = 32] = "Dirty"; | ||
| SubscriberFlags2[SubscriberFlags2["PendingComputed"] = 64] = "PendingComputed"; | ||
| SubscriberFlags2[SubscriberFlags2["PendingEffect"] = 128] = "PendingEffect"; | ||
| SubscriberFlags2[SubscriberFlags2["Cold"] = 256] = "Cold"; | ||
| SubscriberFlags2[SubscriberFlags2["Propagated"] = 224] = "Propagated"; | ||
| SubscriberFlags2[SubscriberFlags2["Recursed"] = 8] = "Recursed"; | ||
| SubscriberFlags2[SubscriberFlags2["Dirty"] = 16] = "Dirty"; | ||
| SubscriberFlags2[SubscriberFlags2["Pending"] = 32] = "Pending"; | ||
| SubscriberFlags2[SubscriberFlags2["Cold"] = 64] = "Cold"; | ||
| SubscriberFlags2[SubscriberFlags2["Propagated"] = 48] = "Propagated"; | ||
| return SubscriberFlags2; | ||
| })(SubscriberFlags || {}); | ||
| function createReactiveSystem({ | ||
| updateComputed, | ||
| notifyEffect: notifyEffect2 | ||
| computed: { | ||
| update: updateComputed2, | ||
| onUnwatched: onUnwatchedComputed = () => { | ||
| } | ||
| }, | ||
| effect: { | ||
| notify: notifyEffect2 | ||
| } | ||
| }) { | ||
@@ -58,3 +62,3 @@ let queuedEffects; | ||
| propagate(link2) { | ||
| let targetFlag = 32 /* Dirty */; | ||
| let targetFlag = 16 /* Dirty */ | 32 /* Pending */; | ||
| let subs = link2; | ||
@@ -65,3 +69,3 @@ let stack = 0; | ||
| const subFlags = sub.flags; | ||
| if (!(subFlags & (4 /* Tracking */ | 16 /* Recursed */ | 224 /* Propagated */)) && (sub.flags = subFlags | targetFlag | 8 /* Notified */, true) || subFlags & 16 /* Recursed */ && !(subFlags & 4 /* Tracking */) && (sub.flags = subFlags & ~16 /* Recursed */ | targetFlag | 8 /* Notified */, true) || !(subFlags & 224 /* Propagated */) && isValidLink(link2, sub) && (sub.flags = subFlags | 16 /* Recursed */ | targetFlag | 8 /* Notified */, sub.subs !== void 0)) { | ||
| if (!(subFlags & (4 /* Tracking */ | 8 /* Recursed */ | 48 /* Propagated */)) && (sub.flags = subFlags | targetFlag, true) || subFlags & 8 /* Recursed */ && !(subFlags & 4 /* Tracking */) && (sub.flags = subFlags & ~8 /* Recursed */ | targetFlag, true) || !(subFlags & 48 /* Propagated */) && isValidLink(link2, sub) && (sub.flags = subFlags | 8 /* Recursed */ | targetFlag, sub.subs !== void 0)) { | ||
| const subSubs = sub.subs; | ||
@@ -72,8 +76,7 @@ if (subSubs !== void 0) { | ||
| link2 = subs = subSubs; | ||
| targetFlag = 64 /* PendingComputed */; | ||
| ++stack; | ||
| } else { | ||
| link2 = subSubs; | ||
| targetFlag = subFlags & 2 /* Effect */ ? 128 /* PendingEffect */ : 64 /* PendingComputed */; | ||
| } | ||
| targetFlag = 32 /* Pending */; | ||
| continue; | ||
@@ -90,4 +93,4 @@ } | ||
| } else if (!(subFlags & (4 /* Tracking */ | targetFlag))) { | ||
| sub.flags = subFlags | targetFlag | 8 /* Notified */; | ||
| if ((subFlags & (2 /* Effect */ | 8 /* Notified */)) === 2 /* Effect */) { | ||
| sub.flags = subFlags | targetFlag; | ||
| if (subFlags & 2 /* Effect */ && !isQueued(sub)) { | ||
| if (queuedEffectsTail !== void 0) { | ||
@@ -100,3 +103,3 @@ queuedEffectsTail.depsTail.nextDep = sub.deps; | ||
| } | ||
| } else if (!(subFlags & targetFlag) && subFlags & 224 /* Propagated */ && isValidLink(link2, sub)) { | ||
| } else if (!(subFlags & targetFlag) && subFlags & 48 /* Propagated */ && isValidLink(link2, sub)) { | ||
| sub.flags = subFlags | targetFlag; | ||
@@ -106,3 +109,3 @@ } | ||
| subs = link2; | ||
| targetFlag = stack ? 64 /* PendingComputed */ : 32 /* Dirty */; | ||
| targetFlag = stack ? 32 /* Pending */ : 16 /* Dirty */ | 32 /* Pending */; | ||
| continue; | ||
@@ -118,3 +121,3 @@ } | ||
| subs = link2; | ||
| targetFlag = stack ? 64 /* PendingComputed */ : 32 /* Dirty */; | ||
| targetFlag = stack ? 32 /* Pending */ : 16 /* Dirty */ | 32 /* Pending */; | ||
| continue top; | ||
@@ -136,3 +139,3 @@ } | ||
| sub.depsTail = void 0; | ||
| sub.flags = sub.flags & ~(8 /* Notified */ | 16 /* Recursed */ | 224 /* Propagated */) | 4 /* Tracking */; | ||
| sub.flags = sub.flags & ~(8 /* Recursed */ | 48 /* Propagated */) | 4 /* Tracking */; | ||
| }, | ||
@@ -162,44 +165,77 @@ /** | ||
| /** | ||
| * Updates the dirty flag for the given subscriber based on its dependencies. | ||
| * Recursively checks and updates all computed subscribers marked as pending. | ||
| * | ||
| * If the subscriber has any pending computeds, this function sets the Dirty flag | ||
| * and returns `true`. Otherwise, it clears the PendingComputed flag and returns `false`. | ||
| * It traverses the linked structure using a stack mechanism. For each computed | ||
| * subscriber in a pending state, updateComputed is called and shallowPropagate | ||
| * is triggered if a value changes. Returns whether any updates occurred. | ||
| * | ||
| * @param sub - The subscriber to update. | ||
| * @param flags - The current flag set for this subscriber. | ||
| * @returns `true` if the subscriber is marked as Dirty; otherwise `false`. | ||
| * @param link - The starting link representing a sequence of pending computeds. | ||
| * @returns `true` if a computed was updated, otherwise `false`. | ||
| */ | ||
| updateDirtyFlag(sub, flags) { | ||
| if (checkDirty(sub.deps)) { | ||
| sub.flags = flags | 32 /* Dirty */; | ||
| return true; | ||
| } else { | ||
| sub.flags = flags & ~64 /* PendingComputed */; | ||
| return false; | ||
| } | ||
| checkDirty(link2) { | ||
| let stack = 0; | ||
| let dirty; | ||
| top: do { | ||
| dirty = false; | ||
| const dep = link2.dep; | ||
| if (dep.version !== link2.version) { | ||
| dirty = true; | ||
| } else if ("flags" in dep) { | ||
| const depFlags = dep.flags; | ||
| if ((depFlags & (1 /* Computed */ | 16 /* Dirty */)) === (1 /* Computed */ | 16 /* Dirty */)) { | ||
| if (updateComputed2(dep)) { | ||
| dirty = true; | ||
| } | ||
| } else if ((depFlags & (1 /* Computed */ | 32 /* Pending */)) === (1 /* Computed */ | 32 /* Pending */)) { | ||
| const depSubs = dep.subs; | ||
| if (depSubs.nextSub !== void 0) { | ||
| depSubs.prevSub = link2; | ||
| } | ||
| link2 = dep.deps; | ||
| ++stack; | ||
| continue; | ||
| } | ||
| } | ||
| if (!dirty && link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue; | ||
| } | ||
| if (stack) { | ||
| let sub = link2.sub; | ||
| do { | ||
| --stack; | ||
| const subSubs = sub.subs; | ||
| if (dirty) { | ||
| if (updateComputed2(sub)) { | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| sub = link2.sub; | ||
| } else { | ||
| sub = subSubs.sub; | ||
| } | ||
| continue; | ||
| } | ||
| } else { | ||
| sub.flags &= ~32 /* Pending */; | ||
| } | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| if (link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue top; | ||
| } | ||
| sub = link2.sub; | ||
| } else { | ||
| if ((link2 = subSubs.nextDep) !== void 0) { | ||
| continue top; | ||
| } | ||
| sub = subSubs.sub; | ||
| } | ||
| dirty = false; | ||
| } while (stack); | ||
| } | ||
| return dirty; | ||
| } while (true); | ||
| }, | ||
| /** | ||
| * Updates the computed subscriber if necessary before its value is accessed. | ||
| * | ||
| * If the subscriber is marked Dirty or PendingComputed, this function runs | ||
| * the provided updateComputed logic and triggers a shallowPropagate for any | ||
| * downstream subscribers if an actual update occurs. | ||
| * | ||
| * @param computed - The computed subscriber to update. | ||
| * @param flags - The current flag set for this subscriber. | ||
| */ | ||
| processComputedUpdate(computed2, flags) { | ||
| if (flags & 256 /* Cold */) { | ||
| warming(computed2, flags, computed2.deps); | ||
| flags = computed2.flags; | ||
| } | ||
| if (flags & 32 /* Dirty */) { | ||
| updateComputed(computed2); | ||
| } else if (checkDirty(computed2.deps)) { | ||
| updateComputed(computed2); | ||
| } else { | ||
| computed2.flags = flags & ~64 /* PendingComputed */; | ||
| } | ||
| }, | ||
| /** | ||
| * Ensures all pending internal effects for the given subscriber are processed. | ||
@@ -215,14 +251,11 @@ * | ||
| */ | ||
| processPendingInnerEffects(sub, flags) { | ||
| if (flags & 128 /* PendingEffect */) { | ||
| sub.flags = flags & ~128 /* PendingEffect */; | ||
| let link2 = sub.deps; | ||
| do { | ||
| const dep = link2.dep; | ||
| if ("flags" in dep && dep.flags & 2 /* Effect */ && dep.flags & 224 /* Propagated */) { | ||
| notifyEffect2(dep); | ||
| } | ||
| link2 = link2.nextDep; | ||
| } while (link2 !== void 0); | ||
| } | ||
| processPendingInnerEffects(sub) { | ||
| let link2 = sub.deps; | ||
| do { | ||
| const dep = link2.dep; | ||
| if ("flags" in dep && dep.flags & 2 /* Effect */ && dep.flags & 48 /* Propagated */) { | ||
| notifyEffect2(dep); | ||
| } | ||
| link2 = link2.nextDep; | ||
| } while (link2 !== void 0); | ||
| }, | ||
@@ -248,8 +281,18 @@ /** | ||
| } | ||
| if (!notifyEffect2(effect2)) { | ||
| effect2.flags &= ~8 /* Notified */; | ||
| } | ||
| notifyEffect2(effect2); | ||
| } | ||
| }, | ||
| warming: warming2, | ||
| cooling: cooling2 | ||
| }; | ||
| function isQueued(effect2) { | ||
| let queuedEffect = queuedEffects; | ||
| while (queuedEffect !== void 0) { | ||
| if (queuedEffect === effect2) { | ||
| return true; | ||
| } | ||
| queuedEffect = queuedEffect.depsTail.nextDep?.sub; | ||
| } | ||
| }; | ||
| return false; | ||
| } | ||
| function linkNewDep(dep, sub, nextDep, depsTail) { | ||
@@ -280,67 +323,2 @@ const newLink = { | ||
| } | ||
| function checkDirty(link2) { | ||
| let stack = 0; | ||
| let dirty; | ||
| top: do { | ||
| dirty = false; | ||
| const dep = link2.dep; | ||
| if (dep.version !== link2.version) { | ||
| dirty = true; | ||
| } else if ("flags" in dep) { | ||
| const depFlags = dep.flags; | ||
| if ((depFlags & (1 /* Computed */ | 32 /* Dirty */)) === (1 /* Computed */ | 32 /* Dirty */)) { | ||
| if (updateComputed(dep)) { | ||
| dirty = true; | ||
| } | ||
| } else if ((depFlags & (1 /* Computed */ | 64 /* PendingComputed */)) === (1 /* Computed */ | 64 /* PendingComputed */)) { | ||
| const depSubs = dep.subs; | ||
| if (depSubs.nextSub !== void 0) { | ||
| depSubs.prevSub = link2; | ||
| } | ||
| link2 = dep.deps; | ||
| ++stack; | ||
| continue; | ||
| } | ||
| } | ||
| if (!dirty && link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue; | ||
| } | ||
| if (stack) { | ||
| let sub = link2.sub; | ||
| do { | ||
| --stack; | ||
| const subSubs = sub.subs; | ||
| if (dirty) { | ||
| if (updateComputed(sub)) { | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| sub = link2.sub; | ||
| } else { | ||
| sub = subSubs.sub; | ||
| } | ||
| continue; | ||
| } | ||
| } else { | ||
| sub.flags &= ~64 /* PendingComputed */; | ||
| } | ||
| if ((link2 = subSubs.prevSub) !== void 0) { | ||
| subSubs.prevSub = void 0; | ||
| if (link2.nextDep !== void 0) { | ||
| link2 = link2.nextDep; | ||
| continue top; | ||
| } | ||
| sub = link2.sub; | ||
| } else { | ||
| if ((link2 = subSubs.nextDep) !== void 0) { | ||
| continue top; | ||
| } | ||
| sub = subSubs.sub; | ||
| } | ||
| dirty = false; | ||
| } while (stack); | ||
| } | ||
| return dirty; | ||
| } while (true); | ||
| } | ||
| function isValidLink(checkLink, sub) { | ||
@@ -386,3 +364,3 @@ const depsTail = sub.depsTail; | ||
| } else if (depFlags & 1 /* Computed */) { | ||
| cooling(dep, depFlags, depDeps); | ||
| onUnwatchedComputed(dep); | ||
| } | ||
@@ -393,4 +371,5 @@ } | ||
| } | ||
| function warming(sub, flags, link2) { | ||
| sub.flags = flags & ~256 /* Cold */; | ||
| function warming2(sub) { | ||
| sub.flags &= ~64 /* Cold */; | ||
| let link2 = sub.deps; | ||
| do { | ||
@@ -409,4 +388,4 @@ const dep = link2.dep; | ||
| const depFlags = dep.flags; | ||
| if (depFlags & 256 /* Cold */) { | ||
| warming(dep, depFlags, dep.deps); | ||
| if (depFlags & 64 /* Cold */) { | ||
| warming2(dep); | ||
| } | ||
@@ -416,4 +395,5 @@ } | ||
| } | ||
| function cooling(sub, flags, link2) { | ||
| sub.flags = flags | 256 /* Cold */ | 64 /* PendingComputed */; | ||
| function cooling2(sub) { | ||
| sub.flags |= 64 /* Cold */; | ||
| let link2 = sub.deps; | ||
| do { | ||
@@ -435,7 +415,4 @@ const dep = link2.dep; | ||
| } | ||
| if (dep.subs === void 0 && "deps" in dep) { | ||
| const depDeps = dep.deps; | ||
| if (depDeps !== void 0) { | ||
| cooling(dep, dep.flags, depDeps); | ||
| } | ||
| if (dep.subs === void 0 && "flags" in dep && dep.flags & 1 /* Computed */ && dep.deps !== void 0) { | ||
| cooling2(dep); | ||
| } | ||
@@ -449,33 +426,24 @@ } while ((link2 = link2.nextDep) !== void 0); | ||
| link, | ||
| warming, | ||
| cooling, | ||
| propagate, | ||
| updateDirtyFlag, | ||
| checkDirty, | ||
| endTracking, | ||
| startTracking, | ||
| endTracking, | ||
| processEffectNotifications, | ||
| processComputedUpdate, | ||
| processPendingInnerEffects | ||
| } = createReactiveSystem({ | ||
| updateComputed(computed2) { | ||
| const prevSub = activeSub; | ||
| activeSub = computed2; | ||
| startTracking(computed2); | ||
| try { | ||
| const oldValue = computed2.currentValue; | ||
| const newValue = computed2.getter(oldValue); | ||
| if (oldValue !== newValue) { | ||
| computed2.currentValue = newValue; | ||
| computed2.version++; | ||
| return true; | ||
| } | ||
| return false; | ||
| } finally { | ||
| activeSub = prevSub; | ||
| endTracking(computed2); | ||
| computed: { | ||
| update: updateComputed, | ||
| onUnwatched(computed2) { | ||
| cooling(computed2); | ||
| } | ||
| }, | ||
| notifyEffect(e) { | ||
| if ("isScope" in e) { | ||
| return notifyEffectScope(e); | ||
| } else { | ||
| return notifyEffect(e); | ||
| effect: { | ||
| notify(e) { | ||
| if ("isScope" in e) { | ||
| notifyEffectScope(e); | ||
| } else { | ||
| notifyEffect(e); | ||
| } | ||
| } | ||
@@ -525,3 +493,3 @@ } | ||
| depsTail: void 0, | ||
| flags: 1 /* Computed */ | 32 /* Dirty */, | ||
| flags: 1 /* Computed */ | 16 /* Dirty */, | ||
| getter | ||
@@ -557,2 +525,20 @@ }); | ||
| } | ||
| function updateComputed(computed2) { | ||
| const prevSub = activeSub; | ||
| activeSub = computed2; | ||
| startTracking(computed2); | ||
| try { | ||
| const oldValue = computed2.currentValue; | ||
| const newValue = computed2.getter(oldValue); | ||
| if (oldValue !== newValue) { | ||
| computed2.currentValue = newValue; | ||
| computed2.version++; | ||
| return true; | ||
| } | ||
| return false; | ||
| } finally { | ||
| activeSub = prevSub; | ||
| endTracking(computed2); | ||
| } | ||
| } | ||
| function runEffect(e) { | ||
@@ -582,21 +568,24 @@ const prevSub = activeSub; | ||
| const flags = e.flags; | ||
| if (flags & 32 /* Dirty */ || flags & 64 /* PendingComputed */ && updateDirtyFlag(e, flags)) { | ||
| if (flags & 16 /* Dirty */ || checkDirty(e.deps)) { | ||
| runEffect(e); | ||
| } else { | ||
| processPendingInnerEffects(e, e.flags); | ||
| e.flags = flags & ~32 /* Pending */; | ||
| processPendingInnerEffects(e); | ||
| } | ||
| return true; | ||
| } | ||
| function notifyEffectScope(e) { | ||
| const flags = e.flags; | ||
| if (flags & 128 /* PendingEffect */) { | ||
| processPendingInnerEffects(e, e.flags); | ||
| return true; | ||
| if (flags & 32 /* Pending */) { | ||
| e.flags = flags & ~32 /* Pending */; | ||
| processPendingInnerEffects(e); | ||
| } | ||
| return false; | ||
| } | ||
| function computedGetter() { | ||
| const flags = this.flags; | ||
| if (flags & (32 /* Dirty */ | 64 /* PendingComputed */)) { | ||
| processComputedUpdate(this, flags); | ||
| if (flags & 64 /* Cold */ && (warming(this), true) || flags & (16 /* Dirty */ | 32 /* Pending */)) { | ||
| if (flags & 16 /* Dirty */ || checkDirty(this.deps)) { | ||
| updateComputed(this); | ||
| } else { | ||
| this.flags &= ~32 /* Pending */; | ||
| } | ||
| } | ||
@@ -603,0 +592,0 @@ if (activeSub !== void 0) { |
+1
-1
| { | ||
| "name": "alien-signals", | ||
| "version": "1.1.0-alpha.3", | ||
| "version": "2.0.0-alpha.0", | ||
| "sideEffects": false, | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
+44
-50
@@ -24,34 +24,37 @@ export interface Dependency { | ||
| Tracking = 4, | ||
| Notified = 8, | ||
| Recursed = 16, | ||
| Dirty = 32, | ||
| PendingComputed = 64, | ||
| PendingEffect = 128, | ||
| Cold = 256, | ||
| Propagated = 224 | ||
| Recursed = 8, | ||
| Dirty = 16, | ||
| Pending = 32, | ||
| Cold = 64, | ||
| Propagated = 48 | ||
| } | ||
| export declare function createReactiveSystem({ updateComputed, notifyEffect, }: { | ||
| /** | ||
| * Updates the computed subscriber's value and returns whether it changed. | ||
| * | ||
| * This function should be called when a computed subscriber is marked as Dirty. | ||
| * The computed subscriber's getter function is invoked, and its value is updated. | ||
| * If the value changes, the new value is stored, and the function returns `true`. | ||
| * | ||
| * @param computed - The computed subscriber to update. | ||
| * @returns `true` if the computed subscriber's value changed; otherwise `false`. | ||
| */ | ||
| updateComputed(computed: Dependency & Subscriber): boolean; | ||
| /** | ||
| * Handles effect notifications by processing the specified `effect`. | ||
| * | ||
| * When an `effect` first receives any of the following flags: | ||
| * - `Dirty` | ||
| * - `PendingComputed` | ||
| * - `PendingEffect` | ||
| * this method will process them and return `true` if the flags are successfully handled. | ||
| * If not fully handled, future changes to these flags will trigger additional calls | ||
| * until the method eventually returns `true`. | ||
| */ | ||
| notifyEffect(effect: Subscriber): boolean; | ||
| export declare function createReactiveSystem({ computed: { update: updateComputed, onUnwatched: onUnwatchedComputed, }, effect: { notify: notifyEffect, }, }: { | ||
| computed: { | ||
| /** | ||
| * Updates the computed subscriber's value and returns whether it changed. | ||
| * | ||
| * This function should be called when a computed subscriber is marked as Dirty. | ||
| * The computed subscriber's getter function is invoked, and its value is updated. | ||
| * If the value changes, the new value is stored, and the function returns `true`. | ||
| * | ||
| * @param computed - The computed subscriber to update. | ||
| * @returns `true` if the computed subscriber's value changed; otherwise `false`. | ||
| */ | ||
| update(computed: Dependency & Subscriber): boolean; | ||
| onUnwatched?: (computed: Dependency & Subscriber) => void; | ||
| }; | ||
| effect: { | ||
| /** | ||
| * Handles effect notifications by processing the specified `effect`. | ||
| * | ||
| * When an `effect` first receives any of the following flags: | ||
| * - `Dirty` | ||
| * - `PendingComputed` | ||
| * - `PendingEffect` | ||
| * this method will process them and return `true` if the flags are successfully handled. | ||
| * If not fully handled, future changes to these flags will trigger additional calls | ||
| * until the method eventually returns `true`. | ||
| */ | ||
| notify(effect: Subscriber): void; | ||
| }; | ||
| }): { | ||
@@ -95,24 +98,13 @@ /** | ||
| /** | ||
| * Updates the dirty flag for the given subscriber based on its dependencies. | ||
| * Recursively checks and updates all computed subscribers marked as pending. | ||
| * | ||
| * If the subscriber has any pending computeds, this function sets the Dirty flag | ||
| * and returns `true`. Otherwise, it clears the PendingComputed flag and returns `false`. | ||
| * It traverses the linked structure using a stack mechanism. For each computed | ||
| * subscriber in a pending state, updateComputed is called and shallowPropagate | ||
| * is triggered if a value changes. Returns whether any updates occurred. | ||
| * | ||
| * @param sub - The subscriber to update. | ||
| * @param flags - The current flag set for this subscriber. | ||
| * @returns `true` if the subscriber is marked as Dirty; otherwise `false`. | ||
| * @param link - The starting link representing a sequence of pending computeds. | ||
| * @returns `true` if a computed was updated, otherwise `false`. | ||
| */ | ||
| updateDirtyFlag(sub: Subscriber, flags: SubscriberFlags): boolean; | ||
| checkDirty(link: Link): boolean; | ||
| /** | ||
| * Updates the computed subscriber if necessary before its value is accessed. | ||
| * | ||
| * If the subscriber is marked Dirty or PendingComputed, this function runs | ||
| * the provided updateComputed logic and triggers a shallowPropagate for any | ||
| * downstream subscribers if an actual update occurs. | ||
| * | ||
| * @param computed - The computed subscriber to update. | ||
| * @param flags - The current flag set for this subscriber. | ||
| */ | ||
| processComputedUpdate(computed: Dependency & Subscriber, flags: SubscriberFlags): void; | ||
| /** | ||
| * Ensures all pending internal effects for the given subscriber are processed. | ||
@@ -128,3 +120,3 @@ * | ||
| */ | ||
| processPendingInnerEffects(sub: Subscriber, flags: SubscriberFlags): void; | ||
| processPendingInnerEffects(sub: Subscriber): void; | ||
| /** | ||
@@ -138,2 +130,4 @@ * Processes queued effect notifications after a batch operation finishes. | ||
| processEffectNotifications(): void; | ||
| warming: (sub: Subscriber & Dependency) => void; | ||
| cooling: (sub: Subscriber & Dependency) => void; | ||
| }; |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
56467
-3.98%1517
-1.81%