@ersbeth/picoflow 0.0.1 → 0.2.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.array.md +55 -0
- 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.flowarray._constructor_.md +49 -0
- package/api/doc/picoflow.flowarray._lastaction.md +13 -0
- package/api/doc/picoflow.flowarray.clear.md +17 -0
- package/api/doc/picoflow.flowarray.dispose.md +55 -0
- package/api/doc/picoflow.flowarray.get.md +19 -0
- package/api/doc/picoflow.flowarray.length.md +13 -0
- package/api/doc/picoflow.flowarray.md +273 -0
- package/api/doc/picoflow.flowarray.pop.md +17 -0
- package/api/doc/picoflow.flowarray.push.md +53 -0
- package/api/doc/picoflow.flowarray.set.md +53 -0
- package/api/doc/picoflow.flowarray.setitem.md +69 -0
- package/api/doc/picoflow.flowarray.shift.md +17 -0
- package/api/doc/picoflow.flowarray.splice.md +85 -0
- package/api/doc/picoflow.flowarray.unshift.md +53 -0
- package/api/doc/picoflow.flowarrayaction.md +37 -0
- 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.flowdisposable.dispose.md +55 -0
- package/api/doc/picoflow.flowdisposable.md +43 -0
- 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 +42 -8
- package/api/doc/picoflow.flowsignal.disposed.md +2 -2
- package/api/doc/picoflow.flowsignal.md +8 -7
- 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.isdisposable.md +55 -0
- package/api/doc/picoflow.map.md +1 -1
- package/api/doc/picoflow.md +149 -13
- 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 +192 -0
- package/api-extractor.json +2 -1
- package/dist/picoflow.js +513 -305
- package/dist/types/advanced/array.d.ts +116 -0
- package/dist/types/advanced/array.d.ts.map +1 -0
- package/dist/types/advanced/index.d.ts +9 -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/disposable.d.ts +23 -0
- package/dist/types/basic/disposable.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 +11 -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 +40 -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 +38 -13
- package/dist/types/creators.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -9
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/advanced/array.ts +224 -0
- package/src/advanced/index.ts +12 -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/disposable.ts +27 -0
- package/src/basic/effect.ts +96 -0
- package/src/basic/index.ts +10 -0
- package/src/basic/observable.ts +51 -0
- package/src/basic/signal.ts +117 -0
- package/src/basic/state.ts +39 -0
- package/src/creators.ts +66 -15
- package/src/index.ts +26 -11
- package/test/array.test.ts +620 -0
- 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,236 +1,110 @@
|
|
|
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
|
-
dispose() {
|
|
24
|
-
if (this._disposed) throw new Error("
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
dispose(options) {
|
|
20
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
21
|
+
if (options?.self) {
|
|
22
|
+
Array.from(this._effects).forEach(
|
|
23
|
+
(effect) => effect._unregisterDependency(this)
|
|
24
|
+
);
|
|
25
|
+
Array.from(this._listeners).forEach(
|
|
26
|
+
(listener) => listener._unregisterDependency(this)
|
|
27
|
+
);
|
|
28
|
+
} else {
|
|
29
|
+
Array.from(this._effects).forEach((effect) => effect.dispose());
|
|
30
|
+
Array.from(this._listeners).forEach(
|
|
31
|
+
(listener) => listener.dispose()
|
|
32
|
+
);
|
|
33
|
+
}
|
|
27
34
|
Array.from(this._dependencies).forEach((dependency) => {
|
|
28
35
|
this._unregisterDependency(dependency);
|
|
29
36
|
});
|
|
30
37
|
this._disposed = true;
|
|
31
38
|
}
|
|
32
39
|
/**
|
|
33
|
-
* Indicates whether the
|
|
34
|
-
* @remarks
|
|
35
|
-
* Once disposed, the signal should not be used.
|
|
40
|
+
* Indicates whether the FlowSignal has been disposed.
|
|
41
|
+
* @remarks Once disposed, the signal should not be used.
|
|
36
42
|
* @public
|
|
37
43
|
*/
|
|
38
44
|
get disposed() {
|
|
39
45
|
return this._disposed;
|
|
40
46
|
}
|
|
41
47
|
/* INTERNAL ------------------------------------------------------------- */
|
|
42
|
-
|
|
43
|
-
* @internal
|
|
44
|
-
*/
|
|
48
|
+
/*@internal*/
|
|
45
49
|
_disposed = false;
|
|
46
|
-
|
|
47
|
-
* @internal
|
|
48
|
-
*/
|
|
50
|
+
/*@internal*/
|
|
49
51
|
_dependencies = /* @__PURE__ */ new Set();
|
|
50
|
-
|
|
51
|
-
* @internal
|
|
52
|
-
*/
|
|
52
|
+
/*@internal*/
|
|
53
53
|
_listeners = /* @__PURE__ */ new Set();
|
|
54
|
-
|
|
55
|
-
* @internal
|
|
56
|
-
*/
|
|
54
|
+
/*@internal*/
|
|
57
55
|
_effects = /* @__PURE__ */ new Set();
|
|
58
|
-
|
|
59
|
-
* @internal
|
|
60
|
-
* Internal method to watch the signal.
|
|
61
|
-
* @throws Error if the signal is disposed.
|
|
62
|
-
*/
|
|
56
|
+
/*@internal*/
|
|
63
57
|
_watch() {
|
|
64
|
-
if (this._disposed) throw new Error("
|
|
58
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
65
59
|
}
|
|
66
|
-
|
|
67
|
-
* @internal
|
|
68
|
-
* Notifies all listeners and executes all registered effects.
|
|
69
|
-
*/
|
|
60
|
+
/*@internal*/
|
|
70
61
|
_notify() {
|
|
71
62
|
this._listeners.forEach((listener) => listener._notify());
|
|
72
63
|
this._effects.forEach((effect) => effect._exec());
|
|
73
64
|
}
|
|
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
|
-
*/
|
|
65
|
+
/*@internal*/
|
|
79
66
|
_watchFrom(listener) {
|
|
80
67
|
listener._registerDependency(this);
|
|
81
68
|
this._watch();
|
|
82
69
|
}
|
|
83
|
-
|
|
84
|
-
* @internal
|
|
85
|
-
* Registers a dependency with the given FlowSignal.
|
|
86
|
-
* @param dependency - The FlowSignal to register as a dependency.
|
|
87
|
-
*/
|
|
70
|
+
/*@internal*/
|
|
88
71
|
_registerDependency(dependency) {
|
|
89
72
|
this._dependencies.add(dependency);
|
|
90
73
|
dependency._registerListener(this);
|
|
91
74
|
}
|
|
92
|
-
|
|
93
|
-
* @internal
|
|
94
|
-
* Unregisters the given dependency.
|
|
95
|
-
* @param dependency - The FlowSignal to unregister.
|
|
96
|
-
*/
|
|
75
|
+
/*@internal*/
|
|
97
76
|
_unregisterDependency(dependency) {
|
|
98
77
|
this._dependencies.delete(dependency);
|
|
99
78
|
dependency._unregisterListener(this);
|
|
100
79
|
}
|
|
101
|
-
|
|
102
|
-
* @internal
|
|
103
|
-
* Registers a listener (another FlowSignal) to this signal.
|
|
104
|
-
* @param signal - The FlowSignal to register as a listener.
|
|
105
|
-
*/
|
|
80
|
+
/*@internal*/
|
|
106
81
|
_registerListener(signal) {
|
|
107
82
|
this._listeners.add(signal);
|
|
108
83
|
}
|
|
109
|
-
|
|
110
|
-
* @internal
|
|
111
|
-
* Unregisters the given listener.
|
|
112
|
-
* @param signal - The FlowSignal to unregister.
|
|
113
|
-
*/
|
|
84
|
+
/*@internal*/
|
|
114
85
|
_unregisterListener(signal) {
|
|
115
86
|
this._listeners.delete(signal);
|
|
116
87
|
}
|
|
117
|
-
|
|
118
|
-
* @internal
|
|
119
|
-
* Registers a FlowEffect to this signal.
|
|
120
|
-
* @param effect - The FlowEffect to register.
|
|
121
|
-
*/
|
|
88
|
+
/*@internal*/
|
|
122
89
|
_registerEffect(effect) {
|
|
123
90
|
this._effects.add(effect);
|
|
124
91
|
}
|
|
125
|
-
|
|
126
|
-
* @internal
|
|
127
|
-
* Unregisters the given FlowEffect.
|
|
128
|
-
* @param effect - The FlowEffect to unregister.
|
|
129
|
-
*/
|
|
92
|
+
/*@internal*/
|
|
130
93
|
_unregisterEffect(effect) {
|
|
131
94
|
this._effects.delete(effect);
|
|
132
95
|
}
|
|
133
96
|
}
|
|
134
97
|
|
|
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
98
|
class FlowEffect {
|
|
228
|
-
/* API --------------------------------------------------- */
|
|
229
99
|
/**
|
|
230
100
|
* Creates a new FlowEffect.
|
|
231
101
|
*
|
|
232
|
-
* @param apply - A function that
|
|
233
|
-
*
|
|
102
|
+
* @param apply - A side-effect function that receives a getter and a watcher to
|
|
103
|
+
* access and register dependencies on reactive observables and signals.
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* The provided function is executed immediately in a tracked mode to collect dependencies.
|
|
107
|
+
* On subsequent executions, it runs in an untracked mode.
|
|
234
108
|
*
|
|
235
109
|
* @public
|
|
236
110
|
*/
|
|
@@ -240,16 +114,16 @@ class FlowEffect {
|
|
|
240
114
|
this._exec();
|
|
241
115
|
}
|
|
242
116
|
/**
|
|
243
|
-
* Disposes the effect, unregistering all its dependencies.
|
|
117
|
+
* Disposes the effect, unregistering all its tracked dependencies.
|
|
244
118
|
*
|
|
245
119
|
* @remarks
|
|
246
|
-
*
|
|
247
|
-
* disposed
|
|
120
|
+
* Once disposed, the effect must no longer be used. Trying to dispose an effect
|
|
121
|
+
* that is already disposed will throw an error.
|
|
248
122
|
*
|
|
249
123
|
* @public
|
|
250
124
|
*/
|
|
251
125
|
dispose() {
|
|
252
|
-
if (this._disposed) throw new Error("Effect is disposed");
|
|
126
|
+
if (this._disposed) throw new Error("[PicoFlow] Effect is disposed");
|
|
253
127
|
Array.from(this._dependencies).forEach((dependency) => {
|
|
254
128
|
this._unregisterDependency(dependency);
|
|
255
129
|
});
|
|
@@ -258,7 +132,7 @@ class FlowEffect {
|
|
|
258
132
|
/**
|
|
259
133
|
* Indicates whether this effect has been disposed.
|
|
260
134
|
*
|
|
261
|
-
* @returns A boolean value
|
|
135
|
+
* @returns A boolean value that is true if the effect is disposed, false otherwise.
|
|
262
136
|
*
|
|
263
137
|
* @public
|
|
264
138
|
*/
|
|
@@ -266,168 +140,198 @@ class FlowEffect {
|
|
|
266
140
|
return this._disposed;
|
|
267
141
|
}
|
|
268
142
|
/* INTERNAL ------------------------------------------------------------ */
|
|
269
|
-
/**
|
|
270
|
-
* @internal
|
|
271
|
-
*/
|
|
272
143
|
_disposed = false;
|
|
273
|
-
/**
|
|
274
|
-
* @internal
|
|
275
|
-
*/
|
|
276
144
|
_initialized = false;
|
|
277
|
-
/**
|
|
278
|
-
* @internal
|
|
279
|
-
*/
|
|
280
145
|
_dependencies = /* @__PURE__ */ new Set();
|
|
281
|
-
/**
|
|
282
|
-
* @internal
|
|
283
|
-
* A tracked getter that registers a dependency when accessing an observable.
|
|
284
|
-
*/
|
|
285
146
|
_trackedGet = (observable) => observable._getFrom(this);
|
|
286
|
-
/**
|
|
287
|
-
* @internal
|
|
288
|
-
* A tracked watcher that registers a dependency when watching a signal.
|
|
289
|
-
*/
|
|
290
147
|
_trackedWatch = (signal) => signal._watchFrom(this);
|
|
291
|
-
/**
|
|
292
|
-
* @internal
|
|
293
|
-
* An untracked getter that simply retrieves the current value from an observable.
|
|
294
|
-
*/
|
|
295
148
|
_untrackedGet = (observable) => observable.get();
|
|
296
|
-
/**
|
|
297
|
-
* @internal
|
|
298
|
-
* An untracked watcher that calls the default watch on a signal.
|
|
299
|
-
*/
|
|
300
149
|
_untrackedWatch = (signal) => signal._watch();
|
|
301
|
-
/**
|
|
302
|
-
* @internal
|
|
303
|
-
* Execution function used during initialization (tracked mode).
|
|
304
|
-
*/
|
|
305
150
|
_trackedExec;
|
|
306
|
-
/**
|
|
307
|
-
* @internal
|
|
308
|
-
* Execution function used after initialization (untracked mode).
|
|
309
|
-
*/
|
|
310
151
|
_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
|
-
*/
|
|
152
|
+
/*@internal*/
|
|
318
153
|
_exec() {
|
|
319
|
-
if (this._disposed)
|
|
154
|
+
if (this._disposed)
|
|
155
|
+
throw new Error("[PicoFlow] Effect is disposed");
|
|
320
156
|
if (this._initialized) this._untrackedExec();
|
|
321
157
|
else {
|
|
322
158
|
this._trackedExec();
|
|
323
159
|
this._initialized = true;
|
|
324
160
|
}
|
|
325
161
|
}
|
|
326
|
-
|
|
327
|
-
* @internal
|
|
328
|
-
* Registers a dependency on the given signal.
|
|
329
|
-
*
|
|
330
|
-
* @param dependency - The FlowSignal to register as a dependency.
|
|
331
|
-
*/
|
|
162
|
+
/*@internal*/
|
|
332
163
|
_registerDependency(dependency) {
|
|
333
164
|
this._dependencies.add(dependency);
|
|
334
165
|
dependency._registerEffect(this);
|
|
335
166
|
}
|
|
336
|
-
|
|
337
|
-
* @internal
|
|
338
|
-
* Unregisters the given dependency.
|
|
339
|
-
*
|
|
340
|
-
* @param dependency - The FlowSignal to unregister.
|
|
341
|
-
*/
|
|
167
|
+
/*@internal*/
|
|
342
168
|
_unregisterDependency(dependency) {
|
|
343
169
|
this._dependencies.delete(dependency);
|
|
344
170
|
dependency._unregisterEffect(this);
|
|
345
171
|
}
|
|
346
172
|
}
|
|
347
173
|
|
|
348
|
-
class
|
|
174
|
+
class FlowObservable extends FlowSignal {
|
|
175
|
+
/* INTERNAL -------------------------------------------*/
|
|
176
|
+
/*@internal*/
|
|
177
|
+
_value;
|
|
178
|
+
/*@internal*/
|
|
179
|
+
_getFrom(listener) {
|
|
180
|
+
listener._registerDependency(this);
|
|
181
|
+
return this.get();
|
|
182
|
+
}
|
|
349
183
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* @param
|
|
184
|
+
* Subscribes a listener function to changes of the observable.
|
|
185
|
+
* The listener is executed immediately with the current value and on subsequent updates.
|
|
186
|
+
* @param listener - A callback function that receives the new value.
|
|
187
|
+
* @returns A disposer function to cancel the subscription.
|
|
188
|
+
*/
|
|
189
|
+
subscribe(listener) {
|
|
190
|
+
const effect = new FlowEffect((get) => {
|
|
191
|
+
listener(get(this));
|
|
192
|
+
});
|
|
193
|
+
return () => effect.dispose();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
class FlowConstant extends FlowObservable {
|
|
198
|
+
/**
|
|
199
|
+
* Creates a new FlowConstant instance.
|
|
200
|
+
*
|
|
201
|
+
* @param value - Either a direct value of type T or a function returning a value of type T for lazy initialization.
|
|
353
202
|
* @public
|
|
354
203
|
*/
|
|
355
|
-
constructor(
|
|
204
|
+
constructor(value) {
|
|
356
205
|
super();
|
|
357
|
-
this.
|
|
358
|
-
this._fetch = fetch;
|
|
206
|
+
this._initEager(value);
|
|
359
207
|
}
|
|
360
208
|
/**
|
|
361
|
-
* Retrieves the
|
|
362
|
-
*
|
|
363
|
-
*
|
|
209
|
+
* Retrieves the constant value, computing it lazily if needed.
|
|
210
|
+
*
|
|
211
|
+
* Accessing this method will initialize the value if it has not been computed already.
|
|
212
|
+
* Throws an error if the instance has been disposed or if lazy initialization fails.
|
|
213
|
+
*
|
|
214
|
+
* @returns The cached constant value.
|
|
215
|
+
* @throws Error if the constant is disposed or cannot be initialized.
|
|
364
216
|
* @public
|
|
365
217
|
*/
|
|
366
218
|
get() {
|
|
367
|
-
if (this._disposed) throw new Error("
|
|
219
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
220
|
+
this._initLazy();
|
|
368
221
|
return this._value;
|
|
369
222
|
}
|
|
223
|
+
/* INTERNAL --------------------------------------------------------- */
|
|
224
|
+
/*@internal*/
|
|
225
|
+
_initialized = false;
|
|
226
|
+
/*@internal*/
|
|
227
|
+
_init;
|
|
228
|
+
/*@internal*/
|
|
229
|
+
_initEager(value) {
|
|
230
|
+
if (typeof value === "function") {
|
|
231
|
+
this._init = value;
|
|
232
|
+
} else {
|
|
233
|
+
this._value = value;
|
|
234
|
+
this._initialized = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/*@internal*/
|
|
238
|
+
_initLazy() {
|
|
239
|
+
if (!this._initialized && this._init) {
|
|
240
|
+
this._value = this._init();
|
|
241
|
+
this._initialized = true;
|
|
242
|
+
}
|
|
243
|
+
if (!this._initialized)
|
|
244
|
+
throw new Error("[PicoFlow] Primitive can't be initialized");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
class FlowState extends FlowConstant {
|
|
370
249
|
/**
|
|
371
|
-
*
|
|
250
|
+
* Updates the state with a new value.
|
|
251
|
+
* @param value - A new value or a callback function that computes a new value based on the current state.
|
|
372
252
|
* @remarks
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* @
|
|
376
|
-
* @throws Error if the resource is disposed.
|
|
253
|
+
* If the computed new value is strictly equal to the current state value, no change is made and subscribers
|
|
254
|
+
* will not be notified. Otherwise, the state is updated and all subscribers are informed of the change.
|
|
255
|
+
* @throws Error if the state has been disposed.
|
|
377
256
|
* @public
|
|
378
257
|
*/
|
|
379
|
-
|
|
380
|
-
if (this._disposed) throw new Error("
|
|
381
|
-
const
|
|
382
|
-
if (
|
|
383
|
-
this._value =
|
|
258
|
+
set(value) {
|
|
259
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
260
|
+
const next = typeof value === "function" ? value(this._value) : value;
|
|
261
|
+
if (next === this._value) return;
|
|
262
|
+
this._value = next;
|
|
384
263
|
this._notify();
|
|
385
264
|
}
|
|
386
|
-
/* INTERNAL ------------------------------------------------ */
|
|
387
|
-
/**
|
|
388
|
-
* @internal
|
|
389
|
-
* The asynchronous function used to fetch the resource value.
|
|
390
|
-
*/
|
|
391
|
-
_fetch;
|
|
392
265
|
}
|
|
393
266
|
|
|
394
|
-
class
|
|
267
|
+
class FlowDerivation extends FlowObservable {
|
|
395
268
|
/**
|
|
396
|
-
* Creates a new
|
|
397
|
-
* @param
|
|
269
|
+
* Creates a new FlowDerivation.
|
|
270
|
+
* @param compute - A function that computes the derived value. It is provided with two parameters:
|
|
271
|
+
* a getter and a watcher that respect dependency tracking.
|
|
398
272
|
* @public
|
|
399
273
|
*/
|
|
400
|
-
constructor(
|
|
274
|
+
constructor(compute) {
|
|
401
275
|
super();
|
|
402
|
-
this.
|
|
276
|
+
this._initEager(compute);
|
|
403
277
|
}
|
|
404
278
|
/**
|
|
405
|
-
*
|
|
406
|
-
* @returns The current value
|
|
407
|
-
* @
|
|
279
|
+
* Gets the current derived value.
|
|
280
|
+
* @returns The current computed value.
|
|
281
|
+
* @remarks
|
|
282
|
+
* This method lazily initializes and updates the derivation if it is marked as dirty. It throws an error
|
|
283
|
+
* if the derivation has been disposed.
|
|
408
284
|
* @public
|
|
409
285
|
*/
|
|
410
286
|
get() {
|
|
411
|
-
if (this._disposed) throw new Error("
|
|
287
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
288
|
+
this._initLazy();
|
|
289
|
+
this._compute();
|
|
412
290
|
return this._value;
|
|
413
291
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
292
|
+
/* INTERNAL --------------------------------------------------------- */
|
|
293
|
+
_initialized = false;
|
|
294
|
+
_dirty = false;
|
|
295
|
+
_trackedGet = (observable) => observable._getFrom(this);
|
|
296
|
+
_trackedWatch = (signal) => signal._watchFrom(this);
|
|
297
|
+
_untrackedGet = (observable) => observable.get();
|
|
298
|
+
_untrackedWatch = (signal) => signal._watch();
|
|
299
|
+
_trackedCompute;
|
|
300
|
+
_untrackedCompute;
|
|
301
|
+
_initEager(compute) {
|
|
302
|
+
this._trackedCompute = () => compute(this._trackedGet, this._trackedWatch);
|
|
303
|
+
this._untrackedCompute = () => compute(this._untrackedGet, this._untrackedWatch);
|
|
304
|
+
}
|
|
305
|
+
_initLazy() {
|
|
306
|
+
if (!this._initialized) {
|
|
307
|
+
this._value = this._trackedCompute();
|
|
308
|
+
this._initialized = true;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/* @internal */
|
|
312
|
+
_compute() {
|
|
313
|
+
if (this._dirty) {
|
|
314
|
+
this._value = this._untrackedCompute();
|
|
315
|
+
this._dirty = false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/* @internal */
|
|
319
|
+
_notify() {
|
|
320
|
+
this._dirty = true;
|
|
321
|
+
super._notify();
|
|
322
|
+
}
|
|
323
|
+
/* @internal */
|
|
324
|
+
_watch() {
|
|
325
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
326
|
+
this._initLazy();
|
|
327
|
+
this._compute();
|
|
428
328
|
}
|
|
429
329
|
}
|
|
430
330
|
|
|
331
|
+
function isDisposable(obj) {
|
|
332
|
+
return obj !== null && obj !== void 0 && typeof obj.dispose === "function";
|
|
333
|
+
}
|
|
334
|
+
|
|
431
335
|
class FlowMap extends FlowState {
|
|
432
336
|
/**
|
|
433
337
|
* A reactive state that holds the most recent key and value that were set.
|
|
@@ -454,15 +358,16 @@ class FlowMap extends FlowState {
|
|
|
454
358
|
*
|
|
455
359
|
* @param key - The key at which to set the value.
|
|
456
360
|
* @param value - The value to set.
|
|
361
|
+
* @throws If the FlowMap instance is disposed.
|
|
457
362
|
*
|
|
458
363
|
* @remarks
|
|
459
|
-
*
|
|
460
|
-
*
|
|
364
|
+
* Updates the internal map, emits the key-value pair via {@link FlowMap.$lastSet},
|
|
365
|
+
* and notifies all subscribers of the change.
|
|
461
366
|
*
|
|
462
367
|
* @public
|
|
463
368
|
*/
|
|
464
369
|
setAt(key, value) {
|
|
465
|
-
if (this._disposed) throw new Error("
|
|
370
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
466
371
|
this._value.set(key, value);
|
|
467
372
|
this.$lastSet.set({ key, value });
|
|
468
373
|
this._notify();
|
|
@@ -471,16 +376,16 @@ class FlowMap extends FlowState {
|
|
|
471
376
|
* Deletes the value at the specified key from the underlying map.
|
|
472
377
|
*
|
|
473
378
|
* @param key - The key to delete.
|
|
379
|
+
* @throws If the FlowMap instance is disposed.
|
|
474
380
|
*
|
|
475
381
|
* @remarks
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
* of the change.
|
|
382
|
+
* Removes the key from the internal map, emits the deleted key and its value via {@link FlowMap.$lastDeleted},
|
|
383
|
+
* and notifies all subscribers of the change.
|
|
479
384
|
*
|
|
480
385
|
* @public
|
|
481
386
|
*/
|
|
482
387
|
delete(key) {
|
|
483
|
-
if (this._disposed) throw new Error("
|
|
388
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
484
389
|
const value = this._value.get(key);
|
|
485
390
|
this._value.delete(key);
|
|
486
391
|
this.$lastDeleted.set({ key, value });
|
|
@@ -489,29 +394,26 @@ class FlowMap extends FlowState {
|
|
|
489
394
|
}
|
|
490
395
|
|
|
491
396
|
class FlowStream extends FlowObservable {
|
|
492
|
-
/* API -------------------------------------------------------- */
|
|
493
397
|
/**
|
|
494
398
|
* Creates a new FlowStream.
|
|
495
399
|
* @param updater - A function that receives a setter to update the stream's value.
|
|
496
400
|
* It should return a disposer function that will be called upon disposal.
|
|
497
|
-
* @param initial - The initial value of the stream.
|
|
498
401
|
* @public
|
|
499
402
|
*/
|
|
500
|
-
constructor(updater
|
|
403
|
+
constructor(updater) {
|
|
501
404
|
super();
|
|
502
|
-
this._value = initial;
|
|
503
405
|
this._disposer = updater((value) => {
|
|
504
406
|
this._set(value);
|
|
505
407
|
});
|
|
506
408
|
}
|
|
507
409
|
/**
|
|
508
410
|
* Retrieves the current value of the stream.
|
|
509
|
-
* @returns The current value.
|
|
411
|
+
* @returns The current value, or undefined if no value has been set yet.
|
|
510
412
|
* @throws Error if the stream is disposed.
|
|
511
413
|
* @public
|
|
512
414
|
*/
|
|
513
415
|
get() {
|
|
514
|
-
if (this._disposed) throw new Error("
|
|
416
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
515
417
|
return this._value;
|
|
516
418
|
}
|
|
517
419
|
/**
|
|
@@ -526,36 +428,339 @@ class FlowStream extends FlowObservable {
|
|
|
526
428
|
this._disposer();
|
|
527
429
|
}
|
|
528
430
|
/* INTERNAL ------------------------------------------------------ */
|
|
431
|
+
_disposer;
|
|
432
|
+
_set(value) {
|
|
433
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
434
|
+
if (value === this._value) return;
|
|
435
|
+
this._value = value;
|
|
436
|
+
this._notify();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
class FlowStreamAsync extends FlowObservable {
|
|
529
441
|
/**
|
|
530
|
-
*
|
|
531
|
-
*
|
|
442
|
+
* Creates a new asynchronous FlowStream.
|
|
443
|
+
* @param updater - A function that receives a setter to update the stream's value.
|
|
444
|
+
* It should return a disposer function that will be called upon disposal.
|
|
445
|
+
* @remarks The updater function can invoke the setter asynchronously to update the stream.
|
|
446
|
+
* @public
|
|
532
447
|
*/
|
|
533
|
-
|
|
448
|
+
constructor(updater) {
|
|
449
|
+
super();
|
|
450
|
+
this._disposer = updater((value) => {
|
|
451
|
+
this._set(value);
|
|
452
|
+
});
|
|
453
|
+
this._value = new Promise((resolve) => {
|
|
454
|
+
this._resolve = resolve;
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Retrieves the current value of the stream as a Promise.
|
|
459
|
+
* @returns A Promise that resolves to the current value.
|
|
460
|
+
* @throws Error if the stream is disposed.
|
|
461
|
+
* @public
|
|
462
|
+
*/
|
|
463
|
+
get() {
|
|
464
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
465
|
+
return this._value;
|
|
466
|
+
}
|
|
534
467
|
/**
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
* @
|
|
468
|
+
* Disposes the stream, releasing all resources.
|
|
469
|
+
* @remarks In addition to disposing the underlying observable, this method calls the disposer
|
|
470
|
+
* returned by the updater.
|
|
471
|
+
* @public
|
|
539
472
|
*/
|
|
473
|
+
dispose() {
|
|
474
|
+
super.dispose();
|
|
475
|
+
this._disposer();
|
|
476
|
+
}
|
|
477
|
+
/* INTERNAL ------------------------------------------------------ */
|
|
478
|
+
_initialized = false;
|
|
479
|
+
_awaitedValue;
|
|
480
|
+
_resolve;
|
|
481
|
+
_disposer;
|
|
540
482
|
_set(value) {
|
|
541
|
-
if (this._disposed) throw new Error("
|
|
483
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
484
|
+
if (!this._initialized) {
|
|
485
|
+
this._resolve(value);
|
|
486
|
+
this._initialized = true;
|
|
487
|
+
this._awaitedValue = value;
|
|
488
|
+
this._notify();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (value === this._awaitedValue) return;
|
|
492
|
+
this._value = Promise.resolve(value);
|
|
493
|
+
this._awaitedValue = value;
|
|
494
|
+
this._notify();
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
class FlowResource extends FlowObservable {
|
|
499
|
+
/**
|
|
500
|
+
* Creates a new FlowResource.
|
|
501
|
+
* @param fetch - An asynchronous function that retrieves the resource's value.
|
|
502
|
+
*
|
|
503
|
+
* @public
|
|
504
|
+
*/
|
|
505
|
+
constructor(fetch) {
|
|
506
|
+
super();
|
|
507
|
+
this._fetch = fetch;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Retrieves the current resource value.
|
|
511
|
+
* @returns The current value, or undefined if the resource has not been fetched yet.
|
|
512
|
+
* @throws Error if the resource is disposed.
|
|
513
|
+
* @public
|
|
514
|
+
*/
|
|
515
|
+
get() {
|
|
516
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
517
|
+
return this._value;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Asynchronously fetches a new value for the resource.
|
|
521
|
+
* @remarks
|
|
522
|
+
* Executes the internal fetch function. If the fetched value differs from the current one,
|
|
523
|
+
* updates the resource's value and notifies subscribers.
|
|
524
|
+
* @returns A Promise that resolves when the fetch operation is complete.
|
|
525
|
+
* @throws Error if the resource is disposed.
|
|
526
|
+
* @public
|
|
527
|
+
*/
|
|
528
|
+
async fetch() {
|
|
529
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
530
|
+
const value = await this._fetch();
|
|
542
531
|
if (value === this._value) return;
|
|
543
532
|
this._value = value;
|
|
544
533
|
this._notify();
|
|
545
534
|
}
|
|
535
|
+
/* INTERNAL ------------------------------------------------ */
|
|
536
|
+
_fetch;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
class FlowResourceAsync extends FlowObservable {
|
|
540
|
+
/**
|
|
541
|
+
* Creates a new FlowResource.
|
|
542
|
+
* @param fetch - An asynchronous function that retrieves the resource's value.
|
|
543
|
+
* @public
|
|
544
|
+
*/
|
|
545
|
+
constructor(fetch) {
|
|
546
|
+
super();
|
|
547
|
+
this._fetch = fetch;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Retrieves the current resource value.
|
|
551
|
+
* @returns The current value, or undefined if the resource has not been fetched yet.
|
|
552
|
+
* @throws Error if the resource is disposed.
|
|
553
|
+
* @public
|
|
554
|
+
*/
|
|
555
|
+
get() {
|
|
556
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
557
|
+
if (!this._value) this._value = this._fetch();
|
|
558
|
+
return this._value;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Asynchronously fetches a new value for the resource.
|
|
562
|
+
* @remarks
|
|
563
|
+
* Executes the internal fetch function. If the fetched value differs from the current one,
|
|
564
|
+
* updates the resource's value and notifies subscribers.
|
|
565
|
+
* @returns A Promise that resolves when the fetch operation is complete.
|
|
566
|
+
* @throws Error if the resource is disposed.
|
|
567
|
+
* @public
|
|
568
|
+
*/
|
|
569
|
+
async fetch() {
|
|
570
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
571
|
+
this._value = this._fetch();
|
|
572
|
+
this._notify();
|
|
573
|
+
}
|
|
574
|
+
/* INTERNAL ------------------------------------------------ */
|
|
575
|
+
_fetch;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
class FlowArray extends FlowObservable {
|
|
579
|
+
/**
|
|
580
|
+
* Last action performed on the FlowArray.
|
|
581
|
+
* @public
|
|
582
|
+
*/
|
|
583
|
+
$lastAction;
|
|
584
|
+
/**
|
|
585
|
+
* Creates an instance of FlowArray.
|
|
586
|
+
* @param value - Initial array value.
|
|
587
|
+
* @public
|
|
588
|
+
*/
|
|
589
|
+
constructor(value = []) {
|
|
590
|
+
super();
|
|
591
|
+
this._value = value;
|
|
592
|
+
this.$lastAction = state({
|
|
593
|
+
type: "set",
|
|
594
|
+
items: value
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Gets the current length of the array.
|
|
599
|
+
* @returns The length of the array.
|
|
600
|
+
* @public
|
|
601
|
+
*/
|
|
602
|
+
get length() {
|
|
603
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
604
|
+
return this._value.length;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Returns a copy of the internal array.
|
|
608
|
+
* @returns A copy of the array.
|
|
609
|
+
* @public
|
|
610
|
+
*/
|
|
611
|
+
get() {
|
|
612
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
613
|
+
return [...this._value];
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Replaces the entire array with new items.
|
|
617
|
+
* @param items - The new array of items.
|
|
618
|
+
* @public
|
|
619
|
+
*/
|
|
620
|
+
set(items) {
|
|
621
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
622
|
+
this._value.forEach((item) => {
|
|
623
|
+
if (isDisposable(item)) item.dispose({ self: true });
|
|
624
|
+
});
|
|
625
|
+
this._value = items;
|
|
626
|
+
this._notify();
|
|
627
|
+
this.$lastAction.set({ type: "set", items });
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Replaces an item at a specific index.
|
|
631
|
+
* @param index - The index of the item to replace.
|
|
632
|
+
* @param item - The new item.
|
|
633
|
+
* @public
|
|
634
|
+
*/
|
|
635
|
+
setItem(index, item) {
|
|
636
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
637
|
+
if (index < 0 || index >= this._value.length) {
|
|
638
|
+
throw new Error("[PicoFlow] Index out of bounds");
|
|
639
|
+
}
|
|
640
|
+
this._value[index] = item;
|
|
641
|
+
this._notify();
|
|
642
|
+
this.$lastAction.set({ type: "setItem", index, item });
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Appends an item to the end of the array.
|
|
646
|
+
* @param item - The item to append.
|
|
647
|
+
* @public
|
|
648
|
+
*/
|
|
649
|
+
push(item) {
|
|
650
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
651
|
+
this._value.push(item);
|
|
652
|
+
this._notify();
|
|
653
|
+
this.$lastAction.set({ type: "push", item });
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Removes the last item from the array.
|
|
657
|
+
* @public
|
|
658
|
+
*/
|
|
659
|
+
pop() {
|
|
660
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
661
|
+
const item = this._value.pop();
|
|
662
|
+
if (isDisposable(item)) {
|
|
663
|
+
item.dispose({ self: true });
|
|
664
|
+
}
|
|
665
|
+
this._notify();
|
|
666
|
+
this.$lastAction.set({ type: "pop" });
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Inserts an item at the beginning of the array.
|
|
670
|
+
* @param item - The item to insert.
|
|
671
|
+
* @public
|
|
672
|
+
*/
|
|
673
|
+
unshift(item) {
|
|
674
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
675
|
+
this._value.unshift(item);
|
|
676
|
+
this._notify();
|
|
677
|
+
this.$lastAction.set({ type: "unshift", item });
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Removes the first item from the array.
|
|
681
|
+
* @public
|
|
682
|
+
*/
|
|
683
|
+
shift() {
|
|
684
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
685
|
+
const item = this._value.shift();
|
|
686
|
+
if (isDisposable(item)) {
|
|
687
|
+
item.dispose({ self: true });
|
|
688
|
+
}
|
|
689
|
+
this._notify();
|
|
690
|
+
this.$lastAction.set({ type: "shift" });
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Changes the content of the array.
|
|
694
|
+
* @param start - The starting index.
|
|
695
|
+
* @param deleteCount - Number of items to remove.
|
|
696
|
+
* @param newItems - New items to add.
|
|
697
|
+
* @public
|
|
698
|
+
*/
|
|
699
|
+
splice(start, deleteCount, ...newItems) {
|
|
700
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
701
|
+
const items = this._value.splice(start, deleteCount, ...newItems);
|
|
702
|
+
items.forEach((item) => {
|
|
703
|
+
if (isDisposable(item)) item.dispose({ self: true });
|
|
704
|
+
});
|
|
705
|
+
this._notify();
|
|
706
|
+
this.$lastAction.set({
|
|
707
|
+
type: "splice",
|
|
708
|
+
start,
|
|
709
|
+
deleteCount,
|
|
710
|
+
items: newItems
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Clears all items from the array.
|
|
715
|
+
* @public
|
|
716
|
+
*/
|
|
717
|
+
clear() {
|
|
718
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
719
|
+
const items = [...this._value];
|
|
720
|
+
items.forEach((item) => {
|
|
721
|
+
if (isDisposable(item)) item.dispose({ self: true });
|
|
722
|
+
});
|
|
723
|
+
this._value = [];
|
|
724
|
+
this._notify();
|
|
725
|
+
this.$lastAction.set({ type: "clear" });
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Disposes the FlowArray and its items.
|
|
729
|
+
* @param options - Disposal options.
|
|
730
|
+
* @public
|
|
731
|
+
*/
|
|
732
|
+
dispose(options) {
|
|
733
|
+
super.dispose(options);
|
|
734
|
+
this._value.forEach((item) => {
|
|
735
|
+
if (isDisposable(item)) item.dispose(options);
|
|
736
|
+
});
|
|
737
|
+
this._value = [];
|
|
738
|
+
}
|
|
739
|
+
/* INTERNAL */
|
|
740
|
+
/*@internal*/
|
|
741
|
+
_value = [];
|
|
546
742
|
}
|
|
547
743
|
|
|
548
744
|
function signal() {
|
|
549
745
|
return new FlowSignal();
|
|
550
746
|
}
|
|
747
|
+
function constant(value) {
|
|
748
|
+
return new FlowConstant(value);
|
|
749
|
+
}
|
|
551
750
|
function state(value) {
|
|
552
751
|
return new FlowState(value);
|
|
553
752
|
}
|
|
554
|
-
function resource(fn
|
|
555
|
-
return new FlowResource(fn
|
|
753
|
+
function resource(fn) {
|
|
754
|
+
return new FlowResource(fn);
|
|
556
755
|
}
|
|
557
|
-
function
|
|
558
|
-
return new
|
|
756
|
+
function resourceAsync(fn) {
|
|
757
|
+
return new FlowResourceAsync(fn);
|
|
758
|
+
}
|
|
759
|
+
function stream(updater) {
|
|
760
|
+
return new FlowStream(updater);
|
|
761
|
+
}
|
|
762
|
+
function streamAsync(updater) {
|
|
763
|
+
return new FlowStreamAsync(updater);
|
|
559
764
|
}
|
|
560
765
|
function derivation(fn) {
|
|
561
766
|
return new FlowDerivation(fn);
|
|
@@ -568,5 +773,8 @@ function map(initial) {
|
|
|
568
773
|
new Map(initial ? Object.entries(initial) : [])
|
|
569
774
|
);
|
|
570
775
|
}
|
|
776
|
+
function array(initial) {
|
|
777
|
+
return new FlowArray(initial);
|
|
778
|
+
}
|
|
571
779
|
|
|
572
|
-
export { derivation, effect, map, resource, signal, state, stream };
|
|
780
|
+
export { array, constant, derivation, effect, isDisposable, map, resource, resourceAsync, signal, state, stream, streamAsync };
|