@typed/async-data 0.12.0 → 0.13.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 (75) hide show
  1. package/.nvmrc +1 -0
  2. package/biome.json +36 -0
  3. package/dist/AsyncData.d.ts +196 -0
  4. package/dist/AsyncData.js +285 -0
  5. package/dist/AsyncData.js.map +1 -0
  6. package/dist/LazyRef.d.ts +21 -0
  7. package/dist/LazyRef.js +27 -0
  8. package/dist/LazyRef.js.map +1 -0
  9. package/dist/Progress.d.ts +25 -0
  10. package/dist/Progress.js +21 -0
  11. package/dist/Progress.js.map +1 -0
  12. package/dist/{dts/TypeId.d.ts → TypeId.d.ts} +0 -1
  13. package/dist/TypeId.js +8 -0
  14. package/dist/TypeId.js.map +1 -0
  15. package/dist/_internal.d.ts +16 -0
  16. package/dist/_internal.js +53 -0
  17. package/dist/_internal.js.map +1 -0
  18. package/dist/index.d.ts +4 -0
  19. package/dist/index.js +5 -0
  20. package/dist/index.js.map +1 -0
  21. package/package.json +31 -49
  22. package/readme.md +218 -0
  23. package/src/AsyncData.test.ts +89 -0
  24. package/src/AsyncData.ts +555 -595
  25. package/src/LazyRef.ts +87 -0
  26. package/src/Progress.ts +18 -65
  27. package/src/TypeId.ts +1 -1
  28. package/src/_internal.ts +114 -0
  29. package/src/index.ts +4 -0
  30. package/tsconfig.json +27 -0
  31. package/AsyncData/package.json +0 -6
  32. package/LICENSE +0 -21
  33. package/Progress/package.json +0 -6
  34. package/README.md +0 -5
  35. package/Schema/package.json +0 -6
  36. package/TypeId/package.json +0 -6
  37. package/dist/cjs/AsyncData.js +0 -399
  38. package/dist/cjs/AsyncData.js.map +0 -1
  39. package/dist/cjs/Progress.js +0 -62
  40. package/dist/cjs/Progress.js.map +0 -1
  41. package/dist/cjs/Schema.js +0 -539
  42. package/dist/cjs/Schema.js.map +0 -1
  43. package/dist/cjs/TypeId.js +0 -14
  44. package/dist/cjs/TypeId.js.map +0 -1
  45. package/dist/cjs/internal/async-data.js +0 -94
  46. package/dist/cjs/internal/async-data.js.map +0 -1
  47. package/dist/cjs/internal/tag.js +0 -12
  48. package/dist/cjs/internal/tag.js.map +0 -1
  49. package/dist/dts/AsyncData.d.ts +0 -386
  50. package/dist/dts/AsyncData.d.ts.map +0 -1
  51. package/dist/dts/Progress.d.ts +0 -43
  52. package/dist/dts/Progress.d.ts.map +0 -1
  53. package/dist/dts/Schema.d.ts +0 -78
  54. package/dist/dts/Schema.d.ts.map +0 -1
  55. package/dist/dts/TypeId.d.ts.map +0 -1
  56. package/dist/dts/internal/async-data.d.ts +0 -43
  57. package/dist/dts/internal/async-data.d.ts.map +0 -1
  58. package/dist/dts/internal/tag.d.ts +0 -6
  59. package/dist/dts/internal/tag.d.ts.map +0 -1
  60. package/dist/esm/AsyncData.js +0 -372
  61. package/dist/esm/AsyncData.js.map +0 -1
  62. package/dist/esm/Progress.js +0 -49
  63. package/dist/esm/Progress.js.map +0 -1
  64. package/dist/esm/Schema.js +0 -500
  65. package/dist/esm/Schema.js.map +0 -1
  66. package/dist/esm/TypeId.js +0 -8
  67. package/dist/esm/TypeId.js.map +0 -1
  68. package/dist/esm/internal/async-data.js +0 -91
  69. package/dist/esm/internal/async-data.js.map +0 -1
  70. package/dist/esm/internal/tag.js +0 -6
  71. package/dist/esm/internal/tag.js.map +0 -1
  72. package/dist/esm/package.json +0 -4
  73. package/src/Schema.ts +0 -754
  74. package/src/internal/async-data.ts +0 -114
  75. package/src/internal/tag.ts +0 -9
