@nlozgachev/pipelined 0.31.0 → 0.32.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/dist/utils.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { M as Maybe, R as Result, T as Task } from './Task-BDcKwFAj.mjs';
1
+ import { M as Maybe, E as Equality, b as Ordering, R as Result, T as Task } from './Task-CJZfcOkO.mjs';
2
2
  import { N as NonEmptyList } from './NonEmptyList-BlGFjor5.mjs';
3
3
 
4
4
  /**
@@ -173,8 +173,26 @@ declare namespace Arr {
173
173
  * ```
174
174
  */
175
175
  const uniqBy: <A, B>(f: (a: A) => B) => (data: readonly A[]) => readonly A[];
176
+ /**
177
+ * Removes duplicate elements using a custom equality check.
178
+ * Preserves the order of first occurrences. Complements `uniq` (reference equality)
179
+ * and `uniqBy` (key extraction).
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * type Point = { x: number; y: number };
184
+ * const eqPoint: Equality<Point> = (a, b) => a.x === b.x && a.y === b.y;
185
+ *
186
+ * pipe(
187
+ * [{ x: 1, y: 1 }, { x: 2, y: 2 }, { x: 1, y: 1 }],
188
+ * Arr.uniqWith(eqPoint),
189
+ * ); // [{ x: 1, y: 1 }, { x: 2, y: 2 }]
190
+ * ```
191
+ */
192
+ const uniqWith: <A>(eq: Equality<A>) => (data: readonly A[]) => readonly A[];
176
193
  /**
177
194
  * Sorts an array using a comparison function. Returns a new array.
195
+ * To sort with a typed `Ordering<A>`, prefer `Arr.sortWith`.
178
196
  *
179
197
  * @example
180
198
  * ```ts
@@ -182,6 +200,19 @@ declare namespace Arr {
182
200
  * ```
183
201
  */
184
202
  const sortBy: <A>(compare: (a: A, b: A) => number) => (data: readonly A[]) => readonly A[];
203
+ /**
204
+ * Sorts an array using an `Ordering<A>`. Returns a new array without mutating the original.
205
+ * Use this over `sortBy` when you have a typed `Ordering<A>` from the `Ordering` module.
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
210
+ *
211
+ * const byPrice = pipe(Ordering.number, Ordering.by((p: Product) => p.price));
212
+ * pipe(products, Arr.sortWith(byPrice));
213
+ * ```
214
+ */
215
+ const sortWith: <A>(ord: Ordering<A>) => (data: readonly A[]) => readonly A[];
185
216
  /**
186
217
  * Pairs up elements from two arrays. Stops at the shorter array.
187
218
  *
@@ -945,6 +976,46 @@ declare namespace Num {
945
976
  * ```
946
977
  */
947
978
  const remainder: (divisor: number) => (n: number) => Maybe<number>;
979
+ /**
980
+ * Computes the sum of a list of numbers. Returns `0` if the list is empty.
981
+ *
982
+ * @example
983
+ * ```ts
984
+ * Num.sum([1, 2, 3]); // 6
985
+ * Num.sum([]); // 0
986
+ * ```
987
+ */
988
+ const sum: (ns: readonly number[]) => number;
989
+ /**
990
+ * Computes the mean of a list of numbers. Returns `None` if the list is empty.
991
+ *
992
+ * @example
993
+ * ```ts
994
+ * Num.mean([1, 2, 3]); // Some(2)
995
+ * Num.mean([]); // None
996
+ * ```
997
+ */
998
+ const mean: (ns: readonly number[]) => Maybe<number>;
999
+ /**
1000
+ * Computes the minimum of a list of numbers. Returns `None` if the list is empty.
1001
+ *
1002
+ * @example
1003
+ * ```ts
1004
+ * Num.min([5, 1, 3]); // Some(1)
1005
+ * Num.min([]); // None
1006
+ * ```
1007
+ */
1008
+ const min: (ns: readonly number[]) => Maybe<number>;
1009
+ /**
1010
+ * Computes the maximum of a list of numbers. Returns `None` if the list is empty.
1011
+ *
1012
+ * @example
1013
+ * ```ts
1014
+ * Num.max([1, 5, 3]); // Some(5)
1015
+ * Num.max([]); // None
1016
+ * ```
1017
+ */
1018
+ const max: (ns: readonly number[]) => Maybe<number>;
948
1019
  }
