Compare commits

...

8 Commits

Author SHA1 Message Date
Patrick Stevens
18c7a2e920 Continuous integration to true (#161) 2024-06-09 10:56:11 +01:00
Patrick Stevens
f371ee59fe Say which mock function wasn't implemented (#160) 2024-06-04 18:36:49 +01:00
dependabot[bot]
f8296e54bc Bump fantomas from 6.3.4 to 6.3.7 (#158)
* Bump fantomas from 6.3.4 to 6.3.7

Bumps [fantomas](https://github.com/fsprojects/fantomas) from 6.3.4 to 6.3.7.
- [Release notes](https://github.com/fsprojects/fantomas/releases)
- [Changelog](https://github.com/fsprojects/fantomas/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fsprojects/fantomas/compare/v6.3.4...v6.3.7)

---
updated-dependencies:
- dependency-name: fantomas
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Upgrade Fantomas

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-06-03 18:31:24 +01:00
Patrick Stevens
adf497c5db Tidy up a bit more (#156) 2024-06-01 15:57:53 +01:00
Patrick Stevens
04ecbe6002 Simplify flake (#155) 2024-05-31 21:58:33 +01:00
Patrick Stevens
7b14e52e9d Use our DSLs a bit more (#154) 2024-05-31 19:20:28 +01:00
Patrick Stevens
8e47f39efc Make more extensive use of our own DSLs (#153) 2024-05-31 16:54:05 +00:00
Patrick Stevens
6942ba42b9 Update changelog (#152) 2024-05-30 22:37:05 +01:00
45 changed files with 1802 additions and 2284 deletions

View File

@@ -3,7 +3,7 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"fantomas": { "fantomas": {
"version": "6.3.4", "version": "6.3.7",
"commands": [ "commands": [
"fantomas" "fantomas"
] ]

View File

@@ -1,5 +1,14 @@
Notable changes are recorded here. 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 # 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. 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.

View File

@@ -60,7 +60,7 @@ module TreeCata =
instructions.RemoveAt (instructions.Count - 1) instructions.RemoveAt (instructions.Count - 1)
match currentInstruction with match currentInstruction with
| Instruction.Process__TreeBuilder (x) -> | Instruction.Process__TreeBuilder x ->
match x with match x with
| TreeBuilder.Child (arg0_0) -> | TreeBuilder.Child (arg0_0) ->
instructions.Add Instruction.TreeBuilder_Child instructions.Add Instruction.TreeBuilder_Child
@@ -68,7 +68,7 @@ module TreeCata =
| TreeBuilder.Parent (arg0_0) -> | TreeBuilder.Parent (arg0_0) ->
instructions.Add Instruction.TreeBuilder_Parent instructions.Add Instruction.TreeBuilder_Parent
instructions.Add (Instruction.Process__Tree arg0_0) instructions.Add (Instruction.Process__Tree arg0_0)
| Instruction.Process__Tree (x) -> | Instruction.Process__Tree x ->
match x with match x with
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add | Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
| Tree.Pair (arg0_0, arg1_0, arg2_0) -> | Tree.Pair (arg0_0, arg1_0, arg2_0) ->
@@ -92,13 +92,13 @@ module TreeCata =
let arg0_0 = treeStack.[treeStack.Count - 1] let arg0_0 = treeStack.[treeStack.Count - 1]
treeStack.RemoveAt (treeStack.Count - 1) treeStack.RemoveAt (treeStack.Count - 1)
cata.TreeBuilder.Parent arg0_0 |> treeBuilderStack.Add cata.TreeBuilder.Parent arg0_0 |> treeBuilderStack.Add
| Instruction.Tree_Pair (arg2_0) -> | Instruction.Tree_Pair arg2_0 ->
let arg0_0 = treeStack.[treeStack.Count - 1] let arg0_0 = treeStack.[treeStack.Count - 1]
treeStack.RemoveAt (treeStack.Count - 1) treeStack.RemoveAt (treeStack.Count - 1)
let arg1_0 = treeStack.[treeStack.Count - 1] let arg1_0 = treeStack.[treeStack.Count - 1]
treeStack.RemoveAt (treeStack.Count - 1) treeStack.RemoveAt (treeStack.Count - 1)
cata.Tree.Pair arg0_0 arg1_0 arg2_0 |> treeStack.Add 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_len = arg0_0
let arg0_0 = let arg0_0 =

View File

@@ -41,7 +41,7 @@ module FileSystemItemCata =
instructions.RemoveAt (instructions.Count - 1) instructions.RemoveAt (instructions.Count - 1)
match currentInstruction with match currentInstruction with
| Instruction.Process__FileSystemItem (x) -> | Instruction.Process__FileSystemItem x ->
match x with match x with
| FileSystemItem.Directory ({ | FileSystemItem.Directory ({
Name = name Name = name
@@ -116,7 +116,7 @@ module GiftCata =
instructions.RemoveAt (instructions.Count - 1) instructions.RemoveAt (instructions.Count - 1)
match currentInstruction with match currentInstruction with
| Instruction.Process__Gift (x) -> | Instruction.Process__Gift x ->
match x with match x with
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add | Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate 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) -> | Gift.WithACard (arg0_0, message) ->
instructions.Add (Instruction.Gift_WithACard (message)) instructions.Add (Instruction.Gift_WithACard (message))
instructions.Add (Instruction.Process__Gift arg0_0) instructions.Add (Instruction.Process__Gift arg0_0)
| Instruction.Gift_Wrapped (arg1_0) -> | Instruction.Gift_Wrapped arg1_0 ->
let arg0_0 = giftStack.[giftStack.Count - 1] let arg0_0 = giftStack.[giftStack.Count - 1]
giftStack.RemoveAt (giftStack.Count - 1) giftStack.RemoveAt (giftStack.Count - 1)
cata.Gift.Wrapped arg0_0 arg1_0 |> giftStack.Add cata.Gift.Wrapped arg0_0 arg1_0 |> giftStack.Add
@@ -137,7 +137,7 @@ module GiftCata =
let arg0_0 = giftStack.[giftStack.Count - 1] let arg0_0 = giftStack.[giftStack.Count - 1]
giftStack.RemoveAt (giftStack.Count - 1) giftStack.RemoveAt (giftStack.Count - 1)
cata.Gift.Boxed arg0_0 |> giftStack.Add cata.Gift.Boxed arg0_0 |> giftStack.Add
| Instruction.Gift_WithACard (message) -> | Instruction.Gift_WithACard message ->
let arg0_0 = giftStack.[giftStack.Count - 1] let arg0_0 = giftStack.[giftStack.Count - 1]
giftStack.RemoveAt (giftStack.Count - 1) giftStack.RemoveAt (giftStack.Count - 1)
cata.Gift.WithACard arg0_0 message |> giftStack.Add cata.Gift.WithACard arg0_0 message |> giftStack.Add

View File

@@ -8,8 +8,7 @@
namespace ConsumePlugin namespace ConsumePlugin
/// Module containing JSON parsing methods for the InnerType type /// Module containing JSON parsing methods for the InnerType type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module InnerType = module InnerType =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerType = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerType =
@@ -31,8 +30,7 @@ module InnerType =
namespace ConsumePlugin namespace ConsumePlugin
/// Module containing JSON parsing methods for the JsonRecordType type /// Module containing JSON parsing methods for the JsonRecordType type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module JsonRecordType = module JsonRecordType =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordType = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordType =

View File

@@ -19,9 +19,9 @@ type internal PublicTypeMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : PublicTypeMock = static member Empty : PublicTypeMock =
{ {
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
} }
interface IPublicType with interface IPublicType with
@@ -44,9 +44,9 @@ type public PublicTypeInternalFalseMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : PublicTypeInternalFalseMock = static member Empty : PublicTypeInternalFalseMock =
{ {
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
} }
interface IPublicTypeInternalFalse with interface IPublicTypeInternalFalse with
@@ -68,8 +68,8 @@ type internal InternalTypeMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : InternalTypeMock = static member Empty : InternalTypeMock =
{ {
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
} }
interface InternalType with interface InternalType with
@@ -90,8 +90,8 @@ type private PrivateTypeMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : PrivateTypeMock = static member Empty : PrivateTypeMock =
{ {
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
} }
interface PrivateType with interface PrivateType with
@@ -112,8 +112,8 @@ type private PrivateTypeInternalFalseMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : PrivateTypeInternalFalseMock = static member Empty : PrivateTypeInternalFalseMock =
{ {
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
} }
interface PrivateTypeInternalFalse with interface PrivateTypeInternalFalse with
@@ -133,7 +133,7 @@ type internal VeryPublicTypeMock<'a, 'b> =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty () : VeryPublicTypeMock<'a, 'b> = 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 interface VeryPublicType<'a, 'b> with
@@ -157,12 +157,12 @@ type internal CurriedMock<'a> =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty () : CurriedMock<'a> = static member Empty () : CurriedMock<'a> =
{ {
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
} }
interface Curried<'a> with interface Curried<'a> with
@@ -195,9 +195,9 @@ type internal TypeWithInterfaceMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : TypeWithInterfaceMock = static member Empty : TypeWithInterfaceMock =
{ {
Dispose = (fun _ -> ()) Dispose = (fun () -> ())
Mem1 = (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 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
} }
interface TypeWithInterface with interface TypeWithInterface with

View File

@@ -41,8 +41,7 @@ module MemberJsonSerializeExtension =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymOpeningHours type /// Module containing JSON parsing methods for the GymOpeningHours type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module GymOpeningHours = module GymOpeningHours =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymOpeningHours = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymOpeningHours =
@@ -78,8 +77,7 @@ module GymOpeningHours =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymAccessOptions type /// Module containing JSON parsing methods for the GymAccessOptions type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module GymAccessOptions = module GymAccessOptions =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAccessOptions = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAccessOptions =
@@ -114,8 +112,7 @@ module GymAccessOptions =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymLocation type /// Module containing JSON parsing methods for the GymLocation type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module GymLocation = module GymLocation =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymLocation = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymLocation =
@@ -192,8 +189,7 @@ module GymLocation =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymAddress type /// Module containing JSON parsing methods for the GymAddress type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module GymAddress = module GymAddress =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAddress = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAddress =
@@ -259,8 +255,7 @@ module GymAddress =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the Gym type /// Module containing JSON parsing methods for the Gym type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Gym = module Gym =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Gym = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Gym =
@@ -620,8 +615,7 @@ module MemberJsonParseExtension =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymAttendance type /// Module containing JSON parsing methods for the GymAttendance type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module GymAttendance = module GymAttendance =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAttendance = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAttendance =
@@ -743,8 +737,7 @@ module GymAttendance =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the MemberActivityDto type /// Module containing JSON parsing methods for the MemberActivityDto type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module MemberActivityDto = module MemberActivityDto =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : MemberActivityDto = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : MemberActivityDto =
@@ -832,8 +825,7 @@ module MemberActivityDto =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the SessionsAggregate type /// Module containing JSON parsing methods for the SessionsAggregate type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SessionsAggregate = module SessionsAggregate =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsAggregate = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsAggregate =
@@ -881,8 +873,7 @@ module SessionsAggregate =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the VisitGym type /// Module containing JSON parsing methods for the VisitGym type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module VisitGym = module VisitGym =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : VisitGym = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : VisitGym =
@@ -930,8 +921,7 @@ module VisitGym =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the Visit type /// Module containing JSON parsing methods for the Visit type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Visit = module Visit =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
@@ -993,8 +983,7 @@ module Visit =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the SessionsSummary type /// Module containing JSON parsing methods for the SessionsSummary type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module SessionsSummary = module SessionsSummary =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
@@ -1029,8 +1018,7 @@ module SessionsSummary =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the Sessions type /// Module containing JSON parsing methods for the Sessions type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Sessions = module Sessions =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Sessions = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Sessions =
@@ -1066,8 +1054,7 @@ module Sessions =
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the UriThing type /// Module containing JSON parsing methods for the UriThing type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module UriThing = module UriThing =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : UriThing = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : UriThing =

View File

@@ -17,8 +17,7 @@ open System.Net.Http
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module PureGymApi = module PureGymApi =
/// Create a REST client. /// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IPureGymApi = let make (client : System.Net.Http.HttpClient) : IPureGymApi =
@@ -1055,8 +1054,7 @@ open System.Net.Http
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module internal ApiWithoutBaseAddress = module internal ApiWithoutBaseAddress =
/// Create a REST client. /// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IApiWithoutBaseAddress = let make (client : System.Net.Http.HttpClient) : IApiWithoutBaseAddress =
@@ -1107,8 +1105,7 @@ open System.Net.Http
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module ApiWithBasePath = module ApiWithBasePath =
/// Create a REST client. /// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IApiWithBasePath = let make (client : System.Net.Http.HttpClient) : IApiWithBasePath =
@@ -1159,8 +1156,7 @@ open System.Net.Http
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module ApiWithBasePathAndAddress = module ApiWithBasePathAndAddress =
/// Create a REST client. /// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IApiWithBasePathAndAddress = let make (client : System.Net.Http.HttpClient) : IApiWithBasePathAndAddress =
@@ -1205,8 +1201,7 @@ open System.Net.Http
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module ApiWithHeaders = 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. /// 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 let make
@@ -1268,8 +1263,7 @@ open System.Net.Http
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module ApiWithHeaders2 = 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. /// 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 let make

View File

@@ -167,7 +167,7 @@ module FirstDuJsonSerializeExtension =
match input with match input with
| FirstDu.EmptyCase -> node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "emptyCase") | 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") node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case1")
let dataNode = System.Text.Json.Nodes.JsonObject () let dataNode = System.Text.Json.Nodes.JsonObject ()
dataNode.Add ("data", System.Text.Json.Nodes.JsonValue.Create<string> arg0) dataNode.Add ("data", System.Text.Json.Nodes.JsonValue.Create<string> arg0)

View File

@@ -8,8 +8,7 @@
namespace ConsumePlugin namespace ConsumePlugin
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type /// Module containing JSON parsing methods for the JwtVaultAuthResponse type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module JwtVaultAuthResponse = module JwtVaultAuthResponse =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultAuthResponse = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultAuthResponse =
@@ -164,8 +163,7 @@ module JwtVaultAuthResponse =
namespace ConsumePlugin namespace ConsumePlugin
/// Module containing JSON parsing methods for the JwtVaultResponse type /// Module containing JSON parsing methods for the JwtVaultResponse type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module JwtVaultResponse = module JwtVaultResponse =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultResponse = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultResponse =
@@ -239,8 +237,7 @@ module JwtVaultResponse =
namespace ConsumePlugin namespace ConsumePlugin
/// Module containing JSON parsing methods for the JwtSecretResponse type /// Module containing JSON parsing methods for the JwtSecretResponse type
[<RequireQualifiedAccess>] [<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module JwtSecretResponse = module JwtSecretResponse =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtSecretResponse = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtSecretResponse =
@@ -455,8 +452,7 @@ open System.Threading.Tasks
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module VaultClient = module VaultClient =
/// Create a REST client. /// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IVaultClient = let make (client : System.Net.Http.HttpClient) : IVaultClient =
@@ -553,8 +549,7 @@ open System.Threading.Tasks
open RestEase open RestEase
/// Module for constructing a REST client. /// Module for constructing a REST client.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
[<RequireQualifiedAccess>]
module VaultClientNonExtensionMethod = module VaultClientNonExtensionMethod =
/// Create a REST client. /// Create a REST client.
let make (client : System.Net.Http.HttpClient) : IVaultClientNonExtensionMethod = let make (client : System.Net.Http.HttpClient) : IVaultClientNonExtensionMethod =

View File

@@ -41,7 +41,7 @@ module MyListCata =
instructions.RemoveAt (instructions.Count - 1) instructions.RemoveAt (instructions.Count - 1)
match currentInstruction with match currentInstruction with
| Instruction.Process__MyList (x) -> | Instruction.Process__MyList x ->
match x with match x with
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add | MyList.Nil -> cata.MyList.Nil |> myListStack.Add
| MyList.Cons ({ | MyList.Cons ({
@@ -50,7 +50,7 @@ module MyListCata =
}) -> }) ->
instructions.Add (Instruction.MyList_Cons (head)) instructions.Add (Instruction.MyList_Cons (head))
instructions.Add (Instruction.Process__MyList tail) instructions.Add (Instruction.Process__MyList tail)
| Instruction.MyList_Cons (head) -> | Instruction.MyList_Cons head ->
let tail = myListStack.[myListStack.Count - 1] let tail = myListStack.[myListStack.Count - 1]
myListStack.RemoveAt (myListStack.Count - 1) myListStack.RemoveAt (myListStack.Count - 1)
cata.MyList.Cons head tail |> myListStack.Add cata.MyList.Cons head tail |> myListStack.Add
@@ -97,13 +97,13 @@ module MyList2Cata =
instructions.RemoveAt (instructions.Count - 1) instructions.RemoveAt (instructions.Count - 1)
match currentInstruction with match currentInstruction with
| Instruction.Process__MyList2 (x) -> | Instruction.Process__MyList2 x ->
match x with match x with
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add | MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
| MyList2.Cons (arg0_0, arg1_0) -> | MyList2.Cons (arg0_0, arg1_0) ->
instructions.Add (Instruction.MyList2_Cons (arg0_0)) instructions.Add (Instruction.MyList2_Cons (arg0_0))
instructions.Add (Instruction.Process__MyList2 arg1_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] let arg1_0 = myList2Stack.[myList2Stack.Count - 1]
myList2Stack.RemoveAt (myList2Stack.Count - 1) myList2Stack.RemoveAt (myList2Stack.Count - 1)
cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add

View File

@@ -11,18 +11,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.133" PrivateAssets="all"/> <PackageReference Include="Nerdbank.GitVersioning" Version="3.6.133" PrivateAssets="all"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/> <SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
</ItemGroup> </ItemGroup>
<!-- <PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
SourceLink doesn't support F# deterministic builds out of the box, <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
so tell SourceLink that our source root is going to be remapped. </PropertyGroup>
-->
<Target Name="MapSourceRoot" BeforeTargets="_GenerateSourceLinkFile" Condition="'$(SourceRootMappedPathsFeatureSupported)' != 'true'">
<ItemGroup>
<SourceRoot Update="@(SourceRoot)">
<MappedPath>Z:\CheckoutRoot\WoofWare.Myriad\</MappedPath>
</SourceRoot>
</ItemGroup>
</Target>
</Project> </Project>

View File

@@ -193,12 +193,13 @@ module TestJsonSerde =
let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu> let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu>
Gen.listOf duGen let mutable i = 0
|> Gen.eval 100 (StdGen.StdGen (rand.Next (), rand.Next ()))
|> List.iter (fun du -> 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 let tag = decompose du
counts.[tag] <- counts.[tag] + 1 counts.[tag] <- counts.[tag] + 1
) i <- i + 1
for i in counts do for i in counts do
i |> shouldBeGreaterThan 0 i |> shouldBeGreaterThan 0

View File

@@ -12,7 +12,8 @@ module TestSurface =
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
[<Test>] [<Test>]
let ``Check version against remote`` () = // https://github.com/nunit/nunit3-vs-adapter/issues/876
let CheckVersionAgainstRemote () =
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins" MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins"
[<Test ; Explicit>] [<Test ; Explicit>]

View File

@@ -1,10 +1,8 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Fantomas.FCS.Xml open Fantomas.FCS.Xml
open Myriad.Core.AstExtensions
type internal ParameterInfo = type internal ParameterInfo =
{ {
@@ -98,30 +96,6 @@ type internal AdtProduct =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal AstHelper = 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 instantiateRecord (fields : (RecordFieldName * SynExpr option) list) : SynExpr =
let fields = let fields =
fields fields
@@ -130,86 +104,17 @@ module internal AstHelper =
SynExpr.Record (None, None, fields, range0) SynExpr.Record (None, None, fields, range0)
let defineRecordType (record : RecordType) : SynTypeDefn = let defineRecordType (record : RecordType) : SynTypeDefn =
let repr =
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, Seq.toList record.Fields, range0), range0)
let name = let name =
SynComponentInfo.Create ( SynComponentInfo.create record.Name
[ record.Name ], |> SynComponentInfo.setAccessibility record.Accessibility
?xmldoc = record.XmlDoc, |> match record.XmlDoc with
?parameters = record.Generics, | None -> id
access = record.Accessibility | Some doc -> SynComponentInfo.withDocString doc
) |> SynComponentInfo.setGenerics record.Generics
let trivia : SynTypeDefnTrivia = SynTypeDefnRepr.record (Seq.toList record.Fields)
{ |> SynTypeDefn.create name
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0 |> SynTypeDefn.withMemberDefns (defaultArg record.Members SynMemberDefns.Empty)
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
let rec private extractOpensFromDecl (moduleDecls : SynModuleDecl list) : SynOpenDeclTarget list = let rec private extractOpensFromDecl (moduleDecls : SynModuleDecl list) : SynOpenDeclTarget list =
moduleDecls moduleDecls
@@ -231,12 +136,12 @@ module internal AstHelper =
| SynType.Paren (inner, _) -> | SynType.Paren (inner, _) ->
let result, _ = convertSigParam inner let result, _ = convertSigParam inner
result, true result, true
| SynType.LongIdent ident -> | SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
{ {
Attributes = [] Attributes = []
IsOptional = false IsOptional = false
Id = None Id = None
Type = SynType.CreateLongIdent ident Type = SynType.createLongIdent ident
}, },
false false
| SynType.SignatureParameter (attrs, opt, id, usedType, _) -> | SynType.SignatureParameter (attrs, opt, id, usedType, _) ->
@@ -254,7 +159,7 @@ module internal AstHelper =
Attributes = [] Attributes = []
IsOptional = false IsOptional = false
Id = None Id = None
Type = SynType.Var (typar, range0) Type = SynType.var typar
}, },
false false
| _ -> failwithf "expected SignatureParameter, got: %+A" ty | _ -> 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 | _ -> 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. /// 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 = let rec getType (ty : SynType) : (SynType * bool) list * SynType =
match ty with match ty with
@@ -299,7 +200,7 @@ module internal AstHelper =
| SynType.Paren (argType, _) -> getType argType, true | SynType.Paren (argType, _) -> getType argType, true
| _ -> getType argType, false | _ -> getType argType, false
((toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret ((SynType.toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret
| _ -> [], ty | _ -> [], ty
let private parseMember (slotSig : SynValSig) (flags : SynMemberFlags) : Choice<MemberInfo, PropertyInfo> = let private parseMember (slotSig : SynValSig) (flags : SynMemberFlags) : Choice<MemberInfo, PropertyInfo> =
@@ -356,7 +257,7 @@ module internal AstHelper =
Attributes = [] Attributes = []
IsOptional = false IsOptional = false
Id = None Id = None
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident) Type = SynType.createLongIdent ident
} }
|> List.singleton |> List.singleton
} }
@@ -368,7 +269,7 @@ module internal AstHelper =
Attributes = [] Attributes = []
IsOptional = false IsOptional = false
Id = None Id = None
Type = SynType.Var (typar, range0) Type = SynType.var typar
} }
|> List.singleton |> List.singleton
} }
@@ -522,190 +423,3 @@ module internal AstHelper =
} }
) )
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr | _ -> 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

View File

@@ -2,9 +2,6 @@ namespace WoofWare.Myriad.Plugins
open System.Net.Http open System.Net.Http
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Myriad.Core
type internal HttpClientGeneratorOutputSpec = type internal HttpClientGeneratorOutputSpec =
{ {
@@ -14,7 +11,6 @@ type internal HttpClientGeneratorOutputSpec =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal HttpClientGenerator = module internal HttpClientGenerator =
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core.Ast
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
type PathSpec = type PathSpec =
@@ -82,7 +78,7 @@ module internal HttpClientGenerator =
let matchingAttrs = let matchingAttrs =
attrs attrs
|> List.choose (fun attr -> |> List.choose (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "Get" | "Get"
| "GetAttribute" | "GetAttribute"
| "WoofWare.Myriad.Plugins.RestEase.Get" | "WoofWare.Myriad.Plugins.RestEase.Get"
@@ -144,7 +140,7 @@ module internal HttpClientGenerator =
let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list = let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list =
attrs attrs
|> List.choose (fun attr -> |> List.choose (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "Header" | "Header"
| "RestEase.Header" | "RestEase.Header"
| "WoofWare.Myriad.Plugins.RestEase.Header" -> | "WoofWare.Myriad.Plugins.RestEase.Header" ->
@@ -158,7 +154,7 @@ module internal HttpClientGenerator =
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool = let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
attrs attrs
|> List.exists (fun attr -> |> List.exists (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "AllowAnyStatusCode" | "AllowAnyStatusCode"
| "AllowAnyStatusCodeAttribute" | "AllowAnyStatusCodeAttribute"
| "RestEase.AllowAnyStatusCode" | "RestEase.AllowAnyStatusCode"
@@ -174,35 +170,6 @@ module internal HttpClientGenerator =
(info : MemberInfo) (info : MemberInfo)
: SynMemberDefn : 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 = let args =
info.Args info.Args
|> List.map (fun arg -> |> List.map (fun arg ->
@@ -213,15 +180,13 @@ module internal HttpClientGenerator =
let argType = let argType =
if arg.IsOptional then if arg.IsOptional then
SynType.CreateApp ( SynType.appPostfix "option" arg.Type
SynType.CreateLongIdent (SynLongIdent.CreateString "option"),
[ arg.Type ],
isPostfix = true
)
else else
arg.Type 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 = let cancellationTokenArg =
@@ -229,26 +194,6 @@ module internal HttpClientGenerator =
| None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}" | None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}"
| Some (arg, _) -> arg | 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 = let requestUriTrailer =
(info.UrlTemplate, info.Args) (info.UrlTemplate, info.Args)
||> List.fold (fun template arg -> ||> List.fold (fun template arg ->
@@ -269,10 +214,10 @@ module internal HttpClientGenerator =
template template
|> SynExpr.callMethodArg |> SynExpr.callMethodArg
"Replace" "Replace"
(SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
SynExpr.CreateConstString ("{" + substituteId + "}") SynExpr.CreateConst ("{" + substituteId + "}")
SynExpr.callMethod "ToString" (SynExpr.CreateIdent varName) SynExpr.callMethod "ToString" (SynExpr.createIdent' varName)
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ] SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
) )
@@ -314,30 +259,27 @@ module internal HttpClientGenerator =
let urlSeparator = let urlSeparator =
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong // apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
let questionMark = let questionMark =
SynExpr.CreateConst (SynConst.Int32 63) SynExpr.CreateConst 63
|> SynExpr.applyFunction (SynExpr.CreateIdentString "char") |> SynExpr.applyFunction (SynExpr.createIdent "char")
|> SynExpr.CreateParen |> SynExpr.paren
let containsQuestion = let containsQuestion =
info.UrlTemplate info.UrlTemplate
|> SynExpr.callMethodArg "IndexOf" questionMark |> SynExpr.callMethodArg "IndexOf" questionMark
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst (SynConst.Int32 0)) |> SynExpr.greaterThanOrEqual (SynExpr.CreateConst 0)
SynExpr.ifThenElse SynExpr.ifThenElse containsQuestion (SynExpr.CreateConst "?") (SynExpr.CreateConst "&")
containsQuestion |> SynExpr.paren
(SynExpr.CreateConst (SynConst.CreateString "?"))
(SynExpr.CreateConst (SynConst.CreateString "&"))
|> SynExpr.CreateParen
let prefix = let prefix =
SynExpr.CreateIdent firstValueId SynExpr.createIdent' firstValueId
|> SynExpr.toString firstValue.Type |> SynExpr.toString firstValue.Type
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]) SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
) )
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConstString (firstKey + "="))) |> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConst (firstKey + "=")))
(prefix, queryParams) (prefix, queryParams)
||> List.fold (fun uri (paramKey, paramValue) -> ||> List.fold (fun uri (paramKey, paramValue) ->
@@ -346,16 +288,16 @@ module internal HttpClientGenerator =
| None -> failwith "Unable to get parameter variable name from anonymous parameter" | None -> failwith "Unable to get parameter variable name from anonymous parameter"
| Some id -> id | Some id -> id
SynExpr.toString paramValue.Type (SynExpr.CreateIdent paramValueId) SynExpr.toString paramValue.Type (SynExpr.createIdent' paramValueId)
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ] SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
) )
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConstString ("&" + paramKey + "="))) |> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConst ("&" + paramKey + "=")))
) )
|> SynExpr.plus requestUriTrailer |> SynExpr.plus requestUriTrailer
|> SynExpr.CreateParen |> SynExpr.paren
let requestUri = let requestUri =
let uriIdent = SynExpr.createLongIdent [ "System" ; "Uri" ] let uriIdent = SynExpr.createLongIdent [ "System" ; "Uri" ]
@@ -364,45 +306,37 @@ module internal HttpClientGenerator =
let baseAddress = let baseAddress =
[ [
SynMatchClause.Create ( SynMatchClause.create
SynPat.CreateNull, SynPat.createNull
None, (match info.BaseAddress with
match info.BaseAddress with | None ->
| None -> [
[ SynExpr.applyFunction (SynExpr.createIdent "nameof") (SynExpr.paren baseAddress)
SynExpr.CreateApp (SynExpr.CreateIdentString "nameof", SynExpr.CreateParen baseAddress) SynExpr.CreateConst
SynExpr.CreateConstString "No base address was supplied on the type, and no BaseAddress was on the HttpClient."
"No base address was supplied on the type, and no BaseAddress was on the HttpClient." ]
] |> SynExpr.tuple
|> SynExpr.CreateParenedTuple |> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ]) |> SynExpr.paren
|> SynExpr.CreateParen |> SynExpr.applyFunction (SynExpr.createIdent "raise")
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise") | Some expr -> SynExpr.applyFunction uriIdent expr)
| Some expr -> SynExpr.CreateApp (uriIdent, expr) SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
)
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v")
] ]
|> SynExpr.createMatch baseAddress |> SynExpr.createMatch baseAddress
|> SynExpr.CreateParen |> SynExpr.paren
SynExpr.App ( [
ExprAtomicFlag.Atomic, baseAddress
false, SynExpr.applyFunction
uriIdent, uriIdent
SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
baseAddress requestUriTrailer
SynExpr.CreateApp ( SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
uriIdent, ])
SynExpr.CreateParenedTuple ]
[ |> SynExpr.tuple
requestUriTrailer |> SynExpr.applyFunction uriIdent
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
]
)
],
range0
)
let bodyParams = let bodyParams =
info.Args info.Args
@@ -436,56 +370,43 @@ module internal HttpClientGenerator =
let httpReqMessageConstructor = let httpReqMessageConstructor =
[ [
SynExpr.equals SynExpr.equals
(SynExpr.CreateIdentString "Method") (SynExpr.createIdent "Method")
(SynExpr.createLongIdent (SynExpr.createLongIdent
[ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ]) [ "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 = let returnExpr =
match info.TaskReturnType with match info.TaskReturnType with
| HttpResponseMessage -> SynExpr.CreateIdentString "response" | HttpResponseMessage -> SynExpr.createIdent "response"
| String -> SynExpr.CreateIdentString "responseString" | String -> SynExpr.createIdent "responseString"
| Stream -> SynExpr.CreateIdentString "responseStream" | Stream -> SynExpr.createIdent "responseStream"
| RestEaseResponseType contents -> | RestEaseResponseType contents ->
let deserialiser = let deserialiser =
SynExpr.CreateLambda ( JsonParseGenerator.parseNode
[ SynPat.CreateConst SynConst.Unit ], None
SynExpr.CreateParen ( JsonParseGenerator.JsonParseOption.None
JsonParseGenerator.parseNode contents
None (SynExpr.createIdent "jsonNode")
JsonParseGenerator.JsonParseOption.None |> SynExpr.paren
contents |> SynExpr.createThunk
(SynExpr.CreateIdentString "jsonNode")
)
)
// new RestEase.Response (content : string, response : HttpResponseMessage, deserialiser : unit -> 'T) // new RestEase.Response (content : string, response : HttpResponseMessage, deserialiser : unit -> 'T)
SynExpr.New ( SynExpr.createNew
false, (SynType.app' (SynType.createLongIdent' [ "RestEase" ; "Response" ]) [ SynType.Anon range0 ])
SynType.App ( (SynExpr.tupleNoParen
SynType.CreateLongIdent (SynLongIdent.Create [ "RestEase" ; "Response" ]),
Some range0,
[ SynType.Anon range0 ],
[],
Some range0,
false,
range0
),
SynExpr.CreateParenedTuple
[ [
SynExpr.CreateIdentString "responseString" SynExpr.createIdent "responseString"
SynExpr.CreateIdentString "response" SynExpr.createIdent "response"
SynExpr.CreateParen deserialiser deserialiser
], ])
range0
)
| retType -> | retType ->
JsonParseGenerator.parseNode JsonParseGenerator.parseNode
None None
JsonParseGenerator.JsonParseOption.None JsonParseGenerator.JsonParseOption.None
retType retType
(SynExpr.CreateIdentString "jsonNode") (SynExpr.createIdent "jsonNode")
let handleBodyParams = let handleBodyParams =
match bodyParam with match bodyParam with
@@ -498,20 +419,15 @@ module internal HttpClientGenerator =
[ [
Let ( Let (
"queryParams", "queryParams",
SynExpr.New ( SynExpr.createNew
false, (SynType.createLongIdent'
SynType.CreateLongIdent ( [ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ])
SynLongIdent.Create (SynExpr.createIdent' bodyParamName)
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ]
),
SynExpr.CreateParen (SynExpr.CreateIdent bodyParamName),
range0
)
) )
Do ( Do (
SynExpr.LongIdentSet ( SynExpr.LongIdentSet (
SynLongIdent.Create [ "httpMessage" ; "Content" ], SynLongIdent.createS' [ "httpMessage" ; "Content" ],
SynExpr.CreateIdentString "queryParams", SynExpr.createIdent "queryParams",
range0 range0
) )
) )
@@ -520,8 +436,8 @@ module internal HttpClientGenerator =
[ [
Do ( Do (
SynExpr.LongIdentSet ( SynExpr.LongIdentSet (
SynLongIdent.Create [ "httpMessage" ; "Content" ], SynLongIdent.createS' [ "httpMessage" ; "Content" ],
SynExpr.CreateIdent bodyParamName, SynExpr.createIdent' bodyParamName,
range0 range0
) )
) )
@@ -530,38 +446,27 @@ module internal HttpClientGenerator =
[ [
Let ( Let (
"queryParams", "queryParams",
SynExpr.New ( SynExpr.createNew
false, (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "StringContent" ])
SynType.CreateLongIdent ( (SynExpr.createIdent' bodyParamName
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "StringContent" ] |> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
), |> SynExpr.pipeThroughFunction (
SynExpr.CreateParen ( SynExpr.createLambda
SynExpr.CreateIdent bodyParamName "node"
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty) (SynExpr.ifThenElse
|> SynExpr.pipeThroughFunction ( (SynExpr.applyFunction
SynExpr.createLambda (SynExpr.createIdent "isNull")
"node" (SynExpr.createIdent "node"))
(SynExpr.ifThenElse (SynExpr.applyFunction
(SynExpr.CreateApp ( (SynExpr.createLongIdent [ "node" ; "ToJsonString" ])
SynExpr.CreateIdentString "isNull", (SynExpr.CreateConst ()))
SynExpr.CreateIdentString "node" (SynExpr.CreateConst "null"))
)) ))
(SynExpr.CreateApp (
SynExpr.CreateLongIdent (
SynLongIdent.Create [ "node" ; "ToJsonString" ]
),
SynExpr.CreateConst SynConst.Unit
))
(SynExpr.CreateConst (SynConst.CreateString "null")))
)
),
range0
)
) )
Do ( Do (
SynExpr.LongIdentSet ( SynExpr.LongIdentSet (
SynLongIdent.Create [ "httpMessage" ; "Content" ], SynLongIdent.createS' [ "httpMessage" ; "Content" ],
SynExpr.CreateIdent (Ident.Create "queryParams"), SynExpr.createIdent "queryParams",
range0 range0
) )
) )
@@ -572,10 +477,9 @@ module internal HttpClientGenerator =
LetBang ( LetBang (
"responseString", "responseString",
SynExpr.awaitTask ( SynExpr.awaitTask (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ], (SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ])
SynExpr.CreateIdentString "ct" (SynExpr.createIdent "ct")
)
) )
) )
@@ -583,10 +487,9 @@ module internal HttpClientGenerator =
LetBang ( LetBang (
"responseStream", "responseStream",
SynExpr.awaitTask ( SynExpr.awaitTask (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ], (SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ])
SynExpr.CreateIdentString "ct" (SynExpr.createIdent "ct")
)
) )
) )
@@ -594,47 +497,39 @@ module internal HttpClientGenerator =
LetBang ( LetBang (
"jsonNode", "jsonNode",
SynExpr.awaitTask ( SynExpr.awaitTask (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ], (SynExpr.createLongIdent
SynExpr.CreateParenedTuple [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ])
(SynExpr.tuple
[ [
SynExpr.CreateIdentString "responseStream" SynExpr.createIdent "responseStream"
SynExpr.equals SynExpr.equals (SynExpr.createIdent "cancellationToken") (SynExpr.createIdent "ct")
(SynExpr.CreateIdentString "cancellationToken") ])
(SynExpr.CreateIdentString "ct")
]
)
) )
) )
let setVariableHeaders = let setVariableHeaders =
variableHeaders variableHeaders
|> List.map (fun (headerName, callToGetValue) -> |> List.map (fun (headerName, callToGetValue) ->
Do ( [
SynExpr.CreateApp ( headerName
SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ], SynExpr.applyFunction
SynExpr.CreateParenedTuple (SynExpr.createLongIdent'
[ [ Ident.create "this" ; callToGetValue ; Ident.create "ToString" ])
headerName (SynExpr.CreateConst ())
SynExpr.CreateApp ( ]
SynExpr.createLongIdent' |> SynExpr.tuple
[ Ident.Create "this" ; callToGetValue ; Ident.Create "ToString" ], |> SynExpr.applyFunction (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
SynExpr.CreateConst SynConst.Unit |> Do
)
]
)
)
) )
let setConstantHeaders = let setConstantHeaders =
constantHeaders constantHeaders
|> List.map (fun (headerName, headerValue) -> |> List.map (fun (headerName, headerValue) ->
Do ( SynExpr.applyFunction
SynExpr.CreateApp ( (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ], (SynExpr.tuple [ headerName ; headerValue ])
SynExpr.CreateParenedTuple [ headerName ; headerValue ] |> Do
)
)
) )
[ [
@@ -643,14 +538,9 @@ module internal HttpClientGenerator =
yield yield
Use ( Use (
"httpMessage", "httpMessage",
SynExpr.New ( SynExpr.createNew
false, (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ])
SynType.CreateLongIdent ( httpReqMessageConstructor
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ]
),
httpReqMessageConstructor,
range0
)
) )
yield! handleBodyParams yield! handleBodyParams
@@ -662,21 +552,18 @@ module internal HttpClientGenerator =
LetBang ( LetBang (
"response", "response",
SynExpr.awaitTask ( SynExpr.awaitTask (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "client" ; "SendAsync" ], (SynExpr.createLongIdent [ "client" ; "SendAsync" ])
SynExpr.CreateParenedTuple (SynExpr.tuple [ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ])
[ SynExpr.CreateIdentString "httpMessage" ; SynExpr.CreateIdentString "ct" ]
)
) )
) )
if info.EnsureSuccessHttpCode then if info.EnsureSuccessHttpCode then
yield yield
Let ( Let (
"response", "response",
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ], (SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ])
SynExpr.CreateConst SynConst.Unit (SynExpr.CreateConst ())
)
) )
match info.TaskReturnType with match info.TaskReturnType with
| HttpResponseMessage -> () | HttpResponseMessage -> ()
@@ -691,30 +578,22 @@ module internal HttpClientGenerator =
yield jsonNode yield jsonNode
] ]
|> SynExpr.createCompExpr "async" returnExpr |> SynExpr.createCompExpr "async" returnExpr
|> SynExpr.startAsTask (SynLongIdent.CreateFromLongIdent [ cancellationTokenArg ]) |> SynExpr.startAsTask cancellationTokenArg
SynBinding.SynBinding ( let thisIdent =
None, if variableHeaders.IsEmpty then "_" else "this"
SynBindingKind.Normal, |> Ident.create
false,
false, let args = args |> List.map snd |> SynPat.tuple |> List.singleton
[],
PreXmlDoc.Empty, SynBinding.basic [ thisIdent ; info.Identifier ] args implementation
valData,
headPat,
None,
implementation,
range0,
DebugPointAtBinding.Yes range0,
SynBinding.triviaZero true
)
|> SynBinding.withAccessibility info.Accessibility |> SynBinding.withAccessibility info.Accessibility
|> fun b -> SynMemberDefn.Member (b, range0) |> SynMemberDefn.memberImplementation
let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list = let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list =
attrs attrs
|> List.choose (fun attr -> |> List.choose (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "RestEase.Query" | "RestEase.Query"
| "RestEase.QueryAttribute" | "RestEase.QueryAttribute"
| "WoofWare.Myriad.Plugins.RestEase.Query" | "WoofWare.Myriad.Plugins.RestEase.Query"
@@ -755,7 +634,7 @@ module internal HttpClientGenerator =
let extractBasePath (attrs : SynAttribute list) : SynExpr option = let extractBasePath (attrs : SynAttribute list) : SynExpr option =
attrs attrs
|> List.tryPick (fun attr -> |> List.tryPick (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "BasePath" | "BasePath"
| "RestEase.BasePath" | "RestEase.BasePath"
| "WoofWare.Myriad.Plugins.RestEase.BasePath" | "WoofWare.Myriad.Plugins.RestEase.BasePath"
@@ -768,7 +647,7 @@ module internal HttpClientGenerator =
let extractBaseAddress (attrs : SynAttribute list) : SynExpr option = let extractBaseAddress (attrs : SynAttribute list) : SynExpr option =
attrs attrs
|> List.tryPick (fun attr -> |> List.tryPick (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "BaseAddress" | "BaseAddress"
| "RestEase.BaseAddress" | "RestEase.BaseAddress"
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress" | "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
@@ -883,46 +762,13 @@ module internal HttpClientGenerator =
let propertyMembers = let propertyMembers =
properties properties
|> List.map (fun (_, pi) -> |> List.map (fun (_, pi) ->
SynMemberDefn.Member ( SynExpr.createLongIdent' [ Ident.lowerFirstLetter pi.Identifier ]
SynBinding.SynBinding ( |> SynExpr.applyTo (SynExpr.CreateConst ())
pi.Accessibility, |> SynBinding.basic [ Ident.create "_" ; pi.Identifier ] []
SynBindingKind.Normal, |> SynBinding.withReturnAnnotation pi.Type
pi.IsInline, |> SynBinding.setInline pi.IsInline
false, |> SynBinding.withAccessibility pi.Accessibility
[], |> SynMemberDefn.memberImplementation
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
)
) )
let members = propertyMembers @ nonPropertyMembers let members = propertyMembers @ nonPropertyMembers
@@ -932,12 +778,12 @@ module internal HttpClientGenerator =
"Extension methods" "Extension methods"
else else
"Module") "Module")
|> sprintf " %s for constructing a REST client." |> sprintf "%s for constructing a REST client."
|> PreXmlDoc.Create |> PreXmlDoc.create
let interfaceImpl = let interfaceImpl =
SynExpr.ObjExpr ( SynExpr.ObjExpr (
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name), SynType.createLongIdent interfaceType.Name,
None, None,
Some range0, Some range0,
[], [],
@@ -950,54 +796,26 @@ module internal HttpClientGenerator =
let headerArgs = let headerArgs =
properties properties
|> List.map (fun (_, pi) -> |> List.map (fun (_, pi) ->
SynPat.CreateTyped ( SynPat.namedI (Ident.lowerFirstLetter pi.Identifier)
SynPat.CreateNamed (Ident.lowerFirstLetter pi.Identifier), |> SynPat.annotateType (SynType.funFromDomain (SynType.named "unit") pi.Type)
SynType.CreateFun (SynType.CreateLongIdent "unit", pi.Type)
)
|> SynPat.CreateParen
) )
let clientCreationArg = let clientCreationArg =
SynPat.CreateTyped ( SynPat.named "client"
SynPat.CreateNamed (Ident.Create "client"), |> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpClient" ])
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpClient" ])
)
|> SynPat.CreateParen
let xmlDoc = let xmlDoc =
if properties.IsEmpty then if properties.IsEmpty then
" Create a REST client." "Create a REST client."
else 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." "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 |> PreXmlDoc.create
let functionName = Ident.Create "client" let functionName = Ident.create "client"
let valData = let pattern = SynLongIdent.createS "make"
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
SynValData.SynValData ( let returnInfo = SynType.createLongIdent interfaceType.Name
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 nameWithoutLeadingI = let nameWithoutLeadingI =
List.last interfaceType.Name List.last interfaceType.Name
@@ -1011,74 +829,54 @@ module internal HttpClientGenerator =
let createFunc = let createFunc =
if spec.ExtensionMethods then if spec.ExtensionMethods then
let binding = let binding =
SynBinding.basic SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
(SynLongIdent.CreateString "make")
(headerArgs @ [ clientCreationArg ])
interfaceImpl
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.makeStaticMember
|> SynBinding.withReturnAnnotation returnInfo |> 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 = let containingType =
SynTypeDefn.SynTypeDefn ( SynTypeDefnRepr.augmentation ()
SynComponentInfo.Create ( |> SynTypeDefn.create componentInfo
[ Ident.Create nameWithoutLeadingI ], |> SynTypeDefn.withMemberDefns [ binding ]
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
}
)
SynModuleDecl.Types ([ containingType ], range0) SynModuleDecl.Types ([ containingType ], range0)
else else
SynBinding.basic (SynLongIdent.CreateString "make") (headerArgs @ [ clientCreationArg ]) interfaceImpl SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> List.singleton |> SynModuleDecl.createLet
|> SynModuleDecl.CreateLet
let moduleName : LongIdent = let moduleName =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ Ident.Create (nameWithoutLeadingI + "HttpClientExtension") ] Ident.create (nameWithoutLeadingI + "HttpClientExtension")
else else
[ Ident.Create nameWithoutLeadingI ] Ident.create nameWithoutLeadingI
let attribs = let attribs =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ SynAttributeList.Create SynAttribute.autoOpen ] [ SynAttribute.autoOpen ]
else else
[ [ SynAttribute.compilationRepresentation ; SynAttribute.requireQualifiedAccess ]
SynAttributeList.Create SynAttribute.compilationRepresentation
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
]
let modInfo = let modInfo =
SynComponentInfo.Create ( SynComponentInfo.create moduleName
moduleName, |> SynComponentInfo.withDocString docString
attributes = attribs, |> SynComponentInfo.addAttributes attribs
xmldoc = docString, |> SynComponentInfo.setAccessibility interfaceType.Accessibility
access = interfaceType.Accessibility
)
SynModuleOrNamespace.CreateNamespace ( [
ns, for openStatement in opens do
decls = yield SynModuleDecl.openAny openStatement
[ yield SynModuleDecl.nestedModule modInfo [ createFunc ]
for openStatement in opens do ]
yield SynModuleDecl.CreateOpen openStatement |> SynModuleOrNamespace.createNamespace ns
yield SynModuleDecl.CreateNestedModule (modInfo, [ createFunc ])
] open Myriad.Core
)
/// Myriad generator that provides an HTTP client for an interface type using RestEase annotations. /// Myriad generator that provides an HTTP client for an interface type using RestEase annotations.
[<MyriadGenerator("http-client")>] [<MyriadGenerator("http-client")>]

View File

@@ -2,9 +2,7 @@ namespace WoofWare.Myriad.Plugins
open System open System
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml open Fantomas.FCS.Xml
open Myriad.Core
type internal GenerateMockOutputSpec = type internal GenerateMockOutputSpec =
{ {
@@ -14,7 +12,6 @@ type internal GenerateMockOutputSpec =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal InterfaceMockGenerator = module internal InterfaceMockGenerator =
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core.Ast
let private getName (SynField (_, _, id, _, _, _, _, _, _)) = let private getName (SynField (_, _, id, _, _, _, _, _, _)) =
match id with match id with
@@ -46,72 +43,67 @@ module internal InterfaceMockGenerator =
) )
|> Set.ofSeq |> 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.createLongIdent [ "System" ; "NotImplementedException" ]
|> SynExpr.applyTo (SynExpr.CreateConstString "Unimplemented mock function") |> SynExpr.applyTo failString
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise") |> SynExpr.applyFunction (SynExpr.createIdent "raise")
|> SynExpr.createLambda "_" |> SynExpr.createLambda "_"
let constructorReturnType = let constructorReturnType =
match interfaceType.Generics with match interfaceType.Generics with
| None -> SynType.CreateLongIdent name | None -> SynType.createLongIdent' [ name ]
| Some generics -> | Some generics ->
let generics = let generics =
generics.TyparDecls generics.TyparDecls
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0)) |> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
SynType.App ( SynType.app name generics
SynType.CreateLongIdent name,
Some range0,
generics,
List.replicate (generics.Length - 1) range0,
Some range0,
false,
range0
)
let constructorFields = let constructorFields =
let extras = let extras =
if inherits.Contains KnownInheritance.IDisposable then if inherits.Contains KnownInheritance.IDisposable then
let unitFun = SynExpr.createLambda "_" SynExpr.CreateUnit let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
[ [ (SynLongIdent.createS "Dispose", true), Some unitFun ]
(SynLongIdent.CreateFromLongIdent [ Ident.Create "Dispose" ], true), Some unitFun
]
else else
[] []
let nonExtras = let nonExtras =
fields 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 extras @ nonExtras
let constructor = let constructor =
SynBinding.basic SynBinding.basic
(SynLongIdent.CreateString "Empty") [ Ident.create "Empty" ]
(if interfaceType.Generics.IsNone then (if interfaceType.Generics.IsNone then
[] []
else else
[ SynPat.CreateConst SynConst.Unit ]) [ SynPat.unit ])
(AstHelper.instantiateRecord constructorFields) (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 |> SynBinding.withReturnAnnotation constructorReturnType
|> fun m -> SynMemberDefn.Member (m, range0) |> SynMemberDefn.staticMember
let fields = let fields =
let extras = let extras =
if inherits.Contains KnownInheritance.IDisposable then if inherits.Contains KnownInheritance.IDisposable then
[ {
SynField.Create ( Attrs = []
SynType.CreateFun (SynType.CreateUnit, SynType.CreateUnit), Ident = Some (Ident.create "Dispose")
Ident.Create "Dispose", Type = SynType.funFromDomain SynType.unit SynType.unit
xmldoc = PreXmlDoc.Create " Implementation of IDisposable.Dispose" }
) |> SynField.make
] |> SynField.withDocString (PreXmlDoc.create "Implementation of IDisposable.Dispose")
|> List.singleton
else else
[] []
@@ -121,47 +113,6 @@ module internal InterfaceMockGenerator =
let members = let members =
interfaceType.Members interfaceType.Members
|> List.map (fun memberInfo -> |> 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 = let headArgs =
memberInfo.Args memberInfo.Args
|> List.mapi (fun i tupledArgs -> |> List.mapi (fun i tupledArgs ->
@@ -169,27 +120,15 @@ module internal InterfaceMockGenerator =
tupledArgs.Args tupledArgs.Args
|> List.mapi (fun j ty -> |> List.mapi (fun j ty ->
match ty.Type with match ty.Type with
| UnitType -> SynPat.Const (SynConst.Unit, range0) | UnitType -> SynPat.unit
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}") | _ -> SynPat.named $"arg_%i{i}_%i{j}"
) )
match args with match args with
| [] -> failwith "somehow got no args at all" | [] -> failwith "somehow got no args at all"
| [ arg ] -> arg | [ arg ] -> arg
| args -> | args -> SynPat.tuple args
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0) |> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
|> 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
) )
let body = let body =
@@ -199,10 +138,10 @@ module internal InterfaceMockGenerator =
args.Args args.Args
|> List.mapi (fun j arg -> |> List.mapi (fun j arg ->
match arg.Type with match arg.Type with
| UnitType -> SynExpr.CreateConst SynConst.Unit | UnitType -> SynExpr.CreateConst ()
| _ -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}" | _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
) )
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
) )
match tuples |> List.rev with match tuples |> List.rev with
@@ -210,38 +149,17 @@ module internal InterfaceMockGenerator =
| last :: rest -> | last :: rest ->
(last, rest) (last, rest)
||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail)) ||> List.fold SynExpr.applyTo
|> SynExpr.applyFunction ( |> SynExpr.applyFunction (
SynExpr.createLongIdent' [ Ident.Create "this" ; memberInfo.Identifier ] SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
) )
SynMemberDefn.Member ( SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body
SynBinding.SynBinding ( |> SynMemberDefn.memberImplementation
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
)
) )
let interfaceName = let interfaceName =
let baseName = let baseName = SynType.createLongIdent interfaceType.Name
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
match interfaceType.Generics with match interfaceType.Generics with
| None -> baseName | None -> baseName
@@ -251,17 +169,9 @@ module internal InterfaceMockGenerator =
| SynTyparDecls.PostfixList (decls, _, _) -> decls | SynTyparDecls.PostfixList (decls, _, _) -> decls
| SynTyparDecls.PrefixList (decls, _) -> decls | SynTyparDecls.PrefixList (decls, _) -> decls
| SynTyparDecls.SinglePrefix (decl, _) -> [ decl ] | SynTyparDecls.SinglePrefix (decl, _) -> [ decl ]
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0)) |> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
SynType.App ( SynType.app' baseName generics
baseName,
Some range0,
generics,
List.replicate (generics.Length - 1) range0,
Some range0,
false,
range0
)
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0) SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
@@ -279,18 +189,15 @@ module internal InterfaceMockGenerator =
|> Seq.map (fun inheritance -> |> Seq.map (fun inheritance ->
match inheritance with match inheritance with
| KnownInheritance.IDisposable -> | KnownInheritance.IDisposable ->
let binding = let mem =
SynBinding.basic SynExpr.createLongIdent [ "this" ; "Dispose" ]
(SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; Ident.Create "Dispose" ]) |> SynExpr.applyTo (SynExpr.CreateConst ())
[ SynPat.CreateConst SynConst.Unit ] |> SynBinding.basic [ Ident.create "this" ; Ident.create "Dispose" ] [ SynPat.unit ]
(SynExpr.CreateApp (SynExpr.createLongIdent [ "this" ; "Dispose" ], SynExpr.CreateUnit)) |> SynBinding.withReturnAnnotation SynType.unit
|> SynBinding.withReturnAnnotation (SynType.Unit ()) |> SynMemberDefn.memberImplementation
|> SynBinding.makeInstanceMember
let mem = SynMemberDefn.Member (binding, range0)
SynMemberDefn.Interface ( SynMemberDefn.Interface (
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "IDisposable" ]), SynType.createLongIdent' [ "System" ; "IDisposable" ],
Some range0, Some range0,
Some [ mem ], Some [ mem ],
range0 range0
@@ -300,7 +207,7 @@ module internal InterfaceMockGenerator =
let record = let record =
{ {
Name = Ident.Create name Name = Ident.create name
Fields = fields Fields = fields
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces) Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
XmlDoc = Some xmlDoc XmlDoc = Some xmlDoc
@@ -314,7 +221,7 @@ module internal InterfaceMockGenerator =
let private buildType (x : ParameterInfo) : SynType = let private buildType (x : ParameterInfo) : SynType =
if x.IsOptional then if x.IsOptional then
SynType.App (SynType.CreateLongIdent "option", Some range0, [ x.Type ], [], Some range0, false, range0) SynType.app "option" [ x.Type ]
else else
x.Type x.Type
@@ -331,19 +238,15 @@ module internal InterfaceMockGenerator =
let constructMember (mem : MemberInfo) : SynField = let constructMember (mem : MemberInfo) : SynField =
let inputType = mem.Args |> List.map constructMemberSinglePlace let inputType = mem.Args |> List.map constructMemberSinglePlace
let funcType = AstHelper.toFun inputType mem.ReturnType let funcType = SynType.toFun inputType mem.ReturnType
SynField.SynField ( {
[], Type = funcType
false, Attrs = []
Some mem.Identifier, Ident = Some mem.Identifier
funcType, }
false, |> SynField.make
mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty, |> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
None,
range0,
SynFieldTrivia.Zero
)
let createRecord let createRecord
(namespaceId : LongIdent) (namespaceId : LongIdent)
@@ -353,7 +256,7 @@ module internal InterfaceMockGenerator =
= =
let interfaceType = AstHelper.parseInterface interfaceType let interfaceType = AstHelper.parseInterface interfaceType
let fields = interfaceType.Members |> List.map constructMember 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 = let name =
List.last interfaceType.Name List.last interfaceType.Name
@@ -367,10 +270,10 @@ module internal InterfaceMockGenerator =
let typeDecl = createType spec name interfaceType docString fields let typeDecl = createType spec name interfaceType docString fields
SynModuleOrNamespace.CreateNamespace ( [ yield! opens |> List.map SynModuleDecl.openAny ; yield typeDecl ]
namespaceId, |> SynModuleOrNamespace.createNamespace namespaceId
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
) open Myriad.Core
/// Myriad generator that creates a record which implements the given interface, /// Myriad generator that creates a record which implements the given interface,
/// but with every field mocked out. /// but with every field mocked out.

View File

@@ -4,8 +4,6 @@ open System
open System.Text open System.Text
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Myriad.Core
type internal JsonParseOutputSpec = type internal JsonParseOutputSpec =
{ {
@@ -15,7 +13,6 @@ type internal JsonParseOutputSpec =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal JsonParseGenerator = module internal JsonParseGenerator =
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core.Ast
type JsonParseOption = type JsonParseOption =
{ {
@@ -30,30 +27,23 @@ module internal JsonParseGenerator =
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v) /// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v)
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) = let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
let raiseExpr = let raiseExpr =
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateApp ( (SynExpr.createIdent "sprintf")
SynExpr.CreateIdentString "sprintf", (SynExpr.CreateConst "Required key '%s' not found on JSON object")
SynExpr.CreateConstString "Required key '%s' not found on JSON object" |> SynExpr.applyTo (SynExpr.paren propertyName)
), |> SynExpr.paren
SynExpr.CreateParen propertyName
)
|> SynExpr.CreateParen
|> SynExpr.applyFunction ( |> SynExpr.applyFunction (
SynExpr.CreateLongIdent ( SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
)
) )
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise") |> SynExpr.applyFunction (SynExpr.createIdent "raise")
SynExpr.CreateMatch ( [
indexed, SynMatchClause.create SynPat.createNull raiseExpr
[ SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
SynMatchClause.Create (SynPat.CreateNull, None, raiseExpr) ]
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v") |> SynExpr.createMatch indexed
] |> SynExpr.paren
)
|> SynExpr.CreateParen
/// {node}.AsValue().GetValue<{typeName}> () /// {node}.AsValue().GetValue<{typeName}> ()
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`. /// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
@@ -81,10 +71,8 @@ module internal JsonParseGenerator =
/// {type}.jsonParse {node} /// {type}.jsonParse {node}
let typeJsonParse (typeName : LongIdent) (node : SynExpr) : SynExpr = let typeJsonParse (typeName : LongIdent) (node : SynExpr) : SynExpr =
SynExpr.CreateApp ( node
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (typeName @ [ Ident.Create "jsonParse" ])), |> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ Ident.create "jsonParse" ]))
node
)
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it. /// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
/// body is the body of a lambda which takes a parameter `elt`. /// body is the body of a lambda which takes a parameter `elt`.
@@ -103,51 +91,41 @@ module internal JsonParseGenerator =
| Some propertyName -> assertNotNull propertyName node | Some propertyName -> assertNotNull propertyName node
|> SynExpr.callMethod "AsArray" |> SynExpr.callMethod "AsArray"
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateApp ( SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "elt" body)
SynExpr.CreateLongIdent (SynLongIdent.Create [ "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 /// match {node} with | null -> None | v -> {body} |> Some
/// Use the variable `v` to get access to the `Some`. /// Use the variable `v` to get access to the `Some`.
let createParseLineOption (node : SynExpr) (body : SynExpr) : SynExpr = 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 (SynExpr.createIdent "None")
[ SynMatchClause.create (SynPat.named "v") body
SynMatchClause.Create (SynPat.CreateNull, None, SynExpr.CreateIdent (Ident.Create "None")) ]
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, body) |> SynExpr.createMatch node
]
)
/// Given e.g. "float", returns "System.Double.Parse" /// Given e.g. "float", returns "System.Double.Parse"
let parseFunction (typeName : string) : LongIdent = let parseFunction (typeName : string) : LongIdent =
let qualified = let qualified =
match AstHelper.qualifyPrimitiveType typeName with match Primitives.qualifyType typeName with
| Some x -> x | Some x -> x
| None -> failwith $"Could not recognise type %s{typeName} as a primitive." | 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)) /// 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. /// 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 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" ] // No need to paren here, we're on the LHS of a `let`
|> SynExpr.createLet SynExpr.tupleNoParen [ SynExpr.createIdent "key" ; SynExpr.createIdent "value" ]
[ |> SynExpr.createLet [ SynBinding.basic [ Ident.create "value" ] [] (value valueArg) ]
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "value"), expr = value valueArg) |> SynExpr.createLet [ SynBinding.basic [ Ident.create "key" ] [] (key keyArg) ]
]
|> SynExpr.createLet
[
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "key"), expr = key keyArg)
]
|> SynExpr.createLambda "kvp" |> SynExpr.createLambda "kvp"
/// A conforming JSON object has only strings as keys. But it would be reasonable to allow the user /// 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 | String -> key
| Uri -> | Uri ->
key key
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ])) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
| _ -> | _ ->
failwithf 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." $"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 | None -> basic
| Some option -> | Some option ->
let cond = let cond =
SynExpr.DotGet ( SynExpr.DotGet (SynExpr.createIdent "exc", range0, SynLongIdent.createS "Message", range0)
SynExpr.CreateIdentString "exc", |> SynExpr.callMethodArg "Contains" (SynExpr.CreateConst "cannot be converted to")
range0,
SynLongIdent.CreateString "Message",
range0
)
|> SynExpr.callMethodArg
"Contains"
(SynExpr.CreateConst (SynConst.CreateString "cannot be converted to"))
let handler = let handler =
asValueGetValue propertyName "string" node asValueGetValue propertyName "string" node
@@ -213,91 +184,82 @@ module internal JsonParseGenerator =
|> SynExpr.ifThenElse |> SynExpr.ifThenElse
(SynExpr.equals (SynExpr.equals
option option
(SynExpr.CreateLongIdent ( (SynExpr.createLongIdent
SynLongIdent.Create [
[ "System"
"System" "Text"
"Text" "Json"
"Json" "Serialization"
"Serialization" "JsonNumberHandling"
"JsonNumberHandling" "AllowReadingFromString"
"AllowReadingFromString" ]))
]
)))
SynExpr.reraise SynExpr.reraise
|> SynExpr.ifThenElse cond SynExpr.reraise |> SynExpr.ifThenElse cond SynExpr.reraise
basic basic
|> SynExpr.pipeThroughTryWith |> SynExpr.pipeThroughTryWith
(SynPat.IsInst ( (SynPat.IsInst (
SynType.LongIdent (SynLongIdent.Create [ "System" ; "InvalidOperationException" ]), SynType.LongIdent (SynLongIdent.createS' [ "System" ; "InvalidOperationException" ]),
range0 range0
)) ))
handler handler
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node | PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
| OptionType ty -> | OptionType ty ->
parseNode None options ty (SynExpr.CreateIdentString "v") parseNode None options ty (SynExpr.createIdent "v")
|> createParseLineOption node |> createParseLineOption node
| ListType ty -> | ListType ty ->
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt")) parseNode None options ty (SynExpr.createIdent "elt")
|> asArrayMapped propertyName "List" node |> asArrayMapped propertyName "List" node
| ArrayType ty -> | ArrayType ty ->
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt")) parseNode None options ty (SynExpr.createIdent "elt")
|> asArrayMapped propertyName "Array" node |> asArrayMapped propertyName "Array" node
| IDictionaryType (keyType, valueType) -> | IDictionaryType (keyType, valueType) ->
node node
|> asObject propertyName |> asObject propertyName
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]), (SynExpr.createLongIdent [ "Seq" ; "map" ])
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType) (dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
)
) )
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "dict" ])) |> SynExpr.pipeThroughFunction (SynExpr.createIdent "dict")
| DictionaryType (keyType, valueType) -> | DictionaryType (keyType, valueType) ->
node node
|> asObject propertyName |> asObject propertyName
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]), (SynExpr.createLongIdent [ "Seq" ; "map" ])
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType) (dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
)
) )
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]), (SynExpr.createLongIdent [ "Seq" ; "map" ])
SynExpr.CreateLongIdent ( (SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ])
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ]
)
)
) )
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "Dictionary" ]) SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "Dictionary" ]
) )
| IReadOnlyDictionaryType (keyType, valueType) -> | IReadOnlyDictionaryType (keyType, valueType) ->
node node
|> asObject propertyName |> asObject propertyName
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]), (SynExpr.createLongIdent [ "Seq" ; "map" ])
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType) (dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
)
) )
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "readOnlyDict" ])) |> SynExpr.pipeThroughFunction (SynExpr.createIdent "readOnlyDict")
| MapType (keyType, valueType) -> | MapType (keyType, valueType) ->
node node
|> asObject propertyName |> asObject propertyName
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]), (SynExpr.createLongIdent [ "Seq" ; "map" ])
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType) (dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
)
) )
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Map" ; "ofSeq" ])) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Map" ; "ofSeq" ])
| BigInt -> | BigInt ->
node node
|> SynExpr.callMethod "ToJsonString" |> SynExpr.callMethod "ToJsonString"
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Numerics" ; "BigInteger" ; "Parse" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Numerics" ; "BigInteger" ; "Parse" ])
| _ -> | _ ->
// Let's just hope that we've also got our own type annotation! // Let's just hope that we've also got our own type annotation!
@@ -314,7 +276,7 @@ module internal JsonParseGenerator =
/// propertyName is probably a string literal, but it could be a [<Literal>] variable /// propertyName is probably a string literal, but it could be a [<Literal>] variable
/// The result of this function is the body of a let-binding (not including the LHS of that let-binding). /// 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 = let createParseRhs (options : JsonParseOption) (propertyName : SynExpr) (fieldType : SynType) : SynExpr =
let objectToParse = SynExpr.CreateIdentString "node" |> SynExpr.index propertyName let objectToParse = SynExpr.createIdent "node" |> SynExpr.index propertyName
parseNode (Some propertyName) options fieldType objectToParse parseNode (Some propertyName) options fieldType objectToParse
let isJsonNumberHandling (literal : LongIdent) : bool = let isJsonNumberHandling (literal : LongIdent) : bool =
@@ -331,54 +293,47 @@ module internal JsonParseGenerator =
/// That is, we give you access to a `JsonNode` called `node`, /// That is, we give you access to a `JsonNode` called `node`,
/// and you must return a `typeName`. /// and you must return a `typeName`.
let scaffolding (spec : JsonParseOutputSpec) (typeName : LongIdent) (functionBody : SynExpr) : SynModuleDecl = 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 inputArg = "node"
let functionName = Ident.Create "jsonParse" let functionName = Ident.create "jsonParse"
let arg = let arg =
SynPat.CreateNamed inputArg SynPat.named inputArg
|> SynPat.annotateType ( |> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
)
if spec.ExtensionMethods then if spec.ExtensionMethods then
let binding = let binding =
SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ arg ] functionBody SynBinding.basic [ functionName ] [ arg ] functionBody
|> SynBinding.makeStaticMember
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> 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 = let containingType =
SynTypeDefn.SynTypeDefn ( SynTypeDefnRepr.augmentation ()
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"), |> SynTypeDefn.create componentInfo
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0), |> SynTypeDefn.withMemberDefns [ binding ]
[ mem ],
None,
range0,
{
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
EqualsRange = None
WithKeyword = None
}
)
SynModuleDecl.Types ([ containingType ], range0) SynModuleDecl.Types ([ containingType ], range0)
else else
SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ arg ] functionBody SynBinding.basic [ functionName ] [ arg ] functionBody
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> List.singleton |> SynModuleDecl.createLet
|> SynModuleDecl.CreateLet
let getParseOptions (fieldAttrs : SynAttribute list) = let getParseOptions (fieldAttrs : SynAttribute list) =
(JsonParseOption.None, fieldAttrs) (JsonParseOption.None, fieldAttrs)
||> List.fold (fun options attr -> ||> List.fold (fun options attr ->
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then if
(SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
then
let qualifiedEnumValue = let qualifiedEnumValue =
match SynExpr.stripOptionalParen attr.ArgExpr with match SynExpr.stripOptionalParen attr.ArgExpr with
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident -> | SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
@@ -401,15 +356,15 @@ module internal JsonParseGenerator =
options options
) )
let createRecordMaker (spec : JsonParseOutputSpec) (fields : SynFieldData<Ident> list) =
let createRecordMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynFieldData<Ident> list) =
let assignments = let assignments =
fields fields
|> List.mapi (fun i fieldData -> |> List.mapi (fun i fieldData ->
let propertyNameAttr = let propertyNameAttr =
fieldData.Attrs fieldData.Attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal) (SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
) )
let options = getParseOptions fieldData.Attrs let options = getParseOptions fieldData.Attrs
@@ -425,18 +380,17 @@ module internal JsonParseGenerator =
if fieldData.Ident.idText.Length > 1 then if fieldData.Ident.idText.Length > 1 then
sb.Append (fieldData.Ident.idText.Substring 1) |> ignore<StringBuilder> sb.Append (fieldData.Ident.idText.Substring 1) |> ignore<StringBuilder>
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst sb.ToString () |> SynExpr.CreateConst
| Some name -> name.ArgExpr | Some name -> name.ArgExpr
createParseRhs options propertyName fieldData.Type createParseRhs options propertyName fieldData.Type
|> SynBinding.basic (SynLongIdent.CreateString $"arg_%i{i}") [] |> SynBinding.basic [ Ident.create $"arg_%i{i}" ] []
) )
let finalConstruction = let finalConstruction =
fields fields
|> List.mapi (fun i fieldData -> |> List.mapi (fun i fieldData ->
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true), (SynLongIdent.createI fieldData.Ident, true), Some (SynExpr.createIdent $"arg_%i{i}")
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateString $"arg_%i{i}"))
) )
|> AstHelper.instantiateRecord |> AstHelper.instantiateRecord
@@ -458,19 +412,19 @@ module internal JsonParseGenerator =
let options = getParseOptions field.Attrs let options = getParseOptions field.Attrs
createParseRhs options propertyName field.Type createParseRhs options propertyName field.Type
) )
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ])) |> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ]))
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.index (SynExpr.CreateConstString "data") (SynExpr.CreateIdentString "node") SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|> assertNotNull (SynExpr.CreateConstString "data") |> assertNotNull (SynExpr.CreateConst "data")
|> SynBinding.basic (SynLongIdent.CreateString "node") [] |> SynBinding.basic [ Ident.create "node" ] []
] ]
match propertyName with match propertyName with
| SynExpr.Const (synConst, _) -> | SynExpr.Const (synConst, _) ->
SynMatchClause.SynMatchClause ( SynMatchClause.SynMatchClause (
SynPat.CreateConst synConst, SynPat.createConst synConst,
None, None,
body, body,
range0, range0,
@@ -481,30 +435,19 @@ module internal JsonParseGenerator =
} }
) )
| _ -> | _ ->
SynMatchClause.SynMatchClause ( SynMatchClause.create (SynPat.named "x") body
SynPat.CreateNamed (Ident.Create "x"), |> SynMatchClause.withWhere (SynExpr.equals (SynExpr.createIdent "x") propertyName)
Some (SynExpr.equals (SynExpr.CreateIdentString "x") propertyName),
body,
range0,
DebugPointAtTarget.Yes,
{
ArrowRange = Some range0
BarRange = Some range0
}
)
) )
|> fun l -> |> fun l ->
l l
@ [ @ [
let fail = let fail =
SynExpr.plus SynExpr.plus (SynExpr.CreateConst "Unrecognised 'type' field value: ") (SynExpr.createIdent "v")
(SynExpr.CreateConstString "Unrecognised 'type' field value: ") |> SynExpr.paren
(SynExpr.CreateIdentString "v") |> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|> SynExpr.CreateParen
|> SynExpr.applyFunction (SynExpr.CreateIdentString "failwith")
SynMatchClause.SynMatchClause ( SynMatchClause.SynMatchClause (
SynPat.CreateNamed (Ident.Create "v"), SynPat.named "v",
None, None,
fail, fail,
range0, range0,
@@ -515,34 +458,21 @@ module internal JsonParseGenerator =
} }
) )
] ]
|> SynExpr.createMatch (SynExpr.CreateIdentString "ty") |> SynExpr.createMatch (SynExpr.createIdent "ty")
|> SynExpr.createLet |> SynExpr.createLet
[ [
let property = SynExpr.CreateConstString "type" let property = SynExpr.CreateConst "type"
SynExpr.CreateIdentString "node" SynExpr.createIdent "node"
|> SynExpr.index property |> SynExpr.index property
|> assertNotNull property |> assertNotNull property
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.createLambda SynExpr.createLambda
"v" "v"
(SynExpr.callGenericMethod "GetValue" [ Ident.Create "string" ] (SynExpr.CreateIdentString "v")) (SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v"))
) )
|> SynBinding.basic (SynLongIdent.CreateString "ty") [] |> SynBinding.basic [ Ident.create "ty" ] []
] ]
(*
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
*)
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) = let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) = let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
@@ -553,12 +483,9 @@ module internal JsonParseGenerator =
let attributes = let attributes =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ SynAttributeList.Create SynAttribute.autoOpen ] [ SynAttribute.autoOpen ]
else else
[ [ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
SynAttributeList.Create SynAttribute.compilationRepresentation
]
let xmlDoc = let xmlDoc =
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "." let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
@@ -569,8 +496,8 @@ module internal JsonParseGenerator =
else else
"methods" "methods"
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type" $"Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|> PreXmlDoc.Create |> PreXmlDoc.create
let moduleName = let moduleName =
if spec.ExtensionMethods then if spec.ExtensionMethods then
@@ -581,39 +508,39 @@ module internal JsonParseGenerator =
List.last ident List.last ident
|> fun i -> i.idText |> fun i -> i.idText
|> fun s -> s + "JsonParseExtension" |> fun s -> s + "JsonParseExtension"
|> Ident.Create |> Ident.create
List.take (List.length ident - 1) ident @ [ expanded ] List.take (List.length ident - 1) ident @ [ expanded ]
else else
ident ident
let info = let info =
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc) SynComponentInfo.createLong moduleName
|> SynComponentInfo.withDocString xmlDoc
|> SynComponentInfo.addAttributes attributes
let decl = let decl =
match synTypeDefnRepr with match synTypeDefnRepr with
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) -> | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) ->
let fields = fields |> List.map SynField.extractWithIdent fields |> List.map SynField.extractWithIdent |> createRecordMaker spec
createRecordMaker spec ident fields
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) -> | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) ->
let optionGet (i : Ident option) = let optionGet (i : Ident option) =
match i with match i with
| None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field." | None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field."
| Some i -> i | Some i -> i
let cases = cases
cases |> List.map SynUnionCase.extract
|> List.map SynUnionCase.extract |> List.map (UnionCase.mapIdentFields optionGet)
|> List.map (UnionCase.mapIdentFields optionGet) |> createUnionMaker spec ident
createUnionMaker spec ident cases
| _ -> failwithf "Not a record or union type" | _ -> failwithf "Not a record or union type"
let mdl = [ scaffolding spec ident decl ]
[ scaffolding spec ident decl ] |> SynModuleDecl.nestedModule info
|> fun d -> SynModuleDecl.CreateNestedModule (info, d) |> 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, /// Myriad generator that provides a method (possibly an extension method) for a record type,
/// containing a JSON parse function. /// containing a JSON parse function.

View File

@@ -3,9 +3,6 @@ namespace WoofWare.Myriad.Plugins
open System open System
open System.Text open System.Text
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Myriad.Core
type internal JsonSerializeOutputSpec = type internal JsonSerializeOutputSpec =
{ {
@@ -15,7 +12,6 @@ type internal JsonSerializeOutputSpec =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal JsonSerializeGenerator = module internal JsonSerializeGenerator =
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core.Ast
/// Given `input.Ident`, for example, choose how to add it to the ambient `node`. /// 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)`. /// 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 -> | OptionType ty ->
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field // fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
[ let noneClause =
SynMatchClause.Create ( // The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
SynPat.CreateLongIdent (SynLongIdent.CreateString "None", []), // identically equal to null. We have to work around this later, but we might as well just
None, // be efficient here and whip up the null directly.
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"` SynExpr.createNull ()
// identically equal to null. We have to work around this later, but we might as well just |> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
// be efficient here and whip up the null directly. |> SynMatchClause.create (SynPat.named "None")
SynExpr.CreateNull
|> SynExpr.upcast' ( let someClause =
SynType.CreateLongIdent ( SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "field")
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ] |> 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 ( [ noneClause ; someClause ]
SynPat.CreateLongIdent ( |> SynExpr.createMatch (SynExpr.createIdent "field")
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")
|> SynExpr.createLambda "field" |> SynExpr.createLambda "field"
| ArrayType ty | ArrayType ty
| ListType ty -> | ListType ty ->
@@ -84,22 +67,21 @@ module internal JsonSerializeGenerator =
DebugPointAtInOrTo.Yes range0, DebugPointAtInOrTo.Yes range0,
SeqExprOnly.SeqExprOnly false, SeqExprOnly.SeqExprOnly false,
true, true,
SynPat.CreateNamed (Ident.Create "mem"), SynPat.named "mem",
SynExpr.CreateIdent (Ident.Create "field"), SynExpr.createIdent "field",
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.CreateLongIdent (SynLongIdent.Create [ "arr" ; "Add" ]), (SynExpr.createLongIdent [ "arr" ; "Add" ])
SynExpr.CreateParen (SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "mem")) (SynExpr.paren (SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "mem"))),
),
range0 range0
) )
SynExpr.CreateIdentString "arr" SynExpr.createIdent "arr"
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ] SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ]
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.CreateString "arr") [] |> SynBinding.basic [ Ident.create "arr" ] []
] ]
|> SynExpr.createLambda "field" |> SynExpr.createLambda "field"
| IDictionaryType (_keyType, valueType) | IDictionaryType (_keyType, valueType)
@@ -117,46 +99,30 @@ module internal JsonSerializeGenerator =
DebugPointAtInOrTo.Yes range0, DebugPointAtInOrTo.Yes range0,
SeqExprOnly.SeqExprOnly false, SeqExprOnly.SeqExprOnly false,
true, true,
SynPat.CreateParen ( SynPat.paren (
SynPat.CreateLongIdent ( SynPat.identWithArgs
SynLongIdent.CreateString "KeyValue", [ Ident.create "KeyValue" ]
[ (SynArgPats.create [ Ident.create "key" ; Ident.create "value" ])
SynPat.CreateParen (
SynPat.Tuple (
false,
[
SynPat.CreateNamed (Ident.Create "key")
SynPat.CreateNamed (Ident.Create "value")
],
[ range0 ],
range0
)
)
]
)
), ),
SynExpr.CreateIdent (Ident.Create "field"), SynExpr.createIdent "field",
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "ret" ; "Add" ], (SynExpr.createLongIdent [ "ret" ; "Add" ])
SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
SynExpr.CreateApp ( SynExpr.createLongIdent [ "key" ; "ToString" ]
SynExpr.createLongIdent [ "key" ; "ToString" ], |> SynExpr.applyTo (SynExpr.CreateConst ())
SynExpr.CreateConst SynConst.Unit SynExpr.applyFunction (serializeNode valueType) (SynExpr.createIdent "value")
) ]),
SynExpr.CreateApp (serializeNode valueType, SynExpr.CreateIdentString "value")
]
),
range0 range0
) )
SynExpr.CreateIdentString "ret" SynExpr.createIdent "ret"
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.CreateString "ret") [] |> SynBinding.basic [ Ident.create "ret" ] []
] ]
|> SynExpr.createLambda "field" |> SynExpr.createLambda "field"
| _ -> | _ ->
@@ -166,22 +132,27 @@ module internal JsonSerializeGenerator =
| SynType.LongIdent ident -> ident.LongIdent | SynType.LongIdent ident -> ident.LongIdent
| _ -> failwith $"Unrecognised type: %+A{fieldType}" | _ -> 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 /// propertyName is probably a string literal, but it could be a [<Literal>] variable
/// `node.Add ({propertyName}, {toJsonNode})` /// `node.Add ({propertyName}, {toJsonNode})`
let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr = let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
[ [
propertyName 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" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr = let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr =
let propertyNameAttr = let propertyNameAttr =
attrs 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 match propertyNameAttr with
| None -> | None ->
@@ -191,7 +162,7 @@ module internal JsonSerializeGenerator =
if fieldId.idText.Length > 1 then if fieldId.idText.Length > 1 then
sb.Append fieldId.idText.[1..] |> ignore sb.Append fieldId.idText.[1..] |> ignore
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst sb.ToString () |> SynExpr.CreateConst
| Some name -> name.ArgExpr | Some name -> name.ArgExpr
/// `populateNode` will be inserted before we return the `node` variable. /// `populateNode` will be inserted before we return the `node` variable.
@@ -207,67 +178,58 @@ module internal JsonSerializeGenerator =
(populateNode : SynExpr) (populateNode : SynExpr)
: SynModuleDecl : SynModuleDecl
= =
let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node" let xmlDoc = PreXmlDoc.create "Serialize to a JSON node"
let returnInfo = let returnInfo =
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ] SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|> SynType.LongIdent |> SynType.LongIdent
let functionName = Ident.Create "toJsonNode" let functionName = Ident.create "toJsonNode"
let assignments = let assignments =
[ [
populateNode 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.createLet
[ [
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.CreateString "node") [] |> SynBinding.basic [ Ident.create "node" ] []
] ]
let pattern = let pattern =
SynPat.CreateNamed inputArgName SynPat.namedI inputArgName
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName)) |> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName))
if spec.ExtensionMethods then if spec.ExtensionMethods then
let binding = let componentInfo =
SynComponentInfo.createLong typeName
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
let memberDef =
assignments assignments
|> SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ pattern ] |> SynBinding.basic [ functionName ] [ pattern ]
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> SynBinding.makeStaticMember |> SynMemberDefn.staticMember
let mem = SynMemberDefn.Member (binding, range0)
let containingType = let containingType =
SynTypeDefn.SynTypeDefn ( SynTypeDefnRepr.augmentation ()
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"), |> SynTypeDefn.create componentInfo
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0), |> SynTypeDefn.withMemberDefns [ memberDef ]
[ mem ],
None,
range0,
{
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
EqualsRange = None
WithKeyword = None
}
)
SynModuleDecl.Types ([ containingType ], range0) SynModuleDecl.Types ([ containingType ], range0)
else else
let binding = assignments
assignments |> SynBinding.basic [ functionName ] [ pattern ]
|> SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ pattern ] |> SynBinding.withReturnAnnotation returnInfo
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withXmlDoc xmlDoc |> SynModuleDecl.createLet
SynModuleDecl.CreateLet [ binding ]
let recordModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) = 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 let fields = fields |> List.map SynField.extractWithIdent
fields fields
@@ -275,25 +237,25 @@ module internal JsonSerializeGenerator =
let propertyName = getPropertyName fieldData.Ident fieldData.Attrs let propertyName = getPropertyName fieldData.Ident fieldData.Attrs
createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type
) )
|> SynExpr.CreateSequential |> SynExpr.sequential
|> fun expr -> SynExpr.Do (expr, range0) |> fun expr -> SynExpr.Do (expr, range0)
|> scaffolding spec typeName inputArg |> scaffolding spec typeName inputArg
let unionModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (cases : SynUnionCase list) = 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 let fields = cases |> List.map SynUnionCase.extract
fields fields
|> List.map (fun unionCase -> |> List.map (fun unionCase ->
let propertyName = getPropertyName unionCase.Ident unionCase.Attrs 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 argPats = SynArgPats.create caseNames
let pattern = let pattern =
SynPat.LongIdent ( SynPat.LongIdent (
SynLongIdent.CreateFromLongIdent (typeName @ [ unionCase.Ident ]), SynLongIdent.create (typeName @ [ unionCase.Ident ]),
None, None,
None, None,
argPats, argPats,
@@ -303,26 +265,18 @@ module internal JsonSerializeGenerator =
let typeLine = let typeLine =
[ [
SynExpr.CreateConstString "type" SynExpr.CreateConst "type"
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ], (SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ])
propertyName propertyName
)
] ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
let dataNode = let dataNode =
SynBinding.Let ( SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
pattern = SynPat.CreateNamed (Ident.Create "dataNode"), |> SynExpr.applyTo (SynExpr.CreateConst ())
expr = |> SynBinding.basic [ Ident.create "dataNode" ] []
SynExpr.CreateApp (
SynExpr.CreateLongIdent (
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
),
SynExpr.CreateConst SynConst.Unit
)
)
let dataBindings = let dataBindings =
(unionCase.Fields, caseNames) (unionCase.Fields, caseNames)
@@ -331,20 +285,20 @@ module internal JsonSerializeGenerator =
let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs
let node = let node =
SynExpr.CreateApp (serializeNode fieldData.Type, SynExpr.CreateIdent caseName) SynExpr.applyFunction (serializeNode fieldData.Type) (SynExpr.createIdent' caseName)
[ propertyName ; node ] [ propertyName ; node ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ])
) )
let assignToNode = let assignToNode =
[ SynExpr.CreateConstString "data" ; SynExpr.CreateIdentString "dataNode" ] [ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
let dataNode = let dataNode =
SynExpr.CreateSequential (dataBindings @ [ assignToNode ]) SynExpr.sequential (dataBindings @ [ assignToNode ])
|> SynExpr.createLet [ dataNode ] |> SynExpr.createLet [ dataNode ]
let action = let action =
@@ -353,11 +307,11 @@ module internal JsonSerializeGenerator =
if not dataBindings.IsEmpty then if not dataBindings.IsEmpty then
yield dataNode 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 |> scaffolding spec typeName inputArg
let createModule let createModule
@@ -374,12 +328,9 @@ module internal JsonSerializeGenerator =
let attributes = let attributes =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ SynAttributeList.Create SynAttribute.autoOpen ] [ SynAttribute.autoOpen ]
else else
[ [ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
SynAttributeList.Create SynAttribute.compilationRepresentation
]
let xmlDoc = let xmlDoc =
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "." let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
@@ -390,8 +341,8 @@ module internal JsonSerializeGenerator =
else else
"methods" "methods"
$" Module containing JSON serializing %s{description} for the %s{fullyQualified} type" $"Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|> PreXmlDoc.Create |> PreXmlDoc.create
let moduleName = let moduleName =
if spec.ExtensionMethods then if spec.ExtensionMethods then
@@ -402,14 +353,16 @@ module internal JsonSerializeGenerator =
List.last ident List.last ident
|> fun i -> i.idText |> fun i -> i.idText
|> fun s -> s + "JsonSerializeExtension" |> fun s -> s + "JsonSerializeExtension"
|> Ident.Create |> Ident.create
List.take (List.length ident - 1) ident @ [ expanded ] List.take (List.length ident - 1) ident @ [ expanded ]
else else
ident ident
let info = let info =
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc) SynComponentInfo.createLong moduleName
|> SynComponentInfo.addAttributes attributes
|> SynComponentInfo.withDocString xmlDoc
let decls = let decls =
match synTypeDefnRepr with match synTypeDefnRepr with
@@ -419,12 +372,13 @@ module internal JsonSerializeGenerator =
[ unionModule spec ident unionFields ] [ unionModule spec ident unionFields ]
| _ -> failwithf "Only record types currently supported." | _ -> 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 ( open Myriad.Core
namespaceId,
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
)
/// Myriad generator that provides a method (possibly an extension method) for a record type, /// Myriad generator that provides a method (possibly an extension method) for a record type,
/// containing a JSON serialization function. /// containing a JSON serialization function.

