@ersbeth/picoflow 0.0.1 → 0.1.0
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/api/doc/index.md +1 -1
- package/api/doc/picoflow.constant.md +55 -0
- package/api/doc/picoflow.derivation.md +1 -1
- package/api/doc/picoflow.effect.md +1 -1
- package/api/doc/picoflow.flowconstant._constructor_.md +49 -0
- package/api/doc/picoflow.flowconstant.get.md +25 -0
- package/api/doc/picoflow.flowconstant.md +88 -0
- package/api/doc/picoflow.flowderivation._constructor_.md +2 -2
- package/api/doc/picoflow.flowderivation.get.md +2 -2
- package/api/doc/picoflow.flowderivation.md +2 -2
- package/api/doc/picoflow.floweffect._constructor_.md +7 -2
- package/api/doc/picoflow.floweffect.dispose.md +3 -3
- package/api/doc/picoflow.floweffect.disposed.md +1 -1
- package/api/doc/picoflow.floweffect.md +4 -4
- package/api/doc/picoflow.flowgetter.md +2 -2
- package/api/doc/picoflow.flowmap._lastdeleted.md +1 -1
- package/api/doc/picoflow.flowmap._lastset.md +1 -1
- package/api/doc/picoflow.flowmap.delete.md +6 -2
- package/api/doc/picoflow.flowmap.md +5 -7
- package/api/doc/picoflow.flowmap.setat.md +6 -2
- package/api/doc/picoflow.flowobservable.get.md +3 -3
- package/api/doc/picoflow.flowobservable.md +18 -4
- package/api/doc/picoflow.flowobservable.subscribe.md +55 -0
- package/api/doc/picoflow.flowresource._constructor_.md +2 -18
- package/api/doc/picoflow.flowresource.fetch.md +1 -1
- package/api/doc/picoflow.flowresource.get.md +4 -4
- package/api/doc/picoflow.flowresource.md +4 -4
- package/api/doc/picoflow.flowresourceasync._constructor_.md +49 -0
- package/api/doc/picoflow.flowresourceasync.fetch.md +27 -0
- package/api/doc/picoflow.flowresourceasync.get.md +23 -0
- package/api/doc/picoflow.flowresourceasync.md +100 -0
- package/api/doc/picoflow.flowsignal.dispose.md +3 -7
- package/api/doc/picoflow.flowsignal.disposed.md +2 -2
- package/api/doc/picoflow.flowsignal.md +5 -5
- package/api/doc/picoflow.flowsignal.trigger.md +3 -7
- package/api/doc/picoflow.flowstate.md +4 -52
- package/api/doc/picoflow.flowstate.set.md +5 -5
- package/api/doc/picoflow.flowstream._constructor_.md +3 -19
- package/api/doc/picoflow.flowstream.dispose.md +1 -1
- package/api/doc/picoflow.flowstream.get.md +4 -4
- package/api/doc/picoflow.flowstream.md +5 -5
- package/api/doc/picoflow.flowstreamasync._constructor_.md +54 -0
- package/api/doc/picoflow.flowstreamasync.dispose.md +21 -0
- package/api/doc/picoflow.flowstreamasync.get.md +23 -0
- package/api/doc/picoflow.flowstreamasync.md +100 -0
- package/api/doc/picoflow.flowstreamdisposer.md +13 -0
- package/api/doc/picoflow.flowstreamsetter.md +13 -0
- package/api/doc/picoflow.flowstreamupdater.md +19 -0
- package/api/doc/picoflow.flowwatcher.md +1 -1
- package/api/doc/picoflow.map.md +1 -1
- package/api/doc/picoflow.md +80 -14
- package/api/doc/picoflow.resource.md +2 -18
- package/api/doc/picoflow.resourceasync.md +55 -0
- package/api/doc/picoflow.signal.md +1 -1
- package/api/doc/picoflow.state.md +3 -3
- package/api/doc/picoflow.stream.md +2 -18
- package/api/doc/picoflow.streamasync.md +55 -0
- package/api/picoflow.public.api.md +131 -0
- package/api-extractor.json +2 -1
- package/dist/picoflow.js +326 -302
- package/dist/types/advanced/index.d.ts +7 -0
- package/dist/types/advanced/index.d.ts.map +1 -0
- package/dist/types/{map.d.ts → advanced/map.d.ts} +12 -12
- package/dist/types/advanced/map.d.ts.map +1 -0
- package/dist/types/advanced/resource.d.ts +39 -0
- package/dist/types/advanced/resource.d.ts.map +1 -0
- package/dist/types/{resource.d.ts → advanced/resourceAsync.d.ts} +6 -11
- package/dist/types/advanced/resourceAsync.d.ts.map +1 -0
- package/dist/types/advanced/stream.d.ts +59 -0
- package/dist/types/advanced/stream.d.ts.map +1 -0
- package/dist/types/advanced/streamAsync.d.ts +43 -0
- package/dist/types/advanced/streamAsync.d.ts.map +1 -0
- package/dist/types/basic/constant.d.ts +32 -0
- package/dist/types/basic/constant.d.ts.map +1 -0
- package/dist/types/basic/derivation.d.ts +40 -0
- package/dist/types/basic/derivation.d.ts.map +1 -0
- package/dist/types/basic/effect.d.ts +56 -0
- package/dist/types/basic/effect.d.ts.map +1 -0
- package/dist/types/basic/index.d.ts +9 -0
- package/dist/types/basic/index.d.ts.map +1 -0
- package/dist/types/basic/observable.d.ts +34 -0
- package/dist/types/basic/observable.d.ts.map +1 -0
- package/dist/types/basic/signal.d.ts +37 -0
- package/dist/types/basic/signal.d.ts.map +1 -0
- package/dist/types/basic/state.d.ts +26 -0
- package/dist/types/basic/state.d.ts.map +1 -0
- package/dist/types/creators.d.ts +29 -13
- package/dist/types/creators.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -9
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/advanced/index.ts +10 -0
- package/src/{map.ts → advanced/map.ts} +14 -14
- package/src/advanced/resource.ts +56 -0
- package/src/{resource.ts → advanced/resourceAsync.ts} +9 -16
- package/src/advanced/stream.ts +87 -0
- package/src/advanced/streamAsync.ts +82 -0
- package/src/basic/constant.ts +64 -0
- package/src/basic/derivation.ts +86 -0
- package/src/basic/effect.ts +96 -0
- package/src/basic/index.ts +8 -0
- package/src/basic/observable.ts +51 -0
- package/src/basic/signal.ts +105 -0
- package/src/basic/state.ts +39 -0
- package/src/creators.ts +54 -15
- package/src/index.ts +21 -11
- package/test/constant.test.ts +46 -0
- package/test/derivation.test.ts +30 -6
- package/test/effect.test.ts +29 -0
- package/test/map.test.ts +38 -0
- package/test/resource.test.ts +18 -16
- package/test/resourceAsync.test.ts +108 -0
- package/test/signal.test.ts +18 -1
- package/test/state.test.ts +107 -2
- package/test/stream.test.ts +38 -13
- package/test/streamAsync.test.ts +194 -0
- package/tsconfig.json +3 -1
- package/api/doc/picoflow.flowdisposer.md +0 -13
- package/api/doc/picoflow.flowsetter.md +0 -13
- package/api/doc/picoflow.flowstate._constructor_.md +0 -49
- package/api/doc/picoflow.flowstate.get.md +0 -23
- package/api/doc/picoflow.flowupdater.md +0 -19
- package/api/picoflow.api.md +0 -145
- package/dist/types/derivation.d.ts +0 -58
- package/dist/types/derivation.d.ts.map +0 -1
- package/dist/types/effect.d.ts +0 -108
- package/dist/types/effect.d.ts.map +0 -1
- package/dist/types/map.d.ts.map +0 -1
- package/dist/types/observable.d.ts +0 -40
- package/dist/types/observable.d.ts.map +0 -1
- package/dist/types/resource.d.ts.map +0 -1
- package/dist/types/signal.d.ts +0 -111
- package/dist/types/signal.d.ts.map +0 -1
- package/dist/types/state.d.ts +0 -39
- package/dist/types/state.d.ts.map +0 -1
- package/dist/types/stream.d.ts +0 -71
- package/dist/types/stream.d.ts.map +0 -1
- package/src/derivation.ts +0 -96
- package/src/effect.ts +0 -152
- package/src/observable.ts +0 -50
- package/src/signal.ts +0 -166
- package/src/state.ts +0 -52
- package/src/stream.ts +0 -99
package/dist/picoflow.js
CHANGED
|
@@ -1,27 +1,23 @@
|
|
|
1
1
|
class FlowSignal {
|
|
2
|
-
/* API ---------------------------------------------------------------------- */
|
|
3
2
|
/**
|
|
4
|
-
* Triggers the
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @throws Error if the signal is disposed.
|
|
3
|
+
* Triggers the FlowSignal.
|
|
4
|
+
* Notifies all registered listeners and schedules execution of associated effects.
|
|
5
|
+
* @throws If the FlowSignal has already been disposed.
|
|
8
6
|
* @public
|
|
9
7
|
*/
|
|
10
8
|
trigger() {
|
|
11
|
-
if (this._disposed) throw new Error("
|
|
9
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
12
10
|
this._notify();
|
|
13
11
|
}
|
|
14
12
|
/**
|
|
15
|
-
* Disposes the
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* will throw an error.
|
|
20
|
-
* @throws Error if the signal is already disposed.
|
|
13
|
+
* Disposes the FlowSignal.
|
|
14
|
+
* Cleans up all registered effects, listeners, and dependencies.
|
|
15
|
+
* Once disposed, further usage of the signal will throw an error.
|
|
16
|
+
* @throws If the FlowSignal is already disposed.
|
|
21
17
|
* @public
|
|
22
18
|
*/
|
|
23
19
|
dispose() {
|
|
24
|
-
if (this._disposed) throw new Error("
|
|
20
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
25
21
|
Array.from(this._effects).forEach((effect) => effect.dispose());
|
|
26
22
|
Array.from(this._listeners).forEach((listener) => listener.dispose());
|
|
27
23
|
Array.from(this._dependencies).forEach((dependency) => {
|
|
@@ -30,207 +26,74 @@ class FlowSignal {
|
|
|
30
26
|
this._disposed = true;
|
|
31
27
|
}
|
|
32
28
|
/**
|
|
33
|
-
* Indicates whether the
|
|
34
|
-
* @remarks
|
|
35
|
-
* Once disposed, the signal should not be used.
|
|
29
|
+
* Indicates whether the FlowSignal has been disposed.
|
|
30
|
+
* @remarks Once disposed, the signal should not be used.
|
|
36
31
|
* @public
|
|
37
32
|
*/
|
|
38
33
|
get disposed() {
|
|
39
34
|
return this._disposed;
|
|
40
35
|
}
|
|
41
36
|
/* INTERNAL ------------------------------------------------------------- */
|
|
42
|
-
|
|
43
|
-
* @internal
|
|
44
|
-
*/
|
|
37
|
+
/*@internal*/
|
|
45
38
|
_disposed = false;
|
|
46
|
-
|
|
47
|
-
* @internal
|
|
48
|
-
*/
|
|
39
|
+
/*@internal*/
|
|
49
40
|
_dependencies = /* @__PURE__ */ new Set();
|
|
50
|
-
|
|
51
|
-
* @internal
|
|
52
|
-
*/
|
|
41
|
+
/*@internal*/
|
|
53
42
|
_listeners = /* @__PURE__ */ new Set();
|
|
54
|
-
|
|
55
|
-
* @internal
|
|
56
|
-
*/
|
|
43
|
+
/*@internal*/
|
|
57
44
|
_effects = /* @__PURE__ */ new Set();
|
|
58
|
-
|
|
59
|
-
* @internal
|
|
60
|
-
* Internal method to watch the signal.
|
|
61
|
-
* @throws Error if the signal is disposed.
|
|
62
|
-
*/
|
|
45
|
+
/*@internal*/
|
|
63
46
|
_watch() {
|
|
64
|
-
if (this._disposed) throw new Error("
|
|
47
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
65
48
|
}
|
|
66
|
-
|
|
67
|
-
* @internal
|
|
68
|
-
* Notifies all listeners and executes all registered effects.
|
|
69
|
-
*/
|
|
49
|
+
/*@internal*/
|
|
70
50
|
_notify() {
|
|
71
51
|
this._listeners.forEach((listener) => listener._notify());
|
|
72
52
|
this._effects.forEach((effect) => effect._exec());
|
|
73
53
|
}
|
|
74
|
-
|
|
75
|
-
* @internal
|
|
76
|
-
* Registers a dependency from the given listener and watches the signal.
|
|
77
|
-
* @param listener - A FlowSignal or FlowEffect that will depend on this signal.
|
|
78
|
-
*/
|
|
54
|
+
/*@internal*/
|
|
79
55
|
_watchFrom(listener) {
|
|
80
56
|
listener._registerDependency(this);
|
|
81
57
|
this._watch();
|
|
82
58
|
}
|
|
83
|
-
|
|
84
|
-
* @internal
|
|
85
|
-
* Registers a dependency with the given FlowSignal.
|
|
86
|
-
* @param dependency - The FlowSignal to register as a dependency.
|
|
87
|
-
*/
|
|
59
|
+
/*@internal*/
|
|
88
60
|
_registerDependency(dependency) {
|
|
89
61
|
this._dependencies.add(dependency);
|
|
90
62
|
dependency._registerListener(this);
|
|
91
63
|
}
|
|
92
|
-
|
|
93
|
-
* @internal
|
|
94
|
-
* Unregisters the given dependency.
|
|
95
|
-
* @param dependency - The FlowSignal to unregister.
|
|
96
|
-
*/
|
|
64
|
+
/*@internal*/
|
|
97
65
|
_unregisterDependency(dependency) {
|
|
98
66
|
this._dependencies.delete(dependency);
|
|
99
67
|
dependency._unregisterListener(this);
|
|
100
68
|
}
|
|
101
|
-
|
|
102
|
-
* @internal
|
|
103
|
-
* Registers a listener (another FlowSignal) to this signal.
|
|
104
|
-
* @param signal - The FlowSignal to register as a listener.
|
|
105
|
-
*/
|
|
69
|
+
/*@internal*/
|
|
106
70
|
_registerListener(signal) {
|
|
107
71
|
this._listeners.add(signal);
|
|
108
72
|
}
|
|
109
|
-
|
|
110
|
-
* @internal
|
|
111
|
-
* Unregisters the given listener.
|
|
112
|
-
* @param signal - The FlowSignal to unregister.
|
|
113
|
-
*/
|
|
73
|
+
/*@internal*/
|
|
114
74
|
_unregisterListener(signal) {
|
|
115
75
|
this._listeners.delete(signal);
|
|
116
76
|
}
|
|
117
|
-
|
|
118
|
-
* @internal
|
|
119
|
-
* Registers a FlowEffect to this signal.
|
|
120
|
-
* @param effect - The FlowEffect to register.
|
|
121
|
-
*/
|
|
77
|
+
/*@internal*/
|
|
122
78
|
_registerEffect(effect) {
|
|
123
79
|
this._effects.add(effect);
|
|
124
80
|
}
|
|
125
|
-
|
|
126
|
-
* @internal
|
|
127
|
-
* Unregisters the given FlowEffect.
|
|
128
|
-
* @param effect - The FlowEffect to unregister.
|
|
129
|
-
*/
|
|
81
|
+
/*@internal*/
|
|
130
82
|
_unregisterEffect(effect) {
|
|
131
83
|
this._effects.delete(effect);
|
|
132
84
|
}
|
|
133
85
|
}
|
|
134
86
|
|
|
135
|
-
class FlowObservable extends FlowSignal {
|
|
136
|
-
/* INTERNAL -------------------------------------------*/
|
|
137
|
-
/**
|
|
138
|
-
* @internal
|
|
139
|
-
* Internal storage for the observable's value.
|
|
140
|
-
*/
|
|
141
|
-
_value;
|
|
142
|
-
/**
|
|
143
|
-
* @internal
|
|
144
|
-
* Retrieves the current value from the observable and registers a dependency
|
|
145
|
-
* from the provided listener.
|
|
146
|
-
* @param listener - The FlowObservable or FlowEffect that is accessing this observable.
|
|
147
|
-
* @returns The current value, as returned by {@link FlowObservable.get}.
|
|
148
|
-
*/
|
|
149
|
-
_getFrom(listener) {
|
|
150
|
-
listener._registerDependency(this);
|
|
151
|
-
return this.get();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
class FlowDerivation extends FlowObservable {
|
|
156
|
-
/**
|
|
157
|
-
* Creates a new FlowDerivation.
|
|
158
|
-
* @param compute - A function that computes the derived value. It is provided with a getter
|
|
159
|
-
* and a watcher function to access observables and signals dependencies.
|
|
160
|
-
* @public
|
|
161
|
-
*/
|
|
162
|
-
constructor(compute) {
|
|
163
|
-
super();
|
|
164
|
-
this._trackedExec = () => compute(this._trackedGet, this._trackedWatch);
|
|
165
|
-
this._untrackedExec = () => compute(this._untrackedGet, this._untrackedWatch);
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Gets the current derived value.
|
|
169
|
-
* @returns The current computed value.
|
|
170
|
-
* @remarks
|
|
171
|
-
* This method ensures that the derivation is up-to-date before returning the value.
|
|
172
|
-
* @public
|
|
173
|
-
*/
|
|
174
|
-
get() {
|
|
175
|
-
this._exec();
|
|
176
|
-
return this._value;
|
|
177
|
-
}
|
|
178
|
-
/* INTERNAL MEMBERS AND METHODS */
|
|
179
|
-
/** @internal */
|
|
180
|
-
_initialized = false;
|
|
181
|
-
/** @internal */
|
|
182
|
-
_dirty = true;
|
|
183
|
-
/** @internal */
|
|
184
|
-
_trackedGet = (observable) => observable._getFrom(this);
|
|
185
|
-
/** @internal */
|
|
186
|
-
_trackedWatch = (signal) => signal._watchFrom(this);
|
|
187
|
-
/** @internal */
|
|
188
|
-
_untrackedGet = (observable) => observable.get();
|
|
189
|
-
/** @internal */
|
|
190
|
-
_untrackedWatch = (signal) => signal._watch();
|
|
191
|
-
/** @internal */
|
|
192
|
-
_trackedExec;
|
|
193
|
-
/** @internal */
|
|
194
|
-
_untrackedExec;
|
|
195
|
-
/**
|
|
196
|
-
* @internal
|
|
197
|
-
* Executes the compute function if necessary to update the derived value.
|
|
198
|
-
*/
|
|
199
|
-
_exec() {
|
|
200
|
-
if (this._disposed) throw new Error("Effect is disposed");
|
|
201
|
-
if (this._dirty) {
|
|
202
|
-
if (this._initialized) this._value = this._untrackedExec();
|
|
203
|
-
else {
|
|
204
|
-
this._value = this._trackedExec();
|
|
205
|
-
this._initialized = true;
|
|
206
|
-
}
|
|
207
|
-
this._dirty = false;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* @internal
|
|
212
|
-
* Marks the derivation as dirty and notifies downstream dependencies.
|
|
213
|
-
*/
|
|
214
|
-
_notify() {
|
|
215
|
-
this._dirty = true;
|
|
216
|
-
super._notify();
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* @internal
|
|
220
|
-
* Ensures that the derivation is up-to-date when it is watched.
|
|
221
|
-
*/
|
|
222
|
-
_watch() {
|
|
223
|
-
this._exec();
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
87
|
class FlowEffect {
|
|
228
|
-
/* API --------------------------------------------------- */
|
|
229
88
|
/**
|
|
230
89
|
* Creates a new FlowEffect.
|
|
231
90
|
*
|
|
232
|
-
* @param apply - A function that
|
|
233
|
-
*
|
|
91
|
+
* @param apply - A side-effect function that receives a getter and a watcher to
|
|
92
|
+
* access and register dependencies on reactive observables and signals.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* The provided function is executed immediately in a tracked mode to collect dependencies.
|
|
96
|
+
* On subsequent executions, it runs in an untracked mode.
|
|
234
97
|
*
|
|
235
98
|
* @public
|
|
236
99
|
*/
|
|
@@ -240,16 +103,16 @@ class FlowEffect {
|
|
|
240
103
|
this._exec();
|
|
241
104
|
}
|
|
242
105
|
/**
|
|
243
|
-
* Disposes the effect, unregistering all its dependencies.
|
|
106
|
+
* Disposes the effect, unregistering all its tracked dependencies.
|
|
244
107
|
*
|
|
245
108
|
* @remarks
|
|
246
|
-
*
|
|
247
|
-
* disposed
|
|
109
|
+
* Once disposed, the effect must no longer be used. Trying to dispose an effect
|
|
110
|
+
* that is already disposed will throw an error.
|
|
248
111
|
*
|
|
249
112
|
* @public
|
|
250
113
|
*/
|
|
251
114
|
dispose() {
|
|
252
|
-
if (this._disposed) throw new Error("Effect is disposed");
|
|
115
|
+
if (this._disposed) throw new Error("[PicoFlow] Effect is disposed");
|
|
253
116
|
Array.from(this._dependencies).forEach((dependency) => {
|
|
254
117
|
this._unregisterDependency(dependency);
|
|
255
118
|
});
|
|
@@ -258,7 +121,7 @@ class FlowEffect {
|
|
|
258
121
|
/**
|
|
259
122
|
* Indicates whether this effect has been disposed.
|
|
260
123
|
*
|
|
261
|
-
* @returns A boolean value
|
|
124
|
+
* @returns A boolean value that is true if the effect is disposed, false otherwise.
|
|
262
125
|
*
|
|
263
126
|
* @public
|
|
264
127
|
*/
|
|
@@ -266,165 +129,191 @@ class FlowEffect {
|
|
|
266
129
|
return this._disposed;
|
|
267
130
|
}
|
|
268
131
|
/* INTERNAL ------------------------------------------------------------ */
|
|
269
|
-
/**
|
|
270
|
-
* @internal
|
|
271
|
-
*/
|
|
272
132
|
_disposed = false;
|
|
273
|
-
/**
|
|
274
|
-
* @internal
|
|
275
|
-
*/
|
|
276
133
|
_initialized = false;
|
|
277
|
-
/**
|
|
278
|
-
* @internal
|
|
279
|
-
*/
|
|
280
134
|
_dependencies = /* @__PURE__ */ new Set();
|
|
281
|
-
/**
|
|
282
|
-
* @internal
|
|
283
|
-
* A tracked getter that registers a dependency when accessing an observable.
|
|
284
|
-
*/
|
|
285
135
|
_trackedGet = (observable) => observable._getFrom(this);
|
|
286
|
-
/**
|
|
287
|
-
* @internal
|
|
288
|
-
* A tracked watcher that registers a dependency when watching a signal.
|
|
289
|
-
*/
|
|
290
136
|
_trackedWatch = (signal) => signal._watchFrom(this);
|
|
291
|
-
/**
|
|
292
|
-
* @internal
|
|
293
|
-
* An untracked getter that simply retrieves the current value from an observable.
|
|
294
|
-
*/
|
|
295
137
|
_untrackedGet = (observable) => observable.get();
|
|
296
|
-
/**
|
|
297
|
-
* @internal
|
|
298
|
-
* An untracked watcher that calls the default watch on a signal.
|
|
299
|
-
*/
|
|
300
138
|
_untrackedWatch = (signal) => signal._watch();
|
|
301
|
-
/**
|
|
302
|
-
* @internal
|
|
303
|
-
* Execution function used during initialization (tracked mode).
|
|
304
|
-
*/
|
|
305
139
|
_trackedExec;
|
|
306
|
-
/**
|
|
307
|
-
* @internal
|
|
308
|
-
* Execution function used after initialization (untracked mode).
|
|
309
|
-
*/
|
|
310
140
|
_untrackedExec;
|
|
311
|
-
|
|
312
|
-
* @internal
|
|
313
|
-
* Executes the effect. If the effect has not been initialized, it runs in tracked mode;
|
|
314
|
-
* otherwise, it runs in untracked mode.
|
|
315
|
-
*
|
|
316
|
-
* @throws Error if the effect has been disposed.
|
|
317
|
-
*/
|
|
141
|
+
/*@internal*/
|
|
318
142
|
_exec() {
|
|
319
|
-
if (this._disposed)
|
|
143
|
+
if (this._disposed)
|
|
144
|
+
throw new Error("[PicoFlow] Effect is disposed");
|
|
320
145
|
if (this._initialized) this._untrackedExec();
|
|
321
146
|
else {
|
|
322
147
|
this._trackedExec();
|
|
323
148
|
this._initialized = true;
|
|
324
149
|
}
|
|
325
150
|
}
|
|
326
|
-
|
|
327
|
-
* @internal
|
|
328
|
-
* Registers a dependency on the given signal.
|
|
329
|
-
*
|
|
330
|
-
* @param dependency - The FlowSignal to register as a dependency.
|
|
331
|
-
*/
|
|
151
|
+
/*@internal*/
|
|
332
152
|
_registerDependency(dependency) {
|
|
333
153
|
this._dependencies.add(dependency);
|
|
334
154
|
dependency._registerEffect(this);
|
|
335
155
|
}
|
|
336
|
-
|
|
337
|
-
* @internal
|
|
338
|
-
* Unregisters the given dependency.
|
|
339
|
-
*
|
|
340
|
-
* @param dependency - The FlowSignal to unregister.
|
|
341
|
-
*/
|
|
156
|
+
/*@internal*/
|
|
342
157
|
_unregisterDependency(dependency) {
|
|
343
158
|
this._dependencies.delete(dependency);
|
|
344
159
|
dependency._unregisterEffect(this);
|
|
345
160
|
}
|
|
346
161
|
}
|
|
347
162
|
|
|
348
|
-
class
|
|
163
|
+
class FlowObservable extends FlowSignal {
|
|
164
|
+
/* INTERNAL -------------------------------------------*/
|
|
165
|
+
/*@internal*/
|
|
166
|
+
_value;
|
|
167
|
+
/*@internal*/
|
|
168
|
+
_getFrom(listener) {
|
|
169
|
+
listener._registerDependency(this);
|
|
170
|
+
return this.get();
|
|
171
|
+
}
|
|
349
172
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* @param
|
|
173
|
+
* Subscribes a listener function to changes of the observable.
|
|
174
|
+
* The listener is executed immediately with the current value and on subsequent updates.
|
|
175
|
+
* @param listener - A callback function that receives the new value.
|
|
176
|
+
* @returns A disposer function to cancel the subscription.
|
|
177
|
+
*/
|
|
178
|
+
subscribe(listener) {
|
|
179
|
+
const effect = new FlowEffect((get) => {
|
|
180
|
+
listener(get(this));
|
|
181
|
+
});
|
|
182
|
+
return () => effect.dispose();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
class FlowConstant extends FlowObservable {
|
|
187
|
+
/**
|
|
188
|
+
* Creates a new FlowConstant instance.
|
|
189
|
+
*
|
|
190
|
+
* @param value - Either a direct value of type T or a function returning a value of type T for lazy initialization.
|
|
353
191
|
* @public
|
|
354
192
|
*/
|
|
355
|
-
constructor(
|
|
193
|
+
constructor(value) {
|
|
356
194
|
super();
|
|
357
|
-
this.
|
|
358
|
-
this._fetch = fetch;
|
|
195
|
+
this._initEager(value);
|
|
359
196
|
}
|
|
360
197
|
/**
|
|
361
|
-
* Retrieves the
|
|
362
|
-
*
|
|
363
|
-
*
|
|
198
|
+
* Retrieves the constant value, computing it lazily if needed.
|
|
199
|
+
*
|
|
200
|
+
* Accessing this method will initialize the value if it has not been computed already.
|
|
201
|
+
* Throws an error if the instance has been disposed or if lazy initialization fails.
|
|
202
|
+
*
|
|
203
|
+
* @returns The cached constant value.
|
|
204
|
+
* @throws Error if the constant is disposed or cannot be initialized.
|
|
364
205
|
* @public
|
|
365
206
|
*/
|
|
366
207
|
get() {
|
|
367
|
-
if (this._disposed) throw new Error("
|
|
208
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
209
|
+
this._initLazy();
|
|
368
210
|
return this._value;
|
|
369
211
|
}
|
|
212
|
+
/* INTERNAL --------------------------------------------------------- */
|
|
213
|
+
/*@internal*/
|
|
214
|
+
_initialized = false;
|
|
215
|
+
/*@internal*/
|
|
216
|
+
_init;
|
|
217
|
+
/*@internal*/
|
|
218
|
+
_initEager(value) {
|
|
219
|
+
if (typeof value === "function") {
|
|
220
|
+
this._init = value;
|
|
221
|
+
} else {
|
|
222
|
+
this._value = value;
|
|
223
|
+
this._initialized = true;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/*@internal*/
|
|
227
|
+
_initLazy() {
|
|
228
|
+
if (!this._initialized && this._init) {
|
|
229
|
+
this._value = this._init();
|
|
230
|
+
this._initialized = true;
|
|
231
|
+
}
|
|
232
|
+
if (!this._initialized)
|
|
233
|
+
throw new Error("[PicoFlow] Primitive can't be initialized");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
class FlowState extends FlowConstant {
|
|
370
238
|
/**
|
|
371
|
-
*
|
|
239
|
+
* Updates the state with a new value.
|
|
240
|
+
* @param value - A new value or a callback function that computes a new value based on the current state.
|
|
372
241
|
* @remarks
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* @
|
|
376
|
-
* @throws Error if the resource is disposed.
|
|
242
|
+
* If the computed new value is strictly equal to the current state value, no change is made and subscribers
|
|
243
|
+
* will not be notified. Otherwise, the state is updated and all subscribers are informed of the change.
|
|
244
|
+
* @throws Error if the state has been disposed.
|
|
377
245
|
* @public
|
|
378
246
|
*/
|
|
379
|
-
|
|
380
|
-
if (this._disposed) throw new Error("
|
|
381
|
-
const
|
|
382
|
-
if (
|
|
383
|
-
this._value =
|
|
247
|
+
set(value) {
|
|
248
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
249
|
+
const next = typeof value === "function" ? value(this._value) : value;
|
|
250
|
+
if (next === this._value) return;
|
|
251
|
+
this._value = next;
|
|
384
252
|
this._notify();
|
|
385
253
|
}
|
|
386
|
-
/* INTERNAL ------------------------------------------------ */
|
|
387
|
-
/**
|
|
388
|
-
* @internal
|
|
389
|
-
* The asynchronous function used to fetch the resource value.
|
|
390
|
-
*/
|
|
391
|
-
_fetch;
|
|
392
254
|
}
|
|
393
255
|
|
|
394
|
-
class
|
|
256
|
+
class FlowDerivation extends FlowObservable {
|
|
395
257
|
/**
|
|
396
|
-
* Creates a new
|
|
397
|
-
* @param
|
|
258
|
+
* Creates a new FlowDerivation.
|
|
259
|
+
* @param compute - A function that computes the derived value. It is provided with two parameters:
|
|
260
|
+
* a getter and a watcher that respect dependency tracking.
|
|
398
261
|
* @public
|
|
399
262
|
*/
|
|
400
|
-
constructor(
|
|
263
|
+
constructor(compute) {
|
|
401
264
|
super();
|
|
402
|
-
this.
|
|
265
|
+
this._initEager(compute);
|
|
403
266
|
}
|
|
404
267
|
/**
|
|
405
|
-
*
|
|
406
|
-
* @returns The current value
|
|
407
|
-
* @
|
|
268
|
+
* Gets the current derived value.
|
|
269
|
+
* @returns The current computed value.
|
|
270
|
+
* @remarks
|
|
271
|
+
* This method lazily initializes and updates the derivation if it is marked as dirty. It throws an error
|
|
272
|
+
* if the derivation has been disposed.
|
|
408
273
|
* @public
|
|
409
274
|
*/
|
|
410
275
|
get() {
|
|
411
|
-
if (this._disposed) throw new Error("
|
|
276
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
277
|
+
this._initLazy();
|
|
278
|
+
this._compute();
|
|
412
279
|
return this._value;
|
|
413
280
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
281
|
+
/* INTERNAL --------------------------------------------------------- */
|
|
282
|
+
_initialized = false;
|
|
283
|
+
_dirty = false;
|
|
284
|
+
_trackedGet = (observable) => observable._getFrom(this);
|
|
285
|
+
_trackedWatch = (signal) => signal._watchFrom(this);
|
|
286
|
+
_untrackedGet = (observable) => observable.get();
|
|
287
|
+
_untrackedWatch = (signal) => signal._watch();
|
|
288
|
+
_trackedCompute;
|
|
289
|
+
_untrackedCompute;
|
|
290
|
+
_initEager(compute) {
|
|
291
|
+
this._trackedCompute = () => compute(this._trackedGet, this._trackedWatch);
|
|
292
|
+
this._untrackedCompute = () => compute(this._untrackedGet, this._untrackedWatch);
|
|
293
|
+
}
|
|
294
|
+
_initLazy() {
|
|
295
|
+
if (!this._initialized) {
|
|
296
|
+
this._value = this._trackedCompute();
|
|
297
|
+
this._initialized = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/* @internal */
|
|
301
|
+
_compute() {
|
|
302
|
+
if (this._dirty) {
|
|
303
|
+
this._value = this._untrackedCompute();
|
|
304
|
+
this._dirty = false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/* @internal */
|
|
308
|
+
_notify() {
|
|
309
|
+
this._dirty = true;
|
|
310
|
+
super._notify();
|
|
311
|
+
}
|
|
312
|
+
/* @internal */
|
|
313
|
+
_watch() {
|
|
314
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
315
|
+
this._initLazy();
|
|
316
|
+
this._compute();
|
|
428
317
|
}
|
|
429
318
|
}
|
|
430
319
|
|
|
@@ -454,15 +343,16 @@ class FlowMap extends FlowState {
|
|
|
454
343
|
*
|
|
455
344
|
* @param key - The key at which to set the value.
|
|
456
345
|
* @param value - The value to set.
|
|
346
|
+
* @throws If the FlowMap instance is disposed.
|
|
457
347
|
*
|
|
458
348
|
* @remarks
|
|
459
|
-
*
|
|
460
|
-
*
|
|
349
|
+
* Updates the internal map, emits the key-value pair via {@link FlowMap.$lastSet},
|
|
350
|
+
* and notifies all subscribers of the change.
|
|
461
351
|
*
|
|
462
352
|
* @public
|
|
463
353
|
*/
|
|
464
354
|
setAt(key, value) {
|
|
465
|
-
if (this._disposed) throw new Error("
|
|
355
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
466
356
|
this._value.set(key, value);
|
|
467
357
|
this.$lastSet.set({ key, value });
|
|
468
358
|
this._notify();
|
|
@@ -471,16 +361,16 @@ class FlowMap extends FlowState {
|
|
|
471
361
|
* Deletes the value at the specified key from the underlying map.
|
|
472
362
|
*
|
|
473
363
|
* @param key - The key to delete.
|
|
364
|
+
* @throws If the FlowMap instance is disposed.
|
|
474
365
|
*
|
|
475
366
|
* @remarks
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
* of the change.
|
|
367
|
+
* Removes the key from the internal map, emits the deleted key and its value via {@link FlowMap.$lastDeleted},
|
|
368
|
+
* and notifies all subscribers of the change.
|
|
479
369
|
*
|
|
480
370
|
* @public
|
|
481
371
|
*/
|
|
482
372
|
delete(key) {
|
|
483
|
-
if (this._disposed) throw new Error("
|
|
373
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
484
374
|
const value = this._value.get(key);
|
|
485
375
|
this._value.delete(key);
|
|
486
376
|
this.$lastDeleted.set({ key, value });
|
|
@@ -489,29 +379,26 @@ class FlowMap extends FlowState {
|
|
|
489
379
|
}
|
|
490
380
|
|
|
491
381
|
class FlowStream extends FlowObservable {
|
|
492
|
-
/* API -------------------------------------------------------- */
|
|
493
382
|
/**
|
|
494
383
|
* Creates a new FlowStream.
|
|
495
384
|
* @param updater - A function that receives a setter to update the stream's value.
|
|
496
385
|
* It should return a disposer function that will be called upon disposal.
|
|
497
|
-
* @param initial - The initial value of the stream.
|
|
498
386
|
* @public
|
|
499
387
|
*/
|
|
500
|
-
constructor(updater
|
|
388
|
+
constructor(updater) {
|
|
501
389
|
super();
|
|
502
|
-
this._value = initial;
|
|
503
390
|
this._disposer = updater((value) => {
|
|
504
391
|
this._set(value);
|
|
505
392
|
});
|
|
506
393
|
}
|
|
507
394
|
/**
|
|
508
395
|
* Retrieves the current value of the stream.
|
|
509
|
-
* @returns The current value.
|
|
396
|
+
* @returns The current value, or undefined if no value has been set yet.
|
|
510
397
|
* @throws Error if the stream is disposed.
|
|
511
398
|
* @public
|
|
512
399
|
*/
|
|
513
400
|
get() {
|
|
514
|
-
if (this._disposed) throw new Error("
|
|
401
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
515
402
|
return this._value;
|
|
516
403
|
}
|
|
517
404
|
/**
|
|
@@ -526,36 +413,173 @@ class FlowStream extends FlowObservable {
|
|
|
526
413
|
this._disposer();
|
|
527
414
|
}
|
|
528
415
|
/* INTERNAL ------------------------------------------------------ */
|
|
416
|
+
_disposer;
|
|
417
|
+
_set(value) {
|
|
418
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
419
|
+
if (value === this._value) return;
|
|
420
|
+
this._value = value;
|
|
421
|
+
this._notify();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
class FlowStreamAsync extends FlowObservable {
|
|
529
426
|
/**
|
|
530
|
-
*
|
|
531
|
-
*
|
|
427
|
+
* Creates a new asynchronous FlowStream.
|
|
428
|
+
* @param updater - A function that receives a setter to update the stream's value.
|
|
429
|
+
* It should return a disposer function that will be called upon disposal.
|
|
430
|
+
* @remarks The updater function can invoke the setter asynchronously to update the stream.
|
|
431
|
+
* @public
|
|
532
432
|
*/
|
|
533
|
-
|
|
433
|
+
constructor(updater) {
|
|
434
|
+
super();
|
|
435
|
+
this._disposer = updater((value) => {
|
|
436
|
+
this._set(value);
|
|
437
|
+
});
|
|
438
|
+
this._value = new Promise((resolve) => {
|
|
439
|
+
this._resolve = resolve;
|
|
440
|
+
});
|
|
441
|
+
}
|
|
534
442
|
/**
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
* @
|
|
538
|
-
* @
|
|
443
|
+
* Retrieves the current value of the stream as a Promise.
|
|
444
|
+
* @returns A Promise that resolves to the current value.
|
|
445
|
+
* @throws Error if the stream is disposed.
|
|
446
|
+
* @public
|
|
539
447
|
*/
|
|
448
|
+
get() {
|
|
449
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
450
|
+
return this._value;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Disposes the stream, releasing all resources.
|
|
454
|
+
* @remarks In addition to disposing the underlying observable, this method calls the disposer
|
|
455
|
+
* returned by the updater.
|
|
456
|
+
* @public
|
|
457
|
+
*/
|
|
458
|
+
dispose() {
|
|
459
|
+
super.dispose();
|
|
460
|
+
this._disposer();
|
|
461
|
+
}
|
|
462
|
+
/* INTERNAL ------------------------------------------------------ */
|
|
463
|
+
_initialized = false;
|
|
464
|
+
_awaitedValue;
|
|
465
|
+
_resolve;
|
|
466
|
+
_disposer;
|
|
540
467
|
_set(value) {
|
|
541
|
-
if (this._disposed) throw new Error("
|
|
468
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
469
|
+
if (!this._initialized) {
|
|
470
|
+
this._resolve(value);
|
|
471
|
+
this._initialized = true;
|
|
472
|
+
this._awaitedValue = value;
|
|
473
|
+
this._notify();
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (value === this._awaitedValue) return;
|
|
477
|
+
this._value = Promise.resolve(value);
|
|
478
|
+
this._awaitedValue = value;
|
|
479
|
+
this._notify();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
class FlowResource extends FlowObservable {
|
|
484
|
+
/**
|
|
485
|
+
* Creates a new FlowResource.
|
|
486
|
+
* @param fetch - An asynchronous function that retrieves the resource's value.
|
|
487
|
+
*
|
|
488
|
+
* @public
|
|
489
|
+
*/
|
|
490
|
+
constructor(fetch) {
|
|
491
|
+
super();
|
|
492
|
+
this._fetch = fetch;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Retrieves the current resource value.
|
|
496
|
+
* @returns The current value, or undefined if the resource has not been fetched yet.
|
|
497
|
+
* @throws Error if the resource is disposed.
|
|
498
|
+
* @public
|
|
499
|
+
*/
|
|
500
|
+
get() {
|
|
501
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
502
|
+
return this._value;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Asynchronously fetches a new value for the resource.
|
|
506
|
+
* @remarks
|
|
507
|
+
* Executes the internal fetch function. If the fetched value differs from the current one,
|
|
508
|
+
* updates the resource's value and notifies subscribers.
|
|
509
|
+
* @returns A Promise that resolves when the fetch operation is complete.
|
|
510
|
+
* @throws Error if the resource is disposed.
|
|
511
|
+
* @public
|
|
512
|
+
*/
|
|
513
|
+
async fetch() {
|
|
514
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
515
|
+
const value = await this._fetch();
|
|
542
516
|
if (value === this._value) return;
|
|
543
517
|
this._value = value;
|
|
544
518
|
this._notify();
|
|
545
519
|
}
|
|
520
|
+
/* INTERNAL ------------------------------------------------ */
|
|
521
|
+
_fetch;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
class FlowResourceAsync extends FlowObservable {
|
|
525
|
+
/**
|
|
526
|
+
* Creates a new FlowResource.
|
|
527
|
+
* @param fetch - An asynchronous function that retrieves the resource's value.
|
|
528
|
+
* @public
|
|
529
|
+
*/
|
|
530
|
+
constructor(fetch) {
|
|
531
|
+
super();
|
|
532
|
+
this._fetch = fetch;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Retrieves the current resource value.
|
|
536
|
+
* @returns The current value, or undefined if the resource has not been fetched yet.
|
|
537
|
+
* @throws Error if the resource is disposed.
|
|
538
|
+
* @public
|
|
539
|
+
*/
|
|
540
|
+
get() {
|
|
541
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
542
|
+
if (!this._value) this._value = this._fetch();
|
|
543
|
+
return this._value;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Asynchronously fetches a new value for the resource.
|
|
547
|
+
* @remarks
|
|
548
|
+
* Executes the internal fetch function. If the fetched value differs from the current one,
|
|
549
|
+
* updates the resource's value and notifies subscribers.
|
|
550
|
+
* @returns A Promise that resolves when the fetch operation is complete.
|
|
551
|
+
* @throws Error if the resource is disposed.
|
|
552
|
+
* @public
|
|
553
|
+
*/
|
|
554
|
+
async fetch() {
|
|
555
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
556
|
+
this._value = this._fetch();
|
|
557
|
+
this._notify();
|
|
558
|
+
}
|
|
559
|
+
/* INTERNAL ------------------------------------------------ */
|
|
560
|
+
_fetch;
|
|
546
561
|
}
|
|
547
562
|
|
|
548
563
|
function signal() {
|
|
549
564
|
return new FlowSignal();
|
|
550
565
|
}
|
|
566
|
+
function constant(value) {
|
|
567
|
+
return new FlowConstant(value);
|
|
568
|
+
}
|
|
551
569
|
function state(value) {
|
|
552
570
|
return new FlowState(value);
|
|
553
571
|
}
|
|
554
|
-
function resource(fn
|
|
555
|
-
return new FlowResource(fn
|
|
572
|
+
function resource(fn) {
|
|
573
|
+
return new FlowResource(fn);
|
|
574
|
+
}
|
|
575
|
+
function resourceAsync(fn) {
|
|
576
|
+
return new FlowResourceAsync(fn);
|
|
577
|
+
}
|
|
578
|
+
function stream(updater) {
|
|
579
|
+
return new FlowStream(updater);
|
|
556
580
|
}
|
|
557
|
-
function
|
|
558
|
-
return new
|
|
581
|
+
function streamAsync(updater) {
|
|
582
|
+
return new FlowStreamAsync(updater);
|
|
559
583
|
}
|
|
560
584
|
function derivation(fn) {
|
|
561
585
|
return new FlowDerivation(fn);
|
|
@@ -569,4 +593,4 @@ function map(initial) {
|
|
|
569
593
|
);
|
|
570
594
|
}
|
|
571
595
|
|
|
572
|
-
export { derivation, effect, map, resource, signal, state, stream };
|
|
596
|
+
export { constant, derivation, effect, map, resource, resourceAsync, signal, state, stream, streamAsync };
|