@nunofyobiz/effect-extras 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -3
- package/dist/ArrayX.d.ts +381 -0
- package/dist/ArrayX.d.ts.map +1 -0
- package/dist/ArrayX.js +493 -0
- package/dist/ArrayX.js.map +1 -0
- package/dist/BigIntX.d.ts +24 -0
- package/dist/BigIntX.d.ts.map +1 -0
- package/dist/BigIntX.js +30 -0
- package/dist/BigIntX.js.map +1 -0
- package/dist/BooleanX.d.ts +25 -0
- package/dist/BooleanX.d.ts.map +1 -0
- package/dist/BooleanX.js +25 -0
- package/dist/BooleanX.js.map +1 -0
- package/dist/DurationX.d.ts +73 -0
- package/dist/DurationX.d.ts.map +1 -0
- package/dist/DurationX.js +91 -0
- package/dist/DurationX.js.map +1 -0
- package/dist/EffectX.d.ts +120 -0
- package/dist/EffectX.d.ts.map +1 -0
- package/dist/EffectX.js +140 -0
- package/dist/EffectX.js.map +1 -0
- package/dist/FormDataX.d.ts +49 -0
- package/dist/FormDataX.d.ts.map +1 -0
- package/dist/FormDataX.js +42 -0
- package/dist/FormDataX.js.map +1 -0
- package/dist/InclusiveOr.d.ts +1123 -0
- package/dist/InclusiveOr.d.ts.map +1 -0
- package/dist/InclusiveOr.js +1074 -0
- package/dist/InclusiveOr.js.map +1 -0
- package/dist/MapX.d.ts +32 -0
- package/dist/MapX.d.ts.map +1 -0
- package/dist/MapX.js +49 -0
- package/dist/MapX.js.map +1 -0
- package/dist/NonNullableX.d.ts +174 -0
- package/dist/NonNullableX.d.ts.map +1 -0
- package/dist/NonNullableX.js +217 -0
- package/dist/NonNullableX.js.map +1 -0
- package/dist/NumberX.d.ts +178 -0
- package/dist/NumberX.d.ts.map +1 -0
- package/dist/NumberX.js +214 -0
- package/dist/NumberX.js.map +1 -0
- package/dist/OptionX.d.ts +187 -0
- package/dist/OptionX.d.ts.map +1 -0
- package/dist/OptionX.js +201 -0
- package/dist/OptionX.js.map +1 -0
- package/dist/OrderX.d.ts +32 -0
- package/dist/OrderX.d.ts.map +1 -0
- package/dist/OrderX.js +32 -0
- package/dist/OrderX.js.map +1 -0
- package/dist/PredicateX.d.ts +108 -0
- package/dist/PredicateX.d.ts.map +1 -0
- package/dist/PredicateX.js +111 -0
- package/dist/PredicateX.js.map +1 -0
- package/dist/PromiseX.d.ts +32 -0
- package/dist/PromiseX.d.ts.map +1 -0
- package/dist/PromiseX.js +32 -0
- package/dist/PromiseX.js.map +1 -0
- package/dist/RecordX.d.ts +450 -0
- package/dist/RecordX.d.ts.map +1 -0
- package/dist/RecordX.js +487 -0
- package/dist/RecordX.js.map +1 -0
- package/dist/ResultX.d.ts +50 -0
- package/dist/ResultX.d.ts.map +1 -0
- package/dist/ResultX.js +50 -0
- package/dist/ResultX.js.map +1 -0
- package/dist/SchemaX.d.ts +249 -0
- package/dist/SchemaX.d.ts.map +1 -0
- package/dist/SchemaX.js +243 -0
- package/dist/SchemaX.js.map +1 -0
- package/dist/SetX.d.ts +121 -0
- package/dist/SetX.d.ts.map +1 -0
- package/dist/SetX.js +137 -0
- package/dist/SetX.js.map +1 -0
- package/dist/StringX.d.ts +131 -0
- package/dist/StringX.d.ts.map +1 -0
- package/dist/StringX.js +149 -0
- package/dist/StringX.js.map +1 -0
- package/dist/StructX.d.ts +219 -0
- package/dist/StructX.d.ts.map +1 -0
- package/dist/StructX.js +173 -0
- package/dist/StructX.js.map +1 -0
- package/dist/WarnResult.d.ts +1191 -0
- package/dist/WarnResult.d.ts.map +1 -0
- package/dist/WarnResult.js +991 -0
- package/dist/WarnResult.js.map +1 -0
- package/dist/index.d.ts +23 -3772
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -1011
- package/dist/index.js.map +1 -1
- package/package.json +18 -5
- package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +6 -88
- package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
- package/src/InclusiveOr.ts +1255 -0
- package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +5 -0
- package/src/{OptionX/OptionX.ts → OptionX.ts} +8 -2
- package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +41 -0
- package/src/{RecordX/RecordX.ts → RecordX.ts} +184 -2
- package/src/StringX.ts +210 -0
- package/src/{WarnResult/WarnResult.ts → WarnResult.ts} +297 -227
- package/src/index.ts +22 -20
- package/src/ArrayX/index.ts +0 -1
- package/src/BigIntX/index.ts +0 -1
- package/src/BooleanX/index.ts +0 -1
- package/src/DurationX/index.ts +0 -1
- package/src/EffectX/index.ts +0 -1
- package/src/FormDataX/index.ts +0 -1
- package/src/MapX/index.ts +0 -1
- package/src/NonNullableX/index.ts +0 -2
- package/src/NumberX/index.ts +0 -1
- package/src/OptionX/index.ts +0 -1
- package/src/OrderX/index.ts +0 -1
- package/src/PredicateX/index.ts +0 -1
- package/src/PromiseX/index.ts +0 -1
- package/src/RecordX/index.ts +0 -1
- package/src/ResultX/index.ts +0 -1
- package/src/SchemaX/index.ts +0 -1
- package/src/SetX/index.ts +0 -1
- package/src/StringX/StringX.ts +0 -97
- package/src/StringX/index.ts +0 -1
- package/src/StructX/index.ts +0 -1
- package/src/WarnResult/index.ts +0 -1
- /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
- /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
- /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
- /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
- /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
- /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
- /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
- /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
- /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
- /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
- /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
- /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
package/README.md
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@nunofyobiz/effect-extras)
|
|
4
4
|
[](https://github.com/nunofyobiz/effect-extras/actions/workflows/ci.yml)
|
|
5
|
+
[](https://nunofyobiz.github.io/effect-extras/)
|
|
5
6
|
[](./LICENSE)
|
|
6
7
|
|
|
8
|
+
📖 **[API reference & docs →](https://nunofyobiz.github.io/effect-extras/)**
|
|
9
|
+
|
|
7
10
|
Generic, framework-agnostic extensions of the [Effect](https://effect.website)
|
|
8
11
|
standard library. These are the `*X` utility modules — `ArrayX`, `OptionX`,
|
|
9
12
|
`RecordX`, `StructX`, and friends — that extend Effect's own modules with small,
|
|
@@ -35,6 +38,33 @@ pnpm add @nunofyobiz/effect-extras
|
|
|
35
38
|
compatible version of `effect`. This package extends Effect; it does not bundle
|
|
36
39
|
it.
|
|
37
40
|
|
|
41
|
+
## Tree-shaking
|
|
42
|
+
|
|
43
|
+
The package is **side-effect free** (`"sideEffects": false`) and is built — the
|
|
44
|
+
same way [Effect](https://effect.website) is — with `tsc` (one ESM file per
|
|
45
|
+
module, no bundling) plus Babel's
|
|
46
|
+
[`annotate-pure-calls`](https://github.com/Andarist/babel-plugin-annotate-pure-calls)
|
|
47
|
+
pass, which stamps every helper `/*#__PURE__*/`. A bundler therefore keeps only
|
|
48
|
+
what you actually use. Three import styles, finest-grained first:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// Subpath, named — only this function (and its real deps) reach your bundle.
|
|
52
|
+
import { compactNullable } from "@nunofyobiz/effect-extras/ArrayX";
|
|
53
|
+
|
|
54
|
+
// Subpath, namespace — `ArrayX.*`, tree-shaken per function (Effect-style).
|
|
55
|
+
import * as ArrayX from "@nunofyobiz/effect-extras/ArrayX";
|
|
56
|
+
|
|
57
|
+
// Root barrel — convenient; unused *modules* are shaken away, but a module you
|
|
58
|
+
// touch is kept whole (per-module granularity).
|
|
59
|
+
import { ArrayX } from "@nunofyobiz/effect-extras";
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Measured (minified + brotli, `effect` externalized): a single function lands at
|
|
63
|
+
**~40 B**, a whole module at **~1 kB**, the entire library at **~4.4 kB** — so a
|
|
64
|
+
subpath import pays for what it uses, not the library. Budgets are enforced in CI
|
|
65
|
+
via [size-limit](https://github.com/ai/size-limit); packaging correctness via
|
|
66
|
+
[publint](https://publint.dev).
|
|
67
|
+
|
|
38
68
|
## What belongs here
|
|
39
69
|
|
|
40
70
|
This package has exactly one job: hold the generic `*X` helpers that extend
|
|
@@ -93,16 +123,19 @@ shape — not before.
|
|
|
93
123
|
|
|
94
124
|
## Modules
|
|
95
125
|
|
|
96
|
-
Each module is exported as a namespace from the package root
|
|
126
|
+
Each module is exported as a namespace — from the package root and from a
|
|
127
|
+
matching subpath (`@nunofyobiz/effect-extras/ArrayX`); see
|
|
128
|
+
[Tree-shaking](#tree-shaking):
|
|
97
129
|
|
|
98
130
|
| Module | Extends / purpose |
|
|
99
131
|
| -------------- | -------------------------------------------------------------------------- |
|
|
100
|
-
| `ArrayX` | Array helpers (grouping, ordered insertion
|
|
132
|
+
| `ArrayX` | Array helpers (grouping, ordered insertion) |
|
|
101
133
|
| `BigIntX` | BigInt helpers (`toNumberOrThrow`) |
|
|
102
134
|
| `BooleanX` | Boolean helpers |
|
|
103
135
|
| `DurationX` | Duration / DateTime diff helpers |
|
|
104
136
|
| `EffectX` | Effect bridges (`flattenOption`, `fromOptionOrElse`, `tryUntil`) |
|
|
105
137
|
| `FormDataX` | Schema-based `FormData` parsing |
|
|
138
|
+
| `InclusiveOr` | Inclusive-or of a `left` and/or `right` — terminology-free `WarnResult` |
|
|
106
139
|
| `MapX` | Native `Map` helpers |
|
|
107
140
|
| `NonNullableX` | Non-nullable assertions (`fromNullableOrThrow`, exported as `nn`) |
|
|
108
141
|
| `NumberX` | Number helpers |
|
|
@@ -125,7 +158,9 @@ pnpm install
|
|
|
125
158
|
pnpm tc # typecheck (src + tests)
|
|
126
159
|
pnpm lint # ESLint (formatting included via eslint-plugin-prettier)
|
|
127
160
|
pnpm test # vitest run
|
|
128
|
-
pnpm build # emit dist/ (ESM +
|
|
161
|
+
pnpm build # emit dist/ (one ESM file + .d.ts per module): tsc + babel
|
|
162
|
+
pnpm publint # validate packaging (exports map, types, ESM) — needs a build
|
|
163
|
+
pnpm treeshake # enforce per-function tree-shaking budgets (size-limit) — needs a build
|
|
129
164
|
pnpm knip # unused code / deps
|
|
130
165
|
pnpm check-all # all of the above, in CI order
|
|
131
166
|
```
|
package/dist/ArrayX.d.ts
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `Array` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Array, Equivalence, Option, Order, Predicate } from "effect";
|
|
7
|
+
/**
|
|
8
|
+
* Returns a shallow copy of `array` between `start` (inclusive) and `end`
|
|
9
|
+
* (exclusive), as a pipeable, dual-form alias for `Array.prototype.slice`.
|
|
10
|
+
*
|
|
11
|
+
* `Array.prototype.slice` is already non-mutating (it returns a shallow copy),
|
|
12
|
+
* but it isn't pipeable. This helper makes it composable inside `pipe(...)`
|
|
13
|
+
* chains alongside the rest of the codebase's Effect-style utilities.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { pipe } from "effect"
|
|
18
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
19
|
+
*
|
|
20
|
+
* // data-first
|
|
21
|
+
* assert.deepStrictEqual(ArrayX.slice([1, 2, 3, 4], 1, 3), [2, 3])
|
|
22
|
+
*
|
|
23
|
+
* // data-last (pipeable)
|
|
24
|
+
* assert.deepStrictEqual(pipe([1, 2, 3, 4], ArrayX.slice(1, 3)), [2, 3])
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @category getters
|
|
28
|
+
* @since 0.0.0
|
|
29
|
+
*/
|
|
30
|
+
export declare const slice: (<A>(start: number, end: number) => (array: readonly A[]) => A[]) & (<A>(array: readonly A[], start: number, end: number) => A[]);
|
|
31
|
+
/**
|
|
32
|
+
* Inserts or moves a unique item in an array at a specified position.
|
|
33
|
+
*
|
|
34
|
+
* **Assumption**: Items should be unique in the array based on standard equality.
|
|
35
|
+
*
|
|
36
|
+
* **Happy case**: If the item doesn't exist in the array and the destination reference item is found:
|
|
37
|
+
* The new item is inserted before the destination reference item
|
|
38
|
+
*
|
|
39
|
+
* **Item not found in array**:
|
|
40
|
+
* - If destination reference item is found: The new item is inserted before the destination reference item
|
|
41
|
+
* - If destination reference item is not found: The new item is inserted at the end of the array
|
|
42
|
+
*
|
|
43
|
+
* **Item found but duplicated**:
|
|
44
|
+
* - If destination reference item is found: All existing copies are removed, then a single copy is inserted before the destination reference item
|
|
45
|
+
* - If destination reference item is not found: All existing copies are removed, then a single copy is inserted at the end of the array
|
|
46
|
+
*
|
|
47
|
+
* @param array - The input array to modify
|
|
48
|
+
* @param config - Configuration object containing:
|
|
49
|
+
* - `item`: The item to insert or update (must be a string or number)
|
|
50
|
+
* - `insertToBeLeftOf`: The item to position the new/updated item before,
|
|
51
|
+
* or null to insert at the end
|
|
52
|
+
*
|
|
53
|
+
* @returns A new array with the item inserted or moved to the specified position
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
58
|
+
*
|
|
59
|
+
* // Move an existing item to sit just before "c"
|
|
60
|
+
* assert.deepStrictEqual(
|
|
61
|
+
* ArrayX.insertUniq(["a", "b", "c", "d"], { item: "a", insertToBeLeftOf: "c" }),
|
|
62
|
+
* ["b", "a", "c", "d"],
|
|
63
|
+
* )
|
|
64
|
+
*
|
|
65
|
+
* // Insert a brand-new item; unknown destination falls through to the end
|
|
66
|
+
* assert.deepStrictEqual(
|
|
67
|
+
* ArrayX.insertUniq(["a", "b"], { item: "new", insertToBeLeftOf: null }),
|
|
68
|
+
* ["a", "b", "new"],
|
|
69
|
+
* )
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @category combinators
|
|
73
|
+
* @since 0.0.0
|
|
74
|
+
*/
|
|
75
|
+
export declare const insertUniq: (<A extends string | number>(config: {
|
|
76
|
+
item: A;
|
|
77
|
+
insertToBeLeftOf: A | null;
|
|
78
|
+
}) => (array: readonly A[] | A[]) => A[]) & (<A extends string | number>(array: readonly A[] | A[], config: {
|
|
79
|
+
item: A;
|
|
80
|
+
insertToBeLeftOf: A | null;
|
|
81
|
+
}) => A[]);
|
|
82
|
+
/**
|
|
83
|
+
* Maps over `array` while threading an accumulator, iterating from right to
|
|
84
|
+
* left instead of left to right.
|
|
85
|
+
*
|
|
86
|
+
* Identical to `Array.mapAccum`, except the traversal order is reversed: `f` is
|
|
87
|
+
* called on the last element first, and the resulting array is returned in the
|
|
88
|
+
* original (left-to-right) order. Use it when each element's mapped value
|
|
89
|
+
* depends on state accumulated from the elements that follow it.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
94
|
+
*
|
|
95
|
+
* // Running suffix-sum: each slot holds the sum of itself and everything after it
|
|
96
|
+
* assert.deepStrictEqual(
|
|
97
|
+
* ArrayX.mapRightAccum([1, 2, 3], 0, (total, n) => [total + n, total + n]),
|
|
98
|
+
* [6, [6, 5, 3]],
|
|
99
|
+
* )
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @category folding
|
|
103
|
+
* @since 0.0.0
|
|
104
|
+
*/
|
|
105
|
+
export declare const mapRightAccum: (<A, B, C>(initialAccumulator: C, f: (accumulator: C, a: A, index: number) => [C, B]) => (array: A[]) => [C, B[]]) & (<A, B, C>(array: A[], initialAccumulator: C, f: (accumulator: C, a: A, index: number) => [C, B]) => [C, B[]]);
|
|
106
|
+
/**
|
|
107
|
+
* Returns the maximum element of `array` according to `order`, wrapped in an
|
|
108
|
+
* `Option` so that empty arrays are handled safely.
|
|
109
|
+
*
|
|
110
|
+
* Effect's `Array.max` throws on an empty array; this returns `Option.none()`
|
|
111
|
+
* instead, and `Option.some(max)` otherwise. Reach for it whenever the input
|
|
112
|
+
* array might be empty.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* import { Option, Order, pipe } from "effect"
|
|
117
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
118
|
+
*
|
|
119
|
+
* assert.deepStrictEqual(
|
|
120
|
+
* pipe([3, 7, 2], ArrayX.maxOption(Order.Number)),
|
|
121
|
+
* Option.some(7),
|
|
122
|
+
* )
|
|
123
|
+
* assert.deepStrictEqual(
|
|
124
|
+
* pipe([], ArrayX.maxOption(Order.Number)),
|
|
125
|
+
* Option.none(),
|
|
126
|
+
* )
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @category getters
|
|
130
|
+
* @since 0.0.0
|
|
131
|
+
*/
|
|
132
|
+
export declare const maxOption: (<A>(order: Order.Order<A>) => (array: A[]) => Option.Option<A>) & (<A>(array: A[], order: Order.Order<A>) => Option.Option<A>);
|
|
133
|
+
/**
|
|
134
|
+
* Returns the smallest element of `array` (per `order`) that matches
|
|
135
|
+
* `predicate`, narrowed to the refined type `B`, or `Option.none()` if none
|
|
136
|
+
* match.
|
|
137
|
+
*
|
|
138
|
+
* Combines a refinement filter with `Array.min`: only elements satisfying
|
|
139
|
+
* `predicate` are considered, and the minimum of those (by `order`) is
|
|
140
|
+
* returned. The refinement narrows the element type, so the resulting `Option`
|
|
141
|
+
* carries the more specific `B`.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* import { Option, Order, pipe } from "effect"
|
|
146
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
147
|
+
*
|
|
148
|
+
* const isEven = (n: number): n is number => n % 2 === 0
|
|
149
|
+
*
|
|
150
|
+
* assert.deepStrictEqual(
|
|
151
|
+
* pipe([3, 4, 1, 2, 5], ArrayX.takeFirstWhere(isEven, Order.Number)),
|
|
152
|
+
* Option.some(2),
|
|
153
|
+
* )
|
|
154
|
+
* assert.deepStrictEqual(
|
|
155
|
+
* pipe([1, 3, 5], ArrayX.takeFirstWhere(isEven, Order.Number)),
|
|
156
|
+
* Option.none(),
|
|
157
|
+
* )
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @category getters
|
|
161
|
+
* @since 0.0.0
|
|
162
|
+
*/
|
|
163
|
+
export declare const takeFirstWhere: (<A, B extends A>(predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => (array: A[]) => Option.Option<B>) & (<A, B extends A>(array: A[], predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => Option.Option<B>);
|
|
164
|
+
/**
|
|
165
|
+
* Returns the largest element of `array` (per `order`) that matches
|
|
166
|
+
* `predicate`, narrowed to the refined type `B`, or `Option.none()` if none
|
|
167
|
+
* match.
|
|
168
|
+
*
|
|
169
|
+
* The mirror of {@link takeFirstWhere}: only elements satisfying `predicate`
|
|
170
|
+
* are considered, and the maximum of those (by `order`) is returned. The
|
|
171
|
+
* refinement narrows the element type, so the resulting `Option` carries the
|
|
172
|
+
* more specific `B`.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* import { Option, Order, pipe } from "effect"
|
|
177
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
178
|
+
*
|
|
179
|
+
* const isEven = (n: number): n is number => n % 2 === 0
|
|
180
|
+
*
|
|
181
|
+
* assert.deepStrictEqual(
|
|
182
|
+
* pipe([3, 4, 1, 2, 5], ArrayX.takeLastWhere(isEven, Order.Number)),
|
|
183
|
+
* Option.some(4),
|
|
184
|
+
* )
|
|
185
|
+
* assert.deepStrictEqual(
|
|
186
|
+
* pipe([1, 3, 5], ArrayX.takeLastWhere(isEven, Order.Number)),
|
|
187
|
+
* Option.none(),
|
|
188
|
+
* )
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* @category getters
|
|
192
|
+
* @since 0.0.0
|
|
193
|
+
*/
|
|
194
|
+
export declare const takeLastWhere: (<A, B extends A>(predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => (array: A[]) => Option.Option<B>) & (<A, B extends A>(array: A[], predicate: Predicate.Refinement<A, B>, order: Order.Order<B>) => Option.Option<B>);
|
|
195
|
+
/**
|
|
196
|
+
* Groups `items` into a partial record keyed by the category each item maps to
|
|
197
|
+
* via `categorize`.
|
|
198
|
+
*
|
|
199
|
+
* Each item is appended to the array under its category, preserving input
|
|
200
|
+
* order. The result is `Partial<Record<C, A[]>>` because not every possible
|
|
201
|
+
* category `C` is guaranteed to appear — only categories that received at least
|
|
202
|
+
* one item are present.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
207
|
+
*
|
|
208
|
+
* const parity = (n: number) => (n % 2 === 0 ? "even" : "odd")
|
|
209
|
+
*
|
|
210
|
+
* assert.deepStrictEqual(ArrayX.categorize([1, 2, 3, 4], parity), {
|
|
211
|
+
* odd: [1, 3],
|
|
212
|
+
* even: [2, 4],
|
|
213
|
+
* })
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @category folding
|
|
217
|
+
* @since 0.0.0
|
|
218
|
+
*/
|
|
219
|
+
export declare const categorize: <A, C extends string>(items: Iterable<A>, categorize: (a: A) => C) => Partial<Record<C, A[]>>;
|
|
220
|
+
/**
|
|
221
|
+
* Removes all `null` and `undefined` elements from `array`, narrowing the
|
|
222
|
+
* element type to `NonNullable<A>`.
|
|
223
|
+
*
|
|
224
|
+
* Falsy-but-present values such as `0` and `""` are kept — only nullish values
|
|
225
|
+
* are dropped. Use it to clean up an array of optionals into a dense array of
|
|
226
|
+
* known-present values.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
231
|
+
*
|
|
232
|
+
* assert.deepStrictEqual(
|
|
233
|
+
* ArrayX.compactNullable([1, null, 2, undefined, 0, ""]),
|
|
234
|
+
* [1, 2, 0, ""],
|
|
235
|
+
* )
|
|
236
|
+
* ```
|
|
237
|
+
*
|
|
238
|
+
* @category filtering
|
|
239
|
+
* @since 0.0.0
|
|
240
|
+
*/
|
|
241
|
+
export declare const compactNullable: <A>(array: A[]) => NonNullable<A>[];
|
|
242
|
+
/**
|
|
243
|
+
* Drops the leading elements of `array` until `predicate` first holds, keeping
|
|
244
|
+
* everything from the first match onward.
|
|
245
|
+
*
|
|
246
|
+
* The first matching element and all subsequent elements are retained
|
|
247
|
+
* regardless of whether they match — only the prefix *before* the first match
|
|
248
|
+
* is trimmed. If nothing matches, returns an empty array.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* import { Predicate } from "effect"
|
|
253
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
254
|
+
*
|
|
255
|
+
* // Trims the leading strings, then keeps everything (including the trailing "b")
|
|
256
|
+
* assert.deepStrictEqual(
|
|
257
|
+
* ArrayX.filterHead(["a", 1, 2, "b"], Predicate.isNumber),
|
|
258
|
+
* [1, 2, "b"],
|
|
259
|
+
* )
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* @category filtering
|
|
263
|
+
* @since 0.0.0
|
|
264
|
+
*/
|
|
265
|
+
export declare const filterHead: (<A>(predicate: Predicate.Predicate<A>) => (array: A[]) => A[]) & (<A>(array: A[], predicate: Predicate.Predicate<A>) => A[]);
|
|
266
|
+
/**
|
|
267
|
+
* Drops the trailing elements of `array` after `predicate` last holds, keeping
|
|
268
|
+
* everything up to and including the last match.
|
|
269
|
+
*
|
|
270
|
+
* The mirror of {@link filterHead}: the last matching element and all preceding
|
|
271
|
+
* elements are retained regardless of whether they match — only the suffix
|
|
272
|
+
* *after* the last match is trimmed. If nothing matches, returns an empty
|
|
273
|
+
* array.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* import { Predicate } from "effect"
|
|
278
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
279
|
+
*
|
|
280
|
+
* // Keeps the leading "a" and trims the trailing strings after the last number
|
|
281
|
+
* assert.deepStrictEqual(
|
|
282
|
+
* ArrayX.filterTail(["a", 1, 2, "b"], Predicate.isNumber),
|
|
283
|
+
* ["a", 1, 2],
|
|
284
|
+
* )
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* @category filtering
|
|
288
|
+
* @since 0.0.0
|
|
289
|
+
*/
|
|
290
|
+
export declare const filterTail: (<A>(predicate: Predicate.Predicate<A>) => (array: A[]) => A[]) & (<A>(array: A[], predicate: Predicate.Predicate<A>) => A[]);
|
|
291
|
+
/**
|
|
292
|
+
* Maps `f` over `array` and drops every result that is `null` or `undefined`,
|
|
293
|
+
* narrowing the element type to `NonNullable<B>`.
|
|
294
|
+
*
|
|
295
|
+
* A nullable-friendly `Array.filterMap`: where `filterMap` expects `f` to
|
|
296
|
+
* return an `Option`, this accepts a function returning `B | null` (or
|
|
297
|
+
* `undefined`) and treats nullish results as "skip this element". Falsy-but-
|
|
298
|
+
* present values such as `0` and `""` are kept.
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* ```ts
|
|
302
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
303
|
+
*
|
|
304
|
+
* // Keep only the even numbers, mapped to their halves
|
|
305
|
+
* assert.deepStrictEqual(
|
|
306
|
+
* ArrayX.filterMapNullable([1, 2, 3, 4], (n) => (n % 2 === 0 ? n / 2 : null)),
|
|
307
|
+
* [1, 2],
|
|
308
|
+
* )
|
|
309
|
+
* ```
|
|
310
|
+
*
|
|
311
|
+
* @category filtering
|
|
312
|
+
* @since 0.0.0
|
|
313
|
+
*/
|
|
314
|
+
export declare const filterMapNullable: (<A, B>(f: (a: A) => B | null) => (array: A[]) => NonNullable<B>[]) & (<A, B>(array: A[], f: (a: A) => B | null) => NonNullable<B>[]);
|
|
315
|
+
/**
|
|
316
|
+
* Finds the first element of a 2-dimensional array (row-major order) matching
|
|
317
|
+
* `predicate`, returning it alongside its row and column indices.
|
|
318
|
+
*
|
|
319
|
+
* Scans rows top-to-bottom and, within each row, left-to-right. On a match
|
|
320
|
+
* returns `Option.some([value, rowIndex, columnIndex])`; if no element matches
|
|
321
|
+
* (or the grid is empty), returns `Option.none()`.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```ts
|
|
325
|
+
* import { Option } from "effect"
|
|
326
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
327
|
+
*
|
|
328
|
+
* const grid = [
|
|
329
|
+
* ["A", "B", "C"],
|
|
330
|
+
* ["D", "E", "F"],
|
|
331
|
+
* ]
|
|
332
|
+
*
|
|
333
|
+
* assert.deepStrictEqual(
|
|
334
|
+
* ArrayX.findFirstWithIndex2d(grid, (cell) => cell === "E"),
|
|
335
|
+
* Option.some(["E", 1, 1]),
|
|
336
|
+
* )
|
|
337
|
+
* ```
|
|
338
|
+
*
|
|
339
|
+
* @category getters
|
|
340
|
+
* @since 0.0.0
|
|
341
|
+
*/
|
|
342
|
+
export declare const findFirstWithIndex2d: (<A>(predicate: Predicate.Predicate<A>) => (array: A[][]) => Option.Option<[A, number, number]>) & (<A>(array: A[][], predicate: Predicate.Predicate<A>) => Option.Option<[A, number, number]>);
|
|
343
|
+
/**
|
|
344
|
+
* Splits `array` into runs of consecutive elements that share the same group
|
|
345
|
+
* value, where the group is derived by `chunk` and compared with the provided
|
|
346
|
+
* `Equivalence`.
|
|
347
|
+
*
|
|
348
|
+
* Only *adjacent* elements are grouped: a new run starts every time the group
|
|
349
|
+
* value changes from the previous element. Each entry in the result carries the
|
|
350
|
+
* `group` value and the non-empty array of `values` that produced it, preserving
|
|
351
|
+
* input order. An empty input yields an empty array. Use it for run-length-style
|
|
352
|
+
* segmentation; reach for `Array.groupBy` instead when you want all elements
|
|
353
|
+
* with the same key collapsed regardless of position.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```ts
|
|
357
|
+
* import { Equivalence } from "effect"
|
|
358
|
+
* import { ArrayX } from "@nunofyobiz/effect-extras"
|
|
359
|
+
*
|
|
360
|
+
* // Group adjacent numbers by parity
|
|
361
|
+
* assert.deepStrictEqual(
|
|
362
|
+
* ArrayX.chunkBy([2, 4, 1, 3, 6], (n) => n % 2 === 0, Equivalence.Boolean),
|
|
363
|
+
* [
|
|
364
|
+
* { group: true, values: [2, 4] },
|
|
365
|
+
* { group: false, values: [1, 3] },
|
|
366
|
+
* { group: true, values: [6] },
|
|
367
|
+
* ],
|
|
368
|
+
* )
|
|
369
|
+
* ```
|
|
370
|
+
*
|
|
371
|
+
* @category folding
|
|
372
|
+
* @since 0.0.0
|
|
373
|
+
*/
|
|
374
|
+
export declare const chunkBy: (<A, B>(chunk: (a: A) => B, GroupEquivalence: Equivalence.Equivalence<B>) => (array: A[]) => {
|
|
375
|
+
group: B;
|
|
376
|
+
values: Array.NonEmptyArray<A>;
|
|
377
|
+
}[]) & (<A, B>(array: A[], chunk: (a: A) => B, GroupEquivalence: Equivalence.Equivalence<B>) => {
|
|
378
|
+
group: B;
|
|
379
|
+
values: Array.NonEmptyArray<A>;
|
|
380
|
+
}[]);
|
|
381
|
+
//# sourceMappingURL=ArrayX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArrayX.d.ts","sourceRoot":"","sources":["../src/ArrayX.ts"],"names":[],"mappings":"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"}
|