@nunofyobiz/effect-extras 2.0.0 → 2.1.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.
Files changed (127) hide show
  1. package/README.md +36 -2
  2. package/dist/ArrayX.d.ts +415 -0
  3. package/dist/ArrayX.d.ts.map +1 -0
  4. package/dist/ArrayX.js +547 -0
  5. package/dist/ArrayX.js.map +1 -0
  6. package/dist/BigIntX.d.ts +24 -0
  7. package/dist/BigIntX.d.ts.map +1 -0
  8. package/dist/BigIntX.js +30 -0
  9. package/dist/BigIntX.js.map +1 -0
  10. package/dist/BooleanX.d.ts +25 -0
  11. package/dist/BooleanX.d.ts.map +1 -0
  12. package/dist/BooleanX.js +25 -0
  13. package/dist/BooleanX.js.map +1 -0
  14. package/dist/DurationX.d.ts +73 -0
  15. package/dist/DurationX.d.ts.map +1 -0
  16. package/dist/DurationX.js +91 -0
  17. package/dist/DurationX.js.map +1 -0
  18. package/dist/EffectX.d.ts +120 -0
  19. package/dist/EffectX.d.ts.map +1 -0
  20. package/dist/EffectX.js +140 -0
  21. package/dist/EffectX.js.map +1 -0
  22. package/dist/FormDataX.d.ts +49 -0
  23. package/dist/FormDataX.d.ts.map +1 -0
  24. package/dist/FormDataX.js +42 -0
  25. package/dist/FormDataX.js.map +1 -0
  26. package/dist/MapX.d.ts +32 -0
  27. package/dist/MapX.d.ts.map +1 -0
  28. package/dist/MapX.js +49 -0
  29. package/dist/MapX.js.map +1 -0
  30. package/dist/NonNullableX.d.ts +174 -0
  31. package/dist/NonNullableX.d.ts.map +1 -0
  32. package/dist/NonNullableX.js +212 -0
  33. package/dist/NonNullableX.js.map +1 -0
  34. package/dist/NumberX.d.ts +178 -0
  35. package/dist/NumberX.d.ts.map +1 -0
  36. package/dist/NumberX.js +214 -0
  37. package/dist/NumberX.js.map +1 -0
  38. package/dist/OptionX.d.ts +181 -0
  39. package/dist/OptionX.d.ts.map +1 -0
  40. package/dist/OptionX.js +195 -0
  41. package/dist/OptionX.js.map +1 -0
  42. package/dist/OrderX.d.ts +32 -0
  43. package/dist/OrderX.d.ts.map +1 -0
  44. package/dist/OrderX.js +32 -0
  45. package/dist/OrderX.js.map +1 -0
  46. package/dist/PredicateX.d.ts +76 -0
  47. package/dist/PredicateX.d.ts.map +1 -0
  48. package/dist/PredicateX.js +73 -0
  49. package/dist/PredicateX.js.map +1 -0
  50. package/dist/PromiseX.d.ts +32 -0
  51. package/dist/PromiseX.d.ts.map +1 -0
  52. package/dist/PromiseX.js +32 -0
  53. package/dist/PromiseX.js.map +1 -0
  54. package/dist/RecordX.d.ts +323 -0
  55. package/dist/RecordX.d.ts.map +1 -0
  56. package/dist/RecordX.js +326 -0
  57. package/dist/RecordX.js.map +1 -0
  58. package/dist/ResultX.d.ts +50 -0
  59. package/dist/ResultX.d.ts.map +1 -0
  60. package/dist/ResultX.js +50 -0
  61. package/dist/ResultX.js.map +1 -0
  62. package/dist/SchemaX.d.ts +249 -0
  63. package/dist/SchemaX.d.ts.map +1 -0
  64. package/dist/SchemaX.js +243 -0
  65. package/dist/SchemaX.js.map +1 -0
  66. package/dist/SetX.d.ts +121 -0
  67. package/dist/SetX.d.ts.map +1 -0
  68. package/dist/SetX.js +137 -0
  69. package/dist/SetX.js.map +1 -0
  70. package/dist/StringX.d.ts +70 -0
  71. package/dist/StringX.d.ts.map +1 -0
  72. package/dist/StringX.js +81 -0
  73. package/dist/StringX.js.map +1 -0
  74. package/dist/StructX.d.ts +219 -0
  75. package/dist/StructX.d.ts.map +1 -0
  76. package/dist/StructX.js +173 -0
  77. package/dist/StructX.js.map +1 -0
  78. package/dist/WarnResult.d.ts +1146 -0
  79. package/dist/WarnResult.d.ts.map +1 -0
  80. package/dist/WarnResult.js +1060 -0
  81. package/dist/WarnResult.js.map +1 -0
  82. package/dist/index.d.ts +22 -3772
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +21 -1011
  85. package/dist/index.js.map +1 -1
  86. package/package.json +18 -5
  87. package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +3 -3
  88. package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
  89. package/src/{RecordX/RecordX.ts → RecordX.ts} +1 -1
  90. package/src/index.ts +21 -20
  91. package/src/ArrayX/index.ts +0 -1
  92. package/src/BigIntX/index.ts +0 -1
  93. package/src/BooleanX/index.ts +0 -1
  94. package/src/DurationX/index.ts +0 -1
  95. package/src/EffectX/index.ts +0 -1
  96. package/src/FormDataX/index.ts +0 -1
  97. package/src/MapX/index.ts +0 -1
  98. package/src/NonNullableX/index.ts +0 -2
  99. package/src/NumberX/index.ts +0 -1
  100. package/src/OptionX/index.ts +0 -1
  101. package/src/OrderX/index.ts +0 -1
  102. package/src/PredicateX/index.ts +0 -1
  103. package/src/PromiseX/index.ts +0 -1
  104. package/src/RecordX/index.ts +0 -1
  105. package/src/ResultX/index.ts +0 -1
  106. package/src/SchemaX/index.ts +0 -1
  107. package/src/SetX/index.ts +0 -1
  108. package/src/StringX/index.ts +0 -1
  109. package/src/StructX/index.ts +0 -1
  110. package/src/WarnResult/index.ts +0 -1
  111. /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
  112. /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
  113. /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
  114. /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
  115. /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
  116. /package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +0 -0
  117. /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
  118. /package/src/{OptionX/OptionX.ts → OptionX.ts} +0 -0
  119. /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
  120. /package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +0 -0
  121. /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
  122. /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
  123. /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
  124. /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
  125. /package/src/{StringX/StringX.ts → StringX.ts} +0 -0
  126. /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
  127. /package/src/{WarnResult/WarnResult.ts → WarnResult.ts} +0 -0
