@nunofyobiz/effect-extras 2.0.0 → 3.0.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 (133) hide show
  1. package/README.md +38 -3
  2. package/dist/ArrayX.d.ts +381 -0
  3. package/dist/ArrayX.d.ts.map +1 -0
  4. package/dist/ArrayX.js +493 -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/InclusiveOr.d.ts +1123 -0
  27. package/dist/InclusiveOr.d.ts.map +1 -0
  28. package/dist/InclusiveOr.js +1074 -0
  29. package/dist/InclusiveOr.js.map +1 -0
  30. package/dist/MapX.d.ts +32 -0
  31. package/dist/MapX.d.ts.map +1 -0
  32. package/dist/MapX.js +49 -0
  33. package/dist/MapX.js.map +1 -0
  34. package/dist/NonNullableX.d.ts +174 -0
  35. package/dist/NonNullableX.d.ts.map +1 -0
  36. package/dist/NonNullableX.js +217 -0
  37. package/dist/NonNullableX.js.map +1 -0
  38. package/dist/NumberX.d.ts +178 -0
  39. package/dist/NumberX.d.ts.map +1 -0
  40. package/dist/NumberX.js +214 -0
  41. package/dist/NumberX.js.map +1 -0
  42. package/dist/OptionX.d.ts +187 -0
  43. package/dist/OptionX.d.ts.map +1 -0
  44. package/dist/OptionX.js +201 -0
  45. package/dist/OptionX.js.map +1 -0
  46. package/dist/OrderX.d.ts +32 -0
  47. package/dist/OrderX.d.ts.map +1 -0
  48. package/dist/OrderX.js +32 -0
  49. package/dist/OrderX.js.map +1 -0
  50. package/dist/PredicateX.d.ts +108 -0
  51. package/dist/PredicateX.d.ts.map +1 -0
  52. package/dist/PredicateX.js +111 -0
  53. package/dist/PredicateX.js.map +1 -0
  54. package/dist/PromiseX.d.ts +32 -0
  55. package/dist/PromiseX.d.ts.map +1 -0
  56. package/dist/PromiseX.js +32 -0
  57. package/dist/PromiseX.js.map +1 -0
  58. package/dist/RecordX.d.ts +450 -0
  59. package/dist/RecordX.d.ts.map +1 -0
  60. package/dist/RecordX.js +487 -0
  61. package/dist/RecordX.js.map +1 -0
  62. package/dist/ResultX.d.ts +50 -0
  63. package/dist/ResultX.d.ts.map +1 -0
  64. package/dist/ResultX.js +50 -0
  65. package/dist/ResultX.js.map +1 -0
  66. package/dist/SchemaX.d.ts +249 -0
  67. package/dist/SchemaX.d.ts.map +1 -0
  68. package/dist/SchemaX.js +243 -0
  69. package/dist/SchemaX.js.map +1 -0
  70. package/dist/SetX.d.ts +121 -0
  71. package/dist/SetX.d.ts.map +1 -0
  72. package/dist/SetX.js +137 -0
  73. package/dist/SetX.js.map +1 -0
  74. package/dist/StringX.d.ts +131 -0
  75. package/dist/StringX.d.ts.map +1 -0
  76. package/dist/StringX.js +149 -0
  77. package/dist/StringX.js.map +1 -0
  78. package/dist/StructX.d.ts +219 -0
  79. package/dist/StructX.d.ts.map +1 -0
  80. package/dist/StructX.js +173 -0
  81. package/dist/StructX.js.map +1 -0
  82. package/dist/WarnResult.d.ts +1191 -0
  83. package/dist/WarnResult.d.ts.map +1 -0
  84. package/dist/WarnResult.js +991 -0
  85. package/dist/WarnResult.js.map +1 -0
  86. package/dist/index.d.ts +23 -3772
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +22 -1011
  89. package/dist/index.js.map +1 -1
  90. package/package.json +18 -5
  91. package/src/{ArrayX/ArrayX.ts → ArrayX.ts} +6 -88
  92. package/src/{DurationX/DurationX.ts → DurationX.ts} +1 -1
  93. package/src/InclusiveOr.ts +1255 -0
  94. package/src/{NonNullableX/NonNullableX.ts → NonNullableX.ts} +5 -0
  95. package/src/{OptionX/OptionX.ts → OptionX.ts} +8 -2
  96. package/src/{PredicateX/PredicateX.ts → PredicateX.ts} +41 -0
  97. package/src/{RecordX/RecordX.ts → RecordX.ts} +184 -2
  98. package/src/StringX.ts +210 -0
  99. package/src/{WarnResult/WarnResult.ts → WarnResult.ts} +297 -227
  100. package/src/index.ts +22 -20
  101. package/src/ArrayX/index.ts +0 -1
  102. package/src/BigIntX/index.ts +0 -1
  103. package/src/BooleanX/index.ts +0 -1
  104. package/src/DurationX/index.ts +0 -1
  105. package/src/EffectX/index.ts +0 -1
  106. package/src/FormDataX/index.ts +0 -1
  107. package/src/MapX/index.ts +0 -1
  108. package/src/NonNullableX/index.ts +0 -2
  109. package/src/NumberX/index.ts +0 -1
  110. package/src/OptionX/index.ts +0 -1
  111. package/src/OrderX/index.ts +0 -1
  112. package/src/PredicateX/index.ts +0 -1
  113. package/src/PromiseX/index.ts +0 -1
  114. package/src/RecordX/index.ts +0 -1
  115. package/src/ResultX/index.ts +0 -1
  116. package/src/SchemaX/index.ts +0 -1
  117. package/src/SetX/index.ts +0 -1
  118. package/src/StringX/StringX.ts +0 -97
  119. package/src/StringX/index.ts +0 -1
  120. package/src/StructX/index.ts +0 -1
  121. package/src/WarnResult/index.ts +0 -1
  122. /package/src/{BigIntX/BigIntX.ts → BigIntX.ts} +0 -0
  123. /package/src/{BooleanX/BooleanX.ts → BooleanX.ts} +0 -0
  124. /package/src/{EffectX/EffectX.ts → EffectX.ts} +0 -0
  125. /package/src/{FormDataX/FormDataX.ts → FormDataX.ts} +0 -0
  126. /package/src/{MapX/MapX.ts → MapX.ts} +0 -0
  127. /package/src/{NumberX/NumberX.ts → NumberX.ts} +0 -0
  128. /package/src/{OrderX/OrderX.ts → OrderX.ts} +0 -0
  129. /package/src/{PromiseX/PromiseX.ts → PromiseX.ts} +0 -0
  130. /package/src/{ResultX/ResultX.ts → ResultX.ts} +0 -0
  131. /package/src/{SchemaX/SchemaX.ts → SchemaX.ts} +0 -0
  132. /package/src/{SetX/SetX.ts → SetX.ts} +0 -0
  133. /package/src/{StructX/StructX.ts → StructX.ts} +0 -0
