@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.
Files changed (65) hide show
  1. package/Atom/package.json +6 -0
  2. package/AtomRef/package.json +6 -0
  3. package/Hydration/package.json +6 -0
  4. package/LICENSE +21 -0
  5. package/README.md +3 -0
  6. package/Registry/package.json +6 -0
  7. package/Result/package.json +6 -0
  8. package/dist/cjs/Atom.js +1079 -0
  9. package/dist/cjs/Atom.js.map +1 -0
  10. package/dist/cjs/AtomRef.js +261 -0
  11. package/dist/cjs/AtomRef.js.map +1 -0
  12. package/dist/cjs/Hydration.js +100 -0
  13. package/dist/cjs/Hydration.js.map +1 -0
  14. package/dist/cjs/Registry.js +128 -0
  15. package/dist/cjs/Registry.js.map +1 -0
  16. package/dist/cjs/Result.js +454 -0
  17. package/dist/cjs/Result.js.map +1 -0
  18. package/dist/cjs/index.js +37 -0
  19. package/dist/cjs/index.js.map +1 -0
  20. package/dist/cjs/internal/registry.js +701 -0
  21. package/dist/cjs/internal/registry.js.map +1 -0
  22. package/dist/cjs/internal/runtime.js +92 -0
  23. package/dist/cjs/internal/runtime.js.map +1 -0
  24. package/dist/dts/Atom.d.ts +597 -0
  25. package/dist/dts/Atom.d.ts.map +1 -0
  26. package/dist/dts/AtomRef.d.ts +55 -0
  27. package/dist/dts/AtomRef.d.ts.map +1 -0
  28. package/dist/dts/Hydration.d.ts +27 -0
  29. package/dist/dts/Hydration.d.ts.map +1 -0
  30. package/dist/dts/Registry.d.ts +115 -0
  31. package/dist/dts/Registry.d.ts.map +1 -0
  32. package/dist/dts/Result.d.ts +351 -0
  33. package/dist/dts/Result.d.ts.map +1 -0
  34. package/dist/dts/index.d.ts +21 -0
  35. package/dist/dts/index.d.ts.map +1 -0
  36. package/dist/dts/internal/registry.d.ts +2 -0
  37. package/dist/dts/internal/registry.d.ts.map +1 -0
  38. package/dist/dts/internal/runtime.d.ts +2 -0
  39. package/dist/dts/internal/runtime.d.ts.map +1 -0
  40. package/dist/esm/Atom.js +1029 -0
  41. package/dist/esm/Atom.js.map +1 -0
  42. package/dist/esm/AtomRef.js +232 -0
  43. package/dist/esm/AtomRef.js.map +1 -0
  44. package/dist/esm/Hydration.js +71 -0
  45. package/dist/esm/Hydration.js.map +1 -0
  46. package/dist/esm/Registry.js +98 -0
  47. package/dist/esm/Registry.js.map +1 -0
  48. package/dist/esm/Result.js +403 -0
  49. package/dist/esm/Result.js.map +1 -0
  50. package/dist/esm/index.js +21 -0
  51. package/dist/esm/index.js.map +1 -0
  52. package/dist/esm/internal/registry.js +672 -0
  53. package/dist/esm/internal/registry.js.map +1 -0
  54. package/dist/esm/internal/runtime.js +64 -0
  55. package/dist/esm/internal/runtime.js.map +1 -0
  56. package/dist/esm/package.json +4 -0
  57. package/package.json +72 -0
  58. package/src/Atom.ts +1865 -0
  59. package/src/AtomRef.ts +282 -0
  60. package/src/Hydration.ts +98 -0
  61. package/src/Registry.ts +204 -0
  62. package/src/Result.ts +767 -0
  63. package/src/index.ts +24 -0
  64. package/src/internal/registry.ts +810 -0
  65. 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
+ }