Skip to content

Commit 569569f

Browse files
authored
Optional subsections (#32)
* feat: optional subsections * revert to simple case * chore: remove unnecessary change * chore: removed WIP * chore: remove WIP --------- Co-authored-by: queil <[email protected]>
1 parent 765421d commit 569569f

File tree

10 files changed

+108
-83
lines changed

10 files changed

+108
-83
lines changed

.vscode/launch.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": ".NET Core Launch (console)",
9+
"type": "coreclr",
10+
"request": "launch",
11+
"preLaunchTask": "build",
12+
"program": "dotnet",
13+
"args": [
14+
"test"
15+
],
16+
"cwd": "${workspaceFolder}/tests/FsConfig.Tests",
17+
"stopAtEntry": false,
18+
"console": "internalConsole",
19+
"env": {
20+
"VSTEST_HOST_DEBUG": "1"
21+
}
22+
}
23+
]
24+
}

.vscode/settings.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{
2-
"FSharp.fsacRuntime":"netcore",
32
"FSharp.enableAnalyzers": true,
43
"FSharp.analyzersPath": [
54
"./packages/analyzers"

.vscode/tasks.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"type": "msbuild",
6+
"problemMatcher": [
7+
"$msCompile"
8+
],
9+
"group": {
10+
"kind": "build",
11+
"isDefault": true
12+
},
13+
"label": "build",
14+
"detail": "Build the FsConfig.Tests.fsproj project using dotnet build"
15+
}
16+
]
17+
}

src/FsConfig/Config.fs

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -185,43 +185,6 @@ module internal Core =
185185
)
186186
| _ -> None
187187

