mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-06 04:28:42 +00:00
Enforce non-nullability in more cases during JSON parse (#367)
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
Notable changes are recorded here.
|
Notable changes are recorded here.
|
||||||
|
|
||||||
|
# WoofWare.Myriad.Plugins 5.0.1
|
||||||
|
|
||||||
|
We now enforce non-nullability on more types during JSON parse.
|
||||||
|
We have always expected you to consume nullable types wrapped in an `option`, but now we enforce this in more cases by throwing `ArgumentNullException`.
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 3.0.1
|
# WoofWare.Myriad.Plugins 3.0.1
|
||||||
|
|
||||||
Semantics of `HttpClient`'s URI component composition changed:
|
Semantics of `HttpClient`'s URI component composition changed:
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -71,7 +71,11 @@ module JsonRecordType =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.Int32> ())
|
||||||
|
)
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_4 =
|
let arg_4 =
|
||||||
@@ -84,7 +88,11 @@ module JsonRecordType =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.String> ())
|
||||||
|
)
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_3 =
|
let arg_3 =
|
||||||
@@ -109,7 +117,11 @@ module JsonRecordType =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.Int32> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_1 =
|
let arg_1 =
|
||||||
|
@@ -60,7 +60,11 @@ module GymOpeningHours =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.String> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_0 =
|
let arg_0 =
|
||||||
@@ -1038,7 +1042,11 @@ module Sessions =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> Visit.jsonParse elt)
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> Visit.jsonParse elt)
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_0 =
|
let arg_0 =
|
||||||
|
@@ -48,7 +48,14 @@ module PureGymApi =
|
|||||||
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|
|
||||||
return jsonNode.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq
|
return
|
||||||
|
jsonNode.AsArray ()
|
||||||
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> Gym.jsonParse elt)
|
||||||
|
)
|
||||||
|
|> List.ofSeq
|
||||||
}
|
}
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
|
@@ -408,7 +408,11 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
|
|
||||||
let value =
|
let value =
|
||||||
(kvp.Value).AsArray ()
|
(kvp.Value).AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Char> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.Char> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
key, value
|
key, value
|
||||||
@@ -676,7 +680,11 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.Int32> ())
|
||||||
|
)
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_4 =
|
let arg_4 =
|
||||||
@@ -689,7 +697,11 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.String> ())
|
||||||
|
)
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_3 =
|
let arg_3 =
|
||||||
@@ -714,7 +726,11 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.Int32> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_1 =
|
let arg_1 =
|
||||||
|
@@ -94,7 +94,11 @@ module JwtVaultAuthResponse =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.String> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_3 =
|
let arg_3 =
|
||||||
@@ -107,7 +111,11 @@ module JwtVaultAuthResponse =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.String> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_2 =
|
let arg_2 =
|
||||||
@@ -120,7 +128,11 @@ module JwtVaultAuthResponse =
|
|||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsArray ()
|
.AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|
|> Seq.map (fun elt ->
|
||||||
|
(match elt with
|
||||||
|
| null -> raise (System.ArgumentNullException ())
|
||||||
|
| elt -> elt.AsValue().GetValue<System.String> ())
|
||||||
|
)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_1 =
|
let arg_1 =
|
||||||
|
@@ -26,7 +26,7 @@ module internal JsonParseGenerator =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ({propertyName} not found)) | v -> v)
|
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ({propertyName} not found)) | v -> v)
|
||||||
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
|
let assertPropertyExists (propertyName : SynExpr) (indexed : SynExpr) =
|
||||||
let raiseExpr =
|
let raiseExpr =
|
||||||
SynExpr.applyFunction
|
SynExpr.applyFunction
|
||||||
(SynExpr.createIdent "sprintf")
|
(SynExpr.createIdent "sprintf")
|
||||||
@@ -46,28 +46,42 @@ module internal JsonParseGenerator =
|
|||||||
|> SynExpr.createMatch indexed
|
|> SynExpr.createMatch indexed
|
||||||
|> SynExpr.paren
|
|> SynExpr.paren
|
||||||
|
|
||||||
|
let assertNotNull (body : SynExpr) (boundIdent : Ident) : SynExpr =
|
||||||
|
let raiseExpr =
|
||||||
|
SynExpr.CreateConst ()
|
||||||
|
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|
||||||
|
|> SynExpr.paren
|
||||||
|
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||||
|
|
||||||
|
[
|
||||||
|
SynMatchClause.create SynPat.createNull raiseExpr
|
||||||
|
SynMatchClause.create (SynPat.namedI boundIdent) body
|
||||||
|
]
|
||||||
|
|> SynExpr.createMatch (SynExpr.createIdent' boundIdent)
|
||||||
|
|> SynExpr.paren
|
||||||
|
|
||||||
/// {node}.AsValue().GetValue<{typeName}> ()
|
/// {node}.AsValue().GetValue<{typeName}> ()
|
||||||
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
/// If `propertyName` is Some, uses `assertPropertyExists {node}` instead of `{node}`.
|
||||||
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
|
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertPropertyExists propertyName node
|
||||||
|> SynExpr.callMethod "AsValue"
|
|> SynExpr.callMethod "AsValue"
|
||||||
|> SynExpr.callGenericMethod' "GetValue" typeName
|
|> SynExpr.callGenericMethod' "GetValue" typeName
|
||||||
|
|
||||||
let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertPropertyExists propertyName node
|
||||||
|> SynExpr.callMethod "AsValue"
|
|> SynExpr.callMethod "AsValue"
|
||||||
|> SynExpr.callGenericMethod (SynLongIdent.createS "GetValue") [ SynType.createLongIdent typeName ]
|
|> SynExpr.callGenericMethod (SynLongIdent.createS "GetValue") [ SynType.createLongIdent typeName ]
|
||||||
|
|
||||||
/// {node}.AsObject()
|
/// {node}.AsObject()
|
||||||
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
/// If `propertyName` is Some, uses `assertPropertyExists {node}` instead of `{node}`.
|
||||||
let asObject (propertyName : SynExpr option) (node : SynExpr) : SynExpr =
|
let asObject (propertyName : SynExpr option) (node : SynExpr) : SynExpr =
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertPropertyExists propertyName node
|
||||||
|> SynExpr.callMethod "AsObject"
|
|> SynExpr.callMethod "AsObject"
|
||||||
|
|
||||||
/// {type}.jsonParse {node}
|
/// {type}.jsonParse {node}
|
||||||
@@ -77,8 +91,8 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
|
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
|
||||||
/// body is the body of a lambda which takes a parameter `elt`.
|
/// body is the body of a lambda which takes a parameter `elt`.
|
||||||
/// {assertNotNull node}.AsArray()
|
/// {assertPropertyExists node}.AsArray()
|
||||||
/// |> Seq.map (fun elt -> {body})
|
/// |> Seq.map (fun elt -> {assertNotNull} {body})
|
||||||
/// |> {collectionType}.ofSeq
|
/// |> {collectionType}.ofSeq
|
||||||
let asArrayMapped
|
let asArrayMapped
|
||||||
(propertyName : SynExpr option)
|
(propertyName : SynExpr option)
|
||||||
@@ -89,10 +103,12 @@ module internal JsonParseGenerator =
|
|||||||
=
|
=
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertPropertyExists propertyName node
|
||||||
|> SynExpr.callMethod "AsArray"
|
|> SynExpr.callMethod "AsArray"
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "elt" body)
|
SynExpr.applyFunction
|
||||||
|
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||||
|
(SynExpr.createLambda "elt" (assertNotNull body (Ident.create "elt")))
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ])
|
||||||
|
|
||||||
@@ -177,27 +193,29 @@ module internal JsonParseGenerator =
|
|||||||
=
|
=
|
||||||
// TODO: parsing format for DateTime etc
|
// TODO: parsing format for DateTime etc
|
||||||
match fieldType with
|
match fieldType with
|
||||||
|
// Struct types
|
||||||
| DateOnly ->
|
| DateOnly ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateOnly" ; "Parse" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateOnly" ; "Parse" ])
|
||||||
| Uri ->
|
|
||||||
node
|
|
||||||
|> asValueGetValue propertyName "string"
|
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
|
|
||||||
| Guid ->
|
|
||||||
node
|
|
||||||
|> asValueGetValue propertyName "string"
|
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Guid" ; "Parse" ])
|
|
||||||
| DateTime ->
|
| DateTime ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
|
||||||
|
| NumberType typeName -> parseNumberType options propertyName node typeName
|
||||||
|
| Guid ->
|
||||||
|
node
|
||||||
|
|> asValueGetValue propertyName "string"
|
||||||
|
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Guid" ; "Parse" ])
|
||||||
|
// Reference types
|
||||||
|
| Uri ->
|
||||||
|
node
|
||||||
|
|> asValueGetValue propertyName "string"
|
||||||
|
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
|
||||||
| DateTimeOffset ->
|
| DateTimeOffset ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTimeOffset" ; "Parse" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTimeOffset" ; "Parse" ])
|
||||||
| NumberType typeName -> parseNumberType options propertyName node typeName
|
|
||||||
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
||||||
| OptionType ty ->
|
| OptionType ty ->
|
||||||
let someClause =
|
let someClause =
|
||||||
@@ -291,7 +309,7 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertPropertyExists propertyName node
|
||||||
|> typeJsonParse typeName
|
|> typeJsonParse typeName
|
||||||
|
|
||||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||||
@@ -505,7 +523,7 @@ module internal JsonParseGenerator =
|
|||||||
|> SynExpr.createLet
|
|> SynExpr.createLet
|
||||||
[
|
[
|
||||||
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|
||||||
|> assertNotNull (SynExpr.CreateConst "data")
|
|> assertPropertyExists (SynExpr.CreateConst "data")
|
||||||
|> SynBinding.basic [ Ident.create "node" ] []
|
|> SynBinding.basic [ Ident.create "node" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -553,7 +571,7 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
SynExpr.createIdent "node"
|
SynExpr.createIdent "node"
|
||||||
|> SynExpr.index property
|
|> SynExpr.index property
|
||||||
|> assertNotNull property
|
|> assertPropertyExists property
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.createLambda "v" (SynExpr.callGenericMethod' "GetValue" "string" (SynExpr.createIdent "v"))
|
SynExpr.createLambda "v" (SynExpr.callGenericMethod' "GetValue" "string" (SynExpr.createIdent "v"))
|
||||||
)
|
)
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "4.0",
|
"version": "5.0",
|
||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
|
Reference in New Issue
Block a user