@typed/guard 0.6.0 → 0.7.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/.nvmrc +1 -0
- package/biome.json +36 -0
- package/dist/ExtensibleFunction.d.ts +1 -0
- package/dist/ExtensibleFunction.js +7 -0
- package/dist/ExtensibleFunction.js.map +1 -0
- package/dist/Guard.d.ts +143 -0
- package/dist/{esm/index.js → Guard.js} +32 -107
- package/dist/Guard.js.map +1 -0
- package/dist/Guardable.d.ts +10 -0
- package/dist/Guardable.js +13 -0
- package/dist/Guardable.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/package.json +28 -21
- package/readme.md +197 -0
- package/src/ExtensibleFunction.test.ts +104 -0
- package/src/ExtensibleFunction.ts +8 -0
- package/src/Guard.test.ts +189 -0
- package/src/Guard.ts +536 -0
- package/src/Guardable.test.ts +18 -0
- package/src/Guardable.ts +21 -0
- package/src/index.ts +3 -494
- package/tsconfig.json +27 -0
- package/LICENSE +0 -21
- package/README.md +0 -5
- package/dist/cjs/index.js +0 -199
- package/dist/cjs/index.js.map +0 -1
- package/dist/dts/index.d.ts +0 -254
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/package.json +0 -4
package/src/Guard.ts
ADDED
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Cause,
|
|
3
|
+
type Context,
|
|
4
|
+
Effect,
|
|
5
|
+
type Layer,
|
|
6
|
+
Option,
|
|
7
|
+
Pipeable,
|
|
8
|
+
type Predicate,
|
|
9
|
+
type Runtime,
|
|
10
|
+
Schema,
|
|
11
|
+
} from 'effect'
|
|
12
|
+
import { dual } from 'effect/Function'
|
|
13
|
+
import type { ParseOptions } from 'effect/SchemaAST'
|
|
14
|
+
|
|
15
|
+
export type Guard<I, O = never, E = never, R = never> = (
|
|
16
|
+
input: I,
|
|
17
|
+
) => Effect.Effect<Option.Option<O>, E, R> | Effect.Effect<never, E, R>
|
|
18
|
+
|
|
19
|
+
export namespace Guard {
|
|
20
|
+
export type Input<T> = [T] extends [Guard<infer I, infer _R, infer _E, infer _O>] ? I : never
|
|
21
|
+
|
|
22
|
+
export type Output<T> = [T] extends [Guard<infer _I, infer O, infer _E, infer _R>] ? O : never
|
|
23
|
+
|
|
24
|
+
export type Error<T> = [T] extends [Guard<infer _I, infer _O, infer E, infer _R>] ? E : never
|
|
25
|
+
|
|
26
|
+
export type Context<T> = [T] extends [Guard<infer _I, infer _O, infer _E, infer R>] ? R : never
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const identity: <A>(a: A) => Effect.Effect<Option.Option<A>> = Effect.succeedSome
|
|
30
|
+
|
|
31
|
+
export const compose: {
|
|
32
|
+
<O, B, E2, R2>(
|
|
33
|
+
output: Guard<O, B, E2, R2>,
|
|
34
|
+
): <I, R, E>(input: Guard<I, O, E, R>) => Guard<I, B, E | E2, R | R2>
|
|
35
|
+
<I, O, E, R, B, E2, R2>(
|
|
36
|
+
input: Guard<I, O, E, R>,
|
|
37
|
+
output: Guard<O, B, E2, R2>,
|
|
38
|
+
): Guard<I, B, E | E2, R | R2>
|
|
39
|
+
} = dual(2, function flatMap<
|
|
40
|
+
I,
|
|
41
|
+
O,
|
|
42
|
+
E,
|
|
43
|
+
R,
|
|
44
|
+
B,
|
|
45
|
+
E2,
|
|
46
|
+
R2,
|
|
47
|
+
>(input: Guard<I, O, E, R>, output: Guard<O, B, E2, R2>): Guard<I, B, E | E2, R | R2> {
|
|
48
|
+
return (i) =>
|
|
49
|
+
Effect.flatMap(
|
|
50
|
+
input(i),
|
|
51
|
+
Option.match({
|
|
52
|
+
onNone: () => Effect.succeedNone,
|
|
53
|
+
onSome: output,
|
|
54
|
+
}),
|
|
55
|
+
)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
export const mapEffect: {
|
|
59
|
+
<O, B, E2, R2>(
|
|
60
|
+
f: (o: O) => Effect.Effect<B, E2, R2>,
|
|
61
|
+
): <I, R, E>(guard: Guard<I, O, E, R>) => Guard<I, B, E | E2, R | R2>
|
|
62
|
+
<I, O, E, R, B, E2, R2>(
|
|
63
|
+
guard: Guard<I, O, E, R>,
|
|
64
|
+
f: (o: O) => Effect.Effect<B, E2, R2>,
|
|
65
|
+
): Guard<I, B, E | E2, R | R2>
|
|
66
|
+
} = dual(2, function mapEffect<
|
|
67
|
+
I,
|
|
68
|
+
O,
|
|
69
|
+
E,
|
|
70
|
+
R,
|
|
71
|
+
B,
|
|
72
|
+
E2,
|
|
73
|
+
R2,
|
|
74
|
+
>(guard: Guard<I, O, E, R>, f: (o: O) => Effect.Effect<B, E2, R2>): Guard<I, B, E | E2, R | R2> {
|
|
75
|
+
return compose(guard, (o) => Effect.asSome(f(o)))
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
export const map: {
|
|
79
|
+
<O, B>(f: (o: O) => B): <I, R, E>(guard: Guard<I, O, E, R>) => Guard<I, B, E, R>
|
|
80
|
+
<I, O, E, R, B>(guard: Guard<I, O, E, R>, f: (o: O) => B): Guard<I, B, E, R>
|
|
81
|
+
} = dual(2, function map<I, O, E, R, B>(guard: Guard<I, O, E, R>, f: (o: O) => B): Guard<
|
|
82
|
+
I,
|
|
83
|
+
B,
|
|
84
|
+
E,
|
|
85
|
+
R
|
|
86
|
+
> {
|
|
87
|
+
return mapEffect(guard, (o) => Effect.sync(() => f(o)))
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
export const tap: {
|
|
91
|
+
<O, B, E2, R2>(
|
|
92
|
+
f: (o: O) => Effect.Effect<B, E2, R2>,
|
|
93
|
+
): <I, R, E>(guard: Guard<I, O, E, R>) => Guard<I, O, E | E2, R | R2>
|
|
94
|
+
<I, O, E, R, B, E2, R2>(
|
|
95
|
+
guard: Guard<I, O, E, R>,
|
|
96
|
+
f: (o: O) => Effect.Effect<B, E2, R2>,
|
|
97
|
+
): Guard<I, O, E | E2, R | R2>
|
|
98
|
+
} = dual(2, function tap<
|
|
99
|
+
I,
|
|
100
|
+
O,
|
|
101
|
+
E,
|
|
102
|
+
R,
|
|
103
|
+
B,
|
|
104
|
+
E2,
|
|
105
|
+
R2,
|
|
106
|
+
>(guard: Guard<I, O, E, R>, f: (o: O) => Effect.Effect<B, E2, R2>): Guard<I, O, E | E2, R | R2> {
|
|
107
|
+
return compose(guard, (o) => Effect.as(f(o), Option.some(o)))
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
export const filterMap: {
|
|
111
|
+
<O, B>(f: (o: O) => Option.Option<B>): <I, R, E>(guard: Guard<I, O, E, R>) => Guard<I, B, E, R>
|
|
112
|
+
<I, O, E, R, B>(guard: Guard<I, O, E, R>, f: (o: O) => Option.Option<B>): Guard<I, B, E, R>
|
|
113
|
+
} = dual(
|
|
114
|
+
2,
|
|
115
|
+
<I, O, E, R, B>(guard: Guard<I, O, E, R>, f: (o: O) => Option.Option<B>): Guard<I, B, E, R> => {
|
|
116
|
+
return (i) => Effect.map(guard(i), Option.filterMap(f))
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
export const filter: {
|
|
121
|
+
<O, O2 extends O>(
|
|
122
|
+
predicate: (o: O) => o is O2,
|
|
123
|
+
): <I, R, E>(guard: Guard<I, O, E, R>) => Guard<I, O, E, R>
|
|
124
|
+
<O>(predicate: (o: O) => boolean): <I, R, E>(guard: Guard<I, O, E, R>) => Guard<I, O, E, R>
|
|
125
|
+
<I, O, E, R, O2 extends O>(
|
|
126
|
+
guard: Guard<I, O, E, R>,
|
|
127
|
+
predicate: (o: O) => o is O2,
|
|
128
|
+
): Guard<I, O, E, R>
|
|
129
|
+
<I, O, E, R>(guard: Guard<I, O, E, R>, predicate: (o: O) => boolean): Guard<I, O, E, R>
|
|
130
|
+
} = dual(
|
|
131
|
+
2,
|
|
132
|
+
<I, O, E, R>(guard: Guard<I, O, E, R>, predicate: (o: O) => boolean): Guard<I, O, E, R> => {
|
|
133
|
+
return (i) => Effect.map(guard(i), Option.filter(predicate))
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
export function any<const GS extends Readonly<Record<string, Guard<any, any, any, any>>>>(
|
|
138
|
+
guards: GS,
|
|
139
|
+
): Guard<AnyInput<GS>, AnyOutput<GS>, Guard.Error<GS[keyof GS]>, Guard.Context<GS[keyof GS]>> {
|
|
140
|
+
return (i: AnyInput<GS>) =>
|
|
141
|
+
Effect.gen(function* () {
|
|
142
|
+
for (const [_tag, guard] of Object.entries(guards)) {
|
|
143
|
+
const match = yield* guard(i)
|
|
144
|
+
if (Option.isSome(match)) {
|
|
145
|
+
return Option.some({ _tag, value: match.value } as AnyOutput<GS>)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return Option.none()
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type AnyInput<GS extends Readonly<Record<string, Guard<any, any, any, any>>>> = Guard.Input<
|
|
153
|
+
GS[keyof GS]
|
|
154
|
+
>
|
|
155
|
+
|
|
156
|
+
export type AnyOutput<GS extends Readonly<Record<string, Guard<any, any, any, any>>>> = [
|
|
157
|
+
{
|
|
158
|
+
[K in keyof GS]: { readonly _tag: K; readonly value: Guard.Output<GS[K]> }
|
|
159
|
+
}[keyof GS],
|
|
160
|
+
] extends [infer R]
|
|
161
|
+
? R
|
|
162
|
+
: never
|
|
163
|
+
|
|
164
|
+
export function liftPredicate<A, B extends A>(predicate: Predicate.Refinement<A, B>): Guard<A, B>
|
|
165
|
+
export function liftPredicate<A>(predicate: Predicate.Predicate<A>): Guard<A, A>
|
|
166
|
+
export function liftPredicate<A>(predicate: Predicate.Predicate<A>): Guard<A, A> {
|
|
167
|
+
return (a) => Effect.sync(() => (predicate(a) ? Option.some(a) : Option.none()))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export const catchAllCause: {
|
|
171
|
+
<E = never, O2 = never, E2 = never, R2 = never>(
|
|
172
|
+
f: (e: Cause.Cause<E>) => Effect.Effect<O2, E2, R2>,
|
|
173
|
+
): <I = never, O = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O | O2, E2, R | R2>
|
|
174
|
+
<I = never, O = never, E = never, R = never, O2 = never, E2 = never, R2 = never>(
|
|
175
|
+
guard: Guard<I, O, E, R>,
|
|
176
|
+
f: (e: Cause.Cause<E>) => Effect.Effect<O2, E2, R2>,
|
|
177
|
+
): Guard<I, O | O2, E2, R | R2>
|
|
178
|
+
} = dual(2, function catchAllCause<
|
|
179
|
+
I,
|
|
180
|
+
O,
|
|
181
|
+
E,
|
|
182
|
+
R,
|
|
183
|
+
O2,
|
|
184
|
+
E2,
|
|
185
|
+
R2,
|
|
186
|
+
>(guard: Guard<I, O, E, R>, f: (e: Cause.Cause<E>) => Effect.Effect<O2, E2, R2>): Guard<
|
|
187
|
+
I,
|
|
188
|
+
O | O2,
|
|
189
|
+
E2,
|
|
190
|
+
R | R2
|
|
191
|
+
> {
|
|
192
|
+
return (i) => Effect.catchAllCause(guard(i), (a) => Effect.asSome(f(a)))
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
export const catchAll: {
|
|
196
|
+
<E = never, O2 = never, E2 = never, R2 = never>(
|
|
197
|
+
f: (e: E) => Effect.Effect<O2, E2, R2>,
|
|
198
|
+
): <I = never, O = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O | O2, E2, R | R2>
|
|
199
|
+
<I = never, O = never, E = never, R = never, O2 = never, E2 = never, R2 = never>(
|
|
200
|
+
guard: Guard<I, O, E, R>,
|
|
201
|
+
f: (e: E) => Effect.Effect<O2, E2, R2>,
|
|
202
|
+
): Guard<I, O | O2, E2, R | R2>
|
|
203
|
+
} = dual(2, function catchAll<
|
|
204
|
+
I,
|
|
205
|
+
O,
|
|
206
|
+
E,
|
|
207
|
+
R,
|
|
208
|
+
O2,
|
|
209
|
+
E2,
|
|
210
|
+
R2,
|
|
211
|
+
>(guard: Guard<I, O, E, R>, f: (e: E) => Effect.Effect<O2, E2, R2>): Guard<I, O | O2, E2, R | R2> {
|
|
212
|
+
return (i) => Effect.catchAll(guard(i), (a) => Effect.asSome(f(a)))
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
export const catchTag: {
|
|
216
|
+
<
|
|
217
|
+
E = never,
|
|
218
|
+
K extends E extends { _tag: string } ? E['_tag'] : never = never,
|
|
219
|
+
O2 = never,
|
|
220
|
+
E2 = never,
|
|
221
|
+
R2 = never,
|
|
222
|
+
>(
|
|
223
|
+
tag: K,
|
|
224
|
+
f: (e: Extract<E, { _tag: K }>) => Effect.Effect<O2, E2, R2>,
|
|
225
|
+
): <I = never, O = never, R = never>(
|
|
226
|
+
guard: Guard<I, O, E, R>,
|
|
227
|
+
) => Guard<I, O | O2, E2 | Exclude<E, { _tag: K }>, R | R2>
|
|
228
|
+
|
|
229
|
+
<
|
|
230
|
+
I = never,
|
|
231
|
+
O = never,
|
|
232
|
+
E = never,
|
|
233
|
+
R = never,
|
|
234
|
+
K extends E extends { _tag: string } ? E['_tag'] : never = never,
|
|
235
|
+
O2 = never,
|
|
236
|
+
E2 = never,
|
|
237
|
+
R2 = never,
|
|
238
|
+
>(
|
|
239
|
+
guard: Guard<I, O, E, R>,
|
|
240
|
+
tag: K,
|
|
241
|
+
f: (e: Extract<E, { _tag: K }>) => Effect.Effect<O2, E2, R2>,
|
|
242
|
+
): Guard<I, O | O2, E2 | Exclude<E, { _tag: K }>, R | R2>
|
|
243
|
+
} = dual(3, function catchTag<
|
|
244
|
+
I,
|
|
245
|
+
O,
|
|
246
|
+
E,
|
|
247
|
+
R,
|
|
248
|
+
K extends E extends { _tag: string } ? E['_tag'] : never,
|
|
249
|
+
O2,
|
|
250
|
+
E2,
|
|
251
|
+
R2,
|
|
252
|
+
>(guard: Guard<I, O, E, R>, tag: K, f: (e: Extract<E, { _tag: K }>) => Effect.Effect<O2, E2, R2>): Guard<
|
|
253
|
+
I,
|
|
254
|
+
O | O2,
|
|
255
|
+
Exclude<E, { _tag: K }> | E2,
|
|
256
|
+
R | R2
|
|
257
|
+
> {
|
|
258
|
+
return (i) => Effect.catchTag(guard(i), tag, (e) => Effect.asSome(f(e)))
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
export const provide: {
|
|
262
|
+
<R2>(
|
|
263
|
+
provided: Context.Context<R2>,
|
|
264
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, O, E, Exclude<R, R2>>
|
|
265
|
+
<R2>(
|
|
266
|
+
provided: Runtime.Runtime<R2>,
|
|
267
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, O, E, Exclude<R, R2>>
|
|
268
|
+
<R2, E2, R3>(
|
|
269
|
+
provided: Layer.Layer<R2, E2, R3>,
|
|
270
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, O, E | E2, Exclude<R, R2> | R3>
|
|
271
|
+
|
|
272
|
+
<I, O, E, R, R2>(
|
|
273
|
+
guard: Guard<I, O, E, R>,
|
|
274
|
+
provided: Context.Context<R2>,
|
|
275
|
+
): Guard<I, O, E, Exclude<R, R2>>
|
|
276
|
+
<I, O, E, R, R2>(
|
|
277
|
+
guard: Guard<I, O, E, R>,
|
|
278
|
+
provided: Runtime.Runtime<R2>,
|
|
279
|
+
): Guard<I, O, E, Exclude<R, R2>>
|
|
280
|
+
<I, O, E, R, R2, E2, R3>(
|
|
281
|
+
guard: Guard<I, O, E, R>,
|
|
282
|
+
provided: Layer.Layer<R2, E2, R3>,
|
|
283
|
+
): Guard<I, O, E | E2, Exclude<R, R2> | R3>
|
|
284
|
+
} = dual(2, function provide<
|
|
285
|
+
I,
|
|
286
|
+
O,
|
|
287
|
+
E,
|
|
288
|
+
R,
|
|
289
|
+
R2,
|
|
290
|
+
>(guard: Guard<I, O, E, R>, provided: Context.Context<R2>): Guard<I, O, E, Exclude<R, R2>> {
|
|
291
|
+
return (i) => Effect.provide(guard(i), provided)
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
export const provideService: {
|
|
295
|
+
<Id, S>(
|
|
296
|
+
tag: Context.Tag<Id, S>,
|
|
297
|
+
service: S,
|
|
298
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, O, E, Exclude<R, Id>>
|
|
299
|
+
<I, O, E, R, Id, S>(
|
|
300
|
+
guard: Guard<I, O, E, R>,
|
|
301
|
+
tag: Context.Tag<Id, S>,
|
|
302
|
+
service: S,
|
|
303
|
+
): Guard<I, O, E, Exclude<R, Id>>
|
|
304
|
+
} = dual(3, function provideService<
|
|
305
|
+
I,
|
|
306
|
+
O,
|
|
307
|
+
E,
|
|
308
|
+
R,
|
|
309
|
+
Id,
|
|
310
|
+
S,
|
|
311
|
+
>(guard: Guard<I, O, E, R>, tag: Context.Tag<Id, S>, service: S): Guard<I, O, E, Exclude<R, Id>> {
|
|
312
|
+
return (i) => Effect.provideService(guard(i), tag, service)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
export const provideServiceEffect: {
|
|
316
|
+
<Id, S, E2, R2>(
|
|
317
|
+
tag: Context.Tag<Id, S>,
|
|
318
|
+
service: Effect.Effect<S, E2, R2>,
|
|
319
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, O, E | E2, Exclude<R, Id> | R2>
|
|
320
|
+
<I, O, E, R, Id, S, E2, R2>(
|
|
321
|
+
guard: Guard<I, O, E, R>,
|
|
322
|
+
tag: Context.Tag<Id, S>,
|
|
323
|
+
service: Effect.Effect<S, E2, R2>,
|
|
324
|
+
): Guard<I, O, E | E2, Exclude<R, Id> | R2>
|
|
325
|
+
} = dual(3, function provideServiceEffect<
|
|
326
|
+
I,
|
|
327
|
+
O,
|
|
328
|
+
E,
|
|
329
|
+
R,
|
|
330
|
+
Id,
|
|
331
|
+
S,
|
|
332
|
+
E2,
|
|
333
|
+
R2,
|
|
334
|
+
>(guard: Guard<I, O, E, R>, tag: Context.Tag<Id, S>, service: Effect.Effect<S, E2, R2>): Guard<
|
|
335
|
+
I,
|
|
336
|
+
O,
|
|
337
|
+
E | E2,
|
|
338
|
+
Exclude<R, Id> | R2
|
|
339
|
+
> {
|
|
340
|
+
return (i) => Effect.provideServiceEffect(guard(i), tag, service)
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
const parseOptions: ParseOptions = { errors: 'all', onExcessProperty: 'ignore' }
|
|
344
|
+
|
|
345
|
+
export function fromSchemaDecode<A, I, R>(schema: Schema.Schema<A, I, R>): Guard<I, A, never, R> {
|
|
346
|
+
const decode_ = Schema.decode(schema)
|
|
347
|
+
return (i: I) =>
|
|
348
|
+
decode_(i, parseOptions).pipe(
|
|
349
|
+
Effect.asSome,
|
|
350
|
+
Effect.catchTag('ParseError', (e) => Effect.succeedNone),
|
|
351
|
+
)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function fromSchemaDecodeUnknown<A, I, R>(
|
|
355
|
+
schema: Schema.Schema<A, I, R>,
|
|
356
|
+
): Guard<unknown, A, never, R> {
|
|
357
|
+
const decode_ = Schema.decodeUnknown(schema)
|
|
358
|
+
return (i: unknown) =>
|
|
359
|
+
decode_(i, parseOptions).pipe(
|
|
360
|
+
Effect.asSome,
|
|
361
|
+
Effect.catchTag('ParseError', () => Effect.succeedNone),
|
|
362
|
+
)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function fromSchemaEncode<A, I, R>(schema: Schema.Schema<A, I, R>): Guard<A, I, never, R> {
|
|
366
|
+
const encode_ = Schema.encode(schema)
|
|
367
|
+
return (a: A) =>
|
|
368
|
+
encode_(a, parseOptions).pipe(
|
|
369
|
+
Effect.asSome,
|
|
370
|
+
Effect.catchTag('ParseError', () => Effect.succeedNone),
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export const decode: {
|
|
375
|
+
<A, O, R2>(
|
|
376
|
+
schema: Schema.Schema<A, O, R2>,
|
|
377
|
+
): <I, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, A, E, R | R2>
|
|
378
|
+
|
|
379
|
+
<I, O, E, R, A, R2>(
|
|
380
|
+
guard: Guard<I, O, E, R>,
|
|
381
|
+
schema: Schema.Schema<A, O, R2>,
|
|
382
|
+
): Guard<I, A, E, R | R2>
|
|
383
|
+
} = dual(2, function decode<
|
|
384
|
+
I,
|
|
385
|
+
O,
|
|
386
|
+
E,
|
|
387
|
+
R,
|
|
388
|
+
A,
|
|
389
|
+
R2,
|
|
390
|
+
>(guard: Guard<I, O, E, R>, schema: Schema.Schema<A, O, R2>): Guard<I, A, E, R | R2> {
|
|
391
|
+
return compose(guard, fromSchemaDecode(schema))
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
export const encode: {
|
|
395
|
+
<O, A, R2>(
|
|
396
|
+
schema: Schema.Schema<O, A, R2>,
|
|
397
|
+
): <I, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, A, E, R | R2>
|
|
398
|
+
|
|
399
|
+
<I, O, E, R, A, R2>(
|
|
400
|
+
guard: Guard<I, O, E, R>,
|
|
401
|
+
schema: Schema.Schema<O, A, R2>,
|
|
402
|
+
): Guard<I, A, E, R | R2>
|
|
403
|
+
} = dual(2, function encode<
|
|
404
|
+
I,
|
|
405
|
+
O,
|
|
406
|
+
E,
|
|
407
|
+
R,
|
|
408
|
+
A,
|
|
409
|
+
R2,
|
|
410
|
+
>(guard: Guard<I, O, E, R>, schema: Schema.Schema<O, A, R2>): Guard<I, A, E, R | R2> {
|
|
411
|
+
return compose(guard, fromSchemaEncode(schema))
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
const let_: {
|
|
415
|
+
<O, K extends PropertyKey, B>(
|
|
416
|
+
key: K,
|
|
417
|
+
value: (o: O) => B,
|
|
418
|
+
): <I, E = never, R = never>(guard: Guard<I, O, E, R>) => Guard<I, O & { [k in K]: B }, E, R>
|
|
419
|
+
|
|
420
|
+
<I, O, E, R, K extends PropertyKey, B>(
|
|
421
|
+
guard: Guard<I, O, E, R>,
|
|
422
|
+
key: K,
|
|
423
|
+
value: (o: O) => B,
|
|
424
|
+
): Guard<I, O & { [k in K]: B }, E, R>
|
|
425
|
+
} = dual(3, function let_<
|
|
426
|
+
I,
|
|
427
|
+
O,
|
|
428
|
+
E,
|
|
429
|
+
R,
|
|
430
|
+
K extends PropertyKey,
|
|
431
|
+
B,
|
|
432
|
+
>(guard: Guard<I, O, E, R>, key: K, value: (o: O) => B): Guard<I, O & { [k in K]: B }, E, R> {
|
|
433
|
+
return map(guard, (a) => ({ ...a, [key]: value(a) }) as O & { [k in K]: B })
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
export { let_ as let }
|
|
437
|
+
|
|
438
|
+
export const attachProperty: {
|
|
439
|
+
<K extends PropertyKey, B>(
|
|
440
|
+
key: K,
|
|
441
|
+
value: B,
|
|
442
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, O & { readonly [k in K]: B }, E, R>
|
|
443
|
+
|
|
444
|
+
<I, O, E, R, K extends PropertyKey, B>(
|
|
445
|
+
guard: Guard<I, O, E, R>,
|
|
446
|
+
key: K,
|
|
447
|
+
value: B,
|
|
448
|
+
): Guard<I, O & { readonly [k in K]: B }, E, R>
|
|
449
|
+
} = dual(3, function attachProperty<
|
|
450
|
+
I,
|
|
451
|
+
O,
|
|
452
|
+
E,
|
|
453
|
+
R,
|
|
454
|
+
K extends PropertyKey,
|
|
455
|
+
B,
|
|
456
|
+
>(guard: Guard<I, O, E, R>, key: K, value: B): Guard<I, O & { readonly [k in K]: B }, E, R> {
|
|
457
|
+
return map(guard, (a) => ({ ...a, [key]: value }) as O & { readonly [k in K]: B })
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
export const addTag: {
|
|
461
|
+
<B>(
|
|
462
|
+
value: B,
|
|
463
|
+
): <I, O, E = never, R = never>(
|
|
464
|
+
guard: Guard<I, O, E, R>,
|
|
465
|
+
) => Guard<I, O & { readonly _tag: B }, E, R>
|
|
466
|
+
|
|
467
|
+
<I, O, E, R, B>(guard: Guard<I, O, E, R>, value: B): Guard<I, O & { readonly _tag: B }, E, R>
|
|
468
|
+
} = dual(2, function addTag<I, O, E, R, B>(guard: Guard<I, O, E, R>, value: B): Guard<
|
|
469
|
+
I,
|
|
470
|
+
O & { readonly _tag: B },
|
|
471
|
+
E,
|
|
472
|
+
R
|
|
473
|
+
> {
|
|
474
|
+
return map(guard, (a) => ({ ...a, _tag: value }) as O & { readonly _tag: B })
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
export const bindTo: {
|
|
478
|
+
<K extends PropertyKey>(
|
|
479
|
+
key: K,
|
|
480
|
+
): <I, O, E, R>(guard: Guard<I, O, E, R>) => Guard<I, { [k in K]: O }, E, R>
|
|
481
|
+
<I, O, E, R, K extends PropertyKey>(
|
|
482
|
+
guard: Guard<I, O, E, R>,
|
|
483
|
+
key: K,
|
|
484
|
+
): Guard<I, { [k in K]: O }, E, R>
|
|
485
|
+
} = dual(
|
|
486
|
+
2,
|
|
487
|
+
<I, O, E, R, K extends PropertyKey>(
|
|
488
|
+
guard: Guard<I, O, E, R>,
|
|
489
|
+
key: K,
|
|
490
|
+
): Guard<I, { [k in K]: O }, E, R> => map(guard, (a) => ({ [key]: a }) as { [k in K]: O }),
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
export const bind: {
|
|
494
|
+
<I, O, E, R, K extends PropertyKey, B, E2, R2>(
|
|
495
|
+
key: K,
|
|
496
|
+
f: Guard<O, B, E2, R2>,
|
|
497
|
+
): (guard: Guard<I, O, E, R>) => Guard<I, O & { [k in K]: B }, E | E2, R | R2>
|
|
498
|
+
|
|
499
|
+
<I, O, E, R, K extends PropertyKey, B, E2, R2>(
|
|
500
|
+
guard: Guard<I, O, E, R>,
|
|
501
|
+
key: K,
|
|
502
|
+
f: Guard<O, B, E2, R2>,
|
|
503
|
+
): Guard<I, O & { [k in K]: B }, E | E2, R | R2>
|
|
504
|
+
} = dual(3, function bind<
|
|
505
|
+
I,
|
|
506
|
+
O,
|
|
507
|
+
E,
|
|
508
|
+
R,
|
|
509
|
+
K extends PropertyKey,
|
|
510
|
+
B,
|
|
511
|
+
E2,
|
|
512
|
+
R2,
|
|
513
|
+
>(guard: Guard<I, O, E, R>, key: K, f: Guard<O, B, E2, R2>): Guard<
|
|
514
|
+
I,
|
|
515
|
+
O & { [k in K]: B },
|
|
516
|
+
E | E2,
|
|
517
|
+
R | R2
|
|
518
|
+
> {
|
|
519
|
+
const f_ = bindTo(f, key)
|
|
520
|
+
|
|
521
|
+
return compose(guard, (o) =>
|
|
522
|
+
Effect.map(
|
|
523
|
+
f_(o),
|
|
524
|
+
Option.map((b) => ({ ...o, ...b })),
|
|
525
|
+
),
|
|
526
|
+
)
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
declare global {
|
|
530
|
+
interface Function extends Pipeable.Pipeable {}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
Function.prototype.pipe = function pipe() {
|
|
534
|
+
// biome-ignore lint/style/noArguments: This is a pipeable function
|
|
535
|
+
return Pipeable.pipeArguments(this, arguments)
|
|
536
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from '@effect/vitest'
|
|
2
|
+
import { Effect, Option } from 'effect'
|
|
3
|
+
import { Guardable, GUARDABLE } from './Guardable.js'
|
|
4
|
+
|
|
5
|
+
describe('Guardable', () => {
|
|
6
|
+
it('should be a Guard function', async () => {
|
|
7
|
+
class Test extends Guardable<number, number> {
|
|
8
|
+
constructor(readonly multiplier: number) {
|
|
9
|
+
super()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
[GUARDABLE] = (input: number) => Effect.succeedSome(input * this.multiplier)
|
|
13
|
+
}
|
|
14
|
+
const test = new Test(3)
|
|
15
|
+
|
|
16
|
+
expect(await Effect.runPromise(test(1))).toEqual(Option.some(3))
|
|
17
|
+
})
|
|
18
|
+
})
|
package/src/Guardable.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Pipeable } from 'effect'
|
|
2
|
+
import { ExtensibleFunction } from './ExtensibleFunction'
|
|
3
|
+
import type { Guard } from './Guard.js'
|
|
4
|
+
|
|
5
|
+
export const GUARDABLE = Symbol.for('@typed/guard/Guardable')
|
|
6
|
+
export type GUARDABLE = typeof GUARDABLE
|
|
7
|
+
|
|
8
|
+
export abstract class Guardable<I, O, E = never, R = never> extends ExtensibleFunction<
|
|
9
|
+
Guard<I, O, E, R>
|
|
10
|
+
> implements Pipeable.Pipeable {
|
|
11
|
+
constructor() {
|
|
12
|
+
super((input) => this[GUARDABLE](input))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
abstract readonly [GUARDABLE]: Guard<I, O, E, R>
|
|
16
|
+
|
|
17
|
+
pipe() {
|
|
18
|
+
// biome-ignore lint/style/noArguments: This is a pipeable function
|
|
19
|
+
return Pipeable.pipeArguments(this, arguments)
|
|
20
|
+
}
|
|
21
|
+
}
|