import { isPrimitive } from "./helpers/isPrimitive"; export class Signal

{ value: P; subscribers: Set<(newValue: P, oldValue: P) => void>; constructor(initialValue?: P) { this.value = initialValue; this.subscribers = new Set(); } get() { // Track the signal's access (assume some global tracking function is available) if (globalThis.trackDependency) { globalThis.trackDependency(this); } return this.value; } set(newValue) { if (typeof newValue === 'function') { newValue = newValue(this.value); } if (this.value !== newValue) { const oldValue = this.value; this.value = newValue; this.notifySubscribers(this.value, oldValue); } } mutSet(newValue) { const oldValue = this.value; if (typeof newValue === 'function') { newValue = newValue(this.value); } if (isPrimitive(this.value)) { this.value = newValue; } this.notifySubscribers(this.value, oldValue); } subscribe(callback) { const unsubscribe = () => { this.unsubscribe(callback); }; this.subscribers.add(callback); return unsubscribe; } // Unsubscribe from changes unsubscribe(callback) { this.subscribers.delete(callback); } notifySubscribers(newValue, oldValue) { this.subscribers.forEach((callback) => callback(this.value, oldValue)); } } // Implementation of Signal.Computed export class Computed

extends Signal

{ computeFn: () => P; dependencies: Set>; constructor(computeFn) { super(); this.computeFn = computeFn; this.value = undefined; this.subscribers = new Set(); this.dependencies = new Set(); // Track dependencies (other signals) // Compute the initial value and set up tracking this.compute(true); } // Compute the value and track dependencies compute(val?: boolean) { // Unsubscribe from previous dependencies // this.dependencies.forEach((dep) => dep.unsubscribe(this.update)); // Track dependencies during the computation // this.dependencies.clear(); if (val) { // Monkey-patch the dependency tracking system const trackDependency = (signal) => { this.dependencies.add(signal); signal.subscribe(this.update); // Subscribe to changes }; // Temporarily replace the global `trackDependency` function globalThis.trackDependency = trackDependency; } // Compute the new value const newValue = this.computeFn(); // Clean up the monkey-patch delete globalThis.trackDependency; // If the computed value has changed, notify subscribers if (newValue !== this.value) { const oldValue = this.value; this.value = newValue; this.notifySubscribers(this.value, oldValue); } } // Method to call when a dependency changes update = () => { this.compute(); // Recompute value when dependencies change }; } export function effect(fn) { const signals: Signal[] = []; // Assume we have some mechanism to track dependencies globalThis.trackDependency = (signal) => { signal.subscribe(fn); // Subscribe to changes signals.push(signal); }; // Run the effect function fn(); // Clean up the monkey-patch delete globalThis.trackDependency; // Subscribe the effect to signal changes const unsubscribe = () => { // Cleanup logic to unsubscribe if needed signals.forEach((signal) => { signal.unsubscribe(fn); // Subscribe to changes }); }; // Return an unsubscribe function return unsubscribe; } export function state

(value: P): Signal

{ return new Signal

(value); }; export function stateArray

(value: P[]): Signal[]> { return new Signal[]>(value.map((val) => new Signal(val))); }; export function computed

(cb: () => P): Computed

{ return new Computed

(cb); };