@nlozgachev/pipelined 0.6.4

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