@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,249 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Schema` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { Schema } from "effect";
7
+ /**
8
+ * A `Schema` for a non-empty string that is trimmed on both decode and encode.
9
+ *
10
+ * Leading and trailing whitespace is stripped, and the resulting value must be
11
+ * non-empty — so a whitespace-only input (e.g. `" "`) fails the
12
+ * `NonEmptyString` refinement after trimming. Use it wherever user-supplied text
13
+ * should be normalized and guaranteed to carry content.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Effect, Schema } from "effect"
18
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * const decoded = Effect.runSync(
21
+ * Schema.decodeEffect(SchemaX.TrimmedNonEmptyString)(" hello "),
22
+ * )
23
+ * assert.deepStrictEqual(decoded, "hello")
24
+ * ```
25
+ *
26
+ * @category constructors
27
+ * @since 0.0.0
28
+ */
29
+ export declare const TrimmedNonEmptyString: Schema.decodeTo<Schema.toType<Schema.NonEmptyString>, Schema.NonEmptyString, never, never>;
30
+ /**
31
+ * A `Schema` for a URL-safe file path built on top of {@link
32
+ * TrimmedNonEmptyString}.
33
+ *
34
+ * On decode the path is `decodeURIComponent`-ed (percent-escapes are expanded);
35
+ * on encode it is `encodeURIComponent`-ed back into its URL-safe form. The
36
+ * underlying value is also trimmed and required to be non-empty. Use it at the
37
+ * boundary between stored/transmitted encoded paths and the decoded paths your
38
+ * code works with.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import { Effect, Schema } from "effect"
43
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
44
+ *
45
+ * // Decoding expands percent-escapes
46
+ * const decoded = Effect.runSync(
47
+ * Schema.decodeEffect(SchemaX.URLSafeFilePath)("a%2Fb.txt"),
48
+ * )
49
+ * assert.deepStrictEqual(decoded, "a/b.txt")
50
+ *
51
+ * // Encoding produces the URL-safe form
52
+ * const encoded = Effect.runSync(
53
+ * Schema.encodeEffect(SchemaX.URLSafeFilePath)("a/b.txt"),
54
+ * )
55
+ * assert.deepStrictEqual(encoded, "a%2Fb.txt")
56
+ * ```
57
+ *
58
+ * @category constructors
59
+ * @since 0.0.0
60
+ */
61
+ export declare const URLSafeFilePath: Schema.decodeTo<Schema.toType<Schema.decodeTo<Schema.toType<Schema.NonEmptyString>, Schema.NonEmptyString, never, never>>, Schema.decodeTo<Schema.toType<Schema.NonEmptyString>, Schema.NonEmptyString, never, never>, never, never>;
62
+ /**
63
+ * Transforms a `bigint` `Schema` so its value is clamped to be non-negative,
64
+ * mapping any value below `0n` up to `0n` on both decode and encode.
65
+ *
66
+ * Unlike a refinement that *rejects* negative input, this *coerces* it: a
67
+ * negative `bigint` decodes to `0n` rather than failing. Apply it to a `bigint`
68
+ * schema whenever negative magnitudes are meaningless and should be floored at
69
+ * zero rather than treated as errors.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * import { Effect, Schema } from "effect"
74
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
75
+ *
76
+ * const NonNegative = SchemaX.nonNegativeBigInt(Schema.BigInt)
77
+ *
78
+ * // Negative values are clamped up to 0n
79
+ * assert.deepStrictEqual(
80
+ * Effect.runSync(Schema.decodeEffect(NonNegative)(-5n)),
81
+ * 0n,
82
+ * )
83
+ *
84
+ * // Non-negative values pass through unchanged
85
+ * assert.deepStrictEqual(
86
+ * Effect.runSync(Schema.decodeEffect(NonNegative)(7n)),
87
+ * 7n,
88
+ * )
89
+ * ```
90
+ *
91
+ * @category combinators
92
+ * @since 0.0.0
93
+ */
94
+ export declare const nonNegativeBigInt: <S extends Schema.Schema<bigint>>(schema: S) => Schema.decodeTo<Schema.toType<S>, S, never, never>;
95
+ /**
96
+ * Extracts the "constructor input" type of a `Schema` — what `.make({...})`
97
+ * accepts.
98
+ *
99
+ * Differs from `S["Type"]` (the decoded type) in that fields carrying
100
+ * constructor defaults (e.g. an `Overrideable` timestamp) are *optional* in
101
+ * `MakeIn` but *required* in `Type`. Use it in signatures that accept a value to
102
+ * construct, so callers can pass a plain object literal without supplying the
103
+ * defaulted, override-branded fields.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * import { Schema } from "effect"
108
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
109
+ *
110
+ * const Person = Schema.Struct({ name: Schema.String, age: Schema.Number })
111
+ *
112
+ * const input: SchemaX.MakeIn<typeof Person> = { name: "Ada", age: 36 }
113
+ *
114
+ * assert.deepStrictEqual(input, { name: "Ada", age: 36 })
115
+ * ```
116
+ *
117
+ * @category models
118
+ * @since 0.0.0
119
+ */
120
+ export type MakeIn<S extends {
121
+ readonly "~type.make.in": unknown;
122
+ }> = S["~type.make.in"];
123
+ /**
124
+ * Returns a new `Schema.Struct` containing only the named `keys` of `schema`.
125
+ *
126
+ * Restores the v3 ergonomics of `mySchema.pick("a", "b")` — v4 removed the
127
+ * `.pick(...)` method from `Schema.Struct` instances, so this rebuilds it on top
128
+ * of v4's `mapFields` primitive. Each picked field keeps its original schema,
129
+ * including any refinements.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * import { Effect, Schema } from "effect"
134
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
135
+ *
136
+ * const Source = Schema.Struct({
137
+ * a: Schema.Number,
138
+ * b: Schema.String,
139
+ * c: Schema.Boolean,
140
+ * })
141
+ *
142
+ * const Picked = SchemaX.pick(Source, "a", "b")
143
+ *
144
+ * const decoded = Effect.runSync(
145
+ * Schema.decodeEffect(Picked)({ a: 1, b: "hi" }),
146
+ * )
147
+ * assert.deepStrictEqual(decoded, { a: 1, b: "hi" })
148
+ * ```
149
+ *
150
+ * @category combinators
151
+ * @since 0.0.0
152
+ */
153
+ export declare const pick: <const Fields extends Schema.Struct.Fields, const Keys extends readonly (keyof Fields & string)[]>(schema: Schema.Struct<Fields>, ...keys: Keys) => Schema.Struct<Pick<Fields, Keys[number]>>;
154
+ /**
155
+ * Returns a new `Schema.Struct` with the named `keys` of `schema` removed.
156
+ *
157
+ * The complement of {@link pick}, restoring the v3 ergonomics of
158
+ * `mySchema.omit("a")` that v4 dropped from `Schema.Struct` instances. Every
159
+ * surviving field keeps its original schema, including any refinements.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * import { Effect, Schema } from "effect"
164
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
165
+ *
166
+ * const Source = Schema.Struct({
167
+ * a: Schema.Number,
168
+ * b: Schema.String,
169
+ * c: Schema.Boolean,
170
+ * })
171
+ *
172
+ * const Omitted = SchemaX.omit(Source, "c")
173
+ *
174
+ * const decoded = Effect.runSync(
175
+ * Schema.decodeEffect(Omitted)({ a: 1, b: "hi" }),
176
+ * )
177
+ * assert.deepStrictEqual(decoded, { a: 1, b: "hi" })
178
+ * ```
179
+ *
180
+ * @category combinators
181
+ * @since 0.0.0
182
+ */
183
+ export declare const omit: <const Fields extends Schema.Struct.Fields, const Keys extends readonly (keyof Fields & string)[]>(schema: Schema.Struct<Fields>, ...keys: Keys) => Schema.Struct<Omit<Fields, Keys[number]>>;
184
+ /**
185
+ * Returns a new `Schema.Struct` in which every field of `schema` is made
186
+ * optional.
187
+ *
188
+ * Restores the v3 `Schema.partial(mySchema)` behaviour that v4 removed, by
189
+ * wrapping each field in `Schema.optional`. A decoded value may therefore omit
190
+ * any field; fields that *are* present still have to satisfy their original
191
+ * schema, refinements included.
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * import { Effect, Schema } from "effect"
196
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
197
+ *
198
+ * const Source = Schema.Struct({ a: Schema.Number, b: Schema.String })
199
+ * const Partial = SchemaX.partial(Source)
200
+ *
201
+ * // All fields may be absent
202
+ * assert.deepStrictEqual(Effect.runSync(Schema.decodeEffect(Partial)({})), {})
203
+ *
204
+ * // A present subset still decodes
205
+ * assert.deepStrictEqual(
206
+ * Effect.runSync(Schema.decodeEffect(Partial)({ a: 1 })),
207
+ * { a: 1 },
208
+ * )
209
+ * ```
210
+ *
211
+ * @category combinators
212
+ * @since 0.0.0
213
+ */
214
+ export declare const partial: <Fields extends Schema.Struct.Fields>(schema: Schema.Struct<Fields>) => Schema.Struct<{ [K in keyof Fields]: Schema.optional<Fields[K]>; }>;
215
+ /**
216
+ * Returns a new `Schema.Struct` containing only the named `keys` of `schema`,
217
+ * with every picked field made optional.
218
+ *
219
+ * Equivalent to `partial(pick(schema, ...keys))`, but reads more directly for
220
+ * the common "partial update over a subset of fields" pattern: select the
221
+ * mutable fields of an entity, then allow any of them to be omitted in the
222
+ * update payload. Composes {@link pick} and {@link partial} in one call.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * import { Effect, Schema } from "effect"
227
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
228
+ *
229
+ * const Source = Schema.Struct({
230
+ * a: Schema.Number,
231
+ * b: Schema.String,
232
+ * c: Schema.Boolean,
233
+ * })
234
+ *
235
+ * const Update = SchemaX.pickPartial(Source, "a", "b")
236
+ *
237
+ * // Only picked fields are known, and each may be omitted
238
+ * assert.deepStrictEqual(Effect.runSync(Schema.decodeEffect(Update)({})), {})
239
+ * assert.deepStrictEqual(
240
+ * Effect.runSync(Schema.decodeEffect(Update)({ a: 1 })),
241
+ * { a: 1 },
242
+ * )
243
+ * ```
244
+ *
245
+ * @category combinators
246
+ * @since 0.0.0
247
+ */
248
+ export declare const pickPartial: <const Fields extends Schema.Struct.Fields, const Keys extends readonly (keyof Fields & string)[]>(schema: Schema.Struct<Fields>, ...keys: Keys) => Schema.Struct<{ [K in Keys[number]]: Schema.optional<Fields[K]>; }>;
249
+ //# sourceMappingURL=SchemaX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaX.d.ts","sourceRoot":"","sources":["../src/SchemaX.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAU,MAAM,EAAwB,MAAM,QAAQ,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,qBAAqB,4FAKjC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,eAAe,sOAK3B,CAAC;AAaF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,iBAAiB,GAxC3B,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,uDAwCM,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,IAChE,CAAC,CAAC,eAAe,CAAC,CAAC;AAQrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,IAAI,GACf,KAAK,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EACzC,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,EAErD,QAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAC7B,GAAG,MAAM,IAAI,KACZ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAOxC,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,IAAI,GACf,KAAK,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EACzC,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,EAErD,QAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAC7B,GAAG,MAAM,IAAI,KACZ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAOxC,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EACzD,QAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAC5B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAE,CAOhE,CAAC;AAEL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GACtB,KAAK,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,EACzC,KAAK,CAAC,IAAI,SAAS,SAAS,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,EAErD,QAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAC7B,GAAG,MAAM,IAAI,KACZ,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAE,CACpC,CAAC"}
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Generic, framework-agnostic extensions to Effect's `Schema` module.
3
+ *
4
+ * @since 0.0.0
5
+ */
6
+ import { BigInt, Schema, SchemaGetter, Struct } from "effect";
7
+ /**
8
+ * A `Schema` for a non-empty string that is trimmed on both decode and encode.
9
+ *
10
+ * Leading and trailing whitespace is stripped, and the resulting value must be
11
+ * non-empty — so a whitespace-only input (e.g. `" "`) fails the
12
+ * `NonEmptyString` refinement after trimming. Use it wherever user-supplied text
13
+ * should be normalized and guaranteed to carry content.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { Effect, Schema } from "effect"
18
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
19
+ *
20
+ * const decoded = Effect.runSync(
21
+ * Schema.decodeEffect(SchemaX.TrimmedNonEmptyString)(" hello "),
22
+ * )
23
+ * assert.deepStrictEqual(decoded, "hello")
24
+ * ```
25
+ *
26
+ * @category constructors
27
+ * @since 0.0.0
28
+ */
29
+ export const TrimmedNonEmptyString = /*#__PURE__*/Schema.NonEmptyString.pipe(/*#__PURE__*/Schema.decode({
30
+ decode: /*#__PURE__*/SchemaGetter.transform(s => s.trim()),
31
+ encode: /*#__PURE__*/SchemaGetter.transform(s => s.trim())
32
+ }));
33
+ /**
34
+ * A `Schema` for a URL-safe file path built on top of {@link
35
+ * TrimmedNonEmptyString}.
36
+ *
37
+ * On decode the path is `decodeURIComponent`-ed (percent-escapes are expanded);
38
+ * on encode it is `encodeURIComponent`-ed back into its URL-safe form. The
39
+ * underlying value is also trimmed and required to be non-empty. Use it at the
40
+ * boundary between stored/transmitted encoded paths and the decoded paths your
41
+ * code works with.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import { Effect, Schema } from "effect"
46
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
47
+ *
48
+ * // Decoding expands percent-escapes
49
+ * const decoded = Effect.runSync(
50
+ * Schema.decodeEffect(SchemaX.URLSafeFilePath)("a%2Fb.txt"),
51
+ * )
52
+ * assert.deepStrictEqual(decoded, "a/b.txt")
53
+ *
54
+ * // Encoding produces the URL-safe form
55
+ * const encoded = Effect.runSync(
56
+ * Schema.encodeEffect(SchemaX.URLSafeFilePath)("a/b.txt"),
57
+ * )
58
+ * assert.deepStrictEqual(encoded, "a%2Fb.txt")
59
+ * ```
60
+ *
61
+ * @category constructors
62
+ * @since 0.0.0
63
+ */
64
+ export const URLSafeFilePath = /*#__PURE__*/TrimmedNonEmptyString.pipe(/*#__PURE__*/Schema.decode({
65
+ decode: /*#__PURE__*/SchemaGetter.transform(path => decodeURIComponent(path)),
66
+ encode: /*#__PURE__*/SchemaGetter.transform(path => encodeURIComponent(path))
67
+ }));
68
+ // Internal — only used to construct nonNegativeBigInt below.
69
+ const clampMinBigInt = min => schema => schema.pipe(Schema.decode({
70
+ decode: SchemaGetter.transform(value => BigInt.max(value, min)),
71
+ encode: SchemaGetter.transform(value => BigInt.max(value, min))
72
+ }));
73
+ /**
74
+ * Transforms a `bigint` `Schema` so its value is clamped to be non-negative,
75
+ * mapping any value below `0n` up to `0n` on both decode and encode.
76
+ *
77
+ * Unlike a refinement that *rejects* negative input, this *coerces* it: a
78
+ * negative `bigint` decodes to `0n` rather than failing. Apply it to a `bigint`
79
+ * schema whenever negative magnitudes are meaningless and should be floored at
80
+ * zero rather than treated as errors.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * import { Effect, Schema } from "effect"
85
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
86
+ *
87
+ * const NonNegative = SchemaX.nonNegativeBigInt(Schema.BigInt)
88
+ *
89
+ * // Negative values are clamped up to 0n
90
+ * assert.deepStrictEqual(
91
+ * Effect.runSync(Schema.decodeEffect(NonNegative)(-5n)),
92
+ * 0n,
93
+ * )
94
+ *
95
+ * // Non-negative values pass through unchanged
96
+ * assert.deepStrictEqual(
97
+ * Effect.runSync(Schema.decodeEffect(NonNegative)(7n)),
98
+ * 7n,
99
+ * )
100
+ * ```
101
+ *
102
+ * @category combinators
103
+ * @since 0.0.0
104
+ */
105
+ export const nonNegativeBigInt = /*#__PURE__*/clampMinBigInt(0n);
106
+ // ---------------------------------------------------------------------------
107
+ // Schema.Struct utilities — v4 removed the `.pick(...)`, `.omit(...)`, and
108
+ // `Schema.partial(...)` methods that v3 had on `Schema.Struct` instances. These
109
+ // helpers restore the same ergonomics on top of v4's `mapFields` primitive.
110
+ // ---------------------------------------------------------------------------
111
+ /**
112
+ * Returns a new `Schema.Struct` containing only the named `keys` of `schema`.
113
+ *
114
+ * Restores the v3 ergonomics of `mySchema.pick("a", "b")` — v4 removed the
115
+ * `.pick(...)` method from `Schema.Struct` instances, so this rebuilds it on top
116
+ * of v4's `mapFields` primitive. Each picked field keeps its original schema,
117
+ * including any refinements.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { Effect, Schema } from "effect"
122
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
123
+ *
124
+ * const Source = Schema.Struct({
125
+ * a: Schema.Number,
126
+ * b: Schema.String,
127
+ * c: Schema.Boolean,
128
+ * })
129
+ *
130
+ * const Picked = SchemaX.pick(Source, "a", "b")
131
+ *
132
+ * const decoded = Effect.runSync(
133
+ * Schema.decodeEffect(Picked)({ a: 1, b: "hi" }),
134
+ * )
135
+ * assert.deepStrictEqual(decoded, { a: 1, b: "hi" })
136
+ * ```
137
+ *
138
+ * @category combinators
139
+ * @since 0.0.0
140
+ */
141
+ export const pick = (schema, ...keys) => schema.mapFields(fields => Struct.pick(fields, keys));
142
+ /**
143
+ * Returns a new `Schema.Struct` with the named `keys` of `schema` removed.
144
+ *
145
+ * The complement of {@link pick}, restoring the v3 ergonomics of
146
+ * `mySchema.omit("a")` that v4 dropped from `Schema.Struct` instances. Every
147
+ * surviving field keeps its original schema, including any refinements.
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * import { Effect, Schema } from "effect"
152
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
153
+ *
154
+ * const Source = Schema.Struct({
155
+ * a: Schema.Number,
156
+ * b: Schema.String,
157
+ * c: Schema.Boolean,
158
+ * })
159
+ *
160
+ * const Omitted = SchemaX.omit(Source, "c")
161
+ *
162
+ * const decoded = Effect.runSync(
163
+ * Schema.decodeEffect(Omitted)({ a: 1, b: "hi" }),
164
+ * )
165
+ * assert.deepStrictEqual(decoded, { a: 1, b: "hi" })
166
+ * ```
167
+ *
168
+ * @category combinators
169
+ * @since 0.0.0
170
+ */
171
+ export const omit = (schema, ...keys) => schema.mapFields(fields => Struct.omit(fields, keys));
172
+ /**
173
+ * Returns a new `Schema.Struct` in which every field of `schema` is made
174
+ * optional.
175
+ *
176
+ * Restores the v3 `Schema.partial(mySchema)` behaviour that v4 removed, by
177
+ * wrapping each field in `Schema.optional`. A decoded value may therefore omit
178
+ * any field; fields that *are* present still have to satisfy their original
179
+ * schema, refinements included.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * import { Effect, Schema } from "effect"
184
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
185
+ *
186
+ * const Source = Schema.Struct({ a: Schema.Number, b: Schema.String })
187
+ * const Partial = SchemaX.partial(Source)
188
+ *
189
+ * // All fields may be absent
190
+ * assert.deepStrictEqual(Effect.runSync(Schema.decodeEffect(Partial)({})), {})
191
+ *
192
+ * // A present subset still decodes
193
+ * assert.deepStrictEqual(
194
+ * Effect.runSync(Schema.decodeEffect(Partial)({ a: 1 })),
195
+ * { a: 1 },
196
+ * )
197
+ * ```
198
+ *
199
+ * @category combinators
200
+ * @since 0.0.0
201
+ */
202
+ export const partial = schema => schema.mapFields(fields => {
203
+ const result = {};
204
+ for (const key of Object.keys(fields)) {
205
+ result[key] = Schema.optional(fields[key]);
206
+ }
207
+ return result;
208
+ });
209
+ /**
210
+ * Returns a new `Schema.Struct` containing only the named `keys` of `schema`,
211
+ * with every picked field made optional.
212
+ *
213
+ * Equivalent to `partial(pick(schema, ...keys))`, but reads more directly for
214
+ * the common "partial update over a subset of fields" pattern: select the
215
+ * mutable fields of an entity, then allow any of them to be omitted in the
216
+ * update payload. Composes {@link pick} and {@link partial} in one call.
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * import { Effect, Schema } from "effect"
221
+ * import { SchemaX } from "@nunofyobiz/effect-extras"
222
+ *
223
+ * const Source = Schema.Struct({
224
+ * a: Schema.Number,
225
+ * b: Schema.String,
226
+ * c: Schema.Boolean,
227
+ * })
228
+ *
229
+ * const Update = SchemaX.pickPartial(Source, "a", "b")
230
+ *
231
+ * // Only picked fields are known, and each may be omitted
232
+ * assert.deepStrictEqual(Effect.runSync(Schema.decodeEffect(Update)({})), {})
233
+ * assert.deepStrictEqual(
234
+ * Effect.runSync(Schema.decodeEffect(Update)({ a: 1 })),
235
+ * { a: 1 },
236
+ * )
237
+ * ```
238
+ *
239
+ * @category combinators
240
+ * @since 0.0.0
241
+ */
242
+ export const pickPartial = (schema, ...keys) => partial(pick(schema, ...keys));
243
+ //# sourceMappingURL=SchemaX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaX.js","names":["BigInt","Schema","SchemaGetter","Struct","TrimmedNonEmptyString","NonEmptyString","pipe","decode","transform","s","trim","encode","URLSafeFilePath","path","decodeURIComponent","encodeURIComponent","clampMinBigInt","min","schema","value","max","nonNegativeBigInt","pick","keys","mapFields","fields","omit","partial","result","key","Object","optional","pickPartial"],"sources":["../src/SchemaX.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,SAASA,MAAM,EAAEC,MAAM,EAAEC,YAAY,EAAEC,MAAM,QAAQ,QAAQ;AAE7D;;;;;;;;;;;;;;;;;;;;;;AAsBA,OAAO,MAAMC,qBAAqB,gBAAGH,MAAM,CAACI,cAAc,CAACC,IAAI,cAC7DL,MAAM,CAACM,MAAM,CAAC;EACZA,MAAM,eAAEL,YAAY,CAACM,SAAS,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,EAAE,CAAC;EAC/CC,MAAM,eAAET,YAAY,CAACM,SAAS,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,EAAE;CAC/C,CAAC,CACH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,OAAO,MAAME,eAAe,gBAAGR,qBAAqB,CAACE,IAAI,cACvDL,MAAM,CAACM,MAAM,CAAC;EACZA,MAAM,eAAEL,YAAY,CAACM,SAAS,CAAEK,IAAI,IAAKC,kBAAkB,CAACD,IAAI,CAAC,CAAC;EAClEF,MAAM,eAAET,YAAY,CAACM,SAAS,CAAEK,IAAI,IAAKE,kBAAkB,CAACF,IAAI,CAAC;CAClE,CAAC,CACH;AAED;AACA,MAAMG,cAAc,GACjBC,GAAW,IACsBC,MAAS,IACzCA,MAAM,CAACZ,IAAI,CACTL,MAAM,CAACM,MAAM,CAAC;EACZA,MAAM,EAAEL,YAAY,CAACM,SAAS,CAAEW,KAAK,IAAKnB,MAAM,CAACoB,GAAG,CAACD,KAAK,EAAEF,GAAG,CAAC,CAAC;EACjEN,MAAM,EAAET,YAAY,CAACM,SAAS,CAAEW,KAAK,IAAKnB,MAAM,CAACoB,GAAG,CAACD,KAAK,EAAEF,GAAG,CAAC;CACjE,CAAC,CACH;AAEL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,OAAO,MAAMI,iBAAiB,gBAAGL,cAAc,CAAC,EAAE,CAAC;AA8BnD;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,OAAO,MAAMM,IAAI,GAAGA,CAIlBJ,MAA6B,EAC7B,GAAGK,IAAU,KAEbL,MAAM,CAACM,SAAS,CACbC,MAAM,IACLtB,MAAM,CAACmB,IAAI,CAACG,MAAM,EAAEF,IAAiC,CAGpD,CACJ;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,OAAO,MAAMG,IAAI,GAAGA,CAIlBR,MAA6B,EAC7B,GAAGK,IAAU,KAEbL,MAAM,CAACM,SAAS,CACbC,MAAM,IACLtB,MAAM,CAACuB,IAAI,CAACD,MAAM,EAAEF,IAAiC,CAGpD,CACJ;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,OAAO,MAAMI,OAAO,GAClBT,MAA6B,IAE7BA,MAAM,CAACM,SAAS,CAAEC,MAAM,IAAI;EAC1B,MAAMG,MAAM,GAAyD,EAAE;EACvE,KAAK,MAAMC,GAAG,IAAIC,MAAM,CAACP,IAAI,CAACE,MAAM,CAAqB,EAAE;IACzDG,MAAM,CAACC,GAAG,CAAC,GAAG5B,MAAM,CAAC8B,QAAQ,CAACN,MAAM,CAACI,GAAG,CAAC,CAAC;EAC5C;EACA,OAAOD,MAA6D;AACtE,CAAC,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,OAAO,MAAMI,WAAW,GAAGA,CAIzBd,MAA6B,EAC7B,GAAGK,IAAU,KAEbI,OAAO,CAACL,IAAI,CAACJ,MAAM,EAAE,GAAGK,IAAI,CAAC,CAAC","ignoreList":[]}
package/dist/SetX.d.ts ADDED
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Runs a mutating function against a copy of `set`, leaving the original
3
+ * untouched, and returns the mutated copy.
4
+ *
5
+ * Use it to reuse imperative `Set` mutation code (`.add`, `.delete`) without
6
+ * sacrificing immutability: the callback may freely mutate the set it receives
7
+ * because it operates on a fresh clone. Supports both data-first and data-last
8
+ * (pipeable) call styles.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { SetX } from "@nunofyobiz/effect-extras"
13
+ * import { pipe } from "effect"
14
+ *
15
+ * const original = new Set(["a", "b"])
16
+ *
17
+ * const result = pipe(
18
+ * original,
19
+ * SetX.safelyMutate((set) => {
20
+ * set.delete("a")
21
+ * return set.add("c")
22
+ * })
23
+ * )
24
+ *
25
+ * assert.deepStrictEqual(result, new Set(["b", "c"]))
26
+ * // The original is left intact
27
+ * assert.deepStrictEqual(original, new Set(["a", "b"]))
28
+ * ```
29
+ *
30
+ * @category combinators
31
+ * @since 0.0.0
32
+ */
33
+ export declare const safelyMutate: (<A>(mutate: (set: Set<A>) => Set<A>) => (set: Set<A>) => Set<A>) & (<A>(set: Set<A>, mutate: (set: Set<A>) => Set<A>) => Set<A>);
34
+ /**
35
+ * Returns a new `Set` with `value` added, leaving the input set unchanged.
36
+ *
37
+ * When `value` is already present the input set is returned as-is (no copy),
38
+ * making repeated adds of existing members allocation-free. Supports both
39
+ * data-first and data-last (pipeable) call styles.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { SetX } from "@nunofyobiz/effect-extras"
44
+ * import { pipe } from "effect"
45
+ *
46
+ * // Data-first — adds a new element into a fresh set
47
+ * assert.deepStrictEqual(
48
+ * SetX.add(new Set(["a", "b"]), "c"),
49
+ * new Set(["a", "b", "c"])
50
+ * )
51
+ *
52
+ * // Data-last — existing element leaves the set unchanged
53
+ * assert.deepStrictEqual(
54
+ * pipe(new Set(["a", "b"]), SetX.add("b")),
55
+ * new Set(["a", "b"])
56
+ * )
57
+ * ```
58
+ *
59
+ * @category combinators
60
+ * @since 0.0.0
61
+ */
62
+ export declare const add: (<A>(value: A) => (set: Set<A>) => Set<A>) & (<A>(set: Set<A>, value: A) => Set<A>);
63
+ /**
64
+ * Returns a new `Set` with `value` removed, leaving the input set unchanged.
65
+ *
66
+ * When `value` is absent the input set is returned as-is (no copy). Supports both
67
+ * data-first and data-last (pipeable) call styles.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { SetX } from "@nunofyobiz/effect-extras"
72
+ * import { pipe } from "effect"
73
+ *
74
+ * // Data-first — removes an existing element into a fresh set
75
+ * assert.deepStrictEqual(
76
+ * SetX.remove(new Set(["a", "b", "c"]), "c"),
77
+ * new Set(["a", "b"])
78
+ * )
79
+ *
80
+ * // Data-last — absent element leaves the set unchanged
81
+ * assert.deepStrictEqual(
82
+ * pipe(new Set(["a", "b"]), SetX.remove("z")),
83
+ * new Set(["a", "b"])
84
+ * )
85
+ * ```
86
+ *
87
+ * @category combinators
88
+ * @since 0.0.0
89
+ */
90
+ export declare const remove: (<A>(value: A) => (set: Set<A>) => Set<A>) & (<A>(set: Set<A>, value: A) => Set<A>);
91
+ /**
92
+ * Returns a new `Set` with `value` added if it was absent or removed if it was
93
+ * present, leaving the input set unchanged.
94
+ *
95
+ * Use it for membership toggles (selection state, feature flags by key) where a
96
+ * value's presence should flip on each call. Supports both data-first and
97
+ * data-last (pipeable) call styles.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * import { SetX } from "@nunofyobiz/effect-extras"
102
+ * import { pipe } from "effect"
103
+ *
104
+ * // Data-first — absent value gets added
105
+ * assert.deepStrictEqual(
106
+ * SetX.toggle(new Set(["a", "b"]), "c"),
107
+ * new Set(["a", "b", "c"])
108
+ * )
109
+ *
110
+ * // Data-last — present value gets removed
111
+ * assert.deepStrictEqual(
112
+ * pipe(new Set(["a", "b", "c"]), SetX.toggle("b")),
113
+ * new Set(["a", "c"])
114
+ * )
115
+ * ```
116
+ *
117
+ * @category combinators
118
+ * @since 0.0.0
119
+ */
120
+ export declare const toggle: (<A>(value: A) => (set: Set<A>) => Set<A>) & (<A>(set: Set<A>, value: A) => Set<A>);
121
+ //# sourceMappingURL=SetX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetX.d.ts","sourceRoot":"","sources":["../src/SetX.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,YAAY,IACtB,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MAC9D,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAI3D,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,GAAG,IACb,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MACvC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAKrC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,MAAM,IAChB,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MACvC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAQpC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,MAAM,IAChB,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,MACvC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAKrC,CAAC"}