@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
package/dist/NumberX.js
ADDED
|
@@ -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"}
|
package/dist/OptionX.js
ADDED
|
@@ -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":[]}
|
package/dist/OrderX.d.ts
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 { 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":[]}
|