mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-05 12:08:46 +00:00
Compare commits
10 Commits
WoofWare.M
...
WoofWare.M
Author | SHA1 | Date | |
---|---|---|---|
|
8da0fd01fe | ||
|
18c7a2e920 | ||
|
f371ee59fe | ||
|
f8296e54bc | ||
|
adf497c5db | ||
|
04ecbe6002 | ||
|
7b14e52e9d | ||
|
8e47f39efc | ||
|
6942ba42b9 | ||
|
b98080690d |
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fantomas": {
|
||||
"version": "6.3.4",
|
||||
"version": "6.3.7",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
|
@@ -1,5 +1,14 @@
|
||||
Notable changes are recorded here.
|
||||
|
||||
# WoofWare.Myriad.Plugins 2.1.33
|
||||
|
||||
`JsonParse` can now deserialize the discriminated unions which `JsonSerialize` wrote out.
|
||||
|
||||
# WoofWare.Myriad.Plugins 2.1.32, WoofWare.Myriad.Plugins.Attributes 3.1.4
|
||||
|
||||
`JsonSerialize` can now serialize many discriminated unions.
|
||||
(This operation is inherently opinionated, because JSON does not model discriminated unions.)
|
||||
|
||||
# WoofWare.Myriad.Plugins 2.1.20, WoofWare.Myriad.Plugins.Attributes 3.0.1
|
||||
|
||||
We now bundle copies of the RestEase attributes in `WoofWare.Myriad.Plugins.Attributes`, in case you don't want to take a dependency on RestEase.
|
||||
|
@@ -60,7 +60,7 @@ module TreeCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__TreeBuilder (x) ->
|
||||
| Instruction.Process__TreeBuilder x ->
|
||||
match x with
|
||||
| TreeBuilder.Child (arg0_0) ->
|
||||
instructions.Add Instruction.TreeBuilder_Child
|
||||
@@ -68,7 +68,7 @@ module TreeCata =
|
||||
| TreeBuilder.Parent (arg0_0) ->
|
||||
instructions.Add Instruction.TreeBuilder_Parent
|
||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||
| Instruction.Process__Tree (x) ->
|
||||
| Instruction.Process__Tree x ->
|
||||
match x with
|
||||
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
||||
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||
@@ -92,13 +92,13 @@ module TreeCata =
|
||||
let arg0_0 = treeStack.[treeStack.Count - 1]
|
||||
treeStack.RemoveAt (treeStack.Count - 1)
|
||||
cata.TreeBuilder.Parent arg0_0 |> treeBuilderStack.Add
|
||||
| Instruction.Tree_Pair (arg2_0) ->
|
||||
| Instruction.Tree_Pair arg2_0 ->
|
||||
let arg0_0 = treeStack.[treeStack.Count - 1]
|
||||
treeStack.RemoveAt (treeStack.Count - 1)
|
||||
let arg1_0 = treeStack.[treeStack.Count - 1]
|
||||
treeStack.RemoveAt (treeStack.Count - 1)
|
||||
cata.Tree.Pair arg0_0 arg1_0 arg2_0 |> treeStack.Add
|
||||
| Instruction.Tree_Sequential (arg0_0) ->
|
||||
| Instruction.Tree_Sequential arg0_0 ->
|
||||
let arg0_0_len = arg0_0
|
||||
|
||||
let arg0_0 =
|
||||
|
@@ -41,7 +41,7 @@ module FileSystemItemCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__FileSystemItem (x) ->
|
||||
| Instruction.Process__FileSystemItem x ->
|
||||
match x with
|
||||
| FileSystemItem.Directory ({
|
||||
Name = name
|
||||
@@ -116,7 +116,7 @@ module GiftCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__Gift (x) ->
|
||||
| Instruction.Process__Gift x ->
|
||||
match x with
|
||||
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
|
||||
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate arg0_0 |> giftStack.Add
|
||||
@@ -129,7 +129,7 @@ module GiftCata =
|
||||
| Gift.WithACard (arg0_0, message) ->
|
||||
instructions.Add (Instruction.Gift_WithACard (message))
|
||||
instructions.Add (Instruction.Process__Gift arg0_0)
|
||||
| Instruction.Gift_Wrapped (arg1_0) ->
|
||||
| Instruction.Gift_Wrapped arg1_0 ->
|
||||
let arg0_0 = giftStack.[giftStack.Count - 1]
|
||||
giftStack.RemoveAt (giftStack.Count - 1)
|
||||
cata.Gift.Wrapped arg0_0 arg1_0 |> giftStack.Add
|
||||
@@ -137,7 +137,7 @@ module GiftCata =
|
||||
let arg0_0 = giftStack.[giftStack.Count - 1]
|
||||
giftStack.RemoveAt (giftStack.Count - 1)
|
||||
cata.Gift.Boxed arg0_0 |> giftStack.Add
|
||||
| Instruction.Gift_WithACard (message) ->
|
||||
| Instruction.Gift_WithACard message ->
|
||||
let arg0_0 = giftStack.[giftStack.Count - 1]
|
||||
giftStack.RemoveAt (giftStack.Count - 1)
|
||||
cata.Gift.WithACard arg0_0 message |> giftStack.Add
|
||||
|
@@ -8,8 +8,7 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the InnerType type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module InnerType =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerType =
|
||||
@@ -31,8 +30,7 @@ module InnerType =
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JsonRecordType type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JsonRecordType =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordType =
|
||||
|
@@ -19,9 +19,9 @@ type internal PublicTypeMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
}
|
||||
|
||||
interface IPublicType with
|
||||
@@ -44,9 +44,9 @@ type public PublicTypeInternalFalseMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
}
|
||||
|
||||
interface IPublicTypeInternalFalse with
|
||||
@@ -68,8 +68,8 @@ type internal InternalTypeMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : InternalTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface InternalType with
|
||||
@@ -90,8 +90,8 @@ type private PrivateTypeMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateType with
|
||||
@@ -112,8 +112,8 @@ type private PrivateTypeInternalFalseMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateTypeInternalFalse with
|
||||
@@ -133,7 +133,7 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
}
|
||||
|
||||
interface VeryPublicType<'a, 'b> with
|
||||
@@ -157,12 +157,12 @@ type internal CurriedMock<'a> =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : CurriedMock<'a> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
|
||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
|
||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
|
||||
}
|
||||
|
||||
interface Curried<'a> with
|
||||
@@ -195,9 +195,9 @@ type internal TypeWithInterfaceMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : TypeWithInterfaceMock =
|
||||
{
|
||||
Dispose = (fun _ -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface TypeWithInterface with
|
||||
|
@@ -41,8 +41,7 @@ module MemberJsonSerializeExtension =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymOpeningHours type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymOpeningHours =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymOpeningHours =
|
||||
@@ -78,8 +77,7 @@ module GymOpeningHours =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymAccessOptions type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymAccessOptions =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAccessOptions =
|
||||
@@ -114,8 +112,7 @@ module GymAccessOptions =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymLocation type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymLocation =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymLocation =
|
||||
@@ -192,8 +189,7 @@ module GymLocation =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymAddress type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymAddress =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAddress =
|
||||
@@ -259,8 +255,7 @@ module GymAddress =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the Gym type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module Gym =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Gym =
|
||||
@@ -620,8 +615,7 @@ module MemberJsonParseExtension =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymAttendance type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymAttendance =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAttendance =
|
||||
@@ -743,8 +737,7 @@ module GymAttendance =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the MemberActivityDto type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module MemberActivityDto =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : MemberActivityDto =
|
||||
@@ -832,8 +825,7 @@ module MemberActivityDto =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the SessionsAggregate type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module SessionsAggregate =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsAggregate =
|
||||
@@ -881,8 +873,7 @@ module SessionsAggregate =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the VisitGym type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module VisitGym =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : VisitGym =
|
||||
@@ -930,8 +921,7 @@ module VisitGym =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the Visit type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module Visit =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
|
||||
@@ -993,8 +983,7 @@ module Visit =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the SessionsSummary type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module SessionsSummary =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
|
||||
@@ -1029,8 +1018,7 @@ module SessionsSummary =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the Sessions type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module Sessions =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Sessions =
|
||||
@@ -1066,8 +1054,7 @@ module Sessions =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the UriThing type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module UriThing =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : UriThing =
|
||||
|
@@ -17,8 +17,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module PureGymApi =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IPureGymApi =
|
||||
@@ -1055,8 +1054,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module internal ApiWithoutBaseAddress =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IApiWithoutBaseAddress =
|
||||
@@ -1107,8 +1105,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithBasePath =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IApiWithBasePath =
|
||||
@@ -1159,8 +1156,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithBasePathAndAddress =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IApiWithBasePathAndAddress =
|
||||
@@ -1205,8 +1201,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithHeaders =
|
||||
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||
let make
|
||||
@@ -1268,8 +1263,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithHeaders2 =
|
||||
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||
let make
|
||||
|
@@ -167,7 +167,7 @@ module FirstDuJsonSerializeExtension =
|
||||
|
||||
match input with
|
||||
| FirstDu.EmptyCase -> node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "emptyCase")
|
||||
| FirstDu.Case1 (arg0) ->
|
||||
| FirstDu.Case1 arg0 ->
|
||||
node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case1")
|
||||
let dataNode = System.Text.Json.Nodes.JsonObject ()
|
||||
dataNode.Add ("data", System.Text.Json.Nodes.JsonValue.Create<string> arg0)
|
||||
@@ -378,3 +378,83 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
||||
E = arg_4
|
||||
F = arg_5
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the FirstDu type
|
||||
[<AutoOpen>]
|
||||
module FirstDuJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type FirstDu with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : FirstDu =
|
||||
let ty =
|
||||
(match node.["type"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("type")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
|> (fun v -> v.GetValue<string> ())
|
||||
|
||||
match ty with
|
||||
| "emptyCase" -> FirstDu.EmptyCase
|
||||
| "case1" ->
|
||||
let node =
|
||||
(match node.["data"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("data")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
|
||||
FirstDu.Case1 (
|
||||
(match node.["data"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("data")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
)
|
||||
| "case2" ->
|
||||
let node =
|
||||
(match node.["data"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("data")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
|
||||
FirstDu.Case2 (
|
||||
JsonRecordTypeWithBoth.jsonParse (
|
||||
match node.["record"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("record")
|
||||
)
|
||||
)
|
||||
| v -> v
|
||||
),
|
||||
(match node.["i"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("i")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
)
|
||||
| v -> failwith ("Unrecognised 'type' field value: " + v)
|
||||
|
@@ -8,8 +8,7 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JwtVaultAuthResponse =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultAuthResponse =
|
||||
@@ -164,8 +163,7 @@ module JwtVaultAuthResponse =
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtVaultResponse type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JwtVaultResponse =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultResponse =
|
||||
@@ -239,8 +237,7 @@ module JwtVaultResponse =
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtSecretResponse type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JwtSecretResponse =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtSecretResponse =
|
||||
@@ -455,8 +452,7 @@ open System.Threading.Tasks
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module VaultClient =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IVaultClient =
|
||||
@@ -553,8 +549,7 @@ open System.Threading.Tasks
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module VaultClientNonExtensionMethod =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IVaultClientNonExtensionMethod =
|
||||
|
@@ -41,7 +41,7 @@ module MyListCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__MyList (x) ->
|
||||
| Instruction.Process__MyList x ->
|
||||
match x with
|
||||
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
||||
| MyList.Cons ({
|
||||
@@ -50,7 +50,7 @@ module MyListCata =
|
||||
}) ->
|
||||
instructions.Add (Instruction.MyList_Cons (head))
|
||||
instructions.Add (Instruction.Process__MyList tail)
|
||||
| Instruction.MyList_Cons (head) ->
|
||||
| Instruction.MyList_Cons head ->
|
||||
let tail = myListStack.[myListStack.Count - 1]
|
||||
myListStack.RemoveAt (myListStack.Count - 1)
|
||||
cata.MyList.Cons head tail |> myListStack.Add
|
||||
@@ -97,13 +97,13 @@ module MyList2Cata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__MyList2 (x) ->
|
||||
| Instruction.Process__MyList2 x ->
|
||||
match x with
|
||||
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
||||
| MyList2.Cons (arg0_0, arg1_0) ->
|
||||
instructions.Add (Instruction.MyList2_Cons (arg0_0))
|
||||
instructions.Add (Instruction.Process__MyList2 arg1_0)
|
||||
| Instruction.MyList2_Cons (arg0_0) ->
|
||||
| Instruction.MyList2_Cons arg0_0 ->
|
||||
let arg1_0 = myList2Stack.[myList2Stack.Count - 1]
|
||||
myList2Stack.RemoveAt (myList2Stack.Count - 1)
|
||||
cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add
|
||||
|
@@ -29,6 +29,7 @@ type JsonRecordTypeWithBoth =
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
type FirstDu =
|
||||
| EmptyCase
|
||||
| Case1 of data : string
|
||||
|
@@ -10,19 +10,10 @@
|
||||
<WarnOn>FS3388,FS3559</WarnOn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.133" PrivateAssets="all"/>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.139" PrivateAssets="all"/>
|
||||
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
|
||||
</ItemGroup>
|
||||
<!--
|
||||
SourceLink doesn't support F# deterministic builds out of the box,
|
||||
so tell SourceLink that our source root is going to be remapped.
|
||||
-->
|
||||
<Target Name="MapSourceRoot" BeforeTargets="_GenerateSourceLinkFile" Condition="'$(SourceRootMappedPathsFeatureSupported)' != 'true'">
|
||||
<ItemGroup>
|
||||
<SourceRoot Update="@(SourceRoot)">
|
||||
<MappedPath>Z:\CheckoutRoot\WoofWare.Myriad\</MappedPath>
|
||||
</SourceRoot>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
@@ -12,7 +12,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.40" />
|
||||
<PackageReference Include="ApiSurface" Version="4.0.41" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
|
@@ -2,10 +2,9 @@ namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.IO
|
||||
open System.Text
|
||||
open System.Text.Json
|
||||
open System.Text.Json.Nodes
|
||||
open FsCheck.Random
|
||||
open Microsoft.FSharp.Reflection
|
||||
open NUnit.Framework
|
||||
open FsCheck
|
||||
open FsUnitTyped
|
||||
@@ -124,3 +123,83 @@ module TestJsonSerde =
|
||||
|> shouldEqual (
|
||||
sprintf """{"it\u0027s-a-me":"%s","map":{},"readOnlyDict":{},"dict":{},"concreteDict":{}}""" guidStr
|
||||
)
|
||||
|
||||
type Generators =
|
||||
static member TestCase () =
|
||||
{ new Arbitrary<InnerTypeWithBoth>() with
|
||||
override x.Generator = innerGen 5
|
||||
}
|
||||
|
||||
let sanitiseInner (r : InnerTypeWithBoth) : InnerTypeWithBoth =
|
||||
{
|
||||
Thing = r.Thing
|
||||
Map = r.Map
|
||||
ReadOnlyDict = r.ReadOnlyDict
|
||||
Dict = r.Dict
|
||||
ConcreteDict = r.ConcreteDict
|
||||
}
|
||||
|
||||
let sanitiseRec (r : JsonRecordTypeWithBoth) : JsonRecordTypeWithBoth =
|
||||
{
|
||||
A = r.A
|
||||
B = if isNull r.B then "<null>" else r.B
|
||||
C =
|
||||
if Object.ReferenceEquals (r.C, (null : obj)) then
|
||||
[]
|
||||
else
|
||||
r.C
|
||||
D = sanitiseInner r.D
|
||||
E = if isNull r.E then [||] else r.E
|
||||
F =
|
||||
if Object.ReferenceEquals (r.F, (null : obj)) then
|
||||
[||]
|
||||
else
|
||||
r.F
|
||||
}
|
||||
|
||||
let duGen =
|
||||
gen {
|
||||
let! case = Gen.choose (0, 2)
|
||||
|
||||
match case with
|
||||
| 0 -> return FirstDu.EmptyCase
|
||||
| 1 ->
|
||||
let! s = Arb.generate<NonNull<string>>
|
||||
return FirstDu.Case1 s.Get
|
||||
| 2 ->
|
||||
let! i = Arb.generate<int>
|
||||
let! record = outerGen
|
||||
return FirstDu.Case2 (record, i)
|
||||
| _ -> return failwith $"unexpected: %i{case}"
|
||||
}
|
||||
|
||||
[<Test>]
|
||||
let ``Discriminated union works`` () =
|
||||
let property (du : FirstDu) : unit =
|
||||
du
|
||||
|> FirstDu.toJsonNode
|
||||
|> fun s -> s.ToJsonString ()
|
||||
|> JsonNode.Parse
|
||||
|> FirstDu.jsonParse
|
||||
|> shouldEqual du
|
||||
|
||||
property |> Prop.forAll (Arb.fromGen duGen) |> Check.QuickThrowOnFailure
|
||||
|
||||
[<Test>]
|
||||
let ``DU generator covers all cases`` () =
|
||||
let rand = Random ()
|
||||
let cases = FSharpType.GetUnionCases typeof<FirstDu>
|
||||
let counts = Array.zeroCreate<int> cases.Length
|
||||
|
||||
let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu>
|
||||
|
||||
let mutable i = 0
|
||||
|
||||
while i < 10_000 && Array.exists (fun i -> i = 0) counts do
|
||||
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
|
||||
let tag = decompose du
|
||||
counts.[tag] <- counts.[tag] + 1
|
||||
i <- i + 1
|
||||
|
||||
for i in counts do
|
||||
i |> shouldBeGreaterThan 0
|
||||
|
@@ -12,7 +12,8 @@ module TestSurface =
|
||||
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
||||
|
||||
[<Test>]
|
||||
let ``Check version against remote`` () =
|
||||
// https://github.com/nunit/nunit3-vs-adapter/issues/876
|
||||
let CheckVersionAgainstRemote () =
|
||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins"
|
||||
|
||||
[<Test ; Explicit>]
|
||||
|
@@ -33,7 +33,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.40"/>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.41"/>
|
||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
||||
|
@@ -1,10 +1,8 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core.AstExtensions
|
||||
|
||||
type internal ParameterInfo =
|
||||
{
|
||||
@@ -98,30 +96,6 @@ type internal AdtProduct =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal AstHelper =
|
||||
|
||||
/// Given e.g. "byte", returns "System.Byte".
|
||||
let qualifyPrimitiveType (typeName : string) : LongIdent option =
|
||||
match typeName with
|
||||
| "float32"
|
||||
| "single" -> [ "System" ; "Single" ] |> Some
|
||||
| "float"
|
||||
| "double" -> [ "System" ; "Double" ] |> Some
|
||||
| "byte"
|
||||
| "uint8" -> [ "System" ; "Byte" ] |> Some
|
||||
| "sbyte"
|
||||
| "int8" -> [ "System" ; "SByte" ] |> Some
|
||||
| "int16" -> [ "System" ; "Int16" ] |> Some
|
||||
| "int"
|
||||
| "int32" -> [ "System" ; "Int32" ] |> Some
|
||||
| "int64" -> [ "System" ; "Int64" ] |> Some
|
||||
| "uint16" -> [ "System" ; "UInt16" ] |> Some
|
||||
| "uint"
|
||||
| "uint32" -> [ "System" ; "UInt32" ] |> Some
|
||||
| "uint64" -> [ "System" ; "UInt64" ] |> Some
|
||||
| "char" -> [ "System" ; "Char" ] |> Some
|
||||
| "decimal" -> [ "System" ; "Decimal" ] |> Some
|
||||
| _ -> None
|
||||
|> Option.map (List.map Ident.Create)
|
||||
|
||||
let instantiateRecord (fields : (RecordFieldName * SynExpr option) list) : SynExpr =
|
||||
let fields =
|
||||
fields
|
||||
@@ -130,86 +104,17 @@ module internal AstHelper =
|
||||
SynExpr.Record (None, None, fields, range0)
|
||||
|
||||
let defineRecordType (record : RecordType) : SynTypeDefn =
|
||||
let repr =
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, Seq.toList record.Fields, range0), range0)
|
||||
|
||||
let name =
|
||||
SynComponentInfo.Create (
|
||||
[ record.Name ],
|
||||
?xmldoc = record.XmlDoc,
|
||||
?parameters = record.Generics,
|
||||
access = record.Accessibility
|
||||
)
|
||||
SynComponentInfo.create record.Name
|
||||
|> SynComponentInfo.setAccessibility record.Accessibility
|
||||
|> match record.XmlDoc with
|
||||
| None -> id
|
||||
| Some doc -> SynComponentInfo.withDocString doc
|
||||
|> SynComponentInfo.setGenerics record.Generics
|
||||
|
||||
let trivia : SynTypeDefnTrivia =
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = Some range0
|
||||
WithKeyword = Some range0
|
||||
}
|
||||
|
||||
SynTypeDefn (name, repr, defaultArg record.Members SynMemberDefns.Empty, None, range0, trivia)
|
||||
|
||||
let isOptionIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isUnitIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
| _ -> false
|
||||
|
||||
let isListIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider FSharpList or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isArrayIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when
|
||||
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|
||||
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
|
||||
->
|
||||
true
|
||||
| _ -> false
|
||||
|
||||
let isResponseIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Response" ]
|
||||
| [ "RestEase" ; "Response" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isMapIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Map" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isReadOnlyDictionaryIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IReadOnlyDictionary" ]
|
||||
| [ "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isDictionaryIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Dictionary" ]
|
||||
| [ "Generic" ; "Dictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "Dictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isIDictionaryIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IDictionary" ]
|
||||
| [ "Generic" ; "IDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
|
||||
| _ -> false
|
||||
SynTypeDefnRepr.record (Seq.toList record.Fields)
|
||||
|> SynTypeDefn.create name
|
||||
|> SynTypeDefn.withMemberDefns (defaultArg record.Members SynMemberDefns.Empty)
|
||||
|
||||
let rec private extractOpensFromDecl (moduleDecls : SynModuleDecl list) : SynOpenDeclTarget list =
|
||||
moduleDecls
|
||||
@@ -231,12 +136,12 @@ module internal AstHelper =
|
||||
| SynType.Paren (inner, _) ->
|
||||
let result, _ = convertSigParam inner
|
||||
result, true
|
||||
| SynType.LongIdent ident ->
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
{
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.CreateLongIdent ident
|
||||
Type = SynType.createLongIdent ident
|
||||
},
|
||||
false
|
||||
| SynType.SignatureParameter (attrs, opt, id, usedType, _) ->
|
||||
@@ -254,7 +159,7 @@ module internal AstHelper =
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.Var (typar, range0)
|
||||
Type = SynType.var typar
|
||||
},
|
||||
false
|
||||
| _ -> failwithf "expected SignatureParameter, got: %+A" ty
|
||||
@@ -283,10 +188,6 @@ module internal AstHelper =
|
||||
}
|
||||
| _ -> failwithf "Didn't have alternating type-and-star in interface member definition: %+A" tupleType
|
||||
|
||||
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
||||
(ret, List.rev inputs)
|
||||
||> List.fold (fun ty input -> SynType.CreateFun (input, ty))
|
||||
|
||||
/// Returns the args (where these are tuple types if curried) in order, and the return type.
|
||||
let rec getType (ty : SynType) : (SynType * bool) list * SynType =
|
||||
match ty with
|
||||
@@ -299,7 +200,7 @@ module internal AstHelper =
|
||||
| SynType.Paren (argType, _) -> getType argType, true
|
||||
| _ -> getType argType, false
|
||||
|
||||
((toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret
|
||||
((SynType.toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret
|
||||
| _ -> [], ty
|
||||
|
||||
let private parseMember (slotSig : SynValSig) (flags : SynMemberFlags) : Choice<MemberInfo, PropertyInfo> =
|
||||
@@ -356,7 +257,7 @@ module internal AstHelper =
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident)
|
||||
Type = SynType.createLongIdent ident
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
@@ -368,7 +269,7 @@ module internal AstHelper =
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.Var (typar, range0)
|
||||
Type = SynType.var typar
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
@@ -522,190 +423,3 @@ module internal AstHelper =
|
||||
}
|
||||
)
|
||||
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
||||
|
||||
[<AutoOpen>]
|
||||
module internal SynTypePatterns =
|
||||
let (|OptionType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isOptionIdent ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident when AstHelper.isUnitIdent ident -> Some ()
|
||||
| _ -> None
|
||||
|
||||
let (|ListType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|ArrayType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isArrayIdent ident ->
|
||||
Some innerType
|
||||
| SynType.Array (1, innerType, _) -> Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|RestEaseResponseType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isResponseIdent ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|DictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isDictionaryIdent ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isIDictionaryIdent ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
|
||||
AstHelper.isReadOnlyDictionaryIdent ident
|
||||
->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|MapType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isMapIdent ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|BigInt|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "bigint" ]
|
||||
| [ "BigInteger" ]
|
||||
| [ "Numerics" ; "BigInteger" ]
|
||||
| [ "System" ; "Numerics" ; "BigInteger" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Returns the type, qualified as in e.g. `System.Boolean`.
|
||||
let (|PrimitiveType|_|) (fieldType : SynType) : LongIdent option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> AstHelper.qualifyPrimitiveType i.idText
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|String|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] ->
|
||||
[ "string" ]
|
||||
|> List.tryFind (fun s -> s = i.idText)
|
||||
|> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Byte|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Guid|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Guid" ]
|
||||
| [ "Guid" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Http" ; "HttpResponseMessage" ]
|
||||
| [ "HttpResponseMessage" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpContent|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Http" ; "HttpContent" ]
|
||||
| [ "HttpContent" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Stream|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "IO" ; "Stream" ]
|
||||
| [ "IO" ; "Stream" ]
|
||||
| [ "Stream" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|NumberType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "string" ; "float" ; "int" ; "bool" ] |> List.tryFind (fun s -> s = i.idText)
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateOnly|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateOnly" ]
|
||||
| [ "DateOnly" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateTime|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateTime" ]
|
||||
| [ "DateTime" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Uri|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Uri" ]
|
||||
| [ "Uri" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Task|_|) (fieldType : SynType) : SynType option =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "Task" ]
|
||||
| [ "Tasks" ; "Task" ]
|
||||
| [ "Threading" ; "Tasks" ; "Task" ]
|
||||
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
|
||||
match args with
|
||||
| [ arg ] -> Some arg
|
||||
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,6 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System.Net.Http
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal HttpClientGeneratorOutputSpec =
|
||||
{
|
||||
@@ -14,7 +11,6 @@ type internal HttpClientGeneratorOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal HttpClientGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type PathSpec =
|
||||
@@ -82,7 +78,7 @@ module internal HttpClientGenerator =
|
||||
let matchingAttrs =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "Get"
|
||||
| "GetAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Get"
|
||||
@@ -144,7 +140,7 @@ module internal HttpClientGenerator =
|
||||
let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "Header"
|
||||
| "RestEase.Header"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Header" ->
|
||||
@@ -158,7 +154,7 @@ module internal HttpClientGenerator =
|
||||
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
|
||||
attrs
|
||||
|> List.exists (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "AllowAnyStatusCode"
|
||||
| "AllowAnyStatusCodeAttribute"
|
||||
| "RestEase.AllowAnyStatusCode"
|
||||
@@ -174,35 +170,6 @@ module internal HttpClientGenerator =
|
||||
(info : MemberInfo)
|
||||
: SynMemberDefn
|
||||
=
|
||||
let valInfo =
|
||||
SynValInfo.SynValInfo (
|
||||
[
|
||||
[ SynArgInfo.Empty ]
|
||||
[
|
||||
for arg in info.Args do
|
||||
match arg.Id with
|
||||
| None -> yield SynArgInfo.CreateIdString (failwith "TODO: create an arg name")
|
||||
| Some id -> yield SynArgInfo.CreateId id
|
||||
]
|
||||
],
|
||||
SynArgInfo.Empty
|
||||
)
|
||||
|
||||
let valData =
|
||||
SynValData (
|
||||
Some
|
||||
{
|
||||
IsInstance = true
|
||||
IsDispatchSlot = false
|
||||
IsOverrideOrExplicitImpl = true
|
||||
IsFinal = false
|
||||
GetterOrSetterIsCompilerGenerated = false
|
||||
MemberKind = SynMemberKind.Member
|
||||
},
|
||||
valInfo,
|
||||
None
|
||||
)
|
||||
|
||||
let args =
|
||||
info.Args
|
||||
|> List.map (fun arg ->
|
||||
@@ -213,15 +180,13 @@ module internal HttpClientGenerator =
|
||||
|
||||
let argType =
|
||||
if arg.IsOptional then
|
||||
SynType.CreateApp (
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateString "option"),
|
||||
[ arg.Type ],
|
||||
isPostfix = true
|
||||
)
|
||||
SynType.appPostfix "option" arg.Type
|
||||
else
|
||||
arg.Type
|
||||
|
||||
argName, SynPat.CreateTyped (SynPat.CreateNamed argName, argType)
|
||||
// We'll be tupling these up anyway, so don't need the parens
|
||||
// around the type annotations.
|
||||
argName, SynPat.annotateTypeNoParen argType (SynPat.namedI argName)
|
||||
)
|
||||
|
||||
let cancellationTokenArg =
|
||||
@@ -229,26 +194,6 @@ module internal HttpClientGenerator =
|
||||
| None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}"
|
||||
| Some (arg, _) -> arg
|
||||
|
||||
let argPats =
|
||||
let args = args |> List.map snd
|
||||
|
||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|> SynPat.CreateParen
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
|
||||
let headPat =
|
||||
let thisIdent = if variableHeaders.IsEmpty then "_" else "this"
|
||||
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ Ident.Create thisIdent ; info.Identifier ],
|
||||
None,
|
||||
None,
|
||||
argPats,
|
||||
None,
|
||||
range0
|
||||
)
|
||||
|
||||
let requestUriTrailer =
|
||||
(info.UrlTemplate, info.Args)
|
||||
||> List.fold (fun template arg ->
|
||||
@@ -269,10 +214,10 @@ module internal HttpClientGenerator =
|
||||
template
|
||||
|> SynExpr.callMethodArg
|
||||
"Replace"
|
||||
(SynExpr.CreateParenedTuple
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.CreateConstString ("{" + substituteId + "}")
|
||||
SynExpr.callMethod "ToString" (SynExpr.CreateIdent varName)
|
||||
SynExpr.CreateConst ("{" + substituteId + "}")
|
||||
SynExpr.callMethod "ToString" (SynExpr.createIdent' varName)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||
)
|
||||
@@ -314,30 +259,27 @@ module internal HttpClientGenerator =
|
||||
let urlSeparator =
|
||||
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
||||
let questionMark =
|
||||
SynExpr.CreateConst (SynConst.Int32 63)
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "char")
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.CreateConst 63
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "char")
|
||||
|> SynExpr.paren
|
||||
|
||||
let containsQuestion =
|
||||
info.UrlTemplate
|
||||
|> SynExpr.callMethodArg "IndexOf" questionMark
|
||||
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst (SynConst.Int32 0))
|
||||
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst 0)
|
||||
|
||||
SynExpr.ifThenElse
|
||||
containsQuestion
|
||||
(SynExpr.CreateConst (SynConst.CreateString "?"))
|
||||
(SynExpr.CreateConst (SynConst.CreateString "&"))
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.ifThenElse containsQuestion (SynExpr.CreateConst "?") (SynExpr.CreateConst "&")
|
||||
|> SynExpr.paren
|
||||
|
||||
let prefix =
|
||||
SynExpr.CreateIdent firstValueId
|
||||
SynExpr.createIdent' firstValueId
|
||||
|> SynExpr.toString firstValue.Type
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConstString (firstKey + "=")))
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConst (firstKey + "=")))
|
||||
|
||||
(prefix, queryParams)
|
||||
||> List.fold (fun uri (paramKey, paramValue) ->
|
||||
@@ -346,16 +288,16 @@ module internal HttpClientGenerator =
|
||||
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
||||
| Some id -> id
|
||||
|
||||
SynExpr.toString paramValue.Type (SynExpr.CreateIdent paramValueId)
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.toString paramValue.Type (SynExpr.createIdent' paramValueId)
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConstString ("&" + paramKey + "=")))
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConst ("&" + paramKey + "=")))
|
||||
)
|
||||
|> SynExpr.plus requestUriTrailer
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|
||||
let requestUri =
|
||||
let uriIdent = SynExpr.createLongIdent [ "System" ; "Uri" ]
|
||||
@@ -364,45 +306,37 @@ module internal HttpClientGenerator =
|
||||
|
||||
let baseAddress =
|
||||
[
|
||||
SynMatchClause.Create (
|
||||
SynPat.CreateNull,
|
||||
None,
|
||||
match info.BaseAddress with
|
||||
| None ->
|
||||
[
|
||||
SynExpr.CreateApp (SynExpr.CreateIdentString "nameof", SynExpr.CreateParen baseAddress)
|
||||
SynExpr.CreateConstString
|
||||
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise")
|
||||
| Some expr -> SynExpr.CreateApp (uriIdent, expr)
|
||||
)
|
||||
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v")
|
||||
SynMatchClause.create
|
||||
SynPat.createNull
|
||||
(match info.BaseAddress with
|
||||
| None ->
|
||||
[
|
||||
SynExpr.applyFunction (SynExpr.createIdent "nameof") (SynExpr.paren baseAddress)
|
||||
SynExpr.CreateConst
|
||||
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
| Some expr -> SynExpr.applyFunction uriIdent expr)
|
||||
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
|
||||
]
|
||||
|> SynExpr.createMatch baseAddress
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|
||||
SynExpr.App (
|
||||
ExprAtomicFlag.Atomic,
|
||||
false,
|
||||
uriIdent,
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
baseAddress
|
||||
SynExpr.CreateApp (
|
||||
uriIdent,
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
requestUriTrailer
|
||||
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
|
||||
]
|
||||
)
|
||||
],
|
||||
range0
|
||||
)
|
||||
[
|
||||
baseAddress
|
||||
SynExpr.applyFunction
|
||||
uriIdent
|
||||
(SynExpr.tuple
|
||||
[
|
||||
requestUriTrailer
|
||||
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
|
||||
])
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction uriIdent
|
||||
|
||||
let bodyParams =
|
||||
info.Args
|
||||
@@ -436,56 +370,43 @@ module internal HttpClientGenerator =
|
||||
let httpReqMessageConstructor =
|
||||
[
|
||||
SynExpr.equals
|
||||
(SynExpr.CreateIdentString "Method")
|
||||
(SynExpr.createIdent "Method")
|
||||
(SynExpr.createLongIdent
|
||||
[ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ])
|
||||
SynExpr.equals (SynExpr.CreateIdentString "RequestUri") (SynExpr.CreateIdentString "uri")
|
||||
SynExpr.equals (SynExpr.createIdent "RequestUri") (SynExpr.createIdent "uri")
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tupleNoParen
|
||||
|
||||
let returnExpr =
|
||||
match info.TaskReturnType with
|
||||
| HttpResponseMessage -> SynExpr.CreateIdentString "response"
|
||||
| String -> SynExpr.CreateIdentString "responseString"
|
||||
| Stream -> SynExpr.CreateIdentString "responseStream"
|
||||
| HttpResponseMessage -> SynExpr.createIdent "response"
|
||||
| String -> SynExpr.createIdent "responseString"
|
||||
| Stream -> SynExpr.createIdent "responseStream"
|
||||
| RestEaseResponseType contents ->
|
||||
let deserialiser =
|
||||
SynExpr.CreateLambda (
|
||||
[ SynPat.CreateConst SynConst.Unit ],
|
||||
SynExpr.CreateParen (
|
||||
JsonParseGenerator.parseNode
|
||||
None
|
||||
JsonParseGenerator.JsonParseOption.None
|
||||
contents
|
||||
(SynExpr.CreateIdentString "jsonNode")
|
||||
)
|
||||
)
|
||||
JsonParseGenerator.parseNode
|
||||
None
|
||||
JsonParseGenerator.JsonParseOption.None
|
||||
contents
|
||||
(SynExpr.createIdent "jsonNode")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.createThunk
|
||||
|
||||
// new RestEase.Response (content : string, response : HttpResponseMessage, deserialiser : unit -> 'T)
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent (SynLongIdent.Create [ "RestEase" ; "Response" ]),
|
||||
Some range0,
|
||||
[ SynType.Anon range0 ],
|
||||
[],
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
),
|
||||
SynExpr.CreateParenedTuple
|
||||
SynExpr.createNew
|
||||
(SynType.app' (SynType.createLongIdent' [ "RestEase" ; "Response" ]) [ SynType.Anon range0 ])
|
||||
(SynExpr.tupleNoParen
|
||||
[
|
||||
SynExpr.CreateIdentString "responseString"
|
||||
SynExpr.CreateIdentString "response"
|
||||
SynExpr.CreateParen deserialiser
|
||||
],
|
||||
range0
|
||||
)
|
||||
SynExpr.createIdent "responseString"
|
||||
SynExpr.createIdent "response"
|
||||
deserialiser
|
||||
])
|
||||
| retType ->
|
||||
JsonParseGenerator.parseNode
|
||||
None
|
||||
JsonParseGenerator.JsonParseOption.None
|
||||
retType
|
||||
(SynExpr.CreateIdentString "jsonNode")
|
||||
(SynExpr.createIdent "jsonNode")
|
||||
|
||||
let handleBodyParams =
|
||||
match bodyParam with
|
||||
@@ -498,20 +419,15 @@ module internal HttpClientGenerator =
|
||||
[
|
||||
Let (
|
||||
"queryParams",
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create
|
||||
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ]
|
||||
),
|
||||
SynExpr.CreateParen (SynExpr.CreateIdent bodyParamName),
|
||||
range0
|
||||
)
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent'
|
||||
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ])
|
||||
(SynExpr.createIdent' bodyParamName)
|
||||
)
|
||||
Do (
|
||||
SynExpr.LongIdentSet (
|
||||
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||
SynExpr.CreateIdentString "queryParams",
|
||||
SynLongIdent.createS' [ "httpMessage" ; "Content" ],
|
||||
SynExpr.createIdent "queryParams",
|
||||
range0
|
||||
)
|
||||
)
|
||||
@@ -520,8 +436,8 @@ module internal HttpClientGenerator =
|
||||
[
|
||||
Do (
|
||||
SynExpr.LongIdentSet (
|
||||
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||
SynExpr.CreateIdent bodyParamName,
|
||||
SynLongIdent.createS' [ "httpMessage" ; "Content" ],
|
||||
SynExpr.createIdent' bodyParamName,
|
||||
range0
|
||||
)
|
||||
)
|
||||
@@ -530,38 +446,27 @@ module internal HttpClientGenerator =
|
||||
[
|
||||
Let (
|
||||
"queryParams",
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "StringContent" ]
|
||||
),
|
||||
SynExpr.CreateParen (
|
||||
SynExpr.CreateIdent bodyParamName
|
||||
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"node"
|
||||
(SynExpr.ifThenElse
|
||||
(SynExpr.CreateApp (
|
||||
SynExpr.CreateIdentString "isNull",
|
||||
SynExpr.CreateIdentString "node"
|
||||
))
|
||||
(SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "node" ; "ToJsonString" ]
|
||||
),
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
))
|
||||
(SynExpr.CreateConst (SynConst.CreateString "null")))
|
||||
)
|
||||
),
|
||||
range0
|
||||
)
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "StringContent" ])
|
||||
(SynExpr.createIdent' bodyParamName
|
||||
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"node"
|
||||
(SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "isNull")
|
||||
(SynExpr.createIdent "node"))
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "node" ; "ToJsonString" ])
|
||||
(SynExpr.CreateConst ()))
|
||||
(SynExpr.CreateConst "null"))
|
||||
))
|
||||
)
|
||||
Do (
|
||||
SynExpr.LongIdentSet (
|
||||
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||
SynExpr.CreateIdent (Ident.Create "queryParams"),
|
||||
SynLongIdent.createS' [ "httpMessage" ; "Content" ],
|
||||
SynExpr.createIdent "queryParams",
|
||||
range0
|
||||
)
|
||||
)
|
||||
@@ -572,10 +477,9 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"responseString",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ],
|
||||
SynExpr.CreateIdentString "ct"
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ])
|
||||
(SynExpr.createIdent "ct")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -583,10 +487,9 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"responseStream",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ],
|
||||
SynExpr.CreateIdentString "ct"
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ])
|
||||
(SynExpr.createIdent "ct")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -594,47 +497,39 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"jsonNode",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent
|
||||
[ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.CreateIdentString "responseStream"
|
||||
SynExpr.equals
|
||||
(SynExpr.CreateIdentString "cancellationToken")
|
||||
(SynExpr.CreateIdentString "ct")
|
||||
]
|
||||
)
|
||||
SynExpr.createIdent "responseStream"
|
||||
SynExpr.equals (SynExpr.createIdent "cancellationToken") (SynExpr.createIdent "ct")
|
||||
])
|
||||
)
|
||||
)
|
||||
|
||||
let setVariableHeaders =
|
||||
variableHeaders
|
||||
|> List.map (fun (headerName, callToGetValue) ->
|
||||
Do (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
headerName
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent'
|
||||
[ Ident.Create "this" ; callToGetValue ; Ident.Create "ToString" ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
[
|
||||
headerName
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent'
|
||||
[ Ident.create "this" ; callToGetValue ; Ident.create "ToString" ])
|
||||
(SynExpr.CreateConst ())
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|
||||
|> Do
|
||||
)
|
||||
|
||||
let setConstantHeaders =
|
||||
constantHeaders
|
||||
|> List.map (fun (headerName, headerValue) ->
|
||||
Do (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ],
|
||||
SynExpr.CreateParenedTuple [ headerName ; headerValue ]
|
||||
)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|
||||
(SynExpr.tuple [ headerName ; headerValue ])
|
||||
|> Do
|
||||
)
|
||||
|
||||
[
|
||||
@@ -643,14 +538,9 @@ module internal HttpClientGenerator =
|
||||
yield
|
||||
Use (
|
||||
"httpMessage",
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ]
|
||||
),
|
||||
httpReqMessageConstructor,
|
||||
range0
|
||||
)
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ])
|
||||
httpReqMessageConstructor
|
||||
)
|
||||
|
||||
yield! handleBodyParams
|
||||
@@ -662,21 +552,18 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"response",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "client" ; "SendAsync" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
[ SynExpr.CreateIdentString "httpMessage" ; SynExpr.CreateIdentString "ct" ]
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "client" ; "SendAsync" ])
|
||||
(SynExpr.tuple [ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ])
|
||||
)
|
||||
)
|
||||
if info.EnsureSuccessHttpCode then
|
||||
yield
|
||||
Let (
|
||||
"response",
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ])
|
||||
(SynExpr.CreateConst ())
|
||||
)
|
||||
match info.TaskReturnType with
|
||||
| HttpResponseMessage -> ()
|
||||
@@ -691,30 +578,22 @@ module internal HttpClientGenerator =
|
||||
yield jsonNode
|
||||
]
|
||||
|> SynExpr.createCompExpr "async" returnExpr
|
||||
|> SynExpr.startAsTask (SynLongIdent.CreateFromLongIdent [ cancellationTokenArg ])
|
||||
|> SynExpr.startAsTask cancellationTokenArg
|
||||
|
||||
SynBinding.SynBinding (
|
||||
None,
|
||||
SynBindingKind.Normal,
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
valData,
|
||||
headPat,
|
||||
None,
|
||||
implementation,
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
SynBinding.triviaZero true
|
||||
)
|
||||
let thisIdent =
|
||||
if variableHeaders.IsEmpty then "_" else "this"
|
||||
|> Ident.create
|
||||
|
||||
let args = args |> List.map snd |> SynPat.tuple |> List.singleton
|
||||
|
||||
SynBinding.basic [ thisIdent ; info.Identifier ] args implementation
|
||||
|> SynBinding.withAccessibility info.Accessibility
|
||||
|> fun b -> SynMemberDefn.Member (b, range0)
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "RestEase.Query"
|
||||
| "RestEase.QueryAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Query"
|
||||
@@ -755,7 +634,7 @@ module internal HttpClientGenerator =
|
||||
let extractBasePath (attrs : SynAttribute list) : SynExpr option =
|
||||
attrs
|
||||
|> List.tryPick (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "BasePath"
|
||||
| "RestEase.BasePath"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BasePath"
|
||||
@@ -768,7 +647,7 @@ module internal HttpClientGenerator =
|
||||
let extractBaseAddress (attrs : SynAttribute list) : SynExpr option =
|
||||
attrs
|
||||
|> List.tryPick (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "BaseAddress"
|
||||
| "RestEase.BaseAddress"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
|
||||
@@ -883,46 +762,13 @@ module internal HttpClientGenerator =
|
||||
let propertyMembers =
|
||||
properties
|
||||
|> List.map (fun (_, pi) ->
|
||||
SynMemberDefn.Member (
|
||||
SynBinding.SynBinding (
|
||||
pi.Accessibility,
|
||||
SynBindingKind.Normal,
|
||||
pi.IsInline,
|
||||
false,
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
SynValData.SynValData (
|
||||
Some
|
||||
{
|
||||
IsInstance = true
|
||||
IsDispatchSlot = false
|
||||
IsOverrideOrExplicitImpl = true
|
||||
IsFinal = false
|
||||
GetterOrSetterIsCompilerGenerated = false
|
||||
MemberKind = SynMemberKind.Member
|
||||
},
|
||||
SynValInfo.SynValInfo ([ [ SynArgInfo.Empty ] ; [] ], SynArgInfo.Empty),
|
||||
None
|
||||
),
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ Ident.Create "_" ; pi.Identifier ],
|
||||
[]
|
||||
),
|
||||
Some (SynBindingReturnInfo.Create pi.Type),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent' [ Ident.lowerFirstLetter pi.Identifier ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
),
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
{
|
||||
LeadingKeyword = SynLeadingKeyword.Member range0
|
||||
InlineKeyword = if pi.IsInline then Some range0 else None
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
),
|
||||
range0
|
||||
)
|
||||
SynExpr.createLongIdent' [ Ident.lowerFirstLetter pi.Identifier ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "_" ; pi.Identifier ] []
|
||||
|> SynBinding.withReturnAnnotation pi.Type
|
||||
|> SynBinding.setInline pi.IsInline
|
||||
|> SynBinding.withAccessibility pi.Accessibility
|
||||
|> SynMemberDefn.memberImplementation
|
||||
)
|
||||
|
||||
let members = propertyMembers @ nonPropertyMembers
|
||||
@@ -932,12 +778,12 @@ module internal HttpClientGenerator =
|
||||
"Extension methods"
|
||||
else
|
||||
"Module")
|
||||
|> sprintf " %s for constructing a REST client."
|
||||
|> PreXmlDoc.Create
|
||||
|> sprintf "%s for constructing a REST client."
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let interfaceImpl =
|
||||
SynExpr.ObjExpr (
|
||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name),
|
||||
SynType.createLongIdent interfaceType.Name,
|
||||
None,
|
||||
Some range0,
|
||||
[],
|
||||
@@ -950,54 +796,26 @@ module internal HttpClientGenerator =
|
||||
let headerArgs =
|
||||
properties
|
||||
|> List.map (fun (_, pi) ->
|
||||
SynPat.CreateTyped (
|
||||
SynPat.CreateNamed (Ident.lowerFirstLetter pi.Identifier),
|
||||
SynType.CreateFun (SynType.CreateLongIdent "unit", pi.Type)
|
||||
)
|
||||
|> SynPat.CreateParen
|
||||
SynPat.namedI (Ident.lowerFirstLetter pi.Identifier)
|
||||
|> SynPat.annotateType (SynType.funFromDomain (SynType.named "unit") pi.Type)
|
||||
)
|
||||
|
||||
let clientCreationArg =
|
||||
SynPat.CreateTyped (
|
||||
SynPat.CreateNamed (Ident.Create "client"),
|
||||
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpClient" ])
|
||||
)
|
||||
|> SynPat.CreateParen
|
||||
SynPat.named "client"
|
||||
|> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpClient" ])
|
||||
|
||||
let xmlDoc =
|
||||
if properties.IsEmpty then
|
||||
" Create a REST client."
|
||||
"Create a REST client."
|
||||
else
|
||||
" Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties."
|
||||
|> PreXmlDoc.Create
|
||||
"Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties."
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let functionName = Ident.Create "client"
|
||||
let functionName = Ident.create "client"
|
||||
|
||||
let valData =
|
||||
let memberFlags =
|
||||
if spec.ExtensionMethods then
|
||||
{
|
||||
SynMemberFlags.IsInstance = false
|
||||
SynMemberFlags.IsDispatchSlot = false
|
||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||
SynMemberFlags.IsFinal = false
|
||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||
}
|
||||
|> Some
|
||||
else
|
||||
None
|
||||
let pattern = SynLongIdent.createS "make"
|
||||
|
||||
SynValData.SynValData (
|
||||
memberFlags,
|
||||
SynValInfo.SynValInfo ([ [ SynArgInfo.SynArgInfo ([], false, Some functionName) ] ], SynArgInfo.Empty),
|
||||
None
|
||||
)
|
||||
|
||||
let pattern = SynLongIdent.CreateString "make"
|
||||
|
||||
let returnInfo =
|
||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
|
||||
let returnInfo = SynType.createLongIdent interfaceType.Name
|
||||
|
||||
let nameWithoutLeadingI =
|
||||
List.last interfaceType.Name
|
||||
@@ -1011,74 +829,54 @@ module internal HttpClientGenerator =
|
||||
let createFunc =
|
||||
if spec.ExtensionMethods then
|
||||
let binding =
|
||||
SynBinding.basic
|
||||
(SynLongIdent.CreateString "make")
|
||||
(headerArgs @ [ clientCreationArg ])
|
||||
interfaceImpl
|
||||
SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.makeStaticMember
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
let componentInfo =
|
||||
SynComponentInfo.create (Ident.create nameWithoutLeadingI)
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for HTTP clients")
|
||||
|
||||
let containingType =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.Create (
|
||||
[ Ident.Create nameWithoutLeadingI ],
|
||||
xmldoc = PreXmlDoc.Create " Extension methods for HTTP clients"
|
||||
),
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||
[ mem ],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ binding ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
|
||||
else
|
||||
SynBinding.basic (SynLongIdent.CreateString "make") (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
||||
SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> List.singleton
|
||||
|> SynModuleDecl.CreateLet
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let moduleName : LongIdent =
|
||||
let moduleName =
|
||||
if spec.ExtensionMethods then
|
||||
[ Ident.Create (nameWithoutLeadingI + "HttpClientExtension") ]
|
||||
Ident.create (nameWithoutLeadingI + "HttpClientExtension")
|
||||
else
|
||||
[ Ident.Create nameWithoutLeadingI ]
|
||||
Ident.create nameWithoutLeadingI
|
||||
|
||||
let attribs =
|
||||
if spec.ExtensionMethods then
|
||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||
[ SynAttribute.autoOpen ]
|
||||
else
|
||||
[
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
]
|
||||
[ SynAttribute.compilationRepresentation ; SynAttribute.requireQualifiedAccess ]
|
||||
|
||||
let modInfo =
|
||||
SynComponentInfo.Create (
|
||||
moduleName,
|
||||
attributes = attribs,
|
||||
xmldoc = docString,
|
||||
access = interfaceType.Accessibility
|
||||
)
|
||||
SynComponentInfo.create moduleName
|
||||
|> SynComponentInfo.withDocString docString
|
||||
|> SynComponentInfo.addAttributes attribs
|
||||
|> SynComponentInfo.setAccessibility interfaceType.Accessibility
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
ns,
|
||||
decls =
|
||||
[
|
||||
for openStatement in opens do
|
||||
yield SynModuleDecl.CreateOpen openStatement
|
||||
yield SynModuleDecl.CreateNestedModule (modInfo, [ createFunc ])
|
||||
]
|
||||
)
|
||||
[
|
||||
for openStatement in opens do
|
||||
yield SynModuleDecl.openAny openStatement
|
||||
yield SynModuleDecl.nestedModule modInfo [ createFunc ]
|
||||
]
|
||||
|> SynModuleOrNamespace.createNamespace ns
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that provides an HTTP client for an interface type using RestEase annotations.
|
||||
[<MyriadGenerator("http-client")>]
|
||||
|
@@ -2,9 +2,7 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal GenerateMockOutputSpec =
|
||||
{
|
||||
@@ -14,7 +12,6 @@ type internal GenerateMockOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal InterfaceMockGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
let private getName (SynField (_, _, id, _, _, _, _, _, _)) =
|
||||
match id with
|
||||
@@ -46,72 +43,67 @@ module internal InterfaceMockGenerator =
|
||||
)
|
||||
|> Set.ofSeq
|
||||
|
||||
let failwithFun =
|
||||
let failwithFun (SynField (_, _, idOpt, _, _, _, _, _, _)) =
|
||||
let failString =
|
||||
match idOpt with
|
||||
| None -> SynExpr.CreateConst "Unimplemented mock function"
|
||||
| Some ident -> SynExpr.CreateConst $"Unimplemented mock function: %s{ident.idText}"
|
||||
|
||||
SynExpr.createLongIdent [ "System" ; "NotImplementedException" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConstString "Unimplemented mock function")
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise")
|
||||
|> SynExpr.applyTo failString
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
|> SynExpr.createLambda "_"
|
||||
|
||||
let constructorReturnType =
|
||||
match interfaceType.Generics with
|
||||
| None -> SynType.CreateLongIdent name
|
||||
| None -> SynType.createLongIdent' [ name ]
|
||||
| Some generics ->
|
||||
|
||||
let generics =
|
||||
generics.TyparDecls
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent name,
|
||||
Some range0,
|
||||
generics,
|
||||
List.replicate (generics.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
)
|
||||
SynType.app name generics
|
||||
|
||||
let constructorFields =
|
||||
let extras =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
let unitFun = SynExpr.createLambda "_" SynExpr.CreateUnit
|
||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
||||
|
||||
[
|
||||
(SynLongIdent.CreateFromLongIdent [ Ident.Create "Dispose" ], true), Some unitFun
|
||||
]
|
||||
[ (SynLongIdent.createS "Dispose", true), Some unitFun ]
|
||||
else
|
||||
[]
|
||||
|
||||
let nonExtras =
|
||||
fields
|
||||
|> List.map (fun field -> (SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
||||
|> List.map (fun field -> (SynLongIdent.createI (getName field), true), Some (failwithFun field))
|
||||
|
||||
extras @ nonExtras
|
||||
|
||||
let constructor =
|
||||
SynBinding.basic
|
||||
(SynLongIdent.CreateString "Empty")
|
||||
[ Ident.create "Empty" ]
|
||||
(if interfaceType.Generics.IsNone then
|
||||
[]
|
||||
else
|
||||
[ SynPat.CreateConst SynConst.Unit ])
|
||||
[ SynPat.unit ])
|
||||
(AstHelper.instantiateRecord constructorFields)
|
||||
|> SynBinding.makeStaticMember
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.Create " An implementation where every method throws.")
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|
||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
||||
|> fun m -> SynMemberDefn.Member (m, range0)
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let fields =
|
||||
let extras =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
[
|
||||
SynField.Create (
|
||||
SynType.CreateFun (SynType.CreateUnit, SynType.CreateUnit),
|
||||
Ident.Create "Dispose",
|
||||
xmldoc = PreXmlDoc.Create " Implementation of IDisposable.Dispose"
|
||||
)
|
||||
]
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (Ident.create "Dispose")
|
||||
Type = SynType.funFromDomain SynType.unit SynType.unit
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (PreXmlDoc.create "Implementation of IDisposable.Dispose")
|
||||
|> List.singleton
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -121,47 +113,6 @@ module internal InterfaceMockGenerator =
|
||||
let members =
|
||||
interfaceType.Members
|
||||
|> List.map (fun memberInfo ->
|
||||
|
||||
let synValData =
|
||||
SynValData.SynValData (
|
||||
Some
|
||||
{
|
||||
IsInstance = true
|
||||
IsDispatchSlot = false
|
||||
IsOverrideOrExplicitImpl = true
|
||||
IsFinal = false
|
||||
GetterOrSetterIsCompilerGenerated = false
|
||||
MemberKind = SynMemberKind.Member
|
||||
},
|
||||
valInfo =
|
||||
SynValInfo.SynValInfo (
|
||||
curriedArgInfos =
|
||||
[
|
||||
yield
|
||||
[
|
||||
SynArgInfo.SynArgInfo (
|
||||
attributes = [],
|
||||
optional = false,
|
||||
ident = None
|
||||
)
|
||||
]
|
||||
yield!
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i arg ->
|
||||
arg.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynArgInfo.SynArgInfo ([], false, None)
|
||||
| _ -> SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
)
|
||||
],
|
||||
returnInfo =
|
||||
SynArgInfo.SynArgInfo (attributes = [], optional = false, ident = None)
|
||||
),
|
||||
thisIdOpt = None
|
||||
)
|
||||
|
||||
let headArgs =
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i tupledArgs ->
|
||||
@@ -169,27 +120,15 @@ module internal InterfaceMockGenerator =
|
||||
tupledArgs.Args
|
||||
|> List.mapi (fun j ty ->
|
||||
match ty.Type with
|
||||
| UnitType -> SynPat.Const (SynConst.Unit, range0)
|
||||
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}")
|
||||
| UnitType -> SynPat.unit
|
||||
| _ -> SynPat.named $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|
||||
match args with
|
||||
| [] -> failwith "somehow got no args at all"
|
||||
| [ arg ] -> arg
|
||||
| args ->
|
||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|> SynPat.CreateParen
|
||||
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
||||
)
|
||||
|
||||
let headPat =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ],
|
||||
None,
|
||||
None,
|
||||
SynArgPats.Pats headArgs,
|
||||
None,
|
||||
range0
|
||||
| args -> SynPat.tuple args
|
||||
|> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
|
||||
)
|
||||
|
||||
let body =
|
||||
@@ -199,10 +138,10 @@ module internal InterfaceMockGenerator =
|
||||
args.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynExpr.CreateConst SynConst.Unit
|
||||
| _ -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}"
|
||||
| UnitType -> SynExpr.CreateConst ()
|
||||
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
)
|
||||
|
||||
match tuples |> List.rev with
|
||||
@@ -210,38 +149,17 @@ module internal InterfaceMockGenerator =
|
||||
| last :: rest ->
|
||||
|
||||
(last, rest)
|
||||
||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail))
|
||||
||> List.fold SynExpr.applyTo
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent' [ Ident.Create "this" ; memberInfo.Identifier ]
|
||||
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
|
||||
)
|
||||
|
||||
SynMemberDefn.Member (
|
||||
SynBinding.SynBinding (
|
||||
None,
|
||||
SynBindingKind.Normal,
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
synValData,
|
||||
headPat,
|
||||
None,
|
||||
body,
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
{
|
||||
LeadingKeyword = SynLeadingKeyword.Member range0
|
||||
InlineKeyword = None
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
),
|
||||
range0
|
||||
)
|
||||
SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body
|
||||
|> SynMemberDefn.memberImplementation
|
||||
)
|
||||
|
||||
let interfaceName =
|
||||
let baseName =
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
|
||||
let baseName = SynType.createLongIdent interfaceType.Name
|
||||
|
||||
match interfaceType.Generics with
|
||||
| None -> baseName
|
||||
@@ -251,17 +169,9 @@ module internal InterfaceMockGenerator =
|
||||
| SynTyparDecls.PostfixList (decls, _, _) -> decls
|
||||
| SynTyparDecls.PrefixList (decls, _) -> decls
|
||||
| SynTyparDecls.SinglePrefix (decl, _) -> [ decl ]
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.App (
|
||||
baseName,
|
||||
Some range0,
|
||||
generics,
|
||||
List.replicate (generics.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
)
|
||||
SynType.app' baseName generics
|
||||
|
||||
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
|
||||
|
||||
@@ -279,18 +189,15 @@ module internal InterfaceMockGenerator =
|
||||
|> Seq.map (fun inheritance ->
|
||||
match inheritance with
|
||||
| KnownInheritance.IDisposable ->
|
||||
let binding =
|
||||
SynBinding.basic
|
||||
(SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; Ident.Create "Dispose" ])
|
||||
[ SynPat.CreateConst SynConst.Unit ]
|
||||
(SynExpr.CreateApp (SynExpr.createLongIdent [ "this" ; "Dispose" ], SynExpr.CreateUnit))
|
||||
|> SynBinding.withReturnAnnotation (SynType.Unit ())
|
||||
|> SynBinding.makeInstanceMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
let mem =
|
||||
SynExpr.createLongIdent [ "this" ; "Dispose" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "this" ; Ident.create "Dispose" ] [ SynPat.unit ]
|
||||
|> SynBinding.withReturnAnnotation SynType.unit
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
SynMemberDefn.Interface (
|
||||
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "IDisposable" ]),
|
||||
SynType.createLongIdent' [ "System" ; "IDisposable" ],
|
||||
Some range0,
|
||||
Some [ mem ],
|
||||
range0
|
||||
@@ -300,7 +207,7 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let record =
|
||||
{
|
||||
Name = Ident.Create name
|
||||
Name = Ident.create name
|
||||
Fields = fields
|
||||
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
|
||||
XmlDoc = Some xmlDoc
|
||||
@@ -314,7 +221,7 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let private buildType (x : ParameterInfo) : SynType =
|
||||
if x.IsOptional then
|
||||
SynType.App (SynType.CreateLongIdent "option", Some range0, [ x.Type ], [], Some range0, false, range0)
|
||||
SynType.app "option" [ x.Type ]
|
||||
else
|
||||
x.Type
|
||||
|
||||
@@ -331,19 +238,15 @@ module internal InterfaceMockGenerator =
|
||||
let constructMember (mem : MemberInfo) : SynField =
|
||||
let inputType = mem.Args |> List.map constructMemberSinglePlace
|
||||
|
||||
let funcType = AstHelper.toFun inputType mem.ReturnType
|
||||
let funcType = SynType.toFun inputType mem.ReturnType
|
||||
|
||||
SynField.SynField (
|
||||
[],
|
||||
false,
|
||||
Some mem.Identifier,
|
||||
funcType,
|
||||
false,
|
||||
mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty,
|
||||
None,
|
||||
range0,
|
||||
SynFieldTrivia.Zero
|
||||
)
|
||||
{
|
||||
Type = funcType
|
||||
Attrs = []
|
||||
Ident = Some mem.Identifier
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
|
||||
|
||||
let createRecord
|
||||
(namespaceId : LongIdent)
|
||||
@@ -353,7 +256,7 @@ module internal InterfaceMockGenerator =
|
||||
=
|
||||
let interfaceType = AstHelper.parseInterface interfaceType
|
||||
let fields = interfaceType.Members |> List.map constructMember
|
||||
let docString = PreXmlDoc.Create " Mock record type for an interface"
|
||||
let docString = PreXmlDoc.create "Mock record type for an interface"
|
||||
|
||||
let name =
|
||||
List.last interfaceType.Name
|
||||
@@ -367,10 +270,10 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let typeDecl = createType spec name interfaceType docString fields
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
namespaceId,
|
||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
||||
)
|
||||
[ yield! opens |> List.map SynModuleDecl.openAny ; yield typeDecl ]
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that creates a record which implements the given interface,
|
||||
/// but with every field mocked out.
|
||||
|
@@ -4,8 +4,6 @@ open System
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal JsonParseOutputSpec =
|
||||
{
|
||||
@@ -15,7 +13,6 @@ type internal JsonParseOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal JsonParseGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
type JsonParseOption =
|
||||
{
|
||||
@@ -30,30 +27,23 @@ module internal JsonParseGenerator =
|
||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v)
|
||||
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
|
||||
let raiseExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateIdentString "sprintf",
|
||||
SynExpr.CreateConstString "Required key '%s' not found on JSON object"
|
||||
),
|
||||
SynExpr.CreateParen propertyName
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "Required key '%s' not found on JSON object")
|
||||
|> SynExpr.applyTo (SynExpr.paren propertyName)
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
|
||||
)
|
||||
SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
|
||||
SynExpr.CreateMatch (
|
||||
indexed,
|
||||
[
|
||||
SynMatchClause.Create (SynPat.CreateNull, None, raiseExpr)
|
||||
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v")
|
||||
]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
[
|
||||
SynMatchClause.create SynPat.createNull raiseExpr
|
||||
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
|
||||
]
|
||||
|> SynExpr.createMatch indexed
|
||||
|> SynExpr.paren
|
||||
|
||||
/// {node}.AsValue().GetValue<{typeName}> ()
|
||||
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
||||
@@ -81,10 +71,8 @@ module internal JsonParseGenerator =
|
||||
|
||||
/// {type}.jsonParse {node}
|
||||
let typeJsonParse (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (typeName @ [ Ident.Create "jsonParse" ])),
|
||||
node
|
||||
)
|
||||
node
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ Ident.create "jsonParse" ]))
|
||||
|
||||
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
|
||||
/// body is the body of a lambda which takes a parameter `elt`.
|
||||
@@ -103,51 +91,41 @@ module internal JsonParseGenerator =
|
||||
| Some propertyName -> assertNotNull propertyName node
|
||||
|> SynExpr.callMethod "AsArray"
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
SynExpr.createLambda "elt" body
|
||||
)
|
||||
SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "elt" body)
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ collectionType ; "ofSeq" ]))
|
||||
|> 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.CreateIdentString "Some") body
|
||||
let body = SynExpr.pipeThroughFunction (SynExpr.createIdent "Some") body
|
||||
|
||||
SynExpr.CreateMatch (
|
||||
node,
|
||||
[
|
||||
SynMatchClause.Create (SynPat.CreateNull, None, SynExpr.CreateIdent (Ident.Create "None"))
|
||||
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, body)
|
||||
]
|
||||
)
|
||||
[
|
||||
SynMatchClause.create SynPat.createNull (SynExpr.createIdent "None")
|
||||
SynMatchClause.create (SynPat.named "v") body
|
||||
]
|
||||
|> SynExpr.createMatch node
|
||||
|
||||
/// Given e.g. "float", returns "System.Double.Parse"
|
||||
let parseFunction (typeName : string) : LongIdent =
|
||||
let qualified =
|
||||
match AstHelper.qualifyPrimitiveType typeName with
|
||||
match Primitives.qualifyType typeName with
|
||||
| Some x -> x
|
||||
| None -> failwith $"Could not recognise type %s{typeName} as a primitive."
|
||||
|
||||
List.append qualified [ Ident.Create "Parse" ]
|
||||
List.append qualified [ Ident.create "Parse" ]
|
||||
|
||||
/// fun kvp -> let key = {key(kvp)} in let value = {value(kvp)} in (key, value))
|
||||
/// The inputs will be fed with appropriate SynExprs to apply them to the `kvp.Key` and `kvp.Value` args.
|
||||
let dictionaryMapper (key : SynExpr -> SynExpr) (value : SynExpr -> SynExpr) : SynExpr =
|
||||
let keyArg = SynExpr.createLongIdent [ "kvp" ; "Key" ] |> SynExpr.CreateParen
|
||||
let keyArg = SynExpr.createLongIdent [ "kvp" ; "Key" ] |> SynExpr.paren
|
||||
|
||||
let valueArg = SynExpr.createLongIdent [ "kvp" ; "Value" ] |> SynExpr.CreateParen
|
||||
let valueArg = SynExpr.createLongIdent [ "kvp" ; "Value" ] |> SynExpr.paren
|
||||
|
||||
SynExpr.CreateTuple [ SynExpr.CreateIdentString "key" ; SynExpr.CreateIdentString "value" ]
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "value"), expr = value valueArg)
|
||||
]
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "key"), expr = key keyArg)
|
||||
]
|
||||
// No need to paren here, we're on the LHS of a `let`
|
||||
SynExpr.tupleNoParen [ SynExpr.createIdent "key" ; SynExpr.createIdent "value" ]
|
||||
|> SynExpr.createLet [ SynBinding.basic [ Ident.create "value" ] [] (value valueArg) ]
|
||||
|> SynExpr.createLet [ SynBinding.basic [ Ident.create "key" ] [] (key keyArg) ]
|
||||
|> SynExpr.createLambda "kvp"
|
||||
|
||||
/// A conforming JSON object has only strings as keys. But it would be reasonable to allow the user
|
||||
@@ -157,7 +135,7 @@ module internal JsonParseGenerator =
|
||||
| String -> key
|
||||
| Uri ->
|
||||
key
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
|
||||
| _ ->
|
||||
failwithf
|
||||
$"Unable to parse the key type %+A{desiredType} of a JSON object. Keys are strings, and this plugin does not know how to convert to that from a string."
|
||||
@@ -197,15 +175,8 @@ module internal JsonParseGenerator =
|
||||
| None -> basic
|
||||
| Some option ->
|
||||
let cond =
|
||||
SynExpr.DotGet (
|
||||
SynExpr.CreateIdentString "exc",
|
||||
range0,
|
||||
SynLongIdent.CreateString "Message",
|
||||
range0
|
||||
)
|
||||
|> SynExpr.callMethodArg
|
||||
"Contains"
|
||||
(SynExpr.CreateConst (SynConst.CreateString "cannot be converted to"))
|
||||
SynExpr.DotGet (SynExpr.createIdent "exc", range0, SynLongIdent.createS "Message", range0)
|
||||
|> SynExpr.callMethodArg "Contains" (SynExpr.CreateConst "cannot be converted to")
|
||||
|
||||
let handler =
|
||||
asValueGetValue propertyName "string" node
|
||||
@@ -213,91 +184,82 @@ module internal JsonParseGenerator =
|
||||
|> SynExpr.ifThenElse
|
||||
(SynExpr.equals
|
||||
option
|
||||
(SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create
|
||||
[
|
||||
"System"
|
||||
"Text"
|
||||
"Json"
|
||||
"Serialization"
|
||||
"JsonNumberHandling"
|
||||
"AllowReadingFromString"
|
||||
]
|
||||
)))
|
||||
(SynExpr.createLongIdent
|
||||
[
|
||||
"System"
|
||||
"Text"
|
||||
"Json"
|
||||
"Serialization"
|
||||
"JsonNumberHandling"
|
||||
"AllowReadingFromString"
|
||||
]))
|
||||
SynExpr.reraise
|
||||
|> SynExpr.ifThenElse cond SynExpr.reraise
|
||||
|
||||
basic
|
||||
|> SynExpr.pipeThroughTryWith
|
||||
(SynPat.IsInst (
|
||||
SynType.LongIdent (SynLongIdent.Create [ "System" ; "InvalidOperationException" ]),
|
||||
SynType.LongIdent (SynLongIdent.createS' [ "System" ; "InvalidOperationException" ]),
|
||||
range0
|
||||
))
|
||||
handler
|
||||
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
||||
| OptionType ty ->
|
||||
parseNode None options ty (SynExpr.CreateIdentString "v")
|
||||
parseNode None options ty (SynExpr.createIdent "v")
|
||||
|> createParseLineOption node
|
||||
| ListType ty ->
|
||||
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt"))
|
||||
parseNode None options ty (SynExpr.createIdent "elt")
|
||||
|> asArrayMapped propertyName "List" node
|
||||
| ArrayType ty ->
|
||||
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt"))
|
||||
parseNode None options ty (SynExpr.createIdent "elt")
|
||||
|> asArrayMapped propertyName "Array" node
|
||||
| IDictionaryType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "dict" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "dict")
|
||||
| DictionaryType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ]
|
||||
)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ])
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "Dictionary" ])
|
||||
SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "Dictionary" ]
|
||||
)
|
||||
| IReadOnlyDictionaryType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "readOnlyDict" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "readOnlyDict")
|
||||
| MapType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Map" ; "ofSeq" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Map" ; "ofSeq" ])
|
||||
| BigInt ->
|
||||
node
|
||||
|> SynExpr.callMethod "ToJsonString"
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Numerics" ; "BigInteger" ; "Parse" ])
|
||||
| _ ->
|
||||
// Let's just hope that we've also got our own type annotation!
|
||||
@@ -314,9 +276,8 @@ module internal JsonParseGenerator =
|
||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||
/// The result of this function is the body of a let-binding (not including the LHS of that let-binding).
|
||||
let createParseRhs (options : JsonParseOption) (propertyName : SynExpr) (fieldType : SynType) : SynExpr =
|
||||
SynExpr.CreateIdentString "node"
|
||||
|> SynExpr.index propertyName
|
||||
|> parseNode (Some propertyName) options fieldType
|
||||
let objectToParse = SynExpr.createIdent "node" |> SynExpr.index propertyName
|
||||
parseNode (Some propertyName) options fieldType objectToParse
|
||||
|
||||
let isJsonNumberHandling (literal : LongIdent) : bool =
|
||||
match List.rev literal |> List.map (fun ident -> ident.idText) with
|
||||
@@ -332,133 +293,186 @@ module internal JsonParseGenerator =
|
||||
/// That is, we give you access to a `JsonNode` called `node`,
|
||||
/// and you must return a `typeName`.
|
||||
let scaffolding (spec : JsonParseOutputSpec) (typeName : LongIdent) (functionBody : SynExpr) : SynModuleDecl =
|
||||
let xmlDoc = PreXmlDoc.Create " Parse from a JSON node."
|
||||
let xmlDoc = PreXmlDoc.create "Parse from a JSON node."
|
||||
|
||||
let returnInfo = SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName)
|
||||
let returnInfo = SynType.createLongIdent typeName
|
||||
|
||||
let inputArg = Ident.Create "node"
|
||||
let functionName = Ident.Create "jsonParse"
|
||||
let inputArg = "node"
|
||||
let functionName = Ident.create "jsonParse"
|
||||
|
||||
let arg =
|
||||
SynPat.CreateNamed inputArg
|
||||
|> SynPat.annotateType (
|
||||
SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
)
|
||||
SynPat.named inputArg
|
||||
|> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|
||||
if spec.ExtensionMethods then
|
||||
let binding =
|
||||
SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ arg ] functionBody
|
||||
|> SynBinding.makeStaticMember
|
||||
SynBinding.basic [ functionName ] [ arg ] functionBody
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
let componentInfo =
|
||||
SynComponentInfo.createLong typeName
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
||||
|
||||
let containingType =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"),
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||
[ mem ],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ binding ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
else
|
||||
SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ arg ] functionBody
|
||||
SynBinding.basic [ functionName ] [ arg ] functionBody
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> List.singleton
|
||||
|> SynModuleDecl.CreateLet
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let createMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynFieldData<Ident> list) =
|
||||
let getParseOptions (fieldAttrs : SynAttribute list) =
|
||||
(JsonParseOption.None, fieldAttrs)
|
||||
||> List.fold (fun options attr ->
|
||||
if
|
||||
(SynLongIdent.toString attr.TypeName)
|
||||
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
|
||||
then
|
||||
let qualifiedEnumValue =
|
||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
||||
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
|
||||
// Make sure it's fully qualified
|
||||
SynExpr.createLongIdent
|
||||
[
|
||||
"System"
|
||||
"Text"
|
||||
"Json"
|
||||
"Serialization"
|
||||
"JsonNumberHandling"
|
||||
"AllowReadingFromString"
|
||||
]
|
||||
| _ -> attr.ArgExpr
|
||||
|
||||
{
|
||||
JsonNumberHandlingArg = Some qualifiedEnumValue
|
||||
}
|
||||
else
|
||||
options
|
||||
)
|
||||
|
||||
let createRecordMaker (spec : JsonParseOutputSpec) (fields : SynFieldData<Ident> list) =
|
||||
let assignments =
|
||||
fields
|
||||
|> List.mapi (fun i fieldData ->
|
||||
let propertyNameAttr =
|
||||
fieldData.Attrs
|
||||
|> List.tryFind (fun attr ->
|
||||
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||
(SynLongIdent.toString attr.TypeName)
|
||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||
)
|
||||
|
||||
let options =
|
||||
(JsonParseOption.None, fieldData.Attrs)
|
||||
||> List.fold (fun options attr ->
|
||||
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
|
||||
let qualifiedEnumValue =
|
||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
||||
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when
|
||||
isJsonNumberHandling ident
|
||||
->
|
||||
// Make sure it's fully qualified
|
||||
SynExpr.createLongIdent
|
||||
[
|
||||
"System"
|
||||
"Text"
|
||||
"Json"
|
||||
"Serialization"
|
||||
"JsonNumberHandling"
|
||||
"AllowReadingFromString"
|
||||
]
|
||||
| _ -> attr.ArgExpr
|
||||
|
||||
{
|
||||
JsonNumberHandlingArg = Some qualifiedEnumValue
|
||||
}
|
||||
else
|
||||
options
|
||||
)
|
||||
let options = getParseOptions fieldData.Attrs
|
||||
|
||||
let propertyName =
|
||||
match propertyNameAttr with
|
||||
| None ->
|
||||
let sb = StringBuilder fieldData.Ident.idText.Length
|
||||
sb.Append (Char.ToLowerInvariant fieldData.Ident.idText.[0]) |> ignore
|
||||
|
||||
sb.Append (Char.ToLowerInvariant fieldData.Ident.idText.[0])
|
||||
|> ignore<StringBuilder>
|
||||
|
||||
if fieldData.Ident.idText.Length > 1 then
|
||||
sb.Append fieldData.Ident.idText.[1..] |> ignore
|
||||
sb.Append (fieldData.Ident.idText.Substring 1) |> ignore<StringBuilder>
|
||||
|
||||
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||
sb.ToString () |> SynExpr.CreateConst
|
||||
| Some name -> name.ArgExpr
|
||||
|
||||
createParseRhs options propertyName fieldData.Type
|
||||
|> SynBinding.basic (SynLongIdent.CreateString $"arg_%i{i}") []
|
||||
|> SynBinding.basic [ Ident.create $"arg_%i{i}" ] []
|
||||
)
|
||||
|
||||
let finalConstruction =
|
||||
fields
|
||||
|> List.mapi (fun i fieldData ->
|
||||
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true),
|
||||
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateString $"arg_%i{i}"))
|
||||
(SynLongIdent.createI fieldData.Ident, true), Some (SynExpr.createIdent $"arg_%i{i}")
|
||||
)
|
||||
|> AstHelper.instantiateRecord
|
||||
|
||||
let assignments =
|
||||
(finalConstruction, assignments)
|
||||
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)
|
||||
(finalConstruction, assignments)
|
||||
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)
|
||||
|
||||
assignments |> scaffolding spec typeName
|
||||
let createUnionMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : UnionCase<Ident> list) =
|
||||
fields
|
||||
|> List.map (fun case ->
|
||||
let propertyName = JsonSerializeGenerator.getPropertyName case.Ident case.Attrs
|
||||
|
||||
(*
|
||||
let body =
|
||||
if case.Fields.IsEmpty then
|
||||
SynExpr.createLongIdent' (typeName @ [ case.Ident ])
|
||||
else
|
||||
case.Fields
|
||||
|> List.map (fun field ->
|
||||
let propertyName = JsonSerializeGenerator.getPropertyName field.Ident field.Attrs
|
||||
let options = getParseOptions field.Attrs
|
||||
createParseRhs options propertyName field.Type
|
||||
)
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ]))
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|
||||
|> assertNotNull (SynExpr.CreateConst "data")
|
||||
|> SynBinding.basic [ Ident.create "node" ] []
|
||||
]
|
||||
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : FirstDu =
|
||||
let ty =
|
||||
match node.["type"] with
|
||||
| null -> raise (System.Collections.Generic.KeyNotFoundException ())
|
||||
| v -> v.GetValue<string> ()
|
||||
match ty with
|
||||
| "emptyCase" -> FirstDu.EmptyCase
|
||||
| "case1" ->
|
||||
FirstDu.Case1
|
||||
| "case2" -> FirstDu.Case2
|
||||
| _ -> failwithf "Unrecognised case name: %s" ty
|
||||
*)
|
||||
match propertyName with
|
||||
| SynExpr.Const (synConst, _) ->
|
||||
SynMatchClause.SynMatchClause (
|
||||
SynPat.createConst synConst,
|
||||
None,
|
||||
body,
|
||||
range0,
|
||||
DebugPointAtTarget.Yes,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
BarRange = Some range0
|
||||
}
|
||||
)
|
||||
| _ ->
|
||||
SynMatchClause.create (SynPat.named "x") body
|
||||
|> SynMatchClause.withWhere (SynExpr.equals (SynExpr.createIdent "x") propertyName)
|
||||
)
|
||||
|> fun l ->
|
||||
l
|
||||
@ [
|
||||
let fail =
|
||||
SynExpr.plus (SynExpr.CreateConst "Unrecognised 'type' field value: ") (SynExpr.createIdent "v")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
SynMatchClause.SynMatchClause (
|
||||
SynPat.named "v",
|
||||
None,
|
||||
fail,
|
||||
range0,
|
||||
DebugPointAtTarget.Yes,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
BarRange = Some range0
|
||||
}
|
||||
)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "ty")
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
let property = SynExpr.CreateConst "type"
|
||||
|
||||
SynExpr.createIdent "node"
|
||||
|> SynExpr.index property
|
||||
|> assertNotNull property
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"v"
|
||||
(SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v"))
|
||||
)
|
||||
|> SynBinding.basic [ Ident.create "ty" ] []
|
||||
]
|
||||
|
||||
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||
@@ -469,12 +483,9 @@ module internal JsonParseGenerator =
|
||||
|
||||
let attributes =
|
||||
if spec.ExtensionMethods then
|
||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||
[ SynAttribute.autoOpen ]
|
||||
else
|
||||
[
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
]
|
||||
[ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
|
||||
|
||||
let xmlDoc =
|
||||
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||
@@ -485,8 +496,8 @@ module internal JsonParseGenerator =
|
||||
else
|
||||
"methods"
|
||||
|
||||
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.Create
|
||||
$"Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let moduleName =
|
||||
if spec.ExtensionMethods then
|
||||
@@ -497,29 +508,39 @@ module internal JsonParseGenerator =
|
||||
List.last ident
|
||||
|> fun i -> i.idText
|
||||
|> fun s -> s + "JsonParseExtension"
|
||||
|> Ident.Create
|
||||
|> Ident.create
|
||||
|
||||
List.take (List.length ident - 1) ident @ [ expanded ]
|
||||
else
|
||||
ident
|
||||
|
||||
let info =
|
||||
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||
SynComponentInfo.createLong moduleName
|
||||
|> SynComponentInfo.withDocString xmlDoc
|
||||
|> SynComponentInfo.addAttributes attributes
|
||||
|
||||
let decls =
|
||||
let decl =
|
||||
match synTypeDefnRepr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) ->
|
||||
let fields = fields |> List.map SynField.extractWithIdent
|
||||
[ createMaker spec ident fields ]
|
||||
fields |> List.map SynField.extractWithIdent |> createRecordMaker spec
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) ->
|
||||
let cases = cases |> List.map SynUnionCase.extract
|
||||
// [ createMaker spec ident cases ]
|
||||
failwith "Unions are not yet supported"
|
||||
let optionGet (i : Ident option) =
|
||||
match i with
|
||||
| None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field."
|
||||
| Some i -> i
|
||||
|
||||
cases
|
||||
|> List.map SynUnionCase.extract
|
||||
|> List.map (UnionCase.mapIdentFields optionGet)
|
||||
|> createUnionMaker spec ident
|
||||
| _ -> failwithf "Not a record or union type"
|
||||
|
||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||
[ scaffolding spec ident decl ]
|
||||
|> SynModuleDecl.nestedModule info
|
||||
|> List.singleton
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||
/// containing a JSON parse function.
|
||||
|
@@ -3,9 +3,6 @@ namespace WoofWare.Myriad.Plugins
|
||||
open System
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal JsonSerializeOutputSpec =
|
||||
{
|
||||
@@ -15,7 +12,6 @@ type internal JsonSerializeOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal JsonSerializeGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
/// 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)`.
|
||||
@@ -40,37 +36,24 @@ module internal JsonSerializeGenerator =
|
||||
)
|
||||
| OptionType ty ->
|
||||
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
|
||||
[
|
||||
SynMatchClause.Create (
|
||||
SynPat.CreateLongIdent (SynLongIdent.CreateString "None", []),
|
||||
None,
|
||||
// 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 (
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
)
|
||||
)
|
||||
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 someClause =
|
||||
SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "field")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|> SynMatchClause.create (
|
||||
SynPat.identWithArgs [ Ident.create "Some" ] (SynArgPats.create [ Ident.create "field" ])
|
||||
)
|
||||
|
||||
SynMatchClause.Create (
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateString "Some",
|
||||
[ SynPat.CreateNamed (Ident.Create "field") ]
|
||||
),
|
||||
None,
|
||||
SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "field")
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.upcast' (
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.CreateIdentString "field")
|
||||
[ noneClause ; someClause ]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "field")
|
||||
|> SynExpr.createLambda "field"
|
||||
| ArrayType ty
|
||||
| ListType ty ->
|
||||
@@ -84,22 +67,21 @@ module internal JsonSerializeGenerator =
|
||||
DebugPointAtInOrTo.Yes range0,
|
||||
SeqExprOnly.SeqExprOnly false,
|
||||
true,
|
||||
SynPat.CreateNamed (Ident.Create "mem"),
|
||||
SynExpr.CreateIdent (Ident.Create "field"),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "arr" ; "Add" ]),
|
||||
SynExpr.CreateParen (SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "mem"))
|
||||
),
|
||||
SynPat.named "mem",
|
||||
SynExpr.createIdent "field",
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "arr" ; "Add" ])
|
||||
(SynExpr.paren (SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "mem"))),
|
||||
range0
|
||||
)
|
||||
SynExpr.CreateIdentString "arr"
|
||||
SynExpr.createIdent "arr"
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "arr") []
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "arr" ] []
|
||||
]
|
||||
|> SynExpr.createLambda "field"
|
||||
| IDictionaryType (_keyType, valueType)
|
||||
@@ -117,46 +99,30 @@ module internal JsonSerializeGenerator =
|
||||
DebugPointAtInOrTo.Yes range0,
|
||||
SeqExprOnly.SeqExprOnly false,
|
||||
true,
|
||||
SynPat.CreateParen (
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateString "KeyValue",
|
||||
[
|
||||
SynPat.CreateParen (
|
||||
SynPat.Tuple (
|
||||
false,
|
||||
[
|
||||
SynPat.CreateNamed (Ident.Create "key")
|
||||
SynPat.CreateNamed (Ident.Create "value")
|
||||
],
|
||||
[ range0 ],
|
||||
range0
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
SynPat.paren (
|
||||
SynPat.identWithArgs
|
||||
[ Ident.create "KeyValue" ]
|
||||
(SynArgPats.create [ Ident.create "key" ; Ident.create "value" ])
|
||||
),
|
||||
SynExpr.CreateIdent (Ident.Create "field"),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "ret" ; "Add" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
SynExpr.createIdent "field",
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "ret" ; "Add" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "key" ; "ToString" ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
SynExpr.CreateApp (serializeNode valueType, SynExpr.CreateIdentString "value")
|
||||
]
|
||||
),
|
||||
SynExpr.createLongIdent [ "key" ; "ToString" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
SynExpr.applyFunction (serializeNode valueType) (SynExpr.createIdent "value")
|
||||
]),
|
||||
range0
|
||||
)
|
||||
SynExpr.CreateIdentString "ret"
|
||||
SynExpr.createIdent "ret"
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "ret") []
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "ret" ] []
|
||||
]
|
||||
|> SynExpr.createLambda "field"
|
||||
| _ ->
|
||||
@@ -166,22 +132,27 @@ 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" ])
|
||||
|
||||
/// 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.CreateApp (serializeNode fieldType, SynExpr.createLongIdent' [ Ident.Create "input" ; fieldId ])
|
||||
SynExpr.applyFunction
|
||||
(serializeNode fieldType)
|
||||
(SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ])
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
|
||||
let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr =
|
||||
let propertyNameAttr =
|
||||
attrs
|
||||
|> List.tryFind (fun attr -> attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal))
|
||||
|> List.tryFind (fun attr ->
|
||||
(SynLongIdent.toString attr.TypeName)
|
||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||
)
|
||||
|
||||
match propertyNameAttr with
|
||||
| None ->
|
||||
@@ -191,7 +162,7 @@ module internal JsonSerializeGenerator =
|
||||
if fieldId.idText.Length > 1 then
|
||||
sb.Append fieldId.idText.[1..] |> ignore
|
||||
|
||||
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||
sb.ToString () |> SynExpr.CreateConst
|
||||
| Some name -> name.ArgExpr
|
||||
|
||||
/// `populateNode` will be inserted before we return the `node` variable.
|
||||
@@ -207,67 +178,58 @@ module internal JsonSerializeGenerator =
|
||||
(populateNode : SynExpr)
|
||||
: SynModuleDecl
|
||||
=
|
||||
let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node"
|
||||
let xmlDoc = PreXmlDoc.create "Serialize to a JSON node"
|
||||
|
||||
let returnInfo =
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
|> SynType.LongIdent
|
||||
|
||||
let functionName = Ident.Create "toJsonNode"
|
||||
let functionName = Ident.create "toJsonNode"
|
||||
|
||||
let assignments =
|
||||
[
|
||||
populateNode
|
||||
SynExpr.Upcast (SynExpr.CreateIdentString "node", SynType.Anon range0, range0)
|
||||
SynExpr.Upcast (SynExpr.createIdent "node", SynType.Anon range0, range0)
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "node") []
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "node" ] []
|
||||
]
|
||||
|
||||
let pattern =
|
||||
SynPat.CreateNamed inputArgName
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName))
|
||||
SynPat.namedI inputArgName
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName))
|
||||
|
||||
if spec.ExtensionMethods then
|
||||
let binding =
|
||||
let componentInfo =
|
||||
SynComponentInfo.createLong typeName
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
||||
|
||||
let memberDef =
|
||||
assignments
|
||||
|> SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ pattern ]
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.makeStaticMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let containingType =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"),
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||
[ mem ],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ memberDef ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
else
|
||||
let binding =
|
||||
assignments
|
||||
|> SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ pattern ]
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|
||||
SynModuleDecl.CreateLet [ binding ]
|
||||
assignments
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let recordModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
||||
let inputArg = Ident.Create "input"
|
||||
let inputArg = Ident.create "input"
|
||||
let fields = fields |> List.map SynField.extractWithIdent
|
||||
|
||||
fields
|
||||
@@ -275,25 +237,25 @@ module internal JsonSerializeGenerator =
|
||||
let propertyName = getPropertyName fieldData.Ident fieldData.Attrs
|
||||
createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type
|
||||
)
|
||||
|> SynExpr.CreateSequential
|
||||
|> 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"
|
||||
let inputArg = Ident.create "input"
|
||||
let fields = cases |> List.map SynUnionCase.extract
|
||||
|
||||
fields
|
||||
|> List.map (fun unionCase ->
|
||||
let propertyName = getPropertyName unionCase.Ident unionCase.Attrs
|
||||
|
||||
let caseNames = unionCase.Fields |> List.mapi (fun i _ -> Ident.Create $"arg%i{i}")
|
||||
let caseNames = unionCase.Fields |> List.mapi (fun i _ -> Ident.create $"arg%i{i}")
|
||||
|
||||
let argPats = SynArgPats.create caseNames
|
||||
|
||||
let pattern =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent (typeName @ [ unionCase.Ident ]),
|
||||
SynLongIdent.create (typeName @ [ unionCase.Ident ]),
|
||||
None,
|
||||
None,
|
||||
argPats,
|
||||
@@ -303,26 +265,18 @@ module internal JsonSerializeGenerator =
|
||||
|
||||
let typeLine =
|
||||
[
|
||||
SynExpr.CreateConstString "type"
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ],
|
||||
SynExpr.CreateConst "type"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ])
|
||||
propertyName
|
||||
)
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
|
||||
let dataNode =
|
||||
SynBinding.Let (
|
||||
pattern = SynPat.CreateNamed (Ident.Create "dataNode"),
|
||||
expr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
),
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
)
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "dataNode" ] []
|
||||
|
||||
let dataBindings =
|
||||
(unionCase.Fields, caseNames)
|
||||
@@ -331,20 +285,20 @@ module internal JsonSerializeGenerator =
|
||||
let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs
|
||||
|
||||
let node =
|
||||
SynExpr.CreateApp (serializeNode fieldData.Type, SynExpr.CreateIdent caseName)
|
||||
SynExpr.applyFunction (serializeNode fieldData.Type) (SynExpr.createIdent' caseName)
|
||||
|
||||
[ propertyName ; node ]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ])
|
||||
)
|
||||
|
||||
let assignToNode =
|
||||
[ SynExpr.CreateConstString "data" ; SynExpr.CreateIdentString "dataNode" ]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
[ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
|
||||
let dataNode =
|
||||
SynExpr.CreateSequential (dataBindings @ [ assignToNode ])
|
||||
SynExpr.sequential (dataBindings @ [ assignToNode ])
|
||||
|> SynExpr.createLet [ dataNode ]
|
||||
|
||||
let action =
|
||||
@@ -353,11 +307,11 @@ module internal JsonSerializeGenerator =
|
||||
if not dataBindings.IsEmpty then
|
||||
yield dataNode
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|
||||
SynMatchClause.Create (pattern, None, action)
|
||||
SynMatchClause.create pattern action
|
||||
)
|
||||
|> fun clauses -> SynExpr.CreateMatch (SynExpr.CreateIdent inputArg, clauses)
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' inputArg)
|
||||
|> scaffolding spec typeName inputArg
|
||||
|
||||
let createModule
|
||||
@@ -374,12 +328,9 @@ module internal JsonSerializeGenerator =
|
||||
|
||||
let attributes =
|
||||
if spec.ExtensionMethods then
|
||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||
[ SynAttribute.autoOpen ]
|
||||
else
|
||||
[
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
]
|
||||
[ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
|
||||
|
||||
let xmlDoc =
|
||||
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||
@@ -390,8 +341,8 @@ module internal JsonSerializeGenerator =
|
||||
else
|
||||
"methods"
|
||||
|
||||
$" Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.Create
|
||||
$"Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let moduleName =
|
||||
if spec.ExtensionMethods then
|
||||
@@ -402,14 +353,16 @@ module internal JsonSerializeGenerator =
|
||||
List.last ident
|
||||
|> fun i -> i.idText
|
||||
|> fun s -> s + "JsonSerializeExtension"
|
||||
|> Ident.Create
|
||||
|> Ident.create
|
||||
|
||||
List.take (List.length ident - 1) ident @ [ expanded ]
|
||||
else
|
||||
ident
|
||||
|
||||
let info =
|
||||
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||
SynComponentInfo.createLong moduleName
|
||||
|> SynComponentInfo.addAttributes attributes
|
||||
|> SynComponentInfo.withDocString xmlDoc
|
||||
|
||||
let decls =
|
||||
match synTypeDefnRepr with
|
||||
@@ -419,12 +372,13 @@ module internal JsonSerializeGenerator =
|
||||
[ unionModule spec ident unionFields ]
|
||||
| _ -> failwithf "Only record types currently supported."
|
||||
|
||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||
[
|
||||
yield! opens |> List.map SynModuleDecl.openAny
|
||||
yield SynModuleDecl.nestedModule info decls
|
||||
]
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
namespaceId,
|
||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
|
||||
)
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||
/// containing a JSON serialization function.
|
||||
|
30
WoofWare.Myriad.Plugins/Primitives.fs
Normal file
30
WoofWare.Myriad.Plugins/Primitives.fs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Primitives =
|
||||
/// Given e.g. "byte", returns "System.Byte".
|
||||
let qualifyType (typeName : string) : LongIdent option =
|
||||
match typeName with
|
||||
| "float32"
|
||||
| "single" -> [ "System" ; "Single" ] |> Some
|
||||
| "float"
|
||||
| "double" -> [ "System" ; "Double" ] |> Some
|
||||
| "byte"
|
||||
| "uint8" -> [ "System" ; "Byte" ] |> Some
|
||||
| "sbyte"
|
||||
| "int8" -> [ "System" ; "SByte" ] |> Some
|
||||
| "int16" -> [ "System" ; "Int16" ] |> Some
|
||||
| "int"
|
||||
| "int32" -> [ "System" ; "Int32" ] |> Some
|
||||
| "int64" -> [ "System" ; "Int64" ] |> Some
|
||||
| "uint16" -> [ "System" ; "UInt16" ] |> Some
|
||||
| "uint"
|
||||
| "uint32" -> [ "System" ; "UInt32" ] |> Some
|
||||
| "uint64" -> [ "System" ; "UInt64" ] |> Some
|
||||
| "char" -> [ "System" ; "Char" ] |> Some
|
||||
| "decimal" -> [ "System" ; "Decimal" ] |> Some
|
||||
| _ -> None
|
||||
|> Option.map (List.map (fun i -> (Ident (i, range0))))
|
@@ -1,14 +1,11 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal RemoveOptionsGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
let private removeOption (s : SynField) : SynField =
|
||||
let (SynField.SynField (synAttributeLists,
|
||||
@@ -47,7 +44,7 @@ module internal RemoveOptionsGenerator =
|
||||
(fields : SynField list)
|
||||
=
|
||||
let fields : SynField list = fields |> List.map removeOption
|
||||
let name = Ident.Create "Short"
|
||||
let name = Ident.create "Short"
|
||||
|
||||
let record =
|
||||
{
|
||||
@@ -64,20 +61,10 @@ module internal RemoveOptionsGenerator =
|
||||
SynModuleDecl.Types ([ typeDecl ], range0)
|
||||
|
||||
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynFieldData<Ident> list) =
|
||||
let xmlDoc = PreXmlDoc.Create " Remove the optional members of the input."
|
||||
let xmlDoc = PreXmlDoc.create "Remove the optional members of the input."
|
||||
|
||||
let returnInfo =
|
||||
SynBindingReturnInfo.Create (SynType.LongIdent (SynLongIdent.CreateFromLongIdent withOptionsType))
|
||||
|
||||
let inputArg = Ident.Create "input"
|
||||
let functionName = Ident.Create "shorten"
|
||||
|
||||
let inputVal =
|
||||
SynValData.SynValData (
|
||||
None,
|
||||
SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty),
|
||||
Some inputArg
|
||||
)
|
||||
let inputArg = Ident.create "input"
|
||||
let functionName = Ident.create "shorten"
|
||||
|
||||
let body =
|
||||
fields
|
||||
@@ -93,65 +80,31 @@ module internal RemoveOptionsGenerator =
|
||||
let body =
|
||||
match fieldData.Type with
|
||||
| OptionType _ ->
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.LongIdent (
|
||||
false,
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_PipeRight" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "|>") ]
|
||||
),
|
||||
None,
|
||||
range0
|
||||
),
|
||||
accessor
|
||||
),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "Option.defaultWith"),
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.CreateFromLongIdent (
|
||||
withoutOptionsType
|
||||
@ [ Ident.Create (sprintf "Default%s" fieldData.Ident.idText) ]
|
||||
)
|
||||
)
|
||||
)
|
||||
accessor
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Option" ; "defaultWith" ])
|
||||
(SynExpr.createLongIdent' (
|
||||
withoutOptionsType
|
||||
@ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ]
|
||||
))
|
||||
)
|
||||
| _ -> accessor
|
||||
|
||||
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true), Some body
|
||||
(SynLongIdent.createI fieldData.Ident, true), Some body
|
||||
)
|
||||
|> AstHelper.instantiateRecord
|
||||
|
||||
let pattern =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ functionName ],
|
||||
None,
|
||||
None,
|
||||
SynArgPats.Pats
|
||||
[
|
||||
SynPat.CreateTyped (
|
||||
SynPat.CreateNamed inputArg,
|
||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent withoutOptionsType)
|
||||
)
|
||||
|> SynPat.CreateParen
|
||||
],
|
||||
None,
|
||||
range0
|
||||
)
|
||||
|
||||
let binding =
|
||||
SynBinding.Let (
|
||||
isInline = false,
|
||||
isMutable = false,
|
||||
xmldoc = xmlDoc,
|
||||
returnInfo = returnInfo,
|
||||
expr = body,
|
||||
valData = inputVal,
|
||||
pattern = pattern
|
||||
)
|
||||
|
||||
SynModuleDecl.CreateLet [ binding ]
|
||||
SynBinding.basic
|
||||
[ functionName ]
|
||||
[
|
||||
SynPat.named inputArg.idText
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create withoutOptionsType))
|
||||
]
|
||||
body
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation (SynType.LongIdent (SynLongIdent.create withOptionsType))
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let createRecordModule (namespaceId : LongIdent) (typeDefn : SynTypeDefn) =
|
||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||
@@ -167,30 +120,29 @@ module internal RemoveOptionsGenerator =
|
||||
let decls =
|
||||
[
|
||||
createType (Some doc) accessibility typeParams fields
|
||||
createMaker [ Ident.Create "Short" ] recordId fieldData
|
||||
]
|
||||
|
||||
let attributes =
|
||||
[
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
createMaker [ Ident.create "Short" ] recordId fieldData
|
||||
]
|
||||
|
||||
let xmlDoc =
|
||||
recordId
|
||||
|> Seq.map (fun i -> i.idText)
|
||||
|> String.concat "."
|
||||
|> sprintf " Module containing an option-truncated version of the %s type"
|
||||
|> PreXmlDoc.Create
|
||||
|> sprintf "Module containing an option-truncated version of the %s type"
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let info =
|
||||
SynComponentInfo.Create (recordId, attributes = attributes, xmldoc = xmlDoc)
|
||||
SynComponentInfo.createLong recordId
|
||||
|> SynComponentInfo.withDocString xmlDoc
|
||||
|> SynComponentInfo.addAttributes [ SynAttribute.compilationRepresentation ]
|
||||
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
|
||||
|
||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||
SynModuleDecl.nestedModule info decls
|
||||
|> List.singleton
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
| _ -> failwithf "Not a record type"
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that stamps out a record with option types stripped
|
||||
/// from the fields at the top level.
|
||||
[<MyriadGenerator("remove-options")>]
|
||||
|
49
WoofWare.Myriad.Plugins/SynExpr/CompExpr.fs
Normal file
49
WoofWare.Myriad.Plugins/SynExpr/CompExpr.fs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
|
||||
type internal CompExprBinding =
|
||||
| LetBang of varName : string * rhs : SynExpr
|
||||
| Let of varName : string * rhs : SynExpr
|
||||
| Use of varName : string * rhs : SynExpr
|
||||
| Do of body : SynExpr
|
||||
|
||||
(*
|
||||
Potential API!
|
||||
type internal CompExprBindings =
|
||||
private
|
||||
{
|
||||
/// These are stored in reverse.
|
||||
Bindings : CompExprBinding list
|
||||
CompExprName : string
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal CompExprBindings =
|
||||
let make (name : string) : CompExprBindings =
|
||||
{
|
||||
Bindings = []
|
||||
CompExprName = name
|
||||
}
|
||||
|
||||
let thenDo (body : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (Do body :: bindings.Bindings)
|
||||
}
|
||||
|
||||
let thenLet (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (Let (varName, value) :: bindings.Bindings)
|
||||
}
|
||||
|
||||
let thenLetBang (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (LetBang (varName, value) :: bindings.Bindings)
|
||||
}
|
||||
|
||||
|
||||
let thenUse (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (LetBang (varName, value) :: bindings.Bindings)
|
||||
}
|
||||
*)
|
@@ -3,12 +3,14 @@ namespace WoofWare.Myriad.Plugins
|
||||
open System
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Myriad.Core
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Ident =
|
||||
let inline create (s : string) = Ident (s, range0)
|
||||
|
||||
let lowerFirstLetter (x : Ident) : Ident =
|
||||
let result = StringBuilder x.idText.Length
|
||||
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
|
||||
result.Append x.idText.[1..] |> ignore
|
||||
Ident.Create ((result : StringBuilder).ToString ())
|
||||
create ((result : StringBuilder).ToString ())
|
9
WoofWare.Myriad.Plugins/SynExpr/PreXmlDoc.fs
Normal file
9
WoofWare.Myriad.Plugins/SynExpr/PreXmlDoc.fs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PreXmlDoc =
|
||||
let create (s : string) : PreXmlDoc =
|
||||
PreXmlDoc.Create ([| " " + s |], range0)
|
@@ -1,18 +1,16 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynArgPats =
|
||||
let create (caseNames : Ident list) : SynArgPats =
|
||||
if caseNames.IsEmpty then
|
||||
SynArgPats.Pats []
|
||||
else
|
||||
|
||||
caseNames
|
||||
|> List.map (fun ident -> SynPat.Named (SynIdent.SynIdent (ident, None), false, None, range0))
|
||||
|> fun ps -> SynPat.Tuple (false, ps, List.replicate (ps.Length - 1) range0, range0)
|
||||
|> fun p -> SynPat.Paren (p, range0)
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
match caseNames.Length with
|
||||
| 0 -> SynArgPats.Pats []
|
||||
| 1 -> [ SynPat.named caseNames.[0].idText ] |> SynArgPats.Pats
|
||||
| _ ->
|
||||
caseNames
|
||||
|> List.map (fun i -> SynPat.named i.idText)
|
||||
|> SynPat.tuple
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
|
@@ -2,20 +2,25 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynAttribute =
|
||||
let internal compilationRepresentation : SynAttribute =
|
||||
{
|
||||
TypeName = SynLongIdent.CreateString "CompilationRepresentation"
|
||||
TypeName = SynLongIdent.createS "CompilationRepresentation"
|
||||
ArgExpr =
|
||||
SynExpr.CreateLongIdent (
|
||||
false,
|
||||
SynLongIdent.Create [ "CompilationRepresentationFlags" ; "ModuleSuffix" ],
|
||||
None
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
[ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
|
||||
|> SynExpr.createLongIdent
|
||||
|> SynExpr.paren
|
||||
Target = None
|
||||
AppliesToGetterAndSetter = false
|
||||
Range = range0
|
||||
}
|
||||
|
||||
let internal requireQualifiedAccess : SynAttribute =
|
||||
{
|
||||
TypeName = SynLongIdent.createS "RequireQualifiedAccess"
|
||||
ArgExpr = SynExpr.CreateConst ()
|
||||
Target = None
|
||||
AppliesToGetterAndSetter = false
|
||||
Range = range0
|
||||
@@ -23,8 +28,8 @@ module internal SynAttribute =
|
||||
|
||||
let internal autoOpen : SynAttribute =
|
||||
{
|
||||
TypeName = SynLongIdent.CreateString "AutoOpen"
|
||||
ArgExpr = SynExpr.CreateConst SynConst.Unit
|
||||
TypeName = SynLongIdent.createS "AutoOpen"
|
||||
ArgExpr = SynExpr.CreateConst ()
|
||||
Target = None
|
||||
AppliesToGetterAndSetter = false
|
||||
Range = range0
|
||||
|
@@ -16,14 +16,18 @@ module internal SynBinding =
|
||||
let rec private getName (pat : SynPat) : Ident option =
|
||||
match stripParen pat with
|
||||
| SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name
|
||||
| SynPat.Wild _ -> None
|
||||
| SynPat.Typed (pat, _, _) -> getName pat
|
||||
| SynPat.Const _ -> None
|
||||
| SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) ->
|
||||
match longIdent with
|
||||
| [ x ] -> Some x
|
||||
| _ -> failwithf "got long ident %O ; can only get the name of a long ident with one component" longIdent
|
||||
| _ -> failwithf "unrecognised pattern: %+A" pat
|
||||
| _ -> None
|
||||
|
||||
let private getArgInfo (pat : SynPat) : SynArgInfo list =
|
||||
// TODO: this only copes with one layer of tupling
|
||||
match stripParen pat with
|
||||
| SynPat.Tuple (_, pats, _, _) -> pats |> List.map (fun pat -> SynArgInfo.SynArgInfo ([], false, getName pat))
|
||||
| pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ]
|
||||
|
||||
let triviaZero (isMember : bool) =
|
||||
{
|
||||
@@ -36,10 +40,10 @@ module internal SynBinding =
|
||||
SynLeadingKeyword.Let range0
|
||||
}
|
||||
|
||||
let basic (name : SynLongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
|
||||
let basic (name : LongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
|
||||
let valInfo : SynValInfo =
|
||||
args
|
||||
|> List.map (fun pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ])
|
||||
|> List.map getArgInfo
|
||||
|> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None))
|
||||
|
||||
SynBinding.SynBinding (
|
||||
@@ -50,7 +54,7 @@ module internal SynBinding =
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
SynValData.SynValData (None, valInfo, None),
|
||||
SynPat.LongIdent (name, None, None, SynArgPats.Pats args, None, range0),
|
||||
SynPat.identWithArgs name (SynArgPats.Pats args),
|
||||
None,
|
||||
body,
|
||||
range0,
|
||||
@@ -103,7 +107,7 @@ module internal SynBinding =
|
||||
trivia
|
||||
)
|
||||
|
||||
let makeInline (binding : SynBinding) : SynBinding =
|
||||
let inline makeInline (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
||||
SynBinding (
|
||||
@@ -124,6 +128,33 @@ module internal SynBinding =
|
||||
}
|
||||
)
|
||||
|
||||
let inline makeNotInline (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
||||
SynBinding (
|
||||
acc,
|
||||
kind,
|
||||
false,
|
||||
mut,
|
||||
attrs,
|
||||
doc,
|
||||
valData,
|
||||
headPat,
|
||||
ret,
|
||||
expr,
|
||||
range,
|
||||
debugPoint,
|
||||
{ trivia with
|
||||
InlineKeyword = None
|
||||
}
|
||||
)
|
||||
|
||||
let inline setInline (isInline : bool) (binding : SynBinding) : SynBinding =
|
||||
if isInline then
|
||||
makeInline binding
|
||||
else
|
||||
makeNotInline binding
|
||||
|
||||
let makeStaticMember (binding : SynBinding) : SynBinding =
|
||||
let memberFlags =
|
||||
{
|
||||
|
50
WoofWare.Myriad.Plugins/SynExpr/SynComponentInfo.fs
Normal file
50
WoofWare.Myriad.Plugins/SynExpr/SynComponentInfo.fs
Normal file
@@ -0,0 +1,50 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynComponentInfo =
|
||||
let inline createLong (name : LongIdent) =
|
||||
SynComponentInfo.SynComponentInfo ([], None, [], name, PreXmlDoc.Empty, false, None, range0)
|
||||
|
||||
let inline create (name : Ident) = createLong [ name ]
|
||||
|
||||
let inline withDocString (doc : PreXmlDoc) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, _, postfix, access, range) ->
|
||||
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
|
||||
|
||||
let inline setGenerics (typars : SynTyparDecls option) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, _, constraints, name, doc, postfix, access, range) ->
|
||||
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
|
||||
|
||||
let inline withGenerics (typars : SynTyparDecl list) (i : SynComponentInfo) : SynComponentInfo =
|
||||
let inner =
|
||||
if typars.IsEmpty then
|
||||
None
|
||||
else
|
||||
Some (SynTyparDecls.PostfixList (typars, [], range0))
|
||||
|
||||
setGenerics inner i
|
||||
|
||||
let inline setAccessibility (acc : SynAccess option) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, _, range) ->
|
||||
SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, acc, range)
|
||||
|
||||
let inline withAccessibility (acc : SynAccess) (i : SynComponentInfo) : SynComponentInfo =
|
||||
setAccessibility (Some acc) i
|
||||
|
||||
let inline addAttributes (attrs : SynAttribute list) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (oldAttrs, typars, constraints, name, doc, postfix, acc, range) ->
|
||||
let attrs =
|
||||
{
|
||||
SynAttributeList.Attributes = attrs
|
||||
SynAttributeList.Range = range0
|
||||
}
|
||||
|
||||
SynComponentInfo.SynComponentInfo ((attrs :: oldAttrs), typars, constraints, name, doc, postfix, acc, range)
|
@@ -3,14 +3,18 @@ namespace WoofWare.Myriad.Plugins
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Myriad.Core
|
||||
open Myriad.Core.Ast
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
type internal CompExprBinding =
|
||||
| LetBang of varName : string * rhs : SynExpr
|
||||
| Let of varName : string * rhs : SynExpr
|
||||
| Use of varName : string * rhs : SynExpr
|
||||
| Do of body : SynExpr
|
||||
[<AutoOpen>]
|
||||
module internal SynExprExtensions =
|
||||
type SynExpr with
|
||||
static member CreateConst (s : string) : SynExpr =
|
||||
SynExpr.Const (SynConst.String (s, SynStringKind.Regular, range0), range0)
|
||||
|
||||
static member CreateConst () : SynExpr = SynExpr.Const (SynConst.Unit, range0)
|
||||
|
||||
static member CreateConst (i : int32) : SynExpr =
|
||||
SynExpr.Const (SynConst.Int32 i, range0)
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynExpr =
|
||||
@@ -19,20 +23,11 @@ module internal SynExpr =
|
||||
let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
|
||||
|
||||
/// {f} {x}
|
||||
let applyTo (x : SynExpr) (f : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
|
||||
let inline applyTo (x : SynExpr) (f : SynExpr) : SynExpr = applyFunction f x
|
||||
|
||||
/// {expr} |> {func}
|
||||
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_PipeRight" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "|>") ]
|
||||
)
|
||||
),
|
||||
expr
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.pipe, expr)
|
||||
|> applyTo func
|
||||
|
||||
/// if {cond} then {trueBranch} else {falseBranch}
|
||||
@@ -58,7 +53,7 @@ module internal SynExpr =
|
||||
/// try {body} with | {exc} as exc -> {handler}
|
||||
let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr =
|
||||
let clause =
|
||||
SynMatchClause.Create (SynPat.As (exc, SynPat.CreateNamed (Ident.Create "exc"), range0), None, handler)
|
||||
SynMatchClause.create (SynPat.As (exc, SynPat.named "exc", range0)) handler
|
||||
|
||||
SynExpr.TryWith (
|
||||
body,
|
||||
@@ -76,17 +71,7 @@ module internal SynExpr =
|
||||
|
||||
/// {a} = {b}
|
||||
let equals (a : SynExpr) (b : SynExpr) =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
Ident.CreateLong "op_Equality",
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "=") ]
|
||||
)
|
||||
),
|
||||
a
|
||||
)
|
||||
|> applyTo b
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.eq, a) |> applyTo b
|
||||
|
||||
/// {a} + {b}
|
||||
let plus (a : SynExpr) (b : SynExpr) =
|
||||
@@ -112,46 +97,49 @@ module internal SynExpr =
|
||||
SynExpr.DotGet (
|
||||
obj,
|
||||
range0,
|
||||
SynLongIdent.SynLongIdent (id = [ Ident.Create meth ], dotRanges = [], trivia = [ None ]),
|
||||
SynLongIdent.SynLongIdent (id = [ Ident.create meth ], dotRanges = [], trivia = [ None ]),
|
||||
range0
|
||||
)
|
||||
|> applyTo arg
|
||||
|
||||
/// {obj}.{meth}()
|
||||
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
||||
callMethodArg meth (SynExpr.CreateConst SynConst.Unit) obj
|
||||
callMethodArg meth (SynExpr.CreateConst ()) obj
|
||||
|
||||
let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
|
||||
range0,
|
||||
[ SynType.LongIdent (SynLongIdent.CreateFromLongIdent ty) ],
|
||||
[ SynType.LongIdent (SynLongIdent.create ty) ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
|> applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
/// {obj}.{meth}<ty>()
|
||||
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
|
||||
range0,
|
||||
[ SynType.CreateLongIdent ty ],
|
||||
[ SynType.createLongIdent' [ ty ] ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
|> applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
let index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.DotIndexedGet (obj, property, range0, range0)
|
||||
|
||||
let inline paren (e : SynExpr) : SynExpr =
|
||||
SynExpr.Paren (e, range0, Some range0, range0)
|
||||
|
||||
/// (fun {varName} -> {body})
|
||||
let createLambda (varName : string) (body : SynExpr) : SynExpr =
|
||||
let parsedDataPat = [ SynPat.CreateNamed (Ident.Create varName) ]
|
||||
let parsedDataPat = [ SynPat.named varName ]
|
||||
|
||||
SynExpr.Lambda (
|
||||
false,
|
||||
@@ -164,39 +152,82 @@ module internal SynExpr =
|
||||
ArrowRange = Some range0
|
||||
}
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> paren
|
||||
|
||||
let reraise : SynExpr =
|
||||
SynExpr.CreateIdent (Ident.Create "reraise")
|
||||
|> applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
let createThunk (body : SynExpr) : SynExpr =
|
||||
SynExpr.Lambda (
|
||||
false,
|
||||
false,
|
||||
SynSimplePats.Create [],
|
||||
body,
|
||||
Some ([ SynPat.unit ], body),
|
||||
range0,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
}
|
||||
)
|
||||
|> paren
|
||||
|
||||
let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0))
|
||||
|
||||
let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i
|
||||
|
||||
let inline createLongIdent' (ident : Ident list) : SynExpr =
|
||||
SynExpr.LongIdent (false, SynLongIdent.create ident, None, range0)
|
||||
|
||||
let inline createLongIdent (ident : string list) : SynExpr =
|
||||
createLongIdent' (ident |> List.map Ident.create)
|
||||
|
||||
let tupleNoParen (args : SynExpr list) : SynExpr =
|
||||
SynExpr.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|
||||
let inline tuple (args : SynExpr list) = args |> tupleNoParen |> paren
|
||||
|
||||
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
|
||||
let startAsTask (ct : SynLongIdent) (body : SynExpr) =
|
||||
let startAsTask (ct : Ident) (body : SynExpr) =
|
||||
let lambda =
|
||||
[
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "a")
|
||||
createIdent "a"
|
||||
equals
|
||||
(SynExpr.LongIdent (true, SynLongIdent.CreateString "cancellationToken", None, range0))
|
||||
(SynExpr.CreateLongIdent ct)
|
||||
(SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
|
||||
(createIdent' ct)
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> applyFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "StartAsTask" ]))
|
||||
|> tuple
|
||||
|> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ])
|
||||
|> createLambda "a"
|
||||
|
||||
pipeThroughFunction lambda body
|
||||
|
||||
let createLongIdent (ident : string list) : SynExpr =
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create ident)
|
||||
|
||||
let createLongIdent' (ident : Ident list) : SynExpr =
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident)
|
||||
|
||||
let createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
|
||||
let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
|
||||
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty)
|
||||
|
||||
let createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr = SynExpr.CreateMatch (matchOn, cases)
|
||||
let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr =
|
||||
SynExpr.Match (
|
||||
DebugPointAtBinding.Yes range0,
|
||||
matchOn,
|
||||
cases,
|
||||
range0,
|
||||
{
|
||||
MatchKeyword = range0
|
||||
WithKeyword = range0
|
||||
}
|
||||
)
|
||||
|
||||
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.CreateTyped (expr, ty)
|
||||
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.Typed (expr, ty, range0)
|
||||
|
||||
let inline createNew (ty : SynType) (args : SynExpr) : SynExpr =
|
||||
SynExpr.New (false, ty, paren args, range0)
|
||||
|
||||
let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr =
|
||||
SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0)
|
||||
|
||||
let inline createNull () : SynExpr = SynExpr.Null range0
|
||||
|
||||
let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
let sequential (exprs : SynExpr list) : SynExpr =
|
||||
exprs
|
||||
|> List.reduce (fun a b -> SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, a, b, range0))
|
||||
|
||||
/// {compExpr} { {lets} ; return {ret} }
|
||||
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
|
||||
@@ -211,7 +242,7 @@ module internal SynExpr =
|
||||
DebugPointAtBinding.Yes range0,
|
||||
false,
|
||||
true,
|
||||
SynPat.CreateNamed (Ident.Create lhs),
|
||||
SynPat.named lhs,
|
||||
rhs,
|
||||
[],
|
||||
state,
|
||||
@@ -220,90 +251,50 @@ module internal SynExpr =
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
)
|
||||
| Let (lhs, rhs) ->
|
||||
createLet [ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ] state
|
||||
| Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state
|
||||
| Use (lhs, rhs) ->
|
||||
SynExpr.LetOrUse (
|
||||
false,
|
||||
true,
|
||||
[ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ],
|
||||
[ SynBinding.basic [ Ident.create lhs ] [] rhs ],
|
||||
state,
|
||||
range0,
|
||||
{
|
||||
SynExprLetOrUseTrivia.InKeyword = None
|
||||
}
|
||||
)
|
||||
| Do body -> SynExpr.CreateSequential [ SynExpr.Do (body, range0) ; state ]
|
||||
| Do body -> sequential [ SynExpr.Do (body, range0) ; state ]
|
||||
)
|
||||
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateIdent (Ident.Create compExpr),
|
||||
SynExpr.ComputationExpr (false, contents, range0)
|
||||
)
|
||||
applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0))
|
||||
|
||||
/// {expr} |> Async.AwaitTask
|
||||
let awaitTask (expr : SynExpr) : SynExpr =
|
||||
expr
|
||||
|> pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "AwaitTask" ]))
|
||||
expr |> pipeThroughFunction (createLongIdent [ "Async" ; "AwaitTask" ])
|
||||
|
||||
/// {ident}.ToString ()
|
||||
/// with special casing for some types like DateTime
|
||||
let toString (ty : SynType) (ident : SynExpr) =
|
||||
match ty with
|
||||
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-dd")
|
||||
| DateTime ->
|
||||
ident
|
||||
|> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-ddTHH:mm:ss")
|
||||
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-dd")
|
||||
| DateTime -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-ddTHH:mm:ss")
|
||||
| _ -> callMethod "ToString" ident
|
||||
|
||||
let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0)
|
||||
|
||||
/// {ident} - {rhs}
|
||||
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_Subtraction" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "-") ]
|
||||
)
|
||||
),
|
||||
SynExpr.CreateLongIdent ident
|
||||
),
|
||||
rhs
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.sub, SynExpr.CreateLongIdent ident)
|
||||
|> applyTo rhs
|
||||
|
||||
/// {ident} - {n}
|
||||
let minusN (ident : SynLongIdent) (n : int) : SynExpr =
|
||||
minus ident (SynExpr.CreateConst (SynConst.Int32 n))
|
||||
let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n)
|
||||
|
||||
/// {y} > {x}
|
||||
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_GreaterThan" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation ">") ]
|
||||
)
|
||||
),
|
||||
y
|
||||
),
|
||||
x
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.ge, y) |> applyTo x
|
||||
|
||||
/// {y} >= {x}
|
||||
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_GreaterThanOrEqual" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
||||
)
|
||||
),
|
||||
y
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.geq, y)
|
||||
|> applyTo x
|
||||
|
@@ -1,6 +1,9 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
|
||||
type internal SynFieldData<'Ident> =
|
||||
{
|
||||
@@ -37,3 +40,30 @@ module internal SynField =
|
||||
| None -> failwith "expected field identifier to have a value, but it did not"
|
||||
| Some i -> i
|
||||
)
|
||||
|
||||
let make (data : SynFieldData<Ident option>) : SynField =
|
||||
let attrs : SynAttributeList list =
|
||||
data.Attrs
|
||||
|> List.map (fun l ->
|
||||
{
|
||||
Attributes = [ l ]
|
||||
Range = range0
|
||||
}
|
||||
)
|
||||
|
||||
SynField.SynField (
|
||||
attrs,
|
||||
false,
|
||||
data.Ident,
|
||||
data.Type,
|
||||
false,
|
||||
PreXmlDoc.Empty,
|
||||
None,
|
||||
range0,
|
||||
SynFieldTrivia.Zero
|
||||
)
|
||||
|
||||
let withDocString (doc : PreXmlDoc) (f : SynField) : SynField =
|
||||
match f with
|
||||
| SynField (attributes, isStatic, idOpt, fieldType, isMutable, _, accessibility, range, trivia) ->
|
||||
SynField (attributes, isStatic, idOpt, fieldType, isMutable, doc, accessibility, range, trivia)
|
||||
|
106
WoofWare.Myriad.Plugins/SynExpr/SynLongIdent.fs
Normal file
106
WoofWare.Myriad.Plugins/SynExpr/SynLongIdent.fs
Normal file
@@ -0,0 +1,106 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Syntax
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynLongIdent =
|
||||
|
||||
let geq =
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.create "op_GreaterThanOrEqual" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
||||
)
|
||||
|
||||
let ge =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ Some (IdentTrivia.OriginalNotation ">") ])
|
||||
|
||||
let sub =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Subtraction" ], [], [ Some (IdentTrivia.OriginalNotation "-") ])
|
||||
|
||||
let eq =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Equality" ], [], [ Some (IdentTrivia.OriginalNotation "=") ])
|
||||
|
||||
let pipe =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_PipeRight" ], [], [ Some (IdentTrivia.OriginalNotation "|>") ])
|
||||
|
||||
let toString (sli : SynLongIdent) : string =
|
||||
sli.LongIdent |> List.map _.idText |> String.concat "."
|
||||
|
||||
let create (ident : LongIdent) : SynLongIdent =
|
||||
let commas =
|
||||
match ident with
|
||||
| [] -> []
|
||||
| _ :: commas -> commas |> List.map (fun _ -> range0)
|
||||
|
||||
SynLongIdent.SynLongIdent (ident, commas, List.replicate ident.Length None)
|
||||
|
||||
let inline createI (i : Ident) : SynLongIdent = create [ i ]
|
||||
|
||||
let inline createS (s : string) : SynLongIdent = createI (Ident (s, range0))
|
||||
|
||||
let inline createS' (s : string list) : SynLongIdent =
|
||||
create (s |> List.map (fun i -> Ident (i, range0)))
|
||||
|
||||
let isUnit (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
| _ -> false
|
||||
|
||||
let isList (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider FSharpList or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isArray (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when
|
||||
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|
||||
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
|
||||
->
|
||||
true
|
||||
| _ -> false
|
||||
|
||||
let isOption (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isResponse (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Response" ]
|
||||
| [ "RestEase" ; "Response" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isMap (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Map" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isReadOnlyDictionary (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IReadOnlyDictionary" ]
|
||||
| [ "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isDictionary (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Dictionary" ]
|
||||
| [ "Generic" ; "Dictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "Dictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isIDictionary (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IDictionary" ]
|
||||
| [ "Generic" ; "IDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
|
||||
| _ -> false
|
24
WoofWare.Myriad.Plugins/SynExpr/SynMatchClause.fs
Normal file
24
WoofWare.Myriad.Plugins/SynExpr/SynMatchClause.fs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynMatchClause =
|
||||
let create (lhs : SynPat) (rhs : SynExpr) : SynMatchClause =
|
||||
SynMatchClause.SynMatchClause (
|
||||
lhs,
|
||||
None,
|
||||
rhs,
|
||||
range0,
|
||||
DebugPointAtTarget.Yes,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
BarRange = Some range0
|
||||
}
|
||||
)
|
||||
|
||||
let withWhere (where : SynExpr) (m : SynMatchClause) : SynMatchClause =
|
||||
match m with
|
||||
| SynMatchClause (synPat, _, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia) ->
|
||||
SynMatchClause (synPat, Some where, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia)
|
65
WoofWare.Myriad.Plugins/SynExpr/SynMemberDefn.fs
Normal file
65
WoofWare.Myriad.Plugins/SynExpr/SynMemberDefn.fs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Xml
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynMemberDefn =
|
||||
let private interfaceMemberSlotFlags =
|
||||
{
|
||||
SynMemberFlags.IsInstance = true
|
||||
SynMemberFlags.IsDispatchSlot = true
|
||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||
SynMemberFlags.IsFinal = false
|
||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||
}
|
||||
|
||||
|
||||
let abstractMember
|
||||
(ident : SynIdent)
|
||||
(typars : SynTyparDecls option)
|
||||
(arity : SynValInfo)
|
||||
(xmlDoc : PreXmlDoc)
|
||||
(returnType : SynType)
|
||||
: SynMemberDefn
|
||||
=
|
||||
let slot =
|
||||
SynValSig.SynValSig (
|
||||
[],
|
||||
ident,
|
||||
SynValTyparDecls.SynValTyparDecls (typars, true),
|
||||
returnType,
|
||||
arity,
|
||||
false,
|
||||
false,
|
||||
xmlDoc,
|
||||
None,
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
InlineKeyword = None
|
||||
LeadingKeyword = SynLeadingKeyword.Abstract range0
|
||||
}
|
||||
)
|
||||
|
||||
SynMemberDefn.AbstractSlot (
|
||||
slot,
|
||||
interfaceMemberSlotFlags,
|
||||
range0,
|
||||
{
|
||||
GetSetKeywords = None
|
||||
}
|
||||
)
|
||||
|
||||
let staticMember (binding : SynBinding) : SynMemberDefn =
|
||||
let binding = SynBinding.makeStaticMember binding
|
||||
SynMemberDefn.Member (binding, range0)
|
||||
|
||||
let memberImplementation (binding : SynBinding) : SynMemberDefn =
|
||||
let binding = SynBinding.makeInstanceMember binding
|
||||
SynMemberDefn.Member (binding, range0)
|
28
WoofWare.Myriad.Plugins/SynExpr/SynModuleDecl.fs
Normal file
28
WoofWare.Myriad.Plugins/SynExpr/SynModuleDecl.fs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynModuleDecl =
|
||||
|
||||
let inline openAny (ident : SynOpenDeclTarget) : SynModuleDecl = SynModuleDecl.Open (ident, range0)
|
||||
|
||||
let inline createLets (bindings : SynBinding list) : SynModuleDecl =
|
||||
SynModuleDecl.Let (false, bindings, range0)
|
||||
|
||||
let inline createLet (binding : SynBinding) : SynModuleDecl = createLets [ binding ]
|
||||
|
||||
let nestedModule (info : SynComponentInfo) (decls : SynModuleDecl list) : SynModuleDecl =
|
||||
SynModuleDecl.NestedModule (
|
||||
info,
|
||||
false,
|
||||
decls,
|
||||
false,
|
||||
range0,
|
||||
{
|
||||
ModuleKeyword = Some range0
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
)
|
24
WoofWare.Myriad.Plugins/SynExpr/SynModuleOrNamespace.fs
Normal file
24
WoofWare.Myriad.Plugins/SynExpr/SynModuleOrNamespace.fs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynModuleOrNamespace =
|
||||
|
||||
let createNamespace (name : LongIdent) (decls : SynModuleDecl list) =
|
||||
SynModuleOrNamespace.SynModuleOrNamespace (
|
||||
name,
|
||||
false,
|
||||
SynModuleOrNamespaceKind.DeclaredNamespace,
|
||||
decls,
|
||||
PreXmlDoc.Empty,
|
||||
[],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.Namespace range0
|
||||
}
|
||||
)
|
@@ -5,6 +5,31 @@ open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynPat =
|
||||
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
|
||||
|
||||
let annotateType (ty : SynType) (pat : SynPat) =
|
||||
SynPat.Paren (SynPat.Typed (pat, ty, range0), range0)
|
||||
let inline annotateTypeNoParen (ty : SynType) (pat : SynPat) = SynPat.Typed (pat, ty, range0)
|
||||
|
||||
let inline annotateType (ty : SynType) (pat : SynPat) = paren (annotateTypeNoParen ty pat)
|
||||
|
||||
let inline named (s : string) : SynPat =
|
||||
SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0)
|
||||
|
||||
let inline namedI (i : Ident) : SynPat =
|
||||
SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0)
|
||||
|
||||
let inline identWithArgs (i : LongIdent) (args : SynArgPats) : SynPat =
|
||||
SynPat.LongIdent (SynLongIdent.create i, None, None, args, None, range0)
|
||||
|
||||
let inline tupleNoParen (elements : SynPat list) : SynPat =
|
||||
match elements with
|
||||
| [] -> failwith "Can't tuple no elements in a pattern"
|
||||
| [ p ] -> p
|
||||
| elements -> SynPat.Tuple (false, elements, List.replicate (elements.Length - 1) range0, range0)
|
||||
|
||||
let inline tuple (elements : SynPat list) : SynPat = tupleNoParen elements |> paren
|
||||
|
||||
let inline createConst (c : SynConst) = SynPat.Const (c, range0)
|
||||
|
||||
let unit = createConst SynConst.Unit
|
||||
|
||||
let createNull = SynPat.Null range0
|
||||
|
@@ -1,6 +1,7 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynType =
|
||||
@@ -8,3 +9,231 @@ module internal SynType =
|
||||
match ty with
|
||||
| SynType.Paren (ty, _) -> stripOptionalParen ty
|
||||
| ty -> ty
|
||||
|
||||
let inline createLongIdent (ident : LongIdent) : SynType =
|
||||
SynType.LongIdent (SynLongIdent.create ident)
|
||||
|
||||
let inline createLongIdent' (ident : string list) : SynType =
|
||||
SynType.LongIdent (SynLongIdent.createS' ident)
|
||||
|
||||
let inline named (name : string) = createLongIdent' [ name ]
|
||||
|
||||
let inline app' (name : SynType) (args : SynType list) : SynType =
|
||||
if args.IsEmpty then
|
||||
failwith "Type cannot be applied to no arguments"
|
||||
|
||||
SynType.App (name, Some range0, args, List.replicate (args.Length - 1) range0, Some range0, false, range0)
|
||||
|
||||
let inline app (name : string) (args : SynType list) : SynType = app' (named name) args
|
||||
|
||||
let inline appPostfix (name : string) (arg : SynType) : SynType =
|
||||
SynType.App (named name, None, [ arg ], [], None, true, range0)
|
||||
|
||||
let inline funFromDomain (domain : SynType) (range : SynType) : SynType =
|
||||
SynType.Fun (
|
||||
domain,
|
||||
range,
|
||||
range0,
|
||||
{
|
||||
ArrowRange = range0
|
||||
}
|
||||
)
|
||||
|
||||
let inline signatureParamOfType (ty : SynType) (name : Ident option) : SynType =
|
||||
SynType.SignatureParameter ([], false, name, ty, range0)
|
||||
|
||||
let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0)
|
||||
|
||||
let unit : SynType = named "unit"
|
||||
let int : SynType = named "int"
|
||||
|
||||
/// Given ['a1, 'a2] and 'ret, returns 'a1 -> 'a2 -> 'ret.
|
||||
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
||||
(ret, List.rev inputs) ||> List.fold (fun ty input -> funFromDomain input ty)
|
||||
|
||||
[<AutoOpen>]
|
||||
module internal SynTypePatterns =
|
||||
let (|OptionType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isOption ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident when SynLongIdent.isUnit ident -> Some ()
|
||||
| _ -> None
|
||||
|
||||
let (|ListType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isList ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|ArrayType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isArray ident ->
|
||||
Some innerType
|
||||
| SynType.Array (1, innerType, _) -> Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|RestEaseResponseType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isResponse ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|DictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isDictionary ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isIDictionary ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
|
||||
SynLongIdent.isReadOnlyDictionary ident
|
||||
->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|MapType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isMap ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|BigInt|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "bigint" ]
|
||||
| [ "BigInteger" ]
|
||||
| [ "Numerics" ; "BigInteger" ]
|
||||
| [ "System" ; "Numerics" ; "BigInteger" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Returns the type, qualified as in e.g. `System.Boolean`.
|
||||
let (|PrimitiveType|_|) (fieldType : SynType) : LongIdent option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> Primitives.qualifyType i.idText
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|String|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] ->
|
||||
[ "string" ]
|
||||
|> List.tryFind (fun s -> s = i.idText)
|
||||
|> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Byte|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Guid|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Guid" ]
|
||||
| [ "Guid" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Http" ; "HttpResponseMessage" ]
|
||||
| [ "HttpResponseMessage" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpContent|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Http" ; "HttpContent" ]
|
||||
| [ "HttpContent" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Stream|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "IO" ; "Stream" ]
|
||||
| [ "IO" ; "Stream" ]
|
||||
| [ "Stream" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|NumberType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "string" ; "float" ; "int" ; "bool" ] |> List.tryFind (fun s -> s = i.idText)
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateOnly|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateOnly" ]
|
||||
| [ "DateOnly" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateTime|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateTime" ]
|
||||
| [ "DateTime" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Uri|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Uri" ]
|
||||
| [ "Uri" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Task|_|) (fieldType : SynType) : SynType option =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "Task" ]
|
||||
| [ "Tasks" ; "Task" ]
|
||||
| [ "Threading" ; "Tasks" ; "Task" ]
|
||||
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
|
||||
match args with
|
||||
| [ arg ] -> Some arg
|
||||
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
27
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefn.fs
Normal file
27
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefn.fs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynTypeDefn =
|
||||
|
||||
let inline create (componentInfo : SynComponentInfo) (repr : SynTypeDefnRepr) : SynTypeDefn =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
componentInfo,
|
||||
repr,
|
||||
[],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = Some range0
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
|
||||
let inline withMemberDefns (members : SynMemberDefn list) (r : SynTypeDefn) : SynTypeDefn =
|
||||
match r with
|
||||
| SynTypeDefn (typeInfo, typeRepr, _, ctor, range, trivia) ->
|
||||
SynTypeDefn.SynTypeDefn (typeInfo, typeRepr, members, ctor, range, trivia)
|
20
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefnRepr.fs
Normal file
20
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefnRepr.fs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynTypeDefnRepr =
|
||||
|
||||
let inline interfaceType (mems : SynMemberDefns) : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Unspecified, mems, range0)
|
||||
|
||||
/// Indicates the body of a `type Foo with {body}` extension type declaration.
|
||||
let inline augmentation () : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0)
|
||||
|
||||
let inline union (cases : SynUnionCase list) : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (None, cases, range0), range0)
|
||||
|
||||
let inline record (fields : SynField list) : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, fields, range0), range0)
|
@@ -9,6 +9,15 @@ type internal UnionCase<'Ident> =
|
||||
Ident : Ident
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal UnionCase =
|
||||
let mapIdentFields<'a, 'b> (f : 'a -> 'b) (unionCase : UnionCase<'a>) : UnionCase<'b> =
|
||||
{
|
||||
Fields = unionCase.Fields |> List.map (SynField.mapIdent f)
|
||||
Attrs = unionCase.Attrs
|
||||
Ident = unionCase.Ident
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynUnionCase =
|
||||
let extract (SynUnionCase (attrs, id, caseType, _, _, _, _)) : UnionCase<Ident option> =
|
||||
|
@@ -25,17 +25,28 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="List.fs"/>
|
||||
<Compile Include="Ident.fs" />
|
||||
<Compile Include="AstHelper.fs"/>
|
||||
<Compile Include="Primitives.fs" />
|
||||
<Compile Include="SynExpr\PreXmlDoc.fs" />
|
||||
<Compile Include="SynExpr\Ident.fs" />
|
||||
<Compile Include="SynExpr\SynLongIdent.fs" />
|
||||
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
|
||||
<Compile Include="SynExpr\SynPat.fs" />
|
||||
<Compile Include="SynExpr\SynBinding.fs" />
|
||||
<Compile Include="SynExpr\SynExpr.fs" />
|
||||
<Compile Include="SynExpr\SynType.fs" />
|
||||
<Compile Include="SynExpr\SynAttribute.fs" />
|
||||
<Compile Include="SynExpr\SynMatchClause.fs" />
|
||||
<Compile Include="SynExpr\CompExpr.fs" />
|
||||
<Compile Include="SynExpr\SynExpr.fs" />
|
||||
<Compile Include="SynExpr\SynArgPats.fs" />
|
||||
<Compile Include="SynExpr\SynField.fs" />
|
||||
<Compile Include="SynExpr\SynUnionCase.fs" />
|
||||
<Compile Include="SynExpr\SynPat.fs" />
|
||||
<Compile Include="SynExpr\SynTypeDefnRepr.fs" />
|
||||
<Compile Include="SynExpr\SynTypeDefn.fs" />
|
||||
<Compile Include="SynExpr\SynComponentInfo.fs" />
|
||||
<Compile Include="SynExpr\SynMemberDefn.fs" />
|
||||
<Compile Include="SynExpr\SynAttribute.fs" />
|
||||
<Compile Include="SynExpr\SynModuleDecl.fs" />
|
||||
<Compile Include="SynExpr\SynModuleOrNamespace.fs" />
|
||||
<Compile Include="AstHelper.fs" />
|
||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||
<Compile Include="InterfaceMockGenerator.fs"/>
|
||||
<Compile Include="JsonSerializeGenerator.fs"/>
|
||||
|
@@ -7,6 +7,7 @@
|
||||
":/",
|
||||
":^WoofWare.Myriad.Plugins.Test/",
|
||||
":^WoofWare.Myriad.Plugins.Attributes/Test/",
|
||||
":^/.github/"
|
||||
":^/.github/",
|
||||
":^/CHANGELOG.md"
|
||||
]
|
||||
}
|
||||
|
35
flake.nix
35
flake.nix
@@ -45,44 +45,19 @@
|
||||
packages = {
|
||||
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
||||
fsharp-analyzers = dotnetTool "FSharp.Analyzers.Cli" "fsharp-analyzers" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fsharp-analyzers.version (builtins.head (builtins.filter (elem: elem.pname == "fsharp-analyzers") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
||||
fetchDeps = let
|
||||
flags = [];
|
||||
runtimeIds = ["win-x64"] ++ map (system: pkgs.dotnetCorePackages.systemToDotnetRid system) dotnet-sdk.meta.platforms;
|
||||
in
|
||||
pkgs.writeShellScriptBin "fetch-${pname}-deps" (builtins.readFile (pkgs.substituteAll {
|
||||
src = ./nix/fetchDeps.sh;
|
||||
pname = pname;
|
||||
binPath = pkgs.lib.makeBinPath [pkgs.coreutils dotnet-sdk (pkgs.nuget-to-nix.override {inherit dotnet-sdk;})];
|
||||
projectFiles = toString ["./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj" "./ConsumePlugin/ConsumePlugin.fsproj" "./WoofWare.Myriad.Plugins.Attributes/WoofWare.Myriad.Plugins.Attributes.fsproj"];
|
||||
testProjectFiles = ["./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj" "./WoofWare.Myriad.Plugins.Attributes/Test/Woofware.Myriad.Plugins.Attributes.Test.fsproj"];
|
||||
rids = pkgs.lib.concatStringsSep "\" \"" runtimeIds;
|
||||
packages = dotnet-sdk.packages;
|
||||
storeSrc = pkgs.srcOnly {
|
||||
src = ./.;
|
||||
pname = pname;
|
||||
version = version;
|
||||
};
|
||||
}));
|
||||
default = pkgs.buildDotnetModule {
|
||||
pname = pname;
|
||||
inherit pname version dotnet-sdk dotnet-runtime;
|
||||
name = "WoofWare.Myriad.Plugins";
|
||||
version = version;
|
||||
src = ./.;
|
||||
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj";
|
||||
nugetDeps = ./nix/deps.nix;
|
||||
testProjectFile = "./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj";
|
||||
disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"];
|
||||
nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result` and put the result here
|
||||
doCheck = true;
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
dotnet-runtime = dotnet-runtime;
|
||||
};
|
||||
};
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
(with dotnetCorePackages;
|
||||
combinePackages [
|
||||
dotnet-sdk_8
|
||||
dotnetPackages.Nuget
|
||||
])
|
||||
];
|
||||
buildInputs = [dotnet-sdk];
|
||||
packages = [
|
||||
pkgs.alejandra
|
||||
pkgs.nodePackages.markdown-link-check
|
||||
|
141
nix/deps.nix
141
nix/deps.nix
@@ -1,20 +1,15 @@
|
||||
# This file was automatically generated by passthru.fetch-deps.
|
||||
# Please don't edit it manually, your changes might get overwritten!
|
||||
# Please dont edit it manually, your changes might get overwritten!
|
||||
{fetchNuGet}: [
|
||||
(fetchNuGet {
|
||||
pname = "fsharp-analyzers";
|
||||
version = "0.26.0";
|
||||
sha256 = "sha256-60Bl36LOb/zVNdH2SBSuQ5O41lP9dKTNZbs5vvYs+3U=";
|
||||
pname = "ApiSurface";
|
||||
version = "4.0.41";
|
||||
sha256 = "03kfa5ngmgkik9lc58sp8s9rrh9g40hhgjnrv662ks0d0y2i9i89";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "fantomas";
|
||||
version = "6.3.4";
|
||||
sha256 = "sha256-1aWqZynBkQoznenGoP0sbf1PcUXAbcHiWyECuv89xa0=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "ApiSurface";
|
||||
version = "4.0.40";
|
||||
sha256 = "1c9z0b6minlripwrjmv4yd5w8zj4lcpak4x41izh7ygx8kgmbvx0";
|
||||
version = "6.3.7";
|
||||
sha256 = "1z1a5bw7vwz6g8nvfgkvx66jnm4hmvn62vbyq0as60nw0jlvaidl";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Fantomas.Core";
|
||||
@@ -31,6 +26,11 @@
|
||||
version = "2.16.6";
|
||||
sha256 = "176rwky6b5rk8dzldiz4068p7m9c5y9ygzbhadrs14jkl94pc56n";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "fsharp-analyzers";
|
||||
version = "0.26.0";
|
||||
sha256 = "0xgv5kvbwfdvcp6s8x7xagbbi4s3mqa4ixni6pazqvyflbgnah7b";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FSharp.Core";
|
||||
version = "4.3.4";
|
||||
@@ -56,66 +56,26 @@
|
||||
version = "6.0.26";
|
||||
sha256 = "1d8nkz24vsm0iy2xm8y5ak2q1w1p99dxyz0y26acs6sfk2na0vm6";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Ref";
|
||||
version = "8.0.1";
|
||||
sha256 = "0yaaiqq7mi6sclyrb1v0fyncanbx0ifmnnhv9whynqj8439jsdwh";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1za8lc52m4z54d68wd64c2nhzy05g3gx171k5cdlx73fbymiys9z";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0dsdgqg7566qximmjfza4x9if3icy4kskq698ddj5apdia88h2mw";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1zpbmz6z8758gwywzg0bac8kx9x39sxxc9j4a4r2jl74l9ssw4vm";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1gjz379y61ag9whi78qxx09bwkwcznkx2mzypgycibxk61g11da1";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1i8ydlwjzk7j0mzvn0rpljxfp1h50zwaqalnyvfxai1fwgigzgw5";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0w3mrs4zdl9mfanl1j81759xwwrzmicsjxn6yfxv5yrxbxzq695n";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "02src68hd3213sd1a2ms1my7i92knfmdxclvv90il9cky2zsq8kw";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0a9aljr4fy4haq6ndz2y723liv5hbfpss1rn45s88nmgcp27m15m";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.win-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1gxlmfdkfzmhw9pac5jiv674nn6i1zymcp2hj81irjwhhjk01mf5";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.win-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "01kzndyqmsvcq49i2jrv7ymfp0l71yxfylv1cy3nhkdbprqz8ipx";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.Build.Tasks.Git";
|
||||
version = "8.0.0";
|
||||
sha256 = "0055f69q3hbagqp8gl3nk0vfn4qyqyxsxyy7pd0g7wm3z28byzmx";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.CodeCoverage";
|
||||
version = "17.10.0";
|
||||
@@ -131,111 +91,46 @@
|
||||
version = "6.0.26";
|
||||
sha256 = "19y6c6v20bgf7x7rrh4rx9y7s5fy8vp5m4j9b6gi1wp4rpb5mza4";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0dhpdlcdz7adcfh9w01fc867051m35fqaxnvj3fqvqhgcm2n3143";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0p7hhidaa3mnyiwnsijwy8578v843x8hh99255s69qwwyld6falv";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1aw6mc7zcmzs1grxz2wa9cw9kfj8pz7zpj417xnp1a9n4ix1bxgr";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1mq11xsv9g1vsasp6k80y7xlvwi9hrpk5dgm773fvy8538s01gfv";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1dzg3prng9zfdzz7gcgywjdbwzhwm85j89z0jahynxx4q2dra4b9";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1chac9b4424ihrrnlzvc7qz6j4ymfjyv4kzyazzzw19yhymdkh2s";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "010f8wn15s2kv7yyzgys3pv9i1mxw20hpv1ig2zhybjxs8lpj8jj";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.win-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0i7g9fsqjnbh9rc6807m57r2idg5pkcw6xjfwhnxkcpgqm96258v";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.win-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1ssj1cyam3nfidm8q82kvh4i3fzm2lzb3bxw6ck09hwhvwh909z4";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Ref";
|
||||
version = "6.0.26";
|
||||
sha256 = "12gb52dhg5h9hgnyqh1zgj2w46paxv2pfh33pphl9ajhrdr7hlsb";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Ref";
|
||||
version = "8.0.1";
|
||||
sha256 = "02r4jg4ha0qksix9v6s3cpmvavmz54gkawkxy9bvknw5ynxhhl1l";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "164hfrwqz5dxcbb441lridk4mzcqmarb0b7ckgvqhsvpawyjw88v";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0353whnjgz3sqhzsfrviad3a3db4pk7hl7m4wwppv5mqdg9i9ri5";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0islayddpnflviqpbq4djc4f3v9nhsa2y76k5x6il3csq5vdw2hq";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1g5b30f4l8a1zjjr3b8pk9mcqxkxqwa86362f84646xaj4iw3a4d";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1acn5zw1pxzmcg3c0pbf9hal36fbdh9mvbsiwra7simrk7hzqpdc";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0cdrpdaq5sl3602anfx1p0z0ncx2sjjvl6mgsd6y38g47n7f95jc";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "00f9l9dkdz0zv5csaw8fkm6s8ckrj5n9k3ygz12daa22l3bcn6ii";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1fk1flqp6ji0l4c2gvh83ykndpx7a2nkkgrgkgql3c75j1k2v1s9";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.win-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0i2p356phfc5y6qnr3vyrzjfi1mrbwfb6g85k4q37bbyxjfp7zl9";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.win-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "198576cdkl72xs29zznff9ls763p8pfr0zji7b74dqxd5ga0s3bd";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.Platforms";
|
||||
version = "1.1.0";
|
||||
@@ -256,16 +151,6 @@
|
||||
version = "1.1.3";
|
||||
sha256 = "05smkcyxir59rgrmp7d6327vvrlacdgldfxhmyr1azclvga1zfsq";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.SourceLink.Common";
|
||||
version = "8.0.0";
|
||||
sha256 = "0xrr8yd34ij7dqnyddkp2awfmf9qn3c89xmw2f3npaa4wnajmx81";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.SourceLink.GitHub";
|
||||
version = "8.0.0";
|
||||
sha256 = "1gdx7n45wwia3yvang3ls92sk3wrymqcx9p349j8wba2lyjf9m44";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||
version = "17.10.0";
|
||||
@@ -288,8 +173,8 @@
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Nerdbank.GitVersioning";
|
||||
version = "3.6.133";
|
||||
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
||||
version = "3.6.139";
|
||||
sha256 = "0npcryhq3r0c2zi940jk39h13mzc4hyg7z8gm6jdmxi1aqv1vh8c";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NETStandard.Library";
|
||||
|
@@ -1,73 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This file was adapted from
|
||||
# https://github.com/NixOS/nixpkgs/blob/b981d811453ab84fb3ea593a9b33b960f1ab9147/pkgs/build-support/dotnet/build-dotnet-module/default.nix#L173
|
||||
set -euo pipefail
|
||||
export PATH="@binPath@"
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--keep-sources|-k)
|
||||
keepSources=1
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "usage: $0 [--keep-sources] [--help] <output path>"
|
||||
echo " <output path> The path to write the lockfile to. A temporary file is used if this is not set"
|
||||
echo " --keep-sources Don't remove temporary directories upon exit, useful for debugging"
|
||||
echo " --help Show this help message"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
done
|
||||
tmp=$(mktemp -td "@pname@-tmp-XXXXXX")
|
||||
export tmp
|
||||
HOME=$tmp/home
|
||||
exitTrap() {
|
||||
test -n "${ranTrap-}" && return
|
||||
ranTrap=1
|
||||
if test -n "${keepSources-}"; then
|
||||
echo -e "Path to the source: $tmp/src\nPath to the fake home: $tmp/home"
|
||||
else
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
# Since mktemp is used this will be empty if the script didnt succesfully complete
|
||||
if ! test -s "$depsFile"; then
|
||||
rm -rf "$depsFile"
|
||||
fi
|
||||
}
|
||||
trap exitTrap EXIT INT TERM
|
||||
dotnetRestore() {
|
||||
local -r project="${1-}"
|
||||
local -r rid="$2"
|
||||
dotnet restore "${project-}" \
|
||||
-p:ContinuousIntegrationBuild=true \
|
||||
-p:Deterministic=true \
|
||||
--packages "$tmp/nuget_pkgs" \
|
||||
--runtime "$rid" \
|
||||
--no-cache \
|
||||
--force
|
||||
}
|
||||
declare -a projectFiles=( @projectFiles@ )
|
||||
declare -a testProjectFiles=( @testProjectFiles@ )
|
||||
export DOTNET_NOLOGO=1
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
depsFile=$(realpath "${1:-$(mktemp -t "@pname@-deps-XXXXXX.nix")}")
|
||||
mkdir -p "$tmp/nuget_pkgs"
|
||||
storeSrc="@storeSrc@"
|
||||
src="$tmp/src"
|
||||
cp -rT "$storeSrc" "$src"
|
||||
chmod -R +w "$src"
|
||||
cd "$src"
|
||||
echo "Restoring project..."
|
||||
rids=("@rids@")
|
||||
for rid in "${rids[@]}"; do
|
||||
(( ${#projectFiles[@]} == 0 )) && dotnetRestore "" "$rid"
|
||||
for project in "${projectFiles[@]-}" "${testProjectFiles[@]-}"; do
|
||||
dotnetRestore "$project" "$rid"
|
||||
done
|
||||
done
|
||||
echo "Successfully restored project"
|
||||
echo "Writing lockfile..."
|
||||
echo -e "# This file was automatically generated by passthru.fetch-deps.\n# Please don't edit it manually, your changes might get overwritten!\n" > "$depsFile"
|
||||
nuget-to-nix "$tmp/nuget_pkgs" "@packages@" >> "$depsFile"
|
||||
echo "Successfully wrote lockfile to $depsFile"
|
Reference in New Issue
Block a user