188-
let parseFSharpOption<'T> name value (fsharpOption: IShapeFSharpOption) =
189-
let wrap (p: ConfigParseResult<'a>) = unbox<ConfigParseResult<'T>> p
190-
191-
fsharpOption.Element.Accept
192-
{ new ITypeVisitor<ConfigParseResult<'T>> with
193-
member __.Visit<'t>() =
194-
match value with
195-
| None ->
196-
let result: ConfigParseResult<'t option> = None |> Ok
197-
wrap result
198-
| Some v ->
199-
match getTryParseFunc<'t> fsharpOption.Element with
200-
| Some tryParseFunc ->
201-
match shapeof<'t> with
202-
| Shape.String ->
203-
if String.IsNullOrWhiteSpace v then
204-
let result: ConfigParseResult<'t option> = None |> Ok
205-
wrap result
206-
else
207-
tryParseWith name v tryParseFunc
208-
|> Result.bind (
209-
Some
210-
>> Ok
211-
>> wrap
212-
)
213-
| _ ->
214-
tryParseWith name v tryParseFunc
215-
|> Result.bind (
216-
Some
217-
>> Ok
218-
>> wrap
219-
)
220-
| None ->
221-
notSupported name
222-
|> Error
223-
}
224-
225188
let parseListReducer name tryParseFunc acc element =
226189
acc
227190
|> Result.bind (fun xs ->
@@ -285,7 +248,8 @@ module internal Core =
285248
match targetTypeShape with
286249
| Shape.FSharpRecord (:? ShapeFSharpRecord<'T> as shape) ->
287250
parseFSharpRecord configReader fieldNameCanonicalizer (Prefix args.Name) shape
288-
| Shape.FSharpOption fsharpOption -> parseFSharpOption<'T> args.Name value fsharpOption
251+
| Shape.FSharpOption fsharpOption ->
252+
parseFSharpOption configReader fieldNameCanonicalizer args fsharpOption
289253
| Shape.FSharpList fsharpList ->
290254
parseFSharpList<'T> args.Name value fsharpList args.ListSplitChar
291255
| _ ->
@@ -364,6 +328,35 @@ module internal Core =
364328
(Ok [])
365329
|> Result.map (List.fold (fun acc f -> f acc) record)
366330

331+
and parseFSharpOption
332+
(configReader: IConfigReader)
333+
(fieldNameCanonicalizer: FieldNameCanonicalizer)
334+
args
335+
(fsharpOption: IShapeFSharpOption)
336+
=
337+
let wrap (p: ConfigParseResult<'a>) = unbox<ConfigParseResult<'T>> p
338+
339+
fsharpOption.Element.Accept
340+
{ new ITypeVisitor<ConfigParseResult<'T>> with
341+
member __.Visit<'t>() =
342+
343+
match parseInternal<'t> configReader fieldNameCanonicalizer args with
344+
| Ok (value) ->
345+
match box value with
346+
| :? string as s when String.IsNullOrWhiteSpace s ->
347+
let result: ConfigParseResult<'t option> = None |> Ok
348+
wrap result
349+
| _ ->
350+
Some(value)
351+
|> Ok
352+
|> wrap
353+
| Error (BadValue v) -> Error(BadValue v)
354+
| Error (NotFound _) ->
355+
let result: ConfigParseResult<'t option> = None |> Ok
356+
wrap result
357+
| Error (NotSupported x) -> Error(NotSupported x)
358+
}
359+
367360
[<AutoOpen>]
368361
module Config =
369362
open Core

tests/FsConfig.Tests/AppConfig.fs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ module ``App Config tests`` =
6767

6868
test <@ appConfig.Get<Config>() = expected @>
6969

70+
[<Test>]
71+
member __.``getOptionalRecord should succeed``() =
72+
let expected =
73+
{
74+
optionalSubsectionNone = None
75+
optionalSubsectionSome = Some({ apiKey = "abc-def"; value = 1 })
76+
77+
}
78+
79+
|> Ok
80+
81+
test <@ appConfig.Get<ConfigWithOptionalSubsection>() = expected @>
7082

7183
[<Test>]
7284
member __.``get list of DU with custom name``() =

tests/FsConfig.Tests/AssemblyInfo.fs

Lines changed: 0 additions & 23 deletions
This file was deleted.

tests/FsConfig.Tests/Common.fs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,10 @@ module Common =
9292
type ConfigWithUri = { Uri: Uri }
9393

9494
type ConfigWithInvalidUri = { InvalidUri: Uri }
95+
96+
type ConfigWithOptionalSubsection = {
97+
optionalSubsectionNone: Subsection option
98+
optionalSubsectionSome: Subsection option
99+
}
100+
101+
and Subsection = { apiKey: string; value: int }

tests/FsConfig.Tests/FsConfig.Tests.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818
<ProjectReference Include="..\..\src\FsConfig\FsConfig.fsproj" />
1919
</ItemGroup>
2020
<Import Project="..\..\.paket\Paket.Restore.targets" />
21-
</Project>
21+
</Project>

tests/FsConfig.Tests/Main.fs

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/FsConfig.Tests/settings.json

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
{
2-
"processId" : "123",
3-
"processName" : "FsConfig",
4-
"magicNumber" : 42,
5-
"aws" : {
6-
"accessKeyId" : "Id-123",
7-
"defaultRegion" : "us-east-1",
8-
"secretAccessKey" : "secret123"
9-
},
10-
"colors" : "Red,Green",
11-
"uri": "https://example.com",
12-
"invalidUri": "invalid"
2+
"processId": "123",
3+
"processName": "FsConfig",
4+
"magicNumber": 42,
5+
"aws": {
6+
"accessKeyId": "Id-123",
7+
"defaultRegion": "us-east-1",
8+
"secretAccessKey": "secret123"
9+
},
10+
"colors": "Red,Green",
11+
"uri": "https://example.com",
12+
"invalidUri": "invalid",
13+
"optionalSubsectionNone": {},
14+
"optionalSubsectionSome": {
15+
"apiKey": "abc-def",
16+
"value": 1
17+
}
1318
}

0 commit comments

Comments
 (0)