@mark1russell7/collections 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -4
- package/build/core/layers.js.map +1 -1
- package/build/dag/index.d.ts +9 -4
- package/build/dag/index.d.ts.map +1 -1
- package/build/dag/index.js +5 -3
- package/build/dag/index.js.map +1 -1
- package/build/index.d.ts +36 -218
- package/build/index.d.ts.map +1 -1
- package/build/index.js +63 -234
- package/build/index.js.map +1 -1
- package/build/layers.d.ts +3 -1
- package/build/layers.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/behaviors/readonly.ts +24 -0
- package/src/behaviors/safe.ts +78 -132
- package/src/core/layers.ts +3 -1
- package/src/dag/executor.ts +5 -3
- package/src/dag/types.ts +4 -1
- package/src/impl/hash-map.ts +18 -28
- package/src/index.ts +0 -16
- package/src/interfaces/list.ts +4 -4
- package/src/core/effects.ts +0 -327
package/build/layers.d.ts
CHANGED
|
@@ -24,7 +24,9 @@ type InnerOf<L> = L extends ((next: infer I) => any) ? I : never;
|
|
|
24
24
|
type OuterOf<L> = L extends ((next: any) => infer O) ? O : never;
|
|
25
25
|
/**
|
|
26
26
|
* This type checks each neighbor pair of a list of layers. The result of the inner neighbor must
|
|
27
|
-
* fit the input of the outer neighbor.
|
|
27
|
+
* fit the input of the outer neighbor. A bad pair makes the compiler refuse the call. The compiler
|
|
28
|
+
* marks the first argument, not the bad pair. Its message shows the type that the first bad pair
|
|
29
|
+
* needs. At the place of the inner neighbor, it needs a layer that gives the input of the outer one.
|
|
28
30
|
*
|
|
29
31
|
* The type is tail recursive, so the compiler accepts a chain of 100 layers.
|
|
30
32
|
*/
|
package/build/layers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layers.d.ts","names":[],"sources":["../src/core/layers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;KAoBY,MAAM,aAAa,QAAQ,UAAU,MAAM,UAAU;;KAGrD,QAAQ,KAAK,YAAW,YAAY,aAAY;;KAGhD,QAAQ,KAAK,YAAW,oBAAoB,KAAI
|
|
1
|
+
{"version":3,"file":"layers.d.ts","names":[],"sources":["../src/core/layers.ts"],"mappings":";;;;;;;;;;;;;;;;;;;KAoBY,MAAM,aAAa,QAAQ,UAAU,MAAM,UAAU;;KAGrD,QAAQ,KAAK,YAAW,YAAY,aAAY;;KAGhD,QAAQ,KAAK,YAAW,oBAAoB,KAAI;;;;;;;;;KAUhD,MAAM,8BAA8B,iDAC9C,0BAA0B,SAAS,YAAY,MAC1C,QAAQ,aAAa,QAAQ,MAC5B,gBAAgB,MAAM,iBAAiB,MAAM,mBAChC,MAAM,GAAG,WAAW,QAAQ,QAAQ,kBACtC,SAAS;;;;;;KAOhB,SAAS,gCACnB,yBACK,GAAG,MAAM,MAAM,IAChB,0BAA0B,uBACxB,wCAAwC,SACrC,MAAM,QAAQ,UAAU,QAAQ,iBAEnC,0BAA0B,QACvB,MAAM,QAAQ,OAAO,QAAQ;;KAI5B,OAAO,8BAA8B,iBAC/C,0BAA0B,gBAAgB,QAAQ,OAAO,MAAM,MAAM,QAAQ,UAAU;;;;;KAM7E,QAAQ,gCAClB,wCAAwC,SACnC,MAAM,QAAQ,UAAU,OAAO,KAAK,QAAQ,QAC7C,SAAS;;;;;;;;;;;;;iBAcC,cAAc,mBAAmB,YAAY,QAAQ,IAAI,MAAM,KAAK,SAAS"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@mark1russell7/collections",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.1",
|
|
5
5
|
"description": "Collections with no dependencies: lists, maps, queues, a summary tree, channels, lazy operations and dependency graphs.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"collections",
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"@mark1russell7/rigor-bench": "^0.2.5",
|
|
72
72
|
"@mark1russell7/rigor-generators": "^0.1.5",
|
|
73
73
|
"@mark1russell7/rigor-statistics": "^0.1.8",
|
|
74
|
+
"@mark1russell7/rigor-testkit": "^0.1.0",
|
|
74
75
|
"@types/node": "^26.6.5",
|
|
75
76
|
"esbuild": "^0.28.2",
|
|
76
77
|
"fast-check": "^4.10.2",
|
|
@@ -78,6 +79,9 @@
|
|
|
78
79
|
"typescript": "^7.0.2",
|
|
79
80
|
"vitest": "^5.0.3"
|
|
80
81
|
},
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"@mark1russell7/optional": "^1.2.0"
|
|
84
|
+
},
|
|
81
85
|
"scripts": {
|
|
82
86
|
"build": "tsdown",
|
|
83
87
|
"test": "vitest run",
|
|
@@ -84,6 +84,30 @@ const MUTATING_METHODS = new Set([
|
|
|
84
84
|
"compute",
|
|
85
85
|
"merge",
|
|
86
86
|
"putAll",
|
|
87
|
+
|
|
88
|
+
// Queue changes that give undefined on an empty queue (C27: a readonly view removed an element)
|
|
89
|
+
"pollOrUndefined",
|
|
90
|
+
|
|
91
|
+
// The internal changes of the structures of this package. TypeScript marks them private, but a call at run
|
|
92
|
+
// time reaches them. `readonly.test.ts` puts each method of each structure in the reads or in this list.
|
|
93
|
+
"ensureCapacity",
|
|
94
|
+
"trimToSize",
|
|
95
|
+
"grow",
|
|
96
|
+
"resize",
|
|
97
|
+
"removeAtOffset",
|
|
98
|
+
"unlinkNode",
|
|
99
|
+
"heapify",
|
|
100
|
+
"bubbleUp",
|
|
101
|
+
"bubbleDown",
|
|
102
|
+
"addToEnd",
|
|
103
|
+
"moveToEnd",
|
|
104
|
+
"removeFromBucket",
|
|
105
|
+
"removeFromList",
|
|
106
|
+
"deleteNode",
|
|
107
|
+
"fixAfterInsertion",
|
|
108
|
+
"fixAfterDeletion",
|
|
109
|
+
"rotateLeft",
|
|
110
|
+
"rotateRight",
|
|
87
111
|
]);
|
|
88
112
|
|
|
89
113
|
/** Methods that return a view of the collection: the view is readonly too. */
|
package/src/behaviors/safe.ts
CHANGED
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This module wraps collection operations that throw errors to instead return
|
|
5
|
-
* Option<T> or Result<T, E>, enabling functional error handling.
|
|
2
|
+
* The safe middleware. Each operation that throws on a missing element has a safe form in the property `safe`. The safe
|
|
3
|
+
* form gives an `Optional` or a `Result` of `@mark1russell7/optional`, and does not throw.
|
|
6
4
|
*
|
|
7
5
|
* @example
|
|
8
|
-
*
|
|
9
|
-
* safeList<number>()
|
|
10
|
-
* )(arrayList<number>())
|
|
6
|
+
* import { isSome } from "@mark1russell7/optional";
|
|
11
7
|
*
|
|
12
|
-
* const
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* }
|
|
8
|
+
* const list = compose(safeList<number>())(arrayList<number>());
|
|
9
|
+
* const value = list.safe.get(10); // an Optional<number>, not an exception
|
|
10
|
+
* if (isSome(value)) console.log(value.value);
|
|
16
11
|
*/
|
|
17
12
|
|
|
18
13
|
import type { Middleware } from "../core/middleware.js";
|
|
19
14
|
import type { List } from "../interfaces/list.js";
|
|
20
15
|
import type { Queue, Deque } from "../interfaces/queue.js";
|
|
21
16
|
import type { MapLike } from "../interfaces/map.js";
|
|
22
|
-
import { type
|
|
23
|
-
import { None, Some, tryCatch } from "../core/effects.js";
|
|
17
|
+
import { none, some, toOptional, tryCatch, type Optional, type Result } from "@mark1russell7/optional";
|
|
24
18
|
|
|
25
19
|
/**
|
|
26
20
|
* Safe operations for List.
|
|
27
21
|
*/
|
|
28
22
|
export interface SafeListOperations<T> {
|
|
29
23
|
/**
|
|
30
|
-
* Get element at index,
|
|
24
|
+
* Get element at index, as an optional.
|
|
31
25
|
*/
|
|
32
|
-
get(index: number):
|
|
26
|
+
get(index: number): Optional<T>;
|
|
33
27
|
|
|
34
28
|
/**
|
|
35
29
|
* Set element at index, giving Result with old value or error.
|
|
@@ -42,24 +36,24 @@ export interface SafeListOperations<T> {
|
|
|
42
36
|
removeAt(index: number): Result<T, string>;
|
|
43
37
|
|
|
44
38
|
/**
|
|
45
|
-
* Get first element as
|
|
39
|
+
* Get first element as an optional.
|
|
46
40
|
*/
|
|
47
|
-
first():
|
|
41
|
+
first(): Optional<T>;
|
|
48
42
|
|
|
49
43
|
/**
|
|
50
|
-
* Get last element as
|
|
44
|
+
* Get last element as an optional.
|
|
51
45
|
*/
|
|
52
|
-
last():
|
|
46
|
+
last(): Optional<T>;
|
|
53
47
|
|
|
54
48
|
/**
|
|
55
|
-
* Pop element,
|
|
49
|
+
* Pop element, as an optional.
|
|
56
50
|
*/
|
|
57
|
-
pop():
|
|
51
|
+
pop(): Optional<T>;
|
|
58
52
|
|
|
59
53
|
/**
|
|
60
|
-
* Shift element,
|
|
54
|
+
* Shift element, as an optional.
|
|
61
55
|
*/
|
|
62
|
-
shift():
|
|
56
|
+
shift(): Optional<T>;
|
|
63
57
|
}
|
|
64
58
|
|
|
65
59
|
/**
|
|
@@ -67,19 +61,19 @@ export interface SafeListOperations<T> {
|
|
|
67
61
|
*/
|
|
68
62
|
export interface SafeQueueOperations<T> {
|
|
69
63
|
/**
|
|
70
|
-
* Peek at head element as
|
|
64
|
+
* Peek at head element as an optional.
|
|
71
65
|
*/
|
|
72
|
-
peek():
|
|
66
|
+
peek(): Optional<T>;
|
|
73
67
|
|
|
74
68
|
/**
|
|
75
|
-
* Poll element as
|
|
69
|
+
* Poll element as an optional.
|
|
76
70
|
*/
|
|
77
|
-
poll():
|
|
71
|
+
poll(): Optional<T>;
|
|
78
72
|
|
|
79
73
|
/**
|
|
80
|
-
* Dequeue element as
|
|
74
|
+
* Dequeue element as an optional.
|
|
81
75
|
*/
|
|
82
|
-
dequeue():
|
|
76
|
+
dequeue(): Optional<T>;
|
|
83
77
|
}
|
|
84
78
|
|
|
85
79
|
/**
|
|
@@ -87,29 +81,29 @@ export interface SafeQueueOperations<T> {
|
|
|
87
81
|
*/
|
|
88
82
|
export interface SafeDequeOperations<T> extends SafeQueueOperations<T> {
|
|
89
83
|
/**
|
|
90
|
-
* Peek at first element as
|
|
84
|
+
* Peek at first element as an optional.
|
|
91
85
|
*/
|
|
92
|
-
peekFirst():
|
|
86
|
+
peekFirst(): Optional<T>;
|
|
93
87
|
|
|
94
88
|
/**
|
|
95
|
-
* Peek at last element as
|
|
89
|
+
* Peek at last element as an optional.
|
|
96
90
|
*/
|
|
97
|
-
peekLast():
|
|
91
|
+
peekLast(): Optional<T>;
|
|
98
92
|
|
|
99
93
|
/**
|
|
100
|
-
* Poll first element as
|
|
94
|
+
* Poll first element as an optional.
|
|
101
95
|
*/
|
|
102
|
-
pollFirst():
|
|
96
|
+
pollFirst(): Optional<T>;
|
|
103
97
|
|
|
104
98
|
/**
|
|
105
|
-
* Poll last element as
|
|
99
|
+
* Poll last element as an optional.
|
|
106
100
|
*/
|
|
107
|
-
pollLast():
|
|
101
|
+
pollLast(): Optional<T>;
|
|
108
102
|
|
|
109
103
|
/**
|
|
110
|
-
* Pop element as
|
|
104
|
+
* Pop element as an optional.
|
|
111
105
|
*/
|
|
112
|
-
pop():
|
|
106
|
+
pop(): Optional<T>;
|
|
113
107
|
}
|
|
114
108
|
|
|
115
109
|
/**
|
|
@@ -117,9 +111,9 @@ export interface SafeDequeOperations<T> extends SafeQueueOperations<T> {
|
|
|
117
111
|
*/
|
|
118
112
|
export interface SafeMapOperations<K, V> {
|
|
119
113
|
/**
|
|
120
|
-
* Get value for key as
|
|
114
|
+
* Get value for key as an optional.
|
|
121
115
|
*/
|
|
122
|
-
get(key: K):
|
|
116
|
+
get(key: K): Optional<V>;
|
|
123
117
|
|
|
124
118
|
/**
|
|
125
119
|
* Set value for key, giving Result with old value or success.
|
|
@@ -135,7 +129,7 @@ export interface SafeMapOperations<K, V> {
|
|
|
135
129
|
/**
|
|
136
130
|
* This function makes a safe List middleware.
|
|
137
131
|
*
|
|
138
|
-
* This function exposes a `safe` property with
|
|
132
|
+
* This function exposes a `safe` property with Optional/Result-based operations.
|
|
139
133
|
*/
|
|
140
134
|
export function safeList<T>(): Middleware<
|
|
141
135
|
List<T>,
|
|
@@ -143,14 +137,8 @@ export function safeList<T>(): Middleware<
|
|
|
143
137
|
> {
|
|
144
138
|
return (next: List<T>): List<T> & { safe: SafeListOperations<T> } => {
|
|
145
139
|
const safe: SafeListOperations<T> = {
|
|
146
|
-
get(index: number):
|
|
147
|
-
return tryCatch(
|
|
148
|
-
() => next.get(index),
|
|
149
|
-
() => "Index out of bounds"
|
|
150
|
-
).match<Option<T>>({
|
|
151
|
-
Ok: (value) => Some(value),
|
|
152
|
-
Err: () => None,
|
|
153
|
-
}) as Option<T>;
|
|
140
|
+
get(index: number): Optional<T> {
|
|
141
|
+
return toOptional(tryCatch(() => next.get(index)));
|
|
154
142
|
},
|
|
155
143
|
|
|
156
144
|
set(index: number, element: T): Result<T, string> {
|
|
@@ -167,34 +155,22 @@ export function safeList<T>(): Middleware<
|
|
|
167
155
|
);
|
|
168
156
|
},
|
|
169
157
|
|
|
170
|
-
first():
|
|
171
|
-
return next.isEmpty ?
|
|
158
|
+
first(): Optional<T> {
|
|
159
|
+
return next.isEmpty ? none : some(next.first());
|
|
172
160
|
},
|
|
173
161
|
|
|
174
|
-
last():
|
|
175
|
-
return next.isEmpty ?
|
|
162
|
+
last(): Optional<T> {
|
|
163
|
+
return next.isEmpty ? none : some(next.last());
|
|
176
164
|
},
|
|
177
165
|
|
|
178
|
-
pop():
|
|
179
|
-
if (next.isEmpty) return
|
|
180
|
-
return tryCatch(
|
|
181
|
-
() => next.pop(),
|
|
182
|
-
() => "List is empty"
|
|
183
|
-
).match<Option<T>>({
|
|
184
|
-
Ok: (value) => Some(value),
|
|
185
|
-
Err: () => None,
|
|
186
|
-
}) as Option<T>;
|
|
166
|
+
pop(): Optional<T> {
|
|
167
|
+
if (next.isEmpty) return none;
|
|
168
|
+
return toOptional(tryCatch(() => next.pop()));
|
|
187
169
|
},
|
|
188
170
|
|
|
189
|
-
shift():
|
|
190
|
-
if (next.isEmpty) return
|
|
191
|
-
return tryCatch(
|
|
192
|
-
() => next.shift(),
|
|
193
|
-
() => "List is empty"
|
|
194
|
-
).match<Option<T>>({
|
|
195
|
-
Ok: (value) => Some(value),
|
|
196
|
-
Err: () => None,
|
|
197
|
-
}) as Option<T>;
|
|
171
|
+
shift(): Optional<T> {
|
|
172
|
+
if (next.isEmpty) return none;
|
|
173
|
+
return toOptional(tryCatch(() => next.shift()));
|
|
198
174
|
},
|
|
199
175
|
};
|
|
200
176
|
|
|
@@ -212,37 +188,19 @@ export function safeQueue<T>(): Middleware<
|
|
|
212
188
|
> {
|
|
213
189
|
return (next: Queue<T>): Queue<T> & { safe: SafeQueueOperations<T> } => {
|
|
214
190
|
const safe: SafeQueueOperations<T> = {
|
|
215
|
-
peek():
|
|
216
|
-
if (next.isEmpty) return
|
|
217
|
-
return tryCatch(
|
|
218
|
-
() => next.peek(),
|
|
219
|
-
() => "Queue is empty"
|
|
220
|
-
).match<Option<T>>({
|
|
221
|
-
Ok: (value) => Some(value),
|
|
222
|
-
Err: () => None,
|
|
223
|
-
}) as Option<T>;
|
|
191
|
+
peek(): Optional<T> {
|
|
192
|
+
if (next.isEmpty) return none;
|
|
193
|
+
return toOptional(tryCatch(() => next.peek()));
|
|
224
194
|
},
|
|
225
195
|
|
|
226
|
-
poll():
|
|
227
|
-
if (next.isEmpty) return
|
|
228
|
-
return tryCatch(
|
|
229
|
-
() => next.poll(),
|
|
230
|
-
() => "Queue is empty"
|
|
231
|
-
).match<Option<T>>({
|
|
232
|
-
Ok: (value) => Some(value),
|
|
233
|
-
Err: () => None,
|
|
234
|
-
}) as Option<T>;
|
|
196
|
+
poll(): Optional<T> {
|
|
197
|
+
if (next.isEmpty) return none;
|
|
198
|
+
return toOptional(tryCatch(() => next.poll()));
|
|
235
199
|
},
|
|
236
200
|
|
|
237
|
-
dequeue():
|
|
238
|
-
if (next.isEmpty) return
|
|
239
|
-
return tryCatch(
|
|
240
|
-
() => next.dequeue(),
|
|
241
|
-
() => "Queue is empty"
|
|
242
|
-
).match<Option<T>>({
|
|
243
|
-
Ok: (value) => Some(value),
|
|
244
|
-
Err: () => None,
|
|
245
|
-
}) as Option<T>;
|
|
201
|
+
dequeue(): Optional<T> {
|
|
202
|
+
if (next.isEmpty) return none;
|
|
203
|
+
return toOptional(tryCatch(() => next.dequeue()));
|
|
246
204
|
},
|
|
247
205
|
};
|
|
248
206
|
|
|
@@ -259,55 +217,43 @@ export function safeDeque<T>(): Middleware<
|
|
|
259
217
|
> {
|
|
260
218
|
return (next: Deque<T>): Deque<T> & { safe: SafeDequeOperations<T> } => {
|
|
261
219
|
const safe: SafeDequeOperations<T> = {
|
|
262
|
-
peek():
|
|
263
|
-
return next.isEmpty ?
|
|
220
|
+
peek(): Optional<T> {
|
|
221
|
+
return next.isEmpty ? none : some(next.peekFirst());
|
|
264
222
|
},
|
|
265
223
|
|
|
266
|
-
poll():
|
|
224
|
+
poll(): Optional<T> {
|
|
267
225
|
// One poll: before, the test and the result each called pollFirst(), so poll() removed
|
|
268
226
|
// two elements and returned the second (BUGS-2026-07 L12)
|
|
269
|
-
if (next.isEmpty) return
|
|
270
|
-
return
|
|
227
|
+
if (next.isEmpty) return none;
|
|
228
|
+
return some(next.pollFirst() as T);
|
|
271
229
|
},
|
|
272
230
|
|
|
273
|
-
dequeue():
|
|
274
|
-
if (next.isEmpty) return
|
|
275
|
-
return tryCatch(
|
|
276
|
-
() => next.dequeue(),
|
|
277
|
-
() => "Deque is empty"
|
|
278
|
-
).match<Option<T>>({
|
|
279
|
-
Ok: (value) => Some(value),
|
|
280
|
-
Err: () => None,
|
|
281
|
-
}) as Option<T>;
|
|
231
|
+
dequeue(): Optional<T> {
|
|
232
|
+
if (next.isEmpty) return none;
|
|
233
|
+
return toOptional(tryCatch(() => next.dequeue()));
|
|
282
234
|
},
|
|
283
235
|
|
|
284
|
-
peekFirst():
|
|
285
|
-
return next.isEmpty ?
|
|
236
|
+
peekFirst(): Optional<T> {
|
|
237
|
+
return next.isEmpty ? none : some(next.peekFirst());
|
|
286
238
|
},
|
|
287
239
|
|
|
288
|
-
peekLast():
|
|
289
|
-
return next.isEmpty ?
|
|
240
|
+
peekLast(): Optional<T> {
|
|
241
|
+
return next.isEmpty ? none : some(next.peekLast());
|
|
290
242
|
},
|
|
291
243
|
|
|
292
|
-
pollFirst():
|
|
244
|
+
pollFirst(): Optional<T> {
|
|
293
245
|
const result = next.pollFirst();
|
|
294
|
-
return result !== undefined ?
|
|
246
|
+
return result !== undefined ? some(result) : none;
|
|
295
247
|
},
|
|
296
248
|
|
|
297
|
-
pollLast():
|
|
249
|
+
pollLast(): Optional<T> {
|
|
298
250
|
const result = next.pollLast();
|
|
299
|
-
return result !== undefined ?
|
|
251
|
+
return result !== undefined ? some(result) : none;
|
|
300
252
|
},
|
|
301
253
|
|
|
302
|
-
pop():
|
|
303
|
-
if (next.isEmpty) return
|
|
304
|
-
return tryCatch(
|
|
305
|
-
() => next.pop(),
|
|
306
|
-
() => "Deque is empty"
|
|
307
|
-
).match<Option<T>>({
|
|
308
|
-
Ok: (value) => Some(value),
|
|
309
|
-
Err: () => None,
|
|
310
|
-
}) as Option<T>;
|
|
254
|
+
pop(): Optional<T> {
|
|
255
|
+
if (next.isEmpty) return none;
|
|
256
|
+
return toOptional(tryCatch(() => next.pop()));
|
|
311
257
|
},
|
|
312
258
|
};
|
|
313
259
|
|
|
@@ -326,8 +272,8 @@ export function safeMap<K, V>(): Middleware<
|
|
|
326
272
|
next: MapLike<K, V>
|
|
327
273
|
): MapLike<K, V> & { safe: SafeMapOperations<K, V> } => {
|
|
328
274
|
const safe: SafeMapOperations<K, V> = {
|
|
329
|
-
get(key: K):
|
|
330
|
-
return next.has(key) ?
|
|
275
|
+
get(key: K): Optional<V> {
|
|
276
|
+
return next.has(key) ? some(next.get(key)) : none;
|
|
331
277
|
},
|
|
332
278
|
|
|
333
279
|
set(key: K, value: V): Result<V | undefined, string> {
|
package/src/core/layers.ts
CHANGED
|
@@ -28,7 +28,9 @@ export type OuterOf<L> = L extends (next: any) => infer O ? O : never;
|
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* This type checks each neighbor pair of a list of layers. The result of the inner neighbor must
|
|
31
|
-
* fit the input of the outer neighbor.
|
|
31
|
+
* fit the input of the outer neighbor. A bad pair makes the compiler refuse the call. The compiler
|
|
32
|
+
* marks the first argument, not the bad pair. Its message shows the type that the first bad pair
|
|
33
|
+
* needs. At the place of the inner neighbor, it needs a layer that gives the input of the outer one.
|
|
32
34
|
*
|
|
33
35
|
* The type is tail recursive, so the compiler accepts a chain of 100 layers.
|
|
34
36
|
*/
|
package/src/dag/executor.ts
CHANGED
|
@@ -71,9 +71,11 @@ function notify<T>(name: string, listener: ((arg: T) => void) | undefined, arg:
|
|
|
71
71
|
* With `skipDependents` (the default), a node whose dependency failed or was skipped does not start. Its result has
|
|
72
72
|
* `skipped: true` and an error that names those dependencies. A dependency outside the DAG does not count.
|
|
73
73
|
*
|
|
74
|
-
* `failFast` operates
|
|
75
|
-
*
|
|
76
|
-
* starts.
|
|
74
|
+
* `failFast` operates on levels. When a node of a level fails, each node of that level continues to its end.
|
|
75
|
+
* This includes the nodes that did not start before the failure, when `concurrency` is less than the
|
|
76
|
+
* size of the level. No later level starts. The run does not cancel a node.
|
|
77
|
+
*
|
|
78
|
+
* A node that did not start (`skipped: true`) calls neither `onNodeStart` nor `onNodeComplete`.
|
|
77
79
|
*/
|
|
78
80
|
export async function executeDAG<TNode extends DAGNode>(
|
|
79
81
|
dag: DependencyDAG<TNode>,
|
package/src/dag/types.ts
CHANGED
|
@@ -39,7 +39,10 @@ export interface DependencyDAG<TNode extends DAGNode = DAGNode> {
|
|
|
39
39
|
export interface DAGExecutionOptions<TNode extends DAGNode = DAGNode> {
|
|
40
40
|
/** Max parallel operations per level (default: 4) */
|
|
41
41
|
concurrency?: number;
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* When this value is true, no level starts after a level with a failure. The default is true.
|
|
44
|
+
* Each node of the level with the failure runs, also a node that did not start before the failure.
|
|
45
|
+
*/
|
|
43
46
|
failFast?: boolean;
|
|
44
47
|
/**
|
|
45
48
|
* When this value is true, a node whose dependency failed or was skipped does not start. Its result has `skipped: true`.
|
package/src/impl/hash-map.ts
CHANGED
|
@@ -136,46 +136,36 @@ export class HashMap<K, V> implements MapLike<K, V> {
|
|
|
136
136
|
// ========================================================================
|
|
137
137
|
|
|
138
138
|
has(key: K): boolean {
|
|
139
|
-
|
|
140
|
-
const index = this.bucketIndex(hash);
|
|
141
|
-
let node = this._buckets[index] ?? null;
|
|
142
|
-
|
|
143
|
-
while (node !== null) {
|
|
144
|
-
if (node.hash === hash && this._keyEq(node.key, key)) {
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
node = node.next;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return false;
|
|
139
|
+
return this.findNode(key) !== null;
|
|
151
140
|
}
|
|
152
141
|
|
|
153
142
|
get(key: K): V {
|
|
154
|
-
|
|
155
|
-
|
|
143
|
+
// The node, not the value, tells if the key is present: a key can have the value undefined (C8)
|
|
144
|
+
const node = this.findNode(key);
|
|
145
|
+
if (node === null) {
|
|
156
146
|
throw new Error(`Key not found: ${key}`);
|
|
157
147
|
}
|
|
158
|
-
return value;
|
|
148
|
+
return node.value;
|
|
159
149
|
}
|
|
160
150
|
|
|
161
151
|
getOrUndefined(key: K): V | undefined {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
let node = this._buckets[index] ?? null;
|
|
152
|
+
return this.findNode(key)?.value;
|
|
153
|
+
}
|
|
165
154
|
|
|
155
|
+
getOrDefault(key: K, defaultValue: V): V {
|
|
156
|
+
const node = this.findNode(key);
|
|
157
|
+
return node !== null ? node.value : defaultValue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** This method finds the node of a key, or gives `null`. */
|
|
161
|
+
private findNode(key: K): Node<K, V> | null {
|
|
162
|
+
const hash = this._keyHash(key);
|
|
163
|
+
let node = this._buckets[this.bucketIndex(hash)] ?? null;
|
|
166
164
|
while (node !== null) {
|
|
167
|
-
if (node.hash === hash && this._keyEq(node.key, key))
|
|
168
|
-
return node.value;
|
|
169
|
-
}
|
|
165
|
+
if (node.hash === hash && this._keyEq(node.key, key)) return node;
|
|
170
166
|
node = node.next;
|
|
171
167
|
}
|
|
172
|
-
|
|
173
|
-
return undefined;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
getOrDefault(key: K, defaultValue: V): V {
|
|
177
|
-
const value = this.getOrUndefined(key);
|
|
178
|
-
return value !== undefined ? value : defaultValue;
|
|
168
|
+
return null;
|
|
179
169
|
}
|
|
180
170
|
|
|
181
171
|
containsValue(value: V): boolean {
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
// ============================================================================
|
|
11
11
|
|
|
12
12
|
export * from "./core/traits.js";
|
|
13
|
-
export * from "./core/effects.js";
|
|
14
13
|
export * from "./core/policies.js";
|
|
15
14
|
export * from "./core/middleware.js";
|
|
16
15
|
export * from "./core/events.js";
|
|
@@ -220,18 +219,3 @@ export {
|
|
|
220
219
|
groupBy,
|
|
221
220
|
} from "./utils/factories.js";
|
|
222
221
|
|
|
223
|
-
// Effects
|
|
224
|
-
export {
|
|
225
|
-
None,
|
|
226
|
-
Some,
|
|
227
|
-
type Option,
|
|
228
|
-
Ok,
|
|
229
|
-
Err,
|
|
230
|
-
type Result,
|
|
231
|
-
isSome,
|
|
232
|
-
isNone,
|
|
233
|
-
isOk,
|
|
234
|
-
isErr,
|
|
235
|
-
getOrElse,
|
|
236
|
-
unwrap,
|
|
237
|
-
} from "./core/effects.js";
|
package/src/interfaces/list.ts
CHANGED
|
@@ -43,10 +43,9 @@ export interface ReadonlyList<T> extends ReadonlyCollection<T> {
|
|
|
43
43
|
lastIndexOf(element: T, fromIndex?: number): number;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* This method gives a
|
|
47
|
-
* and toIndex (exclusive).
|
|
46
|
+
* This method gives a new list with the elements from fromIndex (inclusive) to toIndex (exclusive).
|
|
48
47
|
*
|
|
49
|
-
*
|
|
48
|
+
* The new list is a copy, not a view. A change to one list does not change the other list.
|
|
50
49
|
*
|
|
51
50
|
* @param fromIndex Start index (inclusive)
|
|
52
51
|
* @param toIndex End index (exclusive)
|
|
@@ -135,7 +134,8 @@ export interface List<T> extends ReadonlyList<T>, Collection<T> {
|
|
|
135
134
|
reverse(): void;
|
|
136
135
|
|
|
137
136
|
/**
|
|
138
|
-
* This method gives a mutable
|
|
137
|
+
* This method gives a new mutable list with the elements from fromIndex (inclusive) to toIndex (exclusive).
|
|
138
|
+
* The new list is a copy, not a view.
|
|
139
139
|
*
|
|
140
140
|
* @param fromIndex Start index (inclusive)
|
|
141
141
|
* @param toIndex End index (exclusive)
|