resultar 2.0.0-beta.1 → 2.0.0-beta.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 CHANGED
@@ -42,6 +42,19 @@ pnpm add resultar
42
42
  npm install resultar
43
43
  ```
44
44
 
45
+ ## V2 Deprecation Notice
46
+
47
+ The `2.0.0` line removes deprecated APIs before stable release:
48
+
49
+ | Removed API | Use instead |
50
+ | --- | --- |
51
+ | `Result#finally(fn)` | `Result#log(fn)` for immediate side effects, or `Result#toDisposable(fn)` for Node.js `using` cleanup |
52
+ | `ResultAsync#finally(fn)` | `ResultAsync#log(fn)` for immediate side effects, or `ResultAsync#toAsyncDisposable(fn)` for Node.js `await using` cleanup |
53
+ | `ResultAsync#safeUnwrap()` | `yield* resultAsync` inside `safeTry(async function* () { ... })` |
54
+ | `safeTryAsync(...)` | `safeTry(async function* () { ... })` |
55
+
56
+ `Result#safeUnwrap()` remains available for compatibility, but new code should prefer `yield* result`.
57
+
45
58
  ## Philosophy
46
59
 
47
60
  Resultar is a small explicit-result library, not an application runtime or an Effect-style framework.
@@ -70,7 +83,7 @@ For backend and application code, prefer this stack:
70
83
  2. Return them through `StrictResult` or `StrictResultAsync`.
71
84
  3. Compose with `map`, `andThen`, `asyncAndThen`, `orElse`, `catchTag`, and `catchTags`.
72
85
  4. Map outcomes at boundaries with `matchTags` or `matchTagsPartial`.
73
- 5. Use `tap`, `tapError`, `log`, and `finally` only for best-effort side effects.
86
+ 5. Use `tap`, `tapError`, and `log` only for best-effort side effects.
74
87
 
75
88
  ```ts
76
89
  import type { StrictResult } from 'resultar'
@@ -95,6 +108,42 @@ Avoid using strings or loose objects for production-facing expected failures:
95
108
  type ParseError = 'InvalidPort'
96
109
  ```
97
110
 
111
+ ### No-Discard Check
112
+
113
+ Resultar ships a type-aware check for discarded `Result` and `ResultAsync` values:
114
+
115
+ ```json
116
+ {
117
+ "scripts": {
118
+ "lint:resultar": "resultar-no-discard --project tsconfig.json"
119
+ }
120
+ }
121
+ ```
122
+
123
+ It fails code that ignores a returned result:
124
+
125
+ ```ts
126
+ saveUser(input)
127
+ ```
128
+
129
+ Handle the result, return it, or mark an intentional discard with `void`:
130
+
131
+ ```ts
132
+ const result = saveUser(input)
133
+ return saveUser(input)
134
+ void saveUser(input)
135
+ ```
136
+
137
+ For Oxlint users, run it next to Oxlint because this rule needs TypeScript return-type information:
138
+
139
+ ```json
140
+ {
141
+ "scripts": {
142
+ "lint": "oxlint && resultar-no-discard --project tsconfig.json"
143
+ }
144
+ }
145
+ ```
146
+
98
147
  ## API Decision Guide
99
148
 
100
149
  Use `map` when the `Ok` value changes and the transform cannot fail.
@@ -598,8 +647,8 @@ const savePort = (): ResultAsync<number, Error> =>
598
647
 
599
648
  ## Side Effects
600
649
 
601
- Use `tap`, `tapError`, `log`, and `finally` for best-effort observation and cleanup. They are not
602
- transform methods: use `map`, `mapErr`, `andThen`, or `orElse` when the value or error should change.
650
+ Use `tap`, `tapError`, and `log` for best-effort observation. They are not transform methods: use
651
+ `map`, `mapErr`, `andThen`, or `orElse` when the value or error should change.
603
652
 
604
653
  `tap(fn)` runs only for `Ok` and returns the original result unchanged.
605
654
 