View 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))))

View File

@@ -1,14 +1,11 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml open Fantomas.FCS.Xml
open Myriad.Core
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal RemoveOptionsGenerator = module internal RemoveOptionsGenerator =
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core.Ast
let private removeOption (s : SynField) : SynField = let private removeOption (s : SynField) : SynField =
let (SynField.SynField (synAttributeLists, let (SynField.SynField (synAttributeLists,
@@ -47,7 +44,7 @@ module internal RemoveOptionsGenerator =
(fields : SynField list) (fields : SynField list)
= =
let fields : SynField list = fields |> List.map removeOption let fields : SynField list = fields |> List.map removeOption
let name = Ident.Create "Short" let name = Ident.create "Short"
let record = let record =
{ {
@@ -64,20 +61,10 @@ module internal RemoveOptionsGenerator =
SynModuleDecl.Types ([ typeDecl ], range0) SynModuleDecl.Types ([ typeDecl ], range0)
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynFieldData<Ident> list) = 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 = let inputArg = Ident.create "input"
SynBindingReturnInfo.Create (SynType.LongIdent (SynLongIdent.CreateFromLongIdent withOptionsType)) let functionName = Ident.create "shorten"
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 body = let body =
fields fields
@@ -93,65 +80,31 @@ module internal RemoveOptionsGenerator =
let body = let body =
match fieldData.Type with match fieldData.Type with
| OptionType _ -> | OptionType _ ->
SynExpr.CreateApp ( accessor
SynExpr.CreateAppInfix ( |> SynExpr.pipeThroughFunction (
SynExpr.LongIdent ( SynExpr.applyFunction
false, (SynExpr.createLongIdent [ "Option" ; "defaultWith" ])
SynLongIdent.SynLongIdent ( (SynExpr.createLongIdent' (
[ Ident.Create "op_PipeRight" ], withoutOptionsType
[], @ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ]
[ 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 | _ -> accessor
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true), Some body (SynLongIdent.createI fieldData.Ident, true), Some body
) )
|> AstHelper.instantiateRecord |> AstHelper.instantiateRecord
let pattern = SynBinding.basic
SynPat.LongIdent ( [ functionName ]
SynLongIdent.CreateFromLongIdent [ functionName ], [
None, SynPat.named inputArg.idText
None, |> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create withoutOptionsType))
SynArgPats.Pats ]
[ body
SynPat.CreateTyped ( |> SynBinding.withXmlDoc xmlDoc
SynPat.CreateNamed inputArg, |> SynBinding.withReturnAnnotation (SynType.LongIdent (SynLongIdent.create withOptionsType))
SynType.LongIdent (SynLongIdent.CreateFromLongIdent withoutOptionsType) |> SynModuleDecl.createLet
)
|> 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 ]
let createRecordModule (namespaceId : LongIdent) (typeDefn : SynTypeDefn) = let createRecordModule (namespaceId : LongIdent) (typeDefn : SynTypeDefn) =
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) = let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
@@ -167,30 +120,29 @@ module internal RemoveOptionsGenerator =
let decls = let decls =
[ [
createType (Some doc) accessibility typeParams fields createType (Some doc) accessibility typeParams fields
createMaker [ Ident.Create "Short" ] recordId fieldData createMaker [ Ident.create "Short" ] recordId fieldData
]
let attributes =
[
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
SynAttributeList.Create SynAttribute.compilationRepresentation
] ]
let xmlDoc = let xmlDoc =
recordId recordId
|> Seq.map (fun i -> i.idText) |> Seq.map (fun i -> i.idText)
|> String.concat "." |> String.concat "."
|> sprintf " Module containing an option-truncated version of the %s type" |> sprintf "Module containing an option-truncated version of the %s type"
|> PreXmlDoc.Create |> PreXmlDoc.create
let info = 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) SynModuleDecl.nestedModule info decls
|> List.singleton
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ]) |> SynModuleOrNamespace.createNamespace namespaceId
| _ -> failwithf "Not a record type" | _ -> failwithf "Not a record type"
open Myriad.Core
/// Myriad generator that stamps out a record with option types stripped /// Myriad generator that stamps out a record with option types stripped
/// from the fields at the top level. /// from the fields at the top level.
[<MyriadGenerator("remove-options")>] [<MyriadGenerator("remove-options")>]

View 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)
}
*)

