Skip to content

Commit 1f65c9a

Browse files
authored
Merge pull request #24 from mta-solutions/additional-vctx-functions
Add additional VCtx functions
2 parents fb8ffa4 + f5eb5b2 commit 1f65c9a

File tree

11 files changed

+418
-46
lines changed

11 files changed

+418
-46
lines changed

FSharp.Data.Validation.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Data.Validation.Gira
1515
EndProject
1616
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Data.Validation.Async", "src\FSharp.Data.Validation.Async\FSharp.Data.Validation.Async.fsproj", "{CF59CFDC-CE24-4F02-A454-2FE0CC1A9FA9}"
1717
EndProject
18+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.Data.Validation.Async.Tests", "tests\FSharp.Data.Validation.Async.Tests\FSharp.Data.Validation.Async.Tests.fsproj", "{0B92DFE3-181E-4713-B03F-B747D8D38187}"
19+
EndProject
1820
Global
1921
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2022
Debug|Any CPU = Debug|Any CPU
@@ -97,6 +99,18 @@ Global
9799
{CF59CFDC-CE24-4F02-A454-2FE0CC1A9FA9}.Release|x64.Build.0 = Release|Any CPU
98100
{CF59CFDC-CE24-4F02-A454-2FE0CC1A9FA9}.Release|x86.ActiveCfg = Release|Any CPU
99101
{CF59CFDC-CE24-4F02-A454-2FE0CC1A9FA9}.Release|x86.Build.0 = Release|Any CPU
102+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
103+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Debug|Any CPU.Build.0 = Debug|Any CPU
104+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Debug|x64.ActiveCfg = Debug|Any CPU
105+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Debug|x64.Build.0 = Debug|Any CPU
106+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Debug|x86.ActiveCfg = Debug|Any CPU
107+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Debug|x86.Build.0 = Debug|Any CPU
108+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Release|Any CPU.ActiveCfg = Release|Any CPU
109+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Release|Any CPU.Build.0 = Release|Any CPU
110+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Release|x64.ActiveCfg = Release|Any CPU
111+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Release|x64.Build.0 = Release|Any CPU
112+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Release|x86.ActiveCfg = Release|Any CPU
113+
{0B92DFE3-181E-4713-B03F-B747D8D38187}.Release|x86.Build.0 = Release|Any CPU
100114
EndGlobalSection
101115
GlobalSection(SolutionProperties) = preSolution
102116
HideSolutionNode = FALSE

README.md

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,21 +1069,10 @@ Here is an example of what it might look like.
10691069
### Validating Async Data
10701070

10711071
What if we need to validate data that is retrieved asynchronously?
1072-
There are three functions available in the `FSharp.Data.Validation.Async` package that can help with this:
1073-
1074-
- `bindToAsync`
1075-
- `bindAsync`
1076-
- `bindFromAsync`
1077-
1078-
The `bindToAsync` function is used to bind a value to an asynchronous computation.
1072+
There are multiple functions available in the `FSharp.Data.Validation.Async` package that can help with this.
1073+
For example, the `bindToAsync` function is used to bind a value to an asynchronous computation.
10791074
The value is passed to the computation and the result is returned.
10801075

1081-
The `bindAsync` function is used to bind an asynchronous computation to a value.
1082-
The computation is executed and the result is passed to the function.
1083-
1084-
The `bindFromAsync` function is used to bind an asynchronous computation to another asynchronous computation.
1085-
The first computation is executed and the result is passed to the second computation.
1086-
10871076
Let's say we have a function that retrieves a user's data from a database.
10881077
We want to validate the data before we use it.
10891078
We can use the `bindToAsync` function to bind the data to a validation computation.
@@ -1112,6 +1101,8 @@ The `getUserDataAndValidate` function retrieves the user data and validates it.
11121101
The `bindToAsync` function is used to bind the data to the validation computation.
11131102
The result is an asynchronous computation that returns the validated data.
11141103

1104+
See the `FSharp.Data.Validation.Async` documentation for more information on the available functions.
1105+
11151106
## Validation Operations
11161107

