mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-27 06:39:00 +00:00
Compare commits
2 Commits
WoofWare.M
...
d86bd743af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d86bd743af | ||
|
|
dff2431bc8 |
@@ -3,16 +3,16 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fantomas": {
|
||||
"version": "6.3.4",
|
||||
"version": "6.3.0-alpha-007",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
},
|
||||
"fsharp-analyzers": {
|
||||
"version": "0.26.0",
|
||||
"version": "0.24.0",
|
||||
"commands": [
|
||||
"fsharp-analyzers"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ root=true
|
||||
|
||||
[*]
|
||||
charset=utf-8
|
||||
end_of_line=crlf
|
||||
trim_trailing_whitespace=true
|
||||
insert_final_newline=true
|
||||
indent_style=space
|
||||
|
||||
10
.gitattributes
vendored
10
.gitattributes
vendored
@@ -1,5 +1,5 @@
|
||||
* eol=auto
|
||||
*.sh text eol=lf
|
||||
*.yaml text
|
||||
*.nix text eol=lf
|
||||
hooks/pre-push text eol=lf
|
||||
* eol=auto
|
||||
*.sh text eol=lf
|
||||
*.yaml text
|
||||
*.nix text eol=lf
|
||||
hooks/pre-push text eol=lf
|
||||
|
||||
42
.github/workflows/dotnet.yaml
vendored
42
.github/workflows/dotnet.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
- name: Build project
|
||||
run: nix develop --command dotnet build ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj
|
||||
- name: Run analyzers
|
||||
run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/*/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001 GRA-DISPBEFOREASYNC-001 --exclude-analyzers PartialAppAnalyzer
|
||||
run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/0.8.0/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001 GRA-DISPBEFOREASYNC-001 --exclude-analyzers PartialAppAnalyzer
|
||||
|
||||
build-nix:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -188,7 +188,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@V27
|
||||
uses: cachix/install-nix-action@v25
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -206,25 +206,3 @@ jobs:
|
||||
path: packed-attribute
|
||||
- name: Publish to NuGet (attribute)
|
||||
run: nix develop --command dotnet nuget push "packed-attribute/WoofWare.Myriad.Plugins.Attributes.*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
|
||||
github-release-plugin:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
|
||||
needs: [all-required-checks-complete]
|
||||
environment: main-deploy
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download NuGet artifact (plugin)
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
- name: Download NuGet artifact (attribute)
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
- name: Tag and release plugin
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: sh .github/workflows/tag.sh
|
||||
|
||||
17
.github/workflows/tag.sh
vendored
17
.github/workflows/tag.sh
vendored
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
find . -maxdepth 1 -type f -name '*.nupkg' -exec sh -c 'tag=$(basename "$1" .nupkg); git tag "$tag"; git push origin "$tag"' shell {} \;
|
||||
|
||||
export TAG
|
||||
TAG=$(find . -maxdepth 1 -type f -name 'WoofWare.Myriad.Plugins.*.nupkg' -exec sh -c 'basename "$1" .nupkg' shell {} \; | grep -v Attributes)
|
||||
|
||||
case "$TAG" in
|
||||
*"
|
||||
"*)
|
||||
echo "Error: TAG contains a newline; multiple plugins found."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# target_commitish empty indicates the repo default branch
|
||||
curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases -d '{"tag_name":"'"$TAG"'","target_commitish":"","name":"'"$TAG"'","draft":false,"prerelease":false,"generate_release_notes":false}'
|
||||
@@ -11,12 +11,12 @@ type PairOpKind =
|
||||
| ThenDoSeq
|
||||
|
||||
[<CreateCatamorphism "TreeCata">]
|
||||
type Tree<'a, 'b> =
|
||||
| Const of Const<'a> * 'b
|
||||
| Pair of Tree<'a, 'b> * Tree<'a, 'b> * PairOpKind
|
||||
| Sequential of Tree<'a, 'b> list
|
||||
| Builder of Tree<'a, 'b> * TreeBuilder<'b, 'a>
|
||||
type Tree<'a> =
|
||||
| Const of Const<'a>
|
||||
| Pair of Tree<'a> * Tree<'a> * PairOpKind
|
||||
| Sequential of Tree<'a> list
|
||||
| Builder of Tree<'a> * TreeBuilder<'a>
|
||||
|
||||
and TreeBuilder<'b, 'a> =
|
||||
| Child of TreeBuilder<'b, 'a>
|
||||
| Parent of Tree<'a, 'b>
|
||||
and TreeBuilder<'a> =
|
||||
| Child of TreeBuilder<'a>
|
||||
| Parent of Tree<'a>
|
||||
|
||||
@@ -12,16 +12,16 @@ namespace ConsumePlugin
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Description of how to combine cases during a fold
|
||||
type TreeBuilderCataCase<'b, 'a, 'TreeBuilder, 'Tree> =
|
||||
type TreeBuilderCataCase<'a, 'TreeBuilder, 'Tree> =
|
||||
/// How to operate on the Child case
|
||||
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
||||
/// How to operate on the Parent case
|
||||
abstract Parent : 'Tree -> 'TreeBuilder
|
||||
|
||||
/// Description of how to combine cases during a fold
|
||||
type TreeCataCase<'a, 'b, 'TreeBuilder, 'Tree> =
|
||||
type TreeCataCase<'a, 'TreeBuilder, 'Tree> =
|
||||
/// How to operate on the Const case
|
||||
abstract Const : Const<'a> -> 'b -> 'Tree
|
||||
abstract Const : Const -> 'Tree
|
||||
/// How to operate on the Pair case
|
||||
abstract Pair : 'Tree -> 'Tree -> PairOpKind -> 'Tree
|
||||
/// How to operate on the Sequential case
|
||||
@@ -30,30 +30,30 @@ type TreeCataCase<'a, 'b, 'TreeBuilder, 'Tree> =
|
||||
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
||||
|
||||
/// Specifies how to perform a fold (catamorphism) over the type Tree and its friends.
|
||||
type TreeCata<'b, 'a, 'TreeBuilder, 'Tree> =
|
||||
type TreeCata<'a, 'a, 'TreeBuilder, 'Tree> =
|
||||
{
|
||||
/// How to perform a fold (catamorphism) over the type TreeBuilder
|
||||
TreeBuilder : TreeBuilderCataCase<'b, 'a, 'TreeBuilder, 'Tree>
|
||||
TreeBuilder : TreeBuilderCataCase<'a, 'TreeBuilder, 'Tree>
|
||||
/// How to perform a fold (catamorphism) over the type Tree
|
||||
Tree : TreeCataCase<'a, 'b, 'TreeBuilder, 'Tree>
|
||||
Tree : TreeCataCase<'a, 'TreeBuilder, 'Tree>
|
||||
}
|
||||
|
||||
/// Methods to perform a catamorphism over the type Tree
|
||||
[<RequireQualifiedAccess>]
|
||||
module TreeCata =
|
||||
[<RequireQualifiedAccess>]
|
||||
type private Instruction<'b, 'a> =
|
||||
| Process__TreeBuilder of TreeBuilder<'b, 'a>
|
||||
| Process__Tree of Tree<'a, 'b>
|
||||
type private Instruction<'a, 'a> =
|
||||
| Process__TreeBuilder of TreeBuilder<'a>
|
||||
| Process__Tree of Tree<'a>
|
||||
| TreeBuilder_Child
|
||||
| TreeBuilder_Parent
|
||||
| Tree_Pair of PairOpKind
|
||||
| Tree_Sequential of int
|
||||
| Tree_Builder
|
||||
|
||||
let private loop (cata : TreeCata<'b, 'a, 'TreeBuilder, 'Tree>) (instructions : ResizeArray<Instruction<'b, 'a>>) =
|
||||
let treeStack = ResizeArray<'Tree> ()
|
||||
let treeBuilderStack = ResizeArray<'TreeBuilder> ()
|
||||
let private loop (cata : TreeCata<_, _, _, _>) (instructions : ResizeArray<Instruction<_, _>>) =
|
||||
let treeStack = ResizeArray ()
|
||||
let treeBuilderStack = ResizeArray ()
|
||||
|
||||
while instructions.Count > 0 do
|
||||
let currentInstruction = instructions.[instructions.Count - 1]
|
||||
@@ -70,7 +70,7 @@ module TreeCata =
|
||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||
| Instruction.Process__Tree x ->
|
||||
match x with
|
||||
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
||||
| Tree.Const (arg0_0) -> cata.Tree.Const arg0_0 |> treeStack.Add
|
||||
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||
instructions.Add (Instruction.Tree_Pair (arg2_0))
|
||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||
@@ -121,8 +121,8 @@ module TreeCata =
|
||||
|
||||
/// Execute the catamorphism.
|
||||
let runTreeBuilder
|
||||
(cata : TreeCata<'b, 'a, 'TreeBuilderRet, 'TreeRet>)
|
||||
(x : TreeBuilder<'b, 'a>)
|
||||
(cata : TreeCata<'a, 'a, 'TreeBuilderRet, 'TreeRet>)
|
||||
(x : TreeBuilder<'a, 'a>)
|
||||
: 'TreeBuilderRet
|
||||
=
|
||||
let instructions = ResizeArray ()
|
||||
@@ -131,7 +131,7 @@ module TreeCata =
|
||||
Seq.exactlyOne treeBuilderRetStack
|
||||
|
||||
/// Execute the catamorphism.
|
||||
let runTree (cata : TreeCata<'b, 'a, 'TreeBuilderRet, 'TreeRet>) (x : Tree<'a, 'b>) : 'TreeRet =
|
||||
let runTree (cata : TreeCata<'a, 'a, 'TreeBuilderRet, 'TreeRet>) (x : Tree<'a, 'a>) : 'TreeRet =
|
||||
let instructions = ResizeArray ()
|
||||
instructions.Add (Instruction.Process__Tree x)
|
||||
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
||||
|
||||
@@ -33,8 +33,8 @@ module FileSystemItemCata =
|
||||
| Process__FileSystemItem of FileSystemItem
|
||||
| FileSystemItem_Directory of string * int * int
|
||||
|
||||
let private loop (cata : FileSystemCata<'FileSystemItem>) (instructions : ResizeArray<Instruction>) =
|
||||
let fileSystemItemStack = ResizeArray<'FileSystemItem> ()
|
||||
let private loop (cata : FileSystemCata<_>) (instructions : ResizeArray<Instruction>) =
|
||||
let fileSystemItemStack = ResizeArray ()
|
||||
|
||||
while instructions.Count > 0 do
|
||||
let currentInstruction = instructions.[instructions.Count - 1]
|
||||
@@ -108,8 +108,8 @@ module GiftCata =
|
||||
| Gift_Boxed
|
||||
| Gift_WithACard of string
|
||||
|
||||
let private loop (cata : GiftCata<'Gift>) (instructions : ResizeArray<Instruction>) =
|
||||
let giftStack = ResizeArray<'Gift> ()
|
||||
let private loop (cata : GiftCata<_>) (instructions : ResizeArray<Instruction>) =
|
||||
let giftStack = ResizeArray ()
|
||||
|
||||
while instructions.Count > 0 do
|
||||
let currentInstruction = instructions.[instructions.Count - 1]
|
||||
|
||||
@@ -129,230 +129,24 @@ module ToGetExtensionMethodJsonParseExtension =
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : ToGetExtensionMethod =
|
||||
let Whiskey = System.Numerics.BigInteger.Parse (node.["whiskey"].ToJsonString ())
|
||||
|
||||
let Victor =
|
||||
(match node.["victor"] with
|
||||
let Sailor =
|
||||
(match node.["sailor"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
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")
|
||||
sprintf "Required key '%s' not found on JSON object" ("sailor")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<float> ()
|
||||
|
||||
let Bravo =
|
||||
(match node.["bravo"] with
|
||||
let Soldier =
|
||||
(match node.["soldier"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("bravo")
|
||||
sprintf "Required key '%s' not found on JSON object" ("soldier")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
@@ -360,12 +154,24 @@ module ToGetExtensionMethodJsonParseExtension =
|
||||
.GetValue<string> ()
|
||||
|> System.Uri
|
||||
|
||||
let Alpha =
|
||||
(match node.["alpha"] with
|
||||
let Tailor =
|
||||
(match node.["tailor"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("alpha")
|
||||
sprintf "Required key '%s' not found on JSON object" ("tailor")
|
||||
)
|
||||
)
|
||||
| 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)
|
||||
@@ -373,25 +179,8 @@ module ToGetExtensionMethodJsonParseExtension =
|
||||
.GetValue<string> ()
|
||||
|
||||
{
|
||||
Alpha = Alpha
|
||||
Bravo = Bravo
|
||||
Charlie = Charlie
|
||||
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
|
||||
Tinker = Tinker
|
||||
Tailor = Tailor
|
||||
Soldier = Soldier
|
||||
Sailor = Sailor
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
namespace SomeNamespace
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -26,11 +25,10 @@ type internal PublicTypeMock =
|
||||
|
||||
interface IPublicType with
|
||||
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)
|
||||
namespace SomeNamespace
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -51,11 +49,10 @@ type public PublicTypeInternalFalseMock =
|
||||
|
||||
interface IPublicTypeInternalFalse with
|
||||
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)
|
||||
namespace SomeNamespace
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -74,10 +71,9 @@ type internal InternalTypeMock =
|
||||
|
||||
interface InternalType with
|
||||
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
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -96,10 +92,9 @@ type private PrivateTypeMock =
|
||||
|
||||
interface PrivateType with
|
||||
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
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -118,10 +113,9 @@ type private PrivateTypeInternalFalseMock =
|
||||
|
||||
interface PrivateTypeInternalFalse with
|
||||
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
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -137,10 +131,9 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
@@ -166,9 +159,9 @@ type internal CurriedMock<'a> =
|
||||
}
|
||||
|
||||
interface Curried<'a> with
|
||||
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.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (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.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)) =
|
||||
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
@@ -178,31 +171,3 @@ type internal CurriedMock<'a> =
|
||||
|
||||
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)
|
||||
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,40 +87,6 @@ module PureGymApi =
|
||||
}
|
||||
|> (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) =
|
||||
async {
|
||||
let! ct = Async.CancellationToken
|
||||
@@ -322,52 +288,7 @@ module PureGymApi =
|
||||
| v -> v),
|
||||
System.Uri (
|
||||
("/v2/gymSessions/member"
|
||||
+ (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="
|
||||
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
||||
+ "&toDate="
|
||||
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
||||
@@ -1219,69 +1140,6 @@ module ApiWithHeaders =
|
||||
member _.SomeHeader : string = someHeader ()
|
||||
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) =
|
||||
async {
|
||||
let! ct = Async.CancellationToken
|
||||
|
||||
@@ -210,7 +210,7 @@ module InnerTypeWithBothJsonParseExtension =
|
||||
|
||||
let value =
|
||||
(kvp.Value).AsArray ()
|
||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Char> ())
|
||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<char> ())
|
||||
|> List.ofSeq
|
||||
|
||||
key, value
|
||||
|
||||
@@ -32,27 +32,10 @@ type JsonRecordType =
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
type ToGetExtensionMethod =
|
||||
{
|
||||
Alpha : string
|
||||
Bravo : System.Uri
|
||||
Charlie : 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
|
||||
Tinker : string
|
||||
Tailor : int
|
||||
Soldier : System.Uri
|
||||
Sailor : float
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
|
||||
@@ -33,8 +33,8 @@ module MyListCata =
|
||||
| Process__MyList of MyList<'a>
|
||||
| MyList_Cons of 'a
|
||||
|
||||
let private loop (cata : MyListCata<'a, 'MyList>) (instructions : ResizeArray<Instruction<'a>>) =
|
||||
let myListStack = ResizeArray<'MyList> ()
|
||||
let private loop (cata : MyListCata<_, _>) (instructions : ResizeArray<Instruction<_>>) =
|
||||
let myListStack = ResizeArray ()
|
||||
|
||||
while instructions.Count > 0 do
|
||||
let currentInstruction = instructions.[instructions.Count - 1]
|
||||
@@ -89,8 +89,8 @@ module MyList2Cata =
|
||||
| Process__MyList2 of MyList2<'a>
|
||||
| MyList2_Cons of 'a
|
||||
|
||||
let private loop (cata : MyList2Cata<'a, 'MyList2>) (instructions : ResizeArray<Instruction<'a>>) =
|
||||
let myList2Stack = ResizeArray<'MyList2> ()
|
||||
let private loop (cata : MyList2Cata<_, _>) (instructions : ResizeArray<Instruction<_>>) =
|
||||
let myList2Stack = ResizeArray ()
|
||||
|
||||
while instructions.Count > 0 do
|
||||
let currentInstruction = instructions.[instructions.Count - 1]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
namespace SomeNamespace
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<GenerateMock>]
|
||||
@@ -42,9 +41,3 @@ type Curried<'a> =
|
||||
abstract Mem4 : (int * string) -> ('a * int) -> string
|
||||
abstract Mem5 : x : int * string -> ('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,9 +17,6 @@ type IPureGymApi =
|
||||
[<Get "v1/gyms/{gym_id}/attendance">]
|
||||
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">]
|
||||
abstract GetMember : ?ct : CancellationToken -> Member Task
|
||||
|
||||
@@ -41,10 +38,6 @@ type IPureGymApi =
|
||||
abstract GetSessions :
|
||||
[<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
|
||||
[<Post "users/new">]
|
||||
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
||||
@@ -127,8 +120,7 @@ type internal IApiWithoutBaseAddress =
|
||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||
[<BasePath "foo">]
|
||||
type IApiWithBasePath =
|
||||
// Example where we use the bundled attributes rather than RestEase's
|
||||
[<WoofWare.Myriad.Plugins.RestEase.Get "endpoint/{param}">]
|
||||
[<Get "endpoint/{param}">]
|
||||
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
||||
|
||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||
@@ -149,16 +141,3 @@ type IApiWithHeaders =
|
||||
|
||||
[<Get "endpoint/{param}">]
|
||||
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>
|
||||
|
||||
12
README.md
12
README.md
@@ -332,7 +332,7 @@ thereby allowing the programmer to use F#'s record-update syntax.
|
||||
Takes a collection of mutually recursive discriminated unions:
|
||||
|
||||
```fsharp
|
||||
[<CreateCatamorphism "MyCata">]
|
||||
[<CreateCatamorphism>]
|
||||
type Expr =
|
||||
| Const of Const
|
||||
| Pair of Expr * Expr * PairOpKind
|
||||
@@ -356,7 +356,7 @@ type ExprBuilderCata<'Expr, 'ExprBuilder> =
|
||||
abstract Child : 'ExprBuilder -> 'ExprBuilder
|
||||
abstract Parent : 'Expr -> 'ExprBuilder
|
||||
|
||||
type MyCata<'Expr, 'ExprBuilder> =
|
||||
type Cata<'Expr, 'ExprBuilder> =
|
||||
{
|
||||
Expr : ExprCata<'Expr, 'ExprBuilder>
|
||||
ExprBuilder : ExprBuilderCata<'Expr, 'ExprBuilder>
|
||||
@@ -364,10 +364,10 @@ type MyCata<'Expr, 'ExprBuilder> =
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module ExprCata =
|
||||
let runExpr (cata : MyCata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
|
||||
let runExpr (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
|
||||
failwith "this is implemented"
|
||||
|
||||
let runExprBuilder (cata : MyCata<'ExprRet, 'ExprBuilderRet>) (x : ExprBuilder) : 'ExprBuilderRet =
|
||||
let runExprBuilder (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : ExprBuilder) : 'ExprBuilderRet =
|
||||
failwith "this is implemented"
|
||||
```
|
||||
|
||||
@@ -381,10 +381,6 @@ and then each time you only plug in what you want to do.
|
||||
* Mutually recursive DUs are supported (as in the example above).
|
||||
Every DU in a recursive `type Foo... and Bar...` knot will be given an appropriate cata, as long as any one of those DUs has the `[<CreateCatamorphism>]` attribute.
|
||||
* There is *limited* support for records and for lists.
|
||||
* There is *extremely brittle* support for generics in the DUs you are cata'ing over.
|
||||
It is based on the names of the generic parameters, so you must ensure that generic parameters with the same name have the same meaning across the various cases in your recursive knot of DUs.
|
||||
(If you overstep the bounds of what this generator can do, you will get compile-time errors, e.g. with generics being constrained to each other's values.)
|
||||
See the [List tests](./WoofWare.Myriad.Plugins.Test/TestCataGenerator/TestMyList2.fs) for an example, where we re-implement `FSharpList<'a>`.
|
||||
|
||||
### Limitations
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
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,33 +18,4 @@ WoofWare.Myriad.Plugins.JsonSerializeAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
||||
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
|
||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
||||
@@ -11,9 +11,11 @@ module TestSurface =
|
||||
[<Test>]
|
||||
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
||||
|
||||
(*
|
||||
[<Test>]
|
||||
let ``Check version against remote`` () =
|
||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
||||
*)
|
||||
|
||||
[<Test ; Explicit>]
|
||||
let ``Update API surface`` () =
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.39" />
|
||||
<PackageReference Include="ApiSurface" Version="4.0.28" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Attributes.fs"/>
|
||||
<Compile Include="RestEase.fs" />
|
||||
<EmbeddedResource Include="version.json"/>
|
||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||
<None Include="..\README.md">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": "3.0",
|
||||
"version": "2.2",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
"pathFilters": null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ open FsCheck
|
||||
|
||||
[<TestFixture>]
|
||||
module TestCataGenerator =
|
||||
let idCata<'a, 'b> : TreeCata<'a, 'b, _, _> =
|
||||
let idCata : TreeCata<_, _> =
|
||||
{
|
||||
Tree =
|
||||
{ new TreeCataCase<_, _, _, _> with
|
||||
member _.Const x y = Const (x, y)
|
||||
{ new TreeCataCase<_, _> with
|
||||
member _.Const x = Const x
|
||||
member _.Pair x y z = Pair (x, y, z)
|
||||
member _.Sequential xs = Sequential xs
|
||||
member _.Builder x b = Builder (x, b)
|
||||
}
|
||||
TreeBuilder =
|
||||
{ new TreeBuilderCataCase<_, _, _, _> with
|
||||
{ new TreeBuilderCataCase<_, _> with
|
||||
member _.Child x = Child x
|
||||
member _.Parent x = Parent x
|
||||
}
|
||||
@@ -27,7 +27,7 @@ module TestCataGenerator =
|
||||
[<Test>]
|
||||
let ``Example`` () =
|
||||
let x =
|
||||
Tree.Pair (Tree.Const (Const.Verbatim 0, "hi"), Tree.Const (Const.String "", "bye"), PairOpKind.ThenDoSeq)
|
||||
Tree.Pair (Tree.Const (Const.Int 0), Tree.Const (Const.String ""), PairOpKind.ThenDoSeq)
|
||||
|
||||
TreeCata.runTree idCata x |> shouldEqual x
|
||||
|
||||
@@ -36,7 +36,7 @@ module TestCataGenerator =
|
||||
let ``Cata works`` () =
|
||||
let builderCases = ref 0
|
||||
|
||||
let property (x : Tree<int, string>) =
|
||||
let property (x : Tree) =
|
||||
match x with
|
||||
| Tree.Builder _ -> Interlocked.Increment builderCases |> ignore
|
||||
| _ -> ()
|
||||
|
||||
@@ -21,6 +21,7 @@ module TestMyList =
|
||||
Tail = tail
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[<Test>]
|
||||
|
||||
@@ -14,8 +14,9 @@ module TestMyList2 =
|
||||
{ new MyList2CataCase<'a, _> with
|
||||
member _.Nil = MyList2.Nil
|
||||
|
||||
member _.Cons (head : 'a) (tail : MyList2<'a>) = MyList2.Cons (head, tail)
|
||||
member _.Cons head tail = MyList2.Cons (head, tail)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[<Test>]
|
||||
|
||||
@@ -89,7 +89,6 @@ module TestPureGymRestApi =
|
||||
let api = PureGymApi.make client
|
||||
|
||||
api.GetGymAttendance(requestedGym).Result |> shouldEqual expected
|
||||
api.GetGymAttendance'(requestedGym).Result |> shouldEqual expected
|
||||
|
||||
let memberCases =
|
||||
PureGymDtos.memberCases |> List.allPairs baseUris |> List.map TestCaseData
|
||||
@@ -235,33 +234,6 @@ module TestPureGymRestApi =
|
||||
|
||||
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>]
|
||||
let ``URI example`` () =
|
||||
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System
|
||||
open System.Numerics
|
||||
open System.Text.Json.Nodes
|
||||
open ConsumePlugin
|
||||
open NUnit.Framework
|
||||
@@ -13,62 +12,15 @@ module TestExtensionMethod =
|
||||
[<Test>]
|
||||
let ``Parse via extension method`` () =
|
||||
let json =
|
||||
"""{
|
||||
"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
|
||||
}"""
|
||||
"""{"tinker": "job", "tailor": 3, "soldier": "https://example.com", "sailor": 3.1}"""
|
||||
|> JsonNode.Parse
|
||||
|
||||
let expected =
|
||||
{
|
||||
Alpha = "hello!"
|
||||
Bravo = Uri "https://example.com"
|
||||
Charlie = 0.3341
|
||||
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
|
||||
Tinker = "job"
|
||||
Tailor = 3
|
||||
Soldier = Uri "https://example.com"
|
||||
Sailor = 3.1
|
||||
}
|
||||
|
||||
let actual = ToGetExtensionMethod.jsonParse json
|
||||
|
||||
actual |> shouldEqual expected
|
||||
ToGetExtensionMethod.jsonParse json |> shouldEqual expected
|
||||
|
||||
@@ -33,12 +33,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.39"/>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.28"/>
|
||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.0.1"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -54,7 +54,6 @@ type internal InterfaceType =
|
||||
{
|
||||
Attributes : SynAttribute list
|
||||
Name : LongIdent
|
||||
Inherits : SynType list
|
||||
Members : MemberInfo list
|
||||
Properties : PropertyInfo list
|
||||
Generics : SynTyparDecls option
|
||||
@@ -77,9 +76,6 @@ type internal AdtNode =
|
||||
{
|
||||
Type : SynType
|
||||
Name : Ident option
|
||||
/// An ordered list, so you can look up any given generic within `this.Type`
|
||||
/// to discover what its index is in the parent DU which defined it.
|
||||
GenericsOfParent : SynTyparDecl list
|
||||
}
|
||||
|
||||
/// A DU is a sum of products (e.g. `type Thing = Foo of a * b`);
|
||||
@@ -89,39 +85,11 @@ type internal AdtProduct =
|
||||
{
|
||||
Name : SynIdent
|
||||
Fields : AdtNode list
|
||||
/// This AdtProduct represents a product in which there might be
|
||||
/// some bound type parameters. This field lists the bound
|
||||
/// type parameters in the order they appeared on the parent type.
|
||||
Generics : SynTyparDecl list
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal AstHelper =
|
||||
|
||||
/// Given e.g. "byte", returns "System.Byte".
|
||||
let qualifyPrimitiveType (typeName : string) : LongIdent option =
|
||||
match typeName with
|
||||
| "float32"
|
||||
| "single" -> [ "System" ; "Single" ] |> Some
|
||||
| "float"
|
||||
| "double" -> [ "System" ; "Double" ] |> Some
|
||||
| "byte"
|
||||
| "uint8" -> [ "System" ; "Byte" ] |> Some
|
||||
| "sbyte"
|
||||
| "int8" -> [ "System" ; "SByte" ] |> Some
|
||||
| "int16" -> [ "System" ; "Int16" ] |> Some
|
||||
| "int"
|
||||
| "int32" -> [ "System" ; "Int32" ] |> Some
|
||||
| "int64" -> [ "System" ; "Int64" ] |> Some
|
||||
| "uint16" -> [ "System" ; "UInt16" ] |> Some
|
||||
| "uint"
|
||||
| "uint32" -> [ "System" ; "UInt32" ] |> Some
|
||||
| "uint64" -> [ "System" ; "UInt64" ] |> Some
|
||||
| "char" -> [ "System" ; "Char" ] |> Some
|
||||
| "decimal" -> [ "System" ; "Decimal" ] |> Some
|
||||
| _ -> None
|
||||
|> Option.map (List.map Ident.Create)
|
||||
|
||||
let instantiateRecord (fields : (RecordFieldName * SynExpr option) list) : SynExpr =
|
||||
let fields =
|
||||
fields
|
||||
@@ -156,11 +124,6 @@ module internal AstHelper =
|
||||
// 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
|
||||
@@ -372,18 +335,7 @@ module internal AstHelper =
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
| arg ->
|
||||
{
|
||||
HasParen = false
|
||||
Args =
|
||||
{
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = arg
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
| _ -> failwith $"Unrecognised args in interface method declaration: %+A{args}"
|
||||
|> fun ty ->
|
||||
{ ty with
|
||||
HasParen = ty.HasParen || hasParen
|
||||
@@ -427,26 +379,22 @@ module internal AstHelper =
|
||||
|
||||
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
||||
|
||||
let members, inherits =
|
||||
let members, properties =
|
||||
match synTypeDefnRepr with
|
||||
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
||||
members
|
||||
|> List.map (fun defn ->
|
||||
match defn with
|
||||
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> Choice1Of2 (parseMember slotSig flags)
|
||||
| SynMemberDefn.Inherit (baseType, _asIdent, _) -> Choice2Of2 baseType
|
||||
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> parseMember slotSig flags
|
||||
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
||||
)
|
||||
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
||||
|> List.partitionChoice
|
||||
|
||||
let members, properties = members |> List.partitionChoice
|
||||
|
||||
{
|
||||
Members = members
|
||||
Properties = properties
|
||||
Name = interfaceName
|
||||
Inherits = inherits
|
||||
Attributes = attrs
|
||||
Generics = typars
|
||||
Accessibility = accessibility
|
||||
@@ -487,30 +435,15 @@ module internal AstHelper =
|
||||
{
|
||||
Type = ty
|
||||
Name = id
|
||||
GenericsOfParent = typars
|
||||
}
|
||||
)
|
||||
Generics = typars
|
||||
}
|
||||
)
|
||||
|
||||
cases, typars, access
|
||||
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
||||
|
||||
let getRecordFields (SynTypeDefn.SynTypeDefn (typeInfo, repr, _, _, _, _)) : AdtNode list =
|
||||
let (SynComponentInfo.SynComponentInfo (typeParams = typars)) = typeInfo
|
||||
|
||||
let typars =
|
||||
match typars with
|
||||
| None -> []
|
||||
| Some (SynTyparDecls.PrefixList (decls, _)) -> decls
|
||||
| Some (SynTyparDecls.SinglePrefix (l, _)) -> [ l ]
|
||||
| Some (SynTyparDecls.PostfixList (decls, constraints, _)) ->
|
||||
if not constraints.IsEmpty then
|
||||
failwith "Constrained type parameters not currently supported"
|
||||
|
||||
decls
|
||||
|
||||
let getRecordFields (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : AdtNode list =
|
||||
match repr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_, fields, _), _) ->
|
||||
fields
|
||||
@@ -518,7 +451,6 @@ module internal AstHelper =
|
||||
{
|
||||
Name = ident
|
||||
Type = ty
|
||||
GenericsOfParent = typars
|
||||
}
|
||||
)
|
||||
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
||||
@@ -531,11 +463,6 @@ module internal SynTypePatterns =
|
||||
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 ->
|
||||
@@ -581,23 +508,14 @@ module internal SynTypePatterns =
|
||||
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 =
|
||||
/// Returns the string name of the type.
|
||||
let (|PrimitiveType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> AstHelper.qualifyPrimitiveType i.idText
|
||||
| [ i ] ->
|
||||
[ "string" ; "float" ; "int" ; "bool" ; "char" ]
|
||||
|> List.tryFind (fun s -> s = i.idText)
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
|
||||
@@ -35,10 +35,8 @@ module internal CataGenerator =
|
||||
/// The relationship this field has with the parent type (or the
|
||||
/// recursive knot of parent types)
|
||||
Description : FieldDescription
|
||||
/// Any generic parameters this field consumes.
|
||||
/// This only makes sense in the context of a UnionAnalysis:
|
||||
/// it is an index into the parent Union's collection of generic parameters.
|
||||
RequiredGenerics : int list option
|
||||
/// Any generic parameters this field consumes
|
||||
RequiredGenerics : SynType list option
|
||||
}
|
||||
|
||||
type CataUnionRecordField = (Ident * CataUnionBasicField) list
|
||||
@@ -121,10 +119,12 @@ module internal CataGenerator =
|
||||
(userProvidedTypars : SynTyparDecl list)
|
||||
(allArtificialTypars : SynType list)
|
||||
(relevantTypar : SynType)
|
||||
(analysis : UnionAnalysis)
|
||||
(unionType : SynTypeDefn)
|
||||
: SynBinding
|
||||
=
|
||||
let relevantTypeName = analysis.ParentTypeName
|
||||
let relevantTypeName =
|
||||
match unionType with
|
||||
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (longId = id), _, _, _, _, _) -> List.last id
|
||||
|
||||
let allArtificialTyparNames =
|
||||
allArtificialTypars
|
||||
@@ -134,11 +134,7 @@ module internal CataGenerator =
|
||||
| _ -> failwith "logic error in generator"
|
||||
)
|
||||
|
||||
let userProvidedTyparsForCase =
|
||||
analysis.Typars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, ty)) -> SynType.Var (ty, range0))
|
||||
|
||||
let userProvidedTyparsForCata =
|
||||
let userProvidedTypars =
|
||||
userProvidedTypars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, ty)) -> SynType.Var (ty, range0))
|
||||
|
||||
@@ -149,7 +145,7 @@ module internal CataGenerator =
|
||||
|
||||
let inputObjectType =
|
||||
let baseType =
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent relevantTypeName)
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ relevantTypeName ])
|
||||
|
||||
if userProvidedTypars.Length = 0 then
|
||||
baseType
|
||||
@@ -157,7 +153,7 @@ module internal CataGenerator =
|
||||
SynType.App (
|
||||
baseType,
|
||||
Some range0,
|
||||
userProvidedTyparsForCase,
|
||||
userProvidedTypars,
|
||||
List.replicate (userProvidedTypars.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
@@ -174,7 +170,7 @@ module internal CataGenerator =
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataName ]),
|
||||
Some range0,
|
||||
userProvidedTyparsForCata @ allArtificialTypars,
|
||||
userProvidedTypars @ allArtificialTypars,
|
||||
List.replicate (userProvidedTypars.Length + allArtificialTypars.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
@@ -198,8 +194,8 @@ module internal CataGenerator =
|
||||
None
|
||||
),
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateString ("run" + List.last(relevantTypeName).idText),
|
||||
[ SynPat.CreateParen cataObject ; SynPat.CreateParen inputObject ]
|
||||
SynLongIdent.CreateString ("run" + relevantTypeName.idText),
|
||||
[ SynPat.CreateParen (cataObject) ; SynPat.CreateParen inputObject ]
|
||||
),
|
||||
Some (SynBindingReturnInfo.Create relevantTypar),
|
||||
SynExpr.CreateTyped (
|
||||
@@ -223,7 +219,10 @@ module internal CataGenerator =
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "Add" ]),
|
||||
SynExpr.CreateParen (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent analysis.AssociatedProcessInstruction,
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create
|
||||
[ "Instruction" ; "Process__" + relevantTypeName.idText ]
|
||||
),
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "x")
|
||||
)
|
||||
)
|
||||
@@ -304,19 +303,14 @@ module internal CataGenerator =
|
||||
/// Get the fields of this particular union case, and describe their relation to the
|
||||
/// recursive knot of user-provided DUs for which we are creating a cata.
|
||||
let analyse
|
||||
(availableGenerics : SynTyparDecl list)
|
||||
(allRecordTypes : SynTypeDefn list)
|
||||
(allUnionTypes : SynTypeDefn list)
|
||||
(argIndex : int)
|
||||
(fields : AdtNode list)
|
||||
: CataUnionBasicField list
|
||||
=
|
||||
let availableGenerics =
|
||||
availableGenerics
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident)
|
||||
|
||||
let rec go (prefix : string) (name : Ident option) (ty : SynType) : CataUnionBasicField =
|
||||
let dealWithPrimitive (typeArgs : int list option) (ty : SynType) (typeName : LongIdent) =
|
||||
let dealWithPrimitive (typeArgs : SynType list option) (ty : SynType) (typeName : LongIdent) =
|
||||
let key = typeName |> List.map _.idText |> String.concat "/"
|
||||
|
||||
let isKnownUnion =
|
||||
@@ -347,7 +341,7 @@ module internal CataGenerator =
|
||||
RequiredGenerics = typeArgs
|
||||
}
|
||||
|
||||
let rec dealWithType (typeArgs : int list option) (stripped : SynType) =
|
||||
let rec dealWithType (typeArgs : SynType list option) (stripped : SynType) =
|
||||
match stripped with
|
||||
| ListType child ->
|
||||
let gone = go (prefix + "_") None child
|
||||
@@ -388,20 +382,7 @@ module internal CataGenerator =
|
||||
| SynType.App (ty, _, childTypeArgs, _, _, _, _) ->
|
||||
match typeArgs with
|
||||
| Some _ -> failwithf "Nested applications of types not supported in %+A" ty
|
||||
| None ->
|
||||
let childTypeArgs =
|
||||
childTypeArgs
|
||||
|> List.map (fun generic ->
|
||||
let generic =
|
||||
match generic with
|
||||
| SynType.Var (SynTypar.SynTypar (name, _, _), _) -> name
|
||||
| _ -> failwithf "Unrecognised generic arg: %+A" generic
|
||||
|
||||
availableGenerics
|
||||
|> List.findIndex (fun knownGeneric -> knownGeneric.idText = generic.idText)
|
||||
)
|
||||
|
||||
dealWithType (Some childTypeArgs) (SynType.stripOptionalParen ty)
|
||||
| None -> dealWithType (Some childTypeArgs) (SynType.stripOptionalParen ty)
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ty, _, _)) -> dealWithPrimitive typeArgs stripped ty
|
||||
| SynType.Var (typar, _) ->
|
||||
{
|
||||
@@ -476,8 +457,6 @@ module internal CataGenerator =
|
||||
{
|
||||
Name = name |> Option.map Ident.lowerFirstLetter
|
||||
Type = ty
|
||||
// TODO this is definitely wrong
|
||||
GenericsOfParent = []
|
||||
}
|
||||
)
|
||||
|
||||
@@ -520,7 +499,6 @@ module internal CataGenerator =
|
||||
false,
|
||||
range0
|
||||
)
|
||||
GenericsOfParent = union.Typars
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
@@ -533,28 +511,12 @@ module internal CataGenerator =
|
||||
|
||||
/// Build the DU which defines the states our state machine can be in.
|
||||
let createInstructionType (analysis : UnionAnalysis list) : SynTypeDefn =
|
||||
let parentGenerics =
|
||||
analysis
|
||||
|> List.collect _.Typars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||
|> List.distinct
|
||||
|> List.map (fun i ->
|
||||
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||
)
|
||||
|
||||
// One union case for each union type, and then
|
||||
// a union case for each union case which contains a recursive reference.
|
||||
let casesFromProcess : SynUnionCase list =
|
||||
baseCases analysis
|
||||
|> List.map (fun unionCase ->
|
||||
let fields =
|
||||
unionCase.Fields
|
||||
|> List.map (fun field ->
|
||||
// TODO: adjust type parameters
|
||||
SynField.Create field.Type
|
||||
)
|
||||
|
||||
SynUnionCase.Create (unionCase.Name, fields)
|
||||
SynUnionCase.Create (unionCase.Name, unionCase.Fields |> List.map (fun f -> SynField.Create f.Type))
|
||||
)
|
||||
|
||||
let casesFromCases =
|
||||
@@ -566,22 +528,14 @@ module internal CataGenerator =
|
||||
let cases = casesFromProcess @ casesFromCases
|
||||
|
||||
let typars =
|
||||
let count = analysis |> List.map (fun x -> List.length x.Typars) |> List.max
|
||||
|
||||
if analysis |> List.forall (fun x -> x.Typars.IsEmpty) then
|
||||
None
|
||||
else
|
||||
|
||||
let typars =
|
||||
analysis
|
||||
|> List.collect _.Typars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||
|> List.distinct
|
||||
|> List.map (fun i ->
|
||||
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||
)
|
||||
|
||||
Some (SynTyparDecls.PostfixList (typars, [], range0))
|
||||
// TODO: deduplicate names where we have the same generic across multiple DUs
|
||||
analysis
|
||||
|> List.collect _.Typars
|
||||
|> fun x ->
|
||||
if x.IsEmpty then
|
||||
None
|
||||
else
|
||||
Some (SynTyparDecls.PostfixList (x, [], range0))
|
||||
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.SynComponentInfo (
|
||||
@@ -679,26 +633,7 @@ module internal CataGenerator =
|
||||
[ SynType.Var (generics.[getNameKeyUnion ty], range0) ],
|
||||
true
|
||||
)
|
||||
| FieldDescription.NonRecursive ty ->
|
||||
match field.RequiredGenerics with
|
||||
| None -> ty
|
||||
| Some generics ->
|
||||
let generics =
|
||||
generics
|
||||
|> List.map (fun i ->
|
||||
let (SynTyparDecl.SynTyparDecl (_, typar)) = analysis.Typars.[i]
|
||||
SynType.Var (typar, range0)
|
||||
)
|
||||
|
||||
SynType.App (
|
||||
ty,
|
||||
Some range0,
|
||||
generics,
|
||||
List.replicate (generics.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
)
|
||||
| FieldDescription.NonRecursive ty -> ty
|
||||
|
||||
SynType.Fun (
|
||||
SynType.SignatureParameter (
|
||||
@@ -785,11 +720,7 @@ module internal CataGenerator =
|
||||
|
||||
let userInputGenerics =
|
||||
analysis.Typars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||
|> List.distinct
|
||||
|> List.map (fun i ->
|
||||
SynType.Var (SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false), range0)
|
||||
)
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||
|
||||
let ty =
|
||||
SynType.App (
|
||||
@@ -820,11 +751,9 @@ module internal CataGenerator =
|
||||
// A "real" generic for each generic in the user-provided type
|
||||
let genericsFromUserInput =
|
||||
analysis
|
||||
|> List.collect _.Typars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||
|> List.distinct
|
||||
|> List.map (fun i ->
|
||||
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||
|> List.collect (fun analysis ->
|
||||
// TODO: deduplicate generics with the same name from different cases
|
||||
analysis.Typars
|
||||
)
|
||||
|
||||
let genericsFromCata =
|
||||
@@ -877,18 +806,21 @@ module internal CataGenerator =
|
||||
prod.Fields
|
||||
|> List.indexed
|
||||
|> List.collect (fun (i, node) ->
|
||||
let availableGenerics =
|
||||
match node.Type with
|
||||
| SynType.App (_, _, vars, _, _, _, _) -> vars
|
||||
| _ -> []
|
||||
|
||||
match getNameUnion node.Type with
|
||||
| None ->
|
||||
analyse typars allRecordTypes allUnionTypes i [ node ]
|
||||
|> List.map CataUnionField.Basic
|
||||
analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic
|
||||
| Some name ->
|
||||
|
||||
match Map.tryFind (List.last(name).idText) recordTypes with
|
||||
| None ->
|
||||
analyse typars allRecordTypes allUnionTypes i [ node ]
|
||||
|> List.map CataUnionField.Basic
|
||||
analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic
|
||||
| Some fields ->
|
||||
List.zip fields (analyse typars allRecordTypes allUnionTypes i fields)
|
||||
List.zip fields (analyse allRecordTypes allUnionTypes i fields)
|
||||
|> List.map (fun (field, analysis) -> Option.get field.Name, analysis)
|
||||
|> CataUnionField.Record
|
||||
|> List.singleton
|
||||
@@ -1378,20 +1310,16 @@ module internal CataGenerator =
|
||||
None
|
||||
)
|
||||
|
||||
let userSuppliedGenerics =
|
||||
analysis
|
||||
|> List.collect _.Typars
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||
|> List.distinct
|
||||
|> List.map (fun i -> SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||
// A generic for each DU case, and a generic for each generic in the DU
|
||||
let genericCount = analysis.Length + (analysis |> List.sumBy _.Typars.Length)
|
||||
|
||||
let instructionsArrType =
|
||||
if not userSuppliedGenerics.IsEmpty then
|
||||
if genericCount > analysis.Length then
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent "Instruction",
|
||||
Some range0,
|
||||
userSuppliedGenerics |> List.map (fun x -> SynType.Var (x, range0)),
|
||||
List.replicate (userSuppliedGenerics.Length - 1) range0,
|
||||
List.replicate (genericCount - analysis.Length) (SynType.Anon range0),
|
||||
List.replicate (genericCount - analysis.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
@@ -1399,14 +1327,6 @@ module internal CataGenerator =
|
||||
else
|
||||
SynType.CreateLongIdent "Instruction"
|
||||
|
||||
let cataGenerics =
|
||||
[
|
||||
for generic in userSuppliedGenerics do
|
||||
yield SynType.Var (generic, range0)
|
||||
for case in analysis do
|
||||
yield SynType.Var (SynTypar.SynTypar (case.GenericName, TyparStaticReq.None, false), range0)
|
||||
]
|
||||
|
||||
let headPat =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateString "loop",
|
||||
@@ -1420,8 +1340,8 @@ module internal CataGenerator =
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataTypeName ]),
|
||||
Some range0,
|
||||
cataGenerics,
|
||||
List.replicate (cataGenerics.Length - 1) range0,
|
||||
List.replicate genericCount (SynType.Anon range0),
|
||||
List.replicate (genericCount - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
@@ -1536,20 +1456,7 @@ module internal CataGenerator =
|
||||
SynPat.Named (SynIdent.SynIdent (unionCase.StackName, None), false, None, range0),
|
||||
None,
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.CreateIdent (Ident.Create "ResizeArray"),
|
||||
range0,
|
||||
[
|
||||
SynType.Var (
|
||||
SynTypar.SynTypar (unionCase.GenericName, TyparStaticReq.None, false),
|
||||
range0
|
||||
)
|
||||
],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
),
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "ResizeArray"),
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
),
|
||||
range0,
|
||||
@@ -1619,21 +1526,15 @@ module internal CataGenerator =
|
||||
|> fun x -> SynType.Var (x, range0)
|
||||
)
|
||||
|
||||
let userProvidedGenerics =
|
||||
analysis
|
||||
|> List.collect _.Typars
|
||||
|> List.map (fun (SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||
|> List.distinct
|
||||
|> List.map (fun x ->
|
||||
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create x, TyparStaticReq.None, false))
|
||||
)
|
||||
let userProvidedGenerics = analysis |> List.collect (fun x -> x.Typars)
|
||||
|
||||
let runFunctions =
|
||||
List.zip analysis allTypars
|
||||
|> List.map (fun (analysis, relevantTypar) ->
|
||||
createRunFunction cataName userProvidedGenerics allTypars relevantTypar analysis
|
||||
List.zip allUnionTypes allTypars
|
||||
|> List.map (fun (unionType, relevantTypar) ->
|
||||
createRunFunction cataName userProvidedGenerics allTypars relevantTypar unionType
|
||||
)
|
||||
|
||||
|
||||
let cataStructures =
|
||||
createCataStructure analysis
|
||||
|> List.map (fun repr -> SynModuleDecl.Types ([ repr ], range0))
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
open System.Net.Http
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
@@ -80,50 +82,34 @@ module internal HttpClientGenerator =
|
||||
match attr.TypeName.AsString with
|
||||
| "Get"
|
||||
| "GetAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Get"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.GetAttribute"
|
||||
| "RestEase.Get"
|
||||
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
||||
| "Post"
|
||||
| "PostAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Post"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.PostAttribute"
|
||||
| "RestEase.Post"
|
||||
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
||||
| "Put"
|
||||
| "PutAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Put"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.PutAttribute"
|
||||
| "RestEase.Put"
|
||||
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
||||
| "Delete"
|
||||
| "DeleteAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Delete"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.DeleteAttribute"
|
||||
| "RestEase.Delete"
|
||||
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
||||
| "Head"
|
||||
| "HeadAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Head"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.HeadAttribute"
|
||||
| "RestEase.Head"
|
||||
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
||||
| "Options"
|
||||
| "OptionsAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Options"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.OptionsAttribute"
|
||||
| "RestEase.Options"
|
||||
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
||||
| "Patch"
|
||||
| "PatchAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Patch"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.PatchAttribute"
|
||||
| "RestEase.Patch"
|
||||
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
||||
| "Trace"
|
||||
| "TraceAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Trace"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.TraceAttribute"
|
||||
| "RestEase.Trace"
|
||||
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
||||
| _ -> None
|
||||
@@ -141,8 +127,7 @@ module internal HttpClientGenerator =
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
| "Header"
|
||||
| "RestEase.Header"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Header" ->
|
||||
| "RestEase.Header" ->
|
||||
match attr.ArgExpr with
|
||||
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
||||
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
||||
@@ -308,27 +293,6 @@ module internal HttpClientGenerator =
|
||||
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
||||
| 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 =
|
||||
SynExpr.CreateIdent firstValueId
|
||||
|> SynExpr.toString firstValue.Type
|
||||
@@ -337,7 +301,7 @@ module internal HttpClientGenerator =
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConstString (firstKey + "=")))
|
||||
|> SynExpr.plus (SynExpr.CreateConstString ("?" + firstKey + "="))
|
||||
|
||||
(prefix, queryParams)
|
||||
||> List.fold (fun uri (paramKey, paramValue) ->
|
||||
@@ -745,10 +709,6 @@ module internal HttpClientGenerator =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
| "RestEase.Query"
|
||||
| "RestEase.QueryAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Query"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.QueryAttribute"
|
||||
| "Query"
|
||||
| "QueryAttribute" ->
|
||||
match attr.ArgExpr with
|
||||
@@ -757,22 +717,14 @@ module internal HttpClientGenerator =
|
||||
Some (HttpAttribute.Query (Some s))
|
||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
||||
| _ -> None
|
||||
| "RestEase.Path"
|
||||
| "RestEase.PathAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Path"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.PathAttribute"
|
||||
| "Path"
|
||||
| "PathAttribute" ->
|
||||
match attr.ArgExpr |> SynExpr.stripOptionalParen with
|
||||
match attr.ArgExpr with
|
||||
| SynExpr.Const (SynConst.String (s, SynStringKind.Regular, _), _) ->
|
||||
Some (HttpAttribute.Path (PathSpec.Verbatim s))
|
||||
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
||||
| _ -> None
|
||||
| "RestEase.Body"
|
||||
| "RestEase.BodyAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Body"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BodyAttribute"
|
||||
| "Body"
|
||||
| "BodyAttribute" ->
|
||||
match attr.ArgExpr with
|
||||
@@ -788,10 +740,8 @@ module internal HttpClientGenerator =
|
||||
match attr.TypeName.AsString with
|
||||
| "BasePath"
|
||||
| "RestEase.BasePath"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BasePath"
|
||||
| "BasePathAttribute"
|
||||
| "RestEase.BasePathAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
||||
| "RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
||||
| _ -> None
|
||||
)
|
||||
|
||||
@@ -801,10 +751,8 @@ module internal HttpClientGenerator =
|
||||
match attr.TypeName.AsString with
|
||||
| "BaseAddress"
|
||||
| "RestEase.BaseAddress"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
|
||||
| "BaseAddressAttribute"
|
||||
| "RestEase.BaseAddressAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
||||
| "RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
||||
| _ -> None
|
||||
)
|
||||
|
||||
@@ -816,10 +764,6 @@ module internal HttpClientGenerator =
|
||||
=
|
||||
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 =
|
||||
interfaceType.Attributes
|
||||
|> extractHeaderInformation
|
||||
|
||||
@@ -21,9 +21,6 @@ module internal InterfaceMockGenerator =
|
||||
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
||||
| Some id -> id
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type private KnownInheritance = | IDisposable
|
||||
|
||||
let createType
|
||||
(spec : GenerateMockOutputSpec)
|
||||
(name : string)
|
||||
@@ -32,20 +29,6 @@ module internal InterfaceMockGenerator =
|
||||
(fields : SynField list)
|
||||
: 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 =
|
||||
{
|
||||
SynMemberFlags.IsInstance = false
|
||||
@@ -107,23 +90,6 @@ module internal InterfaceMockGenerator =
|
||||
)
|
||||
|> 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 =
|
||||
SynMemberDefn.Member (
|
||||
SynBinding.SynBinding (
|
||||
@@ -136,7 +102,12 @@ module internal InterfaceMockGenerator =
|
||||
SynValData.SynValData (Some synValData, SynValInfo.Empty, None),
|
||||
constructorIdent,
|
||||
Some constructorReturnType,
|
||||
AstHelper.instantiateRecord constructorFields,
|
||||
AstHelper.instantiateRecord (
|
||||
fields
|
||||
|> List.map (fun field ->
|
||||
((SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
||||
)
|
||||
),
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
{ SynExpr.synBindingTriviaZero true with
|
||||
@@ -146,21 +117,6 @@ module internal InterfaceMockGenerator =
|
||||
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 members =
|
||||
interfaceType.Members
|
||||
@@ -194,9 +150,7 @@ module internal InterfaceMockGenerator =
|
||||
|> 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}"
|
||||
SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
)
|
||||
],
|
||||
@@ -211,18 +165,10 @@ module internal InterfaceMockGenerator =
|
||||
|> List.mapi (fun i tupledArgs ->
|
||||
let args =
|
||||
tupledArgs.Args
|
||||
|> List.mapi (fun j ty ->
|
||||
match ty.Type with
|
||||
| UnitType -> SynPat.Const (SynConst.Unit, range0)
|
||||
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}")
|
||||
)
|
||||
|> List.mapi (fun j _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}"))
|
||||
|
||||
match args with
|
||||
| [] -> failwith "somehow got no args at all"
|
||||
| [ arg ] -> arg
|
||||
| args ->
|
||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|> SynPat.CreateParen
|
||||
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
|
||||
)
|
||||
|
||||
@@ -241,11 +187,7 @@ module internal InterfaceMockGenerator =
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i args ->
|
||||
args.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynExpr.CreateConst SynConst.Unit
|
||||
| _ -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|> List.mapi (fun j args -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}")
|
||||
|> SynExpr.CreateParenedTuple
|
||||
)
|
||||
|
||||
@@ -322,100 +264,11 @@ module internal InterfaceMockGenerator =
|
||||
| Some (SynAccess.Internal _), _ -> SynAccess.Internal 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 =
|
||||
{
|
||||
Name = Ident.Create name
|
||||
Fields = fields
|
||||
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
|
||||
Members = Some [ constructor ; interfaceMembers ]
|
||||
XmlDoc = Some xmlDoc
|
||||
Generics = interfaceType.Generics
|
||||
Accessibility = Some access
|
||||
@@ -480,6 +333,7 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let typeDecl = createType spec name interfaceType docString fields
|
||||
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
namespaceId,
|
||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
||||
|
||||
@@ -62,13 +62,6 @@ module internal JsonParseGenerator =
|
||||
/// {node}.AsValue().GetValue<{typeName}> ()
|
||||
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
||||
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
|
||||
| None -> node
|
||||
| Some propertyName -> assertNotNull propertyName node
|
||||
@@ -129,12 +122,7 @@ module internal JsonParseGenerator =
|
||||
|
||||
/// Given e.g. "float", returns "System.Double.Parse"
|
||||
let parseFunction (typeName : string) : LongIdent =
|
||||
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" ]
|
||||
List.append (SynExpr.qualifyPrimitiveType typeName) [ Ident.Create "Parse" ]
|
||||
|
||||
/// fun kvp -> let key = {key(kvp)} in let value = {value(kvp)} in (key, value))
|
||||
/// The inputs will be fed with appropriate SynExprs to apply them to the `kvp.Key` and `kvp.Value` args.
|
||||
@@ -264,7 +252,7 @@ module internal JsonParseGenerator =
|
||||
range0
|
||||
))
|
||||
handler
|
||||
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
||||
| PrimitiveType typeName -> asValueGetValue propertyName typeName node
|
||||
| OptionType ty ->
|
||||
parseNode None options ty (SynExpr.CreateIdentString "v")
|
||||
|> createParseLineOption node
|
||||
@@ -324,11 +312,6 @@ module internal JsonParseGenerator =
|
||||
)
|
||||
)
|
||||
|> 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 typeName =
|
||||
|
||||
@@ -107,6 +107,24 @@ module internal SynExpr =
|
||||
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen 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}
|
||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
@@ -123,22 +141,8 @@ module internal SynExpr =
|
||||
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
||||
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>()
|
||||
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
||||
let callGenericMethod (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||
@@ -307,19 +311,3 @@ module internal SynExpr =
|
||||
),
|
||||
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="Ident.fs" />
|
||||
<Compile Include="AstHelper.fs"/>
|
||||
<Compile Include="SynExpr.fs" />
|
||||
<Compile Include="SynExpr.fs"/>
|
||||
<Compile Include="SynType.fs"/>
|
||||
<Compile Include="SynAttribute.fs"/>
|
||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.10.0]" />
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.8.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
76
nix/deps.nix
76
nix/deps.nix
@@ -3,18 +3,23 @@
|
||||
{fetchNuGet}: [
|
||||
(fetchNuGet {
|
||||
pname = "fsharp-analyzers";
|
||||
version = "0.26.0";
|
||||
sha256 = "sha256-60Bl36LOb/zVNdH2SBSuQ5O41lP9dKTNZbs5vvYs+3U=";
|
||||
version = "0.24.0";
|
||||
sha256 = "sha256-cNaM/yHI28sHDGamKMrU237ltOyrR+8vPNUImB5RxjU=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "fantomas";
|
||||
version = "6.3.4";
|
||||
sha256 = "sha256-1aWqZynBkQoznenGoP0sbf1PcUXAbcHiWyECuv89xa0=";
|
||||
version = "6.3.0-alpha-007";
|
||||
sha256 = "sha256-uZw6h6k/DS4BcYtK9cv8TLS0H8MZDO3WBaPPTdtTgu0=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "ApiSurface";
|
||||
version = "4.0.39";
|
||||
sha256 = "sha256-I4K5nJbltsfL/1r+KPTIo2wUd30zsCC2pkrnIRnsRHM=";
|
||||
version = "4.0.28";
|
||||
sha256 = "1gg0dqbgbb8aqn2lxi5gf2wq969kgskby5wph6m2b3hdkz7265ak";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "coverlet.collector";
|
||||
version = "6.0.0";
|
||||
sha256 = "12j34vrkmph8lspbafnqmfnj2qvysz1jcrks2khw798s6dwv0j90";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Fantomas.Core";
|
||||
@@ -116,11 +121,21 @@
|
||||
version = "8.0.0";
|
||||
sha256 = "0055f69q3hbagqp8gl3nk0vfn4qyqyxsxyy7pd0g7wm3z28byzmx";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.CodeCoverage";
|
||||
version = "17.8.0";
|
||||
sha256 = "173wjadp3gan4x2jfjchngnc4ca4mb95h1sbb28jydfkfw0z1zvj";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.CodeCoverage";
|
||||
version = "17.9.0";
|
||||
sha256 = "1gljgi69k0fz8vy8bn6xlyxabj6q4vls2zza9wz7ng6ix3irm89r";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NET.Test.Sdk";
|
||||
version = "17.8.0";
|
||||
sha256 = "1syvl3g0hbrcgfi9rq6pld8s8hqqww4dflf1lxn59ccddyyx0gmv";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NET.Test.Sdk";
|
||||
version = "17.9.0";
|
||||
@@ -266,11 +281,21 @@
|
||||
version = "8.0.0";
|
||||
sha256 = "1gdx7n45wwia3yvang3ls92sk3wrymqcx9p349j8wba2lyjf9m44";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||
version = "17.8.0";
|
||||
sha256 = "0b0i7lmkrcfvim8i3l93gwqvkhhhfzd53fqfnygdqvkg6np0cg7m";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||
version = "17.9.0";
|
||||
sha256 = "1kgsl9w9fganbm9wvlkqgk0ag9hfi58z88rkfybc6kvg78bx89ca";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.TestHost";
|
||||
version = "17.8.0";
|
||||
sha256 = "0f5jah93kjkvxwmhwb78lw11m9pkkq9fvf135hpymmmpxqbdh97q";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.TestHost";
|
||||
version = "17.9.0";
|
||||
@@ -291,6 +316,11 @@
|
||||
version = "3.6.133";
|
||||
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NETStandard.Library";
|
||||
version = "2.0.0";
|
||||
sha256 = "1bc4ba8ahgk15m8k4nd7x406nhi0kwqzbgjk2dmw52ss553xz7iy";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NETStandard.Library";
|
||||
version = "2.0.3";
|
||||
@@ -308,23 +338,28 @@
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Common";
|
||||
version = "6.9.1";
|
||||
sha256 = "0ic3d46r9v05pkczpmskw86yzixm6iwshbw0ya8i2957nhhlymw8";
|
||||
version = "6.8.0";
|
||||
sha256 = "0l3ij8iwy7wj6s7f93lzi9168r4wz8zyin6a08iwgk7hvq44cia1";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Configuration";
|
||||
version = "6.9.1";
|
||||
sha256 = "07z4qgbibpg59j2r05ifnqdyqf2xinm33rx7gjyr1f73kzg01m33";
|
||||
version = "6.8.0";
|
||||
sha256 = "0x03p408smkmv1gv7pmvsia4lkn0xaj4wfrkl58pjf8bbv51y0yw";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Frameworks";
|
||||
version = "6.9.1";
|
||||
sha256 = "0s3az3ac53icjnmb14hfjcmkvzscvrkm62jgqf48yvsbysyhqm5s";
|
||||
version = "6.5.0";
|
||||
sha256 = "0s37d1p4md0k6d4cy6sq36f2dgkd9qfbzapxhkvi8awwh0vrynhj";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Frameworks";
|
||||
version = "6.8.0";
|
||||
sha256 = "0i2xvhgkjkjr496i3pg8hamwv6505fia45qhn7jg5m01wb3cvsjl";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Packaging";
|
||||
version = "6.9.1";
|
||||
sha256 = "0w0arkmzg3qh1brq4vm10zrsjm7nw706ld4y5kqcmvjpd16f4b4y";
|
||||
version = "6.8.0";
|
||||
sha256 = "031z4s905bxi94h3f0qy4j1b6jxdxgqgpkzqvvpfxch07szxcbim";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Protocol";
|
||||
@@ -333,13 +368,18 @@
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Versioning";
|
||||
version = "6.9.1";
|
||||
sha256 = "0xrs82dydy9cgxf0qypr01wawwnq1nf6fc7rwisb4y5v4r259fdm";
|
||||
version = "6.8.0";
|
||||
sha256 = "1sd25h46fd12ng780r02q4ijcx1imkb53kj1y2y7cwg5myh537ks";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit";
|
||||
version = "4.1.0";
|
||||
sha256 = "0fj6xwgqaxq3mrai86bklclfmjkzf038mrslwfqf4ignaz9f7g5j";
|
||||
version = "3.13.3";
|
||||
sha256 = "0wdzfkygqnr73s6lpxg5b1pwaqz9f414fxpvpdmf72bvh4jaqzv6";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit";
|
||||
version = "4.0.1";
|
||||
sha256 = "0jgiq3dbwli5r70j0bw7021d69r7bhr58s8kphlpjmf7k47l5pcd";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit3TestAdapter";
|
||||
|
||||
Reference in New Issue
Block a user