View File

@@ -3,12 +3,14 @@ namespace WoofWare.Myriad.Plugins
open System open System
open System.Text open System.Text
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Myriad.Core open Fantomas.FCS.Text.Range
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal Ident = module internal Ident =
let inline create (s : string) = Ident (s, range0)
let lowerFirstLetter (x : Ident) : Ident = let lowerFirstLetter (x : Ident) : Ident =
let result = StringBuilder x.idText.Length let result = StringBuilder x.idText.Length
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
result.Append x.idText.[1..] |> ignore result.Append x.idText.[1..] |> ignore
Ident.Create ((result : StringBuilder).ToString ()) create ((result : StringBuilder).ToString ())

View 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)

View File

@@ -1,18 +1,16 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynArgPats = module internal SynArgPats =
let create (caseNames : Ident list) : SynArgPats = let create (caseNames : Ident list) : SynArgPats =
if caseNames.IsEmpty then match caseNames.Length with
SynArgPats.Pats [] | 0 -> SynArgPats.Pats []
else | 1 -> [ SynPat.named caseNames.[0].idText ] |> SynArgPats.Pats
| _ ->
caseNames caseNames
|> List.map (fun ident -> SynPat.Named (SynIdent.SynIdent (ident, None), false, None, range0)) |> List.map (fun i -> SynPat.named i.idText)
|> fun ps -> SynPat.Tuple (false, ps, List.replicate (ps.Length - 1) range0, range0) |> SynPat.tuple
|> fun p -> SynPat.Paren (p, range0) |> List.singleton
|> List.singleton |> SynArgPats.Pats
|> SynArgPats.Pats