@@ -0,0 +1,201 @@
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, pipe } 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
+ * // Data-last (piped): the piped Option fills the first tuple slot
33
+ * assert.deepStrictEqual(
34
+ * pipe(Option.some(1), OptionX.tupleOf(Option.some("a"))),
35
+ * Option.some([1, "a"]),
36
+ * )
37
+ * ```
38
+ *
39
+ * @category combinators
40
+ * @since 0.0.0
41
+ */
42
+ export const tupleOf = /*#__PURE__*/dual(2, (a, b) => Option.flatMap(a, a => Option.map(b, b => [a, b])));
43
+ /**
44
+ * Runs a side effect with the value of an `Option` when it is `Some`, doing
45
+ * nothing when it is `None`.
46
+ *
47
+ * A shorthand for the "if Some, do something" branch of `Option.match` where the
48
+ * `None` case is a no-op. The callback's return value is ignored — `ifSome`
49
+ * always returns `void`.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import { Option } from "effect"
54
+ * import { OptionX } from "@nunofyobiz/effect-extras"
55
+ *
56
+ * const log: Array<number> = []
57
+ * OptionX.ifSome(Option.some(1), (value) => log.push(value))
58
+ * OptionX.ifSome(Option.none<number>(), (value) => log.push(value))
59
+ *
60
+ * assert.deepStrictEqual(log, [1])
61
+ * ```
62
+ *
63
+ * @category sequencing
64
+ * @since 0.0.0
65
+ */
66
+ export const ifSome = /*#__PURE__*/dual(2, (self, ifSome) => {
67
+ Option.match(self, {
68
+ onSome: value => {
69
+ ifSome(value);
70
+ // Don't return anything
71
+ },
72
+ onNone: () => {
73
+ // Do nothing
74
+ }
75
+ });
76
+ });
77
+ /**
78
+ * Runs a side effect with the value of an `Option` when it is `Some`, then
79
+ * returns the `Option` unchanged.
80
+ *
81
+ * The pass-through counterpart of {@link ifSome}: it taps into a `Some` value
82
+ * (for logging, metrics, debugging) without breaking a `pipe` chain, since it
83
+ * returns the original `Option`. For `None` it is a no-op.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * import { Option, pipe } from "effect"
88
+ * import { OptionX } from "@nunofyobiz/effect-extras"
89
+ *
90
+ * const log: Array<number> = []
91
+ * const result = pipe(
92
+ * Option.some(1),
93
+ * OptionX.inspectSome((value) => log.push(value)),
94
+ * Option.map((value) => value + 1),
95
+ * )
96
+ *
97
+ * assert.deepStrictEqual(result, Option.some(2))
98
+ * assert.deepStrictEqual(log, [1])
99
+ * ```
100
+ *
101
+ * @category sequencing
102
+ * @since 0.0.0
103
+ */
104
+ export const inspectSome = /*#__PURE__*/dual(2, (self, function_) => {
105
+ ifSome(self, function_);
106
+ return self;
107
+ });
108
+ /**
109
+ * Normalizes a possibly-nullish `Option` into a plain `Option`, mapping `null`
110
+ * and `undefined` to `None`.
111
+ *
112
+ * Handy at boundaries where an `Option` value might itself arrive as `null` or
113
+ * `undefined` (for example an optional field that holds an `Option`): the result
114
+ * is always a well-formed `Option`, never `null`/`undefined`.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * import { Option } from "effect"
119
+ * import { OptionX } from "@nunofyobiz/effect-extras"
120
+ *
121
+ * assert.deepStrictEqual(OptionX.fromNullableOption(Option.some(1)), Option.some(1))
122
+ * assert.deepStrictEqual(OptionX.fromNullableOption(null), Option.none())
123
+ * assert.deepStrictEqual(OptionX.fromNullableOption(undefined), Option.none())
124
+ * ```
125
+ *
126
+ * @category constructors
127
+ * @since 0.0.0
128
+ */
129
+ export const fromNullableOption = nullableOption => Predicate.isNotNullish(nullableOption) ? nullableOption : Option.none();
130
+ /**
131
+ * Maps the value of an `Option` when it is `Some`, returning `null` when it is
132
+ * `None`.
133
+ *
134
+ * A shorthand for `pipe(self, Option.map(map), Option.getOrNull)`. The `null`
135
+ * fallback makes it especially convenient in JSX/React, where rendering `null`
136
+ * skips output — `mapSomeOrNull(value, (v) => render(v))` replaces a more verbose
137
+ * `Option.match` with `onNone: () => null`.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * import { Option, pipe } from "effect"
142
+ * import { OptionX } from "@nunofyobiz/effect-extras"
143
+ *
144
+ * // data-first
145
+ * assert.deepStrictEqual(OptionX.mapSomeOrNull(Option.some(1), (v) => v + 1), 2)
146
+ *
147
+ * // None maps to null
148
+ * assert.deepStrictEqual(
149
+ * OptionX.mapSomeOrNull(Option.none<number>(), (v) => v + 1),
150
+ * null,
151
+ * )
152
+ *
153
+ * // data-last (piped)
154
+ * assert.deepStrictEqual(
155
+ * pipe(Option.some(1), OptionX.mapSomeOrNull((v) => v + 1)),
156
+ * 2,
157
+ * )
158
+ * ```
159
+ *
160
+ * @category mapping
161
+ * @since 0.0.0
162
+ */
163
+ export const mapSomeOrNull = /*#__PURE__*/dual(2, (self, map) => pipe(self, Option.map(map), Option.getOrNull));
164
+ /**
165
+ * Maps the value of an `Option` when it is `Some`, returning `undefined` when it
166
+ * is `None`.
167
+ *
168
+ * The `undefined`-returning counterpart of {@link mapSomeOrNull}: a shorthand for
169
+ * `pipe(self, Option.map(map), Option.getOrUndefined)`. Reach for it when the
170
+ * consuming API expects `undefined` rather than `null` for "absent" (for example
171
+ * an optional prop or a value spread into an object).
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * import { Option, pipe } from "effect"
176
+ * import { OptionX } from "@nunofyobiz/effect-extras"
177
+ *
178
+ * // data-first
179
+ * assert.deepStrictEqual(
180
+ * OptionX.mapSomeOrUndefined(Option.some(1), (v) => v + 1),
181
+ * 2,
182
+ * )
183
+ *
184
+ * // None maps to undefined
185
+ * assert.deepStrictEqual(
186
+ * OptionX.mapSomeOrUndefined(Option.none<number>(), (v) => v + 1),
187
+ * undefined,
188
+ * )
189
+ *
190
+ * // data-last (piped)
191
+ * assert.deepStrictEqual(
192
+ * pipe(Option.some(1), OptionX.mapSomeOrUndefined((v) => v + 1)),
193
+ * 2,
194
+ * )
195
+ * ```
196
+ *
197
+ * @category mapping
198
+ * @since 0.0.0
199
+ */
200
+ export const mapSomeOrUndefined = /*#__PURE__*/dual(2, (self, map) => pipe(self, Option.map(map), Option.getOrUndefined));
201
+ //# 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,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":[]}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Predicate` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Predicate } from "effect";
7
+ /**
8
+ * Runs a refinement against `value` and branches on the result, passing the
9
+ * narrowed value to the `whenTrue` handler.
10
+ *
11
+ * It pairs a `Predicate.Refinement<A, B>` with two continuations so the success
12
+ * branch receives `value` already narrowed to `B`, replacing an `if`/`else` that
13
+ * would otherwise re-check or cast. Supports both data-first and data-last
14
+ * (pipeable) call styles.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
19
+ * import { Predicate, pipe } from "effect"
20
+ *
21
+ * // Data-first
22
+ * assert.deepStrictEqual(
23
+ * PredicateX.matchRefine("hello", Predicate.isString, {
24
+ * whenTrue: (value) => `String: ${value}`,
25
+ * whenFalse: () => "Not a string"
26
+ * }),
27
+ * "String: hello"
28
+ * )
29
+ *
30
+ * // Data-last (pipeable)
31
+ * assert.deepStrictEqual(
32
+ * pipe(
33
+ * 42,
34
+ * PredicateX.matchRefine(Predicate.isString, {
35
+ * whenTrue: (value) => `String: ${value}`,
36
+ * whenFalse: () => "Not a string"
37
+ * })
38
+ * ),
39
+ * "Not a string"
40
+ * )
41
+ * ```
42
+ *
43
+ * @category pattern matching
44
+ * @since 0.0.0
45
+ */
46
+ export declare const matchRefine: (<A, B extends A, C>(predicate: Predicate.Refinement<A, B>, handlers: {
47
+ whenFalse: () => C;
48
+ whenTrue: (value: B) => C;
49
+ }) => (value: A) => C) & (<A, B extends A, C>(value: A, predicate: Predicate.Refinement<A, B>, handlers: {
50
+ whenFalse: () => C;
51
+ whenTrue: (value: B) => C;
52
+ }) => C);
53
+ /**
54
+ * Refines an `unknown` value to a non-empty `string`, returning `true` only when
55
+ * the value is present, is a `string`, and has at least one character.
56
+ *
57
+ * This is the compound guard the repo's conventions call for: it folds
58
+ * `Predicate.isNotNullish`, `Predicate.isString`, and `String.isNonEmpty` into a
59
+ * single reusable refinement so call sites get `value is string` narrowing
60
+ * without restating the three checks.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
65
+ *
66
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString("hello"), true)
67
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(""), false)
68
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(null), false)
69
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(123), false)
70
+ * ```
71
+ *
72
+ * @category refinements
73
+ * @since 0.0.0
74
+ */
75
+ export declare function isNonEmptyString(value: unknown): value is string;
76
+ /**
77
+ * Refines an `unknown` value to a plain `Record<string, unknown>` — `true` only
78
+ * for a non-null, non-array object whose prototype is `Object.prototype` (an
79
+ * object literal) or `null` (an `Object.create(null)` map).
80
+ *
81
+ * Effect ships no `Predicate.isRecord`. `Predicate.isObject` is the closest, but
82
+ * it also accepts `Map`, `Set`, `Date`, `RegExp`, and class instances. This guard
83
+ * adds a prototype check to rule those out, narrowing to `Record<string, unknown>`
84
+ * so the JSON-tree helpers (`RecordX.deepMerge`, `RecordX.canonicalize`,
85
+ * `RecordX.deleteByPath`) can compose without an `as` cast.
86
+ *
87
+ * It is named **`unsafe`** because the narrowing comes purely from the value's
88
+ * runtime shape — it does *not* validate the key or value types. A symbol-keyed
89
+ * entry still passes despite the `string` key claim, and values are asserted
90
+ * `unknown` without any check. Treat it as a structural convenience, not a
91
+ * `Schema` validation: reach for `Schema` when you need real key/value guarantees.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
96
+ *
97
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord({ a: 1 }), true)
98
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord(Object.create(null)), true)
99
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord([1, 2]), false)
100
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord(new Map()), false)
101
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord(null), false)
102
+ * ```
103
+ *
104
+ * @category refinements
105
+ * @since 0.0.0
106
+ */
107
+ export declare function unsafeIsRecord(value: unknown): value is Record<string, unknown>;
108
+ //# sourceMappingURL=PredicateX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PredicateX.d.ts","sourceRoot":"","sources":["../src/PredicateX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAU,MAAM,QAAQ,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,WAAW,IACrB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,aACL,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,YAC3B;IACR,SAAS,EAAE,MAAM,CAAC,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;CAC3B,KACE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MACnB,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,SACT,CAAC,aACG,SAAS,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,YAC3B;IAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAA;CAAE,KACxD,CAAC,CAQP,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAMhE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMlC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Predicate` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Predicate, String } from "effect";
7
+ import { dual } from "effect/Function";
8
+ /**
9
+ * Runs a refinement against `value` and branches on the result, passing the
10
+ * narrowed value to the `whenTrue` handler.
11
+ *
12
+ * It pairs a `Predicate.Refinement<A, B>` with two continuations so the success
13
+ * branch receives `value` already narrowed to `B`, replacing an `if`/`else` that
14
+ * would otherwise re-check or cast. Supports both data-first and data-last
15
+ * (pipeable) call styles.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
20
+ * import { Predicate, pipe } from "effect"
21
+ *
22
+ * // Data-first
23
+ * assert.deepStrictEqual(
24
+ * PredicateX.matchRefine("hello", Predicate.isString, {
25
+ * whenTrue: (value) => `String: ${value}`,
26
+ * whenFalse: () => "Not a string"
27
+ * }),
28
+ * "String: hello"
29
+ * )
30
+ *
31
+ * // Data-last (pipeable)
32
+ * assert.deepStrictEqual(
33
+ * pipe(
34
+ * 42,
35
+ * PredicateX.matchRefine(Predicate.isString, {
36
+ * whenTrue: (value) => `String: ${value}`,
37
+ * whenFalse: () => "Not a string"
38
+ * })
39
+ * ),
40
+ * "Not a string"
41
+ * )
42
+ * ```
43
+ *
44
+ * @category pattern matching
45
+ * @since 0.0.0
46
+ */
47
+ export const matchRefine = /*#__PURE__*/dual(3, (value, predicate, handlers) => predicate(value) ? handlers.whenTrue(value) : handlers.whenFalse());
48
+ /**
49
+ * Refines an `unknown` value to a non-empty `string`, returning `true` only when
50
+ * the value is present, is a `string`, and has at least one character.
51
+ *
52
+ * This is the compound guard the repo's conventions call for: it folds
53
+ * `Predicate.isNotNullish`, `Predicate.isString`, and `String.isNonEmpty` into a
54
+ * single reusable refinement so call sites get `value is string` narrowing
55
+ * without restating the three checks.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
60
+ *
61
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString("hello"), true)
62
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(""), false)
63
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(null), false)
64
+ * assert.deepStrictEqual(PredicateX.isNonEmptyString(123), false)
65
+ * ```
66
+ *
67
+ * @category refinements
68
+ * @since 0.0.0
69
+ */
70
+ export function isNonEmptyString(value) {
71
+ return Predicate.isNotNullish(value) && Predicate.isString(value) && String.isNonEmpty(value);
72
+ }
73
+ /**
74
+ * Refines an `unknown` value to a plain `Record<string, unknown>` — `true` only
75
+ * for a non-null, non-array object whose prototype is `Object.prototype` (an
76
+ * object literal) or `null` (an `Object.create(null)` map).
77
+ *
78
+ * Effect ships no `Predicate.isRecord`. `Predicate.isObject` is the closest, but
79
+ * it also accepts `Map`, `Set`, `Date`, `RegExp`, and class instances. This guard
80
+ * adds a prototype check to rule those out, narrowing to `Record<string, unknown>`
81
+ * so the JSON-tree helpers (`RecordX.deepMerge`, `RecordX.canonicalize`,
82
+ * `RecordX.deleteByPath`) can compose without an `as` cast.
83
+ *
84
+ * It is named **`unsafe`** because the narrowing comes purely from the value's
85
+ * runtime shape — it does *not* validate the key or value types. A symbol-keyed
86
+ * entry still passes despite the `string` key claim, and values are asserted
87
+ * `unknown` without any check. Treat it as a structural convenience, not a
88
+ * `Schema` validation: reach for `Schema` when you need real key/value guarantees.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * import { PredicateX } from "@nunofyobiz/effect-extras"
93
+ *
94
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord({ a: 1 }), true)
95
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord(Object.create(null)), true)
96
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord([1, 2]), false)
97
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord(new Map()), false)
98
+ * assert.deepStrictEqual(PredicateX.unsafeIsRecord(null), false)
99
+ * ```
100
+ *
101
+ * @category refinements
102
+ * @since 0.0.0
103
+ */
104
+ export function unsafeIsRecord(value) {
105
+ if (!Predicate.isObject(value)) {
106
+ return false;
107
+ }
108
+ const prototype = Object.getPrototypeOf(value);
109
+ return prototype === Object.prototype || prototype === null;
110
+ }
111
+ //# sourceMappingURL=PredicateX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PredicateX.js","names":["Predicate","String","dual","matchRefine","value","predicate","handlers","whenTrue","whenFalse","isNonEmptyString","isNotNullish","isString","isNonEmpty","unsafeIsRecord","isObject","prototype","Object","getPrototypeOf"],"sources":["../src/PredicateX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,SAAS,EAAEC,MAAM,QAAQ,QAAQ;AAC1C,SAASC,IAAI,QAAQ,iBAAiB;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,OAAO,MAAMC,WAAW,gBAAGD,IAAI,CAc7B,CAAC,EACD,CACEE,KAAQ,EACRC,SAAqC,EACrCC,QAA2D,KACpDD,SAAS,CAACD,KAAK,CAAC,GAAGE,QAAQ,CAACC,QAAQ,CAACH,KAAK,CAAC,GAAGE,QAAQ,CAACE,SAAS,EAAG,CAC7E;AAED;;;;;;;;;;;;;;;;;;;;;;AAsBA,OAAM,SAAUC,gBAAgBA,CAACL,KAAc;EAC7C,OACEJ,SAAS,CAACU,YAAY,CAACN,KAAK,CAAC,IAC7BJ,SAAS,CAACW,QAAQ,CAACP,KAAK,CAAC,IACzBH,MAAM,CAACW,UAAU,CAACR,KAAK,CAAC;AAE5B;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,OAAM,SAAUS,cAAcA,CAC5BT,KAAc;EAEd,IAAI,CAACJ,SAAS,CAACc,QAAQ,CAACV,KAAK,CAAC,EAAE;IAC9B,OAAO,KAAK;EACd;EACA,MAAMW,SAAS,GAAGC,MAAM,CAACC,cAAc,CAACb,KAAK,CAAC;EAC9C,OAAOW,SAAS,KAAKC,MAAM,CAACD,SAAS,IAAIA,SAAS,KAAK,IAAI;AAC7D","ignoreList":[]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Helpers for working with native `Promise`s.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ /**
7
+ * Discards the resolved value of a `Promise`, returning a `Promise<void>` that
8
+ * resolves once the original settles.
9
+ *
10
+ * Useful when you await a promise only for its side effect and want the result
11
+ * type to reflect that nothing meaningful is produced — for example when an API
12
+ * expects a `Promise<void>` or when narrowing a value-bearing promise to keep
13
+ * call sites from accidentally depending on the resolved value. A rejection of
14
+ * the original promise still propagates.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { PromiseX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * const run = async (): Promise<void> => {
21
+ * const result = await PromiseX.asVoid(Promise.resolve(42))
22
+ * assert.deepStrictEqual(result, undefined)
23
+ * }
24
+ *
25
+ * void run()
26
+ * ```
27
+ *
28
+ * @category conversions
29
+ * @since 0.0.0
30
+ */
31
+ export declare const asVoid: <T>(promise: Promise<T>) => Promise<void>;
32
+ //# sourceMappingURL=PromiseX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseX.d.ts","sourceRoot":"","sources":["../src/PromiseX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,IAAI,CAC7B,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Helpers for working with native `Promise`s.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ /**
7
+ * Discards the resolved value of a `Promise`, returning a `Promise<void>` that
8
+ * resolves once the original settles.
9
+ *
10
+ * Useful when you await a promise only for its side effect and want the result
11
+ * type to reflect that nothing meaningful is produced — for example when an API
12
+ * expects a `Promise<void>` or when narrowing a value-bearing promise to keep
13
+ * call sites from accidentally depending on the resolved value. A rejection of
14
+ * the original promise still propagates.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { PromiseX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * const run = async (): Promise<void> => {
21
+ * const result = await PromiseX.asVoid(Promise.resolve(42))
22
+ * assert.deepStrictEqual(result, undefined)
23
+ * }
24
+ *
25
+ * void run()
26
+ * ```
27
+ *
28
+ * @category conversions
29
+ * @since 0.0.0
30
+ */
31
+ export const asVoid = promise => promise.then(() => undefined);
32
+ //# sourceMappingURL=PromiseX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromiseX.js","names":["asVoid","promise","then","undefined"],"sources":["../src/PromiseX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,OAAO,MAAMA,MAAM,GAAOC,OAAmB,IAC3CA,OAAO,CAACC,IAAI,CAAC,MAAMC,SAAS,CAAC","ignoreList":[]}