11171108
### `refute*` Operations
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# FSharp.Data.Validation.Async
2+
3+
## Description
4+
5+
This library provides a small set of functions that extend the `FSharp.Data.Validation` library to work with asynchronous workflows.
6+
7+
## Functions
8+
9+
- `bindToAsync: ('A -> Async<VCtx<'F, 'B>>) -> VCtx<'F, 'A> -> Async<VCtx<'F, 'B>>`
10+
- `bindAsync: ('A -> Async<VCtx<'F, 'B>>) -> Async<VCtx<'F, 'A>> -> Async<VCtx<'F, 'B>>`
11+
- `bindFromAsync: ('A -> VCtx<'F, 'B>) -> Async<VCtx<'F, 'A>> -> Async<VCtx<'F, 'B>>`
12+
- `combineAsync: Async<VCtx<'F, 'A>> -> Async<VCtx<'F, 'B>> -> Async<VCtx<'F, 'A * 'B>>`
13+
- `bindAndMergeSourcesAsync: ('A -> Async<VCtx<'F, 'B>>) -> Async<VCtx<'F, 'A>> -> Async<VCtx<'F, 'A * 'B>>`
14+
- `bindToAndMergeSourcesAsync: ('A -> Async<VCtx<'F, 'B>>) -> VCtx<'F, 'A> -> Async<VCtx<'F, 'A * 'B>>`
15+
- `bindFromAndMergeSourcesAsync: ('A -> VCtx<'F, 'B>) -> Async<VCtx<'F, 'A>> -> Async<VCtx<'F, 'A * 'B>>`
16+
- `mapAsync: ('A -> Async<'B>) -> VCtx<'F, 'A> -> Async<VCtx<'F, 'B>>`

src/FSharp.Data.Validation.Async/VCtx.fs

