@nlozgachev/pipekit 0.1.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.
Files changed (100) hide show
  1. package/README.md +182 -0
  2. package/esm/mod.js +3 -0
  3. package/esm/package.json +3 -0
  4. package/esm/src/Composition/compose.js +3 -0
  5. package/esm/src/Composition/curry.js +42 -0
  6. package/esm/src/Composition/flip.js +20 -0
  7. package/esm/src/Composition/flow.js +8 -0
  8. package/esm/src/Composition/fn.js +85 -0
  9. package/esm/src/Composition/index.js +10 -0
  10. package/esm/src/Composition/memoize.js +66 -0
  11. package/esm/src/Composition/not.js +25 -0
  12. package/esm/src/Composition/pipe.js +3 -0
  13. package/esm/src/Composition/tap.js +33 -0
  14. package/esm/src/Composition/uncurry.js +32 -0
  15. package/esm/src/Core/Arr.js +461 -0
  16. package/esm/src/Core/InternalTypes.js +1 -0
  17. package/esm/src/Core/Option.js +195 -0
  18. package/esm/src/Core/Rec.js +167 -0
  19. package/esm/src/Core/RemoteData.js +210 -0
  20. package/esm/src/Core/Result.js +173 -0
  21. package/esm/src/Core/Task.js +108 -0
  22. package/esm/src/Core/TaskResult.js +63 -0
  23. package/esm/src/Core/Validation.js +215 -0
  24. package/esm/src/Core/index.js +8 -0
  25. package/esm/src/Types/NonEmptyList.js +14 -0
  26. package/esm/src/Types/index.js +1 -0
  27. package/package.json +60 -0
  28. package/script/mod.js +19 -0
  29. package/script/package.json +3 -0
  30. package/script/src/Composition/compose.js +6 -0
  31. package/script/src/Composition/curry.js +48 -0
  32. package/script/src/Composition/flip.js +24 -0
  33. package/script/src/Composition/flow.js +11 -0
  34. package/script/src/Composition/fn.js +98 -0
  35. package/script/src/Composition/index.js +26 -0
  36. package/script/src/Composition/memoize.js +71 -0
  37. package/script/src/Composition/not.js +29 -0
  38. package/script/src/Composition/pipe.js +6 -0
  39. package/script/src/Composition/tap.js +37 -0
  40. package/script/src/Composition/uncurry.js +38 -0
  41. package/script/src/Core/Arr.js +464 -0
  42. package/script/src/Core/InternalTypes.js +2 -0
  43. package/script/src/Core/Option.js +198 -0
  44. package/script/src/Core/Rec.js +170 -0
  45. package/script/src/Core/RemoteData.js +213 -0
  46. package/script/src/Core/Result.js +176 -0
  47. package/script/src/Core/Task.js +111 -0
  48. package/script/src/Core/TaskResult.js +66 -0
  49. package/script/src/Core/Validation.js +218 -0
  50. package/script/src/Core/index.js +24 -0
  51. package/script/src/Types/NonEmptyList.js +18 -0
  52. package/script/src/Types/index.js +17 -0
  53. package/types/mod.d.ts +4 -0
  54. package/types/mod.d.ts.map +1 -0
  55. package/types/src/Composition/compose.d.ts +33 -0
  56. package/types/src/Composition/compose.d.ts.map +1 -0
  57. package/types/src/Composition/curry.d.ts +43 -0
  58. package/types/src/Composition/curry.d.ts.map +1 -0
  59. package/types/src/Composition/flip.d.ts +21 -0
  60. package/types/src/Composition/flip.d.ts.map +1 -0
  61. package/types/src/Composition/flow.d.ts +56 -0
  62. package/types/src/Composition/flow.d.ts.map +1 -0
  63. package/types/src/Composition/fn.d.ts +76 -0
  64. package/types/src/Composition/fn.d.ts.map +1 -0
  65. package/types/src/Composition/index.d.ts +11 -0
  66. package/types/src/Composition/index.d.ts.map +1 -0
  67. package/types/src/Composition/memoize.d.ts +46 -0
  68. package/types/src/Composition/memoize.d.ts.map +1 -0
  69. package/types/src/Composition/not.d.ts +26 -0
  70. package/types/src/Composition/not.d.ts.map +1 -0
  71. package/types/src/Composition/pipe.d.ts +56 -0
  72. package/types/src/Composition/pipe.d.ts.map +1 -0
  73. package/types/src/Composition/tap.d.ts +31 -0
  74. package/types/src/Composition/tap.d.ts.map +1 -0
  75. package/types/src/Composition/uncurry.d.ts +54 -0
  76. package/types/src/Composition/uncurry.d.ts.map +1 -0
  77. package/types/src/Core/Arr.d.ts +355 -0
  78. package/types/src/Core/Arr.d.ts.map +1 -0
  79. package/types/src/Core/InternalTypes.d.ts +14 -0
  80. package/types/src/Core/InternalTypes.d.ts.map +1 -0
  81. package/types/src/Core/Option.d.ts +214 -0
  82. package/types/src/Core/Option.d.ts.map +1 -0
  83. package/types/src/Core/Rec.d.ts +121 -0
  84. package/types/src/Core/Rec.d.ts.map +1 -0
  85. package/types/src/Core/RemoteData.d.ts +196 -0
  86. package/types/src/Core/RemoteData.d.ts.map +1 -0
  87. package/types/src/Core/Result.d.ts +185 -0
  88. package/types/src/Core/Result.d.ts.map +1 -0
  89. package/types/src/Core/Task.d.ts +125 -0
  90. package/types/src/Core/Task.d.ts.map +1 -0
  91. package/types/src/Core/TaskResult.d.ts +78 -0
  92. package/types/src/Core/TaskResult.d.ts.map +1 -0
  93. package/types/src/Core/Validation.d.ts +217 -0
  94. package/types/src/Core/Validation.d.ts.map +1 -0
  95. package/types/src/Core/index.d.ts +9 -0
  96. package/types/src/Core/index.d.ts.map +1 -0
  97. package/types/src/Types/NonEmptyList.d.ts +29 -0
  98. package/types/src/Types/NonEmptyList.d.ts.map +1 -0
  99. package/types/src/Types/index.d.ts +2 -0
  100. package/types/src/Types/index.d.ts.map +1 -0
