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