@nunofyobiz/effect-extras 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -2
- package/dist/ArrayX.d.ts +415 -0
- package/dist/ArrayX.d.ts.map +1 -0
- package/dist/ArrayX.js +547 -0
- package/dist/ArrayX.js.map +1 -0
- package/dist/BigIntX.d.ts +24 -0
- package/dist/BigIntX.d.ts.map +1 -0
- package/dist/BigIntX.js +30 -0
- package/dist/BigIntX.js.map +1 -0
- package/dist/BooleanX.d.ts +25 -0
- package/dist/BooleanX.d.ts.map +1 -0
- package/dist/BooleanX.js +25 -0
- package/dist/BooleanX.js.map +1 -0
- package/dist/DurationX.d.ts +73 -0
- package/dist/DurationX.d.ts.map +1 -0
- package/dist/DurationX.js +91 -0
- package/dist/DurationX.js.map +1 -0
- package/dist/EffectX.d.ts +120 -0
- package/dist/EffectX.d.ts.map +1 -0
- package/dist/EffectX.js +140 -0
- package/dist/EffectX.js.map +1 -0
- package/dist/FormDataX.d.ts +49 -0
- package/dist/FormDataX.d.ts.map +1 -0
- package/dist/FormDataX.js +42 -0
- package/dist/FormDataX.js.map +1 -0
- package/dist/MapX.d.ts +32 -0
- package/dist/MapX.d.ts.map +1 -0
- package/dist/MapX.js +49 -0
- package/dist/MapX.js.map +1 -0
- package/dist/NonNullableX.d.ts +174 -0
- package/dist/NonNullableX.d.ts.map +1 -0
- package/dist/NonNullableX.js +212 -0
- package/dist/NonNullableX.js.map +1 -0
- package/dist/NumberX.d.ts +178 -0
- package/dist/NumberX.d.ts.map +1 -0
- package/dist/NumberX.js +214 -0
- package/dist/NumberX.js.map +1 -0
- package/dist/OptionX.d.ts +181 -0
- package/dist/OptionX.d.ts.map +1 -0
- package/dist/OptionX.js +195 -0
- package/dist/OptionX.js.map +1 -0
- package/dist/OrderX.d.ts +32 -0
- package/dist/OrderX.d.ts.map +1 -0
- package/dist/OrderX.js +32 -0
- package/dist/OrderX.js.map +1 -0
- package/dist/PredicateX.d.ts +76 -0
- package/dist/PredicateX.d.ts.map +1 -0
- package/dist/PredicateX.js +73 -0
- package/dist/PredicateX.js.map +1 -0
- package/dist/PromiseX.d.ts +32 -0
- package/dist/PromiseX.d.ts.map +1 -0
- package/dist/PromiseX.js +32 -0
- package/dist/PromiseX.js.map +1 -0
- package/dist/RecordX.d.ts +323 -0
- package/dist/RecordX.d.ts.map +1 -0
- package/dist/RecordX.js +326 -0
- package/dist/RecordX.js.map +1 -0
- package/dist/ResultX.d.ts +50 -0
- package/dist/ResultX.d.ts.map +1 -0
- package/dist/ResultX.js +50 -0
- package/dist/ResultX.js.map +1 -0
- package/dist/SchemaX.d.ts +249 -0
- package/dist/SchemaX.d.ts.map +1 -0
- package/dist/SchemaX.js +243 -0
- package/dist/SchemaX.js.map +1 -0
- package/dist/SetX.d.ts +121 -0
- package/dist/SetX.d.ts.map +1 -0
- package/dist/SetX.js +137 -0
- package/dist/SetX.js.map +1 -0
- package/dist/StringX.d.ts +70 -0
- package/dist/StringX.d.ts.map +1 -0
- package/dist/StringX.js +81 -0
- package/dist/StringX.js.map +1 -0
- package/dist/StructX.d.ts +219 -0
- package/dist/StructX.d.ts.map +1 -0
- package/dist/StructX.js +173 -0
- package/dist/StructX.js.map +1 -0
- package/dist/WarnResult.d.ts +1146 -0
- package/dist/WarnResult.d.ts.map +1 -0
- package/dist/WarnResult.js +1060 -0
- package/dist/WarnResult.js.map +1 -0
- package/dist/index.d.ts +22 -3772
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -1011
- package/dist/index.js.map +1 -1
- package/package.json +18 -5
- package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +3 -3
- package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
- package/src/{RecordX/RecordX.ts → RecordX.ts} +1 -1
- package/src/index.ts +21 -20
- package/src/ArrayX/index.ts +0 -1
- package/src/BigIntX/index.ts +0 -1
- package/src/BooleanX/index.ts +0 -1
- package/src/DurationX/index.ts +0 -1
- package/src/EffectX/index.ts +0 -1
- package/src/FormDataX/index.ts +0 -1
- package/src/MapX/index.ts +0 -1
- package/src/NonNullableX/index.ts +0 -2
- package/src/NumberX/index.ts +0 -1
- package/src/OptionX/index.ts +0 -1
- package/src/OrderX/index.ts +0 -1
- package/src/PredicateX/index.ts +0 -1
- package/src/PromiseX/index.ts +0 -1
- package/src/RecordX/index.ts +0 -1
- package/src/ResultX/index.ts +0 -1
- package/src/SchemaX/index.ts +0 -1
- package/src/SetX/index.ts +0 -1
- package/src/StringX/index.ts +0 -1
- package/src/StructX/index.ts +0 -1
- package/src/WarnResult/index.ts +0 -1
- /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
- /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
- /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
- /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
- /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
- /package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +0 -0
- /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
- /package/src/{OptionX/OptionX.ts → OptionX.ts} +0 -0
- /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
- /package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +0 -0
- /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
- /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
- /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
- /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
- /package/src/{StringX/StringX.ts → StringX.ts} +0 -0
- /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
- /package/src/{WarnResult/WarnResult.ts → WarnResult.ts} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `Duration` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { DateTime, Duration } from "effect";
|
|
7
|
+
/**
|
|
8
|
+
* Computes the elapsed `Duration` from `that` to `self`, clamped at zero.
|
|
9
|
+
*
|
|
10
|
+
* Represents the time that has passed since the reference instant `that`. When
|
|
11
|
+
* `that` lies in the future relative to `self`, the elapsed time is `zero`
|
|
12
|
+
* rather than a negative duration.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { DateTime, Duration, pipe } from "effect"
|
|
17
|
+
* import { DurationX } from "@nunofyobiz/effect-extras"
|
|
18
|
+
*
|
|
19
|
+
* const earlier = DateTime.makeUnsafe(1000)
|
|
20
|
+
* const later = DateTime.makeUnsafe(4000)
|
|
21
|
+
*
|
|
22
|
+
* // data-first
|
|
23
|
+
* assert.deepStrictEqual(DurationX.diff(later, earlier), Duration.seconds(3))
|
|
24
|
+
*
|
|
25
|
+
* // future reference clamps to zero
|
|
26
|
+
* assert.deepStrictEqual(DurationX.diff(earlier, later), Duration.zero)
|
|
27
|
+
*
|
|
28
|
+
* // data-last (piped)
|
|
29
|
+
* assert.deepStrictEqual(
|
|
30
|
+
* pipe(later, DurationX.diff(earlier)),
|
|
31
|
+
* Duration.seconds(3),
|
|
32
|
+
* )
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @category combinators
|
|
36
|
+
* @since 0.0.0
|
|
37
|
+
*/
|
|
38
|
+
export declare const diff: ((that: DateTime.DateTime) => (self: DateTime.DateTime) => Duration.Duration) & ((self: DateTime.DateTime, that: DateTime.DateTime) => Duration.Duration);
|
|
39
|
+
/**
|
|
40
|
+
* Transforms a `Duration` by converting it to a numeric `unit`, applying `map`,
|
|
41
|
+
* then converting back.
|
|
42
|
+
*
|
|
43
|
+
* Lets you operate on a duration in whatever unit is convenient — round it to
|
|
44
|
+
* whole minutes, halve its seconds, floor its days — without juggling
|
|
45
|
+
* conversions by hand. The `map` callback receives the duration expressed as a
|
|
46
|
+
* `number` of `unit`s and returns the new count.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { Duration, Number, pipe } from "effect"
|
|
51
|
+
* import { DurationX } from "@nunofyobiz/effect-extras"
|
|
52
|
+
*
|
|
53
|
+
* // data-first: halve a 4-second duration
|
|
54
|
+
* assert.deepStrictEqual(
|
|
55
|
+
* DurationX.mapAsUnit(Duration.seconds(4), "second", Number.divideUnsafe(2)),
|
|
56
|
+
* Duration.seconds(2),
|
|
57
|
+
* )
|
|
58
|
+
*
|
|
59
|
+
* // data-last (piped)
|
|
60
|
+
* assert.deepStrictEqual(
|
|
61
|
+
* pipe(
|
|
62
|
+
* Duration.minutes(10),
|
|
63
|
+
* DurationX.mapAsUnit("minute", (minutes) => minutes + 5),
|
|
64
|
+
* ),
|
|
65
|
+
* Duration.minutes(15),
|
|
66
|
+
* )
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @category combinators
|
|
70
|
+
* @since 0.0.0
|
|
71
|
+
*/
|
|
72
|
+
export declare const mapAsUnit: ((unit: Duration.Unit, map: (numberOfUnits: number) => number) => (duration: Duration.Duration) => Duration.Duration) & ((duration: Duration.Duration, unit: Duration.Unit, map: (numberOfUnits: number) => number) => Duration.Duration);
|
|
73
|
+
//# sourceMappingURL=DurationX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DurationX.d.ts","sourceRoot":"","sources":["../src/DurationX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAiB,MAAM,QAAQ,CAAC;AAO3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,IAAI,UAER,QAAQ,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,YAEpE,QAAQ,CAAC,QAAQ,QAAQ,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,CAUxE,CAAC;AAwDF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,SAAS,UAGZ,QAAQ,CAAC,IAAI,OACd,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,KACnC,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ,gBAG3C,QAAQ,CAAC,QAAQ,QACrB,QAAQ,CAAC,IAAI,OACd,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,KACnC,QAAQ,CAAC,QAAQ,CAoBvB,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `Duration` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { DateTime, Duration, Match, Option } from "effect";
|
|
7
|
+
import { dual, pipe } from "effect/Function";
|
|
8
|
+
import * as BigIntX from "./BigIntX.js";
|
|
9
|
+
// Some private constants for conversion
|
|
10
|
+
const MICROS_PER_MILLI = 1000;
|
|
11
|
+
/**
|
|
12
|
+
* Computes the elapsed `Duration` from `that` to `self`, clamped at zero.
|
|
13
|
+
*
|
|
14
|
+
* Represents the time that has passed since the reference instant `that`. When
|
|
15
|
+
* `that` lies in the future relative to `self`, the elapsed time is `zero`
|
|
16
|
+
* rather than a negative duration.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { DateTime, Duration, pipe } from "effect"
|
|
21
|
+
* import { DurationX } from "@nunofyobiz/effect-extras"
|
|
22
|
+
*
|
|
23
|
+
* const earlier = DateTime.makeUnsafe(1000)
|
|
24
|
+
* const later = DateTime.makeUnsafe(4000)
|
|
25
|
+
*
|
|
26
|
+
* // data-first
|
|
27
|
+
* assert.deepStrictEqual(DurationX.diff(later, earlier), Duration.seconds(3))
|
|
28
|
+
*
|
|
29
|
+
* // future reference clamps to zero
|
|
30
|
+
* assert.deepStrictEqual(DurationX.diff(earlier, later), Duration.zero)
|
|
31
|
+
*
|
|
32
|
+
* // data-last (piped)
|
|
33
|
+
* assert.deepStrictEqual(
|
|
34
|
+
* pipe(later, DurationX.diff(earlier)),
|
|
35
|
+
* Duration.seconds(3),
|
|
36
|
+
* )
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @category combinators
|
|
40
|
+
* @since 0.0.0
|
|
41
|
+
*/
|
|
42
|
+
export const diff = /*#__PURE__*/dual(2, (self, that) => Duration.millis(
|
|
43
|
+
// Clamp at 0 — "diff" represents elapsed time since `that`; if `that`
|
|
44
|
+
// is in the future relative to `self`, the elapsed time is zero
|
|
45
|
+
// (not negative).
|
|
46
|
+
Math.max(0, DateTime.toEpochMillis(self) - DateTime.toEpochMillis(that))));
|
|
47
|
+
// Internal — used by mapAsUnit.
|
|
48
|
+
const toUnit = /*#__PURE__*/dual(2, (duration, unit) => Match.value(unit).pipe(Match.whenOr("week", "weeks", () => Duration.toWeeks(duration)), Match.whenOr("day", "days", () => Duration.toDays(duration)), Match.whenOr("hour", "hours", () => Duration.toHours(duration)), Match.whenOr("minute", "minutes", () => Duration.toMinutes(duration)), Match.whenOr("second", "seconds", () => Duration.toSeconds(duration)), Match.whenOr("milli", "millis", () => Duration.toMillis(duration)), Match.whenOr("micro", "micros", () => Duration.toMillis(duration) * MICROS_PER_MILLI), Match.whenOr("nano", "nanos", () => pipe(Duration.toNanos(duration), Option.getOrThrowWith(() => new Error("Duration.toNanos returned None")), BigIntX.toNumberOrThrow)), Match.exhaustive));
|
|
49
|
+
// Internal — used by mapAsUnit.
|
|
50
|
+
const fromUnit = /*#__PURE__*/dual(2, (value, unit) => Match.value(unit).pipe(Match.whenOr("week", "weeks", () => Duration.weeks(value)), Match.whenOr("day", "days", () => Duration.days(value)), Match.whenOr("hour", "hours", () => Duration.hours(value)), Match.whenOr("minute", "minutes", () => Duration.minutes(value)), Match.whenOr("second", "seconds", () => Duration.seconds(value)), Match.whenOr("milli", "millis", () => Duration.millis(value)), Match.whenOr("micro", "micros", () => Duration.micros(BigInt(value))), Match.whenOr("nano", "nanos", () => Duration.nanos(BigInt(value))), Match.exhaustive));
|
|
51
|
+
/**
|
|
52
|
+
* Transforms a `Duration` by converting it to a numeric `unit`, applying `map`,
|
|
53
|
+
* then converting back.
|
|
54
|
+
*
|
|
55
|
+
* Lets you operate on a duration in whatever unit is convenient — round it to
|
|
56
|
+
* whole minutes, halve its seconds, floor its days — without juggling
|
|
57
|
+
* conversions by hand. The `map` callback receives the duration expressed as a
|
|
58
|
+
* `number` of `unit`s and returns the new count.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { Duration, Number, pipe } from "effect"
|
|
63
|
+
* import { DurationX } from "@nunofyobiz/effect-extras"
|
|
64
|
+
*
|
|
65
|
+
* // data-first: halve a 4-second duration
|
|
66
|
+
* assert.deepStrictEqual(
|
|
67
|
+
* DurationX.mapAsUnit(Duration.seconds(4), "second", Number.divideUnsafe(2)),
|
|
68
|
+
* Duration.seconds(2),
|
|
69
|
+
* )
|
|
70
|
+
*
|
|
71
|
+
* // data-last (piped)
|
|
72
|
+
* assert.deepStrictEqual(
|
|
73
|
+
* pipe(
|
|
74
|
+
* Duration.minutes(10),
|
|
75
|
+
* DurationX.mapAsUnit("minute", (minutes) => minutes + 5),
|
|
76
|
+
* ),
|
|
77
|
+
* Duration.minutes(15),
|
|
78
|
+
* )
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @category combinators
|
|
82
|
+
* @since 0.0.0
|
|
83
|
+
*/
|
|
84
|
+
export const mapAsUnit = /*#__PURE__*/dual(3, (duration, unit, map) => pipe(duration,
|
|
85
|
+
// Convert to that unit
|
|
86
|
+
toUnit(unit),
|
|
87
|
+
// Truncate to the requested number of digits
|
|
88
|
+
map,
|
|
89
|
+
// Convert back to a duration
|
|
90
|
+
fromUnit(unit)));
|
|
91
|
+
//# sourceMappingURL=DurationX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DurationX.js","names":["DateTime","Duration","Match","Option","dual","pipe","BigIntX","MICROS_PER_MILLI","diff","self","that","millis","Math","max","toEpochMillis","toUnit","duration","unit","value","whenOr","toWeeks","toDays","toHours","toMinutes","toSeconds","toMillis","toNanos","getOrThrowWith","Error","toNumberOrThrow","exhaustive","fromUnit","weeks","days","hours","minutes","seconds","micros","BigInt","nanos","mapAsUnit","map"],"sources":["../src/DurationX.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `Effect` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Cause, Duration, Effect, Option, Predicate } from "effect";
|
|
7
|
+
/**
|
|
8
|
+
* Flattens an `Effect` that succeeds with an `Option` into an `Effect` that
|
|
9
|
+
* fails with `onNone()` when the `Option` is `None`.
|
|
10
|
+
*
|
|
11
|
+
* When the wrapped `Option` is `Some(value)` the effect succeeds with `value`;
|
|
12
|
+
* when it is `None` the effect fails with the error produced by the `onNone`
|
|
13
|
+
* thunk. An existing failure of the source effect is preserved untouched, so the
|
|
14
|
+
* result's error channel is the union of the original error and the `None`
|
|
15
|
+
* error.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Effect, Option, Result } from "effect"
|
|
20
|
+
* import { EffectX } from "@nunofyobiz/effect-extras"
|
|
21
|
+
*
|
|
22
|
+
* const some = EffectX.flattenOption(
|
|
23
|
+
* Effect.succeed(Option.some(1)),
|
|
24
|
+
* () => "missing",
|
|
25
|
+
* )
|
|
26
|
+
* assert.deepStrictEqual(Effect.runSync(Effect.result(some)), Result.succeed(1))
|
|
27
|
+
*
|
|
28
|
+
* const none = EffectX.flattenOption(
|
|
29
|
+
* Effect.succeed(Option.none<number>()),
|
|
30
|
+
* () => "missing",
|
|
31
|
+
* )
|
|
32
|
+
* assert.deepStrictEqual(
|
|
33
|
+
* Effect.runSync(Effect.result(none)),
|
|
34
|
+
* Result.fail("missing"),
|
|
35
|
+
* )
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @category sequencing
|
|
39
|
+
* @since 0.0.0
|
|
40
|
+
*/
|
|
41
|
+
export declare const flattenOption: (<A, E1, E2, R>(onNone: () => E2) => (effect: Effect.Effect<Option.Option<A>, E1, R>) => Effect.Effect<A, E1 | E2, R>) & (<A, E1, E2, R>(effect: Effect.Effect<Option.Option<A>, E1, R>, onNone: () => E2) => Effect.Effect<A, E1 | E2, R>);
|
|
42
|
+
/**
|
|
43
|
+
* Converts an `Option` to an `Effect`, mapping the `None` case to a caller-chosen
|
|
44
|
+
* error via the `onNone` thunk.
|
|
45
|
+
*
|
|
46
|
+
* Equivalent to `Effect.mapError(Effect.fromOption(option), onNone)`: it bridges
|
|
47
|
+
* the `NoSuchElementError` that `Effect.fromOption` produces to the caller's own
|
|
48
|
+
* error type, so callers never have to handle `NoSuchElementError`. This fills
|
|
49
|
+
* the v4 gap where `Effect.mapError` no longer accepts an `Option` directly —
|
|
50
|
+
* instead of
|
|
51
|
+
* `pipe(option, Effect.fromOption, Effect.mapError(() => new MyError()))`, write
|
|
52
|
+
* `pipe(option, EffectX.fromOptionOrElse(() => new MyError()))`. The `onNone`
|
|
53
|
+
* thunk runs only when the `Option` is `None`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { Effect, Option, Result, pipe } from "effect"
|
|
58
|
+
* import { EffectX } from "@nunofyobiz/effect-extras"
|
|
59
|
+
*
|
|
60
|
+
* // data-first
|
|
61
|
+
* const some = EffectX.fromOptionOrElse(Option.some(42), () => "missing")
|
|
62
|
+
* assert.deepStrictEqual(Effect.runSync(Effect.result(some)), Result.succeed(42))
|
|
63
|
+
*
|
|
64
|
+
* // data-last (piped) — None maps to the chosen error
|
|
65
|
+
* const none = pipe(
|
|
66
|
+
* Option.none<number>(),
|
|
67
|
+
* EffectX.fromOptionOrElse(() => "missing"),
|
|
68
|
+
* )
|
|
69
|
+
* assert.deepStrictEqual(
|
|
70
|
+
* Effect.runSync(Effect.result(none)),
|
|
71
|
+
* Result.fail("missing"),
|
|
72
|
+
* )
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @category conversions
|
|
76
|
+
* @since 0.0.0
|
|
77
|
+
*/
|
|
78
|
+
export declare const fromOptionOrElse: {
|
|
79
|
+
<E>(onNone: () => E): <A>(option: Option.Option<A>) => Effect.Effect<A, E>;
|
|
80
|
+
<A, E>(option: Option.Option<A>, onNone: () => E): Effect.Effect<A, E>;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Repeatedly calls a synchronous `try` thunk until its result satisfies the
|
|
84
|
+
* `until` refinement, sleeping `sleepDuration` between attempts and failing with
|
|
85
|
+
* a `TimeoutError` once `maxDuration` elapses.
|
|
86
|
+
*
|
|
87
|
+
* The thunk is evaluated immediately; if its first result already passes the
|
|
88
|
+
* refinement the effect succeeds without any delay. Otherwise it polls on the
|
|
89
|
+
* `sleepDuration` interval (defaulting to 200ms — the threshold below which a
|
|
90
|
+
* delay reads as "instant" to a user) until either the predicate holds (the
|
|
91
|
+
* effect succeeds with the narrowed `B` value) or `maxDuration` is exceeded (the
|
|
92
|
+
* effect fails with a `Cause.TimeoutError`). Use it to await an external,
|
|
93
|
+
* non-effectful condition such as a flag flipped by a callback.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* import { Duration, Effect } from "effect"
|
|
98
|
+
* import { EffectX } from "@nunofyobiz/effect-extras"
|
|
99
|
+
*
|
|
100
|
+
* // First attempt already matches, so it resolves immediately.
|
|
101
|
+
* const effect = EffectX.tryUntil({
|
|
102
|
+
* try: () => 1,
|
|
103
|
+
* until: (value: number): value is number => value === 1,
|
|
104
|
+
* sleepDuration: Duration.millis(100),
|
|
105
|
+
* maxDuration: Duration.seconds(1),
|
|
106
|
+
* })
|
|
107
|
+
*
|
|
108
|
+
* assert.deepStrictEqual(Effect.runSync(effect), 1)
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* @category sequencing
|
|
112
|
+
* @since 0.0.0
|
|
113
|
+
*/
|
|
114
|
+
export declare const tryUntil: <A, B extends A>({ try: doTry, until: isDone, sleepDuration, maxDuration, }: {
|
|
115
|
+
try: () => A;
|
|
116
|
+
until: Predicate.Refinement<A, B>;
|
|
117
|
+
sleepDuration?: Duration.Duration;
|
|
118
|
+
maxDuration: Duration.Duration;
|
|
119
|
+
}) => Effect.Effect<B, Cause.TimeoutError, never>;
|
|
120
|
+
//# sourceMappingURL=EffectX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EffectX.d.ts","sourceRoot":"","sources":["../src/EffectX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAQ,MAAM,QAAQ,CAAC;AAU1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,aAAa,IACvB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,UACH,MAAM,EAAE,KACb,CACH,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,KAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,MAChC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,UACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,UACtC,MAAM,EAAE,KACb,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAUlC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,gBAAgB,EAAE;IAC7B,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAKxE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,4DAKtC;IACD,GAAG,EAAE,MAAM,CAAC,CAAC;IACb,KAAK,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,aAAa,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAClC,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC;CAChC,KAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAyB7C,CAAC"}
|
package/dist/EffectX.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions to Effect's `Effect` module.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Cause, Duration, Effect, pipe } from "effect";
|
|
7
|
+
import { dual } from "effect/Function";
|
|
8
|
+
/**
|
|
9
|
+
* The duration of time a user registers something as "instant" — used as the
|
|
10
|
+
* default poll interval for {@link tryUntil}. 200ms is the generally agreed
|
|
11
|
+
* value. See https://psychology.stackexchange.com/a/1680
|
|
12
|
+
*/
|
|
13
|
+
const USER_INSTANT_DURATION = /*#__PURE__*/Duration.millis(200);
|
|
14
|
+
/**
|
|
15
|
+
* Flattens an `Effect` that succeeds with an `Option` into an `Effect` that
|
|
16
|
+
* fails with `onNone()` when the `Option` is `None`.
|
|
17
|
+
*
|
|
18
|
+
* When the wrapped `Option` is `Some(value)` the effect succeeds with `value`;
|
|
19
|
+
* when it is `None` the effect fails with the error produced by the `onNone`
|
|
20
|
+
* thunk. An existing failure of the source effect is preserved untouched, so the
|
|
21
|
+
* result's error channel is the union of the original error and the `None`
|
|
22
|
+
* error.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { Effect, Option, Result } from "effect"
|
|
27
|
+
* import { EffectX } from "@nunofyobiz/effect-extras"
|
|
28
|
+
*
|
|
29
|
+
* const some = EffectX.flattenOption(
|
|
30
|
+
* Effect.succeed(Option.some(1)),
|
|
31
|
+
* () => "missing",
|
|
32
|
+
* )
|
|
33
|
+
* assert.deepStrictEqual(Effect.runSync(Effect.result(some)), Result.succeed(1))
|
|
34
|
+
*
|
|
35
|
+
* const none = EffectX.flattenOption(
|
|
36
|
+
* Effect.succeed(Option.none<number>()),
|
|
37
|
+
* () => "missing",
|
|
38
|
+
* )
|
|
39
|
+
* assert.deepStrictEqual(
|
|
40
|
+
* Effect.runSync(Effect.result(none)),
|
|
41
|
+
* Result.fail("missing"),
|
|
42
|
+
* )
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @category sequencing
|
|
46
|
+
* @since 0.0.0
|
|
47
|
+
*/
|
|
48
|
+
export const flattenOption = /*#__PURE__*/dual(2, (effect, onNone) => Effect.flatMap(effect, option => pipe(Effect.fromOption(option), Effect.mapError(onNone))));
|
|
49
|
+
/**
|
|
50
|
+
* Converts an `Option` to an `Effect`, mapping the `None` case to a caller-chosen
|
|
51
|
+
* error via the `onNone` thunk.
|
|
52
|
+
*
|
|
53
|
+
* Equivalent to `Effect.mapError(Effect.fromOption(option), onNone)`: it bridges
|
|
54
|
+
* the `NoSuchElementError` that `Effect.fromOption` produces to the caller's own
|
|
55
|
+
* error type, so callers never have to handle `NoSuchElementError`. This fills
|
|
56
|
+
* the v4 gap where `Effect.mapError` no longer accepts an `Option` directly —
|
|
57
|
+
* instead of
|
|
58
|
+
* `pipe(option, Effect.fromOption, Effect.mapError(() => new MyError()))`, write
|
|
59
|
+
* `pipe(option, EffectX.fromOptionOrElse(() => new MyError()))`. The `onNone`
|
|
60
|
+
* thunk runs only when the `Option` is `None`.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { Effect, Option, Result, pipe } from "effect"
|
|
65
|
+
* import { EffectX } from "@nunofyobiz/effect-extras"
|
|
66
|
+
*
|
|
67
|
+
* // data-first
|
|
68
|
+
* const some = EffectX.fromOptionOrElse(Option.some(42), () => "missing")
|
|
69
|
+
* assert.deepStrictEqual(Effect.runSync(Effect.result(some)), Result.succeed(42))
|
|
70
|
+
*
|
|
71
|
+
* // data-last (piped) — None maps to the chosen error
|
|
72
|
+
* const none = pipe(
|
|
73
|
+
* Option.none<number>(),
|
|
74
|
+
* EffectX.fromOptionOrElse(() => "missing"),
|
|
75
|
+
* )
|
|
76
|
+
* assert.deepStrictEqual(
|
|
77
|
+
* Effect.runSync(Effect.result(none)),
|
|
78
|
+
* Result.fail("missing"),
|
|
79
|
+
* )
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @category conversions
|
|
83
|
+
* @since 0.0.0
|
|
84
|
+
*/
|
|
85
|
+
export const fromOptionOrElse = /*#__PURE__*/dual(2, (option, onNone) => pipe(Effect.fromOption(option), Effect.mapError(onNone)));
|
|
86
|
+
/**
|
|
87
|
+
* Repeatedly calls a synchronous `try` thunk until its result satisfies the
|
|
88
|
+
* `until` refinement, sleeping `sleepDuration` between attempts and failing with
|
|
89
|
+
* a `TimeoutError` once `maxDuration` elapses.
|
|
90
|
+
*
|
|
91
|
+
* The thunk is evaluated immediately; if its first result already passes the
|
|
92
|
+
* refinement the effect succeeds without any delay. Otherwise it polls on the
|
|
93
|
+
* `sleepDuration` interval (defaulting to 200ms — the threshold below which a
|
|
94
|
+
* delay reads as "instant" to a user) until either the predicate holds (the
|
|
95
|
+
* effect succeeds with the narrowed `B` value) or `maxDuration` is exceeded (the
|
|
96
|
+
* effect fails with a `Cause.TimeoutError`). Use it to await an external,
|
|
97
|
+
* non-effectful condition such as a flag flipped by a callback.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* import { Duration, Effect } from "effect"
|
|
102
|
+
* import { EffectX } from "@nunofyobiz/effect-extras"
|
|
103
|
+
*
|
|
104
|
+
* // First attempt already matches, so it resolves immediately.
|
|
105
|
+
* const effect = EffectX.tryUntil({
|
|
106
|
+
* try: () => 1,
|
|
107
|
+
* until: (value: number): value is number => value === 1,
|
|
108
|
+
* sleepDuration: Duration.millis(100),
|
|
109
|
+
* maxDuration: Duration.seconds(1),
|
|
110
|
+
* })
|
|
111
|
+
*
|
|
112
|
+
* assert.deepStrictEqual(Effect.runSync(effect), 1)
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @category sequencing
|
|
116
|
+
* @since 0.0.0
|
|
117
|
+
*/
|
|
118
|
+
export const tryUntil = ({
|
|
119
|
+
try: doTry,
|
|
120
|
+
until: isDone,
|
|
121
|
+
sleepDuration = USER_INSTANT_DURATION,
|
|
122
|
+
maxDuration
|
|
123
|
+
}) => {
|
|
124
|
+
const immediateValue = doTry();
|
|
125
|
+
if (isDone(immediateValue)) {
|
|
126
|
+
return Effect.succeed(immediateValue);
|
|
127
|
+
}
|
|
128
|
+
// Continually call it again on a schedule with a delay
|
|
129
|
+
return Effect.sync(doTry).pipe(
|
|
130
|
+
// Sleep in between each attempt
|
|
131
|
+
Effect.delay(sleepDuration),
|
|
132
|
+
// Keep doing this until the predicate passes
|
|
133
|
+
Effect.repeat({
|
|
134
|
+
until: isDone
|
|
135
|
+
}),
|
|
136
|
+
// Until a timeout occurs. In v4, `Effect.timeout` raises `TimeoutError`
|
|
137
|
+
// on its own — no separate `timeoutFail` overload is needed.
|
|
138
|
+
Effect.timeout(maxDuration), Effect.catchTag("TimeoutError", () => Effect.fail(new Cause.TimeoutError(`Timed out after ${Duration.format(maxDuration)} waiting for value to pass predicate`))));
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=EffectX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EffectX.js","names":["Cause","Duration","Effect","pipe","dual","USER_INSTANT_DURATION","millis","flattenOption","effect","onNone","flatMap","option","fromOption","mapError","fromOptionOrElse","tryUntil","try","doTry","until","isDone","sleepDuration","maxDuration","immediateValue","succeed","sync","delay","repeat","timeout","catchTag","fail","TimeoutError","format"],"sources":["../src/EffectX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,KAAK,EAAEC,QAAQ,EAAEC,MAAM,EAAqBC,IAAI,QAAQ,QAAQ;AACzE,SAASC,IAAI,QAAQ,iBAAiB;AAEtC;;;;;AAKA,MAAMC,qBAAqB,gBAAGJ,QAAQ,CAACK,MAAM,CAAC,GAAG,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,OAAO,MAAMC,aAAa,gBAAGH,IAAI,CAW/B,CAAC,EACD,CACEI,MAA8C,EAC9CC,MAAgB,KAEhBP,MAAM,CAACQ,OAAO,CAACF,MAAM,EAAGG,MAAM,IAC5BR,IAAI,CAACD,MAAM,CAACU,UAAU,CAACD,MAAM,CAAC,EAAET,MAAM,CAACW,QAAQ,CAACJ,MAAM,CAAC,CAAC,CACzD,CACJ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,OAAO,MAAMK,gBAAgB,gBAGzBV,IAAI,CACN,CAAC,EACD,CAAOO,MAAwB,EAAEF,MAAe,KAC9CN,IAAI,CAACD,MAAM,CAACU,UAAU,CAACD,MAAM,CAAC,EAAET,MAAM,CAACW,QAAQ,CAACJ,MAAM,CAAC,CAAC,CAC3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,OAAO,MAAMM,QAAQ,GAAGA,CAAiB;EACvCC,GAAG,EAAEC,KAAK;EACVC,KAAK,EAAEC,MAAM;EACbC,aAAa,GAAGf,qBAAqB;EACrCgB;AAAW,CAMZ,KAAiD;EAChD,MAAMC,cAAc,GAAGL,KAAK,EAAE;EAC9B,IAAIE,MAAM,CAACG,cAAc,CAAC,EAAE;IAC1B,OAAOpB,MAAM,CAACqB,OAAO,CAACD,cAAc,CAAC;EACvC;EAEA;EACA,OAAOpB,MAAM,CAACsB,IAAI,CAACP,KAAK,CAAC,CAACd,IAAI;EAC5B;EACAD,MAAM,CAACuB,KAAK,CAACL,aAAa,CAAC;EAE3B;EACAlB,MAAM,CAACwB,MAAM,CAAC;IAAER,KAAK,EAAEC;EAAM,CAAE,CAAC;EAEhC;EACA;EACAjB,MAAM,CAACyB,OAAO,CAACN,WAAW,CAAC,EAC3BnB,MAAM,CAAC0B,QAAQ,CAAC,cAAc,EAAE,MAC9B1B,MAAM,CAAC2B,IAAI,CACT,IAAI7B,KAAK,CAAC8B,YAAY,CACpB,mBAAmB7B,QAAQ,CAAC8B,MAAM,CAACV,WAAW,CAAC,sCAAsC,CACtF,CACF,CACF,CACF;AACH,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for decoding `FormData` with Effect `Schema`.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Schema } from "effect";
|
|
7
|
+
/**
|
|
8
|
+
* Decodes a `FormData` into a typed value using a `Schema`, throwing on
|
|
9
|
+
* validation failure.
|
|
10
|
+
*
|
|
11
|
+
* Built on v4's native `Schema.fromFormData`, which first parses the `FormData`
|
|
12
|
+
* entries into a nested tree record (bracket-path notation is supported) and then
|
|
13
|
+
* decodes that tree with the provided inner schema. For schemas with non-string
|
|
14
|
+
* fields (for example `Schema.Int`), wrap the inner schema in
|
|
15
|
+
* `Schema.toCodecStringTree(schema, { keepDeclarations: true })` so the
|
|
16
|
+
* string → number/boolean coercion happens. Usable only with schemas that have
|
|
17
|
+
* no decoding services — this is enforced at the type level via
|
|
18
|
+
* `S["DecodingServices"] = never` — and it throws synchronously when the input
|
|
19
|
+
* fails validation.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { Schema } from "effect"
|
|
24
|
+
* import { FormDataX } from "@nunofyobiz/effect-extras"
|
|
25
|
+
*
|
|
26
|
+
* const formData = new FormData()
|
|
27
|
+
* formData.append("name", "John")
|
|
28
|
+
* formData.append("age", "30")
|
|
29
|
+
*
|
|
30
|
+
* const result = FormDataX.decodeSync(
|
|
31
|
+
* formData,
|
|
32
|
+
* Schema.Struct({ name: Schema.String, age: Schema.NumberFromString }),
|
|
33
|
+
* )
|
|
34
|
+
*
|
|
35
|
+
* assert.deepStrictEqual(result, { name: "John", age: 30 })
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @category conversions
|
|
39
|
+
* @since 0.0.0
|
|
40
|
+
*/
|
|
41
|
+
export declare const decodeSync: {
|
|
42
|
+
<S extends Schema.Top & {
|
|
43
|
+
readonly DecodingServices: never;
|
|
44
|
+
}>(formData: FormData, schema: S): S["Type"];
|
|
45
|
+
<S extends Schema.Top & {
|
|
46
|
+
readonly DecodingServices: never;
|
|
47
|
+
}>(schema: S): (formData: FormData) => S["Type"];
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=FormDataX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormDataX.d.ts","sourceRoot":"","sources":["../src/FormDataX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAY,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,UAAU,EAAE;IACvB,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,GAAG;QAAE,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAA;KAAE,EAC1D,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,CAAC,GACR,CAAC,CAAC,MAAM,CAAC,CAAC;IACb,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,GAAG;QAAE,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAA;KAAE,EAC1D,MAAM,EAAE,CAAC,GACR,CAAC,QAAQ,EAAE,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;CAQtC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for decoding `FormData` with Effect `Schema`.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Function, Schema } from "effect";
|
|
7
|
+
/**
|
|
8
|
+
* Decodes a `FormData` into a typed value using a `Schema`, throwing on
|
|
9
|
+
* validation failure.
|
|
10
|
+
*
|
|
11
|
+
* Built on v4's native `Schema.fromFormData`, which first parses the `FormData`
|
|
12
|
+
* entries into a nested tree record (bracket-path notation is supported) and then
|
|
13
|
+
* decodes that tree with the provided inner schema. For schemas with non-string
|
|
14
|
+
* fields (for example `Schema.Int`), wrap the inner schema in
|
|
15
|
+
* `Schema.toCodecStringTree(schema, { keepDeclarations: true })` so the
|
|
16
|
+
* string → number/boolean coercion happens. Usable only with schemas that have
|
|
17
|
+
* no decoding services — this is enforced at the type level via
|
|
18
|
+
* `S["DecodingServices"] = never` — and it throws synchronously when the input
|
|
19
|
+
* fails validation.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { Schema } from "effect"
|
|
24
|
+
* import { FormDataX } from "@nunofyobiz/effect-extras"
|
|
25
|
+
*
|
|
26
|
+
* const formData = new FormData()
|
|
27
|
+
* formData.append("name", "John")
|
|
28
|
+
* formData.append("age", "30")
|
|
29
|
+
*
|
|
30
|
+
* const result = FormDataX.decodeSync(
|
|
31
|
+
* formData,
|
|
32
|
+
* Schema.Struct({ name: Schema.String, age: Schema.NumberFromString }),
|
|
33
|
+
* )
|
|
34
|
+
*
|
|
35
|
+
* assert.deepStrictEqual(result, { name: "John", age: 30 })
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @category conversions
|
|
39
|
+
* @since 0.0.0
|
|
40
|
+
*/
|
|
41
|
+
export const decodeSync = /*#__PURE__*/Function.dual(2, (formData, schema) => Schema.decodeUnknownSync(Schema.fromFormData(schema))(formData));
|
|
42
|
+
//# sourceMappingURL=FormDataX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormDataX.js","names":["Function","Schema","decodeSync","dual","formData","schema","decodeUnknownSync","fromFormData"],"sources":["../src/FormDataX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,QAAQ,EAAEC,MAAM,QAAQ,QAAQ;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,OAAO,MAAMC,UAAU,gBAQnBF,QAAQ,CAACG,IAAI,CACf,CAAC,EACD,CACEC,QAAkB,EAClBC,MAAS,KAETJ,MAAM,CAACK,iBAAiB,CAACL,MAAM,CAACM,YAAY,CAACF,MAAM,CAAC,CAAC,CAACD,QAAQ,CAAC,CAClE","ignoreList":[]}
|
package/dist/MapX.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Like `Map.prototype.get`, but when the key is absent it stores the computed
|
|
3
|
+
* fallback at that key and returns it. Mutates the input map in place.
|
|
4
|
+
*
|
|
5
|
+
* Use it for memoization-style caches where a miss should both populate the map
|
|
6
|
+
* and yield the value in one step. Throws if the resolved value is nullish (only
|
|
7
|
+
* possible when `fallbackIfNotFound` returns `null`/`undefined` for a value type
|
|
8
|
+
* that admits them — treated as a programmer error). Supports both data-first and
|
|
9
|
+
* data-last (pipeable) call styles.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { MapX } from "@nunofyobiz/effect-extras"
|
|
14
|
+
* import { pipe } from "effect"
|
|
15
|
+
*
|
|
16
|
+
* // Miss: stores the fallback and returns it (data-first)
|
|
17
|
+
* const map = new Map<string, number>()
|
|
18
|
+
* assert.deepStrictEqual(MapX.getOrElseSetGet(map, "a", () => 1), 1)
|
|
19
|
+
* assert.deepStrictEqual(map.get("a"), 1)
|
|
20
|
+
*
|
|
21
|
+
* // Hit: returns the existing value, fallback is ignored (data-last)
|
|
22
|
+
* assert.deepStrictEqual(
|
|
23
|
+
* pipe(map, MapX.getOrElseSetGet("a", () => 99)),
|
|
24
|
+
* 1
|
|
25
|
+
* )
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @category combinators
|
|
29
|
+
* @since 0.0.0
|
|
30
|
+
*/
|
|
31
|
+
export declare const getOrElseSetGet: (<K, V>(key: K, fallbackIfNotFound: () => V) => (map: Map<K, V>) => V) & (<K, V>(map: Map<K, V>, key: K, fallbackIfNotFound: () => V) => V);
|
|
32
|
+
//# sourceMappingURL=MapX.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapX.d.ts","sourceRoot":"","sources":["../src/MapX.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,eAAe,IACzB,CAAC,EAAE,CAAC,OAAO,CAAC,sBAAsB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,MACnE,CAAC,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,MAAM,CAAC,KAAK,CAAC,CAahE,CAAC"}
|
package/dist/MapX.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, framework-agnostic extensions for working with `Map`.
|
|
3
|
+
*
|
|
4
|
+
* @since 0.0.0
|
|
5
|
+
*/
|
|
6
|
+
import { Predicate } from "effect";
|
|
7
|
+
import { dual } from "effect/Function";
|
|
8
|
+
/**
|
|
9
|
+
* Like `Map.prototype.get`, but when the key is absent it stores the computed
|
|
10
|
+
* fallback at that key and returns it. Mutates the input map in place.
|
|
11
|
+
*
|
|
12
|
+
* Use it for memoization-style caches where a miss should both populate the map
|
|
13
|
+
* and yield the value in one step. Throws if the resolved value is nullish (only
|
|
14
|
+
* possible when `fallbackIfNotFound` returns `null`/`undefined` for a value type
|
|
15
|
+
* that admits them — treated as a programmer error). Supports both data-first and
|
|
16
|
+
* data-last (pipeable) call styles.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { MapX } from "@nunofyobiz/effect-extras"
|
|
21
|
+
* import { pipe } from "effect"
|
|
22
|
+
*
|
|
23
|
+
* // Miss: stores the fallback and returns it (data-first)
|
|
24
|
+
* const map = new Map<string, number>()
|
|
25
|
+
* assert.deepStrictEqual(MapX.getOrElseSetGet(map, "a", () => 1), 1)
|
|
26
|
+
* assert.deepStrictEqual(map.get("a"), 1)
|
|
27
|
+
*
|
|
28
|
+
* // Hit: returns the existing value, fallback is ignored (data-last)
|
|
29
|
+
* assert.deepStrictEqual(
|
|
30
|
+
* pipe(map, MapX.getOrElseSetGet("a", () => 99)),
|
|
31
|
+
* 1
|
|
32
|
+
* )
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @category combinators
|
|
36
|
+
* @since 0.0.0
|
|
37
|
+
*/
|
|
38
|
+
export const getOrElseSetGet = /*#__PURE__*/dual(3, (map, key, fallbackIfNotFound) => {
|
|
39
|
+
if (!map.has(key)) {
|
|
40
|
+
map.set(key, fallbackIfNotFound());
|
|
41
|
+
return fallbackIfNotFound();
|
|
42
|
+
}
|
|
43
|
+
const existingValue = map.get(key);
|
|
44
|
+
if (Predicate.isNullish(existingValue)) {
|
|
45
|
+
throw new Error(`Value is nullable: ${String(key)}`);
|
|
46
|
+
}
|
|
47
|
+
return existingValue;
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=MapX.js.map
|
package/dist/MapX.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapX.js","names":["Predicate","dual","getOrElseSetGet","map","key","fallbackIfNotFound","has","set","existingValue","get","isNullish","Error","String"],"sources":["../src/MapX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,SAAS,QAAQ,QAAQ;AAClC,SAASC,IAAI,QAAQ,iBAAiB;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,OAAO,MAAMC,eAAe,gBAAGD,IAAI,CAGjC,CAAC,EAAE,CAAOE,GAAc,EAAEC,GAAM,EAAEC,kBAA2B,KAAO;EACpE,IAAI,CAACF,GAAG,CAACG,GAAG,CAACF,GAAG,CAAC,EAAE;IACjBD,GAAG,CAACI,GAAG,CAACH,GAAG,EAAEC,kBAAkB,EAAE,CAAC;IAClC,OAAOA,kBAAkB,EAAE;EAC7B;EAEA,MAAMG,aAAa,GAAGL,GAAG,CAACM,GAAG,CAACL,GAAG,CAAC;EAClC,IAAIJ,SAAS,CAACU,SAAS,CAACF,aAAa,CAAC,EAAE;IACtC,MAAM,IAAIG,KAAK,CAAC,sBAAsBC,MAAM,CAACR,GAAG,CAAC,EAAE,CAAC;EACtD;EAEA,OAAOI,aAAa;AACtB,CAAC,CAAC","ignoreList":[]}
|