massaman 0.0.1-rc.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/dist/array/index.d.mts +2 -0
  4. package/dist/array/index.mjs +2 -0
  5. package/dist/array-C8MqjyiP.mjs +191 -0
  6. package/dist/array-C8MqjyiP.mjs.map +1 -0
  7. package/dist/control/index.d.mts +2 -0
  8. package/dist/control/index.mjs +2 -0
  9. package/dist/control-B4mDPBn6.mjs +164 -0
  10. package/dist/control-B4mDPBn6.mjs.map +1 -0
  11. package/dist/conversion/index.d.mts +2 -0
  12. package/dist/conversion/index.mjs +2 -0
  13. package/dist/conversion-ByBXBR5i.mjs +189 -0
  14. package/dist/conversion-ByBXBR5i.mjs.map +1 -0
  15. package/dist/error/index.d.mts +2 -0
  16. package/dist/error/index.mjs +2 -0
  17. package/dist/function/index.d.mts +2 -0
  18. package/dist/function/index.mjs +2 -0
  19. package/dist/function-2-6QB4m7.mjs +122 -0
  20. package/dist/function-2-6QB4m7.mjs.map +1 -0
  21. package/dist/index-BkyNt8th.d.mts +20 -0
  22. package/dist/index-BkyNt8th.d.mts.map +1 -0
  23. package/dist/index-Br9PO6mU.d.mts +155 -0
  24. package/dist/index-Br9PO6mU.d.mts.map +1 -0
  25. package/dist/index-BuBpCB73.d.mts +197 -0
  26. package/dist/index-BuBpCB73.d.mts.map +1 -0
  27. package/dist/index-COFf0Pih.d.mts +128 -0
  28. package/dist/index-COFf0Pih.d.mts.map +1 -0
  29. package/dist/index-DqsBQ7Pp.d.mts +120 -0
  30. package/dist/index-DqsBQ7Pp.d.mts.map +1 -0
  31. package/dist/index-Dw_tuZdb.d.mts +134 -0
  32. package/dist/index-Dw_tuZdb.d.mts.map +1 -0
  33. package/dist/index.d.mts +12 -0
  34. package/dist/index.mjs +12 -0
  35. package/dist/math/index.d.mts +2 -0
  36. package/dist/math/index.mjs +2 -0
  37. package/dist/object/index.d.mts +2 -0
  38. package/dist/object/index.mjs +2 -0
  39. package/dist/object-BHnp9Sr9.mjs +27 -0
  40. package/dist/object-BHnp9Sr9.mjs.map +1 -0
  41. package/dist/pattern/index.d.mts +2 -0
  42. package/dist/pattern/index.mjs +2 -0
  43. package/dist/predicate/index.d.mts +2 -0
  44. package/dist/predicate/index.mjs +2 -0
  45. package/dist/predicate-CYzSOMLW.mjs +108 -0
  46. package/dist/predicate-CYzSOMLW.mjs.map +1 -0
  47. package/dist/promise/index.d.mts +2 -0
  48. package/dist/promise/index.mjs +2 -0
  49. package/dist/string/index.d.mts +2 -0
  50. package/dist/string/index.mjs +2 -0
  51. package/package.json +108 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zac Rosenbauer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ <div align="center">