@@ -0,0 +1,461 @@
1
+ import { Option } from "./Option.js";
2
+ import { Result } from "./Result.js";
3
+ import { isNonEmptyList } from "../Types/NonEmptyList.js";
4
+ /**
5
+ * Functional array utilities that compose well with pipe.
6
+ * All functions are data-last and curried where applicable.
7
+ * Safe access functions return Option instead of throwing or returning undefined.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * pipe(
12
+ * [1, 2, 3, 4, 5],
13
+ * Arr.filter(n => n > 2),
14
+ * Arr.map(n => n * 10),
15
+ * Arr.head
16
+ * ); // Some(30)
17
+ * ```
18
+ */
19
+ export var Arr;
20
+ (function (Arr) {
21
+ // --- Safe access ---
22
+ /**
23
+ * Returns the first element of an array, or None if the array is empty.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * Arr.head([1, 2, 3]); // Some(1)
28
+ * Arr.head([]); // None
29
+ * ```
30
+ */
31
+ Arr.head = (data) => data.length > 0 ? Option.toSome(data[0]) : Option.toNone();
32
+ /**
33
+ * Returns the last element of an array, or None if the array is empty.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * Arr.last([1, 2, 3]); // Some(3)
38
+ * Arr.last([]); // None
39
+ * ```
40
+ */
41
+ Arr.last = (data) => data.length > 0 ? Option.toSome(data[data.length - 1]) : Option.toNone();
42
+ /**
43
+ * Returns all elements except the first, or None if the array is empty.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * Arr.tail([1, 2, 3]); // Some([2, 3])
48
+ * Arr.tail([]); // None
49
+ * ```
50
+ */
51
+ Arr.tail = (data) => data.length > 0 ? Option.toSome(data.slice(1)) : Option.toNone();
52
+ /**
53
+ * Returns all elements except the last, or None if the array is empty.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * Arr.init([1, 2, 3]); // Some([1, 2])
58
+ * Arr.init([]); // None
59
+ * ```
60
+ */
61
+ Arr.init = (data) => data.length > 0 ? Option.toSome(data.slice(0, -1)) : Option.toNone();
62
+ // --- Search ---
63
+ /**
64
+ * Returns the first element matching the predicate, or None.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * pipe([1, 2, 3, 4], Arr.findFirst(n => n > 2)); // Some(3)
69
+ * ```
70
+ */
71
+ Arr.findFirst = (predicate) => (data) => {
72
+ const idx = data.findIndex(predicate);
73
+ return idx >= 0 ? Option.toSome(data[idx]) : Option.toNone();
74
+ };
75
+ /**
76
+ * Returns the last element matching the predicate, or None.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * pipe([1, 2, 3, 4], Arr.findLast(n => n > 2)); // Some(4)
81
+ * ```
82
+ */
83
+ Arr.findLast = (predicate) => (data) => {
84
+ for (let i = data.length - 1; i >= 0; i--) {
85
+ if (predicate(data[i]))
86
+ return Option.toSome(data[i]);
87
+ }
88
+ return Option.toNone();
89
+ };
90
+ /**
91
+ * Returns the index of the first element matching the predicate, or None.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * pipe([1, 2, 3, 4], Arr.findIndex(n => n > 2)); // Some(2)
96
+ * ```
97
+ */
98
+ Arr.findIndex = (predicate) => (data) => {
99
+ const idx = data.findIndex(predicate);
100
+ return idx >= 0 ? Option.toSome(idx) : Option.toNone();
101
+ };
102
+ // --- Transform ---
103
+ /**
104
+ * Transforms each element of an array.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * pipe([1, 2, 3], Arr.map(n => n * 2)); // [2, 4, 6]
109
+ * ```
110
+ */
111
+ Arr.map = (f) => (data) => data.map(f);
112
+ /**
113
+ * Filters elements that satisfy the predicate.
114
+ *
115
+ * @example
116
+ * ```ts
117
+ * pipe([1, 2, 3, 4], Arr.filter(n => n % 2 === 0)); // [2, 4]
118
+ * ```
119
+ */
120
+ Arr.filter = (predicate) => (data) => data.filter(predicate);
121
+ /**
122
+ * Splits an array into two groups based on a predicate.
123
+ * First group contains elements that satisfy the predicate,
124
+ * second group contains the rest.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * pipe([1, 2, 3, 4], Arr.partition(n => n % 2 === 0)); // [[2, 4], [1, 3]]
129
+ * ```
130
+ */
131
+ Arr.partition = (predicate) => (data) => {
132
+ const pass = [];
133
+ const fail = [];
134
+ for (const a of data) {
135
+ (predicate(a) ? pass : fail).push(a);
136
+ }
137
+ return [pass, fail];
138
+ };
139
+ /**
140
+ * Groups elements by a key function.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * pipe(
145
+ * ["apple", "avocado", "banana"],
146
+ * Arr.groupBy(s => s[0])
147
+ * ); // { a: ["apple", "avocado"], b: ["banana"] }
148
+ * ```
149
+ */
150
+ Arr.groupBy = (f) => (data) => {
151
+ const result = {};
152
+ for (const a of data) {
153
+ const key = f(a);
154
+ if (!result[key])
155
+ result[key] = [];
156
+ result[key].push(a);
157
+ }
158
+ return result;
159
+ };
160
+ /**
161
+ * Removes duplicate elements using strict equality.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * Arr.uniq([1, 2, 2, 3, 1]); // [1, 2, 3]
166
+ * ```
167
+ */
168
+ Arr.uniq = (data) => [
169
+ ...new Set(data),
170
+ ];
171
+ /**
172
+ * Removes duplicate elements by comparing the result of a key function.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * pipe(
177
+ * [{id: 1, name: "a"}, {id: 1, name: "b"}, {id: 2, name: "c"}],
178
+ * Arr.uniqBy(x => x.id)
179
+ * ); // [{id: 1, name: "a"}, {id: 2, name: "c"}]
180
+ * ```
181
+ */
182
+ Arr.uniqBy = (f) => (data) => {
183
+ const seen = new Set();
184
+ const result = [];
185
+ for (const a of data) {
186
+ const key = f(a);
187
+ if (!seen.has(key)) {
188
+ seen.add(key);
189
+ result.push(a);
190
+ }
191
+ }
192
+ return result;
193
+ };
194
+ /**
195
+ * Sorts an array using a comparison function. Returns a new array.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * pipe([3, 1, 2], Arr.sortBy((a, b) => a - b)); // [1, 2, 3]
200
+ * ```
201
+ */
202
+ Arr.sortBy = (compare) => (data) => [...data].sort(compare);
203
+ // --- Combine ---
204
+ /**
205
+ * Pairs up elements from two arrays. Stops at the shorter array.
206
+ *
207
+ * @example
208
+ * ```ts
209
+ * pipe([1, 2, 3], Arr.zip(["a", "b"])); // [[1, "a"], [2, "b"]]
210
+ * ```
211
+ */
212
+ Arr.zip = (other) => (data) => {
213
+ const len = Math.min(data.length, other.length);
214
+ const result = [];
215
+ for (let i = 0; i < len; i++) {
216
+ result.push([data[i], other[i]]);
217
+ }
218
+ return result;
219
+ };
220
+ /**
221
+ * Combines elements from two arrays using a function. Stops at the shorter array.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * pipe([1, 2], Arr.zipWith((a, b) => a + b, ["a", "b"])); // ["1a", "2b"]
226
+ * ```
227
+ */
228
+ Arr.zipWith = (f, other) => (data) => {
229
+ const len = Math.min(data.length, other.length);
230
+ const result = [];
231
+ for (let i = 0; i < len; i++) {
232
+ result.push(f(data[i], other[i]));
233
+ }
234
+ return result;
235
+ };
236
+ /**
237
+ * Inserts a separator between every element.
238
+ *
239
+ * @example
240
+ * ```ts
241
+ * pipe([1, 2, 3], Arr.intersperse(0)); // [1, 0, 2, 0, 3]
242
+ * ```
243
+ */
244
+ Arr.intersperse = (sep) => (data) => {
245
+ if (data.length <= 1)
246
+ return data;
247
+ const result = [data[0]];
248
+ for (let i = 1; i < data.length; i++) {
249
+ result.push(sep, data[i]);
250
+ }
251
+ return result;
252
+ };
253
+ /**
254
+ * Splits an array into chunks of the given size.
255
+ *
256
+ * @example
257
+ * ```ts
258
+ * pipe([1, 2, 3, 4, 5], Arr.chunksOf(2)); // [[1, 2], [3, 4], [5]]
259
+ * ```
260
+ */
261
+ Arr.chunksOf = (n) => (data) => {
262
+ if (n <= 0)
263
+ return [];
264
+ const result = [];
265
+ for (let i = 0; i < data.length; i += n) {
266
+ result.push(data.slice(i, i + n));
267
+ }
268
+ return result;
269
+ };
270
+ /**
271
+ * Flattens a nested array by one level.
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * Arr.flatten([[1, 2], [3], [4, 5]]); // [1, 2, 3, 4, 5]
276
+ * ```
277
+ */
278
+ Arr.flatten = (data) => [].concat(...data);
279
+ /**
280
+ * Maps each element to an array and flattens the result.
281
+ *
282
+ * @example
283
+ * ```ts
284
+ * pipe([1, 2, 3], Arr.flatMap(n => [n, n * 10])); // [1, 10, 2, 20, 3, 30]
285
+ * ```
286
+ */
287
+ Arr.flatMap = (f) => (data) => [].concat(...data.map(f));
288
+ /**
289
+ * Reduces an array from the left.
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * pipe([1, 2, 3], Arr.reduce(0, (acc, n) => acc + n)); // 6
294
+ * ```
295
+ */
296
+ Arr.reduce = (initial, f) => (data) => data.reduce(f, initial);
297
+ // --- Traverse / Sequence ---
298
+ /**
299
+ * Maps each element to an Option and collects the results.
300
+ * Returns None if any mapping returns None.
301
+ *
302
+ * @example
303
+ * ```ts
304
+ * const parseNum = (s: string): Option<number> => {
305
+ * const n = Number(s);
306
+ * return isNaN(n) ? Option.toNone() : Option.of(n);
307
+ * };
308
+ *
309
+ * pipe(["1", "2", "3"], Arr.traverse(parseNum)); // Some([1, 2, 3])
310
+ * pipe(["1", "x", "3"], Arr.traverse(parseNum)); // None
311
+ * ```
312
+ */
313
+ Arr.traverse = (f) => (data) => {
314
+ const result = [];
315
+ for (const a of data) {
316
+ const mapped = f(a);
317
+ if (Option.isNone(mapped))
318
+ return Option.toNone();
319
+ result.push(mapped.value);
320
+ }
321
+ return Option.toSome(result);
322
+ };
323
+ /**
324
+ * Maps each element to a Result and collects the results.
325
+ * Returns the first Err if any mapping fails.
326
+ *
327
+ * @example
328
+ * ```ts
329
+ * pipe(
330
+ * [1, 2, 3],
331
+ * Arr.traverseResult(n => n > 0 ? Result.toOk(n) : Result.toErr("negative"))
332
+ * ); // Ok([1, 2, 3])
333
+ * ```
334
+ */
335
+ Arr.traverseResult = (f) => (data) => {
336
+ const result = [];
337
+ for (const a of data) {
338
+ const mapped = f(a);
339
+ if (Result.isErr(mapped))
340
+ return mapped;
341
+ result.push(mapped.value);
342
+ }
343
+ return Result.toOk(result);
344
+ };
345
+ /**
346
+ * Maps each element to a Task and runs all in parallel.
347
+ *
348
+ * @example
349
+ * ```ts
350
+ * pipe(
351
+ * [1, 2, 3],
352
+ * Arr.traverseTask(n => Task.of(n * 2))
353
+ * )(); // Promise<[2, 4, 6]>
354
+ * ```
355
+ */
356
+ Arr.traverseTask = (f) => (data) => () => Promise.all(data.map((a) => f(a)()));
357
+ /**
358
+ * Collects an array of Options into an Option of array.
359
+ * Returns None if any element is None.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * Arr.sequence([Option.of(1), Option.of(2)]); // Some([1, 2])
364
+ * Arr.sequence([Option.of(1), Option.toNone()]); // None
365
+ * ```
366
+ */
367
+ Arr.sequence = (data) => Arr.traverse((a) => a)(data);
368
+ /**
369
+ * Collects an array of Results into a Result of array.
370
+ * Returns the first Err if any element is Err.
371
+ */
372
+ Arr.sequenceResult = (data) => Arr.traverseResult((a) => a)(data);
373
+ /**
374
+ * Collects an array of Tasks into a Task of array. Runs in parallel.
375
+ */
376
+ Arr.sequenceTask = (data) => Arr.traverseTask((a) => a)(data);
377
+ /**
378
+ * Returns true if the array is non-empty (type guard).
379
+ */
380
+ Arr.isNonEmpty = (data) => isNonEmptyList(data);
381
+ /**
382
+ * Returns the length of an array.
383
+ */
384
+ Arr.size = (data) => data.length;
385
+ /**
386
+ * Returns true if any element satisfies the predicate.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * pipe([1, 2, 3], Arr.some(n => n > 2)); // true
391
+ * ```
392
+ */
393
+ Arr.some = (predicate) => (data) => data.some(predicate);
394
+ /**
395
+ * Returns true if all elements satisfy the predicate.
396
+ *
397
+ * @example
398
+ * ```ts
399
+ * pipe([1, 2, 3], Arr.every(n => n > 0)); // true
400
+ * ```
401
+ */
402
+ Arr.every = (predicate) => (data) => data.every(predicate);
403
+ /**
404
+ * Reverses an array. Returns a new array.
405
+ *
406
+ * @example
407
+ * ```ts
408
+ * Arr.reverse([1, 2, 3]); // [3, 2, 1]
409
+ * ```
410
+ */
411
+ Arr.reverse = (data) => [...data].reverse();
412
+ /**
413
+ * Takes the first n elements from an array.
414
+ *
415
+ * @example
416
+ * ```ts
417
+ * pipe([1, 2, 3, 4], Arr.take(2)); // [1, 2]
418
+ * ```
419
+ */
420
+ Arr.take = (n) => (data) => n <= 0 ? [] : data.slice(0, n);
421
+ /**
422
+ * Drops the first n elements from an array.
423
+ *
424
+ * @example
425
+ * ```ts
426
+ * pipe([1, 2, 3, 4], Arr.drop(2)); // [3, 4]
427
+ * ```
428
+ */
429
+ Arr.drop = (n) => (data) => data.slice(n);
430
+ /**
431
+ * Takes elements from the start while the predicate holds.
432
+ *
433
+ * @example
434
+ * ```ts
435
+ * pipe([1, 2, 3, 1], Arr.takeWhile(n => n < 3)); // [1, 2]
436
+ * ```
437
+ */
438
+ Arr.takeWhile = (predicate) => (data) => {
439
+ const result = [];
440
+ for (const a of data) {
441
+ if (!predicate(a))
442
+ break;
443
+ result.push(a);
444
+ }
445
+ return result;
446
+ };
447
+ /**
448
+ * Drops elements from the start while the predicate holds.
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * pipe([1, 2, 3, 1], Arr.dropWhile(n => n < 3)); // [3, 1]
453
+ * ```
454
+ */
455
+ Arr.dropWhile = (predicate) => (data) => {
456
+ let i = 0;
457
+ while (i < data.length && predicate(data[i]))
458
+ i++;
459
+ return data.slice(i);
460
+ };
461
+ })(Arr || (Arr = {}));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,195 @@
1
+ import { Result } from "./Result.js";
2
+ export var Option;
3
+ (function (Option) {
4
+ /**
5
+ * Wraps a value in a Some.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * Option.of(42); // Some(42)
10
+ * ```
11
+ */
12
+ Option.of = (value) => Option.toSome(value);
13
+ /**
14
+ * Creates a Some containing the given value.
15
+ */
16
+ Option.toSome = (value) => ({ kind: "Some", value });
17
+ /**
18
+ * Type guard that checks if a Option is Some.
19
+ */
20
+ Option.isSome = (data) => data.kind === "Some";
21
+ /**
22
+ * Creates a None (empty Option).
23
+ */
24
+ Option.toNone = () => ({ kind: "None" });
25
+ /**
26
+ * Type guard that checks if a Option is None.
27
+ */
28
+ Option.isNone = (data) => data.kind === "None";
29
+ /**
30
+ * Creates a Option from a nullable value.
31
+ * Returns None if the value is null or undefined, Some otherwise.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * Option.fromNullable(null); // None
36
+ * Option.fromNullable(42); // Some(42)
37
+ * ```
38
+ */
39
+ Option.fromNullable = (value) => value === null || value === undefined ? Option.toNone() : Option.toSome(value);
40
+ /**
41
+ * Extracts the value from a Option, returning null if None.
42
+ */
43
+ Option.toNullable = (data) => Option.isSome(data) ? data.value : null;
44
+ /**
45
+ * Extracts the value from a Option, returning undefined if None.
46
+ */
47
+ Option.toUndefined = (data) => Option.isSome(data) ? data.value : undefined;
48
+ /**
49
+ * Creates a Option from a possibly undefined value.
50
+ * Returns None if undefined, Some otherwise.
51
+ */
52
+ Option.fromUndefined = (value) => value === undefined ? Option.toNone() : Option.toSome(value);
53
+ /**
54
+ * Converts an Option to a Result.
55
+ * Some becomes Ok, None becomes Err with the provided error.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * pipe(
60
+ * Option.of(42),
61
+ * Option.toResult(() => "Value was missing")
62
+ * ); // Ok(42)
63
+ *
64
+ * pipe(
65
+ * Option.toNone(),
66
+ * Option.toResult(() => "Value was missing")
67
+ * ); // Err("Value was missing")
68
+ * ```
69
+ */
70
+ Option.toResult = (onNone) => (data) => Option.isSome(data) ? Result.toOk(data.value) : Result.toErr(onNone());
71
+ /**
72
+ * Creates an Option from a Result.
73
+ * Ok becomes Some, Err becomes None (the error is discarded).
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * Option.fromResult(Result.toOk(42)); // Some(42)
78
+ * Option.fromResult(Result.toErr("oops")); // None
79
+ * ```
80
+ */
81
+ Option.fromResult = (data) => Result.isOk(data) ? Option.toSome(data.value) : Option.toNone();
82
+ /**
83
+ * Transforms the value inside a Option if it exists.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * pipe(Option.of(5), Option.map(n => n * 2)); // Some(10)
88
+ * pipe(Option.toNone(), Option.map(n => n * 2)); // None
89
+ * ```
90
+ */
91
+ Option.map = (f) => (data) => Option.isSome(data) ? Option.toSome(f(data.value)) : data;
92
+ /**
93
+ * Chains Option computations. If the first is Some, passes the value to f.
94
+ * If the first is None, propagates None.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const parseNumber = (s: string): Option<number> => {
99
+ * const n = parseInt(s, 10);
100
+ * return isNaN(n) ? Option.toNone() : Option.of(n);
101
+ * };
102
+ *
103
+ * pipe(Option.of("42"), Option.chain(parseNumber)); // Some(42)
104
+ * pipe(Option.of("abc"), Option.chain(parseNumber)); // None
105
+ * ```
106
+ */
107
+ Option.chain = (f) => (data) => Option.isSome(data) ? f(data.value) : data;
108
+ /**
109
+ * Extracts the value from a Option by providing handlers for both cases.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * pipe(
114
+ * Option.of(5),
115
+ * Option.fold(
116
+ * () => "No value",
117
+ * n => `Value: ${n}`
118
+ * )
119
+ * ); // "Value: 5"
120
+ * ```
121
+ */
122
+ Option.fold = (onNone, onSome) => (data) => Option.isSome(data) ? onSome(data.value) : onNone();
123
+ /**
124
+ * Pattern matches on a Option, returning the result of the matching case.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * pipe(
129
+ * optionUser,
130
+ * Option.match({
131
+ * some: user => `Hello, ${user.name}`,
132
+ * none: () => "Hello, stranger"
133
+ * })
134
+ * );
135
+ * ```
136
+ */
137
+ Option.match = (cases) => (data) => Option.isSome(data) ? cases.some(data.value) : cases.none();
138
+ /**
139
+ * Returns the value inside a Option, or a default value if None.
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * pipe(Option.of(5), Option.getOrElse(0)); // 5
144
+ * pipe(Option.toNone(), Option.getOrElse(0)); // 0
145
+ * ```
146
+ */
147
+ Option.getOrElse = (defaultValue) => (data) => Option.isSome(data) ? data.value : defaultValue;
148
+ /**
149
+ * Executes a side effect on the value without changing the Option.
150
+ * Useful for logging or debugging.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * pipe(
155
+ * Option.of(5),
156
+ * Option.tap(n => console.log("Value:", n)),
157
+ * Option.map(n => n * 2)
158
+ * );
159
+ * ```
160
+ */
161
+ Option.tap = (f) => (data) => {
162
+ if (Option.isSome(data))
163
+ f(data.value);
164
+ return data;
165
+ };
166
+ /**
167
+ * Filters a Option based on a predicate.
168
+ * Returns None if the predicate returns false or if the Option is already None.
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * pipe(Option.of(5), Option.filter(n => n > 3)); // Some(5)
173
+ * pipe(Option.of(2), Option.filter(n => n > 3)); // None
174
+ * ```
175
+ */
176
+ Option.filter = (predicate) => (data) => Option.isSome(data) && predicate(data.value) ? data : Option.toNone();
177
+ /**
178
+ * Recovers from a None by providing a fallback Option.
179
+ */
180
+ Option.recover = (fallback) => (data) => Option.isSome(data) ? data : fallback();
181
+ /**
182
+ * Applies a function wrapped in a Option to a value wrapped in a Option.
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const add = (a: number) => (b: number) => a + b;
187
+ * pipe(
188
+ * Option.of(add),
189
+ * Option.ap(Option.of(5)),
190
+ * Option.ap(Option.of(3))
191
+ * ); // Some(8)
192
+ * ```
193
+ */
194
+ Option.ap = (arg) => (data) => Option.isSome(data) && Option.isSome(arg) ? Option.toSome(data.value(arg.value)) : Option.toNone();
195
+ })(Option || (Option = {}));