View File

@@ -2,20 +2,25 @@ namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynAttribute = module internal SynAttribute =
let internal compilationRepresentation : SynAttribute = let internal compilationRepresentation : SynAttribute =
{ {
TypeName = SynLongIdent.CreateString "CompilationRepresentation" TypeName = SynLongIdent.createS "CompilationRepresentation"
ArgExpr = ArgExpr =
SynExpr.CreateLongIdent ( [ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
false, |> SynExpr.createLongIdent
SynLongIdent.Create [ "CompilationRepresentationFlags" ; "ModuleSuffix" ], |> SynExpr.paren
None Target = None
) AppliesToGetterAndSetter = false
|> SynExpr.CreateParen Range = range0
}
let internal requireQualifiedAccess : SynAttribute =
{
TypeName = SynLongIdent.createS "RequireQualifiedAccess"
ArgExpr = SynExpr.CreateConst ()
Target = None Target = None
AppliesToGetterAndSetter = false AppliesToGetterAndSetter = false
Range = range0 Range = range0
@@ -23,8 +28,8 @@ module internal SynAttribute =
let internal autoOpen : SynAttribute = let internal autoOpen : SynAttribute =
{ {
TypeName = SynLongIdent.CreateString "AutoOpen" TypeName = SynLongIdent.createS "AutoOpen"
ArgExpr = SynExpr.CreateConst SynConst.Unit ArgExpr = SynExpr.CreateConst ()
Target = None Target = None
AppliesToGetterAndSetter = false AppliesToGetterAndSetter = false
Range = range0 Range = range0

View File

@@ -16,14 +16,18 @@ module internal SynBinding =
let rec private getName (pat : SynPat) : Ident option = let rec private getName (pat : SynPat) : Ident option =
match stripParen pat with match stripParen pat with
| SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name | SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name
| SynPat.Wild _ -> None
| SynPat.Typed (pat, _, _) -> getName pat | SynPat.Typed (pat, _, _) -> getName pat
| SynPat.Const _ -> None
| SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) -> | SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) ->
match longIdent with match longIdent with
| [ x ] -> Some x | [ x ] -> Some x
| _ -> failwithf "got long ident %O ; can only get the name of a long ident with one component" longIdent | _ -> 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) = let triviaZero (isMember : bool) =
{ {
@@ -36,10 +40,10 @@ module internal SynBinding =
SynLeadingKeyword.Let range0 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 = let valInfo : SynValInfo =
args args
|> List.map (fun pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ]) |> List.map getArgInfo
|> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None)) |> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None))
SynBinding.SynBinding ( SynBinding.SynBinding (
@@ -50,7 +54,7 @@ module internal SynBinding =
[], [],
PreXmlDoc.Empty, PreXmlDoc.Empty,
SynValData.SynValData (None, valInfo, None), SynValData.SynValData (None, valInfo, None),
SynPat.LongIdent (name, None, None, SynArgPats.Pats args, None, range0), SynPat.identWithArgs name (SynArgPats.Pats args),
None, None,
body, body,
range0, range0,
@@ -103,7 +107,7 @@ module internal SynBinding =
trivia trivia
) )
let makeInline (binding : SynBinding) : SynBinding = let inline makeInline (binding : SynBinding) : SynBinding =
match binding with match binding with
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) -> | SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
SynBinding ( 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 makeStaticMember (binding : SynBinding) : SynBinding =
let memberFlags = let memberFlags =
{ {

View 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)

View File

@@ -3,14 +3,18 @@ namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia open Fantomas.FCS.SyntaxTrivia
open Myriad.Core open Myriad.Core
open Myriad.Core.Ast
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
type internal CompExprBinding = [<AutoOpen>]
| LetBang of varName : string * rhs : SynExpr module internal SynExprExtensions =
| Let of varName : string * rhs : SynExpr type SynExpr with
| Use of varName : string * rhs : SynExpr static member CreateConst (s : string) : SynExpr =
| Do of body : 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>] [<RequireQualifiedAccess>]
module internal SynExpr = module internal SynExpr =
@@ -19,20 +23,11 @@ module internal SynExpr =
let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x) let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
/// {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} /// {expr} |> {func}
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr = let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
SynExpr.CreateAppInfix ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.pipe, expr)
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_PipeRight" ],
[],
[ Some (IdentTrivia.OriginalNotation "|>") ]
)
),
expr
)
|> applyTo func |> applyTo func
/// if {cond} then {trueBranch} else {falseBranch} /// if {cond} then {trueBranch} else {falseBranch}
@@ -58,7 +53,7 @@ module internal SynExpr =
/// try {body} with | {exc} as exc -> {handler} /// try {body} with | {exc} as exc -> {handler}
let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr = let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr =
let clause = 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 ( SynExpr.TryWith (
body, body,
@@ -76,17 +71,7 @@ module internal SynExpr =
/// {a} = {b} /// {a} = {b}
let equals (a : SynExpr) (b : SynExpr) = let equals (a : SynExpr) (b : SynExpr) =
SynExpr.CreateAppInfix ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.eq, a) |> applyTo b
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
Ident.CreateLong "op_Equality",
[],
[ Some (IdentTrivia.OriginalNotation "=") ]
)
),
a
)
|> applyTo b
/// {a} + {b} /// {a} + {b}
let plus (a : SynExpr) (b : SynExpr) = let plus (a : SynExpr) (b : SynExpr) =
@@ -112,46 +97,49 @@ module internal SynExpr =
SynExpr.DotGet ( SynExpr.DotGet (
obj, obj,
range0, range0,
SynLongIdent.SynLongIdent (id = [ Ident.Create meth ], dotRanges = [], trivia = [ None ]), SynLongIdent.SynLongIdent (id = [ Ident.create meth ], dotRanges = [], trivia = [ None ]),
range0 range0
) )
|> applyTo arg |> applyTo arg
/// {obj}.{meth}() /// {obj}.{meth}()
let callMethod (meth : string) (obj : SynExpr) : SynExpr = 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 = let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr =
SynExpr.TypeApp ( SynExpr.TypeApp (
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0), SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
range0, range0,
[ SynType.LongIdent (SynLongIdent.CreateFromLongIdent ty) ], [ SynType.LongIdent (SynLongIdent.create ty) ],
[], [],
Some range0, Some range0,
range0, range0,
range0 range0
) )
|> applyTo (SynExpr.CreateConst SynConst.Unit) |> applyTo (SynExpr.CreateConst ())
/// {obj}.{meth}<ty>() /// {obj}.{meth}<ty>()
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr = let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
SynExpr.TypeApp ( SynExpr.TypeApp (
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0), SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
range0, range0,
[ SynType.CreateLongIdent ty ], [ SynType.createLongIdent' [ ty ] ],
[], [],
Some range0, Some range0,
range0, 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) SynExpr.DotIndexedGet (obj, property, range0, range0)
let inline paren (e : SynExpr) : SynExpr =
SynExpr.Paren (e, range0, Some range0, range0)
/// (fun {varName} -> {body}) /// (fun {varName} -> {body})
let createLambda (varName : string) (body : SynExpr) : SynExpr = let createLambda (varName : string) (body : SynExpr) : SynExpr =
let parsedDataPat = [ SynPat.CreateNamed (Ident.Create varName) ] let parsedDataPat = [ SynPat.named varName ]
SynExpr.Lambda ( SynExpr.Lambda (
false, false,
@@ -164,39 +152,82 @@ module internal SynExpr =
ArrowRange = Some range0 ArrowRange = Some range0
} }
) )
|> SynExpr.CreateParen |> paren
let reraise : SynExpr = let createThunk (body : SynExpr) : SynExpr =
SynExpr.CreateIdent (Ident.Create "reraise") SynExpr.Lambda (
|> applyTo (SynExpr.CreateConst SynConst.Unit) 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) /// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
let startAsTask (ct : SynLongIdent) (body : SynExpr) = let startAsTask (ct : Ident) (body : SynExpr) =
let lambda = let lambda =
[ [
SynExpr.CreateLongIdent (SynLongIdent.CreateString "a") createIdent "a"
equals equals
(SynExpr.LongIdent (true, SynLongIdent.CreateString "cancellationToken", None, range0)) (SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
(SynExpr.CreateLongIdent ct) (createIdent' ct)
] ]
|> SynExpr.CreateParenedTuple |> tuple
|> applyFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "StartAsTask" ])) |> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ])
|> createLambda "a" |> createLambda "a"
pipeThroughFunction lambda body pipeThroughFunction lambda body
let createLongIdent (ident : string list) : SynExpr = let inline createLet (bindings : SynBinding list) (body : SynExpr) : 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 =
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty) 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} } /// {compExpr} { {lets} ; return {ret} }
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr = let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
@@ -211,7 +242,7 @@ module internal SynExpr =
DebugPointAtBinding.Yes range0, DebugPointAtBinding.Yes range0,
false, false,
true, true,
SynPat.CreateNamed (Ident.Create lhs), SynPat.named lhs,
rhs, rhs,
[], [],
state, state,
@@ -220,90 +251,50 @@ module internal SynExpr =
EqualsRange = Some range0 EqualsRange = Some range0
} }
) )
| Let (lhs, rhs) -> | Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state
createLet [ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ] state
| Use (lhs, rhs) -> | Use (lhs, rhs) ->
SynExpr.LetOrUse ( SynExpr.LetOrUse (
false, false,
true, true,
[ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ], [ SynBinding.basic [ Ident.create lhs ] [] rhs ],
state, state,
range0, range0,
{ {
SynExprLetOrUseTrivia.InKeyword = None SynExprLetOrUseTrivia.InKeyword = None
} }
) )
| Do body -> SynExpr.CreateSequential [ SynExpr.Do (body, range0) ; state ] | Do body -> sequential [ SynExpr.Do (body, range0) ; state ]
) )
SynExpr.CreateApp ( applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0))
SynExpr.CreateIdent (Ident.Create compExpr),
SynExpr.ComputationExpr (false, contents, range0)
)
/// {expr} |> Async.AwaitTask /// {expr} |> Async.AwaitTask
let awaitTask (expr : SynExpr) : SynExpr = let awaitTask (expr : SynExpr) : SynExpr =
expr expr |> pipeThroughFunction (createLongIdent [ "Async" ; "AwaitTask" ])
|> pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "AwaitTask" ]))
/// {ident}.ToString () /// {ident}.ToString ()
/// with special casing for some types like DateTime /// with special casing for some types like DateTime
let toString (ty : SynType) (ident : SynExpr) = let toString (ty : SynType) (ident : SynExpr) =
match ty with match ty with
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-dd") | DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-dd")
| DateTime -> | DateTime -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-ddTHH:mm:ss")
ident
|> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-ddTHH:mm:ss")
| _ -> callMethod "ToString" ident | _ -> callMethod "ToString" ident
let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0) let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0)
/// {ident} - {rhs} /// {ident} - {rhs}
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr = let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
SynExpr.CreateApp ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.sub, SynExpr.CreateLongIdent ident)
SynExpr.CreateAppInfix ( |> applyTo rhs
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_Subtraction" ],
[],
[ Some (IdentTrivia.OriginalNotation "-") ]
)
),
SynExpr.CreateLongIdent ident
),
rhs
)
/// {ident} - {n} /// {ident} - {n}
let minusN (ident : SynLongIdent) (n : int) : SynExpr = let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n)
minus ident (SynExpr.CreateConst (SynConst.Int32 n))
/// {y} > {x} /// {y} > {x}
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr = let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
SynExpr.CreateApp ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.ge, y) |> applyTo x
SynExpr.CreateAppInfix (
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_GreaterThan" ],
[],
[ Some (IdentTrivia.OriginalNotation ">") ]
)
),
y
),
x
)
/// {y} >= {x} /// {y} >= {x}
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr = let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
SynExpr.CreateAppInfix ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.geq, y)
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_GreaterThanOrEqual" ],
[],
[ Some (IdentTrivia.OriginalNotation ">=") ]
)
),
y
)
|> applyTo x |> applyTo x