package/src/Schema.ts DELETED
@@ -1,754 +0,0 @@
1
- /**
2
- * @since 1.0.0
3
- */
4
-
5
- import * as Arbitrary from "@effect/schema/Arbitrary"
6
- import * as AST from "@effect/schema/AST"
7
- import * as Eq from "@effect/schema/Equivalence"
8
- import * as ParseResult from "@effect/schema/ParseResult"
9
- import * as Pretty from "@effect/schema/Pretty"
10
- import * as Schema from "@effect/schema/Schema"
11
- import * as Cause from "effect/Cause"
12
- import * as Data from "effect/Data"
13
- import * as Effect from "effect/Effect"
14
- import * as Equal from "effect/Equal"
15
- import * as FiberId from "effect/FiberId"
16
- import * as Option from "effect/Option"
17
- import { hasProperty } from "effect/Predicate"
18
- import * as _AsyncData from "./AsyncData.js"
19
- import * as P from "./Progress.js"
20
-
21
- const NO_DATA_PRETTY = "AsyncData.NoData"
22
- const LOADING_PRETTY = (loading: _AsyncData.Loading) =>
23
- Option.match(loading.progress, {
24
- onNone: () => `AsyncData.Loading(timestamp=${loading.timestamp})`,
25
- onSome: (progress) => `AsyncData.Loading(timestamp=${loading.timestamp}, progress=${P.pretty(progress)})`
26
- })
27
- const FAILURE_PRETTY = <E>(print: Pretty.Pretty<Cause.Cause<E>>) => (failure: _AsyncData.Failure<E>) =>
28
- Option.match(failure.refreshing, {
29
- onNone: () => `AsyncData.Failure(timestamp=${failure.timestamp}, cause=${print(failure.cause)})`,
30
- onSome: () => `AsyncData.Failure(timestamp=${failure.timestamp}, refreshing=true, cause=${print(failure.cause)})`
31
- })
32
- const SUCCESS_PRETTY = <A>(print: Pretty.Pretty<A>) => (success: _AsyncData.Success<A>) =>
33
- Option.match(success.refreshing, {
34
- onNone: () => `AsyncData.Success(timestamp=${success.timestamp}, value=${print(success.value)})`,
35
- onSome: () => `AsyncData.Success(timestamp=${success.timestamp}, refreshing=true, value=${print(success.value)})`
36
- })
37
-
38
- const OPTIMISTIC_PRETTY =
39
- <E, A>(printValue: Pretty.Pretty<A>, printError: Pretty.Pretty<Cause.Cause<E>>) =>
40
- (optimistic: _AsyncData.Optimistic<A, E>) =>
41
- `AsyncData.Optimistic(timestamp=${optimistic.timestamp}, value=${printValue(optimistic.value)}, previous=${
42
- asyncDataPretty(printValue, printError)(optimistic.previous)
43
- })`
44
-
45
- /**
46
- * @since 1.0.0
47
- */
48
- export type NoDataFrom = { readonly _tag: "NoData" }
49
-
50
- const ProgressSchemaJson = Schema.Struct({
51
- loaded: Schema.BigInt,
52
- total: Schema.optional(Schema.BigInt)
53
- })
54
-
55
- const ProgressSchema: Schema.Schema<
56
- P.Progress,
57
- {
58
- readonly loaded: bigint
59
- readonly total: Option.Option<bigint>
60
- }
61
- > = Schema.Data(Schema.Struct({
62
- loaded: Schema.BigIntFromSelf,
63
- total: Schema.OptionFromSelf(Schema.BigIntFromSelf)
64
- }))
65
-
66
- const progressArbitrary: Arbitrary.LazyArbitrary<P.Progress> = (fc) =>
67
- fc.bigInt().chain((loaded) => fc.option(fc.bigInt({ min: loaded })).map((total) => P.make(loaded, total)))
68
-
69
- /**
70
- * @since 1.0.0
71
- */
72
- export const Progress: Schema.Schema<
73
- P.Progress,
74
- { readonly loaded: string; readonly total?: string | undefined }
75
- > = ProgressSchemaJson.pipe(
76
- Schema.transform(
77
- ProgressSchema,
78
- {
79
- decode: (json): P.Progress => P.make(json.loaded, json.total),
80
- encode: (progress) => ({
81
- loaded: progress.loaded,
82
- total: Option.getOrUndefined(progress.total)
83
- })
84
- }
85
- ),
86
- Schema.annotations({
87
- [AST.IdentifierAnnotationId]: "Progress",
88
- [Pretty.PrettyHookId]: () => "Progress",
89
- [Arbitrary.ArbitraryHookId]: (): Arbitrary.LazyArbitrary<P.Progress> => progressArbitrary,
90
- [Eq.EquivalenceHookId]: () => Equal.equals
91
- })
92
- )
93
-
94
- /**
95
- * @since 1.0.0
96
- */
97
- export type ProgressFrom = {
98
- readonly loaded: string
99
- readonly total?: string | undefined
100
- }
101
-
102
- const loadingArbitrary: Arbitrary.LazyArbitrary<_AsyncData.Loading> = (fc) =>
103
- fc.option(progressArbitrary(fc)).map((progress) =>
104
- _AsyncData.loading({
105
- timestamp: Date.now(),
106
- progress: progress || undefined
107
- })
108
- )
109
-
110
- /**
111
- * @since 1.0.0
112
- */
113
- export type LoadingFrom = {
114
- readonly _tag: "Loading"
115
- readonly timestamp: number
116
- readonly progress?: ProgressFrom | undefined
117
- }
118
-
119
- const failureArbitrary = <E>(
120
- cause: Arbitrary.LazyArbitrary<Cause.Cause<E>>
121
- ): Arbitrary.LazyArbitrary<_AsyncData.Failure<E>> =>
122
- (fc) =>
123
- fc.option(loadingArbitrary(fc)).chain((refreshing) =>
124
- cause(fc).chain((cause) =>
125
- fc.date().map((date) =>
126
- _AsyncData.failCause(cause, {
127
- timestamp: date.getTime(),
128
- refreshing: refreshing || undefined
129
- })
130
- )
131
- )
132
- )
133
-
134
- /**
135
- * @since 1.0.0
136
- */
137
- export type FailureFrom<E> = {
138
- readonly _tag: "Failure"
139
- readonly cause: Schema.CauseEncoded<E, unknown>
140
- readonly timestamp: number
141
- readonly refreshing?: LoadingFrom | undefined
142
- }
143
-
144
- const FailureFrom = <E>(
145
- cause: Schema.CauseEncoded<E, unknown>,
146
- timestamp: number,
147
- refreshing?: LoadingFrom
148
- ): FailureFrom<E> => {
149
- const base = {
150
- _tag: "Failure",
151
- cause,
152
- timestamp
153
- } as const
154
-
155
- if (refreshing !== undefined) {
156
- return { ...base, refreshing }
157
- }
158
-
159
- return base
160
- }
161
-
162
- const successArbitrary = <A>(
163
- value: Arbitrary.LazyArbitrary<A>
164
- ): Arbitrary.LazyArbitrary<_AsyncData.Success<A>> =>
165
- (fc) =>
166
- fc.option(loadingArbitrary(fc)).chain((refreshing) =>
167
- value(fc).chain((a) =>
168
- fc.date().map((date) =>
169
- _AsyncData.success(a, {
170
- timestamp: date.getTime(),
171
- refreshing: refreshing || undefined
172
- })
173
- )
174
- )
175
- )
176
-
177
- /**
178
- * @since 1.0.0
179
- */
180
- export type SuccessFrom<A> = {
181
- readonly timestamp: number
182
- readonly _tag: "Success"
183
- readonly value: A
184
- readonly refreshing?: LoadingFrom | undefined
185
- }
186
-
187
- const SuccessFrom = <A>(value: A, timestamp: number, refreshing?: LoadingFrom): SuccessFrom<A> => {
188
- const base = {
189
- _tag: "Success",
190
- value,
191
- timestamp
192
- } as const
193
-
194
- if (refreshing !== undefined) {
195
- return { ...base, refreshing }
196
- }
197
-
198
- return base
199
- }
200
-
201
- /**
202
- * @since 1.0.0
203
- */
204
- export type OptimisticFrom<A, E> = {
205
- readonly timestamp: number
206
- readonly _tag: "Optimistic"
207
- readonly value: A
208
- readonly previous: AsyncDataFrom<A, E>
209
- }
210
-
211
- const OptimisticFrom = <A, E>(value: A, timestamp: number, previous: AsyncDataFrom<A, E>): OptimisticFrom<A, E> => ({
212
- _tag: "Optimistic",
213
- value,
214
- timestamp,
215
- previous
216
- })
217
-
218
- const optimisticArbitrary = <A, E>(
219
- valueArb: Arbitrary.LazyArbitrary<A>,
220
- causeArb: Arbitrary.LazyArbitrary<Cause.Cause<E>>
221
- ): Arbitrary.LazyArbitrary<_AsyncData.Optimistic<A, E>> =>
222
- (fc) =>
223
- asyncDataArbitrary(valueArb, causeArb)(fc).chain((previous) =>
224
- valueArb(fc).chain((value) =>
225
- fc.date().map((date) => _AsyncData.optimistic(previous, value, { timestamp: date.getTime() }))
226
- )
227
- )
228
-
229
- /**
230
- * @since 1.0.0
231
- */
232
- export type AsyncDataFrom<A, E> = NoDataFrom | LoadingFrom | FailureFrom<E> | SuccessFrom<A> | OptimisticFrom<A, E>
233
-
234
- const fromEq = (a: AsyncDataFrom<any, any>, b: AsyncDataFrom<any, any>): boolean => {
235
- if (a._tag !== b._tag) return false
236
-
237
- switch (a._tag) {
238
- case "NoData":
239
- return true
240
- case "Loading": {
241
- const loadingB = b as LoadingFrom
242
-
243
- if (a.timestamp !== loadingB.timestamp) return false
244
-
245
- if (a.progress === undefined && loadingB.progress === undefined) return true
246
- if (a.progress === undefined || loadingB.progress === undefined) return false
247
-
248
- return Equal.equals(Data.struct(a.progress), Data.struct(loadingB.progress))
249
- }
250
- case "Failure": {
251
- const failureB = b as FailureFrom<any>
252
-
253
- if (
254
- !(
255
- Equal.equals(Data.struct(a.cause), Data.struct(failureB.cause)) && a.timestamp === failureB.timestamp
256
- )
257
- ) return false
258
-
259
- if (a.refreshing === undefined && failureB.refreshing === undefined) return true
260
- if (a.refreshing === undefined || failureB.refreshing === undefined) return false
261
-
262
- return Equal.equals(Data.struct(a.refreshing), Data.struct(failureB.refreshing))
263
- }
264
- case "Success": {
265
- const successB = b as SuccessFrom<any>
266
- return Equal.equals(a.value, successB.value) &&
267
- a.timestamp === successB.timestamp &&
268
- Equal.equals(a.refreshing, successB.refreshing)
269
- }
270
- case "Optimistic": {
271
- const optimisticB = b as OptimisticFrom<any, any>
272
- return Equal.equals(a.value, optimisticB.value) &&
273
- a.timestamp === optimisticB.timestamp &&
274
- fromEq(a.previous, optimisticB.previous)
275
- }
276
- }
277
- }
278
-
279
- function isNoDataFrom(value: unknown): value is NoDataFrom {
280
- return hasProperty(value, "_tag") && value._tag === "NoData"
281
- }
282
-
283
- function isProgressFrom(value: unknown): value is ProgressFrom {
284
- if (!(hasProperty(value, "loaded") && typeof value.loaded === "string")) return false
285
-
286
- if (hasProperty(value, "total")) {
287
- if (typeof value.total !== "string") return false
288
- }
289
-
290
- return true
291
- }
292
-
293
- function isLoadingFrom(value: unknown): value is LoadingFrom {
294
- return hasProperty(value, "_tag")
295
- && value._tag === "Loading"
296
- && hasProperty(value, "timestamp")
297
- && typeof value.timestamp === "number"
298
- && (hasProperty(value, "progress") ? isProgressFrom(value.progress) : true)
299
- }
300
-
301
- const isCauseEncoded = Schema.is(Schema.encodedSchema(Schema.Cause({ defect: Schema.Unknown, error: Schema.Unknown })))
302
-
303
- function isFailureFrom(value: unknown): value is FailureFrom<any> {
304
- return hasProperty(value, "_tag")
305
- && value._tag === "Failure"
306
- && hasProperty(value, "cause")
307
- && isCauseEncoded(value.cause)
308
- && hasProperty(value, "timestamp")
309
- && typeof value.timestamp === "number"
310
- && (hasProperty(value, "refreshing") ? value.refreshing === undefined || isLoadingFrom(value.refreshing) : true)
311
- }
312
-
313
- function isSuccessFrom(value: unknown): value is SuccessFrom<any> {
314
- return hasProperty(value, "_tag")
315
- && value._tag === "Success"
316
- && hasProperty(value, "value")
317
- && hasProperty(value, "timestamp")
318
- && typeof value.timestamp === "number"
319
- && (hasProperty(value, "refreshing") ? value.refreshing === undefined || isLoadingFrom(value.refreshing) : true)
320
- }
321
-
322
- function isOptimisticFrom(value: unknown): value is OptimisticFrom<any, any> {
323
- return hasProperty(value, "_tag")
324
- && value._tag === "Optimistic"
325
- && hasProperty(value, "value")
326
- && hasProperty(value, "previous")
327
- && isAsyncDataFrom(value.previous)
328
- && hasProperty(value, "timestamp")
329
- && typeof value.timestamp === "number"
330
- }
331
-
332
- function isAsyncDataFrom<A = unknown, E = unknown>(value: unknown): value is AsyncDataFrom<A, E> {
333
- return isNoDataFrom(value)
334
- || isLoadingFrom(value)
335
- || isFailureFrom(value)
336
- || isSuccessFrom(value)
337
- || isOptimisticFrom(value)
338
- }
339
-
340
- /**
341
- * @since 1.0.0
342
- */
343
- export const asyncDataFromJson = <A, AI, R1, E, EI, R2>(
344
- value: Schema.Schema<A, AI, R1>,
345
- error: Schema.Schema<E, EI, R2>
346
- ): Schema.Schema<AsyncDataFrom<A, E>, AsyncDataFrom<AI, EI>, R1 | R2> => {
347
- const schema = Schema.declare(
348
- [value, Schema.Cause({ error, defect: Schema.Unknown })],
349
- {
350
- decode: (valueSchema, causeSchema) => {
351
- const parseCause = ParseResult.decode(causeSchema)
352
- const parseValue = ParseResult.decode(valueSchema)
353
-
354
- const parseAsyncData = (
355
- input: unknown,
356
- options?: AST.ParseOptions | undefined
357
- ): Effect.Effect<
358
- AsyncDataFrom<A, E>,
359
- ParseResult.ParseIssue,
360
- never
361
- > => {
362
- return Effect.gen(function*() {
363
- if (!isAsyncDataFrom<AI, EI>(input)) {
364
- return yield* Effect.fail<ParseResult.ParseIssue>(new ParseResult.Forbidden(schema.ast, input))
365
- }
366
-
367
- switch (input._tag) {
368
- case "NoData":
369
- case "Loading":
370
- return input
371
- case "Failure": {
372
- const cause = yield* parseCause(input.cause, options)
373
- return FailureFrom(cause, input.timestamp, input.refreshing)
374
- }
375
- case "Success": {
376
- const a = yield* parseValue(input.value, options)
377
- return SuccessFrom(a, input.timestamp, input.refreshing)
378
- }
379
- case "Optimistic": {
380
- const previous = yield* parseAsyncData(input.previous, options)
381
- const value = yield* parseValue(input.value, options)
382
- return OptimisticFrom(value, input.timestamp, previous)
383
- }
384
- }
385
- })
386
- }
387
-
388
- return parseAsyncData
389
- },
390
- encode: (valueSchema, causeSchema) => {
391
- const parseCause = ParseResult.encode(causeSchema)
392
- const parseValue = ParseResult.encode(valueSchema)
393
-
394
- const parseAsyncData = (
395
- input: unknown,
396
- options?: AST.ParseOptions
397
- ): Effect.Effect<
398
- AsyncDataFrom<AI, EI>,
399
- ParseResult.ParseIssue,
400
- never
401
- > => {
402
- return Effect.gen(function*() {
403
- if (!isAsyncDataFrom<A, E>(input)) {
404
- return yield* Effect.fail<ParseResult.ParseIssue>(new ParseResult.Forbidden(schema.ast, input))
405
- }
406
-
407
- switch (input._tag) {
408
- case "NoData":
409
- case "Loading":
410
- return input
411
- case "Failure": {
412
- const cause = yield* parseCause(causeFromToCause(input.cause), options)
413
- return FailureFrom(cause, input.timestamp, input.refreshing)
414
- }
415
- case "Success": {
416
- const a = yield* parseValue(input.value, options)
417
- return SuccessFrom(a, input.timestamp, input.refreshing)
418
- }
419
- case "Optimistic": {
420
- const previous = yield* parseAsyncData(input.previous, options)
421
- const value = yield* parseValue(input.value, options)
422
- return OptimisticFrom(value, input.timestamp, previous)
423
- }
424
- }
425
- })
426
- }
427
-
428
- return parseAsyncData
429
- }
430
- },
431
- {
432
- title: "AsyncDataFrom",
433
- equivalence: () => fromEq,
434
- arbitrary: (valueArb, causeArb) => (fc) =>
435
- asyncDataArbitrary(valueArb, causeArb)(fc).map(asyncDataToAsyncDataFrom),
436
- pretty: (valuePretty, causePretty) => (from) =>
437
- asyncDataPretty(valuePretty, causePretty)(asyncDataFromToAsyncData(from))
438
- }
439
- )
440
-
441
- return schema
442
- }
443
-
444
- /**
445
- * @since 1.0.0
446
- */
447
- export const AsyncData = <A, AI, R1, E, EI, R2>(
448
- valueSchema: Schema.Schema<A, AI, R2>,
449
- errorSchema: Schema.Schema<E, EI, R1>
450
- ): Schema.Schema<_AsyncData.AsyncData<A, E>, AsyncDataFrom<AI, EI>, R1 | R2> => {
451
- const from = asyncDataFromJson(valueSchema, errorSchema)
452
- const to = AsyncDataFromSelf(Schema.typeSchema(valueSchema), Schema.typeSchema(errorSchema))
453
-
454
- return from
455
- .pipe(Schema.transform(
456
- to,
457
- {
458
- decode: asyncDataFromToAsyncData,
459
- encode: asyncDataToAsyncDataFrom
460
- }
461
- ))
462
- }
463
-
464
- /**
465
- * @since 1.0.0
466
- */
467
- export const AsyncDataFromSelf = <A, AI, R1, E, EI, R2>(
468
- value: Schema.Schema<A, AI, R2>,
469
- error: Schema.Schema<E, EI, R1>
470
- ): Schema.Schema<_AsyncData.AsyncData<A, E>, _AsyncData.AsyncData<AI, EI>, R1 | R2> => {
471
- const schema = Schema.declare(
472
- [value, Schema.CauseFromSelf({ error, defect: Schema.Unknown })],
473
- {
474
- decode: (valueSchema, causeSchema) => {
475
- const parseCause = ParseResult.decode(causeSchema)
476
- const parseValue = ParseResult.decode(valueSchema)
477
-
478
- const parseAsyncData = (
479
- input: unknown,
480
- options?: AST.ParseOptions
481
- ): Effect.Effect<
482
- _AsyncData.AsyncData<A, E>,
483
- ParseResult.ParseIssue,
484
- never
485
- > => {
486
- return Effect.gen(function*() {
487
- if (!_AsyncData.isAsyncData<AI, EI>(input)) {
488
- return yield* Effect.fail<ParseResult.ParseIssue>(new ParseResult.Forbidden(schema.ast, input))
489
- }
490
-
491
- switch (input._tag) {
492
- case "NoData":
493
- case "Loading":
494
- return input
495
- case "Failure": {
496
- const cause = yield* parseCause(input.cause, options)
497
-
498
- return _AsyncData.failCause(cause, {
499
- timestamp: input.timestamp,
500
- refreshing: Option.getOrUndefined(input.refreshing)
501
- })
502
- }
503
- case "Success": {
504
- const a = yield* parseValue(input.value, options)
505
-
506
- return _AsyncData.success(a, {
507
- timestamp: input.timestamp,
508
- refreshing: Option.getOrUndefined(input.refreshing)
509
- })
510
- }
511
- case "Optimistic": {
512
- const previous = yield* parseAsyncData(input.previous, options)
513
- const value = yield* parseValue(input.value, options)
514
-
515
- return _AsyncData.optimistic(previous, value, {
516
- timestamp: input.timestamp
517
- })
518
- }
519
- }
520
- })
521
- }
522
-
523
- return parseAsyncData
524
- },
525
- encode: (valueSchema, causeSchema) => {
526
- const parseCause = ParseResult.encode(causeSchema)
527
- const parseValue = ParseResult.encode(valueSchema)
528
-
529
- const parseAsyncData = (
530
- input: unknown,
531
- options?: AST.ParseOptions
532
- ): Effect.Effect<
533
- _AsyncData.AsyncData<AI, EI>,
534
- ParseResult.ParseIssue,
535
- never
536
- > => {
537
- return Effect.gen(function*() {
538
- if (!_AsyncData.isAsyncData<A, E>(input)) {
539
- return yield* Effect.fail(new ParseResult.Forbidden(schema.ast, input))
540
- }
541
-
542
- switch (input._tag) {
543
- case "NoData":
544
- case "Loading":
545
- return input
546
- case "Failure": {
547
- const cause = yield* parseCause(input.cause, options)
548
-
549
- return _AsyncData.failCause(cause, {
550
- timestamp: input.timestamp,
551
- refreshing: Option.getOrUndefined(input.refreshing)
552
- })
553
- }
554
- case "Success": {
555
- const a = yield* parseValue(input.value, options)
556
-
557
- return _AsyncData.success(a, {
558
- timestamp: input.timestamp,
559
- refreshing: Option.getOrUndefined(input.refreshing)
560
- })
561
- }
562
- case "Optimistic": {
563
- const previous = yield* parseAsyncData(input.previous, options)
564
- const value = yield* parseValue(input.value, options)
565
-
566
- return _AsyncData.optimistic(previous, value, {
567
- timestamp: input.timestamp
568
- })
569
- }
570
- }
571
- })
572
- }
573
-
574
- return parseAsyncData
575
- }
576
- },
577
- {
578
- title: "AsyncData",
579
- pretty: asyncDataPretty,
580
- arbitrary: asyncDataArbitrary,
581
- equivalence: () => Equal.equals
582
- }
583
- )
584
- return schema as any
585
- }
586
-
587
- function asyncDataPretty<A, E>(
588
- A: Pretty.Pretty<A>,
589
- E: Pretty.Pretty<Cause.Cause<E>>
590
- ): Pretty.Pretty<_AsyncData.AsyncData<A, E>> {
591
- return _AsyncData.match({
592
- NoData: () => NO_DATA_PRETTY,
593
- Loading: LOADING_PRETTY,
594
- Failure: (_, data) => FAILURE_PRETTY(E)(data),
595
- Success: (_, data) => SUCCESS_PRETTY(A)(data),
596
- Optimistic: (_, data) => OPTIMISTIC_PRETTY(A, E)(data)
597
- })
598
- }
599
-
600
- function asyncDataArbitrary<A, E>(
601
- A: Arbitrary.LazyArbitrary<A>,
602
- E: Arbitrary.LazyArbitrary<Cause.Cause<E>>
603
- ): Arbitrary.LazyArbitrary<_AsyncData.AsyncData<A, E>> {
604
- const failureArb = failureArbitrary(E)
605
- const successArb = successArbitrary(A)
606
- const optimisticArb = optimisticArbitrary(A, E)
607
-
608
- return (fc) =>
609
- fc.oneof(
610
- fc.constant(_AsyncData.noData()),
611
- fc.constant(_AsyncData.loading()),
612
- failureArb(fc),
613
- successArb(fc),
614
- optimisticArb(fc)
615
- )
616
- }
617
-
618
- function progressFromJson(json: ProgressFrom | undefined): Option.Option<P.Progress> {
619
- if (json === undefined) return Option.none()
620
- return Option.some(P.make(BigInt(json.loaded), json.total === undefined ? undefined : BigInt(json.total)))
621
- }
622
-
623
- function progressToJson(progres: Option.Option<P.Progress>): ProgressFrom | undefined {
624
- if (Option.isNone(progres)) return
625
- return {
626
- loaded: progres.value.loaded.toString(),
627
- total: Option.getOrUndefined(progres.value.total)?.toString()
628
- }
629
- }
630
-
631
- function loadingFromJson(json: LoadingFrom | undefined): _AsyncData.Loading | undefined {
632
- if (json === undefined) return
633
- return _AsyncData.loading({
634
- timestamp: json.timestamp,
635
- progress: Option.getOrUndefined(progressFromJson(json.progress))
636
- })
637
- }
638
-
639
- function loadingToJson(loading: _AsyncData.Loading): LoadingFrom {
640
- const from: LoadingFrom = {
641
- _tag: "Loading",
642
- timestamp: loading.timestamp
643
- }
644
-
645
- if (Option.isSome(loading.progress)) {
646
- return { ...from, progress: progressToJson(loading.progress) }
647
- }
648
-
649
- return from
650
- }
651
-
652
- function causeFromToCause<E>(from: Schema.CauseEncoded<E, unknown>): Cause.Cause<E> {
653
- switch (from._tag) {
654
- case "Die":
655
- return Cause.die(from.defect)
656
- case "Empty":
657
- return Cause.empty
658
- case "Fail":
659
- return Cause.fail(from.error)
660
- case "Interrupt":
661
- return Cause.interrupt(fiberIdFromToFiberId(from.fiberId))
662
- case "Parallel":
663
- return Cause.parallel(causeFromToCause(from.left), causeFromToCause(from.right))
664
- case "Sequential":
665
- return Cause.sequential(causeFromToCause(from.left), causeFromToCause(from.right))
666
- }
667
- }
668
-
669
- function fiberIdFromToFiberId(id: Schema.FiberIdEncoded): FiberId.FiberId {
670
- switch (id._tag) {
671
- case "None":
672
- return FiberId.none
673
- case "Runtime":
674
- return FiberId.runtime(id.id, id.startTimeMillis)
675
- case "Composite":
676
- return FiberId.composite(fiberIdFromToFiberId(id.left), fiberIdFromToFiberId(id.right))
677
- }
678
- }
679
-
680
- function causeToCauseEncoded<E>(cause: Cause.Cause<E>): Schema.CauseEncoded<E, unknown> {
681
- switch (cause._tag) {
682
- case "Die":
683
- return { _tag: "Die", defect: cause.defect }
684
- case "Empty":
685
- return { _tag: "Empty" }
686
- case "Fail":
687
- return { _tag: "Fail", error: cause.error }
688
- case "Interrupt":
689
- return { _tag: "Interrupt", fiberId: fiberIdToFiberIdFrom(cause.fiberId) }
690
- case "Parallel":
691
- return { _tag: "Parallel", left: causeToCauseEncoded(cause.left), right: causeToCauseEncoded(cause.right) }
692
- case "Sequential":
693
- return { _tag: "Sequential", left: causeToCauseEncoded(cause.left), right: causeToCauseEncoded(cause.right) }
694
- }
695
- }
696
-
697
- function fiberIdToFiberIdFrom(id: FiberId.FiberId): Schema.FiberIdEncoded {
698
- switch (id._tag) {
699
- case "None":
700
- return { _tag: "None" }
701
- case "Runtime":
702
- return { _tag: "Runtime", id: id.id, startTimeMillis: id.startTimeMillis }
703
- case "Composite":
704
- return { _tag: "Composite", left: fiberIdToFiberIdFrom(id.left), right: fiberIdToFiberIdFrom(id.right) }
705
- }
706
- }
707
-
708
- const NO_DATA_FROM: NoDataFrom = { _tag: "NoData" } as const
709
-
710
- function asyncDataToAsyncDataFrom<A, E>(data: _AsyncData.AsyncData<A, E>): AsyncDataFrom<A, E> {
711
- switch (data._tag) {
712
- case "NoData":
713
- return NO_DATA_FROM
714
- case "Loading":
715
- return loadingToJson(data)
716
- case "Failure":
717
- return FailureFrom(
718
- causeToCauseEncoded(data.cause),
719
- data.timestamp,
720
- Option.getOrUndefined(Option.map(data.refreshing, loadingToJson))
721
- )
722
- case "Success":
723
- return SuccessFrom(
724
- data.value,
725
- data.timestamp,
726
- Option.getOrUndefined(Option.map(data.refreshing, loadingToJson))
727
- )
728
- case "Optimistic":
729
- return OptimisticFrom(data.value, data.timestamp, asyncDataToAsyncDataFrom(data.previous))
730
- }
731
- }
732
-
733
- function asyncDataFromToAsyncData<A, E>(data: AsyncDataFrom<A, E>): _AsyncData.AsyncData<A, E> {
734
- switch (data._tag) {
735
- case "NoData":
736
- return _AsyncData.noData()
737
- case "Loading":
738
- return loadingFromJson(data)!
739
- case "Failure":
740
- return _AsyncData.failCause(causeFromToCause(data.cause), {
741
- timestamp: data.timestamp,
742
- refreshing: loadingFromJson(data.refreshing)
743
- })
744
- case "Success":
745
- return _AsyncData.success(data.value, {
746
- timestamp: data.timestamp,
747
- refreshing: loadingFromJson(data.refreshing)
748
- })
749
- case "Optimistic":
750
- return _AsyncData.optimistic(asyncDataFromToAsyncData(data.previous), data.value, {
751
- timestamp: data.timestamp
752
- })
753
- }
754
- }