@@ -651,18 +700,21 @@ const result = fetchUser('usr_123')
651
700
  .log((user, error) => audit.write({ error, user }))
652
701
  ```
653
702
 
654
- `finally(fn)` runs a best-effort cleanup callback with both `(value, error)`. On `Result`, the
655
- callback runs before the method returns. On `ResultAsync`, it runs when the inner promise settles to a
656
- `Result`, and async cleanup is awaited before the original result is returned.
703
+ For Node.js 24 cleanup, use `toDisposable(fn)` or `toAsyncDisposable(fn)`. Those APIs defer cleanup
704
+ until the resource is disposed with `using`, `await using`, or the matching symbol method.
657
705
 
658
706
  ```ts
659
- const result = findUser('usr_123').finally((_user, _error) => {
707
+ using result = findUser('usr_123').toDisposable((_user, _error) => {
660
708
  span.end()
661
709
  })
710
+
711
+ await using asyncResult = fetchUser('usr_123').toAsyncDisposable(async (_user, _error) => {
712
+ await span.end()
713
+ })
662
714
  ```
663
715
 
664
- Callback errors thrown by `tap`, `tapError`, `log`, and `finally` are intentionally ignored so
665
- observability or cleanup code does not replace the original result. For `ResultAsync`, rejected
716
+ Callback errors thrown by `tap`, `tapError`, `log`, and disposable cleanup are intentionally ignored
717
+ so observability or cleanup code does not replace the original result. For `ResultAsync`, rejected
666
718
  callback promises are ignored too. Put fallible work in `andThen`, `orElse`, `tryCatch`, or
667
719
  `tryCatchAsync` when those failures should become part of the result type.
668
720
 
@@ -726,7 +778,7 @@ library around `Result` and `ResultAsync`.
726
778
  - `tap(fn)` run a side effect only when `Ok`; preserves the original result
727
779
  - `tapError(fn)` run a side effect only when `Err`; preserves the original result
728
780
  - `log(fn)` run a side effect for both states as `(value, error)`; preserves the original result
729
- - `finally(fn)` run best-effort cleanup with `(value, error)`; callback errors are ignored
781
+ - `toDisposable(fn)` create a Node.js `Disposable` result for `using`
730
782
  - `match(okFn, errFn)`
731
783
  - `matchTags(okFn, handlers)`
732
784
  - `matchTagsPartial(okFn, handlers, fallback)`
@@ -757,7 +809,6 @@ library around `Result` and `ResultAsync`.
757
809
  - `fromSafePromise(promise)`
758
810
  - `fromThrowableAsync(fn, errorFn?)`
759
811
  - `tryCatchAsync(promiseOrFn, errorFn?)` catches rejections and synchronous throws from factories
760
- - `safeTryAsync(generator)` deprecated; use `safeTry`
761
812
  - `StrictResultAsync<T, E extends Error>` type alias for Error-only async failure channels
762
813
 
763
814
  ### ResultAsync Methods
@@ -769,14 +820,12 @@ library around `Result` and `ResultAsync`.
769
820
  - `tap(fn)` run a sync or async side effect only when `Ok`; preserves the original result
770
821
  - `tapError(fn)` run a sync or async side effect only when `Err`; preserves the original result
771
822
  - `log(fn)` run a sync or async side effect for both states as `(value, error)`
772
- - `finally(fn)` run best-effort cleanup with `(value, error)` after the inner promise settles to a
773
- `Result`; callback errors and rejections are ignored
823
+ - `toAsyncDisposable(fn)` create a Node.js `AsyncDisposable` result for `await using`
774
824
  - `match(okFn, errFn)`
775
825
  - `matchTags(okFn, handlers)`
776
826
  - `matchTagsPartial(okFn, handlers, fallback)`
777
827
  - `unwrapOr(defaultValue)`
778
828
  - `unwrapOrThrow()`
779
- - `safeUnwrap()`
780
829
 
781
830
  ### Tagged Error Helpers
782
831