@nicolastoulemont/std 0.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 +1 -0
- package/dist/adt/index.d.mts +2 -0
- package/dist/adt/index.mjs +3 -0
- package/dist/adt-DraJkmij.mjs +318 -0
- package/dist/adt-DraJkmij.mjs.map +1 -0
- package/dist/apply-fn.types-CXDoeA7D.d.mts +8 -0
- package/dist/apply-fn.types-CXDoeA7D.d.mts.map +1 -0
- package/dist/brand/index.d.mts +2 -0
- package/dist/brand/index.mjs +3 -0
- package/dist/brand-CTaxGuU9.mjs +165 -0
- package/dist/brand-CTaxGuU9.mjs.map +1 -0
- package/dist/data/index.d.mts +2 -0
- package/dist/data/index.mjs +3 -0
- package/dist/data-DgzWI4R_.mjs +244 -0
- package/dist/data-DgzWI4R_.mjs.map +1 -0
- package/dist/discriminator.types-DCkkrCj4.d.mts +7 -0
- package/dist/discriminator.types-DCkkrCj4.d.mts.map +1 -0
- package/dist/either/index.d.mts +2 -0
- package/dist/either/index.mjs +3 -0
- package/dist/either-CnOBUH7a.mjs +598 -0
- package/dist/either-CnOBUH7a.mjs.map +1 -0
- package/dist/equality/index.d.mts +86 -0
- package/dist/equality/index.d.mts.map +1 -0
- package/dist/equality/index.mjs +3 -0
- package/dist/equality-YMebYwm1.mjs +201 -0
- package/dist/equality-YMebYwm1.mjs.map +1 -0
- package/dist/err/index.d.mts +2 -0
- package/dist/err/index.mjs +3 -0
- package/dist/err-BqQApH9r.mjs +169 -0
- package/dist/err-BqQApH9r.mjs.map +1 -0
- package/dist/flow/index.d.mts +2 -0
- package/dist/flow/index.mjs +3 -0
- package/dist/flow-pRdnqmMY.mjs +21 -0
- package/dist/flow-pRdnqmMY.mjs.map +1 -0
- package/dist/gen/index.d.mts +3 -0
- package/dist/gen/index.mjs +3 -0
- package/dist/gen-YfMC9sDT.mjs +42 -0
- package/dist/gen-YfMC9sDT.mjs.map +1 -0
- package/dist/index-BCrD3pEs.d.mts +222 -0
- package/dist/index-BCrD3pEs.d.mts.map +1 -0
- package/dist/index-BR7takNf.d.mts +186 -0
- package/dist/index-BR7takNf.d.mts.map +1 -0
- package/dist/index-CcPnhWje.d.mts +72 -0
- package/dist/index-CcPnhWje.d.mts.map +1 -0
- package/dist/index-CtJ8Ks9X.d.mts +105 -0
- package/dist/index-CtJ8Ks9X.d.mts.map +1 -0
- package/dist/index-CvGTIg9L.d.mts +211 -0
- package/dist/index-CvGTIg9L.d.mts.map +1 -0
- package/dist/index-DPVT0yK4.d.mts +50 -0
- package/dist/index-DPVT0yK4.d.mts.map +1 -0
- package/dist/index-DgOAEEpu.d.mts +79 -0
- package/dist/index-DgOAEEpu.d.mts.map +1 -0
- package/dist/index-Dtq3kmln.d.mts +394 -0
- package/dist/index-Dtq3kmln.d.mts.map +1 -0
- package/dist/index-bLRqTe5I.d.mts +80 -0
- package/dist/index-bLRqTe5I.d.mts.map +1 -0
- package/dist/index-tkgTLCoq.d.mts +80 -0
- package/dist/index-tkgTLCoq.d.mts.map +1 -0
- package/dist/index-wTrnFgYg.d.mts +57 -0
- package/dist/index-wTrnFgYg.d.mts.map +1 -0
- package/dist/index-yyBTq8Ys.d.mts +79 -0
- package/dist/index-yyBTq8Ys.d.mts.map +1 -0
- package/dist/index.d.mts +135 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +41 -0
- package/dist/index.mjs.map +1 -0
- package/dist/is-promise-BEl3eGZg.mjs +11 -0
- package/dist/is-promise-BEl3eGZg.mjs.map +1 -0
- package/dist/option/index.d.mts +3 -0
- package/dist/option/index.mjs +3 -0
- package/dist/option-CKHDOVea.mjs +410 -0
- package/dist/option-CKHDOVea.mjs.map +1 -0
- package/dist/option.types-D6TYG_i3.d.mts +89 -0
- package/dist/option.types-D6TYG_i3.d.mts.map +1 -0
- package/dist/pipe/index.d.mts +2 -0
- package/dist/pipe/index.mjs +3 -0
- package/dist/pipe-GYxZNkPB.mjs +10 -0
- package/dist/pipe-GYxZNkPB.mjs.map +1 -0
- package/dist/predicate/index.d.mts +2 -0
- package/dist/predicate/index.mjs +3 -0
- package/dist/predicate-B6-EdVgW.mjs +293 -0
- package/dist/predicate-B6-EdVgW.mjs.map +1 -0
- package/dist/result/index.d.mts +3 -0
- package/dist/result/index.mjs +3 -0
- package/dist/result-C5tPWR60.mjs +422 -0
- package/dist/result-C5tPWR60.mjs.map +1 -0
- package/dist/result-D7XJ96pv.mjs +1 -0
- package/dist/result.types-Ce7AEOzj.d.mts +156 -0
- package/dist/result.types-Ce7AEOzj.d.mts.map +1 -0
- package/dist/run/index.d.mts +2 -0
- package/dist/run/index.mjs +3 -0
- package/dist/run-DpXkImo9.mjs +10 -0
- package/dist/run-DpXkImo9.mjs.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
import { t as Result } from "./result-C5tPWR60.mjs";
|
|
2
|
+
import { t as Option } from "./option-CKHDOVea.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/either/either.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a right Either value (success/preferred path).
|
|
7
|
+
*
|
|
8
|
+
* By convention, right represents the correct/preferred outcome.
|
|
9
|
+
*
|
|
10
|
+
* @param value - The right value
|
|
11
|
+
* @returns An Either in the right state
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const result = right(42)
|
|
16
|
+
* // => { right: true, value: 42 }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
const right = (value) => ({
|
|
20
|
+
right: true,
|
|
21
|
+
value,
|
|
22
|
+
*[Symbol.iterator]() {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Create a left Either value (alternative path).
|
|
28
|
+
*
|
|
29
|
+
* By convention, left represents the alternative outcome.
|
|
30
|
+
* Unlike Result's err(), left doesn't imply an error.
|
|
31
|
+
*
|
|
32
|
+
* @param value - The left value
|
|
33
|
+
* @returns An Either in the left state
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const cached = left({ source: "cache", data: cachedValue })
|
|
38
|
+
* // => { right: false, value: { source: "cache", data: cachedValue } }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
const left = (value) => ({
|
|
42
|
+
right: false,
|
|
43
|
+
value,
|
|
44
|
+
*[Symbol.iterator]() {
|
|
45
|
+
yield value;
|
|
46
|
+
throw new Error("Unreachable: Do should short-circuit on left");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Type guard to check if an Either is in the right state.
|
|
51
|
+
*
|
|
52
|
+
* @param either - The Either to check
|
|
53
|
+
* @returns True if right, false if left (with type narrowing)
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* const either = right(42)
|
|
58
|
+
* if (isRight(either)) {
|
|
59
|
+
* console.log(either.value) // Type: number
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
const isRight = (either) => either.right;
|
|
64
|
+
/**
|
|
65
|
+
* Type guard to check if an Either is in the left state.
|
|
66
|
+
*
|
|
67
|
+
* @param either - The Either to check
|
|
68
|
+
* @returns True if left, false if right (with type narrowing)
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* const either = left("error")
|
|
73
|
+
* if (isLeft(either)) {
|
|
74
|
+
* console.log(either.value) // Type: string
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
const isLeft = (either) => !either.right;
|
|
79
|
+
/**
|
|
80
|
+
* Transform the right value of an Either.
|
|
81
|
+
* Left values pass through unchanged.
|
|
82
|
+
*
|
|
83
|
+
* Curried for use with pipe(). Supports async functions.
|
|
84
|
+
*
|
|
85
|
+
* @param fn - Transformation function for right values
|
|
86
|
+
* @returns A curried function that transforms an Either
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* // Sync usage
|
|
91
|
+
* pipe(
|
|
92
|
+
* right(5),
|
|
93
|
+
* map(x => x * 2)
|
|
94
|
+
* ) // => right(10)
|
|
95
|
+
*
|
|
96
|
+
* pipe(
|
|
97
|
+
* left("error"),
|
|
98
|
+
* map(x => x * 2)
|
|
99
|
+
* ) // => left("error")
|
|
100
|
+
*
|
|
101
|
+
* // Async usage
|
|
102
|
+
* await pipe(
|
|
103
|
+
* right(userId),
|
|
104
|
+
* map(async id => await fetchUser(id))
|
|
105
|
+
* ) // => Promise<Either<L, User>>
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
const map = (fn) => (either) => {
|
|
109
|
+
if (!either.right) return either;
|
|
110
|
+
const mapped = fn(either.value);
|
|
111
|
+
if (mapped instanceof Promise) return mapped.then(right);
|
|
112
|
+
return right(mapped);
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Transform the left value of an Either.
|
|
116
|
+
* Right values pass through unchanged.
|
|
117
|
+
*
|
|
118
|
+
* Curried for use with pipe(). Supports async functions.
|
|
119
|
+
*
|
|
120
|
+
* @param fn - Transformation function for left values
|
|
121
|
+
* @returns A curried function that transforms an Either
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* pipe(
|
|
126
|
+
* left("error"),
|
|
127
|
+
* mapLeft(e => e.toUpperCase())
|
|
128
|
+
* ) // => left("ERROR")
|
|
129
|
+
*
|
|
130
|
+
* pipe(
|
|
131
|
+
* right(42),
|
|
132
|
+
* mapLeft(e => e.toUpperCase())
|
|
133
|
+
* ) // => right(42)
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
const mapLeft = (fn) => (either) => {
|
|
137
|
+
if (either.right) return either;
|
|
138
|
+
const mapped = fn(either.value);
|
|
139
|
+
if (mapped instanceof Promise) return mapped.then(left);
|
|
140
|
+
return left(mapped);
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Transform both sides of an Either simultaneously.
|
|
144
|
+
* Unique to Either - not available in Result/Option.
|
|
145
|
+
*
|
|
146
|
+
* Curried for use with pipe(). Supports async functions.
|
|
147
|
+
*
|
|
148
|
+
* @param fnLeft - Transformation function for left values
|
|
149
|
+
* @param fnRight - Transformation function for right values
|
|
150
|
+
* @returns A curried function that transforms an Either
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* pipe(
|
|
155
|
+
* right(5),
|
|
156
|
+
* bimap(
|
|
157
|
+
* e => e.toUpperCase(),
|
|
158
|
+
* x => x * 2
|
|
159
|
+
* )
|
|
160
|
+
* ) // => right(10)
|
|
161
|
+
*
|
|
162
|
+
* pipe(
|
|
163
|
+
* left("error"),
|
|
164
|
+
* bimap(
|
|
165
|
+
* e => e.toUpperCase(),
|
|
166
|
+
* x => x * 2
|
|
167
|
+
* )
|
|
168
|
+
* ) // => left("ERROR")
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
const bimap = (fnLeft, fnRight) => (either) => {
|
|
172
|
+
if (either.right) {
|
|
173
|
+
const mapped$1 = fnRight(either.value);
|
|
174
|
+
if (mapped$1 instanceof Promise) return mapped$1.then(right);
|
|
175
|
+
return right(mapped$1);
|
|
176
|
+
}
|
|
177
|
+
const mapped = fnLeft(either.value);
|
|
178
|
+
if (mapped instanceof Promise) return mapped.then(left);
|
|
179
|
+
return left(mapped);
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Chain operations that return Either.
|
|
183
|
+
* Left values short-circuit the chain.
|
|
184
|
+
*
|
|
185
|
+
* Curried for use with pipe(). Supports async functions.
|
|
186
|
+
* Combines left error unions.
|
|
187
|
+
*
|
|
188
|
+
* @param fn - Function that returns an Either
|
|
189
|
+
* @returns A curried function that chains Eithers
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* // Sync usage
|
|
194
|
+
* pipe(
|
|
195
|
+
* right(5),
|
|
196
|
+
* flatMap(x => right(x * 2)),
|
|
197
|
+
* flatMap(x => right(x + 1))
|
|
198
|
+
* ) // => right(11)
|
|
199
|
+
*
|
|
200
|
+
* pipe(
|
|
201
|
+
* right(5),
|
|
202
|
+
* flatMap(x => left("error")),
|
|
203
|
+
* flatMap(x => right(x + 1)) // Not executed
|
|
204
|
+
* ) // => left("error")
|
|
205
|
+
*
|
|
206
|
+
* // Async usage
|
|
207
|
+
* await pipe(
|
|
208
|
+
* right(userId),
|
|
209
|
+
* flatMap(async id => right(await fetchUser(id))),
|
|
210
|
+
* flatMap(async user => right(await enrichProfile(user)))
|
|
211
|
+
* ) // => Promise<Either<L, EnrichedUser>>
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
const flatMap = (fn) => (either) => {
|
|
215
|
+
if (!either.right) return either;
|
|
216
|
+
return fn(either.value);
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Execute a side effect on right values without modifying the Either.
|
|
220
|
+
* Left values pass through unchanged.
|
|
221
|
+
*
|
|
222
|
+
* Curried for use with pipe(). Supports async functions.
|
|
223
|
+
*
|
|
224
|
+
* @param fn - Side effect function for right values
|
|
225
|
+
* @returns A curried function that executes side effects
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```ts
|
|
229
|
+
* pipe(
|
|
230
|
+
* right(42),
|
|
231
|
+
* tap(x => console.log(x)), // Logs: 42
|
|
232
|
+
* map(x => x * 2)
|
|
233
|
+
* ) // => right(84)
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
const tap = (fn) => (either) => {
|
|
237
|
+
if (!either.right) return either;
|
|
238
|
+
const result = fn(either.value);
|
|
239
|
+
if (result instanceof Promise) return result.then(() => either);
|
|
240
|
+
return either;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Execute a side effect on left values without modifying the Either.
|
|
244
|
+
* Right values pass through unchanged.
|
|
245
|
+
*
|
|
246
|
+
* Curried for use with pipe(). Supports async functions.
|
|
247
|
+
*
|
|
248
|
+
* @param fn - Side effect function for left values
|
|
249
|
+
* @returns A curried function that executes side effects
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```ts
|
|
253
|
+
* pipe(
|
|
254
|
+
* left("error"),
|
|
255
|
+
* tapLeft(e => console.error(e)), // Logs: error
|
|
256
|
+
* mapLeft(e => e.toUpperCase())
|
|
257
|
+
* ) // => left("ERROR")
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
const tapLeft = (fn) => (either) => {
|
|
261
|
+
if (either.right) return either;
|
|
262
|
+
const result = fn(either.value);
|
|
263
|
+
if (result instanceof Promise) return result.then(() => either);
|
|
264
|
+
return either;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Recover from a left value by providing an alternative Either.
|
|
268
|
+
* Right values pass through unchanged.
|
|
269
|
+
*
|
|
270
|
+
* Curried for use with pipe(). Supports async functions.
|
|
271
|
+
* Combines right value unions.
|
|
272
|
+
*
|
|
273
|
+
* @param fn - Function that returns an alternative Either
|
|
274
|
+
* @returns A curried function that recovers from left
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```ts
|
|
278
|
+
* pipe(
|
|
279
|
+
* left("error"),
|
|
280
|
+
* orElse(() => right(42))
|
|
281
|
+
* ) // => right(42)
|
|
282
|
+
*
|
|
283
|
+
* pipe(
|
|
284
|
+
* right(10),
|
|
285
|
+
* orElse(() => right(42))
|
|
286
|
+
* ) // => right(10)
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
const orElse = (fn) => (either) => {
|
|
290
|
+
if (either.right) return either;
|
|
291
|
+
return fn(either.value);
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* Swap left and right values.
|
|
295
|
+
* Unique to Either - not available in Result/Option.
|
|
296
|
+
*
|
|
297
|
+
* Curried for use with pipe().
|
|
298
|
+
*
|
|
299
|
+
* @returns A curried function that swaps left and right
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* pipe(
|
|
304
|
+
* left("error"),
|
|
305
|
+
* swap()
|
|
306
|
+
* ) // => right("error")
|
|
307
|
+
*
|
|
308
|
+
* pipe(
|
|
309
|
+
* right(42),
|
|
310
|
+
* swap()
|
|
311
|
+
* ) // => left(42)
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
const swap = () => (either) => either.right ? left(either.value) : right(either.value);
|
|
315
|
+
/**
|
|
316
|
+
* Filter right values based on a predicate.
|
|
317
|
+
* Failed predicates convert to left with onFail callback.
|
|
318
|
+
* Left values pass through unchanged.
|
|
319
|
+
*
|
|
320
|
+
* Curried for use with pipe().
|
|
321
|
+
*
|
|
322
|
+
* @param predicate - Function to test right values
|
|
323
|
+
* @param onFail - Function to produce left value on failure
|
|
324
|
+
* @returns A curried function that filters an Either
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```ts
|
|
328
|
+
* pipe(
|
|
329
|
+
* right(5),
|
|
330
|
+
* filter(x => x > 3, x => `${x} is too small`)
|
|
331
|
+
* ) // => right(5)
|
|
332
|
+
*
|
|
333
|
+
* pipe(
|
|
334
|
+
* right(2),
|
|
335
|
+
* filter(x => x > 3, x => `${x} is too small`)
|
|
336
|
+
* ) // => left("2 is too small")
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
const filter = (predicate, onFail) => (either) => {
|
|
340
|
+
if (!either.right) return either;
|
|
341
|
+
return predicate(either.value) ? either : left(onFail(either.value));
|
|
342
|
+
};
|
|
343
|
+
function all(eithers) {
|
|
344
|
+
if (Array.isArray(eithers)) {
|
|
345
|
+
const values = [];
|
|
346
|
+
for (const either of eithers) {
|
|
347
|
+
if (!either.right) return either;
|
|
348
|
+
values.push(either.value);
|
|
349
|
+
}
|
|
350
|
+
return right(values);
|
|
351
|
+
}
|
|
352
|
+
const result = {};
|
|
353
|
+
for (const key in eithers) {
|
|
354
|
+
const either = eithers[key];
|
|
355
|
+
if (!either.right) return either;
|
|
356
|
+
result[key] = either.value;
|
|
357
|
+
}
|
|
358
|
+
return right(result);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Extract the right value or return a default.
|
|
362
|
+
*
|
|
363
|
+
* Curried for use with pipe().
|
|
364
|
+
*
|
|
365
|
+
* @param defaultValue - Value to return if Either is left
|
|
366
|
+
* @returns A curried function that extracts the value
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* ```ts
|
|
370
|
+
* pipe(
|
|
371
|
+
* right(42),
|
|
372
|
+
* unwrapOr(0)
|
|
373
|
+
* ) // => 42
|
|
374
|
+
*
|
|
375
|
+
* pipe(
|
|
376
|
+
* left("error"),
|
|
377
|
+
* unwrapOr(0)
|
|
378
|
+
* ) // => 0
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
const unwrapOr = (defaultValue) => (either) => either.right ? either.value : defaultValue;
|
|
382
|
+
/**
|
|
383
|
+
* Extract the right value or compute one from the left value.
|
|
384
|
+
*
|
|
385
|
+
* Curried for use with pipe().
|
|
386
|
+
*
|
|
387
|
+
* @param fn - Function to compute default from left value
|
|
388
|
+
* @returns A curried function that extracts the value
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```ts
|
|
392
|
+
* pipe(
|
|
393
|
+
* right(42),
|
|
394
|
+
* unwrapOrElse(() => 0)
|
|
395
|
+
* ) // => 42
|
|
396
|
+
*
|
|
397
|
+
* pipe(
|
|
398
|
+
* left("error"),
|
|
399
|
+
* unwrapOrElse(e => e.length)
|
|
400
|
+
* ) // => 5
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
const unwrapOrElse = (fn) => (either) => either.right ? either.value : fn(either.value);
|
|
404
|
+
/**
|
|
405
|
+
* Pattern match on an Either with handlers for both cases.
|
|
406
|
+
*
|
|
407
|
+
* Curried for use with pipe().
|
|
408
|
+
*
|
|
409
|
+
* @param handlers - Object with left and right handler functions
|
|
410
|
+
* @returns A curried function that pattern matches
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```ts
|
|
414
|
+
* pipe(
|
|
415
|
+
* right(42),
|
|
416
|
+
* match({
|
|
417
|
+
* left: e => `Error: ${e}`,
|
|
418
|
+
* right: x => `Success: ${x}`
|
|
419
|
+
* })
|
|
420
|
+
* ) // => "Success: 42"
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
const match = (handlers) => (either) => either.right ? handlers.right(either.value) : handlers.left(either.value);
|
|
424
|
+
/**
|
|
425
|
+
* Convert a Result to an Either.
|
|
426
|
+
* Result's ok becomes right, err becomes left.
|
|
427
|
+
*
|
|
428
|
+
* @param result - The Result to convert
|
|
429
|
+
* @returns An Either with the same semantics
|
|
430
|
+
*
|
|
431
|
+
* @example
|
|
432
|
+
* ```ts
|
|
433
|
+
* fromResult(Result.ok(42)) // => right(42)
|
|
434
|
+
* fromResult(Result.err("error")) // => left("error")
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
437
|
+
const fromResult = (result) => result.ok ? right(result.value) : left(result.error);
|
|
438
|
+
/**
|
|
439
|
+
* Convert an Either to a Result.
|
|
440
|
+
* Either's right becomes ok, left becomes err.
|
|
441
|
+
*
|
|
442
|
+
* Curried for use with pipe().
|
|
443
|
+
*
|
|
444
|
+
* @param either - The Either to convert
|
|
445
|
+
* @returns A Result with error semantics
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* ```ts
|
|
449
|
+
* pipe(
|
|
450
|
+
* right(42),
|
|
451
|
+
* toResult
|
|
452
|
+
* ) // => Result.ok(42)
|
|
453
|
+
*
|
|
454
|
+
* pipe(
|
|
455
|
+
* left("error"),
|
|
456
|
+
* toResult
|
|
457
|
+
* ) // => Result.err("error")
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
const toResult = (either) => either.right ? Result.ok(either.value) : Result.err(either.value);
|
|
461
|
+
/**
|
|
462
|
+
* Convert an Option to an Either.
|
|
463
|
+
* Option's some becomes right, none becomes left with onNone callback.
|
|
464
|
+
*
|
|
465
|
+
* @param option - The Option to convert
|
|
466
|
+
* @param onNone - Function to produce left value for none
|
|
467
|
+
* @returns An Either
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* ```ts
|
|
471
|
+
* fromOption(Option.some(42), () => "not found") // => right(42)
|
|
472
|
+
* fromOption(Option.none(), () => "not found") // => left("not found")
|
|
473
|
+
* ```
|
|
474
|
+
*/
|
|
475
|
+
const fromOption = (option, onNone) => option.some ? right(option.value) : left(onNone());
|
|
476
|
+
/**
|
|
477
|
+
* Convert an Either to an Option.
|
|
478
|
+
* Either's right becomes some, left is discarded.
|
|
479
|
+
*
|
|
480
|
+
* Curried for use with pipe().
|
|
481
|
+
*
|
|
482
|
+
* @param either - The Either to convert
|
|
483
|
+
* @returns An Option (left value is discarded)
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* ```ts
|
|
487
|
+
* pipe(
|
|
488
|
+
* right(42),
|
|
489
|
+
* toOption
|
|
490
|
+
* ) // => Option.some(42)
|
|
491
|
+
*
|
|
492
|
+
* pipe(
|
|
493
|
+
* left("error"),
|
|
494
|
+
* toOption
|
|
495
|
+
* ) // => Option.none()
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
498
|
+
const toOption = (either) => either.right ? Option.some(either.value) : Option.none();
|
|
499
|
+
/**
|
|
500
|
+
* Convert a nullable value to an Either.
|
|
501
|
+
* null/undefined becomes left with onNull callback, otherwise right.
|
|
502
|
+
*
|
|
503
|
+
* @param value - The nullable value
|
|
504
|
+
* @param onNull - Function to produce left value for null/undefined
|
|
505
|
+
* @returns An Either
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* ```ts
|
|
509
|
+
* fromNullable(42, () => "not found") // => right(42)
|
|
510
|
+
* fromNullable(null, () => "not found") // => left("not found")
|
|
511
|
+
* fromNullable(undefined, () => "not found") // => left("not found")
|
|
512
|
+
* ```
|
|
513
|
+
*/
|
|
514
|
+
const fromNullable = (value, onNull) => value === null || value === void 0 ? left(onNull()) : right(value);
|
|
515
|
+
/**
|
|
516
|
+
* Create an Either from a predicate.
|
|
517
|
+
* Predicate success becomes right, failure becomes left with onFail callback.
|
|
518
|
+
*
|
|
519
|
+
* @param value - The value to test
|
|
520
|
+
* @param predicate - Function to test the value
|
|
521
|
+
* @param onFail - Function to produce left value on failure
|
|
522
|
+
* @returns An Either
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```ts
|
|
526
|
+
* fromPredicate(5, x => x > 3, x => `${x} is too small`)
|
|
527
|
+
* // => right(5)
|
|
528
|
+
*
|
|
529
|
+
* fromPredicate(2, x => x > 3, x => `${x} is too small`)
|
|
530
|
+
* // => left("2 is too small")
|
|
531
|
+
* ```
|
|
532
|
+
*/
|
|
533
|
+
const fromPredicate = (value, predicate, onFail) => predicate(value) ? right(value) : left(onFail(value));
|
|
534
|
+
/**
|
|
535
|
+
* Either namespace containing all utility functions for working with Either types.
|
|
536
|
+
*
|
|
537
|
+
* Either represents a value that can be one of two types: Left<L> or Right<R>.
|
|
538
|
+
* By convention, Right is the "success" or preferred path, while Left represents
|
|
539
|
+
* an alternative outcome (not necessarily an error, unlike Result).
|
|
540
|
+
*
|
|
541
|
+
* Use Either when both outcomes are valid and meaningful, not just success/failure.
|
|
542
|
+
* For error handling, prefer Result instead.
|
|
543
|
+
*
|
|
544
|
+
* @see {@link Result} for success/error semantics
|
|
545
|
+
* @see {@link Option} for presence/absence semantics
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```ts
|
|
549
|
+
* import { Either, pipe } from '@repo/std'
|
|
550
|
+
* import type { Either as EitherType } from '@repo/std'
|
|
551
|
+
*
|
|
552
|
+
* // Either for branching logic (cache vs fresh data)
|
|
553
|
+
* const fetchOrCache = (id: number): EitherType<CachedData, FreshData> =>
|
|
554
|
+
* cache.has(id) ? Either.left(cache.get(id)) : Either.right(fetch(id))
|
|
555
|
+
*
|
|
556
|
+
* const result = pipe(
|
|
557
|
+
* fetchOrCache(1),
|
|
558
|
+
* Either.map(data => data.value),
|
|
559
|
+
* Either.unwrapOr(defaultValue)
|
|
560
|
+
* )
|
|
561
|
+
*
|
|
562
|
+
* // Async example
|
|
563
|
+
* const processed = await pipe(
|
|
564
|
+
* Either.right(userId),
|
|
565
|
+
* Either.map(async id => await fetchUser(id)),
|
|
566
|
+
* Either.flatMap(async user => Either.right(await enrichUser(user)))
|
|
567
|
+
* )
|
|
568
|
+
* ```
|
|
569
|
+
*/
|
|
570
|
+
const Either = {
|
|
571
|
+
left,
|
|
572
|
+
right,
|
|
573
|
+
isLeft,
|
|
574
|
+
isRight,
|
|
575
|
+
map,
|
|
576
|
+
mapLeft,
|
|
577
|
+
bimap,
|
|
578
|
+
flatMap,
|
|
579
|
+
tap,
|
|
580
|
+
tapLeft,
|
|
581
|
+
orElse,
|
|
582
|
+
swap,
|
|
583
|
+
filter,
|
|
584
|
+
all,
|
|
585
|
+
unwrapOr,
|
|
586
|
+
unwrapOrElse,
|
|
587
|
+
match,
|
|
588
|
+
fromResult,
|
|
589
|
+
toResult,
|
|
590
|
+
fromOption,
|
|
591
|
+
toOption,
|
|
592
|
+
fromNullable,
|
|
593
|
+
fromPredicate
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
//#endregion
|
|
597
|
+
export { Either as t };
|
|
598
|
+
//# sourceMappingURL=either-CnOBUH7a.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"either-CnOBUH7a.mjs","names":["mapped"],"sources":["../src/either/either.ts"],"sourcesContent":["import { Option } from \"../option\"\nimport type { Option as OptionType } from \"../option/option.types\"\nimport { Result } from \"../result\"\nimport type { Result as ResultType } from \"../result/result.types\"\nimport type {\n AllArrayReturn,\n AllObjectReturn,\n Either as EitherType,\n EitherBimap,\n EitherFilter,\n EitherFlatMap,\n EitherMap,\n EitherMapLeft,\n EitherOrElse,\n EitherTap,\n EitherTapLeft,\n} from \"./either.types\"\n\n// ============================================================================\n// Constructors\n// ============================================================================\n\n/**\n * Create a right Either value (success/preferred path).\n *\n * By convention, right represents the correct/preferred outcome.\n *\n * @param value - The right value\n * @returns An Either in the right state\n *\n * @example\n * ```ts\n * const result = right(42)\n * // => { right: true, value: 42 }\n * ```\n */\nexport const right = <R>(value: R): EitherType<never, R> => ({\n right: true,\n value,\n // oxlint-disable-next-line require-yield\n *[Symbol.iterator](): Generator<never, R, unknown> {\n return value\n },\n})\n\n/**\n * Create a left Either value (alternative path).\n *\n * By convention, left represents the alternative outcome.\n * Unlike Result's err(), left doesn't imply an error.\n *\n * @param value - The left value\n * @returns An Either in the left state\n *\n * @example\n * ```ts\n * const cached = left({ source: \"cache\", data: cachedValue })\n * // => { right: false, value: { source: \"cache\", data: cachedValue } }\n * ```\n */\nexport const left = <L>(value: L): EitherType<L, never> => ({\n right: false,\n value,\n *[Symbol.iterator](): Generator<L, never, unknown> {\n yield value\n throw new Error(\"Unreachable: Do should short-circuit on left\")\n },\n})\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard to check if an Either is in the right state.\n *\n * @param either - The Either to check\n * @returns True if right, false if left (with type narrowing)\n *\n * @example\n * ```ts\n * const either = right(42)\n * if (isRight(either)) {\n * console.log(either.value) // Type: number\n * }\n * ```\n */\nexport const isRight = <L, R>(either: EitherType<L, R>): either is Extract<EitherType<L, R>, { right: true }> =>\n either.right\n\n/**\n * Type guard to check if an Either is in the left state.\n *\n * @param either - The Either to check\n * @returns True if left, false if right (with type narrowing)\n *\n * @example\n * ```ts\n * const either = left(\"error\")\n * if (isLeft(either)) {\n * console.log(either.value) // Type: string\n * }\n * ```\n */\nexport const isLeft = <L, R>(either: EitherType<L, R>): either is Extract<EitherType<L, R>, { right: false }> =>\n !either.right\n\n// ============================================================================\n// Right-biased Transformations\n// ============================================================================\n\n/**\n * Transform the right value of an Either.\n * Left values pass through unchanged.\n *\n * Curried for use with pipe(). Supports async functions.\n *\n * @param fn - Transformation function for right values\n * @returns A curried function that transforms an Either\n *\n * @example\n * ```ts\n * // Sync usage\n * pipe(\n * right(5),\n * map(x => x * 2)\n * ) // => right(10)\n *\n * pipe(\n * left(\"error\"),\n * map(x => x * 2)\n * ) // => left(\"error\")\n *\n * // Async usage\n * await pipe(\n * right(userId),\n * map(async id => await fetchUser(id))\n * ) // => Promise<Either<L, User>>\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const map: EitherMap = (fn) => (either) => {\n if (!either.right) return either as any\n const mapped = fn(either.value)\n if (mapped instanceof Promise) {\n return mapped.then(right) as any\n }\n return right(mapped) as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n\n/**\n * Transform the left value of an Either.\n * Right values pass through unchanged.\n *\n * Curried for use with pipe(). Supports async functions.\n *\n * @param fn - Transformation function for left values\n * @returns A curried function that transforms an Either\n *\n * @example\n * ```ts\n * pipe(\n * left(\"error\"),\n * mapLeft(e => e.toUpperCase())\n * ) // => left(\"ERROR\")\n *\n * pipe(\n * right(42),\n * mapLeft(e => e.toUpperCase())\n * ) // => right(42)\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const mapLeft: EitherMapLeft = (fn) => (either) => {\n if (either.right) return either as any\n const mapped = fn(either.value)\n if (mapped instanceof Promise) {\n return mapped.then(left) as any\n }\n return left(mapped) as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Transform both sides of an Either simultaneously.\n * Unique to Either - not available in Result/Option.\n *\n * Curried for use with pipe(). Supports async functions.\n *\n * @param fnLeft - Transformation function for left values\n * @param fnRight - Transformation function for right values\n * @returns A curried function that transforms an Either\n *\n * @example\n * ```ts\n * pipe(\n * right(5),\n * bimap(\n * e => e.toUpperCase(),\n * x => x * 2\n * )\n * ) // => right(10)\n *\n * pipe(\n * left(\"error\"),\n * bimap(\n * e => e.toUpperCase(),\n * x => x * 2\n * )\n * ) // => left(\"ERROR\")\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const bimap: EitherBimap = (fnLeft, fnRight) => (either) => {\n if (either.right) {\n const mapped = fnRight(either.value)\n if (mapped instanceof Promise) {\n return mapped.then(right) as any\n }\n return right(mapped) as any\n }\n const mapped = fnLeft(either.value)\n if (mapped instanceof Promise) {\n return mapped.then(left) as any\n }\n return left(mapped) as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Chain operations that return Either.\n * Left values short-circuit the chain.\n *\n * Curried for use with pipe(). Supports async functions.\n * Combines left error unions.\n *\n * @param fn - Function that returns an Either\n * @returns A curried function that chains Eithers\n *\n * @example\n * ```ts\n * // Sync usage\n * pipe(\n * right(5),\n * flatMap(x => right(x * 2)),\n * flatMap(x => right(x + 1))\n * ) // => right(11)\n *\n * pipe(\n * right(5),\n * flatMap(x => left(\"error\")),\n * flatMap(x => right(x + 1)) // Not executed\n * ) // => left(\"error\")\n *\n * // Async usage\n * await pipe(\n * right(userId),\n * flatMap(async id => right(await fetchUser(id))),\n * flatMap(async user => right(await enrichProfile(user)))\n * ) // => Promise<Either<L, EnrichedUser>>\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const flatMap: EitherFlatMap = (fn) => (either) => {\n if (!either.right) return either as any\n const result = fn(either.value)\n return result as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Execute a side effect on right values without modifying the Either.\n * Left values pass through unchanged.\n *\n * Curried for use with pipe(). Supports async functions.\n *\n * @param fn - Side effect function for right values\n * @returns A curried function that executes side effects\n *\n * @example\n * ```ts\n * pipe(\n * right(42),\n * tap(x => console.log(x)), // Logs: 42\n * map(x => x * 2)\n * ) // => right(84)\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const tap: EitherTap = (fn) => (either) => {\n if (!either.right) return either as any\n const result = fn(either.value)\n if (result instanceof Promise) {\n return result.then(() => either) as any\n }\n return either as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Execute a side effect on left values without modifying the Either.\n * Right values pass through unchanged.\n *\n * Curried for use with pipe(). Supports async functions.\n *\n * @param fn - Side effect function for left values\n * @returns A curried function that executes side effects\n *\n * @example\n * ```ts\n * pipe(\n * left(\"error\"),\n * tapLeft(e => console.error(e)), // Logs: error\n * mapLeft(e => e.toUpperCase())\n * ) // => left(\"ERROR\")\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const tapLeft: EitherTapLeft = (fn) => (either) => {\n if (either.right) return either as any\n const result = fn(either.value)\n if (result instanceof Promise) {\n return result.then(() => either) as any\n }\n return either as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n// ============================================================================\n// Recovery/Fallback\n// ============================================================================\n\n/**\n * Recover from a left value by providing an alternative Either.\n * Right values pass through unchanged.\n *\n * Curried for use with pipe(). Supports async functions.\n * Combines right value unions.\n *\n * @param fn - Function that returns an alternative Either\n * @returns A curried function that recovers from left\n *\n * @example\n * ```ts\n * pipe(\n * left(\"error\"),\n * orElse(() => right(42))\n * ) // => right(42)\n *\n * pipe(\n * right(10),\n * orElse(() => right(42))\n * ) // => right(10)\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const orElse: EitherOrElse = (fn) => (either) => {\n if (either.right) return either as any\n const result = fn(either.value)\n return result as any\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Swap left and right values.\n * Unique to Either - not available in Result/Option.\n *\n * Curried for use with pipe().\n *\n * @returns A curried function that swaps left and right\n *\n * @example\n * ```ts\n * pipe(\n * left(\"error\"),\n * swap()\n * ) // => right(\"error\")\n *\n * pipe(\n * right(42),\n * swap()\n * ) // => left(42)\n * ```\n */\nexport const swap =\n <L, R>() =>\n (either: EitherType<L, R>): EitherType<R, L> =>\n either.right ? left(either.value) : right(either.value)\n\n// ============================================================================\n// Filtering\n// ============================================================================\n\n/**\n * Filter right values based on a predicate.\n * Failed predicates convert to left with onFail callback.\n * Left values pass through unchanged.\n *\n * Curried for use with pipe().\n *\n * @param predicate - Function to test right values\n * @param onFail - Function to produce left value on failure\n * @returns A curried function that filters an Either\n *\n * @example\n * ```ts\n * pipe(\n * right(5),\n * filter(x => x > 3, x => `${x} is too small`)\n * ) // => right(5)\n *\n * pipe(\n * right(2),\n * filter(x => x > 3, x => `${x} is too small`)\n * ) // => left(\"2 is too small\")\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const filter: EitherFilter = (predicate, onFail) => (either) => {\n if (!either.right) return either as any\n return predicate(either.value) ? (either as any) : left(onFail(either.value))\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n// ============================================================================\n// Combinators\n// ============================================================================\n\n/**\n * Combine multiple Eithers into a single Either.\n * Short-circuits on the first left value.\n *\n * Supports both array and object inputs with full type preservation.\n *\n * @param eithers - Array or object of Eithers to combine\n * @returns Either with all right values or first left\n *\n * @example\n * ```ts\n * // Array form (with const assertion for tuple typing)\n * all([right(1), right(\"hello\")] as const)\n * // => right([1, \"hello\"])\n *\n * all([right(1), left(\"error\"), right(3)])\n * // => left(\"error\")\n *\n * // Object form\n * all({ a: right(1), b: right(\"hello\") })\n * // => right({ a: 1, b: \"hello\" })\n * ```\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-member-access, strict-boolean-expressions, no-unsafe-assignment -- Required for handling union types in overloaded function */\nexport function all<const T extends readonly EitherType<unknown, unknown>[]>(eithers: T): AllArrayReturn<T>\nexport function all<const T extends Record<string, EitherType<unknown, unknown>>>(eithers: T): AllObjectReturn<T>\nexport function all(eithers: any): any {\n // Array case\n if (Array.isArray(eithers)) {\n const values: unknown[] = []\n for (const either of eithers) {\n if (!either.right) return either\n values.push(either.value)\n }\n return right(values)\n }\n\n // Object case\n const result: Record<string, unknown> = {}\n for (const key in eithers) {\n const either = eithers[key]\n if (!either.right) return either\n result[key] = either.value\n }\n return right(result)\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-member-access, strict-boolean-expressions, no-unsafe-assignment */\n// ============================================================================\n// Extraction\n// ============================================================================\n\n/**\n * Extract the right value or return a default.\n *\n * Curried for use with pipe().\n *\n * @param defaultValue - Value to return if Either is left\n * @returns A curried function that extracts the value\n *\n * @example\n * ```ts\n * pipe(\n * right(42),\n * unwrapOr(0)\n * ) // => 42\n *\n * pipe(\n * left(\"error\"),\n * unwrapOr(0)\n * ) // => 0\n * ```\n */\nexport const unwrapOr =\n <R>(defaultValue: R) =>\n <L>(either: EitherType<L, R>): R =>\n either.right ? either.value : defaultValue\n\n/**\n * Extract the right value or compute one from the left value.\n *\n * Curried for use with pipe().\n *\n * @param fn - Function to compute default from left value\n * @returns A curried function that extracts the value\n *\n * @example\n * ```ts\n * pipe(\n * right(42),\n * unwrapOrElse(() => 0)\n * ) // => 42\n *\n * pipe(\n * left(\"error\"),\n * unwrapOrElse(e => e.length)\n * ) // => 5\n * ```\n */\nexport const unwrapOrElse =\n <L, R>(fn: (left: L) => R) =>\n (either: EitherType<L, R>): R =>\n either.right ? either.value : fn(either.value)\n\n/**\n * Pattern match on an Either with handlers for both cases.\n *\n * Curried for use with pipe().\n *\n * @param handlers - Object with left and right handler functions\n * @returns A curried function that pattern matches\n *\n * @example\n * ```ts\n * pipe(\n * right(42),\n * match({\n * left: e => `Error: ${e}`,\n * right: x => `Success: ${x}`\n * })\n * ) // => \"Success: 42\"\n * ```\n */\nexport const match =\n <L, R, U>(handlers: { left: (value: L) => U; right: (value: R) => U }) =>\n (either: EitherType<L, R>): U =>\n either.right ? handlers.right(either.value) : handlers.left(either.value)\n\n// ============================================================================\n// Conversions\n// ============================================================================\n\n/**\n * Convert a Result to an Either.\n * Result's ok becomes right, err becomes left.\n *\n * @param result - The Result to convert\n * @returns An Either with the same semantics\n *\n * @example\n * ```ts\n * fromResult(Result.ok(42)) // => right(42)\n * fromResult(Result.err(\"error\")) // => left(\"error\")\n * ```\n */\nexport const fromResult = <R, E>(result: ResultType<R, E>): EitherType<E, R> =>\n result.ok ? right(result.value) : left(result.error)\n\n/**\n * Convert an Either to a Result.\n * Either's right becomes ok, left becomes err.\n *\n * Curried for use with pipe().\n *\n * @param either - The Either to convert\n * @returns A Result with error semantics\n *\n * @example\n * ```ts\n * pipe(\n * right(42),\n * toResult\n * ) // => Result.ok(42)\n *\n * pipe(\n * left(\"error\"),\n * toResult\n * ) // => Result.err(\"error\")\n * ```\n */\nexport const toResult = <L, R>(either: EitherType<L, R>): ResultType<R, L> =>\n either.right ? Result.ok(either.value) : Result.err(either.value)\n\n/**\n * Convert an Option to an Either.\n * Option's some becomes right, none becomes left with onNone callback.\n *\n * @param option - The Option to convert\n * @param onNone - Function to produce left value for none\n * @returns An Either\n *\n * @example\n * ```ts\n * fromOption(Option.some(42), () => \"not found\") // => right(42)\n * fromOption(Option.none(), () => \"not found\") // => left(\"not found\")\n * ```\n */\nexport const fromOption = <R, L>(option: OptionType<R>, onNone: () => L): EitherType<L, R> =>\n option.some ? right(option.value) : left(onNone())\n\n/**\n * Convert an Either to an Option.\n * Either's right becomes some, left is discarded.\n *\n * Curried for use with pipe().\n *\n * @param either - The Either to convert\n * @returns An Option (left value is discarded)\n *\n * @example\n * ```ts\n * pipe(\n * right(42),\n * toOption\n * ) // => Option.some(42)\n *\n * pipe(\n * left(\"error\"),\n * toOption\n * ) // => Option.none()\n * ```\n */\nexport const toOption = <L, R>(either: EitherType<L, R>): OptionType<R> =>\n either.right ? Option.some(either.value) : Option.none<R>()\n\n/**\n * Convert a nullable value to an Either.\n * null/undefined becomes left with onNull callback, otherwise right.\n *\n * @param value - The nullable value\n * @param onNull - Function to produce left value for null/undefined\n * @returns An Either\n *\n * @example\n * ```ts\n * fromNullable(42, () => \"not found\") // => right(42)\n * fromNullable(null, () => \"not found\") // => left(\"not found\")\n * fromNullable(undefined, () => \"not found\") // => left(\"not found\")\n * ```\n */\nexport const fromNullable = <R, L>(value: R | null | undefined, onNull: () => L): EitherType<L, R> =>\n value === null || value === undefined ? left(onNull()) : right(value)\n\n/**\n * Create an Either from a predicate.\n * Predicate success becomes right, failure becomes left with onFail callback.\n *\n * @param value - The value to test\n * @param predicate - Function to test the value\n * @param onFail - Function to produce left value on failure\n * @returns An Either\n *\n * @example\n * ```ts\n * fromPredicate(5, x => x > 3, x => `${x} is too small`)\n * // => right(5)\n *\n * fromPredicate(2, x => x > 3, x => `${x} is too small`)\n * // => left(\"2 is too small\")\n * ```\n */\nexport const fromPredicate = <R, L>(\n value: R,\n predicate: (value: R) => boolean,\n onFail: (value: R) => L,\n): EitherType<L, R> => (predicate(value) ? right(value) : left(onFail(value)))\n\n// ============================================================================\n// Namespace Export\n// ============================================================================\n\n/**\n * Either namespace containing all utility functions for working with Either types.\n *\n * Either represents a value that can be one of two types: Left<L> or Right<R>.\n * By convention, Right is the \"success\" or preferred path, while Left represents\n * an alternative outcome (not necessarily an error, unlike Result).\n *\n * Use Either when both outcomes are valid and meaningful, not just success/failure.\n * For error handling, prefer Result instead.\n *\n * @see {@link Result} for success/error semantics\n * @see {@link Option} for presence/absence semantics\n *\n * @example\n * ```ts\n * import { Either, pipe } from '@repo/std'\n * import type { Either as EitherType } from '@repo/std'\n *\n * // Either for branching logic (cache vs fresh data)\n * const fetchOrCache = (id: number): EitherType<CachedData, FreshData> =>\n * cache.has(id) ? Either.left(cache.get(id)) : Either.right(fetch(id))\n *\n * const result = pipe(\n * fetchOrCache(1),\n * Either.map(data => data.value),\n * Either.unwrapOr(defaultValue)\n * )\n *\n * // Async example\n * const processed = await pipe(\n * Either.right(userId),\n * Either.map(async id => await fetchUser(id)),\n * Either.flatMap(async user => Either.right(await enrichUser(user)))\n * )\n * ```\n */\nexport const Either = {\n // Constructors\n left,\n right,\n\n // Type guards\n isLeft,\n isRight,\n\n // Transformations\n map,\n mapLeft,\n bimap,\n flatMap,\n tap,\n tapLeft,\n\n // Recovery\n orElse,\n swap,\n\n // Filtering\n filter,\n\n // Combinators\n all,\n\n // Extraction\n unwrapOr,\n unwrapOrElse,\n match,\n\n // Conversions\n fromResult,\n toResult,\n fromOption,\n toOption,\n fromNullable,\n fromPredicate,\n} as const\n"],"mappings":"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"}
|