Lines changed: 122 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ namespace FSharp.Data.Validation
33
[<RequireQualifiedAccess>]
44
module VCtx =
55
/// <summary>
6-
/// Binds a function that returns an asynchronous computation to a validation context.
6+
/// Binds a function that returns an asynchronous validation context to a validation context.
77
/// </summary>
88
/// <remarks>
99
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into an
10-
/// asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c> and a validation context <c>c</c>
11-
/// of type <c>VCtx&lt;'F, 'A&gt;</c>. It returns an asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.
10+
/// asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c> and a validation context <c>c</c>
11+
/// of type <c>VCtx&lt;'F, 'A&gt;</c>. It returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.
1212
///
1313
/// The function handles the following cases:
1414
/// <list type="bullet">
@@ -23,9 +23,9 @@ module VCtx =
2323
/// </item>
2424
/// </list>
2525
/// </remarks>
26-
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns an asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</param>
26+
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</param>
2727
/// <param name="c">A validation context of type <c>VCtx&lt;'F, 'A&gt;</c>.</param>
28-
/// <returns>An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</returns>
28+
/// <returns>An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</returns>
2929
let bindToAsync (fn:'A -> Async<VCtx<'F, 'B>>) (c: VCtx<'F, 'A>): Async<VCtx<'F, 'B>> =
3030
async {
3131
match c with
@@ -40,24 +40,24 @@ module VCtx =
4040
}
4141

4242
/// <summary>
43-
/// Binds a function that returns a validation context to an asynchronous computation.
43+
/// Binds a function that returns an asynchronous validation context to an asynchronous validation context.
4444
/// </summary>
4545
/// <remarks>
4646
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into a validation context
47-
/// of type <c>VCtx&lt;'F, 'B&gt;</c> and an asynchronous computation <c>c</c> of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.
48-
/// It returns an asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.
47+
/// of type <c>VCtx&lt;'F, 'B&gt;</c> and an asynchronous validation context <c>c</c> of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.
48+
/// It returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.
4949
/// </remarks>
5050
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns a validation context of type <c>VCtx&lt;'F, 'B&gt;</c>.</param>
51-
/// <param name="c">An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.</param>
52-
/// <returns>An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</returns>
51+
/// <param name="c">An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.</param>
52+
/// <returns>An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</returns>
5353
let bindAsync (fn:'A -> Async<VCtx<'F, 'B>>) (c: Async<VCtx<'F, 'A>>): Async<VCtx<'F, 'B>> =
5454
async {
5555
let! c' = c
5656
return! bindToAsync fn c'
5757
}
5858

5959
/// <summary>
60-
/// Binds a function that returns a validation context to a validation context.
60+
/// Binds a function that returns a validation context to an asynchronous validation context.
6161
/// </summary>
6262
/// <remarks>
6363
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into a validation context
@@ -69,3 +69,114 @@ module VCtx =
6969
/// <returns>A validation context of type <c>VCtx&lt;'F, 'B&gt;</c>.</returns>
7070
let bindFromAsync (fn:'A -> VCtx<'F, 'B>) (c: Async<VCtx<'F, 'A>>): Async<VCtx<'F, 'B>> =
7171
bindAsync (fn >> async.Return) c
72+
73+
/// <summary>
74+
/// Merge sources of two asynchronous computations of validation contexts into a single asynchronous validation context.
75+
/// </summary>
76+
/// <remarks>
77+
/// This function takes two asynchronous validation contexts <c>c1</c> and <c>c2</c> of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>
78+
/// and returns an asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'A * 'B&gt;&gt;</c> that merges the results.
79+
/// </remarks>
80+
/// <param name="c1">An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.</param>
81+
/// <param name="c2">An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</param>
82+
/// <returns>An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'A * 'B&gt;&gt;</c>.</returns>
83+
/// <seealso cref="VCtx.mergeSources"/>
84+
let mergeSourcesAsync
85+
(c1: Async<VCtx<'F,'A>>)
86+
(c2: Async<VCtx<'F,'B>>)
87+
: Async<VCtx<'F,'A * 'B>> =
88+
async {
89+
let! a = c1
90+
let! b = c2
91+
return VCtx.mergeSources a b
92+
}
93+
94+
/// <summary>
95+
/// Binds a function that returns an asynchronous validation context to an asynchronous validation context and merges the results.
96+
/// </summary>
97+
/// <remarks>
98+
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into an asynchronous computation
99+
/// of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c> and an asynchronous computation <c>c</c> of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.
100+
/// It returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A * 'B&gt;&gt;</c> that merges the results.
101+
/// </remarks>
102+
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns an asynchronous validation computation of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</param>
103+
/// <param name="c">An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.</param>
104+
/// <returns>An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A * 'B&gt;&gt;</c>.</returns>
105+
/// <seealso cref="VCtx.bindAsync"/>
106+
/// <seealso cref="VCtx.mergeSourcesAsync"/>
107+
let bindAndMergeSourcesAsync
108+
(fn: 'A -> Async<VCtx<'F,'B>>)
109+
(c: Async<VCtx<'F,'A>>)
110+
: Async<VCtx<'F,'A * 'B>> =
111+
bindAsync fn c |> mergeSourcesAsync c
112+
113+
/// <summary>
114+
/// Binds a function that returns an asynchronous validation context to a validation context and merges the results.
115+
/// </summary>
116+
/// <remarks>
117+
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into an
118+
/// asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c> and a validation context <c>c</c>
119+
/// of type <c>VCtx&lt;'F, 'A&gt;</c>. It returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.
120+
/// </remarks>
121+
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</param>
122+
/// <param name="c">A validation context of type <c>VCtx&lt;'F, 'A&gt;</c>.</param>
123+
/// <returns>An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</returns>
124+
/// <seealso cref="VCtx.bindToAsync"/>
125+
/// <seealso cref="VCtx.mergeSources"/>
126+
let bindToAndMergeSourcesAsync
127+
(fn: 'A -> Async<VCtx<'F,'B>>)
128+
(c: VCtx<'F,'A>)
129+
: Async<VCtx<'F,'A * 'B>> =
130+
async {
131+
let! b = bindToAsync fn c
132+
return VCtx.mergeSources c b
133+
}
134+
135+
// bindFromAndMergeSourcesAsync: ('A -> VCtx<'F, 'B>) -> Async<VCtx<'F, 'A>> -> Async<VCtx<'F, 'A * 'B>>
136+
137+
/// <summary>
138+
/// Binds a function that returns a validation context to an asynchronous validation context and merges the results.
139+
/// </summary>
140+
/// <remarks>
141+
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into a validation context
142+
/// of type <c>VCtx&lt;'F, 'B&gt;</c> and an asynchronous validation context <c>c</c> of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.
143+
/// It returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A * 'B&gt;&gt;</c> that merges the results.
144+
/// </remarks>
145+
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns a validation context of type <c>VCtx&lt;'F, 'B&gt;</c>.</param>
146+
/// <param name="c">An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.</param>
147+
/// <returns>An asynchronous computation of type <c>Async&lt;VCtx&lt;'F, 'A * 'B&gt;&gt;</c>.</returns>
148+
/// <seealso cref="VCtx.bindFromAsync"/>
149+
/// <seealso cref="VCtx.mergeSources"/>
150+
let bindFromAndMergeSourcesAsync
151+
(fn: 'A -> VCtx<'F, 'B>)
152+
(c: Async<VCtx<'F, 'A>>)
153+
: Async<VCtx<'F, 'A * 'B>> =
154+
let b = bindFromAsync fn c
155+
mergeSourcesAsync c b
156+
157+
/// <summary>
158+
/// Maps a function over the value of a validation context. The function returns an asynchronous computation.
159+
/// </summary>
160+
/// <remarks>
161+
/// This function takes a function <c>fn</c> that transforms a value of type <c>'A</c> into an asynchronous computation
162+
/// of type <c>Async&lt;'B&gt;</c> and an asynchronous validation context <c>c</c> of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.
163+
/// It returns an asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.
164+
/// </remarks>
165+
/// <param name="fn">A function that takes a value of type <c>'A</c> and returns an asynchronous computation of type <c>Async&lt;'B&gt;</c>.</param>
166+
/// <param name="c">An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'A&gt;&gt;</c>.</param>
167+
/// <returns>An asynchronous validation context of type <c>Async&lt;VCtx&lt;'F, 'B&gt;&gt;</c>.</returns>
168+
let mapAsync
169+
(fn: 'A -> Async<'B>)
170+
(c: Async<VCtx<'F,'A>>)
171+
: Async<VCtx<'F,'B>> =
172+
async {
173+
let! c' = c
174+
match c' with
175+
| ValidCtx a ->
176+
let! b = fn a
177+
return ValidCtx b
178+
| RefutedCtx (gfs,lfs) -> return RefutedCtx (gfs,lfs)
179+
| DisputedCtx (gfs,lfs,a) ->
180+
let! b = fn a
181+
return DisputedCtx (gfs,lfs, b)
182+
}

src/FSharp.Data.Validation.Giraffe/FSharp.Data.Validation.Giraffe.fsproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
<PackagePath>\</PackagePath>
1919
</None>
2020
</ItemGroup>
21-
21+
2222
<ItemGroup>
2323
<PackageReference Update="FSharp.Core" Version="[6.0.6,)" />
2424
<PackageReference Include="Giraffe" Version="[6,)" />
25+
<PackageReference Include="System.Text.Json" Version="[6.0.11,)" />
2526
</ItemGroup>
2627
</Project>

src/FSharp.Data.Validation/VCtx.fs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,37 @@ module VCtx =
4545
(gfs, Utilities.mergeFailures lfs <| Utilities.mergeFailures lfs3 lfs2)
4646
| Global _a -> (gfs @ gfs', Utilities.mergeFailures lfs lfs')
4747

48-
type VCtxBuilder() =
49-
member this.Bind(v:VCtx<'F, 'A>, fn:'A -> VCtx<'F, 'B>): VCtx<'F, 'B> =
50-
VCtx.bind fn v
51-
52-
member this.MergeSources(v1: VCtx<'F, 'A>, v2: VCtx<'F, 'B>) =
48+
/// <summary>
49+
/// Merges two validation contexts. If one of the contexts is refuted, the result is refuted. If one of the contexts
50+
/// is disputed, the result is disputed. Otherwise, the result is valid. The result is a tuple of the values of the
51+
/// two input contexts.
52+
/// </summary>
53+
/// <param name="v1">The first validation context.</param>
54+
/// <param name="v2">The second validation context.</param>
55+
/// <returns>A validation context that combines the results of the two input validation contexts.</returns>
56+
/// <remarks>
57+
/// This function takes two validation contexts <c>v1</c> and <c>v2</c> and returns a tupled validation context.
58+
/// Prioritizes refuted contexts over disputed contexts and disputed contexts over valid contexts.
59+
/// </remarks>
60+
let mergeSources (v1: VCtx<'F, 'A>) (v2: VCtx<'F, 'B>): VCtx<'F, 'A * 'B> =
5361
match (v1, v2) with
5462
| ValidCtx a, ValidCtx b -> ValidCtx (a, b)
55-
| ValidCtx _, DisputedCtx (gfs', lfs', _) -> RefutedCtx (gfs', lfs')
63+
| ValidCtx a, DisputedCtx (gfs', lfs', b) -> DisputedCtx (gfs', lfs', (a, b))
5664
| ValidCtx _, RefutedCtx (gfs', lfs') -> RefutedCtx (gfs', lfs')
57-
| DisputedCtx (gfs, lfs, _), ValidCtx _ -> RefutedCtx (gfs, lfs)
58-
| DisputedCtx (gfs, lfs, _), DisputedCtx (gfs', lfs', _) -> RefutedCtx (gfs @ gfs', Utilities.mergeFailures lfs lfs')
65+
| DisputedCtx (gfs, lfs, a), ValidCtx b -> DisputedCtx (gfs, lfs, (a, b))
66+
| DisputedCtx (gfs, lfs, a), DisputedCtx (gfs', lfs', b) -> DisputedCtx (gfs @ gfs', Utilities.mergeFailures lfs lfs', (a, b))
5967
| DisputedCtx (gfs, lfs, _), RefutedCtx (gfs', lfs') -> RefutedCtx (gfs @ gfs', Utilities.mergeFailures lfs lfs')
6068
| RefutedCtx (gfs, lfs), ValidCtx _ -> RefutedCtx (gfs, lfs)
6169
| RefutedCtx (gfs, lfs), DisputedCtx (gfs', lfs', _) -> RefutedCtx (gfs @ gfs', Utilities.mergeFailures lfs lfs')
6270
| RefutedCtx (gfs, lfs), RefutedCtx (gfs', lfs') -> RefutedCtx (gfs @ gfs', Utilities.mergeFailures lfs lfs')
6371

72+
type VCtxBuilder() =
73+
member this.Bind(v:VCtx<'F, 'A>, fn:'A -> VCtx<'F, 'B>): VCtx<'F, 'B> =
74+
VCtx.bind fn v
75+
76+
member this.MergeSources(v1: VCtx<'F, 'A>, v2: VCtx<'F, 'B>) =
77+
VCtx.mergeSources v1 v2
78+
6479
member this.For(v:VCtx<'F, 'A>, fn:'A -> VCtx<'F, 'B>): VCtx<'F, 'B> = this.Bind(v, fn)
6580

6681
member this.Return(a:'A): VCtx<'F, 'A> = ValidCtx a
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
<GenerateProgramFile>false</GenerateProgramFile>
8+
<IsTestProject>true</IsTestProject>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<Compile Include="Tests.fs" />
13+
<Compile Include="Program.fs" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\..\src\FSharp.Data.Validation.Async\FSharp.Data.Validation.Async.fsproj" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<PackageReference Update="FSharp.Core" Version="8.0.100" />
22+
<PackageReference Include="coverlet.collector" Version="6.0.2">
23+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24+
<PrivateAssets>all</PrivateAssets>
25+
</PackageReference>
26+
<PackageReference Include="FsCheck" Version="2.16.6" />
27+
<PackageReference Include="FsCheck.Xunit" Version="2.16.6" />
28+
<PackageReference Include="FsUnit.xUnit" Version="6.0.1" />
29+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
30+
<PackageReference Include="xunit" Version="2.9.2" />
31+
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
32+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
33+
<PrivateAssets>all</PrivateAssets>
34+
</PackageReference>
35+
</ItemGroup>
36+
37+
</Project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module Program = let [<EntryPoint>] main _ = 0

0 commit comments

Comments
 (0)