Created
March 28, 2025 05:08
-
-
Save johnsoncodehk/ddf9c8f619a937522d842f7c1669c839 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createReactiveSystem, Dependency, Link, Subscriber, SubscriberFlags } from 'alien-signals/esm'; | |
import { ReactiveFramework } from "../util/reactiveFramework"; | |
let toCleanup: (() => void)[] = []; | |
export const alienSignalsStaticDeps: ReactiveFramework = { | |
type: "pure", | |
name: "alien-signals (static deps)", | |
signal: (initial) => { | |
const data = signal(initial); | |
return data; | |
}, | |
computed: (deps, fn) => { | |
const c = computed(() => fn(...deps.map(dep => dep.value))); | |
for (const dep of deps) { | |
link(dep, c); | |
} | |
return c; | |
}, | |
effect: (deps, fn) => { | |
const e = effect(() => fn(...deps.map(dep => dep.value))); | |
for (const dep of deps) { | |
link(dep, e); | |
} | |
toCleanup.push(e.stop.bind(e)); | |
}, | |
withBatch: (fn) => { | |
startBatch(); | |
fn(); | |
endBatch(); | |
}, | |
withBuild: (fn) => fn(), | |
cleanup: () => { | |
for (const cleanup of toCleanup) { | |
cleanup(); | |
} | |
toCleanup = []; | |
}, | |
}; | |
const { | |
link, | |
propagate, | |
endTracking, | |
startTracking, | |
updateDirtyFlag, | |
processComputedUpdate, | |
processEffectNotifications, | |
} = createReactiveSystem({ | |
updateComputed(computed: Computed) { | |
return computed.update(); | |
}, | |
notifyEffect(effect: Effect) { | |
effect.notify(); | |
return true; | |
}, | |
}); | |
let batchDepth = 0; | |
function startBatch(): void { | |
++batchDepth; | |
} | |
function endBatch(): void { | |
if (!--batchDepth) { | |
processEffectNotifications(); | |
} | |
} | |
function signal<T>(): Signal<T | undefined>; | |
function signal<T>(oldValue: T): Signal<T>; | |
function signal<T>(oldValue?: T): Signal<T | undefined> { | |
return new Signal(oldValue); | |
} | |
class Signal<T = any> implements Dependency { | |
// Dependency fields | |
subs: Link | undefined = undefined; | |
subsTail: Link | undefined = undefined; | |
constructor( | |
public currentValue: T | |
) { } | |
get value(): T { | |
return this.currentValue; | |
} | |
set value(value: T) { | |
if (this.currentValue !== value) { | |
this.currentValue = value; | |
const subs = this.subs; | |
if (subs !== undefined) { | |
propagate(subs); | |
if (!batchDepth) { | |
processEffectNotifications(); | |
} | |
} | |
} | |
} | |
} | |
function computed<T>(getter: () => T): Computed<T> { | |
return new Computed<T>(getter); | |
} | |
class Computed<T = any> implements Subscriber, Dependency { | |
currentValue: T | undefined = undefined; | |
// Dependency fields | |
subs: Link | undefined = undefined; | |
subsTail: Link | undefined = undefined; | |
// Subscriber fields | |
deps: Link | undefined = undefined; | |
depsTail: Link | undefined = undefined; | |
flags: SubscriberFlags = SubscriberFlags.Computed | SubscriberFlags.Dirty; | |
constructor( | |
public getter: () => T | |
) { } | |
get value(): T { | |
const flags = this.flags; | |
if (flags & (SubscriberFlags.PendingComputed | SubscriberFlags.Dirty)) { | |
processComputedUpdate(this, flags); | |
} | |
return this.currentValue!; | |
} | |
update(): boolean { | |
this.flags &= ~(SubscriberFlags.Notified | SubscriberFlags.Recursed | SubscriberFlags.Propagated); | |
const oldValue = this.currentValue; | |
const newValue = this.getter(); | |
if (oldValue !== newValue) { | |
this.currentValue = newValue; | |
return true; | |
} | |
return false; | |
} | |
} | |
function effect<T>(fn: () => T): Effect<T> { | |
const e = new Effect(fn); | |
e.run(); | |
return e; | |
} | |
class Effect<T = any> implements Subscriber { | |
// Subscriber fields | |
deps: Link | undefined = undefined; | |
depsTail: Link | undefined = undefined; | |
flags: SubscriberFlags = SubscriberFlags.Effect; | |
constructor( | |
public run: () => T | |
) { } | |
notify(): void { | |
const flags = this.flags; | |
if ( | |
flags & SubscriberFlags.Dirty | |
|| (flags & SubscriberFlags.PendingComputed && updateDirtyFlag(this, flags)) | |
) { | |
this.flags &= ~(SubscriberFlags.Notified | SubscriberFlags.Recursed | SubscriberFlags.Propagated); | |
this.run(); | |
} | |
} | |
stop(): void { | |
startTracking(this); | |
endTracking(this); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment