@nunofyobiz/effect-extras 1.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.
Files changed (128) hide show
  1. package/README.md +50 -6
  2. package/dist/ArrayX.d.ts +415 -0
  3. package/dist/ArrayX.d.ts.map +1 -0
  4. package/dist/ArrayX.js +547 -0
  5. package/dist/ArrayX.js.map +1 -0
  6. package/dist/BigIntX.d.ts +24 -0
  7. package/dist/BigIntX.d.ts.map +1 -0
  8. package/dist/BigIntX.js +30 -0
  9. package/dist/BigIntX.js.map +1 -0
  10. package/dist/BooleanX.d.ts +25 -0
  11. package/dist/BooleanX.d.ts.map +1 -0
  12. package/dist/BooleanX.js +25 -0
  13. package/dist/BooleanX.js.map +1 -0
  14. package/dist/DurationX.d.ts +73 -0
  15. package/dist/DurationX.d.ts.map +1 -0
  16. package/dist/DurationX.js +91 -0
  17. package/dist/DurationX.js.map +1 -0
  18. package/dist/EffectX.d.ts +120 -0
  19. package/dist/EffectX.d.ts.map +1 -0
  20. package/dist/EffectX.js +140 -0
  21. package/dist/EffectX.js.map +1 -0
  22. package/dist/FormDataX.d.ts +49 -0
  23. package/dist/FormDataX.d.ts.map +1 -0
  24. package/dist/FormDataX.js +42 -0
  25. package/dist/FormDataX.js.map +1 -0
  26. package/dist/MapX.d.ts +32 -0
  27. package/dist/MapX.d.ts.map +1 -0
  28. package/dist/MapX.js +49 -0
  29. package/dist/MapX.js.map +1 -0
  30. package/dist/NonNullableX.d.ts +174 -0
  31. package/dist/NonNullableX.d.ts.map +1 -0
  32. package/dist/NonNullableX.js +212 -0
  33. package/dist/NonNullableX.js.map +1 -0
  34. package/dist/NumberX.d.ts +178 -0
  35. package/dist/NumberX.d.ts.map +1 -0
  36. package/dist/NumberX.js +214 -0
  37. package/dist/NumberX.js.map +1 -0
  38. package/dist/OptionX.d.ts +181 -0
  39. package/dist/OptionX.d.ts.map +1 -0
  40. package/dist/OptionX.js +195 -0
  41. package/dist/OptionX.js.map +1 -0
  42. package/dist/OrderX.d.ts +32 -0
  43. package/dist/OrderX.d.ts.map +1 -0
  44. package/dist/OrderX.js +32 -0
  45. package/dist/OrderX.js.map +1 -0
  46. package/dist/PredicateX.d.ts +76 -0
  47. package/dist/PredicateX.d.ts.map +1 -0
  48. package/dist/PredicateX.js +73 -0
  49. package/dist/PredicateX.js.map +1 -0
  50. package/dist/PromiseX.d.ts +32 -0
  51. package/dist/PromiseX.d.ts.map +1 -0
  52. package/dist/PromiseX.js +32 -0
  53. package/dist/PromiseX.js.map +1 -0
  54. package/dist/RecordX.d.ts +323 -0
  55. package/dist/RecordX.d.ts.map +1 -0
  56. package/dist/RecordX.js +326 -0
  57. package/dist/RecordX.js.map +1 -0
  58. package/dist/ResultX.d.ts +50 -0
  59. package/dist/ResultX.d.ts.map +1 -0
  60. package/dist/ResultX.js +50 -0
  61. package/dist/ResultX.js.map +1 -0
  62. package/dist/SchemaX.d.ts +249 -0
  63. package/dist/SchemaX.d.ts.map +1 -0
  64. package/dist/SchemaX.js +243 -0
  65. package/dist/SchemaX.js.map +1 -0
  66. package/dist/SetX.d.ts +121 -0
  67. package/dist/SetX.d.ts.map +1 -0
  68. package/dist/SetX.js +137 -0
  69. package/dist/SetX.js.map +1 -0
  70. package/dist/StringX.d.ts +70 -0
  71. package/dist/StringX.d.ts.map +1 -0
  72. package/dist/StringX.js +81 -0
  73. package/dist/StringX.js.map +1 -0
  74. package/dist/StructX.d.ts +219 -0
  75. package/dist/StructX.d.ts.map +1 -0
  76. package/dist/StructX.js +173 -0
  77. package/dist/StructX.js.map +1 -0
  78. package/dist/WarnResult.d.ts +1146 -0
  79. package/dist/WarnResult.d.ts.map +1 -0
  80. package/dist/WarnResult.js +1060 -0
  81. package/dist/WarnResult.js.map +1 -0
  82. package/dist/index.d.ts +22 -3703
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +21 -1005
  85. package/dist/index.js.map +1 -1
  86. package/package.json +18 -5
  87. package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +29 -27
  88. package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
  89. package/src/{RecordX/RecordX.ts → RecordX.ts} +1 -1
  90. package/src/WarnResult.ts +1265 -0
  91. package/src/index.ts +21 -20
  92. package/src/ArrayX/index.ts +0 -1
  93. package/src/BigIntX/index.ts +0 -1
  94. package/src/BooleanX/index.ts +0 -1
  95. package/src/DurationX/index.ts +0 -1
  96. package/src/EffectX/index.ts +0 -1
  97. package/src/FormDataX/index.ts +0 -1
  98. package/src/MapX/index.ts +0 -1
  99. package/src/NonNullableX/index.ts +0 -2
  100. package/src/NumberX/index.ts +0 -1
  101. package/src/OptionX/index.ts +0 -1
  102. package/src/OrderX/index.ts +0 -1
  103. package/src/PredicateX/index.ts +0 -1
  104. package/src/PromiseX/index.ts +0 -1
  105. package/src/RecordX/index.ts +0 -1
  106. package/src/ResultX/index.ts +0 -1
  107. package/src/SchemaX/index.ts +0 -1
  108. package/src/SetX/index.ts +0 -1
  109. package/src/StringX/index.ts +0 -1
  110. package/src/StructX/index.ts +0 -1
  111. package/src/These/These.ts +0 -1173
  112. package/src/These/index.ts +0 -1
  113. /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
  114. /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
  115. /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
  116. /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
  117. /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
  118. /package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +0 -0
  119. /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
  120. /package/src/{OptionX/OptionX.ts → OptionX.ts} +0 -0
  121. /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
  122. /package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +0 -0
  123. /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
  124. /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
  125. /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
  126. /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
  127. /package/src/{StringX/StringX.ts → StringX.ts} +0 -0
  128. /package/src/{StructX/StructX.ts → StructX.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"}
@@ -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
@@ -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":[]}