uneventful 0.0.12 → 0.0.13
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/dist/call-or-wait-CvOF0pao.mjs +22 -0
- package/dist/ext.d.ts +5 -4
- package/dist/ext.mjs +2 -2
- package/dist/hooks-BnMYHRlM.mjs +583 -0
- package/dist/{jobutils-Dvu-e99o.mjs → jobutils-O9tOTNKC.mjs} +116 -36
- package/dist/mod.d.ts +16 -54
- package/dist/mod.mjs +8 -8
- package/dist/shared.d.ts +87 -50
- package/dist/shared.mjs +51 -3
- package/dist/signals.d.ts +131 -19
- package/dist/signals.mjs +75 -530
- package/dist/{sinks-5TuxCRtX.d.ts → sinks-B_LfTZgF.d.ts} +1 -1
- package/dist/{types-N2ua11te.d.ts → types-pElgImr7.d.ts} +8 -57
- package/dist/{utils-cyEhnyp7.mjs → utils-BgqyDPjA.mjs} +33 -3
- package/dist/utils.d.ts +52 -7
- package/dist/utils.mjs +1 -1
- package/package.json +11 -12
- package/dist/call-or-wait-EzXJX5Dq.mjs +0 -111
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { s as start, j as connect, p as isValue, h as isError, f as markHandled } from './jobutils-O9tOTNKC.mjs';
|
|
2
|
+
import { i as isFunction } from './utils-BgqyDPjA.mjs';
|
|
3
|
+
|
|
4
|
+
function callOrWait(source, method, handler, noArgs) {
|
|
5
|
+
if (source && isFunction(source[method]))
|
|
6
|
+
return source[method]();
|
|
7
|
+
if (!isFunction(source))
|
|
8
|
+
mustBeSourceOrSignal();
|
|
9
|
+
return (source.length === 0 ? noArgs(source) : false) || start((job) => {
|
|
10
|
+
connect(source, (v) => handler(job, v)).do((r) => {
|
|
11
|
+
if (isValue(r))
|
|
12
|
+
job.throw(new Error("Stream ended"));
|
|
13
|
+
else if (isError(r))
|
|
14
|
+
job.throw(markHandled(r));
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function mustBeSourceOrSignal() {
|
|
19
|
+
throw new TypeError("not a source or signal");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { callOrWait as c, mustBeSourceOrSignal as m };
|
package/dist/ext.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PlainFunction } from './types-
|
|
1
|
+
import { P as PlainFunction } from './types-pElgImr7.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* This module provides helpers for creating *extensions*: a way of extending
|
|
@@ -15,7 +15,6 @@ import { P as PlainFunction } from './types-N2ua11te.js';
|
|
|
15
15
|
*
|
|
16
16
|
* @module uneventful/ext
|
|
17
17
|
*
|
|
18
|
-
* @experimental
|
|
19
18
|
* @disableGroups
|
|
20
19
|
* @summary Tools for extending objects with extra state and behavior, without
|
|
21
20
|
* directly modifying them.
|
|
@@ -100,7 +99,7 @@ declare function ext<Target extends WeakKey, ExtType extends Object>(factory: (t
|
|
|
100
99
|
* arguments (minus an initial `target` argument).
|
|
101
100
|
*/
|
|
102
101
|
declare function method<Target extends object, Method extends PlainFunction>(factory: (tgt: Target, map: WeakMap<Target, Method>) => Method, map?: WeakMap<Target, Method>): (tgt: Target, ...args: Parameters<Method>) => ReturnType<Method>;
|
|
103
|
-
/** Helper types for working with {@link Ext} Subclasses */
|
|
102
|
+
/** Helper types for working with {@link Ext} Subclasses @experimental */
|
|
104
103
|
declare namespace Ext {
|
|
105
104
|
/** Get the target type of an {@link Ext} subclass constructor */
|
|
106
105
|
type Target<T extends Ext.Class> = InstanceType<T>["of"];
|
|
@@ -144,6 +143,8 @@ declare namespace Ext {
|
|
|
144
143
|
*
|
|
145
144
|
* Instance and static members you can override to customize extension creation,
|
|
146
145
|
* deletion, target and return types.
|
|
146
|
+
*
|
|
147
|
+
* @experimental
|
|
147
148
|
*/
|
|
148
149
|
declare abstract class Ext<Target extends WeakKey = WeakKey> {
|
|
149
150
|
/**
|
|
@@ -205,7 +206,7 @@ declare abstract class Ext<Target extends WeakKey = WeakKey> {
|
|
|
205
206
|
*
|
|
206
207
|
* __new__(tgt: SomeType): Job<this> {
|
|
207
208
|
* const ext = this.__inst__(tgt);
|
|
208
|
-
*
|
|
209
|
+
* return start(this.__inst__(tgt).setup())
|
|
209
210
|
* }
|
|
210
211
|
* }
|
|
211
212
|
* ```
|
package/dist/ext.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as setMap } from './utils-
|
|
1
|
+
import { s as setMap } from './utils-BgqyDPjA.mjs';
|
|
2
2
|
|
|
3
3
|
function ext(factory, map = /* @__PURE__ */ new WeakMap()) {
|
|
4
4
|
return (tgt) => map.has(tgt) ? map.get(tgt) : setMap(map, tgt, factory(tgt, map));
|
|
@@ -73,7 +73,7 @@ class Ext {
|
|
|
73
73
|
*
|
|
74
74
|
* __new__(tgt: SomeType): Job<this> {
|
|
75
75
|
* const ext = this.__inst__(tgt);
|
|
76
|
-
*
|
|
76
|
+
* return start(this.__inst__(tgt).setup())
|
|
77
77
|
* }
|
|
78
78
|
* }
|
|
79
79
|
* ```
|
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import { M as pushCtx, N as popCtx, c as backpressure, I as IsStream, _ as _Job, d as root, h as isError, f as markHandled, g as getJob, o as currentCell } from './jobutils-O9tOTNKC.mjs';
|
|
2
|
+
import { h as batch, d as defer, c as apply, s as setMap } from './utils-BgqyDPjA.mjs';
|
|
3
|
+
|
|
4
|
+
const ruleQueues = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
function ruleQueue(scheduleFn = defer) {
|
|
6
|
+
ruleQueues.has(scheduleFn) || ruleQueues.set(scheduleFn, batch(runRules, scheduleFn));
|
|
7
|
+
return ruleQueues.get(scheduleFn);
|
|
8
|
+
}
|
|
9
|
+
var currentRule;
|
|
10
|
+
const ruleStops = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
const defaultQ = /* @__PURE__ */ ruleQueue(defer);
|
|
12
|
+
var currentQueue;
|
|
13
|
+
function runRules(q) {
|
|
14
|
+
if (currentQueue)
|
|
15
|
+
return;
|
|
16
|
+
while (q.size) {
|
|
17
|
+
currentQueue = this;
|
|
18
|
+
try {
|
|
19
|
+
for (currentRule of q) {
|
|
20
|
+
currentRule.catchUp();
|
|
21
|
+
q.delete(currentRule);
|
|
22
|
+
}
|
|
23
|
+
} finally {
|
|
24
|
+
currentQueue = currentRule = unset;
|
|
25
|
+
}
|
|
26
|
+
demandChanges.flush();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
class WriteConflict extends Error {
|
|
30
|
+
}
|
|
31
|
+
class CircularDependency extends Error {
|
|
32
|
+
}
|
|
33
|
+
var timestamp = 1;
|
|
34
|
+
const fntrackers = /* @__PURE__ */ new WeakMap();
|
|
35
|
+
const obtrackers = /* @__PURE__ */ new WeakMap();
|
|
36
|
+
const monitors = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
const staleStreams = batch((q) => {
|
|
38
|
+
for (const cell of q)
|
|
39
|
+
if (!cell.subscribers) {
|
|
40
|
+
++timestamp;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
q.clear();
|
|
44
|
+
});
|
|
45
|
+
const demandChanges = batch((q) => {
|
|
46
|
+
for (const cell of q)
|
|
47
|
+
cell.updateDemand();
|
|
48
|
+
});
|
|
49
|
+
const dirtyStack = [];
|
|
50
|
+
function markDependentsDirty(cell) {
|
|
51
|
+
const latestSource = cell.latestSource = timestamp;
|
|
52
|
+
for (; cell; cell = dirtyStack.pop()) {
|
|
53
|
+
for (let sub = cell.subscribers; sub; sub = sub.nT) {
|
|
54
|
+
const tgt = sub.tgt;
|
|
55
|
+
if (tgt.latestSource >= latestSource)
|
|
56
|
+
continue;
|
|
57
|
+
tgt.latestSource = latestSource;
|
|
58
|
+
tgt.queue?.add(tgt);
|
|
59
|
+
if (tgt.subscribers)
|
|
60
|
+
dirtyStack.push(tgt);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function returnValue() {
|
|
65
|
+
return this.value;
|
|
66
|
+
}
|
|
67
|
+
function throwValue() {
|
|
68
|
+
throw this.value;
|
|
69
|
+
}
|
|
70
|
+
const notCaughtUp = [];
|
|
71
|
+
var freesubs;
|
|
72
|
+
const unset = void 0;
|
|
73
|
+
function mksub(source, target) {
|
|
74
|
+
let sub = freesubs;
|
|
75
|
+
if (sub) {
|
|
76
|
+
freesubs = sub.old;
|
|
77
|
+
sub.src = source;
|
|
78
|
+
sub.nS = unset;
|
|
79
|
+
sub.pS = target.sources;
|
|
80
|
+
sub.tgt = target;
|
|
81
|
+
sub.nT = sub.pT = unset;
|
|
82
|
+
sub.ts = source.lastChanged;
|
|
83
|
+
sub.old = source.adding;
|
|
84
|
+
} else
|
|
85
|
+
sub = {
|
|
86
|
+
src: source,
|
|
87
|
+
nS: unset,
|
|
88
|
+
pS: target.sources,
|
|
89
|
+
tgt: target,
|
|
90
|
+
nT: unset,
|
|
91
|
+
pT: unset,
|
|
92
|
+
ts: source.lastChanged,
|
|
93
|
+
old: source.adding
|
|
94
|
+
};
|
|
95
|
+
if (target.sources)
|
|
96
|
+
target.sources.nS = sub;
|
|
97
|
+
target.sources = sub;
|
|
98
|
+
source.adding = sub;
|
|
99
|
+
if (target.flags & 1 /* Observed */)
|
|
100
|
+
source.subscribe(sub);
|
|
101
|
+
}
|
|
102
|
+
function removeConstListener(sub) {
|
|
103
|
+
const { tgt, nS, pS } = sub;
|
|
104
|
+
if (sub.src.adding === sub)
|
|
105
|
+
sub.src.adding = sub.old;
|
|
106
|
+
delsub(sub);
|
|
107
|
+
if (tgt.sources === sub)
|
|
108
|
+
(tgt.sources = nS || pS) || tgt.becomeConstant();
|
|
109
|
+
}
|
|
110
|
+
function delsub(sub) {
|
|
111
|
+
sub.src.unsubscribe(sub);
|
|
112
|
+
if (sub.nS)
|
|
113
|
+
sub.nS.pS = sub.pS;
|
|
114
|
+
if (sub.pS)
|
|
115
|
+
sub.pS.nS = sub.nS;
|
|
116
|
+
sub.src = sub.tgt = sub.nS = sub.pS = sub.nT = sub.pT = unset;
|
|
117
|
+
sub.old = freesubs;
|
|
118
|
+
freesubs = sub;
|
|
119
|
+
}
|
|
120
|
+
function subscribeAll(c) {
|
|
121
|
+
for (let s = firstSource(c); s; s = s.nS)
|
|
122
|
+
s.src.subscribe(s);
|
|
123
|
+
toggleDemand(c);
|
|
124
|
+
}
|
|
125
|
+
function unsubscribeAll(c) {
|
|
126
|
+
for (let s = firstSource(c); s; s = s.nS)
|
|
127
|
+
s.src.unsubscribe(s);
|
|
128
|
+
toggleDemand(c);
|
|
129
|
+
}
|
|
130
|
+
const sentinel = {};
|
|
131
|
+
function firstSource(c) {
|
|
132
|
+
let s = c.sources;
|
|
133
|
+
if (s)
|
|
134
|
+
while (s.pS)
|
|
135
|
+
s = s.pS;
|
|
136
|
+
return s;
|
|
137
|
+
}
|
|
138
|
+
function toggleDemand(c) {
|
|
139
|
+
if (((c.flags ^= 1 /* Observed */) & 64 /* Stateful */) === 64 /* Stateful */) {
|
|
140
|
+
demandChanges.has(c) ? demandChanges.delete(c) : demandChanges.add(c);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
let dummySource;
|
|
144
|
+
class Cell {
|
|
145
|
+
constructor() {
|
|
146
|
+
this.value = void 0;
|
|
147
|
+
// the value
|
|
148
|
+
this.validThrough = 0;
|
|
149
|
+
// timestamp of most recent validation or recalculation
|
|
150
|
+
this.lastChanged = 0;
|
|
151
|
+
// timestamp of last value change
|
|
152
|
+
this.latestSource = timestamp;
|
|
153
|
+
// max lastChanged of this cell or any ancestor source
|
|
154
|
+
this.flags = 0;
|
|
155
|
+
this.job = void 0;
|
|
156
|
+
/** The subscription being added during the current calculation - used for uniqueness */
|
|
157
|
+
this.adding = unset;
|
|
158
|
+
/** Linked list of sources */
|
|
159
|
+
this.sources = unset;
|
|
160
|
+
/** Linked list of targets */
|
|
161
|
+
this.subscribers = unset;
|
|
162
|
+
this.queue = void 0;
|
|
163
|
+
/**
|
|
164
|
+
* The computation to be performed (if {@link Is.Compute}) or the
|
|
165
|
+
* setup/teardown for {@link Is.Stateful}.
|
|
166
|
+
*/
|
|
167
|
+
this.compute = returnValue;
|
|
168
|
+
}
|
|
169
|
+
stream(sink, _conn, inlet) {
|
|
170
|
+
let lastValue = sentinel;
|
|
171
|
+
Cell.mkRule(() => {
|
|
172
|
+
const val = this.getValue();
|
|
173
|
+
if (val !== lastValue) {
|
|
174
|
+
pushCtx();
|
|
175
|
+
try {
|
|
176
|
+
sink(lastValue = val);
|
|
177
|
+
} finally {
|
|
178
|
+
popCtx();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}, inlet ? ruleQueue(backpressure(inlet)) : defaultQ);
|
|
182
|
+
return IsStream;
|
|
183
|
+
}
|
|
184
|
+
getValue() {
|
|
185
|
+
if (arguments.length)
|
|
186
|
+
return apply(this.stream, this, arguments);
|
|
187
|
+
const dep = currentCell;
|
|
188
|
+
if (dep && this.flags & 132 /* Variable */ && (dep.flags & 8 /* Peeking */) === 0) {
|
|
189
|
+
if (this.flags & 32 /* Running */)
|
|
190
|
+
throw new CircularDependency("Cached function dependency cycle");
|
|
191
|
+
let s = this.adding;
|
|
192
|
+
if (!s || s.tgt !== dep) {
|
|
193
|
+
mksub(this, dep);
|
|
194
|
+
s = this.adding;
|
|
195
|
+
} else {
|
|
196
|
+
if (s.ts === -1) {
|
|
197
|
+
s.ts = this.lastChanged;
|
|
198
|
+
if (s.nS) {
|
|
199
|
+
s.nS.pS = s.pS;
|
|
200
|
+
if (s.pS)
|
|
201
|
+
s.pS.nS = s.nS;
|
|
202
|
+
s.nS = unset;
|
|
203
|
+
s.pS = dep.sources;
|
|
204
|
+
dep.sources.nS = s;
|
|
205
|
+
dep.sources = s;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.catchUp();
|
|
210
|
+
if (this.adding === s)
|
|
211
|
+
s.ts = this.lastChanged;
|
|
212
|
+
} else
|
|
213
|
+
this.catchUp();
|
|
214
|
+
if (this.flags & 16 /* Error */)
|
|
215
|
+
throw this.value;
|
|
216
|
+
return this.value;
|
|
217
|
+
}
|
|
218
|
+
shouldWrite(changed) {
|
|
219
|
+
const cell = currentCell || currentRule;
|
|
220
|
+
if (cell) {
|
|
221
|
+
if (!cell.queue)
|
|
222
|
+
throw new WriteConflict("Side-effects not allowed outside rules");
|
|
223
|
+
if (this.adding && this.adding.tgt === cell)
|
|
224
|
+
throw new CircularDependency("Can't update direct dependency");
|
|
225
|
+
if (this.validThrough === timestamp || this.hasBeenRead())
|
|
226
|
+
throw new WriteConflict("Value already used");
|
|
227
|
+
} else if (changed) {
|
|
228
|
+
if (this.validThrough === timestamp || notCaughtUp.length) {
|
|
229
|
+
++timestamp;
|
|
230
|
+
notCaughtUp.length = 0;
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
this.lastChanged === timestamp || markDependentsDirty(this);
|
|
236
|
+
if (this.sources)
|
|
237
|
+
this.sources.ts = 0;
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
setValue(val, isErr) {
|
|
241
|
+
if (this.shouldWrite(val !== this.value || isErr !== !!(this.flags & 16 /* Error */))) {
|
|
242
|
+
this.value = val;
|
|
243
|
+
this.lastChanged = timestamp;
|
|
244
|
+
this.flags = isErr ? this.flags | 16 /* Error */ : this.flags & ~16 /* Error */;
|
|
245
|
+
}
|
|
246
|
+
this.compute = isErr ? throwValue : returnValue;
|
|
247
|
+
}
|
|
248
|
+
setCalc(compute) {
|
|
249
|
+
if (this.shouldWrite(compute !== this.compute)) {
|
|
250
|
+
this.flags |= 4 /* Compute */;
|
|
251
|
+
this.compute = compute;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
hasBeenRead() {
|
|
255
|
+
if (notCaughtUp.length) {
|
|
256
|
+
for (const cell of notCaughtUp)
|
|
257
|
+
cell.catchUp();
|
|
258
|
+
notCaughtUp.length = 0;
|
|
259
|
+
}
|
|
260
|
+
return this.validThrough === timestamp;
|
|
261
|
+
}
|
|
262
|
+
catchUp() {
|
|
263
|
+
const { validThrough } = this;
|
|
264
|
+
if (validThrough === timestamp)
|
|
265
|
+
return;
|
|
266
|
+
this.validThrough = timestamp;
|
|
267
|
+
if (!(this.flags & 4 /* Compute */)) {
|
|
268
|
+
if (this.flags & 256 /* Stream */ && !this.subscribers) {
|
|
269
|
+
this.lastChanged = timestamp;
|
|
270
|
+
staleStreams.add(this);
|
|
271
|
+
}
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (this.sources) {
|
|
275
|
+
for (let sub = this.sources; sub; sub = sub.nS) {
|
|
276
|
+
const s = sub.src;
|
|
277
|
+
if (sub.ts !== s.lastChanged)
|
|
278
|
+
return this.doRecalc();
|
|
279
|
+
if (s.subscribers && s.latestSource <= validThrough)
|
|
280
|
+
continue;
|
|
281
|
+
s.catchUp();
|
|
282
|
+
if (s.lastChanged > validThrough) {
|
|
283
|
+
return this.doRecalc();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
for (let sub = this.sources; sub; sub = sub.nS) {
|
|
287
|
+
if (sub.src.validThrough !== timestamp)
|
|
288
|
+
notCaughtUp.push(sub.src);
|
|
289
|
+
}
|
|
290
|
+
} else
|
|
291
|
+
return this.doRecalc();
|
|
292
|
+
}
|
|
293
|
+
doRecalc() {
|
|
294
|
+
pushCtx(void 0, this);
|
|
295
|
+
if (this.flags & 64 /* Stateful */) {
|
|
296
|
+
this.job?.restart();
|
|
297
|
+
}
|
|
298
|
+
for (let sub = this.sources; sub; sub = sub.nS) {
|
|
299
|
+
sub.ts = -1;
|
|
300
|
+
sub.old = sub.src.adding;
|
|
301
|
+
sub.src.adding = sub;
|
|
302
|
+
this.sources = sub;
|
|
303
|
+
}
|
|
304
|
+
this.flags |= 32 /* Running */;
|
|
305
|
+
try {
|
|
306
|
+
try {
|
|
307
|
+
const future = this.compute();
|
|
308
|
+
if (future !== this.value || !this.lastChanged || this.flags & 16 /* Error */) {
|
|
309
|
+
this.value = future;
|
|
310
|
+
this.lastChanged = timestamp;
|
|
311
|
+
}
|
|
312
|
+
this.flags &= ~16 /* Error */;
|
|
313
|
+
} catch (e) {
|
|
314
|
+
this.flags |= 16 /* Error */;
|
|
315
|
+
this.value = e;
|
|
316
|
+
this.lastChanged = timestamp;
|
|
317
|
+
if (currentRule === this)
|
|
318
|
+
throw e;
|
|
319
|
+
}
|
|
320
|
+
} finally {
|
|
321
|
+
this.flags &= ~32 /* Running */;
|
|
322
|
+
if (this.flags & 64 /* Stateful */) {
|
|
323
|
+
demandChanges.delete(this);
|
|
324
|
+
if (this.flags & (16 /* Error */ | 2 /* Stopped */)) {
|
|
325
|
+
this.flags &= ~2 /* Stopped */;
|
|
326
|
+
this.job?.restart();
|
|
327
|
+
} else if (this.flags & 1 /* Observed */) ; else {
|
|
328
|
+
this.job?.restart();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
popCtx();
|
|
332
|
+
let head = unset;
|
|
333
|
+
for (let sub = this.sources; sub; ) {
|
|
334
|
+
const pS = sub.pS;
|
|
335
|
+
sub.src.adding = sub.old;
|
|
336
|
+
sub.old = unset;
|
|
337
|
+
if (sub.ts === -1)
|
|
338
|
+
delsub(sub);
|
|
339
|
+
else
|
|
340
|
+
head = sub;
|
|
341
|
+
sub = pS;
|
|
342
|
+
}
|
|
343
|
+
(this.sources = head) || this.becomeConstant();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
becomeConstant() {
|
|
347
|
+
if (this.flags & 32 /* Running */)
|
|
348
|
+
return;
|
|
349
|
+
if (this.flags & 64 /* Stateful */) {
|
|
350
|
+
mksub(dummySource ||= Cell.mkValue(null), this);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
this.flags &= ~4 /* Compute */;
|
|
354
|
+
if (this.flags & 132 /* Variable */)
|
|
355
|
+
return;
|
|
356
|
+
while (this.adding)
|
|
357
|
+
removeConstListener(this.adding);
|
|
358
|
+
for (let sub = this.subscribers; sub; ) {
|
|
359
|
+
const { nT } = sub;
|
|
360
|
+
sub.ts !== this.lastChanged || removeConstListener(sub);
|
|
361
|
+
sub = nT;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
stop() {
|
|
365
|
+
this.setQ();
|
|
366
|
+
if (this.flags & 32 /* Running */) {
|
|
367
|
+
this.flags |= 2 /* Stopped */;
|
|
368
|
+
} else
|
|
369
|
+
this.updateDemand();
|
|
370
|
+
ruleStops.get(this)?.();
|
|
371
|
+
}
|
|
372
|
+
setQ(queue) {
|
|
373
|
+
if (queue == this.queue)
|
|
374
|
+
return;
|
|
375
|
+
if (!this.subscribers) {
|
|
376
|
+
queue || !this.queue || unsubscribeAll(this);
|
|
377
|
+
}
|
|
378
|
+
if (this.queue) {
|
|
379
|
+
if (this.queue.has(this))
|
|
380
|
+
queue?.add(this);
|
|
381
|
+
this.queue.delete(this);
|
|
382
|
+
} else if (queue) {
|
|
383
|
+
queue.add(this);
|
|
384
|
+
this.subscribers || subscribeAll(this);
|
|
385
|
+
}
|
|
386
|
+
this.queue = queue;
|
|
387
|
+
}
|
|
388
|
+
subscribe(sub) {
|
|
389
|
+
if (!this.subscribers && !this.queue) {
|
|
390
|
+
subscribeAll(this);
|
|
391
|
+
}
|
|
392
|
+
if (this.subscribers !== sub && !sub.pT) {
|
|
393
|
+
sub.nT = this.subscribers;
|
|
394
|
+
if (this.subscribers)
|
|
395
|
+
this.subscribers.pT = sub;
|
|
396
|
+
this.subscribers = sub;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
unsubscribe(sub) {
|
|
400
|
+
if (sub.nT)
|
|
401
|
+
sub.nT.pT = sub.pT;
|
|
402
|
+
if (sub.pT)
|
|
403
|
+
sub.pT.nT = sub.nT;
|
|
404
|
+
if (this.subscribers === sub)
|
|
405
|
+
this.subscribers = sub.nT;
|
|
406
|
+
sub.nT = sub.pT = unset;
|
|
407
|
+
if (!this.subscribers && !this.queue) {
|
|
408
|
+
unsubscribeAll(this);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
static mkValue(val) {
|
|
412
|
+
const cell = new Cell();
|
|
413
|
+
cell.flags = 128 /* Mutable */;
|
|
414
|
+
cell.value = val;
|
|
415
|
+
cell.lastChanged = timestamp;
|
|
416
|
+
return cell;
|
|
417
|
+
}
|
|
418
|
+
isObserved() {
|
|
419
|
+
if (this.flags & 8 /* Peeking */)
|
|
420
|
+
return false;
|
|
421
|
+
return !!((this.flags |= 64 /* Stateful */) & 1 /* Observed */);
|
|
422
|
+
}
|
|
423
|
+
getJob() {
|
|
424
|
+
if (!this.isObserved())
|
|
425
|
+
throw new Error("Job API used in unobserved signal or peek()");
|
|
426
|
+
if (this.job)
|
|
427
|
+
return this.job;
|
|
428
|
+
this.flags |= 64 /* Stateful */;
|
|
429
|
+
return this.job = new _Job();
|
|
430
|
+
}
|
|
431
|
+
updateDemand() {
|
|
432
|
+
demandChanges.delete(this);
|
|
433
|
+
if (monitors.has(this)) {
|
|
434
|
+
monitors.get(this)();
|
|
435
|
+
} else if (this.flags & 1 /* Observed */) {
|
|
436
|
+
this.shouldWrite(true);
|
|
437
|
+
} else {
|
|
438
|
+
this.job?.restart();
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
static mkStream(src, val) {
|
|
442
|
+
const cell = this.mkValue(val);
|
|
443
|
+
cell.flags |= 64 /* Stateful */ | 256 /* Stream */;
|
|
444
|
+
const write = (v) => {
|
|
445
|
+
cell.setValue(v, false);
|
|
446
|
+
};
|
|
447
|
+
let job;
|
|
448
|
+
monitors.set(cell, () => {
|
|
449
|
+
if (!cell.subscribers) {
|
|
450
|
+
write(val);
|
|
451
|
+
job?.end();
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (job)
|
|
455
|
+
return;
|
|
456
|
+
job = new _Job(root).do((r) => {
|
|
457
|
+
if (isError(r)) {
|
|
458
|
+
cell.setValue(markHandled(r), true);
|
|
459
|
+
} else {
|
|
460
|
+
cell.setValue(val, false);
|
|
461
|
+
}
|
|
462
|
+
job = unset;
|
|
463
|
+
});
|
|
464
|
+
pushCtx(job);
|
|
465
|
+
try {
|
|
466
|
+
src(write, job);
|
|
467
|
+
} catch (e) {
|
|
468
|
+
job.end();
|
|
469
|
+
root.asyncThrow(e);
|
|
470
|
+
} finally {
|
|
471
|
+
popCtx();
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
return cell;
|
|
475
|
+
}
|
|
476
|
+
peek(fn, thisArg, args) {
|
|
477
|
+
if (this.flags & 8 /* Peeking */)
|
|
478
|
+
return apply(fn, thisArg, args);
|
|
479
|
+
this.flags |= 8 /* Peeking */;
|
|
480
|
+
try {
|
|
481
|
+
return apply(fn, thisArg, args);
|
|
482
|
+
} finally {
|
|
483
|
+
this.flags &= ~8 /* Peeking */;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
unchangedIf(newVal, equals) {
|
|
487
|
+
return this.flags & 16 /* Error */ || !equals(this.value, newVal) ? newVal : this.value;
|
|
488
|
+
}
|
|
489
|
+
recalcWhen(fnOrKey, fn = unset) {
|
|
490
|
+
if (this.flags & 8 /* Peeking */)
|
|
491
|
+
return;
|
|
492
|
+
let trackers = fn ? obtrackers.get(fn) || setMap(obtrackers, fn, /* @__PURE__ */ new WeakMap()) : fntrackers;
|
|
493
|
+
let signal = trackers.get(fnOrKey);
|
|
494
|
+
if (!signal) {
|
|
495
|
+
const src = fn ? fn(fnOrKey) : fnOrKey;
|
|
496
|
+
let ct = 0;
|
|
497
|
+
const c = Cell.mkStream((s) => (src(() => s(++ct)), IsStream), ct);
|
|
498
|
+
trackers.set(fnOrKey, signal = c.getValue.bind(c));
|
|
499
|
+
}
|
|
500
|
+
signal();
|
|
501
|
+
}
|
|
502
|
+
static mkCached(compute) {
|
|
503
|
+
const cell = new Cell();
|
|
504
|
+
cell.compute = compute;
|
|
505
|
+
cell.flags = 4 /* Compute */;
|
|
506
|
+
return cell;
|
|
507
|
+
}
|
|
508
|
+
static mkRule(fn, q) {
|
|
509
|
+
const outer = getJob(), cell = Cell.mkCached(() => {
|
|
510
|
+
try {
|
|
511
|
+
const cleanup = fn();
|
|
512
|
+
if (cleanup)
|
|
513
|
+
(cell.job || cell.getJob()).must(cleanup);
|
|
514
|
+
} catch (e) {
|
|
515
|
+
cell.stop();
|
|
516
|
+
throw e;
|
|
517
|
+
}
|
|
518
|
+
}), stop = cell.stop.bind(cell);
|
|
519
|
+
ruleStops.set(cell, outer.release(stop));
|
|
520
|
+
cell.flags |= 64 /* Stateful */;
|
|
521
|
+
cell.setQ(q);
|
|
522
|
+
return stop;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function getCell(f = "") {
|
|
526
|
+
if (!currentCell || currentCell.flags & 8 /* Peeking */)
|
|
527
|
+
throw new Error(
|
|
528
|
+
`${f}must be called from a reactive expression`
|
|
529
|
+
);
|
|
530
|
+
return currentCell;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const allHooks = /* @__PURE__ */ new WeakMap();
|
|
534
|
+
function indexOf(hooks, site) {
|
|
535
|
+
if (hooks[0 /* CURRENT */] === site)
|
|
536
|
+
return hooks[1 /* OFFSET */];
|
|
537
|
+
let pos = hooks.indexOf(site, hooks[1 /* OFFSET */]);
|
|
538
|
+
if (pos < 0 && hooks[1 /* OFFSET */] > 2 /* FIRST */)
|
|
539
|
+
pos = hooks.indexOf(site, 2 /* FIRST */);
|
|
540
|
+
hooks[0 /* CURRENT */] = site;
|
|
541
|
+
return hooks[1 /* OFFSET */] = pos < 0 ? hooks.length : pos;
|
|
542
|
+
}
|
|
543
|
+
function getHooks(ctx = currentCell || getCell("hook-using functions ")) {
|
|
544
|
+
return allHooks.get(ctx) || setMap(allHooks, ctx, [null, 2 /* FIRST */]);
|
|
545
|
+
}
|
|
546
|
+
function findOrCreateMemos(hooks, site, size = 0) {
|
|
547
|
+
if (indexOf(hooks, site) < hooks.length)
|
|
548
|
+
return true;
|
|
549
|
+
if (size) {
|
|
550
|
+
hooks.push(site);
|
|
551
|
+
hooks.length += size;
|
|
552
|
+
}
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
function getMemo(hooks, offset) {
|
|
556
|
+
return hooks[hooks[1 /* OFFSET */] + offset];
|
|
557
|
+
}
|
|
558
|
+
function setMemo(hooks, offset, val) {
|
|
559
|
+
return hooks[hooks[1 /* OFFSET */] + offset] = val;
|
|
560
|
+
}
|
|
561
|
+
function perSignal(func, site, name) {
|
|
562
|
+
const hooks = getHooks(currentCell || getCell(name));
|
|
563
|
+
return findOrCreateMemos(hooks, site) ? (
|
|
564
|
+
// Fast path - return a no-op function with the constant result
|
|
565
|
+
// (avoids any dynamic memory allocation)
|
|
566
|
+
getMemo(hooks, 1)
|
|
567
|
+
) : (
|
|
568
|
+
// Slow path - needs to receive args to call the function,
|
|
569
|
+
// and then save the closure for future fast path calls
|
|
570
|
+
(...args) => {
|
|
571
|
+
const hooks2 = getHooks(currentCell || getCell(name));
|
|
572
|
+
if (findOrCreateMemos(hooks2, site, 1)) {
|
|
573
|
+
return getMemo(hooks2, 1)();
|
|
574
|
+
} else {
|
|
575
|
+
const result = func(...args);
|
|
576
|
+
setMemo(hooks2, 1, () => result);
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export { Cell as C, WriteConflict as W, CircularDependency as a, currentRule as c, defaultQ as d, getCell as g, perSignal as p, ruleQueue as r };
|