949
1020
 
950
1021
  /**
@@ -1204,6 +1275,15 @@ declare namespace Str {
1204
1275
  * ```
1205
1276
  */
1206
1277
  const toLowerCase: (s: string) => string;
1278
+ /**
1279
+ * Converts the first character of a string to uppercase.
1280
+ *
1281
+ * @example
1282
+ * ```ts
1283
+ * pipe("hello", Str.capitalize); // "Hello"
1284
+ * ```
1285
+ */
1286
+ const capitalize: (s: string) => string;
1207
1287
  /**
1208
1288
  * Splits a string into lines, normalising `\r\n` and `\r` line endings.
1209
1289
  *
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { M as Maybe, R as Result, T as Task } from './Task-CnF22Q2o.js';
1
+ import { M as Maybe, E as Equality, b as Ordering, R as Result, T as Task } from './Task-CjYKLeTY.js';
2
2
  import { N as NonEmptyList } from './NonEmptyList-BlGFjor5.js';
3
3
 
4
4
  /**
@@ -173,8 +173,26 @@ declare namespace Arr {
173
173
  * ```
174
174
  */
175
175
  const uniqBy: <A, B>(f: (a: A) => B) => (data: readonly A[]) => readonly A[];
176
+ /**
177
+ * Removes duplicate elements using a custom equality check.
178
+ * Preserves the order of first occurrences. Complements `uniq` (reference equality)
179
+ * and `uniqBy` (key extraction).
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * type Point = { x: number; y: number };
184
+ * const eqPoint: Equality<Point> = (a, b) => a.x === b.x && a.y === b.y;
185
+ *
186
+ * pipe(
187
+ * [{ x: 1, y: 1 }, { x: 2, y: 2 }, { x: 1, y: 1 }],
188
+ * Arr.uniqWith(eqPoint),
189
+ * ); // [{ x: 1, y: 1 }, { x: 2, y: 2 }]
190
+ * ```
191
+ */
192
+ const uniqWith: <A>(eq: Equality<A>) => (data: readonly A[]) => readonly A[];
176
193
  /**
177
194
  * Sorts an array using a comparison function. Returns a new array.
195
+ * To sort with a typed `Ordering<A>`, prefer `Arr.sortWith`.
178
196
  *
179
197
  * @example
180
198
  * ```ts
@@ -182,6 +200,19 @@ declare namespace Arr {
182
200
  * ```
183
201
  */
184
202
  const sortBy: <A>(compare: (a: A, b: A) => number) => (data: readonly A[]) => readonly A[];
203
+ /**
204
+ * Sorts an array using an `Ordering<A>`. Returns a new array without mutating the original.
205
+ * Use this over `sortBy` when you have a typed `Ordering<A>` from the `Ordering` module.
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
210
+ *
211
+ * const byPrice = pipe(Ordering.number, Ordering.by((p: Product) => p.price));
212
+ * pipe(products, Arr.sortWith(byPrice));
213
+ * ```
214
+ */
215
+ const sortWith: <A>(ord: Ordering<A>) => (data: readonly A[]) => readonly A[];
185
216
  /**
186
217
  * Pairs up elements from two arrays. Stops at the shorter array.
187
218
  *
@@ -945,6 +976,46 @@ declare namespace Num {
945
976
  * ```
946
977
  */
947
978
  const remainder: (divisor: number) => (n: number) => Maybe<number>;
979
+ /**
980
+ * Computes the sum of a list of numbers. Returns `0` if the list is empty.
981
+ *
982
+ * @example
983
+ * ```ts
984
+ * Num.sum([1, 2, 3]); // 6
985
+ * Num.sum([]); // 0
986
+ * ```
987
+ */
988
+ const sum: (ns: readonly number[]) => number;
989
+ /**
990
+ * Computes the mean of a list of numbers. Returns `None` if the list is empty.
991
+ *
992
+ * @example
993
+ * ```ts
994
+ * Num.mean([1, 2, 3]); // Some(2)
995
+ * Num.mean([]); // None
996
+ * ```
997
+ */
998
+ const mean: (ns: readonly number[]) => Maybe<number>;
999
+ /**
1000
+ * Computes the minimum of a list of numbers. Returns `None` if the list is empty.
1001
+ *
1002
+ * @example
1003
+ * ```ts
1004
+ * Num.min([5, 1, 3]); // Some(1)
1005
+ * Num.min([]); // None
1006
+ * ```
1007
+ */
1008
+ const min: (ns: readonly number[]) => Maybe<number>;
1009
+ /**
1010
+ * Computes the maximum of a list of numbers. Returns `None` if the list is empty.
1011
+ *
1012
+ * @example
1013
+ * ```ts
1014
+ * Num.max([1, 5, 3]); // Some(5)
1015
+ * Num.max([]); // None
1016
+ * ```
1017
+ */
1018
+ const max: (ns: readonly number[]) => Maybe<number>;
948
1019
  }
