@onrails/result 0.4.2 → 0.5.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/DESIGN.md +12 -1
- package/README.md +45 -1
- package/dist/compat/neverthrow.cjs +234 -48
- package/dist/compat/neverthrow.cjs.map +1 -1
- package/dist/compat/neverthrow.d.cts +38 -4
- package/dist/compat/neverthrow.d.ts +38 -4
- package/dist/compat/neverthrow.js +230 -49
- package/dist/compat/neverthrow.js.map +1 -1
- package/dist/extra.cjs +43 -2
- package/dist/extra.cjs.map +1 -1
- package/dist/extra.js +43 -2
- package/dist/extra.js.map +1 -1
- package/dist/fluent.cjs +88 -14
- package/dist/fluent.cjs.map +1 -1
- package/dist/fluent.js +88 -14
- package/dist/fluent.js.map +1 -1
- package/dist/index.cjs +120 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +120 -38
- package/dist/index.js.map +1 -1
- package/dist/internal/ctor.d.cts +8 -8
- package/dist/internal/ctor.d.ts +8 -8
- package/dist/internal/proto.d.cts +3 -0
- package/dist/internal/proto.d.ts +3 -0
- package/dist/railway.cjs +105 -31
- package/dist/railway.cjs.map +1 -1
- package/dist/railway.js +105 -31
- package/dist/railway.js.map +1 -1
- package/dist/try-gen.cjs +43 -6
- package/dist/try-gen.cjs.map +1 -1
- package/dist/try-gen.js +43 -6
- package/dist/try-gen.js.map +1 -1
- package/dist/types.d.cts +67 -9
- package/dist/types.d.ts +67 -9
- package/package.json +2 -1
package/DESIGN.md
CHANGED
|
@@ -29,6 +29,17 @@ type Result<T, E> =
|
|
|
29
29
|
- Optional dot-chaining via `fluent(r)` in `@onrails/result/fluent`. Mirrors every instance-appropriate core transform; `test/parity.spec.ts` enforces the mirror (both directions) across core, fluent, and the neverthrow compat shim. `ResultAsync` is already fluent (its methods return `ResultAsync`) — no `fluentAsync` wrapper; wrapping it would just be a one-line delegate to itself.
|
|
30
30
|
- The fluent wrapper stays local: `fluent(r)` opens and a terminal (`toResult`/`toString`/`match`/`unwrapOr`) closes within one expression — it's a closure over data, not data, so it must never be a return type, an exported binding, a stored field, or an argument to a serialize/`postMessage`/cache call. `@onrails/eslint-plugin` and `@onrails/biome-plugin` enforce this via `fluent-stays-local` (RFC 0002 §9).
|
|
31
31
|
|
|
32
|
+
## Prototype carriers (breaking)
|
|
33
|
+
|
|
34
|
+
`ok` / `err` return live carriers: `_tag` plus `value` / `error` as own enumerable properties, with `map`, `mapErr`, `flatMap`/`andThen`, `recover`, `tap`, `tapErr`, `match` and `unwrapOr` on a shared non-enumerable prototype (`src/internal/proto.ts`). `r.map(f).flatMap(g)` works on any core `Result`, with core semantics (`tap` propagates throws, `recover` keeps `T`). The neverthrow-semantics names (`andTee`, `orElse`, ...) stay in compat.
|
|
35
|
+
|
|
36
|
+
- **Serialization:** `JSON.stringify` output is unchanged (same keys, same order). `JSON.parse`, `structuredClone`, spread and `postMessage` return plain data without the methods, while the type still claims them. Lift at every such sink with `Result.from`. `ResultData<T, E>` is the plain shape `from` accepts. Suite `test/prototype-core.spec.ts` covers all four routes.
|
|
37
|
+
- **Literals:** a hand-written `{ _tag: "Ok", value }` is no longer a `Result` (it lacks the methods). `onrails-codemod --literals` rewrites them to `ok` / `err`.
|
|
38
|
+
- **Narrowed branches:** `Err<T, E>` now carries `T` through its methods, so returning a narrowed `Err` as a `Result` with a different `T` needs `err(r.error)` (the same as neverthrow).
|
|
39
|
+
- **Redux, immer:** carriers are not plain objects (prototype is not `Object.prototype`). Redux Toolkit's serializability check flags them, and immer will not draft them. Store `ResultData` (or call `Result.from` on read) and convert at the edge.
|
|
40
|
+
- **Compat shim:** `CompatResult` still wraps a core carrier (`inner`) and now delegates `map`, `mapErr`, `andThen` and `unwrapOr` to the prototype methods. It cannot collapse into the core carrier: its semantics differ by design (`orElse` widens, `andTee` swallows throws, `value` / `error` getters throw), and the differential suite (`neverthrow-diff.spec.ts`) pins exactly that.
|
|
41
|
+
- **Packages:** `result` does not know `maybe`. `Maybe` has the mirrored prototype and `Maybe.from`; `toResult` / `fromResult` stay in `@onrails/maybe/interop`.
|
|
42
|
+
|
|
32
43
|
## Sync / async interop
|
|
33
44
|
|
|
34
45
|
Two distinct lift paths:
|
|
@@ -102,7 +113,7 @@ Use `flatMap` for dependent checks where later checks need earlier successful va
|
|
|
102
113
|
|
|
103
114
|
## v1.0 gate
|
|
104
115
|
|
|
105
|
-
- bun tests: core ops,
|
|
116
|
+
- bun tests: core ops, functor/monad/error-functor laws on `Result` and `ResultAsync` (`test/result.laws.spec.ts`), JSON and `structuredClone` round-trips, and a neverthrow differential (`test/neverthrow-diff.spec.ts`): a surface diff against the installed package plus randomised op chains run through both libraries.
|
|
106
117
|
- README with tagged-error guidance.
|
|
107
118
|
- **Not** in v1.0: npm publish.
|
|
108
119
|
|
package/README.md
CHANGED
|
@@ -356,6 +356,25 @@ Both cap at **12 steps**. That cap is deliberate: a single recursive variadic si
|
|
|
356
356
|
|
|
357
357
|
## Breaking changes
|
|
358
358
|
|
|
359
|
+
### Carriers have methods; plain data needs `Result.from`
|
|
360
|
+
|
|
361
|
+
`ok` / `err` (and `some` / `none` in `@onrails/maybe`) now return carriers with `map`, `mapErr`, `flatMap` / `andThen`, `recover`, `tap`, `tapErr`, `match` and `unwrapOr` on a non-enumerable prototype, so `ok(2).map(f).flatMap(g)` works with no wrapper. `_tag` and `value` / `error` are still the only own keys, and `JSON.stringify` output is byte-identical. The module functions (`map(r, f)`, `map(f)(r)`) are unchanged.
|
|
362
|
+
|
|
363
|
+
| Before | After |
|
|
364
|
+
|---|---|
|
|
365
|
+
| `{ _tag: "Ok", value: x }` | `ok(x)` — run `onrails-codemod <dir> --literals` |
|
|
366
|
+
| `{ _tag: "Err", error: e }` | `err(e)` |
|
|
367
|
+
| `{ _tag: "Some", value: x }` / `{ _tag: "None" }` | `some(x)` / `none()` |
|
|
368
|
+
| `JSON.parse(raw) as Result<T, E>` | `Result.from<T, E>(JSON.parse(raw))` |
|
|
369
|
+
| `structuredClone(r)` used as a `Result` | `Result.from(structuredClone(r))` |
|
|
370
|
+
| `if (isErr(r)) return r;` returning a different `T` | `if (isErr(r)) return err(r.error);` |
|
|
371
|
+
|
|
372
|
+
`JSON.parse`, `structuredClone`, object spread, `postMessage` and IndexedDB hand back plain data without the methods, while the type still claims them. `Result.from` (and `Maybe.from`) lift it back; `ResultData<T, E>` / `MaybeData<T>` name the plain shape. `@onrails/eslint-plugin` and `@onrails/biome-plugin` ship `carrier-sinks-need-from` to flag the cast forms.
|
|
373
|
+
|
|
374
|
+
**Redux Toolkit.** Carriers are not plain objects (their prototype is not `Object.prototype`), so the serializability middleware warns on them in actions and state. Keep `ResultData` / `MaybeData` in the store and call `Result.from` / `Maybe.from` in selectors,. Both are cheap: `from` is one allocation.
|
|
375
|
+
|
|
376
|
+
**immer.** `produce` only drafts plain objects and arrays, so a carrier inside state is treated as an opaque value: replace it wholesale (`draft.user = ok(next)`), do not mutate through it. Carriers are never mutated by the library, so sharing them across drafts is safe.
|
|
377
|
+
|
|
359
378
|
### `ok` / `err` lock inline literals
|
|
360
379
|
|
|
361
380
|
Inline literals no longer widen: `ok("a")` is `Result<"a", never>` and `err({ kind: "io" })` carries `{ readonly kind: "io" }`. Annotated values and generic type parameters are unaffected. One call shape needs a change:
|
|
@@ -405,7 +424,28 @@ import { ResultAsync, Result, ok, err, okAsync, errAsync } from "@onrails/result
|
|
|
405
424
|
- `Result` / `ResultAsync` are class-shaped (`CompatResult` / `CompatResultAsync`).
|
|
406
425
|
- `await ra` resolves to a `CompatResult<T, E>` (thenable), so `.isOk()`, `.value`, `.error`, `.match()`, `.unwrapOr()` all work without an extra `.resolve()` call.
|
|
407
426
|
- `andThen` / `chain` / `flatMap` / `orElse` accept any of `CompatResultAsync` / `ResultAsync` / `CompatResult` / tagged `Result` returns and union the error type.
|
|
408
|
-
- Supported:
|
|
427
|
+
- Supported: every public member of neverthrow 8.x. `bun test` diffs the shim's surface against the real package (`test/neverthrow-diff.spec.ts`), so a new neverthrow member fails CI until it is covered.
|
|
428
|
+
- Guards: `isOk()` / `isErr()` are type guards; `.value` / `.error` are visible only after narrowing, as in neverthrow. The `else` branch of an `isOk()` check is not narrowed to the error side (the shim is one class, not an `Ok | Err` union) — use `match` or `isErr()`.
|
|
429
|
+
- `Ok` / `Err` support `new` and `instanceof`; `safeTry` accepts sync and async generators using `.safeUnwrap()`.
|
|
430
|
+
|
|
431
|
+
#### Compat name to core name
|
|
432
|
+
|
|
433
|
+
| neverthrow / compat | core (`@onrails/result`) | Notes |
|
|
434
|
+
|---|---|---|
|
|
435
|
+
| `r.map(f)` / `r.mapErr(f)` | `map(r, f)` / `mapErr(r, f)` | same |
|
|
436
|
+
| `r.andThen(f)` / `chain` / `flatMap` | `flatMap(r, f)` | `flatMap` is canonical |
|
|
437
|
+
| `r.orElse(f)` | `recover(r, f)` | |
|
|
438
|
+
| `r.andTee(f)` / `r.orTee(f)` | `tap(r, f)` / `tapErr(r, f)` | `tap` takes a pure side effect; compat also swallows a throwing callback, core does not |
|
|
439
|
+
| `r.andThrough(f)` | `flatMap(r, (v) => map(f(v), () => v))` | keeps the original `Ok` value, surfaces the callback's `Err` |
|
|
440
|
+
| `r.asyncMap(f)` | `ResultAsync.fromResult(r).map(f)` | |
|
|
441
|
+
| `r.match(ok, err)` | `match(r, ok, err)` | |
|
|
442
|
+
| `r.unwrapOr(d)` | `unwrapOr(r, d)` | |
|
|
443
|
+
| `r._unsafeUnwrap()` | `unwrapOk(r)` | assertion tier |
|
|
444
|
+
| `Result.fromThrowable(f, h)` | `fromThrowable(f, h)` | |
|
|
445
|
+
| `Result.combine` / `combineWithAllErrors` | `combineTuple` / `validateTuple` | |
|
|
446
|
+
| `safeTry(function* () { ... })` | `tryGen(() => { ... })` | `yield* r.safeUnwrap()` becomes `$(r)`; `tryGen` is sync, use `ResultAsync` chains for async bodies |
|
|
447
|
+
| `ok(1) instanceof Ok` | `isOk(r)` | |
|
|
448
|
+
|
|
409
449
|
- Treat the compat surface as a migration step, not the destination — once a package migrates, switch its imports to `@onrails/result` and `@onrails/result/fluent`.
|
|
410
450
|
|
|
411
451
|
## Subpaths
|
|
@@ -421,4 +461,8 @@ import { ResultAsync, Result, ok, err, okAsync, errAsync } from "@onrails/result
|
|
|
421
461
|
| `@onrails/result/try-gen` | `tryGen`, `yieldResult`, `$` |
|
|
422
462
|
| `@onrails/result/compat/neverthrow` | Migration shim |
|
|
423
463
|
|
|
464
|
+
## Benchmarks
|
|
465
|
+
|
|
466
|
+
Runtime + fair import-graph size vs `neverthrow`: see [`../bench/RESULTS.md`](../bench/RESULTS.md). Regenerated with `bun run bench:md` from the repo root.
|
|
467
|
+
|
|
424
468
|
See [DESIGN.md](./DESIGN.md).
|
|
@@ -1,14 +1,88 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// src/internal/
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
// src/internal/proto.ts
|
|
4
|
+
var INSPECT = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
5
|
+
var OkImpl = class _OkImpl {
|
|
6
|
+
_tag;
|
|
7
|
+
value;
|
|
8
|
+
// explicit assignment order keeps `_tag` first, so JSON key order matches the plain-data shape
|
|
9
|
+
constructor(value) {
|
|
10
|
+
this._tag = "Ok";
|
|
11
|
+
this.value = value;
|
|
12
|
+
}
|
|
13
|
+
[INSPECT](_depth, options, inspect) {
|
|
14
|
+
return `Ok(${inspect(this.value, options)})`;
|
|
15
|
+
}
|
|
16
|
+
map(fn) {
|
|
17
|
+
return new _OkImpl(fn(this.value));
|
|
18
|
+
}
|
|
19
|
+
mapErr(_fn) {
|
|
20
|
+
return new _OkImpl(this.value);
|
|
21
|
+
}
|
|
22
|
+
flatMap(fn) {
|
|
23
|
+
return fn(this.value);
|
|
24
|
+
}
|
|
25
|
+
andThen(fn) {
|
|
26
|
+
return fn(this.value);
|
|
27
|
+
}
|
|
28
|
+
recover(_fn) {
|
|
29
|
+
return new _OkImpl(this.value);
|
|
30
|
+
}
|
|
31
|
+
tap(fn) {
|
|
32
|
+
fn(this.value);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
tapErr(_fn) {
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
match(onOk, _onErr) {
|
|
39
|
+
return onOk(this.value);
|
|
40
|
+
}
|
|
41
|
+
unwrapOr(_defaultValue) {
|
|
42
|
+
return this.value;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var ErrImpl = class _ErrImpl {
|
|
46
|
+
_tag;
|
|
47
|
+
error;
|
|
48
|
+
constructor(error) {
|
|
49
|
+
this._tag = "Err";
|
|
50
|
+
this.error = error;
|
|
51
|
+
}
|
|
52
|
+
[INSPECT](_depth, options, inspect) {
|
|
53
|
+
return `Err(${inspect(this.error, options)})`;
|
|
54
|
+
}
|
|
55
|
+
map(_fn) {
|
|
56
|
+
return new _ErrImpl(this.error);
|
|
57
|
+
}
|
|
58
|
+
mapErr(fn) {
|
|
59
|
+
return new _ErrImpl(fn(this.error));
|
|
60
|
+
}
|
|
61
|
+
flatMap(_fn) {
|
|
62
|
+
return new _ErrImpl(this.error);
|
|
63
|
+
}
|
|
64
|
+
andThen(_fn) {
|
|
65
|
+
return new _ErrImpl(this.error);
|
|
66
|
+
}
|
|
67
|
+
recover(fn) {
|
|
68
|
+
return fn(this.error);
|
|
69
|
+
}
|
|
70
|
+
tap(_fn) {
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
tapErr(fn) {
|
|
74
|
+
fn(this.error);
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
match(_onOk, onErr) {
|
|
78
|
+
return onErr(this.error);
|
|
79
|
+
}
|
|
80
|
+
unwrapOr(defaultValue) {
|
|
81
|
+
return defaultValue;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var newOk = (value) => new OkImpl(value);
|
|
85
|
+
var newErr = (error) => new ErrImpl(error);
|
|
12
86
|
|
|
13
87
|
// src/internal/dual.ts
|
|
14
88
|
var dual = (arity, body) => {
|
|
@@ -22,30 +96,22 @@ var isOk = (result) => result._tag === "Ok";
|
|
|
22
96
|
var isErr = (result) => result._tag === "Err";
|
|
23
97
|
var map = dual(
|
|
24
98
|
2,
|
|
25
|
-
(result, fn) => isOk(result) ?
|
|
99
|
+
(result, fn) => isOk(result) ? newOk(fn(result.value)) : newErr(result.error)
|
|
26
100
|
);
|
|
27
101
|
var mapErr = dual(
|
|
28
102
|
2,
|
|
29
|
-
(result, fn) => isErr(result) ?
|
|
103
|
+
(result, fn) => isErr(result) ? newErr(fn(result.error)) : newOk(result.value)
|
|
30
104
|
);
|
|
31
105
|
var bimap = dual(
|
|
32
106
|
3,
|
|
33
|
-
(result, onOk, onErr) => isOk(result) ?
|
|
34
|
-
);
|
|
35
|
-
var flatMap = dual(
|
|
36
|
-
2,
|
|
37
|
-
(result, fn) => isOk(result) ? fn(result.value) : mkErr(result.error)
|
|
38
|
-
);
|
|
39
|
-
var unwrapOr = dual(
|
|
40
|
-
2,
|
|
41
|
-
(result, defaultValue) => isOk(result) ? result.value : defaultValue
|
|
107
|
+
(result, onOk, onErr) => isOk(result) ? newOk(onOk(result.value)) : newErr(onErr(result.error))
|
|
42
108
|
);
|
|
43
109
|
function fromThrowable(fn, onThrow) {
|
|
44
110
|
return (...args) => {
|
|
45
111
|
try {
|
|
46
|
-
return
|
|
112
|
+
return newOk(fn(...args));
|
|
47
113
|
} catch (error) {
|
|
48
|
-
return
|
|
114
|
+
return newErr(onThrow(error));
|
|
49
115
|
}
|
|
50
116
|
};
|
|
51
117
|
}
|
|
@@ -65,11 +131,11 @@ var sequenceSettled = (settled) => {
|
|
|
65
131
|
const values = [];
|
|
66
132
|
for (const result of settled) {
|
|
67
133
|
if (isErr(result)) {
|
|
68
|
-
return
|
|
134
|
+
return newErr(result.error);
|
|
69
135
|
}
|
|
70
136
|
values.push(result.value);
|
|
71
137
|
}
|
|
72
|
-
return
|
|
138
|
+
return newOk(values);
|
|
73
139
|
};
|
|
74
140
|
var ResultAsync = class _ResultAsync {
|
|
75
141
|
constructor(run) {
|
|
@@ -106,9 +172,9 @@ var ResultAsync = class _ResultAsync {
|
|
|
106
172
|
static fromPromise(promise, onReject) {
|
|
107
173
|
return new _ResultAsync(async () => {
|
|
108
174
|
try {
|
|
109
|
-
return
|
|
175
|
+
return newOk(await promise);
|
|
110
176
|
} catch (error) {
|
|
111
|
-
return
|
|
177
|
+
return newErr(onReject(error));
|
|
112
178
|
}
|
|
113
179
|
});
|
|
114
180
|
}
|
|
@@ -122,7 +188,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
122
188
|
* ```
|
|
123
189
|
*/
|
|
124
190
|
static fromSafePromise(promise) {
|
|
125
|
-
return new _ResultAsync(async () =>
|
|
191
|
+
return new _ResultAsync(async () => newOk(await promise));
|
|
126
192
|
}
|
|
127
193
|
/**
|
|
128
194
|
* Defers work until {@link resolve}. Unlike {@link fromPromise}, the factory
|
|
@@ -140,13 +206,13 @@ var ResultAsync = class _ResultAsync {
|
|
|
140
206
|
return new _ResultAsync(fn);
|
|
141
207
|
}
|
|
142
208
|
static ok(value) {
|
|
143
|
-
return new _ResultAsync(async () =>
|
|
209
|
+
return new _ResultAsync(async () => newOk(value));
|
|
144
210
|
}
|
|
145
211
|
static of(value) {
|
|
146
212
|
return _ResultAsync.ok(value);
|
|
147
213
|
}
|
|
148
214
|
static err(error) {
|
|
149
|
-
return new _ResultAsync(async () =>
|
|
215
|
+
return new _ResultAsync(async () => newErr(error));
|
|
150
216
|
}
|
|
151
217
|
/**
|
|
152
218
|
* Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
|
|
@@ -164,7 +230,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
164
230
|
try {
|
|
165
231
|
return await promise;
|
|
166
232
|
} catch (error) {
|
|
167
|
-
return
|
|
233
|
+
return newErr(mapDefect(error));
|
|
168
234
|
}
|
|
169
235
|
});
|
|
170
236
|
}
|
|
@@ -186,11 +252,11 @@ var ResultAsync = class _ResultAsync {
|
|
|
186
252
|
for (const ra of results) {
|
|
187
253
|
const result = await ra.resolve();
|
|
188
254
|
if (isErr(result)) {
|
|
189
|
-
return
|
|
255
|
+
return newErr(result.error);
|
|
190
256
|
}
|
|
191
257
|
values.push(result.value);
|
|
192
258
|
}
|
|
193
|
-
return
|
|
259
|
+
return newOk(values);
|
|
194
260
|
});
|
|
195
261
|
}
|
|
196
262
|
/**
|
|
@@ -285,7 +351,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
285
351
|
return new _ResultAsync(async () => {
|
|
286
352
|
const first = await this.resolve();
|
|
287
353
|
if (isErr(first)) {
|
|
288
|
-
return first;
|
|
354
|
+
return newErr(first.error);
|
|
289
355
|
}
|
|
290
356
|
const next = fn(first.value);
|
|
291
357
|
return next instanceof _ResultAsync ? next.resolve() : next;
|
|
@@ -317,7 +383,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
317
383
|
return new _ResultAsync(async () => {
|
|
318
384
|
const first = await this.resolve();
|
|
319
385
|
if (!isErr(first)) {
|
|
320
|
-
return first;
|
|
386
|
+
return newOk(first.value);
|
|
321
387
|
}
|
|
322
388
|
const next = fn(first.error);
|
|
323
389
|
return next instanceof _ResultAsync ? next.resolve() : next;
|
|
@@ -438,15 +504,29 @@ var ResultAsync = class _ResultAsync {
|
|
|
438
504
|
var combine = (results) => {
|
|
439
505
|
const values = [];
|
|
440
506
|
for (const result of results) {
|
|
441
|
-
if (isErr(result)) return
|
|
507
|
+
if (isErr(result)) return newErr(result.error);
|
|
442
508
|
values.push(result.value);
|
|
443
509
|
}
|
|
444
|
-
return
|
|
510
|
+
return newOk(values);
|
|
445
511
|
};
|
|
446
512
|
var combineTuple = (results, ..._guard) => (
|
|
447
513
|
// Runtime identical to combine; the cast restores per-index tuple types.
|
|
514
|
+
// `unknown` hop: the tuple type is computed from R, which TS cannot relate to the runtime array.
|
|
448
515
|
combine(results)
|
|
449
516
|
);
|
|
517
|
+
function validateAll(results, combineErrors) {
|
|
518
|
+
const values = [];
|
|
519
|
+
const errors = [];
|
|
520
|
+
for (const result of results) {
|
|
521
|
+
if (isErr(result)) {
|
|
522
|
+
errors.push(result.error);
|
|
523
|
+
} else {
|
|
524
|
+
values.push(result.value);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (errors.length === 0) return newOk(values);
|
|
528
|
+
return newErr(errors);
|
|
529
|
+
}
|
|
450
530
|
|
|
451
531
|
// src/compat/neverthrow.ts
|
|
452
532
|
var CompatResult = class _CompatResult {
|
|
@@ -463,11 +543,12 @@ var CompatResult = class _CompatResult {
|
|
|
463
543
|
combineTuple(results.map((r) => r.inner))
|
|
464
544
|
);
|
|
465
545
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
546
|
+
// The `as unknown as` casts below restore per-index tuple types computed from R, which TS cannot
|
|
547
|
+
// relate to the runtime arrays.
|
|
548
|
+
static combineWithAllErrors(results) {
|
|
549
|
+
return new _CompatResult(
|
|
550
|
+
validateAll(results.map((r) => r.inner))
|
|
551
|
+
);
|
|
471
552
|
}
|
|
472
553
|
isOk() {
|
|
473
554
|
return isOk(this.inner);
|
|
@@ -476,25 +557,68 @@ var CompatResult = class _CompatResult {
|
|
|
476
557
|
return isErr(this.inner);
|
|
477
558
|
}
|
|
478
559
|
map(fn) {
|
|
479
|
-
return new _CompatResult(
|
|
560
|
+
return new _CompatResult(this.inner.map(fn));
|
|
480
561
|
}
|
|
481
562
|
mapErr(fn) {
|
|
482
|
-
return new _CompatResult(
|
|
563
|
+
return new _CompatResult(this.inner.mapErr(fn));
|
|
483
564
|
}
|
|
484
565
|
andThen(fn) {
|
|
485
|
-
return new _CompatResult(
|
|
566
|
+
return new _CompatResult(this.inner.flatMap((value) => fn(value).inner));
|
|
486
567
|
}
|
|
487
568
|
asyncAndThen(fn) {
|
|
488
569
|
return isErr(this.inner) ? CompatResultAsync.err(this.inner.error) : CompatResultAsync.fromInner(coerceToCoreAsync(fn(this.inner.value)));
|
|
489
570
|
}
|
|
490
571
|
orElse(fn) {
|
|
491
|
-
return isOk(this.inner) ? new _CompatResult(this.inner) : fn(this.inner.error);
|
|
572
|
+
return isOk(this.inner) ? new _CompatResult(newOk(this.inner.value)) : fn(this.inner.error);
|
|
492
573
|
}
|
|
493
574
|
match(onOk, onErr) {
|
|
494
575
|
return isOk(this.inner) ? onOk(this.inner.value) : onErr(this.inner.error);
|
|
495
576
|
}
|
|
496
577
|
unwrapOr(defaultValue) {
|
|
497
|
-
return
|
|
578
|
+
return this.inner.unwrapOr(defaultValue);
|
|
579
|
+
}
|
|
580
|
+
andTee(fn) {
|
|
581
|
+
if (isOk(this.inner)) {
|
|
582
|
+
try {
|
|
583
|
+
fn(this.inner.value);
|
|
584
|
+
} catch {
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return this;
|
|
588
|
+
}
|
|
589
|
+
orTee(fn) {
|
|
590
|
+
if (isErr(this.inner)) {
|
|
591
|
+
try {
|
|
592
|
+
fn(this.inner.error);
|
|
593
|
+
} catch {
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
598
|
+
andThrough(fn) {
|
|
599
|
+
if (isErr(this.inner)) return this;
|
|
600
|
+
const through = fn(this.inner.value).inner;
|
|
601
|
+
return isErr(through) ? new _CompatResult(newErr(through.error)) : this;
|
|
602
|
+
}
|
|
603
|
+
asyncAndThrough(fn) {
|
|
604
|
+
const inner = this.inner;
|
|
605
|
+
return CompatResultAsync.fromInner(
|
|
606
|
+
ResultAsync.defer(async () => {
|
|
607
|
+
if (isErr(inner)) return inner;
|
|
608
|
+
const through = await coerceToCoreAsync(fn(inner.value)).resolve();
|
|
609
|
+
return isErr(through) ? newErr(through.error) : inner;
|
|
610
|
+
})
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
asyncMap(fn) {
|
|
614
|
+
return isErr(this.inner) ? CompatResultAsync.err(this.inner.error) : CompatResultAsync.fromSafePromise(fn(this.inner.value));
|
|
615
|
+
}
|
|
616
|
+
/** Yields the `Err` to {@link safeTry} on failure; returns the `Ok` value otherwise. */
|
|
617
|
+
*safeUnwrap() {
|
|
618
|
+
if (isErr(this.inner)) {
|
|
619
|
+
yield new _CompatResult(newErr(this.inner.error));
|
|
620
|
+
}
|
|
621
|
+
return this._unsafeUnwrap();
|
|
498
622
|
}
|
|
499
623
|
_unsafeUnwrap() {
|
|
500
624
|
if (isErr(this.inner)) {
|
|
@@ -510,8 +634,34 @@ var CompatResult = class _CompatResult {
|
|
|
510
634
|
}
|
|
511
635
|
};
|
|
512
636
|
var Result = CompatResult;
|
|
513
|
-
var ok = (value) => new CompatResult(
|
|
514
|
-
var err = (error) => new CompatResult(
|
|
637
|
+
var ok = (value) => new CompatResult(newOk(value));
|
|
638
|
+
var err = (error) => new CompatResult(newErr(error));
|
|
639
|
+
Object.defineProperty(CompatResult.prototype, "value", {
|
|
640
|
+
get() {
|
|
641
|
+
return this._unsafeUnwrap();
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
Object.defineProperty(CompatResult.prototype, "error", {
|
|
645
|
+
get() {
|
|
646
|
+
return this._unsafeUnwrapErr();
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
var Ok = class extends CompatResult {
|
|
650
|
+
constructor(value) {
|
|
651
|
+
super(newOk(value));
|
|
652
|
+
}
|
|
653
|
+
static [Symbol.hasInstance](candidate) {
|
|
654
|
+
return candidate instanceof CompatResult && isOk(candidate.inner);
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
var Err = class extends CompatResult {
|
|
658
|
+
constructor(error) {
|
|
659
|
+
super(newErr(error));
|
|
660
|
+
}
|
|
661
|
+
static [Symbol.hasInstance](candidate) {
|
|
662
|
+
return candidate instanceof CompatResult && isErr(candidate.inner);
|
|
663
|
+
}
|
|
664
|
+
};
|
|
515
665
|
var CompatResultAsync = class _CompatResultAsync {
|
|
516
666
|
constructor(inner) {
|
|
517
667
|
this.inner = inner;
|
|
@@ -543,6 +693,13 @@ var CompatResultAsync = class _CompatResultAsync {
|
|
|
543
693
|
ResultAsync.combine(results.map((r) => r.inner))
|
|
544
694
|
);
|
|
545
695
|
}
|
|
696
|
+
static combineWithAllErrors(results) {
|
|
697
|
+
return new _CompatResultAsync(
|
|
698
|
+
ResultAsync.defer(
|
|
699
|
+
async () => validateAll(await Promise.all(results.map((r) => r.resolve())))
|
|
700
|
+
)
|
|
701
|
+
);
|
|
702
|
+
}
|
|
546
703
|
// biome-ignore lint/suspicious/noThenProperty: thenable shim for `await ra` -> CompatResult
|
|
547
704
|
then(onfulfilled, onrejected) {
|
|
548
705
|
return this.inner.resolve().then((r) => {
|
|
@@ -607,6 +764,21 @@ var CompatResultAsync = class _CompatResultAsync {
|
|
|
607
764
|
})
|
|
608
765
|
);
|
|
609
766
|
}
|
|
767
|
+
andThrough(fn) {
|
|
768
|
+
return new _CompatResultAsync(
|
|
769
|
+
ResultAsync.defer(async () => {
|
|
770
|
+
const r = await this.inner.resolve();
|
|
771
|
+
if (isErr(r)) return r;
|
|
772
|
+
const next = coerceToCore(fn(r.value));
|
|
773
|
+
const through = next instanceof ResultAsync ? await next.resolve() : next;
|
|
774
|
+
return isErr(through) ? newErr(through.error) : r;
|
|
775
|
+
})
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
/** Async twin of {@link CompatResult.safeUnwrap}. */
|
|
779
|
+
async *safeUnwrap() {
|
|
780
|
+
return yield* new CompatResult(await this.inner.resolve()).safeUnwrap();
|
|
781
|
+
}
|
|
610
782
|
orTee(fn) {
|
|
611
783
|
return new _CompatResultAsync(
|
|
612
784
|
ResultAsync.defer(async () => {
|
|
@@ -629,20 +801,34 @@ function coerceToCore(next) {
|
|
|
629
801
|
return next;
|
|
630
802
|
}
|
|
631
803
|
var coerceToCoreAsync = (next) => next instanceof CompatResultAsync ? next.toCore() : next;
|
|
804
|
+
function safeTry(body) {
|
|
805
|
+
const step = body().next();
|
|
806
|
+
if (step instanceof Promise) {
|
|
807
|
+
return CompatResultAsync.fromInner(ResultAsync.defer(async () => (await step).value.inner));
|
|
808
|
+
}
|
|
809
|
+
return step.value;
|
|
810
|
+
}
|
|
632
811
|
var okAsync = CompatResultAsync.ok;
|
|
633
812
|
var errAsync = CompatResultAsync.err;
|
|
634
813
|
var fromPromise = CompatResultAsync.fromPromise;
|
|
635
814
|
var fromSafePromise = CompatResultAsync.fromSafePromise;
|
|
815
|
+
var fromThrowable2 = CompatResult.fromThrowable;
|
|
816
|
+
var fromAsyncThrowable = CompatResultAsync.fromThrowable;
|
|
636
817
|
|
|
637
818
|
exports.CompatResult = CompatResult;
|
|
638
819
|
exports.CompatResultAsync = CompatResultAsync;
|
|
820
|
+
exports.Err = Err;
|
|
821
|
+
exports.Ok = Ok;
|
|
639
822
|
exports.Result = Result;
|
|
640
823
|
exports.ResultAsync = CompatResultAsync;
|
|
641
824
|
exports.err = err;
|
|
642
825
|
exports.errAsync = errAsync;
|
|
826
|
+
exports.fromAsyncThrowable = fromAsyncThrowable;
|
|
643
827
|
exports.fromPromise = fromPromise;
|
|
644
828
|
exports.fromSafePromise = fromSafePromise;
|
|
829
|
+
exports.fromThrowable = fromThrowable2;
|
|
645
830
|
exports.ok = ok;
|
|
646
831
|
exports.okAsync = okAsync;
|
|
832
|
+
exports.safeTry = safeTry;
|
|
647
833
|
//# sourceMappingURL=neverthrow.cjs.map
|
|
648
834
|
//# sourceMappingURL=neverthrow.cjs.map
|