resultar 3.2.1 → 3.3.1
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 +83 -29
- package/dist/index.js +135 -138
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ hidden timers, or helper code that throws.
|
|
|
17
17
|
`{ concurrency }`, and explicit unbounded execution for batch processing and validation.
|
|
18
18
|
- `AbortError` / `isAbortError` and redacted tagged-error props with `redact`, `isRedacted`, and
|
|
19
19
|
`revealRedacted` make cancellation and sensitive error metadata visible at the type boundary.
|
|
20
|
+
- `pipe` lets teams package reusable result combinators without hiding the underlying `Result` /
|
|
21
|
+
`ResultAsync` type.
|
|
20
22
|
|
|
21
23
|
## Main Functionalities
|
|
22
24
|
|
|
@@ -43,8 +45,8 @@ Use it when expected failures should be impossible to miss:
|
|
|
43
45
|
- Ignored `Result` values can be reported by a type-aware no-discard check.
|
|
44
46
|
|
|
45
47
|
Resultar began as an initial fork of `neverthrow`. The v3 line keeps the explicit wrapper model,
|
|
46
|
-
then leans into Resultar-specific tagged errors, strict service-boundary types, TypeScript
|
|
47
|
-
|
|
48
|
+
then leans into Resultar-specific tagged errors, strict service-boundary types, TypeScript 7-first
|
|
49
|
+
diagnostics, and ESM-only packaging.
|
|
48
50
|
|
|
49
51
|
## Install
|
|
50
52
|
|
|
@@ -59,7 +61,7 @@ npm install resultar
|
|
|
59
61
|
## Requirements
|
|
60
62
|
|
|
61
63
|
- Node.js 24+
|
|
62
|
-
- TypeScript
|
|
64
|
+
- TypeScript 7 for the canonical Resultar diagnostics workflow
|
|
63
65
|
- ESM only
|
|
64
66
|
|
|
65
67
|
```ts
|
|
@@ -116,11 +118,12 @@ in normal TypeScript.
|
|
|
116
118
|
| Expected failures are hidden behind `throw` | `Result<T, E>` and `ResultAsync<T, E>` in function signatures |
|
|
117
119
|
| Production errors need stable names and metadata | `createTaggedError` classes with `_tag`, template props, `cause`, and `.toJSON()` |
|
|
118
120
|
| Async flows turn into nested `try/catch` | `tryResultAsync`, `andThen`, `asyncAndThen`, `map`, `orElse`, `safeTry` |
|
|
121
|
+
| Repeated result transforms become noisy | `pipe` with small reusable combinators |
|
|
119
122
|
| Network calls need timeouts, retries, and fallback policy | `ResultAsync.timeout`, `retry`, `retryOrElse`, `race`, and `raceAll` |
|
|
120
123
|
| Batch work needs backpressure without a framework | `ResultAsync.forEach` and mapped `validateAll` with `{ concurrency }` |
|
|
121
124
|
| Resourceful work needs cleanup on every path | `ResultAsync.withResource` and native `AsyncIterable<Result<T, E>>` recipes |
|
|
122
125
|
| Boundary handlers miss cases | `matchTags` for exhaustive tagged-error handling |
|
|
123
|
-
| Results are easy to ignore | `resultar-
|
|
126
|
+
| Results are easy to ignore | `resultar-check` and the `resultar-check` TypeScript plugin |
|
|
124
127
|
| You do not want another application runtime | A small ESM library around explicit values |
|
|
125
128
|
|
|
126
129
|
Nested `try/catch` often masks the error the caller actually needs:
|
|
@@ -156,6 +159,31 @@ const getPosts = (
|
|
|
156
159
|
)
|
|
157
160
|
```
|
|
158
161
|
|
|
162
|
+
The same flow can be written linearly with `safeTry` when the chain gets harder to scan:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const getPostsLinear = (
|
|
166
|
+
url: string,
|
|
167
|
+
): StrictResultAsync<Post[], FetchPostsError | HttpClientError | ParsePostsError> =>
|
|
168
|
+
safeTry(async function* () {
|
|
169
|
+
const response = yield* tryResultAsync(
|
|
170
|
+
fetch(url),
|
|
171
|
+
(cause) => new FetchPostsError({ cause }),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if (response.status >= 400) {
|
|
175
|
+
return HttpClientError.err({ status: response.status })
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const posts = yield* tryResultAsync(
|
|
179
|
+
response.json() as Promise<Post[]>,
|
|
180
|
+
(cause) => new ParsePostsError({ cause }),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return ok(posts)
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
159
187
|
## Async Control Without A Runtime
|
|
160
188
|
|
|
161
189
|
The 3.1 async helpers cover common production workflows while keeping plain `Promise` and
|
|
@@ -477,6 +505,42 @@ const validateCompanyEmail = (
|
|
|
477
505
|
)
|
|
478
506
|
```
|
|
479
507
|
|
|
508
|
+
Use `pipe` when a transform should be named and reused. A pipe step receives the current
|
|
509
|
+
`Result`/`ResultAsync` and returns the next value in the chain:
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
import type { Result, StrictResult } from 'resultar'
|
|
513
|
+
|
|
514
|
+
const normalizeEmail = <E>(result: Result<string, E>): Result<string, E> =>
|
|
515
|
+
result.map((email) => email.trim().toLowerCase())
|
|
516
|
+
|
|
517
|
+
const requireCompanyDomain = (
|
|
518
|
+
result: Result<string, InvalidEmailError>,
|
|
519
|
+
): StrictResult<string, InvalidEmailError | InvalidDomainError> =>
|
|
520
|
+
result.filterOrElse(
|
|
521
|
+
(email) => email.endsWith('@company.com'),
|
|
522
|
+
(email) => new InvalidDomainError({ domain: email.split('@')[1] ?? 'unknown' }),
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
const email = validateEmail(input).pipe(normalizeEmail, requireCompanyDomain)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
The same pattern works for async results. `pipe` is just composition; it does not catch thrown
|
|
529
|
+
errors from the pipe callbacks:
|
|
530
|
+
|
|
531
|
+
```ts
|
|
532
|
+
import type { ResultAsync } from 'resultar'
|
|
533
|
+
|
|
534
|
+
const auditUser =
|
|
535
|
+
<E>(result: ResultAsync<User, E>): ResultAsync<User, E> =>
|
|
536
|
+
result.tap((user) => logger.info({ userId: user.id }, 'user created'))
|
|
537
|
+
|
|
538
|
+
const createdEmail = validateEmail(input)
|
|
539
|
+
.asyncAndThen(ensureUserDoesNotExistAsync)
|
|
540
|
+
.andThen(insertUserAsync)
|
|
541
|
+
.pipe(auditUser, (result) => result.map((user) => user.email))
|
|
542
|
+
```
|
|
543
|
+
|
|
480
544
|
Use `catchTag` or `catchTags` for local recovery from tagged errors:
|
|
481
545
|
|
|
482
546
|
```ts
|
|
@@ -886,19 +950,19 @@ const config = safeTry({
|
|
|
886
950
|
|
|
887
951
|
## No-Discard Validation
|
|
888
952
|
|
|
889
|
-
Resultar values should not be ignored.
|
|
890
|
-
|
|
953
|
+
Resultar values should not be ignored. Use `resultar-check` to run TypeScript 7 and Resultar
|
|
954
|
+
diagnostics through one command.
|
|
891
955
|
|
|
892
956
|
```sh
|
|
893
|
-
pnpm add -D resultar-
|
|
957
|
+
pnpm add -D resultar-check typescript-7@npm:typescript@rc
|
|
894
958
|
```
|
|
895
959
|
|
|
896
|
-
Add a
|
|
960
|
+
Add a check script:
|
|
897
961
|
|
|
898
962
|
```json
|
|
899
963
|
{
|
|
900
964
|
"scripts": {
|
|
901
|
-
"
|
|
965
|
+
"check": "resultar-check -p tsconfig.json --noEmit"
|
|
902
966
|
}
|
|
903
967
|
}
|
|
904
968
|
```
|
|
@@ -922,27 +986,18 @@ The default mode is neverthrow-style `must-use`: it also reports assigned `Resul
|
|
|
922
986
|
only passed around and never consumed with `match`, `unwrapOr`, `_unsafeUnwrap`, `isOk`, `isErr`,
|
|
923
987
|
returned, or explicitly discarded. Use `--mode direct` for the lower-noise expression-only check.
|
|
924
988
|
|
|
925
|
-
|
|
989
|
+
Configure Resultar rules in `tsconfig.json`:
|
|
926
990
|
|
|
927
991
|
```json
|
|
928
992
|
{
|
|
929
993
|
"compilerOptions": {
|
|
930
|
-
"plugins": [{ "name": "resultar-
|
|
994
|
+
"plugins": [{ "name": "resultar-check", "noDiscard": "error" }]
|
|
931
995
|
}
|
|
932
996
|
}
|
|
933
997
|
```
|
|
934
998
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
```sh
|
|
939
|
-
pnpm exec resultar-lint patch
|
|
940
|
-
pnpm exec resultar-lint doctor
|
|
941
|
-
pnpm exec resultar-lint unpatch
|
|
942
|
-
```
|
|
943
|
-
|
|
944
|
-
For TypeScript 7 projects using `typescript@rc`, `resultar-tsgo` exposes a `tsgo` wrapper that runs
|
|
945
|
-
native TypeScript and then Resultar lint validation.
|
|
999
|
+
Oxlint is intentionally not part of the Resultar rules path; use it only for general linting if your
|
|
1000
|
+
project wants it.
|
|
946
1001
|
|
|
947
1002
|
## API Decision Guide
|
|
948
1003
|
|
|
@@ -1021,27 +1076,26 @@ More focused material:
|
|
|
1021
1076
|
- [Full guide](https://github.com/inaiat/resultar/blob/main/DOCUMENTATION.md)
|
|
1022
1077
|
- [Type-safe error handling article, English](https://github.com/inaiat/resultar/blob/main/articles/en/type-safe.md)
|
|
1023
1078
|
- [Artigo sobre tratamento de erros type-safe, Portuguese](https://github.com/inaiat/resultar/blob/main/articles/pt/type-safe.md)
|
|
1024
|
-
- [resultar-
|
|
1025
|
-
- [resultar-tsgo package guide](https://github.com/inaiat/resultar/blob/main/packages/resultar-tsgo/README.md)
|
|
1079
|
+
- [resultar-check package guide](https://github.com/inaiat/resultar/blob/main/packages/resultar-check/README.md)
|
|
1026
1080
|
|
|
1027
1081
|
## Repository
|
|
1028
1082
|
|
|
1029
1083
|
This repository is a pnpm workspace:
|
|
1030
1084
|
|
|
1031
1085
|
- `packages/resultar`: Resultar runtime package.
|
|
1032
|
-
- `packages/resultar-
|
|
1033
|
-
- `packages/resultar-
|
|
1086
|
+
- `packages/resultar-check`: TypeScript 7 plus Resultar validation.
|
|
1087
|
+
- `packages/resultar-lint`: deprecated compatibility wrapper.
|
|
1088
|
+
- `packages/resultar-tsgo`: deprecated compatibility wrapper for older installs.
|
|
1034
1089
|
- `benchmarks`: benchmark package.
|
|
1035
1090
|
- `examples/resultar`: runnable core Resultar cookbook.
|
|
1036
|
-
- `examples/lint`: TypeScript
|
|
1037
|
-
- `examples/tsgo-lint`: TypeScript 7 `typescript@rc` Resultar lint smoke example.
|
|
1091
|
+
- `examples/lint`: TypeScript 7 `resultar-check` smoke example.
|
|
1038
1092
|
|
|
1039
1093
|
Common commands:
|
|
1040
1094
|
|
|
1041
1095
|
```sh
|
|
1042
1096
|
pnpm install
|
|
1043
1097
|
pnpm run fmt:check
|
|
1044
|
-
pnpm run
|
|
1098
|
+
pnpm run check
|
|
1045
1099
|
pnpm test
|
|
1046
1100
|
pnpm run test:cov
|
|
1047
1101
|
pnpm run build
|