agera
Version:
A small push-pull based signal library based on alien-signals algorithm.
547 lines (494 loc) • 12.8 kB
JavaScript
function maybeDestroyEffect(dep) {
if ("g" in dep && dep.g !== void 0) {
dep.g();
dep.g = void 0;
}
}
function clearTracking(link) {
do {
const dep = link.k;
const nextDep = link.o;
const nextSub = link.n;
const prevSub = link.m;
if (nextSub !== void 0) nextSub.m = prevSub; else dep.b = prevSub;
if (prevSub !== void 0) prevSub.n = nextSub; else {
dep.a = nextSub;
if (nextSub === void 0) if ("j" in dep) dep.j(false); else maybeDestroyEffect(dep);
}
if (dep.a === void 0 && "d" in dep) {
const depFlags = dep.c;
if (!(depFlags & 128)) dep.c = depFlags | 128;
const depDeps = dep.d;
if (depDeps !== void 0) {
link = depDeps;
dep.e.o = nextDep;
dep.d = void 0;
dep.e = void 0;
continue;
}
}
link = nextDep;
} while (link !== void 0);
}
function startTracking(sub) {
sub.e = void 0;
sub.c = sub.c & -993 | 16;
}
function endTracking(sub) {
const depsTail = sub.e;
if (depsTail !== void 0) {
const nextDep = depsTail.o;
if (nextDep !== void 0) {
clearTracking(nextDep);
depsTail.o = void 0;
}
} else if (sub.d !== void 0) {
clearTracking(sub.d);
sub.d = void 0;
}
sub.c &= -17;
notifyActivateListeners();
}
function runLazyEffects(link) {
do {
const dep = link.k;
const nextDep = link.o;
if (dep.c & 8) {
dep.c &= -9;
if (dep.c & 4) {
if (dep.d !== void 0) runLazyEffects(dep.d);
} else runEffect(dep, true);
}
link = nextDep;
} while (link !== void 0);
}
const pauseStack = [];
let activeSub;
let queuedEffects;
let queuedEffectsTail;
function updateComputed(computed) {
const prevSub = activeSub;
activeSub = computed;
startTracking(computed);
try {
const oldValue = computed.i;
const newValue = computed.h(oldValue);
if (oldValue !== newValue) {
computed.i = newValue;
return true;
}
return false;
} finally {
activeSub = prevSub;
endTracking(computed);
}
}
function shallowPropagate(link) {
do {
const sub = link.l;
const subFlags = sub.c;
if ((subFlags & 384) == 256) {
sub.c = 160 | subFlags;
if ((subFlags & 34) == 2) {
if (queuedEffectsTail !== void 0) queuedEffectsTail.e.o = sub.d; else queuedEffects = sub;
queuedEffectsTail = sub;
}
}
link = link.n;
} while (link !== void 0);
}
function propagate(link) {
let targetFlag = 128;
let subs = link;
let stack = 0;
top: do {
const sub = link.l;
const subFlags = sub.c;
if (!(subFlags & 976) && (sub.c = subFlags | targetFlag | 32, true) || subFlags & 64 && !(subFlags & 16) && (sub.c = subFlags & -65 | targetFlag | 32,
true) || !(subFlags & 896) && isValidLink(link, sub) && (sub.c = subFlags | 64 | targetFlag | 32,
sub.a !== void 0)) {
const subSubs = sub.a;
if (subSubs !== void 0) {
if (subSubs.n !== void 0) {
subSubs.m = subs;
link = subs = subSubs;
targetFlag = 256;
++stack;
} else {
link = subSubs;
targetFlag = subFlags & 2 ? 512 : 256;
}
continue;
}
if (subFlags & 2) {
if (queuedEffectsTail !== void 0) queuedEffectsTail.e.o = sub.d; else queuedEffects = sub;
queuedEffectsTail = sub;
}
} else if (!(subFlags & (16 | targetFlag))) {
sub.c = subFlags | targetFlag | 32;
if ((subFlags & 34) == 2) {
if (queuedEffectsTail !== void 0) queuedEffectsTail.e.o = sub.d; else queuedEffects = sub;
queuedEffectsTail = sub;
}
} else if (!(subFlags & targetFlag) && subFlags & 896 && isValidLink(link, sub)) sub.c = subFlags | targetFlag;
if ((link = subs.n) !== void 0) {
subs = link;
targetFlag = stack ? 256 : 128;
continue;
}
while (stack) {
--stack;
const depSubs = subs.k.a;
subs = depSubs.m;
depSubs.m = void 0;
if ((link = subs.n) !== void 0) {
subs = link;
targetFlag = stack ? 256 : 128;
continue top;
}
}
break;
} while (true);
}
function checkDirty(link) {
let stack = 0;
let dirty;
top: do {
dirty = false;
const dep = link.k;
if ("c" in dep) {
const depFlags = dep.c;
if (!(129 & ~depFlags)) {
if (updateComputed(dep)) {
const subs = dep.a;
if (subs.n !== void 0) shallowPropagate(subs);
dirty = true;
}
} else if (!(257 & ~depFlags)) {
const depSubs = dep.a;
if (depSubs.n !== void 0) depSubs.m = link;
link = dep.d;
++stack;
continue;
}
}
if (!dirty && link.o !== void 0) {
link = link.o;
continue;
}
if (stack) {
let sub = link.l;
do {
--stack;
const subSubs = sub.a;
if (dirty) {
if (updateComputed(sub)) {
if ((link = subSubs.m) !== void 0) {
subSubs.m = void 0;
shallowPropagate(subSubs);
sub = link.l;
} else sub = subSubs.l;
continue;
}
} else sub.c &= -257;
if ((link = subSubs.m) !== void 0) {
subSubs.m = void 0;
if (link.o !== void 0) {
link = link.o;
continue top;
}
sub = link.l;
} else {
if ((link = subSubs.o) !== void 0) continue top;
sub = subSubs.l;
}
dirty = false;
} while (stack);
}
return dirty;
} while (true);
}
function updateDirtyFlag(sub, flags) {
if (checkDirty(sub.d)) {
sub.c = flags | 128;
return true;
}
sub.c = flags & -257;
return false;
}
function processComputedUpdate(computed, flags) {
if (flags & 128 || (checkDirty(computed.d) ? true : (computed.c = flags & -257,
false))) if (updateComputed(computed)) {
const subs = computed.a;
if (subs !== void 0) shallowPropagate(subs);
}
}
function processPendingInnerEffects(sub, flags) {
if (flags & 512) {
sub.c = flags & -513;
let link = sub.d;
do {
const dep = link.k;
if ("c" in dep && dep.c & 2 && dep.c & 896) notifyEffect(dep);
link = link.o;
} while (link !== void 0);
}
}
function runEffect(e, warmup) {
const prevSub = activeSub;
activeSub = e;
startTracking(e);
try {
if (e.g !== void 0) e.g();
e.g = e.f(warmup);
} finally {
activeSub = prevSub;
endTracking(e);
}
}
function runEffectScope(e, fn) {
const prevSub = activeSub;
activeSub = e;
try {
fn();
} finally {
activeSub = prevSub;
}
}
function notifyEffect(e) {
if (e.c & 4) return notifyEffectScope(e);
return notifyEffectSub(e);
}
function notifyEffectSub(e) {
const flags = e.c;
if (flags & 128 || flags & 256 && updateDirtyFlag(e, flags)) runEffect(e); else processPendingInnerEffects(e, e.c);
return true;
}
function notifyEffectScope(e) {
if (e.c & 512) {
processPendingInnerEffects(e, e.c);
return true;
}
return false;
}
function processEffectNotifications() {
while (queuedEffects !== void 0) {
const effect = queuedEffects;
const depsTail = effect.e;
const queuedNext = depsTail?.o;
if (queuedNext !== void 0) {
depsTail.o = void 0;
queuedEffects = queuedNext.l;
} else {
queuedEffects = void 0;
queuedEffectsTail = void 0;
}
if (!notifyEffect(effect)) effect.c &= -33;
}
}
function pauseTracking() {
pauseStack.push(activeSub);
activeSub = void 0;
}
function resumeTracking() {
activeSub = pauseStack.pop();
}
let activateListeners;
let activateListenersTail;
function queueActivateListener(onActivate) {
const listener = {
j: onActivate,
n: void 0
};
if (activateListenersTail === void 0) activateListeners = listener; else activateListenersTail.n = listener;
activateListenersTail = listener;
}
function notifyActivateListeners() {
if (activateListeners !== void 0 && (activeSub === void 0 || activeSub.c & 4 && !(activeSub.c & 8))) {
let listener = activateListeners;
activateListeners = void 0;
activateListenersTail = void 0;
do {
listener.j(true);
listener = listener.n;
} while (listener !== void 0);
}
}
function linkNewDep(dep, sub, nextDep, depsTail) {
const newLink = {
k: dep,
l: sub,
o: nextDep,
m: void 0,
n: void 0
};
if (depsTail === void 0) sub.d = newLink; else depsTail.o = newLink;
if (dep.a === void 0) {
dep.a = newLink;
if ("j" in dep) queueActivateListener(dep.j);
} else {
const oldTail = dep.b;
newLink.m = oldTail;
oldTail.n = newLink;
}
sub.e = newLink;
dep.b = newLink;
return newLink;
}
function isValidLink(checkLink, sub) {
const depsTail = sub.e;
if (depsTail !== void 0) {
let link2 = sub.d;
do {
if (link2 === checkLink) return true;
if (link2 === depsTail) break;
link2 = link2.o;
} while (link2 !== void 0);
}
return false;
}
function link(dep, sub) {
const currentDep = sub.e;
if (currentDep !== void 0 && currentDep.k === dep) return;
const nextDep = currentDep !== void 0 ? currentDep.o : sub.d;
if (nextDep !== void 0 && nextDep.k === dep) {
sub.e = nextDep;
return;
}
const depLastSub = dep.b;
if (depLastSub !== void 0 && depLastSub.l === sub && isValidLink(depLastSub, sub)) return;
return linkNewDep(dep, sub, nextDep, currentDep);
}
function effectStop() {
startTracking(this);
maybeDestroyEffect(this);
endTracking(this);
}
function lazyEffectsRun() {
this.c &= -9;
notifyActivateListeners();
if (this.d !== void 0) runLazyEffects(this.d);
return effectStop.bind(this);
}
function effect(fn, ignoreLazy = false) {
const e = {
f: fn,
a: void 0,
b: void 0,
d: void 0,
e: void 0,
c: 2,
g: void 0
};
if (activeSub !== void 0) {
link(e, activeSub);
if (!ignoreLazy && activeSub.c & 8) {
e.c |= 8;
return effectStop.bind(e);
}
}
runEffect(e, true);
return effectStop.bind(e);
}
function createEffectScopeInstance() {
return {
a: void 0,
b: void 0,
d: void 0,
e: void 0,
c: 6
};
}
function runEffectScopeInstance(e, fn, lazy = false) {
if (!lazy && activeSub !== void 0) link(e, activeSub);
if (lazy || activeSub !== void 0 && activeSub.c & 8) e.c |= 8;
runEffectScope(e, fn);
if (lazy) return lazyEffectsRun.bind(e);
return effectStop.bind(e);
}
function effectScope(fn, lazy) {
return runEffectScopeInstance(createEffectScopeInstance(), fn, lazy);
}
function createEffectScope() {
return runEffectScopeInstance.bind(null, createEffectScopeInstance());
}
function onActivate($signal, listener) {
const $active = $signal.s.j ||= signal(false);
return effect((warmup => {
const active = $active();
if (!warmup) listener(active);
}), true);
}
let batchDepth = 0;
function startBatch() {
++batchDepth;
}
function endBatch() {
if (! --batchDepth) processEffectNotifications();
}
function createSignal(constructor, instance, ctx = instance) {
const $signal = constructor.bind(ctx);
$signal.s = instance;
return $signal;
}
function signal(value) {
return createSignal(signalGetterSetter, {
i: value,
a: void 0,
b: void 0
});
}
function signalGetterSetter(...value) {
if (value.length) {
if (this.i !== (this.i = value[0])) {
const subs = this.a;
if (subs !== void 0) {
propagate(subs);
if (!batchDepth) processEffectNotifications();
}
}
} else {
if (activeSub !== void 0 && !(activeSub.c & 4)) link(this, activeSub);
return this.i;
}
}
function computed(compute) {
return createSignal(computedGetter, {
i: void 0,
a: void 0,
b: void 0,
d: void 0,
e: void 0,
c: 129,
h: compute
});
}
function computedGetter() {
const flags = this.c;
if (flags & 384) processComputedUpdate(this, flags);
if (activeSub !== void 0 && !(activeSub.c & 4)) link(this, activeSub);
return this.i;
}
function morph($signal, context) {
return createSignal(morphGetterSetter, $signal.s, {
r: $signal,
q: $signal,
p: $signal,
...context
});
}
function morphGetterSetter(...value) {
if (value.length) this.q(value[0]); else return this.p();
}
function update($signal, fn) {
$signal(fn($signal.s.i));
return $signal;
}
function isSignal(value) {
return typeof value == "function" && "s" in value;
}
function isFunctionNotSignal(value) {
return typeof value == "function" && !("s" in value);
}
export { computed, createEffectScope, effect, effectScope, endBatch, isFunctionNotSignal, isSignal, morph, onActivate, pauseTracking, resumeTracking, signal, startBatch, update };
//# sourceMappingURL=index.js.map