mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-05 20:18:43 +00:00
Compare commits
17 Commits
WoofWare.M
...
WoofWare.M
Author | SHA1 | Date | |
---|---|---|---|
|
b9ba07a8a7 | ||
|
e80ed51498 | ||
|
61b07ad802 | ||
|
59369bcb94 | ||
|
072169e4e3 | ||
|
91136a25ab | ||
|
c51038448a | ||
|
09780efb07 | ||
|
f562271c12 | ||
|
e3081c3136 | ||
|
232d2ba5ec | ||
|
f7458f521e | ||
|
bfc25a672b | ||
|
af7fcb3028 | ||
|
91853b1fff | ||
|
1144e93c1c | ||
|
d899d77ae2 |
@@ -3,13 +3,13 @@
|
|||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"fantomas": {
|
"fantomas": {
|
||||||
"version": "6.3.0-alpha-007",
|
"version": "6.3.4",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fantomas"
|
"fantomas"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fsharp-analyzers": {
|
"fsharp-analyzers": {
|
||||||
"version": "0.25.0",
|
"version": "0.26.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fsharp-analyzers"
|
"fsharp-analyzers"
|
||||||
]
|
]
|
||||||
|
18
.github/workflows/dotnet.yaml
vendored
18
.github/workflows/dotnet.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -79,7 +79,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -92,7 +92,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -105,7 +105,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -132,7 +132,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -188,7 +188,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
|
@@ -129,24 +129,230 @@ module ToGetExtensionMethodJsonParseExtension =
|
|||||||
|
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : ToGetExtensionMethod =
|
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : ToGetExtensionMethod =
|
||||||
let Sailor =
|
let Whiskey = System.Numerics.BigInteger.Parse (node.["whiskey"].ToJsonString ())
|
||||||
(match node.["sailor"] with
|
|
||||||
|
let Victor =
|
||||||
|
(match node.["victor"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
sprintf "Required key '%s' not found on JSON object" ("sailor")
|
sprintf "Required key '%s' not found on JSON object" ("victor")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Char> ()
|
||||||
|
|
||||||
|
let Uniform =
|
||||||
|
(match node.["uniform"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("uniform")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Decimal> ()
|
||||||
|
|
||||||
|
let Tango =
|
||||||
|
(match node.["tango"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("tango")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.SByte> ()
|
||||||
|
|
||||||
|
let Quebec =
|
||||||
|
(match node.["quebec"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("quebec")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Byte> ()
|
||||||
|
|
||||||
|
let Papa =
|
||||||
|
(match node.["papa"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("papa")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Byte> ()
|
||||||
|
|
||||||
|
let Oscar =
|
||||||
|
(match node.["oscar"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("oscar")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.SByte> ()
|
||||||
|
|
||||||
|
let November =
|
||||||
|
(match node.["november"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("november")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.UInt16> ()
|
||||||
|
|
||||||
|
let Mike =
|
||||||
|
(match node.["mike"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("mike")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Int16> ()
|
||||||
|
|
||||||
|
let Lima =
|
||||||
|
(match node.["lima"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("lima")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.UInt32> ()
|
||||||
|
|
||||||
|
let Kilo =
|
||||||
|
(match node.["kilo"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("kilo")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Int32> ()
|
||||||
|
|
||||||
|
let Juliette =
|
||||||
|
(match node.["juliette"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("juliette")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.UInt32> ()
|
||||||
|
|
||||||
|
let India =
|
||||||
|
(match node.["india"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("india")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<int> ()
|
||||||
|
|
||||||
|
let Hotel =
|
||||||
|
(match node.["hotel"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("hotel")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.UInt64> ()
|
||||||
|
|
||||||
|
let Golf =
|
||||||
|
(match node.["golf"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("golf")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Int64> ()
|
||||||
|
|
||||||
|
let Foxtrot =
|
||||||
|
(match node.["foxtrot"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("foxtrot")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Double> ()
|
||||||
|
|
||||||
|
let Echo =
|
||||||
|
(match node.["echo"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("echo")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Single> ()
|
||||||
|
|
||||||
|
let Delta =
|
||||||
|
(match node.["delta"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("delta")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v)
|
||||||
|
.AsValue()
|
||||||
|
.GetValue<System.Single> ()
|
||||||
|
|
||||||
|
let Charlie =
|
||||||
|
(match node.["charlie"] with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
|
sprintf "Required key '%s' not found on JSON object" ("charlie")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<float> ()
|
.GetValue<float> ()
|
||||||
|
|
||||||
let Soldier =
|
let Bravo =
|
||||||
(match node.["soldier"] with
|
(match node.["bravo"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
sprintf "Required key '%s' not found on JSON object" ("soldier")
|
sprintf "Required key '%s' not found on JSON object" ("bravo")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
@@ -154,24 +360,12 @@ module ToGetExtensionMethodJsonParseExtension =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.Uri
|
|> System.Uri
|
||||||
|
|
||||||
let Tailor =
|
let Alpha =
|
||||||
(match node.["tailor"] with
|
(match node.["alpha"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
sprintf "Required key '%s' not found on JSON object" ("tailor")
|
sprintf "Required key '%s' not found on JSON object" ("alpha")
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
.AsValue()
|
|
||||||
.GetValue<int> ()
|
|
||||||
|
|
||||||
let Tinker =
|
|
||||||
(match node.["tinker"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("tinker")
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
@@ -179,8 +373,25 @@ module ToGetExtensionMethodJsonParseExtension =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Tinker = Tinker
|
Alpha = Alpha
|
||||||
Tailor = Tailor
|
Bravo = Bravo
|
||||||
Soldier = Soldier
|
Charlie = Charlie
|
||||||
Sailor = Sailor
|
Delta = Delta
|
||||||
|
Echo = Echo
|
||||||
|
Foxtrot = Foxtrot
|
||||||
|
Golf = Golf
|
||||||
|
Hotel = Hotel
|
||||||
|
India = India
|
||||||
|
Juliette = Juliette
|
||||||
|
Kilo = Kilo
|
||||||
|
Lima = Lima
|
||||||
|
Mike = Mike
|
||||||
|
November = November
|
||||||
|
Oscar = Oscar
|
||||||
|
Papa = Papa
|
||||||
|
Quebec = Quebec
|
||||||
|
Tango = Tango
|
||||||
|
Uniform = Uniform
|
||||||
|
Victor = Victor
|
||||||
|
Whiskey = Whiskey
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -25,10 +26,11 @@ type internal PublicTypeMock =
|
|||||||
|
|
||||||
interface IPublicType with
|
interface IPublicType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -49,10 +51,11 @@ type public PublicTypeInternalFalseMock =
|
|||||||
|
|
||||||
interface IPublicTypeInternalFalse with
|
interface IPublicTypeInternalFalse with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -71,9 +74,10 @@ type internal InternalTypeMock =
|
|||||||
|
|
||||||
interface InternalType with
|
interface InternalType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -92,9 +96,10 @@ type private PrivateTypeMock =
|
|||||||
|
|
||||||
interface PrivateType with
|
interface PrivateType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -113,9 +118,10 @@ type private PrivateTypeInternalFalseMock =
|
|||||||
|
|
||||||
interface PrivateTypeInternalFalse with
|
interface PrivateTypeInternalFalse with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -131,9 +137,10 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface VeryPublicType<'a, 'b> with
|
interface VeryPublicType<'a, 'b> with
|
||||||
member this.Mem1 (arg_0_0) = this.Mem1 (arg_0_0)
|
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -159,9 +166,9 @@ type internal CurriedMock<'a> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Curried<'a> with
|
interface Curried<'a> with
|
||||||
member this.Mem1 (arg_0_0) (arg_1_0) = this.Mem1 (arg_0_0) (arg_1_0)
|
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
|
||||||
member this.Mem2 (arg_0_0, arg_0_1) (arg_1_0) = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
||||||
member this.Mem3 ((arg_0_0, arg_0_1)) (arg_1_0) = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
||||||
|
|
||||||
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
||||||
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||||
@@ -171,3 +178,31 @@ type internal CurriedMock<'a> =
|
|||||||
|
|
||||||
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
||||||
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||||
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Mock record type for an interface
|
||||||
|
type internal TypeWithInterfaceMock =
|
||||||
|
{
|
||||||
|
/// Implementation of IDisposable.Dispose
|
||||||
|
Dispose : unit -> unit
|
||||||
|
Mem1 : string option -> string[] Async
|
||||||
|
Mem2 : unit -> string[] Async
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An implementation where every method throws.
|
||||||
|
static member Empty : TypeWithInterfaceMock =
|
||||||
|
{
|
||||||
|
Dispose = (fun _ -> ())
|
||||||
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeWithInterface with
|
||||||
|
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||||
|
member this.Mem2 () = this.Mem2 (())
|
||||||
|
|
||||||
|
interface System.IDisposable with
|
||||||
|
member this.Dispose () : unit = this.Dispose ()
|
||||||
|
@@ -87,6 +87,40 @@ module PureGymApi =
|
|||||||
}
|
}
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
|
member _.GetGymAttendance' (gymId : int, ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (
|
||||||
|
(match client.BaseAddress with
|
||||||
|
| null -> System.Uri "https://whatnot.com"
|
||||||
|
| v -> v),
|
||||||
|
System.Uri (
|
||||||
|
"v1/gyms/{gym_id}/attendance"
|
||||||
|
.Replace ("{gym_id}", gymId.ToString () |> System.Web.HttpUtility.UrlEncode),
|
||||||
|
System.UriKind.Relative
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let response = response.EnsureSuccessStatusCode ()
|
||||||
|
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
|
||||||
|
|
||||||
|
let! jsonNode =
|
||||||
|
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
|
||||||
|
return GymAttendance.jsonParse jsonNode
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
member _.GetMember (ct : CancellationToken option) =
|
member _.GetMember (ct : CancellationToken option) =
|
||||||
async {
|
async {
|
||||||
let! ct = Async.CancellationToken
|
let! ct = Async.CancellationToken
|
||||||
@@ -288,7 +322,52 @@ module PureGymApi =
|
|||||||
| v -> v),
|
| v -> v),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("/v2/gymSessions/member"
|
("/v2/gymSessions/member"
|
||||||
+ "?fromDate="
|
+ (if "/v2/gymSessions/member".IndexOf (char 63) >= 0 then
|
||||||
|
"&"
|
||||||
|
else
|
||||||
|
"?")
|
||||||
|
+ "fromDate="
|
||||||
|
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
||||||
|
+ "&toDate="
|
||||||
|
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
||||||
|
System.UriKind.Relative
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let response = response.EnsureSuccessStatusCode ()
|
||||||
|
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
|
||||||
|
|
||||||
|
let! jsonNode =
|
||||||
|
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
|
||||||
|
return Sessions.jsonParse jsonNode
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
|
member _.GetSessionsWithQuery (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (
|
||||||
|
(match client.BaseAddress with
|
||||||
|
| null -> System.Uri "https://whatnot.com"
|
||||||
|
| v -> v),
|
||||||
|
System.Uri (
|
||||||
|
("/v2/gymSessions/member?foo=1"
|
||||||
|
+ (if "/v2/gymSessions/member?foo=1".IndexOf (char 63) >= 0 then
|
||||||
|
"&"
|
||||||
|
else
|
||||||
|
"?")
|
||||||
|
+ "fromDate="
|
||||||
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
||||||
+ "&toDate="
|
+ "&toDate="
|
||||||
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
||||||
@@ -1140,6 +1219,69 @@ module ApiWithHeaders =
|
|||||||
member _.SomeHeader : string = someHeader ()
|
member _.SomeHeader : string = someHeader ()
|
||||||
member _.SomeOtherHeader : int = someOtherHeader ()
|
member _.SomeOtherHeader : int = someOtherHeader ()
|
||||||
|
|
||||||
|
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (
|
||||||
|
(match client.BaseAddress with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.ArgumentNullException (
|
||||||
|
nameof (client.BaseAddress),
|
||||||
|
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v),
|
||||||
|
System.Uri (
|
||||||
|
"endpoint/{param}"
|
||||||
|
.Replace ("{param}", parameter.ToString () |> System.Web.HttpUtility.UrlEncode),
|
||||||
|
System.UriKind.Relative
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
do httpMessage.Headers.Add ("X-Foo", this.SomeHeader.ToString ())
|
||||||
|
do httpMessage.Headers.Add ("Authorization", this.SomeOtherHeader.ToString ())
|
||||||
|
do httpMessage.Headers.Add ("Header-Name", "Header-Value")
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let response = response.EnsureSuccessStatusCode ()
|
||||||
|
let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask
|
||||||
|
return responseString
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
}
|
||||||
|
namespace PureGym
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Threading
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open System.IO
|
||||||
|
open System.Net
|
||||||
|
open System.Net.Http
|
||||||
|
open RestEase
|
||||||
|
|
||||||
|
/// Module for constructing a REST client.
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module ApiWithHeaders2 =
|
||||||
|
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||||
|
let make
|
||||||
|
(someHeader : unit -> string)
|
||||||
|
(someOtherHeader : unit -> int)
|
||||||
|
(client : System.Net.Http.HttpClient)
|
||||||
|
: IApiWithHeaders2
|
||||||
|
=
|
||||||
|
{ new IApiWithHeaders2 with
|
||||||
|
member _.SomeHeader : string = someHeader ()
|
||||||
|
member _.SomeOtherHeader : int = someOtherHeader ()
|
||||||
|
|
||||||
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
||||||
async {
|
async {
|
||||||
let! ct = Async.CancellationToken
|
let! ct = Async.CancellationToken
|
||||||
|
@@ -210,7 +210,7 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
|
|
||||||
let value =
|
let value =
|
||||||
(kvp.Value).AsArray ()
|
(kvp.Value).AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<char> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Char> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
key, value
|
key, value
|
||||||
|
@@ -32,10 +32,27 @@ type JsonRecordType =
|
|||||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||||
type ToGetExtensionMethod =
|
type ToGetExtensionMethod =
|
||||||
{
|
{
|
||||||
Tinker : string
|
Alpha : string
|
||||||
Tailor : int
|
Bravo : System.Uri
|
||||||
Soldier : System.Uri
|
Charlie : float
|
||||||
Sailor : float
|
Delta : float32
|
||||||
|
Echo : single
|
||||||
|
Foxtrot : double
|
||||||
|
Golf : int64
|
||||||
|
Hotel : uint64
|
||||||
|
India : int
|
||||||
|
Juliette : uint
|
||||||
|
Kilo : int32
|
||||||
|
Lima : uint32
|
||||||
|
Mike : int16
|
||||||
|
November : uint16
|
||||||
|
Oscar : int8
|
||||||
|
Papa : uint8
|
||||||
|
Quebec : byte
|
||||||
|
Tango : sbyte
|
||||||
|
Uniform : decimal
|
||||||
|
Victor : char
|
||||||
|
Whiskey : bigint
|
||||||
}
|
}
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
[<GenerateMock>]
|
[<GenerateMock>]
|
||||||
@@ -41,3 +42,9 @@ type Curried<'a> =
|
|||||||
abstract Mem4 : (int * string) -> ('a * int) -> string
|
abstract Mem4 : (int * string) -> ('a * int) -> string
|
||||||
abstract Mem5 : x : int * string -> ('a * int) -> string
|
abstract Mem5 : x : int * string -> ('a * int) -> string
|
||||||
abstract Mem6 : int * string -> y : 'a * int -> string
|
abstract Mem6 : int * string -> y : 'a * int -> string
|
||||||
|
|
||||||
|
[<GenerateMock>]
|
||||||
|
type TypeWithInterface =
|
||||||
|
inherit IDisposable
|
||||||
|
abstract Mem1 : string option -> string[] Async
|
||||||
|
abstract Mem2 : unit -> string[] Async
|
||||||
|
@@ -17,6 +17,9 @@ type IPureGymApi =
|
|||||||
[<Get "v1/gyms/{gym_id}/attendance">]
|
[<Get "v1/gyms/{gym_id}/attendance">]
|
||||||
abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
||||||
|
|
||||||
|
[<Get "v1/gyms/{gym_id}/attendance">]
|
||||||
|
abstract GetGymAttendance' : [<Path("gym_id")>] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
||||||
|
|
||||||
[<RestEase.GetAttribute "v1/member">]
|
[<RestEase.GetAttribute "v1/member">]
|
||||||
abstract GetMember : ?ct : CancellationToken -> Member Task
|
abstract GetMember : ?ct : CancellationToken -> Member Task
|
||||||
|
|
||||||
@@ -38,6 +41,10 @@ type IPureGymApi =
|
|||||||
abstract GetSessions :
|
abstract GetSessions :
|
||||||
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
||||||
|
|
||||||
|
[<Get "/v2/gymSessions/member?foo=1">]
|
||||||
|
abstract GetSessionsWithQuery :
|
||||||
|
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
||||||
|
|
||||||
// An example from RestEase's own docs
|
// An example from RestEase's own docs
|
||||||
[<Post "users/new">]
|
[<Post "users/new">]
|
||||||
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
||||||
@@ -120,7 +127,8 @@ type internal IApiWithoutBaseAddress =
|
|||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
[<BasePath "foo">]
|
[<BasePath "foo">]
|
||||||
type IApiWithBasePath =
|
type IApiWithBasePath =
|
||||||
[<Get "endpoint/{param}">]
|
// Example where we use the bundled attributes rather than RestEase's
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Get "endpoint/{param}">]
|
||||||
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
@@ -141,3 +149,16 @@ type IApiWithHeaders =
|
|||||||
|
|
||||||
[<Get "endpoint/{param}">]
|
[<Get "endpoint/{param}">]
|
||||||
abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
||||||
|
|
||||||
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Header("Header-Name", "Header-Value")>]
|
||||||
|
type IApiWithHeaders2 =
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Header "X-Foo">]
|
||||||
|
abstract SomeHeader : string
|
||||||
|
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Header "Authorization">]
|
||||||
|
abstract SomeOtherHeader : int
|
||||||
|
|
||||||
|
[<Get "endpoint/{param}">]
|
||||||
|
abstract GetPathParam :
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
||||||
|
63
WoofWare.Myriad.Plugins.Attributes/RestEase.fs
Normal file
63
WoofWare.Myriad.Plugins.Attributes/RestEase.fs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open System
|
||||||
|
|
||||||
|
/// Module containing duplicates of the supported RestEase attributes, in case you don't want
|
||||||
|
/// to take a dependency on RestEase.
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module RestEase =
|
||||||
|
/// Indicates that a method represents an HTTP Get query to the specified endpoint.
|
||||||
|
type GetAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Post query to the specified endpoint.
|
||||||
|
type PostAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Delete query to the specified endpoint.
|
||||||
|
type DeleteAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Head query to the specified endpoint.
|
||||||
|
type HeadAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Options query to the specified endpoint.
|
||||||
|
type OptionsAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Put query to the specified endpoint.
|
||||||
|
type PutAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Patch query to the specified endpoint.
|
||||||
|
type PatchAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Trace query to the specified endpoint.
|
||||||
|
type TraceAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that this argument to a method is interpolated into the HTTP request at runtime
|
||||||
|
/// by setting a query parameter (with the given name) to the value of the annotated argument.
|
||||||
|
type QueryAttribute (paramName : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that this interface represents a REST client which accesses an API whose paths are
|
||||||
|
/// all relative to the given address.
|
||||||
|
type BaseAddressAttribute (addr : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that this interface member causes the interface to set a header with the given name,
|
||||||
|
/// whose value is obtained whenever required by a fresh call to the interface member.
|
||||||
|
type HeaderAttribute (header : string, value : string option) =
|
||||||
|
inherit Attribute ()
|
||||||
|
new (header : string) = HeaderAttribute (header, None)
|
||||||
|
new (header : string, value : string) = HeaderAttribute (header, Some value)
|
||||||
|
|
||||||
|
/// Indicates that this argument to a method is interpolated into the request path at runtime
|
||||||
|
/// by writing it into the templated string that specifies the HTTP query e.g. in the `[<Get "/foo/{template}">]`.
|
||||||
|
type PathAttribute (path : string option) =
|
||||||
|
inherit Attribute ()
|
||||||
|
new (path : string) = PathAttribute (Some path)
|
||||||
|
new () = PathAttribute None
|
@@ -18,4 +18,33 @@ WoofWare.Myriad.Plugins.JsonSerializeAttribute..ctor [constructor]: unit
|
|||||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
||||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
||||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
||||||
|
WoofWare.Myriad.Plugins.RestEase inherit obj
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+DeleteAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+DeleteAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+GetAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+GetAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeadAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeadAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string option)
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string)
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+OptionsAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+OptionsAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PatchAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PatchAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string option
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: unit
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PostAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PostAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PutAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PutAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+QueryAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+QueryAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+TraceAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+TraceAttribute..ctor [constructor]: string
|
@@ -11,11 +11,9 @@ module TestSurface =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
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`` () =
|
let ``Check version against remote`` () =
|
||||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
||||||
*)
|
|
||||||
|
|
||||||
[<Test ; Explicit>]
|
[<Test ; Explicit>]
|
||||||
let ``Update API surface`` () =
|
let ``Update API surface`` () =
|
||||||
|
@@ -12,9 +12,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.30" />
|
<PackageReference Include="ApiSurface" Version="4.0.39" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
||||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Attributes.fs"/>
|
<Compile Include="Attributes.fs"/>
|
||||||
|
<Compile Include="RestEase.fs" />
|
||||||
<EmbeddedResource Include="version.json"/>
|
<EmbeddedResource Include="version.json"/>
|
||||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||||
<None Include="..\README.md">
|
<None Include="..\README.md">
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "2.2",
|
"version": "3.0",
|
||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
"pathFilters": null
|
"pathFilters": null
|
||||||
}
|
}
|
@@ -89,6 +89,7 @@ module TestPureGymRestApi =
|
|||||||
let api = PureGymApi.make client
|
let api = PureGymApi.make client
|
||||||
|
|
||||||
api.GetGymAttendance(requestedGym).Result |> shouldEqual expected
|
api.GetGymAttendance(requestedGym).Result |> shouldEqual expected
|
||||||
|
api.GetGymAttendance'(requestedGym).Result |> shouldEqual expected
|
||||||
|
|
||||||
let memberCases =
|
let memberCases =
|
||||||
PureGymDtos.memberCases |> List.allPairs baseUris |> List.map TestCaseData
|
PureGymDtos.memberCases |> List.allPairs baseUris |> List.map TestCaseData
|
||||||
@@ -234,6 +235,33 @@ module TestPureGymRestApi =
|
|||||||
|
|
||||||
api.GetSessions(startDate, endDate).Result |> shouldEqual expected
|
api.GetSessions(startDate, endDate).Result |> shouldEqual expected
|
||||||
|
|
||||||
|
[<TestCaseSource(nameof sessionsCases)>]
|
||||||
|
let ``Test GetSessionsWithQuery``
|
||||||
|
(baseUri : Uri, (startDate : DateOnly, (endDate : DateOnly, (json : string, expected : Sessions))))
|
||||||
|
=
|
||||||
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
async {
|
||||||
|
message.Method |> shouldEqual HttpMethod.Get
|
||||||
|
|
||||||
|
// This one is specified as being absolute, in its attribute on the IPureGymApi type
|
||||||
|
let expectedUri =
|
||||||
|
let fromDate = dateOnlyToString startDate
|
||||||
|
let toDate = dateOnlyToString endDate
|
||||||
|
$"https://example.com/v2/gymSessions/member?foo=1&fromDate=%s{fromDate}&toDate=%s{toDate}"
|
||||||
|
|
||||||
|
message.RequestUri.ToString () |> shouldEqual expectedUri
|
||||||
|
|
||||||
|
let content = new StringContent (json)
|
||||||
|
let resp = new HttpResponseMessage (HttpStatusCode.OK)
|
||||||
|
resp.Content <- content
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
use client = HttpClientMock.make baseUri proc
|
||||||
|
let api = PureGymApi.make client
|
||||||
|
|
||||||
|
api.GetSessionsWithQuery(startDate, endDate).Result |> shouldEqual expected
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``URI example`` () =
|
let ``URI example`` () =
|
||||||
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
namespace WoofWare.Myriad.Plugins.Test
|
namespace WoofWare.Myriad.Plugins.Test
|
||||||
|
|
||||||
open System
|
open System
|
||||||
|
open System.Numerics
|
||||||
open System.Text.Json.Nodes
|
open System.Text.Json.Nodes
|
||||||
open ConsumePlugin
|
open ConsumePlugin
|
||||||
open NUnit.Framework
|
open NUnit.Framework
|
||||||
@@ -12,15 +13,62 @@ module TestExtensionMethod =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Parse via extension method`` () =
|
let ``Parse via extension method`` () =
|
||||||
let json =
|
let json =
|
||||||
"""{"tinker": "job", "tailor": 3, "soldier": "https://example.com", "sailor": 3.1}"""
|
"""{
|
||||||
|
"alpha": "hello!",
|
||||||
|
"bravo": "https://example.com",
|
||||||
|
"charlie": 0.3341,
|
||||||
|
"delta": 110033.4,
|
||||||
|
"echo": -0.000993,
|
||||||
|
"foxtrot": -999999999999,
|
||||||
|
"golf": -123456789101112,
|
||||||
|
"hotel": 18446744073709551615,
|
||||||
|
"india": 99884,
|
||||||
|
"juliette": 12223334,
|
||||||
|
"kilo": -2147483642,
|
||||||
|
"lima": 4294967293,
|
||||||
|
"mike": -32767,
|
||||||
|
"november": 65533,
|
||||||
|
"oscar": -125,
|
||||||
|
"papa": 253,
|
||||||
|
"quebec": 254,
|
||||||
|
"tango": -3,
|
||||||
|
"uniform": 1004443.300988393349583009,
|
||||||
|
"victor": "x",
|
||||||
|
"whiskey": 123456123456123456123456123456123456123456
|
||||||
|
}"""
|
||||||
|> JsonNode.Parse
|
|> JsonNode.Parse
|
||||||
|
|
||||||
let expected =
|
let expected =
|
||||||
{
|
{
|
||||||
Tinker = "job"
|
Alpha = "hello!"
|
||||||
Tailor = 3
|
Bravo = Uri "https://example.com"
|
||||||
Soldier = Uri "https://example.com"
|
Charlie = 0.3341
|
||||||
Sailor = 3.1
|
Delta = 110033.4f
|
||||||
|
Echo = -0.000993f
|
||||||
|
Foxtrot = -999999999999.0
|
||||||
|
Golf = -123456789101112L
|
||||||
|
Hotel = 18446744073709551615UL
|
||||||
|
India = 99884
|
||||||
|
Juliette = 12223334u
|
||||||
|
Kilo = -2147483642
|
||||||
|
Lima = 4294967293u
|
||||||
|
Mike = -32767s
|
||||||
|
November = 65533us
|
||||||
|
Oscar = -125y
|
||||||
|
Papa = 253uy
|
||||||
|
Quebec = 254uy
|
||||||
|
Tango = -3y
|
||||||
|
Uniform = 1004443.300988393349583009m
|
||||||
|
Victor = 'x'
|
||||||
|
Whiskey =
|
||||||
|
let mutable i = BigInteger 0
|
||||||
|
|
||||||
|
for _ = 0 to 6 do
|
||||||
|
i <- i * BigInteger 1000000 + BigInteger 123456
|
||||||
|
|
||||||
|
i
|
||||||
}
|
}
|
||||||
|
|
||||||
ToGetExtensionMethod.jsonParse json |> shouldEqual expected
|
let actual = ToGetExtensionMethod.jsonParse json
|
||||||
|
|
||||||
|
actual |> shouldEqual expected
|
||||||
|
@@ -33,13 +33,12 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.30"/>
|
<PackageReference Include="ApiSurface" Version="4.0.39"/>
|
||||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.0.1"/>
|
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -54,6 +54,7 @@ type internal InterfaceType =
|
|||||||
{
|
{
|
||||||
Attributes : SynAttribute list
|
Attributes : SynAttribute list
|
||||||
Name : LongIdent
|
Name : LongIdent
|
||||||
|
Inherits : SynType list
|
||||||
Members : MemberInfo list
|
Members : MemberInfo list
|
||||||
Properties : PropertyInfo list
|
Properties : PropertyInfo list
|
||||||
Generics : SynTyparDecls option
|
Generics : SynTyparDecls option
|
||||||
@@ -97,6 +98,30 @@ 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
|
||||||
@@ -131,6 +156,11 @@ module internal AstHelper =
|
|||||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||||
| _ -> false
|
| _ -> 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 =
|
let isListIdent (ident : SynLongIdent) : bool =
|
||||||
match ident.LongIdent with
|
match ident.LongIdent with
|
||||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||||
@@ -342,7 +372,18 @@ module internal AstHelper =
|
|||||||
}
|
}
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
}
|
}
|
||||||
| _ -> failwith $"Unrecognised args in interface method declaration: %+A{args}"
|
| arg ->
|
||||||
|
{
|
||||||
|
HasParen = false
|
||||||
|
Args =
|
||||||
|
{
|
||||||
|
Attributes = []
|
||||||
|
IsOptional = false
|
||||||
|
Id = None
|
||||||
|
Type = arg
|
||||||
|
}
|
||||||
|
|> List.singleton
|
||||||
|
}
|
||||||
|> fun ty ->
|
|> fun ty ->
|
||||||
{ ty with
|
{ ty with
|
||||||
HasParen = ty.HasParen || hasParen
|
HasParen = ty.HasParen || hasParen
|
||||||
@@ -386,22 +427,26 @@ module internal AstHelper =
|
|||||||
|
|
||||||
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
||||||
|
|
||||||
let members, properties =
|
let members, inherits =
|
||||||
match synTypeDefnRepr with
|
match synTypeDefnRepr with
|
||||||
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
||||||
members
|
members
|
||||||
|> List.map (fun defn ->
|
|> List.map (fun defn ->
|
||||||
match defn with
|
match defn with
|
||||||
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> parseMember slotSig flags
|
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> Choice1Of2 (parseMember slotSig flags)
|
||||||
|
| SynMemberDefn.Inherit (baseType, _asIdent, _) -> Choice2Of2 baseType
|
||||||
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
||||||
)
|
)
|
||||||
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
||||||
|> List.partitionChoice
|
|> List.partitionChoice
|
||||||
|
|
||||||
|
let members, properties = members |> List.partitionChoice
|
||||||
|
|
||||||
{
|
{
|
||||||
Members = members
|
Members = members
|
||||||
Properties = properties
|
Properties = properties
|
||||||
Name = interfaceName
|
Name = interfaceName
|
||||||
|
Inherits = inherits
|
||||||
Attributes = attrs
|
Attributes = attrs
|
||||||
Generics = typars
|
Generics = typars
|
||||||
Accessibility = accessibility
|
Accessibility = accessibility
|
||||||
@@ -486,6 +531,11 @@ module internal SynTypePatterns =
|
|||||||
Some innerType
|
Some innerType
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
|
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident when AstHelper.isUnitIdent ident -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
let (|ListType|_|) (fieldType : SynType) =
|
let (|ListType|_|) (fieldType : SynType) =
|
||||||
match fieldType with
|
match fieldType with
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
||||||
@@ -531,14 +581,23 @@ module internal SynTypePatterns =
|
|||||||
Some (key, value)
|
Some (key, value)
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
/// Returns the string name of the type.
|
let (|BigInt|_|) (fieldType : SynType) : unit option =
|
||||||
let (|PrimitiveType|_|) (fieldType : SynType) =
|
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
|
match fieldType with
|
||||||
| SynType.LongIdent ident ->
|
| SynType.LongIdent ident ->
|
||||||
match ident.LongIdent with
|
match ident.LongIdent with
|
||||||
| [ i ] ->
|
| [ i ] -> AstHelper.qualifyPrimitiveType i.idText
|
||||||
[ "string" ; "float" ; "int" ; "bool" ; "char" ]
|
|
||||||
|> List.tryFind (fun s -> s = i.idText)
|
|
||||||
| _ -> None
|
| _ -> None
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Net.Http
|
open System.Net.Http
|
||||||
open System.Text
|
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
@@ -82,34 +80,50 @@ module internal HttpClientGenerator =
|
|||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "Get"
|
| "Get"
|
||||||
| "GetAttribute"
|
| "GetAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Get"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.GetAttribute"
|
||||||
| "RestEase.Get"
|
| "RestEase.Get"
|
||||||
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
||||||
| "Post"
|
| "Post"
|
||||||
| "PostAttribute"
|
| "PostAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Post"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PostAttribute"
|
||||||
| "RestEase.Post"
|
| "RestEase.Post"
|
||||||
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
||||||
| "Put"
|
| "Put"
|
||||||
| "PutAttribute"
|
| "PutAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Put"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PutAttribute"
|
||||||
| "RestEase.Put"
|
| "RestEase.Put"
|
||||||
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
||||||
| "Delete"
|
| "Delete"
|
||||||
| "DeleteAttribute"
|
| "DeleteAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Delete"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.DeleteAttribute"
|
||||||
| "RestEase.Delete"
|
| "RestEase.Delete"
|
||||||
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
||||||
| "Head"
|
| "Head"
|
||||||
| "HeadAttribute"
|
| "HeadAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Head"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.HeadAttribute"
|
||||||
| "RestEase.Head"
|
| "RestEase.Head"
|
||||||
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
||||||
| "Options"
|
| "Options"
|
||||||
| "OptionsAttribute"
|
| "OptionsAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Options"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.OptionsAttribute"
|
||||||
| "RestEase.Options"
|
| "RestEase.Options"
|
||||||
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
||||||
| "Patch"
|
| "Patch"
|
||||||
| "PatchAttribute"
|
| "PatchAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Patch"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PatchAttribute"
|
||||||
| "RestEase.Patch"
|
| "RestEase.Patch"
|
||||||
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
||||||
| "Trace"
|
| "Trace"
|
||||||
| "TraceAttribute"
|
| "TraceAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Trace"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.TraceAttribute"
|
||||||
| "RestEase.Trace"
|
| "RestEase.Trace"
|
||||||
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
||||||
| _ -> None
|
| _ -> None
|
||||||
@@ -127,7 +141,8 @@ module internal HttpClientGenerator =
|
|||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "Header"
|
| "Header"
|
||||||
| "RestEase.Header" ->
|
| "RestEase.Header"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Header" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
||||||
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
||||||
@@ -293,6 +308,27 @@ 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
|
||||||
|
|
||||||
|
let urlSeparator =
|
||||||
|
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
||||||
|
let questionMark =
|
||||||
|
SynExpr.CreateParen (
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateIdentString "char",
|
||||||
|
SynExpr.CreateConst (SynConst.Int32 63)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let containsQuestion =
|
||||||
|
info.UrlTemplate
|
||||||
|
|> SynExpr.callMethodArg "IndexOf" questionMark
|
||||||
|
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst (SynConst.Int32 0))
|
||||||
|
|
||||||
|
SynExpr.ifThenElse
|
||||||
|
containsQuestion
|
||||||
|
(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
|
||||||
@@ -301,7 +337,7 @@ module internal HttpClientGenerator =
|
|||||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
||||||
)
|
)
|
||||||
|> SynExpr.CreateParen
|
|> SynExpr.CreateParen
|
||||||
|> SynExpr.plus (SynExpr.CreateConstString ("?" + firstKey + "="))
|
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConstString (firstKey + "=")))
|
||||||
|
|
||||||
(prefix, queryParams)
|
(prefix, queryParams)
|
||||||
||> List.fold (fun uri (paramKey, paramValue) ->
|
||> List.fold (fun uri (paramKey, paramValue) ->
|
||||||
@@ -709,6 +745,10 @@ module internal HttpClientGenerator =
|
|||||||
attrs
|
attrs
|
||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
|
| "RestEase.Query"
|
||||||
|
| "RestEase.QueryAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Query"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.QueryAttribute"
|
||||||
| "Query"
|
| "Query"
|
||||||
| "QueryAttribute" ->
|
| "QueryAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -717,14 +757,22 @@ module internal HttpClientGenerator =
|
|||||||
Some (HttpAttribute.Query (Some s))
|
Some (HttpAttribute.Query (Some s))
|
||||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
| "RestEase.Path"
|
||||||
|
| "RestEase.PathAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Path"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PathAttribute"
|
||||||
| "Path"
|
| "Path"
|
||||||
| "PathAttribute" ->
|
| "PathAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr |> SynExpr.stripOptionalParen with
|
||||||
| SynExpr.Const (SynConst.String (s, SynStringKind.Regular, _), _) ->
|
| SynExpr.Const (SynConst.String (s, SynStringKind.Regular, _), _) ->
|
||||||
Some (HttpAttribute.Path (PathSpec.Verbatim s))
|
Some (HttpAttribute.Path (PathSpec.Verbatim s))
|
||||||
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
||||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
| "RestEase.Body"
|
||||||
|
| "RestEase.BodyAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Body"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BodyAttribute"
|
||||||
| "Body"
|
| "Body"
|
||||||
| "BodyAttribute" ->
|
| "BodyAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -740,8 +788,10 @@ module internal HttpClientGenerator =
|
|||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "BasePath"
|
| "BasePath"
|
||||||
| "RestEase.BasePath"
|
| "RestEase.BasePath"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BasePath"
|
||||||
| "BasePathAttribute"
|
| "BasePathAttribute"
|
||||||
| "RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
| "RestEase.BasePathAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
||||||
| _ -> None
|
| _ -> None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -751,8 +801,10 @@ module internal HttpClientGenerator =
|
|||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "BaseAddress"
|
| "BaseAddress"
|
||||||
| "RestEase.BaseAddress"
|
| "RestEase.BaseAddress"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
|
||||||
| "BaseAddressAttribute"
|
| "BaseAddressAttribute"
|
||||||
| "RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
| "RestEase.BaseAddressAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
||||||
| _ -> None
|
| _ -> None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -764,6 +816,10 @@ module internal HttpClientGenerator =
|
|||||||
=
|
=
|
||||||
let interfaceType = AstHelper.parseInterface interfaceType
|
let interfaceType = AstHelper.parseInterface interfaceType
|
||||||
|
|
||||||
|
if not (List.isEmpty interfaceType.Inherits) then
|
||||||
|
failwith
|
||||||
|
"HttpClientGenerator does not support inheritance. Remove the `inherit` keyword if you want to use this generator."
|
||||||
|
|
||||||
let constantHeaders =
|
let constantHeaders =
|
||||||
interfaceType.Attributes
|
interfaceType.Attributes
|
||||||
|> extractHeaderInformation
|
|> extractHeaderInformation
|
||||||
|
@@ -21,6 +21,9 @@ module internal InterfaceMockGenerator =
|
|||||||
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
||||||
| Some id -> id
|
| Some id -> id
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type private KnownInheritance = | IDisposable
|
||||||
|
|
||||||
let createType
|
let createType
|
||||||
(spec : GenerateMockOutputSpec)
|
(spec : GenerateMockOutputSpec)
|
||||||
(name : string)
|
(name : string)
|
||||||
@@ -29,6 +32,20 @@ module internal InterfaceMockGenerator =
|
|||||||
(fields : SynField list)
|
(fields : SynField list)
|
||||||
: SynModuleDecl
|
: SynModuleDecl
|
||||||
=
|
=
|
||||||
|
let inherits =
|
||||||
|
interfaceType.Inherits
|
||||||
|
|> Seq.map (fun ty ->
|
||||||
|
match ty with
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) ->
|
||||||
|
match name |> List.map _.idText with
|
||||||
|
| [] -> failwith "Unexpected empty identifier in inheritance declaration"
|
||||||
|
| [ "IDisposable" ]
|
||||||
|
| [ "System" ; "IDisposable" ] -> KnownInheritance.IDisposable
|
||||||
|
| _ -> failwithf "Unrecognised inheritance identifier: %+A" name
|
||||||
|
| x -> failwithf "Unrecognised type in inheritance: %+A" x
|
||||||
|
)
|
||||||
|
|> Set.ofSeq
|
||||||
|
|
||||||
let synValData =
|
let synValData =
|
||||||
{
|
{
|
||||||
SynMemberFlags.IsInstance = false
|
SynMemberFlags.IsInstance = false
|
||||||
@@ -90,6 +107,23 @@ module internal InterfaceMockGenerator =
|
|||||||
)
|
)
|
||||||
|> SynBindingReturnInfo.Create
|
|> SynBindingReturnInfo.Create
|
||||||
|
|
||||||
|
let constructorFields =
|
||||||
|
let extras =
|
||||||
|
if inherits.Contains KnownInheritance.IDisposable then
|
||||||
|
let unitFun = SynExpr.createLambda "_" SynExpr.CreateUnit
|
||||||
|
|
||||||
|
[
|
||||||
|
(SynLongIdent.CreateFromLongIdent [ Ident.Create "Dispose" ], true), Some unitFun
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
|
||||||
|
let nonExtras =
|
||||||
|
fields
|
||||||
|
|> List.map (fun field -> (SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
||||||
|
|
||||||
|
extras @ nonExtras
|
||||||
|
|
||||||
let constructor =
|
let constructor =
|
||||||
SynMemberDefn.Member (
|
SynMemberDefn.Member (
|
||||||
SynBinding.SynBinding (
|
SynBinding.SynBinding (
|
||||||
@@ -102,12 +136,7 @@ module internal InterfaceMockGenerator =
|
|||||||
SynValData.SynValData (Some synValData, SynValInfo.Empty, None),
|
SynValData.SynValData (Some synValData, SynValInfo.Empty, None),
|
||||||
constructorIdent,
|
constructorIdent,
|
||||||
Some constructorReturnType,
|
Some constructorReturnType,
|
||||||
AstHelper.instantiateRecord (
|
AstHelper.instantiateRecord constructorFields,
|
||||||
fields
|
|
||||||
|> List.map (fun field ->
|
|
||||||
((SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
range0,
|
range0,
|
||||||
DebugPointAtBinding.Yes range0,
|
DebugPointAtBinding.Yes range0,
|
||||||
{ SynExpr.synBindingTriviaZero true with
|
{ SynExpr.synBindingTriviaZero true with
|
||||||
@@ -117,6 +146,21 @@ module internal InterfaceMockGenerator =
|
|||||||
range0
|
range0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let fields =
|
||||||
|
let extras =
|
||||||
|
if inherits.Contains KnownInheritance.IDisposable then
|
||||||
|
[
|
||||||
|
SynField.Create (
|
||||||
|
SynType.CreateFun (SynType.CreateUnit, SynType.CreateUnit),
|
||||||
|
Ident.Create "Dispose",
|
||||||
|
xmldoc = PreXmlDoc.Create " Implementation of IDisposable.Dispose"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
|
||||||
|
extras @ fields
|
||||||
|
|
||||||
let interfaceMembers =
|
let interfaceMembers =
|
||||||
let members =
|
let members =
|
||||||
interfaceType.Members
|
interfaceType.Members
|
||||||
@@ -150,7 +194,9 @@ module internal InterfaceMockGenerator =
|
|||||||
|> List.mapi (fun i arg ->
|
|> List.mapi (fun i arg ->
|
||||||
arg.Args
|
arg.Args
|
||||||
|> List.mapi (fun j arg ->
|
|> List.mapi (fun j arg ->
|
||||||
SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
match arg.Type with
|
||||||
|
| UnitType -> SynArgInfo.SynArgInfo ([], false, None)
|
||||||
|
| _ -> SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -165,10 +211,18 @@ module internal InterfaceMockGenerator =
|
|||||||
|> List.mapi (fun i tupledArgs ->
|
|> List.mapi (fun i tupledArgs ->
|
||||||
let args =
|
let args =
|
||||||
tupledArgs.Args
|
tupledArgs.Args
|
||||||
|> List.mapi (fun j _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}"))
|
|> List.mapi (fun j ty ->
|
||||||
|
match ty.Type with
|
||||||
|
| UnitType -> SynPat.Const (SynConst.Unit, range0)
|
||||||
|
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}")
|
||||||
|
)
|
||||||
|
|
||||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
match args with
|
||||||
|> SynPat.CreateParen
|
| [] -> failwith "somehow got no args at all"
|
||||||
|
| [ arg ] -> arg
|
||||||
|
| args ->
|
||||||
|
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||||
|
|> SynPat.CreateParen
|
||||||
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -187,7 +241,11 @@ module internal InterfaceMockGenerator =
|
|||||||
memberInfo.Args
|
memberInfo.Args
|
||||||
|> List.mapi (fun i args ->
|
|> List.mapi (fun i args ->
|
||||||
args.Args
|
args.Args
|
||||||
|> List.mapi (fun j args -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}")
|
|> List.mapi (fun j arg ->
|
||||||
|
match arg.Type with
|
||||||
|
| UnitType -> SynExpr.CreateConst SynConst.Unit
|
||||||
|
| _ -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}"
|
||||||
|
)
|
||||||
|> SynExpr.CreateParenedTuple
|
|> SynExpr.CreateParenedTuple
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -264,11 +322,100 @@ module internal InterfaceMockGenerator =
|
|||||||
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
||||||
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
||||||
|
|
||||||
|
let extraInterfaces =
|
||||||
|
inherits
|
||||||
|
|> Seq.map (fun inheritance ->
|
||||||
|
match inheritance with
|
||||||
|
| KnownInheritance.IDisposable ->
|
||||||
|
let valData =
|
||||||
|
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
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
returnInfo =
|
||||||
|
SynArgInfo.SynArgInfo (attributes = [], optional = false, ident = None)
|
||||||
|
),
|
||||||
|
thisIdOpt = None
|
||||||
|
)
|
||||||
|
|
||||||
|
let headArgs = [ SynPat.Const (SynConst.Unit, range0) ]
|
||||||
|
|
||||||
|
let headPat =
|
||||||
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; Ident.Create "Dispose" ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Pats headArgs,
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
let binding =
|
||||||
|
SynBinding.SynBinding (
|
||||||
|
None,
|
||||||
|
SynBindingKind.Normal,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[],
|
||||||
|
PreXmlDoc.Empty,
|
||||||
|
valData,
|
||||||
|
headPat,
|
||||||
|
Some (
|
||||||
|
SynBindingReturnInfo.SynBindingReturnInfo (
|
||||||
|
SynType.Unit (),
|
||||||
|
range0,
|
||||||
|
[],
|
||||||
|
SynBindingReturnInfoTrivia.Zero
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "this" ; "Dispose" ]),
|
||||||
|
SynExpr.CreateUnit
|
||||||
|
),
|
||||||
|
range0,
|
||||||
|
DebugPointAtBinding.Yes range0,
|
||||||
|
{
|
||||||
|
LeadingKeyword = SynLeadingKeyword.Member range0
|
||||||
|
InlineKeyword = None
|
||||||
|
EqualsRange = Some range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let mem = SynMemberDefn.Member (binding, range0)
|
||||||
|
|
||||||
|
SynMemberDefn.Interface (
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "IDisposable" ]),
|
||||||
|
Some range0,
|
||||||
|
Some [ mem ],
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> Seq.toList
|
||||||
|
|
||||||
let record =
|
let record =
|
||||||
{
|
{
|
||||||
Name = Ident.Create name
|
Name = Ident.Create name
|
||||||
Fields = fields
|
Fields = fields
|
||||||
Members = Some [ constructor ; interfaceMembers ]
|
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
|
||||||
XmlDoc = Some xmlDoc
|
XmlDoc = Some xmlDoc
|
||||||
Generics = interfaceType.Generics
|
Generics = interfaceType.Generics
|
||||||
Accessibility = Some access
|
Accessibility = Some access
|
||||||
@@ -333,7 +480,6 @@ module internal InterfaceMockGenerator =
|
|||||||
|
|
||||||
let typeDecl = createType spec name interfaceType docString fields
|
let typeDecl = createType spec name interfaceType docString fields
|
||||||
|
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
namespaceId,
|
namespaceId,
|
||||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
||||||
|
@@ -62,6 +62,13 @@ module internal JsonParseGenerator =
|
|||||||
/// {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}`.
|
||||||
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
|
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
|
||||||
|
match propertyName with
|
||||||
|
| None -> node
|
||||||
|
| Some propertyName -> assertNotNull propertyName node
|
||||||
|
|> SynExpr.callMethod "AsValue"
|
||||||
|
|> SynExpr.callGenericMethod' "GetValue" typeName
|
||||||
|
|
||||||
|
let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertNotNull propertyName node
|
||||||
@@ -122,7 +129,12 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
/// 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 =
|
||||||
List.append (SynExpr.qualifyPrimitiveType typeName) [ Ident.Create "Parse" ]
|
let qualified =
|
||||||
|
match AstHelper.qualifyPrimitiveType typeName with
|
||||||
|
| Some x -> x
|
||||||
|
| None -> failwith $"Could not recognise type %s{typeName} as a primitive."
|
||||||
|
|
||||||
|
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.
|
||||||
@@ -252,7 +264,7 @@ module internal JsonParseGenerator =
|
|||||||
range0
|
range0
|
||||||
))
|
))
|
||||||
handler
|
handler
|
||||||
| PrimitiveType typeName -> asValueGetValue 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.CreateIdentString "v")
|
||||||
|> createParseLineOption node
|
|> createParseLineOption node
|
||||||
@@ -312,6 +324,11 @@ module internal JsonParseGenerator =
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Map" ; "ofSeq" ]))
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Map" ; "ofSeq" ]))
|
||||||
|
| BigInt ->
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Numerics" ; "BigInteger" ; "Parse" ]),
|
||||||
|
SynExpr.CreateParen (node |> SynExpr.callMethod "ToJsonString")
|
||||||
|
)
|
||||||
| _ ->
|
| _ ->
|
||||||
// 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!
|
||||||
let typeName =
|
let typeName =
|
||||||
|
@@ -107,24 +107,6 @@ module internal SynExpr =
|
|||||||
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr
|
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr
|
||||||
| expr -> expr
|
| expr -> expr
|
||||||
|
|
||||||
/// Given e.g. "byte", returns "System.Byte".
|
|
||||||
let qualifyPrimitiveType (typeName : string) : LongIdent =
|
|
||||||
match typeName with
|
|
||||||
| "float32" -> [ "System" ; "Single" ]
|
|
||||||
| "float" -> [ "System" ; "Double" ]
|
|
||||||
| "byte"
|
|
||||||
| "uint8" -> [ "System" ; "Byte" ]
|
|
||||||
| "sbyte" -> [ "System" ; "SByte" ]
|
|
||||||
| "int16" -> [ "System" ; "Int16" ]
|
|
||||||
| "int" -> [ "System" ; "Int32" ]
|
|
||||||
| "int64" -> [ "System" ; "Int64" ]
|
|
||||||
| "uint16" -> [ "System" ; "UInt16" ]
|
|
||||||
| "uint"
|
|
||||||
| "uint32" -> [ "System" ; "UInt32" ]
|
|
||||||
| "uint64" -> [ "System" ; "UInt64" ]
|
|
||||||
| _ -> failwith $"Unable to identify a parsing function `string -> %s{typeName}`"
|
|
||||||
|> List.map Ident.Create
|
|
||||||
|
|
||||||
/// {obj}.{meth} {arg}
|
/// {obj}.{meth} {arg}
|
||||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr =
|
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr =
|
||||||
SynExpr.CreateApp (
|
SynExpr.CreateApp (
|
||||||
@@ -141,8 +123,22 @@ module internal SynExpr =
|
|||||||
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 SynConst.Unit) obj
|
||||||
|
|
||||||
|
let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.TypeApp (
|
||||||
|
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||||
|
range0,
|
||||||
|
[ SynType.LongIdent (SynLongIdent.CreateFromLongIdent ty) ],
|
||||||
|
[],
|
||||||
|
Some range0,
|
||||||
|
range0,
|
||||||
|
range0
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
|
||||||
/// {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.CreateApp (
|
SynExpr.CreateApp (
|
||||||
SynExpr.TypeApp (
|
SynExpr.TypeApp (
|
||||||
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||||
@@ -311,3 +307,19 @@ module internal SynExpr =
|
|||||||
),
|
),
|
||||||
x
|
x
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/// {y} >= {x}
|
||||||
|
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
[ Ident.Create "op_GreaterThanOrEqual" ],
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
y
|
||||||
|
),
|
||||||
|
x
|
||||||
|
)
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
<Compile Include="List.fs"/>
|
<Compile Include="List.fs"/>
|
||||||
<Compile Include="Ident.fs" />
|
<Compile Include="Ident.fs" />
|
||||||
<Compile Include="AstHelper.fs"/>
|
<Compile Include="AstHelper.fs"/>
|
||||||
<Compile Include="SynExpr.fs"/>
|
<Compile Include="SynExpr.fs" />
|
||||||
<Compile Include="SynType.fs"/>
|
<Compile Include="SynType.fs"/>
|
||||||
<Compile Include="SynAttribute.fs"/>
|
<Compile Include="SynAttribute.fs"/>
|
||||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.9.3]" />
|
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.10.0]" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -7,7 +7,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
self,
|
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
flake-utils,
|
flake-utils,
|
||||||
...
|
...
|
||||||
|
31
nix/deps.nix
31
nix/deps.nix
@@ -3,23 +3,18 @@
|
|||||||
{fetchNuGet}: [
|
{fetchNuGet}: [
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "fsharp-analyzers";
|
pname = "fsharp-analyzers";
|
||||||
version = "0.25.0";
|
version = "0.26.0";
|
||||||
sha256 = "sha256-njfJYi40jNvrD+mgu9LtQw2Omh8P1SSDThesozH0KQY=";
|
sha256 = "sha256-60Bl36LOb/zVNdH2SBSuQ5O41lP9dKTNZbs5vvYs+3U=";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "fantomas";
|
pname = "fantomas";
|
||||||
version = "6.3.0-alpha-007";
|
version = "6.3.4";
|
||||||
sha256 = "sha256-uZw6h6k/DS4BcYtK9cv8TLS0H8MZDO3WBaPPTdtTgu0=";
|
sha256 = "sha256-1aWqZynBkQoznenGoP0sbf1PcUXAbcHiWyECuv89xa0=";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "ApiSurface";
|
pname = "ApiSurface";
|
||||||
version = "4.0.30";
|
version = "4.0.39";
|
||||||
sha256 = "0khbp0dx87m4kx1a5b9vgh1pp88vr9w8vpqvxf6afrpcyynwrrcr";
|
sha256 = "sha256-I4K5nJbltsfL/1r+KPTIo2wUd30zsCC2pkrnIRnsRHM=";
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "coverlet.collector";
|
|
||||||
version = "6.0.0";
|
|
||||||
sha256 = "12j34vrkmph8lspbafnqmfnj2qvysz1jcrks2khw798s6dwv0j90";
|
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Fantomas.Core";
|
pname = "Fantomas.Core";
|
||||||
@@ -296,11 +291,6 @@
|
|||||||
version = "3.6.133";
|
version = "3.6.133";
|
||||||
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NETStandard.Library";
|
|
||||||
version = "2.0.0";
|
|
||||||
sha256 = "1bc4ba8ahgk15m8k4nd7x406nhi0kwqzbgjk2dmw52ss553xz7iy";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NETStandard.Library";
|
pname = "NETStandard.Library";
|
||||||
version = "2.0.3";
|
version = "2.0.3";
|
||||||
@@ -348,13 +338,8 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit";
|
pname = "NUnit";
|
||||||
version = "3.13.3";
|
version = "4.1.0";
|
||||||
sha256 = "0wdzfkygqnr73s6lpxg5b1pwaqz9f414fxpvpdmf72bvh4jaqzv6";
|
sha256 = "0fj6xwgqaxq3mrai86bklclfmjkzf038mrslwfqf4ignaz9f7g5j";
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NUnit";
|
|
||||||
version = "4.0.1";
|
|
||||||
sha256 = "0jgiq3dbwli5r70j0bw7021d69r7bhr58s8kphlpjmf7k47l5pcd";
|
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit3TestAdapter";
|
pname = "NUnit3TestAdapter";
|
||||||
|
Reference in New Issue
Block a user