View File

@@ -1,6 +1,9 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Text.Range
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
type internal SynFieldData<'Ident> = type internal SynFieldData<'Ident> =
{ {
@@ -37,3 +40,30 @@ module internal SynField =
| None -> failwith "expected field identifier to have a value, but it did not" | None -> failwith "expected field identifier to have a value, but it did not"
| Some i -> i | 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)

View 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

View 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)

View 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)

View 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
}
)

View 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
}
)

View File

@@ -5,6 +5,31 @@ open Fantomas.FCS.Text.Range
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynPat = module internal SynPat =
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
let annotateType (ty : SynType) (pat : SynPat) = let inline annotateTypeNoParen (ty : SynType) (pat : SynPat) = SynPat.Typed (pat, ty, range0)
SynPat.Paren (SynPat.Typed (pat, ty, range0), 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

View File

@@ -1,6 +1,7 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynType = module internal SynType =
@@ -8,3 +9,231 @@ module internal SynType =
match ty with match ty with
| SynType.Paren (ty, _) -> stripOptionalParen ty | SynType.Paren (ty, _) -> stripOptionalParen ty
| ty -> 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

View 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)

View 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)

View File

@@ -25,17 +25,28 @@
<ItemGroup> <ItemGroup>
<Compile Include="List.fs"/> <Compile Include="List.fs"/>
<Compile Include="Ident.fs" /> <Compile Include="Primitives.fs" />
<Compile Include="AstHelper.fs"/> <Compile Include="SynExpr\PreXmlDoc.fs" />
<Compile Include="SynExpr\Ident.fs" />
<Compile Include="SynExpr\SynLongIdent.fs" />
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" /> <Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
<Compile Include="SynExpr\SynPat.fs" />
<Compile Include="SynExpr\SynBinding.fs" /> <Compile Include="SynExpr\SynBinding.fs" />
<Compile Include="SynExpr\SynExpr.fs" />
<Compile Include="SynExpr\SynType.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\SynArgPats.fs" />
<Compile Include="SynExpr\SynField.fs" /> <Compile Include="SynExpr\SynField.fs" />
<Compile Include="SynExpr\SynUnionCase.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="RemoveOptionsGenerator.fs"/>
<Compile Include="InterfaceMockGenerator.fs"/> <Compile Include="InterfaceMockGenerator.fs"/>
<Compile Include="JsonSerializeGenerator.fs"/> <Compile Include="JsonSerializeGenerator.fs"/>

