@mark1russell7/collections 0.9.4 → 0.9.6

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/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.9.4",
4
+ "version": "0.9.6",
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",
@@ -76,6 +76,8 @@
76
76
  "@mark1russell7/rigor-generators": "^0.1.5",
77
77
  "@mark1russell7/rigor-statistics": "^0.1.8",
78
78
  "@mark1russell7/rigor-testkit": "^0.1.0",
79
+ "@stryker-mutator/core": "^10.1.1",
80
+ "@stryker-mutator/vitest-runner": "^10.1.1",
79
81
  "@types/node": "^26.6.5",
80
82
  "@vitest/coverage-v8": "^5.1.0",
81
83
  "esbuild": "^0.28.2",
@@ -22,12 +22,19 @@
22
22
 
23
23
  import type { AsyncQueue as IAsyncQueue } from "../interfaces/queue.js";
24
24
 
25
+ /** The text of the error of a put, a new one or a waiting one, on a closed queue. */
26
+ const CLOSED = "Queue is closed";
27
+
28
+ /** The text of the error of a take, a peek or a wait on a queue that is closed and empty. */
29
+ const CLOSED_AND_EMPTY = "Queue is closed and empty";
30
+
25
31
  /**
26
32
  * Options for making an AsyncQueue.
27
33
  */
