@reely/signals 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ Pick the style you like; the two mix freely. A `ReactiveValue<T>` is anything re
|
|
|
32
32
|
|
|
33
33
|
Effects run synchronously, and a computed recomputes only when it is read after a change. A write of an equal value (`Object.is`, or the `equals` you pass) changes nothing. A signal holds any value, a function included: `set` and `.value =` store it; `update` calls only the function you pass it.
|
|
34
34
|
|
|
35
|
+
A batch that puts a signal back where it was reruns nothing that read it before the batch. A run of an effect or computed does not follow a signal it writes itself, so a run that writes what it reads settles instead of looping; effects that keep writing each other's signals stop with an error after 100 waves, and a computed that reads itself throws one.
|
|
36
|
+
|
|
35
37
|
```ts
|
|
36
38
|
import { signal } from '@reely/signals';
|
|
37
39
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as subscribe, c as write, i as signal$1, l as noop, n as computed$1, r as effect$1, s as untracked, t as batch } from "./signals-
|
|
1
|
+
import { a as subscribe, c as write, i as signal$1, l as noop, n as computed$1, r as effect$1, s as untracked, t as batch } from "./signals-MA_mML__.js";
|
|
2
2
|
import { hasSome } from "@reely/basics";
|
|
3
3
|
//#region ../utils/dist/lib/objects/setPrototype.js
|
|
4
4
|
function setPrototype(proto, object) {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { hasSome } from "@reely/basics";
|
|
2
|
+
//#region ../utils/dist/lib/objects/isNil.js
|
|
3
|
+
function isNil(value) {
|
|
4
|
+
return value === null || value === void 0;
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
2
7
|
//#region ../utils/dist/lib/objects/isInstanceOf.js
|
|
3
8
|
function isInstanceOf(instanceType, instance) {
|
|
4
9
|
return instance instanceof instanceType;
|
|
@@ -13,6 +18,7 @@ var epoch = 0;
|
|
|
13
18
|
var tracker = null;
|
|
14
19
|
var running = null;
|
|
15
20
|
var batchDepth = 0;
|
|
21
|
+
var batchWrites = [];
|
|
16
22
|
var queue = [];
|
|
17
23
|
var flushing = false;
|
|
18
24
|
var setTracker = (observer) => {
|
|
@@ -31,6 +37,7 @@ var Signal = class {
|
|
|
31
37
|
version = 0;
|
|
32
38
|
observers = /* @__PURE__ */ new Set();
|
|
33
39
|
refresh = noop;
|
|
40
|
+
beforeBatch = null;
|
|
34
41
|
constructor(value, options) {
|
|
35
42
|
this.value = value;
|
|
36
43
|
this.options = options;
|
|
@@ -42,15 +49,27 @@ var Signal = class {
|
|
|
42
49
|
observe(observer) {
|
|
43
50
|
this.observers.add(observer);
|
|
44
51
|
}
|
|
52
|
+
forgetBatch() {
|
|
53
|
+
this.beforeBatch = null;
|
|
54
|
+
}
|
|
45
55
|
unobserve(observer) {
|
|
46
56
|
this.observers.delete(observer);
|
|
47
57
|
}
|
|
48
58
|
write(value) {
|
|
49
59
|
const { equals = Object.is } = this.options;
|
|
50
60
|
if (equals !== false && equals(this.value, value)) return;
|
|
51
|
-
this.
|
|
52
|
-
|
|
61
|
+
if (batchDepth > 0 && isNil(this.beforeBatch)) {
|
|
62
|
+
this.beforeBatch = {
|
|
63
|
+
value: this.value,
|
|
64
|
+
version: this.version
|
|
65
|
+
};
|
|
66
|
+
batchWrites.push(this);
|
|
67
|
+
}
|
|
68
|
+
const { beforeBatch } = this;
|
|
69
|
+
const reverted = hasSome(beforeBatch) && equals !== false && equals(beforeBatch.value, value);
|
|
53
70
|
epoch++;
|
|
71
|
+
this.value = value;
|
|
72
|
+
this.version = reverted ? beforeBatch.version : epoch;
|
|
54
73
|
running?.onOwnWrite(this);
|
|
55
74
|
const idle = queue.length === 0;
|
|
56
75
|
for (const observer of this.observers) observer.mark(this);
|
|
@@ -67,6 +86,7 @@ var Computation = class {
|
|
|
67
86
|
checkedAt = -1;
|
|
68
87
|
markedAt = -1;
|
|
69
88
|
deafTo = null;
|
|
89
|
+
refreshing = false;
|
|
70
90
|
constructor(fn) {
|
|
71
91
|
this.fn = fn;
|
|
72
92
|
}
|
|
@@ -97,8 +117,23 @@ var Computation = class {
|
|
|
97
117
|
if (this.linked) source.observe(this);
|
|
98
118
|
}
|
|
99
119
|
refresh() {
|
|
120
|
+
if (this.refreshing) throw new Error("reelx: a cycle of computeds, one reads itself through what it reads");
|
|
100
121
|
const current = this.outcome;
|
|
101
122
|
if (hasSome(current) && !this.needsCheck && (this.linked || this.checkedAt === epoch)) return current;
|
|
123
|
+
this.refreshing = true;
|
|
124
|
+
try {
|
|
125
|
+
return this.update(current);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.outcome = null;
|
|
128
|
+
throw error;
|
|
129
|
+
} finally {
|
|
130
|
+
this.refreshing = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
detach() {
|
|
134
|
+
for (const source of this.sources.keys()) source.unobserve(this);
|
|
135
|
+
}
|
|
136
|
+
update(current) {
|
|
102
137
|
this.needsCheck = false;
|
|
103
138
|
this.checkedAt = epoch;
|
|
104
139
|
if (hasSome(current) && !this.sourceChanged()) return current;
|
|
@@ -126,9 +161,6 @@ var Computation = class {
|
|
|
126
161
|
this.outcome = next;
|
|
127
162
|
return next;
|
|
128
163
|
}
|
|
129
|
-
detach() {
|
|
130
|
-
for (const source of this.sources.keys()) source.unobserve(this);
|
|
131
|
-
}
|
|
132
164
|
unlink(source) {
|
|
133
165
|
this.sources.delete(source);
|
|
134
166
|
source.unobserve(this);
|
|
@@ -274,7 +306,12 @@ var batch = (fn) => {
|
|
|
274
306
|
try {
|
|
275
307
|
return fn();
|
|
276
308
|
} finally {
|
|
277
|
-
if (--batchDepth === 0)
|
|
309
|
+
if (--batchDepth === 0) {
|
|
310
|
+
const written = batchWrites;
|
|
311
|
+
batchWrites = [];
|
|
312
|
+
written.forEach((each) => each.forgetBatch());
|
|
313
|
+
flushSync();
|
|
314
|
+
}
|
|
278
315
|
}
|
|
279
316
|
};
|
|
280
317
|
/** Runs `fn` without subscribing the running effect or computed to what it reads. */
|
|
@@ -291,4 +328,4 @@ var subscriberCount = (read) => nodes.get(read)?.observers.size ?? 0;
|
|
|
291
328
|
//#endregion
|
|
292
329
|
export { subscribe as a, write as c, signal as i, noop as l, computed as n, subscriberCount as o, effect as r, untracked as s, batch as t };
|
|
293
330
|
|
|
294
|
-
//# sourceMappingURL=signals-
|
|
331
|
+
//# sourceMappingURL=signals-MA_mML__.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals-MA_mML__.js","names":[],"sources":["../../utils/dist/lib/objects/isNil.js","../../utils/dist/lib/objects/isInstanceOf.js","../../utils/dist/lib/fp/noop.js","../src/lib/reelx.core.ts"],"sourcesContent":["export default function isNil(value) {\n return value === null || value === undefined;\n}\n","export default function isInstanceOf(instanceType, instance) {\n return instance instanceof instanceType;\n}\n","export default function noop() {\n return undefined;\n}\n","// A push-pull signal graph: a write marks what may have changed, a read brings a node up to date.\nimport { hasSome } from '@reely/basics';\nimport type { Nullable } from '@reely/utils';\nimport { isInstanceOf, isNil, noop } from '@reely/utils';\n\n/** A value read reactively: a signal, a computed or any getter of them; an effect or computed that reads it follows it. */\nexport type ReactiveValue<T> = () => T;\n\n// a method type: its parameters stay bivariant, so a `Signal<T>` is a `Signal<unknown>`\ntype Equality<T> = { bivarianceHack(previous: T, next: T): boolean }['bivarianceHack'];\n\n/** How a signal tells a write that changes nothing from one that notifies. */\nexport interface SignalOptions<T> {\n /**\n * Whether a write leaves the value unchanged, so nothing is notified; `Object.is` by default.\n * `false` (or `() => false`) notifies every write, for an object changed in place.\n */\n equals?: Equality<T> | false;\n}\n\ninterface Source {\n // grows with every change of the value, so an observer can tell whether what it read is still current\n readonly version: number;\n readonly observers: ReadonlySet<Computation<unknown>>;\n refresh(): void;\n observe(observer: Computation<unknown>): void;\n unobserve(observer: Computation<unknown>): void;\n}\n\ninterface Link {\n version: number;\n readIn: number;\n}\n\n// the value, or what the computation threw\ntype Outcome<T> = { readonly threw: false; readonly value: T } | { readonly threw: true; readonly value: unknown };\n\nconst MAX_FLUSH_WAVES = 100;\n\n// grows with every write: an unlinked computed hears no writes, but one checked at this epoch is current;\n// a signal's version is the epoch of its last change, so a version is never handed out twice\nlet epoch = 0;\nlet tracker: Nullable<Computation<unknown>> = null;\n// the computation whose `fn` runs now, tracked or not: its own writes never run it again\nlet running: Nullable<Computation<unknown>> = null;\nlet batchDepth = 0;\n// the signals written in the batch running now, which remember what they held before it\nlet batchWrites: Signal<unknown>[] = [];\nlet queue: Effect[] = [];\nlet flushing = false;\n\nconst setTracker = (observer: Nullable<Computation<unknown>>): Nullable<Computation<unknown>> => {\n const outer = tracker;\n tracker = observer;\n return outer;\n};\n\nconst setRunning = (computation: Nullable<Computation<unknown>>): Nullable<Computation<unknown>> => {\n const outer = running;\n running = computation;\n return outer;\n};\n\nclass Signal<T> implements Source {\n public version = 0;\n public readonly observers = new Set<Computation<unknown>>();\n public readonly refresh = noop;\n // the value and version before the first write of the batch running now\n private beforeBatch: Nullable<{ readonly value: T; readonly version: number }> = null;\n\n constructor(private value: T, private readonly options: SignalOptions<T>) {}\n\n public readonly read = (): T => {\n tracker?.onRead(this);\n return this.value;\n };\n\n public observe(observer: Computation<unknown>): void {\n this.observers.add(observer);\n }\n\n public forgetBatch(): void {\n this.beforeBatch = null;\n }\n\n public unobserve(observer: Computation<unknown>): void {\n this.observers.delete(observer);\n }\n\n public write(value: T): void {\n const { equals = Object.is } = this.options;\n if (equals !== false && equals(this.value, value)) {\n return;\n }\n if (batchDepth > 0 && isNil(this.beforeBatch)) {\n this.beforeBatch = { value: this.value, version: this.version };\n batchWrites.push(this);\n }\n const { beforeBatch } = this;\n // a batch that puts the value back changes nothing for what read it before the batch\n const reverted = hasSome(beforeBatch) && equals !== false && equals(beforeBatch.value, value);\n epoch++;\n this.value = value;\n this.version = reverted ? beforeBatch.version : epoch;\n running?.onOwnWrite(this);\n const idle = queue.length === 0;\n for (const observer of this.observers) {\n observer.mark(this);\n }\n if (idle && queue.length > 0 && batchDepth === 0 && !flushing) {\n flushSync();\n }\n }\n}\n\n// runs `fn` recording what it reads, and reruns it on demand only when one of those sources changed\nabstract class Computation<T> {\n public version = 0;\n // a source may have changed; the versions of the sources tell whether one did\n protected needsCheck = false;\n // in the order first read\n protected readonly sources = new Map<Source, Link>();\n protected outcome: Nullable<Outcome<T>> = null;\n private runCount = 0;\n private checkedAt = -1;\n private markedAt = -1;\n private deafTo: Nullable<Set<Source>> = null;\n // checking its sources or computing: a read of it now is a cycle\n private refreshing = false;\n\n constructor(private readonly fn: () => T) {}\n\n // whether its sources hold it, so that their writes reach it\n protected abstract get linked(): boolean;\n\n // `written` is the signal whose write this mark carries\n public mark(written: Source): void {\n // once per write: a node already marked by an earlier write still passes a new one on\n if (this.markedAt === epoch) {\n return;\n }\n this.markedAt = epoch;\n // A run does not depend on a signal it writes, read directly or through a computed: its own\n // write coming back makes it deaf to that signal until it reads it again or runs again.\n if (this === running) {\n this.deafTo ??= new Set();\n this.deafTo.add(written);\n } else if (!this.deafTo?.has(written)) {\n this.onMarked(written);\n }\n }\n\n // what a run writes itself is not a change it missed\n public onOwnWrite(source: Source): void {\n const link = this.sources.get(source);\n if (hasSome(link)) {\n link.version = source.version;\n }\n }\n\n public onRead(source: Source): void {\n this.deafTo?.delete(source);\n const link = this.sources.get(source);\n if (hasSome(link)) {\n link.version = source.version;\n link.readIn = this.runCount;\n return;\n }\n this.sources.set(source, { version: source.version, readIn: this.runCount });\n if (this.linked) {\n source.observe(this);\n }\n }\n\n public refresh(): Outcome<T> {\n if (this.refreshing) {\n throw new Error('reelx: a cycle of computeds, one reads itself through what it reads');\n }\n const current = this.outcome;\n if (hasSome(current) && !this.needsCheck && (this.linked || this.checkedAt === epoch)) {\n return current;\n }\n this.refreshing = true;\n try {\n return this.update(current);\n } catch (error) {\n // a cycle among its sources broke the check off: the next read computes it afresh\n this.outcome = null;\n throw error;\n } finally {\n this.refreshing = false;\n }\n }\n\n protected detach(): void {\n for (const source of this.sources.keys()) {\n source.unobserve(this);\n }\n }\n\n private update(current: Nullable<Outcome<T>>): Outcome<T> {\n this.needsCheck = false;\n this.checkedAt = epoch;\n if (hasSome(current) && !this.sourceChanged()) {\n return current;\n }\n\n const { fn } = this;\n this.runCount++;\n this.deafTo = null;\n const outer = setTracker(this);\n const outerRunning = setRunning(this);\n let next: Outcome<T>;\n try {\n next = { threw: false, value: fn() };\n } catch (error) {\n next = { threw: true, value: error };\n }\n setTracker(outer);\n setRunning(outerRunning);\n this.dropUnread();\n if (!hasSome(current) || current.threw !== next.threw || !Object.is(current.value, next.value)) {\n this.version++;\n }\n this.outcome = next;\n return next;\n }\n\n private unlink(source: Source): void {\n this.sources.delete(source);\n source.unobserve(this);\n }\n\n private sourceChanged(): boolean {\n for (const [source, { version }] of this.sources) {\n source.refresh();\n if (source.version !== version) {\n return true;\n }\n }\n return false;\n }\n\n private dropUnread(): void {\n for (const [source, link] of this.sources) {\n if (link.readIn !== this.runCount) {\n this.unlink(source);\n }\n }\n }\n\n protected abstract onMarked(written: Source): void;\n}\n\nclass Computed<T> extends Computation<T> implements Source {\n public readonly observers = new Set<Computation<unknown>>();\n\n protected get linked(): boolean {\n return this.observers.size > 0;\n }\n\n public readonly read = (): T => {\n const outcome = this.refresh();\n tracker?.onRead(this);\n if (outcome.threw) {\n throw outcome.value;\n }\n return outcome.value;\n };\n\n public observe(observer: Computation<unknown>): void {\n if (this.observers.size === 0) {\n for (const source of this.sources.keys()) {\n source.observe(this);\n }\n }\n this.observers.add(observer);\n }\n\n public unobserve(observer: Computation<unknown>): void {\n if (this.observers.delete(observer) && this.observers.size === 0) {\n this.detach();\n }\n }\n\n protected onMarked(written: Source): void {\n this.needsCheck = true;\n for (const observer of this.observers) {\n observer.mark(written);\n }\n }\n}\n\n// stays linked until disposed; a mark queues it to run\nclass Effect extends Computation<void> {\n private disposed = false;\n\n protected get linked(): boolean {\n return !this.disposed;\n }\n\n public readonly dispose = (): void => {\n this.disposed = true;\n this.detach();\n this.sources.clear();\n };\n\n // runs it if what it read has changed, and throws what that run threw\n public run(): void {\n if (this.disposed) {\n return;\n }\n const before = this.outcome;\n const after = this.refresh();\n if (after !== before && after.threw) {\n throw after.value;\n }\n }\n\n // taken out of the queue without running: the next write queues it again\n public dequeue(): void {\n this.needsCheck = false;\n }\n\n protected onMarked(): void {\n if (!this.needsCheck) {\n this.needsCheck = true;\n queue.push(this);\n }\n }\n}\n\n/** Runs the queued effects now; what they write joins as the next wave. Every effect runs, the first error is rethrown. */\nconst flushSync = (): void => {\n if (flushing) {\n return;\n }\n flushing = true;\n let failure: Nullable<{ readonly error: unknown }> = null;\n try {\n let wave = 0;\n while (queue.length > 0) {\n wave++;\n if (wave > MAX_FLUSH_WAVES) {\n const dropped = queue;\n queue = [];\n dropped.forEach((effect) => effect.dequeue());\n throw new Error(\n `reelx: a cycle of effects, each writes a signal another one reads (${MAX_FLUSH_WAVES} waves)`,\n { cause: failure?.error }\n );\n }\n const effects = queue;\n queue = [];\n for (const effect of effects) {\n try {\n effect.run();\n } catch (error) {\n failure ??= { error };\n }\n }\n }\n } finally {\n flushing = false;\n }\n if (hasSome(failure)) {\n throw failure.error;\n }\n};\n\n// the node behind each reader, for writes and for `subscriberCount`\nconst nodes = new WeakMap<ReactiveValue<unknown>, Signal<unknown> | Computed<unknown>>();\n\nconst toReactiveValue = <T>(node: Signal<T> | Computed<T>): ReactiveValue<T> => {\n nodes.set(node.read, node);\n return node.read;\n};\n\n/** A value that effects and computeds re-read when it is written; a function is held as a value too. */\nexport const signal = <T>(initial: T, options: SignalOptions<T> = {}): ReactiveValue<T> =>\n toReactiveValue(new Signal(initial, options));\n\n/** A value derived from what `fn` reads, recomputed on read after one of them changes; what `fn` throws is rethrown until then. */\nexport const computed = <T>(fn: () => T): ReactiveValue<T> => toReactiveValue(new Computed(fn));\n\n/** Writes `value` to the signal `read` reads (a computed's reader is ignored); a value its `equals` finds unchanged changes nothing. */\nexport const write = <T>(read: ReactiveValue<T>, value: T): void => {\n const node = nodes.get(read);\n if (isInstanceOf(Signal, node)) {\n node.write(value);\n }\n};\n\n/** Runs `fn` now and again after every change of what it read. Returns `dispose`; creation that throws leaves nothing subscribed. */\nexport const effect = (fn: () => void): (() => void) => {\n const node = new Effect(fn);\n try {\n batch(() => {\n try {\n node.run();\n } catch (error) {\n // before the flush that ends the batch, so it never runs an effect whose creation threw\n node.dispose();\n throw error;\n }\n });\n } catch (error) {\n node.dispose();\n throw error;\n }\n return node.dispose;\n};\n\n/**\n * Calls `cb` with the value of `read` and the one before it: now, unless it is `undefined`, then\n * after every change `read` notifies. Returns `unsubscribe`.\n */\nexport const subscribe = <T>(read: ReactiveValue<T>, cb: (value: T, prevValue?: T) => void): (() => void) => {\n let last: T | undefined;\n let started = false;\n return effect(() => {\n const value = read();\n const previous = last;\n last = value;\n if (started || !Object.is(value, undefined)) {\n untracked(() => cb(value, previous));\n }\n started = true;\n });\n};\n\n/** Groups writes: effects run once, when the outermost `batch` ends, even if `fn` throws. */\nexport const batch = <T>(fn: () => T): T => {\n batchDepth++;\n try {\n return fn();\n } finally {\n if (--batchDepth === 0) {\n const written = batchWrites;\n batchWrites = [];\n written.forEach((each) => each.forgetBatch());\n flushSync();\n }\n }\n};\n\n/** Runs `fn` without subscribing the running effect or computed to what it reads. */\nexport const untracked = <T>(fn: () => T): T => {\n const outer = setTracker(null);\n try {\n return fn();\n } finally {\n setTracker(outer);\n }\n};\n\n/** How many effects and computeds read `read` now: tests count them to prove that `dispose` released them. */\nexport const subscriberCount = (read: ReactiveValue<unknown>): number => nodes.get(read)?.observers.size ?? 0;\n"],"mappings":"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"}
|
package/dist/testing.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { o as subscriberCount } from "./signals-
|
|
1
|
+
import { o as subscriberCount } from "./signals-MA_mML__.js";
|
|
2
2
|
export { subscriberCount };
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signals-CHdm5V62.js","names":[],"sources":["../../utils/dist/lib/objects/isInstanceOf.js","../../utils/dist/lib/fp/noop.js","../src/lib/reelx.core.ts"],"sourcesContent":["export default function isInstanceOf(instanceType, instance) {\n return instance instanceof instanceType;\n}\n","export default function noop() {\n return undefined;\n}\n","// A push-pull signal graph: a write marks what may have changed, a read brings a node up to date.\nimport { hasSome } from '@reely/basics';\nimport type { Nullable } from '@reely/utils';\nimport { isInstanceOf, noop } from '@reely/utils';\n\n/** A value read reactively: a signal, a computed or any getter of them; an effect or computed that reads it follows it. */\nexport type ReactiveValue<T> = () => T;\n\n// a method type: its parameters stay bivariant, so a `Signal<T>` is a `Signal<unknown>`\ntype Equality<T> = { bivarianceHack(previous: T, next: T): boolean }['bivarianceHack'];\n\n/** How a signal tells a write that changes nothing from one that notifies. */\nexport interface SignalOptions<T> {\n /**\n * Whether a write leaves the value unchanged, so nothing is notified; `Object.is` by default.\n * `false` (or `() => false`) notifies every write, for an object changed in place.\n */\n equals?: Equality<T> | false;\n}\n\ninterface Source {\n // grows with every change of the value, so an observer can tell whether what it read is still current\n readonly version: number;\n readonly observers: ReadonlySet<Computation<unknown>>;\n refresh(): void;\n observe(observer: Computation<unknown>): void;\n unobserve(observer: Computation<unknown>): void;\n}\n\ninterface Link {\n version: number;\n readIn: number;\n}\n\n// the value, or what the computation threw\ntype Outcome<T> = { readonly threw: false; readonly value: T } | { readonly threw: true; readonly value: unknown };\n\nconst MAX_FLUSH_WAVES = 100;\n\n// grows with every write: an unlinked computed hears no writes, but one checked at this epoch is current\nlet epoch = 0;\nlet tracker: Nullable<Computation<unknown>> = null;\n// the computation whose `fn` runs now, tracked or not: its own writes never run it again\nlet running: Nullable<Computation<unknown>> = null;\nlet batchDepth = 0;\nlet queue: Effect[] = [];\nlet flushing = false;\n\nconst setTracker = (observer: Nullable<Computation<unknown>>): Nullable<Computation<unknown>> => {\n const outer = tracker;\n tracker = observer;\n return outer;\n};\n\nconst setRunning = (computation: Nullable<Computation<unknown>>): Nullable<Computation<unknown>> => {\n const outer = running;\n running = computation;\n return outer;\n};\n\nclass Signal<T> implements Source {\n public version = 0;\n public readonly observers = new Set<Computation<unknown>>();\n public readonly refresh = noop;\n\n constructor(private value: T, private readonly options: SignalOptions<T>) {}\n\n public readonly read = (): T => {\n tracker?.onRead(this);\n return this.value;\n };\n\n public observe(observer: Computation<unknown>): void {\n this.observers.add(observer);\n }\n\n public unobserve(observer: Computation<unknown>): void {\n this.observers.delete(observer);\n }\n\n public write(value: T): void {\n const { equals = Object.is } = this.options;\n if (equals !== false && equals(this.value, value)) {\n return;\n }\n this.value = value;\n this.version++;\n epoch++;\n running?.onOwnWrite(this);\n const idle = queue.length === 0;\n for (const observer of this.observers) {\n observer.mark(this);\n }\n if (idle && queue.length > 0 && batchDepth === 0 && !flushing) {\n flushSync();\n }\n }\n}\n\n// runs `fn` recording what it reads, and reruns it on demand only when one of those sources changed\nabstract class Computation<T> {\n public version = 0;\n // a source may have changed; the versions of the sources tell whether one did\n protected needsCheck = false;\n // in the order first read\n protected readonly sources = new Map<Source, Link>();\n protected outcome: Nullable<Outcome<T>> = null;\n private runCount = 0;\n private checkedAt = -1;\n private markedAt = -1;\n private deafTo: Nullable<Set<Source>> = null;\n\n constructor(private readonly fn: () => T) {}\n\n // whether its sources hold it, so that their writes reach it\n protected abstract get linked(): boolean;\n\n // `written` is the signal whose write this mark carries\n public mark(written: Source): void {\n // once per write: a node already marked by an earlier write still passes a new one on\n if (this.markedAt === epoch) {\n return;\n }\n this.markedAt = epoch;\n // A run does not depend on a signal it writes, read directly or through a computed: its own\n // write coming back makes it deaf to that signal until it reads it again or runs again.\n if (this === running) {\n this.deafTo ??= new Set();\n this.deafTo.add(written);\n } else if (!this.deafTo?.has(written)) {\n this.onMarked(written);\n }\n }\n\n // what a run writes itself is not a change it missed\n public onOwnWrite(source: Source): void {\n const link = this.sources.get(source);\n if (hasSome(link)) {\n link.version = source.version;\n }\n }\n\n public onRead(source: Source): void {\n this.deafTo?.delete(source);\n const link = this.sources.get(source);\n if (hasSome(link)) {\n link.version = source.version;\n link.readIn = this.runCount;\n return;\n }\n this.sources.set(source, { version: source.version, readIn: this.runCount });\n if (this.linked) {\n source.observe(this);\n }\n }\n\n public refresh(): Outcome<T> {\n const current = this.outcome;\n if (hasSome(current) && !this.needsCheck && (this.linked || this.checkedAt === epoch)) {\n return current;\n }\n this.needsCheck = false;\n this.checkedAt = epoch;\n if (hasSome(current) && !this.sourceChanged()) {\n return current;\n }\n\n const { fn } = this;\n this.runCount++;\n this.deafTo = null;\n const outer = setTracker(this);\n const outerRunning = setRunning(this);\n let next: Outcome<T>;\n try {\n next = { threw: false, value: fn() };\n } catch (error) {\n next = { threw: true, value: error };\n }\n setTracker(outer);\n setRunning(outerRunning);\n this.dropUnread();\n if (!hasSome(current) || current.threw !== next.threw || !Object.is(current.value, next.value)) {\n this.version++;\n }\n this.outcome = next;\n return next;\n }\n\n protected detach(): void {\n for (const source of this.sources.keys()) {\n source.unobserve(this);\n }\n }\n\n private unlink(source: Source): void {\n this.sources.delete(source);\n source.unobserve(this);\n }\n\n private sourceChanged(): boolean {\n for (const [source, { version }] of this.sources) {\n source.refresh();\n if (source.version !== version) {\n return true;\n }\n }\n return false;\n }\n\n private dropUnread(): void {\n for (const [source, link] of this.sources) {\n if (link.readIn !== this.runCount) {\n this.unlink(source);\n }\n }\n }\n\n protected abstract onMarked(written: Source): void;\n}\n\nclass Computed<T> extends Computation<T> implements Source {\n public readonly observers = new Set<Computation<unknown>>();\n\n protected get linked(): boolean {\n return this.observers.size > 0;\n }\n\n public readonly read = (): T => {\n const outcome = this.refresh();\n tracker?.onRead(this);\n if (outcome.threw) {\n throw outcome.value;\n }\n return outcome.value;\n };\n\n public observe(observer: Computation<unknown>): void {\n if (this.observers.size === 0) {\n for (const source of this.sources.keys()) {\n source.observe(this);\n }\n }\n this.observers.add(observer);\n }\n\n public unobserve(observer: Computation<unknown>): void {\n if (this.observers.delete(observer) && this.observers.size === 0) {\n this.detach();\n }\n }\n\n protected onMarked(written: Source): void {\n this.needsCheck = true;\n for (const observer of this.observers) {\n observer.mark(written);\n }\n }\n}\n\n// stays linked until disposed; a mark queues it to run\nclass Effect extends Computation<void> {\n private disposed = false;\n\n protected get linked(): boolean {\n return !this.disposed;\n }\n\n public readonly dispose = (): void => {\n this.disposed = true;\n this.detach();\n this.sources.clear();\n };\n\n // runs it if what it read has changed, and throws what that run threw\n public run(): void {\n if (this.disposed) {\n return;\n }\n const before = this.outcome;\n const after = this.refresh();\n if (after !== before && after.threw) {\n throw after.value;\n }\n }\n\n // taken out of the queue without running: the next write queues it again\n public dequeue(): void {\n this.needsCheck = false;\n }\n\n protected onMarked(): void {\n if (!this.needsCheck) {\n this.needsCheck = true;\n queue.push(this);\n }\n }\n}\n\n/** Runs the queued effects now; what they write joins as the next wave. Every effect runs, the first error is rethrown. */\nconst flushSync = (): void => {\n if (flushing) {\n return;\n }\n flushing = true;\n let failure: Nullable<{ readonly error: unknown }> = null;\n try {\n let wave = 0;\n while (queue.length > 0) {\n wave++;\n if (wave > MAX_FLUSH_WAVES) {\n const dropped = queue;\n queue = [];\n dropped.forEach((effect) => effect.dequeue());\n throw new Error(\n `reelx: a cycle of effects, each writes a signal another one reads (${MAX_FLUSH_WAVES} waves)`,\n { cause: failure?.error }\n );\n }\n const effects = queue;\n queue = [];\n for (const effect of effects) {\n try {\n effect.run();\n } catch (error) {\n failure ??= { error };\n }\n }\n }\n } finally {\n flushing = false;\n }\n if (hasSome(failure)) {\n throw failure.error;\n }\n};\n\n// the node behind each reader, for writes and for `subscriberCount`\nconst nodes = new WeakMap<ReactiveValue<unknown>, Signal<unknown> | Computed<unknown>>();\n\nconst toReactiveValue = <T>(node: Signal<T> | Computed<T>): ReactiveValue<T> => {\n nodes.set(node.read, node);\n return node.read;\n};\n\n/** A value that effects and computeds re-read when it is written; a function is held as a value too. */\nexport const signal = <T>(initial: T, options: SignalOptions<T> = {}): ReactiveValue<T> =>\n toReactiveValue(new Signal(initial, options));\n\n/** A value derived from what `fn` reads, recomputed on read after one of them changes; what `fn` throws is rethrown until then. */\nexport const computed = <T>(fn: () => T): ReactiveValue<T> => toReactiveValue(new Computed(fn));\n\n/** Writes `value` to the signal `read` reads (a computed's reader is ignored); a value its `equals` finds unchanged changes nothing. */\nexport const write = <T>(read: ReactiveValue<T>, value: T): void => {\n const node = nodes.get(read);\n if (isInstanceOf(Signal, node)) {\n node.write(value);\n }\n};\n\n/** Runs `fn` now and again after every change of what it read. Returns `dispose`; creation that throws leaves nothing subscribed. */\nexport const effect = (fn: () => void): (() => void) => {\n const node = new Effect(fn);\n try {\n batch(() => {\n try {\n node.run();\n } catch (error) {\n // before the flush that ends the batch, so it never runs an effect whose creation threw\n node.dispose();\n throw error;\n }\n });\n } catch (error) {\n node.dispose();\n throw error;\n }\n return node.dispose;\n};\n\n/**\n * Calls `cb` with the value of `read` and the one before it: now, unless it is `undefined`, then\n * after every change `read` notifies. Returns `unsubscribe`.\n */\nexport const subscribe = <T>(read: ReactiveValue<T>, cb: (value: T, prevValue?: T) => void): (() => void) => {\n let last: T | undefined;\n let started = false;\n return effect(() => {\n const value = read();\n const previous = last;\n last = value;\n if (started || !Object.is(value, undefined)) {\n untracked(() => cb(value, previous));\n }\n started = true;\n });\n};\n\n/** Groups writes: effects run once, when the outermost `batch` ends, even if `fn` throws. */\nexport const batch = <T>(fn: () => T): T => {\n batchDepth++;\n try {\n return fn();\n } finally {\n if (--batchDepth === 0) {\n flushSync();\n }\n }\n};\n\n/** Runs `fn` without subscribing the running effect or computed to what it reads. */\nexport const untracked = <T>(fn: () => T): T => {\n const outer = setTracker(null);\n try {\n return fn();\n } finally {\n setTracker(outer);\n }\n};\n\n/** How many effects and computeds read `read` now: tests count them to prove that `dispose` released them. */\nexport const subscriberCount = (read: ReactiveValue<unknown>): number => nodes.get(read)?.observers.size ?? 0;\n"],"mappings":"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"}
|