@shirudo/result 0.0.1 → 0.0.3
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 +99 -1
- package/dist/index.cjs +487 -942
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +390 -807
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +390 -807
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +485 -942
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -10
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
//#region src/pipeable.ts
|
|
2
|
+
//#region src/core/pipeable.ts
|
|
3
3
|
var Pipeable = class {
|
|
4
4
|
pipe(...ops) {
|
|
5
5
|
let ret = this;
|
|
@@ -14,19 +14,13 @@ var Pipeable = class {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
//#endregion
|
|
17
|
-
//#region src/
|
|
18
|
-
function isResult(value) {
|
|
19
|
-
return typeof value === "object" && value !== null && "isOk" in value && typeof value.isOk === "function" && "isErr" in value && typeof value.isErr === "function";
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
//#endregion
|
|
23
|
-
//#region src/matcher.ts
|
|
17
|
+
//#region src/core/matcher.ts
|
|
24
18
|
/**
|
|
25
|
-
* Matcher
|
|
19
|
+
* Matcher für Err-Values (liefert einen beliebigen Return-Type, z.B. string messages).
|
|
26
20
|
*
|
|
27
21
|
* - `.when(Ctor, handler)` matched via `instanceof`
|
|
28
|
-
* - `.whenGuard(guard, handler)` matched via
|
|
29
|
-
* - `.run()`
|
|
22
|
+
* - `.whenGuard(guard, handler)` matched via Type-Guard
|
|
23
|
+
* - `.run()` ist nur erlaubt, wenn alle Error-Cases behandelt wurden (`E` wurde zu `never` reduziert)
|
|
30
24
|
*/
|
|
31
25
|
var ErrorMatchBuilder = class ErrorMatchBuilder {
|
|
32
26
|
#error;
|
|
@@ -58,12 +52,15 @@ var ErrorMatchBuilder = class ErrorMatchBuilder {
|
|
|
58
52
|
throw this.#error;
|
|
59
53
|
}
|
|
60
54
|
};
|
|
55
|
+
function isResult$1(value) {
|
|
56
|
+
return typeof value === "object" && value !== null && "isOk" in value && typeof value.isOk === "function" && "isErr" in value && typeof value.isErr === "function";
|
|
57
|
+
}
|
|
61
58
|
/**
|
|
62
|
-
* Matcher
|
|
59
|
+
* Matcher für `Result`-Errors, der immer wieder ein `Result` zurückgibt.
|
|
63
60
|
*
|
|
64
|
-
*
|
|
65
|
-
* -
|
|
66
|
-
* -
|
|
61
|
+
* Handler dürfen:
|
|
62
|
+
* - ein `Result` zurückgeben (wird direkt returned)
|
|
63
|
+
* - einen Error-Wert zurückgeben (wird automatisch zu `Err(error)` gewrappt)
|
|
67
64
|
*/
|
|
68
65
|
var ErrMatchBuilder = class ErrMatchBuilder {
|
|
69
66
|
#makeErr;
|
|
@@ -84,7 +81,7 @@ var ErrMatchBuilder = class ErrMatchBuilder {
|
|
|
84
81
|
if (this.#resolved) return this;
|
|
85
82
|
if (this.#error instanceof ctor) {
|
|
86
83
|
const out = handler(this.#error);
|
|
87
|
-
const resolved = isResult(out) ? out : this.#makeErr(out);
|
|
84
|
+
const resolved = isResult$1(out) ? out : this.#makeErr(out);
|
|
88
85
|
return new ErrMatchBuilder(this.#makeErr, this.#error, resolved);
|
|
89
86
|
}
|
|
90
87
|
return this;
|
|
@@ -94,7 +91,7 @@ var ErrMatchBuilder = class ErrMatchBuilder {
|
|
|
94
91
|
const error = this.#error;
|
|
95
92
|
if (guard(error)) {
|
|
96
93
|
const out = handler(error);
|
|
97
|
-
const resolved = isResult(out) ? out : this.#makeErr(out);
|
|
94
|
+
const resolved = isResult$1(out) ? out : this.#makeErr(out);
|
|
98
95
|
return new ErrMatchBuilder(this.#makeErr, this.#error, resolved);
|
|
99
96
|
}
|
|
100
97
|
return this;
|
|
@@ -102,688 +99,19 @@ var ErrMatchBuilder = class ErrMatchBuilder {
|
|
|
102
99
|
otherwise(handler) {
|
|
103
100
|
if (this.#resolved) return this.#resolved;
|
|
104
101
|
const out = handler(this.#error);
|
|
105
|
-
return isResult(out) ? out : this.#makeErr(out);
|
|
102
|
+
return isResult$1(out) ? out : this.#makeErr(out);
|
|
106
103
|
}
|
|
107
104
|
run() {
|
|
108
105
|
if (this.#resolved) return this.#resolved;
|
|
109
106
|
throw this.#error;
|
|
110
107
|
}
|
|
111
108
|
};
|
|
112
|
-
/**
|
|
113
|
-
* Universal matcher for `Result` (Ok + Err in a single chain).
|
|
114
|
-
*
|
|
115
|
-
* - `.err(Ctor, handler)` matched via `instanceof`
|
|
116
|
-
* - `.errVal(value, handler)` matched via `Object.is`
|
|
117
|
-
* - `.ok(handler)` defines the success branch
|
|
118
|
-
* - `.run()` is only allowed after `.ok()` is set
|
|
119
|
-
*
|
|
120
|
-
* Lazy: if the Result is `Ok`, Err cases are not evaluated in `.run()`.
|
|
121
|
-
*/
|
|
122
|
-
var ResultMatchBuilder = class ResultMatchBuilder {
|
|
123
|
-
#result;
|
|
124
|
-
#errCases;
|
|
125
|
-
#okHandler;
|
|
126
|
-
constructor(result, errCases = [], okHandler) {
|
|
127
|
-
this.#result = result;
|
|
128
|
-
this.#errCases = Object.freeze([...errCases]);
|
|
129
|
-
this.#okHandler = okHandler;
|
|
130
|
-
Object.freeze(this);
|
|
131
|
-
}
|
|
132
|
-
static fromResult(result) {
|
|
133
|
-
return new ResultMatchBuilder(result);
|
|
134
|
-
}
|
|
135
|
-
err(ctor, handler) {
|
|
136
|
-
return new ResultMatchBuilder(this.#result, [...this.#errCases, {
|
|
137
|
-
kind: "ctor",
|
|
138
|
-
ctor,
|
|
139
|
-
handler
|
|
140
|
-
}], this.#okHandler);
|
|
141
|
-
}
|
|
142
|
-
errVal(value, handler) {
|
|
143
|
-
return new ResultMatchBuilder(this.#result, [...this.#errCases, {
|
|
144
|
-
kind: "val",
|
|
145
|
-
value,
|
|
146
|
-
handler
|
|
147
|
-
}], this.#okHandler);
|
|
148
|
-
}
|
|
149
|
-
ok(handler) {
|
|
150
|
-
return new ResultMatchBuilder(this.#result, this.#errCases, handler);
|
|
151
|
-
}
|
|
152
|
-
run() {
|
|
153
|
-
const result = this.#result;
|
|
154
|
-
if (result.isOk()) {
|
|
155
|
-
const okHandler = this.#okHandler;
|
|
156
|
-
if (!okHandler) throw new Error("ResultMatchBuilder.run() requires an ok() handler.");
|
|
157
|
-
return okHandler(result.value);
|
|
158
|
-
}
|
|
159
|
-
if (result.isErr()) {
|
|
160
|
-
const error = result.error;
|
|
161
|
-
for (const c of this.#errCases) {
|
|
162
|
-
if (c.kind === "ctor") {
|
|
163
|
-
if (error instanceof c.ctor) return c.handler(error);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (Object.is(error, c.value)) return c.handler(error);
|
|
167
|
-
}
|
|
168
|
-
throw error;
|
|
169
|
-
}
|
|
170
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
//#endregion
|
|
175
|
-
//#region src/conversions/fromNullable.ts
|
|
176
|
-
/**
|
|
177
|
-
* Converts `null | undefined` to `Err`, everything else to `Ok`.
|
|
178
|
-
*
|
|
179
|
-
* **Type Safety**: The type assertion `as NonNullable<T>` is safe,
|
|
180
|
-
* as the runtime check guarantees that the value is not null/undefined.
|
|
181
|
-
*
|
|
182
|
-
* @param value The value to check
|
|
183
|
-
* @param error The error to use if value is null/undefined
|
|
184
|
-
* @returns An Ok Result with the NonNullable value, or an Err Result with the error
|
|
185
|
-
*
|
|
186
|
-
* @example
|
|
187
|
-
* ```ts
|
|
188
|
-
* fromNullable(user, 'User not found')
|
|
189
|
-
* // Ok(user) or Err('User not found')
|
|
190
|
-
* ```
|
|
191
|
-
*/
|
|
192
|
-
function fromNullable(value, error) {
|
|
193
|
-
if (value === null || value === void 0) return Result.err(error);
|
|
194
|
-
return Result.ok(value);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
//#endregion
|
|
198
|
-
//#region src/conversions/fromPromise.ts
|
|
199
|
-
async function fromPromise(promise, errorMapper) {
|
|
200
|
-
try {
|
|
201
|
-
const value = await promise;
|
|
202
|
-
return Result.ok(value);
|
|
203
|
-
} catch (error) {
|
|
204
|
-
try {
|
|
205
|
-
return Result.err(errorMapper ? errorMapper(error) : error);
|
|
206
|
-
} catch (mapperError) {
|
|
207
|
-
return Result.err(mapperError);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
//#endregion
|
|
213
|
-
//#region src/conversions/try.ts
|
|
214
|
-
/**
|
|
215
|
-
* Executes a function and catches exceptions.
|
|
216
|
-
*
|
|
217
|
-
* @param fn The function to execute
|
|
218
|
-
* @returns An Ok Result with the return value, or an Err Result with the caught exception
|
|
219
|
-
*
|
|
220
|
-
* @example
|
|
221
|
-
* ```ts
|
|
222
|
-
* const result = tryFn(() => JSON.parse(input));
|
|
223
|
-
* // Ok(parsed) or Err(SyntaxError)
|
|
224
|
-
* ```
|
|
225
|
-
*/
|
|
226
|
-
function tryFn(fn) {
|
|
227
|
-
try {
|
|
228
|
-
return Result.ok(fn());
|
|
229
|
-
} catch (error) {
|
|
230
|
-
return Result.err(error);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
//#endregion
|
|
235
|
-
//#region src/conversions/toPromise.ts
|
|
236
|
-
/**
|
|
237
|
-
* Converts a Result to a Promise.
|
|
238
|
-
* Ok → resolves with the value, Err → rejects with the error
|
|
239
|
-
*
|
|
240
|
-
* @param result The Result to convert
|
|
241
|
-
* @returns A Promise that resolves with the value if Ok, or rejects with the error if Err
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* ```ts
|
|
245
|
-
* const result = ok(42);
|
|
246
|
-
* const promise = toPromise(result);
|
|
247
|
-
* const value = await promise; // 42
|
|
248
|
-
* ```
|
|
249
|
-
*/
|
|
250
|
-
function toPromise(result) {
|
|
251
|
-
if (result.isOk()) return Promise.resolve(result.value);
|
|
252
|
-
return Promise.reject(result.error);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
//#endregion
|
|
256
|
-
//#region src/conversions/toNullable.ts
|
|
257
|
-
/**
|
|
258
|
-
* Converts a Result to `T | null`.
|
|
259
|
-
* Ok → returns the value, Err → returns null
|
|
260
|
-
*
|
|
261
|
-
* @param result The Result to convert
|
|
262
|
-
* @returns The value if Ok, or null if Err
|
|
263
|
-
*
|
|
264
|
-
* @example
|
|
265
|
-
* ```ts
|
|
266
|
-
* const result = ok(42);
|
|
267
|
-
* const value = toNullable(result); // 42
|
|
268
|
-
*
|
|
269
|
-
* const errResult = err('error');
|
|
270
|
-
* const nullValue = toNullable(errResult); // null
|
|
271
|
-
* ```
|
|
272
|
-
*/
|
|
273
|
-
function toNullable(result) {
|
|
274
|
-
if (result.isOk()) return result.value;
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region src/result.ts
|
|
280
|
-
var Result = class Result extends Pipeable {
|
|
281
|
-
#state;
|
|
282
|
-
constructor(state) {
|
|
283
|
-
super();
|
|
284
|
-
Object.freeze(state);
|
|
285
|
-
this.#state = state;
|
|
286
|
-
Object.freeze(this);
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Creates an Ok Result with the given value.
|
|
290
|
-
*
|
|
291
|
-
* **Note**: `null` and `undefined` are allowed as values.
|
|
292
|
-
* If you want to convert `null`/`undefined` to an Err, use `fromNullable()`.
|
|
293
|
-
*
|
|
294
|
-
* @param value The value for the Ok Result
|
|
295
|
-
* @returns An Ok Result with the given value
|
|
296
|
-
*
|
|
297
|
-
* @example
|
|
298
|
-
* ```ts
|
|
299
|
-
* const result = Result.ok(42);
|
|
300
|
-
* const nullResult = Result.ok(null); // Allowed!
|
|
301
|
-
* ```
|
|
302
|
-
*/
|
|
303
|
-
static ok(value) {
|
|
304
|
-
return new Result({
|
|
305
|
-
_tag: "Ok",
|
|
306
|
-
value
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Creates an Err Result with the given error.
|
|
311
|
-
*
|
|
312
|
-
* **Note**: `null` and `undefined` are allowed as errors.
|
|
313
|
-
*
|
|
314
|
-
* @param error The error for the Err Result
|
|
315
|
-
* @returns An Err Result with the given error
|
|
316
|
-
*
|
|
317
|
-
* @example
|
|
318
|
-
* ```ts
|
|
319
|
-
* const result = Result.err('error message');
|
|
320
|
-
* const nullError = Result.err(null); // Allowed!
|
|
321
|
-
* ```
|
|
322
|
-
*/
|
|
323
|
-
static err(error) {
|
|
324
|
-
return new Result({
|
|
325
|
-
_tag: "Err",
|
|
326
|
-
error
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Converts `null | undefined` to `Err`, everything else to `Ok`.
|
|
331
|
-
*
|
|
332
|
-
* **Type Safety**: The type assertion `as NonNullable<T>` is safe,
|
|
333
|
-
* as the runtime check guarantees that the value is not null/undefined.
|
|
334
|
-
*
|
|
335
|
-
* @param value The value to check
|
|
336
|
-
* @param error The error to use if value is null/undefined
|
|
337
|
-
* @returns An Ok Result with the NonNullable value, or an Err Result with the error
|
|
338
|
-
*
|
|
339
|
-
* @example
|
|
340
|
-
* ```ts
|
|
341
|
-
* Result.fromNullable(user, 'User not found')
|
|
342
|
-
* // Ok(user) or Err('User not found')
|
|
343
|
-
* ```
|
|
344
|
-
*/
|
|
345
|
-
static fromNullable(value, error) {
|
|
346
|
-
return fromNullable(value, error);
|
|
347
|
-
}
|
|
348
|
-
static fromPromise(promise, errorMapper) {
|
|
349
|
-
return fromPromise(promise, errorMapper);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Executes a function and catches exceptions.
|
|
353
|
-
*
|
|
354
|
-
* @example
|
|
355
|
-
* ```ts
|
|
356
|
-
* const result = Result.try(() => JSON.parse(input));
|
|
357
|
-
* // Ok(parsed) or Err(SyntaxError)
|
|
358
|
-
* ```
|
|
359
|
-
*/
|
|
360
|
-
static try(fn) {
|
|
361
|
-
return tryFn(fn);
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Checks if the Result is Ok.
|
|
365
|
-
*
|
|
366
|
-
* @returns `true` if the Result is Ok (and narrows the type)
|
|
367
|
-
*
|
|
368
|
-
* @example
|
|
369
|
-
* ```ts
|
|
370
|
-
* if (result.isOk()) {
|
|
371
|
-
* const value: T = result.value; // TypeScript knows that value is defined
|
|
372
|
-
* }
|
|
373
|
-
* ```
|
|
374
|
-
*/
|
|
375
|
-
isOk() {
|
|
376
|
-
return this.#state._tag === "Ok";
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Checks if the Result is Err.
|
|
380
|
-
*
|
|
381
|
-
* @returns `true` if the Result is Err (and narrows the type)
|
|
382
|
-
*
|
|
383
|
-
* @example
|
|
384
|
-
* ```ts
|
|
385
|
-
* if (result.isErr()) {
|
|
386
|
-
* const error: E = result.error; // TypeScript knows that error is defined
|
|
387
|
-
* }
|
|
388
|
-
* ```
|
|
389
|
-
*/
|
|
390
|
-
isErr() {
|
|
391
|
-
return this.#state._tag === "Err";
|
|
392
|
-
}
|
|
393
|
-
get value() {
|
|
394
|
-
return this.#state._tag === "Ok" ? this.#state.value : void 0;
|
|
395
|
-
}
|
|
396
|
-
get error() {
|
|
397
|
-
return this.#state._tag === "Err" ? this.#state.error : void 0;
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Returns the value, guaranteed to be defined after `isOk()` check.
|
|
401
|
-
* This method provides better type narrowing than the `value` getter.
|
|
402
|
-
*
|
|
403
|
-
* ⚠️ **Warning**: This method throws an Error if called on an Err result.
|
|
404
|
-
* Use this method only after a type guard (`if (result.isOk())`).
|
|
405
|
-
* For a safer alternative with a custom message, use `expect()`.
|
|
406
|
-
*
|
|
407
|
-
* @throws {Error} If called on an Err result
|
|
408
|
-
*
|
|
409
|
-
* @example
|
|
410
|
-
* ```ts
|
|
411
|
-
* if (result.isOk()) {
|
|
412
|
-
* const value = result.unwrap(); // Type is T, not T | undefined
|
|
413
|
-
* }
|
|
414
|
-
* ```
|
|
415
|
-
*/
|
|
416
|
-
unwrap() {
|
|
417
|
-
if (this.#state._tag === "Ok") return this.#state.value;
|
|
418
|
-
const errorStr = (() => {
|
|
419
|
-
try {
|
|
420
|
-
const error = this.#state.error;
|
|
421
|
-
if (error === null) return "null";
|
|
422
|
-
if (error === void 0) return "undefined";
|
|
423
|
-
if (typeof error === "string") return error;
|
|
424
|
-
if (error instanceof Error) return error.message;
|
|
425
|
-
if (typeof error === "object" && "toString" in error) try {
|
|
426
|
-
return String(error);
|
|
427
|
-
} catch {
|
|
428
|
-
return "[unstringifiable error]";
|
|
429
|
-
}
|
|
430
|
-
return String(error);
|
|
431
|
-
} catch {
|
|
432
|
-
return "[unstringifiable error]";
|
|
433
|
-
}
|
|
434
|
-
})();
|
|
435
|
-
throw new Error(`Called unwrap() on Err: ${errorStr}`);
|
|
436
|
-
}
|
|
437
|
-
/**
|
|
438
|
-
* Returns the error, guaranteed to be defined after `isErr()` check.
|
|
439
|
-
* This method provides better type narrowing than the `error` getter.
|
|
440
|
-
*
|
|
441
|
-
* ⚠️ **Warning**: This method throws an Error if called on an Ok result.
|
|
442
|
-
* Use this method only after a type guard (`if (result.isErr())`).
|
|
443
|
-
* For a safer alternative with a custom message, use `expectErr()`.
|
|
444
|
-
*
|
|
445
|
-
* @throws {Error} If called on an Ok result
|
|
446
|
-
*
|
|
447
|
-
* @example
|
|
448
|
-
* ```ts
|
|
449
|
-
* if (result.isErr()) {
|
|
450
|
-
* const error = result.unwrapErr(); // Type is E, not E | undefined
|
|
451
|
-
* }
|
|
452
|
-
* ```
|
|
453
|
-
*/
|
|
454
|
-
unwrapErr() {
|
|
455
|
-
if (this.#state._tag === "Err") return this.#state.error;
|
|
456
|
-
const valueStr = (() => {
|
|
457
|
-
try {
|
|
458
|
-
const value = this.#state.value;
|
|
459
|
-
if (value === null) return "null";
|
|
460
|
-
if (value === void 0) return "undefined";
|
|
461
|
-
if (typeof value === "string") return value;
|
|
462
|
-
if (value instanceof Error) return value.message;
|
|
463
|
-
if (typeof value === "object" && "toString" in value) try {
|
|
464
|
-
return String(value);
|
|
465
|
-
} catch {
|
|
466
|
-
return "[unstringifiable value]";
|
|
467
|
-
}
|
|
468
|
-
return String(value);
|
|
469
|
-
} catch {
|
|
470
|
-
return "[unstringifiable value]";
|
|
471
|
-
}
|
|
472
|
-
})();
|
|
473
|
-
throw new Error(`Called unwrapErr() on Ok: ${valueStr}`);
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Returns the value with a custom error message if the result is Err.
|
|
477
|
-
* Similar to `unwrap()`, but allows you to provide a custom error message.
|
|
478
|
-
*
|
|
479
|
-
* ⚠️ **Warning**: This method throws an Error if called on an Err result.
|
|
480
|
-
* Use this method only if you are sure the Result is Ok,
|
|
481
|
-
* or if you need a meaningful error message.
|
|
482
|
-
*
|
|
483
|
-
* @param message Custom error message to throw if result is Err
|
|
484
|
-
* @returns The value if result is Ok
|
|
485
|
-
* @throws {Error} If called on an Err result with the provided message
|
|
486
|
-
*
|
|
487
|
-
* @example
|
|
488
|
-
* ```ts
|
|
489
|
-
* const result = fetchUser(id);
|
|
490
|
-
* const user = result.expect('User should exist'); // Throws with custom message if Err
|
|
491
|
-
* ```
|
|
492
|
-
*/
|
|
493
|
-
expect(message) {
|
|
494
|
-
if (this.#state._tag === "Ok") return this.#state.value;
|
|
495
|
-
throw new Error(message);
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Returns the error with a custom error message if the result is Ok.
|
|
499
|
-
* Similar to `unwrapErr()`, but allows you to provide a custom error message.
|
|
500
|
-
*
|
|
501
|
-
* ⚠️ **Warning**: This method throws an Error if called on an Ok result.
|
|
502
|
-
* Use this method only if you are sure the Result is Err,
|
|
503
|
-
* or if you need a meaningful error message.
|
|
504
|
-
*
|
|
505
|
-
* @param message Custom error message to throw if result is Ok
|
|
506
|
-
* @returns The error if result is Err
|
|
507
|
-
* @throws {Error} If called on an Ok result with the provided message
|
|
508
|
-
*
|
|
509
|
-
* @example
|
|
510
|
-
* ```ts
|
|
511
|
-
* const result = validateInput(input);
|
|
512
|
-
* if (result.isErr()) {
|
|
513
|
-
* const error = result.expectErr('Validation should have failed'); // Throws if Ok
|
|
514
|
-
* }
|
|
515
|
-
* ```
|
|
516
|
-
*/
|
|
517
|
-
expectErr(message) {
|
|
518
|
-
if (this.#state._tag === "Err") return this.#state.error;
|
|
519
|
-
throw new Error(message);
|
|
520
|
-
}
|
|
521
|
-
unwrapOr(defaultValue) {
|
|
522
|
-
return this.#state._tag === "Ok" ? this.#state.value : defaultValue;
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Converts the Result to a Promise.
|
|
526
|
-
* Ok → resolves with the value, Err → rejects with the error
|
|
527
|
-
*
|
|
528
|
-
* This instance method delegates to the standalone `toPromise()` function.
|
|
529
|
-
*
|
|
530
|
-
* @returns A Promise that resolves with the value if Ok, or rejects with the error if Err
|
|
531
|
-
*
|
|
532
|
-
* @example
|
|
533
|
-
* ```ts
|
|
534
|
-
* const result = ok(42);
|
|
535
|
-
* const promise = result.toPromise();
|
|
536
|
-
* const value = await promise; // 42
|
|
537
|
-
*
|
|
538
|
-
* const errResult = err('error');
|
|
539
|
-
* try {
|
|
540
|
-
* await errResult.toPromise();
|
|
541
|
-
* } catch (error) {
|
|
542
|
-
* console.log(error); // 'error'
|
|
543
|
-
* }
|
|
544
|
-
* ```
|
|
545
|
-
*/
|
|
546
|
-
toPromise() {
|
|
547
|
-
return toPromise(this);
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Converts the Result to `T | null`.
|
|
551
|
-
* Ok → returns the value, Err → returns null
|
|
552
|
-
*
|
|
553
|
-
* This instance method delegates to the standalone `toNullable()` function.
|
|
554
|
-
*
|
|
555
|
-
* @returns The value if Ok, or null if Err
|
|
556
|
-
*
|
|
557
|
-
* @example
|
|
558
|
-
* ```ts
|
|
559
|
-
* const result = ok(42);
|
|
560
|
-
* const value = result.toNullable(); // 42
|
|
561
|
-
*
|
|
562
|
-
* const errResult = err('error');
|
|
563
|
-
* const nullValue = errResult.toNullable(); // null
|
|
564
|
-
* ```
|
|
565
|
-
*/
|
|
566
|
-
toNullable() {
|
|
567
|
-
return toNullable(this);
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* Enables `yield* result` in generators (Do-notation).
|
|
571
|
-
*
|
|
572
|
-
* The iterator yields the `Result` itself; the runner (see `task`) decides:
|
|
573
|
-
* - Ok → sends back the Ok value (`next(value)`), `yield*` yields `T`
|
|
574
|
-
* - Err → aborts and returns the Err Result
|
|
575
|
-
*/
|
|
576
|
-
*[Symbol.iterator]() {
|
|
577
|
-
return yield this;
|
|
578
|
-
}
|
|
579
|
-
/**
|
|
580
|
-
* Universal pattern matcher for Ok + Err cases.
|
|
581
|
-
*
|
|
582
|
-
* Use this to exhaustively match on both success and error cases with type-based
|
|
583
|
-
* and value-based pattern matching.
|
|
584
|
-
*
|
|
585
|
-
* @example
|
|
586
|
-
* ```ts
|
|
587
|
-
* const message = result
|
|
588
|
-
* .match()
|
|
589
|
-
* .err(NetworkError, e => `Network: ${e.message}`)
|
|
590
|
-
* .err(ValidationError, e => `Validation: ${e.message}`)
|
|
591
|
-
* .ok(val => `Success: ${val}`)
|
|
592
|
-
* .run();
|
|
593
|
-
* ```
|
|
594
|
-
*/
|
|
595
|
-
match() {
|
|
596
|
-
return ResultMatchBuilder.fromResult(this);
|
|
597
|
-
}
|
|
598
|
-
matchErr() {
|
|
599
|
-
if (this.isErr()) return new ErrorMatchBuilder(this.error);
|
|
600
|
-
throw new Error("matchErr() can only be called on Err results. Use `if (result.isErr()) { ... }` first.");
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Matches on the Err value, but normalizes every branch to a `Result`:
|
|
604
|
-
* - Handlers may return a `Result` (returned directly)
|
|
605
|
-
* - or an error value (wrapped to `Err(error)`)
|
|
606
|
-
*/
|
|
607
|
-
matchErrResult() {
|
|
608
|
-
const makeErr = (error) => Result.err(error);
|
|
609
|
-
return ErrMatchBuilder.fromResult(this, makeErr);
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* @deprecated Use `.match()` instead. Will be removed in next major version.
|
|
613
|
-
*/
|
|
614
|
-
pattern() {
|
|
615
|
-
return this.match();
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* @deprecated Use `.match()` instead. Will be removed in next major version.
|
|
619
|
-
*/
|
|
620
|
-
switch() {
|
|
621
|
-
return this.match();
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* Folds the Result into a single value by applying one of two functions.
|
|
625
|
-
*
|
|
626
|
-
* This is a direct method equivalent to the `match` pipe operator.
|
|
627
|
-
* Use this when you want to handle both Ok and Err cases and return a single value.
|
|
628
|
-
*
|
|
629
|
-
* @param onOk Function to apply if the Result is Ok
|
|
630
|
-
* @param onErr Function to apply if the Result is Err
|
|
631
|
-
* @returns The result of applying the appropriate function
|
|
632
|
-
*
|
|
633
|
-
* @example
|
|
634
|
-
* ```ts
|
|
635
|
-
* const result = ok(42);
|
|
636
|
-
* const message = result.fold(
|
|
637
|
-
* val => `Success: ${val}`,
|
|
638
|
-
* err => `Error: ${err}`
|
|
639
|
-
* );
|
|
640
|
-
* // message = "Success: 42"
|
|
641
|
-
* ```
|
|
642
|
-
*
|
|
643
|
-
* @example
|
|
644
|
-
* ```ts
|
|
645
|
-
* // Works with discriminated unions
|
|
646
|
-
* const result: Result<string, number> = err(404);
|
|
647
|
-
* const response = result.fold(
|
|
648
|
-
* data => ({ success: true as const, data }),
|
|
649
|
-
* code => ({ success: false as const, code })
|
|
650
|
-
* );
|
|
651
|
-
* // response: { success: true; data: string } | { success: false; code: number }
|
|
652
|
-
* ```
|
|
653
|
-
*/
|
|
654
|
-
fold(onOk, onErr) {
|
|
655
|
-
if (this.isOk()) return onOk(this.value);
|
|
656
|
-
if (this.isErr()) return onErr(this.error);
|
|
657
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
658
|
-
}
|
|
659
|
-
/**
|
|
660
|
-
* Returns the Result as a discriminated union (`{ _tag: 'Ok', value } | { _tag: 'Err', error }`).
|
|
661
|
-
* Useful for libraries like `ts-pattern` that match on plain object unions.
|
|
662
|
-
*/
|
|
663
|
-
toUnion() {
|
|
664
|
-
return this.#state;
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Serializes the Result into a simple object format.
|
|
668
|
-
* Preserves the original types.
|
|
669
|
-
*/
|
|
670
|
-
serialize() {
|
|
671
|
-
if (this.#state._tag === "Ok") return {
|
|
672
|
-
isSuccess: true,
|
|
673
|
-
data: this.#state.value
|
|
674
|
-
};
|
|
675
|
-
return {
|
|
676
|
-
isSuccess: false,
|
|
677
|
-
error: this.#state.error
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* Serializes the Result into a user-friendly format.
|
|
682
|
-
* Converts errors to readable strings.
|
|
683
|
-
*/
|
|
684
|
-
toUserFriendly() {
|
|
685
|
-
if (this.#state._tag === "Ok") return {
|
|
686
|
-
isSuccess: true,
|
|
687
|
-
data: this.#state.value
|
|
688
|
-
};
|
|
689
|
-
const error = this.#state.error;
|
|
690
|
-
const toSafeString = (value) => {
|
|
691
|
-
try {
|
|
692
|
-
return String(value);
|
|
693
|
-
} catch {
|
|
694
|
-
return "[Unstringifiable error]";
|
|
695
|
-
}
|
|
696
|
-
};
|
|
697
|
-
return {
|
|
698
|
-
isSuccess: false,
|
|
699
|
-
error: (() => {
|
|
700
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
701
|
-
const message = error.message;
|
|
702
|
-
return typeof message === "string" ? message : toSafeString(error);
|
|
703
|
-
}
|
|
704
|
-
return toSafeString(error);
|
|
705
|
-
})()
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
const ok = Result.ok;
|
|
710
|
-
const err = Result.err;
|
|
711
|
-
/**
|
|
712
|
-
* Helper for conditional Result creation.
|
|
713
|
-
* Avoids type inference issues with ternary operators.
|
|
714
|
-
*
|
|
715
|
-
* @example
|
|
716
|
-
* ```ts
|
|
717
|
-
* const result = okIf(value > 5, value, 'too small');
|
|
718
|
-
* // instead of: value > 5 ? ok(value) : err('too small')
|
|
719
|
-
* ```
|
|
720
|
-
*/
|
|
721
|
-
function okIf(condition, okValue, errValue) {
|
|
722
|
-
return condition ? ok(okValue) : err(errValue);
|
|
723
|
-
}
|
|
724
|
-
/**
|
|
725
|
-
* Helper for conditional Result creation with lazy evaluation.
|
|
726
|
-
* Evaluates values only when they are needed.
|
|
727
|
-
*
|
|
728
|
-
* @example
|
|
729
|
-
* ```ts
|
|
730
|
-
* const result = okIfLazy(
|
|
731
|
-
* value > 5,
|
|
732
|
-
* () => expensiveComputation(value),
|
|
733
|
-
* () => 'too small'
|
|
734
|
-
* );
|
|
735
|
-
* ```
|
|
736
|
-
*/
|
|
737
|
-
function okIfLazy(condition, okFn, errFn) {
|
|
738
|
-
return condition ? ok(okFn()) : err(errFn());
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
//#endregion
|
|
742
|
-
//#region src/gen.ts
|
|
743
|
-
async function task(makeGenerator, onThrow) {
|
|
744
|
-
const iterator = makeGenerator();
|
|
745
|
-
let input = void 0;
|
|
746
|
-
while (true) {
|
|
747
|
-
let step;
|
|
748
|
-
try {
|
|
749
|
-
step = await iterator.next(input);
|
|
750
|
-
} catch (caught) {
|
|
751
|
-
if (!onThrow) throw caught;
|
|
752
|
-
return err(onThrow(caught));
|
|
753
|
-
}
|
|
754
|
-
if (step.done) try {
|
|
755
|
-
const awaited = await step.value;
|
|
756
|
-
if (isResult(awaited)) return awaited;
|
|
757
|
-
return ok(awaited);
|
|
758
|
-
} catch (caught) {
|
|
759
|
-
if (!onThrow) throw caught;
|
|
760
|
-
return err(onThrow(caught));
|
|
761
|
-
}
|
|
762
|
-
const yielded = step.value;
|
|
763
|
-
if (!isResult(yielded)) throw new TypeError("task() expected yielded values to be Result. Use `yield*` on a Result.");
|
|
764
|
-
if (yielded.isOk()) {
|
|
765
|
-
input = yielded.value;
|
|
766
|
-
continue;
|
|
767
|
-
}
|
|
768
|
-
if (yielded.isErr()) {
|
|
769
|
-
try {
|
|
770
|
-
if (typeof iterator.return === "function") await iterator.return(void 0);
|
|
771
|
-
} catch (caught) {
|
|
772
|
-
if (!onThrow) throw caught;
|
|
773
|
-
return err(onThrow(caught));
|
|
774
|
-
}
|
|
775
|
-
return yielded;
|
|
776
|
-
}
|
|
777
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
const gen = task;
|
|
781
109
|
|
|
782
110
|
//#endregion
|
|
783
|
-
//#region src/
|
|
111
|
+
//#region src/core/map.ts
|
|
784
112
|
/**
|
|
785
|
-
*
|
|
786
|
-
*
|
|
113
|
+
* Transformiert den Wert (Ok-Fall).
|
|
114
|
+
* Entspricht Rust `map`.
|
|
787
115
|
*/
|
|
788
116
|
function map(project) {
|
|
789
117
|
return (source) => {
|
|
@@ -793,10 +121,10 @@ function map(project) {
|
|
|
793
121
|
}
|
|
794
122
|
|
|
795
123
|
//#endregion
|
|
796
|
-
//#region src/
|
|
124
|
+
//#region src/core/mapErr.ts
|
|
797
125
|
/**
|
|
798
|
-
*
|
|
799
|
-
*
|
|
126
|
+
* Transformiert den Fehler (Err-Fall).
|
|
127
|
+
* Entspricht Rust `map_err`.
|
|
800
128
|
*/
|
|
801
129
|
function mapErr(project) {
|
|
802
130
|
return (source) => {
|
|
@@ -806,10 +134,10 @@ function mapErr(project) {
|
|
|
806
134
|
}
|
|
807
135
|
|
|
808
136
|
//#endregion
|
|
809
|
-
//#region src/
|
|
137
|
+
//#region src/core/mapBoth.ts
|
|
810
138
|
/**
|
|
811
|
-
*
|
|
812
|
-
*
|
|
139
|
+
* Transformiert sowohl den Ok-Wert als auch den Err-Fehler.
|
|
140
|
+
* Entspricht FP `bimap` / `mapBoth`.
|
|
813
141
|
*/
|
|
814
142
|
function mapBoth(mapOk, mapErr$1) {
|
|
815
143
|
return (source) => {
|
|
@@ -819,15 +147,15 @@ function mapBoth(mapOk, mapErr$1) {
|
|
|
819
147
|
};
|
|
820
148
|
}
|
|
821
149
|
/**
|
|
822
|
-
* Alias
|
|
150
|
+
* Alias für `mapBoth`.
|
|
823
151
|
*/
|
|
824
152
|
const bimap = mapBoth;
|
|
825
153
|
|
|
826
154
|
//#endregion
|
|
827
|
-
//#region src/
|
|
155
|
+
//#region src/core/flatMap.ts
|
|
828
156
|
/**
|
|
829
|
-
*
|
|
830
|
-
*
|
|
157
|
+
* Verkettet eine weitere Operation, die ein Result zurückgibt.
|
|
158
|
+
* Entspricht Rust `and_then` oder JS `flatMap`.
|
|
831
159
|
*/
|
|
832
160
|
function flatMap(project) {
|
|
833
161
|
return (source) => {
|
|
@@ -837,10 +165,42 @@ function flatMap(project) {
|
|
|
837
165
|
}
|
|
838
166
|
|
|
839
167
|
//#endregion
|
|
840
|
-
//#region src/
|
|
168
|
+
//#region src/core/zip.ts
|
|
169
|
+
function zipImpl(left, right) {
|
|
170
|
+
if (left.isErr()) return left;
|
|
171
|
+
if (right.isErr()) return right;
|
|
172
|
+
if (left.isOk() && right.isOk()) return ok([left.value, right.value]);
|
|
173
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
174
|
+
}
|
|
175
|
+
function zip(...args) {
|
|
176
|
+
if (args.length === 1) {
|
|
177
|
+
const right$1 = args[0];
|
|
178
|
+
return (left$1) => zipImpl(left$1, right$1);
|
|
179
|
+
}
|
|
180
|
+
const [left, right] = args;
|
|
181
|
+
return zipImpl(left, right);
|
|
182
|
+
}
|
|
183
|
+
function combineImpl(left, right) {
|
|
184
|
+
if (left.isOk() && right.isOk()) return ok([left.value, right.value]);
|
|
185
|
+
const errors = [];
|
|
186
|
+
if (left.isErr()) errors.push(left.error);
|
|
187
|
+
if (right.isErr()) errors.push(right.error);
|
|
188
|
+
return err(errors);
|
|
189
|
+
}
|
|
190
|
+
function combine(...args) {
|
|
191
|
+
if (args.length === 1) {
|
|
192
|
+
const right$1 = args[0];
|
|
193
|
+
return (left$1) => combineImpl(left$1, right$1);
|
|
194
|
+
}
|
|
195
|
+
const [left, right] = args;
|
|
196
|
+
return combineImpl(left, right);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/core/tap.ts
|
|
841
201
|
/**
|
|
842
|
-
*
|
|
843
|
-
*
|
|
202
|
+
* Führt einen Seiteneffekt aus (Logging, Debugging), ohne das Result zu ändern.
|
|
203
|
+
* Entspricht Rust `inspect` / `inspect_err`.
|
|
844
204
|
*/
|
|
845
205
|
function tap(observer) {
|
|
846
206
|
return (source) => {
|
|
@@ -851,10 +211,10 @@ function tap(observer) {
|
|
|
851
211
|
}
|
|
852
212
|
|
|
853
213
|
//#endregion
|
|
854
|
-
//#region src/
|
|
214
|
+
//#region src/core/filter.ts
|
|
855
215
|
/**
|
|
856
|
-
*
|
|
857
|
-
*
|
|
216
|
+
* Prüft eine Bedingung. Wenn falsch, wird das Result zu Err.
|
|
217
|
+
* Entspricht Rust `filter` (teilweise).
|
|
858
218
|
*/
|
|
859
219
|
function filter(predicate, errorFn) {
|
|
860
220
|
return (source) => {
|
|
@@ -867,31 +227,61 @@ function filter(predicate, errorFn) {
|
|
|
867
227
|
}
|
|
868
228
|
|
|
869
229
|
//#endregion
|
|
870
|
-
//#region src/
|
|
230
|
+
//#region src/core/match.ts
|
|
871
231
|
/**
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
* This is the pipe operator equivalent of the `.fold()` instance method.
|
|
232
|
+
* Löst das Result auf. Das Ende der Pipe.
|
|
233
|
+
* Entspricht Rust `match`.
|
|
876
234
|
*/
|
|
877
|
-
function
|
|
235
|
+
function match(handlers) {
|
|
878
236
|
return (source) => {
|
|
879
237
|
if (source.isOk()) return handlers.ok(source.value);
|
|
880
238
|
if (source.isErr()) return handlers.err(source.error);
|
|
881
239
|
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
882
240
|
};
|
|
883
241
|
}
|
|
242
|
+
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/core/recover.ts
|
|
245
|
+
/**
|
|
246
|
+
* Recover: wandelt Err in Ok(defaultValue) um.
|
|
247
|
+
* Ergebnis ist garantiert Ok → Error-Typ wird `never`.
|
|
248
|
+
*/
|
|
249
|
+
function recover(defaultValue) {
|
|
250
|
+
return (source) => {
|
|
251
|
+
if (source.isOk()) return source;
|
|
252
|
+
if (source.isErr()) return ok(defaultValue);
|
|
253
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
254
|
+
};
|
|
255
|
+
}
|
|
884
256
|
/**
|
|
885
|
-
*
|
|
257
|
+
* Wie `recover`, aber berechnet den Default-Wert anhand des Errors.
|
|
886
258
|
*/
|
|
887
|
-
|
|
259
|
+
function recoverWith(fn) {
|
|
260
|
+
return (source) => {
|
|
261
|
+
if (source.isOk()) return source;
|
|
262
|
+
if (source.isErr()) return ok(fn(source.error));
|
|
263
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
264
|
+
};
|
|
265
|
+
}
|
|
888
266
|
|
|
889
267
|
//#endregion
|
|
890
|
-
//#region src/
|
|
268
|
+
//#region src/core/swap.ts
|
|
891
269
|
/**
|
|
892
|
-
*
|
|
893
|
-
*
|
|
894
|
-
|
|
270
|
+
* Tauscht Ok und Err.
|
|
271
|
+
* Result<T, E> → Result<E, T>
|
|
272
|
+
*/
|
|
273
|
+
function swap(result) {
|
|
274
|
+
if (result.isOk()) return err(result.value);
|
|
275
|
+
if (result.isErr()) return ok(result.error);
|
|
276
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/core/tryCatch.ts
|
|
281
|
+
/**
|
|
282
|
+
* Führt eine Funktion aus und fängt Exceptions ab.
|
|
283
|
+
* Wandelt Exceptions in Result<E> um.
|
|
284
|
+
* Entspricht Rust `Result::from` für fallible Operationen.
|
|
895
285
|
*/
|
|
896
286
|
function tryCatch(fn, errorMapper) {
|
|
897
287
|
return (source) => {
|
|
@@ -905,9 +295,9 @@ function tryCatch(fn, errorMapper) {
|
|
|
905
295
|
}
|
|
906
296
|
|
|
907
297
|
//#endregion
|
|
908
|
-
//#region src/
|
|
298
|
+
//#region src/core/tryMap.ts
|
|
909
299
|
/**
|
|
910
|
-
*
|
|
300
|
+
* Wie `map`, aber fängt Exceptions ab und wandelt sie in Err um.
|
|
911
301
|
*/
|
|
912
302
|
function tryMap(project, errorMapper) {
|
|
913
303
|
return (source) => {
|
|
@@ -922,33 +312,29 @@ function tryMap(project, errorMapper) {
|
|
|
922
312
|
}
|
|
923
313
|
|
|
924
314
|
//#endregion
|
|
925
|
-
//#region src/
|
|
926
|
-
/**
|
|
927
|
-
* Recover: turns Err into Ok(defaultValue).
|
|
928
|
-
* Result is guaranteed Ok → error type becomes `never`.
|
|
929
|
-
*/
|
|
930
|
-
function recover(defaultValue) {
|
|
931
|
-
return (source) => {
|
|
932
|
-
if (source.isOk()) return source;
|
|
933
|
-
if (source.isErr()) return ok(defaultValue);
|
|
934
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
935
|
-
};
|
|
936
|
-
}
|
|
315
|
+
//#region src/core/collectFirstOk.ts
|
|
937
316
|
/**
|
|
938
|
-
*
|
|
317
|
+
* Parse a set of `Result`s, short-circuits when an input value is `Ok`.
|
|
318
|
+
* If no `Ok` is found, returns an `Err` containing the collected error values.
|
|
319
|
+
* Useful for "try multiple approaches until one works" patterns.
|
|
939
320
|
*/
|
|
940
|
-
function
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
if (
|
|
321
|
+
function collectFirstOk(results) {
|
|
322
|
+
const errors = [];
|
|
323
|
+
for (const result of results) {
|
|
324
|
+
if (result.isOk()) return ok(result.value);
|
|
325
|
+
if (result.isErr()) {
|
|
326
|
+
errors.push(result.error);
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
944
329
|
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
945
|
-
}
|
|
330
|
+
}
|
|
331
|
+
return err(errors);
|
|
946
332
|
}
|
|
947
333
|
|
|
948
334
|
//#endregion
|
|
949
|
-
//#region src/
|
|
335
|
+
//#region src/core/mapAsync.ts
|
|
950
336
|
/**
|
|
951
|
-
* Async
|
|
337
|
+
* Async-Version von map.
|
|
952
338
|
*/
|
|
953
339
|
function mapAsync(project) {
|
|
954
340
|
return async (source) => {
|
|
@@ -958,9 +344,9 @@ function mapAsync(project) {
|
|
|
958
344
|
}
|
|
959
345
|
|
|
960
346
|
//#endregion
|
|
961
|
-
//#region src/
|
|
347
|
+
//#region src/core/mapErrAsync.ts
|
|
962
348
|
/**
|
|
963
|
-
* Async
|
|
349
|
+
* Async-Version von mapErr.
|
|
964
350
|
*/
|
|
965
351
|
function mapErrAsync(project) {
|
|
966
352
|
return async (source) => {
|
|
@@ -970,10 +356,9 @@ function mapErrAsync(project) {
|
|
|
970
356
|
}
|
|
971
357
|
|
|
972
358
|
//#endregion
|
|
973
|
-
//#region src/
|
|
359
|
+
//#region src/core/flatMapAsync.ts
|
|
974
360
|
/**
|
|
975
|
-
* Async
|
|
976
|
-
* Allows different error types in the projected Result.
|
|
361
|
+
* Async-Version von flatMap.
|
|
977
362
|
*/
|
|
978
363
|
function flatMapAsync(project) {
|
|
979
364
|
return async (source) => {
|
|
@@ -983,9 +368,9 @@ function flatMapAsync(project) {
|
|
|
983
368
|
}
|
|
984
369
|
|
|
985
370
|
//#endregion
|
|
986
|
-
//#region src/
|
|
371
|
+
//#region src/core/tapAsync.ts
|
|
987
372
|
/**
|
|
988
|
-
* Async
|
|
373
|
+
* Async-Version von tap.
|
|
989
374
|
*/
|
|
990
375
|
function tapAsync(observer) {
|
|
991
376
|
return async (source) => {
|
|
@@ -996,9 +381,9 @@ function tapAsync(observer) {
|
|
|
996
381
|
}
|
|
997
382
|
|
|
998
383
|
//#endregion
|
|
999
|
-
//#region src/
|
|
384
|
+
//#region src/core/filterAsync.ts
|
|
1000
385
|
/**
|
|
1001
|
-
* Async
|
|
386
|
+
* Async-Version von filter.
|
|
1002
387
|
*/
|
|
1003
388
|
function filterAsync(predicate, errorFn) {
|
|
1004
389
|
return async (source) => {
|
|
@@ -1011,29 +396,22 @@ function filterAsync(predicate, errorFn) {
|
|
|
1011
396
|
}
|
|
1012
397
|
|
|
1013
398
|
//#endregion
|
|
1014
|
-
//#region src/
|
|
399
|
+
//#region src/core/matchAsync.ts
|
|
1015
400
|
/**
|
|
1016
|
-
* Async
|
|
1017
|
-
* The end of the pipe.
|
|
1018
|
-
*
|
|
1019
|
-
* This is the async pipe operator equivalent of the `.fold()` instance method.
|
|
401
|
+
* Async-Version von match.
|
|
1020
402
|
*/
|
|
1021
|
-
function
|
|
403
|
+
function matchAsync(handlers) {
|
|
1022
404
|
return async (source) => {
|
|
1023
405
|
if (source.isOk()) return await handlers.ok(source.value);
|
|
1024
406
|
if (source.isErr()) return await handlers.err(source.error);
|
|
1025
407
|
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
1026
408
|
};
|
|
1027
409
|
}
|
|
1028
|
-
/**
|
|
1029
|
-
* @deprecated Use `foldAsync` instead. Will be removed in next major version.
|
|
1030
|
-
*/
|
|
1031
|
-
const matchAsync = foldAsync;
|
|
1032
410
|
|
|
1033
411
|
//#endregion
|
|
1034
|
-
//#region src/
|
|
412
|
+
//#region src/core/tryCatchAsync.ts
|
|
1035
413
|
/**
|
|
1036
|
-
* Async
|
|
414
|
+
* Async-Version von tryCatch.
|
|
1037
415
|
*/
|
|
1038
416
|
function tryCatchAsync(fn, errorMapper) {
|
|
1039
417
|
return async (source) => {
|
|
@@ -1047,9 +425,9 @@ function tryCatchAsync(fn, errorMapper) {
|
|
|
1047
425
|
}
|
|
1048
426
|
|
|
1049
427
|
//#endregion
|
|
1050
|
-
//#region src/
|
|
428
|
+
//#region src/core/tryMapAsync.ts
|
|
1051
429
|
/**
|
|
1052
|
-
* Async
|
|
430
|
+
* Async-Version von tryMap.
|
|
1053
431
|
*/
|
|
1054
432
|
function tryMapAsync(project, errorMapper) {
|
|
1055
433
|
return async (source) => {
|
|
@@ -1064,10 +442,234 @@ function tryMapAsync(project, errorMapper) {
|
|
|
1064
442
|
}
|
|
1065
443
|
|
|
1066
444
|
//#endregion
|
|
1067
|
-
//#region src/
|
|
445
|
+
//#region src/core/result.ts
|
|
446
|
+
var ResultBase = class extends Pipeable {
|
|
447
|
+
isOk() {
|
|
448
|
+
return this._tag === "Ok";
|
|
449
|
+
}
|
|
450
|
+
isErr() {
|
|
451
|
+
return this._tag === "Err";
|
|
452
|
+
}
|
|
453
|
+
unwrapOr(defaultValue) {
|
|
454
|
+
return this._tag === "Ok" ? this.value : defaultValue;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Folds the Result into a single value by applying one of two functions.
|
|
458
|
+
*/
|
|
459
|
+
fold(onOk, onErr) {
|
|
460
|
+
if (this._tag === "Ok") return onOk(this.value);
|
|
461
|
+
if (this._tag === "Err") return onErr(this.error);
|
|
462
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Enables `yield* result` in generators (Do-notation).
|
|
466
|
+
*
|
|
467
|
+
* The iterator yields the `Result` itself; the runner (see `task`) decides:
|
|
468
|
+
* - Ok → sends back the Ok value (`next(value)`), `yield*` yields `T`
|
|
469
|
+
* - Err → aborts and returns the Err Result
|
|
470
|
+
*/
|
|
471
|
+
*[Symbol.iterator]() {
|
|
472
|
+
return yield this;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Matcht auf den Err-Wert via `.when(...)` Kette.
|
|
476
|
+
*
|
|
477
|
+
* Hinweis: aus Type-Safety-Gründen ist `.match()` nur auf einem bereits zu `Err` verengten Result aufrufbar,
|
|
478
|
+
* z.B. innerhalb von `if (result.isErr()) { ... }`.
|
|
479
|
+
*/
|
|
480
|
+
match() {
|
|
481
|
+
if (this._tag === "Err") return new ErrorMatchBuilder(this.error);
|
|
482
|
+
throw new Error("match() can only be called on Err results. Use `if (result.isErr()) { ... }` first.");
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Matcht auf den Err-Wert, aber normalisiert jeden Branch zu einem `Result`:
|
|
486
|
+
* - Handler dürfen ein `Result` zurückgeben (wird direkt returned)
|
|
487
|
+
* - oder einen Error-Wert (wird zu `Err(error)` gewrappt)
|
|
488
|
+
*/
|
|
489
|
+
matchErr() {
|
|
490
|
+
const makeErr = (error) => err(error);
|
|
491
|
+
return ErrMatchBuilder.fromResult(this, makeErr);
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Serialisiert das Result in ein einfaches Objekt-Format.
|
|
495
|
+
* Behält die ursprünglichen Typen bei.
|
|
496
|
+
*/
|
|
497
|
+
serialize() {
|
|
498
|
+
if (this._tag === "Ok") return {
|
|
499
|
+
isSuccess: true,
|
|
500
|
+
data: this.value
|
|
501
|
+
};
|
|
502
|
+
return {
|
|
503
|
+
isSuccess: false,
|
|
504
|
+
error: this.error
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Serialisiert das Result in ein user-friendly Format.
|
|
509
|
+
* Konvertiert Errors zu lesbaren Strings.
|
|
510
|
+
*/
|
|
511
|
+
toUserFriendly() {
|
|
512
|
+
if (this._tag === "Ok") return {
|
|
513
|
+
isSuccess: true,
|
|
514
|
+
data: this.value
|
|
515
|
+
};
|
|
516
|
+
const error = this.error;
|
|
517
|
+
return {
|
|
518
|
+
isSuccess: false,
|
|
519
|
+
error: error && typeof error === "object" && "message" in error ? error.message : String(error)
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
var Ok = class extends ResultBase {
|
|
524
|
+
_tag = "Ok";
|
|
525
|
+
value;
|
|
526
|
+
error = void 0;
|
|
527
|
+
constructor(value) {
|
|
528
|
+
super();
|
|
529
|
+
this.value = value;
|
|
530
|
+
Object.freeze(this);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
var Err = class extends ResultBase {
|
|
534
|
+
_tag = "Err";
|
|
535
|
+
value = void 0;
|
|
536
|
+
error;
|
|
537
|
+
constructor(error) {
|
|
538
|
+
super();
|
|
539
|
+
this.error = error;
|
|
540
|
+
Object.freeze(this);
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
function ok(value) {
|
|
544
|
+
return new Ok(value);
|
|
545
|
+
}
|
|
546
|
+
function err(error) {
|
|
547
|
+
return new Err(error);
|
|
548
|
+
}
|
|
549
|
+
function okIf(condition, okValue, errValue) {
|
|
550
|
+
return condition ? ok(okValue) : err(errValue);
|
|
551
|
+
}
|
|
552
|
+
function okIfLazy(condition, okFn, errFn) {
|
|
553
|
+
return condition ? ok(okFn()) : err(errFn());
|
|
554
|
+
}
|
|
555
|
+
function fromNullable(value, error) {
|
|
556
|
+
if (value === null || value === void 0) return err(error);
|
|
557
|
+
return ok(value);
|
|
558
|
+
}
|
|
559
|
+
async function fromPromise(promise, errorMapper) {
|
|
560
|
+
try {
|
|
561
|
+
return ok(await promise);
|
|
562
|
+
} catch (error) {
|
|
563
|
+
try {
|
|
564
|
+
return err(errorMapper ? errorMapper(error) : error);
|
|
565
|
+
} catch (mapperError) {
|
|
566
|
+
return err(mapperError);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function tryFn(fn) {
|
|
571
|
+
try {
|
|
572
|
+
return ok(fn());
|
|
573
|
+
} catch (error) {
|
|
574
|
+
return err(error);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const Result = {
|
|
578
|
+
ok,
|
|
579
|
+
err,
|
|
580
|
+
fromNullable,
|
|
581
|
+
fromPromise,
|
|
582
|
+
try: tryFn
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
//#endregion
|
|
586
|
+
//#region src/core/isResult.ts
|
|
587
|
+
/**
|
|
588
|
+
* Checks whether a value is a Result.
|
|
589
|
+
* Pure function alternative for runtime checks.
|
|
590
|
+
*/
|
|
591
|
+
function isResult(value) {
|
|
592
|
+
return typeof value === "object" && value !== null && "isOk" in value && typeof value.isOk === "function" && "isErr" in value && typeof value.isErr === "function";
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
//#endregion
|
|
596
|
+
//#region src/gen.ts
|
|
597
|
+
async function task(makeGenerator, onThrow) {
|
|
598
|
+
const iterator = makeGenerator();
|
|
599
|
+
let input = void 0;
|
|
600
|
+
while (true) {
|
|
601
|
+
let step;
|
|
602
|
+
try {
|
|
603
|
+
step = await iterator.next(input);
|
|
604
|
+
} catch (caught) {
|
|
605
|
+
if (!onThrow) throw caught;
|
|
606
|
+
return err(onThrow(caught));
|
|
607
|
+
}
|
|
608
|
+
if (step.done) try {
|
|
609
|
+
const awaited = await step.value;
|
|
610
|
+
if (isResult(awaited)) return awaited;
|
|
611
|
+
return ok(awaited);
|
|
612
|
+
} catch (caught) {
|
|
613
|
+
if (!onThrow) throw caught;
|
|
614
|
+
return err(onThrow(caught));
|
|
615
|
+
}
|
|
616
|
+
const yielded = step.value;
|
|
617
|
+
if (!isResult(yielded)) throw new TypeError("task() expected yielded values to be Result. Use `yield*` on a Result.");
|
|
618
|
+
if (yielded.isOk()) {
|
|
619
|
+
input = yielded.value;
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
if (yielded.isErr()) {
|
|
623
|
+
try {
|
|
624
|
+
if (typeof iterator.return === "function") await iterator.return(void 0);
|
|
625
|
+
} catch (caught) {
|
|
626
|
+
if (!onThrow) throw caught;
|
|
627
|
+
return err(onThrow(caught));
|
|
628
|
+
}
|
|
629
|
+
return yielded;
|
|
630
|
+
}
|
|
631
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const gen = task;
|
|
635
|
+
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region src/core/fold.ts
|
|
638
|
+
/**
|
|
639
|
+
* Folds the Result into a single value by applying one of two functions.
|
|
640
|
+
* The end of the pipe.
|
|
641
|
+
*
|
|
642
|
+
* This is the pipe operator equivalent of the `.fold()` instance method.
|
|
643
|
+
*/
|
|
644
|
+
function fold(handlers) {
|
|
645
|
+
return (source) => {
|
|
646
|
+
if (source.isOk()) return handlers.ok(source.value);
|
|
647
|
+
if (source.isErr()) return handlers.err(source.error);
|
|
648
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
//#endregion
|
|
653
|
+
//#region src/core/foldAsync.ts
|
|
654
|
+
/**
|
|
655
|
+
* Async version of `fold`. Folds the Result into a single value asynchronously.
|
|
656
|
+
* The end of the pipe.
|
|
657
|
+
*
|
|
658
|
+
* This is the async pipe operator equivalent of the `.fold()` instance method.
|
|
659
|
+
*/
|
|
660
|
+
function foldAsync(handlers) {
|
|
661
|
+
return async (source) => {
|
|
662
|
+
if (source.isOk()) return await handlers.ok(source.value);
|
|
663
|
+
if (source.isErr()) return await handlers.err(source.error);
|
|
664
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
//#endregion
|
|
669
|
+
//#region src/core/unwrap.ts
|
|
1068
670
|
/**
|
|
1069
|
-
*
|
|
1070
|
-
*
|
|
671
|
+
* Gibt den Wert zurück oder wirft einen Error.
|
|
672
|
+
* Entspricht Rust `unwrap`.
|
|
1071
673
|
*/
|
|
1072
674
|
function unwrap(result) {
|
|
1073
675
|
if (result.isOk()) return result.value;
|
|
@@ -1076,10 +678,10 @@ function unwrap(result) {
|
|
|
1076
678
|
}
|
|
1077
679
|
|
|
1078
680
|
//#endregion
|
|
1079
|
-
//#region src/
|
|
681
|
+
//#region src/core/unwrapOr.ts
|
|
1080
682
|
/**
|
|
1081
|
-
*
|
|
1082
|
-
* Pure function
|
|
683
|
+
* Gibt den Wert zurück oder einen Default-Wert.
|
|
684
|
+
* Pure function Alternative zur Instanz-Methode.
|
|
1083
685
|
*/
|
|
1084
686
|
function unwrapOr(result, defaultValue) {
|
|
1085
687
|
if (result.isOk()) return result.value;
|
|
@@ -1087,10 +689,10 @@ function unwrapOr(result, defaultValue) {
|
|
|
1087
689
|
}
|
|
1088
690
|
|
|
1089
691
|
//#endregion
|
|
1090
|
-
//#region src/
|
|
692
|
+
//#region src/core/unwrapOrElse.ts
|
|
1091
693
|
/**
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
694
|
+
* Gibt den Wert zurück oder berechnet einen Default-Wert mit einer Funktion.
|
|
695
|
+
* Entspricht Rust `unwrap_or_else`.
|
|
1094
696
|
*/
|
|
1095
697
|
function unwrapOrElse(result, fn) {
|
|
1096
698
|
if (result.isOk()) return result.value;
|
|
@@ -1099,20 +701,20 @@ function unwrapOrElse(result, fn) {
|
|
|
1099
701
|
}
|
|
1100
702
|
|
|
1101
703
|
//#endregion
|
|
1102
|
-
//#region src/
|
|
704
|
+
//#region src/core/unwrapOrDefault.ts
|
|
1103
705
|
/**
|
|
1104
|
-
* Alias
|
|
1105
|
-
*
|
|
706
|
+
* Alias für `unwrapOr`.
|
|
707
|
+
* Entspricht Rust `unwrap_or_default` (mit explizitem Default-Wert).
|
|
1106
708
|
*/
|
|
1107
709
|
function unwrapOrDefault(result, defaultValue) {
|
|
1108
710
|
return unwrapOr(result, defaultValue);
|
|
1109
711
|
}
|
|
1110
712
|
|
|
1111
713
|
//#endregion
|
|
1112
|
-
//#region src/
|
|
714
|
+
//#region src/core/unwrapOrThrow.ts
|
|
1113
715
|
/**
|
|
1114
|
-
*
|
|
1115
|
-
*
|
|
716
|
+
* Gibt den Wert zurück oder wirft den originalen Err-Wert (nicht gewrappt).
|
|
717
|
+
* Nützlich um `Error`-Instanzen inkl. Stacktrace zu erhalten.
|
|
1116
718
|
*/
|
|
1117
719
|
function unwrapOrThrow(result) {
|
|
1118
720
|
if (result.isOk()) return result.value;
|
|
@@ -1121,10 +723,10 @@ function unwrapOrThrow(result) {
|
|
|
1121
723
|
}
|
|
1122
724
|
|
|
1123
725
|
//#endregion
|
|
1124
|
-
//#region src/
|
|
726
|
+
//#region src/core/unwrapErr.ts
|
|
1125
727
|
/**
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
728
|
+
* Gibt den Fehler zurück oder wirft einen Error.
|
|
729
|
+
* Entspricht Rust `unwrap_err`.
|
|
1128
730
|
*/
|
|
1129
731
|
function unwrapErr(result) {
|
|
1130
732
|
if (result.isErr()) return result.error;
|
|
@@ -1133,10 +735,10 @@ function unwrapErr(result) {
|
|
|
1133
735
|
}
|
|
1134
736
|
|
|
1135
737
|
//#endregion
|
|
1136
|
-
//#region src/
|
|
738
|
+
//#region src/core/expectResult.ts
|
|
1137
739
|
/**
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
740
|
+
* Gibt den Wert zurück oder wirft einen Error mit custom Nachricht.
|
|
741
|
+
* Entspricht Rust `expect`.
|
|
1140
742
|
*/
|
|
1141
743
|
function expectResult(result, message) {
|
|
1142
744
|
if (result.isOk()) return result.value;
|
|
@@ -1144,10 +746,10 @@ function expectResult(result, message) {
|
|
|
1144
746
|
}
|
|
1145
747
|
|
|
1146
748
|
//#endregion
|
|
1147
|
-
//#region src/
|
|
749
|
+
//#region src/core/expectErr.ts
|
|
1148
750
|
/**
|
|
1149
|
-
*
|
|
1150
|
-
*
|
|
751
|
+
* Gibt den Fehler zurück oder wirft einen Error mit custom Nachricht.
|
|
752
|
+
* Entspricht Rust `expect_err`.
|
|
1151
753
|
*/
|
|
1152
754
|
function expectErr(result, message) {
|
|
1153
755
|
if (result.isErr()) return result.error;
|
|
@@ -1155,30 +757,30 @@ function expectErr(result, message) {
|
|
|
1155
757
|
}
|
|
1156
758
|
|
|
1157
759
|
//#endregion
|
|
1158
|
-
//#region src/
|
|
760
|
+
//#region src/core/and.ts
|
|
1159
761
|
/**
|
|
1160
|
-
*
|
|
1161
|
-
*
|
|
762
|
+
* Kombiniert zwei Results. Gibt den zweiten zurück nur wenn erster Ok ist.
|
|
763
|
+
* Entspricht Rust `and`.
|
|
1162
764
|
*/
|
|
1163
765
|
function and(result, other) {
|
|
1164
766
|
return result.isOk() ? other : result;
|
|
1165
767
|
}
|
|
1166
768
|
|
|
1167
769
|
//#endregion
|
|
1168
|
-
//#region src/
|
|
770
|
+
//#region src/core/or.ts
|
|
1169
771
|
/**
|
|
1170
|
-
* Fallback
|
|
1171
|
-
*
|
|
772
|
+
* Fallback zu einem anderen Result wenn erster Err ist.
|
|
773
|
+
* Entspricht Rust `or`.
|
|
1172
774
|
*/
|
|
1173
775
|
function or(result, other) {
|
|
1174
776
|
return result.isOk() ? result : other;
|
|
1175
777
|
}
|
|
1176
778
|
|
|
1177
779
|
//#endregion
|
|
1178
|
-
//#region src/
|
|
780
|
+
//#region src/core/orElse.ts
|
|
1179
781
|
/**
|
|
1180
|
-
* Fallback
|
|
1181
|
-
*
|
|
782
|
+
* Fallback mit einer Funktion die ein Result zurückgibt.
|
|
783
|
+
* Entspricht Rust `or_else`.
|
|
1182
784
|
*/
|
|
1183
785
|
function orElse(result, fn) {
|
|
1184
786
|
if (result.isOk()) return result;
|
|
@@ -1187,10 +789,10 @@ function orElse(result, fn) {
|
|
|
1187
789
|
}
|
|
1188
790
|
|
|
1189
791
|
//#endregion
|
|
1190
|
-
//#region src/
|
|
792
|
+
//#region src/core/mapOr.ts
|
|
1191
793
|
/**
|
|
1192
|
-
*
|
|
1193
|
-
*
|
|
794
|
+
* Transformiert den Wert oder gibt einen Default-Wert zurück.
|
|
795
|
+
* Entspricht Rust `map_or`.
|
|
1194
796
|
*/
|
|
1195
797
|
function mapOr(result, defaultValue, fn) {
|
|
1196
798
|
if (result.isOk()) return fn(result.value);
|
|
@@ -1198,10 +800,10 @@ function mapOr(result, defaultValue, fn) {
|
|
|
1198
800
|
}
|
|
1199
801
|
|
|
1200
802
|
//#endregion
|
|
1201
|
-
//#region src/
|
|
803
|
+
//#region src/core/mapOrElse.ts
|
|
1202
804
|
/**
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
805
|
+
* Transformiert den Wert oder berechnet einen Default-Wert mit einer Funktion.
|
|
806
|
+
* Entspricht Rust `map_or_else`.
|
|
1205
807
|
*/
|
|
1206
808
|
function mapOrElse(result, defaultFn, fn) {
|
|
1207
809
|
if (result.isOk()) return fn(result.value);
|
|
@@ -1210,55 +812,11 @@ function mapOrElse(result, defaultFn, fn) {
|
|
|
1210
812
|
}
|
|
1211
813
|
|
|
1212
814
|
//#endregion
|
|
1213
|
-
//#region src/
|
|
1214
|
-
function zipImpl(left, right) {
|
|
1215
|
-
if (left.isErr()) return left;
|
|
1216
|
-
if (right.isErr()) return right;
|
|
1217
|
-
if (left.isOk() && right.isOk()) return ok([left.value, right.value]);
|
|
1218
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
1219
|
-
}
|
|
1220
|
-
function zip(...args) {
|
|
1221
|
-
if (args.length === 1) {
|
|
1222
|
-
const right$1 = args[0];
|
|
1223
|
-
return (left$1) => zipImpl(left$1, right$1);
|
|
1224
|
-
}
|
|
1225
|
-
const [left, right] = args;
|
|
1226
|
-
return zipImpl(left, right);
|
|
1227
|
-
}
|
|
1228
|
-
function combineImpl(left, right) {
|
|
1229
|
-
if (left.isOk() && right.isOk()) return ok([left.value, right.value]);
|
|
1230
|
-
const errors = [];
|
|
1231
|
-
if (left.isErr()) errors.push(left.error);
|
|
1232
|
-
if (right.isErr()) errors.push(right.error);
|
|
1233
|
-
return err(errors);
|
|
1234
|
-
}
|
|
1235
|
-
function combine(...args) {
|
|
1236
|
-
if (args.length === 1) {
|
|
1237
|
-
const right$1 = args[0];
|
|
1238
|
-
return (left$1) => combineImpl(left$1, right$1);
|
|
1239
|
-
}
|
|
1240
|
-
const [left, right] = args;
|
|
1241
|
-
return combineImpl(left, right);
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
//#endregion
|
|
1245
|
-
//#region src/combinators/swap.ts
|
|
1246
|
-
/**
|
|
1247
|
-
* Swaps Ok and Err.
|
|
1248
|
-
* Result<T, E> → Result<E, T>
|
|
1249
|
-
*/
|
|
1250
|
-
function swap(result) {
|
|
1251
|
-
if (result.isOk()) return err(result.value);
|
|
1252
|
-
if (result.isErr()) return ok(result.error);
|
|
1253
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
//#endregion
|
|
1257
|
-
//#region src/collections/sequence.ts
|
|
815
|
+
//#region src/core/sequence.ts
|
|
1258
816
|
/**
|
|
1259
|
-
*
|
|
1260
|
-
* Short-circuits
|
|
1261
|
-
*
|
|
817
|
+
* Kombiniert eine Liste von Results zu einem Result einer Liste.
|
|
818
|
+
* Short-circuits beim ersten Err.
|
|
819
|
+
* Analog zu Rust `collect::<Result<Vec<_>, _>>()`.
|
|
1262
820
|
*/
|
|
1263
821
|
function sequence(results) {
|
|
1264
822
|
const values = [];
|
|
@@ -1273,23 +831,23 @@ function sequence(results) {
|
|
|
1273
831
|
return ok(values);
|
|
1274
832
|
}
|
|
1275
833
|
/**
|
|
1276
|
-
* Alias
|
|
834
|
+
* Alias für `sequence`.
|
|
1277
835
|
*/
|
|
1278
836
|
function all(results) {
|
|
1279
837
|
return sequence(results);
|
|
1280
838
|
}
|
|
1281
839
|
|
|
1282
840
|
//#endregion
|
|
1283
|
-
//#region src/
|
|
841
|
+
//#region src/core/sequenceRecord.ts
|
|
1284
842
|
/**
|
|
1285
|
-
*
|
|
1286
|
-
* Short-circuits
|
|
843
|
+
* Wie `sequence`, aber für Records/Objekte.
|
|
844
|
+
* Short-circuits beim ersten Err.
|
|
1287
845
|
*/
|
|
1288
846
|
function sequenceRecord(record) {
|
|
1289
847
|
const out = {};
|
|
1290
848
|
for (const key of Object.keys(record)) {
|
|
1291
849
|
const result = record[key];
|
|
1292
|
-
if (!result)
|
|
850
|
+
if (!result) continue;
|
|
1293
851
|
if (result.isOk()) {
|
|
1294
852
|
out[key] = result.value;
|
|
1295
853
|
continue;
|
|
@@ -1301,33 +859,13 @@ function sequenceRecord(record) {
|
|
|
1301
859
|
}
|
|
1302
860
|
|
|
1303
861
|
//#endregion
|
|
1304
|
-
//#region src/
|
|
1305
|
-
/**
|
|
1306
|
-
* Parse a set of `Result`s, short-circuits when an input value is `Ok`.
|
|
1307
|
-
* If no `Ok` is found, returns an `Err` containing the collected error values.
|
|
1308
|
-
* Useful for "try multiple approaches until one works" patterns.
|
|
1309
|
-
*/
|
|
1310
|
-
function collectFirstOk(results) {
|
|
1311
|
-
const errors = [];
|
|
1312
|
-
for (const result of results) {
|
|
1313
|
-
if (result.isOk()) return ok(result.value);
|
|
1314
|
-
if (result.isErr()) {
|
|
1315
|
-
errors.push(result.error);
|
|
1316
|
-
continue;
|
|
1317
|
-
}
|
|
1318
|
-
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
1319
|
-
}
|
|
1320
|
-
return err(errors);
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
//#endregion
|
|
1324
|
-
//#region src/collections/collectFirstOkAsync.ts
|
|
862
|
+
//#region src/core/collectFirstOkAsync.ts
|
|
1325
863
|
/**
|
|
1326
|
-
* Async
|
|
864
|
+
* Async-Version von collectFirstOk.
|
|
1327
865
|
*
|
|
1328
|
-
* -
|
|
1329
|
-
* -
|
|
1330
|
-
* -
|
|
866
|
+
* - Nimmt entweder bereits gestartete Promises oder "Thunks" (`() => Awaitable<Result<...>>`).
|
|
867
|
+
* - Verarbeitet die Inputs strikt sequentiell (wie `for ... of` + `await`).
|
|
868
|
+
* - Gibt das erste `Ok` zurück und sammelt alle Errors wenn kein `Ok` gefunden wird.
|
|
1331
869
|
*/
|
|
1332
870
|
async function collectFirstOkAsync(inputs) {
|
|
1333
871
|
const errors = [];
|
|
@@ -1346,61 +884,43 @@ async function collectFirstOkAsync(inputs) {
|
|
|
1346
884
|
}
|
|
1347
885
|
|
|
1348
886
|
//#endregion
|
|
1349
|
-
//#region src/
|
|
887
|
+
//#region src/core/collectFirstOkParallelAsync.ts
|
|
1350
888
|
/**
|
|
1351
|
-
* Parallel
|
|
889
|
+
* Parallel-Variante von `collectFirstOkAsync`.
|
|
1352
890
|
*
|
|
1353
|
-
* -
|
|
1354
|
-
* -
|
|
1355
|
-
* -
|
|
1356
|
-
* -
|
|
891
|
+
* - Startet alle Inputs sofort (Promises oder Thunks).
|
|
892
|
+
* - Gibt das erste `Ok` zurück, sobald es verfügbar ist.
|
|
893
|
+
* - Wenn kein `Ok` gefunden wird, gibt ein `Err` mit allen Error-Werten (in Input-Reihenfolge) zurück.
|
|
894
|
+
* - Rejections werden als `ErrValue` behandelt (`caught as ErrValue`).
|
|
895
|
+
* - Wenn mehrere Inputs ein `Ok` liefern, gewinnt das zuerst abgeschlossene Ergebnis.
|
|
896
|
+
* Bei gleichzeitiger Completion gewinnt das zuerst beobachtete Ergebnis.
|
|
897
|
+
* - Wenn kein `Ok` kommt und mindestens ein Input nie settled, bleibt das Promise offen.
|
|
1357
898
|
*/
|
|
1358
|
-
async function
|
|
899
|
+
async function collectFirstOkParallelAsync(inputs) {
|
|
1359
900
|
if (inputs.length === 0) return err([]);
|
|
1360
|
-
const
|
|
1361
|
-
const
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
if (
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
if (remaining === 0) {
|
|
1375
|
-
done = true;
|
|
1376
|
-
finishAllErr();
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1379
|
-
inputs.forEach((input, index) => {
|
|
1380
|
-
Promise.resolve().then(() => typeof input === "function" ? input() : input).then((result) => {
|
|
1381
|
-
if (done) return;
|
|
1382
|
-
if (result.isOk()) {
|
|
1383
|
-
done = true;
|
|
1384
|
-
resolve(ok(result.value));
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
if (result.isErr()) {
|
|
1388
|
-
settleError(index, result.error);
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
settleError(index, /* @__PURE__ */ new Error("Unreachable: Result is neither Ok nor Err"));
|
|
1392
|
-
}).catch((caught) => {
|
|
1393
|
-
settleError(index, caught);
|
|
1394
|
-
});
|
|
1395
|
-
});
|
|
901
|
+
const started = inputs.map((input) => typeof input === "function" ? Promise.resolve().then(input) : input);
|
|
902
|
+
const firstOk = new Promise((resolve) => {
|
|
903
|
+
for (const promise of started) promise.then((result) => {
|
|
904
|
+
if (result.isOk()) resolve(ok(result.value));
|
|
905
|
+
}).catch(() => {});
|
|
906
|
+
});
|
|
907
|
+
const allErrors = Promise.allSettled(started).then((settled) => {
|
|
908
|
+
const errors = [];
|
|
909
|
+
for (const entry of settled) if (entry.status === "fulfilled") {
|
|
910
|
+
const result = entry.value;
|
|
911
|
+
if (result.isErr()) errors.push(result.error);
|
|
912
|
+
else if (!result.isOk()) errors.push(/* @__PURE__ */ new Error("Unreachable: Result is neither Ok nor Err"));
|
|
913
|
+
} else errors.push(entry.reason);
|
|
914
|
+
return err(errors);
|
|
1396
915
|
});
|
|
916
|
+
return Promise.race([firstOk, allErrors]);
|
|
1397
917
|
}
|
|
1398
918
|
|
|
1399
919
|
//#endregion
|
|
1400
|
-
//#region src/
|
|
920
|
+
//#region src/core/collectAllErrors.ts
|
|
1401
921
|
/**
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
922
|
+
* Kombiniert eine Liste von Results.
|
|
923
|
+
* Gibt Ok(values) nur zurück wenn alle Ok sind, sonst Err([errors]).
|
|
1404
924
|
*/
|
|
1405
925
|
function collectAllErrors(results) {
|
|
1406
926
|
const values = [];
|
|
@@ -1420,9 +940,9 @@ function collectAllErrors(results) {
|
|
|
1420
940
|
}
|
|
1421
941
|
|
|
1422
942
|
//#endregion
|
|
1423
|
-
//#region src/
|
|
943
|
+
//#region src/core/partition.ts
|
|
1424
944
|
/**
|
|
1425
|
-
*
|
|
945
|
+
* Partitioniert Results in Ok-Werte und Err-Fehler.
|
|
1426
946
|
*/
|
|
1427
947
|
function partition(results) {
|
|
1428
948
|
const oks = [];
|
|
@@ -1442,7 +962,7 @@ function partition(results) {
|
|
|
1442
962
|
}
|
|
1443
963
|
|
|
1444
964
|
//#endregion
|
|
1445
|
-
//#region src/
|
|
965
|
+
//#region src/core/flatten.ts
|
|
1446
966
|
/**
|
|
1447
967
|
* Flacht ein nested Result ab.
|
|
1448
968
|
* Result<Result<T, E>, E> → Result<T, E>
|
|
@@ -1454,30 +974,53 @@ function flatten(result) {
|
|
|
1454
974
|
}
|
|
1455
975
|
|
|
1456
976
|
//#endregion
|
|
1457
|
-
//#region src/
|
|
977
|
+
//#region src/core/toPromise.ts
|
|
978
|
+
/**
|
|
979
|
+
* Konvertiert ein Result zu einem Promise.
|
|
980
|
+
* Ok → resolve(value), Err → reject(error)
|
|
981
|
+
*/
|
|
982
|
+
function toPromise(result) {
|
|
983
|
+
if (result.isOk()) return Promise.resolve(result.value);
|
|
984
|
+
if (result.isErr()) return Promise.reject(result.error);
|
|
985
|
+
throw new Error("Unreachable: Result is neither Ok nor Err");
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/core/toNullable.ts
|
|
990
|
+
/**
|
|
991
|
+
* Konvertiert ein Result zu `T | null`.
|
|
992
|
+
* Ok → value, Err → null
|
|
993
|
+
*/
|
|
994
|
+
function toNullable(result) {
|
|
995
|
+
if (result.isOk()) return result.value;
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
//#endregion
|
|
1000
|
+
//#region src/core/isOk.ts
|
|
1458
1001
|
/**
|
|
1459
|
-
*
|
|
1460
|
-
* Pure function
|
|
1002
|
+
* Prüft ob ein Result Ok ist.
|
|
1003
|
+
* Pure function Alternative zur Instanz-Methode.
|
|
1461
1004
|
*/
|
|
1462
1005
|
function isOk(result) {
|
|
1463
1006
|
return result.isOk();
|
|
1464
1007
|
}
|
|
1465
1008
|
|
|
1466
1009
|
//#endregion
|
|
1467
|
-
//#region src/
|
|
1010
|
+
//#region src/core/isErr.ts
|
|
1468
1011
|
/**
|
|
1469
|
-
*
|
|
1470
|
-
* Pure function
|
|
1012
|
+
* Prüft ob ein Result Err ist.
|
|
1013
|
+
* Pure function Alternative zur Instanz-Methode.
|
|
1471
1014
|
*/
|
|
1472
1015
|
function isErr(result) {
|
|
1473
1016
|
return result.isErr();
|
|
1474
1017
|
}
|
|
1475
1018
|
|
|
1476
1019
|
//#endregion
|
|
1477
|
-
//#region src/
|
|
1020
|
+
//#region src/core/contains.ts
|
|
1478
1021
|
/**
|
|
1479
|
-
*
|
|
1480
|
-
*
|
|
1022
|
+
* Prüft ob das Result einen bestimmten Wert enthält.
|
|
1023
|
+
* Entspricht Rust `contains`.
|
|
1481
1024
|
*/
|
|
1482
1025
|
function contains(result, value) {
|
|
1483
1026
|
if (!result.isOk()) return false;
|
|
@@ -1485,10 +1028,10 @@ function contains(result, value) {
|
|
|
1485
1028
|
}
|
|
1486
1029
|
|
|
1487
1030
|
//#endregion
|
|
1488
|
-
//#region src/
|
|
1031
|
+
//#region src/core/containsErr.ts
|
|
1489
1032
|
/**
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1033
|
+
* Prüft ob das Result einen bestimmten Fehler enthält.
|
|
1034
|
+
* Analog zu `contains` für den Err-Fall.
|
|
1492
1035
|
*/
|
|
1493
1036
|
function containsErr(result, error) {
|
|
1494
1037
|
if (!result.isErr()) return false;
|
|
@@ -1496,6 +1039,8 @@ function containsErr(result, error) {
|
|
|
1496
1039
|
}
|
|
1497
1040
|
|
|
1498
1041
|
//#endregion
|
|
1042
|
+
exports.Err = Err;
|
|
1043
|
+
exports.Ok = Ok;
|
|
1499
1044
|
exports.Result = Result;
|
|
1500
1045
|
exports.all = all;
|
|
1501
1046
|
exports.and = and;
|
|
@@ -1503,7 +1048,7 @@ exports.bimap = bimap;
|
|
|
1503
1048
|
exports.collectAllErrors = collectAllErrors;
|
|
1504
1049
|
exports.collectFirstOk = collectFirstOk;
|
|
1505
1050
|
exports.collectFirstOkAsync = collectFirstOkAsync;
|
|
1506
|
-
exports.
|
|
1051
|
+
exports.collectFirstOkParallelAsync = collectFirstOkParallelAsync;
|
|
1507
1052
|
exports.combine = combine;
|
|
1508
1053
|
exports.contains = contains;
|
|
1509
1054
|
exports.containsErr = containsErr;
|