mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-06 12:38:40 +00:00
Compare commits
4 Commits
WoofWare.M
...
WoofWare.M
Author | SHA1 | Date | |
---|---|---|---|
|
398cd04a2a | ||
|
434c042510 | ||
|
c590db2a65 | ||
|
6a81513a93 |
@@ -14,7 +14,7 @@ module internal InternalTypeNotExtensionSerial =
|
||||
/// Serialize to a JSON node
|
||||
let toJsonNode (input : InternalTypeNotExtensionSerial) : System.Text.Json.Nodes.JsonNode =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
do node.Add ((Literals.something), System.Text.Json.Nodes.JsonValue.Create<string> input.InternalThing2)
|
||||
do node.Add ((Literals.something), (input.InternalThing2 |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node :> _
|
||||
namespace ConsumePlugin
|
||||
|
||||
@@ -29,7 +29,7 @@ module internal InternalTypeExtensionJsonSerializeExtension =
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : InternalTypeExtension) : System.Text.Json.Nodes.JsonNode =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
do node.Add ((Literals.something), System.Text.Json.Nodes.JsonValue.Create<string> input.ExternalThing)
|
||||
do node.Add ((Literals.something), (input.ExternalThing |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node :> _
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
@@ -20,21 +20,26 @@ module MemberJsonSerializeExtension =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add ("id", System.Text.Json.Nodes.JsonValue.Create<int> input.Id)
|
||||
node.Add ("compoundMemberId", System.Text.Json.Nodes.JsonValue.Create<string> input.CompoundMemberId)
|
||||
node.Add ("firstName", System.Text.Json.Nodes.JsonValue.Create<string> input.FirstName)
|
||||
node.Add ("lastName", System.Text.Json.Nodes.JsonValue.Create<string> input.LastName)
|
||||
node.Add ("homeGymId", System.Text.Json.Nodes.JsonValue.Create<int> input.HomeGymId)
|
||||
node.Add ("homeGymName", System.Text.Json.Nodes.JsonValue.Create<string> input.HomeGymName)
|
||||
node.Add ("emailAddress", System.Text.Json.Nodes.JsonValue.Create<string> input.EmailAddress)
|
||||
node.Add ("gymAccessPin", System.Text.Json.Nodes.JsonValue.Create<string> input.GymAccessPin)
|
||||
node.Add ("dateofBirth", System.Text.Json.Nodes.JsonValue.Create<DateOnly> input.DateOfBirth)
|
||||
node.Add ("mobileNumber", System.Text.Json.Nodes.JsonValue.Create<string> input.MobileNumber)
|
||||
node.Add ("postCode", System.Text.Json.Nodes.JsonValue.Create<string> input.Postcode)
|
||||
node.Add ("membershipName", System.Text.Json.Nodes.JsonValue.Create<string> input.MembershipName)
|
||||
node.Add ("membershipLevel", System.Text.Json.Nodes.JsonValue.Create<int> input.MembershipLevel)
|
||||
node.Add ("suspendedReason", System.Text.Json.Nodes.JsonValue.Create<int> input.SuspendedReason)
|
||||
node.Add ("memberStatus", System.Text.Json.Nodes.JsonValue.Create<int> input.MemberStatus)
|
||||
node.Add ("id", (input.Id |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
|
||||
node.Add (
|
||||
"compoundMemberId",
|
||||
(input.CompoundMemberId |> System.Text.Json.Nodes.JsonValue.Create<string>)
|
||||
)
|
||||
|
||||
node.Add ("firstName", (input.FirstName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("lastName", (input.LastName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("homeGymId", (input.HomeGymId |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("homeGymName", (input.HomeGymName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("emailAddress", (input.EmailAddress |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("gymAccessPin", (input.GymAccessPin |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("dateofBirth", (input.DateOfBirth |> System.Text.Json.Nodes.JsonValue.Create<DateOnly>))
|
||||
node.Add ("mobileNumber", (input.MobileNumber |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("postCode", (input.Postcode |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("membershipName", (input.MembershipName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("membershipLevel", (input.MembershipLevel |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("suspendedReason", (input.SuspendedReason |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("memberStatus", (input.MemberStatus |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
|
||||
node :> _
|
||||
|
||||
|
@@ -21,69 +21,69 @@ module InnerTypeWithBothJsonSerializeExtension =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add (("it's-a-me"), System.Text.Json.Nodes.JsonValue.Create<Guid> input.Thing)
|
||||
node.Add (("it's-a-me"), (input.Thing |> System.Text.Json.Nodes.JsonValue.Create<Guid>))
|
||||
|
||||
node.Add (
|
||||
"map",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.Map
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<Uri> value)
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<Uri> value)
|
||||
|
||||
ret
|
||||
)
|
||||
input.Map
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"readOnlyDict",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.ReadOnlyDict
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (
|
||||
key.ToString (),
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (
|
||||
key.ToString (),
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<char> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<char> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
value
|
||||
)
|
||||
arr
|
||||
)
|
||||
value
|
||||
)
|
||||
|
||||
ret
|
||||
)
|
||||
input.ReadOnlyDict
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"dict",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.Dict
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<bool> value)
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<bool> value)
|
||||
|
||||
ret
|
||||
)
|
||||
input.Dict
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"concreteDict",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.ConcreteDict
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), InnerTypeWithBoth.toJsonNode value)
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), InnerTypeWithBoth.toJsonNode value)
|
||||
|
||||
ret
|
||||
)
|
||||
input.ConcreteDict
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node :> _
|
||||
@@ -93,6 +93,24 @@ open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the SomeEnum type
|
||||
[<AutoOpen>]
|
||||
module SomeEnumJsonSerializeExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type SomeEnum with
|
||||
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : SomeEnum) : System.Text.Json.Nodes.JsonNode =
|
||||
match input with
|
||||
| SomeEnum.Blah -> System.Text.Json.Nodes.JsonValue.Create 1
|
||||
| SomeEnum.Thing -> System.Text.Json.Nodes.JsonValue.Create 0
|
||||
| v -> failwith (sprintf "Unrecognised value for enum: %O" v)
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the JsonRecordTypeWithBoth type
|
||||
[<AutoOpen>]
|
||||
module JsonRecordTypeWithBothJsonSerializeExtension =
|
||||
@@ -104,61 +122,93 @@ module JsonRecordTypeWithBothJsonSerializeExtension =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add ("a", System.Text.Json.Nodes.JsonValue.Create<int> input.A)
|
||||
node.Add ("b", System.Text.Json.Nodes.JsonValue.Create<string> input.B)
|
||||
node.Add ("a", (input.A |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("b", (input.B |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
|
||||
node.Add (
|
||||
"c",
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
(input.C
|
||||
|> (fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
input.C
|
||||
arr
|
||||
))
|
||||
)
|
||||
|
||||
node.Add ("d", InnerTypeWithBoth.toJsonNode input.D)
|
||||
node.Add ("d", (input.D |> InnerTypeWithBoth.toJsonNode))
|
||||
|
||||
node.Add (
|
||||
"e",
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
(input.E
|
||||
|> (fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<string> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<string> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
input.E
|
||||
arr
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"arr",
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
(input.Arr
|
||||
|> (fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
input.Arr
|
||||
arr
|
||||
))
|
||||
)
|
||||
|
||||
node.Add ("byte", System.Text.Json.Nodes.JsonValue.Create<byte<measure>> input.Byte)
|
||||
node.Add ("sbyte", System.Text.Json.Nodes.JsonValue.Create<sbyte<measure>> input.Sbyte)
|
||||
node.Add ("i", System.Text.Json.Nodes.JsonValue.Create<int<measure>> input.I)
|
||||
node.Add ("i32", System.Text.Json.Nodes.JsonValue.Create<int32<measure>> input.I32)
|
||||
node.Add ("i64", System.Text.Json.Nodes.JsonValue.Create<int64<measure>> input.I64)
|
||||
node.Add ("u", System.Text.Json.Nodes.JsonValue.Create<uint<measure>> input.U)
|
||||
node.Add ("u32", System.Text.Json.Nodes.JsonValue.Create<uint32<measure>> input.U32)
|
||||
node.Add ("u64", System.Text.Json.Nodes.JsonValue.Create<uint64<measure>> input.U64)
|
||||
node.Add ("f", System.Text.Json.Nodes.JsonValue.Create<float<measure>> input.F)
|
||||
node.Add ("f32", System.Text.Json.Nodes.JsonValue.Create<float32<measure>> input.F32)
|
||||
node.Add ("single", System.Text.Json.Nodes.JsonValue.Create<single<measure>> input.Single)
|
||||
node.Add ("byte", (input.Byte |> System.Text.Json.Nodes.JsonValue.Create<byte<measure>>))
|
||||
node.Add ("sbyte", (input.Sbyte |> System.Text.Json.Nodes.JsonValue.Create<sbyte<measure>>))
|
||||
node.Add ("i", (input.I |> System.Text.Json.Nodes.JsonValue.Create<int<measure>>))
|
||||
node.Add ("i32", (input.I32 |> System.Text.Json.Nodes.JsonValue.Create<int32<measure>>))
|
||||
node.Add ("i64", (input.I64 |> System.Text.Json.Nodes.JsonValue.Create<int64<measure>>))
|
||||
node.Add ("u", (input.U |> System.Text.Json.Nodes.JsonValue.Create<uint<measure>>))
|
||||
node.Add ("u32", (input.U32 |> System.Text.Json.Nodes.JsonValue.Create<uint32<measure>>))
|
||||
node.Add ("u64", (input.U64 |> System.Text.Json.Nodes.JsonValue.Create<uint64<measure>>))
|
||||
node.Add ("f", (input.F |> System.Text.Json.Nodes.JsonValue.Create<float<measure>>))
|
||||
node.Add ("f32", (input.F32 |> System.Text.Json.Nodes.JsonValue.Create<float32<measure>>))
|
||||
node.Add ("single", (input.Single |> System.Text.Json.Nodes.JsonValue.Create<single<measure>>))
|
||||
|
||||
node.Add (
|
||||
"intMeasureOption",
|
||||
(input.IntMeasureOption
|
||||
|> (fun field ->
|
||||
match field with
|
||||
| None -> null :> System.Text.Json.Nodes.JsonNode
|
||||
| Some field ->
|
||||
(System.Text.Json.Nodes.JsonValue.Create<int<measure>> field)
|
||||
:> System.Text.Json.Nodes.JsonNode
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"intMeasureNullable",
|
||||
(input.IntMeasureNullable
|
||||
|> (fun field ->
|
||||
if field.HasValue then
|
||||
System.Text.Json.Nodes.JsonValue.Create<int<measure>> field.Value
|
||||
:> System.Text.Json.Nodes.JsonNode
|
||||
else
|
||||
null :> System.Text.Json.Nodes.JsonNode
|
||||
))
|
||||
)
|
||||
|
||||
node.Add ("enum", (input.Enum |> SomeEnum.toJsonNode))
|
||||
|
||||
node.Add (
|
||||
"timestamp",
|
||||
(input.Timestamp
|
||||
|> (fun field -> field.ToString "o" |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
)
|
||||
|
||||
node :> _
|
||||
namespace ConsumePlugin
|
||||
@@ -192,6 +242,55 @@ module FirstDuJsonSerializeExtension =
|
||||
node.Add ("data", dataNode)
|
||||
|
||||
node :> _
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the HeaderAndValue type
|
||||
[<AutoOpen>]
|
||||
module HeaderAndValueJsonSerializeExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type HeaderAndValue with
|
||||
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : HeaderAndValue) : System.Text.Json.Nodes.JsonNode =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add ("header", (input.Header |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("value", (input.Value |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
|
||||
node :> _
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the Foo type
|
||||
[<AutoOpen>]
|
||||
module FooJsonSerializeExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type Foo with
|
||||
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : Foo) : System.Text.Json.Nodes.JsonNode =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add (
|
||||
"message",
|
||||
(input.Message
|
||||
|> (fun field ->
|
||||
match field with
|
||||
| None -> null :> System.Text.Json.Nodes.JsonNode
|
||||
| Some field -> HeaderAndValue.toJsonNode field
|
||||
))
|
||||
)
|
||||
|
||||
node :> _
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
@@ -299,6 +398,24 @@ module InnerTypeWithBothJsonParseExtension =
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the SomeEnum type
|
||||
[<AutoOpen>]
|
||||
module SomeEnumJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type SomeEnum with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : SomeEnum =
|
||||
match node.GetValueKind () with
|
||||
| System.Text.Json.JsonValueKind.Number -> node.AsValue().GetValue<int> () |> enum<SomeEnum>
|
||||
| System.Text.Json.JsonValueKind.String ->
|
||||
match node.AsValue().GetValue<string>().ToLowerInvariant () with
|
||||
| "blah" -> SomeEnum.Blah
|
||||
| "thing" -> SomeEnum.Thing
|
||||
| v -> failwith ("Unrecognised value for enum: %i" + v)
|
||||
| _ -> failwith ("Unrecognised kind for enum of type: " + "SomeEnum")
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the JsonRecordTypeWithBoth type
|
||||
[<AutoOpen>]
|
||||
module JsonRecordTypeWithBothJsonParseExtension =
|
||||
@@ -307,6 +424,47 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordTypeWithBoth =
|
||||
let arg_20 =
|
||||
(match node.["timestamp"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("timestamp")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
|> System.DateTimeOffset.Parse
|
||||
|
||||
let arg_19 =
|
||||
SomeEnum.jsonParse (
|
||||
match node.["enum"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("enum")
|
||||
)
|
||||
)
|
||||
| v -> v
|
||||
)
|
||||
|
||||
let arg_18 =
|
||||
match node.["intMeasureNullable"] with
|
||||
| null -> System.Nullable ()
|
||||
| v ->
|
||||
v.AsValue().GetValue<System.Int32> ()
|
||||
|> LanguagePrimitives.Int32WithMeasure
|
||||
|> System.Nullable
|
||||
|
||||
let arg_17 =
|
||||
match node.["intMeasureOption"] with
|
||||
| null -> None
|
||||
| v ->
|
||||
v.AsValue().GetValue<System.Int32> ()
|
||||
|> LanguagePrimitives.Int32WithMeasure
|
||||
|> Some
|
||||
|
||||
let arg_16 =
|
||||
(match node.["single"] with
|
||||
| null ->
|
||||
@@ -543,6 +701,10 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
||||
F = arg_14
|
||||
F32 = arg_15
|
||||
Single = arg_16
|
||||
IntMeasureOption = arg_17
|
||||
IntMeasureNullable = arg_18
|
||||
Enum = arg_19
|
||||
Timestamp = arg_20
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
@@ -624,3 +786,59 @@ module FirstDuJsonParseExtension =
|
||||
.GetValue<System.Int32> ()
|
||||
)
|
||||
| v -> failwith ("Unrecognised 'type' field value: " + v)
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the HeaderAndValue type
|
||||
[<AutoOpen>]
|
||||
module HeaderAndValueJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type HeaderAndValue with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : HeaderAndValue =
|
||||
let arg_1 =
|
||||
(match node.["value"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("value")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["header"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("header")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Header = arg_0
|
||||
Value = arg_1
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the Foo type
|
||||
[<AutoOpen>]
|
||||
module FooJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type Foo with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : Foo =
|
||||
let arg_0 =
|
||||
match node.["message"] with
|
||||
| null -> None
|
||||
| v -> HeaderAndValue.jsonParse v |> Some
|
||||
|
||||
{
|
||||
Message = arg_0
|
||||
}
|
||||
|
@@ -16,6 +16,12 @@ type InnerTypeWithBoth =
|
||||
ConcreteDict : Dictionary<string, InnerTypeWithBoth>
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
type SomeEnum =
|
||||
| Blah = 1
|
||||
| Thing = 0
|
||||
|
||||
[<Measure>]
|
||||
type measure
|
||||
|
||||
@@ -40,6 +46,10 @@ type JsonRecordTypeWithBoth =
|
||||
F : float<measure>
|
||||
F32 : float32<measure>
|
||||
Single : single<measure>
|
||||
IntMeasureOption : int<measure> option
|
||||
IntMeasureNullable : int<measure> Nullable
|
||||
Enum : SomeEnum
|
||||
Timestamp : DateTimeOffset
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
@@ -48,3 +58,18 @@ type FirstDu =
|
||||
| EmptyCase
|
||||
| Case1 of data : string
|
||||
| Case2 of record : JsonRecordTypeWithBoth * i : int
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
type HeaderAndValue =
|
||||
{
|
||||
Header : string
|
||||
Value : string
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
type Foo =
|
||||
{
|
||||
Message : HeaderAndValue option
|
||||
}
|
||||
|
@@ -49,3 +49,15 @@ module TestJsonParse =
|
||||
|
||||
let actual = s |> JsonNode.Parse |> InnerType.jsonParse
|
||||
actual |> shouldEqual expected
|
||||
|
||||
[<TestCase("thing", SomeEnum.Thing)>]
|
||||
[<TestCase("Thing", SomeEnum.Thing)>]
|
||||
[<TestCase("THING", SomeEnum.Thing)>]
|
||||
[<TestCase("blah", SomeEnum.Blah)>]
|
||||
[<TestCase("Blah", SomeEnum.Blah)>]
|
||||
[<TestCase("BLAH", SomeEnum.Blah)>]
|
||||
let ``Can deserialise enum`` (str : string, expected : SomeEnum) =
|
||||
sprintf "\"%s\"" str
|
||||
|> JsonNode.Parse
|
||||
|> SomeEnum.jsonParse
|
||||
|> shouldEqual expected
|
||||
|
@@ -89,6 +89,10 @@ module TestJsonSerde =
|
||||
let! f = Arb.generate |> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>))
|
||||
let! f32 = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|
||||
let! single = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|
||||
let! intMeasureOption = Arb.generate
|
||||
let! intMeasureNullable = Arb.generate
|
||||
let! someEnum = Gen.choose (0, 1)
|
||||
let! timestamp = Arb.generate
|
||||
|
||||
return
|
||||
{
|
||||
@@ -109,6 +113,10 @@ module TestJsonSerde =
|
||||
F = f
|
||||
F32 = f32
|
||||
Single = single
|
||||
IntMeasureOption = intMeasureOption
|
||||
IntMeasureNullable = intMeasureNullable
|
||||
Enum = enum<SomeEnum> someEnum
|
||||
Timestamp = timestamp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +134,80 @@ module TestJsonSerde =
|
||||
|
||||
property |> Prop.forAll (Arb.fromGen outerGen) |> Check.QuickThrowOnFailure
|
||||
|
||||
[<Test>]
|
||||
let ``Single example of big record`` () =
|
||||
let guid = Guid.Parse "dfe24db5-9f8d-447b-8463-4c0bcf1166d5"
|
||||
|
||||
let data =
|
||||
{
|
||||
A = 3
|
||||
B = "hello!"
|
||||
C = [ 1 ; -9 ]
|
||||
D =
|
||||
{
|
||||
Thing = guid
|
||||
Map = Map.ofList []
|
||||
ReadOnlyDict = readOnlyDict []
|
||||
Dict = dict []
|
||||
ConcreteDict = Dictionary ()
|
||||
}
|
||||
E = [| "I'm-a-string" |]
|
||||
Arr = [| -18883 ; 9100 |]
|
||||
Byte = 87uy<measure>
|
||||
Sbyte = 89y<measure>
|
||||
I = 199993345<measure>
|
||||
I32 = -485832<measure>
|
||||
I64 = -13458625689L<measure>
|
||||
U = 458582u<measure>
|
||||
U32 = 857362147u<measure>
|
||||
U64 = 1234567892123414596UL<measure>
|
||||
F = 8833345667.1<measure>
|
||||
F32 = 1000.98f<measure>
|
||||
Single = 0.334f<measure>
|
||||
IntMeasureOption = Some 981<measure>
|
||||
IntMeasureNullable = Nullable -883<measure>
|
||||
Enum = enum<SomeEnum> 1
|
||||
Timestamp = DateTimeOffset (2024, 07, 01, 17, 54, 00, TimeSpan.FromHours 1.0)
|
||||
}
|
||||
|
||||
let expected =
|
||||
"""{
|
||||
"a": 3,
|
||||
"b": "hello!",
|
||||
"c": [1, -9],
|
||||
"d": {
|
||||
"it\u0027s-a-me": "dfe24db5-9f8d-447b-8463-4c0bcf1166d5",
|
||||
"map": {},
|
||||
"readOnlyDict": {},
|
||||
"dict": {},
|
||||
"concreteDict": {}
|
||||
},
|
||||
"e": ["I\u0027m-a-string"],
|
||||
"arr": [-18883, 9100],
|
||||
"byte": 87,
|
||||
"sbyte": 89,
|
||||
"i": 199993345,
|
||||
"i32": -485832,
|
||||
"i64": -13458625689,
|
||||
"u": 458582,
|
||||
"u32": 857362147,
|
||||
"u64": 1234567892123414596,
|
||||
"f": 8833345667.1,
|
||||
"f32": 1000.98,
|
||||
"single": 0.334,
|
||||
"intMeasureOption": 981,
|
||||
"intMeasureNullable": -883,
|
||||
"enum": 1,
|
||||
"timestamp": "2024-07-01T17:54:00.0000000\u002B01:00"
|
||||
}
|
||||
"""
|
||||
|> fun s -> s.ToCharArray ()
|
||||
|> Array.filter (fun c -> not (Char.IsWhiteSpace c))
|
||||
|> fun s -> new String (s)
|
||||
|
||||
JsonRecordTypeWithBoth.toJsonNode(data).ToJsonString () |> shouldEqual expected
|
||||
JsonRecordTypeWithBoth.jsonParse (JsonNode.Parse expected) |> shouldEqual data
|
||||
|
||||
[<Test>]
|
||||
let ``Guids are treated just like strings`` () =
|
||||
let guidStr = "b1e7496e-6e79-4158-8579-a01de355d3b2"
|
||||
|
@@ -96,6 +96,11 @@ type internal AdtProduct =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal AstHelper =
|
||||
|
||||
let isEnum (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : bool =
|
||||
match repr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true
|
||||
| _ -> false
|
||||
|
||||
let instantiateRecord (fields : (RecordFieldName * SynExpr option) list) : SynExpr =
|
||||
let fields =
|
||||
fields
|
||||
|
@@ -1070,17 +1070,11 @@ module internal CataGenerator =
|
||||
body
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.createIdent "ResizeArray",
|
||||
range0,
|
||||
(SynExpr.createIdent "ResizeArray")
|
||||
|> SynExpr.typeApp
|
||||
[
|
||||
SynType.var (SynTypar.SynTypar (unionCase.GenericName, TyparStaticReq.None, false))
|
||||
],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ unionCase.StackName ] []
|
||||
]
|
||||
|
@@ -449,7 +449,7 @@ module internal HttpClientGenerator =
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "StringContent" ])
|
||||
(SynExpr.createIdent' bodyParamName
|
||||
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
|
||||
|> SynExpr.pipeThroughFunction (fst (JsonSerializeGenerator.serializeNode ty))
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"node"
|
||||
|
@@ -24,7 +24,7 @@ module internal JsonParseGenerator =
|
||||
JsonNumberHandlingArg = None
|
||||
}
|
||||
|
||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v)
|
||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ({propertyName} not found)) | v -> v)
|
||||
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
|
||||
let raiseExpr =
|
||||
SynExpr.applyFunction
|
||||
@@ -95,17 +95,6 @@ module internal JsonParseGenerator =
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ])
|
||||
|
||||
/// match {node} with | null -> None | v -> {body} |> Some
|
||||
/// Use the variable `v` to get access to the `Some`.
|
||||
let createParseLineOption (node : SynExpr) (body : SynExpr) : SynExpr =
|
||||
let body = SynExpr.pipeThroughFunction (SynExpr.createIdent "Some") body
|
||||
|
||||
[
|
||||
SynMatchClause.create SynPat.createNull (SynExpr.createIdent "None")
|
||||
SynMatchClause.create (SynPat.named "v") body
|
||||
]
|
||||
|> SynExpr.createMatch node
|
||||
|
||||
let dotParse (typeName : LongIdent) : LongIdent =
|
||||
List.append typeName [ Ident.create "Parse" ]
|
||||
|
||||
@@ -203,11 +192,36 @@ module internal JsonParseGenerator =
|
||||
node
|
||||
|> asValueGetValue propertyName "string"
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
|
||||
| DateTimeOffset ->
|
||||
node
|
||||
|> asValueGetValue propertyName "string"
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTimeOffset" ; "Parse" ])
|
||||
| NumberType typeName -> parseNumberType options propertyName node typeName
|
||||
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
||||
| OptionType ty ->
|
||||
parseNode None options ty (SynExpr.createIdent "v")
|
||||
|> createParseLineOption node
|
||||
let someClause =
|
||||
parseNode None options ty (SynExpr.createIdent "v")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynMatchClause.create (SynPat.named "v")
|
||||
|
||||
[
|
||||
SynMatchClause.create SynPat.createNull (SynExpr.createIdent "None")
|
||||
someClause
|
||||
]
|
||||
|> SynExpr.createMatch node
|
||||
| NullableType ty ->
|
||||
let someClause =
|
||||
parseNode None options ty (SynExpr.createIdent "v")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Nullable" ])
|
||||
|> SynMatchClause.create (SynPat.named "v")
|
||||
|
||||
[
|
||||
SynMatchClause.create
|
||||
SynPat.createNull
|
||||
(SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Nullable" ]) (SynExpr.CreateConst ()))
|
||||
someClause
|
||||
]
|
||||
|> SynExpr.createMatch node
|
||||
| ListType ty ->
|
||||
parseNode None options ty (SynExpr.createIdent "elt")
|
||||
|> asArrayMapped propertyName "List" node
|
||||
@@ -478,6 +492,59 @@ module internal JsonParseGenerator =
|
||||
|> SynBinding.basic [ Ident.create "ty" ] []
|
||||
]
|
||||
|
||||
let createEnumMaker
|
||||
(spec : JsonParseOutputSpec)
|
||||
(typeName : LongIdent)
|
||||
(fields : (Ident * SynExpr) list)
|
||||
: SynExpr
|
||||
=
|
||||
let numberKind =
|
||||
[ "System" ; "Text" ; "Json" ; "JsonValueKind" ; "Number" ]
|
||||
|> List.map Ident.create
|
||||
|
||||
let stringKind =
|
||||
[ "System" ; "Text" ; "Json" ; "JsonValueKind" ; "String" ]
|
||||
|> List.map Ident.create
|
||||
|
||||
let fail =
|
||||
SynExpr.plus
|
||||
(SynExpr.CreateConst "Unrecognised kind for enum of type: ")
|
||||
(SynExpr.CreateConst (typeName |> List.map _.idText |> String.concat "."))
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
let failString =
|
||||
SynExpr.plus (SynExpr.CreateConst "Unrecognised value for enum: %i") (SynExpr.createIdent "v")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
let parseString =
|
||||
fields
|
||||
|> List.map (fun (ident, _) ->
|
||||
SynMatchClause.create
|
||||
(SynPat.createConst (
|
||||
SynConst.String (ident.idText.ToLowerInvariant (), SynStringKind.Regular, range0)
|
||||
))
|
||||
(SynExpr.createLongIdent' (typeName @ [ ident ]))
|
||||
)
|
||||
|> fun l -> l @ [ SynMatchClause.create (SynPat.named "v") failString ]
|
||||
|> SynExpr.createMatch (
|
||||
asValueGetValue None "string" (SynExpr.createIdent "node")
|
||||
|> SynExpr.callMethod "ToLowerInvariant"
|
||||
)
|
||||
|
||||
[
|
||||
SynMatchClause.create
|
||||
(SynPat.identWithArgs numberKind (SynArgPats.create []))
|
||||
(asValueGetValue None "int" (SynExpr.createIdent "node")
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.typeApp [ SynType.createLongIdent typeName ] (SynExpr.createIdent "enum")
|
||||
))
|
||||
SynMatchClause.create (SynPat.identWithArgs stringKind (SynArgPats.create [])) parseString
|
||||
SynMatchClause.create (SynPat.named "_") fail
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.callMethod "GetValueKind" (SynExpr.createIdent "node"))
|
||||
|
||||
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||
typeDefn
|
||||
@@ -538,6 +605,13 @@ module internal JsonParseGenerator =
|
||||
|> List.map SynUnionCase.extract
|
||||
|> List.map (UnionCase.mapIdentFields optionGet)
|
||||
|> createUnionMaker spec ident
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum (cases, _range), _) ->
|
||||
cases
|
||||
|> List.map (fun c ->
|
||||
match c with
|
||||
| SynEnumCase.SynEnumCase (_, SynIdent.SynIdent (ident, _), value, _, _, _) -> ident, value
|
||||
)
|
||||
|> createEnumMaker spec ident
|
||||
| _ -> failwithf "Not a record or union type"
|
||||
|
||||
[ scaffolding spec ident decl ]
|
||||
@@ -559,20 +633,21 @@ type JsonParseGenerator () =
|
||||
let ast, _ =
|
||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||
|
||||
let recordsAndUnions =
|
||||
let relevantTypes =
|
||||
Ast.extractTypeDefn ast
|
||||
|> List.map (fun (name, defns) ->
|
||||
defns
|
||||
|> List.choose (fun defn ->
|
||||
if Ast.isRecord defn then Some defn
|
||||
elif Ast.isDu defn then Some defn
|
||||
elif AstHelper.isEnum defn then Some defn
|
||||
else None
|
||||
)
|
||||
|> fun defns -> name, defns
|
||||
)
|
||||
|
||||
let namespaceAndTypes =
|
||||
recordsAndUnions
|
||||
relevantTypes
|
||||
|> List.choose (fun (ns, types) ->
|
||||
types
|
||||
|> List.choose (fun typeDef ->
|
||||
|
@@ -13,9 +13,18 @@ type internal JsonSerializeOutputSpec =
|
||||
module internal JsonSerializeGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
|
||||
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
|
||||
// identically equal to null. We have to work around this later, but we might as well just
|
||||
// be efficient here and whip up the null directly.
|
||||
let private jsonNull () =
|
||||
SynExpr.createNull ()
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|
||||
/// Given `input.Ident`, for example, choose how to add it to the ambient `node`.
|
||||
/// The result is a line like `(fun ident -> InnerType.toJsonNode ident)` or `(fun ident -> JsonValue.Create ident)`.
|
||||
let rec serializeNode (fieldType : SynType) : SynExpr =
|
||||
/// Returns also a bool which is true if the resulting SynExpr represents something of type JsonNode.
|
||||
let rec serializeNode (fieldType : SynType) : SynExpr * bool =
|
||||
// TODO: serialization format for DateTime etc
|
||||
match fieldType with
|
||||
| DateOnly
|
||||
@@ -26,29 +35,43 @@ module internal JsonSerializeGenerator =
|
||||
| Guid
|
||||
| Uri ->
|
||||
// JsonValue.Create<type>
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ],
|
||||
range0,
|
||||
[ fieldType ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||
|> SynExpr.typeApp [ fieldType ]
|
||||
|> fun e -> e, false
|
||||
| DateTimeOffset ->
|
||||
// fun field -> field.ToString("o") |> JsonValue.Create<string>
|
||||
let create =
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||
|> SynExpr.typeApp [ SynType.named "string" ]
|
||||
|
||||
SynExpr.createIdent "field"
|
||||
|> SynExpr.callMethodArg "ToString" (SynExpr.CreateConst "o")
|
||||
|> SynExpr.pipeThroughFunction create
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, false
|
||||
| NullableType ty ->
|
||||
// fun field -> if field.HasValue then {serializeNode ty} field.Value else JsonValue.Create null
|
||||
let inner, innerIsJsonNode = serializeNode ty
|
||||
|
||||
SynExpr.applyFunction inner (SynExpr.createLongIdent [ "field" ; "Value" ])
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|> SynExpr.ifThenElse (SynExpr.createLongIdent [ "field" ; "HasValue" ]) (jsonNull ())
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, innerIsJsonNode
|
||||
| OptionType ty ->
|
||||
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
|
||||
let noneClause =
|
||||
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
|
||||
// identically equal to null. We have to work around this later, but we might as well just
|
||||
// be efficient here and whip up the null directly.
|
||||
SynExpr.createNull ()
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|> SynMatchClause.create (SynPat.named "None")
|
||||
let noneClause = jsonNull () |> SynMatchClause.create (SynPat.named "None")
|
||||
|
||||
let someClause =
|
||||
SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "field")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
let inner, innerIsJsonNode = serializeNode ty
|
||||
let target = SynExpr.applyFunction inner (SynExpr.createIdent "field")
|
||||
|
||||
if innerIsJsonNode then
|
||||
target
|
||||
else
|
||||
target
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|> SynMatchClause.create (
|
||||
SynPat.identWithArgs [ Ident.create "Some" ] (SynArgPats.create [ Ident.create "field" ])
|
||||
)
|
||||
@@ -56,6 +79,7 @@ module internal JsonSerializeGenerator =
|
||||
[ noneClause ; someClause ]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "field")
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, true
|
||||
| ArrayType ty
|
||||
| ListType ty ->
|
||||
// fun field ->
|
||||
@@ -72,7 +96,7 @@ module internal JsonSerializeGenerator =
|
||||
SynExpr.createIdent "field",
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "arr" ; "Add" ])
|
||||
(SynExpr.paren (SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "mem"))),
|
||||
(SynExpr.paren (SynExpr.applyFunction (fst (serializeNode ty)) (SynExpr.createIdent "mem"))),
|
||||
range0
|
||||
)
|
||||
SynExpr.createIdent "arr"
|
||||
@@ -85,6 +109,7 @@ module internal JsonSerializeGenerator =
|
||||
|> SynBinding.basic [ Ident.create "arr" ] []
|
||||
]
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, false
|
||||
| IDictionaryType (_keyType, valueType)
|
||||
| DictionaryType (_keyType, valueType)
|
||||
| IReadOnlyDictionaryType (_keyType, valueType)
|
||||
@@ -112,7 +137,7 @@ module internal JsonSerializeGenerator =
|
||||
[
|
||||
SynExpr.createLongIdent [ "key" ; "ToString" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
SynExpr.applyFunction (serializeNode valueType) (SynExpr.createIdent "value")
|
||||
SynExpr.applyFunction (fst (serializeNode valueType)) (SynExpr.createIdent "value")
|
||||
]),
|
||||
range0
|
||||
)
|
||||
@@ -126,6 +151,7 @@ module internal JsonSerializeGenerator =
|
||||
|> SynBinding.basic [ Ident.create "ret" ] []
|
||||
]
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, false
|
||||
| _ ->
|
||||
// {type}.toJsonNode
|
||||
let typeName =
|
||||
@@ -133,16 +159,17 @@ module internal JsonSerializeGenerator =
|
||||
| SynType.LongIdent ident -> ident.LongIdent
|
||||
| _ -> failwith $"Unrecognised type: %+A{fieldType}"
|
||||
|
||||
SynExpr.createLongIdent' (typeName @ [ Ident.create "toJsonNode" ])
|
||||
SynExpr.createLongIdent' (typeName @ [ Ident.create "toJsonNode" ]), true
|
||||
|
||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||
/// `node.Add ({propertyName}, {toJsonNode})`
|
||||
let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
|
||||
[
|
||||
propertyName
|
||||
SynExpr.applyFunction
|
||||
(serializeNode fieldType)
|
||||
SynExpr.pipeThroughFunction
|
||||
(fst (serializeNode fieldType))
|
||||
(SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ])
|
||||
|> SynExpr.paren
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
@@ -229,8 +256,7 @@ module internal JsonSerializeGenerator =
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let recordModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
||||
let inputArg = Ident.create "input"
|
||||
let recordModule (spec : JsonSerializeOutputSpec) (_typeName : LongIdent) (fields : SynField list) =
|
||||
let fields = fields |> List.map SynField.extractWithIdent
|
||||
|
||||
fields
|
||||
@@ -240,7 +266,6 @@ module internal JsonSerializeGenerator =
|
||||
)
|
||||
|> SynExpr.sequential
|
||||
|> fun expr -> SynExpr.Do (expr, range0)
|
||||
|> scaffolding spec typeName inputArg
|
||||
|
||||
let unionModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (cases : SynUnionCase list) =
|
||||
let inputArg = Ident.create "input"
|
||||
@@ -286,7 +311,7 @@ module internal JsonSerializeGenerator =
|
||||
let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs
|
||||
|
||||
let node =
|
||||
SynExpr.applyFunction (serializeNode fieldData.Type) (SynExpr.createIdent' caseName)
|
||||
SynExpr.applyFunction (fst (serializeNode fieldData.Type)) (SynExpr.createIdent' caseName)
|
||||
|
||||
[ propertyName ; node ]
|
||||
|> SynExpr.tuple
|
||||
@@ -313,7 +338,68 @@ module internal JsonSerializeGenerator =
|
||||
SynMatchClause.create pattern action
|
||||
)
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' inputArg)
|
||||
|> scaffolding spec typeName inputArg
|
||||
|
||||
let enumModule
|
||||
(spec : JsonSerializeOutputSpec)
|
||||
(typeName : LongIdent)
|
||||
(cases : (Ident * SynExpr) list)
|
||||
: SynModuleDecl
|
||||
=
|
||||
let fail =
|
||||
SynExpr.CreateConst "Unrecognised value for enum: %O"
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "sprintf")
|
||||
|> SynExpr.applyTo (SynExpr.createIdent "v")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
let body =
|
||||
cases
|
||||
|> List.map (fun (caseName, value) ->
|
||||
value
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||
)
|
||||
|> SynMatchClause.create (SynPat.identWithArgs (typeName @ [ caseName ]) (SynArgPats.create []))
|
||||
)
|
||||
|> fun l -> l @ [ SynMatchClause.create (SynPat.named "v") fail ]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "input")
|
||||
|
||||
let xmlDoc = PreXmlDoc.create "Serialize to a JSON node"
|
||||
|
||||
let returnInfo =
|
||||
SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
|> SynType.LongIdent
|
||||
|
||||
let functionName = Ident.create "toJsonNode"
|
||||
|
||||
let pattern =
|
||||
SynPat.named "input"
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName))
|
||||
|
||||
if spec.ExtensionMethods then
|
||||
let componentInfo =
|
||||
SynComponentInfo.createLong typeName
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
||||
|
||||
let memberDef =
|
||||
body
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let containingType =
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ memberDef ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
else
|
||||
body
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let createModule
|
||||
(namespaceId : LongIdent)
|
||||
@@ -369,14 +455,23 @@ module internal JsonSerializeGenerator =
|
||||
let decls =
|
||||
match synTypeDefnRepr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _range), _) ->
|
||||
[ recordModule spec ident recordFields ]
|
||||
recordModule spec ident recordFields
|
||||
|> scaffolding spec ident (Ident.create "input")
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, unionFields, _range), _) ->
|
||||
[ unionModule spec ident unionFields ]
|
||||
| _ -> failwithf "Only record types currently supported."
|
||||
unionModule spec ident unionFields
|
||||
|> scaffolding spec ident (Ident.create "input")
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum (cases, _range), _) ->
|
||||
cases
|
||||
|> List.map (fun c ->
|
||||
match c with
|
||||
| SynEnumCase.SynEnumCase (_, SynIdent.SynIdent (ident, _), value, _, _, _) -> ident, value
|
||||
)
|
||||
|> enumModule spec ident
|
||||
| ty -> failwithf "Unsupported type: got %O" ty
|
||||
|
||||
[
|
||||
yield! opens |> List.map SynModuleDecl.openAny
|
||||
yield SynModuleDecl.nestedModule info decls
|
||||
yield decls |> List.singleton |> SynModuleDecl.nestedModule info
|
||||
]
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
@@ -394,20 +489,21 @@ type JsonSerializeGenerator () =
|
||||
let ast, _ =
|
||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||
|
||||
let recordsAndUnions =
|
||||
let relevantTypes =
|
||||
Ast.extractTypeDefn ast
|
||||
|> List.map (fun (name, defns) ->
|
||||
defns
|
||||
|> List.choose (fun defn ->
|
||||
if Ast.isRecord defn then Some defn
|
||||
elif Ast.isDu defn then Some defn
|
||||
elif AstHelper.isEnum defn then Some defn
|
||||
else None
|
||||
)
|
||||
|> fun defns -> name, defns
|
||||
)
|
||||
|
||||
let namespaceAndTypes =
|
||||
recordsAndUnions
|
||||
relevantTypes
|
||||
|> List.choose (fun (ns, types) ->
|
||||
types
|
||||
|> List.choose (fun typeDef ->
|
||||
|
@@ -106,43 +106,33 @@ module internal SynExpr =
|
||||
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr
|
||||
| expr -> expr
|
||||
|
||||
/// {obj}.{meth} {arg}
|
||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
let dotGet (field : string) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.DotGet (
|
||||
obj,
|
||||
range0,
|
||||
SynLongIdent.SynLongIdent (id = [ Ident.create meth ], dotRanges = [], trivia = [ None ]),
|
||||
SynLongIdent.SynLongIdent (id = [ Ident.create field ], dotRanges = [], trivia = [ None ]),
|
||||
range0
|
||||
)
|
||||
|> applyTo arg
|
||||
|
||||
/// {obj}.{meth} {arg}
|
||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr = dotGet meth obj |> applyTo arg
|
||||
|
||||
/// {obj}.{meth}()
|
||||
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
||||
callMethodArg meth (SynExpr.CreateConst ()) obj
|
||||
|
||||
let typeApp (types : SynType list) (operand : SynExpr) =
|
||||
SynExpr.TypeApp (operand, range0, types, List.replicate (types.Length - 1) range0, Some range0, range0, range0)
|
||||
|
||||
let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
|
||||
range0,
|
||||
[ SynType.LongIdent (SynLongIdent.create ty) ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0)
|
||||
|> typeApp [ SynType.LongIdent (SynLongIdent.create ty) ]
|
||||
|> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
/// {obj}.{meth}<ty>()
|
||||
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
|
||||
range0,
|
||||
[ SynType.createLongIdent' [ ty ] ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0)
|
||||
|> typeApp [ SynType.createLongIdent' [ ty ] ]
|
||||
|> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
|
@@ -70,6 +70,12 @@ module internal SynLongIdent =
|
||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isNullable (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "System" ; "Nullable" ]
|
||||
| [ "Nullable" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isResponse (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Response" ]
|
||||
|
@@ -59,6 +59,12 @@ module internal SynTypePatterns =
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|NullableType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isNullable ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident when SynLongIdent.isUnit ident -> Some ()
|
||||
@@ -235,6 +241,15 @@ module internal SynTypePatterns =
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateTimeOffset|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateTimeOffset" ]
|
||||
| [ "DateTimeOffset" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Uri|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
|
Reference in New Issue
Block a user