package/dist/ArrayX.js ADDED
@@ -0,0 +1,547 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Array` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Array, Option, Predicate, Record, pipe } from "effect";
7
+ import { dual, identity } from "effect/Function";
8
+ import * as RecordX from "./RecordX.js";
9
+ import * as WarnResult from "./WarnResult.js";
10
+ import * as ResultX from "./ResultX.js";
11
+ /**
12
+ * Returns a shallow copy of `array` between `start` (inclusive) and `end`
13
+ * (exclusive), as a pipeable, dual-form alias for `Array.prototype.slice`.
14
+ *
15
+ * `Array.prototype.slice` is already non-mutating (it returns a shallow copy),
16
+ * but it isn't pipeable. This helper makes it composable inside `pipe(...)`
17
+ * chains alongside the rest of the codebase's Effect-style utilities.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { pipe } from "effect"
22
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
23
+ *
24
+ * // data-first
25
+ * assert.deepStrictEqual(ArrayX.slice([1, 2, 3, 4], 1, 3), [2, 3])
26
+ *
27
+ * // data-last (pipeable)
28
+ * assert.deepStrictEqual(pipe([1, 2, 3, 4], ArrayX.slice(1, 3)), [2, 3])
29
+ * ```
30
+ *
31
+ * @category getters
32
+ * @since 0.0.0
33
+ */
34
+ export const slice = /*#__PURE__*/dual(3, (array, start, end) => array.slice(start, end));
35
+ /**
36
+ * Zips two arrays into one, calling `f` with a `WarnResult` for each index so
37
+ * that length mismatches are handled explicitly rather than truncated.
38
+ *
39
+ * Unlike `Array.zipWith` (which stops at the shorter array), this walks to the
40
+ * length of the *longer* array. The first array's element fills the `warnings`
41
+ * side and the second array's element fills the `success` side, so at each index
42
+ * `f` receives a `WarnResult.WarnResult<A, B>`: `SuccessWithWarnings` when both
43
+ * arrays have an element, `WarningsOnly` when only the first does, and
44
+ * `SuccessOnly` when only the second does. Use it when the "extra" tail of either
45
+ * array still carries meaning.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { ArrayX, WarnResult } from "@nunofyobiz/effect-extras"
50
+ *
51
+ * const describe = WarnResult.match({
52
+ * WarningsOnly: ({ warnings }) => `warnings ${warnings}`,
53
+ * SuccessOnly: ({ success }) => `success ${success}`,
54
+ * SuccessWithWarnings: ({ warnings, success }) => `both ${warnings}/${success}`,
55
+ * })
56
+ *
57
+ * assert.deepStrictEqual(ArrayX.zipWithWarnings([1, 2, 3], [10, 20], describe), [
58
+ * "both 1/10",
59
+ * "both 2/20",
60
+ * "warnings 3",
61
+ * ])
62
+ * ```
63
+ *
64
+ * @category combinators
65
+ * @since 0.0.0
66
+ */
67
+ export const zipWithWarnings = /*#__PURE__*/dual(3, (array1, array2, f) => {
68
+ const newLength = Math.max(array1.length, array2.length);
69
+ if (newLength === 0) {
70
+ return [];
71
+ }
72
+ return Array.makeBy(newLength, index => {
73
+ if (index < array1.length && index < array2.length) {
74
+ return f(WarnResult.SuccessWithWarnings({
75
+ warnings: array1[index],
76
+ success: array2[index]
77
+ }));
78
+ }
79
+ if (index < array1.length) {
80
+ return f(WarnResult.WarningsOnly({
81
+ warnings: array1[index]
82
+ }));
83
+ }
84
+ if (index < array2.length) {
85
+ return f(WarnResult.SuccessOnly({
86
+ success: array2[index]
87
+ }));
88
+ }
89
+ throw new Error(`Index ${index} is out of bounds for array1 and array2`);
90
+ });
91
+ });
92
+ /**
93
+ * Moves a unique item within an array to a new position, using a custom identification function.
94
+ *
95
+ * **Assumption**: Items should be unique in the array based on the identification function.
96
+ *
97
+ * **Happy case**: If the source item is found exactly once and the destination reference item is found (or null, to move to the end):
98
+ * The source item is moved from its current position to the new position
99
+ *
100
+ * **Source item not found**: The array is returned unchanged, regardless of whether the destination reference item exists.
101
+ *
102
+ * **Source item found but duplicated**:
103
+ * - If destination reference item is found: All copies of the source item are removed, then a single copy is inserted before the destination reference item
104
+ * - If destination reference item is not found: The array is returned completely unchanged (no items are moved or removed)
105
+ *
106
+ * Used internally by {@link insertUniq}; not exported as the codebase has no
107
+ * direct callers.
108
+ */
109
+ const moveUniqWith = /*#__PURE__*/dual(2, (inputArray, {
110
+ identify,
111
+ sourceId,
112
+ moveToBeLeftOfId
113
+ }) => {
114
+ const array = [...inputArray];
115
+ // Find the source item and its index
116
+ const sourceIndex = array.findIndex(item => identify(item) === sourceId);
117
+ if (sourceIndex < 0) {
118
+ return array;
119
+ }
120
+ const sourceItem = array[sourceIndex];
121
+ // Remove ALL occurrences of the source item from the array
122
+ const arrayWithoutSource = array.filter(item => identify(item) !== sourceId);
123
+ // If moveToBeLeftOfId is null, move to end
124
+ if (moveToBeLeftOfId === null) {
125
+ return [...arrayWithoutSource, sourceItem];
126
+ }
127
+ // Find the destination index in the array without the source item
128
+ const destinationIndex = arrayWithoutSource.findIndex(item => identify(item) === moveToBeLeftOfId);
129
+ if (destinationIndex < 0) {
130
+ // If destination not found, leave array completely unchanged
131
+ return array;
132
+ }
133
+ // Insert the source item before the destination index
134
+ return [...slice(arrayWithoutSource, 0, destinationIndex), sourceItem, ...slice(arrayWithoutSource, destinationIndex, arrayWithoutSource.length)];
135
+ });
136
+ /**
137
+ * Inserts or moves a unique item in an array at a specified position.
138
+ *
139
+ * **Assumption**: Items should be unique in the array based on standard equality.
140
+ *
141
+ * **Happy case**: If the item doesn't exist in the array and the destination reference item is found:
142
+ * The new item is inserted before the destination reference item
143
+ *
144
+ * **Item not found in array**:
145
+ * - If destination reference item is found: The new item is inserted before the destination reference item
146
+ * - If destination reference item is not found: The new item is inserted at the end of the array
147
+ *
148
+ * **Item found but duplicated**:
149
+ * - If destination reference item is found: All existing copies are removed, then a single copy is inserted before the destination reference item
150
+ * - If destination reference item is not found: All existing copies are removed, then a single copy is inserted at the end of the array
151
+ *
152
+ * @param array - The input array to modify
153
+ * @param config - Configuration object containing:
154
+ * - `item`: The item to insert or update (must be a string or number)
155
+ * - `insertToBeLeftOf`: The item to position the new/updated item before,
156
+ * or null to insert at the end
157
+ *
158
+ * @returns A new array with the item inserted or moved to the specified position
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
163
+ *
164
+ * // Move an existing item to sit just before "c"
165
+ * assert.deepStrictEqual(
166
+ * ArrayX.insertUniq(["a", "b", "c", "d"], { item: "a", insertToBeLeftOf: "c" }),
167
+ * ["b", "a", "c", "d"],
168
+ * )
169
+ *
170
+ * // Insert a brand-new item; unknown destination falls through to the end
171
+ * assert.deepStrictEqual(
172
+ * ArrayX.insertUniq(["a", "b"], { item: "new", insertToBeLeftOf: null }),
173
+ * ["a", "b", "new"],
174
+ * )
175
+ * ```
176
+ *
177
+ * @category combinators
178
+ * @since 0.0.0
179
+ */
180
+ export const insertUniq = /*#__PURE__*/dual(2, (array, {
181
+ item,
182
+ insertToBeLeftOf
183
+ }) => {
184
+ // Always deduplicate and append the item to the end for insertUniq
185
+ // This ensures we always have exactly one copy of the item, regardless of destination
186
+ const arrayWithNewItem = pipe(array, Array.filter(existingItem => existingItem !== item), Array.append(item));
187
+ // Now move that new item to the desired position
188
+ return moveUniqWith(arrayWithNewItem, {
189
+ identify: identity,
190
+ sourceId: item,
191
+ moveToBeLeftOfId: insertToBeLeftOf
192
+ });
193
+ });
194
+ /**
195
+ * Maps over `array` while threading an accumulator, iterating from right to
196
+ * left instead of left to right.
197
+ *
198
+ * Identical to `Array.mapAccum`, except the traversal order is reversed: `f` is
199
+ * called on the last element first, and the resulting array is returned in the
200
+ * original (left-to-right) order. Use it when each element's mapped value
201
+ * depends on state accumulated from the elements that follow it.
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
206
+ *
207
+ * // Running suffix-sum: each slot holds the sum of itself and everything after it
208
+ * assert.deepStrictEqual(
209
+ * ArrayX.mapRightAccum([1, 2, 3], 0, (total, n) => [total + n, total + n]),
210
+ * [6, [6, 5, 3]],
211
+ * )
212
+ * ```
213
+ *
214
+ * @category folding
215
+ * @since 0.0.0
216
+ */
217
+ export const mapRightAccum = /*#__PURE__*/dual(3, (array, initialAccumulator, f) => {
218
+ const [accumulator, result] = pipe(array, Array.reverse, Array.mapAccum(initialAccumulator, f));
219
+ return [accumulator, Array.reverse(result)];
220
+ });
221
+ /**
222
+ * Returns the maximum element of `array` according to `order`, wrapped in an
223
+ * `Option` so that empty arrays are handled safely.
224
+ *
225
+ * Effect's `Array.max` throws on an empty array; this returns `Option.none()`
226
+ * instead, and `Option.some(max)` otherwise. Reach for it whenever the input
227
+ * array might be empty.
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * import { Option, Order, pipe } from "effect"
232
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
233
+ *
234
+ * assert.deepStrictEqual(
235
+ * pipe([3, 7, 2], ArrayX.maxOption(Order.Number)),
236
+ * Option.some(7),
237
+ * )
238
+ * assert.deepStrictEqual(
239
+ * pipe([], ArrayX.maxOption(Order.Number)),
240
+ * Option.none(),
241
+ * )
242
+ * ```
243
+ *
244
+ * @category getters
245
+ * @since 0.0.0
246
+ */
247
+ export const maxOption = /*#__PURE__*/dual(2, (array, order) => pipe(
248
+ // If the array is empty, there is no max
249
+ array, Option.liftPredicate(Array.isArrayNonEmpty),
250
+ // If it is non-empty, get the max
251
+ Option.map(Array.max(order))));
252
+ const takeFirstOrLastWhere = /*#__PURE__*/dual(3, (array, predicate, takeOne) => pipe(
253
+ // Keep only the items that match
254
+ array, Array.filter(predicate),
255
+ // If there is anything left, take one
256
+ Option.liftPredicate(Array.isArrayNonEmpty), Option.map(takeOne)));
257
+ /**
258
+ * Returns the smallest element of `array` (per `order`) that matches
259
+ * `predicate`, narrowed to the refined type `B`, or `Option.none()` if none
260
+ * match.
261
+ *
262
+ * Combines a refinement filter with `Array.min`: only elements satisfying
263
+ * `predicate` are considered, and the minimum of those (by `order`) is
264
+ * returned. The refinement narrows the element type, so the resulting `Option`
265
+ * carries the more specific `B`.
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * import { Option, Order, pipe } from "effect"
270
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
271
+ *
272
+ * const isEven = (n: number): n is number => n % 2 === 0
273
+ *
274
+ * assert.deepStrictEqual(
275
+ * pipe([3, 4, 1, 2, 5], ArrayX.takeFirstWhere(isEven, Order.Number)),
276
+ * Option.some(2),
277
+ * )
278
+ * assert.deepStrictEqual(
279
+ * pipe([1, 3, 5], ArrayX.takeFirstWhere(isEven, Order.Number)),
280
+ * Option.none(),
281
+ * )
282
+ * ```
283
+ *
284
+ * @category getters
285
+ * @since 0.0.0
286
+ */
287
+ export const takeFirstWhere = /*#__PURE__*/dual(3, (array, predicate, order) => takeFirstOrLastWhere(array, predicate, Array.min(order)));
288
+ /**
289
+ * Returns the largest element of `array` (per `order`) that matches
290
+ * `predicate`, narrowed to the refined type `B`, or `Option.none()` if none
291
+ * match.
292
+ *
293
+ * The mirror of {@link takeFirstWhere}: only elements satisfying `predicate`
294
+ * are considered, and the maximum of those (by `order`) is returned. The
295
+ * refinement narrows the element type, so the resulting `Option` carries the
296
+ * more specific `B`.
297
+ *
298
+ * @example
299
+ * ```ts
300
+ * import { Option, Order, pipe } from "effect"
301
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
302
+ *
303
+ * const isEven = (n: number): n is number => n % 2 === 0
304
+ *
305
+ * assert.deepStrictEqual(
306
+ * pipe([3, 4, 1, 2, 5], ArrayX.takeLastWhere(isEven, Order.Number)),
307
+ * Option.some(4),
308
+ * )
309
+ * assert.deepStrictEqual(
310
+ * pipe([1, 3, 5], ArrayX.takeLastWhere(isEven, Order.Number)),
311
+ * Option.none(),
312
+ * )
313
+ * ```
314
+ *
315
+ * @category getters
316
+ * @since 0.0.0
317
+ */
318
+ export const takeLastWhere = /*#__PURE__*/dual(3, (array, predicate, order) => takeFirstOrLastWhere(array, predicate, Array.max(order)));
319
+ /**
320
+ * Groups `items` into a partial record keyed by the category each item maps to
321
+ * via `categorize`.
322
+ *
323
+ * Each item is appended to the array under its category, preserving input
324
+ * order. The result is `Partial<Record<C, A[]>>` because not every possible
325
+ * category `C` is guaranteed to appear — only categories that received at least
326
+ * one item are present.
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
331
+ *
332
+ * const parity = (n: number) => (n % 2 === 0 ? "even" : "odd")
333
+ *
334
+ * assert.deepStrictEqual(ArrayX.categorize([1, 2, 3, 4], parity), {
335
+ * odd: [1, 3],
336
+ * even: [2, 4],
337
+ * })
338
+ * ```
339
+ *
340
+ * @category folding
341
+ * @since 0.0.0
342
+ */
343
+ export const categorize = (items, categorize) => Array.reduce(items,
344
+ // Start with an empty record of categorized items. `Record.empty()`
345
+ // returns a `NonLiteralKey<C>`-keyed record, which is structurally
346
+ // equivalent to `Partial<Record<C, A[]>>`; the cast tells TypeScript
347
+ // we'll be writing typed keys back via the reducer below.
348
+ Record.empty(),
349
+ // For each item, add it to the appropriate category
350
+ (categorizedItems, item) => RecordX.upsert(categorizedItems, categorize(item),
351
+ // This is the next item's category
352
+ Option.match({
353
+ // This is the first item in this category, so create a new array
354
+ onNone: () => Array.of(item),
355
+ // Append the item to the existing array
356
+ onSome: Array.append(item)
357
+ })));
358
+ /**
359
+ * Removes all `null` and `undefined` elements from `array`, narrowing the
360
+ * element type to `NonNullable<A>`.
361
+ *
362
+ * Falsy-but-present values such as `0` and `""` are kept — only nullish values
363
+ * are dropped. Use it to clean up an array of optionals into a dense array of
364
+ * known-present values.
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
369
+ *
370
+ * assert.deepStrictEqual(
371
+ * ArrayX.compactNullable([1, null, 2, undefined, 0, ""]),
372
+ * [1, 2, 0, ""],
373
+ * )
374
+ * ```
375
+ *
376
+ * @category filtering
377
+ * @since 0.0.0
378
+ */
379
+ export const compactNullable = array => Array.filter(array, Predicate.isNotNullish);
380
+ /**
381
+ * Drops the leading elements of `array` until `predicate` first holds, keeping
382
+ * everything from the first match onward.
383
+ *
384
+ * The first matching element and all subsequent elements are retained
385
+ * regardless of whether they match — only the prefix *before* the first match
386
+ * is trimmed. If nothing matches, returns an empty array.
387
+ *
388
+ * @example
389
+ * ```ts
390
+ * import { Predicate } from "effect"
391
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
392
+ *
393
+ * // Trims the leading strings, then keeps everything (including the trailing "b")
394
+ * assert.deepStrictEqual(
395
+ * ArrayX.filterHead(["a", 1, 2, "b"], Predicate.isNumber),
396
+ * [1, 2, "b"],
397
+ * )
398
+ * ```
399
+ *
400
+ * @category filtering
401
+ * @since 0.0.0
402
+ */
403
+ export const filterHead = /*#__PURE__*/dual(2, (array, predicate) => {
404
+ const firstMatchingIndex = Array.findFirstIndex(array, predicate);
405
+ return Option.match(firstMatchingIndex, {
406
+ onSome: index => slice(array, index, array.length),
407
+ onNone: () => []
408
+ });
409
+ });
410
+ /**
411
+ * Drops the trailing elements of `array` after `predicate` last holds, keeping
412
+ * everything up to and including the last match.
413
+ *
414
+ * The mirror of {@link filterHead}: the last matching element and all preceding
415
+ * elements are retained regardless of whether they match — only the suffix
416
+ * *after* the last match is trimmed. If nothing matches, returns an empty
417
+ * array.
418
+ *
419
+ * @example
420
+ * ```ts
421
+ * import { Predicate } from "effect"
422
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
423
+ *
424
+ * // Keeps the leading "a" and trims the trailing strings after the last number
425
+ * assert.deepStrictEqual(
426
+ * ArrayX.filterTail(["a", 1, 2, "b"], Predicate.isNumber),
427
+ * ["a", 1, 2],
428
+ * )
429
+ * ```
430
+ *
431
+ * @category filtering
432
+ * @since 0.0.0
433
+ */
434
+ export const filterTail = /*#__PURE__*/dual(2, (array, predicate) => {
435
+ const lastMatchingIndex = Array.findLastIndex(array, predicate);
436
+ return Option.match(lastMatchingIndex, {
437
+ onSome: index => slice(array, 0, index + 1),
438
+ onNone: () => []
439
+ });
440
+ });
441
+ /**
442
+ * Maps `f` over `array` and drops every result that is `null` or `undefined`,
443
+ * narrowing the element type to `NonNullable<B>`.
444
+ *
445
+ * A nullable-friendly `Array.filterMap`: where `filterMap` expects `f` to
446
+ * return an `Option`, this accepts a function returning `B | null` (or
447
+ * `undefined`) and treats nullish results as "skip this element". Falsy-but-
448
+ * present values such as `0` and `""` are kept.
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
453
+ *
454
+ * // Keep only the even numbers, mapped to their halves
455
+ * assert.deepStrictEqual(
456
+ * ArrayX.filterMapNullable([1, 2, 3, 4], (n) => (n % 2 === 0 ? n / 2 : null)),
457
+ * [1, 2],
458
+ * )
459
+ * ```
460
+ *
461
+ * @category filtering
462
+ * @since 0.0.0
463
+ */
464
+ export const filterMapNullable = /*#__PURE__*/dual(2, (array, f) => pipe(array, Array.filterMap(value => pipe(f(value), Option.fromNullishOr, ResultX.fromOption))));
465
+ /**
466
+ * Finds the first element of a 2-dimensional array (row-major order) matching
467
+ * `predicate`, returning it alongside its row and column indices.
468
+ *
469
+ * Scans rows top-to-bottom and, within each row, left-to-right. On a match
470
+ * returns `Option.some([value, rowIndex, columnIndex])`; if no element matches
471
+ * (or the grid is empty), returns `Option.none()`.
472
+ *
473
+ * @example
474
+ * ```ts
475
+ * import { Option } from "effect"
476
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
477
+ *
478
+ * const grid = [
479
+ * ["A", "B", "C"],
480
+ * ["D", "E", "F"],
481
+ * ]
482
+ *
483
+ * assert.deepStrictEqual(
484
+ * ArrayX.findFirstWithIndex2d(grid, (cell) => cell === "E"),
485
+ * Option.some(["E", 1, 1]),
486
+ * )
487
+ * ```
488
+ *
489
+ * @category getters
490
+ * @since 0.0.0
491
+ */
492
+ export const findFirstWithIndex2d = /*#__PURE__*/dual(2, (array, predicate) => Array.findFirstWithIndex(array, row => Array.findFirstWithIndex(row, predicate)).pipe(Option.map(([[value, secondIndex], firstIndex]) => [value, firstIndex, secondIndex])));
493
+ /**
494
+ * Splits `array` into runs of consecutive elements that share the same group
495
+ * value, where the group is derived by `chunk` and compared with the provided
496
+ * `Equivalence`.
497
+ *
498
+ * Only *adjacent* elements are grouped: a new run starts every time the group
499
+ * value changes from the previous element. Each entry in the result carries the
500
+ * `group` value and the non-empty array of `values` that produced it, preserving
501
+ * input order. An empty input yields an empty array. Use it for run-length-style
502
+ * segmentation; reach for `Array.groupBy` instead when you want all elements
503
+ * with the same key collapsed regardless of position.
504
+ *
505
+ * @example
506
+ * ```ts
507
+ * import { Equivalence } from "effect"
508
+ * import { ArrayX } from "@nunofyobiz/effect-extras"
509
+ *
510
+ * // Group adjacent numbers by parity
511
+ * assert.deepStrictEqual(
512
+ * ArrayX.chunkBy([2, 4, 1, 3, 6], (n) => n % 2 === 0, Equivalence.Boolean),
513
+ * [
514
+ * { group: true, values: [2, 4] },
515
+ * { group: false, values: [1, 3] },
516
+ * { group: true, values: [6] },
517
+ * ],
518
+ * )
519
+ * ```
520
+ *
521
+ * @category folding
522
+ * @since 0.0.0
523
+ */
524
+ export const chunkBy = /*#__PURE__*/dual(3, (array, chunk, chunkEquals) => {
525
+ if (array.length === 0) {
526
+ return [];
527
+ }
528
+ const result = [];
529
+ for (const item of array) {
530
+ const groupValue = chunk(item);
531
+ if (result.length > 0) {
532
+ const lastGroup = result.at(-1);
533
+ if (lastGroup && chunkEquals(lastGroup.group, groupValue)) {
534
+ // Add to current group
535
+ lastGroup.values.push(item);
536
+ continue;
537
+ }
538
+ }
539
+ // Start a new group
540
+ result.push({
541
+ group: groupValue,
542
+ values: Array.of(item)
543
+ });
544
+ }
545
+ return result;
546
+ });
547
+ //# sourceMappingURL=ArrayX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArrayX.js","names":["Array","Option","Predicate","Record","pipe","dual","identity","RecordX","WarnResult","ResultX","slice","array","start","end","zipWithWarnings","array1","array2","f","newLength","Math","max","length","makeBy","index","SuccessWithWarnings","warnings","success","WarningsOnly","SuccessOnly","Error","moveUniqWith","inputArray","identify","sourceId","moveToBeLeftOfId","sourceIndex","findIndex","item","sourceItem","arrayWithoutSource","filter","destinationIndex","insertUniq","insertToBeLeftOf","arrayWithNewItem","existingItem","append","mapRightAccum","initialAccumulator","accumulator","result","reverse","mapAccum","maxOption","order","liftPredicate","isArrayNonEmpty","map","takeFirstOrLastWhere","predicate","takeOne","takeFirstWhere","min","takeLastWhere","categorize","items","reduce","empty","categorizedItems","upsert","match","onNone","of","onSome","compactNullable","isNotNullish","filterHead","firstMatchingIndex","findFirstIndex","filterTail","lastMatchingIndex","findLastIndex","filterMapNullable","filterMap","value","fromNullishOr","fromOption","findFirstWithIndex2d","findFirstWithIndex","row","secondIndex","firstIndex","chunkBy","chunk","chunkEquals","groupValue","lastGroup","at","group","values","push"],"sources":["../src/ArrayX.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Converts a `bigint` to a `number`, throwing when the value cannot be
3
+ * represented exactly.
4
+ *
5
+ * Delegates to Effect's `BigInt.toNumber`, which returns `None` once the
6
+ * `bigint` falls outside the safe integer range (`Number.MAX_SAFE_INTEGER`).
7
+ * This unwraps that `Option`, throwing instead of silently losing precision —
8
+ * use it only when the value is known to fit.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { BigIntX } from "@nunofyobiz/effect-extras"
13
+ *
14
+ * assert.deepStrictEqual(BigIntX.toNumberOrThrow(42n), 42)
15
+ *
16
+ * // throws when outside the safe integer range
17
+ * assert.throws(() => BigIntX.toNumberOrThrow(9007199254740993n))
18
+ * ```
19
+ *
20
+ * @category unsafe
21
+ * @since 0.0.0
22
+ */
23
+ export declare const toNumberOrThrow: (value: bigint) => number;
24
+ //# sourceMappingURL=BigIntX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BigIntX.d.ts","sourceRoot":"","sources":["../src/BigIntX.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,KAAG,MAK7C,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `BigInt` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { BigInt, Option } from "effect";
7
+ /**
8
+ * Converts a `bigint` to a `number`, throwing when the value cannot be
9
+ * represented exactly.
10
+ *
11
+ * Delegates to Effect's `BigInt.toNumber`, which returns `None` once the
12
+ * `bigint` falls outside the safe integer range (`Number.MAX_SAFE_INTEGER`).
13
+ * This unwraps that `Option`, throwing instead of silently losing precision —
14
+ * use it only when the value is known to fit.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { BigIntX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * assert.deepStrictEqual(BigIntX.toNumberOrThrow(42n), 42)
21
+ *
22
+ * // throws when outside the safe integer range
23
+ * assert.throws(() => BigIntX.toNumberOrThrow(9007199254740993n))
24
+ * ```
25
+ *
26
+ * @category unsafe
27
+ * @since 0.0.0
28
+ */
29
+ export const toNumberOrThrow = value => BigInt.toNumber(value).pipe(Option.getOrThrowWith(() => new Error(`Value ${value} is outside safe integer range`)));
30
+ //# sourceMappingURL=BigIntX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BigIntX.js","names":["BigInt","Option","toNumberOrThrow","value","toNumber","pipe","getOrThrowWith","Error"],"sources":["../src/BigIntX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,MAAM,EAAEC,MAAM,QAAQ,QAAQ;AAEvC;;;;;;;;;;;;;;;;;;;;;;AAsBA,OAAO,MAAMC,eAAe,GAAIC,KAAa,IAC3CH,MAAM,CAACI,QAAQ,CAACD,KAAK,CAAC,CAACE,IAAI,CACzBJ,MAAM,CAACK,cAAc,CACnB,MAAM,IAAIC,KAAK,CAAC,SAASJ,KAAK,gCAAgC,CAAC,CAChE,CACF","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Boolean` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ /**
7
+ * Converts a `boolean` to its binary digit: `1` for `true`, `0` for `false`.
8
+ *
9
+ * Useful when a numeric flag is required — summing booleans to count how many
10
+ * predicates hold, or feeding a bit into bitwise math or an external API that
11
+ * expects `0`/`1` rather than `false`/`true`.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { BooleanX } from "@nunofyobiz/effect-extras"
16
+ *
17
+ * assert.deepStrictEqual(BooleanX.toBinary(true), 1)
18
+ * assert.deepStrictEqual(BooleanX.toBinary(false), 0)
19
+ * ```
20
+ *
21
+ * @category conversions
22
+ * @since 0.0.0
23
+ */
24
+ export declare const toBinary: (value: boolean) => 0 | 1;
25
+ //# sourceMappingURL=BooleanX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BooleanX.d.ts","sourceRoot":"","sources":["../src/BooleanX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,CAAC,GAAG,CAAoB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Boolean` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ /**
7
+ * Converts a `boolean` to its binary digit: `1` for `true`, `0` for `false`.
8
+ *
9
+ * Useful when a numeric flag is required — summing booleans to count how many
10
+ * predicates hold, or feeding a bit into bitwise math or an external API that
11
+ * expects `0`/`1` rather than `false`/`true`.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { BooleanX } from "@nunofyobiz/effect-extras"
16
+ *
17
+ * assert.deepStrictEqual(BooleanX.toBinary(true), 1)
18
+ * assert.deepStrictEqual(BooleanX.toBinary(false), 0)
19
+ * ```
20
+ *
21
+ * @category conversions
22
+ * @since 0.0.0
23
+ */
24
+ export const toBinary = value => value ? 1 : 0;
25
+ //# sourceMappingURL=BooleanX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BooleanX.js","names":["toBinary","value"],"sources":["../src/BooleanX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA;;;;;;;;;;;;;;;;;;AAkBA,OAAO,MAAMA,QAAQ,GAAIC,KAAc,IAAaA,KAAK,GAAG,CAAC,GAAG,CAAE","ignoreList":[]}