View File

@@ -7,6 +7,7 @@
":/", ":/",
":^WoofWare.Myriad.Plugins.Test/", ":^WoofWare.Myriad.Plugins.Test/",
":^WoofWare.Myriad.Plugins.Attributes/Test/", ":^WoofWare.Myriad.Plugins.Attributes/Test/",
":^/.github/" ":^/.github/",
":^/CHANGELOG.md"
] ]
} }

View File

@@ -45,44 +45,19 @@
packages = { 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; 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; 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 { default = pkgs.buildDotnetModule {
pname = pname; inherit pname version dotnet-sdk dotnet-runtime;
name = "WoofWare.Myriad.Plugins"; name = "WoofWare.Myriad.Plugins";
version = version;
src = ./.; src = ./.;
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj"; 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; doCheck = true;
dotnet-sdk = dotnet-sdk;
dotnet-runtime = dotnet-runtime;
}; };
}; };
devShell = pkgs.mkShell { devShell = pkgs.mkShell {
buildInputs = with pkgs; [ buildInputs = [dotnet-sdk];
(with dotnetCorePackages;
combinePackages [
dotnet-sdk_8
dotnetPackages.Nuget
])
];
packages = [ packages = [
pkgs.alejandra pkgs.alejandra
pkgs.nodePackages.markdown-link-check pkgs.nodePackages.markdown-link-check

View File

@@ -1,21 +1,16 @@
# This file was automatically generated by passthru.fetch-deps. # 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}: [
(fetchNuGet {
pname = "fsharp-analyzers";
version = "0.26.0";
sha256 = "sha256-60Bl36LOb/zVNdH2SBSuQ5O41lP9dKTNZbs5vvYs+3U=";
})
(fetchNuGet {
pname = "fantomas";
version = "6.3.4";
sha256 = "sha256-1aWqZynBkQoznenGoP0sbf1PcUXAbcHiWyECuv89xa0=";
})
(fetchNuGet { (fetchNuGet {
pname = "ApiSurface"; pname = "ApiSurface";
version = "4.0.40"; version = "4.0.40";
sha256 = "1c9z0b6minlripwrjmv4yd5w8zj4lcpak4x41izh7ygx8kgmbvx0"; sha256 = "1c9z0b6minlripwrjmv4yd5w8zj4lcpak4x41izh7ygx8kgmbvx0";
}) })
(fetchNuGet {
pname = "fantomas";
version = "6.3.7";
sha256 = "1z1a5bw7vwz6g8nvfgkvx66jnm4hmvn62vbyq0as60nw0jlvaidl";
})
(fetchNuGet { (fetchNuGet {
pname = "Fantomas.Core"; pname = "Fantomas.Core";
version = "6.1.1"; version = "6.1.1";
@@ -31,6 +26,11 @@
version = "2.16.6"; version = "2.16.6";
sha256 = "176rwky6b5rk8dzldiz4068p7m9c5y9ygzbhadrs14jkl94pc56n"; sha256 = "176rwky6b5rk8dzldiz4068p7m9c5y9ygzbhadrs14jkl94pc56n";
}) })
(fetchNuGet {
pname = "fsharp-analyzers";
version = "0.26.0";
sha256 = "0xgv5kvbwfdvcp6s8x7xagbbi4s3mqa4ixni6pazqvyflbgnah7b";
})
(fetchNuGet { (fetchNuGet {
pname = "FSharp.Core"; pname = "FSharp.Core";
version = "4.3.4"; version = "4.3.4";
@@ -56,61 +56,26 @@
version = "6.0.26"; version = "6.0.26";
sha256 = "1d8nkz24vsm0iy2xm8y5ak2q1w1p99dxyz0y26acs6sfk2na0vm6"; sha256 = "1d8nkz24vsm0iy2xm8y5ak2q1w1p99dxyz0y26acs6sfk2na0vm6";
}) })
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Ref";
version = "8.0.1";
sha256 = "0yaaiqq7mi6sclyrb1v0fyncanbx0ifmnnhv9whynqj8439jsdwh";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64"; pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
version = "6.0.26"; version = "6.0.26";
sha256 = "1za8lc52m4z54d68wd64c2nhzy05g3gx171k5cdlx73fbymiys9z"; sha256 = "1za8lc52m4z54d68wd64c2nhzy05g3gx171k5cdlx73fbymiys9z";
}) })
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
version = "8.0.1";
sha256 = "0dsdgqg7566qximmjfza4x9if3icy4kskq698ddj5apdia88h2mw";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64"; pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
version = "6.0.26"; version = "6.0.26";
sha256 = "1zpbmz6z8758gwywzg0bac8kx9x39sxxc9j4a4r2jl74l9ssw4vm"; sha256 = "1zpbmz6z8758gwywzg0bac8kx9x39sxxc9j4a4r2jl74l9ssw4vm";
}) })
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
version = "8.0.1";
sha256 = "1gjz379y61ag9whi78qxx09bwkwcznkx2mzypgycibxk61g11da1";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64"; pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
version = "6.0.26"; version = "6.0.26";
sha256 = "1i8ydlwjzk7j0mzvn0rpljxfp1h50zwaqalnyvfxai1fwgigzgw5"; sha256 = "1i8ydlwjzk7j0mzvn0rpljxfp1h50zwaqalnyvfxai1fwgigzgw5";
}) })
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
version = "8.0.1";
sha256 = "0w3mrs4zdl9mfanl1j81759xwwrzmicsjxn6yfxv5yrxbxzq695n";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64"; pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
version = "6.0.26"; version = "6.0.26";
sha256 = "02src68hd3213sd1a2ms1my7i92knfmdxclvv90il9cky2zsq8kw"; 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 { (fetchNuGet {
pname = "Microsoft.Build.Tasks.Git"; pname = "Microsoft.Build.Tasks.Git";
version = "8.0.0"; version = "8.0.0";
@@ -131,111 +96,46 @@
version = "6.0.26"; version = "6.0.26";
sha256 = "19y6c6v20bgf7x7rrh4rx9y7s5fy8vp5m4j9b6gi1wp4rpb5mza4"; sha256 = "19y6c6v20bgf7x7rrh4rx9y7s5fy8vp5m4j9b6gi1wp4rpb5mza4";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.linux-arm64";
version = "8.0.1";
sha256 = "0dhpdlcdz7adcfh9w01fc867051m35fqaxnvj3fqvqhgcm2n3143";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Host.linux-x64"; pname = "Microsoft.NETCore.App.Host.linux-x64";
version = "6.0.26"; version = "6.0.26";
sha256 = "0p7hhidaa3mnyiwnsijwy8578v843x8hh99255s69qwwyld6falv"; sha256 = "0p7hhidaa3mnyiwnsijwy8578v843x8hh99255s69qwwyld6falv";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.linux-x64";
version = "8.0.1";
sha256 = "1aw6mc7zcmzs1grxz2wa9cw9kfj8pz7zpj417xnp1a9n4ix1bxgr";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Host.osx-arm64"; pname = "Microsoft.NETCore.App.Host.osx-arm64";
version = "6.0.26"; version = "6.0.26";
sha256 = "1mq11xsv9g1vsasp6k80y7xlvwi9hrpk5dgm773fvy8538s01gfv"; sha256 = "1mq11xsv9g1vsasp6k80y7xlvwi9hrpk5dgm773fvy8538s01gfv";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.osx-arm64";
version = "8.0.1";
sha256 = "1dzg3prng9zfdzz7gcgywjdbwzhwm85j89z0jahynxx4q2dra4b9";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Host.osx-x64"; pname = "Microsoft.NETCore.App.Host.osx-x64";
version = "6.0.26"; version = "6.0.26";
sha256 = "1chac9b4424ihrrnlzvc7qz6j4ymfjyv4kzyazzzw19yhymdkh2s"; 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 { (fetchNuGet {
pname = "Microsoft.NETCore.App.Ref"; pname = "Microsoft.NETCore.App.Ref";
version = "6.0.26"; version = "6.0.26";
sha256 = "12gb52dhg5h9hgnyqh1zgj2w46paxv2pfh33pphl9ajhrdr7hlsb"; sha256 = "12gb52dhg5h9hgnyqh1zgj2w46paxv2pfh33pphl9ajhrdr7hlsb";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Ref";
version = "8.0.1";
sha256 = "02r4jg4ha0qksix9v6s3cpmvavmz54gkawkxy9bvknw5ynxhhl1l";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.linux-arm64"; pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
version = "6.0.26"; version = "6.0.26";
sha256 = "164hfrwqz5dxcbb441lridk4mzcqmarb0b7ckgvqhsvpawyjw88v"; sha256 = "164hfrwqz5dxcbb441lridk4mzcqmarb0b7ckgvqhsvpawyjw88v";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
version = "8.0.1";
sha256 = "0353whnjgz3sqhzsfrviad3a3db4pk7hl7m4wwppv5mqdg9i9ri5";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.linux-x64"; pname = "Microsoft.NETCore.App.Runtime.linux-x64";
version = "6.0.26"; version = "6.0.26";
sha256 = "0islayddpnflviqpbq4djc4f3v9nhsa2y76k5x6il3csq5vdw2hq"; sha256 = "0islayddpnflviqpbq4djc4f3v9nhsa2y76k5x6il3csq5vdw2hq";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
version = "8.0.1";
sha256 = "1g5b30f4l8a1zjjr3b8pk9mcqxkxqwa86362f84646xaj4iw3a4d";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.osx-arm64"; pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
version = "6.0.26"; version = "6.0.26";
sha256 = "1acn5zw1pxzmcg3c0pbf9hal36fbdh9mvbsiwra7simrk7hzqpdc"; sha256 = "1acn5zw1pxzmcg3c0pbf9hal36fbdh9mvbsiwra7simrk7hzqpdc";
}) })
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
version = "8.0.1";
sha256 = "0cdrpdaq5sl3602anfx1p0z0ncx2sjjvl6mgsd6y38g47n7f95jc";
})
(fetchNuGet { (fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.osx-x64"; pname = "Microsoft.NETCore.App.Runtime.osx-x64";
version = "6.0.26"; version = "6.0.26";
sha256 = "00f9l9dkdz0zv5csaw8fkm6s8ckrj5n9k3ygz12daa22l3bcn6ii"; 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 { (fetchNuGet {
pname = "Microsoft.NETCore.Platforms"; pname = "Microsoft.NETCore.Platforms";
version = "1.1.0"; version = "1.1.0";

View File

@@ -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"