@ersbeth/picoflow 0.1.0 → 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/picoflow.array.md +55 -0
- 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.flowdisposable.dispose.md +55 -0
- package/api/doc/picoflow.flowdisposable.md +43 -0
- package/api/doc/picoflow.flowsignal.dispose.md +39 -1
- package/api/doc/picoflow.flowsignal.md +3 -2
- package/api/doc/picoflow.isdisposable.md +55 -0
- package/api/doc/picoflow.md +70 -0
- package/api/picoflow.public.api.md +63 -2
- package/dist/picoflow.js +188 -4
- 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 +2 -0
- package/dist/types/advanced/index.d.ts.map +1 -1
- package/dist/types/basic/disposable.d.ts +23 -0
- package/dist/types/basic/disposable.d.ts.map +1 -0
- package/dist/types/basic/index.d.ts +2 -0
- package/dist/types/basic/index.d.ts.map +1 -1
- package/dist/types/basic/signal.d.ts +5 -2
- package/dist/types/basic/signal.d.ts.map +1 -1
- package/dist/types/creators.d.ts +9 -0
- package/dist/types/creators.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -3
- 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 +2 -0
- package/src/basic/disposable.ts +27 -0
- package/src/basic/index.ts +2 -0
- package/src/basic/observable.ts +2 -2
- package/src/basic/signal.ts +17 -5
- package/src/creators.ts +12 -0
- package/src/index.ts +5 -0
- package/test/array.test.ts +620 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { FlowObservable, type FlowState } from "../basic";
|
|
2
|
+
import { isDisposable } from "../basic";
|
|
3
|
+
import { state } from "../creators";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents the actions that can be performed on a FlowArray.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export type FlowArrayAction<T> =
|
|
10
|
+
| {
|
|
11
|
+
type: "set";
|
|
12
|
+
items: T[];
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
type: "setItem";
|
|
16
|
+
index: number;
|
|
17
|
+
item: T;
|
|
18
|
+
}
|
|
19
|
+
| {
|
|
20
|
+
type: "push";
|
|
21
|
+
item: T;
|
|
22
|
+
}
|
|
23
|
+
| {
|
|
24
|
+
type: "pop";
|
|
25
|
+
}
|
|
26
|
+
| {
|
|
27
|
+
type: "unshift";
|
|
28
|
+
item: T;
|
|
29
|
+
}
|
|
30
|
+
| {
|
|
31
|
+
type: "shift";
|
|
32
|
+
}
|
|
33
|
+
| {
|
|
34
|
+
type: "splice";
|
|
35
|
+
start: number;
|
|
36
|
+
deleteCount: number;
|
|
37
|
+
items: T[];
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
type: "clear";
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Represents a reactive array.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export class FlowArray<T> extends FlowObservable<T[]> {
|
|
48
|
+
/**
|
|
49
|
+
* Last action performed on the FlowArray.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
$lastAction: FlowState<FlowArrayAction<T>>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates an instance of FlowArray.
|
|
56
|
+
* @param value - Initial array value.
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
constructor(value: T[] = []) {
|
|
60
|
+
super();
|
|
61
|
+
this._value = value;
|
|
62
|
+
this.$lastAction = state<FlowArrayAction<T>>({
|
|
63
|
+
type: "set",
|
|
64
|
+
items: value,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Gets the current length of the array.
|
|
70
|
+
* @returns The length of the array.
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
get length(): number {
|
|
74
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
75
|
+
return this._value.length;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Returns a copy of the internal array.
|
|
80
|
+
* @returns A copy of the array.
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
get(): T[] {
|
|
84
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
85
|
+
return [...this._value]; // Ensure nobody can modify the original array
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Replaces the entire array with new items.
|
|
90
|
+
* @param items - The new array of items.
|
|
91
|
+
* @public
|
|
92
|
+
*/
|
|
93
|
+
set(items: T[]): void {
|
|
94
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
95
|
+
this._value.forEach((item) => {
|
|
96
|
+
if (isDisposable(item)) item.dispose({ self: true });
|
|
97
|
+
});
|
|
98
|
+
this._value = items;
|
|
99
|
+
this._notify();
|
|
100
|
+
this.$lastAction.set({ type: "set", items: items });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Replaces an item at a specific index.
|
|
105
|
+
* @param index - The index of the item to replace.
|
|
106
|
+
* @param item - The new item.
|
|
107
|
+
* @public
|
|
108
|
+
*/
|
|
109
|
+
setItem(index: number, item: T): void {
|
|
110
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
111
|
+
if (index < 0 || index >= this._value.length) {
|
|
112
|
+
throw new Error("[PicoFlow] Index out of bounds");
|
|
113
|
+
}
|
|
114
|
+
this._value[index] = item;
|
|
115
|
+
this._notify();
|
|
116
|
+
this.$lastAction.set({ type: "setItem", index: index, item: item });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Appends an item to the end of the array.
|
|
121
|
+
* @param item - The item to append.
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
push(item: T): void {
|
|
125
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
126
|
+
this._value.push(item);
|
|
127
|
+
this._notify();
|
|
128
|
+
this.$lastAction.set({ type: "push", item: item });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Removes the last item from the array.
|
|
133
|
+
* @public
|
|
134
|
+
*/
|
|
135
|
+
pop(): void {
|
|
136
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
137
|
+
const item = this._value.pop();
|
|
138
|
+
if (isDisposable(item)) {
|
|
139
|
+
item.dispose({ self: true });
|
|
140
|
+
}
|
|
141
|
+
this._notify();
|
|
142
|
+
this.$lastAction.set({ type: "pop" });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Inserts an item at the beginning of the array.
|
|
147
|
+
* @param item - The item to insert.
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
unshift(item: T): void {
|
|
151
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
152
|
+
this._value.unshift(item);
|
|
153
|
+
this._notify();
|
|
154
|
+
this.$lastAction.set({ type: "unshift", item: item });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Removes the first item from the array.
|
|
159
|
+
* @public
|
|
160
|
+
*/
|
|
161
|
+
shift(): void {
|
|
162
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
163
|
+
const item = this._value.shift();
|
|
164
|
+
if (isDisposable(item)) {
|
|
165
|
+
item.dispose({ self: true });
|
|
166
|
+
}
|
|
167
|
+
this._notify();
|
|
168
|
+
this.$lastAction.set({ type: "shift" });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Changes the content of the array.
|
|
173
|
+
* @param start - The starting index.
|
|
174
|
+
* @param deleteCount - Number of items to remove.
|
|
175
|
+
* @param newItems - New items to add.
|
|
176
|
+
* @public
|
|
177
|
+
*/
|
|
178
|
+
splice(start: number, deleteCount: number, ...newItems: T[]): void {
|
|
179
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
180
|
+
const items = this._value.splice(start, deleteCount, ...newItems);
|
|
181
|
+
items.forEach((item) => {
|
|
182
|
+
if (isDisposable(item)) item.dispose({ self: true });
|
|
183
|
+
});
|
|
184
|
+
this._notify();
|
|
185
|
+
this.$lastAction.set({
|
|
186
|
+
type: "splice",
|
|
187
|
+
start: start,
|
|
188
|
+
deleteCount: deleteCount,
|
|
189
|
+
items: newItems,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Clears all items from the array.
|
|
195
|
+
* @public
|
|
196
|
+
*/
|
|
197
|
+
clear(): void {
|
|
198
|
+
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
199
|
+
const items = [...this._value];
|
|
200
|
+
items.forEach((item) => {
|
|
201
|
+
if (isDisposable(item)) item.dispose({ self: true });
|
|
202
|
+
});
|
|
203
|
+
this._value = [];
|
|
204
|
+
this._notify();
|
|
205
|
+
this.$lastAction.set({ type: "clear" });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Disposes the FlowArray and its items.
|
|
210
|
+
* @param options - Disposal options.
|
|
211
|
+
* @public
|
|
212
|
+
*/
|
|
213
|
+
override dispose(options?: { self: boolean }): void {
|
|
214
|
+
super.dispose(options);
|
|
215
|
+
this._value.forEach((item) => {
|
|
216
|
+
if (isDisposable(item)) item.dispose(options);
|
|
217
|
+
});
|
|
218
|
+
this._value = [];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* INTERNAL */
|
|
222
|
+
|
|
223
|
+
/*@internal*/ protected override _value: T[] = [];
|
|
224
|
+
}
|
package/src/advanced/index.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents an object with a disposable lifecycle.
|
|
3
|
+
* @remarks
|
|
4
|
+
* Objects implementing this interface require explicit resource disposal.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export interface FlowDisposable {
|
|
8
|
+
/**
|
|
9
|
+
* Disposes resources held by this object.
|
|
10
|
+
* @param options - Options to specify disposal behavior.
|
|
11
|
+
*/
|
|
12
|
+
dispose(options?: { self: boolean }): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks whether an object implements the FlowDisposable interface.
|
|
17
|
+
* @param obj - The object to test.
|
|
18
|
+
* @returns True if the object has a dispose method, otherwise false.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export function isDisposable(obj: unknown): obj is FlowDisposable {
|
|
22
|
+
return (
|
|
23
|
+
obj !== null &&
|
|
24
|
+
obj !== undefined &&
|
|
25
|
+
typeof (obj as FlowDisposable).dispose === "function"
|
|
26
|
+
);
|
|
27
|
+
}
|
package/src/basic/index.ts
CHANGED
|
@@ -4,5 +4,7 @@ export { FlowObservable } from "./observable";
|
|
|
4
4
|
export { FlowDerivation } from "./derivation";
|
|
5
5
|
export { FlowEffect } from "./effect";
|
|
6
6
|
export { FlowConstant } from "./constant";
|
|
7
|
+
export { isDisposable } from "./disposable";
|
|
7
8
|
export type { FlowGetter } from "./observable";
|
|
8
9
|
export type { FlowWatcher } from "./signal";
|
|
10
|
+
export type { FlowDisposable } from "./disposable";
|
package/src/basic/observable.ts
CHANGED
|
@@ -12,8 +12,8 @@ export type FlowGetter = <T>(observable: FlowObservable<T>) => T;
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Represents a reactive observable that holds and tracks a value.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
*
|
|
16
|
+
*
|
|
17
17
|
* @remarks Subclasses must implement the {@link FlowObservable.get} method to return the current value.
|
|
18
18
|
* @typeparam T - The type of the value held by the observable.
|
|
19
19
|
* @public
|
package/src/basic/signal.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { FlowDisposable } from "./disposable";
|
|
1
2
|
import type { FlowEffect } from "./effect";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -9,12 +10,12 @@ export type FlowWatcher = (signal: FlowSignal) => void;
|
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Represents a reactive signal.
|
|
12
|
-
*
|
|
13
|
+
*
|
|
13
14
|
* @remarks Use FlowSignal to create reactive streams that notify listeners and execute associated effects.
|
|
14
15
|
* Signals can be triggered and disposed. Once disposed, interactions with the signal will throw errors.
|
|
15
16
|
* @public
|
|
16
17
|
*/
|
|
17
|
-
export class FlowSignal {
|
|
18
|
+
export class FlowSignal implements FlowDisposable {
|
|
18
19
|
/**
|
|
19
20
|
* Triggers the FlowSignal.
|
|
20
21
|
* Notifies all registered listeners and schedules execution of associated effects.
|
|
@@ -33,10 +34,21 @@ export class FlowSignal {
|
|
|
33
34
|
* @throws If the FlowSignal is already disposed.
|
|
34
35
|
* @public
|
|
35
36
|
*/
|
|
36
|
-
public dispose(): void {
|
|
37
|
+
public dispose(options?: { self: boolean }): void {
|
|
37
38
|
if (this._disposed) throw new Error("[PicoFlow] Primitive is disposed");
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
if (options?.self) {
|
|
40
|
+
Array.from(this._effects).forEach((effect) =>
|
|
41
|
+
effect._unregisterDependency(this),
|
|
42
|
+
);
|
|
43
|
+
Array.from(this._listeners).forEach((listener) =>
|
|
44
|
+
listener._unregisterDependency(this),
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
Array.from(this._effects).forEach((effect) => effect.dispose());
|
|
48
|
+
Array.from(this._listeners).forEach((listener) =>
|
|
49
|
+
listener.dispose(),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
40
52
|
Array.from(this._dependencies).forEach((dependency) => {
|
|
41
53
|
this._unregisterDependency(dependency);
|
|
42
54
|
});
|
package/src/creators.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
FlowStream,
|
|
6
6
|
FlowStreamAsync,
|
|
7
7
|
} from "./advanced/";
|
|
8
|
+
import { FlowArray } from "./advanced/array";
|
|
8
9
|
import {
|
|
9
10
|
FlowConstant,
|
|
10
11
|
FlowDerivation,
|
|
@@ -138,3 +139,14 @@ export function map<K extends string | number | symbol, V>(
|
|
|
138
139
|
new Map<K, V>(initial ? (Object.entries(initial) as [K, V][]) : []),
|
|
139
140
|
);
|
|
140
141
|
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates a new reactive array.
|
|
145
|
+
* @typeparam T - The type of the array elements.
|
|
146
|
+
* @param initial - An optional array of initial values.
|
|
147
|
+
* @returns A new instance of {@link FlowArray}.
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
export function array<T>(initial?: T[]): FlowArray<T> {
|
|
151
|
+
return new FlowArray<T>(initial);
|
|
152
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,9 +15,11 @@ export {
|
|
|
15
15
|
derivation,
|
|
16
16
|
effect,
|
|
17
17
|
map,
|
|
18
|
+
array,
|
|
18
19
|
streamAsync,
|
|
19
20
|
resourceAsync,
|
|
20
21
|
} from "./creators";
|
|
22
|
+
export { isDisposable } from "./basic";
|
|
21
23
|
export type {
|
|
22
24
|
FlowDerivation,
|
|
23
25
|
FlowEffect,
|
|
@@ -27,6 +29,7 @@ export type {
|
|
|
27
29
|
FlowWatcher,
|
|
28
30
|
FlowState,
|
|
29
31
|
FlowConstant,
|
|
32
|
+
FlowDisposable,
|
|
30
33
|
} from "./basic/";
|
|
31
34
|
export type {
|
|
32
35
|
FlowResource,
|
|
@@ -37,4 +40,6 @@ export type {
|
|
|
37
40
|
FlowStreamDisposer,
|
|
38
41
|
FlowStreamSetter,
|
|
39
42
|
FlowStreamUpdater,
|
|
43
|
+
FlowArray,
|
|
44
|
+
FlowArrayAction,
|
|
40
45
|
} from "./advanced/";
|