@effect-atom/atom 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Atom/package.json +6 -0
- package/AtomRef/package.json +6 -0
- package/Hydration/package.json +6 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/Registry/package.json +6 -0
- package/Result/package.json +6 -0
- package/dist/cjs/Atom.js +1079 -0
- package/dist/cjs/Atom.js.map +1 -0
- package/dist/cjs/AtomRef.js +261 -0
- package/dist/cjs/AtomRef.js.map +1 -0
- package/dist/cjs/Hydration.js +100 -0
- package/dist/cjs/Hydration.js.map +1 -0
- package/dist/cjs/Registry.js +128 -0
- package/dist/cjs/Registry.js.map +1 -0
- package/dist/cjs/Result.js +454 -0
- package/dist/cjs/Result.js.map +1 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/internal/registry.js +701 -0
- package/dist/cjs/internal/registry.js.map +1 -0
- package/dist/cjs/internal/runtime.js +92 -0
- package/dist/cjs/internal/runtime.js.map +1 -0
- package/dist/dts/Atom.d.ts +597 -0
- package/dist/dts/Atom.d.ts.map +1 -0
- package/dist/dts/AtomRef.d.ts +55 -0
- package/dist/dts/AtomRef.d.ts.map +1 -0
- package/dist/dts/Hydration.d.ts +27 -0
- package/dist/dts/Hydration.d.ts.map +1 -0
- package/dist/dts/Registry.d.ts +115 -0
- package/dist/dts/Registry.d.ts.map +1 -0
- package/dist/dts/Result.d.ts +351 -0
- package/dist/dts/Result.d.ts.map +1 -0
- package/dist/dts/index.d.ts +21 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/internal/registry.d.ts +2 -0
- package/dist/dts/internal/registry.d.ts.map +1 -0
- package/dist/dts/internal/runtime.d.ts +2 -0
- package/dist/dts/internal/runtime.d.ts.map +1 -0
- package/dist/esm/Atom.js +1029 -0
- package/dist/esm/Atom.js.map +1 -0
- package/dist/esm/AtomRef.js +232 -0
- package/dist/esm/AtomRef.js.map +1 -0
- package/dist/esm/Hydration.js +71 -0
- package/dist/esm/Hydration.js.map +1 -0
- package/dist/esm/Registry.js +98 -0
- package/dist/esm/Registry.js.map +1 -0
- package/dist/esm/Result.js +403 -0
- package/dist/esm/Result.js.map +1 -0
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/registry.js +672 -0
- package/dist/esm/internal/registry.js.map +1 -0
- package/dist/esm/internal/runtime.js +64 -0
- package/dist/esm/internal/runtime.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/package.json +72 -0
- package/src/Atom.ts +1865 -0
- package/src/AtomRef.ts +282 -0
- package/src/Hydration.ts +98 -0
- package/src/Registry.ts +204 -0
- package/src/Result.ts +767 -0
- package/src/index.ts +24 -0
- package/src/internal/registry.ts +810 -0
- package/src/internal/runtime.ts +63 -0
package/src/Result.ts
ADDED
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
5
|
+
import * as Cause from "effect/Cause"
|
|
6
|
+
import * as Equal from "effect/Equal"
|
|
7
|
+
import * as Exit from "effect/Exit"
|
|
8
|
+
import type { LazyArg } from "effect/Function"
|
|
9
|
+
import { constTrue, dual, identity } from "effect/Function"
|
|
10
|
+
import * as Hash from "effect/Hash"
|
|
11
|
+
import * as Option from "effect/Option"
|
|
12
|
+
import { type Pipeable, pipeArguments } from "effect/Pipeable"
|
|
13
|
+
import type { Predicate, Refinement } from "effect/Predicate"
|
|
14
|
+
import { hasProperty } from "effect/Predicate"
|
|
15
|
+
import * as Schema_ from "effect/Schema"
|
|
16
|
+
import type * as Types from "effect/Types"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
* @category type ids
|
|
21
|
+
*/
|
|
22
|
+
export const TypeId = Symbol.for("@effect-atom/atom/Result")
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
* @category type ids
|
|
27
|
+
*/
|
|
28
|
+
export type TypeId = typeof TypeId
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @since 1.0.0
|
|
32
|
+
* @category models
|
|
33
|
+
*/
|
|
34
|
+
export type Result<A, E = never> = Initial<A, E> | Success<A, E> | Failure<A, E>
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @since 1.0.0
|
|
38
|
+
* @category Guards
|
|
39
|
+
*/
|
|
40
|
+
export const isResult = (u: unknown): u is Result<unknown, unknown> => hasProperty(u, TypeId)
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @since 1.0.0
|
|
44
|
+
* @category models
|
|
45
|
+
*/
|
|
46
|
+
export declare namespace Result {
|
|
47
|
+
/**
|
|
48
|
+
* @since 1.0.0
|
|
49
|
+
* @category models
|
|
50
|
+
*/
|
|
51
|
+
export interface Proto<A, E> extends Pipeable {
|
|
52
|
+
readonly [TypeId]: {
|
|
53
|
+
readonly E: (_: never) => E
|
|
54
|
+
readonly A: (_: never) => A
|
|
55
|
+
}
|
|
56
|
+
readonly waiting: boolean
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @since 1.0.0
|
|
61
|
+
*/
|
|
62
|
+
export type Success<R> = R extends Result<infer A, infer _> ? A : never
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @since 1.0.0
|
|
66
|
+
*/
|
|
67
|
+
export type Failure<R> = R extends Result<infer _, infer E> ? E : never
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @since 1.0.0
|
|
72
|
+
*/
|
|
73
|
+
export type With<R extends Result<any, any>, A, E> = R extends Initial<infer _A, infer _E> ? Initial<A, E>
|
|
74
|
+
: R extends Success<infer _A, infer _E> ? Success<A, E>
|
|
75
|
+
: R extends Failure<infer _A, infer _E> ? Failure<A, E>
|
|
76
|
+
: never
|
|
77
|
+
|
|
78
|
+
const ResultProto = {
|
|
79
|
+
[TypeId]: {
|
|
80
|
+
E: identity,
|
|
81
|
+
A: identity
|
|
82
|
+
},
|
|
83
|
+
pipe() {
|
|
84
|
+
return pipeArguments(this, arguments)
|
|
85
|
+
},
|
|
86
|
+
[Equal.symbol](this: Result<any, any>, that: Result<any, any>): boolean {
|
|
87
|
+
if (this._tag !== that._tag && this.waiting !== that.waiting) {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
switch (this._tag) {
|
|
91
|
+
case "Initial":
|
|
92
|
+
return true
|
|
93
|
+
case "Success":
|
|
94
|
+
return Equal.equals(this.value, (that as Success<any, any>).value)
|
|
95
|
+
case "Failure":
|
|
96
|
+
return Equal.equals(this.cause, (that as Failure<any, any>).cause)
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
[Hash.symbol](this: Result<any, any>): number {
|
|
100
|
+
const tagHash = Hash.string(`${this._tag}:${this.waiting}`)
|
|
101
|
+
if (this._tag === "Initial") {
|
|
102
|
+
return Hash.cached(this, tagHash)
|
|
103
|
+
}
|
|
104
|
+
return Hash.cached(
|
|
105
|
+
this,
|
|
106
|
+
Hash.combine(tagHash)(this._tag === "Success" ? Hash.hash(this.value) : Hash.hash(this.cause))
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @since 1.0.0
|
|
113
|
+
* @category models
|
|
114
|
+
*/
|
|
115
|
+
export interface Initial<A, E = never> extends Result.Proto<A, E> {
|
|
116
|
+
readonly _tag: "Initial"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @since 1.0.0
|
|
121
|
+
* @category constructors
|
|
122
|
+
*/
|
|
123
|
+
export const fromExit = <A, E>(exit: Exit.Exit<A, E>): Success<A, E> | Failure<A, E> =>
|
|
124
|
+
exit._tag === "Success" ? success(exit.value) : failure(exit.cause)
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @since 1.0.0
|
|
128
|
+
* @category constructors
|
|
129
|
+
*/
|
|
130
|
+
export const fromExitWithPrevious = <A, E>(
|
|
131
|
+
exit: Exit.Exit<A, E>,
|
|
132
|
+
previous: Option.Option<Result<A, E>>
|
|
133
|
+
): Success<A, E> | Failure<A, E> =>
|
|
134
|
+
exit._tag === "Success" ? success(exit.value) : failureWithPrevious(exit.cause, { previous })
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @since 1.0.0
|
|
138
|
+
* @category constructors
|
|
139
|
+
*/
|
|
140
|
+
export const waitingFrom = <A, E>(previous: Option.Option<Result<A, E>>): Result<A, E> => {
|
|
141
|
+
if (previous._tag === "None") {
|
|
142
|
+
return initial(true)
|
|
143
|
+
}
|
|
144
|
+
return waiting(previous.value)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @since 1.0.0
|
|
149
|
+
* @category refinements
|
|
150
|
+
*/
|
|
151
|
+
export const isInitial = <A, E>(result: Result<A, E>): result is Initial<A, E> => result._tag === "Initial"
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @since 1.0.0
|
|
155
|
+
* @category refinements
|
|
156
|
+
*/
|
|
157
|
+
export const isNotInitial = <A, E>(result: Result<A, E>): result is Success<A, E> | Failure<A, E> =>
|
|
158
|
+
result._tag !== "Initial"
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @since 1.0.0
|
|
162
|
+
* @category constructors
|
|
163
|
+
*/
|
|
164
|
+
export const initial = <A = never, E = never>(waiting = false): Initial<A, E> => {
|
|
165
|
+
const result = Object.create(ResultProto)
|
|
166
|
+
result._tag = "Initial"
|
|
167
|
+
result.waiting = waiting
|
|
168
|
+
return result
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @since 1.0.0
|
|
173
|
+
* @category models
|
|
174
|
+
*/
|
|
175
|
+
export interface Success<A, E = never> extends Result.Proto<A, E> {
|
|
176
|
+
readonly _tag: "Success"
|
|
177
|
+
readonly value: A
|
|
178
|
+
readonly timestamp: number
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @since 1.0.0
|
|
183
|
+
* @category refinements
|
|
184
|
+
*/
|
|
185
|
+
export const isSuccess = <A, E>(result: Result<A, E>): result is Success<A, E> => result._tag === "Success"
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @since 1.0.0
|
|
189
|
+
* @category constructors
|
|
190
|
+
*/
|
|
191
|
+
export const success = <A, E = never>(value: A, options?: {
|
|
192
|
+
readonly waiting?: boolean | undefined
|
|
193
|
+
readonly timestamp?: number | undefined
|
|
194
|
+
}): Success<A, E> => {
|
|
195
|
+
const result = Object.create(ResultProto)
|
|
196
|
+
result._tag = "Success"
|
|
197
|
+
result.value = value
|
|
198
|
+
result.waiting = options?.waiting ?? false
|
|
199
|
+
result.timestamp = options?.timestamp ?? Date.now()
|
|
200
|
+
return result
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @since 1.0.0
|
|
205
|
+
* @category models
|
|
206
|
+
*/
|
|
207
|
+
export interface Failure<A, E = never> extends Result.Proto<A, E> {
|
|
208
|
+
readonly _tag: "Failure"
|
|
209
|
+
readonly cause: Cause.Cause<E>
|
|
210
|
+
readonly previousSuccess: Option.Option<Success<A, E>>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @since 1.0.0
|
|
215
|
+
* @category refinements
|
|
216
|
+
*/
|
|
217
|
+
export const isFailure = <A, E>(result: Result<A, E>): result is Failure<A, E> => result._tag === "Failure"
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @since 1.0.0
|
|
221
|
+
* @category refinements
|
|
222
|
+
*/
|
|
223
|
+
export const isInterrupted = <A, E>(result: Result<A, E>): result is Failure<A, E> =>
|
|
224
|
+
result._tag === "Failure" && Cause.isInterruptedOnly(result.cause)
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @since 1.0.0
|
|
228
|
+
* @category constructors
|
|
229
|
+
*/
|
|
230
|
+
export const failure = <E, A = never>(
|
|
231
|
+
cause: Cause.Cause<E>,
|
|
232
|
+
options?: {
|
|
233
|
+
readonly previousSuccess?: Option.Option<Success<A, E>> | undefined
|
|
234
|
+
readonly waiting?: boolean | undefined
|
|
235
|
+
}
|
|
236
|
+
): Failure<A, E> => {
|
|
237
|
+
const result = Object.create(ResultProto)
|
|
238
|
+
result._tag = "Failure"
|
|
239
|
+
result.cause = cause
|
|
240
|
+
result.previousSuccess = options?.previousSuccess ?? Option.none()
|
|
241
|
+
result.waiting = options?.waiting ?? false
|
|
242
|
+
return result
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* @since 1.0.0
|
|
247
|
+
* @category constructors
|
|
248
|
+
*/
|
|
249
|
+
export const failureWithPrevious = <A, E>(
|
|
250
|
+
cause: Cause.Cause<E>,
|
|
251
|
+
options: {
|
|
252
|
+
readonly previous: Option.Option<Result<A, E>>
|
|
253
|
+
readonly waiting?: boolean | undefined
|
|
254
|
+
}
|
|
255
|
+
): Failure<A, E> =>
|
|
256
|
+
failure(cause, {
|
|
257
|
+
previousSuccess: Option.flatMap(options.previous, (result) =>
|
|
258
|
+
isSuccess(result)
|
|
259
|
+
? Option.some(result)
|
|
260
|
+
: isFailure(result)
|
|
261
|
+
? result.previousSuccess
|
|
262
|
+
: Option.none()),
|
|
263
|
+
waiting: options.waiting
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* @since 1.0.0
|
|
268
|
+
* @category constructors
|
|
269
|
+
*/
|
|
270
|
+
export const fail = <E, A = never>(error: E, options?: {
|
|
271
|
+
readonly previousSuccess?: Option.Option<Success<A, E>> | undefined
|
|
272
|
+
readonly waiting?: boolean | undefined
|
|
273
|
+
}): Failure<A, E> => failure(Cause.fail(error), options)
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @since 1.0.0
|
|
277
|
+
* @category constructors
|
|
278
|
+
*/
|
|
279
|
+
export const failWithPrevious = <A, E>(
|
|
280
|
+
error: E,
|
|
281
|
+
options: {
|
|
282
|
+
readonly previous: Option.Option<Result<A, E>>
|
|
283
|
+
readonly waiting?: boolean | undefined
|
|
284
|
+
}
|
|
285
|
+
): Failure<A, E> => failureWithPrevious(Cause.fail(error), options)
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @since 1.0.0
|
|
289
|
+
* @category constructors
|
|
290
|
+
*/
|
|
291
|
+
export const waiting = <R extends Result<any, any>>(self: R): R => {
|
|
292
|
+
if (self.waiting) {
|
|
293
|
+
return self
|
|
294
|
+
}
|
|
295
|
+
const result = Object.assign(Object.create(ResultProto), self)
|
|
296
|
+
result.waiting = true
|
|
297
|
+
return result
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* @since 1.0.0
|
|
302
|
+
* @category constructors
|
|
303
|
+
*/
|
|
304
|
+
export const replacePrevious = <R extends Result<any, any>, XE, A>(
|
|
305
|
+
self: R,
|
|
306
|
+
previous: Option.Option<Result<A, XE>>
|
|
307
|
+
): With<R, A, Result.Failure<R>> => {
|
|
308
|
+
if (self._tag === "Failure") {
|
|
309
|
+
return failureWithPrevious(self.cause, { previous, waiting: self.waiting }) as any
|
|
310
|
+
}
|
|
311
|
+
return self as any
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* @since 1.0.0
|
|
316
|
+
* @category accessors
|
|
317
|
+
*/
|
|
318
|
+
export const value = <A, E>(self: Result<A, E>): Option.Option<A> => {
|
|
319
|
+
if (self._tag === "Success") {
|
|
320
|
+
return Option.some(self.value)
|
|
321
|
+
} else if (self._tag === "Failure") {
|
|
322
|
+
return Option.map(self.previousSuccess, (s) => s.value)
|
|
323
|
+
}
|
|
324
|
+
return Option.none()
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* @since 1.0.0
|
|
329
|
+
* @category accessors
|
|
330
|
+
*/
|
|
331
|
+
export const getOrElse: {
|
|
332
|
+
<B>(orElse: LazyArg<B>): <A, E>(self: Result<A, E>) => A | B
|
|
333
|
+
<A, E, B>(self: Result<A, E>, orElse: LazyArg<B>): A | B
|
|
334
|
+
} = dual(2, <A, E, B>(self: Result<A, E>, orElse: LazyArg<B>): A | B => Option.getOrElse(value(self), orElse))
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @since 1.0.0
|
|
338
|
+
* @category accessors
|
|
339
|
+
*/
|
|
340
|
+
export const getOrThrow = <A, E>(self: Result<A, E>): A =>
|
|
341
|
+
Option.getOrThrowWith(value(self), () => new Cause.NoSuchElementException("Result.getOrThrow: no value found"))
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* @since 1.0.0
|
|
345
|
+
* @category accessors
|
|
346
|
+
*/
|
|
347
|
+
export const cause = <A, E>(self: Result<A, E>): Option.Option<Cause.Cause<E>> =>
|
|
348
|
+
self._tag === "Failure" ? Option.some(self.cause) : Option.none()
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* @since 1.0.0
|
|
352
|
+
* @category accessors
|
|
353
|
+
*/
|
|
354
|
+
export const error = <A, E>(self: Result<A, E>): Option.Option<E> =>
|
|
355
|
+
self._tag === "Failure" ? Cause.failureOption(self.cause) : Option.none()
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* @since 1.0.0
|
|
359
|
+
* @category combinators
|
|
360
|
+
*/
|
|
361
|
+
export const toExit = <A, E>(
|
|
362
|
+
self: Result<A, E>
|
|
363
|
+
): Exit.Exit<A, E | Cause.NoSuchElementException> => {
|
|
364
|
+
switch (self._tag) {
|
|
365
|
+
case "Success": {
|
|
366
|
+
return Exit.succeed(self.value)
|
|
367
|
+
}
|
|
368
|
+
case "Failure": {
|
|
369
|
+
return Exit.failCause(self.cause)
|
|
370
|
+
}
|
|
371
|
+
default: {
|
|
372
|
+
return Exit.fail(new Cause.NoSuchElementException())
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* @since 1.0.0
|
|
379
|
+
* @category combinators
|
|
380
|
+
*/
|
|
381
|
+
export const map: {
|
|
382
|
+
<A, B>(f: (a: A) => B): <E>(self: Result<A, E>) => Result<B, E>
|
|
383
|
+
<E, A, B>(self: Result<A, E>, f: (a: A) => B): Result<B, E>
|
|
384
|
+
} = dual(2, <E, A, B>(self: Result<A, E>, f: (a: A) => B): Result<B, E> => {
|
|
385
|
+
switch (self._tag) {
|
|
386
|
+
case "Initial":
|
|
387
|
+
return self as any as Result<B, E>
|
|
388
|
+
case "Failure":
|
|
389
|
+
return failure(self.cause, {
|
|
390
|
+
previousSuccess: Option.map(self.previousSuccess, (s) => success(f(s.value), s)),
|
|
391
|
+
waiting: self.waiting
|
|
392
|
+
})
|
|
393
|
+
case "Success":
|
|
394
|
+
return success(f(self.value), self)
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* @since 1.0.0
|
|
400
|
+
* @category combinators
|
|
401
|
+
*/
|
|
402
|
+
export const match: {
|
|
403
|
+
<A, E, X, Y, Z>(options: {
|
|
404
|
+
readonly onInitial: (_: Initial<A, E>) => X
|
|
405
|
+
readonly onFailure: (_: Failure<A, E>) => Y
|
|
406
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
407
|
+
}): (self: Result<A, E>) => X | Y | Z
|
|
408
|
+
<A, E, X, Y, Z>(self: Result<A, E>, options: {
|
|
409
|
+
readonly onInitial: (_: Initial<A, E>) => X
|
|
410
|
+
readonly onFailure: (_: Failure<A, E>) => Y
|
|
411
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
412
|
+
}): X | Y | Z
|
|
413
|
+
} = dual(2, <A, E, X, Y, Z>(self: Result<A, E>, options: {
|
|
414
|
+
readonly onInitial: (_: Initial<A, E>) => X
|
|
415
|
+
readonly onFailure: (_: Failure<A, E>) => Y
|
|
416
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
417
|
+
}): X | Y | Z => {
|
|
418
|
+
switch (self._tag) {
|
|
419
|
+
case "Initial":
|
|
420
|
+
return options.onInitial(self)
|
|
421
|
+
case "Failure":
|
|
422
|
+
return options.onFailure(self)
|
|
423
|
+
case "Success":
|
|
424
|
+
return options.onSuccess(self)
|
|
425
|
+
}
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* @since 1.0.0
|
|
430
|
+
* @category combinators
|
|
431
|
+
*/
|
|
432
|
+
export const matchWithError: {
|
|
433
|
+
<A, E, W, X, Y, Z>(options: {
|
|
434
|
+
readonly onInitial: (_: Initial<A, E>) => W
|
|
435
|
+
readonly onError: (error: E, _: Failure<A, E>) => X
|
|
436
|
+
readonly onDefect: (defect: unknown, _: Failure<A, E>) => Y
|
|
437
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
438
|
+
}): (self: Result<A, E>) => W | X | Y | Z
|
|
439
|
+
<A, E, W, X, Y, Z>(self: Result<A, E>, options: {
|
|
440
|
+
readonly onInitial: (_: Initial<A, E>) => W
|
|
441
|
+
readonly onError: (error: E, _: Failure<A, E>) => X
|
|
442
|
+
readonly onDefect: (defect: unknown, _: Failure<A, E>) => Y
|
|
443
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
444
|
+
}): W | X | Y | Z
|
|
445
|
+
} = dual(2, <A, E, W, X, Y, Z>(self: Result<A, E>, options: {
|
|
446
|
+
readonly onInitial: (_: Initial<A, E>) => W
|
|
447
|
+
readonly onError: (error: E, _: Failure<A, E>) => X
|
|
448
|
+
readonly onDefect: (defect: unknown, _: Failure<A, E>) => Y
|
|
449
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
450
|
+
}): W | X | Y | Z => {
|
|
451
|
+
switch (self._tag) {
|
|
452
|
+
case "Initial":
|
|
453
|
+
return options.onInitial(self)
|
|
454
|
+
case "Failure": {
|
|
455
|
+
const e = Cause.failureOrCause(self.cause)
|
|
456
|
+
if (e._tag === "Right") {
|
|
457
|
+
return options.onDefect(Cause.squash(e.right), self)
|
|
458
|
+
}
|
|
459
|
+
return options.onError(e.left, self)
|
|
460
|
+
}
|
|
461
|
+
case "Success":
|
|
462
|
+
return options.onSuccess(self)
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* @since 1.0.0
|
|
468
|
+
* @category combinators
|
|
469
|
+
*/
|
|
470
|
+
export const matchWithWaiting: {
|
|
471
|
+
<A, E, W, X, Y, Z>(options: {
|
|
472
|
+
readonly onWaiting: (_: Result<A, E>) => W
|
|
473
|
+
readonly onError: (error: E, _: Failure<A, E>) => X
|
|
474
|
+
readonly onDefect: (defect: unknown, _: Failure<A, E>) => Y
|
|
475
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
476
|
+
}): (self: Result<A, E>) => W | X | Y | Z
|
|
477
|
+
<A, E, W, X, Y, Z>(self: Result<A, E>, options: {
|
|
478
|
+
readonly onWaiting: (_: Result<A, E>) => W
|
|
479
|
+
readonly onError: (error: E, _: Failure<A, E>) => X
|
|
480
|
+
readonly onDefect: (defect: unknown, _: Failure<A, E>) => Y
|
|
481
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
482
|
+
}): W | X | Y | Z
|
|
483
|
+
} = dual(2, <A, E, W, X, Y, Z>(self: Result<A, E>, options: {
|
|
484
|
+
readonly onWaiting: (_: Result<A, E>) => W
|
|
485
|
+
readonly onError: (error: E, _: Failure<A, E>) => X
|
|
486
|
+
readonly onDefect: (defect: unknown, _: Failure<A, E>) => Y
|
|
487
|
+
readonly onSuccess: (_: Success<A, E>) => Z
|
|
488
|
+
}): W | X | Y | Z => {
|
|
489
|
+
if (self.waiting) {
|
|
490
|
+
return options.onWaiting(self)
|
|
491
|
+
}
|
|
492
|
+
switch (self._tag) {
|
|
493
|
+
case "Initial":
|
|
494
|
+
return options.onWaiting(self)
|
|
495
|
+
case "Failure": {
|
|
496
|
+
const e = Cause.failureOrCause(self.cause)
|
|
497
|
+
if (e._tag === "Right") {
|
|
498
|
+
return options.onDefect(Cause.squash(e.right), self)
|
|
499
|
+
}
|
|
500
|
+
return options.onError(e.left, self)
|
|
501
|
+
}
|
|
502
|
+
case "Success":
|
|
503
|
+
return options.onSuccess(self)
|
|
504
|
+
}
|
|
505
|
+
})
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* @since 1.0.0
|
|
509
|
+
* @category Builder
|
|
510
|
+
*/
|
|
511
|
+
export const builder = <A extends Result<any, any>>(self: A): Builder<
|
|
512
|
+
never,
|
|
513
|
+
A extends Success<infer _A, infer _E> ? _A : never,
|
|
514
|
+
A extends Failure<infer _A, infer _E> ? _E : never,
|
|
515
|
+
A extends Initial<infer _A, infer _E> ? true : never
|
|
516
|
+
> => new BuilderImpl(self) as any
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @since 1.0.0
|
|
520
|
+
* @category Builder
|
|
521
|
+
*/
|
|
522
|
+
export type Builder<Out, A, E, I> =
|
|
523
|
+
& Pipeable
|
|
524
|
+
& {
|
|
525
|
+
onWaiting<B>(f: (result: Result<A, E>) => B): Builder<Out | B, A, E, I>
|
|
526
|
+
onDefect<B>(f: (defect: unknown, result: Failure<A, E>) => B): Builder<Out | B, A, E, I>
|
|
527
|
+
orElse<B>(orElse: LazyArg<B>): Out | B
|
|
528
|
+
orNull(): Out | null
|
|
529
|
+
render(): [A | I] extends [never] ? Out : Out | null
|
|
530
|
+
}
|
|
531
|
+
& ([I] extends [never] ? {} :
|
|
532
|
+
{
|
|
533
|
+
onInitial<B>(f: (result: Initial<A, E>) => B): Builder<Out | B, A, E, never>
|
|
534
|
+
onInitialOrWaiting<B>(f: (result: Result<A, E>) => B): Builder<Out | B, A, E, never>
|
|
535
|
+
})
|
|
536
|
+
& ([A] extends [never] ? {} :
|
|
537
|
+
{
|
|
538
|
+
onSuccess<B>(f: (value: A, result: Success<A, E>) => B): Builder<Out | B, never, E, I>
|
|
539
|
+
})
|
|
540
|
+
& ([E] extends [never] ? {} : {
|
|
541
|
+
onFailure<B>(f: (cause: Cause.Cause<E>, result: Failure<A, E>) => B): Builder<Out | B, A, never, I>
|
|
542
|
+
|
|
543
|
+
onError<B>(f: (error: E, result: Failure<A, E>) => B): Builder<Out | B, A, never, I>
|
|
544
|
+
|
|
545
|
+
onErrorIf<B extends E, C>(
|
|
546
|
+
refinement: Refinement<E, B>,
|
|
547
|
+
f: (error: B, result: Failure<A, E>) => C
|
|
548
|
+
): Builder<Out | C, A, Types.EqualsWith<E, B, E, Exclude<E, B>>, I>
|
|
549
|
+
onErrorIf<C>(
|
|
550
|
+
predicate: Predicate<E>,
|
|
551
|
+
f: (error: E, result: Failure<A, E>) => C
|
|
552
|
+
): Builder<Out | C, A, E, I>
|
|
553
|
+
|
|
554
|
+
onErrorTag<const Tags extends ReadonlyArray<Types.Tags<E>>, B>(
|
|
555
|
+
tags: Tags,
|
|
556
|
+
f: (error: Types.ExtractTag<E, Tags[number]>, result: Failure<A, E>) => B
|
|
557
|
+
): Builder<Out | B, A, Types.ExcludeTag<E, Tags[number]>, I>
|
|
558
|
+
onErrorTag<const Tag extends Types.Tags<E>, B>(
|
|
559
|
+
tag: Tag,
|
|
560
|
+
f: (error: Types.ExtractTag<E, Tag>, result: Failure<A, E>) => B
|
|
561
|
+
): Builder<Out | B, A, Types.ExcludeTag<E, Tag>, I>
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
class BuilderImpl<Out, A, E> {
|
|
565
|
+
constructor(readonly result: Result<A, E>) {}
|
|
566
|
+
public output = Option.none<Out>()
|
|
567
|
+
|
|
568
|
+
when<B extends Result<A, E>, C>(
|
|
569
|
+
refinement: Refinement<Result<A, E>, B>,
|
|
570
|
+
f: (result: B) => Option.Option<C>
|
|
571
|
+
): any
|
|
572
|
+
when<C>(
|
|
573
|
+
refinement: Predicate<Result<A, E>>,
|
|
574
|
+
f: (result: Result<A, E>) => Option.Option<C>
|
|
575
|
+
): any
|
|
576
|
+
when<C>(
|
|
577
|
+
refinement: Predicate<Result<A, E>>,
|
|
578
|
+
f: (result: Result<A, E>) => Option.Option<C>
|
|
579
|
+
): any {
|
|
580
|
+
if (Option.isNone(this.output) && refinement(this.result)) {
|
|
581
|
+
const b = f(this.result)
|
|
582
|
+
if (Option.isSome(b)) {
|
|
583
|
+
;(this as any).output = b
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return this
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
pipe() {
|
|
590
|
+
return pipeArguments(this, arguments)
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
onWaiting<B>(f: (result: Result<A, E>) => B): BuilderImpl<Out | B, A, E> {
|
|
594
|
+
return this.when((r) => r.waiting, (r) => Option.some(f(r)))
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
onInitialOrWaiting<B>(f: (result: Result<A, E>) => B): BuilderImpl<Out | B, A, E> {
|
|
598
|
+
return this.when((r) => isInitial(r) || r.waiting, (r) => Option.some(f(r)))
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
onInitial<B>(f: (result: Initial<A, E>) => B): BuilderImpl<Out | B, A, E> {
|
|
602
|
+
return this.when(isInitial, (r) => Option.some(f(r)))
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
onSuccess<B>(f: (value: A, result: Success<A, E>) => B): BuilderImpl<Out | B, never, E> {
|
|
606
|
+
return this.when(isSuccess, (r) => Option.some(f(r.value, r)))
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
onFailure<B>(f: (cause: Cause.Cause<E>, result: Failure<A, E>) => B): BuilderImpl<Out | B, A, never> {
|
|
610
|
+
return this.when(isFailure, (r) => Option.some(f(r.cause, r)))
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
onError<B>(f: (error: E, result: Failure<A, E>) => B): BuilderImpl<Out | B, A, never> {
|
|
614
|
+
return this.onErrorIf(constTrue, f) as any
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
onErrorIf<C, B extends E = E>(
|
|
618
|
+
refinement: Refinement<E, B> | Predicate<E>,
|
|
619
|
+
f: (error: B, result: Failure<A, E>) => C
|
|
620
|
+
): BuilderImpl<Out | C, A, Types.EqualsWith<E, B, E, Exclude<E, B>>> {
|
|
621
|
+
return this.when(isFailure, (result) =>
|
|
622
|
+
Cause.failureOption(result.cause).pipe(
|
|
623
|
+
Option.filter(refinement),
|
|
624
|
+
Option.map((error) => f(error as B, result))
|
|
625
|
+
))
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
onErrorTag<B>(
|
|
629
|
+
tag: string | ReadonlyArray<string>,
|
|
630
|
+
f: (error: Types.ExtractTag<E, any>, result: Failure<A, E>) => B
|
|
631
|
+
): BuilderImpl<Out | B, A, Types.ExcludeTag<E, any>> {
|
|
632
|
+
return this.onErrorIf(
|
|
633
|
+
(e) => hasProperty(e, "_tag") && (Array.isArray(tag) ? tag.includes(e._tag) : e._tag === tag),
|
|
634
|
+
f
|
|
635
|
+
) as any
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
onDefect<B>(f: (defect: unknown, result: Failure<A, E>) => B): BuilderImpl<Out | B, A, E> {
|
|
639
|
+
return this.when(isFailure, (result) =>
|
|
640
|
+
Cause.dieOption(result.cause).pipe(
|
|
641
|
+
Option.map((defect) => f(defect, result))
|
|
642
|
+
))
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
orElse<B>(orElse: LazyArg<B>): Out | B {
|
|
646
|
+
return Option.getOrElse(this.output, orElse)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
orNull(): Out | null {
|
|
650
|
+
return Option.getOrNull(this.output)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
render(): Out | null {
|
|
654
|
+
if (Option.isSome(this.output)) {
|
|
655
|
+
return this.output.value
|
|
656
|
+
} else if (isFailure(this.result)) {
|
|
657
|
+
throw Cause.squash(this.result.cause)
|
|
658
|
+
}
|
|
659
|
+
return null
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* @since 1.0.0
|
|
665
|
+
* @category Schemas
|
|
666
|
+
*/
|
|
667
|
+
export type PartialEncoded<A, E> = {
|
|
668
|
+
readonly _tag: "Initial"
|
|
669
|
+
readonly waiting: boolean
|
|
670
|
+
} | {
|
|
671
|
+
readonly _tag: "Success"
|
|
672
|
+
readonly waiting: boolean
|
|
673
|
+
readonly timestamp: number
|
|
674
|
+
readonly value: A
|
|
675
|
+
} | {
|
|
676
|
+
readonly _tag: "Failure"
|
|
677
|
+
readonly waiting: boolean
|
|
678
|
+
readonly previousValue: Option.Option<A>
|
|
679
|
+
readonly cause: Cause.Cause<E>
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* @since 1.0.0
|
|
684
|
+
* @category Schemas
|
|
685
|
+
*/
|
|
686
|
+
export type Encoded<A, E> = {
|
|
687
|
+
readonly _tag: "Initial"
|
|
688
|
+
readonly waiting: boolean
|
|
689
|
+
} | {
|
|
690
|
+
readonly _tag: "Success"
|
|
691
|
+
readonly waiting: boolean
|
|
692
|
+
readonly timestamp: number
|
|
693
|
+
readonly value: A
|
|
694
|
+
} | {
|
|
695
|
+
readonly _tag: "Failure"
|
|
696
|
+
readonly waiting: boolean
|
|
697
|
+
readonly previousValue: Schema_.OptionEncoded<A>
|
|
698
|
+
readonly cause: Schema_.CauseEncoded<E, unknown>
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* @since 1.0.0
|
|
703
|
+
* @category Schemas
|
|
704
|
+
*/
|
|
705
|
+
export const schemaFromSelf: Schema_.Schema<Result<any, any>> = Schema_.declare(isResult, {
|
|
706
|
+
identifier: "Result"
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* @since 1.0.0
|
|
711
|
+
* @category Schemas
|
|
712
|
+
*/
|
|
713
|
+
export const Schema = <
|
|
714
|
+
Success extends Schema_.Schema.All = typeof Schema_.Never,
|
|
715
|
+
Error extends Schema_.Schema.All = typeof Schema_.Never
|
|
716
|
+
>(
|
|
717
|
+
options: {
|
|
718
|
+
readonly success?: Success | undefined
|
|
719
|
+
readonly error?: Error | undefined
|
|
720
|
+
}
|
|
721
|
+
): Schema_.transform<
|
|
722
|
+
Schema_.Schema<
|
|
723
|
+
PartialEncoded<Success["Type"], Error["Type"]>,
|
|
724
|
+
Encoded<Success["Encoded"], Error["Encoded"]>,
|
|
725
|
+
Success["Context"] | Error["Context"]
|
|
726
|
+
>,
|
|
727
|
+
Schema_.Schema<Result<Success["Type"], Error["Type"]>>
|
|
728
|
+
> => {
|
|
729
|
+
const success_: Success = options.success ?? Schema_.Never as any
|
|
730
|
+
const error: Error = options.error ?? Schema_.Never as any
|
|
731
|
+
const Success = Schema_.TaggedStruct("Success", {
|
|
732
|
+
waiting: Schema_.Boolean,
|
|
733
|
+
timestamp: Schema_.Number,
|
|
734
|
+
value: success_
|
|
735
|
+
})
|
|
736
|
+
return Schema_.transform(
|
|
737
|
+
Schema_.Union(
|
|
738
|
+
Schema_.TaggedStruct("Initial", {
|
|
739
|
+
waiting: Schema_.Boolean
|
|
740
|
+
}),
|
|
741
|
+
Success,
|
|
742
|
+
Schema_.TaggedStruct("Failure", {
|
|
743
|
+
waiting: Schema_.Boolean,
|
|
744
|
+
previousSuccess: Schema_.Option(Success as any),
|
|
745
|
+
cause: Schema_.Cause({
|
|
746
|
+
error,
|
|
747
|
+
defect: Schema_.Defect
|
|
748
|
+
})
|
|
749
|
+
})
|
|
750
|
+
) as Schema_.Schema<
|
|
751
|
+
PartialEncoded<Success["Type"], Error["Type"]>,
|
|
752
|
+
Encoded<Success["Encoded"], Error["Encoded"]>,
|
|
753
|
+
Success["Context"] | Error["Context"]
|
|
754
|
+
>,
|
|
755
|
+
schemaFromSelf,
|
|
756
|
+
{
|
|
757
|
+
strict: false,
|
|
758
|
+
decode: (e) =>
|
|
759
|
+
e._tag === "Initial"
|
|
760
|
+
? initial(e.waiting)
|
|
761
|
+
: e._tag === "Success"
|
|
762
|
+
? success(e.value, e)
|
|
763
|
+
: failure(e.cause, e),
|
|
764
|
+
encode: identity
|
|
765
|
+
}
|
|
766
|
+
) as any
|
|
767
|
+
}
|