@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,219 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Struct` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Option } from "effect";
7
+ /**
8
+ * Describes the shape of a per-field transformation over an object `O`: a record
9
+ * `T` whose values are functions taking the corresponding field of `O`.
10
+ *
11
+ * Used to type the "evolve" pattern, where each provided key maps to a function
12
+ * that receives that field's current value. Copied from Effect's internal
13
+ * `Struct.evolve()` type, which is not exported — it would be better to use
14
+ * theirs directly if it ever becomes public.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { StructX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * type Transform = StructX.PartialTransform<
21
+ * { a: number; b: string },
22
+ * { a: (n: number) => boolean }
23
+ * >
24
+ *
25
+ * const evolve: Transform = { a: (n) => n > 0 }
26
+ *
27
+ * assert.deepStrictEqual(evolve.a(1), true)
28
+ * ```
29
+ *
30
+ * @category models
31
+ * @since 0.0.0
32
+ */
33
+ export type PartialTransform<O, T> = {
34
+ [K in keyof T]: T[K] extends (a: O[K & keyof O]) => unknown ? T[K] : (a: O[K & keyof O]) => unknown;
35
+ };
36
+ /**
37
+ * Builds a singleton record `{ [name]: value }` when `value` is defined, or an
38
+ * empty object `{}` when it is `undefined` — meant to be spread into an object
39
+ * literal.
40
+ *
41
+ * This is the canonical fix for `exactOptionalPropertyTypes: true` (which this
42
+ * repo enables for Effect Schema). Under that flag, spreading
43
+ * `{ key: maybeUndefined }` into an object whose key is `key?: T` is a type
44
+ * error: the property must be *absent*, not present-but-`undefined`. Spreading
45
+ * `...defined("key", maybeUndefined)` instead conditionally omits the property
46
+ * altogether. Note that `null` and other falsy-but-defined values (`0`, `""`,
47
+ * `false`) are kept — only `undefined` is dropped.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { StructX } from "@nunofyobiz/effect-extras"
52
+ *
53
+ * // Defined value → singleton record
54
+ * assert.deepStrictEqual(StructX.defined("name", "Ada"), { name: "Ada" })
55
+ *
56
+ * // undefined → property omitted entirely
57
+ * assert.deepStrictEqual(StructX.defined("name", undefined), {})
58
+ *
59
+ * // Falsy-but-defined values are kept
60
+ * assert.deepStrictEqual(StructX.defined("name", 0), { name: 0 })
61
+ *
62
+ * // Typical use: spread to conditionally include an optional field
63
+ * const maybeAge: number | undefined = undefined
64
+ * assert.deepStrictEqual({ id: 1, ...StructX.defined("age", maybeAge) }, {
65
+ * id: 1,
66
+ * })
67
+ * ```
68
+ *
69
+ * @category constructors
70
+ * @since 0.0.0
71
+ */
72
+ export declare const defined: <const K extends string, V>(name: K, value: V | undefined) => Partial<Record<K, Exclude<V, undefined>>>;
73
+ /**
74
+ * Removes every property whose value is `undefined` from `record`, narrowing
75
+ * each remaining property type to exclude `undefined`.
76
+ *
77
+ * The bulk counterpart of {@link defined}: instead of building one optional
78
+ * field, it filters a whole object. Very useful for update/patch actions where
79
+ * `undefined` means "leave this field unchanged" while every other value —
80
+ * including `null`, `0`, `""`, `false`, and `Option.none()` — means "set the
81
+ * field to exactly this".
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * import { StructX } from "@nunofyobiz/effect-extras"
86
+ *
87
+ * // Drops `b` (undefined) but keeps every other value, including null/0/false
88
+ * assert.deepStrictEqual(
89
+ * StructX.filterDefined({ a: "x", b: undefined, c: 0, d: null, e: false }),
90
+ * { a: "x", c: 0, d: null, e: false },
91
+ * )
92
+ * ```
93
+ *
94
+ * @category filtering
95
+ * @since 0.0.0
96
+ */
97
+ export declare const filterDefined: <R extends Record<string, unknown>>(record: R) => Partial<{ [P in keyof R]: Exclude<R[P], undefined>; }>;
98
+ /**
99
+ * Builds a singleton record `{ [name]: value }` when `value` is `Some`, or an
100
+ * empty object `{}` when it is `None` — meant to be spread into an object
101
+ * literal.
102
+ *
103
+ * The `Option`-valued sibling of {@link defined}: where `defined` keys off
104
+ * `undefined`, this keys off `Option` presence. Spread `...some("key", opt)` to
105
+ * conditionally include a field only when the `Option` carries a value, which
106
+ * stays correct under `exactOptionalPropertyTypes: true`.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * import { Option } from "effect"
111
+ * import { StructX } from "@nunofyobiz/effect-extras"
112
+ *
113
+ * // Some → singleton record
114
+ * assert.deepStrictEqual(StructX.some("name", Option.some("Ada")), {
115
+ * name: "Ada",
116
+ * })
117
+ *
118
+ * // None → property omitted entirely
119
+ * assert.deepStrictEqual(StructX.some("name", Option.none()), {})
120
+ * ```
121
+ *
122
+ * @category constructors
123
+ * @since 0.0.0
124
+ */
125
+ export declare const some: <const K extends string, V>(name: K, value: Option.Option<V>) => Partial<Record<K, V>>;
126
+ /**
127
+ * Looks up `key` in a record of `Option` values and returns a singleton record
128
+ * when the value is `Some`, or `{}` when the key is absent or its value is
129
+ * `None`.
130
+ *
131
+ * Combines `Record.get` + `Option.flatten` + a singleton builder in one call —
132
+ * ideal for spreading an optional field out of a lookup table into an object
133
+ * literal under `exactOptionalPropertyTypes: true`. By default the output key
134
+ * matches the lookup key; pass `renameKeyTo` to emit the value under a different
135
+ * name.
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * import { Option } from "effect"
140
+ * import { StructX } from "@nunofyobiz/effect-extras"
141
+ *
142
+ * const lookup = {
143
+ * a: Option.some(100),
144
+ * b: Option.none<number>(),
145
+ * }
146
+ *
147
+ * // Some → singleton record under the same key
148
+ * assert.deepStrictEqual(StructX.pickSome(lookup, "a"), { a: 100 })
149
+ *
150
+ * // None → property omitted entirely
151
+ * assert.deepStrictEqual(StructX.pickSome(lookup, "b"), {})
152
+ *
153
+ * // Rename the output key
154
+ * assert.deepStrictEqual(StructX.pickSome(lookup, "a", "count"), { count: 100 })
155
+ * ```
156
+ *
157
+ * @category constructors
158
+ * @since 0.0.0
159
+ */
160
+ export declare function pickSome<const K extends string, V>(record: Record<K, Option.Option<V>>, key: K): Partial<Record<K, V>>;
161
+ export declare function pickSome<const K1 extends string, V, const K2 extends string>(record: Record<K1, Option.Option<V>>, key: K1, renameKeyTo: K2): Partial<Record<K2, V>>;
162
+ /**
163
+ * Builds a singleton record `{ [name]: value }` when `value` is truthy, or an
164
+ * empty object `{}` otherwise — meant to be spread into an object literal.
165
+ *
166
+ * Stricter than {@link defined}: it drops not just `undefined` but every falsy
167
+ * value (`null`, `false`, `0`, `""`, `NaN`), and narrows the value type
168
+ * accordingly. Use it to spread a field only when it carries a meaningful,
169
+ * non-falsy value.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * import { StructX } from "@nunofyobiz/effect-extras"
174
+ *
175
+ * // Truthy value → singleton record
176
+ * assert.deepStrictEqual(StructX.truthy("name", "Ada"), { name: "Ada" })
177
+ *
178
+ * // Falsy values → property omitted entirely
179
+ * assert.deepStrictEqual(StructX.truthy("name", ""), {})
180
+ * assert.deepStrictEqual(StructX.truthy("name", 0), {})
181
+ * assert.deepStrictEqual(StructX.truthy("name", false), {})
182
+ * ```
183
+ *
184
+ * @category constructors
185
+ * @since 0.0.0
186
+ */
187
+ export declare const truthy: <const K extends string, V>(name: K, value: V) => Partial<Record<K, Exclude<NonNullable<V>, false | 0 | "">>>;
188
+ /**
189
+ * Returns `true` when `object` has `key` set to a non-nullish value, narrowing
190
+ * that property to `NonNullable` on the type level.
191
+ *
192
+ * A type guard combining `hasProperty` with a nullish check: after a successful
193
+ * test, TypeScript treats `object[key]` as present and free of `null` /
194
+ * `undefined`. Handy as a predicate passed to `Array.filter` to keep only the
195
+ * elements whose `key` is populated.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * import { pipe } from "effect"
200
+ * import { StructX } from "@nunofyobiz/effect-extras"
201
+ *
202
+ * // data-first
203
+ * assert.deepStrictEqual(
204
+ * StructX.hasNotNullableProperty({ id: "1" }, "id"),
205
+ * true,
206
+ * )
207
+ *
208
+ * // data-last (pipeable); a null value fails the guard
209
+ * assert.deepStrictEqual(
210
+ * pipe({ id: null }, StructX.hasNotNullableProperty("id")),
211
+ * false,
212
+ * )
213
+ * ```
214
+ *
215
+ * @category refinements
216
+ * @since 0.0.0
217
+ */
218
+ export declare const hasNotNullableProperty: (<T, K extends keyof T>(key: K) => (object: T) => object is T & Record<K, NonNullable<T[K]>>) & (<T, K extends keyof T>(object: T, key: K) => object is T & Record<K, NonNullable<T[K]>>);
219
+ //# sourceMappingURL=StructX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StructX.d.ts","sourceRoot":"","sources":["../src/StructX.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Struct` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Option, Predicate, Record, pipe } from "effect";
7
+ import { dual } from "effect/Function";
8
+ /**
9
+ * Builds a singleton record `{ [name]: value }` when `value` is defined, or an
10
+ * empty object `{}` when it is `undefined` — meant to be spread into an object
11
+ * literal.
12
+ *
13
+ * This is the canonical fix for `exactOptionalPropertyTypes: true` (which this
14
+ * repo enables for Effect Schema). Under that flag, spreading
15
+ * `{ key: maybeUndefined }` into an object whose key is `key?: T` is a type
16
+ * error: the property must be *absent*, not present-but-`undefined`. Spreading
17
+ * `...defined("key", maybeUndefined)` instead conditionally omits the property
18
+ * altogether. Note that `null` and other falsy-but-defined values (`0`, `""`,
19
+ * `false`) are kept — only `undefined` is dropped.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { StructX } from "@nunofyobiz/effect-extras"
24
+ *
25
+ * // Defined value → singleton record
26
+ * assert.deepStrictEqual(StructX.defined("name", "Ada"), { name: "Ada" })
27
+ *
28
+ * // undefined → property omitted entirely
29
+ * assert.deepStrictEqual(StructX.defined("name", undefined), {})
30
+ *
31
+ * // Falsy-but-defined values are kept
32
+ * assert.deepStrictEqual(StructX.defined("name", 0), { name: 0 })
33
+ *
34
+ * // Typical use: spread to conditionally include an optional field
35
+ * const maybeAge: number | undefined = undefined
36
+ * assert.deepStrictEqual({ id: 1, ...StructX.defined("age", maybeAge) }, {
37
+ * id: 1,
38
+ * })
39
+ * ```
40
+ *
41
+ * @category constructors
42
+ * @since 0.0.0
43
+ */
44
+ export const defined = (name, value) => Predicate.isUndefined(value) ? {} : Record.singleton(name, value);
45
+ /**
46
+ * Removes every property whose value is `undefined` from `record`, narrowing
47
+ * each remaining property type to exclude `undefined`.
48
+ *
49
+ * The bulk counterpart of {@link defined}: instead of building one optional
50
+ * field, it filters a whole object. Very useful for update/patch actions where
51
+ * `undefined` means "leave this field unchanged" while every other value —
52
+ * including `null`, `0`, `""`, `false`, and `Option.none()` — means "set the
53
+ * field to exactly this".
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { StructX } from "@nunofyobiz/effect-extras"
58
+ *
59
+ * // Drops `b` (undefined) but keeps every other value, including null/0/false
60
+ * assert.deepStrictEqual(
61
+ * StructX.filterDefined({ a: "x", b: undefined, c: 0, d: null, e: false }),
62
+ * { a: "x", c: 0, d: null, e: false },
63
+ * )
64
+ * ```
65
+ *
66
+ * @category filtering
67
+ * @since 0.0.0
68
+ */
69
+ export const filterDefined = record => Object.entries(record).reduce((accumulator, [key, value]) => ({
70
+ ...accumulator,
71
+ ...defined(key, value)
72
+ }), {});
73
+ /**
74
+ * Builds a singleton record `{ [name]: value }` when `value` is `Some`, or an
75
+ * empty object `{}` when it is `None` — meant to be spread into an object
76
+ * literal.
77
+ *
78
+ * The `Option`-valued sibling of {@link defined}: where `defined` keys off
79
+ * `undefined`, this keys off `Option` presence. Spread `...some("key", opt)` to
80
+ * conditionally include a field only when the `Option` carries a value, which
81
+ * stays correct under `exactOptionalPropertyTypes: true`.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * import { Option } from "effect"
86
+ * import { StructX } from "@nunofyobiz/effect-extras"
87
+ *
88
+ * // Some → singleton record
89
+ * assert.deepStrictEqual(StructX.some("name", Option.some("Ada")), {
90
+ * name: "Ada",
91
+ * })
92
+ *
93
+ * // None → property omitted entirely
94
+ * assert.deepStrictEqual(StructX.some("name", Option.none()), {})
95
+ * ```
96
+ *
97
+ * @category constructors
98
+ * @since 0.0.0
99
+ */
100
+ export const some = (name, value) => Option.match(value, {
101
+ onSome: someValue => Record.singleton(name, someValue),
102
+ onNone: () => ({})
103
+ });
104
+ /**
105
+ * Like {@link some}, but with swapped argument order for piping. Returns a
106
+ * singleton record `{ [name]: value }` when the Option is `Some`, or an
107
+ * empty object `{}` when `None`.
108
+ *
109
+ * Internal-only — exists to support {@link pickSome} in data-last form.
110
+ * Not exported because the codebase has no direct callers.
111
+ */
112
+ const someSingleton = /*#__PURE__*/dual(2, (value, name) => some(name, value));
113
+ export function pickSome(record, key, renameKeyTo) {
114
+ return pipe(Record.get(record, key), Option.flatten, someSingleton(renameKeyTo ?? key));
115
+ }
116
+ /**
117
+ * Builds a singleton record `{ [name]: value }` when `value` is truthy, or an
118
+ * empty object `{}` otherwise — meant to be spread into an object literal.
119
+ *
120
+ * Stricter than {@link defined}: it drops not just `undefined` but every falsy
121
+ * value (`null`, `false`, `0`, `""`, `NaN`), and narrows the value type
122
+ * accordingly. Use it to spread a field only when it carries a meaningful,
123
+ * non-falsy value.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * import { StructX } from "@nunofyobiz/effect-extras"
128
+ *
129
+ * // Truthy value → singleton record
130
+ * assert.deepStrictEqual(StructX.truthy("name", "Ada"), { name: "Ada" })
131
+ *
132
+ * // Falsy values → property omitted entirely
133
+ * assert.deepStrictEqual(StructX.truthy("name", ""), {})
134
+ * assert.deepStrictEqual(StructX.truthy("name", 0), {})
135
+ * assert.deepStrictEqual(StructX.truthy("name", false), {})
136
+ * ```
137
+ *
138
+ * @category constructors
139
+ * @since 0.0.0
140
+ */
141
+ export const truthy = (name, value) => Predicate.isTruthy(value) ? Record.singleton(name, value) : {};
142
+ /**
143
+ * Returns `true` when `object` has `key` set to a non-nullish value, narrowing
144
+ * that property to `NonNullable` on the type level.
145
+ *
146
+ * A type guard combining `hasProperty` with a nullish check: after a successful
147
+ * test, TypeScript treats `object[key]` as present and free of `null` /
148
+ * `undefined`. Handy as a predicate passed to `Array.filter` to keep only the
149
+ * elements whose `key` is populated.
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * import { pipe } from "effect"
154
+ * import { StructX } from "@nunofyobiz/effect-extras"
155
+ *
156
+ * // data-first
157
+ * assert.deepStrictEqual(
158
+ * StructX.hasNotNullableProperty({ id: "1" }, "id"),
159
+ * true,
160
+ * )
161
+ *
162
+ * // data-last (pipeable); a null value fails the guard
163
+ * assert.deepStrictEqual(
164
+ * pipe({ id: null }, StructX.hasNotNullableProperty("id")),
165
+ * false,
166
+ * )
167
+ * ```
168
+ *
169
+ * @category refinements
170
+ * @since 0.0.0
171
+ */
172
+ export const hasNotNullableProperty = /*#__PURE__*/dual(2, (object, key) => Predicate.hasProperty(object, key) && Predicate.isNotNullish(object[key]));
173
+ //# sourceMappingURL=StructX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StructX.js","names":["Option","Predicate","Record","pipe","dual","defined","name","value","isUndefined","singleton","filterDefined","record","Object","entries","reduce","accumulator","key","some","match","onSome","someValue","onNone","someSingleton","pickSome","renameKeyTo","get","flatten","truthy","isTruthy","hasNotNullableProperty","object","hasProperty","isNotNullish"],"sources":["../src/StructX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,MAAM,EAAEC,SAAS,EAAEC,MAAM,EAAEC,IAAI,QAAQ,QAAQ;AACxD,SAASC,IAAI,QAAQ,iBAAiB;AAkCtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,OAAO,MAAMC,OAAO,GAAGA,CACrBC,IAAO,EACPC,KAAoB,KAEpBN,SAAS,CAACO,WAAW,CAACD,KAAK,CAAC,GACxB,EAAE,GACFL,MAAM,CAACO,SAAS,CAACH,IAAI,EAAEC,KAA8B,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,OAAO,MAAMG,aAAa,GACxBC,MAAS,IAETC,MAAM,CAACC,OAAO,CAACF,MAAM,CAAC,CAACG,MAAM,CAC3B,CAACC,WAAW,EAAE,CAACC,GAAG,EAAET,KAAK,CAAC,MAAM;EAAE,GAAGQ,WAAW;EAAE,GAAGV,OAAO,CAACW,GAAG,EAAET,KAAK;AAAC,CAAE,CAAC,EAC3E,EAA2D,CAC5D;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,OAAO,MAAMU,IAAI,GAAGA,CAClBX,IAAO,EACPC,KAAuB,KAEvBP,MAAM,CAACkB,KAAK,CAACX,KAAK,EAAE;EAClBY,MAAM,EAAGC,SAAS,IAAKlB,MAAM,CAACO,SAAS,CAACH,IAAI,EAAEc,SAAS,CAAC;EACxDC,MAAM,EAAEA,CAAA,MAAO,EAAE;CAClB,CAAC;AAEJ;;;;;;;;AAQA,MAAMC,aAAa,gBAQflB,IAAI,CACN,CAAC,EACD,CACEG,KAAuB,EACvBD,IAAO,KACmBW,IAAI,CAACX,IAAI,EAAEC,KAAK,CAAC,CAC9C;AA6CD,OAAM,SAAUgB,QAAQA,CACtBZ,MAAoC,EACpCK,GAAO,EACPQ,WAAgB;EAEhB,OAAOrB,IAAI,CACTD,MAAM,CAACuB,GAAG,CAACd,MAAM,EAAEK,GAAG,CAAC,EACvBhB,MAAM,CAAC0B,OAAO,EACdJ,aAAa,CAACE,WAAW,IAAIR,GAAG,CAAC,CAClC;AACH;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,OAAO,MAAMW,MAAM,GAAGA,CACpBrB,IAAO,EACPC,KAAQ,KAERN,SAAS,CAAC2B,QAAQ,CAACrB,KAAK,CAAC,GACrBL,MAAM,CAACO,SAAS,CAACH,IAAI,EAAEC,KAAgD,CAAC,GACxE,EAAE;AAER;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,OAAO,MAAMsB,sBAAsB,gBAAGzB,IAAI,CASxC,CAAC,EACD,CACE0B,MAAS,EACTd,GAAM,KAENf,SAAS,CAAC8B,WAAW,CAACD,MAAM,EAAEd,GAAG,CAAC,IAAIf,SAAS,CAAC+B,YAAY,CAACF,MAAM,CAACd,GAAG,CAAC,CAAC,CAC5E","ignoreList":[]}