949
1020
 
950
1021
  /**
@@ -1204,6 +1275,15 @@ declare namespace Str {
1204
1275
  * ```
1205
1276
  */
1206
1277
  const toLowerCase: (s: string) => string;
1278
+ /**
1279
+ * Converts the first character of a string to uppercase.
1280
+ *
1281
+ * @example
1282
+ * ```ts
1283
+ * pipe("hello", Str.capitalize); // "Hello"
1284
+ * ```
1285
+ */
1286
+ const capitalize: (s: string) => string;
1207
1287
  /**
1208
1288
  * Splits a string into lines, normalising `\r\n` and `\r` line endings.
1209
1289
  *
package/dist/utils.js CHANGED
@@ -127,58 +127,135 @@ var Task;
127
127
  (signal) => Promise.all(tasks.map((t) => toPromise(t, signal)))
128
128
  );
129
129
  Task2.delay = (ms) => (data) => (0, Task2.from)(
130
- (signal) => new Promise(
131
- (resolve2) => setTimeout(
132
- () => toPromise(data, signal).then(resolve2),
133
- ms
134
- )
135
- )
130
+ (signal) => new Promise((resolve2) => {
131
+ let timerId = void 0;
132
+ const onAbort = () => {
133
+ if (timerId !== void 0) {
134
+ clearTimeout(timerId);
135
+ }
136
+ resolve2(toPromise(data, signal));
137
+ };
138
+ if (signal) {
139
+ if (signal.aborted) {
140
+ return resolve2(toPromise(data, signal));
141
+ }
142
+ signal.addEventListener("abort", onAbort, { once: true });
143
+ }
144
+ timerId = setTimeout(() => {
145
+ signal?.removeEventListener("abort", onAbort);
146
+ resolve2(toPromise(data, signal));
147
+ }, ms);
148
+ })
136
149
  );
137
150
  Task2.repeat = (options) => (task) => (0, Task2.from)((signal) => {
138
151
  const { times, delay: ms } = options;
139
152
  if (times <= 0) return Promise.resolve([]);
140
153
  const results = [];
141
- const wait = () => ms !== void 0 && ms > 0 ? new Promise((r) => setTimeout(r, ms)) : Promise.resolve();
142
- const run2 = (left) => toPromise(task, signal).then((a) => {
143
- results.push(a);
144
- if (left <= 1) return results;
145
- return wait().then(() => run2(left - 1));
146
- });
154
+ const wait = () => {
155
+ if (signal?.aborted) return Promise.resolve();
156
+ return new Promise((r) => {
157
+ let timerId = void 0;
158
+ const onAbort = () => {
159
+ if (timerId !== void 0) {
160
+ clearTimeout(timerId);
161
+ }
162
+ r();
163
+ };
164
+ if (signal) {
165
+ signal.addEventListener("abort", onAbort, { once: true });
166
+ }
167
+ timerId = setTimeout(() => {
168
+ signal?.removeEventListener("abort", onAbort);
169
+ r();
170
+ }, ms || 0);
171
+ });
172
+ };
173
+ const run2 = (left) => {
174
+ if (signal?.aborted) {
175
+ return Promise.resolve(results);
176
+ }
177
+ return toPromise(task, signal).then((a) => {
178
+ results.push(a);
179
+ if (left <= 1 || signal?.aborted) return results;
180
+ return wait().then(() => run2(left - 1));
181
+ });
182
+ };
147
183
  return run2(times);
148
184
  });
149
185
  Task2.repeatUntil = (options) => (task) => (0, Task2.from)((signal) => {
150
186
  const { when: predicate, delay: ms, maxAttempts } = options;
151
- const wait = () => ms !== void 0 && ms > 0 ? new Promise((r) => setTimeout(r, ms)) : Promise.resolve();
152
- const run2 = (attempt) => toPromise(task, signal).then((a) => {
153
- if (predicate(a)) return a;
154
- if (maxAttempts !== void 0 && attempt >= maxAttempts) return a;
155
- return wait().then(() => run2(attempt + 1));
156
- });
187
+ const wait = () => {
188
+ if (signal?.aborted) return Promise.resolve();
189
+ return new Promise((r) => {
190
+ let timerId = void 0;
191
+ const onAbort = () => {
192
+ if (timerId !== void 0) {
193
+ clearTimeout(timerId);
194
+ }
195
+ r();
196
+ };
197
+ if (signal) {
198
+ signal.addEventListener("abort", onAbort, { once: true });
199
+ }
200
+ timerId = setTimeout(() => {
201
+ signal?.removeEventListener("abort", onAbort);
202
+ r();
203
+ }, ms || 0);
204
+ });
205
+ };
206
+ const run2 = (attempt, lastValue) => {
207
+ if (signal?.aborted && lastValue !== void 0) {
208
+ return Promise.resolve(lastValue);
209
+ }
210
+ return toPromise(task, signal).then((a) => {
211
+ if (predicate(a)) return a;
212
+ if (maxAttempts !== void 0 && attempt >= maxAttempts) return a;
213
+ if (signal?.aborted) return a;
214
+ return wait().then(() => run2(attempt + 1, a));
215
+ });
216
+ };
157
217
  return run2(1);
158
218
  });
159
219
  Task2.race = (tasks) => (0, Task2.from)((signal) => Promise.race(tasks.map((t) => toPromise(t, signal))));
160
220
  Task2.sequential = (tasks) => (0, Task2.from)(async (signal) => {
161
221
  const results = [];
162
222
  for (const task of tasks) {
223
+ if (signal?.aborted) {
224
+ break;
225
+ }
163
226
  results.push(await toPromise(task, signal));
164
227
  }
165
228
  return results;
166
229
  });
167
230
  Task2.timeout = (ms, onTimeout) => (task) => (0, Task2.from)((outerSignal) => {
168
231
  const controller = new AbortController();
169
- const onOuterAbort = () => controller.abort();
170
- outerSignal?.addEventListener("abort", onOuterAbort, { once: true });
171
232
  let timerId;
233
+ const cleanUp = () => {
234
+ if (timerId !== void 0) {
235
+ clearTimeout(timerId);
236
+ }
237
+ outerSignal?.removeEventListener("abort", onOuterAbort);
238
+ };
239
+ const onOuterAbort = () => {
240
+ cleanUp();
241
+ controller.abort();
242
+ };
243
+ if (outerSignal) {
244
+ if (outerSignal.aborted) {
245
+ controller.abort();
246
+ } else {
247
+ outerSignal.addEventListener("abort", onOuterAbort, { once: true });
248
+ }
249
+ }
172
250
  return Promise.race([
173
251
  toPromise(task, controller.signal).then((a) => {
174
- clearTimeout(timerId);
175
- outerSignal?.removeEventListener("abort", onOuterAbort);
252
+ cleanUp();
176
253
  return Result.ok(a);
177
254
  }),
178
255
  new Promise((resolve2) => {
179
256
  timerId = setTimeout(() => {
180
257
  controller.abort();
181
- outerSignal?.removeEventListener("abort", onOuterAbort);
258
+ cleanUp();
182
259
  resolve2(Result.error(onTimeout()));
183
260
  }, ms);
184
261
  })
@@ -289,11 +366,25 @@ var Arr;
289
366
  }
290
367
  return result;
291
368
  };
369
+ Arr2.uniqWith = (eq) => (data) => {
370
+ const result = [];
371
+ for (const a of data) {
372
+ if (!result.some((x) => eq(x, a))) {
373
+ result.push(a);
374
+ }
375
+ }
376
+ return result;
377
+ };
292
378
  Arr2.sortBy = (compare) => (data) => {
293
379
  const arr = data;
294
380
  if (typeof arr.toSorted === "function") return arr.toSorted(compare);
295
381
  return [...data].sort(compare);
296
382
  };
383
+ Arr2.sortWith = (ord) => (data) => {
384
+ const arr = data;
385
+ if (typeof arr.toSorted === "function") return arr.toSorted(ord);
386
+ return [...data].sort(ord);
387
+ };
297
388
  Arr2.zip = (other) => (data) => {
298
389
  const len = Math.min(data.length, other.length);
299
390
  const result = new Array(len);
@@ -326,7 +417,23 @@ var Arr;
326
417
  }
327
418
  return result;
328
419
  };
329
- Arr2.flatten = (data) => [].concat(...data);
420
+ Arr2.flatten = (data) => {
421
+ let totalLen = 0;
422
+ const outerLen = data.length;
423
+ for (let i = 0; i < outerLen; i++) {
424
+ totalLen += data[i].length;
425
+ }
426
+ const result = new Array(totalLen);
427
+ let idx = 0;
428
+ for (let i = 0; i < outerLen; i++) {
429
+ const chunk = data[i];
430
+ const innerLen = chunk.length;
431
+ for (let j = 0; j < innerLen; j++) {
432
+ result[idx++] = chunk[j];
433
+ }
434
+ }
435
+ return result;
436
+ };
330
437
  Arr2.flatMap = (f) => (data) => {
331
438
  const n = data.length;
332
439
  const result = [];
@@ -565,8 +672,8 @@ var Num;
565
672
  }
566
673
  return result;
567
674
  };
568
- Num2.clamp = (min, max) => (n) => Math.min(Math.max(n, min), max);
569
- Num2.between = (min, max) => (n) => n >= min && n <= max;
675
+ Num2.clamp = (min2, max2) => (n) => Math.min(Math.max(n, min2), max2);
676
+ Num2.between = (min2, max2) => (n) => n >= min2 && n <= max2;
570
677
  Num2.parse = (s) => {
571
678
  if (s.trim() === "") return Maybe.none();
572
679
  const n = Number(s);
@@ -582,6 +689,28 @@ var Num;
582
689
  Num2.floor = (n) => Math.floor(n);
583
690
  Num2.ceil = (n) => Math.ceil(n);
584
691
  Num2.remainder = (divisor) => (n) => divisor === 0 ? Maybe.none() : Maybe.some(n % divisor);
692
+ Num2.sum = (ns) => {
693
+ let result = 0;
694
+ for (let i = 0; i < ns.length; i++) result += ns[i];
695
+ return result;
696
+ };
697
+ Num2.mean = (ns) => ns.length === 0 ? Maybe.none() : Maybe.some((0, Num2.sum)(ns) / ns.length);
698
+ Num2.min = (ns) => {
699
+ if (ns.length === 0) return Maybe.none();
700
+ let [result] = ns;
701
+ for (let i = 1; i < ns.length; i++) {
702
+ if (ns[i] < result) result = ns[i];
703
+ }
704
+ return Maybe.some(result);
705
+ };
706
+ Num2.max = (ns) => {
707
+ if (ns.length === 0) return Maybe.none();
708
+ let [result] = ns;
709
+ for (let i = 1; i < ns.length; i++) {
710
+ if (ns[i] > result) result = ns[i];
711
+ }
712
+ return Maybe.some(result);
713
+ };
585
714
  })(Num || (Num = {}));
586
715
 
587
716
  // src/Utils/Rec.ts
@@ -705,6 +834,7 @@ var Str;
705
834
  Str2.endsWith = (suffix) => (s) => s.endsWith(suffix);
706
835
  Str2.toUpperCase = (s) => s.toUpperCase();
707
836
  Str2.toLowerCase = (s) => s.toLowerCase();
837
+ Str2.capitalize = (s) => s.length === 0 ? "" : s.charAt(0).toUpperCase() + s.slice(1);
708
838
  Str2.lines = (s) => s.split(/\r?\n|\r/);
709
839
  Str2.words = (s) => s.trim().split(/\s+/).filter(Boolean);
710
840
  Str2.isEmpty = (s) => s.length === 0;
package/dist/utils.mjs CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  Rec,
6
6
  Str,
7
7
  Uniq
8
- } from "./chunk-FWYOEWJ2.mjs";
9
- import "./chunk-SDGDJ7CU.mjs";
8
+ } from "./chunk-EHQFUWZW.mjs";
9
+ import "./chunk-TK5ZCGP2.mjs";
10
10
  import "./chunk-DBIC62UV.mjs";
11
11
  export {
12
12
  Arr,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nlozgachev/pipelined",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Opinionated functional abstractions for TypeScript",
5
5
  "license": "BSD-3-Clause",
6
6
  "homepage": "https://pipelined.lozgachev.dev",