28
34
  export interface AsyncQueueOptions {
29
35
  /**
30
- * Maximum capacity. Infinity for unbounded queue.
36
+ * The maximum number of elements: a whole number of 0 or more, or `Infinity` for no bound.
37
+ * Any other value gives a `RangeError`.
31
38
  * @default Infinity
32
39
  */
33
40
  capacity?: number;
@@ -80,7 +87,12 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
80
87
  private readonly defaultTimeout?: number;
81
88
 
82
89
  constructor(options: AsyncQueueOptions = {}) {
83
- this.capacity = options.capacity ?? Infinity;
90
+ const capacity = options.capacity ?? Infinity;
91
+ // A capacity of -1, 1.5 or NaN gave a wrong remainingCapacity, or each put waited with no end.
92
+ if (capacity !== Infinity && !(Number.isInteger(capacity) && capacity >= 0)) {
93
+ throw new RangeError(`The capacity must be a whole number of 0 or more, or Infinity: ${String(capacity)}`);
94
+ }
95
+ this.capacity = capacity;
84
96
  if (options.timeout !== undefined) {
85
97
  this.defaultTimeout = options.timeout;
86
98
  }
@@ -124,7 +136,7 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
124
136
  */
125
137
  async put(element: T, timeout?: number): Promise<void> {
126
138
  if (this._isClosed) {
127
- throw new Error("Queue is closed");
139
+ throw new Error(CLOSED);
128
140
  }
129
141
  if (this.tryPutNow(element)) {
130
142
  return;
@@ -152,7 +164,7 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
152
164
  }
153
165
 
154
166
  /**
155
- * Removes and gives an element from the queue.
167
+ * This method removes an element from the queue and gives it.
156
168
  * If the queue is empty, waits until an element is available.
157
169
  *
158
170
  * @throws Error if queue is closed and empty
@@ -166,7 +178,7 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
166
178
 
167
179
  // If closed and empty, throw
168
180
  if (this._isClosed) {
169
- throw new Error("Queue is closed and empty");
181
+ throw new Error(CLOSED_AND_EMPTY);
170
182
  }
171
183
 
172
184
  // Wait for an element
@@ -203,7 +215,7 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
203
215
  return () => false;
204
216
  }
205
217
  if (this._isClosed) {
206
- onClosed(new Error("Queue is closed and empty"));
218
+ onClosed(new Error(CLOSED_AND_EMPTY));
207
219
  return () => false;
208
220
  }
209
221
  const taker: Resolver<T> = { resolve: onElement, reject: onClosed };
@@ -306,7 +318,7 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
306
318
  }
307
319
 
308
320
  if (this._isClosed) {
309
- throw new Error("Queue is closed and empty");
321
+ throw new Error(CLOSED_AND_EMPTY);
310
322
  }
311
323
 
312
324
  // Wait for the next element without a take. (Before, peek took the element and put it back
@@ -349,7 +361,7 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
349
361
  // Reject all waiting putters
350
362
  for (const putter of this.putters) {
351
363
  this.clearTimeout(putter);
352
- putter.reject(new Error("Queue closed"));
364
+ putter.reject(new Error(CLOSED));
353
365
  }
354
366
  this.putters = [];
355
367
 
@@ -357,12 +369,12 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
357
369
  if (this.buffer.length === 0) {
358
370
  for (const taker of this.takers) {
359
371
  this.clearTimeout(taker);
360
- taker.reject(new Error("Queue closed and empty"));
372
+ taker.reject(new Error(CLOSED_AND_EMPTY));
361
373
  }
362
374
  this.takers = [];
363
375
  for (const peeker of this.peekers) {
364
376
  this.clearTimeout(peeker);
365
- peeker.reject(new Error("Queue closed and empty"));
377
+ peeker.reject(new Error(CLOSED_AND_EMPTY));
366
378
  }
367
379
  this.peekers = [];
368
380
  }
@@ -471,6 +483,8 @@ export class AsyncQueue<T> implements IAsyncQueue<T> {
471
483
  /**
472
484
  * Factory function to make an AsyncQueue.
473
485
  *
486
+ * @throws RangeError if the capacity is not a whole number of 0 or more, or `Infinity`
487
+ *
474
488
  * @example
475
489
  * const queue = asyncQueue<number>({ capacity: 100 })
476
490
  * await queue.put(42)
@@ -42,7 +42,7 @@ export class Channel<T> {
42
42
 
43
43
  /**
44
44
  * This method sends a value through the channel.
45
- * Blocks if channel buffer is full.
45
+ * The call blocks while the buffer of the channel is full.
46
46
  *
47
47
  * @throws Error if channel is closed
48
48
  */
@@ -55,7 +55,7 @@ export class Channel<T> {
55
55
 
56
56
  /**
57
57
  * This method receives a value from the channel.
58
- * Blocks if no value is available.
58
+ * The call blocks while no value is available.
59
59
  *
60
60
  * @throws Error if channel is closed and empty
61
61
  */
@@ -337,7 +337,7 @@ export function fanOut<T>(input: Channel<T>, count: number, bufferSize: number =
337
337
  }
338
338
 
339
339
  /**
340
- * Fan-in: merges multiple input channels into one output channel.
340
+ * Fan-in: this function merges multiple input channels into one output channel.
341
341
  *
342
342
  * @example
343
343
  * const ch1 = channel<number>()
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Bounded behavior - Enforces capacity limits on collections.
2
+ * Bounded behavior: this module enforces capacity limits on collections.
3
3
  *
4
4
  * This module wraps collections to prevent them from exceeding a maximum size.
5
5
  * This module gives various overflow policies to handle full collections.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Evented behavior - Emits typed events on collection mutations.
2
+ * Evented behavior: this module emits typed events on collection mutations.
3
3
  *
4
4
  * This module wraps collections to emit events whenever elements are added, removed,
5
5
  * or the collection is cleared. This module enables reactive programming patterns.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Readonly behavior - Makes immutable views of collections.
2
+ * Readonly behavior: this module makes immutable views of collections.
3
3
  *
4
4
  * This module wraps collections to prevent modifications by throwing errors
5
5
  * on any mutation try. Mirrors Java's Collections.unmodifiable*() methods.
@@ -21,27 +21,27 @@ import { none, some, toOptional, tryCatch, type Optional, type Result } from "@m
21
21
  */
22
22
  export interface SafeListOperations<T> {
23
23
  /**
24
- * Get element at index, as an optional.
24
+ * This method gives the element at an index, as an optional.
25
25
  */
26
26
  get(index: number): Optional<T>;
27
27
 
28
28
  /**
29
- * Set element at index, giving Result with old value or error.
29
+ * This method sets the element at an index. It gives a Result with the old value or an error.
30
30
  */
31
31
  set(index: number, element: T): Result<T, string>;
32
32
 
33
33
  /**
34
- * Remove element at index, giving Result with removed value or error.
34
+ * This method removes the element at an index. It gives a Result with the removed value or an error.
35
35
  */
36
36
  removeAt(index: number): Result<T, string>;
37
37
 
38
38
  /**
39
- * Get first element as an optional.
39
+ * This method gives the first element, as an optional.
40
40
  */
41
41
  first(): Optional<T>;
42
42
 
43
43
  /**
44
- * Get last element as an optional.
44
+ * This method gives the last element, as an optional.
45
45
  */
46
46
  last(): Optional<T>;
47
47
 
@@ -61,17 +61,17 @@ export interface SafeListOperations<T> {
61
61
  */
62
62
  export interface SafeQueueOperations<T> {
63
63
  /**
64
- * Peek at head element as an optional.
64
+ * This method gives the head element as an optional, and does not remove it.
65
65
  */
66
66
  peek(): Optional<T>;
67
67
 
68
68
  /**
69
- * Poll element as an optional.
69
+ * This method removes the head element and gives it as an optional.
70
70
  */
71
71
  poll(): Optional<T>;
72
72
 
73
73
  /**
74
- * Dequeue element as an optional.
74
+ * This method dequeues the head element and gives it as an optional.
75
75
  */
76
76
  dequeue(): Optional<T>;
77
77
  }
@@ -81,27 +81,27 @@ export interface SafeQueueOperations<T> {
81
81
  */
82
82
  export interface SafeDequeOperations<T> extends SafeQueueOperations<T> {
83
83
  /**
84
- * Peek at first element as an optional.
84
+ * This method gives the first element as an optional, and does not remove it.
85
85
  */
86
86
  peekFirst(): Optional<T>;
87
87
 
88
88
  /**
89
- * Peek at last element as an optional.
89
+ * This method gives the last element as an optional, and does not remove it.
90
90
  */
91
91
  peekLast(): Optional<T>;
92
92
 
93
93
  /**
94
- * Poll first element as an optional.
94
+ * This method removes the first element and gives it as an optional.
95
95
  */
96
96
  pollFirst(): Optional<T>;
97
97
 
98
98
  /**
99
- * Poll last element as an optional.
99
+ * This method removes the last element and gives it as an optional.
100
100
  */
101
101
  pollLast(): Optional<T>;
102
102
 
103
103
  /**
104
- * Pop element as an optional.
104
+ * This method pops the top element and gives it as an optional.
105
105
  */
106
106
  pop(): Optional<T>;
107
107
  }
@@ -111,17 +111,17 @@ export interface SafeDequeOperations<T> extends SafeQueueOperations<T> {
111
111
  */
112
112
  export interface SafeMapOperations<K, V> {
113
113
  /**
114
- * Get value for key as an optional.
114
+ * This method gives the value of a key, as an optional.
115
115
  */
116
116
  get(key: K): Optional<V>;
117
117
 
118
118
  /**
119
- * Set value for key, giving Result with old value or success.
119
+ * This method sets the value of a key. It gives a Result with the old value or a success.
120
120
  */
121
121
  set(key: K, value: V): Result<V | undefined, string>;
122
122
 
123
123
  /**
124
- * Delete key, giving Result with deleted value or error.
124
+ * This method deletes a key. It gives a Result with the deleted value or an error.
125
125
  */
126
126
  delete(key: K): Result<V | undefined, string>;
127
127
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Synchronized behavior - Gives thread-safe access with mutex locking.
2
+ * Synchronized behavior: this module gives thread-safe access with mutex locking.
3
3
  *
4
4
  * This module wraps collections to serialize all operations using a mutex, making sure that
5
5
  * thread-safe access in concurrent environments. Mirrors Java's
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * TTL (Time-To-Live) expiration behavior.
3
3
  *
4
- * Automatically expires elements after a specified time period.
4
+ * The behavior removes each element when its time to live ends.
5
5
  * Perfect for temporary caches and time-limited data.
6
6
  *
7
7
  * @example
@@ -20,7 +20,7 @@ import { removals, removalSource, type ElementRemoval, type MapRemoval } from ".
20
20
  import type { Collection } from "../interfaces/collection.js";
21
21
 
22
22
  /**
23
- * Start the background expiration checker without keeping a Node.js process alive.
23
+ * This function starts the background expiration checker, and it does not keep a Node.js process alive.
24
24
  * (In a browser, setInterval gives a number and there is nothing to unref.)
25
25
  */
26
26
  function startExpirationTimer(check: () => void, interval: number): ReturnType<typeof setInterval> {
@@ -368,7 +368,7 @@ export class TTLCache<K, V> {
368
368
  }
369
369
 
370
370
  /**
371
- * Manually trigger cleanup of expired entries.
371
+ * This method removes the expired entries at once.
372
372
  */
373
373
  cleanup(): void {
374
374
  const now = Date.now();
@@ -392,7 +392,7 @@ export class TTLCache<K, V> {
392
392
  }
393
393
 
394
394
  /**
395
- * Get remaining TTL for a key in milliseconds.
395
+ * This method gives the remaining TTL of a key, in milliseconds.
396
396
  * This method gives undefined if key doesn't exist or is expired.
397
397
  */
398
398
  getTTL(key: K): number | undefined {
@@ -404,7 +404,7 @@ export class TTLCache<K, V> {
404
404
  }
405
405
 
406
406
  /**
407
- * Update TTL for an existing key.
407
+ * This method updates the TTL of a key that is in the map.
408
408
  */
409
409
  touch(key: K, customTTL?: number): boolean {
410
410
  const entry = this.map.get(key);
@@ -425,7 +425,7 @@ export class TTLCache<K, V> {
425
425
  }
426
426
 
427
427
  /**
428
- * Stop the background expiration checker and clean up.
428
+ * This method stops the background expiration checker and cleans up.
429
429
  */
430
430
  dispose(): void {
431
431
  if (this.intervalId) {
@@ -54,7 +54,7 @@ export class Emitter<E extends EventMap> {
54
54
  private listeners = new Map<keyof E, Set<Listener<any>>>();
55
55
 
56
56
  /**
57
- * Subscribe to an event.
57
+ * This method subscribes a listener to an event.
58
58
  *
59
59
  * @param event The event name
60
60
  * @param listener The callback to invoke when event is emitted
@@ -79,7 +79,7 @@ export class Emitter<E extends EventMap> {
79
79
  }
80
80
 
81
81
  /**
82
- * Subscribe to an event, but automatically unsubscribe after first emission.
82
+ * This method subscribes a listener to an event, and unsubscribes it after the first emission.
83
83
  *
84
84
  * @param event The event name
85
85
  * @param listener The callback to invoke once
@@ -96,7 +96,7 @@ export class Emitter<E extends EventMap> {
96
96
  }
97
97
 
98
98
  /**
99
- * Emit an event to all registered listeners.
99
+ * This method emits an event to all registered listeners.
100
100
  *
101
101
  * @param event The event name
102
102
  * @param payload The event payload
@@ -121,7 +121,7 @@ export class Emitter<E extends EventMap> {
121
121
  }
122
122
 
123
123
  /**
124
- * Remove all listeners for a specific event, or all events if no event specified.
124
+ * This method removes all listeners of an event, or of all events when the call gives no event.
125
125
  *
126
126
  * @param event Optional event name to clear listeners for
127
127
  */
@@ -134,7 +134,7 @@ export class Emitter<E extends EventMap> {
134
134
  }
135
135
 
136
136
  /**
137
- * Get the number of listeners for a specific event.
137
+ * This method gives the number of listeners of an event.
138
138
  *
139
139
  * @param event The event name
140
140
  * @returns Number of registered listeners
@@ -144,21 +144,21 @@ export class Emitter<E extends EventMap> {
144
144
  }
145
145
 
146
146
  /**
147
- * Get all event names that have at least one listener.
147
+ * This method gives the names of the events that have one or more listeners.
148
148
  */
149
149
  eventNames(): (keyof E)[] {
150
150
  return Array.from(this.listeners.keys());
151
151
  }
152
152
 
153
153
  /**
154
- * Check if there are any listeners for a specific event.
154
+ * This method gives true when an event has one or more listeners.
155
155
  */
156
156
  hasListeners<K extends keyof E>(event: K): boolean {
157
157
  return this.listenerCount(event) > 0;
158
158
  }
159
159
 
160
160
  /**
161
- * Remove all listeners and clean up resources.
161
+ * This method removes all listeners and releases the resources.
162
162
  */
163
163
  dispose(): void {
164
164
  this.listeners.clear();
@@ -166,7 +166,7 @@ export class Emitter<E extends EventMap> {
166
166
  }
167
167
 
168
168
  /**
169
- * Make an event emitter for a specific event map.
169
+ * This function makes an event emitter for an event map.
170
170
  *
171
171
  * This is a convenience factory function.
172
172
  *
@@ -205,7 +205,7 @@ export class EventBatcher<E extends EventMap, K extends keyof E> {
205
205
  }
206
206
 
207
207
  /**
208
- * Add an event to the current batch.
208
+ * This method adds an event to the current batch.
209
209
  */
210
210
  queue(payload: E[K]): void {
211
211
  this.batch.push(payload);
@@ -216,7 +216,7 @@ export class EventBatcher<E extends EventMap, K extends keyof E> {
216
216
  }
217
217
 
218
218
  /**
219
- * Immediately emit all batched events.
219
+ * This method emits all batched events at once.
220
220
  */
221
221
  flush(): void {
222
222
  if (this.timer !== null) {
@@ -232,7 +232,7 @@ export class EventBatcher<E extends EventMap, K extends keyof E> {
232
232
  }
233
233
 
234
234
  /**
235
- * Clean up resources.
235
+ * This method sends the events of the batch and releases the resources.
236
236
  */
237
237
  dispose(): void {
238
238
  this.flush();
@@ -272,7 +272,7 @@ export class AsyncEmitter<E extends EventMap> {
272
272
  }
273
273
 
274
274
  /**
275
- * Emit an event and wait for all async listeners to complete.
275
+ * This method emits an event and waits until all async listeners complete.
276
276
  *
277
277
  * @param event The event name
278
278
  * @param payload The event payload
@@ -340,7 +340,7 @@ export const forwardEvent = <
340
340
  };
341
341
 
342
342
  /**
343
- * Make a filtered event subscription that only fires when predicate is true.
343
+ * This function makes a filtered event subscription that fires only when the predicate is true.
344
344
  *
345
345
  * @example
346
346
  * const emitter = new Emitter<{ change: { value: number } }>()
@@ -90,13 +90,13 @@ export const hasCapability = <C extends Collection<any>, K extends keyof any>(
90
90
  */
91
91
  export interface Evented<E extends Record<string, any>> {
92
92
  /**
93
- * Subscribe to an event.
93
+ * This method subscribes a listener to an event.
94
94
  * @returns Unsubscribe function
95
95
  */
96
96
  on<K extends keyof E>(event: K, handler: (payload: E[K]) => void): () => void;
97
97
 
98
98
  /**
99
- * Emit an event (internal use by middleware).
99
+ * This method emits an event. Only the middleware calls it.
100
100
  * @internal
101
101
  */
102
102
  emit?<K extends keyof E>(event: K, payload: E[K]): void;
@@ -135,7 +135,7 @@ export interface SafeCollection {
135
135
  }
136
136
 
137
137
  /**
138
- * Type helper to extract the element type from a collection.
138
+ * This type gives the element type of a collection.
139
139
  */
140
140
  export type ElementType<C> = C extends {
141
141
  [Symbol.iterator](): Iterator<infer T>;
@@ -148,7 +148,7 @@ export type ElementType<C> = C extends {
148
148
  : never;
149
149
 
150
150
  /**
151
- * Type helper to make all methods of a type return their async equivalents.
151
+ * This type changes each method of a type so that it gives its async equivalent.
152
152
  */
153
153
  export type Asyncify<C> = {
154
154
  [K in keyof C]: C[K] extends (...args: infer Args) => infer R
@@ -265,7 +265,7 @@ export abstract class CollectionBuilder<C> {
265
265
  protected middleware: Middleware<C>[] = [];
266
266
 
267
267
  /**
268
- * Apply a custom middleware.
268
+ * This method applies a custom middleware.
269
269
  */
270
270
  use(middleware: Middleware<C>): this {
271
271
  this.middleware.push(middleware);
@@ -273,7 +273,7 @@ export abstract class CollectionBuilder<C> {
273
273
  }
274
274
 
275
275
  /**
276
- * Build the final collection by composing all middleware with the base.
276
+ * This method builds the final collection: it composes all middleware with the base.
277
277
  */
278
278
  abstract build(): C;
279
279
  }
@@ -209,11 +209,11 @@ export type MergeFunction<T> = (current: T, incoming: T) => T;
209
209
  * Policy for when to compact internal storage.
210
210
  */
211
211
  export interface CompactionPolicy {
212
- /** Compact when the used part of the capacity drops below this ratio (0-1). */
212
+ /** The collection compacts when the used part of its capacity is less than this ratio, from 0 to 1. */
213
213
  readonly minLoadFactor?: number;
214
- /** Compact when wasted space exceeds this many elements. */
214
+ /** The collection compacts when its wasted space is more than this number of elements. */
215
215
  readonly maxWastedSpace?: number;
216
- /** Automatically compact on every removal. */
216
+ /** When it is true, the collection compacts at each removal. */
217
217
  readonly autoCompact?: boolean;
218
218
  }
219
219
 
@@ -5,7 +5,7 @@
5
5
  import type { DAGNode } from "./types.js";
6
6
 
7
7
  /**
8
- * Filter DAG to only include nodes reachable from a root
8
+ * This function filters a DAG to the nodes that a root can reach.
9
9
  */
10
10
  export function filterDAGFromRoot<TNode extends DAGNode>(
11
11
  nodes: Map<string, TNode>,
@@ -33,7 +33,7 @@ export function filterDAGFromRoot<TNode extends DAGNode>(
33
33
  }
34
34
 
35
35
  /**
36
- * Get all ancestors of a node (nodes that this node depends on, transitively)
36
+ * This function gives all ancestors of a node: the nodes that this node depends on, transitively.
37
37
  */
38
38
  export function getAncestors<TNode extends DAGNode>(
39
39
  nodes: Map<string, TNode>,
@@ -62,7 +62,7 @@ export function getAncestors<TNode extends DAGNode>(
62
62
  }
63
63
 
64
64
  /**
65
- * Get all descendants of a node (nodes that depend on this node, transitively)
65
+ * This function gives all descendants of a node: the nodes that depend on this node, transitively.
66
66
  */
67
67
  export function getDescendants<TNode extends DAGNode>(
68
68
  nodes: Map<string, TNode>,
@@ -100,7 +100,7 @@ export function getDescendants<TNode extends DAGNode>(
100
100
  }
101
101
 
102
102
  /**
103
- * Make a DAG node from minimal input
103
+ * This function makes a DAG node from a minimal input.
104
104
  */
105
105
  export function createNode<TData = unknown>(
106
106
  id: string,
@@ -115,7 +115,7 @@ export function createNode<TData = unknown>(
115
115
  }
116
116
 
117
117
  /**
118
- * Build a Map of nodes from an array
118
+ * This function builds a Map of nodes from an array.
119
119
  */
120
120
  export function buildNodeMap<TNode extends DAGNode>(
121
121
  nodes: TNode[]
@@ -11,7 +11,7 @@ import type {
11
11
  } from "./types.js";
12
12
 
13
13
  /**
14
- * Start a batch of items with concurrency limit
14
+ * This function starts a batch of items with a limit of concurrency.
15
15
  */
16
16
  async function executeWithConcurrency<T, R>(
17
17
  items: T[],
@@ -45,7 +45,7 @@ async function executeWithConcurrency<T, R>(
45
45
  }
46
46
 
47
47
  /**
48
- * Call a listener. A listener that throws does not stop the run: the function gives a log
48
+ * This function calls a listener. A listener that throws does not stop the run: the function gives a log
49
49
  * line for its error (deep dive DATA-21).
50
50
  */
51
51
  function notify<T>(name: string, listener: ((arg: T) => void) | undefined, arg: T): string | undefined {
@@ -59,7 +59,7 @@ function notify<T>(name: string, listener: ((arg: T) => void) | undefined, arg:
59
59
  }
60
60
 
61
61
  /**
62
- * Start DAG with level-based parallelization
62
+ * This function starts a DAG level by level, with the nodes of each level in parallel.
63
63
  *
64
64
  * - Levels are processed sequentially (level 0 first, then level 1, and so on)
65
65
  * - Within each level, nodes are processed in parallel up to concurrency limit
@@ -167,7 +167,7 @@ export async function executeDAG<TNode extends DAGNode>(
167
167
  }
168
168
 
169
169
  /**
170
- * Start DAG sequentially (no parallelization)
170
+ * This function starts a DAG one node at a time, with no nodes in parallel.
171
171
  */
172
172
  export async function executeDAGSequential<TNode extends DAGNode>(
173
173
  dag: DependencyDAG<TNode>,
@@ -178,7 +178,7 @@ export async function executeDAGSequential<TNode extends DAGNode>(
178
178
  }
179
179
 
180
180
  /**
181
- * Make a simple processor that wraps an async function
181
+ * This function makes a simple processor that wraps an async function.
182
182
  */
183
183
  export function createProcessor<TNode extends DAGNode>(
184
184
  fn: (node: TNode) => Promise<void>
@@ -8,7 +8,7 @@
8
8
  import type { DAGNode, DependencyDAG } from "./types.js";
9
9
 
10
10
  /**
11
- * Build a leveled DAG from nodes using Kahn's algorithm
11
+ * This function builds a leveled DAG from nodes, with Kahn's algorithm.
12
12
  *
13
13
  * This assigns levels to each node where:
14
14
  * - Level 0: Nodes with no dependencies (leaves)
@@ -97,7 +97,7 @@ export function buildLeveledDAG<TNode extends DAGNode>(
97
97
  }
98
98
 
99
99
  /**
100
- * Get the topological order (flat list, leaves first)
100
+ * This function gives the topological order: a flat list, leaves first.
101
101
  */
102
102
  export function getTopologicalOrder<TNode extends DAGNode>(
103
103
  dag: DependencyDAG<TNode>
@@ -149,7 +149,7 @@ export function groupingBy<T, K>(
149
149
  }
150
150
 
151
151
  /**
152
- * Groups and transforms with a downstream collector.
152
+ * This function groups the elements and transforms each group with a downstream collector.
153
153
  *
154
154
  * @example
155
155
  * const countByAge = collect(