@typed/async-data 1.0.0-beta.4 → 1.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -21
- package/dist/index.d.ts +664 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +501 -35
- package/package.json +16 -8
- package/src/__tests__/assert.type-test.ts +4 -0
- package/src/__tests__/flat-map.type-test.ts +29 -0
- package/src/index.ts +807 -41
- package/src/AsyncData.test.ts +0 -444
- package/src/index.test.ts +0 -497
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAEpC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,EAAE,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACpC;AAED,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE5F,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,25 @@ import * as Option from "effect/Option";
|
|
|
5
5
|
import { hasProperty, isObject, isString } from "effect/Predicate";
|
|
6
6
|
import * as Result from "effect/Result";
|
|
7
7
|
import * as Schema from "effect/Schema";
|
|
8
|
+
/**
|
|
9
|
+
* Builds an Effect Schema codec for recursive AsyncData values.
|
|
10
|
+
* @remarks
|
|
11
|
+
* ## Why
|
|
12
|
+
* A codec gives transport boundaries the same state model as application code while encoding `Cause` as JSON and preserving schema service requirements.
|
|
13
|
+
* ## Ownership and lifetime
|
|
14
|
+
* Codec construction is pure and acquires no resources; decoding and encoding use the services declared by the supplied schemas.
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { AsyncData } from "@typed/async-data"
|
|
18
|
+
* import { Schema } from "effect"
|
|
19
|
+
* const codec = AsyncData(Schema.String, Schema.String)
|
|
20
|
+
* ```
|
|
21
|
+
* See [Effect Schema](https://effect.website/docs/schema/introduction/).
|
|
22
|
+
* @category Schemas
|
|
23
|
+
* @since 1.0.0
|
|
24
|
+
*/
|
|
8
25
|
export const AsyncData = (A, E) => {
|
|
9
|
-
const Progress = Schema.Struct({ loaded: Schema.
|
|
26
|
+
const Progress = Schema.Struct({ loaded: Schema.Finite, total: Schema.optional(Schema.Finite) });
|
|
10
27
|
const NoData = Schema.Struct({ _tag: Schema.tag("NoData") });
|
|
11
28
|
const Loading = Schema.Struct({
|
|
12
29
|
_tag: Schema.tag("Loading"),
|
|
@@ -17,74 +34,400 @@ export const AsyncData = (A, E) => {
|
|
|
17
34
|
value: A,
|
|
18
35
|
progress: Schema.optional(Progress),
|
|
19
36
|
});
|
|
37
|
+
const CauseSchema = Schema.Cause(E, Schema.Defect());
|
|
20
38
|
const Failure = Schema.Struct({
|
|
21
39
|
_tag: Schema.tag("Failure"),
|
|
22
|
-
cause:
|
|
40
|
+
cause: Schema.toCodecJson(CauseSchema),
|
|
23
41
|
progress: Schema.optional(Progress),
|
|
24
42
|
});
|
|
25
43
|
const Optimistic = Schema.Struct({
|
|
26
44
|
_tag: Schema.tag("Optimistic"),
|
|
27
45
|
value: A,
|
|
28
|
-
previous: Schema.suspend(() =>
|
|
46
|
+
previous: Schema.suspend(() => AsyncDataSchema),
|
|
29
47
|
});
|
|
30
|
-
const
|
|
31
|
-
|
|
48
|
+
const AsyncDataSchema = Schema.Union([
|
|
49
|
+
NoData,
|
|
50
|
+
Loading,
|
|
51
|
+
Success,
|
|
52
|
+
Failure,
|
|
53
|
+
Optimistic,
|
|
54
|
+
]);
|
|
55
|
+
return AsyncDataSchema;
|
|
32
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Tests whether an AsyncData value is `NoData`.
|
|
59
|
+
* @remarks
|
|
60
|
+
* ## Why
|
|
61
|
+
* A named refinement narrows the union without duplicating tag checks.
|
|
62
|
+
* ## Ownership and lifetime
|
|
63
|
+
* This pure predicate acquires no resources and does not retain its argument.
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { isNoData, NoData } from "@typed/async-data"
|
|
67
|
+
* isNoData(NoData)
|
|
68
|
+
* ```
|
|
69
|
+
* @category Refinements
|
|
70
|
+
* @since 1.0.0
|
|
71
|
+
*/
|
|
33
72
|
export const isNoData = (asyncData) => asyncData._tag === "NoData";
|
|
73
|
+
/**
|
|
74
|
+
* Tests whether an AsyncData value is loading without a prior result.
|
|
75
|
+
* @remarks
|
|
76
|
+
* ## Why
|
|
77
|
+
* This refinement deliberately excludes refreshing success and failure states.
|
|
78
|
+
* ## Ownership and lifetime
|
|
79
|
+
* This pure predicate acquires no resources and does not retain its argument.
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { isLoading, loading } from "@typed/async-data"
|
|
83
|
+
* isLoading(loading())
|
|
84
|
+
* ```
|
|
85
|
+
* @category Refinements
|
|
86
|
+
* @since 1.0.0
|
|
87
|
+
*/
|
|
34
88
|
export const isLoading = (asyncData) => asyncData._tag === "Loading";
|
|
89
|
+
/**
|
|
90
|
+
* Tests whether an AsyncData value contains a successful value.
|
|
91
|
+
* @remarks
|
|
92
|
+
* ## Why
|
|
93
|
+
* This refinement separates settled or refreshing success from optimistic state.
|
|
94
|
+
* ## Ownership and lifetime
|
|
95
|
+
* This pure predicate acquires no resources and does not retain its argument.
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* import { isSuccess, success } from "@typed/async-data"
|
|
99
|
+
* isSuccess(success(1))
|
|
100
|
+
* ```
|
|
101
|
+
* @category Refinements
|
|
102
|
+
* @since 1.0.0
|
|
103
|
+
*/
|
|
35
104
|
export const isSuccess = (asyncData) => asyncData._tag === "Success";
|
|
105
|
+
/**
|
|
106
|
+
* Tests whether an AsyncData value contains an Effect Cause.
|
|
107
|
+
* @remarks
|
|
108
|
+
* ## Why
|
|
109
|
+
* The refinement exposes complete failure information without treating optimistic history as a current failure.
|
|
110
|
+
* ## Ownership and lifetime
|
|
111
|
+
* This pure predicate acquires no resources and does not retain its argument.
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { failure, isFailure } from "@typed/async-data"
|
|
115
|
+
* import { Cause } from "effect"
|
|
116
|
+
* isFailure(failure(Cause.fail("offline")))
|
|
117
|
+
* ```
|
|
118
|
+
* @category Refinements
|
|
119
|
+
* @since 1.0.0
|
|
120
|
+
*/
|
|
36
121
|
export const isFailure = (asyncData) => asyncData._tag === "Failure";
|
|
122
|
+
/**
|
|
123
|
+
* Tests whether an AsyncData value is an optimistic history node.
|
|
124
|
+
* @remarks
|
|
125
|
+
* ## Why
|
|
126
|
+
* A dedicated refinement makes history traversal explicit and type safe.
|
|
127
|
+
* ## Ownership and lifetime
|
|
128
|
+
* This pure predicate acquires no resources and does not retain its argument.
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* import { isOptimistic, optimistic, success } from "@typed/async-data"
|
|
132
|
+
* isOptimistic(optimistic(success(1), 2))
|
|
133
|
+
* ```
|
|
134
|
+
* @category Refinements
|
|
135
|
+
* @since 1.0.0
|
|
136
|
+
*/
|
|
37
137
|
export const isOptimistic = (asyncData) => asyncData._tag === "Optimistic";
|
|
38
|
-
const
|
|
39
|
-
|
|
138
|
+
const hasValidProgress = (u) => {
|
|
139
|
+
if (!hasProperty(u, "progress") || u.progress === undefined) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
const progress = u.progress;
|
|
143
|
+
return (isObject(progress) &&
|
|
144
|
+
hasProperty(progress, "loaded") &&
|
|
145
|
+
typeof progress.loaded === "number" &&
|
|
146
|
+
Number.isFinite(progress.loaded) &&
|
|
147
|
+
(!hasProperty(progress, "total") ||
|
|
148
|
+
progress.total === undefined ||
|
|
149
|
+
(typeof progress.total === "number" && Number.isFinite(progress.total))));
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Validates the runtime structure of an unknown AsyncData value.
|
|
153
|
+
* @remarks
|
|
154
|
+
* ## Why
|
|
155
|
+
* Boundary validation rejects malformed progress, failure causes, and cyclic optimistic histories before application logic depends on them.
|
|
156
|
+
* ## Ownership and lifetime
|
|
157
|
+
* Validation is iterative, acquires no resources, and retains no visited objects after returning.
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* import { isAsyncData } from "@typed/async-data"
|
|
161
|
+
* isAsyncData({ _tag: "Loading", progress: { loaded: 1 } })
|
|
162
|
+
* ```
|
|
163
|
+
* @category Refinements
|
|
164
|
+
* @since 1.0.0
|
|
165
|
+
*/
|
|
166
|
+
export const isAsyncData = (u) => {
|
|
167
|
+
const visited = new WeakSet();
|
|
168
|
+
let current = u;
|
|
169
|
+
while (isObject(current) && hasProperty(current, "_tag") && isString(current._tag)) {
|
|
170
|
+
switch (current._tag) {
|
|
171
|
+
case "NoData":
|
|
172
|
+
return true;
|
|
173
|
+
case "Loading":
|
|
174
|
+
return hasValidProgress(current);
|
|
175
|
+
case "Success":
|
|
176
|
+
return hasProperty(current, "value") && hasValidProgress(current);
|
|
177
|
+
case "Failure":
|
|
178
|
+
return (hasProperty(current, "cause") && Cause.isCause(current.cause) && hasValidProgress(current));
|
|
179
|
+
case "Optimistic":
|
|
180
|
+
if (visited.has(current) ||
|
|
181
|
+
!hasProperty(current, "value") ||
|
|
182
|
+
!hasProperty(current, "previous")) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
visited.add(current);
|
|
186
|
+
current = current.previous;
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Tests whether a success or failure carries active refresh progress.
|
|
196
|
+
* @remarks
|
|
197
|
+
* ## Why
|
|
198
|
+
* Refreshing keeps an existing result visible while making new work observable.
|
|
199
|
+
* ## Ownership and lifetime
|
|
200
|
+
* This pure predicate acquires no resources and does not retain its argument.
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* import { isRefreshing, success } from "@typed/async-data"
|
|
204
|
+
* isRefreshing(success("cached", { loaded: 0 }))
|
|
205
|
+
* ```
|
|
206
|
+
* @category Refinements
|
|
207
|
+
* @since 1.0.0
|
|
208
|
+
*/
|
|
40
209
|
export const isRefreshing = (asyncData) => (asyncData._tag === "Success" || asyncData._tag === "Failure") &&
|
|
41
210
|
asyncData.progress !== undefined;
|
|
42
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Tests whether the base state is loading or refreshing through optimistic history.
|
|
213
|
+
* @remarks
|
|
214
|
+
* ## Why
|
|
215
|
+
* Pending status follows the underlying operation rather than disappearing when optimistic values are layered above it; cycles return `false`.
|
|
216
|
+
*
|
|
217
|
+
* **Known type/runtime discrepancy:** an `Optimistic` wrapper over a pending base returns `true` at runtime, but the existing type predicate narrows to `Loading | Refreshing<A, E>` and excludes `Optimistic`. Do not use this function to narrow before reading `_tag`; use it only as a pending-status boolean and refine the original value separately. The predicate is retained for compatibility and is not an accurate description of every `true` result.
|
|
218
|
+
* ## Ownership and lifetime
|
|
219
|
+
* This iterative predicate acquires no resources and retains no visited objects after returning.
|
|
220
|
+
* @example
|
|
221
|
+
* ```ts
|
|
222
|
+
* import { isPending, loading, optimistic } from "@typed/async-data"
|
|
223
|
+
* isPending(optimistic(loading(), "draft"))
|
|
224
|
+
* ```
|
|
225
|
+
* @category Refinements
|
|
226
|
+
* @since 1.0.0
|
|
227
|
+
*/
|
|
228
|
+
export const isPending = (asyncData) => {
|
|
229
|
+
const visited = new WeakSet();
|
|
230
|
+
let current = asyncData;
|
|
231
|
+
while (isOptimistic(current)) {
|
|
232
|
+
if (visited.has(current)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
visited.add(current);
|
|
236
|
+
current = current.previous;
|
|
237
|
+
}
|
|
238
|
+
return current._tag === "Loading" || isRefreshing(current);
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* The canonical shared initial AsyncData object.
|
|
242
|
+
* @remarks
|
|
243
|
+
* ## Why
|
|
244
|
+
* A shared singleton avoids allocating an equivalent empty state and gives callers an exact constructor value.
|
|
245
|
+
* ## Ownership and lifetime
|
|
246
|
+
* The module owns this resource-free singleton for the process lifetime. It is not frozen: mutation through an unsafe cast changes the shared value for every caller.
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* import { NoData } from "@typed/async-data"
|
|
250
|
+
* const initial = NoData
|
|
251
|
+
* ```
|
|
252
|
+
* @category Constructors
|
|
253
|
+
* @since 1.0.0
|
|
254
|
+
*/
|
|
43
255
|
export const NoData = { _tag: "NoData" };
|
|
256
|
+
/**
|
|
257
|
+
* Creates a loading state with optional progress.
|
|
258
|
+
* @remarks
|
|
259
|
+
* ## Why
|
|
260
|
+
* The constructor keeps state creation consistent with the discriminated union.
|
|
261
|
+
* ## Ownership and lifetime
|
|
262
|
+
* This pure function acquires no resources and returns a new wrapper.
|
|
263
|
+
* @example
|
|
264
|
+
* ```ts
|
|
265
|
+
* import { loading } from "@typed/async-data"
|
|
266
|
+
* const state = loading({ loaded: 2, total: 5 })
|
|
267
|
+
* ```
|
|
268
|
+
* @category Constructors
|
|
269
|
+
* @since 1.0.0
|
|
270
|
+
*/
|
|
44
271
|
export const loading = (progress) => ({ _tag: "Loading", progress });
|
|
272
|
+
/**
|
|
273
|
+
* Creates a successful state with optional refresh progress.
|
|
274
|
+
* @remarks
|
|
275
|
+
* ## Why
|
|
276
|
+
* The constructor preserves the payload type while making refresh state explicit.
|
|
277
|
+
* ## Ownership and lifetime
|
|
278
|
+
* This pure function acquires no resources; the returned wrapper retains the supplied value.
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* import { success } from "@typed/async-data"
|
|
282
|
+
* const state = success("ready")
|
|
283
|
+
* ```
|
|
284
|
+
* @category Constructors
|
|
285
|
+
* @since 1.0.0
|
|
286
|
+
*/
|
|
45
287
|
export const success = (value, progress) => ({
|
|
46
288
|
_tag: "Success",
|
|
47
289
|
value,
|
|
48
290
|
progress,
|
|
49
291
|
});
|
|
292
|
+
/**
|
|
293
|
+
* Creates a failed state while preserving the complete Effect Cause.
|
|
294
|
+
* @remarks
|
|
295
|
+
* ## Why
|
|
296
|
+
* Accepting `Cause` prevents typed failures, defects, and interruption from being collapsed into one error value.
|
|
297
|
+
* ## Ownership and lifetime
|
|
298
|
+
* This pure function acquires no resources; the returned wrapper retains the supplied persistent Cause.
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* import { failure } from "@typed/async-data"
|
|
302
|
+
* import { Cause } from "effect"
|
|
303
|
+
* const state = failure(Cause.fail("offline"))
|
|
304
|
+
* ```
|
|
305
|
+
* @category Constructors
|
|
306
|
+
* @since 1.0.0
|
|
307
|
+
*/
|
|
50
308
|
export const failure = (cause, progress) => ({
|
|
51
309
|
_tag: "Failure",
|
|
52
310
|
cause,
|
|
53
311
|
progress,
|
|
54
312
|
});
|
|
313
|
+
/**
|
|
314
|
+
* Adds an optimistic value above an existing AsyncData history.
|
|
315
|
+
* @remarks
|
|
316
|
+
* ## Why
|
|
317
|
+
* Keeping `previous` makes rollback and reconciliation explicit rather than mutating or discarding earlier state.
|
|
318
|
+
* ## Ownership and lifetime
|
|
319
|
+
* This pure function acquires no resources; the wrapper retains both supplied values.
|
|
320
|
+
* @example
|
|
321
|
+
* ```ts
|
|
322
|
+
* import { optimistic, success } from "@typed/async-data"
|
|
323
|
+
* const state = optimistic(success("saved"), "saving")
|
|
324
|
+
* ```
|
|
325
|
+
* @category Constructors
|
|
326
|
+
* @since 1.0.0
|
|
327
|
+
*/
|
|
55
328
|
export const optimistic = (previous, value) => ({
|
|
56
329
|
_tag: "Optimistic",
|
|
57
330
|
value,
|
|
58
331
|
previous,
|
|
59
332
|
});
|
|
333
|
+
const optimisticHistory = (data) => {
|
|
334
|
+
const values = [];
|
|
335
|
+
const visited = new WeakSet();
|
|
336
|
+
let current = data;
|
|
337
|
+
while (isOptimistic(current)) {
|
|
338
|
+
if (visited.has(current)) {
|
|
339
|
+
throw new TypeError("Cyclic Optimistic history");
|
|
340
|
+
}
|
|
341
|
+
visited.add(current);
|
|
342
|
+
values.push(current.value);
|
|
343
|
+
current = current.previous;
|
|
344
|
+
}
|
|
345
|
+
return { base: current, values };
|
|
346
|
+
};
|
|
347
|
+
const rebuildOptimistic = (base, values) => {
|
|
348
|
+
let current = base;
|
|
349
|
+
for (let index = values.length - 1; index >= 0; index--) {
|
|
350
|
+
current = optimistic(current, values[index]);
|
|
351
|
+
}
|
|
352
|
+
return current;
|
|
353
|
+
};
|
|
354
|
+
const refreshingProgress = (progress, existing) => progress ?? existing ?? { loaded: 0 };
|
|
355
|
+
/**
|
|
356
|
+
* Starts loading while preserving successful, failed, and optimistic history.
|
|
357
|
+
* @remarks
|
|
358
|
+
* ## Why
|
|
359
|
+
* Refreshes should keep usable values or causes visible, and optimistic layers must remain in their original order. Cyclic history throws `TypeError`.
|
|
360
|
+
* ## Ownership and lifetime
|
|
361
|
+
* This pure transformation acquires no resources and returns new plain wrappers where rebuilding is needed.
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* import { startLoading, success } from "@typed/async-data"
|
|
365
|
+
* const refreshing = startLoading(success("cached"))
|
|
366
|
+
* ```
|
|
367
|
+
* @category Transformations
|
|
368
|
+
* @since 1.0.0
|
|
369
|
+
*/
|
|
60
370
|
export const startLoading = (data, progress) => {
|
|
61
|
-
|
|
62
|
-
|
|
371
|
+
const { base, values } = optimisticHistory(data);
|
|
372
|
+
let result;
|
|
373
|
+
if (isSuccess(base)) {
|
|
374
|
+
result = success(base.value, refreshingProgress(progress, base.progress));
|
|
63
375
|
}
|
|
64
|
-
else if (isFailure(
|
|
65
|
-
|
|
376
|
+
else if (isFailure(base)) {
|
|
377
|
+
result = failure(base.cause, refreshingProgress(progress, base.progress));
|
|
66
378
|
}
|
|
67
|
-
else if (
|
|
68
|
-
|
|
379
|
+
else if (isLoading(base)) {
|
|
380
|
+
result = loading(progress ?? base.progress);
|
|
69
381
|
}
|
|
70
382
|
else {
|
|
71
|
-
|
|
383
|
+
result = loading(progress);
|
|
72
384
|
}
|
|
385
|
+
return rebuildOptimistic(result, values);
|
|
73
386
|
};
|
|
387
|
+
/**
|
|
388
|
+
* Stops loading or refreshing without discarding optimistic history.
|
|
389
|
+
* @remarks
|
|
390
|
+
* ## Why
|
|
391
|
+
* Removing progress settles success and failure while leaving initial or loading state semantics predictable. Cyclic history throws `TypeError`.
|
|
392
|
+
* ## Ownership and lifetime
|
|
393
|
+
* This pure transformation acquires no resources and returns new plain wrappers where rebuilding is needed.
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* import { startLoading, stopLoading, success } from "@typed/async-data"
|
|
397
|
+
* const settled = stopLoading(startLoading(success("cached")))
|
|
398
|
+
* ```
|
|
399
|
+
* @category Transformations
|
|
400
|
+
* @since 1.0.0
|
|
401
|
+
*/
|
|
74
402
|
export const stopLoading = (data) => {
|
|
75
|
-
|
|
76
|
-
|
|
403
|
+
const { base, values } = optimisticHistory(data);
|
|
404
|
+
let result;
|
|
405
|
+
if (isSuccess(base)) {
|
|
406
|
+
result = success(base.value);
|
|
77
407
|
}
|
|
78
|
-
else if (isFailure(
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
else if (isOptimistic(data)) {
|
|
82
|
-
return optimistic(stopLoading(data.previous), data.value);
|
|
408
|
+
else if (isFailure(base)) {
|
|
409
|
+
result = failure(base.cause);
|
|
83
410
|
}
|
|
84
411
|
else {
|
|
85
|
-
|
|
412
|
+
result = base;
|
|
86
413
|
}
|
|
414
|
+
return rebuildOptimistic(result, values);
|
|
87
415
|
};
|
|
416
|
+
/**
|
|
417
|
+
* Exhaustively folds every AsyncData variant, in data-first or data-last form.
|
|
418
|
+
* @remarks
|
|
419
|
+
* ## Why
|
|
420
|
+
* Centralized exhaustive dispatch exposes values and Causes with their full state while TypeScript unifies branch result types.
|
|
421
|
+
* ## Ownership and lifetime
|
|
422
|
+
* Matching is synchronous, acquires no resources, and retains nothing beyond callback behavior.
|
|
423
|
+
* @example
|
|
424
|
+
* ```ts
|
|
425
|
+
* import { match } from "@typed/async-data"
|
|
426
|
+
* const label = match({ NoData: () => "empty", Loading: () => "loading", Failure: () => "failed", Success: String, Optimistic: String })
|
|
427
|
+
* ```
|
|
428
|
+
* @category Folding
|
|
429
|
+
* @since 1.0.0
|
|
430
|
+
*/
|
|
88
431
|
export const match = dual(2, (data, matchers) => {
|
|
89
432
|
if (isSuccess(data)) {
|
|
90
433
|
return matchers.Success(data.value, data);
|
|
@@ -102,6 +445,22 @@ export const match = dual(2, (data, matchers) => {
|
|
|
102
445
|
return matchers.Optimistic(data.value, data);
|
|
103
446
|
}
|
|
104
447
|
});
|
|
448
|
+
/**
|
|
449
|
+
* Returns the current successful or optimistic value as an Effect `Option`.
|
|
450
|
+
* @remarks
|
|
451
|
+
* ## Why
|
|
452
|
+
* `Option` distinguishes an absent value from a present `undefined` payload and composes with Effect's data APIs.
|
|
453
|
+
* ## Ownership and lifetime
|
|
454
|
+
* This pure lookup acquires no resources and does not retain the state.
|
|
455
|
+
* @example
|
|
456
|
+
* ```ts
|
|
457
|
+
* import { getSuccess, success } from "@typed/async-data"
|
|
458
|
+
* const value = getSuccess(success(1))
|
|
459
|
+
* ```
|
|
460
|
+
* See [Effect Option](https://effect.website/docs/data-types/option/).
|
|
461
|
+
* @category Accessors
|
|
462
|
+
* @since 1.0.0
|
|
463
|
+
*/
|
|
105
464
|
export function getSuccess(data) {
|
|
106
465
|
return match(data, {
|
|
107
466
|
NoData: Option.none,
|
|
@@ -112,6 +471,19 @@ export function getSuccess(data) {
|
|
|
112
471
|
});
|
|
113
472
|
}
|
|
114
473
|
/**
|
|
474
|
+
* Returns the complete Cause only when the current state is a Failure.
|
|
475
|
+
* @remarks
|
|
476
|
+
* ## Why
|
|
477
|
+
* The accessor keeps typed errors, defects, and interruption intact for callers that need full failure diagnostics.
|
|
478
|
+
* ## Ownership and lifetime
|
|
479
|
+
* This pure lookup acquires no resources and returns a reference to the persistent Cause.
|
|
480
|
+
* @example
|
|
481
|
+
* ```ts
|
|
482
|
+
* import { failure, getCause } from "@typed/async-data"
|
|
483
|
+
* import { Cause } from "effect"
|
|
484
|
+
* const cause = getCause(failure(Cause.fail("offline")))
|
|
485
|
+
* ```
|
|
486
|
+
* @category Accessors
|
|
115
487
|
* @since 1.0.0
|
|
116
488
|
*/
|
|
117
489
|
export function getCause(data) {
|
|
@@ -124,6 +496,19 @@ export function getCause(data) {
|
|
|
124
496
|
});
|
|
125
497
|
}
|
|
126
498
|
/**
|
|
499
|
+
* Returns the first typed failure found in a Failure Cause.
|
|
500
|
+
* @remarks
|
|
501
|
+
* ## Why
|
|
502
|
+
* This convenience accessor intentionally excludes defects and interruption; use `getCause` when those distinctions matter.
|
|
503
|
+
* ## Ownership and lifetime
|
|
504
|
+
* This pure lookup acquires no resources and does not retain the state.
|
|
505
|
+
* @example
|
|
506
|
+
* ```ts
|
|
507
|
+
* import { failure, getError } from "@typed/async-data"
|
|
508
|
+
* import { Cause } from "effect"
|
|
509
|
+
* const error = getError(failure(Cause.fail("offline")))
|
|
510
|
+
* ```
|
|
511
|
+
* @category Accessors
|
|
127
512
|
* @since 1.0.0
|
|
128
513
|
*/
|
|
129
514
|
export function getError(data) {
|
|
@@ -135,17 +520,50 @@ export function getError(data) {
|
|
|
135
520
|
Optimistic: Option.none,
|
|
136
521
|
});
|
|
137
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* Maps successful and every optimistic value while preserving state structure.
|
|
525
|
+
* @remarks
|
|
526
|
+
* ## Why
|
|
527
|
+
* Value transformations should not erase progress, Causes, or optimistic rollback history. Cyclic history throws `TypeError`.
|
|
528
|
+
* ## Ownership and lifetime
|
|
529
|
+
* This pure transformation acquires no resources and returns new plain wrappers.
|
|
530
|
+
* @example
|
|
531
|
+
* ```ts
|
|
532
|
+
* import { map, success } from "@typed/async-data"
|
|
533
|
+
* const state = map(success(2), (n) => n * 2)
|
|
534
|
+
* ```
|
|
535
|
+
* @category Transformations
|
|
536
|
+
* @since 1.0.0
|
|
537
|
+
*/
|
|
138
538
|
export const map = dual(2, function map(data, f) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return optimistic(map(data.previous, f), f(data.value));
|
|
539
|
+
const { base, values } = optimisticHistory(data);
|
|
540
|
+
let result;
|
|
541
|
+
if (isSuccess(base)) {
|
|
542
|
+
result = success(f(base.value), base.progress);
|
|
144
543
|
}
|
|
145
544
|
else {
|
|
146
|
-
|
|
545
|
+
result = base;
|
|
546
|
+
}
|
|
547
|
+
for (let index = values.length - 1; index >= 0; index--) {
|
|
548
|
+
result = optimistic(result, f(values[index]));
|
|
147
549
|
}
|
|
550
|
+
return result;
|
|
148
551
|
});
|
|
552
|
+
/**
|
|
553
|
+
* Replaces a successful or outer optimistic value with another AsyncData value.
|
|
554
|
+
* @remarks
|
|
555
|
+
* ## Why
|
|
556
|
+
* State-producing transformations can change both value and error types while non-value states pass through unchanged.
|
|
557
|
+
* ## Ownership and lifetime
|
|
558
|
+
* This pure transformation acquires no resources; ownership follows the AsyncData returned by the callback.
|
|
559
|
+
* @example
|
|
560
|
+
* ```ts
|
|
561
|
+
* import { flatMap, success } from "@typed/async-data"
|
|
562
|
+
* const parsed = flatMap(success("2"), (text) => success(Number(text)))
|
|
563
|
+
* ```
|
|
564
|
+
* @category Transformations
|
|
565
|
+
* @since 1.0.0
|
|
566
|
+
*/
|
|
149
567
|
export const flatMap = dual(2, function (data, f) {
|
|
150
568
|
if (isSuccess(data) || isOptimistic(data)) {
|
|
151
569
|
return f(data.value, data);
|
|
@@ -154,16 +572,64 @@ export const flatMap = dual(2, function (data, f) {
|
|
|
154
572
|
return data;
|
|
155
573
|
}
|
|
156
574
|
});
|
|
575
|
+
/**
|
|
576
|
+
* Maps typed failures inside the base Cause while preserving defects, interruption, progress, and optimistic history.
|
|
577
|
+
* @remarks
|
|
578
|
+
* ## Why
|
|
579
|
+
* Error adaptation should use Effect Cause semantics instead of flattening the failure channel. Cyclic history throws `TypeError`.
|
|
580
|
+
* ## Ownership and lifetime
|
|
581
|
+
* This pure transformation acquires no resources and returns new plain wrappers.
|
|
582
|
+
* @example
|
|
583
|
+
* ```ts
|
|
584
|
+
* import { failure, mapError } from "@typed/async-data"
|
|
585
|
+
* import { Cause } from "effect"
|
|
586
|
+
* const state = mapError(failure(Cause.fail(404)), String)
|
|
587
|
+
* ```
|
|
588
|
+
* @category Transformations
|
|
589
|
+
* @since 1.0.0
|
|
590
|
+
*/
|
|
157
591
|
export const mapError = dual(2, function mapError(data, f) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return optimistic(mapError(data.previous, f), data.value);
|
|
592
|
+
const { base, values } = optimisticHistory(data);
|
|
593
|
+
let result;
|
|
594
|
+
if (isFailure(base)) {
|
|
595
|
+
result = failure(Cause.map(base.cause, f), base.progress);
|
|
163
596
|
}
|
|
164
597
|
else {
|
|
165
|
-
|
|
598
|
+
result = base;
|
|
166
599
|
}
|
|
600
|
+
return rebuildOptimistic(result, values);
|
|
167
601
|
});
|
|
602
|
+
/**
|
|
603
|
+
* Converts an Effect Exit to Success or Failure without losing its Cause.
|
|
604
|
+
* @remarks
|
|
605
|
+
* ## Why
|
|
606
|
+
* Exit is Effect's complete computation result, so preserving its Cause keeps typed failures, defects, and interruption available.
|
|
607
|
+
* ## Ownership and lifetime
|
|
608
|
+
* This pure conversion acquires no resources and retains the Exit payload or Cause.
|
|
609
|
+
* @example
|
|
610
|
+
* ```ts
|
|
611
|
+
* import { fromExit } from "@typed/async-data"
|
|
612
|
+
* import { Exit } from "effect"
|
|
613
|
+
* const state = fromExit(Exit.succeed(1))
|
|
614
|
+
* ```
|
|
615
|
+
* @category Conversions
|
|
616
|
+
* @since 1.0.0
|
|
617
|
+
*/
|
|
168
618
|
export const fromExit = (exit) => Exit.isSuccess(exit) ? success(exit.value) : failure(exit.cause);
|
|
619
|
+
/**
|
|
620
|
+
* Converts an Effect Result to Success or a typed Failure Cause.
|
|
621
|
+
* @remarks
|
|
622
|
+
* ## Why
|
|
623
|
+
* Result has only typed success/failure, so a failed result becomes `Cause.fail` without inventing defects or interruption.
|
|
624
|
+
* ## Ownership and lifetime
|
|
625
|
+
* This pure conversion acquires no resources and retains the Result payload.
|
|
626
|
+
* @example
|
|
627
|
+
* ```ts
|
|
628
|
+
* import { fromResult } from "@typed/async-data"
|
|
629
|
+
* import { Result } from "effect"
|
|
630
|
+
* const state = fromResult(Result.succeed(1))
|
|
631
|
+
* ```
|
|
632
|
+
* @category Conversions
|
|
633
|
+
* @since 1.0.0
|
|
634
|
+
*/
|
|
169
635
|
export const fromResult = (result) => Result.isSuccess(result) ? success(result.success) : failure(Cause.fail(result.failure));
|