@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.
Files changed (127) hide show
  1. package/README.md +36 -2
  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 -3772
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +21 -1011
  85. package/dist/index.js.map +1 -1
  86. package/package.json +18 -5
  87. package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +3 -3
  88. package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
  89. package/src/{RecordX/RecordX.ts → RecordX.ts} +1 -1
  90. package/src/index.ts +21 -20
  91. package/src/ArrayX/index.ts +0 -1
  92. package/src/BigIntX/index.ts +0 -1
  93. package/src/BooleanX/index.ts +0 -1
  94. package/src/DurationX/index.ts +0 -1
  95. package/src/EffectX/index.ts +0 -1
  96. package/src/FormDataX/index.ts +0 -1
  97. package/src/MapX/index.ts +0 -1
  98. package/src/NonNullableX/index.ts +0 -2
  99. package/src/NumberX/index.ts +0 -1
  100. package/src/OptionX/index.ts +0 -1
  101. package/src/OrderX/index.ts +0 -1
  102. package/src/PredicateX/index.ts +0 -1
  103. package/src/PromiseX/index.ts +0 -1
  104. package/src/RecordX/index.ts +0 -1
  105. package/src/ResultX/index.ts +0 -1
  106. package/src/SchemaX/index.ts +0 -1
  107. package/src/SetX/index.ts +0 -1
  108. package/src/StringX/index.ts +0 -1
  109. package/src/StructX/index.ts +0 -1
  110. package/src/WarnResult/index.ts +0 -1
  111. /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
  112. /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
  113. /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
  114. /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
  115. /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
  116. /package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +0 -0
  117. /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
  118. /package/src/{OptionX/OptionX.ts → OptionX.ts} +0 -0
  119. /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
  120. /package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +0 -0
  121. /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
  122. /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
  123. /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
  124. /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
  125. /package/src/{StringX/StringX.ts → StringX.ts} +0 -0
  126. /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
  127. /package/src/{WarnResult/WarnResult.ts → WarnResult.ts} +0 -0
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Number` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Number as EffectNumber, Option, pipe } from "effect";
7
+ import { dual } from "effect/Function";
8
+ // Internal — used by unsafeLogBase.
9
+ const logBase = /*#__PURE__*/dual(2, (number, base) => {
10
+ if (number <= 0) {
11
+ return Option.none();
12
+ }
13
+ if (base <= 0 || base === 1) {
14
+ return Option.none();
15
+ }
16
+ if (base < 1 && number >= 1) {
17
+ return Option.none();
18
+ }
19
+ if (base >= 1 && number < 1) {
20
+ return Option.none();
21
+ }
22
+ return Option.some(Math.log(number) / Math.log(base));
23
+ });
24
+ /**
25
+ * Computes the logarithm of `number` in the given `base`, throwing when the
26
+ * inputs fall outside the domain of `log`.
27
+ *
28
+ * Throws when `number <= 0`, when `base` is `<= 0` or `1`, or when `number` and
29
+ * `base` sit on opposite sides of `1` (a fractional base with `number >= 1`, or
30
+ * a base `>= 1` with `number < 1`) — cases where the real logarithm is
31
+ * undefined or non-finite. Reach for it only when the inputs are already known
32
+ * to be valid.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { pipe } from "effect"
37
+ * import { NumberX } from "@nunofyobiz/effect-extras"
38
+ *
39
+ * // data-first
40
+ * assert.deepStrictEqual(NumberX.unsafeLogBase(8, 2), 3)
41
+ * assert.deepStrictEqual(NumberX.unsafeLogBase(100, 10), 2)
42
+ *
43
+ * // data-last (piped)
44
+ * assert.deepStrictEqual(pipe(8, NumberX.unsafeLogBase(2)), 3)
45
+ *
46
+ * // throws outside the domain of log
47
+ * assert.throws(() => NumberX.unsafeLogBase(0, 2))
48
+ * ```
49
+ *
50
+ * @category unsafe
51
+ * @since 0.0.0
52
+ */
53
+ export const unsafeLogBase = /*#__PURE__*/dual(2, (number, base) => Option.getOrThrowWith(logBase(number, base), () => new Error(`Error calculating log base ${base} of ${number}`)));
54
+ /**
55
+ * Converts a number to a percentage of some total.
56
+ *
57
+ * Internal — used by unsafeToPercentOf.
58
+ */
59
+ const toPercentOf = /*#__PURE__*/dual(2, (numerator, total) => pipe(EffectNumber.divide(numerator, total), Option.map(ratio => ratio * 100)));
60
+ /**
61
+ * Expresses `numerator` as a percentage of `total`, throwing on division by
62
+ * zero.
63
+ *
64
+ * Returns `(numerator / total) * 100`. When `total` is `0` the percentage is
65
+ * undefined, so this throws rather than returning `Infinity` or `NaN` — use it
66
+ * only when `total` is known to be non-zero.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * import { pipe } from "effect"
71
+ * import { NumberX } from "@nunofyobiz/effect-extras"
72
+ *
73
+ * // data-first
74
+ * assert.deepStrictEqual(NumberX.unsafeToPercentOf(1, 2), 50)
75
+ * assert.deepStrictEqual(NumberX.unsafeToPercentOf(2, 1), 200)
76
+ *
77
+ * // data-last (piped)
78
+ * assert.deepStrictEqual(pipe(1, NumberX.unsafeToPercentOf(2)), 50)
79
+ *
80
+ * // throws on division by zero
81
+ * assert.throws(() => NumberX.unsafeToPercentOf(1, 0))
82
+ * ```
83
+ *
84
+ * @category unsafe
85
+ * @since 0.0.0
86
+ */
87
+ export const unsafeToPercentOf = /*#__PURE__*/dual(2, (numerator, total) => Option.getOrThrowWith(toPercentOf(numerator, total), () => new Error(`Division by zero when dividing ${numerator} by ${total}`)));
88
+ /**
89
+ * Formats `number` with a fixed number of decimal places, returning a `string`.
90
+ *
91
+ * A pipeable wrapper around `Number.prototype.toFixed` — the result is rounded
92
+ * (not truncated) to `numberDigits` decimals and always carries exactly that
93
+ * many digits after the point.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * import { pipe } from "effect"
98
+ * import { NumberX } from "@nunofyobiz/effect-extras"
99
+ *
100
+ * // data-first
101
+ * assert.deepStrictEqual(NumberX.toFixed(3.236242, 2), "3.24")
102
+ *
103
+ * // data-last (piped)
104
+ * assert.deepStrictEqual(pipe(3.236242, NumberX.toFixed(0)), "3")
105
+ * ```
106
+ *
107
+ * @category conversions
108
+ * @since 0.0.0
109
+ */
110
+ export const toFixed = /*#__PURE__*/dual(2, (number, numberDigits) => number.toFixed(numberDigits));
111
+ /**
112
+ * Rounds `number` to a fixed number of decimal places, returning a `number`.
113
+ *
114
+ * Unlike {@link toFixed}, the result stays a `number` (no trailing zeroes) — it
115
+ * formats via `toFixed` then parses back, which sidesteps the usual
116
+ * floating-point rounding artifacts. See
117
+ * https://stackoverflow.com/a/29494612/22875620.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { pipe } from "effect"
122
+ * import { NumberX } from "@nunofyobiz/effect-extras"
123
+ *
124
+ * // data-first
125
+ * assert.deepStrictEqual(NumberX.roundToDigits(3.236242, 2), 3.24)
126
+ *
127
+ * // data-last (piped)
128
+ * assert.deepStrictEqual(pipe(3.736242, NumberX.roundToDigits(0)), 4)
129
+ * ```
130
+ *
131
+ * @category mapping
132
+ * @since 0.0.0
133
+ */
134
+ export const roundToDigits = /*#__PURE__*/dual(2, (number, numberDigits) => Number(number.toFixed(numberDigits)));
135
+ /**
136
+ * Renders `number` as a `string`, left-padded with zeroes to at least
137
+ * `numberDigits` characters.
138
+ *
139
+ * If the number's string representation is already as long as (or longer than)
140
+ * `numberDigits`, it is returned unchanged.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * import { pipe } from "effect"
145
+ * import { NumberX } from "@nunofyobiz/effect-extras"
146
+ *
147
+ * // data-first
148
+ * assert.deepStrictEqual(NumberX.padLeftZeroes(1, 3), "001")
149
+ *
150
+ * // longer than the target width is returned unchanged
151
+ * assert.deepStrictEqual(NumberX.padLeftZeroes(1000, 3), "1000")
152
+ *
153
+ * // data-last (piped)
154
+ * assert.deepStrictEqual(pipe(10, NumberX.padLeftZeroes(3)), "010")
155
+ * ```
156
+ *
157
+ * @category conversions
158
+ * @since 0.0.0
159
+ */
160
+ export const padLeftZeroes = /*#__PURE__*/dual(2, (number, numberDigits) => number.toString().padStart(numberDigits, "0"));
161
+ /**
162
+ * Converts a `0`-indexed value to its `1`-indexed rank by adding `1`.
163
+ *
164
+ * Handy for presentation where humans count from one (e.g. the element at
165
+ * index `0` is shown as "item 1").
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * import { NumberX } from "@nunofyobiz/effect-extras"
170
+ *
171
+ * assert.deepStrictEqual(NumberX.indexToRank(0), 1)
172
+ * assert.deepStrictEqual(NumberX.indexToRank(4), 5)
173
+ * ```
174
+ *
175
+ * @category mapping
176
+ * @since 0.0.0
177
+ */
178
+ export const indexToRank = index => index + 1;
179
+ const EXCEL_COLUMNS_BASE_CHARS = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
180
+ /**
181
+ * Converts a `0`-indexed column number into its bijective base-26 spreadsheet
182
+ * label (`A`, `B`, …, `Z`, `AA`, `AB`, …).
183
+ *
184
+ * Returns `None` for a negative `index`; every non-negative index maps to a
185
+ * `Some` label. Indexing is `0`-based here, so `0` is `"A"` and `25` is `"Z"`,
186
+ * unlike the `1`-based numbering shown in most spreadsheet references.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * import { Option } from "effect"
191
+ * import { NumberX } from "@nunofyobiz/effect-extras"
192
+ *
193
+ * assert.deepStrictEqual(NumberX.indexToExcel(0), Option.some("A"))
194
+ * assert.deepStrictEqual(NumberX.indexToExcel(26), Option.some("AA"))
195
+ * assert.deepStrictEqual(NumberX.indexToExcel(-1), Option.none())
196
+ * ```
197
+ *
198
+ * @category conversions
199
+ * @since 0.0.0
200
+ */
201
+ export const indexToExcel = index => {
202
+ if (index < 0) {
203
+ return Option.none();
204
+ }
205
+ const baseChars = EXCEL_COLUMNS_BASE_CHARS;
206
+ let excel = "";
207
+ const base = baseChars.length;
208
+ do {
209
+ excel = baseChars[index % base] + excel;
210
+ index = Math.floor(index / base) - 1;
211
+ } while (index >= 0);
212
+ return Option.some(excel);
213
+ };
214
+ //# sourceMappingURL=NumberX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberX.js","names":["Number","EffectNumber","Option","pipe","dual","logBase","number","base","none","some","Math","log","unsafeLogBase","getOrThrowWith","Error","toPercentOf","numerator","total","divide","map","ratio","unsafeToPercentOf","toFixed","numberDigits","roundToDigits","padLeftZeroes","toString","padStart","indexToRank","index","EXCEL_COLUMNS_BASE_CHARS","indexToExcel","baseChars","excel","length","floor"],"sources":["../src/NumberX.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Option` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Option } from "effect";
7
+ /**
8
+ * Combines two `Option`s into an `Option` of a tuple, succeeding only when both
9
+ * are `Some`.
10
+ *
11
+ * Returns `Some([a, b])` when both inputs are `Some`, and `None` if either is
12
+ * `None`. Useful when an operation needs two optional values present at once.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { Option } from "effect"
17
+ * import { OptionX } from "@nunofyobiz/effect-extras"
18
+ *
19
+ * // Both Some — succeeds with the pair
20
+ * assert.deepStrictEqual(
21
+ * OptionX.tupleOf(Option.some(1), Option.some("a")),
22
+ * Option.some([1, "a"]),
23
+ * )
24
+ *
25
+ * // Either None collapses to None
26
+ * assert.deepStrictEqual(
27
+ * OptionX.tupleOf(Option.some(1), Option.none()),
28
+ * Option.none(),
29
+ * )
30
+ * ```
31
+ *
32
+ * @category combinators
33
+ * @since 0.0.0
34
+ */
35
+ export declare const tupleOf: (<A>(a: Option.Option<A>) => <B>(b: Option.Option<B>) => Option.Option<[A, B]>) & (<A, B>(a: Option.Option<A>, b: Option.Option<B>) => Option.Option<[A, B]>);
36
+ /**
37
+ * Runs a side effect with the value of an `Option` when it is `Some`, doing
38
+ * nothing when it is `None`.
39
+ *
40
+ * A shorthand for the "if Some, do something" branch of `Option.match` where the
41
+ * `None` case is a no-op. The callback's return value is ignored — `ifSome`
42
+ * always returns `void`.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { Option } from "effect"
47
+ * import { OptionX } from "@nunofyobiz/effect-extras"
48
+ *
49
+ * const log: Array<number> = []
50
+ * OptionX.ifSome(Option.some(1), (value) => log.push(value))
51
+ * OptionX.ifSome(Option.none<number>(), (value) => log.push(value))
52
+ *
53
+ * assert.deepStrictEqual(log, [1])
54
+ * ```
55
+ *
56
+ * @category sequencing
57
+ * @since 0.0.0
58
+ */
59
+ export declare const ifSome: (<A>(ifSome: (value: A) => void) => (self: Option.Option<A>) => void) & (<A>(self: Option.Option<A>, ifSome: (value: A) => void) => void);
60
+ /**
61
+ * Runs a side effect with the value of an `Option` when it is `Some`, then
62
+ * returns the `Option` unchanged.
63
+ *
64
+ * The pass-through counterpart of {@link ifSome}: it taps into a `Some` value
65
+ * (for logging, metrics, debugging) without breaking a `pipe` chain, since it
66
+ * returns the original `Option`. For `None` it is a no-op.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * import { Option, pipe } from "effect"
71
+ * import { OptionX } from "@nunofyobiz/effect-extras"
72
+ *
73
+ * const log: Array<number> = []
74
+ * const result = pipe(
75
+ * Option.some(1),
76
+ * OptionX.inspectSome((value) => log.push(value)),
77
+ * Option.map((value) => value + 1),
78
+ * )
79
+ *
80
+ * assert.deepStrictEqual(result, Option.some(2))
81
+ * assert.deepStrictEqual(log, [1])
82
+ * ```
83
+ *
84
+ * @category sequencing
85
+ * @since 0.0.0
86
+ */
87
+ export declare const inspectSome: (<A>(function_: (value: A) => void) => (self: Option.Option<A>) => Option.Option<A>) & (<A>(self: Option.Option<A>, function_: (value: A) => void) => Option.Option<A>);
88
+ /**
89
+ * Normalizes a possibly-nullish `Option` into a plain `Option`, mapping `null`
90
+ * and `undefined` to `None`.
91
+ *
92
+ * Handy at boundaries where an `Option` value might itself arrive as `null` or
93
+ * `undefined` (for example an optional field that holds an `Option`): the result
94
+ * is always a well-formed `Option`, never `null`/`undefined`.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * import { Option } from "effect"
99
+ * import { OptionX } from "@nunofyobiz/effect-extras"
100
+ *
101
+ * assert.deepStrictEqual(OptionX.fromNullableOption(Option.some(1)), Option.some(1))
102
+ * assert.deepStrictEqual(OptionX.fromNullableOption(null), Option.none())
103
+ * assert.deepStrictEqual(OptionX.fromNullableOption(undefined), Option.none())
104
+ * ```
105
+ *
106
+ * @category constructors
107
+ * @since 0.0.0
108
+ */
109
+ export declare const fromNullableOption: <A>(nullableOption: Option.Option<A> | null | undefined) => Option.Option<A>;
110
+ /**
111
+ * Maps the value of an `Option` when it is `Some`, returning `null` when it is
112
+ * `None`.
113
+ *
114
+ * A shorthand for `pipe(self, Option.map(map), Option.getOrNull)`. The `null`
115
+ * fallback makes it especially convenient in JSX/React, where rendering `null`
116
+ * skips output — `mapSomeOrNull(value, (v) => render(v))` replaces a more verbose
117
+ * `Option.match` with `onNone: () => null`.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { Option, pipe } from "effect"
122
+ * import { OptionX } from "@nunofyobiz/effect-extras"
123
+ *
124
+ * // data-first
125
+ * assert.deepStrictEqual(OptionX.mapSomeOrNull(Option.some(1), (v) => v + 1), 2)
126
+ *
127
+ * // None maps to null
128
+ * assert.deepStrictEqual(
129
+ * OptionX.mapSomeOrNull(Option.none<number>(), (v) => v + 1),
130
+ * null,
131
+ * )
132
+ *
133
+ * // data-last (piped)
134
+ * assert.deepStrictEqual(
135
+ * pipe(Option.some(1), OptionX.mapSomeOrNull((v) => v + 1)),
136
+ * 2,
137
+ * )
138
+ * ```
139
+ *
140
+ * @category mapping
141
+ * @since 0.0.0
142
+ */
143
+ export declare const mapSomeOrNull: (<A, B>(map: (a: A) => B) => (self: Option.Option<A>) => B | null) & (<A, B>(self: Option.Option<A>, map: (a: A) => B) => B | null);
144
+ /**
145
+ * Maps the value of an `Option` when it is `Some`, returning `undefined` when it
146
+ * is `None`.
147
+ *
148
+ * The `undefined`-returning counterpart of {@link mapSomeOrNull}: a shorthand for
149
+ * `pipe(self, Option.map(map), Option.getOrUndefined)`. Reach for it when the
150
+ * consuming API expects `undefined` rather than `null` for "absent" (for example
151
+ * an optional prop or a value spread into an object).
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * import { Option, pipe } from "effect"
156
+ * import { OptionX } from "@nunofyobiz/effect-extras"
157
+ *
158
+ * // data-first
159
+ * assert.deepStrictEqual(
160
+ * OptionX.mapSomeOrUndefined(Option.some(1), (v) => v + 1),
161
+ * 2,
162
+ * )
163
+ *
164
+ * // None maps to undefined
165
+ * assert.deepStrictEqual(
166
+ * OptionX.mapSomeOrUndefined(Option.none<number>(), (v) => v + 1),
167
+ * undefined,
168
+ * )
169
+ *
170
+ * // data-last (piped)
171
+ * assert.deepStrictEqual(
172
+ * pipe(Option.some(1), OptionX.mapSomeOrUndefined((v) => v + 1)),
173
+ * 2,
174
+ * )
175
+ * ```
176
+ *
177
+ * @category mapping
178
+ * @since 0.0.0
179
+ */
180
+ export declare const mapSomeOrUndefined: (<A, B>(map: (a: A) => B) => (self: Option.Option<A>) => B | undefined) & (<A, B>(self: Option.Option<A>, map: (a: A) => B) => B | undefined);
181
+ //# sourceMappingURL=OptionX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OptionX.d.ts","sourceRoot":"","sources":["../src/OptionX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,MAAM,EAAmB,MAAM,QAAQ,CAAC;AAGjD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,OAAO,IACjB,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAC5E,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAK1E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,MAAM,IAChB,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,MAClE,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK,IAAI,CAW/D,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,WAAW,IACrB,CAAC,aACW,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAC1B,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAChD,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAU/E,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAClC,gBAAgB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,KAClD,MAAM,CAAC,MAAM,CAAC,CAAC,CACuD,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,aAAa,IACvB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,MAC/D,CAAC,EAAE,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAG7D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,kBAAkB,IAC5B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,SAAS,MACpE,CAAC,EAAE,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,CAGlE,CAAC"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Option` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Option, Predicate, pipe } from "effect";
7
+ import { dual } from "effect/Function";
8
+ /**
9
+ * Combines two `Option`s into an `Option` of a tuple, succeeding only when both
10
+ * are `Some`.
11
+ *
12
+ * Returns `Some([a, b])` when both inputs are `Some`, and `None` if either is
13
+ * `None`. Useful when an operation needs two optional values present at once.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Option } from "effect"
18
+ * import { OptionX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * // Both Some — succeeds with the pair
21
+ * assert.deepStrictEqual(
22
+ * OptionX.tupleOf(Option.some(1), Option.some("a")),
23
+ * Option.some([1, "a"]),
24
+ * )
25
+ *
26
+ * // Either None collapses to None
27
+ * assert.deepStrictEqual(
28
+ * OptionX.tupleOf(Option.some(1), Option.none()),
29
+ * Option.none(),
30
+ * )
31
+ * ```
32
+ *
33
+ * @category combinators
34
+ * @since 0.0.0
35
+ */
36
+ export const tupleOf = /*#__PURE__*/dual(2, (a, b) => Option.flatMap(a, a => Option.map(b, b => [a, b])));
37
+ /**
38
+ * Runs a side effect with the value of an `Option` when it is `Some`, doing
39
+ * nothing when it is `None`.
40
+ *
41
+ * A shorthand for the "if Some, do something" branch of `Option.match` where the
42
+ * `None` case is a no-op. The callback's return value is ignored — `ifSome`
43
+ * always returns `void`.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { Option } from "effect"
48
+ * import { OptionX } from "@nunofyobiz/effect-extras"
49
+ *
50
+ * const log: Array<number> = []
51
+ * OptionX.ifSome(Option.some(1), (value) => log.push(value))
52
+ * OptionX.ifSome(Option.none<number>(), (value) => log.push(value))
53
+ *
54
+ * assert.deepStrictEqual(log, [1])
55
+ * ```
56
+ *
57
+ * @category sequencing
58
+ * @since 0.0.0
59
+ */
60
+ export const ifSome = /*#__PURE__*/dual(2, (self, ifSome) => {
61
+ Option.match(self, {
62
+ onSome: value => {
63
+ ifSome(value);
64
+ // Don't return anything
65
+ },
66
+ onNone: () => {
67
+ // Do nothing
68
+ }
69
+ });
70
+ });
71
+ /**
72
+ * Runs a side effect with the value of an `Option` when it is `Some`, then
73
+ * returns the `Option` unchanged.
74
+ *
75
+ * The pass-through counterpart of {@link ifSome}: it taps into a `Some` value
76
+ * (for logging, metrics, debugging) without breaking a `pipe` chain, since it
77
+ * returns the original `Option`. For `None` it is a no-op.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * import { Option, pipe } from "effect"
82
+ * import { OptionX } from "@nunofyobiz/effect-extras"
83
+ *
84
+ * const log: Array<number> = []
85
+ * const result = pipe(
86
+ * Option.some(1),
87
+ * OptionX.inspectSome((value) => log.push(value)),
88
+ * Option.map((value) => value + 1),
89
+ * )
90
+ *
91
+ * assert.deepStrictEqual(result, Option.some(2))
92
+ * assert.deepStrictEqual(log, [1])
93
+ * ```
94
+ *
95
+ * @category sequencing
96
+ * @since 0.0.0
97
+ */
98
+ export const inspectSome = /*#__PURE__*/dual(2, (self, function_) => {
99
+ ifSome(self, function_);
100
+ return self;
101
+ });
102
+ /**
103
+ * Normalizes a possibly-nullish `Option` into a plain `Option`, mapping `null`
104
+ * and `undefined` to `None`.
105
+ *
106
+ * Handy at boundaries where an `Option` value might itself arrive as `null` or
107
+ * `undefined` (for example an optional field that holds an `Option`): the result
108
+ * is always a well-formed `Option`, never `null`/`undefined`.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * import { Option } from "effect"
113
+ * import { OptionX } from "@nunofyobiz/effect-extras"
114
+ *
115
+ * assert.deepStrictEqual(OptionX.fromNullableOption(Option.some(1)), Option.some(1))
116
+ * assert.deepStrictEqual(OptionX.fromNullableOption(null), Option.none())
117
+ * assert.deepStrictEqual(OptionX.fromNullableOption(undefined), Option.none())
118
+ * ```
119
+ *
120
+ * @category constructors
121
+ * @since 0.0.0
122
+ */
123
+ export const fromNullableOption = nullableOption => Predicate.isNotNullish(nullableOption) ? nullableOption : Option.none();
124
+ /**
125
+ * Maps the value of an `Option` when it is `Some`, returning `null` when it is
126
+ * `None`.
127
+ *
128
+ * A shorthand for `pipe(self, Option.map(map), Option.getOrNull)`. The `null`
129
+ * fallback makes it especially convenient in JSX/React, where rendering `null`
130
+ * skips output — `mapSomeOrNull(value, (v) => render(v))` replaces a more verbose
131
+ * `Option.match` with `onNone: () => null`.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * import { Option, pipe } from "effect"
136
+ * import { OptionX } from "@nunofyobiz/effect-extras"
137
+ *
138
+ * // data-first
139
+ * assert.deepStrictEqual(OptionX.mapSomeOrNull(Option.some(1), (v) => v + 1), 2)
140
+ *
141
+ * // None maps to null
142
+ * assert.deepStrictEqual(
143
+ * OptionX.mapSomeOrNull(Option.none<number>(), (v) => v + 1),
144
+ * null,
145
+ * )
146
+ *
147
+ * // data-last (piped)
148
+ * assert.deepStrictEqual(
149
+ * pipe(Option.some(1), OptionX.mapSomeOrNull((v) => v + 1)),
150
+ * 2,
151
+ * )
152
+ * ```
153
+ *
154
+ * @category mapping
155
+ * @since 0.0.0
156
+ */
157
+ export const mapSomeOrNull = /*#__PURE__*/dual(2, (self, map) => pipe(self, Option.map(map), Option.getOrNull));
158
+ /**
159
+ * Maps the value of an `Option` when it is `Some`, returning `undefined` when it
160
+ * is `None`.
161
+ *
162
+ * The `undefined`-returning counterpart of {@link mapSomeOrNull}: a shorthand for
163
+ * `pipe(self, Option.map(map), Option.getOrUndefined)`. Reach for it when the
164
+ * consuming API expects `undefined` rather than `null` for "absent" (for example
165
+ * an optional prop or a value spread into an object).
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * import { Option, pipe } from "effect"
170
+ * import { OptionX } from "@nunofyobiz/effect-extras"
171
+ *
172
+ * // data-first
173
+ * assert.deepStrictEqual(
174
+ * OptionX.mapSomeOrUndefined(Option.some(1), (v) => v + 1),
175
+ * 2,
176
+ * )
177
+ *
178
+ * // None maps to undefined
179
+ * assert.deepStrictEqual(
180
+ * OptionX.mapSomeOrUndefined(Option.none<number>(), (v) => v + 1),
181
+ * undefined,
182
+ * )
183
+ *
184
+ * // data-last (piped)
185
+ * assert.deepStrictEqual(
186
+ * pipe(Option.some(1), OptionX.mapSomeOrUndefined((v) => v + 1)),
187
+ * 2,
188
+ * )
189
+ * ```
190
+ *
191
+ * @category mapping
192
+ * @since 0.0.0
193
+ */
194
+ export const mapSomeOrUndefined = /*#__PURE__*/dual(2, (self, map) => pipe(self, Option.map(map), Option.getOrUndefined));
195
+ //# sourceMappingURL=OptionX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OptionX.js","names":["Option","Predicate","pipe","dual","tupleOf","a","b","flatMap","map","ifSome","self","match","onSome","value","onNone","inspectSome","function_","fromNullableOption","nullableOption","isNotNullish","none","mapSomeOrNull","getOrNull","mapSomeOrUndefined","getOrUndefined"],"sources":["../src/OptionX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,MAAM,EAAEC,SAAS,EAAEC,IAAI,QAAQ,QAAQ;AAChD,SAASC,IAAI,QAAQ,iBAAiB;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,OAAO,MAAMC,OAAO,gBAAGD,IAAI,CAIzB,CAAC,EACD,CAAOE,CAAmB,EAAEC,CAAmB,KAC7CN,MAAM,CAACO,OAAO,CAACF,CAAC,EAAGA,CAAC,IAAKL,MAAM,CAACQ,GAAG,CAACF,CAAC,EAAGA,CAAC,IAAK,CAACD,CAAC,EAAEC,CAAC,CAAC,CAAC,CAAC,CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;AAuBA,OAAO,MAAMG,MAAM,gBAAGN,IAAI,CAGxB,CAAC,EAAE,CAAIO,IAAsB,EAAED,MAA0B,KAAU;EACnET,MAAM,CAACW,KAAK,CAACD,IAAI,EAAE;IACjBE,MAAM,EAAGC,KAAK,IAAI;MAChBJ,MAAM,CAACI,KAAK,CAAC;MACb;IACF,CAAC;IACDC,MAAM,EAAEA,CAAA,KAAK;MACX;IAAA;GAEH,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,OAAO,MAAMC,WAAW,gBAAGZ,IAAI,CAM7B,CAAC,EACD,CACEO,IAAsB,EACtBM,SAA6B,KACT;EACpBP,MAAM,CAACC,IAAI,EAAEM,SAAS,CAAC;EACvB,OAAON,IAAI;AACb,CAAC,CACF;AAED;;;;;;;;;;;;;;;;;;;;;AAqBA,OAAO,MAAMO,kBAAkB,GAC7BC,cAAmD,IAEnDjB,SAAS,CAACkB,YAAY,CAACD,cAAc,CAAC,GAAGA,cAAc,GAAGlB,MAAM,CAACoB,IAAI,EAAE;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,OAAO,MAAMC,aAAa,gBAAGlB,IAAI,CAG/B,CAAC,EAAE,CAAOO,IAAsB,EAAEF,GAAgB,KAClDN,IAAI,CAACQ,IAAI,EAAEV,MAAM,CAACQ,GAAG,CAACA,GAAG,CAAC,EAAER,MAAM,CAACsB,SAAS,CAAC,CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,OAAO,MAAMC,kBAAkB,gBAAGpB,IAAI,CAGpC,CAAC,EAAE,CAAOO,IAAsB,EAAEF,GAAgB,KAClDN,IAAI,CAACQ,IAAI,EAAEV,MAAM,CAACQ,GAAG,CAACA,GAAG,CAAC,EAAER,MAAM,CAACwB,cAAc,CAAC,CACnD","ignoreList":[]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Order` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Order } from "effect";
7
+ /**
8
+ * Builds an `Order.Order` for an enum-like set of values from an explicit rank
9
+ * table, sorting each value by its assigned numeric rank.
10
+ *
11
+ * Use it when a union of string (or other `PropertyKey`) literals has a natural
12
+ * priority that isn't its alphabetical order — pass a record mapping every
13
+ * member to a rank and the resulting order sorts ascending by that rank.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { OrderX } from "@nunofyobiz/effect-extras"
18
+ * import { Array } from "effect"
19
+ *
20
+ * const byAge = OrderX.rankedEnum({ child: 0, parent: 1, grandparent: 2 })
21
+ *
22
+ * assert.deepStrictEqual(
23
+ * Array.sort(["parent", "grandparent", "child"], byAge),
24
+ * ["child", "parent", "grandparent"]
25
+ * )
26
+ * ```
27
+ *
28
+ * @category ordering
29
+ * @since 0.0.0
30
+ */
31
+ export declare const rankedEnum: <const A extends PropertyKey>(ranks: Record<A, number>) => Order.Order<A>;
32
+ //# sourceMappingURL=OrderX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrderX.d.ts","sourceRoot":"","sources":["../src/OrderX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAA0B,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,UAAU,GACpB,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,KAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAExB,CAAC"}
package/dist/OrderX.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Order` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Number as EffectNumber } from "effect";
7
+ /**
8
+ * Builds an `Order.Order` for an enum-like set of values from an explicit rank
9
+ * table, sorting each value by its assigned numeric rank.
10
+ *
11
+ * Use it when a union of string (or other `PropertyKey`) literals has a natural
12
+ * priority that isn't its alphabetical order — pass a record mapping every
13
+ * member to a rank and the resulting order sorts ascending by that rank.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { OrderX } from "@nunofyobiz/effect-extras"
18
+ * import { Array } from "effect"
19
+ *
20
+ * const byAge = OrderX.rankedEnum({ child: 0, parent: 1, grandparent: 2 })
21
+ *
22
+ * assert.deepStrictEqual(
23
+ * Array.sort(["parent", "grandparent", "child"], byAge),
24
+ * ["child", "parent", "grandparent"]
25
+ * )
26
+ * ```
27
+ *
28
+ * @category ordering
29
+ * @since 0.0.0
30
+ */
31
+ export const rankedEnum = ranks => (self, that) => EffectNumber.sign(ranks[self] - ranks[that]);
32
+ //# sourceMappingURL=OrderX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrderX.js","names":["Number","EffectNumber","rankedEnum","ranks","self","that","sign"],"sources":["../src/OrderX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,MAAM,IAAIC,YAAY,QAAe,QAAQ;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,OAAO,MAAMC,UAAU,GACSC,KAAwB,IACtD,CAACC,IAAI,EAAEC,IAAI,KACTJ,YAAY,CAACK,IAAI,CAACH,KAAK,CAACC,IAAI,CAAC,GAAGD,KAAK,CAACE,IAAI,CAAC,CAAC","ignoreList":[]}