2
+ <img src="assets/banner.svg" alt="tadka" width="100%" />
3
+ </div>
4
+
5
+ # tadka
6
+
7
+ A comprehensive functional programming library for TypeScript — a curated unified surface over [es-toolkit](https://es-toolkit.slash.page) and [ts-pattern](https://github.com/gvergnaud/ts-pattern), with custom utilities for composition, predicates, Result-style error handling, and pattern matching.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install tadka
13
+ ```
14
+
15
+ ```bash
16
+ # pnpm
17
+ pnpm add tadka
18
+
19
+ # yarn
20
+ yarn add tadka
21
+ ```
22
+
23
+ ## Features
24
+
25
+ | Feature | Description |
26
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------- |
27
+ | **Unified FP surface** | Array, object, string, function, math, predicate, promise — one curated import root, tree-shakeable. |
28
+ | **Result-style error handling** | `attempt` / `attemptAsync` / `ok` / `err` / `isOk` / `isErr` / `unwrap` — no thrown exceptions. |
29
+ | **Pattern matching** | Full [ts-pattern](https://github.com/gvergnaud/ts-pattern) re-export under `tadka/pattern`. |
30
+ | **Variadic type-guard narrowing** | `allPass([isString, isNotEmpty])` returns a guard that narrows to `string` — composes any arity. |
31
+ | **Async-aware pipelines** | `flowAsync` chains promise-returning functions with end-to-end type inference (up to 7 steps). |
32
+ | **Safe error normalization** | `toError` + `stringify` handle non-`Error` throws, circular refs, Maps/Sets — no more `[object Object]`. |
33
+ | **Branching combinators** | `when` / `unless` / `ifElse` for point-free conditionals inside `flow` pipelines. |
34
+ | **100% test coverage** | Enforced by CI — every line, branch, and function is verified. |
35
+ | **ESM-only, `sideEffects: false`** | 12 subpath exports, tree-shakeable, zero side effects. |
36
+
37
+ ## Usage
38
+
39
+ ```ts
40
+ import { flow, compact, uniq, toArray } from 'tadka'
41
+
42
+ const normalize = flow(toArray, compact, uniq)
43
+ normalize([1, null, 2, 1, null]) // [1, 2]
44
+ ```
45
+
46
+ ```ts
47
+ import { match, P } from 'tadka/pattern'
48
+
49
+ const label = match(status)
50
+ .with('active', () => 'Live')
51
+ .with('draft', () => 'Draft')
52
+ .with(P._, () => 'N/A')
53
+ .exhaustive()
54
+ ```
55
+
56
+ ```ts
57
+ import { attempt, isOk } from 'tadka/control'
58
+
59
+ const result = attempt(() => JSON.parse(raw))
60
+ if (isOk(result)) {
61
+ console.log(result.value)
62
+ } else {
63
+ console.error(result.error)
64
+ }
65
+ ```
66
+
67
+ ```ts
68
+ import { allPass } from 'tadka/predicate'
69
+ import { isString } from 'es-toolkit/predicate'
70
+ import { isNotEmpty } from 'tadka/predicate'
71
+
72
+ const isNonEmptyString = allPass([isString, isNotEmpty])
73
+ if (isNonEmptyString(x)) {
74
+ // x is narrowed to string
75
+ }
76
+ ```
77
+
78
+ ### Error-safe composition
79
+
80
+ `flow` and `flowAsync` don't catch throws — wrap the pipeline with `attempt` / `attemptAsync` to recover:
81
+
82
+ ```ts
83
+ import { flow, attempt, isOk } from 'tadka'
84
+
85
+ const parseUser = flow(JSON.parse, (u) => u.name.trim())
86
+
87
+ const result = attempt(() => parseUser(rawInput))
88
+ if (isOk(result)) {
89
+ return result.value
90
+ }
91
+ return 'unknown'
92
+ ```
93
+
94
+ ## Modules
95
+
96
+ | Subpath | Description |
97
+ | ------------------ | -------------------------------------------------------------------------- |
98
+ | `tadka` | Root barrel — re-exports everything below |
99
+ | `tadka/array` | Array utilities (chunk, groupBy, sortWith, scan, unfold, …) |
100
+ | `tadka/object` | Object utilities (evolve, pick, omit, merge, mapKeys, …) |
101
+ | `tadka/function` | Composition (flow, flowAsync, tap, call, curry, when, unless, ifElse, …) |
102
+ | `tadka/predicate` | Type guards, combinators with variadic narrowing |
103
+ | `tadka/conversion` | Coercion + safe stringification (toError, stringify, toNumber, toArray, …) |
104
+ | `tadka/string` | String transforms (camelCase, kebabCase, trim, …) |
105
+ | `tadka/math` | Numeric utilities (clamp, sum, mean, range, …) |
106
+ | `tadka/promise` | Async helpers (delay, timeout, Mutex, Semaphore) |
107
+ | `tadka/control` | Result-style error handling (attempt, ok, err, isOk, isErr, unwrap, …) |
108
+ | `tadka/pattern` | Pattern matching (match, P, isMatching) |
109
+ | `tadka/error` | Error types (AbortError, TimeoutError) |
110
+
111
+ ## Custom Utilities
112
+
113
+ Utilities that aren't in es-toolkit or ts-pattern — implemented in this package:
114
+
115
+ | Module | Utility | Description |
116
+ | ------------ | ------------------------------------------------ | -------------------------------------------------------------- |
117
+ | `array` | `adjust`, `scan`, `unfold`, `dropRepeats` | Index update, accumulator scan, seed unfold, consecutive dedup |
118
+ | `array` | `reduceWhile`, `ascend`, `descend`, `sortWith` | Short-circuit reduce, comparator factories, multi-key sort |
119
+ | `function` | `flowAsync`, `tap` | Async composition, side-effect-in-pipeline |
120
+ | `function` | `when`, `unless`, `ifElse`, `call`, `callAsync` | Point-free conditionals, named application |
121
+ | `object` | `evolve` | Apply transforms per key |
122
+ | `predicate` | `allPass`, `anyPass`, `both`, `either` | Variadic-narrowing predicate combinators |
123
+ | `predicate` | `isArray`, `isObject`, `isEmpty`, `isNotEmpty` | Type guards + emptiness |
124
+ | `predicate` | `isFiniteNumber`, `isInteger`, `isNaN` | Strict numeric guards (shadowing the broken global `isNaN`) |
125
+ | `control` | `attempt`, `attemptAsync` | Wrap throwing/rejecting code into a `Result` |
126
+ | `control` | `ok`, `err`, `isOk`, `isErr`, `unwrap` | Construct, narrow, and unwrap a `Result` |
127
+ | `conversion` | `toError`, `stringify` | Normalize unknown thrown values + safe JSON of any value |
128
+ | `conversion` | `toNumber`, `toString`, `toBoolean`, `toInteger` | Stable coercion primitives |
129
+ | `conversion` | `toFinite`, `toArray` | Safe coercion with fallback semantics |
130
+
131
+ ## Requirements
132
+
133
+ - Node.js >= 24.0.0
134
+ - ESM only (`require()` / CommonJS is not supported)
135
+ - TypeScript >= 5.9 recommended (variadic narrowing benefits from recent inference)
136
+
137
+ ## License
138
+
139
+ MIT © Zac Rosenbauer
@@ -0,0 +1,2 @@
1
+ import { $ as unionWith, A as last, B as remove, C as initial, D as isSubset, E as intersectionWith, F as orderBy, G as tail, H as sampleSize, I as partition, J as takeRightWhile, K as take, L as pull, M as mapAsync, N as maxBy, O as isSubsetWith, P as minBy, Q as unionBy, R as pullAt, S as head, T as intersectionBy, U as shuffle, V as sample, W as sortBy, X as toFilled, Y as takeWhile, Z as union, _ as flatten, _t as scan, a as difference, at as windowed, b as forEachRight, bt as adjust, c as drop, ct as xorBy, d as dropWhile, dt as zipObject, et as uniq, f as fill, ft as zipWith, g as flatMapDeep, gt as sortWith, h as flatMapAsync, ht as descend, i as countBy, it as unzipWith, j as limitAsync, k as keyBy, l as dropRight, lt as xorWith, m as flatMap, mt as ascend, n as chunk, nt as uniqWith, o as differenceBy, ot as without, p as filterAsync, pt as unfold, q as takeRight, r as compact, rt as unzip, s as differenceWith, st as xor, t as at, tt as uniqBy, u as dropRightWhile, ut as zip, v as flattenDeep, vt as reduceWhile, w as intersection, x as groupBy, y as forEachAsync, yt as dropRepeats, z as reduceAsync } from "../index-Dw_tuZdb.mjs";
2
+ export { adjust, ascend, at, chunk, compact, countBy, descend, difference, differenceBy, differenceWith, drop, dropRepeats, dropRight, dropRightWhile, dropWhile, fill, filterAsync, flatMap, flatMapAsync, flatMapDeep, flatten, flattenDeep, forEachAsync, forEachRight, groupBy, head, initial, intersection, intersectionBy, intersectionWith, isSubset, isSubsetWith, keyBy, last, limitAsync, mapAsync, maxBy, minBy, orderBy, partition, pull, pullAt, reduceAsync, reduceWhile, remove, sample, sampleSize, scan, shuffle, sortBy, sortWith, tail, take, takeRight, takeRightWhile, takeWhile, toFilled, unfold, union, unionBy, unionWith, uniq, uniqBy, uniqWith, unzip, unzipWith, windowed, without, xor, xorBy, xorWith, zip, zipObject, zipWith };
@@ -0,0 +1,2 @@
1
+ import { $ as unionWith, A as last, B as remove, C as initial, D as isSubset, E as intersectionWith, F as orderBy, G as tail, H as sampleSize, I as partition, J as takeRightWhile, K as take, L as pull, M as mapAsync, N as maxBy, O as isSubsetWith, P as minBy, Q as unionBy, R as pullAt, S as head, T as intersectionBy, U as shuffle, V as sample, W as sortBy, X as toFilled, Y as takeWhile, Z as union, _ as flatten, _t as scan, a as difference, at as windowed, b as forEachRight, bt as adjust, c as drop, ct as xorBy, d as dropWhile, dt as zipObject, et as uniq, f as fill, ft as zipWith, g as flatMapDeep, gt as sortWith, h as flatMapAsync, ht as descend, i as countBy, it as unzipWith, j as limitAsync, k as keyBy, l as dropRight, lt as xorWith, m as flatMap, mt as ascend, n as chunk, nt as uniqWith, o as differenceBy, ot as without, p as filterAsync, pt as unfold, q as takeRight, r as compact, rt as unzip, s as differenceWith, st as xor, t as at, tt as uniqBy, u as dropRightWhile, ut as zip, v as flattenDeep, vt as reduceWhile, w as intersection, x as groupBy, y as forEachAsync, yt as dropRepeats, z as reduceAsync } from "../array-C8MqjyiP.mjs";
2
+ export { adjust, ascend, at, chunk, compact, countBy, descend, difference, differenceBy, differenceWith, drop, dropRepeats, dropRight, dropRightWhile, dropWhile, fill, filterAsync, flatMap, flatMapAsync, flatMapDeep, flatten, flattenDeep, forEachAsync, forEachRight, groupBy, head, initial, intersection, intersectionBy, intersectionWith, isSubset, isSubsetWith, keyBy, last, limitAsync, mapAsync, maxBy, minBy, orderBy, partition, pull, pullAt, reduceAsync, reduceWhile, remove, sample, sampleSize, scan, shuffle, sortBy, sortWith, tail, take, takeRight, takeRightWhile, takeWhile, toFilled, unfold, union, unionBy, unionWith, uniq, uniqBy, uniqWith, unzip, unzipWith, windowed, without, xor, xorBy, xorWith, zip, zipObject, zipWith };
@@ -0,0 +1,191 @@
1
+ import { at, chunk, compact, countBy, difference, differenceBy, differenceWith, drop, dropRight, dropRightWhile, dropWhile, fill, filterAsync, flatMap, flatMapAsync, flatMapDeep, flatten, flattenDeep, forEachAsync, forEachRight, groupBy, head, initial, intersection, intersectionBy, intersectionWith, isSubset, isSubsetWith, keyBy, last, limitAsync, mapAsync, maxBy, minBy, orderBy, partition, pull, pullAt, reduceAsync, remove, sample, sampleSize, shuffle, sortBy, tail, take, takeRight, takeRightWhile, takeWhile, toFilled, union, unionBy, unionWith, uniq, uniqBy, uniqWith, unzip, unzipWith, windowed, without, xor, xorBy, xorWith, zip, zipObject, zipWith } from "es-toolkit/array";
2
+ //#region src/array/adjust.ts
3
+ /**
4
+ * Applies a function to the element at the given index, returning a new array.
5
+ *
6
+ * The original array is not modified. If the index is out of bounds, the
7
+ * array is returned unchanged.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * adjust([1, 2, 3], 1, (n) => n * 10)
12
+ * // [1, 20, 3]
13
+ * ```
14
+ */
15
+ function adjust(array, index, fn) {
16
+ const result = [...array];
17
+ if (index >= 0 && index < array.length) result[index] = fn(result[index]);
18
+ return result;
19
+ }
20
+ //#endregion
21
+ //#region src/array/dropRepeats.ts
22
+ /**
23
+ * Removes consecutively repeated elements from an array using strict
24
+ * equality (`===`).
25
+ *
26
+ * Only adjacent duplicates are removed — non-adjacent duplicates are kept.
27
+ * Use {@link uniq} from es-toolkit to remove all duplicates regardless of position.
28
+ *
29
+ * Quirks (inherent to `===`):
30
+ * - `NaN !== NaN`, so adjacent `NaN`s are *not* collapsed.
31
+ * - `-0 === 0`, so adjacent `-0` and `0` *are* collapsed.
32
+ * - Object/array elements compare by reference, not structure.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * dropRepeats([1, 1, 2, 3, 3, 2, 1])
37
+ * // [1, 2, 3, 2, 1]
38
+ * ```
39
+ */
40
+ function dropRepeats(array) {
41
+ return array.reduce((acc, item, index) => {
42
+ if (index === 0 || item !== array[index - 1]) acc.push(item);
43
+ return acc;
44
+ }, []);
45
+ }
46
+ //#endregion
47
+ //#region src/array/reduceWhile.ts
48
+ /**
49
+ * Like `reduce` but stops early when the predicate returns `false`.
50
+ *
51
+ * The predicate receives the current accumulator and element. When it
52
+ * returns `false`, the current accumulator is returned without processing
53
+ * the remaining elements.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * // Sum until we hit a negative number
58
+ * reduceWhile(
59
+ * [1, 2, 3, -1, 5],
60
+ * (acc, n) => n >= 0,
61
+ * (acc, n) => acc + n,
62
+ * 0,
63
+ * )
64
+ * // 6
65
+ * ```
66
+ */
67
+ function reduceWhile(array, predicate, fn, initial) {
68
+ let acc = initial;
69
+ for (let index = 0; index < array.length; index += 1) {
70
+ const value = array[index];
71
+ if (!predicate(acc, value)) return acc;
72
+ acc = fn(acc, value, index);
73
+ }
74
+ return acc;
75
+ }
76
+ //#endregion
77
+ //#region src/array/scan.ts
78
+ /**
79
+ * Like `reduce` but returns an array of all intermediate accumulator values.
80
+ *
81
+ * The result array starts with the initial value and ends with the final
82
+ * accumulator, so its length is `array.length + 1`.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * scan([1, 2, 3, 4], (acc, n) => acc + n, 0)
87
+ * // [0, 1, 3, 6, 10]
88
+ * ```
89
+ */
90
+ function scan(array, fn, initial) {
91
+ return array.reduce((result, item, index) => {
92
+ const prev = result[result.length - 1];
93
+ result.push(fn(prev, item, index));
94
+ return result;
95
+ }, [initial]);
96
+ }
97
+ //#endregion
98
+ //#region src/array/sorting.ts
99
+ /**
100
+ * Creates an ascending comparator from an accessor function.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * users.sort(ascend(u => u.name))
105
+ * ```
106
+ */
107
+ function ascend(fn) {
108
+ return (a, b) => {
109
+ const aa = fn(a);
110
+ const bb = fn(b);
111
+ if (aa < bb) return -1;
112
+ if (aa > bb) return 1;
113
+ return 0;
114
+ };
115
+ }
116
+ /**
117
+ * Creates a descending comparator from an accessor function.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * users.sort(descend(u => u.age))
122
+ * ```
123
+ */
124
+ function descend(fn) {
125
+ return (a, b) => {
126
+ const aa = fn(a);
127
+ const bb = fn(b);
128
+ if (aa > bb) return -1;
129
+ if (aa < bb) return 1;
130
+ return 0;
131
+ };
132
+ }
133
+ /**
134
+ * Sorts an array using multiple comparators in priority order.
135
+ *
136
+ * The first comparator has highest priority. When it returns 0 (tie),
137
+ * the next comparator is used, and so on.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * sortWith(users, [
142
+ * ascend(u => u.department),
143
+ * descend(u => u.age),
144
+ * ])
145
+ * ```
146
+ */
147
+ function sortWith(array, comparators) {
148
+ return [...array].toSorted((a, b) => {
149
+ for (const cmp of comparators) {
150
+ const result = cmp(a, b);
151
+ if (result !== 0) return result;
152
+ }
153
+ return 0;
154
+ });
155
+ }
156
+ //#endregion
157
+ //#region src/array/unfold.ts
158
+ /**
159
+ * Builds an array from a seed value using an iterator function.
160
+ *
161
+ * The iterator receives the current seed and returns either a `[value, nextSeed]`
162
+ * tuple to continue, or `false` to stop.
163
+ *
164
+ * Dual of `reduce` — reduce collapses a list into a value, unfold expands
165
+ * a value into a list.
166
+ *
167
+ * **Termination is the caller's responsibility.** If `fn` never returns
168
+ * `false`, `unfold` will run until memory is exhausted. For bounded
169
+ * generation, encode a counter or limit into the seed.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * unfold((n) => (n > 0 ? [n, n - 1] : false), 5)
174
+ * // [5, 4, 3, 2, 1]
175
+ * ```
176
+ */
177
+ function unfold(fn, seed) {
178
+ const result = [];
179
+ let current = seed;
180
+ let pair = fn(current);
181
+ while (pair !== false) {
182
+ result.push(pair[0]);
183
+ current = pair[1];
184
+ pair = fn(current);
185
+ }
186
+ return result;
187
+ }
188
+ //#endregion
189
+ export { unionWith as $, last as A, remove as B, initial as C, isSubset as D, intersectionWith as E, orderBy as F, tail as G, sampleSize as H, partition as I, takeRightWhile as J, take as K, pull as L, mapAsync as M, maxBy as N, isSubsetWith as O, minBy as P, unionBy as Q, pullAt as R, head as S, intersectionBy as T, shuffle as U, sample as V, sortBy as W, toFilled as X, takeWhile as Y, union as Z, flatten as _, scan as _t, difference as a, windowed as at, forEachRight as b, adjust as bt, drop as c, xorBy as ct, dropWhile as d, zipObject as dt, uniq as et, fill as f, zipWith as ft, flatMapDeep as g, sortWith as gt, flatMapAsync as h, descend as ht, countBy as i, unzipWith as it, limitAsync as j, keyBy as k, dropRight as l, xorWith as lt, flatMap as m, ascend as mt, chunk as n, uniqWith as nt, differenceBy as o, without as ot, filterAsync as p, unfold as pt, takeRight as q, compact as r, unzip as rt, differenceWith as s, xor as st, at as t, uniqBy as tt, dropRightWhile as u, zip as ut, flattenDeep as v, reduceWhile as vt, intersection as w, groupBy as x, forEachAsync as y, dropRepeats as yt, reduceAsync as z };
190
+
191
+ //# sourceMappingURL=array-C8MqjyiP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array-C8MqjyiP.mjs","names":[],"sources":["../src/array/adjust.ts","../src/array/dropRepeats.ts","../src/array/reduceWhile.ts","../src/array/scan.ts","../src/array/sorting.ts","../src/array/unfold.ts"],"sourcesContent":["/**\n * Applies a function to the element at the given index, returning a new array.\n *\n * The original array is not modified. If the index is out of bounds, the\n * array is returned unchanged.\n *\n * @example\n * ```ts\n * adjust([1, 2, 3], 1, (n) => n * 10)\n * // [1, 20, 3]\n * ```\n */\nexport function adjust<T>(array: readonly T[], index: number, fn: (value: T) => T): T[] {\n const result = [...array]\n if (index >= 0 && index < array.length) {\n // oxlint-disable-next-line security/detect-object-injection -- Numeric array index parameter, not user-controlled key\n result[index] = fn(result[index])\n }\n return result\n}\n","/**\n * Removes consecutively repeated elements from an array using strict\n * equality (`===`).\n *\n * Only adjacent duplicates are removed — non-adjacent duplicates are kept.\n * Use {@link uniq} from es-toolkit to remove all duplicates regardless of position.\n *\n * Quirks (inherent to `===`):\n * - `NaN !== NaN`, so adjacent `NaN`s are *not* collapsed.\n * - `-0 === 0`, so adjacent `-0` and `0` *are* collapsed.\n * - Object/array elements compare by reference, not structure.\n *\n * @example\n * ```ts\n * dropRepeats([1, 1, 2, 3, 3, 2, 1])\n * // [1, 2, 3, 2, 1]\n * ```\n */\nexport function dropRepeats<T>(array: readonly T[]): T[] {\n return array.reduce<T[]>((acc, item, index) => {\n if (index === 0 || item !== array[index - 1]) {\n acc.push(item)\n }\n return acc\n }, [])\n}\n","/* oxlint-disable functional/no-let -- iterative impl avoids stack overflow on large arrays */\n\n/**\n * Like `reduce` but stops early when the predicate returns `false`.\n *\n * The predicate receives the current accumulator and element. When it\n * returns `false`, the current accumulator is returned without processing\n * the remaining elements.\n *\n * @example\n * ```ts\n * // Sum until we hit a negative number\n * reduceWhile(\n * [1, 2, 3, -1, 5],\n * (acc, n) => n >= 0,\n * (acc, n) => acc + n,\n * 0,\n * )\n * // 6\n * ```\n */\nexport function reduceWhile<T, R>(\n array: readonly T[],\n predicate: (accumulator: R, value: T) => boolean,\n fn: (accumulator: R, value: T, index: number) => R,\n initial: R\n): R {\n let acc = initial\n for (let index = 0; index < array.length; index += 1) {\n // oxlint-disable-next-line security/detect-object-injection -- Locally computed numeric array index\n const value = array[index]\n if (!predicate(acc, value)) {\n return acc\n }\n acc = fn(acc, value, index)\n }\n return acc\n}\n","/**\n * Like `reduce` but returns an array of all intermediate accumulator values.\n *\n * The result array starts with the initial value and ends with the final\n * accumulator, so its length is `array.length + 1`.\n *\n * @example\n * ```ts\n * scan([1, 2, 3, 4], (acc, n) => acc + n, 0)\n * // [0, 1, 3, 6, 10]\n * ```\n */\nexport function scan<T, R>(\n array: readonly T[],\n fn: (accumulator: R, value: T, index: number) => R,\n initial: R\n): R[] {\n return array.reduce<R[]>(\n (result, item, index) => {\n const prev = result[result.length - 1]\n result.push(fn(prev, item, index))\n return result\n },\n [initial]\n )\n}\n","/**\n * Creates an ascending comparator from an accessor function.\n *\n * @example\n * ```ts\n * users.sort(ascend(u => u.name))\n * ```\n */\nexport function ascend<T>(fn: (value: T) => number | string): (a: T, b: T) => number {\n return (a: T, b: T) => {\n const aa = fn(a)\n const bb = fn(b)\n if (aa < bb) {\n return -1\n }\n if (aa > bb) {\n return 1\n }\n return 0\n }\n}\n\n/**\n * Creates a descending comparator from an accessor function.\n *\n * @example\n * ```ts\n * users.sort(descend(u => u.age))\n * ```\n */\nexport function descend<T>(fn: (value: T) => number | string): (a: T, b: T) => number {\n return (a: T, b: T) => {\n const aa = fn(a)\n const bb = fn(b)\n if (aa > bb) {\n return -1\n }\n if (aa < bb) {\n return 1\n }\n return 0\n }\n}\n\n/**\n * Sorts an array using multiple comparators in priority order.\n *\n * The first comparator has highest priority. When it returns 0 (tie),\n * the next comparator is used, and so on.\n *\n * @example\n * ```ts\n * sortWith(users, [\n * ascend(u => u.department),\n * descend(u => u.age),\n * ])\n * ```\n */\nexport function sortWith<T>(\n array: readonly T[],\n comparators: ReadonlyArray<(a: T, b: T) => number>\n): T[] {\n return [...array].toSorted((a, b) => {\n for (const cmp of comparators) {\n const result = cmp(a, b)\n if (result !== 0) {\n return result\n }\n }\n return 0\n })\n}\n","/* oxlint-disable functional/no-let -- iterative impl avoids stack overflow on large outputs */\n\n/**\n * Builds an array from a seed value using an iterator function.\n *\n * The iterator receives the current seed and returns either a `[value, nextSeed]`\n * tuple to continue, or `false` to stop.\n *\n * Dual of `reduce` — reduce collapses a list into a value, unfold expands\n * a value into a list.\n *\n * **Termination is the caller's responsibility.** If `fn` never returns\n * `false`, `unfold` will run until memory is exhausted. For bounded\n * generation, encode a counter or limit into the seed.\n *\n * @example\n * ```ts\n * unfold((n) => (n > 0 ? [n, n - 1] : false), 5)\n * // [5, 4, 3, 2, 1]\n * ```\n */\nexport function unfold<T, R>(fn: (seed: T) => [R, T] | false, seed: T): R[] {\n const result: R[] = []\n let current = seed\n let pair = fn(current)\n while (pair !== false) {\n result.push(pair[0])\n current = pair[1]\n pair = fn(current)\n }\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,SAAgB,OAAU,OAAqB,OAAe,IAA0B;CACtF,MAAM,SAAS,CAAC,GAAG,MAAM;CACzB,IAAI,SAAS,KAAK,QAAQ,MAAM,QAE9B,OAAO,SAAS,GAAG,OAAO,OAAO;CAEnC,OAAO;;;;;;;;;;;;;;;;;;;;;;ACAT,SAAgB,YAAe,OAA0B;CACvD,OAAO,MAAM,QAAa,KAAK,MAAM,UAAU;EAC7C,IAAI,UAAU,KAAK,SAAS,MAAM,QAAQ,IACxC,IAAI,KAAK,KAAK;EAEhB,OAAO;IACN,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;ACHR,SAAgB,YACd,OACA,WACA,IACA,SACG;CACH,IAAI,MAAM;CACV,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;EAEpD,MAAM,QAAQ,MAAM;EACpB,IAAI,CAAC,UAAU,KAAK,MAAM,EACxB,OAAO;EAET,MAAM,GAAG,KAAK,OAAO,MAAM;;CAE7B,OAAO;;;;;;;;;;;;;;;;ACxBT,SAAgB,KACd,OACA,IACA,SACK;CACL,OAAO,MAAM,QACV,QAAQ,MAAM,UAAU;EACvB,MAAM,OAAO,OAAO,OAAO,SAAS;EACpC,OAAO,KAAK,GAAG,MAAM,MAAM,MAAM,CAAC;EAClC,OAAO;IAET,CAAC,QAAQ,CACV;;;;;;;;;;;;AChBH,SAAgB,OAAU,IAA2D;CACnF,QAAQ,GAAM,MAAS;EACrB,MAAM,KAAK,GAAG,EAAE;EAChB,MAAM,KAAK,GAAG,EAAE;EAChB,IAAI,KAAK,IACP,OAAO;EAET,IAAI,KAAK,IACP,OAAO;EAET,OAAO;;;;;;;;;;;AAYX,SAAgB,QAAW,IAA2D;CACpF,QAAQ,GAAM,MAAS;EACrB,MAAM,KAAK,GAAG,EAAE;EAChB,MAAM,KAAK,GAAG,EAAE;EAChB,IAAI,KAAK,IACP,OAAO;EAET,IAAI,KAAK,IACP,OAAO;EAET,OAAO;;;;;;;;;;;;;;;;;AAkBX,SAAgB,SACd,OACA,aACK;CACL,OAAO,CAAC,GAAG,MAAM,CAAC,UAAU,GAAG,MAAM;EACnC,KAAK,MAAM,OAAO,aAAa;GAC7B,MAAM,SAAS,IAAI,GAAG,EAAE;GACxB,IAAI,WAAW,GACb,OAAO;;EAGX,OAAO;GACP;;;;;;;;;;;;;;;;;;;;;;;ACjDJ,SAAgB,OAAa,IAAiC,MAAc;CAC1E,MAAM,SAAc,EAAE;CACtB,IAAI,UAAU;CACd,IAAI,OAAO,GAAG,QAAQ;CACtB,OAAO,SAAS,OAAO;EACrB,OAAO,KAAK,KAAK,GAAG;EACpB,UAAU,KAAK;EACf,OAAO,GAAG,QAAQ;;CAEpB,OAAO"}
@@ -0,0 +1,2 @@
1
+ import { a as isOk, c as attempt, d as Ok, f as Result, i as isErr, l as attemptAsync, n as invariant, o as ok, r as err, s as unwrap, t as assert, u as Err } from "../index-Br9PO6mU.mjs";
2
+ export { Err, Ok, Result, assert, attempt, attemptAsync, err, invariant, isErr, isOk, ok, unwrap };
@@ -0,0 +1,2 @@
1
+ import { a as err, c as ok, i as attemptAsync, l as unwrap, n as invariant, o as isErr, r as attempt, s as isOk, t as assert } from "../control-B4mDPBn6.mjs";
2
+ export { assert, attempt, attemptAsync, err, invariant, isErr, isOk, ok, unwrap };
@@ -0,0 +1,164 @@
1
+ import { isNil } from "es-toolkit/predicate";
2
+ import { assert, invariant } from "es-toolkit/util";
3
+ //#region src/control/result.ts
4
+ /**
5
+ * Minimal error coercion used internally by `err()`. Kept local to avoid
6
+ * pulling the full conversion module into the `tadka/control` bundle.
7
+ * For richer stringification (Maps, Sets, Errors with own props, circular
8
+ * refs), import `toError` from `tadka/conversion`.
9
+ */
10
+ function coerceError(thrown) {
11
+ if (thrown instanceof Error) return thrown;
12
+ if (typeof thrown === "string") return new Error(thrown);
13
+ try {
14
+ const message = JSON.stringify(thrown) ?? String(thrown);
15
+ return new Error(message, { cause: thrown });
16
+ } catch {
17
+ return new Error(String(thrown), { cause: thrown });
18
+ }
19
+ }
20
+ /**
21
+ * Creates a success result wrapping the given value.
22
+ *
23
+ * @param value - The success value
24
+ * @returns An `Ok` result containing the value
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const result = ok(42)
29
+ * // { ok: true, value: 42 }
30
+ * ```
31
+ */
32
+ function ok(value) {
33
+ return {
34
+ ok: true,
35
+ value,
36
+ error: null
37
+ };
38
+ }
39
+ /**
40
+ * Creates a failure result wrapping the given error.
41
+ *
42
+ * @param error - The error value
43
+ * @returns An `Err` result containing the error
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const result = err(new Error('fail'))
48
+ * // { ok: false, error: Error('fail') }
49
+ * ```
50
+ */
51
+ function err(error) {
52
+ return {
53
+ ok: false,
54
+ value: null,
55
+ error: coerceError(error)
56
+ };
57
+ }
58
+ /**
59
+ * Type guard that narrows a `Result` to `Ok`.
60
+ *
61
+ * @param result - The result to check
62
+ * @returns `true` if the result is `Ok`
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const result = attempt(() => JSON.parse('{}'))
67
+ * if (isOk(result)) {
68
+ * console.log(result.value)
69
+ * }
70
+ * ```
71
+ */
72
+ function isOk(result) {
73
+ return result.ok === true;
74
+ }
75
+ /**
76
+ * Type guard that narrows a `Result` to `Err`.
77
+ *
78
+ * @param result - The result to check
79
+ * @returns `true` if the result is `Err`
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * const result = attempt(() => JSON.parse('bad'))
84
+ * if (isErr(result)) {
85
+ * console.error(result.error)
86
+ * }
87
+ * ```
88
+ */
89
+ function isErr(result) {
90
+ return result.ok === false;
91
+ }
92
+ /**
93
+ * Extract the value from an `Ok` result, or throw on `Err`.
94
+ *
95
+ * When called without a message, throws the original error.
96
+ * When called with a message, throws a new Error with that message
97
+ * and the original error as `cause` (like Rust's `expect`).
98
+ *
99
+ * @param result - The result to unwrap
100
+ * @param message - Optional custom error message (Rust `expect` behavior)
101
+ * @returns The unwrapped value
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * const value = unwrap(ok(42)) // 42
106
+ * unwrap(err('fail')) // throws Error('fail')
107
+ * unwrap(err('fail'), 'config required') // throws Error('config required', { cause: Error('fail') })
108
+ * ```
109
+ */
110
+ function unwrap(result, message) {
111
+ if (result.ok) return result.value;
112
+ if (!isNil(message)) throw new Error(message, { cause: result.error });
113
+ throw result.error;
114
+ }
115
+ //#endregion
116
+ //#region src/control/attempt.ts
117
+ /**
118
+ * Executes a synchronous function and wraps the outcome in a `Result`.
119
+ * Returns `Ok` with the return value on success, `Err` with the thrown value on failure.
120
+ *
121
+ * @param fn - The function to execute
122
+ * @returns A `Result` containing either the value or the error
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * const result = attempt(() => JSON.parse('{"a":1}'))
127
+ * if (isOk(result)) {
128
+ * console.log(result.value) // { a: 1 }
129
+ * }
130
+ * ```
131
+ */
132
+ function attempt(fn) {
133
+ try {
134
+ return ok(fn());
135
+ } catch (error) {
136
+ return err(error);
137
+ }
138
+ }
139
+ /**
140
+ * Executes an asynchronous function and wraps the outcome in a `Result`.
141
+ * Returns `Ok` with the resolved value on success, `Err` with the rejection reason on failure.
142
+ *
143
+ * @param fn - The async function to execute
144
+ * @returns A promise resolving to a `Result` containing either the value or the error
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const result = await attemptAsync(() => fetch('/api/data'))
149
+ * if (isErr(result)) {
150
+ * console.error(result.error)
151
+ * }
152
+ * ```
153
+ */
154
+ async function attemptAsync(fn) {
155
+ try {
156
+ return ok(await fn());
157
+ } catch (error) {
158
+ return err(error);
159
+ }
160
+ }
161
+ //#endregion
162
+ export { err as a, ok as c, attemptAsync as i, unwrap as l, invariant as n, isErr as o, attempt as r, isOk as s, assert as t };
163
+
164
+ //# sourceMappingURL=control-B4mDPBn6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-B4mDPBn6.mjs","names":[],"sources":["../src/control/result.ts","../src/control/attempt.ts"],"sourcesContent":["import { isNil } from 'es-toolkit/predicate'\n\nimport type { Err, Ok, Result } from './types.js'\n\n/**\n * Minimal error coercion used internally by `err()`. Kept local to avoid\n * pulling the full conversion module into the `tadka/control` bundle.\n * For richer stringification (Maps, Sets, Errors with own props, circular\n * refs), import `toError` from `tadka/conversion`.\n */\nfunction coerceError(thrown: unknown): Error {\n if (thrown instanceof Error) {\n return thrown\n }\n if (typeof thrown === 'string') {\n return new Error(thrown)\n }\n try {\n const message = JSON.stringify(thrown) ?? String(thrown)\n return new Error(message, { cause: thrown })\n } catch {\n return new Error(String(thrown), { cause: thrown })\n }\n}\n\n/**\n * Creates a success result wrapping the given value.\n *\n * @param value - The success value\n * @returns An `Ok` result containing the value\n *\n * @example\n * ```ts\n * const result = ok(42)\n * // { ok: true, value: 42 }\n * ```\n */\nexport function ok<T>(value: T): Ok<T> {\n return { ok: true, value, error: null }\n}\n\n/**\n * Creates a failure result wrapping the given error.\n *\n * @param error - The error value\n * @returns An `Err` result containing the error\n *\n * @example\n * ```ts\n * const result = err(new Error('fail'))\n * // { ok: false, error: Error('fail') }\n * ```\n */\nexport function err(error: unknown): Err {\n return { ok: false, value: null, error: coerceError(error) }\n}\n\n/**\n * Type guard that narrows a `Result` to `Ok`.\n *\n * @param result - The result to check\n * @returns `true` if the result is `Ok`\n *\n * @example\n * ```ts\n * const result = attempt(() => JSON.parse('{}'))\n * if (isOk(result)) {\n * console.log(result.value)\n * }\n * ```\n */\nexport function isOk<T>(result: Result<T>): result is Ok<T> {\n return result.ok === true\n}\n\n/**\n * Type guard that narrows a `Result` to `Err`.\n *\n * @param result - The result to check\n * @returns `true` if the result is `Err`\n *\n * @example\n * ```ts\n * const result = attempt(() => JSON.parse('bad'))\n * if (isErr(result)) {\n * console.error(result.error)\n * }\n * ```\n */\nexport function isErr<T>(result: Result<T>): result is Err {\n return result.ok === false\n}\n\n/**\n * Extract the value from an `Ok` result, or throw on `Err`.\n *\n * When called without a message, throws the original error.\n * When called with a message, throws a new Error with that message\n * and the original error as `cause` (like Rust's `expect`).\n *\n * @param result - The result to unwrap\n * @param message - Optional custom error message (Rust `expect` behavior)\n * @returns The unwrapped value\n *\n * @example\n * ```ts\n * const value = unwrap(ok(42)) // 42\n * unwrap(err('fail')) // throws Error('fail')\n * unwrap(err('fail'), 'config required') // throws Error('config required', { cause: Error('fail') })\n * ```\n */\nexport function unwrap<T>(result: Result<T>, message?: string): T {\n if (result.ok) {\n return result.value\n }\n if (!isNil(message)) {\n throw new Error(message, { cause: result.error })\n }\n throw result.error\n}\n","import { err, ok } from './result.js'\nimport type { Result } from './types.js'\n\n/**\n * Executes a synchronous function and wraps the outcome in a `Result`.\n * Returns `Ok` with the return value on success, `Err` with the thrown value on failure.\n *\n * @param fn - The function to execute\n * @returns A `Result` containing either the value or the error\n *\n * @example\n * ```ts\n * const result = attempt(() => JSON.parse('{\"a\":1}'))\n * if (isOk(result)) {\n * console.log(result.value) // { a: 1 }\n * }\n * ```\n */\nexport function attempt<T>(fn: () => T): Result<T> {\n try {\n return ok(fn())\n } catch (error) {\n return err(error)\n }\n}\n\n/**\n * Executes an asynchronous function and wraps the outcome in a `Result`.\n * Returns `Ok` with the resolved value on success, `Err` with the rejection reason on failure.\n *\n * @param fn - The async function to execute\n * @returns A promise resolving to a `Result` containing either the value or the error\n *\n * @example\n * ```ts\n * const result = await attemptAsync(() => fetch('/api/data'))\n * if (isErr(result)) {\n * console.error(result.error)\n * }\n * ```\n */\nexport async function attemptAsync<T>(fn: () => Promise<T>): Promise<Result<T>> {\n try {\n return ok(await fn())\n } catch (error) {\n return err(error)\n }\n}\n"],"mappings":";;;;;;;;;AAUA,SAAS,YAAY,QAAwB;CAC3C,IAAI,kBAAkB,OACpB,OAAO;CAET,IAAI,OAAO,WAAW,UACpB,OAAO,IAAI,MAAM,OAAO;CAE1B,IAAI;EACF,MAAM,UAAU,KAAK,UAAU,OAAO,IAAI,OAAO,OAAO;EACxD,OAAO,IAAI,MAAM,SAAS,EAAE,OAAO,QAAQ,CAAC;SACtC;EACN,OAAO,IAAI,MAAM,OAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,CAAC;;;;;;;;;;;;;;;AAgBvD,SAAgB,GAAM,OAAiB;CACrC,OAAO;EAAE,IAAI;EAAM;EAAO,OAAO;EAAM;;;;;;;;;;;;;;AAezC,SAAgB,IAAI,OAAqB;CACvC,OAAO;EAAE,IAAI;EAAO,OAAO;EAAM,OAAO,YAAY,MAAM;EAAE;;;;;;;;;;;;;;;;AAiB9D,SAAgB,KAAQ,QAAoC;CAC1D,OAAO,OAAO,OAAO;;;;;;;;;;;;;;;;AAiBvB,SAAgB,MAAS,QAAkC;CACzD,OAAO,OAAO,OAAO;;;;;;;;;;;;;;;;;;;;AAqBvB,SAAgB,OAAU,QAAmB,SAAqB;CAChE,IAAI,OAAO,IACT,OAAO,OAAO;CAEhB,IAAI,CAAC,MAAM,QAAQ,EACjB,MAAM,IAAI,MAAM,SAAS,EAAE,OAAO,OAAO,OAAO,CAAC;CAEnD,MAAM,OAAO;;;;;;;;;;;;;;;;;;;ACpGf,SAAgB,QAAW,IAAwB;CACjD,IAAI;EACF,OAAO,GAAG,IAAI,CAAC;UACR,OAAO;EACd,OAAO,IAAI,MAAM;;;;;;;;;;;;;;;;;;AAmBrB,eAAsB,aAAgB,IAA0C;CAC9E,IAAI;EACF,OAAO,GAAG,MAAM,IAAI,CAAC;UACd,OAAO;EACd,OAAO,IAAI,MAAM"}
@@ -0,0 +1,2 @@
1
+ import { a as toFinite, c as toString, i as toError, n as toArray, o as toInteger, r as toBoolean, s as toNumber, t as stringify } from "../index-COFf0Pih.mjs";
2
+ export { stringify, toArray, toBoolean, toError, toFinite, toInteger, toNumber, toString };
@@ -0,0 +1,2 @@
1
+ import { a as toFinite, c as toString, i as toError, n as toArray, o as toInteger, r as toBoolean, s as toNumber, t as stringify } from "../conversion-ByBXBR5i.mjs";
2
+ export { stringify, toArray, toBoolean, toError, toFinite, toInteger, toNumber, toString };