@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.
- package/README.md +36 -2
- package/dist/ArrayX.d.ts +415 -0
- package/dist/ArrayX.d.ts.map +1 -0
- package/dist/ArrayX.js +547 -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/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 +212 -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 +181 -0
- package/dist/OptionX.d.ts.map +1 -0
- package/dist/OptionX.js +195 -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 +76 -0
- package/dist/PredicateX.d.ts.map +1 -0
- package/dist/PredicateX.js +73 -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 +323 -0
- package/dist/RecordX.d.ts.map +1 -0
- package/dist/RecordX.js +326 -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 +70 -0
- package/dist/StringX.d.ts.map +1 -0
- package/dist/StringX.js +81 -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 +1146 -0
- package/dist/WarnResult.d.ts.map +1 -0
- package/dist/WarnResult.js +1060 -0
- package/dist/WarnResult.js.map +1 -0
- package/dist/index.d.ts +22 -3772
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -1011
- package/dist/index.js.map +1 -1
- package/package.json +18 -5
- package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +3 -3
- package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
- package/src/{RecordX/RecordX.ts → RecordX.ts} +1 -1
- package/src/index.ts +21 -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/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/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +0 -0
- /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
- /package/src/{OptionX/OptionX.ts → OptionX.ts} +0 -0
- /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
- /package/src/{PredicateX/PredicateX.ts → PredicateX.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/{StringX/StringX.ts → StringX.ts} +0 -0
- /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
- /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"}
|
package/dist/BigIntX.js
ADDED
|
@@ -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"}
|
package/dist/BooleanX.js
ADDED
|
@@ -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":[]}
|