@ersbeth/picoflow 2.2.0 → 2.3.1
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 +23 -1
- package/SKILL.md +5 -0
- package/dist/picoflow.js +252 -132
- package/dist/types/api/base/flowConfig.d.ts +0 -1
- package/dist/types/api/base/flowDisposable.d.ts +0 -1
- package/dist/types/api/base/flowErrors.d.ts +1 -0
- package/dist/types/api/base/flowObservable.d.ts +0 -1
- package/dist/types/api/base/flowPrimitiveOptions.d.ts +14 -0
- package/dist/types/api/base/flowSubscribable.d.ts +0 -1
- package/dist/types/api/base/flowTracker.d.ts +0 -1
- package/dist/types/api/base/index.d.ts +2 -1
- package/dist/types/api/index.d.ts +0 -1
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts +4 -3
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts +3 -3
- package/dist/types/api/nodes/async/flowStateAsync.d.ts +4 -3
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts +3 -2
- package/dist/types/api/nodes/async/index.d.ts +0 -1
- package/dist/types/api/nodes/collections/flowArray.d.ts +3 -2
- package/dist/types/api/nodes/collections/flowMap.d.ts +3 -2
- package/dist/types/api/nodes/collections/index.d.ts +0 -1
- package/dist/types/api/nodes/flowEffect.d.ts +0 -1
- package/dist/types/api/nodes/flowSignal.d.ts +3 -2
- package/dist/types/api/nodes/flowValue.d.ts +0 -1
- package/dist/types/api/nodes/index.d.ts +0 -1
- package/dist/types/api/nodes/sync/flowConstant.d.ts +3 -2
- package/dist/types/api/nodes/sync/flowDerivation.d.ts +3 -2
- package/dist/types/api/nodes/sync/flowState.d.ts +4 -3
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts +3 -2
- package/dist/types/api/nodes/sync/index.d.ts +0 -1
- package/dist/types/api/nodes/utils.d.ts +0 -1
- package/dist/types/base/dependenciesRegistry.d.ts +1 -0
- package/dist/types/base/dependentsRegistry.d.ts +1 -0
- package/dist/types/base/disposable.d.ts +5 -1
- package/dist/types/base/errors.d.ts +31 -0
- package/dist/types/base/executionStack.d.ts +3 -11
- package/dist/types/base/index.d.ts +3 -1
- package/dist/types/base/node.d.ts +2 -3
- package/dist/types/base/observable.d.ts +1 -2
- package/dist/types/base/observer.d.ts +1 -2
- package/dist/types/converters/index.d.ts +0 -1
- package/dist/types/converters/solid.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/nodes/actionNode.d.ts +1 -23
- package/dist/types/nodes/arrayNode.d.ts +1 -26
- package/dist/types/nodes/effectNode.d.ts +1 -32
- package/dist/types/nodes/index.d.ts +0 -1
- package/dist/types/nodes/mapNode.d.ts +1 -20
- package/dist/types/nodes/signalNode.d.ts +1 -10
- package/dist/types/nodes/valueAsyncNode.d.ts +1 -23
- package/dist/types/nodes/valueNode.d.ts +1 -27
- package/dist/types/nodes/valueSyncNode.d.ts +1 -23
- package/dist/types/schedulers/asyncResolver.d.ts +1 -19
- package/dist/types/schedulers/asyncScheduler.d.ts +1 -21
- package/dist/types/schedulers/index.d.ts +0 -1
- package/dist/types/schedulers/pendingError.d.ts +1 -9
- package/dist/types/schedulers/scheduler.d.ts +1 -10
- package/dist/types/schedulers/syncResolver.d.ts +1 -18
- package/dist/types/schedulers/syncScheduler.d.ts +1 -19
- package/package.json +11 -23
- package/dist/types/api/base/flowConfig.d.ts.map +0 -1
- package/dist/types/api/base/flowDisposable.d.ts.map +0 -1
- package/dist/types/api/base/flowObservable.d.ts.map +0 -1
- package/dist/types/api/base/flowSubscribable.d.ts.map +0 -1
- package/dist/types/api/base/flowTracker.d.ts.map +0 -1
- package/dist/types/api/base/index.d.ts.map +0 -1
- package/dist/types/api/index.d.ts.map +0 -1
- package/dist/types/api/nodes/async/flowConstantAsync.d.ts.map +0 -1
- package/dist/types/api/nodes/async/flowDerivationAsync.d.ts.map +0 -1
- package/dist/types/api/nodes/async/flowStateAsync.d.ts.map +0 -1
- package/dist/types/api/nodes/async/flowWritableDerivationAsync.d.ts.map +0 -1
- package/dist/types/api/nodes/async/index.d.ts.map +0 -1
- package/dist/types/api/nodes/collections/flowArray.d.ts.map +0 -1
- package/dist/types/api/nodes/collections/flowMap.d.ts.map +0 -1
- package/dist/types/api/nodes/collections/index.d.ts.map +0 -1
- package/dist/types/api/nodes/flowEffect.d.ts.map +0 -1
- package/dist/types/api/nodes/flowSignal.d.ts.map +0 -1
- package/dist/types/api/nodes/flowValue.d.ts.map +0 -1
- package/dist/types/api/nodes/index.d.ts.map +0 -1
- package/dist/types/api/nodes/sync/flowConstant.d.ts.map +0 -1
- package/dist/types/api/nodes/sync/flowDerivation.d.ts.map +0 -1
- package/dist/types/api/nodes/sync/flowState.d.ts.map +0 -1
- package/dist/types/api/nodes/sync/flowWritableDerivation.d.ts.map +0 -1
- package/dist/types/api/nodes/sync/index.d.ts.map +0 -1
- package/dist/types/api/nodes/utils.d.ts.map +0 -1
- package/dist/types/base/disposable.d.ts.map +0 -1
- package/dist/types/base/executionStack.d.ts.map +0 -1
- package/dist/types/base/index.d.ts.map +0 -1
- package/dist/types/base/node.d.ts.map +0 -1
- package/dist/types/base/observable.d.ts.map +0 -1
- package/dist/types/base/observer.d.ts.map +0 -1
- package/dist/types/converters/index.d.ts.map +0 -1
- package/dist/types/converters/solid.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/nodes/actionNode.d.ts.map +0 -1
- package/dist/types/nodes/arrayNode.d.ts.map +0 -1
- package/dist/types/nodes/effectNode.d.ts.map +0 -1
- package/dist/types/nodes/index.d.ts.map +0 -1
- package/dist/types/nodes/mapNode.d.ts.map +0 -1
- package/dist/types/nodes/signalNode.d.ts.map +0 -1
- package/dist/types/nodes/valueAsyncNode.d.ts.map +0 -1
- package/dist/types/nodes/valueNode.d.ts.map +0 -1
- package/dist/types/nodes/valueSyncNode.d.ts.map +0 -1
- package/dist/types/schedulers/asyncResolver.d.ts.map +0 -1
- package/dist/types/schedulers/asyncScheduler.d.ts.map +0 -1
- package/dist/types/schedulers/index.d.ts.map +0 -1
- package/dist/types/schedulers/pendingError.d.ts.map +0 -1
- package/dist/types/schedulers/scheduler.d.ts.map +0 -1
- package/dist/types/schedulers/syncResolver.d.ts.map +0 -1
- package/dist/types/schedulers/syncScheduler.d.ts.map +0 -1
package/dist/picoflow.js
CHANGED
|
@@ -1,10 +1,84 @@
|
|
|
1
1
|
import { createResource, onMount, createEffect, resetErrorBoundaries, onCleanup } from 'solid-js';
|
|
2
2
|
|
|
3
|
+
class DependenciesRegistry {
|
|
4
|
+
_dependencies = /* @__PURE__ */ new Set();
|
|
5
|
+
register(dependency, dependent) {
|
|
6
|
+
this._dependencies.add(dependency);
|
|
7
|
+
dependency.registerDependent(dependent);
|
|
8
|
+
}
|
|
9
|
+
unregister(dependency, dependent) {
|
|
10
|
+
this._dependencies.delete(dependency);
|
|
11
|
+
dependency.unregisterDependent(dependent);
|
|
12
|
+
}
|
|
13
|
+
clear(dependent) {
|
|
14
|
+
this._dependencies.forEach((dependency) => {
|
|
15
|
+
dependency.unregisterDependent(dependent);
|
|
16
|
+
});
|
|
17
|
+
this._dependencies.clear();
|
|
18
|
+
}
|
|
19
|
+
forEach(fn) {
|
|
20
|
+
Array.from(this._dependencies).forEach(fn);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class DependentsRegistry {
|
|
25
|
+
_dependents = /* @__PURE__ */ new Set();
|
|
26
|
+
register(dependent) {
|
|
27
|
+
this._dependents.add(dependent);
|
|
28
|
+
}
|
|
29
|
+
unregister(dependent) {
|
|
30
|
+
this._dependents.delete(dependent);
|
|
31
|
+
}
|
|
32
|
+
notifyAll() {
|
|
33
|
+
this._dependents.forEach((dependent) => {
|
|
34
|
+
dependent.notify();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
forEach(fn) {
|
|
38
|
+
Array.from(this._dependents).forEach(fn);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class PicoFlowError extends Error {
|
|
43
|
+
constructor(message) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "PicoFlowError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class PicoFlowDisposedError extends PicoFlowError {
|
|
49
|
+
constructor(message) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = "PicoFlowDisposedError";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
class PicoFlowCycleError extends PicoFlowError {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "PicoFlowCycleError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
class PicoFlowInternalError extends PicoFlowError {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = "PicoFlowInternalError";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
3
67
|
class Disposable {
|
|
4
68
|
_disposed = false;
|
|
69
|
+
_name;
|
|
70
|
+
constructor(name) {
|
|
71
|
+
this._name = name;
|
|
72
|
+
}
|
|
5
73
|
get disposed() {
|
|
6
74
|
return this._disposed;
|
|
7
75
|
}
|
|
76
|
+
/** Builds the disposed-primitive error, naming the primitive when a `name` was given at creation. */
|
|
77
|
+
_disposedError() {
|
|
78
|
+
return new PicoFlowDisposedError(
|
|
79
|
+
this._name ? `[PicoFlow] Primitive "${this._name}" is disposed` : "[PicoFlow] Primitive is disposed"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
8
82
|
}
|
|
9
83
|
|
|
10
84
|
class ExecutionStack {
|
|
@@ -13,6 +87,9 @@ class ExecutionStack {
|
|
|
13
87
|
static _effectQueue = [];
|
|
14
88
|
static _executionScheduled;
|
|
15
89
|
static _coalesceResetScheduled = false;
|
|
90
|
+
/** Per-effect resets accumulated for the microtask scheduled below, so notifying more than one
|
|
91
|
+
* effect in the same sync turn doesn't discard every reset after the first (A2-SEM-5). */
|
|
92
|
+
static _coalesceResets = /* @__PURE__ */ new Set();
|
|
16
93
|
/** Routes any error escaping the flush loop; defaults to logging rather than crashing (A2-SEM-2, A2-SEC-1). */
|
|
17
94
|
static _onFlushError = (error) => console.error(error);
|
|
18
95
|
/**
|
|
@@ -31,12 +108,17 @@ class ExecutionStack {
|
|
|
31
108
|
* and resets per-effect coalesce flags via onReset.
|
|
32
109
|
*/
|
|
33
110
|
static scheduleCoalesceReset(onReset) {
|
|
111
|
+
ExecutionStack._coalesceResets.add(onReset);
|
|
34
112
|
if (ExecutionStack._coalesceResetScheduled) return;
|
|
35
113
|
ExecutionStack._coalesceResetScheduled = true;
|
|
36
114
|
queueMicrotask(() => {
|
|
37
115
|
ExecutionStack._pastSyncTurn = true;
|
|
38
116
|
ExecutionStack._coalesceResetScheduled = false;
|
|
39
|
-
|
|
117
|
+
const resets = ExecutionStack._coalesceResets;
|
|
118
|
+
ExecutionStack._coalesceResets = /* @__PURE__ */ new Set();
|
|
119
|
+
resets.forEach((reset) => {
|
|
120
|
+
reset();
|
|
121
|
+
});
|
|
40
122
|
});
|
|
41
123
|
}
|
|
42
124
|
/** @internal Wired to the public `onFlushError()` API in `src/api/base/flowConfig.ts`. */
|
|
@@ -71,7 +153,9 @@ class ExecutionStack {
|
|
|
71
153
|
if (i >= ExecutionStack._MAX_FLUSH_STEPS) {
|
|
72
154
|
ExecutionStack._pendingQueue.length = 0;
|
|
73
155
|
ExecutionStack._effectQueue.length = 0;
|
|
74
|
-
ExecutionStack._onFlushError(
|
|
156
|
+
ExecutionStack._onFlushError(
|
|
157
|
+
new PicoFlowCycleError("[PicoFlow] Reactive update cycle exceeded maximum depth")
|
|
158
|
+
);
|
|
75
159
|
return;
|
|
76
160
|
}
|
|
77
161
|
const node = queue[i];
|
|
@@ -90,66 +174,59 @@ class ExecutionStack {
|
|
|
90
174
|
}
|
|
91
175
|
|
|
92
176
|
class Node extends Disposable {
|
|
93
|
-
|
|
94
|
-
|
|
177
|
+
_dependenciesRegistry = new DependenciesRegistry();
|
|
178
|
+
_dependentsRegistry = new DependentsRegistry();
|
|
95
179
|
_status = "resolved";
|
|
96
180
|
get status() {
|
|
97
|
-
if (this.disposed) throw
|
|
181
|
+
if (this.disposed) throw this._disposedError();
|
|
98
182
|
return this._status;
|
|
99
183
|
}
|
|
100
184
|
set status(status) {
|
|
101
|
-
if (this.disposed) throw
|
|
185
|
+
if (this.disposed) throw this._disposedError();
|
|
102
186
|
this._status = status;
|
|
103
187
|
}
|
|
104
188
|
registerDependency(dependency) {
|
|
105
|
-
if (this._disposed) throw
|
|
106
|
-
this.
|
|
107
|
-
dependency.registerDependent(this);
|
|
189
|
+
if (this._disposed) throw this._disposedError();
|
|
190
|
+
this._dependenciesRegistry.register(dependency, this);
|
|
108
191
|
}
|
|
109
192
|
unregisterDependency(dependency) {
|
|
110
|
-
if (this._disposed) throw
|
|
111
|
-
this.
|
|
112
|
-
dependency.unregisterDependent(this);
|
|
193
|
+
if (this._disposed) throw this._disposedError();
|
|
194
|
+
this._dependenciesRegistry.unregister(dependency, this);
|
|
113
195
|
}
|
|
114
196
|
clearDependencies() {
|
|
115
|
-
if (this.disposed) throw
|
|
116
|
-
this.
|
|
117
|
-
dependency.unregisterDependent(this);
|
|
118
|
-
});
|
|
119
|
-
this._dependencies.clear();
|
|
197
|
+
if (this.disposed) throw this._disposedError();
|
|
198
|
+
this._dependenciesRegistry.clear(this);
|
|
120
199
|
}
|
|
121
200
|
registerDependent(dependent) {
|
|
122
|
-
if (this.disposed) throw
|
|
123
|
-
this.
|
|
201
|
+
if (this.disposed) throw this._disposedError();
|
|
202
|
+
this._dependentsRegistry.register(dependent);
|
|
124
203
|
}
|
|
125
204
|
unregisterDependent(dependent) {
|
|
126
|
-
if (this.disposed) throw
|
|
127
|
-
this.
|
|
205
|
+
if (this.disposed) throw this._disposedError();
|
|
206
|
+
this._dependentsRegistry.unregister(dependent);
|
|
128
207
|
}
|
|
129
208
|
markDependencyDisposed() {
|
|
130
209
|
}
|
|
131
210
|
notifyDependents() {
|
|
132
211
|
if (this.disposed) return;
|
|
133
|
-
this.
|
|
134
|
-
dependent.notify();
|
|
135
|
-
});
|
|
212
|
+
this._dependentsRegistry.notifyAll();
|
|
136
213
|
}
|
|
137
214
|
watch(tracker) {
|
|
138
|
-
if (this.disposed) throw
|
|
215
|
+
if (this.disposed) throw this._disposedError();
|
|
139
216
|
tracker.registerDependency(this);
|
|
140
217
|
}
|
|
141
218
|
trigger() {
|
|
142
|
-
if (this.disposed) throw
|
|
219
|
+
if (this.disposed) throw this._disposedError();
|
|
143
220
|
this.notifyDependents();
|
|
144
221
|
}
|
|
145
222
|
dispose() {
|
|
146
223
|
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
147
|
-
|
|
224
|
+
this._dependentsRegistry.forEach((dependant) => {
|
|
148
225
|
dependant.markDependencyDisposed();
|
|
149
226
|
dependant.unregisterDependency(this);
|
|
150
227
|
this.unregisterDependent(dependant);
|
|
151
228
|
});
|
|
152
|
-
|
|
229
|
+
this._dependenciesRegistry.forEach((dependency) => {
|
|
153
230
|
this.unregisterDependency(dependency);
|
|
154
231
|
});
|
|
155
232
|
this._disposed = true;
|
|
@@ -157,41 +234,39 @@ class Node extends Disposable {
|
|
|
157
234
|
}
|
|
158
235
|
|
|
159
236
|
class Observable extends Disposable {
|
|
160
|
-
|
|
237
|
+
_dependentsRegistry = new DependentsRegistry();
|
|
161
238
|
_status = "resolved";
|
|
162
239
|
get status() {
|
|
163
|
-
if (this.disposed) throw
|
|
240
|
+
if (this.disposed) throw this._disposedError();
|
|
164
241
|
return this._status;
|
|
165
242
|
}
|
|
166
243
|
set status(status) {
|
|
167
|
-
if (this.disposed) throw
|
|
244
|
+
if (this.disposed) throw this._disposedError();
|
|
168
245
|
this._status = status;
|
|
169
246
|
}
|
|
170
247
|
registerDependent(dependent) {
|
|
171
|
-
if (this.disposed) throw
|
|
172
|
-
this.
|
|
248
|
+
if (this.disposed) throw this._disposedError();
|
|
249
|
+
this._dependentsRegistry.register(dependent);
|
|
173
250
|
}
|
|
174
251
|
unregisterDependent(dependent) {
|
|
175
|
-
if (this.disposed) throw
|
|
176
|
-
this.
|
|
252
|
+
if (this.disposed) throw this._disposedError();
|
|
253
|
+
this._dependentsRegistry.unregister(dependent);
|
|
177
254
|
}
|
|
178
255
|
notifyDependents() {
|
|
179
256
|
if (this.disposed) return;
|
|
180
|
-
this.
|
|
181
|
-
dependent.notify();
|
|
182
|
-
});
|
|
257
|
+
this._dependentsRegistry.notifyAll();
|
|
183
258
|
}
|
|
184
259
|
watch(tracker) {
|
|
185
|
-
if (this.disposed) throw
|
|
260
|
+
if (this.disposed) throw this._disposedError();
|
|
186
261
|
tracker.registerDependency(this);
|
|
187
262
|
}
|
|
188
263
|
trigger() {
|
|
189
|
-
if (this.disposed) throw
|
|
264
|
+
if (this.disposed) throw this._disposedError();
|
|
190
265
|
this.notifyDependents();
|
|
191
266
|
}
|
|
192
267
|
dispose() {
|
|
193
|
-
if (this._disposed) throw
|
|
194
|
-
|
|
268
|
+
if (this._disposed) throw this._disposedError();
|
|
269
|
+
this._dependentsRegistry.forEach((dependant) => {
|
|
195
270
|
dependant.markDependencyDisposed();
|
|
196
271
|
dependant.unregisterDependency(this);
|
|
197
272
|
this.unregisterDependent(dependant);
|
|
@@ -201,34 +276,27 @@ class Observable extends Disposable {
|
|
|
201
276
|
}
|
|
202
277
|
|
|
203
278
|
class Observer extends Disposable {
|
|
204
|
-
|
|
279
|
+
_dependenciesRegistry = new DependenciesRegistry();
|
|
205
280
|
/** Set when a dependency disposed while this observer was queued; consumed by the next execute(). */
|
|
206
281
|
_dependencyDisposed = false;
|
|
207
282
|
markDependencyDisposed() {
|
|
208
283
|
this._dependencyDisposed = true;
|
|
209
284
|
}
|
|
210
285
|
registerDependency(dependency) {
|
|
211
|
-
if (this._disposed) throw
|
|
212
|
-
this.
|
|
213
|
-
dependency.registerDependent(this);
|
|
286
|
+
if (this._disposed) throw this._disposedError();
|
|
287
|
+
this._dependenciesRegistry.register(dependency, this);
|
|
214
288
|
}
|
|
215
289
|
unregisterDependency(dependency) {
|
|
216
|
-
if (this._disposed) throw
|
|
217
|
-
this.
|
|
218
|
-
dependency.unregisterDependent(this);
|
|
290
|
+
if (this._disposed) throw this._disposedError();
|
|
291
|
+
this._dependenciesRegistry.unregister(dependency, this);
|
|
219
292
|
}
|
|
220
293
|
clearDependencies() {
|
|
221
294
|
if (this.disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
222
|
-
this.
|
|
223
|
-
dependency.unregisterDependent(this);
|
|
224
|
-
});
|
|
225
|
-
this._dependencies.clear();
|
|
295
|
+
this._dependenciesRegistry.clear(this);
|
|
226
296
|
}
|
|
227
297
|
dispose() {
|
|
228
|
-
if (this._disposed) throw
|
|
229
|
-
|
|
230
|
-
this.unregisterDependency(dependency);
|
|
231
|
-
});
|
|
298
|
+
if (this._disposed) throw this._disposedError();
|
|
299
|
+
this._dependenciesRegistry.clear(this);
|
|
232
300
|
this._disposed = true;
|
|
233
301
|
}
|
|
234
302
|
}
|
|
@@ -301,7 +369,6 @@ class AsyncResolver {
|
|
|
301
369
|
});
|
|
302
370
|
}
|
|
303
371
|
abort() {
|
|
304
|
-
this._iteration++;
|
|
305
372
|
this._aborted = true;
|
|
306
373
|
}
|
|
307
374
|
}
|
|
@@ -321,14 +388,14 @@ class AsyncScheduler {
|
|
|
321
388
|
this._attachHandlers(this._resolver);
|
|
322
389
|
}
|
|
323
390
|
get settled() {
|
|
324
|
-
if (this._disposed) throw new
|
|
391
|
+
if (this._disposed) throw new PicoFlowDisposedError("[PicoFlow] ComputationScheduler is disposed");
|
|
325
392
|
return this._settled.promise;
|
|
326
393
|
}
|
|
327
394
|
get disposed() {
|
|
328
395
|
return this._disposed;
|
|
329
396
|
}
|
|
330
397
|
overwrite(promise) {
|
|
331
|
-
if (this._disposed) throw new
|
|
398
|
+
if (this._disposed) throw new PicoFlowDisposedError("[PicoFlow] ComputationScheduler is disposed");
|
|
332
399
|
if (this._resolver.finished) {
|
|
333
400
|
this._resolver = new AsyncResolver(this._compute);
|
|
334
401
|
this._settled = Promise.withResolvers();
|
|
@@ -337,7 +404,7 @@ class AsyncScheduler {
|
|
|
337
404
|
this._resolver.overwrite(promise);
|
|
338
405
|
}
|
|
339
406
|
compute() {
|
|
340
|
-
if (this._disposed) throw new
|
|
407
|
+
if (this._disposed) throw new PicoFlowDisposedError("[PicoFlow] ComputationScheduler is disposed");
|
|
341
408
|
if (this._resolver.finished) {
|
|
342
409
|
this._resolver = new AsyncResolver(this._compute);
|
|
343
410
|
this._settled = Promise.withResolvers();
|
|
@@ -429,7 +496,7 @@ class SyncScheduler {
|
|
|
429
496
|
return this._settled.promise;
|
|
430
497
|
}
|
|
431
498
|
overwrite(value) {
|
|
432
|
-
if (this._disposed) throw new
|
|
499
|
+
if (this._disposed) throw new PicoFlowDisposedError("[PicoFlow] ComputationScheduler is disposed");
|
|
433
500
|
if (this._resolver.finished) {
|
|
434
501
|
this._settled = Promise.withResolvers();
|
|
435
502
|
this._resolver = new SyncResolver(this._compute, this._onResolve, this._onReject);
|
|
@@ -437,7 +504,7 @@ class SyncScheduler {
|
|
|
437
504
|
this._resolver.overwrite(value);
|
|
438
505
|
}
|
|
439
506
|
compute() {
|
|
440
|
-
if (this._disposed) throw new
|
|
507
|
+
if (this._disposed) throw new PicoFlowDisposedError("[PicoFlow] ComputationScheduler is disposed");
|
|
441
508
|
if (this._resolver.finished) {
|
|
442
509
|
this._settled = Promise.withResolvers();
|
|
443
510
|
this._resolver = new SyncResolver(this._compute, this._onResolve, this._onReject);
|
|
@@ -463,6 +530,8 @@ class EffectNode extends Observer {
|
|
|
463
530
|
_notifyEpoch = 0;
|
|
464
531
|
/** How many notification epochs have been executed so far. */
|
|
465
532
|
_executedEpoch = 0;
|
|
533
|
+
/** Callbacks registered via {@link onDispose}, run once after dispose() tears down the graph edges. */
|
|
534
|
+
_disposeListeners = [];
|
|
466
535
|
constructor(data, onData, onError, onPending) {
|
|
467
536
|
super();
|
|
468
537
|
this._data = data;
|
|
@@ -472,8 +541,23 @@ class EffectNode extends Observer {
|
|
|
472
541
|
this._notifyEpoch = 1;
|
|
473
542
|
this.execute();
|
|
474
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* Registers a callback to run once this effect is disposed, after the graph edges are torn
|
|
546
|
+
* down. Lets a caller that wraps an effect (e.g. {@link ActionNode.subscribe}) attach its own
|
|
547
|
+
* teardown without patching `dispose` on the returned instance (A2-ARCH-8).
|
|
548
|
+
* @internal
|
|
549
|
+
*/
|
|
550
|
+
onDispose(fn) {
|
|
551
|
+
this._disposeListeners.push(fn);
|
|
552
|
+
}
|
|
553
|
+
dispose() {
|
|
554
|
+
super.dispose();
|
|
555
|
+
this._disposeListeners.forEach((fn) => {
|
|
556
|
+
fn();
|
|
557
|
+
});
|
|
558
|
+
}
|
|
475
559
|
notify() {
|
|
476
|
-
if (this._disposed) throw
|
|
560
|
+
if (this._disposed) throw this._disposedError();
|
|
477
561
|
if (this._queued) {
|
|
478
562
|
if (!this._coalescedWhileQueued) {
|
|
479
563
|
this._coalescedWhileQueued = true;
|
|
@@ -537,8 +621,22 @@ class ValueNode extends Node {
|
|
|
537
621
|
[PICOFLOW_VALUE_NODE] = true;
|
|
538
622
|
_value;
|
|
539
623
|
_error;
|
|
624
|
+
/** Builds the "unreachable state" error, naming the primitive when a `name` was given at creation. */
|
|
625
|
+
_internalError() {
|
|
626
|
+
return new PicoFlowInternalError(
|
|
627
|
+
this._name ? `[PicoFlow] Internal error (${this._name})` : "[PicoFlow] Internal error"
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Hook called just before a tracked read throws `PendingError`, i.e. a dependent registered while
|
|
632
|
+
* this node is mid-flight and has no other way to learn the computation later settled (A2-PERF-4).
|
|
633
|
+
* No-op by default; overridden by {@link ValueAsyncNode} to know when its own post-resolve
|
|
634
|
+
* `notifyDependents()` call cannot be skipped even if the resolved value is unchanged.
|
|
635
|
+
*/
|
|
636
|
+
_markPendingRead() {
|
|
637
|
+
}
|
|
540
638
|
watch(tracker) {
|
|
541
|
-
if (this.disposed) throw
|
|
639
|
+
if (this.disposed) throw this._disposedError();
|
|
542
640
|
super.watch(tracker);
|
|
543
641
|
switch (this.status) {
|
|
544
642
|
case "resolved":
|
|
@@ -546,26 +644,28 @@ class ValueNode extends Node {
|
|
|
546
644
|
case "error":
|
|
547
645
|
throw this._error;
|
|
548
646
|
case "pending": {
|
|
647
|
+
this._markPendingRead();
|
|
549
648
|
throw new PendingError(this._scheduler.settled);
|
|
550
649
|
}
|
|
551
650
|
case "dirty": {
|
|
552
651
|
this.execute();
|
|
553
652
|
switch (this.status) {
|
|
554
653
|
case "pending":
|
|
654
|
+
this._markPendingRead();
|
|
555
655
|
throw new PendingError(this._scheduler.settled);
|
|
556
656
|
case "resolved":
|
|
557
657
|
return;
|
|
558
658
|
case "error":
|
|
559
659
|
throw this._error;
|
|
560
660
|
case "dirty": {
|
|
561
|
-
throw
|
|
661
|
+
throw this._internalError();
|
|
562
662
|
}
|
|
563
663
|
}
|
|
564
664
|
}
|
|
565
665
|
}
|
|
566
666
|
}
|
|
567
667
|
notify() {
|
|
568
|
-
if (this.disposed) throw
|
|
668
|
+
if (this.disposed) throw this._disposedError();
|
|
569
669
|
if (this.status === "dirty") return;
|
|
570
670
|
if (this.status === "pending") {
|
|
571
671
|
ExecutionStack.pushPending(this);
|
|
@@ -578,7 +678,7 @@ class ValueNode extends Node {
|
|
|
578
678
|
this._scheduler.dispose();
|
|
579
679
|
}
|
|
580
680
|
get(tracker) {
|
|
581
|
-
if (this.disposed) throw
|
|
681
|
+
if (this.disposed) throw this._disposedError();
|
|
582
682
|
super.watch(tracker);
|
|
583
683
|
switch (this.status) {
|
|
584
684
|
case "resolved":
|
|
@@ -586,6 +686,7 @@ class ValueNode extends Node {
|
|
|
586
686
|
case "error":
|
|
587
687
|
throw this._error;
|
|
588
688
|
case "pending": {
|
|
689
|
+
this._markPendingRead();
|
|
589
690
|
throw new PendingError(this._scheduler.settled);
|
|
590
691
|
}
|
|
591
692
|
case "dirty": {
|
|
@@ -596,17 +697,18 @@ class ValueNode extends Node {
|
|
|
596
697
|
case "error":
|
|
597
698
|
throw this._error;
|
|
598
699
|
case "pending": {
|
|
700
|
+
this._markPendingRead();
|
|
599
701
|
throw new PendingError(this._scheduler.settled);
|
|
600
702
|
}
|
|
601
703
|
case "dirty": {
|
|
602
|
-
throw
|
|
704
|
+
throw this._internalError();
|
|
603
705
|
}
|
|
604
706
|
}
|
|
605
707
|
}
|
|
606
708
|
}
|
|
607
709
|
}
|
|
608
710
|
async pick() {
|
|
609
|
-
if (this.disposed) throw
|
|
711
|
+
if (this.disposed) throw this._disposedError();
|
|
610
712
|
switch (this.status) {
|
|
611
713
|
case "resolved":
|
|
612
714
|
return this._value;
|
|
@@ -614,7 +716,7 @@ class ValueNode extends Node {
|
|
|
614
716
|
await this._scheduler.settled;
|
|
615
717
|
if (this.status === "resolved") return this._value;
|
|
616
718
|
if (this.status === "error") throw this._error;
|
|
617
|
-
throw
|
|
719
|
+
throw this._internalError();
|
|
618
720
|
}
|
|
619
721
|
case "error":
|
|
620
722
|
throw this._error;
|
|
@@ -627,12 +729,12 @@ class ValueNode extends Node {
|
|
|
627
729
|
await this._scheduler.settled;
|
|
628
730
|
if (this.status === "resolved") return this._value;
|
|
629
731
|
if (this.status === "error") throw this._error;
|
|
630
|
-
throw
|
|
732
|
+
throw this._internalError();
|
|
631
733
|
}
|
|
632
734
|
case "error":
|
|
633
735
|
throw this._error;
|
|
634
736
|
case "dirty": {
|
|
635
|
-
throw
|
|
737
|
+
throw this._internalError();
|
|
636
738
|
}
|
|
637
739
|
}
|
|
638
740
|
}
|
|
@@ -645,7 +747,7 @@ class ValueNode extends Node {
|
|
|
645
747
|
this._scheduler.compute();
|
|
646
748
|
}
|
|
647
749
|
subscribe(onValue, onError, onPending) {
|
|
648
|
-
if (this.disposed) throw
|
|
750
|
+
if (this.disposed) throw this._disposedError();
|
|
649
751
|
const effect = new EffectNode((t) => this.get(t), onValue, onError, onPending);
|
|
650
752
|
return effect;
|
|
651
753
|
}
|
|
@@ -654,8 +756,17 @@ class ValueNode extends Node {
|
|
|
654
756
|
class ValueAsyncNode extends ValueNode {
|
|
655
757
|
_scheduler;
|
|
656
758
|
_compute;
|
|
657
|
-
|
|
658
|
-
|
|
759
|
+
/** Set by {@link ValueNode._markPendingRead} when a dependent registers while this node is mid-flight. */
|
|
760
|
+
_hasPendingReader = false;
|
|
761
|
+
/**
|
|
762
|
+
* True only while the in-flight computation was started by `set()`, which already ran its own
|
|
763
|
+
* eager `notifyDependents()` cascade before this resolution. `refresh()` and a recompute pulled
|
|
764
|
+
* lazily after an upstream `notify()` have no such pre-cascade — for them, `_onResolve`'s own
|
|
765
|
+
* `notifyDependents()` call is the only notification, so it must never be skipped (A2-PERF-4).
|
|
766
|
+
*/
|
|
767
|
+
_pendingFromSet = false;
|
|
768
|
+
constructor(promiseOrCompute, name) {
|
|
769
|
+
super(name);
|
|
659
770
|
if (typeof promiseOrCompute === "function") {
|
|
660
771
|
this._compute = () => promiseOrCompute(this, this._value);
|
|
661
772
|
} else {
|
|
@@ -670,10 +781,18 @@ class ValueAsyncNode extends ValueNode {
|
|
|
670
781
|
}
|
|
671
782
|
_onResolve(value) {
|
|
672
783
|
if (this.disposed) return;
|
|
784
|
+
const changed = value !== this._value;
|
|
785
|
+
const hadPendingReader = this._hasPendingReader;
|
|
786
|
+
const pendingFromSet = this._pendingFromSet;
|
|
787
|
+
this._hasPendingReader = false;
|
|
788
|
+
this._pendingFromSet = false;
|
|
673
789
|
this.status = "resolved";
|
|
674
790
|
this._value = value;
|
|
675
791
|
this._error = void 0;
|
|
676
|
-
this.notifyDependents();
|
|
792
|
+
if (changed || hadPendingReader || !pendingFromSet) this.notifyDependents();
|
|
793
|
+
}
|
|
794
|
+
_markPendingRead() {
|
|
795
|
+
this._hasPendingReader = true;
|
|
677
796
|
}
|
|
678
797
|
_onReject(error) {
|
|
679
798
|
if (this.disposed) return;
|
|
@@ -682,12 +801,13 @@ class ValueAsyncNode extends ValueNode {
|
|
|
682
801
|
this.notifyDependents();
|
|
683
802
|
}
|
|
684
803
|
set(promiseOrUpdater) {
|
|
685
|
-
if (this.disposed) throw
|
|
804
|
+
if (this.disposed) throw this._disposedError();
|
|
686
805
|
if (typeof promiseOrUpdater === "function") {
|
|
687
806
|
const updater = promiseOrUpdater;
|
|
688
807
|
switch (this.status) {
|
|
689
808
|
case "resolved": {
|
|
690
809
|
this.status = "pending";
|
|
810
|
+
this._pendingFromSet = true;
|
|
691
811
|
this._scheduler.overwrite(updater(this._value));
|
|
692
812
|
this.notifyDependents();
|
|
693
813
|
return;
|
|
@@ -696,6 +816,7 @@ class ValueAsyncNode extends ValueNode {
|
|
|
696
816
|
case "error":
|
|
697
817
|
case "dirty": {
|
|
698
818
|
this.status = "pending";
|
|
819
|
+
this._pendingFromSet = true;
|
|
699
820
|
this._scheduler.overwrite(updater(this._value));
|
|
700
821
|
this.notifyDependents();
|
|
701
822
|
return;
|
|
@@ -703,38 +824,39 @@ class ValueAsyncNode extends ValueNode {
|
|
|
703
824
|
}
|
|
704
825
|
} else {
|
|
705
826
|
this.status = "pending";
|
|
827
|
+
this._pendingFromSet = true;
|
|
706
828
|
const promise = promiseOrUpdater;
|
|
707
829
|
this._scheduler.overwrite(promise);
|
|
708
830
|
this.notifyDependents();
|
|
709
831
|
}
|
|
710
832
|
}
|
|
711
833
|
refresh() {
|
|
712
|
-
if (this.disposed) throw
|
|
834
|
+
if (this.disposed) throw this._disposedError();
|
|
713
835
|
this.execute();
|
|
714
836
|
}
|
|
715
837
|
}
|
|
716
838
|
|
|
717
|
-
function constantAsync(valueOrInitializer) {
|
|
718
|
-
return new ValueAsyncNode(valueOrInitializer);
|
|
839
|
+
function constantAsync(valueOrInitializer, options) {
|
|
840
|
+
return new ValueAsyncNode(valueOrInitializer, options?.name);
|
|
719
841
|
}
|
|
720
842
|
|
|
721
|
-
function derivationAsync(compute) {
|
|
722
|
-
return new ValueAsyncNode(compute);
|
|
843
|
+
function derivationAsync(compute, options) {
|
|
844
|
+
return new ValueAsyncNode(compute, options?.name);
|
|
723
845
|
}
|
|
724
846
|
|
|
725
|
-
function stateAsync(valueOrInitializer) {
|
|
726
|
-
return new ValueAsyncNode(valueOrInitializer);
|
|
847
|
+
function stateAsync(valueOrInitializer, options) {
|
|
848
|
+
return new ValueAsyncNode(valueOrInitializer, options?.name);
|
|
727
849
|
}
|
|
728
850
|
|
|
729
|
-
function writableDerivationAsync(compute) {
|
|
730
|
-
return new ValueAsyncNode(compute);
|
|
851
|
+
function writableDerivationAsync(compute, options) {
|
|
852
|
+
return new ValueAsyncNode(compute, options?.name);
|
|
731
853
|
}
|
|
732
854
|
|
|
733
855
|
class ValueSyncNode extends ValueNode {
|
|
734
856
|
_scheduler;
|
|
735
857
|
_compute;
|
|
736
|
-
constructor(valueOrCompute) {
|
|
737
|
-
super();
|
|
858
|
+
constructor(valueOrCompute, name) {
|
|
859
|
+
super(name);
|
|
738
860
|
if (typeof valueOrCompute === "function") {
|
|
739
861
|
this._compute = () => valueOrCompute(this, this._value);
|
|
740
862
|
} else {
|
|
@@ -760,7 +882,7 @@ class ValueSyncNode extends ValueNode {
|
|
|
760
882
|
this._error = error;
|
|
761
883
|
}
|
|
762
884
|
set(valueOrUpdater) {
|
|
763
|
-
if (this.disposed) throw
|
|
885
|
+
if (this.disposed) throw this._disposedError();
|
|
764
886
|
if (typeof valueOrUpdater === "function") {
|
|
765
887
|
const updater = valueOrUpdater;
|
|
766
888
|
switch (this.status) {
|
|
@@ -804,7 +926,7 @@ class ValueSyncNode extends ValueNode {
|
|
|
804
926
|
}
|
|
805
927
|
}
|
|
806
928
|
refresh() {
|
|
807
|
-
if (this.disposed) throw
|
|
929
|
+
if (this.disposed) throw this._disposedError();
|
|
808
930
|
const currentValue = this._value;
|
|
809
931
|
const currentStatus = this.status;
|
|
810
932
|
this.execute();
|
|
@@ -833,7 +955,7 @@ class ActionNode extends ValueSyncNode {
|
|
|
833
955
|
}
|
|
834
956
|
}
|
|
835
957
|
set(valueOrUpdater) {
|
|
836
|
-
if (this.disposed) throw
|
|
958
|
+
if (this.disposed) throw this._disposedError();
|
|
837
959
|
if (typeof valueOrUpdater === "function") {
|
|
838
960
|
const updater = valueOrUpdater;
|
|
839
961
|
const nextValue2 = updater(this._value);
|
|
@@ -848,7 +970,7 @@ class ActionNode extends ValueSyncNode {
|
|
|
848
970
|
super.set(nextValue);
|
|
849
971
|
}
|
|
850
972
|
subscribe(onValue, onError, onPending) {
|
|
851
|
-
if (this.disposed) throw
|
|
973
|
+
if (this.disposed) throw this._disposedError();
|
|
852
974
|
const slot = { queue: [] };
|
|
853
975
|
this._slots.add(slot);
|
|
854
976
|
const effect = new EffectNode(
|
|
@@ -867,11 +989,9 @@ class ActionNode extends ValueSyncNode {
|
|
|
867
989
|
onError,
|
|
868
990
|
onPending
|
|
869
991
|
);
|
|
870
|
-
|
|
871
|
-
effect.dispose = () => {
|
|
992
|
+
effect.onDispose(() => {
|
|
872
993
|
this._slots.delete(slot);
|
|
873
|
-
|
|
874
|
-
};
|
|
994
|
+
});
|
|
875
995
|
return effect;
|
|
876
996
|
}
|
|
877
997
|
dispose() {
|
|
@@ -882,8 +1002,8 @@ class ActionNode extends ValueSyncNode {
|
|
|
882
1002
|
|
|
883
1003
|
class ArrayNode extends ValueSyncNode {
|
|
884
1004
|
$lastAction;
|
|
885
|
-
constructor(value = []) {
|
|
886
|
-
super(value);
|
|
1005
|
+
constructor(value = [], name) {
|
|
1006
|
+
super(value, name);
|
|
887
1007
|
this.$lastAction = new ActionNode({
|
|
888
1008
|
type: "set",
|
|
889
1009
|
setItems: value,
|
|
@@ -899,11 +1019,11 @@ class ArrayNode extends ValueSyncNode {
|
|
|
899
1019
|
return [...values];
|
|
900
1020
|
}
|
|
901
1021
|
get length() {
|
|
902
|
-
if (this.disposed) throw
|
|
1022
|
+
if (this.disposed) throw this._disposedError();
|
|
903
1023
|
return this._value.length;
|
|
904
1024
|
}
|
|
905
1025
|
set(itemsOrUpdater) {
|
|
906
|
-
if (this.disposed) throw
|
|
1026
|
+
if (this.disposed) throw this._disposedError();
|
|
907
1027
|
const previousValue = this._value;
|
|
908
1028
|
super.set(itemsOrUpdater);
|
|
909
1029
|
this.$lastAction.set({
|
|
@@ -914,7 +1034,7 @@ class ArrayNode extends ValueSyncNode {
|
|
|
914
1034
|
return previousValue;
|
|
915
1035
|
}
|
|
916
1036
|
update(index, item) {
|
|
917
|
-
if (this.disposed) throw
|
|
1037
|
+
if (this.disposed) throw this._disposedError();
|
|
918
1038
|
if (index < 0 || index >= this._value.length || !Number.isInteger(index)) {
|
|
919
1039
|
throw new Error("[PicoFlow] Index out of bounds");
|
|
920
1040
|
}
|
|
@@ -930,13 +1050,13 @@ class ArrayNode extends ValueSyncNode {
|
|
|
930
1050
|
return previousValue;
|
|
931
1051
|
}
|
|
932
1052
|
push(item) {
|
|
933
|
-
if (this.disposed) throw
|
|
1053
|
+
if (this.disposed) throw this._disposedError();
|
|
934
1054
|
this._value.push(item);
|
|
935
1055
|
this.notifyDependents();
|
|
936
1056
|
this.$lastAction.set({ type: "push", addedItem: item });
|
|
937
1057
|
}
|
|
938
1058
|
pop() {
|
|
939
|
-
if (this.disposed) throw
|
|
1059
|
+
if (this.disposed) throw this._disposedError();
|
|
940
1060
|
if (this._value.length === 0) return void 0;
|
|
941
1061
|
const item = this._value.pop();
|
|
942
1062
|
this.notifyDependents();
|
|
@@ -944,13 +1064,13 @@ class ArrayNode extends ValueSyncNode {
|
|
|
944
1064
|
return item;
|
|
945
1065
|
}
|
|
946
1066
|
unshift(item) {
|
|
947
|
-
if (this.disposed) throw
|
|
1067
|
+
if (this.disposed) throw this._disposedError();
|
|
948
1068
|
this._value.unshift(item);
|
|
949
1069
|
this.notifyDependents();
|
|
950
1070
|
this.$lastAction.set({ type: "unshift", addedItem: item });
|
|
951
1071
|
}
|
|
952
1072
|
shift() {
|
|
953
|
-
if (this.disposed) throw
|
|
1073
|
+
if (this.disposed) throw this._disposedError();
|
|
954
1074
|
if (this._value.length === 0) return void 0;
|
|
955
1075
|
const item = this._value.shift();
|
|
956
1076
|
this.notifyDependents();
|
|
@@ -958,7 +1078,7 @@ class ArrayNode extends ValueSyncNode {
|
|
|
958
1078
|
return item;
|
|
959
1079
|
}
|
|
960
1080
|
splice(start, deleteCount, ...newItems) {
|
|
961
|
-
if (this.disposed) throw
|
|
1081
|
+
if (this.disposed) throw this._disposedError();
|
|
962
1082
|
const items = this._value.splice(start, deleteCount, ...newItems);
|
|
963
1083
|
this.notifyDependents();
|
|
964
1084
|
this.$lastAction.set({
|
|
@@ -971,7 +1091,7 @@ class ArrayNode extends ValueSyncNode {
|
|
|
971
1091
|
return items;
|
|
972
1092
|
}
|
|
973
1093
|
clear() {
|
|
974
|
-
if (this.disposed) throw
|
|
1094
|
+
if (this.disposed) throw this._disposedError();
|
|
975
1095
|
const previousValue = [...this._value];
|
|
976
1096
|
this._value = [];
|
|
977
1097
|
this.notifyDependents();
|
|
@@ -987,14 +1107,14 @@ class ArrayNode extends ValueSyncNode {
|
|
|
987
1107
|
}
|
|
988
1108
|
}
|
|
989
1109
|
|
|
990
|
-
function array(initial) {
|
|
991
|
-
return new ArrayNode(initial);
|
|
1110
|
+
function array(initial, options) {
|
|
1111
|
+
return new ArrayNode(initial, options?.name);
|
|
992
1112
|
}
|
|
993
1113
|
|
|
994
1114
|
class MapNode extends ValueSyncNode {
|
|
995
1115
|
$lastAction;
|
|
996
|
-
constructor(value = /* @__PURE__ */ new Map()) {
|
|
997
|
-
super(value);
|
|
1116
|
+
constructor(value = /* @__PURE__ */ new Map(), name) {
|
|
1117
|
+
super(value, name);
|
|
998
1118
|
this.$lastAction = new ActionNode({
|
|
999
1119
|
type: "set",
|
|
1000
1120
|
setMap: value,
|
|
@@ -1002,7 +1122,7 @@ class MapNode extends ValueSyncNode {
|
|
|
1002
1122
|
});
|
|
1003
1123
|
}
|
|
1004
1124
|
add(key, value) {
|
|
1005
|
-
if (this.disposed) throw
|
|
1125
|
+
if (this.disposed) throw this._disposedError();
|
|
1006
1126
|
if (this._value.has(key)) {
|
|
1007
1127
|
throw new Error("[PicoFlow] Key already exists");
|
|
1008
1128
|
}
|
|
@@ -1011,7 +1131,7 @@ class MapNode extends ValueSyncNode {
|
|
|
1011
1131
|
this.$lastAction.set({ type: "add", key, addedValue: value });
|
|
1012
1132
|
}
|
|
1013
1133
|
update(key, value) {
|
|
1014
|
-
if (this.disposed) throw
|
|
1134
|
+
if (this.disposed) throw this._disposedError();
|
|
1015
1135
|
if (!this._value.has(key)) throw new Error("[PicoFlow] Key does not exist");
|
|
1016
1136
|
const previousValue = this._value.get(key);
|
|
1017
1137
|
this._value.set(key, value);
|
|
@@ -1025,7 +1145,7 @@ class MapNode extends ValueSyncNode {
|
|
|
1025
1145
|
return previousValue;
|
|
1026
1146
|
}
|
|
1027
1147
|
delete(key) {
|
|
1028
|
-
if (this.disposed) throw
|
|
1148
|
+
if (this.disposed) throw this._disposedError();
|
|
1029
1149
|
if (!this._value.has(key)) throw new Error("[PicoFlow] Key does not exist");
|
|
1030
1150
|
const value = this._value.get(key);
|
|
1031
1151
|
this._value.delete(key);
|
|
@@ -1034,7 +1154,7 @@ class MapNode extends ValueSyncNode {
|
|
|
1034
1154
|
return value;
|
|
1035
1155
|
}
|
|
1036
1156
|
set(mapOrUpdater) {
|
|
1037
|
-
if (this.disposed) throw
|
|
1157
|
+
if (this.disposed) throw this._disposedError();
|
|
1038
1158
|
const previousValue = this._value;
|
|
1039
1159
|
super.set(mapOrUpdater);
|
|
1040
1160
|
this.$lastAction.set({
|
|
@@ -1045,7 +1165,7 @@ class MapNode extends ValueSyncNode {
|
|
|
1045
1165
|
return previousValue;
|
|
1046
1166
|
}
|
|
1047
1167
|
clear() {
|
|
1048
|
-
if (this.disposed) throw
|
|
1168
|
+
if (this.disposed) throw this._disposedError();
|
|
1049
1169
|
const previousValue = this._value;
|
|
1050
1170
|
this._value = /* @__PURE__ */ new Map();
|
|
1051
1171
|
this.notifyDependents();
|
|
@@ -1061,11 +1181,11 @@ class MapNode extends ValueSyncNode {
|
|
|
1061
1181
|
}
|
|
1062
1182
|
}
|
|
1063
1183
|
|
|
1064
|
-
function map(initial) {
|
|
1184
|
+
function map(initial, options) {
|
|
1065
1185
|
if (initial instanceof Map) {
|
|
1066
|
-
return new MapNode(initial);
|
|
1186
|
+
return new MapNode(initial, options?.name);
|
|
1067
1187
|
}
|
|
1068
|
-
return new MapNode(new Map(initial ? Object.entries(initial) : []));
|
|
1188
|
+
return new MapNode(new Map(initial ? Object.entries(initial) : []), options?.name);
|
|
1069
1189
|
}
|
|
1070
1190
|
|
|
1071
1191
|
function subscribe(data, onData, onError, onPending) {
|
|
@@ -1074,30 +1194,30 @@ function subscribe(data, onData, onError, onPending) {
|
|
|
1074
1194
|
|
|
1075
1195
|
class SignalNode extends Observable {
|
|
1076
1196
|
subscribe(onTrigger, onError, onPending) {
|
|
1077
|
-
if (this.disposed) throw
|
|
1197
|
+
if (this.disposed) throw this._disposedError();
|
|
1078
1198
|
const effect = new EffectNode((t) => this.watch(t), onTrigger, onError, onPending);
|
|
1079
1199
|
return effect;
|
|
1080
1200
|
}
|
|
1081
1201
|
}
|
|
1082
1202
|
|
|
1083
|
-
function signal() {
|
|
1084
|
-
return new SignalNode();
|
|
1203
|
+
function signal(options) {
|
|
1204
|
+
return new SignalNode(options?.name);
|
|
1085
1205
|
}
|
|
1086
1206
|
|
|
1087
|
-
function constant(initializer) {
|
|
1088
|
-
return new ValueSyncNode(initializer);
|
|
1207
|
+
function constant(initializer, options) {
|
|
1208
|
+
return new ValueSyncNode(initializer, options?.name);
|
|
1089
1209
|
}
|
|
1090
1210
|
|
|
1091
|
-
function derivation(compute) {
|
|
1092
|
-
return new ValueSyncNode(compute);
|
|
1211
|
+
function derivation(compute, options) {
|
|
1212
|
+
return new ValueSyncNode(compute, options?.name);
|
|
1093
1213
|
}
|
|
1094
1214
|
|
|
1095
|
-
function state(valueOrInitializer) {
|
|
1096
|
-
return new ValueSyncNode(valueOrInitializer);
|
|
1215
|
+
function state(valueOrInitializer, options) {
|
|
1216
|
+
return new ValueSyncNode(valueOrInitializer, options?.name);
|
|
1097
1217
|
}
|
|
1098
1218
|
|
|
1099
|
-
function writableDerivation(compute) {
|
|
1100
|
-
return new ValueSyncNode(compute);
|
|
1219
|
+
function writableDerivation(compute, options) {
|
|
1220
|
+
return new ValueSyncNode(compute, options?.name);
|
|
1101
1221
|
}
|
|
1102
1222
|
|
|
1103
1223
|
function describeFlowInput(value) {
|
|
@@ -1160,4 +1280,4 @@ function from(flow) {
|
|
|
1160
1280
|
throw new Error(`[PicoFlow] from(): expected a FlowValue or getter function, received ${describeFlowInput(flow)}`);
|
|
1161
1281
|
}
|
|
1162
1282
|
|
|
1163
|
-
export { array, constant, constantAsync, derivation, derivationAsync, from, isDisposable, map, onFlushError, signal, state, stateAsync, subscribe, writableDerivation, writableDerivationAsync };
|
|
1283
|
+
export { PicoFlowCycleError, PicoFlowDisposedError, PicoFlowError, PicoFlowInternalError, array, constant, constantAsync, derivation, derivationAsync, from, isDisposable, map, onFlushError, signal, state, stateAsync, subscribe, writableDerivation, writableDerivationAsync };
|