mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-27 22:59:00 +00:00
Compare commits
2 Commits
WoofWare.M
...
d86bd743af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d86bd743af | ||
|
|
dff2431bc8 |
@@ -3,16 +3,16 @@
|
|||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"fantomas": {
|
"fantomas": {
|
||||||
"version": "6.3.4",
|
"version": "6.3.0-alpha-007",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fantomas"
|
"fantomas"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fsharp-analyzers": {
|
"fsharp-analyzers": {
|
||||||
"version": "0.26.0",
|
"version": "0.24.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fsharp-analyzers"
|
"fsharp-analyzers"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ root=true
|
|||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset=utf-8
|
charset=utf-8
|
||||||
|
end_of_line=crlf
|
||||||
trim_trailing_whitespace=true
|
trim_trailing_whitespace=true
|
||||||
insert_final_newline=true
|
insert_final_newline=true
|
||||||
indent_style=space
|
indent_style=space
|
||||||
|
|||||||
10
.gitattributes
vendored
10
.gitattributes
vendored
@@ -1,5 +1,5 @@
|
|||||||
* eol=auto
|
* eol=auto
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
*.yaml text
|
*.yaml text
|
||||||
*.nix text eol=lf
|
*.nix text eol=lf
|
||||||
hooks/pre-push text eol=lf
|
hooks/pre-push text eol=lf
|
||||||
|
|||||||
85
.github/workflows/dotnet.yaml
vendored
85
.github/workflows/dotnet.yaml
vendored
@@ -1,4 +1,3 @@
|
|||||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json
|
|
||||||
name: .NET
|
name: .NET
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -29,7 +28,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -50,7 +49,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -59,7 +58,7 @@ jobs:
|
|||||||
- name: Build project
|
- name: Build project
|
||||||
run: nix develop --command dotnet build ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj
|
run: nix develop --command dotnet build ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj
|
||||||
- name: Run analyzers
|
- 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:
|
build-nix:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -67,7 +66,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -80,41 +79,20 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Run Fantomas
|
- name: Run Fantomas
|
||||||
run: nix run .#fantomas -- --check .
|
run: nix run .#fantomas -- --check .
|
||||||
|
|
||||||
check-accurate-generations:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
|
||||||
- name: Install Nix
|
|
||||||
uses: cachix/install-nix-action@V27
|
|
||||||
with:
|
|
||||||
extra_nix_config: |
|
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Whitespace change
|
|
||||||
run: "echo ' ' >> ConsumePlugin/List.fs"
|
|
||||||
- name: Generate code
|
|
||||||
run: nix develop --command dotnet build
|
|
||||||
- name: Run Fantomas
|
|
||||||
run: nix run .#fantomas -- .
|
|
||||||
- name: Verify there is no diff
|
|
||||||
run: git diff --name-only --no-color --exit-code
|
|
||||||
|
|
||||||
check-nix-format:
|
check-nix-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -127,7 +105,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -140,7 +118,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -154,7 +132,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -196,27 +174,8 @@ jobs:
|
|||||||
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
|
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
|
||||||
run: if [[ $(find packed-attribute -maxdepth 1 -name 'WoofWare.Myriad.Plugins.Attributes.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
|
run: if [[ $(find packed-attribute -maxdepth 1 -name 'WoofWare.Myriad.Plugins.Attributes.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
|
||||||
|
|
||||||
github-release-plugin-dry-run:
|
|
||||||
needs: [nuget-pack]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
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:
|
|
||||||
DRY_RUN: 1
|
|
||||||
GITHUB_TOKEN: mock-token
|
|
||||||
run: sh .github/workflows/tag.sh
|
|
||||||
|
|
||||||
all-required-checks-complete:
|
all-required-checks-complete:
|
||||||
needs: [check-dotnet-format, check-nix-format, check-accurate-generations, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack, github-release-plugin-dry-run]
|
needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "All required checks complete."
|
- run: echo "All required checks complete."
|
||||||
@@ -229,7 +188,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@V27
|
uses: cachix/install-nix-action@v25
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -247,25 +206,3 @@ jobs:
|
|||||||
path: packed-attribute
|
path: packed-attribute
|
||||||
- name: Publish to NuGet (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
|
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
|
|
||||||
|
|||||||
120
.github/workflows/tag.sh
vendored
120
.github/workflows/tag.sh
vendored
@@ -1,120 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo "Dry-run? $DRY_RUN!"
|
|
||||||
|
|
||||||
find . -maxdepth 1 -type f ! -name "$(printf "*\n*")" -name '*.nupkg' | while IFS= read -r file
|
|
||||||
do
|
|
||||||
tag=$(basename "$file" .nupkg)
|
|
||||||
git tag "$tag"
|
|
||||||
${DRY_RUN:+echo} git push origin "$tag"
|
|
||||||
done
|
|
||||||
|
|
||||||
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_body='{"tag_name":"'"$TAG"'","target_commitish":"","name":"'"$TAG"'","draft":false,"prerelease":false,"generate_release_notes":false}'
|
|
||||||
|
|
||||||
echo "cURL body: $curl_body"
|
|
||||||
|
|
||||||
failed_output=$(cat <<'EOF'
|
|
||||||
{
|
|
||||||
"message": "Validation Failed",
|
|
||||||
"errors": [
|
|
||||||
{
|
|
||||||
"resource": "Release",
|
|
||||||
"code": "already_exists",
|
|
||||||
"field": "tag_name"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"documentation_url": "https://docs.github.com/rest/releases/releases#create-a-release"
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
success_output=$(cat <<'EOF'
|
|
||||||
{
|
|
||||||
"url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases/158152116",
|
|
||||||
"assets_url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases/158152116/assets",
|
|
||||||
"upload_url": "https://uploads.github.com/repos/Smaug123/WoofWare.Myriad/releases/158152116/assets{?name,label}",
|
|
||||||
"html_url": "https://github.com/Smaug123/WoofWare.Myriad/releases/tag/WoofWare.Myriad.Plugins.2.1.30",
|
|
||||||
"id": 158152116,
|
|
||||||
"author": {
|
|
||||||
"login": "github-actions[bot]",
|
|
||||||
"id": 41898282,
|
|
||||||
"node_id": "MDM6Qm90NDE4OTgyODI=",
|
|
||||||
"avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
|
|
||||||
"gravatar_id": "",
|
|
||||||
"url": "https://api.github.com/users/github-actions%5Bbot%5D",
|
|
||||||
"html_url": "https://github.com/apps/github-actions",
|
|
||||||
"followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
|
|
||||||
"following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
|
|
||||||
"gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
|
|
||||||
"starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
|
|
||||||
"subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
|
|
||||||
"organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
|
|
||||||
"repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
|
|
||||||
"events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
|
|
||||||
"received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
|
|
||||||
"type": "Bot",
|
|
||||||
"site_admin": false
|
|
||||||
},
|
|
||||||
"node_id": "RE_kwDOJfksgc4JbTW0",
|
|
||||||
"tag_name": "WoofWare.Myriad.Plugins.2.1.30",
|
|
||||||
"target_commitish": "main",
|
|
||||||
"name": "WoofWare.Myriad.Plugins.2.1.30",
|
|
||||||
"draft": false,
|
|
||||||
"prerelease": false,
|
|
||||||
"created_at": "2024-05-30T11:00:55Z",
|
|
||||||
"published_at": "2024-05-30T11:03:02Z",
|
|
||||||
"assets": [
|
|
||||||
|
|
||||||
],
|
|
||||||
"tarball_url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/tarball/WoofWare.Myriad.Plugins.2.1.30",
|
|
||||||
"zipball_url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/zipball/WoofWare.Myriad.Plugins.2.1.30",
|
|
||||||
"body": null
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
HANDLE_OUTPUT=''
|
|
||||||
handle_error() {
|
|
||||||
ERROR_OUTPUT="$1"
|
|
||||||
exit_message=$(echo "$ERROR_OUTPUT" | jq -r --exit-status 'if .errors | length == 1 then .errors[0].code else null end')
|
|
||||||
if [ "$exit_message" = "already_exists" ] ; then
|
|
||||||
HANDLE_OUTPUT="Did not create GitHub release because it already exists at this version."
|
|
||||||
else
|
|
||||||
echo "Unexpected error output from curl: $(cat curl_output.json)"
|
|
||||||
echo "JQ output: $(exit_message)"
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
run_tests() {
|
|
||||||
handle_error "$failed_output"
|
|
||||||
if [ "$HANDLE_OUTPUT" != "Did not create GitHub release because it already exists at this version." ]; then
|
|
||||||
echo "Bad output from handler: $HANDLE_OUTPUT"
|
|
||||||
exit 3
|
|
||||||
fi
|
|
||||||
HANDLE_OUTPUT=''
|
|
||||||
echo "Tests passed."
|
|
||||||
}
|
|
||||||
|
|
||||||
run_tests
|
|
||||||
|
|
||||||
if [ "$DRY_RUN" != 1 ] ; then
|
|
||||||
if curl --fail-with-body -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 "$curl_body" > curl_output.json; then
|
|
||||||
echo "Curl succeeded."
|
|
||||||
else
|
|
||||||
handle_error "$(cat curl_output.json)"
|
|
||||||
echo "$HANDLE_OUTPUT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,27 +1,6 @@
|
|||||||
Notable changes are recorded here.
|
Notable changes are recorded here.
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 2.1.33
|
# WoofWare.Myriad.Plugins 1.4 -> 2.0
|
||||||
|
|
||||||
`JsonParse` can now deserialize the discriminated unions which `JsonSerialize` wrote out.
|
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 2.1.32, WoofWare.Myriad.Plugins.Attributes 3.1.4
|
|
||||||
|
|
||||||
`JsonSerialize` can now serialize many discriminated unions.
|
|
||||||
(This operation is inherently opinionated, because JSON does not model discriminated unions.)
|
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 2.1.20, WoofWare.Myriad.Plugins.Attributes 3.0.1
|
|
||||||
|
|
||||||
We now bundle copies of the RestEase attributes in `WoofWare.Myriad.Plugins.Attributes`, in case you don't want to take a dependency on RestEase.
|
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 2.1.15
|
|
||||||
|
|
||||||
The `GenerateMock` generator now permits a limited amount of inheritance in the record we're mocking out (specifically, `IDisposable`).
|
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 2.1.8
|
|
||||||
|
|
||||||
No change to the packages, but this is when we started creating and tagging GitHub releases, which are a better source of truth than this file.
|
|
||||||
|
|
||||||
# WoofWare.Myriad.Plugins 2.0
|
|
||||||
|
|
||||||
This transition split the attributes (e.g. `[<JsonParseAttribute>]`) into their own assembly, WoofWare.Myriad.Plugins.Attributes.
|
This transition split the attributes (e.g. `[<JsonParseAttribute>]`) into their own assembly, WoofWare.Myriad.Plugins.Attributes.
|
||||||
The new assembly has minimal dependencies, so you may safely use it from your own code.
|
The new assembly has minimal dependencies, so you may safely use it from your own code.
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ type PairOpKind =
|
|||||||
| ThenDoSeq
|
| ThenDoSeq
|
||||||
|
|
||||||
[<CreateCatamorphism "TreeCata">]
|
[<CreateCatamorphism "TreeCata">]
|
||||||
type Tree<'a, 'b> =
|
type Tree<'a> =
|
||||||
| Const of Const<'a> * 'b
|
| Const of Const<'a>
|
||||||
| Pair of Tree<'a, 'b> * Tree<'a, 'b> * PairOpKind
|
| Pair of Tree<'a> * Tree<'a> * PairOpKind
|
||||||
| Sequential of Tree<'a, 'b> list
|
| Sequential of Tree<'a> list
|
||||||
| Builder of Tree<'a, 'b> * TreeBuilder<'b, 'a>
|
| Builder of Tree<'a> * TreeBuilder<'a>
|
||||||
|
|
||||||
and TreeBuilder<'b, 'a> =
|
and TreeBuilder<'a> =
|
||||||
| Child of TreeBuilder<'b, 'a>
|
| Child of TreeBuilder<'a>
|
||||||
| Parent of Tree<'a, 'b>
|
| Parent of Tree<'a>
|
||||||
|
|||||||
@@ -12,16 +12,16 @@ namespace ConsumePlugin
|
|||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
/// 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
|
/// How to operate on the Child case
|
||||||
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
||||||
/// How to operate on the Parent case
|
/// How to operate on the Parent case
|
||||||
abstract Parent : 'Tree -> 'TreeBuilder
|
abstract Parent : 'Tree -> 'TreeBuilder
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
/// 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
|
/// How to operate on the Const case
|
||||||
abstract Const : Const<'a> -> 'b -> 'Tree
|
abstract Const : Const -> 'Tree
|
||||||
/// How to operate on the Pair case
|
/// How to operate on the Pair case
|
||||||
abstract Pair : 'Tree -> 'Tree -> PairOpKind -> 'Tree
|
abstract Pair : 'Tree -> 'Tree -> PairOpKind -> 'Tree
|
||||||
/// How to operate on the Sequential case
|
/// How to operate on the Sequential case
|
||||||
@@ -30,37 +30,37 @@ type TreeCataCase<'a, 'b, 'TreeBuilder, 'Tree> =
|
|||||||
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
||||||
|
|
||||||
/// Specifies how to perform a fold (catamorphism) over the type Tree and its friends.
|
/// 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
|
/// 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
|
/// 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
|
/// Methods to perform a catamorphism over the type Tree
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module TreeCata =
|
module TreeCata =
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
type private Instruction<'b, 'a> =
|
type private Instruction<'a, 'a> =
|
||||||
| Process__TreeBuilder of TreeBuilder<'b, 'a>
|
| Process__TreeBuilder of TreeBuilder<'a>
|
||||||
| Process__Tree of Tree<'a, 'b>
|
| Process__Tree of Tree<'a>
|
||||||
| TreeBuilder_Child
|
| TreeBuilder_Child
|
||||||
| TreeBuilder_Parent
|
| TreeBuilder_Parent
|
||||||
| Tree_Pair of PairOpKind
|
| Tree_Pair of PairOpKind
|
||||||
| Tree_Sequential of int
|
| Tree_Sequential of int
|
||||||
| Tree_Builder
|
| Tree_Builder
|
||||||
|
|
||||||
let private loop (cata : TreeCata<'b, 'a, 'TreeBuilder, 'Tree>) (instructions : ResizeArray<Instruction<'b, 'a>>) =
|
let private loop (cata : TreeCata<_, _, _, _>) (instructions : ResizeArray<Instruction<_, _>>) =
|
||||||
let treeStack = ResizeArray<'Tree> ()
|
let treeStack = ResizeArray ()
|
||||||
let treeBuilderStack = ResizeArray<'TreeBuilder> ()
|
let treeBuilderStack = ResizeArray ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__TreeBuilder (x) ->
|
| Instruction.Process__TreeBuilder x ->
|
||||||
match x with
|
match x with
|
||||||
| TreeBuilder.Child (arg0_0) ->
|
| TreeBuilder.Child (arg0_0) ->
|
||||||
instructions.Add Instruction.TreeBuilder_Child
|
instructions.Add Instruction.TreeBuilder_Child
|
||||||
@@ -68,9 +68,9 @@ module TreeCata =
|
|||||||
| TreeBuilder.Parent (arg0_0) ->
|
| TreeBuilder.Parent (arg0_0) ->
|
||||||
instructions.Add Instruction.TreeBuilder_Parent
|
instructions.Add Instruction.TreeBuilder_Parent
|
||||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||||
| Instruction.Process__Tree (x) ->
|
| Instruction.Process__Tree x ->
|
||||||
match x with
|
match x with
|
||||||
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
| Tree.Const (arg0_0) -> cata.Tree.Const arg0_0 |> treeStack.Add
|
||||||
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||||
instructions.Add (Instruction.Tree_Pair (arg2_0))
|
instructions.Add (Instruction.Tree_Pair (arg2_0))
|
||||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||||
@@ -121,8 +121,8 @@ module TreeCata =
|
|||||||
|
|
||||||
/// Execute the catamorphism.
|
/// Execute the catamorphism.
|
||||||
let runTreeBuilder
|
let runTreeBuilder
|
||||||
(cata : TreeCata<'b, 'a, 'TreeBuilderRet, 'TreeRet>)
|
(cata : TreeCata<'a, 'a, 'TreeBuilderRet, 'TreeRet>)
|
||||||
(x : TreeBuilder<'b, 'a>)
|
(x : TreeBuilder<'a, 'a>)
|
||||||
: 'TreeBuilderRet
|
: 'TreeBuilderRet
|
||||||
=
|
=
|
||||||
let instructions = ResizeArray ()
|
let instructions = ResizeArray ()
|
||||||
@@ -131,7 +131,7 @@ module TreeCata =
|
|||||||
Seq.exactlyOne treeBuilderRetStack
|
Seq.exactlyOne treeBuilderRetStack
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
/// 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 ()
|
let instructions = ResizeArray ()
|
||||||
instructions.Add (Instruction.Process__Tree x)
|
instructions.Add (Instruction.Process__Tree x)
|
||||||
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
||||||
|
|||||||
@@ -33,15 +33,15 @@ module FileSystemItemCata =
|
|||||||
| Process__FileSystemItem of FileSystemItem
|
| Process__FileSystemItem of FileSystemItem
|
||||||
| FileSystemItem_Directory of string * int * int
|
| FileSystemItem_Directory of string * int * int
|
||||||
|
|
||||||
let private loop (cata : FileSystemCata<'FileSystemItem>) (instructions : ResizeArray<Instruction>) =
|
let private loop (cata : FileSystemCata<_>) (instructions : ResizeArray<Instruction>) =
|
||||||
let fileSystemItemStack = ResizeArray<'FileSystemItem> ()
|
let fileSystemItemStack = ResizeArray ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__FileSystemItem (x) ->
|
| Instruction.Process__FileSystemItem x ->
|
||||||
match x with
|
match x with
|
||||||
| FileSystemItem.Directory ({
|
| FileSystemItem.Directory ({
|
||||||
Name = name
|
Name = name
|
||||||
@@ -108,15 +108,15 @@ module GiftCata =
|
|||||||
| Gift_Boxed
|
| Gift_Boxed
|
||||||
| Gift_WithACard of string
|
| Gift_WithACard of string
|
||||||
|
|
||||||
let private loop (cata : GiftCata<'Gift>) (instructions : ResizeArray<Instruction>) =
|
let private loop (cata : GiftCata<_>) (instructions : ResizeArray<Instruction>) =
|
||||||
let giftStack = ResizeArray<'Gift> ()
|
let giftStack = ResizeArray ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__Gift (x) ->
|
| Instruction.Process__Gift x ->
|
||||||
match x with
|
match x with
|
||||||
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
|
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
|
||||||
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate arg0_0 |> giftStack.Add
|
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate arg0_0 |> giftStack.Add
|
||||||
|
|||||||
@@ -8,11 +8,12 @@
|
|||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the InnerType type
|
/// Module containing JSON parsing methods for the InnerType type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module InnerType =
|
module InnerType =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerType =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerType =
|
||||||
let arg_0 =
|
let Thing =
|
||||||
(match node.[(Literals.something)] with
|
(match node.[(Literals.something)] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -25,16 +26,17 @@ module InnerType =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Thing = arg_0
|
Thing = Thing
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the JsonRecordType type
|
/// Module containing JSON parsing methods for the JsonRecordType type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module JsonRecordType =
|
module JsonRecordType =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordType =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordType =
|
||||||
let arg_5 =
|
let F =
|
||||||
(match node.["f"] with
|
(match node.["f"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -47,7 +49,7 @@ module JsonRecordType =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_4 =
|
let E =
|
||||||
(match node.["e"] with
|
(match node.["e"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -60,7 +62,7 @@ module JsonRecordType =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_3 =
|
let D =
|
||||||
InnerType.jsonParse (
|
InnerType.jsonParse (
|
||||||
match node.["d"] with
|
match node.["d"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -72,7 +74,7 @@ module JsonRecordType =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_2 =
|
let C =
|
||||||
(match node.["hi"] with
|
(match node.["hi"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -85,7 +87,7 @@ module JsonRecordType =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_1 =
|
let B =
|
||||||
(match node.["another-thing"] with
|
(match node.["another-thing"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -97,7 +99,7 @@ module JsonRecordType =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let A =
|
||||||
(match node.["a"] with
|
(match node.["a"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -110,12 +112,12 @@ module JsonRecordType =
|
|||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
A = arg_0
|
A = A
|
||||||
B = arg_1
|
B = B
|
||||||
C = arg_2
|
C = C
|
||||||
D = arg_3
|
D = D
|
||||||
E = arg_4
|
E = E
|
||||||
F = arg_5
|
F = F
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
@@ -127,230 +129,24 @@ module ToGetExtensionMethodJsonParseExtension =
|
|||||||
|
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : ToGetExtensionMethod =
|
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : ToGetExtensionMethod =
|
||||||
let arg_20 = System.Numerics.BigInteger.Parse (node.["whiskey"].ToJsonString ())
|
let Sailor =
|
||||||
|
(match node.["sailor"] with
|
||||||
let arg_19 =
|
|
||||||
(match node.["victor"] with
|
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
System.Collections.Generic.KeyNotFoundException (
|
||||||
sprintf "Required key '%s' not found on JSON object" ("victor")
|
sprintf "Required key '%s' not found on JSON object" ("sailor")
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
.AsValue()
|
|
||||||
.GetValue<System.Char> ()
|
|
||||||
|
|
||||||
let arg_18 =
|
|
||||||
(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 arg_17 =
|
|
||||||
(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 arg_16 =
|
|
||||||
(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 arg_15 =
|
|
||||||
(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 arg_14 =
|
|
||||||
(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 arg_13 =
|
|
||||||
(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 arg_12 =
|
|
||||||
(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 arg_11 =
|
|
||||||
(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 arg_10 =
|
|
||||||
(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 arg_9 =
|
|
||||||
(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 arg_8 =
|
|
||||||
(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 arg_7 =
|
|
||||||
(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 arg_6 =
|
|
||||||
(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 arg_5 =
|
|
||||||
(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 arg_4 =
|
|
||||||
(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 arg_3 =
|
|
||||||
(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 arg_2 =
|
|
||||||
(match node.["charlie"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("charlie")
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
| v -> v)
|
| v -> v)
|
||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<float> ()
|
.GetValue<float> ()
|
||||||
|
|
||||||
let arg_1 =
|
let Soldier =
|
||||||
(match node.["bravo"] with
|
(match node.["soldier"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
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)
|
| v -> v)
|
||||||
@@ -358,12 +154,24 @@ module ToGetExtensionMethodJsonParseExtension =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.Uri
|
|> System.Uri
|
||||||
|
|
||||||
let arg_0 =
|
let Tailor =
|
||||||
(match node.["alpha"] with
|
(match node.["tailor"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
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)
|
| v -> v)
|
||||||
@@ -371,25 +179,8 @@ module ToGetExtensionMethodJsonParseExtension =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Alpha = arg_0
|
Tinker = Tinker
|
||||||
Bravo = arg_1
|
Tailor = Tailor
|
||||||
Charlie = arg_2
|
Soldier = Soldier
|
||||||
Delta = arg_3
|
Sailor = Sailor
|
||||||
Echo = arg_4
|
|
||||||
Foxtrot = arg_5
|
|
||||||
Golf = arg_6
|
|
||||||
Hotel = arg_7
|
|
||||||
India = arg_8
|
|
||||||
Juliette = arg_9
|
|
||||||
Kilo = arg_10
|
|
||||||
Lima = arg_11
|
|
||||||
Mike = arg_12
|
|
||||||
November = arg_13
|
|
||||||
Oscar = arg_14
|
|
||||||
Papa = arg_15
|
|
||||||
Quebec = arg_16
|
|
||||||
Tango = arg_17
|
|
||||||
Uniform = arg_18
|
|
||||||
Victor = arg_19
|
|
||||||
Whiskey = arg_20
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -19,18 +18,17 @@ type internal PublicTypeMock =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty : PublicTypeMock =
|
static member Empty : PublicTypeMock =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem3 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPublicType with
|
interface IPublicType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
||||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -44,18 +42,17 @@ type public PublicTypeInternalFalseMock =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty : PublicTypeInternalFalseMock =
|
static member Empty : PublicTypeInternalFalseMock =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem3 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPublicTypeInternalFalse with
|
interface IPublicTypeInternalFalse with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
||||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -68,16 +65,15 @@ type internal InternalTypeMock =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty : InternalTypeMock =
|
static member Empty : InternalTypeMock =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InternalType with
|
interface InternalType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -90,16 +86,15 @@ type private PrivateTypeMock =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty : PrivateTypeMock =
|
static member Empty : PrivateTypeMock =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PrivateType with
|
interface PrivateType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -112,16 +107,15 @@ type private PrivateTypeInternalFalseMock =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty : PrivateTypeInternalFalseMock =
|
static member Empty : PrivateTypeInternalFalseMock =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PrivateTypeInternalFalse with
|
interface PrivateTypeInternalFalse with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -133,14 +127,13 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VeryPublicType<'a, 'b> with
|
interface VeryPublicType<'a, 'b> with
|
||||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
member this.Mem1 (arg_0_0) = this.Mem1 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -157,18 +150,18 @@ type internal CurriedMock<'a> =
|
|||||||
/// An implementation where every method throws.
|
/// An implementation where every method throws.
|
||||||
static member Empty () : CurriedMock<'a> =
|
static member Empty () : CurriedMock<'a> =
|
||||||
{
|
{
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem3 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem4 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem5 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
Mem6 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Curried<'a> with
|
interface Curried<'a> with
|
||||||
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
|
member this.Mem1 (arg_0_0) (arg_1_0) = this.Mem1 (arg_0_0) (arg_1_0)
|
||||||
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
member this.Mem2 (arg_0_0, arg_0_1) (arg_1_0) = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
||||||
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
member this.Mem3 ((arg_0_0, arg_0_1)) (arg_1_0) = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
||||||
|
|
||||||
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
||||||
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||||
@@ -178,31 +171,3 @@ type internal CurriedMock<'a> =
|
|||||||
|
|
||||||
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
||||||
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||||
namespace SomeNamespace
|
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
/// Mock record type for an interface
|
|
||||||
type internal TypeWithInterfaceMock =
|
|
||||||
{
|
|
||||||
/// Implementation of IDisposable.Dispose
|
|
||||||
Dispose : unit -> unit
|
|
||||||
Mem1 : string option -> string[] Async
|
|
||||||
Mem2 : unit -> string[] Async
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An implementation where every method throws.
|
|
||||||
static member Empty : TypeWithInterfaceMock =
|
|
||||||
{
|
|
||||||
Dispose = (fun () -> ())
|
|
||||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
|
||||||
Mem2 = (fun _ -> 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 ()
|
|
||||||
|
|||||||
@@ -41,11 +41,12 @@ module MemberJsonSerializeExtension =
|
|||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the GymOpeningHours type
|
/// Module containing JSON parsing methods for the GymOpeningHours type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module GymOpeningHours =
|
module GymOpeningHours =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymOpeningHours =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymOpeningHours =
|
||||||
let arg_1 =
|
let OpeningHours =
|
||||||
(match node.["openingHours"] with
|
(match node.["openingHours"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -58,7 +59,7 @@ module GymOpeningHours =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_0 =
|
let IsAlwaysOpen =
|
||||||
(match node.["isAlwaysOpen"] with
|
(match node.["isAlwaysOpen"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -71,17 +72,18 @@ module GymOpeningHours =
|
|||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
IsAlwaysOpen = arg_0
|
IsAlwaysOpen = IsAlwaysOpen
|
||||||
OpeningHours = arg_1
|
OpeningHours = OpeningHours
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the GymAccessOptions type
|
/// Module containing JSON parsing methods for the GymAccessOptions type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module GymAccessOptions =
|
module GymAccessOptions =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAccessOptions =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAccessOptions =
|
||||||
let arg_1 =
|
let QrCodeAccess =
|
||||||
(match node.["qrCodeAccess"] with
|
(match node.["qrCodeAccess"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -93,7 +95,7 @@ module GymAccessOptions =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_0 =
|
let PinAccess =
|
||||||
(match node.["pinAccess"] with
|
(match node.["pinAccess"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -106,17 +108,18 @@ module GymAccessOptions =
|
|||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
PinAccess = arg_0
|
PinAccess = PinAccess
|
||||||
QrCodeAccess = arg_1
|
QrCodeAccess = QrCodeAccess
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the GymLocation type
|
/// Module containing JSON parsing methods for the GymLocation type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module GymLocation =
|
module GymLocation =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymLocation =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymLocation =
|
||||||
let arg_1 =
|
let Latitude =
|
||||||
try
|
try
|
||||||
(match node.["latitude"] with
|
(match node.["latitude"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -149,7 +152,7 @@ module GymLocation =
|
|||||||
else
|
else
|
||||||
reraise ()
|
reraise ()
|
||||||
|
|
||||||
let arg_0 =
|
let Longitude =
|
||||||
try
|
try
|
||||||
(match node.["longitude"] with
|
(match node.["longitude"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -183,17 +186,18 @@ module GymLocation =
|
|||||||
reraise ()
|
reraise ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Longitude = arg_0
|
Longitude = Longitude
|
||||||
Latitude = arg_1
|
Latitude = Latitude
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the GymAddress type
|
/// Module containing JSON parsing methods for the GymAddress type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module GymAddress =
|
module GymAddress =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAddress =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAddress =
|
||||||
let arg_5 =
|
let Postcode =
|
||||||
(match node.["postcode"] with
|
(match node.["postcode"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -205,12 +209,12 @@ module GymAddress =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_4 =
|
let County =
|
||||||
match node.["county"] with
|
match node.["county"] with
|
||||||
| null -> None
|
| null -> None
|
||||||
| v -> v.AsValue().GetValue<string> () |> Some
|
| v -> v.AsValue().GetValue<string> () |> Some
|
||||||
|
|
||||||
let arg_3 =
|
let Town =
|
||||||
(match node.["town"] with
|
(match node.["town"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -222,17 +226,17 @@ module GymAddress =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_2 =
|
let AddressLine3 =
|
||||||
match node.["addressLine3"] with
|
match node.["addressLine3"] with
|
||||||
| null -> None
|
| null -> None
|
||||||
| v -> v.AsValue().GetValue<string> () |> Some
|
| v -> v.AsValue().GetValue<string> () |> Some
|
||||||
|
|
||||||
let arg_1 =
|
let AddressLine2 =
|
||||||
match node.["addressLine2"] with
|
match node.["addressLine2"] with
|
||||||
| null -> None
|
| null -> None
|
||||||
| v -> v.AsValue().GetValue<string> () |> Some
|
| v -> v.AsValue().GetValue<string> () |> Some
|
||||||
|
|
||||||
let arg_0 =
|
let AddressLine1 =
|
||||||
(match node.["addressLine1"] with
|
(match node.["addressLine1"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -245,21 +249,22 @@ module GymAddress =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
AddressLine1 = arg_0
|
AddressLine1 = AddressLine1
|
||||||
AddressLine2 = arg_1
|
AddressLine2 = AddressLine2
|
||||||
AddressLine3 = arg_2
|
AddressLine3 = AddressLine3
|
||||||
Town = arg_3
|
Town = Town
|
||||||
County = arg_4
|
County = County
|
||||||
Postcode = arg_5
|
Postcode = Postcode
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the Gym type
|
/// Module containing JSON parsing methods for the Gym type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module Gym =
|
module Gym =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Gym =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Gym =
|
||||||
let arg_10 =
|
let ReopenDate =
|
||||||
(match node.["reopenDate"] with
|
(match node.["reopenDate"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -271,7 +276,7 @@ module Gym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_9 =
|
let TimeZone =
|
||||||
(match node.["timeZone"] with
|
(match node.["timeZone"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -283,7 +288,7 @@ module Gym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_8 =
|
let Location =
|
||||||
GymLocation.jsonParse (
|
GymLocation.jsonParse (
|
||||||
match node.["location"] with
|
match node.["location"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -295,7 +300,7 @@ module Gym =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_7 =
|
let AccessOptions =
|
||||||
GymAccessOptions.jsonParse (
|
GymAccessOptions.jsonParse (
|
||||||
match node.["accessOptions"] with
|
match node.["accessOptions"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -307,7 +312,7 @@ module Gym =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_6 =
|
let GymOpeningHours =
|
||||||
GymOpeningHours.jsonParse (
|
GymOpeningHours.jsonParse (
|
||||||
match node.["gymOpeningHours"] with
|
match node.["gymOpeningHours"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -319,7 +324,7 @@ module Gym =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_5 =
|
let EmailAddress =
|
||||||
(match node.["emailAddress"] with
|
(match node.["emailAddress"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -331,7 +336,7 @@ module Gym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_4 =
|
let PhoneNumber =
|
||||||
(match node.["phoneNumber"] with
|
(match node.["phoneNumber"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -343,7 +348,7 @@ module Gym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_3 =
|
let Address =
|
||||||
GymAddress.jsonParse (
|
GymAddress.jsonParse (
|
||||||
match node.["address"] with
|
match node.["address"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -355,7 +360,7 @@ module Gym =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_2 =
|
let Status =
|
||||||
(match node.["status"] with
|
(match node.["status"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -367,7 +372,7 @@ module Gym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_1 =
|
let Id =
|
||||||
(match node.["id"] with
|
(match node.["id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -379,7 +384,7 @@ module Gym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_0 =
|
let Name =
|
||||||
(match node.["name"] with
|
(match node.["name"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -392,17 +397,17 @@ module Gym =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Name = arg_0
|
Name = Name
|
||||||
Id = arg_1
|
Id = Id
|
||||||
Status = arg_2
|
Status = Status
|
||||||
Address = arg_3
|
Address = Address
|
||||||
PhoneNumber = arg_4
|
PhoneNumber = PhoneNumber
|
||||||
EmailAddress = arg_5
|
EmailAddress = EmailAddress
|
||||||
GymOpeningHours = arg_6
|
GymOpeningHours = GymOpeningHours
|
||||||
AccessOptions = arg_7
|
AccessOptions = AccessOptions
|
||||||
Location = arg_8
|
Location = Location
|
||||||
TimeZone = arg_9
|
TimeZone = TimeZone
|
||||||
ReopenDate = arg_10
|
ReopenDate = ReopenDate
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
@@ -414,7 +419,7 @@ module MemberJsonParseExtension =
|
|||||||
|
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : Member =
|
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : Member =
|
||||||
let arg_14 =
|
let MemberStatus =
|
||||||
(match node.["memberStatus"] with
|
(match node.["memberStatus"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -426,7 +431,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_13 =
|
let SuspendedReason =
|
||||||
(match node.["suspendedReason"] with
|
(match node.["suspendedReason"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -438,7 +443,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_12 =
|
let MembershipLevel =
|
||||||
(match node.["membershipLevel"] with
|
(match node.["membershipLevel"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -450,7 +455,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_11 =
|
let MembershipName =
|
||||||
(match node.["membershipName"] with
|
(match node.["membershipName"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -462,7 +467,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_10 =
|
let Postcode =
|
||||||
(match node.["postCode"] with
|
(match node.["postCode"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -474,7 +479,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_9 =
|
let MobileNumber =
|
||||||
(match node.["mobileNumber"] with
|
(match node.["mobileNumber"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -486,7 +491,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_8 =
|
let DateOfBirth =
|
||||||
(match node.["dateofBirth"] with
|
(match node.["dateofBirth"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -499,7 +504,7 @@ module MemberJsonParseExtension =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.DateOnly.Parse
|
|> System.DateOnly.Parse
|
||||||
|
|
||||||
let arg_7 =
|
let GymAccessPin =
|
||||||
(match node.["gymAccessPin"] with
|
(match node.["gymAccessPin"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -511,7 +516,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_6 =
|
let EmailAddress =
|
||||||
(match node.["emailAddress"] with
|
(match node.["emailAddress"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -523,7 +528,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_5 =
|
let HomeGymName =
|
||||||
(match node.["homeGymName"] with
|
(match node.["homeGymName"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -535,7 +540,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_4 =
|
let HomeGymId =
|
||||||
(match node.["homeGymId"] with
|
(match node.["homeGymId"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -547,7 +552,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_3 =
|
let LastName =
|
||||||
(match node.["lastName"] with
|
(match node.["lastName"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -559,7 +564,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_2 =
|
let FirstName =
|
||||||
(match node.["firstName"] with
|
(match node.["firstName"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -571,7 +576,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_1 =
|
let CompoundMemberId =
|
||||||
(match node.["compoundMemberId"] with
|
(match node.["compoundMemberId"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -583,7 +588,7 @@ module MemberJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let Id =
|
||||||
(match node.["id"] with
|
(match node.["id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -596,30 +601,31 @@ module MemberJsonParseExtension =
|
|||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Id = arg_0
|
Id = Id
|
||||||
CompoundMemberId = arg_1
|
CompoundMemberId = CompoundMemberId
|
||||||
FirstName = arg_2
|
FirstName = FirstName
|
||||||
LastName = arg_3
|
LastName = LastName
|
||||||
HomeGymId = arg_4
|
HomeGymId = HomeGymId
|
||||||
HomeGymName = arg_5
|
HomeGymName = HomeGymName
|
||||||
EmailAddress = arg_6
|
EmailAddress = EmailAddress
|
||||||
GymAccessPin = arg_7
|
GymAccessPin = GymAccessPin
|
||||||
DateOfBirth = arg_8
|
DateOfBirth = DateOfBirth
|
||||||
MobileNumber = arg_9
|
MobileNumber = MobileNumber
|
||||||
Postcode = arg_10
|
Postcode = Postcode
|
||||||
MembershipName = arg_11
|
MembershipName = MembershipName
|
||||||
MembershipLevel = arg_12
|
MembershipLevel = MembershipLevel
|
||||||
SuspendedReason = arg_13
|
SuspendedReason = SuspendedReason
|
||||||
MemberStatus = arg_14
|
MemberStatus = MemberStatus
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the GymAttendance type
|
/// Module containing JSON parsing methods for the GymAttendance type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module GymAttendance =
|
module GymAttendance =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAttendance =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAttendance =
|
||||||
let arg_8 =
|
let MaximumCapacity =
|
||||||
(match node.["maximumCapacity"] with
|
(match node.["maximumCapacity"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -631,7 +637,7 @@ module GymAttendance =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_7 =
|
let LastRefreshedPeopleInClasses =
|
||||||
(match node.["lastRefreshedPeopleInClasses"] with
|
(match node.["lastRefreshedPeopleInClasses"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -644,7 +650,7 @@ module GymAttendance =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.DateTime.Parse
|
|> System.DateTime.Parse
|
||||||
|
|
||||||
let arg_6 =
|
let LastRefreshed =
|
||||||
(match node.["lastRefreshed"] with
|
(match node.["lastRefreshed"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -657,7 +663,7 @@ module GymAttendance =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.DateTime.Parse
|
|> System.DateTime.Parse
|
||||||
|
|
||||||
let arg_5 =
|
let AttendanceTime =
|
||||||
(match node.["attendanceTime"] with
|
(match node.["attendanceTime"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -670,7 +676,7 @@ module GymAttendance =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.DateTime.Parse
|
|> System.DateTime.Parse
|
||||||
|
|
||||||
let arg_4 =
|
let IsApproximate =
|
||||||
(match node.["isApproximate"] with
|
(match node.["isApproximate"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -682,12 +688,12 @@ module GymAttendance =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_3 =
|
let TotalPeopleSuffix =
|
||||||
match node.["totalPeopleSuffix"] with
|
match node.["totalPeopleSuffix"] with
|
||||||
| null -> None
|
| null -> None
|
||||||
| v -> v.AsValue().GetValue<string> () |> Some
|
| v -> v.AsValue().GetValue<string> () |> Some
|
||||||
|
|
||||||
let arg_2 =
|
let TotalPeopleInClasses =
|
||||||
(match node.["totalPeopleInClasses"] with
|
(match node.["totalPeopleInClasses"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -699,7 +705,7 @@ module GymAttendance =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_1 =
|
let TotalPeopleInGym =
|
||||||
(match node.["totalPeopleInGym"] with
|
(match node.["totalPeopleInGym"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -711,7 +717,7 @@ module GymAttendance =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_0 =
|
let Description =
|
||||||
(match node.["description"] with
|
(match node.["description"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -724,24 +730,25 @@ module GymAttendance =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Description = arg_0
|
Description = Description
|
||||||
TotalPeopleInGym = arg_1
|
TotalPeopleInGym = TotalPeopleInGym
|
||||||
TotalPeopleInClasses = arg_2
|
TotalPeopleInClasses = TotalPeopleInClasses
|
||||||
TotalPeopleSuffix = arg_3
|
TotalPeopleSuffix = TotalPeopleSuffix
|
||||||
IsApproximate = arg_4
|
IsApproximate = IsApproximate
|
||||||
AttendanceTime = arg_5
|
AttendanceTime = AttendanceTime
|
||||||
LastRefreshed = arg_6
|
LastRefreshed = LastRefreshed
|
||||||
LastRefreshedPeopleInClasses = arg_7
|
LastRefreshedPeopleInClasses = LastRefreshedPeopleInClasses
|
||||||
MaximumCapacity = arg_8
|
MaximumCapacity = MaximumCapacity
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the MemberActivityDto type
|
/// Module containing JSON parsing methods for the MemberActivityDto type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module MemberActivityDto =
|
module MemberActivityDto =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : MemberActivityDto =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : MemberActivityDto =
|
||||||
let arg_5 =
|
let LastRefreshed =
|
||||||
(match node.["lastRefreshed"] with
|
(match node.["lastRefreshed"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -754,7 +761,7 @@ module MemberActivityDto =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.DateTime.Parse
|
|> System.DateTime.Parse
|
||||||
|
|
||||||
let arg_4 =
|
let IsEstimated =
|
||||||
(match node.["isEstimated"] with
|
(match node.["isEstimated"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -766,7 +773,7 @@ module MemberActivityDto =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_3 =
|
let TotalClasses =
|
||||||
(match node.["totalClasses"] with
|
(match node.["totalClasses"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -778,7 +785,7 @@ module MemberActivityDto =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_2 =
|
let TotalVisits =
|
||||||
(match node.["totalVisits"] with
|
(match node.["totalVisits"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -790,7 +797,7 @@ module MemberActivityDto =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_1 =
|
let AverageDuration =
|
||||||
(match node.["averageDuration"] with
|
(match node.["averageDuration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -802,7 +809,7 @@ module MemberActivityDto =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_0 =
|
let TotalDuration =
|
||||||
(match node.["totalDuration"] with
|
(match node.["totalDuration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -815,21 +822,22 @@ module MemberActivityDto =
|
|||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
TotalDuration = arg_0
|
TotalDuration = TotalDuration
|
||||||
AverageDuration = arg_1
|
AverageDuration = AverageDuration
|
||||||
TotalVisits = arg_2
|
TotalVisits = TotalVisits
|
||||||
TotalClasses = arg_3
|
TotalClasses = TotalClasses
|
||||||
IsEstimated = arg_4
|
IsEstimated = IsEstimated
|
||||||
LastRefreshed = arg_5
|
LastRefreshed = LastRefreshed
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the SessionsAggregate type
|
/// Module containing JSON parsing methods for the SessionsAggregate type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module SessionsAggregate =
|
module SessionsAggregate =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsAggregate =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsAggregate =
|
||||||
let arg_2 =
|
let Duration =
|
||||||
(match node.["Duration"] with
|
(match node.["Duration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -841,7 +849,7 @@ module SessionsAggregate =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_1 =
|
let Visits =
|
||||||
(match node.["Visits"] with
|
(match node.["Visits"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -853,7 +861,7 @@ module SessionsAggregate =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_0 =
|
let Activities =
|
||||||
(match node.["Activities"] with
|
(match node.["Activities"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -866,18 +874,19 @@ module SessionsAggregate =
|
|||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Activities = arg_0
|
Activities = Activities
|
||||||
Visits = arg_1
|
Visits = Visits
|
||||||
Duration = arg_2
|
Duration = Duration
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the VisitGym type
|
/// Module containing JSON parsing methods for the VisitGym type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module VisitGym =
|
module VisitGym =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : VisitGym =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : VisitGym =
|
||||||
let arg_2 =
|
let Status =
|
||||||
(match node.["Status"] with
|
(match node.["Status"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -889,7 +898,7 @@ module VisitGym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_1 =
|
let Name =
|
||||||
(match node.["Name"] with
|
(match node.["Name"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -901,7 +910,7 @@ module VisitGym =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let Id =
|
||||||
(match node.["Id"] with
|
(match node.["Id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -914,18 +923,19 @@ module VisitGym =
|
|||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
Id = arg_0
|
Id = Id
|
||||||
Name = arg_1
|
Name = Name
|
||||||
Status = arg_2
|
Status = Status
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the Visit type
|
/// Module containing JSON parsing methods for the Visit type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module Visit =
|
module Visit =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
|
||||||
let arg_3 =
|
let Gym =
|
||||||
VisitGym.jsonParse (
|
VisitGym.jsonParse (
|
||||||
match node.["Gym"] with
|
match node.["Gym"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -937,7 +947,7 @@ module Visit =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_2 =
|
let Duration =
|
||||||
(match node.["Duration"] with
|
(match node.["Duration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -949,7 +959,7 @@ module Visit =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_1 =
|
let StartTime =
|
||||||
(match node.["StartTime"] with
|
(match node.["StartTime"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -962,7 +972,7 @@ module Visit =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|> System.DateTime.Parse
|
|> System.DateTime.Parse
|
||||||
|
|
||||||
let arg_0 =
|
let IsDurationEstimated =
|
||||||
(match node.["IsDurationEstimated"] with
|
(match node.["IsDurationEstimated"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -975,19 +985,20 @@ module Visit =
|
|||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
IsDurationEstimated = arg_0
|
IsDurationEstimated = IsDurationEstimated
|
||||||
StartTime = arg_1
|
StartTime = StartTime
|
||||||
Duration = arg_2
|
Duration = Duration
|
||||||
Gym = arg_3
|
Gym = Gym
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the SessionsSummary type
|
/// Module containing JSON parsing methods for the SessionsSummary type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module SessionsSummary =
|
module SessionsSummary =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
|
||||||
let arg_1 =
|
let ThisWeek =
|
||||||
SessionsAggregate.jsonParse (
|
SessionsAggregate.jsonParse (
|
||||||
match node.["ThisWeek"] with
|
match node.["ThisWeek"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -999,7 +1010,7 @@ module SessionsSummary =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_0 =
|
let Total =
|
||||||
SessionsAggregate.jsonParse (
|
SessionsAggregate.jsonParse (
|
||||||
match node.["Total"] with
|
match node.["Total"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -1012,17 +1023,18 @@ module SessionsSummary =
|
|||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
Total = arg_0
|
Total = Total
|
||||||
ThisWeek = arg_1
|
ThisWeek = ThisWeek
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the Sessions type
|
/// Module containing JSON parsing methods for the Sessions type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module Sessions =
|
module Sessions =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Sessions =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Sessions =
|
||||||
let arg_1 =
|
let Visits =
|
||||||
(match node.["Visits"] with
|
(match node.["Visits"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -1035,7 +1047,7 @@ module Sessions =
|
|||||||
|> Seq.map (fun elt -> Visit.jsonParse elt)
|
|> Seq.map (fun elt -> Visit.jsonParse elt)
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_0 =
|
let Summary =
|
||||||
SessionsSummary.jsonParse (
|
SessionsSummary.jsonParse (
|
||||||
match node.["Summary"] with
|
match node.["Summary"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -1048,17 +1060,18 @@ module Sessions =
|
|||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
Summary = arg_0
|
Summary = Summary
|
||||||
Visits = arg_1
|
Visits = Visits
|
||||||
}
|
}
|
||||||
namespace PureGym
|
namespace PureGym
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the UriThing type
|
/// Module containing JSON parsing methods for the UriThing type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module UriThing =
|
module UriThing =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : UriThing =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : UriThing =
|
||||||
let arg_0 =
|
let SomeUri =
|
||||||
(match node.["someUri"] with
|
(match node.["someUri"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -1072,5 +1085,5 @@ module UriThing =
|
|||||||
|> System.Uri
|
|> System.Uri
|
||||||
|
|
||||||
{
|
{
|
||||||
SomeUri = arg_0
|
SomeUri = SomeUri
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ open System.Net.Http
|
|||||||
open RestEase
|
open RestEase
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
/// Module for constructing a REST client.
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
module PureGymApi =
|
module PureGymApi =
|
||||||
/// Create a REST client.
|
/// Create a REST client.
|
||||||
let make (client : System.Net.Http.HttpClient) : IPureGymApi =
|
let make (client : System.Net.Http.HttpClient) : IPureGymApi =
|
||||||
@@ -86,40 +87,6 @@ module PureGymApi =
|
|||||||
}
|
}
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
member _.GetGymAttendance' (gymId : int, ct : CancellationToken option) =
|
|
||||||
async {
|
|
||||||
let! ct = Async.CancellationToken
|
|
||||||
|
|
||||||
let uri =
|
|
||||||
System.Uri (
|
|
||||||
(match client.BaseAddress with
|
|
||||||
| null -> System.Uri "https://whatnot.com"
|
|
||||||
| v -> v),
|
|
||||||
System.Uri (
|
|
||||||
"v1/gyms/{gym_id}/attendance"
|
|
||||||
.Replace ("{gym_id}", gymId.ToString () |> System.Web.HttpUtility.UrlEncode),
|
|
||||||
System.UriKind.Relative
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
let httpMessage =
|
|
||||||
new System.Net.Http.HttpRequestMessage (
|
|
||||||
Method = System.Net.Http.HttpMethod.Get,
|
|
||||||
RequestUri = uri
|
|
||||||
)
|
|
||||||
|
|
||||||
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
|
||||||
let response = response.EnsureSuccessStatusCode ()
|
|
||||||
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
|
|
||||||
|
|
||||||
let! jsonNode =
|
|
||||||
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
|
||||||
|> Async.AwaitTask
|
|
||||||
|
|
||||||
return GymAttendance.jsonParse jsonNode
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
|
|
||||||
member _.GetMember (ct : CancellationToken option) =
|
member _.GetMember (ct : CancellationToken option) =
|
||||||
async {
|
async {
|
||||||
let! ct = Async.CancellationToken
|
let! ct = Async.CancellationToken
|
||||||
@@ -321,52 +288,7 @@ module PureGymApi =
|
|||||||
| v -> v),
|
| v -> v),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("/v2/gymSessions/member"
|
("/v2/gymSessions/member"
|
||||||
+ (if "/v2/gymSessions/member".IndexOf (char 63) >= 0 then
|
+ "?fromDate="
|
||||||
"&"
|
|
||||||
else
|
|
||||||
"?")
|
|
||||||
+ "fromDate="
|
|
||||||
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
|
||||||
+ "&toDate="
|
|
||||||
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
|
||||||
System.UriKind.Relative
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
let httpMessage =
|
|
||||||
new System.Net.Http.HttpRequestMessage (
|
|
||||||
Method = System.Net.Http.HttpMethod.Get,
|
|
||||||
RequestUri = uri
|
|
||||||
)
|
|
||||||
|
|
||||||
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
|
||||||
let response = response.EnsureSuccessStatusCode ()
|
|
||||||
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
|
|
||||||
|
|
||||||
let! jsonNode =
|
|
||||||
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
|
||||||
|> Async.AwaitTask
|
|
||||||
|
|
||||||
return Sessions.jsonParse jsonNode
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
|
|
||||||
member _.GetSessionsWithQuery (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
|
|
||||||
async {
|
|
||||||
let! ct = Async.CancellationToken
|
|
||||||
|
|
||||||
let uri =
|
|
||||||
System.Uri (
|
|
||||||
(match client.BaseAddress with
|
|
||||||
| null -> System.Uri "https://whatnot.com"
|
|
||||||
| v -> v),
|
|
||||||
System.Uri (
|
|
||||||
("/v2/gymSessions/member?foo=1"
|
|
||||||
+ (if "/v2/gymSessions/member?foo=1".IndexOf (char 63) >= 0 then
|
|
||||||
"&"
|
|
||||||
else
|
|
||||||
"?")
|
|
||||||
+ "fromDate="
|
|
||||||
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
||||||
+ "&toDate="
|
+ "&toDate="
|
||||||
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
||||||
@@ -1054,7 +976,8 @@ open System.Net.Http
|
|||||||
open RestEase
|
open RestEase
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
/// Module for constructing a REST client.
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
module internal ApiWithoutBaseAddress =
|
module internal ApiWithoutBaseAddress =
|
||||||
/// Create a REST client.
|
/// Create a REST client.
|
||||||
let make (client : System.Net.Http.HttpClient) : IApiWithoutBaseAddress =
|
let make (client : System.Net.Http.HttpClient) : IApiWithoutBaseAddress =
|
||||||
@@ -1105,7 +1028,8 @@ open System.Net.Http
|
|||||||
open RestEase
|
open RestEase
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
/// Module for constructing a REST client.
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
module ApiWithBasePath =
|
module ApiWithBasePath =
|
||||||
/// Create a REST client.
|
/// Create a REST client.
|
||||||
let make (client : System.Net.Http.HttpClient) : IApiWithBasePath =
|
let make (client : System.Net.Http.HttpClient) : IApiWithBasePath =
|
||||||
@@ -1156,7 +1080,8 @@ open System.Net.Http
|
|||||||
open RestEase
|
open RestEase
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
/// Module for constructing a REST client.
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
module ApiWithBasePathAndAddress =
|
module ApiWithBasePathAndAddress =
|
||||||
/// Create a REST client.
|
/// Create a REST client.
|
||||||
let make (client : System.Net.Http.HttpClient) : IApiWithBasePathAndAddress =
|
let make (client : System.Net.Http.HttpClient) : IApiWithBasePathAndAddress =
|
||||||
@@ -1201,7 +1126,8 @@ open System.Net.Http
|
|||||||
open RestEase
|
open RestEase
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
/// Module for constructing a REST client.
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
module ApiWithHeaders =
|
module ApiWithHeaders =
|
||||||
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||||
let make
|
let make
|
||||||
@@ -1214,68 +1140,6 @@ module ApiWithHeaders =
|
|||||||
member _.SomeHeader : string = someHeader ()
|
member _.SomeHeader : string = someHeader ()
|
||||||
member _.SomeOtherHeader : int = someOtherHeader ()
|
member _.SomeOtherHeader : int = someOtherHeader ()
|
||||||
|
|
||||||
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
|
||||||
async {
|
|
||||||
let! ct = Async.CancellationToken
|
|
||||||
|
|
||||||
let uri =
|
|
||||||
System.Uri (
|
|
||||||
(match client.BaseAddress with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.ArgumentNullException (
|
|
||||||
nameof (client.BaseAddress),
|
|
||||||
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v),
|
|
||||||
System.Uri (
|
|
||||||
"endpoint/{param}"
|
|
||||||
.Replace ("{param}", parameter.ToString () |> System.Web.HttpUtility.UrlEncode),
|
|
||||||
System.UriKind.Relative
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
let httpMessage =
|
|
||||||
new System.Net.Http.HttpRequestMessage (
|
|
||||||
Method = System.Net.Http.HttpMethod.Get,
|
|
||||||
RequestUri = uri
|
|
||||||
)
|
|
||||||
|
|
||||||
do httpMessage.Headers.Add ("X-Foo", this.SomeHeader.ToString ())
|
|
||||||
do httpMessage.Headers.Add ("Authorization", this.SomeOtherHeader.ToString ())
|
|
||||||
do httpMessage.Headers.Add ("Header-Name", "Header-Value")
|
|
||||||
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
|
||||||
let response = response.EnsureSuccessStatusCode ()
|
|
||||||
let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask
|
|
||||||
return responseString
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
}
|
|
||||||
namespace PureGym
|
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Threading
|
|
||||||
open System.Threading.Tasks
|
|
||||||
open System.IO
|
|
||||||
open System.Net
|
|
||||||
open System.Net.Http
|
|
||||||
open RestEase
|
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
|
||||||
module ApiWithHeaders2 =
|
|
||||||
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
|
||||||
let make
|
|
||||||
(someHeader : unit -> string)
|
|
||||||
(someOtherHeader : unit -> int)
|
|
||||||
(client : System.Net.Http.HttpClient)
|
|
||||||
: IApiWithHeaders2
|
|
||||||
=
|
|
||||||
{ new IApiWithHeaders2 with
|
|
||||||
member _.SomeHeader : string = someHeader ()
|
|
||||||
member _.SomeOtherHeader : int = someOtherHeader ()
|
|
||||||
|
|
||||||
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
||||||
async {
|
async {
|
||||||
let! ct = Async.CancellationToken
|
let! ct = Async.CancellationToken
|
||||||
|
|||||||
@@ -149,37 +149,6 @@ module JsonRecordTypeWithBothJsonSerializeExtension =
|
|||||||
)
|
)
|
||||||
|
|
||||||
node :> _
|
node :> _
|
||||||
namespace ConsumePlugin
|
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Collections.Generic
|
|
||||||
open System.Text.Json.Serialization
|
|
||||||
|
|
||||||
/// Module containing JSON serializing extension members for the FirstDu type
|
|
||||||
[<AutoOpen>]
|
|
||||||
module FirstDuJsonSerializeExtension =
|
|
||||||
/// Extension methods for JSON parsing
|
|
||||||
type FirstDu with
|
|
||||||
|
|
||||||
/// Serialize to a JSON node
|
|
||||||
static member toJsonNode (input : FirstDu) : System.Text.Json.Nodes.JsonNode =
|
|
||||||
let node = System.Text.Json.Nodes.JsonObject ()
|
|
||||||
|
|
||||||
match input with
|
|
||||||
| FirstDu.EmptyCase -> node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "emptyCase")
|
|
||||||
| FirstDu.Case1 (arg0) ->
|
|
||||||
node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case1")
|
|
||||||
let dataNode = System.Text.Json.Nodes.JsonObject ()
|
|
||||||
dataNode.Add ("data", System.Text.Json.Nodes.JsonValue.Create<string> arg0)
|
|
||||||
node.Add ("data", dataNode)
|
|
||||||
| FirstDu.Case2 (arg0, arg1) ->
|
|
||||||
node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case2")
|
|
||||||
let dataNode = System.Text.Json.Nodes.JsonObject ()
|
|
||||||
dataNode.Add ("record", JsonRecordTypeWithBoth.toJsonNode arg0)
|
|
||||||
dataNode.Add ("i", System.Text.Json.Nodes.JsonValue.Create<int> arg1)
|
|
||||||
node.Add ("data", dataNode)
|
|
||||||
|
|
||||||
node :> _
|
|
||||||
|
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
@@ -191,7 +160,7 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
|
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerTypeWithBoth =
|
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerTypeWithBoth =
|
||||||
let arg_4 =
|
let ConcreteDict =
|
||||||
(match node.["concreteDict"] with
|
(match node.["concreteDict"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -209,7 +178,7 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
|> Seq.map System.Collections.Generic.KeyValuePair
|
|> Seq.map System.Collections.Generic.KeyValuePair
|
||||||
|> System.Collections.Generic.Dictionary
|
|> System.Collections.Generic.Dictionary
|
||||||
|
|
||||||
let arg_3 =
|
let Dict =
|
||||||
(match node.["dict"] with
|
(match node.["dict"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -226,7 +195,7 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
)
|
)
|
||||||
|> dict
|
|> dict
|
||||||
|
|
||||||
let arg_2 =
|
let ReadOnlyDict =
|
||||||
(match node.["readOnlyDict"] with
|
(match node.["readOnlyDict"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -241,14 +210,14 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
|
|
||||||
let value =
|
let value =
|
||||||
(kvp.Value).AsArray ()
|
(kvp.Value).AsArray ()
|
||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Char> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<char> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
key, value
|
key, value
|
||||||
)
|
)
|
||||||
|> readOnlyDict
|
|> readOnlyDict
|
||||||
|
|
||||||
let arg_1 =
|
let Map =
|
||||||
(match node.["map"] with
|
(match node.["map"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -265,7 +234,7 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
)
|
)
|
||||||
|> Map.ofSeq
|
|> Map.ofSeq
|
||||||
|
|
||||||
let arg_0 =
|
let Thing =
|
||||||
(match node.[("it's-a-me")] with
|
(match node.[("it's-a-me")] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -279,11 +248,11 @@ module InnerTypeWithBothJsonParseExtension =
|
|||||||
|> System.Guid.Parse
|
|> System.Guid.Parse
|
||||||
|
|
||||||
{
|
{
|
||||||
Thing = arg_0
|
Thing = Thing
|
||||||
Map = arg_1
|
Map = Map
|
||||||
ReadOnlyDict = arg_2
|
ReadOnlyDict = ReadOnlyDict
|
||||||
Dict = arg_3
|
Dict = Dict
|
||||||
ConcreteDict = arg_4
|
ConcreteDict = ConcreteDict
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
@@ -295,7 +264,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
|
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordTypeWithBoth =
|
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordTypeWithBoth =
|
||||||
let arg_5 =
|
let F =
|
||||||
(match node.["f"] with
|
(match node.["f"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -308,7 +277,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_4 =
|
let E =
|
||||||
(match node.["e"] with
|
(match node.["e"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -321,7 +290,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
|
||||||
let arg_3 =
|
let D =
|
||||||
InnerTypeWithBoth.jsonParse (
|
InnerTypeWithBoth.jsonParse (
|
||||||
match node.["d"] with
|
match node.["d"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -333,7 +302,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_2 =
|
let C =
|
||||||
(match node.["c"] with
|
(match node.["c"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -346,7 +315,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_1 =
|
let B =
|
||||||
(match node.["b"] with
|
(match node.["b"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -358,7 +327,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let A =
|
||||||
(match node.["a"] with
|
(match node.["a"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -371,90 +340,10 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
|||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
A = arg_0
|
A = A
|
||||||
B = arg_1
|
B = B
|
||||||
C = arg_2
|
C = C
|
||||||
D = arg_3
|
D = D
|
||||||
E = arg_4
|
E = E
|
||||||
F = arg_5
|
F = F
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
|
||||||
|
|
||||||
/// Module containing JSON parsing extension members for the FirstDu type
|
|
||||||
[<AutoOpen>]
|
|
||||||
module FirstDuJsonParseExtension =
|
|
||||||
/// Extension methods for JSON parsing
|
|
||||||
type FirstDu with
|
|
||||||
|
|
||||||
/// Parse from a JSON node.
|
|
||||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : FirstDu =
|
|
||||||
let ty =
|
|
||||||
(match node.["type"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("type")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
|> (fun v -> v.GetValue<string> ())
|
|
||||||
|
|
||||||
match ty with
|
|
||||||
| "emptyCase" -> FirstDu.EmptyCase
|
|
||||||
| "case1" ->
|
|
||||||
let node =
|
|
||||||
(match node.["data"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("data")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
|
|
||||||
FirstDu.Case1 (
|
|
||||||
(match node.["data"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("data")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
.AsValue()
|
|
||||||
.GetValue<string> ()
|
|
||||||
)
|
|
||||||
| "case2" ->
|
|
||||||
let node =
|
|
||||||
(match node.["data"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("data")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
|
|
||||||
FirstDu.Case2 (
|
|
||||||
JsonRecordTypeWithBoth.jsonParse (
|
|
||||||
match node.["record"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("record")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v
|
|
||||||
),
|
|
||||||
(match node.["i"] with
|
|
||||||
| null ->
|
|
||||||
raise (
|
|
||||||
System.Collections.Generic.KeyNotFoundException (
|
|
||||||
sprintf "Required key '%s' not found on JSON object" ("i")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
| v -> v)
|
|
||||||
.AsValue()
|
|
||||||
.GetValue<int> ()
|
|
||||||
)
|
|
||||||
| v -> failwith ("Unrecognised 'type' field value: " + v)
|
|
||||||
|
|||||||
@@ -8,11 +8,12 @@
|
|||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type
|
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module JwtVaultAuthResponse =
|
module JwtVaultAuthResponse =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultAuthResponse =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultAuthResponse =
|
||||||
let arg_10 =
|
let NumUses =
|
||||||
(match node.["num_uses"] with
|
(match node.["num_uses"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -24,7 +25,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_9 =
|
let Orphan =
|
||||||
(match node.["orphan"] with
|
(match node.["orphan"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -36,7 +37,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_8 =
|
let EntityId =
|
||||||
(match node.["entity_id"] with
|
(match node.["entity_id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -48,7 +49,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_7 =
|
let TokenType =
|
||||||
(match node.["token_type"] with
|
(match node.["token_type"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -60,7 +61,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_6 =
|
let Renewable =
|
||||||
(match node.["renewable"] with
|
(match node.["renewable"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -72,7 +73,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_5 =
|
let LeaseDuration =
|
||||||
(match node.["lease_duration"] with
|
(match node.["lease_duration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -84,7 +85,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_4 =
|
let IdentityPolicies =
|
||||||
(match node.["identity_policies"] with
|
(match node.["identity_policies"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -97,7 +98,7 @@ module JwtVaultAuthResponse =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_3 =
|
let TokenPolicies =
|
||||||
(match node.["token_policies"] with
|
(match node.["token_policies"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -110,7 +111,7 @@ module JwtVaultAuthResponse =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_2 =
|
let Policies =
|
||||||
(match node.["policies"] with
|
(match node.["policies"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -123,7 +124,7 @@ module JwtVaultAuthResponse =
|
|||||||
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|
||||||
|> List.ofSeq
|
|> List.ofSeq
|
||||||
|
|
||||||
let arg_1 =
|
let Accessor =
|
||||||
(match node.["accessor"] with
|
(match node.["accessor"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -135,7 +136,7 @@ module JwtVaultAuthResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let ClientToken =
|
||||||
(match node.["client_token"] with
|
(match node.["client_token"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -148,26 +149,27 @@ module JwtVaultAuthResponse =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
ClientToken = arg_0
|
ClientToken = ClientToken
|
||||||
Accessor = arg_1
|
Accessor = Accessor
|
||||||
Policies = arg_2
|
Policies = Policies
|
||||||
TokenPolicies = arg_3
|
TokenPolicies = TokenPolicies
|
||||||
IdentityPolicies = arg_4
|
IdentityPolicies = IdentityPolicies
|
||||||
LeaseDuration = arg_5
|
LeaseDuration = LeaseDuration
|
||||||
Renewable = arg_6
|
Renewable = Renewable
|
||||||
TokenType = arg_7
|
TokenType = TokenType
|
||||||
EntityId = arg_8
|
EntityId = EntityId
|
||||||
Orphan = arg_9
|
Orphan = Orphan
|
||||||
NumUses = arg_10
|
NumUses = NumUses
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the JwtVaultResponse type
|
/// Module containing JSON parsing methods for the JwtVaultResponse type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module JwtVaultResponse =
|
module JwtVaultResponse =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultResponse =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultResponse =
|
||||||
let arg_4 =
|
let Auth =
|
||||||
JwtVaultAuthResponse.jsonParse (
|
JwtVaultAuthResponse.jsonParse (
|
||||||
match node.["auth"] with
|
match node.["auth"] with
|
||||||
| null ->
|
| null ->
|
||||||
@@ -179,7 +181,7 @@ module JwtVaultResponse =
|
|||||||
| v -> v
|
| v -> v
|
||||||
)
|
)
|
||||||
|
|
||||||
let arg_3 =
|
let LeaseDuration =
|
||||||
(match node.["lease_duration"] with
|
(match node.["lease_duration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -191,7 +193,7 @@ module JwtVaultResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_2 =
|
let Renewable =
|
||||||
(match node.["renewable"] with
|
(match node.["renewable"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -203,7 +205,7 @@ module JwtVaultResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_1 =
|
let LeaseId =
|
||||||
(match node.["lease_id"] with
|
(match node.["lease_id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -215,7 +217,7 @@ module JwtVaultResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let RequestId =
|
||||||
(match node.["request_id"] with
|
(match node.["request_id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -228,20 +230,21 @@ module JwtVaultResponse =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
RequestId = arg_0
|
RequestId = RequestId
|
||||||
LeaseId = arg_1
|
LeaseId = LeaseId
|
||||||
Renewable = arg_2
|
Renewable = Renewable
|
||||||
LeaseDuration = arg_3
|
LeaseDuration = LeaseDuration
|
||||||
Auth = arg_4
|
Auth = Auth
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
/// Module containing JSON parsing methods for the JwtSecretResponse type
|
/// Module containing JSON parsing methods for the JwtSecretResponse type
|
||||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
[<RequireQualifiedAccess>]
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
module JwtSecretResponse =
|
module JwtSecretResponse =
|
||||||
/// Parse from a JSON node.
|
/// Parse from a JSON node.
|
||||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtSecretResponse =
|
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtSecretResponse =
|
||||||
let arg_11 =
|
let Data8 =
|
||||||
(match node.["data8"] with
|
(match node.["data8"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -259,7 +262,7 @@ module JwtSecretResponse =
|
|||||||
|> Seq.map System.Collections.Generic.KeyValuePair
|
|> Seq.map System.Collections.Generic.KeyValuePair
|
||||||
|> System.Collections.Generic.Dictionary
|
|> System.Collections.Generic.Dictionary
|
||||||
|
|
||||||
let arg_10 =
|
let Data7 =
|
||||||
(match node.["data7"] with
|
(match node.["data7"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -276,7 +279,7 @@ module JwtSecretResponse =
|
|||||||
)
|
)
|
||||||
|> Map.ofSeq
|
|> Map.ofSeq
|
||||||
|
|
||||||
let arg_9 =
|
let Data6 =
|
||||||
(match node.["data6"] with
|
(match node.["data6"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -293,7 +296,7 @@ module JwtSecretResponse =
|
|||||||
)
|
)
|
||||||
|> dict
|
|> dict
|
||||||
|
|
||||||
let arg_8 =
|
let Data5 =
|
||||||
(match node.["data5"] with
|
(match node.["data5"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -310,7 +313,7 @@ module JwtSecretResponse =
|
|||||||
)
|
)
|
||||||
|> readOnlyDict
|
|> readOnlyDict
|
||||||
|
|
||||||
let arg_7 =
|
let Data4 =
|
||||||
(match node.["data4"] with
|
(match node.["data4"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -327,7 +330,7 @@ module JwtSecretResponse =
|
|||||||
)
|
)
|
||||||
|> Map.ofSeq
|
|> Map.ofSeq
|
||||||
|
|
||||||
let arg_6 =
|
let Data3 =
|
||||||
(match node.["data3"] with
|
(match node.["data3"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -345,7 +348,7 @@ module JwtSecretResponse =
|
|||||||
|> Seq.map System.Collections.Generic.KeyValuePair
|
|> Seq.map System.Collections.Generic.KeyValuePair
|
||||||
|> System.Collections.Generic.Dictionary
|
|> System.Collections.Generic.Dictionary
|
||||||
|
|
||||||
let arg_5 =
|
let Data2 =
|
||||||
(match node.["data2"] with
|
(match node.["data2"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -362,7 +365,7 @@ module JwtSecretResponse =
|
|||||||
)
|
)
|
||||||
|> dict
|
|> dict
|
||||||
|
|
||||||
let arg_4 =
|
let Data =
|
||||||
(match node.["data"] with
|
(match node.["data"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -379,7 +382,7 @@ module JwtSecretResponse =
|
|||||||
)
|
)
|
||||||
|> readOnlyDict
|
|> readOnlyDict
|
||||||
|
|
||||||
let arg_3 =
|
let LeaseDuration =
|
||||||
(match node.["lease_duration"] with
|
(match node.["lease_duration"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -391,7 +394,7 @@ module JwtSecretResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<int> ()
|
.GetValue<int> ()
|
||||||
|
|
||||||
let arg_2 =
|
let Renewable =
|
||||||
(match node.["renewable"] with
|
(match node.["renewable"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -403,7 +406,7 @@ module JwtSecretResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<bool> ()
|
.GetValue<bool> ()
|
||||||
|
|
||||||
let arg_1 =
|
let LeaseId =
|
||||||
(match node.["lease_id"] with
|
(match node.["lease_id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -415,7 +418,7 @@ module JwtSecretResponse =
|
|||||||
.AsValue()
|
.AsValue()
|
||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
let arg_0 =
|
let RequestId =
|
||||||
(match node.["request_id"] with
|
(match node.["request_id"] with
|
||||||
| null ->
|
| null ->
|
||||||
raise (
|
raise (
|
||||||
@@ -428,18 +431,18 @@ module JwtSecretResponse =
|
|||||||
.GetValue<string> ()
|
.GetValue<string> ()
|
||||||
|
|
||||||
{
|
{
|
||||||
RequestId = arg_0
|
RequestId = RequestId
|
||||||
LeaseId = arg_1
|
LeaseId = LeaseId
|
||||||
Renewable = arg_2
|
Renewable = Renewable
|
||||||
LeaseDuration = arg_3
|
LeaseDuration = LeaseDuration
|
||||||
Data = arg_4
|
Data = Data
|
||||||
Data2 = arg_5
|
Data2 = Data2
|
||||||
Data3 = arg_6
|
Data3 = Data3
|
||||||
Data4 = arg_7
|
Data4 = Data4
|
||||||
Data5 = arg_8
|
Data5 = Data5
|
||||||
Data6 = arg_9
|
Data6 = Data6
|
||||||
Data7 = arg_10
|
Data7 = Data7
|
||||||
Data8 = arg_11
|
Data8 = Data8
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
@@ -452,7 +455,8 @@ open System.Threading.Tasks
|
|||||||
open RestEase
|
open RestEase
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
/// Module for constructing a REST client.
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
module VaultClient =
|
module VaultClient =
|
||||||
/// Create a REST client.
|
/// Create a REST client.
|
||||||
let make (client : System.Net.Http.HttpClient) : IVaultClient =
|
let make (client : System.Net.Http.HttpClient) : IVaultClient =
|
||||||
@@ -539,200 +543,3 @@ module VaultClient =
|
|||||||
}
|
}
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
}
|
}
|
||||||
namespace ConsumePlugin
|
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Collections.Generic
|
|
||||||
open System.Text.Json.Serialization
|
|
||||||
open System.Threading
|
|
||||||
open System.Threading.Tasks
|
|
||||||
open RestEase
|
|
||||||
|
|
||||||
/// Module for constructing a REST client.
|
|
||||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
|
||||||
module VaultClientNonExtensionMethod =
|
|
||||||
/// Create a REST client.
|
|
||||||
let make (client : System.Net.Http.HttpClient) : IVaultClientNonExtensionMethod =
|
|
||||||
{ new IVaultClientNonExtensionMethod with
|
|
||||||
member _.GetSecret
|
|
||||||
(jwt : JwtVaultResponse, path : string, mountPoint : 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 (
|
|
||||||
"v1/{mountPoint}/{path}"
|
|
||||||
.Replace("{path}", path.ToString () |> System.Web.HttpUtility.UrlEncode)
|
|
||||||
.Replace (
|
|
||||||
"{mountPoint}",
|
|
||||||
mountPoint.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 JwtSecretResponse.jsonParse jsonNode
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
|
|
||||||
member _.GetJwt (role : string, jwt : 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 ("v1/auth/jwt/login", 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 JwtVaultResponse.jsonParse jsonNode
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
}
|
|
||||||
namespace ConsumePlugin
|
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Collections.Generic
|
|
||||||
open System.Text.Json.Serialization
|
|
||||||
open System.Threading
|
|
||||||
open System.Threading.Tasks
|
|
||||||
open RestEase
|
|
||||||
|
|
||||||
/// Extension methods for constructing a REST client.
|
|
||||||
[<AutoOpen>]
|
|
||||||
module VaultClientExtensionMethodHttpClientExtension =
|
|
||||||
/// Extension methods for HTTP clients
|
|
||||||
type VaultClientExtensionMethod with
|
|
||||||
|
|
||||||
/// Create a REST client.
|
|
||||||
static member make (client : System.Net.Http.HttpClient) : IVaultClientExtensionMethod =
|
|
||||||
{ new IVaultClientExtensionMethod with
|
|
||||||
member _.GetSecret
|
|
||||||
(jwt : JwtVaultResponse, path : string, mountPoint : 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 (
|
|
||||||
"v1/{mountPoint}/{path}"
|
|
||||||
.Replace("{path}", path.ToString () |> System.Web.HttpUtility.UrlEncode)
|
|
||||||
.Replace (
|
|
||||||
"{mountPoint}",
|
|
||||||
mountPoint.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 JwtSecretResponse.jsonParse jsonNode
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
|
|
||||||
member _.GetJwt (role : string, jwt : 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 ("v1/auth/jwt/login", 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 JwtVaultResponse.jsonParse jsonNode
|
|
||||||
}
|
|
||||||
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -32,27 +32,10 @@ type JsonRecordType =
|
|||||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||||
type ToGetExtensionMethod =
|
type ToGetExtensionMethod =
|
||||||
{
|
{
|
||||||
Alpha : string
|
Tinker : string
|
||||||
Bravo : System.Uri
|
Tailor : int
|
||||||
Charlie : float
|
Soldier : System.Uri
|
||||||
Delta : float32
|
Sailor : float
|
||||||
Echo : single
|
|
||||||
Foxtrot : double
|
|
||||||
Golf : int64
|
|
||||||
Hotel : uint64
|
|
||||||
India : int
|
|
||||||
Juliette : uint
|
|
||||||
Kilo : int32
|
|
||||||
Lima : uint32
|
|
||||||
Mike : int16
|
|
||||||
November : uint16
|
|
||||||
Oscar : int8
|
|
||||||
Papa : uint8
|
|
||||||
Quebec : byte
|
|
||||||
Tango : sbyte
|
|
||||||
Uniform : decimal
|
|
||||||
Victor : char
|
|
||||||
Whiskey : bigint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
|
|||||||
@@ -33,15 +33,15 @@ module MyListCata =
|
|||||||
| Process__MyList of MyList<'a>
|
| Process__MyList of MyList<'a>
|
||||||
| MyList_Cons of 'a
|
| MyList_Cons of 'a
|
||||||
|
|
||||||
let private loop (cata : MyListCata<'a, 'MyList>) (instructions : ResizeArray<Instruction<'a>>) =
|
let private loop (cata : MyListCata<_, _>) (instructions : ResizeArray<Instruction<_>>) =
|
||||||
let myListStack = ResizeArray<'MyList> ()
|
let myListStack = ResizeArray ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__MyList (x) ->
|
| Instruction.Process__MyList x ->
|
||||||
match x with
|
match x with
|
||||||
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
||||||
| MyList.Cons ({
|
| MyList.Cons ({
|
||||||
@@ -89,15 +89,15 @@ module MyList2Cata =
|
|||||||
| Process__MyList2 of MyList2<'a>
|
| Process__MyList2 of MyList2<'a>
|
||||||
| MyList2_Cons of 'a
|
| MyList2_Cons of 'a
|
||||||
|
|
||||||
let private loop (cata : MyList2Cata<'a, 'MyList2>) (instructions : ResizeArray<Instruction<'a>>) =
|
let private loop (cata : MyList2Cata<_, _>) (instructions : ResizeArray<Instruction<_>>) =
|
||||||
let myList2Stack = ResizeArray<'MyList2> ()
|
let myList2Stack = ResizeArray ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__MyList2 (x) ->
|
| Instruction.Process__MyList2 x ->
|
||||||
match x with
|
match x with
|
||||||
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
||||||
| MyList2.Cons (arg0_0, arg1_0) ->
|
| MyList2.Cons (arg0_0, arg1_0) ->
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
open System
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
[<GenerateMock>]
|
[<GenerateMock>]
|
||||||
@@ -42,9 +41,3 @@ type Curried<'a> =
|
|||||||
abstract Mem4 : (int * string) -> ('a * int) -> string
|
abstract Mem4 : (int * string) -> ('a * int) -> string
|
||||||
abstract Mem5 : x : int * string -> ('a * int) -> string
|
abstract Mem5 : x : int * string -> ('a * int) -> string
|
||||||
abstract Mem6 : int * string -> y : 'a * int -> string
|
abstract Mem6 : int * string -> y : 'a * int -> string
|
||||||
|
|
||||||
[<GenerateMock>]
|
|
||||||
type TypeWithInterface =
|
|
||||||
inherit IDisposable
|
|
||||||
abstract Mem1 : string option -> string[] Async
|
|
||||||
abstract Mem2 : unit -> string[] Async
|
|
||||||
|
|||||||
@@ -17,9 +17,6 @@ type IPureGymApi =
|
|||||||
[<Get "v1/gyms/{gym_id}/attendance">]
|
[<Get "v1/gyms/{gym_id}/attendance">]
|
||||||
abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
||||||
|
|
||||||
[<Get "v1/gyms/{gym_id}/attendance">]
|
|
||||||
abstract GetGymAttendance' : [<Path("gym_id")>] gymId : int * ?ct : CancellationToken -> Task<GymAttendance>
|
|
||||||
|
|
||||||
[<RestEase.GetAttribute "v1/member">]
|
[<RestEase.GetAttribute "v1/member">]
|
||||||
abstract GetMember : ?ct : CancellationToken -> Member Task
|
abstract GetMember : ?ct : CancellationToken -> Member Task
|
||||||
|
|
||||||
@@ -41,10 +38,6 @@ type IPureGymApi =
|
|||||||
abstract GetSessions :
|
abstract GetSessions :
|
||||||
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
||||||
|
|
||||||
[<Get "/v2/gymSessions/member?foo=1">]
|
|
||||||
abstract GetSessionsWithQuery :
|
|
||||||
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
|
||||||
|
|
||||||
// An example from RestEase's own docs
|
// An example from RestEase's own docs
|
||||||
[<Post "users/new">]
|
[<Post "users/new">]
|
||||||
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
||||||
@@ -127,8 +120,7 @@ type internal IApiWithoutBaseAddress =
|
|||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
[<BasePath "foo">]
|
[<BasePath "foo">]
|
||||||
type IApiWithBasePath =
|
type IApiWithBasePath =
|
||||||
// Example where we use the bundled attributes rather than RestEase's
|
[<Get "endpoint/{param}">]
|
||||||
[<WoofWare.Myriad.Plugins.RestEase.Get "endpoint/{param}">]
|
|
||||||
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
@@ -149,16 +141,3 @@ type IApiWithHeaders =
|
|||||||
|
|
||||||
[<Get "endpoint/{param}">]
|
[<Get "endpoint/{param}">]
|
||||||
abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
|
||||||
[<WoofWare.Myriad.Plugins.RestEase.Header("Header-Name", "Header-Value")>]
|
|
||||||
type IApiWithHeaders2 =
|
|
||||||
[<WoofWare.Myriad.Plugins.RestEase.Header "X-Foo">]
|
|
||||||
abstract SomeHeader : string
|
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.RestEase.Header "Authorization">]
|
|
||||||
abstract SomeOtherHeader : int
|
|
||||||
|
|
||||||
[<Get "endpoint/{param}">]
|
|
||||||
abstract GetPathParam :
|
|
||||||
[<WoofWare.Myriad.Plugins.RestEase.Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
|
||||||
|
|||||||
@@ -27,10 +27,3 @@ type JsonRecordTypeWithBoth =
|
|||||||
E : string array
|
E : string array
|
||||||
F : int[]
|
F : int[]
|
||||||
}
|
}
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
|
||||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
|
||||||
type FirstDu =
|
|
||||||
| EmptyCase
|
|
||||||
| Case1 of data : string
|
|
||||||
| Case2 of record : JsonRecordTypeWithBoth * i : int
|
|
||||||
|
|||||||
@@ -76,33 +76,3 @@ type IVaultClient =
|
|||||||
|
|
||||||
[<Get "v1/auth/jwt/login">]
|
[<Get "v1/auth/jwt/login">]
|
||||||
abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse>
|
abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse>
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.HttpClient false>]
|
|
||||||
type IVaultClientNonExtensionMethod =
|
|
||||||
[<Get "v1/{mountPoint}/{path}">]
|
|
||||||
abstract GetSecret :
|
|
||||||
jwt : JwtVaultResponse *
|
|
||||||
[<Path "path">] path : string *
|
|
||||||
[<Path "mountPoint">] mountPoint : string *
|
|
||||||
?ct : CancellationToken ->
|
|
||||||
Task<JwtSecretResponse>
|
|
||||||
|
|
||||||
[<Get "v1/auth/jwt/login">]
|
|
||||||
abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse>
|
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.HttpClient(true)>]
|
|
||||||
type IVaultClientExtensionMethod =
|
|
||||||
[<Get "v1/{mountPoint}/{path}">]
|
|
||||||
abstract GetSecret :
|
|
||||||
jwt : JwtVaultResponse *
|
|
||||||
[<Path "path">] path : string *
|
|
||||||
[<Path "mountPoint">] mountPoint : string *
|
|
||||||
?ct : CancellationToken ->
|
|
||||||
Task<JwtSecretResponse>
|
|
||||||
|
|
||||||
[<Get "v1/auth/jwt/login">]
|
|
||||||
abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse>
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
type VaultClientExtensionMethod =
|
|
||||||
static member thisClashes = 99
|
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -143,9 +143,6 @@ module InnerTypeWithBoth =
|
|||||||
node
|
node
|
||||||
```
|
```
|
||||||
|
|
||||||
Also includes an *opinionated* serializer for discriminated unions.
|
|
||||||
(Any such serializer must be opinionated, because JSON does not natively model DUs.)
|
|
||||||
|
|
||||||
As in `JsonParse`, you can optionally supply the boolean `true` to the attribute,
|
As in `JsonParse`, you can optionally supply the boolean `true` to the attribute,
|
||||||
which will cause Myriad to stamp out an extension method rather than a module with the same name as the type.
|
which will cause Myriad to stamp out an extension method rather than a module with the same name as the type.
|
||||||
|
|
||||||
@@ -335,7 +332,7 @@ thereby allowing the programmer to use F#'s record-update syntax.
|
|||||||
Takes a collection of mutually recursive discriminated unions:
|
Takes a collection of mutually recursive discriminated unions:
|
||||||
|
|
||||||
```fsharp
|
```fsharp
|
||||||
[<CreateCatamorphism "MyCata">]
|
[<CreateCatamorphism>]
|
||||||
type Expr =
|
type Expr =
|
||||||
| Const of Const
|
| Const of Const
|
||||||
| Pair of Expr * Expr * PairOpKind
|
| Pair of Expr * Expr * PairOpKind
|
||||||
@@ -359,7 +356,7 @@ type ExprBuilderCata<'Expr, 'ExprBuilder> =
|
|||||||
abstract Child : 'ExprBuilder -> 'ExprBuilder
|
abstract Child : 'ExprBuilder -> 'ExprBuilder
|
||||||
abstract Parent : 'Expr -> 'ExprBuilder
|
abstract Parent : 'Expr -> 'ExprBuilder
|
||||||
|
|
||||||
type MyCata<'Expr, 'ExprBuilder> =
|
type Cata<'Expr, 'ExprBuilder> =
|
||||||
{
|
{
|
||||||
Expr : ExprCata<'Expr, 'ExprBuilder>
|
Expr : ExprCata<'Expr, 'ExprBuilder>
|
||||||
ExprBuilder : ExprBuilderCata<'Expr, 'ExprBuilder>
|
ExprBuilder : ExprBuilderCata<'Expr, 'ExprBuilder>
|
||||||
@@ -367,10 +364,10 @@ type MyCata<'Expr, 'ExprBuilder> =
|
|||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module ExprCata =
|
module ExprCata =
|
||||||
let runExpr (cata : MyCata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
|
let runExpr (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
|
||||||
failwith "this is implemented"
|
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"
|
failwith "this is implemented"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -384,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).
|
* 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.
|
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 *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
|
### Limitations
|
||||||
|
|
||||||
|
|||||||
@@ -60,17 +60,8 @@ type JsonParseAttribute (isExtensionMethod : bool) =
|
|||||||
/// generator should apply during build.
|
/// generator should apply during build.
|
||||||
/// This generator is intended to replicate much of the functionality of RestEase,
|
/// This generator is intended to replicate much of the functionality of RestEase,
|
||||||
/// i.e. to stamp out HTTP REST clients from interfaces defining the API.
|
/// i.e. to stamp out HTTP REST clients from interfaces defining the API.
|
||||||
///
|
type HttpClientAttribute () =
|
||||||
/// If you supply isExtensionMethod = true, you will get extension methods.
|
|
||||||
/// These can only be consumed from F#, but the benefit is that they don't use up the module name
|
|
||||||
/// (since by default we create a module called "{TypeName}").
|
|
||||||
type HttpClientAttribute (isExtensionMethod : bool) =
|
|
||||||
inherit Attribute ()
|
inherit Attribute ()
|
||||||
/// The default value of `isExtensionMethod`, the optional argument to the HttpClientAttribute constructor.
|
|
||||||
static member DefaultIsExtensionMethod = false
|
|
||||||
|
|
||||||
/// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details.
|
|
||||||
new () = HttpClientAttribute HttpClientAttribute.DefaultIsExtensionMethod
|
|
||||||
|
|
||||||
/// Attribute indicating a DU type to which the "create catamorphism" Myriad
|
/// Attribute indicating a DU type to which the "create catamorphism" Myriad
|
||||||
/// generator should apply during build.
|
/// generator should apply during build.
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -6,10 +6,7 @@ WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: unit
|
|||||||
WoofWare.Myriad.Plugins.GenerateMockAttribute.DefaultIsInternal [static property]: [read-only] bool
|
WoofWare.Myriad.Plugins.GenerateMockAttribute.DefaultIsInternal [static property]: [read-only] bool
|
||||||
WoofWare.Myriad.Plugins.GenerateMockAttribute.get_DefaultIsInternal [static method]: unit -> bool
|
WoofWare.Myriad.Plugins.GenerateMockAttribute.get_DefaultIsInternal [static method]: unit -> bool
|
||||||
WoofWare.Myriad.Plugins.HttpClientAttribute inherit System.Attribute
|
WoofWare.Myriad.Plugins.HttpClientAttribute inherit System.Attribute
|
||||||
WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: bool
|
|
||||||
WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: unit
|
WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: unit
|
||||||
WoofWare.Myriad.Plugins.HttpClientAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
|
||||||
WoofWare.Myriad.Plugins.HttpClientAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
|
||||||
WoofWare.Myriad.Plugins.JsonParseAttribute inherit System.Attribute
|
WoofWare.Myriad.Plugins.JsonParseAttribute inherit System.Attribute
|
||||||
WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: bool
|
WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: bool
|
||||||
WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: unit
|
WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: unit
|
||||||
@@ -21,33 +18,4 @@ WoofWare.Myriad.Plugins.JsonSerializeAttribute..ctor [constructor]: unit
|
|||||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
||||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
||||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
||||||
WoofWare.Myriad.Plugins.RestEase inherit obj
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+DeleteAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+DeleteAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+GetAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+GetAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+HeadAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+HeadAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string option)
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string)
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+OptionsAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+OptionsAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PatchAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PatchAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PathAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string option
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: unit
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PostAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PostAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PutAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+PutAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+QueryAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+QueryAttribute..ctor [constructor]: string
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+TraceAttribute inherit System.Attribute
|
|
||||||
WoofWare.Myriad.Plugins.RestEase+TraceAttribute..ctor [constructor]: string
|
|
||||||
@@ -11,9 +11,11 @@ module TestSurface =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
||||||
|
|
||||||
|
(*
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Check version against remote`` () =
|
let ``Check version against remote`` () =
|
||||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
||||||
|
*)
|
||||||
|
|
||||||
[<Test ; Explicit>]
|
[<Test ; Explicit>]
|
||||||
let ``Update API surface`` () =
|
let ``Update API surface`` () =
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.40" />
|
<PackageReference Include="ApiSurface" Version="4.0.28" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
<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"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Attributes.fs"/>
|
<Compile Include="Attributes.fs"/>
|
||||||
<Compile Include="RestEase.fs" />
|
|
||||||
<EmbeddedResource Include="version.json"/>
|
<EmbeddedResource Include="version.json"/>
|
||||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||||
<None Include="..\README.md">
|
<None Include="..\README.md">
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "3.1",
|
"version": "2.2",
|
||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
"pathFilters": [
|
"pathFilters": null
|
||||||
":/README.md",
|
|
||||||
":/LICENSE",
|
|
||||||
":/WoofWare.Myriad.Plugins/logo.png",
|
|
||||||
":/Directory.Build.props",
|
|
||||||
":/global.json",
|
|
||||||
"./",
|
|
||||||
"^./Test"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ open FsCheck
|
|||||||
|
|
||||||
[<TestFixture>]
|
[<TestFixture>]
|
||||||
module TestCataGenerator =
|
module TestCataGenerator =
|
||||||
let idCata<'a, 'b> : TreeCata<'a, 'b, _, _> =
|
let idCata : TreeCata<_, _> =
|
||||||
{
|
{
|
||||||
Tree =
|
Tree =
|
||||||
{ new TreeCataCase<_, _, _, _> with
|
{ new TreeCataCase<_, _> with
|
||||||
member _.Const x y = Const (x, y)
|
member _.Const x = Const x
|
||||||
member _.Pair x y z = Pair (x, y, z)
|
member _.Pair x y z = Pair (x, y, z)
|
||||||
member _.Sequential xs = Sequential xs
|
member _.Sequential xs = Sequential xs
|
||||||
member _.Builder x b = Builder (x, b)
|
member _.Builder x b = Builder (x, b)
|
||||||
}
|
}
|
||||||
TreeBuilder =
|
TreeBuilder =
|
||||||
{ new TreeBuilderCataCase<_, _, _, _> with
|
{ new TreeBuilderCataCase<_, _> with
|
||||||
member _.Child x = Child x
|
member _.Child x = Child x
|
||||||
member _.Parent x = Parent x
|
member _.Parent x = Parent x
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ module TestCataGenerator =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Example`` () =
|
let ``Example`` () =
|
||||||
let x =
|
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
|
TreeCata.runTree idCata x |> shouldEqual x
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ module TestCataGenerator =
|
|||||||
let ``Cata works`` () =
|
let ``Cata works`` () =
|
||||||
let builderCases = ref 0
|
let builderCases = ref 0
|
||||||
|
|
||||||
let property (x : Tree<int, string>) =
|
let property (x : Tree) =
|
||||||
match x with
|
match x with
|
||||||
| Tree.Builder _ -> Interlocked.Increment builderCases |> ignore
|
| Tree.Builder _ -> Interlocked.Increment builderCases |> ignore
|
||||||
| _ -> ()
|
| _ -> ()
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ module TestMyList =
|
|||||||
Tail = tail
|
Tail = tail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ module TestMyList2 =
|
|||||||
{ new MyList2CataCase<'a, _> with
|
{ new MyList2CataCase<'a, _> with
|
||||||
member _.Nil = MyList2.Nil
|
member _.Nil = MyList2.Nil
|
||||||
|
|
||||||
member _.Cons (head : 'a) (tail : MyList2<'a>) = MyList2.Cons (head, tail)
|
member _.Cons head tail = MyList2.Cons (head, tail)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ module TestPureGymRestApi =
|
|||||||
let api = PureGymApi.make client
|
let api = PureGymApi.make client
|
||||||
|
|
||||||
api.GetGymAttendance(requestedGym).Result |> shouldEqual expected
|
api.GetGymAttendance(requestedGym).Result |> shouldEqual expected
|
||||||
api.GetGymAttendance'(requestedGym).Result |> shouldEqual expected
|
|
||||||
|
|
||||||
let memberCases =
|
let memberCases =
|
||||||
PureGymDtos.memberCases |> List.allPairs baseUris |> List.map TestCaseData
|
PureGymDtos.memberCases |> List.allPairs baseUris |> List.map TestCaseData
|
||||||
@@ -235,33 +234,6 @@ module TestPureGymRestApi =
|
|||||||
|
|
||||||
api.GetSessions(startDate, endDate).Result |> shouldEqual expected
|
api.GetSessions(startDate, endDate).Result |> shouldEqual expected
|
||||||
|
|
||||||
[<TestCaseSource(nameof sessionsCases)>]
|
|
||||||
let ``Test GetSessionsWithQuery``
|
|
||||||
(baseUri : Uri, (startDate : DateOnly, (endDate : DateOnly, (json : string, expected : Sessions))))
|
|
||||||
=
|
|
||||||
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
|
||||||
async {
|
|
||||||
message.Method |> shouldEqual HttpMethod.Get
|
|
||||||
|
|
||||||
// This one is specified as being absolute, in its attribute on the IPureGymApi type
|
|
||||||
let expectedUri =
|
|
||||||
let fromDate = dateOnlyToString startDate
|
|
||||||
let toDate = dateOnlyToString endDate
|
|
||||||
$"https://example.com/v2/gymSessions/member?foo=1&fromDate=%s{fromDate}&toDate=%s{toDate}"
|
|
||||||
|
|
||||||
message.RequestUri.ToString () |> shouldEqual expectedUri
|
|
||||||
|
|
||||||
let content = new StringContent (json)
|
|
||||||
let resp = new HttpResponseMessage (HttpStatusCode.OK)
|
|
||||||
resp.Content <- content
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
||||||
use client = HttpClientMock.make baseUri proc
|
|
||||||
let api = PureGymApi.make client
|
|
||||||
|
|
||||||
api.GetSessionsWithQuery(startDate, endDate).Result |> shouldEqual expected
|
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``URI example`` () =
|
let ``URI example`` () =
|
||||||
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
|||||||
@@ -87,10 +87,8 @@ module TestVaultClient =
|
|||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
[<TestCase 1>]
|
[<Test>]
|
||||||
[<TestCase 2>]
|
let ``URI example`` () =
|
||||||
[<TestCase 3>]
|
|
||||||
let ``URI example`` (vaultClientId : int) =
|
|
||||||
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
async {
|
async {
|
||||||
message.Method |> shouldEqual HttpMethod.Get
|
message.Method |> shouldEqual HttpMethod.Get
|
||||||
@@ -114,25 +112,10 @@ module TestVaultClient =
|
|||||||
}
|
}
|
||||||
|
|
||||||
use client = HttpClientMock.make (Uri "https://my-vault.com") proc
|
use client = HttpClientMock.make (Uri "https://my-vault.com") proc
|
||||||
|
let api = VaultClient.make client
|
||||||
|
|
||||||
let value =
|
let vaultResponse = api.GetJwt("role", "jwt").Result
|
||||||
match vaultClientId with
|
let value = api.GetSecret(vaultResponse, "path", "mount").Result
|
||||||
| 1 ->
|
|
||||||
let api = VaultClient.make client
|
|
||||||
let vaultResponse = api.GetJwt("role", "jwt").Result
|
|
||||||
let value = api.GetSecret(vaultResponse, "path", "mount").Result
|
|
||||||
value
|
|
||||||
| 2 ->
|
|
||||||
let api = VaultClientNonExtensionMethod.make client
|
|
||||||
let vaultResponse = api.GetJwt("role", "jwt").Result
|
|
||||||
let value = api.GetSecret(vaultResponse, "path", "mount").Result
|
|
||||||
value
|
|
||||||
| 3 ->
|
|
||||||
let api = VaultClientExtensionMethod.make client
|
|
||||||
let vaultResponse = api.GetJwt("role", "jwt").Result
|
|
||||||
let value = api.GetSecret(vaultResponse, "path", "mount").Result
|
|
||||||
value
|
|
||||||
| _ -> failwith $"Unrecognised ID: %i{vaultClientId}"
|
|
||||||
|
|
||||||
value.Data
|
value.Data
|
||||||
|> Seq.toList
|
|> Seq.toList
|
||||||
@@ -185,5 +168,3 @@ module TestVaultClient =
|
|||||||
"key8_1", "https://example.com/data8/1"
|
"key8_1", "https://example.com/data8/1"
|
||||||
"key8_2", "https://example.com/data8/2"
|
"key8_2", "https://example.com/data8/2"
|
||||||
]
|
]
|
||||||
|
|
||||||
let _canSeePastExtensionMethod = VaultClientExtensionMethod.thisClashes
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace WoofWare.Myriad.Plugins.Test
|
namespace WoofWare.Myriad.Plugins.Test
|
||||||
|
|
||||||
open System
|
open System
|
||||||
open System.Numerics
|
|
||||||
open System.Text.Json.Nodes
|
open System.Text.Json.Nodes
|
||||||
open ConsumePlugin
|
open ConsumePlugin
|
||||||
open NUnit.Framework
|
open NUnit.Framework
|
||||||
@@ -13,62 +12,15 @@ module TestExtensionMethod =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Parse via extension method`` () =
|
let ``Parse via extension method`` () =
|
||||||
let json =
|
let json =
|
||||||
"""{
|
"""{"tinker": "job", "tailor": 3, "soldier": "https://example.com", "sailor": 3.1}"""
|
||||||
"alpha": "hello!",
|
|
||||||
"bravo": "https://example.com",
|
|
||||||
"charlie": 0.3341,
|
|
||||||
"delta": 110033.4,
|
|
||||||
"echo": -0.000993,
|
|
||||||
"foxtrot": -999999999999,
|
|
||||||
"golf": -123456789101112,
|
|
||||||
"hotel": 18446744073709551615,
|
|
||||||
"india": 99884,
|
|
||||||
"juliette": 12223334,
|
|
||||||
"kilo": -2147483642,
|
|
||||||
"lima": 4294967293,
|
|
||||||
"mike": -32767,
|
|
||||||
"november": 65533,
|
|
||||||
"oscar": -125,
|
|
||||||
"papa": 253,
|
|
||||||
"quebec": 254,
|
|
||||||
"tango": -3,
|
|
||||||
"uniform": 1004443.300988393349583009,
|
|
||||||
"victor": "x",
|
|
||||||
"whiskey": 123456123456123456123456123456123456123456
|
|
||||||
}"""
|
|
||||||
|> JsonNode.Parse
|
|> JsonNode.Parse
|
||||||
|
|
||||||
let expected =
|
let expected =
|
||||||
{
|
{
|
||||||
Alpha = "hello!"
|
Tinker = "job"
|
||||||
Bravo = Uri "https://example.com"
|
Tailor = 3
|
||||||
Charlie = 0.3341
|
Soldier = Uri "https://example.com"
|
||||||
Delta = 110033.4f
|
Sailor = 3.1
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let actual = ToGetExtensionMethod.jsonParse json
|
ToGetExtensionMethod.jsonParse json |> shouldEqual expected
|
||||||
|
|
||||||
actual |> shouldEqual expected
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ open FsUnitTyped
|
|||||||
|
|
||||||
[<TestFixture>]
|
[<TestFixture>]
|
||||||
module TestJsonParse =
|
module TestJsonParse =
|
||||||
let _canSeePastExtensionMethod = ToGetExtensionMethod.thisModuleWouldClash
|
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Single example`` () =
|
let ``Single example`` () =
|
||||||
let s =
|
let s =
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ namespace WoofWare.Myriad.Plugins.Test
|
|||||||
|
|
||||||
open System
|
open System
|
||||||
open System.Collections.Generic
|
open System.Collections.Generic
|
||||||
|
open System.IO
|
||||||
|
open System.Text
|
||||||
|
open System.Text.Json
|
||||||
open System.Text.Json.Nodes
|
open System.Text.Json.Nodes
|
||||||
open FsCheck.Random
|
|
||||||
open Microsoft.FSharp.Reflection
|
|
||||||
open NUnit.Framework
|
open NUnit.Framework
|
||||||
open FsCheck
|
open FsCheck
|
||||||
open FsUnitTyped
|
open FsUnitTyped
|
||||||
@@ -123,83 +124,3 @@ module TestJsonSerde =
|
|||||||
|> shouldEqual (
|
|> shouldEqual (
|
||||||
sprintf """{"it\u0027s-a-me":"%s","map":{},"readOnlyDict":{},"dict":{},"concreteDict":{}}""" guidStr
|
sprintf """{"it\u0027s-a-me":"%s","map":{},"readOnlyDict":{},"dict":{},"concreteDict":{}}""" guidStr
|
||||||
)
|
)
|
||||||
|
|
||||||
type Generators =
|
|
||||||
static member TestCase () =
|
|
||||||
{ new Arbitrary<InnerTypeWithBoth>() with
|
|
||||||
override x.Generator = innerGen 5
|
|
||||||
}
|
|
||||||
|
|
||||||
let sanitiseInner (r : InnerTypeWithBoth) : InnerTypeWithBoth =
|
|
||||||
{
|
|
||||||
Thing = r.Thing
|
|
||||||
Map = r.Map
|
|
||||||
ReadOnlyDict = r.ReadOnlyDict
|
|
||||||
Dict = r.Dict
|
|
||||||
ConcreteDict = r.ConcreteDict
|
|
||||||
}
|
|
||||||
|
|
||||||
let sanitiseRec (r : JsonRecordTypeWithBoth) : JsonRecordTypeWithBoth =
|
|
||||||
{
|
|
||||||
A = r.A
|
|
||||||
B = if isNull r.B then "<null>" else r.B
|
|
||||||
C =
|
|
||||||
if Object.ReferenceEquals (r.C, (null : obj)) then
|
|
||||||
[]
|
|
||||||
else
|
|
||||||
r.C
|
|
||||||
D = sanitiseInner r.D
|
|
||||||
E = if isNull r.E then [||] else r.E
|
|
||||||
F =
|
|
||||||
if Object.ReferenceEquals (r.F, (null : obj)) then
|
|
||||||
[||]
|
|
||||||
else
|
|
||||||
r.F
|
|
||||||
}
|
|
||||||
|
|
||||||
let duGen =
|
|
||||||
gen {
|
|
||||||
let! case = Gen.choose (0, 2)
|
|
||||||
|
|
||||||
match case with
|
|
||||||
| 0 -> return FirstDu.EmptyCase
|
|
||||||
| 1 ->
|
|
||||||
let! s = Arb.generate<NonNull<string>>
|
|
||||||
return FirstDu.Case1 s.Get
|
|
||||||
| 2 ->
|
|
||||||
let! i = Arb.generate<int>
|
|
||||||
let! record = outerGen
|
|
||||||
return FirstDu.Case2 (record, i)
|
|
||||||
| _ -> return failwith $"unexpected: %i{case}"
|
|
||||||
}
|
|
||||||
|
|
||||||
[<Test>]
|
|
||||||
let ``Discriminated union works`` () =
|
|
||||||
let property (du : FirstDu) : unit =
|
|
||||||
du
|
|
||||||
|> FirstDu.toJsonNode
|
|
||||||
|> fun s -> s.ToJsonString ()
|
|
||||||
|> JsonNode.Parse
|
|
||||||
|> FirstDu.jsonParse
|
|
||||||
|> shouldEqual du
|
|
||||||
|
|
||||||
property |> Prop.forAll (Arb.fromGen duGen) |> Check.QuickThrowOnFailure
|
|
||||||
|
|
||||||
[<Test>]
|
|
||||||
let ``DU generator covers all cases`` () =
|
|
||||||
let rand = Random ()
|
|
||||||
let cases = FSharpType.GetUnionCases typeof<FirstDu>
|
|
||||||
let counts = Array.zeroCreate<int> cases.Length
|
|
||||||
|
|
||||||
let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu>
|
|
||||||
|
|
||||||
let mutable i = 0
|
|
||||||
|
|
||||||
while i < 10_000 && Array.exists (fun i -> i = 0) counts do
|
|
||||||
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
|
|
||||||
let tag = decompose du
|
|
||||||
counts.[tag] <- counts.[tag] + 1
|
|
||||||
i <- i + 1
|
|
||||||
|
|
||||||
for i in counts do
|
|
||||||
i |> shouldBeGreaterThan 0
|
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ module TestSurface =
|
|||||||
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
// https://github.com/nunit/nunit3-vs-adapter/issues/876
|
let ``Check version against remote`` () =
|
||||||
let CheckVersionAgainstRemote () =
|
|
||||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins"
|
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins"
|
||||||
|
|
||||||
[<Test ; Explicit>]
|
[<Test ; Explicit>]
|
||||||
|
|||||||
@@ -33,12 +33,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.40"/>
|
<PackageReference Include="ApiSurface" Version="4.0.28"/>
|
||||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
<PackageReference Include="NUnit" Version="4.0.1"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
open Fantomas.FCS.Text.Range
|
open Fantomas.FCS.Text.Range
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
|
open Myriad.Core.AstExtensions
|
||||||
|
|
||||||
type internal ParameterInfo =
|
type internal ParameterInfo =
|
||||||
{
|
{
|
||||||
@@ -52,7 +54,6 @@ type internal InterfaceType =
|
|||||||
{
|
{
|
||||||
Attributes : SynAttribute list
|
Attributes : SynAttribute list
|
||||||
Name : LongIdent
|
Name : LongIdent
|
||||||
Inherits : SynType list
|
|
||||||
Members : MemberInfo list
|
Members : MemberInfo list
|
||||||
Properties : PropertyInfo list
|
Properties : PropertyInfo list
|
||||||
Generics : SynTyparDecls option
|
Generics : SynTyparDecls option
|
||||||
@@ -75,9 +76,6 @@ type internal AdtNode =
|
|||||||
{
|
{
|
||||||
Type : SynType
|
Type : SynType
|
||||||
Name : Ident option
|
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`);
|
/// A DU is a sum of products (e.g. `type Thing = Foo of a * b`);
|
||||||
@@ -87,10 +85,6 @@ type internal AdtProduct =
|
|||||||
{
|
{
|
||||||
Name : SynIdent
|
Name : SynIdent
|
||||||
Fields : AdtNode list
|
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>]
|
[<RequireQualifiedAccess>]
|
||||||
@@ -104,17 +98,81 @@ module internal AstHelper =
|
|||||||
SynExpr.Record (None, None, fields, range0)
|
SynExpr.Record (None, None, fields, range0)
|
||||||
|
|
||||||
let defineRecordType (record : RecordType) : SynTypeDefn =
|
let defineRecordType (record : RecordType) : SynTypeDefn =
|
||||||
let name =
|
let repr =
|
||||||
SynComponentInfo.create record.Name
|
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, Seq.toList record.Fields, range0), range0)
|
||||||
|> SynComponentInfo.setAccessibility record.Accessibility
|
|
||||||
|> match record.XmlDoc with
|
|
||||||
| None -> id
|
|
||||||
| Some doc -> SynComponentInfo.withDocString doc
|
|
||||||
|> SynComponentInfo.setGenerics record.Generics
|
|
||||||
|
|
||||||
SynTypeDefnRepr.record (Seq.toList record.Fields)
|
let name =
|
||||||
|> SynTypeDefn.create name
|
SynComponentInfo.Create (
|
||||||
|> SynTypeDefn.withMemberDefns (defaultArg record.Members SynMemberDefns.Empty)
|
[ record.Name ],
|
||||||
|
?xmldoc = record.XmlDoc,
|
||||||
|
?parameters = record.Generics,
|
||||||
|
access = record.Accessibility
|
||||||
|
)
|
||||||
|
|
||||||
|
let trivia : SynTypeDefnTrivia =
|
||||||
|
{
|
||||||
|
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||||
|
EqualsRange = Some range0
|
||||||
|
WithKeyword = Some range0
|
||||||
|
}
|
||||||
|
|
||||||
|
SynTypeDefn (name, repr, defaultArg record.Members SynMemberDefns.Empty, None, range0, trivia)
|
||||||
|
|
||||||
|
let isOptionIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||||
|
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isListIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||||
|
// TODO: consider FSharpList or whatever it is
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isArrayIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] when
|
||||||
|
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
|
||||||
|
->
|
||||||
|
true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isResponseIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent |> List.map _.idText with
|
||||||
|
| [ "Response" ]
|
||||||
|
| [ "RestEase" ; "Response" ] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isMapIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent |> List.map _.idText with
|
||||||
|
| [ "Map" ] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isReadOnlyDictionaryIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent |> List.map _.idText with
|
||||||
|
| [ "IReadOnlyDictionary" ]
|
||||||
|
| [ "Generic" ; "IReadOnlyDictionary" ]
|
||||||
|
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
|
||||||
|
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isDictionaryIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent |> List.map _.idText with
|
||||||
|
| [ "Dictionary" ]
|
||||||
|
| [ "Generic" ; "Dictionary" ]
|
||||||
|
| [ "Collections" ; "Generic" ; "Dictionary" ]
|
||||||
|
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
let isIDictionaryIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent |> List.map _.idText with
|
||||||
|
| [ "IDictionary" ]
|
||||||
|
| [ "Generic" ; "IDictionary" ]
|
||||||
|
| [ "Collections" ; "Generic" ; "IDictionary" ]
|
||||||
|
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
let rec private extractOpensFromDecl (moduleDecls : SynModuleDecl list) : SynOpenDeclTarget list =
|
let rec private extractOpensFromDecl (moduleDecls : SynModuleDecl list) : SynOpenDeclTarget list =
|
||||||
moduleDecls
|
moduleDecls
|
||||||
@@ -136,12 +194,12 @@ module internal AstHelper =
|
|||||||
| SynType.Paren (inner, _) ->
|
| SynType.Paren (inner, _) ->
|
||||||
let result, _ = convertSigParam inner
|
let result, _ = convertSigParam inner
|
||||||
result, true
|
result, true
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
| SynType.LongIdent ident ->
|
||||||
{
|
{
|
||||||
Attributes = []
|
Attributes = []
|
||||||
IsOptional = false
|
IsOptional = false
|
||||||
Id = None
|
Id = None
|
||||||
Type = SynType.createLongIdent ident
|
Type = SynType.CreateLongIdent ident
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
| SynType.SignatureParameter (attrs, opt, id, usedType, _) ->
|
| SynType.SignatureParameter (attrs, opt, id, usedType, _) ->
|
||||||
@@ -159,7 +217,7 @@ module internal AstHelper =
|
|||||||
Attributes = []
|
Attributes = []
|
||||||
IsOptional = false
|
IsOptional = false
|
||||||
Id = None
|
Id = None
|
||||||
Type = SynType.var typar
|
Type = SynType.Var (typar, range0)
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
| _ -> failwithf "expected SignatureParameter, got: %+A" ty
|
| _ -> failwithf "expected SignatureParameter, got: %+A" ty
|
||||||
@@ -190,7 +248,7 @@ module internal AstHelper =
|
|||||||
|
|
||||||
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
||||||
(ret, List.rev inputs)
|
(ret, List.rev inputs)
|
||||||
||> List.fold (fun ty input -> SynType.funFromDomain input ty)
|
||> List.fold (fun ty input -> SynType.CreateFun (input, ty))
|
||||||
|
|
||||||
/// Returns the args (where these are tuple types if curried) in order, and the return type.
|
/// Returns the args (where these are tuple types if curried) in order, and the return type.
|
||||||
let rec getType (ty : SynType) : (SynType * bool) list * SynType =
|
let rec getType (ty : SynType) : (SynType * bool) list * SynType =
|
||||||
@@ -261,7 +319,7 @@ module internal AstHelper =
|
|||||||
Attributes = []
|
Attributes = []
|
||||||
IsOptional = false
|
IsOptional = false
|
||||||
Id = None
|
Id = None
|
||||||
Type = SynType.createLongIdent ident
|
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident)
|
||||||
}
|
}
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
}
|
}
|
||||||
@@ -273,22 +331,11 @@ module internal AstHelper =
|
|||||||
Attributes = []
|
Attributes = []
|
||||||
IsOptional = false
|
IsOptional = false
|
||||||
Id = None
|
Id = None
|
||||||
Type = SynType.var typar
|
Type = SynType.Var (typar, range0)
|
||||||
}
|
|
||||||
|> List.singleton
|
|
||||||
}
|
|
||||||
| arg ->
|
|
||||||
{
|
|
||||||
HasParen = false
|
|
||||||
Args =
|
|
||||||
{
|
|
||||||
Attributes = []
|
|
||||||
IsOptional = false
|
|
||||||
Id = None
|
|
||||||
Type = arg
|
|
||||||
}
|
}
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
}
|
}
|
||||||
|
| _ -> failwith $"Unrecognised args in interface method declaration: %+A{args}"
|
||||||
|> fun ty ->
|
|> fun ty ->
|
||||||
{ ty with
|
{ ty with
|
||||||
HasParen = ty.HasParen || hasParen
|
HasParen = ty.HasParen || hasParen
|
||||||
@@ -332,26 +379,22 @@ module internal AstHelper =
|
|||||||
|
|
||||||
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
||||||
|
|
||||||
let members, inherits =
|
let members, properties =
|
||||||
match synTypeDefnRepr with
|
match synTypeDefnRepr with
|
||||||
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
||||||
members
|
members
|
||||||
|> List.map (fun defn ->
|
|> List.map (fun defn ->
|
||||||
match defn with
|
match defn with
|
||||||
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> Choice1Of2 (parseMember slotSig flags)
|
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> parseMember slotSig flags
|
||||||
| SynMemberDefn.Inherit (baseType, _asIdent, _) -> Choice2Of2 baseType
|
|
||||||
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
||||||
)
|
)
|
||||||
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
||||||
|> List.partitionChoice
|
|> List.partitionChoice
|
||||||
|
|
||||||
let members, properties = members |> List.partitionChoice
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Members = members
|
Members = members
|
||||||
Properties = properties
|
Properties = properties
|
||||||
Name = interfaceName
|
Name = interfaceName
|
||||||
Inherits = inherits
|
|
||||||
Attributes = attrs
|
Attributes = attrs
|
||||||
Generics = typars
|
Generics = typars
|
||||||
Accessibility = accessibility
|
Accessibility = accessibility
|
||||||
@@ -392,30 +435,15 @@ module internal AstHelper =
|
|||||||
{
|
{
|
||||||
Type = ty
|
Type = ty
|
||||||
Name = id
|
Name = id
|
||||||
GenericsOfParent = typars
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Generics = typars
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
cases, typars, access
|
cases, typars, access
|
||||||
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
||||||
|
|
||||||
let getRecordFields (SynTypeDefn.SynTypeDefn (typeInfo, repr, _, _, _, _)) : AdtNode list =
|
let getRecordFields (SynTypeDefn.SynTypeDefn (_, 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
|
|
||||||
|
|
||||||
match repr with
|
match repr with
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_, fields, _), _) ->
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_, fields, _), _) ->
|
||||||
fields
|
fields
|
||||||
@@ -423,7 +451,179 @@ module internal AstHelper =
|
|||||||
{
|
{
|
||||||
Name = ident
|
Name = ident
|
||||||
Type = ty
|
Type = ty
|
||||||
GenericsOfParent = typars
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
||||||
|
|
||||||
|
[<AutoOpen>]
|
||||||
|
module internal SynTypePatterns =
|
||||||
|
let (|OptionType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isOptionIdent ident ->
|
||||||
|
Some innerType
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|ListType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
||||||
|
Some innerType
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|ArrayType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isArrayIdent ident ->
|
||||||
|
Some innerType
|
||||||
|
| SynType.Array (1, innerType, _) -> Some innerType
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|RestEaseResponseType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isResponseIdent ident ->
|
||||||
|
Some innerType
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|DictionaryType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isDictionaryIdent ident ->
|
||||||
|
Some (key, value)
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|IDictionaryType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isIDictionaryIdent ident ->
|
||||||
|
Some (key, value)
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
|
||||||
|
AstHelper.isReadOnlyDictionaryIdent ident
|
||||||
|
->
|
||||||
|
Some (key, value)
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|MapType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isMapIdent ident ->
|
||||||
|
Some (key, value)
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
/// Returns the string name of the type.
|
||||||
|
let (|PrimitiveType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] ->
|
||||||
|
[ "string" ; "float" ; "int" ; "bool" ; "char" ]
|
||||||
|
|> List.tryFind (fun s -> s = i.idText)
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|String|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] ->
|
||||||
|
[ "string" ]
|
||||||
|
|> List.tryFind (fun s -> s = i.idText)
|
||||||
|
|> Option.map ignore<string>
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|Byte|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|Guid|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "Guid" ]
|
||||||
|
| [ "Guid" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||||
|
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||||
|
| [ "Http" ; "HttpResponseMessage" ]
|
||||||
|
| [ "HttpResponseMessage" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|HttpContent|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
|
||||||
|
| [ "Net" ; "Http" ; "HttpContent" ]
|
||||||
|
| [ "Http" ; "HttpContent" ]
|
||||||
|
| [ "HttpContent" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|Stream|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "IO" ; "Stream" ]
|
||||||
|
| [ "IO" ; "Stream" ]
|
||||||
|
| [ "Stream" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|NumberType|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident ->
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] -> [ "string" ; "float" ; "int" ; "bool" ] |> List.tryFind (fun s -> s = i.idText)
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|DateOnly|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||||
|
match ident |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "DateOnly" ]
|
||||||
|
| [ "DateOnly" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|DateTime|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||||
|
match ident |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "DateTime" ]
|
||||||
|
| [ "DateTime" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|Uri|_|) (fieldType : SynType) =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||||
|
match ident |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "System" ; "Uri" ]
|
||||||
|
| [ "Uri" ] -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
|
let (|Task|_|) (fieldType : SynType) : SynType option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
|
||||||
|
match ident |> List.map (fun i -> i.idText) with
|
||||||
|
| [ "Task" ]
|
||||||
|
| [ "Tasks" ; "Task" ]
|
||||||
|
| [ "Threading" ; "Tasks" ; "Task" ]
|
||||||
|
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
|
||||||
|
match args with
|
||||||
|
| [ arg ] -> Some arg
|
||||||
|
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
|
||||||
|
| _ -> None
|
||||||
|
| _ -> None
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,13 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open System
|
||||||
open System.Net.Http
|
open System.Net.Http
|
||||||
|
open System.Text
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
open Myriad.Core
|
open Myriad.Core
|
||||||
|
|
||||||
type internal HttpClientGeneratorOutputSpec =
|
|
||||||
{
|
|
||||||
ExtensionMethods : bool
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal HttpClientGenerator =
|
module internal HttpClientGenerator =
|
||||||
open Fantomas.FCS.Text.Range
|
open Fantomas.FCS.Text.Range
|
||||||
@@ -82,53 +79,37 @@ module internal HttpClientGenerator =
|
|||||||
let matchingAttrs =
|
let matchingAttrs =
|
||||||
attrs
|
attrs
|
||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match SynLongIdent.toString attr.TypeName with
|
match attr.TypeName.AsString with
|
||||||
| "Get"
|
| "Get"
|
||||||
| "GetAttribute"
|
| "GetAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Get"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.GetAttribute"
|
|
||||||
| "RestEase.Get"
|
| "RestEase.Get"
|
||||||
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
||||||
| "Post"
|
| "Post"
|
||||||
| "PostAttribute"
|
| "PostAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Post"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.PostAttribute"
|
|
||||||
| "RestEase.Post"
|
| "RestEase.Post"
|
||||||
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
||||||
| "Put"
|
| "Put"
|
||||||
| "PutAttribute"
|
| "PutAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Put"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.PutAttribute"
|
|
||||||
| "RestEase.Put"
|
| "RestEase.Put"
|
||||||
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
||||||
| "Delete"
|
| "Delete"
|
||||||
| "DeleteAttribute"
|
| "DeleteAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Delete"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.DeleteAttribute"
|
|
||||||
| "RestEase.Delete"
|
| "RestEase.Delete"
|
||||||
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
||||||
| "Head"
|
| "Head"
|
||||||
| "HeadAttribute"
|
| "HeadAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Head"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.HeadAttribute"
|
|
||||||
| "RestEase.Head"
|
| "RestEase.Head"
|
||||||
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
||||||
| "Options"
|
| "Options"
|
||||||
| "OptionsAttribute"
|
| "OptionsAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Options"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.OptionsAttribute"
|
|
||||||
| "RestEase.Options"
|
| "RestEase.Options"
|
||||||
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
||||||
| "Patch"
|
| "Patch"
|
||||||
| "PatchAttribute"
|
| "PatchAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Patch"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.PatchAttribute"
|
|
||||||
| "RestEase.Patch"
|
| "RestEase.Patch"
|
||||||
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
||||||
| "Trace"
|
| "Trace"
|
||||||
| "TraceAttribute"
|
| "TraceAttribute"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Trace"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.TraceAttribute"
|
|
||||||
| "RestEase.Trace"
|
| "RestEase.Trace"
|
||||||
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
||||||
| _ -> None
|
| _ -> None
|
||||||
@@ -144,10 +125,9 @@ module internal HttpClientGenerator =
|
|||||||
let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list =
|
let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list =
|
||||||
attrs
|
attrs
|
||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match SynLongIdent.toString attr.TypeName with
|
match attr.TypeName.AsString with
|
||||||
| "Header"
|
| "Header"
|
||||||
| "RestEase.Header"
|
| "RestEase.Header" ->
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Header" ->
|
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
||||||
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
||||||
@@ -158,7 +138,7 @@ module internal HttpClientGenerator =
|
|||||||
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
|
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
|
||||||
attrs
|
attrs
|
||||||
|> List.exists (fun attr ->
|
|> List.exists (fun attr ->
|
||||||
match SynLongIdent.toString attr.TypeName with
|
match attr.TypeName.AsString with
|
||||||
| "AllowAnyStatusCode"
|
| "AllowAnyStatusCode"
|
||||||
| "AllowAnyStatusCodeAttribute"
|
| "AllowAnyStatusCodeAttribute"
|
||||||
| "RestEase.AllowAnyStatusCode"
|
| "RestEase.AllowAnyStatusCode"
|
||||||
@@ -213,7 +193,11 @@ module internal HttpClientGenerator =
|
|||||||
|
|
||||||
let argType =
|
let argType =
|
||||||
if arg.IsOptional then
|
if arg.IsOptional then
|
||||||
SynType.appPostfix "option" arg.Type
|
SynType.CreateApp (
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateString "option"),
|
||||||
|
[ arg.Type ],
|
||||||
|
isPostfix = true
|
||||||
|
)
|
||||||
else
|
else
|
||||||
arg.Type
|
arg.Type
|
||||||
|
|
||||||
@@ -225,15 +209,25 @@ module internal HttpClientGenerator =
|
|||||||
| None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}"
|
| None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}"
|
||||||
| Some (arg, _) -> arg
|
| Some (arg, _) -> arg
|
||||||
|
|
||||||
|
let argPats =
|
||||||
|
let args = args |> List.map snd
|
||||||
|
|
||||||
|
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||||
|
|> SynPat.CreateParen
|
||||||
|
|> List.singleton
|
||||||
|
|> SynArgPats.Pats
|
||||||
|
|
||||||
let headPat =
|
let headPat =
|
||||||
let thisIdent = if variableHeaders.IsEmpty then "_" else "this"
|
let thisIdent = if variableHeaders.IsEmpty then "_" else "this"
|
||||||
|
|
||||||
args
|
SynPat.LongIdent (
|
||||||
|> List.map snd
|
SynLongIdent.CreateFromLongIdent [ Ident.Create thisIdent ; info.Identifier ],
|
||||||
|> SynPat.tuple
|
None,
|
||||||
|> List.singleton
|
None,
|
||||||
|> SynArgPats.Pats
|
argPats,
|
||||||
|> SynPat.identWithArgs [ Ident.create thisIdent ; info.Identifier ]
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
let requestUriTrailer =
|
let requestUriTrailer =
|
||||||
(info.UrlTemplate, info.Args)
|
(info.UrlTemplate, info.Args)
|
||||||
@@ -255,12 +249,14 @@ module internal HttpClientGenerator =
|
|||||||
template
|
template
|
||||||
|> SynExpr.callMethodArg
|
|> SynExpr.callMethodArg
|
||||||
"Replace"
|
"Replace"
|
||||||
(SynExpr.tuple
|
(SynExpr.CreateParenedTuple
|
||||||
[
|
[
|
||||||
SynExpr.CreateConst ("{" + substituteId + "}")
|
SynExpr.CreateConstString ("{" + substituteId + "}")
|
||||||
SynExpr.callMethod "ToString" (SynExpr.createIdent' varName)
|
SynExpr.callMethod "ToString" (SynExpr.CreateIdent varName)
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
| _ -> template
|
| _ -> template
|
||||||
@@ -297,30 +293,15 @@ module internal HttpClientGenerator =
|
|||||||
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
||||||
| Some id -> id
|
| Some id -> id
|
||||||
|
|
||||||
let urlSeparator =
|
|
||||||
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
|
||||||
let questionMark =
|
|
||||||
SynExpr.CreateConst 63
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createIdent "char")
|
|
||||||
|> SynExpr.paren
|
|
||||||
|
|
||||||
let containsQuestion =
|
|
||||||
info.UrlTemplate
|
|
||||||
|> SynExpr.callMethodArg "IndexOf" questionMark
|
|
||||||
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst 0)
|
|
||||||
|
|
||||||
SynExpr.ifThenElse containsQuestion (SynExpr.CreateConst "?") (SynExpr.CreateConst "&")
|
|
||||||
|> SynExpr.paren
|
|
||||||
|
|
||||||
let prefix =
|
let prefix =
|
||||||
SynExpr.createIdent' firstValueId
|
SynExpr.CreateIdent firstValueId
|
||||||
|> SynExpr.toString firstValue.Type
|
|> SynExpr.toString firstValue.Type
|
||||||
|> SynExpr.paren
|
|> SynExpr.CreateParen
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
||||||
)
|
)
|
||||||
|> SynExpr.paren
|
|> SynExpr.CreateParen
|
||||||
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConst (firstKey + "=")))
|
|> SynExpr.plus (SynExpr.CreateConstString ("?" + firstKey + "="))
|
||||||
|
|
||||||
(prefix, queryParams)
|
(prefix, queryParams)
|
||||||
||> List.fold (fun uri (paramKey, paramValue) ->
|
||> List.fold (fun uri (paramKey, paramValue) ->
|
||||||
@@ -329,55 +310,82 @@ module internal HttpClientGenerator =
|
|||||||
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
||||||
| Some id -> id
|
| Some id -> id
|
||||||
|
|
||||||
SynExpr.toString paramValue.Type (SynExpr.createIdent' paramValueId)
|
SynExpr.toString paramValue.Type (SynExpr.CreateIdent paramValueId)
|
||||||
|> SynExpr.paren
|
|> SynExpr.CreateParen
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.paren
|
|> SynExpr.CreateParen
|
||||||
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConst ("&" + paramKey + "=")))
|
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConstString ("&" + paramKey + "=")))
|
||||||
)
|
)
|
||||||
|> SynExpr.plus requestUriTrailer
|
|> SynExpr.plus requestUriTrailer
|
||||||
|> SynExpr.paren
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
let requestUri =
|
let requestUri =
|
||||||
let uriIdent = SynExpr.createLongIdent [ "System" ; "Uri" ]
|
let uriIdent = SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ])
|
||||||
|
|
||||||
let baseAddress = SynExpr.createLongIdent [ "client" ; "BaseAddress" ]
|
|
||||||
|
|
||||||
let baseAddress =
|
let baseAddress =
|
||||||
[
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "client" ; "BaseAddress" ])
|
||||||
SynMatchClause.create
|
|
||||||
SynPat.createNull
|
|
||||||
(match info.BaseAddress with
|
|
||||||
| None ->
|
|
||||||
[
|
|
||||||
SynExpr.applyFunction (SynExpr.createIdent "nameof") (SynExpr.paren baseAddress)
|
|
||||||
SynExpr.CreateConst
|
|
||||||
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
|
||||||
]
|
|
||||||
|> SynExpr.tuple
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|
|
||||||
|> SynExpr.paren
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
|
||||||
| Some expr -> SynExpr.applyFunction uriIdent expr)
|
|
||||||
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
|
|
||||||
]
|
|
||||||
|> SynExpr.createMatch baseAddress
|
|
||||||
|> SynExpr.paren
|
|
||||||
|
|
||||||
[
|
let baseAddress =
|
||||||
baseAddress
|
SynExpr.CreateMatch (
|
||||||
SynExpr.applyFunction
|
baseAddress,
|
||||||
uriIdent
|
[
|
||||||
(SynExpr.tuple
|
SynMatchClause.Create (
|
||||||
[
|
SynPat.CreateNull,
|
||||||
requestUriTrailer
|
None,
|
||||||
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
|
match info.BaseAddress with
|
||||||
])
|
| None ->
|
||||||
]
|
SynExpr.CreateApp (
|
||||||
|> SynExpr.tuple
|
SynExpr.CreateIdentString "raise",
|
||||||
|> SynExpr.applyFunction uriIdent
|
SynExpr.CreateParen (
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "ArgumentNullException" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateIdentString "nameof",
|
||||||
|
SynExpr.CreateParen baseAddress
|
||||||
|
)
|
||||||
|
SynExpr.CreateConstString
|
||||||
|
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| Some expr -> SynExpr.CreateApp (uriIdent, expr)
|
||||||
|
)
|
||||||
|
SynMatchClause.Create (
|
||||||
|
SynPat.CreateNamed (Ident.Create "v"),
|
||||||
|
None,
|
||||||
|
SynExpr.CreateIdentString "v"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
|
SynExpr.App (
|
||||||
|
ExprAtomicFlag.Atomic,
|
||||||
|
false,
|
||||||
|
uriIdent,
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[
|
||||||
|
baseAddress
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
uriIdent,
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[
|
||||||
|
requestUriTrailer
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "UriKind" ; "Relative" ])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
let bodyParams =
|
let bodyParams =
|
||||||
info.Args
|
info.Args
|
||||||
@@ -411,43 +419,58 @@ module internal HttpClientGenerator =
|
|||||||
let httpReqMessageConstructor =
|
let httpReqMessageConstructor =
|
||||||
[
|
[
|
||||||
SynExpr.equals
|
SynExpr.equals
|
||||||
(SynExpr.createIdent "Method")
|
(SynExpr.CreateIdentString "Method")
|
||||||
(SynExpr.createLongIdent
|
(SynExpr.CreateLongIdent (
|
||||||
[ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ])
|
SynLongIdent.Create
|
||||||
SynExpr.equals (SynExpr.createIdent "RequestUri") (SynExpr.createIdent "uri")
|
[ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ]
|
||||||
|
))
|
||||||
|
SynExpr.equals (SynExpr.CreateIdentString "RequestUri") (SynExpr.CreateIdentString "uri")
|
||||||
]
|
]
|
||||||
|> SynExpr.tupleNoParen
|
|> SynExpr.CreateParenedTuple
|
||||||
|
|
||||||
let returnExpr =
|
let returnExpr =
|
||||||
match info.TaskReturnType with
|
match info.TaskReturnType with
|
||||||
| HttpResponseMessage -> SynExpr.createIdent "response"
|
| HttpResponseMessage -> SynExpr.CreateIdentString "response"
|
||||||
| String -> SynExpr.createIdent "responseString"
|
| String -> SynExpr.CreateIdentString "responseString"
|
||||||
| Stream -> SynExpr.createIdent "responseStream"
|
| Stream -> SynExpr.CreateIdentString "responseStream"
|
||||||
| RestEaseResponseType contents ->
|
| RestEaseResponseType contents ->
|
||||||
let deserialiser =
|
let deserialiser =
|
||||||
JsonParseGenerator.parseNode
|
SynExpr.CreateLambda (
|
||||||
None
|
[ SynPat.CreateConst SynConst.Unit ],
|
||||||
JsonParseGenerator.JsonParseOption.None
|
SynExpr.CreateParen (
|
||||||
contents
|
JsonParseGenerator.parseNode
|
||||||
(SynExpr.createIdent "jsonNode")
|
None
|
||||||
|> SynExpr.paren
|
JsonParseGenerator.JsonParseOption.None
|
||||||
|> SynExpr.createThunk
|
contents
|
||||||
|
(SynExpr.CreateIdentString "jsonNode")
|
||||||
|
)
|
||||||
|
)
|
||||||
// new RestEase.Response (content : string, response : HttpResponseMessage, deserialiser : unit -> 'T)
|
// new RestEase.Response (content : string, response : HttpResponseMessage, deserialiser : unit -> 'T)
|
||||||
SynExpr.createNew
|
SynExpr.New (
|
||||||
(SynType.app' (SynType.createLongIdent' [ "RestEase" ; "Response" ]) [ SynType.Anon range0 ])
|
false,
|
||||||
(SynExpr.CreateTuple
|
SynType.App (
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.Create [ "RestEase" ; "Response" ]),
|
||||||
|
Some range0,
|
||||||
|
[ SynType.Anon range0 ],
|
||||||
|
[],
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
),
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
[
|
[
|
||||||
SynExpr.createIdent "responseString"
|
SynExpr.CreateIdentString "responseString"
|
||||||
SynExpr.createIdent "response"
|
SynExpr.CreateIdentString "response"
|
||||||
deserialiser
|
SynExpr.CreateParen deserialiser
|
||||||
])
|
],
|
||||||
|
range0
|
||||||
|
)
|
||||||
| retType ->
|
| retType ->
|
||||||
JsonParseGenerator.parseNode
|
JsonParseGenerator.parseNode
|
||||||
None
|
None
|
||||||
JsonParseGenerator.JsonParseOption.None
|
JsonParseGenerator.JsonParseOption.None
|
||||||
retType
|
retType
|
||||||
(SynExpr.createIdent "jsonNode")
|
(SynExpr.CreateIdentString "jsonNode")
|
||||||
|
|
||||||
let handleBodyParams =
|
let handleBodyParams =
|
||||||
match bodyParam with
|
match bodyParam with
|
||||||
@@ -460,15 +483,20 @@ module internal HttpClientGenerator =
|
|||||||
[
|
[
|
||||||
Let (
|
Let (
|
||||||
"queryParams",
|
"queryParams",
|
||||||
SynExpr.createNew
|
SynExpr.New (
|
||||||
(SynType.createLongIdent'
|
false,
|
||||||
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ])
|
SynType.CreateLongIdent (
|
||||||
(SynExpr.createIdent' bodyParamName)
|
SynLongIdent.Create
|
||||||
|
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateParen (SynExpr.CreateIdent bodyParamName),
|
||||||
|
range0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
Do (
|
Do (
|
||||||
SynExpr.LongIdentSet (
|
SynExpr.LongIdentSet (
|
||||||
SynLongIdent.createS' [ "httpMessage" ; "Content" ],
|
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||||
SynExpr.createIdent "queryParams",
|
SynExpr.CreateIdentString "queryParams",
|
||||||
range0
|
range0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -477,8 +505,8 @@ module internal HttpClientGenerator =
|
|||||||
[
|
[
|
||||||
Do (
|
Do (
|
||||||
SynExpr.LongIdentSet (
|
SynExpr.LongIdentSet (
|
||||||
SynLongIdent.createS' [ "httpMessage" ; "Content" ],
|
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||||
SynExpr.createIdent' bodyParamName,
|
SynExpr.CreateIdent bodyParamName,
|
||||||
range0
|
range0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -487,27 +515,38 @@ module internal HttpClientGenerator =
|
|||||||
[
|
[
|
||||||
Let (
|
Let (
|
||||||
"queryParams",
|
"queryParams",
|
||||||
SynExpr.createNew
|
SynExpr.New (
|
||||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "StringContent" ])
|
false,
|
||||||
(SynExpr.createIdent' bodyParamName
|
SynType.CreateLongIdent (
|
||||||
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
|
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "StringContent" ]
|
||||||
|> SynExpr.pipeThroughFunction (
|
),
|
||||||
SynExpr.createLambda
|
SynExpr.CreateParen (
|
||||||
"node"
|
SynExpr.CreateIdent bodyParamName
|
||||||
(SynExpr.ifThenElse
|
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
|
||||||
(SynExpr.applyFunction
|
|> SynExpr.pipeThroughFunction (
|
||||||
(SynExpr.createIdent "isNull")
|
SynExpr.createLambda
|
||||||
(SynExpr.createIdent "node"))
|
"node"
|
||||||
(SynExpr.applyFunction
|
(SynExpr.ifThenElse
|
||||||
(SynExpr.createLongIdent [ "node" ; "ToJsonString" ])
|
(SynExpr.CreateApp (
|
||||||
(SynExpr.CreateConst ()))
|
SynExpr.CreateIdentString "isNull",
|
||||||
(SynExpr.CreateConst "null"))
|
SynExpr.CreateIdentString "node"
|
||||||
))
|
))
|
||||||
|
(SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "node" ; "ToJsonString" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
))
|
||||||
|
(SynExpr.CreateConst (SynConst.CreateString "null")))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
range0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
Do (
|
Do (
|
||||||
SynExpr.LongIdentSet (
|
SynExpr.LongIdentSet (
|
||||||
SynLongIdent.createS' [ "httpMessage" ; "Content" ],
|
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||||
SynExpr.createIdent "queryParams",
|
SynExpr.CreateIdent (Ident.Create "queryParams"),
|
||||||
range0
|
range0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -518,9 +557,12 @@ module internal HttpClientGenerator =
|
|||||||
LetBang (
|
LetBang (
|
||||||
"responseString",
|
"responseString",
|
||||||
SynExpr.awaitTask (
|
SynExpr.awaitTask (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ])
|
SynExpr.CreateLongIdent (
|
||||||
(SynExpr.createIdent "ct")
|
SynLongIdent.Create [ "response" ; "Content" ; "ReadAsStringAsync" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateIdentString "ct"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -528,9 +570,12 @@ module internal HttpClientGenerator =
|
|||||||
LetBang (
|
LetBang (
|
||||||
"responseStream",
|
"responseStream",
|
||||||
SynExpr.awaitTask (
|
SynExpr.awaitTask (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ])
|
SynExpr.CreateLongIdent (
|
||||||
(SynExpr.createIdent "ct")
|
SynLongIdent.Create [ "response" ; "Content" ; "ReadAsStreamAsync" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateIdentString "ct"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -538,50 +583,67 @@ module internal HttpClientGenerator =
|
|||||||
LetBang (
|
LetBang (
|
||||||
"jsonNode",
|
"jsonNode",
|
||||||
SynExpr.awaitTask (
|
SynExpr.awaitTask (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent
|
SynExpr.CreateLongIdent (
|
||||||
[ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ])
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ]
|
||||||
(SynExpr.tuple
|
),
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
[
|
[
|
||||||
SynExpr.createIdent "responseStream"
|
SynExpr.CreateIdentString "responseStream"
|
||||||
SynExpr.equals (SynExpr.createIdent "cancellationToken") (SynExpr.createIdent "ct")
|
SynExpr.equals
|
||||||
])
|
(SynExpr.CreateIdentString "cancellationToken")
|
||||||
|
(SynExpr.CreateIdentString "ct")
|
||||||
|
]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let setVariableHeaders =
|
let setVariableHeaders =
|
||||||
variableHeaders
|
variableHeaders
|
||||||
|> List.map (fun (headerName, callToGetValue) ->
|
|> List.map (fun (headerName, callToGetValue) ->
|
||||||
[
|
Do (
|
||||||
headerName
|
SynExpr.CreateApp (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "httpMessage" ; "Headers" ; "Add" ]),
|
||||||
(SynExpr.createLongIdent'
|
SynExpr.CreateParenedTuple
|
||||||
[ Ident.create "this" ; callToGetValue ; Ident.create "ToString" ])
|
[
|
||||||
(SynExpr.CreateConst ())
|
headerName
|
||||||
]
|
SynExpr.CreateApp (
|
||||||
|> SynExpr.tuple
|
SynExpr.CreateLongIdent (
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|
SynLongIdent.CreateFromLongIdent
|
||||||
|> Do
|
[ Ident.Create "this" ; callToGetValue ; Ident.Create "ToString" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let setConstantHeaders =
|
let setConstantHeaders =
|
||||||
constantHeaders
|
constantHeaders
|
||||||
|> List.map (fun (headerName, headerValue) ->
|
|> List.map (fun (headerName, headerValue) ->
|
||||||
SynExpr.applyFunction
|
Do (
|
||||||
(SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|
SynExpr.CreateApp (
|
||||||
(SynExpr.tuple [ headerName ; headerValue ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "httpMessage" ; "Headers" ; "Add" ]),
|
||||||
|> Do
|
SynExpr.CreateParenedTuple [ headerName ; headerValue ]
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
[
|
[
|
||||||
yield LetBang ("ct", SynExpr.createLongIdent [ "Async" ; "CancellationToken" ])
|
yield LetBang ("ct", SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "CancellationToken" ]))
|
||||||
yield Let ("uri", requestUri)
|
yield Let ("uri", requestUri)
|
||||||
yield
|
yield
|
||||||
Use (
|
Use (
|
||||||
"httpMessage",
|
"httpMessage",
|
||||||
SynExpr.createNew
|
SynExpr.New (
|
||||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ])
|
false,
|
||||||
httpReqMessageConstructor
|
SynType.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ]
|
||||||
|
),
|
||||||
|
httpReqMessageConstructor,
|
||||||
|
range0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
yield! handleBodyParams
|
yield! handleBodyParams
|
||||||
@@ -593,18 +655,21 @@ module internal HttpClientGenerator =
|
|||||||
LetBang (
|
LetBang (
|
||||||
"response",
|
"response",
|
||||||
SynExpr.awaitTask (
|
SynExpr.awaitTask (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "client" ; "SendAsync" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "client" ; "SendAsync" ]),
|
||||||
(SynExpr.tuple [ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ])
|
SynExpr.CreateParenedTuple
|
||||||
|
[ SynExpr.CreateIdentString "httpMessage" ; SynExpr.CreateIdentString "ct" ]
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if info.EnsureSuccessHttpCode then
|
if info.EnsureSuccessHttpCode then
|
||||||
yield
|
yield
|
||||||
Let (
|
Let (
|
||||||
"response",
|
"response",
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "response" ; "EnsureSuccessStatusCode" ]),
|
||||||
(SynExpr.CreateConst ())
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
)
|
)
|
||||||
match info.TaskReturnType with
|
match info.TaskReturnType with
|
||||||
| HttpResponseMessage -> ()
|
| HttpResponseMessage -> ()
|
||||||
@@ -619,34 +684,31 @@ module internal HttpClientGenerator =
|
|||||||
yield jsonNode
|
yield jsonNode
|
||||||
]
|
]
|
||||||
|> SynExpr.createCompExpr "async" returnExpr
|
|> SynExpr.createCompExpr "async" returnExpr
|
||||||
|> SynExpr.startAsTask cancellationTokenArg
|
|> SynExpr.startAsTask (SynLongIdent.CreateFromLongIdent [ cancellationTokenArg ])
|
||||||
|
|
||||||
SynBinding.SynBinding (
|
SynMemberDefn.Member (
|
||||||
None,
|
SynBinding.SynBinding (
|
||||||
SynBindingKind.Normal,
|
info.Accessibility,
|
||||||
false,
|
SynBindingKind.Normal,
|
||||||
false,
|
false,
|
||||||
[],
|
false,
|
||||||
PreXmlDoc.Empty,
|
[],
|
||||||
valData,
|
PreXmlDoc.Empty,
|
||||||
headPat,
|
valData,
|
||||||
None,
|
headPat,
|
||||||
implementation,
|
None,
|
||||||
range0,
|
implementation,
|
||||||
DebugPointAtBinding.Yes range0,
|
range0,
|
||||||
SynBinding.triviaZero true
|
DebugPointAtBinding.Yes range0,
|
||||||
|
SynExpr.synBindingTriviaZero true
|
||||||
|
),
|
||||||
|
range0
|
||||||
)
|
)
|
||||||
|> SynBinding.withAccessibility info.Accessibility
|
|
||||||
|> fun b -> SynMemberDefn.Member (b, range0)
|
|
||||||
|
|
||||||
let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list =
|
let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list =
|
||||||
attrs
|
attrs
|
||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match SynLongIdent.toString attr.TypeName with
|
match attr.TypeName.AsString with
|
||||||
| "RestEase.Query"
|
|
||||||
| "RestEase.QueryAttribute"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Query"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.QueryAttribute"
|
|
||||||
| "Query"
|
| "Query"
|
||||||
| "QueryAttribute" ->
|
| "QueryAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -655,22 +717,14 @@ module internal HttpClientGenerator =
|
|||||||
Some (HttpAttribute.Query (Some s))
|
Some (HttpAttribute.Query (Some s))
|
||||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
| "RestEase.Path"
|
|
||||||
| "RestEase.PathAttribute"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Path"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.PathAttribute"
|
|
||||||
| "Path"
|
| "Path"
|
||||||
| "PathAttribute" ->
|
| "PathAttribute" ->
|
||||||
match attr.ArgExpr |> SynExpr.stripOptionalParen with
|
match attr.ArgExpr with
|
||||||
| SynExpr.Const (SynConst.String (s, SynStringKind.Regular, _), _) ->
|
| SynExpr.Const (SynConst.String (s, SynStringKind.Regular, _), _) ->
|
||||||
Some (HttpAttribute.Path (PathSpec.Verbatim s))
|
Some (HttpAttribute.Path (PathSpec.Verbatim s))
|
||||||
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
||||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
| "RestEase.Body"
|
|
||||||
| "RestEase.BodyAttribute"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.Body"
|
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.BodyAttribute"
|
|
||||||
| "Body"
|
| "Body"
|
||||||
| "BodyAttribute" ->
|
| "BodyAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -683,41 +737,33 @@ module internal HttpClientGenerator =
|
|||||||
let extractBasePath (attrs : SynAttribute list) : SynExpr option =
|
let extractBasePath (attrs : SynAttribute list) : SynExpr option =
|
||||||
attrs
|
attrs
|
||||||
|> List.tryPick (fun attr ->
|
|> List.tryPick (fun attr ->
|
||||||
match SynLongIdent.toString attr.TypeName with
|
match attr.TypeName.AsString with
|
||||||
| "BasePath"
|
| "BasePath"
|
||||||
| "RestEase.BasePath"
|
| "RestEase.BasePath"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.BasePath"
|
|
||||||
| "BasePathAttribute"
|
| "BasePathAttribute"
|
||||||
| "RestEase.BasePathAttribute"
|
| "RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
|
||||||
| _ -> None
|
| _ -> None
|
||||||
)
|
)
|
||||||
|
|
||||||
let extractBaseAddress (attrs : SynAttribute list) : SynExpr option =
|
let extractBaseAddress (attrs : SynAttribute list) : SynExpr option =
|
||||||
attrs
|
attrs
|
||||||
|> List.tryPick (fun attr ->
|
|> List.tryPick (fun attr ->
|
||||||
match SynLongIdent.toString attr.TypeName with
|
match attr.TypeName.AsString with
|
||||||
| "BaseAddress"
|
| "BaseAddress"
|
||||||
| "RestEase.BaseAddress"
|
| "RestEase.BaseAddress"
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
|
|
||||||
| "BaseAddressAttribute"
|
| "BaseAddressAttribute"
|
||||||
| "RestEase.BaseAddressAttribute"
|
| "RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
||||||
| "WoofWare.Myriad.Plugins.RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
|
||||||
| _ -> None
|
| _ -> None
|
||||||
)
|
)
|
||||||
|
|
||||||
let createModule
|
let createModule
|
||||||
(opens : SynOpenDeclTarget list)
|
(opens : SynOpenDeclTarget list)
|
||||||
(ns : LongIdent)
|
(ns : LongIdent)
|
||||||
(interfaceType : SynTypeDefn, spec : HttpClientGeneratorOutputSpec)
|
(interfaceType : SynTypeDefn)
|
||||||
: SynModuleOrNamespace
|
: SynModuleOrNamespace
|
||||||
=
|
=
|
||||||
let interfaceType = AstHelper.parseInterface interfaceType
|
let interfaceType = AstHelper.parseInterface interfaceType
|
||||||
|
|
||||||
if not (List.isEmpty interfaceType.Inherits) then
|
|
||||||
failwith
|
|
||||||
"HttpClientGenerator does not support inheritance. Remove the `inherit` keyword if you want to use this generator."
|
|
||||||
|
|
||||||
let constantHeaders =
|
let constantHeaders =
|
||||||
interfaceType.Attributes
|
interfaceType.Attributes
|
||||||
|> extractHeaderInformation
|
|> extractHeaderInformation
|
||||||
@@ -832,11 +878,17 @@ module internal HttpClientGenerator =
|
|||||||
SynValInfo.SynValInfo ([ [ SynArgInfo.Empty ] ; [] ], SynArgInfo.Empty),
|
SynValInfo.SynValInfo ([ [ SynArgInfo.Empty ] ; [] ], SynArgInfo.Empty),
|
||||||
None
|
None
|
||||||
),
|
),
|
||||||
SynPat.CreateLongIdent (SynLongIdent.create [ Ident.create "_" ; pi.Identifier ], []),
|
SynPat.CreateLongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ Ident.Create "_" ; pi.Identifier ],
|
||||||
|
[]
|
||||||
|
),
|
||||||
Some (SynBindingReturnInfo.Create pi.Type),
|
Some (SynBindingReturnInfo.Create pi.Type),
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent' [ Ident.lowerFirstLetter pi.Identifier ])
|
SynExpr.CreateLongIdent (
|
||||||
(SynExpr.CreateConst ()),
|
SynLongIdent.CreateFromLongIdent [ Ident.lowerFirstLetter pi.Identifier ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
),
|
||||||
range0,
|
range0,
|
||||||
DebugPointAtBinding.Yes range0,
|
DebugPointAtBinding.Yes range0,
|
||||||
{
|
{
|
||||||
@@ -851,17 +903,11 @@ module internal HttpClientGenerator =
|
|||||||
|
|
||||||
let members = propertyMembers @ nonPropertyMembers
|
let members = propertyMembers @ nonPropertyMembers
|
||||||
|
|
||||||
let docString =
|
let docString = PreXmlDoc.Create " Module for constructing a REST client."
|
||||||
(if spec.ExtensionMethods then
|
|
||||||
"Extension methods"
|
|
||||||
else
|
|
||||||
"Module")
|
|
||||||
|> sprintf "%s for constructing a REST client."
|
|
||||||
|> PreXmlDoc.create
|
|
||||||
|
|
||||||
let interfaceImpl =
|
let interfaceImpl =
|
||||||
SynExpr.ObjExpr (
|
SynExpr.ObjExpr (
|
||||||
SynType.createLongIdent interfaceType.Name,
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name),
|
||||||
None,
|
None,
|
||||||
Some range0,
|
Some range0,
|
||||||
[],
|
[],
|
||||||
@@ -874,100 +920,80 @@ module internal HttpClientGenerator =
|
|||||||
let headerArgs =
|
let headerArgs =
|
||||||
properties
|
properties
|
||||||
|> List.map (fun (_, pi) ->
|
|> List.map (fun (_, pi) ->
|
||||||
SynPat.namedI (Ident.lowerFirstLetter pi.Identifier)
|
SynPat.CreateTyped (
|
||||||
|> SynPat.annotateType (SynType.funFromDomain (SynType.named "unit") pi.Type)
|
SynPat.CreateNamed (Ident.lowerFirstLetter pi.Identifier),
|
||||||
|
SynType.CreateFun (SynType.CreateLongIdent "unit", pi.Type)
|
||||||
|
)
|
||||||
|
|> SynPat.CreateParen
|
||||||
)
|
)
|
||||||
|
|
||||||
let clientCreationArg =
|
let clientCreationArg =
|
||||||
SynPat.named "client"
|
SynPat.CreateTyped (
|
||||||
|> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpClient" ])
|
SynPat.CreateNamed (Ident.Create "client"),
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpClient" ])
|
||||||
|
)
|
||||||
|
|> SynPat.CreateParen
|
||||||
|
|
||||||
let xmlDoc =
|
let xmlDoc =
|
||||||
if properties.IsEmpty then
|
if properties.IsEmpty then
|
||||||
"Create a REST client."
|
" Create a REST client."
|
||||||
else
|
else
|
||||||
"Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties."
|
" Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties."
|
||||||
|> PreXmlDoc.create
|
|
||||||
|
|
||||||
let functionName = Ident.create "client"
|
let createFunc =
|
||||||
|
SynBinding.SynBinding (
|
||||||
let valData =
|
None,
|
||||||
let memberFlags =
|
SynBindingKind.Normal,
|
||||||
if spec.ExtensionMethods then
|
false,
|
||||||
{
|
false,
|
||||||
SynMemberFlags.IsInstance = false
|
[],
|
||||||
SynMemberFlags.IsDispatchSlot = false
|
PreXmlDoc.Create xmlDoc,
|
||||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
SynValData.SynValData (
|
||||||
SynMemberFlags.IsFinal = false
|
None,
|
||||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
SynValInfo.SynValInfo (
|
||||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
[ [ SynArgInfo.SynArgInfo ([], false, Some (Ident.Create "client")) ] ],
|
||||||
}
|
SynArgInfo.Empty
|
||||||
|> Some
|
),
|
||||||
else
|
|
||||||
None
|
None
|
||||||
|
),
|
||||||
SynValData.SynValData (
|
SynPat.CreateLongIdent (SynLongIdent.CreateString "make", headerArgs @ [ clientCreationArg ]),
|
||||||
memberFlags,
|
Some (
|
||||||
SynValInfo.SynValInfo ([ [ SynArgInfo.SynArgInfo ([], false, Some functionName) ] ], SynArgInfo.Empty),
|
SynBindingReturnInfo.Create (
|
||||||
None
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
interfaceImpl,
|
||||||
|
range0,
|
||||||
|
DebugPointAtBinding.NoneAtLet,
|
||||||
|
SynExpr.synBindingTriviaZero false
|
||||||
)
|
)
|
||||||
|
|> List.singleton
|
||||||
|
|> SynModuleDecl.CreateLet
|
||||||
|
|
||||||
let pattern = SynLongIdent.createS "make"
|
let moduleName : LongIdent =
|
||||||
|
|
||||||
let returnInfo = SynType.createLongIdent interfaceType.Name
|
|
||||||
|
|
||||||
let nameWithoutLeadingI =
|
|
||||||
List.last interfaceType.Name
|
List.last interfaceType.Name
|
||||||
|> _.idText
|
|> _.idText
|
||||||
|> fun s ->
|
|> fun s ->
|
||||||
if s.StartsWith 'I' then
|
if s.StartsWith 'I' then
|
||||||
s.Substring 1
|
s.[1..]
|
||||||
else
|
else
|
||||||
failwith $"Expected interface type to start with 'I', but was: %s{s}"
|
failwith $"Expected interface type to start with 'I', but was: %s{s}"
|
||||||
|
|> Ident.Create
|
||||||
let createFunc =
|
|> List.singleton
|
||||||
if spec.ExtensionMethods then
|
|
||||||
let binding =
|
|
||||||
SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
|
||||||
|> SynBinding.withReturnAnnotation returnInfo
|
|
||||||
|> SynMemberDefn.staticMember
|
|
||||||
|
|
||||||
let componentInfo =
|
|
||||||
SynComponentInfo.create (Ident.create nameWithoutLeadingI)
|
|
||||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for HTTP clients")
|
|
||||||
|
|
||||||
let containingType =
|
|
||||||
SynTypeDefnRepr.augmentation ()
|
|
||||||
|> SynTypeDefn.create componentInfo
|
|
||||||
|> SynTypeDefn.withMemberDefns [ binding ]
|
|
||||||
|
|
||||||
SynModuleDecl.Types ([ containingType ], range0)
|
|
||||||
|
|
||||||
else
|
|
||||||
SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
|
||||||
|> SynBinding.withReturnAnnotation returnInfo
|
|
||||||
|> List.singleton
|
|
||||||
|> SynModuleDecl.CreateLet
|
|
||||||
|
|
||||||
let moduleName =
|
|
||||||
if spec.ExtensionMethods then
|
|
||||||
Ident.create (nameWithoutLeadingI + "HttpClientExtension")
|
|
||||||
else
|
|
||||||
Ident.create nameWithoutLeadingI
|
|
||||||
|
|
||||||
let attribs =
|
let attribs =
|
||||||
if spec.ExtensionMethods then
|
[
|
||||||
[ SynAttribute.autoOpen ]
|
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||||
else
|
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||||
[ SynAttribute.compilationRepresentation ; SynAttribute.requireQualifiedAccess ]
|
]
|
||||||
|
|
||||||
let modInfo =
|
let modInfo =
|
||||||
SynComponentInfo.create moduleName
|
SynComponentInfo.Create (
|
||||||
|> SynComponentInfo.withDocString docString
|
moduleName,
|
||||||
|> SynComponentInfo.addAttributes attribs
|
attributes = attribs,
|
||||||
|> SynComponentInfo.setAccessibility interfaceType.Accessibility
|
xmldoc = docString,
|
||||||
|
access = interfaceType.Accessibility
|
||||||
|
)
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
ns,
|
ns,
|
||||||
@@ -997,29 +1023,9 @@ type HttpClientGenerator () =
|
|||||||
let namespaceAndTypes =
|
let namespaceAndTypes =
|
||||||
types
|
types
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.choose (fun (ns, types) ->
|
||||||
types
|
match types |> List.filter Ast.hasAttribute<HttpClientAttribute> with
|
||||||
|> List.choose (fun typeDef ->
|
| [] -> None
|
||||||
match Ast.getAttribute<HttpClientAttribute> typeDef with
|
| types -> Some (ns, types)
|
||||||
| None -> None
|
|
||||||
| Some attr ->
|
|
||||||
let arg =
|
|
||||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
|
||||||
| SynExpr.Const (SynConst.Bool value, _) -> value
|
|
||||||
| SynExpr.Const (SynConst.Unit, _) -> JsonParseAttribute.DefaultIsExtensionMethod
|
|
||||||
| arg ->
|
|
||||||
failwith
|
|
||||||
$"Unrecognised argument %+A{arg} to [<%s{nameof HttpClientAttribute}>]. Literals are not supported. Use `true` or `false` (or unit) only."
|
|
||||||
|
|
||||||
let spec =
|
|
||||||
{
|
|
||||||
ExtensionMethods = arg
|
|
||||||
}
|
|
||||||
|
|
||||||
Some (typeDef, spec)
|
|
||||||
)
|
|
||||||
|> function
|
|
||||||
| [] -> None
|
|
||||||
| ty -> Some (ns, ty)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
open System
|
open System
|
||||||
open System.Text
|
open System.Text
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.Text.Range
|
open Myriad.Core
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal Ident =
|
module internal Ident =
|
||||||
let inline create (s : string) = Ident (s, range0)
|
|
||||||
|
|
||||||
let lowerFirstLetter (x : Ident) : Ident =
|
let lowerFirstLetter (x : Ident) : Ident =
|
||||||
let result = StringBuilder x.idText.Length
|
let result = StringBuilder x.idText.Length
|
||||||
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
|
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
|
||||||
result.Append x.idText.[1..] |> ignore
|
result.Append x.idText.[1..] |> ignore
|
||||||
create ((result : StringBuilder).ToString ())
|
Ident.Create ((result : StringBuilder).ToString ())
|
||||||
@@ -21,9 +21,6 @@ module internal InterfaceMockGenerator =
|
|||||||
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
||||||
| Some id -> id
|
| Some id -> id
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
type private KnownInheritance = | IDisposable
|
|
||||||
|
|
||||||
let createType
|
let createType
|
||||||
(spec : GenerateMockOutputSpec)
|
(spec : GenerateMockOutputSpec)
|
||||||
(name : string)
|
(name : string)
|
||||||
@@ -32,80 +29,93 @@ module internal InterfaceMockGenerator =
|
|||||||
(fields : SynField list)
|
(fields : SynField list)
|
||||||
: SynModuleDecl
|
: SynModuleDecl
|
||||||
=
|
=
|
||||||
let inherits =
|
let synValData =
|
||||||
interfaceType.Inherits
|
{
|
||||||
|> Seq.map (fun ty ->
|
SynMemberFlags.IsInstance = false
|
||||||
match ty with
|
SynMemberFlags.IsDispatchSlot = false
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) ->
|
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||||
match name |> List.map _.idText with
|
SynMemberFlags.IsFinal = false
|
||||||
| [] -> failwith "Unexpected empty identifier in inheritance declaration"
|
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||||
| [ "IDisposable" ]
|
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||||
| [ "System" ; "IDisposable" ] -> KnownInheritance.IDisposable
|
}
|
||||||
| _ -> failwithf "Unrecognised inheritance identifier: %+A" name
|
|
||||||
| x -> failwithf "Unrecognised type in inheritance: %+A" x
|
|
||||||
)
|
|
||||||
|> Set.ofSeq
|
|
||||||
|
|
||||||
let failwithFun =
|
let failwithFun =
|
||||||
SynExpr.createLongIdent [ "System" ; "NotImplementedException" ]
|
SynExpr.createLambda
|
||||||
|> SynExpr.applyTo (SynExpr.CreateConst "Unimplemented mock function")
|
"x"
|
||||||
|> SynExpr.paren
|
(SynExpr.CreateApp (
|
||||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
SynExpr.CreateIdentString "raise",
|
||||||
|> SynExpr.createLambda "_"
|
SynExpr.CreateParen (
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "NotImplementedException" ]),
|
||||||
|
SynExpr.CreateConstString "Unimplemented mock function"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
let constructorIdent =
|
||||||
|
let generics =
|
||||||
|
interfaceType.Generics
|
||||||
|
|> Option.map (fun generics -> SynValTyparDecls (Some generics, false))
|
||||||
|
|
||||||
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateString "Empty",
|
||||||
|
None,
|
||||||
|
None, // no generics on the "Empty", only on the return type
|
||||||
|
SynArgPats.Pats (
|
||||||
|
if generics.IsNone then
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
[ SynPat.CreateParen (SynPat.CreateConst SynConst.Unit) ]
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
let constructorReturnType =
|
let constructorReturnType =
|
||||||
match interfaceType.Generics with
|
match interfaceType.Generics with
|
||||||
| None -> SynType.createLongIdent' [ name ]
|
| None -> SynType.CreateLongIdent name
|
||||||
| Some generics ->
|
| Some generics ->
|
||||||
|
let generics =
|
||||||
|
generics.TyparDecls
|
||||||
|
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||||
|
|
||||||
let generics =
|
SynType.App (
|
||||||
generics.TyparDecls
|
SynType.CreateLongIdent name,
|
||||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
Some range0,
|
||||||
|
generics,
|
||||||
SynType.app name generics
|
List.replicate (generics.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
let constructorFields =
|
false,
|
||||||
let extras =
|
range0
|
||||||
if inherits.Contains KnownInheritance.IDisposable then
|
)
|
||||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
|> SynBindingReturnInfo.Create
|
||||||
|
|
||||||
[ (SynLongIdent.createS "Dispose", true), Some unitFun ]
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
|
|
||||||
let nonExtras =
|
|
||||||
fields
|
|
||||||
|> List.map (fun field -> (SynLongIdent.createI (getName field), true), Some failwithFun)
|
|
||||||
|
|
||||||
extras @ nonExtras
|
|
||||||
|
|
||||||
let constructor =
|
let constructor =
|
||||||
SynBinding.basic
|
SynMemberDefn.Member (
|
||||||
[ Ident.create "Empty" ]
|
SynBinding.SynBinding (
|
||||||
(if interfaceType.Generics.IsNone then
|
None,
|
||||||
[]
|
SynBindingKind.Normal,
|
||||||
else
|
false,
|
||||||
[ SynPat.unit ])
|
false,
|
||||||
(AstHelper.instantiateRecord constructorFields)
|
[],
|
||||||
|> SynBinding.makeStaticMember
|
PreXmlDoc.Create " An implementation where every method throws.",
|
||||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|
SynValData.SynValData (Some synValData, SynValInfo.Empty, None),
|
||||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
constructorIdent,
|
||||||
|> fun m -> SynMemberDefn.Member (m, range0)
|
Some constructorReturnType,
|
||||||
|
AstHelper.instantiateRecord (
|
||||||
let fields =
|
fields
|
||||||
let extras =
|
|> List.map (fun field ->
|
||||||
if inherits.Contains KnownInheritance.IDisposable then
|
((SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
||||||
[
|
|
||||||
SynField.Create (
|
|
||||||
SynType.funFromDomain SynType.unit SynType.unit,
|
|
||||||
Ident.create "Dispose",
|
|
||||||
xmldoc = PreXmlDoc.create "Implementation of IDisposable.Dispose"
|
|
||||||
)
|
)
|
||||||
]
|
),
|
||||||
else
|
range0,
|
||||||
[]
|
DebugPointAtBinding.Yes range0,
|
||||||
|
{ SynExpr.synBindingTriviaZero true with
|
||||||
extras @ fields
|
LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
let interfaceMembers =
|
let interfaceMembers =
|
||||||
let members =
|
let members =
|
||||||
@@ -140,9 +150,7 @@ module internal InterfaceMockGenerator =
|
|||||||
|> List.mapi (fun i arg ->
|
|> List.mapi (fun i arg ->
|
||||||
arg.Args
|
arg.Args
|
||||||
|> List.mapi (fun j arg ->
|
|> List.mapi (fun j arg ->
|
||||||
match arg.Type with
|
SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
||||||
| UnitType -> SynArgInfo.SynArgInfo ([], false, None)
|
|
||||||
| _ -> SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -157,22 +165,16 @@ module internal InterfaceMockGenerator =
|
|||||||
|> List.mapi (fun i tupledArgs ->
|
|> List.mapi (fun i tupledArgs ->
|
||||||
let args =
|
let args =
|
||||||
tupledArgs.Args
|
tupledArgs.Args
|
||||||
|> List.mapi (fun j ty ->
|
|> List.mapi (fun j _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}"))
|
||||||
match ty.Type with
|
|
||||||
| UnitType -> SynPat.unit
|
|
||||||
| _ -> SynPat.named $"arg_%i{i}_%i{j}"
|
|
||||||
)
|
|
||||||
|
|
||||||
match args with
|
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||||
| [] -> failwith "somehow got no args at all"
|
|> SynPat.CreateParen
|
||||||
| [ arg ] -> arg
|
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
||||||
| args -> SynPat.tuple args
|
|
||||||
|> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let headPat =
|
let headPat =
|
||||||
SynPat.LongIdent (
|
SynPat.LongIdent (
|
||||||
SynLongIdent.create [ Ident.create "this" ; memberInfo.Identifier ],
|
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
SynArgPats.Pats headArgs,
|
SynArgPats.Pats headArgs,
|
||||||
@@ -185,12 +187,8 @@ module internal InterfaceMockGenerator =
|
|||||||
memberInfo.Args
|
memberInfo.Args
|
||||||
|> List.mapi (fun i args ->
|
|> List.mapi (fun i args ->
|
||||||
args.Args
|
args.Args
|
||||||
|> List.mapi (fun j arg ->
|
|> List.mapi (fun j args -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}")
|
||||||
match arg.Type with
|
|> SynExpr.CreateParenedTuple
|
||||||
| UnitType -> SynExpr.CreateConst ()
|
|
||||||
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
|
|
||||||
)
|
|
||||||
|> SynExpr.tuple
|
|
||||||
)
|
)
|
||||||
|
|
||||||
match tuples |> List.rev with
|
match tuples |> List.rev with
|
||||||
@@ -198,10 +196,14 @@ module internal InterfaceMockGenerator =
|
|||||||
| last :: rest ->
|
| last :: rest ->
|
||||||
|
|
||||||
(last, rest)
|
(last, rest)
|
||||||
||> List.fold SynExpr.applyTo
|
||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail))
|
||||||
|> SynExpr.applyFunction (
|
|> fun args ->
|
||||||
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
|
SynExpr.CreateApp (
|
||||||
)
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ]
|
||||||
|
),
|
||||||
|
args
|
||||||
|
)
|
||||||
|
|
||||||
SynMemberDefn.Member (
|
SynMemberDefn.Member (
|
||||||
SynBinding.SynBinding (
|
SynBinding.SynBinding (
|
||||||
@@ -228,7 +230,8 @@ module internal InterfaceMockGenerator =
|
|||||||
)
|
)
|
||||||
|
|
||||||
let interfaceName =
|
let interfaceName =
|
||||||
let baseName = SynType.createLongIdent interfaceType.Name
|
let baseName =
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
|
||||||
|
|
||||||
match interfaceType.Generics with
|
match interfaceType.Generics with
|
||||||
| None -> baseName
|
| None -> baseName
|
||||||
@@ -238,9 +241,17 @@ module internal InterfaceMockGenerator =
|
|||||||
| SynTyparDecls.PostfixList (decls, _, _) -> decls
|
| SynTyparDecls.PostfixList (decls, _, _) -> decls
|
||||||
| SynTyparDecls.PrefixList (decls, _) -> decls
|
| SynTyparDecls.PrefixList (decls, _) -> decls
|
||||||
| SynTyparDecls.SinglePrefix (decl, _) -> [ decl ]
|
| SynTyparDecls.SinglePrefix (decl, _) -> [ decl ]
|
||||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||||
|
|
||||||
SynType.app' baseName generics
|
SynType.App (
|
||||||
|
baseName,
|
||||||
|
Some range0,
|
||||||
|
generics,
|
||||||
|
List.replicate (generics.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
|
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
|
||||||
|
|
||||||
@@ -253,34 +264,11 @@ module internal InterfaceMockGenerator =
|
|||||||
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
||||||
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
||||||
|
|
||||||
let extraInterfaces =
|
|
||||||
inherits
|
|
||||||
|> Seq.map (fun inheritance ->
|
|
||||||
match inheritance with
|
|
||||||
| KnownInheritance.IDisposable ->
|
|
||||||
let binding =
|
|
||||||
SynExpr.createLongIdent [ "this" ; "Dispose" ]
|
|
||||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
|
||||||
|> SynBinding.basic [ Ident.create "this" ; Ident.create "Dispose" ] [ SynPat.unit ]
|
|
||||||
|> SynBinding.withReturnAnnotation SynType.unit
|
|
||||||
|> SynBinding.makeInstanceMember
|
|
||||||
|
|
||||||
let mem = SynMemberDefn.Member (binding, range0)
|
|
||||||
|
|
||||||
SynMemberDefn.Interface (
|
|
||||||
SynType.createLongIdent' [ "System" ; "IDisposable" ],
|
|
||||||
Some range0,
|
|
||||||
Some [ mem ],
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|> Seq.toList
|
|
||||||
|
|
||||||
let record =
|
let record =
|
||||||
{
|
{
|
||||||
Name = Ident.create name
|
Name = Ident.Create name
|
||||||
Fields = fields
|
Fields = fields
|
||||||
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
|
Members = Some [ constructor ; interfaceMembers ]
|
||||||
XmlDoc = Some xmlDoc
|
XmlDoc = Some xmlDoc
|
||||||
Generics = interfaceType.Generics
|
Generics = interfaceType.Generics
|
||||||
Accessibility = Some access
|
Accessibility = Some access
|
||||||
@@ -292,7 +280,7 @@ module internal InterfaceMockGenerator =
|
|||||||
|
|
||||||
let private buildType (x : ParameterInfo) : SynType =
|
let private buildType (x : ParameterInfo) : SynType =
|
||||||
if x.IsOptional then
|
if x.IsOptional then
|
||||||
SynType.app "option" [ x.Type ]
|
SynType.App (SynType.CreateLongIdent "option", Some range0, [ x.Type ], [], Some range0, false, range0)
|
||||||
else
|
else
|
||||||
x.Type
|
x.Type
|
||||||
|
|
||||||
@@ -331,20 +319,21 @@ module internal InterfaceMockGenerator =
|
|||||||
=
|
=
|
||||||
let interfaceType = AstHelper.parseInterface interfaceType
|
let interfaceType = AstHelper.parseInterface interfaceType
|
||||||
let fields = interfaceType.Members |> List.map constructMember
|
let fields = interfaceType.Members |> List.map constructMember
|
||||||
let docString = PreXmlDoc.create "Mock record type for an interface"
|
let docString = PreXmlDoc.Create " Mock record type for an interface"
|
||||||
|
|
||||||
let name =
|
let name =
|
||||||
List.last interfaceType.Name
|
List.last interfaceType.Name
|
||||||
|> _.idText
|
|> _.idText
|
||||||
|> fun s ->
|
|> fun s ->
|
||||||
if s.StartsWith 'I' && s.Length > 1 && Char.IsUpper s.[1] then
|
if s.StartsWith 'I' && s.Length > 1 && Char.IsUpper s.[1] then
|
||||||
s.Substring 1
|
s.[1..]
|
||||||
else
|
else
|
||||||
s
|
s
|
||||||
|> fun s -> s + "Mock"
|
|> fun s -> s + "Mock"
|
||||||
|
|
||||||
let typeDecl = createType spec name interfaceType docString fields
|
let typeDecl = createType spec name interfaceType docString fields
|
||||||
|
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
namespaceId,
|
namespaceId,
|
||||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ open System
|
|||||||
open System.Text
|
open System.Text
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
|
open Fantomas.FCS.Xml
|
||||||
open Myriad.Core
|
open Myriad.Core
|
||||||
|
|
||||||
type internal JsonParseOutputSpec =
|
type internal JsonParseOutputSpec =
|
||||||
@@ -29,34 +30,38 @@ module internal JsonParseGenerator =
|
|||||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v)
|
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v)
|
||||||
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
|
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
|
||||||
let raiseExpr =
|
let raiseExpr =
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createIdent "sprintf")
|
SynExpr.CreateIdentString "raise",
|
||||||
(SynExpr.CreateConst "Required key '%s' not found on JSON object")
|
SynExpr.CreateParen (
|
||||||
|> SynExpr.applyTo (SynExpr.paren propertyName)
|
SynExpr.CreateApp (
|
||||||
|> SynExpr.paren
|
SynExpr.CreateLongIdent (
|
||||||
|> SynExpr.applyFunction (
|
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
|
||||||
SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
|
),
|
||||||
|
SynExpr.CreateParen (
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateIdentString "sprintf",
|
||||||
|
SynExpr.CreateConstString "Required key '%s' not found on JSON object"
|
||||||
|
),
|
||||||
|
SynExpr.CreateParen propertyName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.paren
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
|
||||||
|
|
||||||
[
|
SynExpr.CreateMatch (
|
||||||
SynMatchClause.create SynPat.createNull raiseExpr
|
indexed,
|
||||||
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
|
[
|
||||||
]
|
SynMatchClause.Create (SynPat.CreateNull, None, raiseExpr)
|
||||||
|> SynExpr.createMatch indexed
|
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v")
|
||||||
|> SynExpr.paren
|
]
|
||||||
|
)
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
/// {node}.AsValue().GetValue<{typeName}> ()
|
/// {node}.AsValue().GetValue<{typeName}> ()
|
||||||
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
||||||
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
|
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
|
||||||
match propertyName with
|
|
||||||
| None -> node
|
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
|
||||||
|> SynExpr.callMethod "AsValue"
|
|
||||||
|> SynExpr.callGenericMethod' "GetValue" typeName
|
|
||||||
|
|
||||||
let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
|
||||||
match propertyName with
|
match propertyName with
|
||||||
| None -> node
|
| None -> node
|
||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertNotNull propertyName node
|
||||||
@@ -73,8 +78,10 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
/// {type}.jsonParse {node}
|
/// {type}.jsonParse {node}
|
||||||
let typeJsonParse (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
let typeJsonParse (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
||||||
node
|
SynExpr.CreateApp (
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ Ident.create "jsonParse" ]))
|
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (typeName @ [ Ident.Create "jsonParse" ])),
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
|
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
|
||||||
/// body is the body of a lambda which takes a parameter `elt`.
|
/// body is the body of a lambda which takes a parameter `elt`.
|
||||||
@@ -93,40 +100,64 @@ module internal JsonParseGenerator =
|
|||||||
| Some propertyName -> assertNotNull propertyName node
|
| Some propertyName -> assertNotNull propertyName node
|
||||||
|> SynExpr.callMethod "AsArray"
|
|> SynExpr.callMethod "AsArray"
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "elt" body)
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||||
|
SynExpr.createLambda "elt" body
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ collectionType ; "ofSeq" ]))
|
||||||
|
|
||||||
/// match {node} with | null -> None | v -> {body} |> Some
|
/// match {node} with | null -> None | v -> {body} |> Some
|
||||||
/// Use the variable `v` to get access to the `Some`.
|
/// Use the variable `v` to get access to the `Some`.
|
||||||
let createParseLineOption (node : SynExpr) (body : SynExpr) : SynExpr =
|
let createParseLineOption (node : SynExpr) (body : SynExpr) : SynExpr =
|
||||||
let body = SynExpr.pipeThroughFunction (SynExpr.createIdent "Some") body
|
let body = SynExpr.pipeThroughFunction (SynExpr.CreateIdentString "Some") body
|
||||||
|
|
||||||
[
|
SynExpr.CreateMatch (
|
||||||
SynMatchClause.create SynPat.createNull (SynExpr.createIdent "None")
|
node,
|
||||||
SynMatchClause.create (SynPat.named "v") body
|
[
|
||||||
]
|
SynMatchClause.Create (SynPat.CreateNull, None, SynExpr.CreateIdent (Ident.Create "None"))
|
||||||
|> SynExpr.createMatch node
|
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, body)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
/// Given e.g. "float", returns "System.Double.Parse"
|
/// Given e.g. "float", returns "System.Double.Parse"
|
||||||
let parseFunction (typeName : string) : LongIdent =
|
let parseFunction (typeName : string) : LongIdent =
|
||||||
let qualified =
|
List.append (SynExpr.qualifyPrimitiveType typeName) [ Ident.Create "Parse" ]
|
||||||
match Primitives.qualifyType typeName with
|
|
||||||
| Some x -> x
|
|
||||||
| None -> failwith $"Could not recognise type %s{typeName} as a primitive."
|
|
||||||
|
|
||||||
List.append qualified [ Ident.create "Parse" ]
|
|
||||||
|
|
||||||
/// fun kvp -> let key = {key(kvp)} in let value = {value(kvp)} in (key, value))
|
/// fun kvp -> let key = {key(kvp)} in let value = {value(kvp)} in (key, value))
|
||||||
/// The inputs will be fed with appropriate SynExprs to apply them to the `kvp.Key` and `kvp.Value` args.
|
/// The inputs will be fed with appropriate SynExprs to apply them to the `kvp.Key` and `kvp.Value` args.
|
||||||
let dictionaryMapper (key : SynExpr -> SynExpr) (value : SynExpr -> SynExpr) : SynExpr =
|
let dictionaryMapper (key : SynExpr -> SynExpr) (value : SynExpr -> SynExpr) : SynExpr =
|
||||||
let keyArg = SynExpr.createLongIdent [ "kvp" ; "Key" ] |> SynExpr.paren
|
let keyArg =
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "kvp" ; "Key" ])
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
let valueArg = SynExpr.createLongIdent [ "kvp" ; "Value" ] |> SynExpr.paren
|
let valueArg =
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "kvp" ; "Value" ])
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
SynExpr.CreateTuple [ SynExpr.createIdent "key" ; SynExpr.createIdent "value" ]
|
SynExpr.LetOrUse (
|
||||||
|> SynExpr.createLet [ SynBinding.Let (pattern = SynPat.named "value", expr = value valueArg) ]
|
false,
|
||||||
|> SynExpr.createLet [ SynBinding.Let (pattern = SynPat.named "key", expr = key keyArg) ]
|
false,
|
||||||
|
[
|
||||||
|
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "key"), expr = key keyArg)
|
||||||
|
],
|
||||||
|
SynExpr.LetOrUse (
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[
|
||||||
|
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "value"), expr = value valueArg)
|
||||||
|
],
|
||||||
|
SynExpr.CreateTuple [ SynExpr.CreateIdentString "key" ; SynExpr.CreateIdentString "value" ],
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
InKeyword = None
|
||||||
|
}
|
||||||
|
),
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
InKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|> SynExpr.createLambda "kvp"
|
|> SynExpr.createLambda "kvp"
|
||||||
|
|
||||||
/// A conforming JSON object has only strings as keys. But it would be reasonable to allow the user
|
/// A conforming JSON object has only strings as keys. But it would be reasonable to allow the user
|
||||||
@@ -136,7 +167,7 @@ module internal JsonParseGenerator =
|
|||||||
| String -> key
|
| String -> key
|
||||||
| Uri ->
|
| Uri ->
|
||||||
key
|
key
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ]))
|
||||||
| _ ->
|
| _ ->
|
||||||
failwithf
|
failwithf
|
||||||
$"Unable to parse the key type %+A{desiredType} of a JSON object. Keys are strings, and this plugin does not know how to convert to that from a string."
|
$"Unable to parse the key type %+A{desiredType} of a JSON object. Keys are strings, and this plugin does not know how to convert to that from a string."
|
||||||
@@ -156,19 +187,25 @@ module internal JsonParseGenerator =
|
|||||||
| DateOnly ->
|
| DateOnly ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateOnly" ; "Parse" ])
|
|> SynExpr.pipeThroughFunction (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "DateOnly" ; "Parse" ])
|
||||||
|
)
|
||||||
| Uri ->
|
| Uri ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ]))
|
||||||
| Guid ->
|
| Guid ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Guid" ; "Parse" ])
|
|> SynExpr.pipeThroughFunction (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Guid" ; "Parse" ])
|
||||||
|
)
|
||||||
| DateTime ->
|
| DateTime ->
|
||||||
node
|
node
|
||||||
|> asValueGetValue propertyName "string"
|
|> asValueGetValue propertyName "string"
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
|
|> SynExpr.pipeThroughFunction (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "DateTime" ; "Parse" ])
|
||||||
|
)
|
||||||
| NumberType typeName ->
|
| NumberType typeName ->
|
||||||
let basic = asValueGetValue propertyName typeName node
|
let basic = asValueGetValue propertyName typeName node
|
||||||
|
|
||||||
@@ -176,92 +213,105 @@ module internal JsonParseGenerator =
|
|||||||
| None -> basic
|
| None -> basic
|
||||||
| Some option ->
|
| Some option ->
|
||||||
let cond =
|
let cond =
|
||||||
SynExpr.DotGet (SynExpr.createIdent "exc", range0, SynLongIdent.createS "Message", range0)
|
SynExpr.DotGet (
|
||||||
|> SynExpr.callMethodArg "Contains" (SynExpr.CreateConst "cannot be converted to")
|
SynExpr.CreateIdentString "exc",
|
||||||
|
range0,
|
||||||
|
SynLongIdent.CreateString "Message",
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|> SynExpr.callMethodArg
|
||||||
|
"Contains"
|
||||||
|
(SynExpr.CreateConst (SynConst.CreateString "cannot be converted to"))
|
||||||
|
|
||||||
let handler =
|
let handler =
|
||||||
asValueGetValue propertyName "string" node
|
asValueGetValue propertyName "string" node
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent' (parseFunction typeName))
|
|> SynExpr.pipeThroughFunction (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (parseFunction typeName))
|
||||||
|
)
|
||||||
|> SynExpr.ifThenElse
|
|> SynExpr.ifThenElse
|
||||||
(SynExpr.equals
|
(SynExpr.equals
|
||||||
option
|
option
|
||||||
(SynExpr.createLongIdent
|
(SynExpr.CreateLongIdent (
|
||||||
[
|
SynLongIdent.Create
|
||||||
"System"
|
[
|
||||||
"Text"
|
"System"
|
||||||
"Json"
|
"Text"
|
||||||
"Serialization"
|
"Json"
|
||||||
"JsonNumberHandling"
|
"Serialization"
|
||||||
"AllowReadingFromString"
|
"JsonNumberHandling"
|
||||||
]))
|
"AllowReadingFromString"
|
||||||
|
]
|
||||||
|
)))
|
||||||
SynExpr.reraise
|
SynExpr.reraise
|
||||||
|> SynExpr.ifThenElse cond SynExpr.reraise
|
|> SynExpr.ifThenElse cond SynExpr.reraise
|
||||||
|
|
||||||
basic
|
basic
|
||||||
|> SynExpr.pipeThroughTryWith
|
|> SynExpr.pipeThroughTryWith
|
||||||
(SynPat.IsInst (
|
(SynPat.IsInst (
|
||||||
SynType.LongIdent (SynLongIdent.createS' [ "System" ; "InvalidOperationException" ]),
|
SynType.LongIdent (SynLongIdent.Create [ "System" ; "InvalidOperationException" ]),
|
||||||
range0
|
range0
|
||||||
))
|
))
|
||||||
handler
|
handler
|
||||||
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
| PrimitiveType typeName -> asValueGetValue propertyName typeName node
|
||||||
| OptionType ty ->
|
| OptionType ty ->
|
||||||
parseNode None options ty (SynExpr.createIdent "v")
|
parseNode None options ty (SynExpr.CreateIdentString "v")
|
||||||
|> createParseLineOption node
|
|> createParseLineOption node
|
||||||
| ListType ty ->
|
| ListType ty ->
|
||||||
parseNode None options ty (SynExpr.createIdent "elt")
|
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt"))
|
||||||
|> asArrayMapped propertyName "List" node
|
|> asArrayMapped propertyName "List" node
|
||||||
| ArrayType ty ->
|
| ArrayType ty ->
|
||||||
parseNode None options ty (SynExpr.createIdent "elt")
|
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt"))
|
||||||
|> asArrayMapped propertyName "Array" node
|
|> asArrayMapped propertyName "Array" node
|
||||||
| IDictionaryType (keyType, valueType) ->
|
| IDictionaryType (keyType, valueType) ->
|
||||||
node
|
node
|
||||||
|> asObject propertyName
|
|> asObject propertyName
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "dict")
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "dict" ]))
|
||||||
| DictionaryType (keyType, valueType) ->
|
| DictionaryType (keyType, valueType) ->
|
||||||
node
|
node
|
||||||
|> asObject propertyName
|
|> asObject propertyName
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||||
(SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ])
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ]
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "Dictionary" ]
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "Dictionary" ])
|
||||||
)
|
)
|
||||||
| IReadOnlyDictionaryType (keyType, valueType) ->
|
| IReadOnlyDictionaryType (keyType, valueType) ->
|
||||||
node
|
node
|
||||||
|> asObject propertyName
|
|> asObject propertyName
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "readOnlyDict")
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "readOnlyDict" ]))
|
||||||
| MapType (keyType, valueType) ->
|
| MapType (keyType, valueType) ->
|
||||||
node
|
node
|
||||||
|> asObject propertyName
|
|> asObject propertyName
|
||||||
|> SynExpr.pipeThroughFunction (
|
|> SynExpr.pipeThroughFunction (
|
||||||
SynExpr.applyFunction
|
SynExpr.CreateApp (
|
||||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Map" ; "ofSeq" ])
|
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Map" ; "ofSeq" ]))
|
||||||
| BigInt ->
|
|
||||||
node
|
|
||||||
|> SynExpr.callMethod "ToJsonString"
|
|
||||||
|> SynExpr.paren
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Numerics" ; "BigInteger" ; "Parse" ])
|
|
||||||
| _ ->
|
| _ ->
|
||||||
// Let's just hope that we've also got our own type annotation!
|
// Let's just hope that we've also got our own type annotation!
|
||||||
let typeName =
|
let typeName =
|
||||||
@@ -277,8 +327,9 @@ module internal JsonParseGenerator =
|
|||||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||||
/// The result of this function is the body of a let-binding (not including the LHS of that let-binding).
|
/// The result of this function is the body of a let-binding (not including the LHS of that let-binding).
|
||||||
let createParseRhs (options : JsonParseOption) (propertyName : SynExpr) (fieldType : SynType) : SynExpr =
|
let createParseRhs (options : JsonParseOption) (propertyName : SynExpr) (fieldType : SynType) : SynExpr =
|
||||||
let objectToParse = SynExpr.createIdent "node" |> SynExpr.index propertyName
|
SynExpr.CreateIdentString "node"
|
||||||
parseNode (Some propertyName) options fieldType objectToParse
|
|> SynExpr.index propertyName
|
||||||
|
|> parseNode (Some propertyName) options fieldType
|
||||||
|
|
||||||
let isJsonNumberHandling (literal : LongIdent) : bool =
|
let isJsonNumberHandling (literal : LongIdent) : bool =
|
||||||
match List.rev literal |> List.map (fun ident -> ident.idText) with
|
match List.rev literal |> List.map (fun ident -> ident.idText) with
|
||||||
@@ -289,259 +340,270 @@ module internal JsonParseGenerator =
|
|||||||
| [ _ ; "JsonNumberHandling" ; "Serialization" ; "Json" ; "Text" ; "System" ] -> true
|
| [ _ ; "JsonNumberHandling" ; "Serialization" ; "Json" ; "Text" ; "System" ] -> true
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
/// `populateNode` will be inserted before we return the `node` variable.
|
let createMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
||||||
///
|
let xmlDoc = PreXmlDoc.Create " Parse from a JSON node."
|
||||||
/// That is, we give you access to a `JsonNode` called `node`,
|
|
||||||
/// and you must return a `typeName`.
|
|
||||||
let scaffolding (spec : JsonParseOutputSpec) (typeName : LongIdent) (functionBody : SynExpr) : SynModuleDecl =
|
|
||||||
let xmlDoc = PreXmlDoc.create "Parse from a JSON node."
|
|
||||||
|
|
||||||
let returnInfo = SynType.createLongIdent typeName
|
let returnInfo =
|
||||||
|
SynBindingReturnInfo.Create (SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName))
|
||||||
|
|
||||||
let inputArg = "node"
|
let inputArg = Ident.Create "node"
|
||||||
let functionName = Ident.create "jsonParse"
|
let functionName = Ident.Create "jsonParse"
|
||||||
|
|
||||||
let arg =
|
let inputVal =
|
||||||
SynPat.named inputArg
|
let memberFlags =
|
||||||
|> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
if spec.ExtensionMethods then
|
||||||
|
{
|
||||||
|
SynMemberFlags.IsInstance = false
|
||||||
|
SynMemberFlags.IsDispatchSlot = false
|
||||||
|
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||||
|
SynMemberFlags.IsFinal = false
|
||||||
|
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||||
|
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||||
|
}
|
||||||
|
|> Some
|
||||||
|
else
|
||||||
|
None
|
||||||
|
|
||||||
if spec.ExtensionMethods then
|
let thisIdOpt = if spec.ExtensionMethods then None else Some inputArg
|
||||||
let binding =
|
|
||||||
SynBinding.basic [ functionName ] [ arg ] functionBody
|
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
|
||||||
|> SynBinding.withReturnAnnotation returnInfo
|
|
||||||
|> SynMemberDefn.staticMember
|
|
||||||
|
|
||||||
let componentInfo =
|
SynValData.SynValData (
|
||||||
SynComponentInfo.createLong typeName
|
memberFlags,
|
||||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty),
|
||||||
|
thisIdOpt
|
||||||
|
)
|
||||||
|
|
||||||
let containingType =
|
|
||||||
SynTypeDefnRepr.augmentation ()
|
|
||||||
|> SynTypeDefn.create componentInfo
|
|
||||||
|> SynTypeDefn.withMemberDefns [ binding ]
|
|
||||||
|
|
||||||
SynModuleDecl.Types ([ containingType ], range0)
|
|
||||||
else
|
|
||||||
SynBinding.basic [ functionName ] [ arg ] functionBody
|
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
|
||||||
|> SynBinding.withReturnAnnotation returnInfo
|
|
||||||
|> List.singleton
|
|
||||||
|> SynModuleDecl.CreateLet
|
|
||||||
|
|
||||||
let getParseOptions (fieldAttrs : SynAttribute list) =
|
|
||||||
(JsonParseOption.None, fieldAttrs)
|
|
||||||
||> List.fold (fun options attr ->
|
|
||||||
if
|
|
||||||
(SynLongIdent.toString attr.TypeName)
|
|
||||||
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
|
|
||||||
then
|
|
||||||
let qualifiedEnumValue =
|
|
||||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
|
||||||
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
|
|
||||||
// Make sure it's fully qualified
|
|
||||||
SynExpr.createLongIdent
|
|
||||||
[
|
|
||||||
"System"
|
|
||||||
"Text"
|
|
||||||
"Json"
|
|
||||||
"Serialization"
|
|
||||||
"JsonNumberHandling"
|
|
||||||
"AllowReadingFromString"
|
|
||||||
]
|
|
||||||
| _ -> attr.ArgExpr
|
|
||||||
|
|
||||||
{
|
|
||||||
JsonNumberHandlingArg = Some qualifiedEnumValue
|
|
||||||
}
|
|
||||||
else
|
|
||||||
options
|
|
||||||
)
|
|
||||||
|
|
||||||
let createRecordMaker (spec : JsonParseOutputSpec) (fields : SynFieldData<Ident> list) =
|
|
||||||
let assignments =
|
let assignments =
|
||||||
fields
|
fields
|
||||||
|> List.mapi (fun i fieldData ->
|
|> List.map (fun (SynField (attrs, _, id, fieldType, _, _, _, _, _)) ->
|
||||||
|
let id =
|
||||||
|
match id with
|
||||||
|
| None -> failwith "didn't get an ID on field"
|
||||||
|
| Some id -> id
|
||||||
|
|
||||||
|
let attrs = attrs |> List.collect (fun l -> l.Attributes)
|
||||||
|
|
||||||
let propertyNameAttr =
|
let propertyNameAttr =
|
||||||
fieldData.Attrs
|
attrs
|
||||||
|> List.tryFind (fun attr ->
|
|> List.tryFind (fun attr ->
|
||||||
(SynLongIdent.toString attr.TypeName)
|
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let options = getParseOptions fieldData.Attrs
|
let options =
|
||||||
|
(JsonParseOption.None, attrs)
|
||||||
|
||> List.fold (fun options attr ->
|
||||||
|
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
|
||||||
|
let qualifiedEnumValue =
|
||||||
|
match SynExpr.stripOptionalParen attr.ArgExpr with
|
||||||
|
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when
|
||||||
|
isJsonNumberHandling ident
|
||||||
|
->
|
||||||
|
// Make sure it's fully qualified
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create
|
||||||
|
[
|
||||||
|
"System"
|
||||||
|
"Text"
|
||||||
|
"Json"
|
||||||
|
"Serialization"
|
||||||
|
"JsonNumberHandling"
|
||||||
|
"AllowReadingFromString"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
| _ -> attr.ArgExpr
|
||||||
|
|
||||||
|
{
|
||||||
|
JsonNumberHandlingArg = Some qualifiedEnumValue
|
||||||
|
}
|
||||||
|
else
|
||||||
|
options
|
||||||
|
)
|
||||||
|
|
||||||
let propertyName =
|
let propertyName =
|
||||||
match propertyNameAttr with
|
match propertyNameAttr with
|
||||||
| None ->
|
| None ->
|
||||||
let sb = StringBuilder fieldData.Ident.idText.Length
|
let sb = StringBuilder id.idText.Length
|
||||||
|
sb.Append (Char.ToLowerInvariant id.idText.[0]) |> ignore
|
||||||
|
|
||||||
sb.Append (Char.ToLowerInvariant fieldData.Ident.idText.[0])
|
if id.idText.Length > 1 then
|
||||||
|> ignore<StringBuilder>
|
sb.Append id.idText.[1..] |> ignore
|
||||||
|
|
||||||
if fieldData.Ident.idText.Length > 1 then
|
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||||
sb.Append (fieldData.Ident.idText.Substring 1) |> ignore<StringBuilder>
|
|
||||||
|
|
||||||
sb.ToString () |> SynExpr.CreateConst
|
|
||||||
| Some name -> name.ArgExpr
|
| Some name -> name.ArgExpr
|
||||||
|
|
||||||
createParseRhs options propertyName fieldData.Type
|
let pattern =
|
||||||
|> SynBinding.basic [ Ident.create $"arg_%i{i}" ] []
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ id ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Empty,
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
SynBinding.Let (
|
||||||
|
isInline = false,
|
||||||
|
isMutable = false,
|
||||||
|
expr = createParseRhs options propertyName fieldType,
|
||||||
|
valData = inputVal,
|
||||||
|
pattern = pattern
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let finalConstruction =
|
let finalConstruction =
|
||||||
fields
|
fields
|
||||||
|> List.mapi (fun i fieldData ->
|
|> List.map (fun (SynField (_, _, id, _, _, _, _, _, _)) ->
|
||||||
(SynLongIdent.createI fieldData.Ident, true), Some (SynExpr.createIdent $"arg_%i{i}")
|
let id =
|
||||||
|
match id with
|
||||||
|
| None -> failwith "Expected record field to have an identifying name"
|
||||||
|
| Some id -> id
|
||||||
|
|
||||||
|
(SynLongIdent.CreateFromLongIdent [ id ], true),
|
||||||
|
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ id ]))
|
||||||
)
|
)
|
||||||
|> AstHelper.instantiateRecord
|
|> AstHelper.instantiateRecord
|
||||||
|
|
||||||
(finalConstruction, assignments)
|
let assignments =
|
||||||
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)
|
(finalConstruction, assignments)
|
||||||
|
||> List.fold (fun final assignment ->
|
||||||
let createUnionMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : UnionCase<Ident> list) =
|
SynExpr.LetOrUse (
|
||||||
fields
|
false,
|
||||||
|> List.map (fun case ->
|
false,
|
||||||
let propertyName = JsonSerializeGenerator.getPropertyName case.Ident case.Attrs
|
[ assignment ],
|
||||||
|
final,
|
||||||
let body =
|
|
||||||
if case.Fields.IsEmpty then
|
|
||||||
SynExpr.createLongIdent' (typeName @ [ case.Ident ])
|
|
||||||
else
|
|
||||||
case.Fields
|
|
||||||
|> List.map (fun field ->
|
|
||||||
let propertyName = JsonSerializeGenerator.getPropertyName field.Ident field.Attrs
|
|
||||||
let options = getParseOptions field.Attrs
|
|
||||||
createParseRhs options propertyName field.Type
|
|
||||||
)
|
|
||||||
|> SynExpr.tuple
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ]))
|
|
||||||
|> SynExpr.createLet
|
|
||||||
[
|
|
||||||
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|
|
||||||
|> assertNotNull (SynExpr.CreateConst "data")
|
|
||||||
|> SynBinding.basic [ Ident.create "node" ] []
|
|
||||||
]
|
|
||||||
|
|
||||||
match propertyName with
|
|
||||||
| SynExpr.Const (synConst, _) ->
|
|
||||||
SynMatchClause.SynMatchClause (
|
|
||||||
SynPat.CreateConst synConst,
|
|
||||||
None,
|
|
||||||
body,
|
|
||||||
range0,
|
range0,
|
||||||
DebugPointAtTarget.Yes,
|
|
||||||
{
|
{
|
||||||
ArrowRange = Some range0
|
InKeyword = None
|
||||||
BarRange = Some range0
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
| _ ->
|
)
|
||||||
SynMatchClause.create (SynPat.named "x") body
|
|
||||||
|> SynMatchClause.withWhere (SynExpr.equals (SynExpr.createIdent "x") propertyName)
|
|
||||||
)
|
|
||||||
|> fun l ->
|
|
||||||
l
|
|
||||||
@ [
|
|
||||||
let fail =
|
|
||||||
SynExpr.plus (SynExpr.CreateConst "Unrecognised 'type' field value: ") (SynExpr.createIdent "v")
|
|
||||||
|> SynExpr.paren
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
|
||||||
|
|
||||||
SynMatchClause.SynMatchClause (
|
let pattern =
|
||||||
SynPat.named "v",
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ functionName ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Pats
|
||||||
|
[
|
||||||
|
SynPat.CreateTyped (
|
||||||
|
SynPat.CreateNamed inputArg,
|
||||||
|
SynType.LongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> SynPat.CreateParen
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
if spec.ExtensionMethods then
|
||||||
|
let binding =
|
||||||
|
SynBinding.SynBinding (
|
||||||
None,
|
None,
|
||||||
fail,
|
SynBindingKind.Normal,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[],
|
||||||
|
xmlDoc,
|
||||||
|
inputVal,
|
||||||
|
pattern,
|
||||||
|
Some returnInfo,
|
||||||
|
assignments,
|
||||||
range0,
|
range0,
|
||||||
DebugPointAtTarget.Yes,
|
DebugPointAtBinding.NoneAtInvisible,
|
||||||
{
|
{
|
||||||
ArrowRange = Some range0
|
LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0)
|
||||||
BarRange = Some range0
|
InlineKeyword = None
|
||||||
|
EqualsRange = Some range0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
]
|
|
||||||
|> SynExpr.createMatch (SynExpr.createIdent "ty")
|
|
||||||
|> SynExpr.createLet
|
|
||||||
[
|
|
||||||
let property = SynExpr.CreateConst "type"
|
|
||||||
|
|
||||||
SynExpr.createIdent "node"
|
let mem = SynMemberDefn.Member (binding, range0)
|
||||||
|> SynExpr.index property
|
|
||||||
|> assertNotNull property
|
let containingType =
|
||||||
|> SynExpr.pipeThroughFunction (
|
SynTypeDefn.SynTypeDefn (
|
||||||
SynExpr.createLambda
|
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"),
|
||||||
"v"
|
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||||
(SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v"))
|
[ mem ],
|
||||||
|
None,
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||||
|
EqualsRange = None
|
||||||
|
WithKeyword = None
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|> SynBinding.basic [ Ident.create "ty" ] []
|
|
||||||
]
|
|
||||||
|
|
||||||
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
SynModuleDecl.Types ([ containingType ], range0)
|
||||||
|
else
|
||||||
|
let binding =
|
||||||
|
SynBinding.Let (
|
||||||
|
isInline = false,
|
||||||
|
isMutable = false,
|
||||||
|
xmldoc = xmlDoc,
|
||||||
|
returnInfo = returnInfo,
|
||||||
|
expr = assignments,
|
||||||
|
valData = inputVal,
|
||||||
|
pattern = pattern
|
||||||
|
)
|
||||||
|
|
||||||
|
SynModuleDecl.CreateLet [ binding ]
|
||||||
|
|
||||||
|
let createRecordModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
||||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||||
typeDefn
|
typeDefn
|
||||||
|
|
||||||
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, _access, _)) =
|
let (SynComponentInfo (_attributes, _typeParams, _constraints, recordId, _, _preferPostfix, _access, _)) =
|
||||||
synComponentInfo
|
synComponentInfo
|
||||||
|
|
||||||
let attributes =
|
match synTypeDefnRepr with
|
||||||
if spec.ExtensionMethods then
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _recordRange), _) ->
|
||||||
[ SynAttribute.autoOpen ]
|
|
||||||
else
|
|
||||||
[ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
|
|
||||||
|
|
||||||
let xmlDoc =
|
let decls = [ createMaker spec recordId recordFields ]
|
||||||
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
|
||||||
|
|
||||||
let description =
|
let attributes =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
"extension members"
|
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||||
else
|
else
|
||||||
"methods"
|
[
|
||||||
|
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||||
|
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||||
|
]
|
||||||
|
|
||||||
$"Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
let xmlDoc =
|
||||||
|> PreXmlDoc.create
|
let fullyQualified = recordId |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||||
|
|
||||||
let moduleName =
|
let description =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
match ident with
|
"extension members"
|
||||||
| [] -> failwith "unexpectedly got an empty identifier for record name"
|
else
|
||||||
| ident ->
|
"methods"
|
||||||
let expanded =
|
|
||||||
List.last ident
|
|
||||||
|> fun i -> i.idText
|
|
||||||
|> fun s -> s + "JsonParseExtension"
|
|
||||||
|> Ident.create
|
|
||||||
|
|
||||||
List.take (List.length ident - 1) ident @ [ expanded ]
|
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
||||||
else
|
|> PreXmlDoc.Create
|
||||||
ident
|
|
||||||
|
|
||||||
let info =
|
let moduleName =
|
||||||
SynComponentInfo.createLong moduleName
|
if spec.ExtensionMethods then
|
||||||
|> SynComponentInfo.withDocString xmlDoc
|
match recordId with
|
||||||
|> SynComponentInfo.addAttributes attributes
|
| [] -> failwith "unexpectedly got an empty identifier for record name"
|
||||||
|
| recordId ->
|
||||||
|
let expanded =
|
||||||
|
List.last recordId
|
||||||
|
|> fun i -> i.idText
|
||||||
|
|> fun s -> s + "JsonParseExtension"
|
||||||
|
|> Ident.Create
|
||||||
|
|
||||||
let decl =
|
List.take (List.length recordId - 1) recordId @ [ expanded ]
|
||||||
match synTypeDefnRepr with
|
else
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) ->
|
recordId
|
||||||
fields |> List.map SynField.extractWithIdent |> createRecordMaker spec
|
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) ->
|
|
||||||
let optionGet (i : Ident option) =
|
|
||||||
match i with
|
|
||||||
| None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field."
|
|
||||||
| Some i -> i
|
|
||||||
|
|
||||||
cases
|
let info =
|
||||||
|> List.map SynUnionCase.extract
|
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||||
|> List.map (UnionCase.mapIdentFields optionGet)
|
|
||||||
|> createUnionMaker spec ident
|
|
||||||
| _ -> failwithf "Not a record or union type"
|
|
||||||
|
|
||||||
let mdl =
|
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||||
[ scaffolding spec ident decl ]
|
|
||||||
|> fun d -> SynModuleDecl.CreateNestedModule (info, d)
|
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||||
|
| _ -> failwithf "Not a record type"
|
||||||
|
|
||||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||||
/// containing a JSON parse function.
|
/// containing a JSON parse function.
|
||||||
@@ -555,20 +617,10 @@ type JsonParseGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let recordsAndUnions =
|
let records = Ast.extractRecords ast
|
||||||
Ast.extractTypeDefn ast
|
|
||||||
|> List.map (fun (name, defns) ->
|
|
||||||
defns
|
|
||||||
|> List.choose (fun defn ->
|
|
||||||
if Ast.isRecord defn then Some defn
|
|
||||||
elif Ast.isDu defn then Some defn
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|> fun defns -> name, defns
|
|
||||||
)
|
|
||||||
|
|
||||||
let namespaceAndTypes =
|
let namespaceAndRecords =
|
||||||
recordsAndUnions
|
records
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.choose (fun (ns, types) ->
|
||||||
types
|
types
|
||||||
|> List.choose (fun typeDef ->
|
|> List.choose (fun typeDef ->
|
||||||
@@ -596,9 +648,13 @@ type JsonParseGenerator () =
|
|||||||
)
|
)
|
||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
namespaceAndTypes
|
namespaceAndRecords
|
||||||
|> List.collect (fun (ns, types) ->
|
|> List.collect (fun (ns, records) ->
|
||||||
types |> List.map (fun (ty, spec) -> JsonParseGenerator.createModule ns spec ty)
|
records
|
||||||
|
|> List.map (fun (record, spec) ->
|
||||||
|
let recordModule = JsonParseGenerator.createRecordModule ns spec record
|
||||||
|
recordModule
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Output.Ast modules
|
Output.Ast modules
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
open System
|
open System
|
||||||
open System.Text
|
open System.Text
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
|
open Fantomas.FCS.Xml
|
||||||
open Myriad.Core
|
open Myriad.Core
|
||||||
|
|
||||||
type internal JsonSerializeOutputSpec =
|
type internal JsonSerializeOutputSpec =
|
||||||
@@ -28,7 +30,9 @@ module internal JsonSerializeGenerator =
|
|||||||
| Uri ->
|
| Uri ->
|
||||||
// JsonValue.Create<type>
|
// JsonValue.Create<type>
|
||||||
SynExpr.TypeApp (
|
SynExpr.TypeApp (
|
||||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ],
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||||
|
),
|
||||||
range0,
|
range0,
|
||||||
[ fieldType ],
|
[ fieldType ],
|
||||||
[],
|
[],
|
||||||
@@ -38,24 +42,39 @@ module internal JsonSerializeGenerator =
|
|||||||
)
|
)
|
||||||
| OptionType ty ->
|
| OptionType ty ->
|
||||||
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
|
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
|
||||||
let noneClause =
|
SynExpr.CreateMatch (
|
||||||
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
|
SynExpr.CreateIdentString "field",
|
||||||
// identically equal to null. We have to work around this later, but we might as well just
|
[
|
||||||
// be efficient here and whip up the null directly.
|
SynMatchClause.Create (
|
||||||
SynExpr.createNull ()
|
SynPat.CreateLongIdent (SynLongIdent.CreateString "None", []),
|
||||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
None,
|
||||||
|> SynMatchClause.create (SynPat.named "None")
|
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
|
||||||
|
// identically equal to null. We have to work around this later, but we might as well just
|
||||||
|
// be efficient here and whip up the null directly.
|
||||||
|
SynExpr.CreateNull
|
||||||
|
|> SynExpr.upcast' (
|
||||||
|
SynType.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
let someClause =
|
SynMatchClause.Create (
|
||||||
SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "field")
|
SynPat.CreateLongIdent (
|
||||||
|> SynExpr.paren
|
SynLongIdent.CreateString "Some",
|
||||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
[ SynPat.CreateNamed (Ident.Create "field") ]
|
||||||
|> SynMatchClause.create (
|
),
|
||||||
SynPat.CreateLongIdent (SynLongIdent.createS "Some", [ SynPat.named "field" ])
|
None,
|
||||||
)
|
SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "field")
|
||||||
|
|> SynExpr.CreateParen
|
||||||
[ noneClause ; someClause ]
|
|> SynExpr.upcast' (
|
||||||
|> SynExpr.createMatch (SynExpr.createIdent "field")
|
SynType.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|> SynExpr.createLambda "field"
|
|> SynExpr.createLambda "field"
|
||||||
| ArrayType ty
|
| ArrayType ty
|
||||||
| ListType ty ->
|
| ListType ty ->
|
||||||
@@ -63,70 +82,116 @@ module internal JsonSerializeGenerator =
|
|||||||
// let arr = JsonArray ()
|
// let arr = JsonArray ()
|
||||||
// for mem in field do arr.Add ({serializeNode} mem)
|
// for mem in field do arr.Add ({serializeNode} mem)
|
||||||
// arr
|
// arr
|
||||||
[
|
SynExpr.LetOrUse (
|
||||||
SynExpr.ForEach (
|
false,
|
||||||
DebugPointAtFor.Yes range0,
|
false,
|
||||||
DebugPointAtInOrTo.Yes range0,
|
|
||||||
SeqExprOnly.SeqExprOnly false,
|
|
||||||
true,
|
|
||||||
SynPat.named "mem",
|
|
||||||
SynExpr.createIdent "field",
|
|
||||||
SynExpr.applyFunction
|
|
||||||
(SynExpr.createLongIdent [ "arr" ; "Add" ])
|
|
||||||
(SynExpr.paren (SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "mem"))),
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
SynExpr.createIdent "arr"
|
|
||||||
]
|
|
||||||
|> SynExpr.sequential
|
|
||||||
|> SynExpr.createLet
|
|
||||||
[
|
[
|
||||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ]
|
SynBinding.Let (
|
||||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
pattern = SynPat.CreateNamed (Ident.Create "arr"),
|
||||||
|> SynBinding.basic [ Ident.create "arr" ] []
|
expr =
|
||||||
]
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
SynExpr.CreateSequential
|
||||||
|
[
|
||||||
|
SynExpr.ForEach (
|
||||||
|
DebugPointAtFor.Yes range0,
|
||||||
|
DebugPointAtInOrTo.Yes range0,
|
||||||
|
SeqExprOnly.SeqExprOnly false,
|
||||||
|
true,
|
||||||
|
SynPat.CreateNamed (Ident.Create "mem"),
|
||||||
|
SynExpr.CreateIdent (Ident.Create "field"),
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "arr" ; "Add" ]),
|
||||||
|
SynExpr.CreateParen (
|
||||||
|
SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "mem")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
SynExpr.CreateIdentString "arr"
|
||||||
|
],
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
InKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|> SynExpr.createLambda "field"
|
|> SynExpr.createLambda "field"
|
||||||
| IDictionaryType (_keyType, valueType)
|
| IDictionaryType (keyType, valueType)
|
||||||
| DictionaryType (_keyType, valueType)
|
| DictionaryType (keyType, valueType)
|
||||||
| IReadOnlyDictionaryType (_keyType, valueType)
|
| IReadOnlyDictionaryType (keyType, valueType)
|
||||||
| MapType (_keyType, valueType) ->
|
| MapType (keyType, valueType) ->
|
||||||
// fun field ->
|
// fun field ->
|
||||||
// let ret = JsonObject ()
|
// let ret = JsonObject ()
|
||||||
// for (KeyValue(key, value)) in field do
|
// for (KeyValue(key, value)) in field do
|
||||||
// ret.Add (key.ToString (), {serializeNode} value)
|
// ret.Add (key.ToString (), {serializeNode} value)
|
||||||
// ret
|
// ret
|
||||||
[
|
SynExpr.LetOrUse (
|
||||||
SynExpr.ForEach (
|
false,
|
||||||
DebugPointAtFor.Yes range0,
|
false,
|
||||||
DebugPointAtInOrTo.Yes range0,
|
|
||||||
SeqExprOnly.SeqExprOnly false,
|
|
||||||
true,
|
|
||||||
SynPat.paren (
|
|
||||||
SynPat.CreateLongIdent (
|
|
||||||
SynLongIdent.createS "KeyValue",
|
|
||||||
[ SynPat.tuple [ SynPat.named "key" ; SynPat.named "value" ] ]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
SynExpr.createIdent "field",
|
|
||||||
SynExpr.applyFunction
|
|
||||||
(SynExpr.createLongIdent [ "ret" ; "Add" ])
|
|
||||||
(SynExpr.tuple
|
|
||||||
[
|
|
||||||
SynExpr.createLongIdent [ "key" ; "ToString" ]
|
|
||||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
|
||||||
SynExpr.applyFunction (serializeNode valueType) (SynExpr.createIdent "value")
|
|
||||||
]),
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
SynExpr.createIdent "ret"
|
|
||||||
]
|
|
||||||
|> SynExpr.sequential
|
|
||||||
|> SynExpr.createLet
|
|
||||||
[
|
[
|
||||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
SynBinding.Let (
|
||||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
pattern = SynPat.CreateNamed (Ident.Create "ret"),
|
||||||
|> SynBinding.basic [ Ident.create "ret" ] []
|
expr =
|
||||||
]
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
SynExpr.CreateSequential
|
||||||
|
[
|
||||||
|
SynExpr.ForEach (
|
||||||
|
DebugPointAtFor.Yes range0,
|
||||||
|
DebugPointAtInOrTo.Yes range0,
|
||||||
|
SeqExprOnly.SeqExprOnly false,
|
||||||
|
true,
|
||||||
|
SynPat.CreateParen (
|
||||||
|
SynPat.CreateLongIdent (
|
||||||
|
SynLongIdent.CreateString "KeyValue",
|
||||||
|
[
|
||||||
|
SynPat.CreateParen (
|
||||||
|
SynPat.Tuple (
|
||||||
|
false,
|
||||||
|
[
|
||||||
|
SynPat.CreateNamed (Ident.Create "key")
|
||||||
|
SynPat.CreateNamed (Ident.Create "value")
|
||||||
|
],
|
||||||
|
[ range0 ],
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SynExpr.CreateIdent (Ident.Create "field"),
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "ret" ; "Add" ]),
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "key" ; "ToString" ]),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
SynExpr.CreateApp (serializeNode valueType, SynExpr.CreateIdentString "value")
|
||||||
|
]
|
||||||
|
),
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
SynExpr.CreateIdentString "ret"
|
||||||
|
],
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
InKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|> SynExpr.createLambda "field"
|
|> SynExpr.createLambda "field"
|
||||||
| _ ->
|
| _ ->
|
||||||
// {type}.toJsonNode
|
// {type}.toJsonNode
|
||||||
@@ -135,195 +200,213 @@ module internal JsonSerializeGenerator =
|
|||||||
| SynType.LongIdent ident -> ident.LongIdent
|
| SynType.LongIdent ident -> ident.LongIdent
|
||||||
| _ -> failwith $"Unrecognised type: %+A{fieldType}"
|
| _ -> failwith $"Unrecognised type: %+A{fieldType}"
|
||||||
|
|
||||||
SynExpr.createLongIdent' (typeName @ [ Ident.create "toJsonNode" ])
|
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (typeName @ [ Ident.Create "toJsonNode" ]))
|
||||||
|
|
||||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||||
/// `node.Add ({propertyName}, {toJsonNode})`
|
/// `node.Add ({propertyName}, {toJsonNode})`
|
||||||
let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
|
let createSerializeRhs (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
|
||||||
[
|
let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "node" ; "Add" ])
|
||||||
propertyName
|
|
||||||
SynExpr.applyFunction
|
|
||||||
(serializeNode fieldType)
|
|
||||||
(SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ])
|
|
||||||
]
|
|
||||||
|> SynExpr.tuple
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
|
||||||
|
|
||||||
let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr =
|
let args =
|
||||||
let propertyNameAttr =
|
SynExpr.CreateParenedTuple
|
||||||
attrs
|
|
||||||
|> List.tryFind (fun attr ->
|
|
||||||
(SynLongIdent.toString attr.TypeName)
|
|
||||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
|
||||||
)
|
|
||||||
|
|
||||||
match propertyNameAttr with
|
|
||||||
| None ->
|
|
||||||
let sb = StringBuilder fieldId.idText.Length
|
|
||||||
sb.Append (Char.ToLowerInvariant fieldId.idText.[0]) |> ignore
|
|
||||||
|
|
||||||
if fieldId.idText.Length > 1 then
|
|
||||||
sb.Append fieldId.idText.[1..] |> ignore
|
|
||||||
|
|
||||||
sb.ToString () |> SynExpr.CreateConst
|
|
||||||
| Some name -> name.ArgExpr
|
|
||||||
|
|
||||||
/// `populateNode` will be inserted before we return the `node` variable.
|
|
||||||
///
|
|
||||||
/// That is, we give you access to a `JsonObject` called `node`,
|
|
||||||
/// and you have access to a variable `inputArgName` which is of type `typeName`.
|
|
||||||
/// Your job is to provide a `populateNode` expression which has the side effect
|
|
||||||
/// of mutating `node` to faithfully reflect the value of `inputArgName`.
|
|
||||||
let scaffolding
|
|
||||||
(spec : JsonSerializeOutputSpec)
|
|
||||||
(typeName : LongIdent)
|
|
||||||
(inputArgName : Ident)
|
|
||||||
(populateNode : SynExpr)
|
|
||||||
: SynModuleDecl
|
|
||||||
=
|
|
||||||
let xmlDoc = PreXmlDoc.create "Serialize to a JSON node"
|
|
||||||
|
|
||||||
let returnInfo =
|
|
||||||
SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
|
||||||
|> SynType.LongIdent
|
|
||||||
|
|
||||||
let functionName = Ident.create "toJsonNode"
|
|
||||||
|
|
||||||
let assignments =
|
|
||||||
[
|
|
||||||
populateNode
|
|
||||||
SynExpr.Upcast (SynExpr.createIdent "node", SynType.Anon range0, range0)
|
|
||||||
]
|
|
||||||
|> SynExpr.sequential
|
|
||||||
|> SynExpr.createLet
|
|
||||||
[
|
[
|
||||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
propertyName
|
||||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
SynExpr.CreateApp (
|
||||||
|> SynBinding.basic [ Ident.create "node" ] []
|
serializeNode fieldType,
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ Ident.Create "input" ; fieldId ])
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SynExpr.CreateApp (func, args)
|
||||||
|
|
||||||
|
let createMaker (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
||||||
|
let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node"
|
||||||
|
|
||||||
|
let returnInfo =
|
||||||
|
SynBindingReturnInfo.Create (
|
||||||
|
SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||||
|
)
|
||||||
|
|
||||||
|
let inputArg = Ident.Create "input"
|
||||||
|
let functionName = Ident.Create "toJsonNode"
|
||||||
|
|
||||||
|
let inputVal =
|
||||||
|
let memberFlags =
|
||||||
|
if spec.ExtensionMethods then
|
||||||
|
{
|
||||||
|
SynMemberFlags.IsInstance = false
|
||||||
|
SynMemberFlags.IsDispatchSlot = false
|
||||||
|
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||||
|
SynMemberFlags.IsFinal = false
|
||||||
|
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||||
|
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||||
|
}
|
||||||
|
|> Some
|
||||||
|
else
|
||||||
|
None
|
||||||
|
|
||||||
|
let thisIdOpt = if spec.ExtensionMethods then None else Some inputArg
|
||||||
|
|
||||||
|
SynValData.SynValData (
|
||||||
|
memberFlags,
|
||||||
|
SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty),
|
||||||
|
thisIdOpt
|
||||||
|
)
|
||||||
|
|
||||||
|
let assignments =
|
||||||
|
fields
|
||||||
|
|> List.map (fun (SynField (attrs, _, id, fieldType, _, _, _, _, _)) ->
|
||||||
|
let id =
|
||||||
|
match id with
|
||||||
|
| None -> failwith "didn't get an ID on field"
|
||||||
|
| Some id -> id
|
||||||
|
|
||||||
|
let attrs = attrs |> List.collect (fun l -> l.Attributes)
|
||||||
|
|
||||||
|
let propertyNameAttr =
|
||||||
|
attrs
|
||||||
|
|> List.tryFind (fun attr ->
|
||||||
|
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||||
|
)
|
||||||
|
|
||||||
|
let propertyName =
|
||||||
|
match propertyNameAttr with
|
||||||
|
| None ->
|
||||||
|
let sb = StringBuilder id.idText.Length
|
||||||
|
sb.Append (Char.ToLowerInvariant id.idText.[0]) |> ignore
|
||||||
|
|
||||||
|
if id.idText.Length > 1 then
|
||||||
|
sb.Append id.idText.[1..] |> ignore
|
||||||
|
|
||||||
|
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||||
|
| Some name -> name.ArgExpr
|
||||||
|
|
||||||
|
let pattern =
|
||||||
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ id ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Empty,
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
createSerializeRhs propertyName id fieldType
|
||||||
|
)
|
||||||
|
|
||||||
|
let finalConstruction =
|
||||||
|
fields
|
||||||
|
|> List.map (fun (SynField (_, _, id, _, _, _, _, _, _)) ->
|
||||||
|
let id =
|
||||||
|
match id with
|
||||||
|
| None -> failwith "Expected record field to have an identifying name"
|
||||||
|
| Some id -> id
|
||||||
|
|
||||||
|
(SynLongIdent.CreateFromLongIdent [ id ], true),
|
||||||
|
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ id ]))
|
||||||
|
)
|
||||||
|
|> AstHelper.instantiateRecord
|
||||||
|
|
||||||
|
let assignments = assignments |> SynExpr.CreateSequential
|
||||||
|
|
||||||
|
let assignments =
|
||||||
|
SynExpr.LetOrUse (
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[
|
||||||
|
SynBinding.Let (
|
||||||
|
pattern = SynPat.CreateNamed (Ident.Create "node"),
|
||||||
|
expr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
SynExpr.CreateSequential
|
||||||
|
[
|
||||||
|
SynExpr.Do (assignments, range0)
|
||||||
|
SynExpr.Upcast (SynExpr.CreateIdentString "node", SynType.Anon range0, range0)
|
||||||
|
],
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
InKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let pattern =
|
let pattern =
|
||||||
SynPat.CreateNamed inputArgName
|
SynPat.LongIdent (
|
||||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName))
|
SynLongIdent.CreateFromLongIdent [ functionName ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Pats
|
||||||
|
[
|
||||||
|
SynPat.CreateTyped (
|
||||||
|
SynPat.CreateNamed inputArg,
|
||||||
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName)
|
||||||
|
)
|
||||||
|
|> SynPat.CreateParen
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
let componentInfo =
|
let binding =
|
||||||
SynComponentInfo.createLong typeName
|
SynBinding.SynBinding (
|
||||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
None,
|
||||||
|
SynBindingKind.Normal,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[],
|
||||||
|
xmlDoc,
|
||||||
|
inputVal,
|
||||||
|
pattern,
|
||||||
|
Some returnInfo,
|
||||||
|
assignments,
|
||||||
|
range0,
|
||||||
|
DebugPointAtBinding.NoneAtInvisible,
|
||||||
|
{
|
||||||
|
LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0)
|
||||||
|
InlineKeyword = None
|
||||||
|
EqualsRange = Some range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
let memberDef =
|
let mem = SynMemberDefn.Member (binding, range0)
|
||||||
assignments
|
|
||||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
|
||||||
|> SynBinding.withReturnAnnotation returnInfo
|
|
||||||
|> SynMemberDefn.staticMember
|
|
||||||
|
|
||||||
let containingType =
|
let containingType =
|
||||||
SynTypeDefnRepr.augmentation ()
|
SynTypeDefn.SynTypeDefn (
|
||||||
|> SynTypeDefn.create componentInfo
|
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"),
|
||||||
|> SynTypeDefn.withMemberDefns [ memberDef ]
|
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||||
|
[ mem ],
|
||||||
|
None,
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||||
|
EqualsRange = None
|
||||||
|
WithKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
SynModuleDecl.Types ([ containingType ], range0)
|
SynModuleDecl.Types ([ containingType ], range0)
|
||||||
else
|
else
|
||||||
let binding =
|
let binding =
|
||||||
assignments
|
SynBinding.Let (
|
||||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
isInline = false,
|
||||||
|> SynBinding.withReturnAnnotation returnInfo
|
isMutable = false,
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
xmldoc = xmlDoc,
|
||||||
|
returnInfo = returnInfo,
|
||||||
|
expr = assignments,
|
||||||
|
valData = inputVal,
|
||||||
|
pattern = pattern
|
||||||
|
)
|
||||||
|
|
||||||
SynModuleDecl.CreateLet [ binding ]
|
SynModuleDecl.CreateLet [ binding ]
|
||||||
|
|
||||||
let recordModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
let createRecordModule
|
||||||
let inputArg = Ident.create "input"
|
|
||||||
let fields = fields |> List.map SynField.extractWithIdent
|
|
||||||
|
|
||||||
fields
|
|
||||||
|> List.map (fun fieldData ->
|
|
||||||
let propertyName = getPropertyName fieldData.Ident fieldData.Attrs
|
|
||||||
createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type
|
|
||||||
)
|
|
||||||
|> SynExpr.sequential
|
|
||||||
|> fun expr -> SynExpr.Do (expr, range0)
|
|
||||||
|> scaffolding spec typeName inputArg
|
|
||||||
|
|
||||||
let unionModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (cases : SynUnionCase list) =
|
|
||||||
let inputArg = Ident.create "input"
|
|
||||||
let fields = cases |> List.map SynUnionCase.extract
|
|
||||||
|
|
||||||
fields
|
|
||||||
|> List.map (fun unionCase ->
|
|
||||||
let propertyName = getPropertyName unionCase.Ident unionCase.Attrs
|
|
||||||
|
|
||||||
let caseNames = unionCase.Fields |> List.mapi (fun i _ -> Ident.create $"arg%i{i}")
|
|
||||||
|
|
||||||
let argPats = SynArgPats.create caseNames
|
|
||||||
|
|
||||||
let pattern =
|
|
||||||
SynPat.LongIdent (
|
|
||||||
SynLongIdent.create (typeName @ [ unionCase.Ident ]),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
argPats,
|
|
||||||
None,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
let typeLine =
|
|
||||||
[
|
|
||||||
SynExpr.CreateConst "type"
|
|
||||||
SynExpr.applyFunction
|
|
||||||
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ])
|
|
||||||
propertyName
|
|
||||||
]
|
|
||||||
|> SynExpr.tuple
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
|
||||||
|
|
||||||
let dataNode =
|
|
||||||
SynBinding.Let (
|
|
||||||
pattern = SynPat.named "dataNode",
|
|
||||||
expr =
|
|
||||||
SynExpr.applyFunction
|
|
||||||
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ])
|
|
||||||
(SynExpr.CreateConst ())
|
|
||||||
)
|
|
||||||
|
|
||||||
let dataBindings =
|
|
||||||
(unionCase.Fields, caseNames)
|
|
||||||
||> List.zip
|
|
||||||
|> List.map (fun (fieldData, caseName) ->
|
|
||||||
let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs
|
|
||||||
|
|
||||||
let node =
|
|
||||||
SynExpr.applyFunction (serializeNode fieldData.Type) (SynExpr.createIdent' caseName)
|
|
||||||
|
|
||||||
[ propertyName ; node ]
|
|
||||||
|> SynExpr.tuple
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ])
|
|
||||||
)
|
|
||||||
|
|
||||||
let assignToNode =
|
|
||||||
[ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ]
|
|
||||||
|> SynExpr.tuple
|
|
||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
|
||||||
|
|
||||||
let dataNode =
|
|
||||||
SynExpr.sequential (dataBindings @ [ assignToNode ])
|
|
||||||
|> SynExpr.createLet [ dataNode ]
|
|
||||||
|
|
||||||
let action =
|
|
||||||
[
|
|
||||||
yield typeLine
|
|
||||||
if not dataBindings.IsEmpty then
|
|
||||||
yield dataNode
|
|
||||||
]
|
|
||||||
|> SynExpr.sequential
|
|
||||||
|
|
||||||
SynMatchClause.create pattern action
|
|
||||||
)
|
|
||||||
|> SynExpr.createMatch (SynExpr.createIdent' inputArg)
|
|
||||||
|> scaffolding spec typeName inputArg
|
|
||||||
|
|
||||||
let createModule
|
|
||||||
(namespaceId : LongIdent)
|
(namespaceId : LongIdent)
|
||||||
(opens : SynOpenDeclTarget list)
|
(opens : SynOpenDeclTarget list)
|
||||||
(spec : JsonSerializeOutputSpec)
|
(spec : JsonSerializeOutputSpec)
|
||||||
@@ -332,61 +415,60 @@ module internal JsonSerializeGenerator =
|
|||||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||||
typeDefn
|
typeDefn
|
||||||
|
|
||||||
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, _access, _)) =
|
let (SynComponentInfo (_attributes, _typeParams, _constraints, recordId, _, _preferPostfix, _access, _)) =
|
||||||
synComponentInfo
|
synComponentInfo
|
||||||
|
|
||||||
let attributes =
|
match synTypeDefnRepr with
|
||||||
if spec.ExtensionMethods then
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _recordRange), _) ->
|
||||||
[ SynAttribute.autoOpen ]
|
|
||||||
else
|
|
||||||
[ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
|
|
||||||
|
|
||||||
let xmlDoc =
|
let decls = [ createMaker spec recordId recordFields ]
|
||||||
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
|
||||||
|
|
||||||
let description =
|
let attributes =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
"extension members"
|
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||||
else
|
else
|
||||||
"methods"
|
[
|
||||||
|
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||||
|
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||||
|
]
|
||||||
|
|
||||||
$"Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
let xmlDoc =
|
||||||
|> PreXmlDoc.create
|
let fullyQualified = recordId |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||||
|
|
||||||
let moduleName =
|
let description =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
match ident with
|
"extension members"
|
||||||
| [] -> failwith "unexpectedly got an empty identifier for type name"
|
else
|
||||||
| ident ->
|
"methods"
|
||||||
let expanded =
|
|
||||||
List.last ident
|
|
||||||
|> fun i -> i.idText
|
|
||||||
|> fun s -> s + "JsonSerializeExtension"
|
|
||||||
|> Ident.create
|
|
||||||
|
|
||||||
List.take (List.length ident - 1) ident @ [ expanded ]
|
$" Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
||||||
else
|
|> PreXmlDoc.Create
|
||||||
ident
|
|
||||||
|
|
||||||
let info =
|
let moduleName =
|
||||||
SynComponentInfo.createLong moduleName
|
if spec.ExtensionMethods then
|
||||||
|> SynComponentInfo.addAttributes attributes
|
match recordId with
|
||||||
|> SynComponentInfo.withDocString xmlDoc
|
| [] -> failwith "unexpectedly got an empty identifier for record name"
|
||||||
|
| recordId ->
|
||||||
|
let expanded =
|
||||||
|
List.last recordId
|
||||||
|
|> fun i -> i.idText
|
||||||
|
|> fun s -> s + "JsonSerializeExtension"
|
||||||
|
|> Ident.Create
|
||||||
|
|
||||||
let decls =
|
List.take (List.length recordId - 1) recordId @ [ expanded ]
|
||||||
match synTypeDefnRepr with
|
else
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _range), _) ->
|
recordId
|
||||||
[ recordModule spec ident recordFields ]
|
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, unionFields, _range), _) ->
|
|
||||||
[ unionModule spec ident unionFields ]
|
|
||||||
| _ -> failwithf "Only record types currently supported."
|
|
||||||
|
|
||||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
let info =
|
||||||
|
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||||
namespaceId,
|
|
||||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
)
|
namespaceId,
|
||||||
|
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
|
||||||
|
)
|
||||||
|
| _ -> failwithf "Not a record type"
|
||||||
|
|
||||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||||
/// containing a JSON serialization function.
|
/// containing a JSON serialization function.
|
||||||
@@ -400,20 +482,10 @@ type JsonSerializeGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let recordsAndUnions =
|
let records = Ast.extractRecords ast
|
||||||
Ast.extractTypeDefn ast
|
|
||||||
|> List.map (fun (name, defns) ->
|
|
||||||
defns
|
|
||||||
|> List.choose (fun defn ->
|
|
||||||
if Ast.isRecord defn then Some defn
|
|
||||||
elif Ast.isDu defn then Some defn
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|> fun defns -> name, defns
|
|
||||||
)
|
|
||||||
|
|
||||||
let namespaceAndTypes =
|
let namespaceAndRecords =
|
||||||
recordsAndUnions
|
records
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.choose (fun (ns, types) ->
|
||||||
types
|
types
|
||||||
|> List.choose (fun typeDef ->
|
|> List.choose (fun typeDef ->
|
||||||
@@ -443,10 +515,13 @@ type JsonSerializeGenerator () =
|
|||||||
let opens = AstHelper.extractOpens ast
|
let opens = AstHelper.extractOpens ast
|
||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
namespaceAndTypes
|
namespaceAndRecords
|
||||||
|> List.collect (fun (ns, types) ->
|
|> List.collect (fun (ns, records) ->
|
||||||
types
|
records
|
||||||
|> List.map (fun (ty, spec) -> JsonSerializeGenerator.createModule ns opens spec ty)
|
|> List.map (fun (record, spec) ->
|
||||||
|
let recordModule = JsonSerializeGenerator.createRecordModule ns opens spec record
|
||||||
|
recordModule
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Output.Ast modules
|
Output.Ast modules
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal Primitives =
|
|
||||||
/// Given e.g. "byte", returns "System.Byte".
|
|
||||||
let qualifyType (typeName : string) : LongIdent option =
|
|
||||||
match typeName with
|
|
||||||
| "float32"
|
|
||||||
| "single" -> [ "System" ; "Single" ] |> Some
|
|
||||||
| "float"
|
|
||||||
| "double" -> [ "System" ; "Double" ] |> Some
|
|
||||||
| "byte"
|
|
||||||
| "uint8" -> [ "System" ; "Byte" ] |> Some
|
|
||||||
| "sbyte"
|
|
||||||
| "int8" -> [ "System" ; "SByte" ] |> Some
|
|
||||||
| "int16" -> [ "System" ; "Int16" ] |> Some
|
|
||||||
| "int"
|
|
||||||
| "int32" -> [ "System" ; "Int32" ] |> Some
|
|
||||||
| "int64" -> [ "System" ; "Int64" ] |> Some
|
|
||||||
| "uint16" -> [ "System" ; "UInt16" ] |> Some
|
|
||||||
| "uint"
|
|
||||||
| "uint32" -> [ "System" ; "UInt32" ] |> Some
|
|
||||||
| "uint64" -> [ "System" ; "UInt64" ] |> Some
|
|
||||||
| "char" -> [ "System" ; "Char" ] |> Some
|
|
||||||
| "decimal" -> [ "System" ; "Decimal" ] |> Some
|
|
||||||
| _ -> None
|
|
||||||
|> Option.map (List.map (fun i -> (Ident (i, range0))))
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
|
open Myriad.Core
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal RemoveOptionsGenerator =
|
module internal RemoveOptionsGenerator =
|
||||||
@@ -45,7 +47,7 @@ module internal RemoveOptionsGenerator =
|
|||||||
(fields : SynField list)
|
(fields : SynField list)
|
||||||
=
|
=
|
||||||
let fields : SynField list = fields |> List.map removeOption
|
let fields : SynField list = fields |> List.map removeOption
|
||||||
let name = Ident.create "Short"
|
let name = Ident.Create "Short"
|
||||||
|
|
||||||
let record =
|
let record =
|
||||||
{
|
{
|
||||||
@@ -61,51 +63,92 @@ module internal RemoveOptionsGenerator =
|
|||||||
|
|
||||||
SynModuleDecl.Types ([ typeDecl ], range0)
|
SynModuleDecl.Types ([ typeDecl ], range0)
|
||||||
|
|
||||||
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynFieldData<Ident> list) =
|
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynField list) =
|
||||||
let xmlDoc = PreXmlDoc.create "Remove the optional members of the input."
|
let xmlDoc = PreXmlDoc.Create " Remove the optional members of the input."
|
||||||
|
|
||||||
let inputArg = Ident.create "input"
|
let returnInfo =
|
||||||
let functionName = Ident.create "shorten"
|
SynBindingReturnInfo.Create (SynType.LongIdent (SynLongIdent.CreateFromLongIdent withOptionsType))
|
||||||
|
|
||||||
|
let inputArg = Ident.Create "input"
|
||||||
|
let functionName = Ident.Create "shorten"
|
||||||
|
|
||||||
|
let inputVal =
|
||||||
|
SynValData.SynValData (
|
||||||
|
None,
|
||||||
|
SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty),
|
||||||
|
Some inputArg
|
||||||
|
)
|
||||||
|
|
||||||
let body =
|
let body =
|
||||||
fields
|
fields
|
||||||
|> List.map (fun fieldData ->
|
|> List.map (fun (SynField (_, _, id, fieldType, _, _, _, _, _)) ->
|
||||||
|
let id =
|
||||||
|
match id with
|
||||||
|
| None -> failwith "Expected record field to have an identifying name"
|
||||||
|
| Some id -> id
|
||||||
|
|
||||||
let accessor =
|
let accessor =
|
||||||
SynExpr.LongIdent (
|
SynExpr.LongIdent (false, SynLongIdent ([ inputArg ; id ], [ range0 ], []), None, range0)
|
||||||
false,
|
|
||||||
SynLongIdent ([ inputArg ; fieldData.Ident ], [ range0 ], []),
|
|
||||||
None,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
let body =
|
let body =
|
||||||
match fieldData.Type with
|
match fieldType with
|
||||||
| OptionType _ ->
|
| OptionType _ ->
|
||||||
accessor
|
SynExpr.CreateApp (
|
||||||
|> SynExpr.pipeThroughFunction (
|
SynExpr.CreateAppInfix (
|
||||||
SynExpr.applyFunction
|
SynExpr.LongIdent (
|
||||||
(SynExpr.createLongIdent [ "Option" ; "defaultWith" ])
|
false,
|
||||||
(SynExpr.createLongIdent' (
|
SynLongIdent.SynLongIdent (
|
||||||
withoutOptionsType
|
[ Ident.Create "op_PipeRight" ],
|
||||||
@ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ]
|
[],
|
||||||
))
|
[ Some (IdentTrivia.OriginalNotation "|>") ]
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
),
|
||||||
|
accessor
|
||||||
|
),
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.CreateString "Option.defaultWith"),
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent (
|
||||||
|
withoutOptionsType @ [ Ident.Create (sprintf "Default%s" id.idText) ]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
| _ -> accessor
|
| _ -> accessor
|
||||||
|
|
||||||
(SynLongIdent.createI fieldData.Ident, true), Some body
|
(SynLongIdent.CreateFromLongIdent [ id ], true), Some body
|
||||||
)
|
)
|
||||||
|> AstHelper.instantiateRecord
|
|> AstHelper.instantiateRecord
|
||||||
|
|
||||||
|
let pattern =
|
||||||
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ functionName ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Pats
|
||||||
|
[
|
||||||
|
SynPat.CreateTyped (
|
||||||
|
SynPat.CreateNamed inputArg,
|
||||||
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent withoutOptionsType)
|
||||||
|
)
|
||||||
|
|> SynPat.CreateParen
|
||||||
|
],
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
let binding =
|
let binding =
|
||||||
SynBinding.basic
|
SynBinding.Let (
|
||||||
[ functionName ]
|
isInline = false,
|
||||||
[
|
isMutable = false,
|
||||||
SynPat.named inputArg.idText
|
xmldoc = xmlDoc,
|
||||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create withoutOptionsType))
|
returnInfo = returnInfo,
|
||||||
]
|
expr = body,
|
||||||
body
|
valData = inputVal,
|
||||||
|> SynBinding.withXmlDoc xmlDoc
|
pattern = pattern
|
||||||
|> SynBinding.withReturnAnnotation (SynType.LongIdent (SynLongIdent.create withOptionsType))
|
)
|
||||||
|
|
||||||
SynModuleDecl.CreateLet [ binding ]
|
SynModuleDecl.CreateLet [ binding ]
|
||||||
|
|
||||||
@@ -117,35 +160,35 @@ module internal RemoveOptionsGenerator =
|
|||||||
synComponentInfo
|
synComponentInfo
|
||||||
|
|
||||||
match synTypeDefnRepr with
|
match synTypeDefnRepr with
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (accessibility, fields, _range), _) ->
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (accessibility, recordFields, _recordRange), _) ->
|
||||||
let fieldData = fields |> List.map SynField.extractWithIdent
|
|
||||||
|
|
||||||
let decls =
|
let decls =
|
||||||
[
|
[
|
||||||
createType (Some doc) accessibility typeParams fields
|
createType (Some doc) accessibility typeParams recordFields
|
||||||
createMaker [ Ident.create "Short" ] recordId fieldData
|
createMaker [ Ident.Create "Short" ] recordId recordFields
|
||||||
|
]
|
||||||
|
|
||||||
|
let attributes =
|
||||||
|
[
|
||||||
|
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||||
|
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||||
]
|
]
|
||||||
|
|
||||||
let xmlDoc =
|
let xmlDoc =
|
||||||
recordId
|
recordId
|
||||||
|> Seq.map (fun i -> i.idText)
|
|> Seq.map (fun i -> i.idText)
|
||||||
|> String.concat "."
|
|> String.concat "."
|
||||||
|> sprintf "Module containing an option-truncated version of the %s type"
|
|> sprintf " Module containing an option-truncated version of the %s type"
|
||||||
|> PreXmlDoc.create
|
|> PreXmlDoc.Create
|
||||||
|
|
||||||
let info =
|
let info =
|
||||||
SynComponentInfo.createLong recordId
|
SynComponentInfo.Create (recordId, attributes = attributes, xmldoc = xmlDoc)
|
||||||
|> SynComponentInfo.withDocString xmlDoc
|
|
||||||
|> SynComponentInfo.addAttributes [ SynAttribute.compilationRepresentation ]
|
|
||||||
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
|
|
||||||
|
|
||||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||||
| _ -> failwithf "Not a record type"
|
| _ -> failwithf "Not a record type"
|
||||||
|
|
||||||
open Myriad.Core
|
|
||||||
|
|
||||||
/// Myriad generator that stamps out a record with option types stripped
|
/// Myriad generator that stamps out a record with option types stripped
|
||||||
/// from the fields at the top level.
|
/// from the fields at the top level.
|
||||||
[<MyriadGenerator("remove-options")>]
|
[<MyriadGenerator("remove-options")>]
|
||||||
|
|||||||
31
WoofWare.Myriad.Plugins/SynAttribute.fs
Normal file
31
WoofWare.Myriad.Plugins/SynAttribute.fs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.Syntax
|
||||||
|
open Fantomas.FCS.Text.Range
|
||||||
|
open Myriad.Core
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynAttribute =
|
||||||
|
let internal compilationRepresentation : SynAttribute =
|
||||||
|
{
|
||||||
|
TypeName = SynLongIdent.CreateString "CompilationRepresentation"
|
||||||
|
ArgExpr =
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
false,
|
||||||
|
SynLongIdent.Create [ "CompilationRepresentationFlags" ; "ModuleSuffix" ],
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
Target = None
|
||||||
|
AppliesToGetterAndSetter = false
|
||||||
|
Range = range0
|
||||||
|
}
|
||||||
|
|
||||||
|
let internal autoOpen : SynAttribute =
|
||||||
|
{
|
||||||
|
TypeName = SynLongIdent.CreateString "AutoOpen"
|
||||||
|
ArgExpr = SynExpr.CreateConst SynConst.Unit
|
||||||
|
Target = None
|
||||||
|
AppliesToGetterAndSetter = false
|
||||||
|
Range = range0
|
||||||
|
}
|
||||||
313
WoofWare.Myriad.Plugins/SynExpr.fs
Normal file
313
WoofWare.Myriad.Plugins/SynExpr.fs
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.Syntax
|
||||||
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
|
open Myriad.Core
|
||||||
|
open Myriad.Core.Ast
|
||||||
|
open Fantomas.FCS.Text.Range
|
||||||
|
|
||||||
|
type internal CompExprBinding =
|
||||||
|
| LetBang of varName : string * rhs : SynExpr
|
||||||
|
| Let of varName : string * rhs : SynExpr
|
||||||
|
| Use of varName : string * rhs : SynExpr
|
||||||
|
| Do of body : SynExpr
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynExpr =
|
||||||
|
|
||||||
|
/// {expr} |> {func}
|
||||||
|
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
[ Ident.Create "op_PipeRight" ],
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation "|>") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
expr
|
||||||
|
),
|
||||||
|
func
|
||||||
|
)
|
||||||
|
|
||||||
|
/// if {cond} then {trueBranch} else {falseBranch}
|
||||||
|
/// Note that this function puts the trueBranch last, for pipelining convenience:
|
||||||
|
/// we assume that the `else` branch is more like an error case and is less interesting.
|
||||||
|
let ifThenElse (cond : SynExpr) (falseBranch : SynExpr) (trueBranch : SynExpr) : SynExpr =
|
||||||
|
SynExpr.IfThenElse (
|
||||||
|
cond,
|
||||||
|
trueBranch,
|
||||||
|
Some falseBranch,
|
||||||
|
DebugPointAtBinding.Yes range0,
|
||||||
|
false,
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
IfKeyword = range0
|
||||||
|
IsElif = false
|
||||||
|
ThenKeyword = range0
|
||||||
|
ElseKeyword = Some range0
|
||||||
|
IfToThenRange = range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/// try {body} with | {exc} as exc -> {handler}
|
||||||
|
let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr =
|
||||||
|
let clause =
|
||||||
|
SynMatchClause.Create (SynPat.As (exc, SynPat.CreateNamed (Ident.Create "exc"), range0), None, handler)
|
||||||
|
|
||||||
|
SynExpr.TryWith (
|
||||||
|
body,
|
||||||
|
[ clause ],
|
||||||
|
range0,
|
||||||
|
DebugPointAtTry.Yes range0,
|
||||||
|
DebugPointAtWith.Yes range0,
|
||||||
|
{
|
||||||
|
TryKeyword = range0
|
||||||
|
TryToWithRange = range0
|
||||||
|
WithKeyword = range0
|
||||||
|
WithToEndRange = range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/// {a} = {b}
|
||||||
|
let equals (a : SynExpr) (b : SynExpr) =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
Ident.CreateLong "op_Equality",
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation "=") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
a
|
||||||
|
),
|
||||||
|
b
|
||||||
|
)
|
||||||
|
|
||||||
|
/// {a} + {b}
|
||||||
|
let plus (a : SynExpr) (b : SynExpr) =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
Ident.CreateLong "op_Addition",
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation "+") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
a
|
||||||
|
),
|
||||||
|
b
|
||||||
|
)
|
||||||
|
|
||||||
|
let rec stripOptionalParen (expr : SynExpr) : SynExpr =
|
||||||
|
match expr with
|
||||||
|
| 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 (
|
||||||
|
SynExpr.DotGet (
|
||||||
|
obj,
|
||||||
|
range0,
|
||||||
|
SynLongIdent.SynLongIdent (id = [ Ident.Create meth ], dotRanges = [], trivia = [ None ]),
|
||||||
|
range0
|
||||||
|
),
|
||||||
|
arg
|
||||||
|
)
|
||||||
|
|
||||||
|
/// {obj}.{meth}()
|
||||||
|
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
||||||
|
callMethodArg meth (SynExpr.CreateConst SynConst.Unit) obj
|
||||||
|
|
||||||
|
/// {obj}.{meth}<ty>()
|
||||||
|
let callGenericMethod (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.TypeApp (
|
||||||
|
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||||
|
range0,
|
||||||
|
[ SynType.CreateLongIdent ty ],
|
||||||
|
[],
|
||||||
|
Some range0,
|
||||||
|
range0,
|
||||||
|
range0
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
|
||||||
|
let index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
||||||
|
SynExpr.DotIndexedGet (obj, property, range0, range0)
|
||||||
|
|
||||||
|
/// (fun {varName} -> {body})
|
||||||
|
let createLambda (varName : string) (body : SynExpr) : SynExpr =
|
||||||
|
let parsedDataPat = [ SynPat.CreateNamed (Ident.Create varName) ]
|
||||||
|
|
||||||
|
SynExpr.Lambda (
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
SynSimplePats.Create [ SynSimplePat.CreateId (Ident.Create varName) ],
|
||||||
|
body,
|
||||||
|
Some (parsedDataPat, body),
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
ArrowRange = Some range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
|
let reraise : SynExpr =
|
||||||
|
SynExpr.CreateApp (SynExpr.CreateIdent (Ident.Create "reraise"), SynExpr.CreateConst SynConst.Unit)
|
||||||
|
|
||||||
|
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
|
||||||
|
let startAsTask (ct : SynLongIdent) (body : SynExpr) =
|
||||||
|
let lambda =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "StartAsTask" ]),
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.CreateString "a")
|
||||||
|
equals
|
||||||
|
(SynExpr.LongIdent (true, SynLongIdent.CreateString "cancellationToken", None, range0))
|
||||||
|
(SynExpr.CreateLongIdent ct)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|> createLambda "a"
|
||||||
|
|
||||||
|
pipeThroughFunction lambda body
|
||||||
|
|
||||||
|
/// {compExpr} { {lets} ; return {ret} }
|
||||||
|
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
|
||||||
|
let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0)
|
||||||
|
|
||||||
|
let contents : SynExpr =
|
||||||
|
(retStatement, List.rev lets)
|
||||||
|
||> List.fold (fun state binding ->
|
||||||
|
match binding with
|
||||||
|
| LetBang (lhs, rhs) ->
|
||||||
|
SynExpr.LetOrUseBang (
|
||||||
|
DebugPointAtBinding.Yes range0,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
SynPat.CreateNamed (Ident.Create lhs),
|
||||||
|
rhs,
|
||||||
|
[],
|
||||||
|
state,
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
EqualsRange = Some range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
| Let (lhs, rhs) ->
|
||||||
|
SynExpr.LetOrUse (
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ],
|
||||||
|
state,
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
SynExprLetOrUseTrivia.InKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
| Use (lhs, rhs) ->
|
||||||
|
SynExpr.LetOrUse (
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
[ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ],
|
||||||
|
state,
|
||||||
|
range0,
|
||||||
|
{
|
||||||
|
SynExprLetOrUseTrivia.InKeyword = None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
| Do body -> SynExpr.CreateSequential [ SynExpr.Do (body, range0) ; state ]
|
||||||
|
)
|
||||||
|
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateIdent (Ident.Create compExpr),
|
||||||
|
SynExpr.ComputationExpr (false, contents, range0)
|
||||||
|
)
|
||||||
|
|
||||||
|
/// {expr} |> Async.AwaitTask
|
||||||
|
let awaitTask (expr : SynExpr) : SynExpr =
|
||||||
|
expr
|
||||||
|
|> pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "AwaitTask" ]))
|
||||||
|
|
||||||
|
/// {ident}.ToString ()
|
||||||
|
/// with special casing for some types like DateTime
|
||||||
|
let toString (ty : SynType) (ident : SynExpr) =
|
||||||
|
match ty with
|
||||||
|
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-dd")
|
||||||
|
| DateTime ->
|
||||||
|
ident
|
||||||
|
|> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-ddTHH:mm:ss")
|
||||||
|
| _ -> callMethod "ToString" ident
|
||||||
|
|
||||||
|
let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0)
|
||||||
|
|
||||||
|
let synBindingTriviaZero (isMember : bool) =
|
||||||
|
{
|
||||||
|
SynBindingTrivia.EqualsRange = Some range0
|
||||||
|
InlineKeyword = None
|
||||||
|
LeadingKeyword =
|
||||||
|
if isMember then
|
||||||
|
SynLeadingKeyword.Member range0
|
||||||
|
else
|
||||||
|
SynLeadingKeyword.Let range0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {ident} - {rhs}
|
||||||
|
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
[ Ident.Create "op_Subtraction" ],
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation "-") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SynExpr.CreateLongIdent ident
|
||||||
|
),
|
||||||
|
rhs
|
||||||
|
)
|
||||||
|
|
||||||
|
/// {ident} - {n}
|
||||||
|
let minusN (ident : SynLongIdent) (n : int) : SynExpr =
|
||||||
|
minus ident (SynExpr.CreateConst (SynConst.Int32 n))
|
||||||
|
|
||||||
|
/// {y} > {x}
|
||||||
|
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
[ Ident.Create "op_GreaterThan" ],
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation ">") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
y
|
||||||
|
),
|
||||||
|
x
|
||||||
|
)
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
type internal CompExprBinding =
|
|
||||||
| LetBang of varName : string * rhs : SynExpr
|
|
||||||
| Let of varName : string * rhs : SynExpr
|
|
||||||
| Use of varName : string * rhs : SynExpr
|
|
||||||
| Do of body : SynExpr
|
|
||||||
|
|
||||||
(*
|
|
||||||
Potential API!
|
|
||||||
type internal CompExprBindings =
|
|
||||||
private
|
|
||||||
{
|
|
||||||
/// These are stored in reverse.
|
|
||||||
Bindings : CompExprBinding list
|
|
||||||
CompExprName : string
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal CompExprBindings =
|
|
||||||
let make (name : string) : CompExprBindings =
|
|
||||||
{
|
|
||||||
Bindings = []
|
|
||||||
CompExprName = name
|
|
||||||
}
|
|
||||||
|
|
||||||
let thenDo (body : SynExpr) (bindings : CompExprBindings) =
|
|
||||||
{ bindings with
|
|
||||||
Bindings = (Do body :: bindings.Bindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
let thenLet (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
|
||||||
{ bindings with
|
|
||||||
Bindings = (Let (varName, value) :: bindings.Bindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
let thenLetBang (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
|
||||||
{ bindings with
|
|
||||||
Bindings = (LetBang (varName, value) :: bindings.Bindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let thenUse (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
|
||||||
{ bindings with
|
|
||||||
Bindings = (LetBang (varName, value) :: bindings.Bindings)
|
|
||||||
}
|
|
||||||
*)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal PreXmlDoc =
|
|
||||||
let create (s : string) : PreXmlDoc =
|
|
||||||
PreXmlDoc.Create ([| " " + s |], range0)
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynArgPats =
|
|
||||||
let create (caseNames : Ident list) : SynArgPats =
|
|
||||||
if caseNames.IsEmpty then
|
|
||||||
SynArgPats.Pats []
|
|
||||||
else
|
|
||||||
|
|
||||||
caseNames
|
|
||||||
|> List.map (fun i -> SynPat.named i.idText)
|
|
||||||
|> SynPat.tuple
|
|
||||||
|> List.singleton
|
|
||||||
|> SynArgPats.Pats
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynAttribute =
|
|
||||||
let internal compilationRepresentation : SynAttribute =
|
|
||||||
{
|
|
||||||
TypeName = SynLongIdent.createS "CompilationRepresentation"
|
|
||||||
ArgExpr =
|
|
||||||
[ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
|
|
||||||
|> SynExpr.createLongIdent
|
|
||||||
|> SynExpr.paren
|
|
||||||
Target = None
|
|
||||||
AppliesToGetterAndSetter = false
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
|
|
||||||
let internal requireQualifiedAccess : SynAttribute =
|
|
||||||
{
|
|
||||||
TypeName = SynLongIdent.createS "RequireQualifiedAccess"
|
|
||||||
ArgExpr = SynExpr.CreateConst ()
|
|
||||||
Target = None
|
|
||||||
AppliesToGetterAndSetter = false
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
|
|
||||||
let internal autoOpen : SynAttribute =
|
|
||||||
{
|
|
||||||
TypeName = SynLongIdent.createS "AutoOpen"
|
|
||||||
ArgExpr = SynExpr.CreateConst ()
|
|
||||||
Target = None
|
|
||||||
AppliesToGetterAndSetter = false
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynBinding =
|
|
||||||
|
|
||||||
let rec private stripParen (pat : SynPat) =
|
|
||||||
match pat with
|
|
||||||
| SynPat.Paren (p, _) -> stripParen p
|
|
||||||
| _ -> pat
|
|
||||||
|
|
||||||
let rec private getName (pat : SynPat) : Ident option =
|
|
||||||
match stripParen pat with
|
|
||||||
| SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name
|
|
||||||
| SynPat.Wild _ -> None
|
|
||||||
| SynPat.Typed (pat, _, _) -> getName pat
|
|
||||||
| SynPat.Const _ -> None
|
|
||||||
| SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) ->
|
|
||||||
match longIdent with
|
|
||||||
| [ x ] -> Some x
|
|
||||||
| _ -> failwithf "got long ident %O ; can only get the name of a long ident with one component" longIdent
|
|
||||||
| _ -> failwithf "unrecognised pattern: %+A" pat
|
|
||||||
|
|
||||||
let triviaZero (isMember : bool) =
|
|
||||||
{
|
|
||||||
SynBindingTrivia.EqualsRange = Some range0
|
|
||||||
InlineKeyword = None
|
|
||||||
LeadingKeyword =
|
|
||||||
if isMember then
|
|
||||||
SynLeadingKeyword.Member range0
|
|
||||||
else
|
|
||||||
SynLeadingKeyword.Let range0
|
|
||||||
}
|
|
||||||
|
|
||||||
let basic (name : LongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
|
|
||||||
let valInfo : SynValInfo =
|
|
||||||
args
|
|
||||||
|> List.map (fun pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ])
|
|
||||||
|> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None))
|
|
||||||
|
|
||||||
SynBinding.SynBinding (
|
|
||||||
None,
|
|
||||||
SynBindingKind.Normal,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
[],
|
|
||||||
PreXmlDoc.Empty,
|
|
||||||
SynValData.SynValData (None, valInfo, None),
|
|
||||||
SynPat.identWithArgs name (SynArgPats.Pats args),
|
|
||||||
None,
|
|
||||||
body,
|
|
||||||
range0,
|
|
||||||
DebugPointAtBinding.Yes range0,
|
|
||||||
triviaZero false
|
|
||||||
)
|
|
||||||
|
|
||||||
let withAccessibility (acc : SynAccess option) (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (_, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
|
||||||
let headPat =
|
|
||||||
match headPat with
|
|
||||||
| SynPat.LongIdent (ident, extra, options, argPats, _, range) ->
|
|
||||||
SynPat.LongIdent (ident, extra, options, argPats, acc, range)
|
|
||||||
| _ -> failwithf "unrecognised head pattern: %O" headPat
|
|
||||||
|
|
||||||
SynBinding (acc, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
|
|
||||||
|
|
||||||
let withXmlDoc (doc : PreXmlDoc) (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (acc, kind, inl, mut, attrs, _, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
|
||||||
SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
|
|
||||||
|
|
||||||
let withReturnAnnotation (ty : SynType) (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, _, expr, range, debugPoint, trivia) ->
|
|
||||||
let retInfo =
|
|
||||||
SynBindingReturnInfo.SynBindingReturnInfo (
|
|
||||||
ty,
|
|
||||||
range0,
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
ColonRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
SynBinding (
|
|
||||||
acc,
|
|
||||||
kind,
|
|
||||||
inl,
|
|
||||||
mut,
|
|
||||||
attrs,
|
|
||||||
doc,
|
|
||||||
valData,
|
|
||||||
headPat,
|
|
||||||
Some retInfo,
|
|
||||||
expr,
|
|
||||||
range,
|
|
||||||
debugPoint,
|
|
||||||
trivia
|
|
||||||
)
|
|
||||||
|
|
||||||
let makeInline (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
|
||||||
SynBinding (
|
|
||||||
acc,
|
|
||||||
kind,
|
|
||||||
true,
|
|
||||||
mut,
|
|
||||||
attrs,
|
|
||||||
doc,
|
|
||||||
valData,
|
|
||||||
headPat,
|
|
||||||
ret,
|
|
||||||
expr,
|
|
||||||
range,
|
|
||||||
debugPoint,
|
|
||||||
{ trivia with
|
|
||||||
InlineKeyword = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let makeStaticMember (binding : SynBinding) : SynBinding =
|
|
||||||
let memberFlags =
|
|
||||||
{
|
|
||||||
SynMemberFlags.IsInstance = false
|
|
||||||
SynMemberFlags.IsDispatchSlot = false
|
|
||||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
|
||||||
SynMemberFlags.IsFinal = false
|
|
||||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
|
||||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
|
||||||
}
|
|
||||||
|
|
||||||
match binding with
|
|
||||||
| SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
|
||||||
let valData =
|
|
||||||
match valData with
|
|
||||||
| SynValData.SynValData (_, valInfo, _) -> SynValData.SynValData (Some memberFlags, valInfo, None)
|
|
||||||
|
|
||||||
let trivia =
|
|
||||||
{ trivia with
|
|
||||||
LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0)
|
|
||||||
}
|
|
||||||
|
|
||||||
SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia)
|
|
||||||
|
|
||||||
let makeInstanceMember (binding : SynBinding) : SynBinding =
|
|
||||||
let memberFlags =
|
|
||||||
{
|
|
||||||
SynMemberFlags.IsInstance = true
|
|
||||||
SynMemberFlags.IsDispatchSlot = false
|
|
||||||
SynMemberFlags.IsOverrideOrExplicitImpl = true
|
|
||||||
SynMemberFlags.IsFinal = false
|
|
||||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
|
||||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
|
||||||
}
|
|
||||||
|
|
||||||
match binding with
|
|
||||||
| SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
|
||||||
let valData =
|
|
||||||
match valData with
|
|
||||||
| SynValData.SynValData (_, valInfo, _) -> SynValData.SynValData (Some memberFlags, valInfo, None)
|
|
||||||
|
|
||||||
let trivia =
|
|
||||||
{ trivia with
|
|
||||||
LeadingKeyword = SynLeadingKeyword.Member range0
|
|
||||||
}
|
|
||||||
|
|
||||||
SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia)
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynComponentInfo =
|
|
||||||
let inline createLong (name : LongIdent) =
|
|
||||||
SynComponentInfo.SynComponentInfo ([], None, [], name, PreXmlDoc.Empty, false, None, range0)
|
|
||||||
|
|
||||||
let inline create (name : Ident) = createLong [ name ]
|
|
||||||
|
|
||||||
let inline withDocString (doc : PreXmlDoc) (i : SynComponentInfo) : SynComponentInfo =
|
|
||||||
match i with
|
|
||||||
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, _, postfix, access, range) ->
|
|
||||||
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
|
|
||||||
|
|
||||||
let inline setGenerics (typars : SynTyparDecls option) (i : SynComponentInfo) : SynComponentInfo =
|
|
||||||
match i with
|
|
||||||
| SynComponentInfo.SynComponentInfo (attrs, _, constraints, name, doc, postfix, access, range) ->
|
|
||||||
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
|
|
||||||
|
|
||||||
let inline withGenerics (typars : SynTyparDecl list) (i : SynComponentInfo) : SynComponentInfo =
|
|
||||||
let inner =
|
|
||||||
if typars.IsEmpty then
|
|
||||||
None
|
|
||||||
else
|
|
||||||
Some (SynTyparDecls.PostfixList (typars, [], range0))
|
|
||||||
|
|
||||||
setGenerics inner i
|
|
||||||
|
|
||||||
let inline setAccessibility (acc : SynAccess option) (i : SynComponentInfo) : SynComponentInfo =
|
|
||||||
match i with
|
|
||||||
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, _, range) ->
|
|
||||||
SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, acc, range)
|
|
||||||
|
|
||||||
let inline withAccessibility (acc : SynAccess) (i : SynComponentInfo) : SynComponentInfo =
|
|
||||||
setAccessibility (Some acc) i
|
|
||||||
|
|
||||||
let inline addAttributes (attrs : SynAttribute list) (i : SynComponentInfo) : SynComponentInfo =
|
|
||||||
match i with
|
|
||||||
| SynComponentInfo.SynComponentInfo (oldAttrs, typars, constraints, name, doc, postfix, acc, range) ->
|
|
||||||
let attrs =
|
|
||||||
{
|
|
||||||
SynAttributeList.Attributes = attrs
|
|
||||||
SynAttributeList.Range = range0
|
|
||||||
}
|
|
||||||
|
|
||||||
SynComponentInfo.SynComponentInfo ((attrs :: oldAttrs), typars, constraints, name, doc, postfix, acc, range)
|
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Myriad.Core
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<AutoOpen>]
|
|
||||||
module internal SynExprExtensions =
|
|
||||||
type SynExpr with
|
|
||||||
static member CreateConst (s : string) : SynExpr =
|
|
||||||
SynExpr.Const (SynConst.String (s, SynStringKind.Regular, range0), range0)
|
|
||||||
|
|
||||||
static member CreateConst () : SynExpr = SynExpr.Const (SynConst.Unit, range0)
|
|
||||||
|
|
||||||
static member CreateConst (i : int32) : SynExpr =
|
|
||||||
SynExpr.Const (SynConst.Int32 i, range0)
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynExpr =
|
|
||||||
|
|
||||||
/// {f} {x}
|
|
||||||
let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
|
|
||||||
|
|
||||||
/// {f} {x}
|
|
||||||
let inline applyTo (x : SynExpr) (f : SynExpr) : SynExpr = applyFunction f x
|
|
||||||
|
|
||||||
/// {expr} |> {func}
|
|
||||||
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
|
|
||||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.pipe, expr)
|
|
||||||
|> applyTo func
|
|
||||||
|
|
||||||
/// if {cond} then {trueBranch} else {falseBranch}
|
|
||||||
/// Note that this function puts the trueBranch last, for pipelining convenience:
|
|
||||||
/// we assume that the `else` branch is more like an error case and is less interesting.
|
|
||||||
let ifThenElse (cond : SynExpr) (falseBranch : SynExpr) (trueBranch : SynExpr) : SynExpr =
|
|
||||||
SynExpr.IfThenElse (
|
|
||||||
cond,
|
|
||||||
trueBranch,
|
|
||||||
Some falseBranch,
|
|
||||||
DebugPointAtBinding.Yes range0,
|
|
||||||
false,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
IfKeyword = range0
|
|
||||||
IsElif = false
|
|
||||||
ThenKeyword = range0
|
|
||||||
ElseKeyword = Some range0
|
|
||||||
IfToThenRange = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/// try {body} with | {exc} as exc -> {handler}
|
|
||||||
let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr =
|
|
||||||
let clause =
|
|
||||||
SynMatchClause.create (SynPat.As (exc, SynPat.named "exc", range0)) handler
|
|
||||||
|
|
||||||
SynExpr.TryWith (
|
|
||||||
body,
|
|
||||||
[ clause ],
|
|
||||||
range0,
|
|
||||||
DebugPointAtTry.Yes range0,
|
|
||||||
DebugPointAtWith.Yes range0,
|
|
||||||
{
|
|
||||||
TryKeyword = range0
|
|
||||||
TryToWithRange = range0
|
|
||||||
WithKeyword = range0
|
|
||||||
WithToEndRange = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
/// {a} = {b}
|
|
||||||
let equals (a : SynExpr) (b : SynExpr) =
|
|
||||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.eq, a) |> applyTo b
|
|
||||||
|
|
||||||
/// {a} + {b}
|
|
||||||
let plus (a : SynExpr) (b : SynExpr) =
|
|
||||||
SynExpr.CreateAppInfix (
|
|
||||||
SynExpr.CreateLongIdent (
|
|
||||||
SynLongIdent.SynLongIdent (
|
|
||||||
Ident.CreateLong "op_Addition",
|
|
||||||
[],
|
|
||||||
[ Some (IdentTrivia.OriginalNotation "+") ]
|
|
||||||
)
|
|
||||||
),
|
|
||||||
a
|
|
||||||
)
|
|
||||||
|> applyTo b
|
|
||||||
|
|
||||||
let rec stripOptionalParen (expr : SynExpr) : SynExpr =
|
|
||||||
match expr with
|
|
||||||
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr
|
|
||||||
| expr -> expr
|
|
||||||
|
|
||||||
/// {obj}.{meth} {arg}
|
|
||||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotGet (
|
|
||||||
obj,
|
|
||||||
range0,
|
|
||||||
SynLongIdent.SynLongIdent (id = [ Ident.create meth ], dotRanges = [], trivia = [ None ]),
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|> applyTo arg
|
|
||||||
|
|
||||||
/// {obj}.{meth}()
|
|
||||||
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
|
||||||
callMethodArg meth (SynExpr.CreateConst ()) obj
|
|
||||||
|
|
||||||
let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.TypeApp (
|
|
||||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
|
|
||||||
range0,
|
|
||||||
[ SynType.LongIdent (SynLongIdent.create ty) ],
|
|
||||||
[],
|
|
||||||
Some range0,
|
|
||||||
range0,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|> applyTo (SynExpr.CreateConst ())
|
|
||||||
|
|
||||||
/// {obj}.{meth}<ty>()
|
|
||||||
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.TypeApp (
|
|
||||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
|
|
||||||
range0,
|
|
||||||
[ SynType.createLongIdent' [ ty ] ],
|
|
||||||
[],
|
|
||||||
Some range0,
|
|
||||||
range0,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|> applyTo (SynExpr.CreateConst ())
|
|
||||||
|
|
||||||
let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotIndexedGet (obj, property, range0, range0)
|
|
||||||
|
|
||||||
let inline paren (e : SynExpr) : SynExpr =
|
|
||||||
SynExpr.Paren (e, range0, Some range0, range0)
|
|
||||||
|
|
||||||
/// (fun {varName} -> {body})
|
|
||||||
let createLambda (varName : string) (body : SynExpr) : SynExpr =
|
|
||||||
let parsedDataPat = [ SynPat.named varName ]
|
|
||||||
|
|
||||||
SynExpr.Lambda (
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
SynSimplePats.Create [ SynSimplePat.CreateId (Ident.Create varName) ],
|
|
||||||
body,
|
|
||||||
Some (parsedDataPat, body),
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
ArrowRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> paren
|
|
||||||
|
|
||||||
let createThunk (body : SynExpr) : SynExpr =
|
|
||||||
SynExpr.Lambda (
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
SynSimplePats.Create [],
|
|
||||||
body,
|
|
||||||
Some ([ SynPat.unit ], body),
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
ArrowRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> paren
|
|
||||||
|
|
||||||
let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0))
|
|
||||||
|
|
||||||
let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i
|
|
||||||
|
|
||||||
let inline createLongIdent' (ident : Ident list) : SynExpr =
|
|
||||||
SynExpr.LongIdent (false, SynLongIdent.create ident, None, range0)
|
|
||||||
|
|
||||||
let inline createLongIdent (ident : string list) : SynExpr =
|
|
||||||
createLongIdent' (ident |> List.map Ident.create)
|
|
||||||
|
|
||||||
let tupleNoParen (args : SynExpr list) : SynExpr =
|
|
||||||
SynExpr.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
|
||||||
|
|
||||||
let inline tuple (args : SynExpr list) = args |> tupleNoParen |> paren
|
|
||||||
|
|
||||||
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
|
|
||||||
let startAsTask (ct : Ident) (body : SynExpr) =
|
|
||||||
let lambda =
|
|
||||||
[
|
|
||||||
createIdent "a"
|
|
||||||
equals
|
|
||||||
(SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
|
|
||||||
(createIdent' ct)
|
|
||||||
]
|
|
||||||
|> tuple
|
|
||||||
|> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ])
|
|
||||||
|> createLambda "a"
|
|
||||||
|
|
||||||
pipeThroughFunction lambda body
|
|
||||||
|
|
||||||
let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
|
|
||||||
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty)
|
|
||||||
|
|
||||||
let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr =
|
|
||||||
SynExpr.Match (
|
|
||||||
DebugPointAtBinding.Yes range0,
|
|
||||||
matchOn,
|
|
||||||
cases,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
MatchKeyword = range0
|
|
||||||
WithKeyword = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.Typed (expr, ty, range0)
|
|
||||||
|
|
||||||
let inline createNew (ty : SynType) (args : SynExpr) : SynExpr =
|
|
||||||
SynExpr.New (false, ty, paren args, range0)
|
|
||||||
|
|
||||||
let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr =
|
|
||||||
SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0)
|
|
||||||
|
|
||||||
let inline createNull () : SynExpr = SynExpr.Null range0
|
|
||||||
|
|
||||||
let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ())
|
|
||||||
|
|
||||||
let sequential (exprs : SynExpr list) : SynExpr =
|
|
||||||
exprs
|
|
||||||
|> List.reduce (fun a b -> SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, a, b, range0))
|
|
||||||
|
|
||||||
/// {compExpr} { {lets} ; return {ret} }
|
|
||||||
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
|
|
||||||
let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0)
|
|
||||||
|
|
||||||
let contents : SynExpr =
|
|
||||||
(retStatement, List.rev lets)
|
|
||||||
||> List.fold (fun state binding ->
|
|
||||||
match binding with
|
|
||||||
| LetBang (lhs, rhs) ->
|
|
||||||
SynExpr.LetOrUseBang (
|
|
||||||
DebugPointAtBinding.Yes range0,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
SynPat.named lhs,
|
|
||||||
rhs,
|
|
||||||
[],
|
|
||||||
state,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
EqualsRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
| Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state
|
|
||||||
| Use (lhs, rhs) ->
|
|
||||||
SynExpr.LetOrUse (
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
[ SynBinding.basic [ Ident.create lhs ] [] rhs ],
|
|
||||||
state,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
SynExprLetOrUseTrivia.InKeyword = None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
| Do body -> sequential [ SynExpr.Do (body, range0) ; state ]
|
|
||||||
)
|
|
||||||
|
|
||||||
applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0))
|
|
||||||
|
|
||||||
/// {expr} |> Async.AwaitTask
|
|
||||||
let awaitTask (expr : SynExpr) : SynExpr =
|
|
||||||
expr |> pipeThroughFunction (createLongIdent [ "Async" ; "AwaitTask" ])
|
|
||||||
|
|
||||||
/// {ident}.ToString ()
|
|
||||||
/// with special casing for some types like DateTime
|
|
||||||
let toString (ty : SynType) (ident : SynExpr) =
|
|
||||||
match ty with
|
|
||||||
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-dd")
|
|
||||||
| DateTime -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-ddTHH:mm:ss")
|
|
||||||
| _ -> callMethod "ToString" ident
|
|
||||||
|
|
||||||
let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0)
|
|
||||||
|
|
||||||
/// {ident} - {rhs}
|
|
||||||
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
|
|
||||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.sub, SynExpr.CreateLongIdent ident)
|
|
||||||
|> applyTo rhs
|
|
||||||
|
|
||||||
/// {ident} - {n}
|
|
||||||
let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n)
|
|
||||||
|
|
||||||
/// {y} > {x}
|
|
||||||
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
|
|
||||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.ge, y) |> applyTo x
|
|
||||||
|
|
||||||
/// {y} >= {x}
|
|
||||||
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
|
||||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.geq, y)
|
|
||||||
|> applyTo x
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynExprLetOrUseTrivia =
|
|
||||||
let empty : SynExprLetOrUseTrivia =
|
|
||||||
{
|
|
||||||
InKeyword = None
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
type internal SynFieldData<'Ident> =
|
|
||||||
{
|
|
||||||
Attrs : SynAttribute list
|
|
||||||
Ident : 'Ident
|
|
||||||
Type : SynType
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynField =
|
|
||||||
/// Get the useful information out of a SynField.
|
|
||||||
let extract (SynField (attrs, _, id, fieldType, _, _, _, _, _)) : SynFieldData<Ident option> =
|
|
||||||
{
|
|
||||||
Attrs = attrs |> List.collect (fun l -> l.Attributes)
|
|
||||||
Ident = id
|
|
||||||
Type = fieldType
|
|
||||||
}
|
|
||||||
|
|
||||||
let mapIdent<'a, 'b> (f : 'a -> 'b) (x : SynFieldData<'a>) : SynFieldData<'b> =
|
|
||||||
let ident = f x.Ident
|
|
||||||
|
|
||||||
{
|
|
||||||
Attrs = x.Attrs
|
|
||||||
Ident = ident
|
|
||||||
Type = x.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Throws if the field has no identifier.
|
|
||||||
let extractWithIdent (f : SynField) : SynFieldData<Ident> =
|
|
||||||
f
|
|
||||||
|> extract
|
|
||||||
|> mapIdent (fun ident ->
|
|
||||||
match ident with
|
|
||||||
| None -> failwith "expected field identifier to have a value, but it did not"
|
|
||||||
| Some i -> i
|
|
||||||
)
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynLongIdent =
|
|
||||||
|
|
||||||
let geq =
|
|
||||||
SynLongIdent.SynLongIdent (
|
|
||||||
[ Ident.create "op_GreaterThanOrEqual" ],
|
|
||||||
[],
|
|
||||||
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
|
||||||
)
|
|
||||||
|
|
||||||
let ge =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ Some (IdentTrivia.OriginalNotation ">") ])
|
|
||||||
|
|
||||||
let sub =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Subtraction" ], [], [ Some (IdentTrivia.OriginalNotation "-") ])
|
|
||||||
|
|
||||||
let eq =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Equality" ], [], [ Some (IdentTrivia.OriginalNotation "=") ])
|
|
||||||
|
|
||||||
let pipe =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_PipeRight" ], [], [ Some (IdentTrivia.OriginalNotation "|>") ])
|
|
||||||
|
|
||||||
let toString (sli : SynLongIdent) : string =
|
|
||||||
sli.LongIdent |> List.map _.idText |> String.concat "."
|
|
||||||
|
|
||||||
let create (ident : LongIdent) : SynLongIdent =
|
|
||||||
let commas =
|
|
||||||
match ident with
|
|
||||||
| [] -> []
|
|
||||||
| _ :: commas -> commas |> List.map (fun _ -> range0)
|
|
||||||
|
|
||||||
SynLongIdent.SynLongIdent (ident, commas, List.replicate ident.Length None)
|
|
||||||
|
|
||||||
let inline createI (i : Ident) : SynLongIdent = create [ i ]
|
|
||||||
|
|
||||||
let inline createS (s : string) : SynLongIdent = createI (Ident (s, range0))
|
|
||||||
|
|
||||||
let inline createS' (s : string list) : SynLongIdent =
|
|
||||||
create (s |> List.map (fun i -> Ident (i, range0)))
|
|
||||||
|
|
||||||
let isUnit (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isList (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
|
||||||
// TODO: consider FSharpList or whatever it is
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isArray (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] when
|
|
||||||
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|
|
||||||
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
|
|
||||||
->
|
|
||||||
true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isOption (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
|
|
||||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isResponse (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "Response" ]
|
|
||||||
| [ "RestEase" ; "Response" ] -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isMap (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "Map" ] -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isReadOnlyDictionary (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "IReadOnlyDictionary" ]
|
|
||||||
| [ "Generic" ; "IReadOnlyDictionary" ]
|
|
||||||
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
|
|
||||||
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isDictionary (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "Dictionary" ]
|
|
||||||
| [ "Generic" ; "Dictionary" ]
|
|
||||||
| [ "Collections" ; "Generic" ; "Dictionary" ]
|
|
||||||
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isIDictionary (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "IDictionary" ]
|
|
||||||
| [ "Generic" ; "IDictionary" ]
|
|
||||||
| [ "Collections" ; "Generic" ; "IDictionary" ]
|
|
||||||
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
|
|
||||||
| _ -> false
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynMatchClause =
|
|
||||||
let create (lhs : SynPat) (rhs : SynExpr) : SynMatchClause =
|
|
||||||
SynMatchClause.SynMatchClause (
|
|
||||||
lhs,
|
|
||||||
None,
|
|
||||||
rhs,
|
|
||||||
range0,
|
|
||||||
DebugPointAtTarget.Yes,
|
|
||||||
{
|
|
||||||
ArrowRange = Some range0
|
|
||||||
BarRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let withWhere (where : SynExpr) (m : SynMatchClause) : SynMatchClause =
|
|
||||||
match m with
|
|
||||||
| SynMatchClause (synPat, _, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia) ->
|
|
||||||
SynMatchClause (synPat, Some where, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia)
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynMemberDefn =
|
|
||||||
let private interfaceMemberSlotFlags =
|
|
||||||
{
|
|
||||||
SynMemberFlags.IsInstance = true
|
|
||||||
SynMemberFlags.IsDispatchSlot = true
|
|
||||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
|
||||||
SynMemberFlags.IsFinal = false
|
|
||||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
|
||||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let abstractMember
|
|
||||||
(ident : SynIdent)
|
|
||||||
(typars : SynTyparDecls option)
|
|
||||||
(arity : SynValInfo)
|
|
||||||
(xmlDoc : PreXmlDoc)
|
|
||||||
(returnType : SynType)
|
|
||||||
: SynMemberDefn
|
|
||||||
=
|
|
||||||
let slot =
|
|
||||||
SynValSig.SynValSig (
|
|
||||||
[],
|
|
||||||
ident,
|
|
||||||
SynValTyparDecls.SynValTyparDecls (typars, true),
|
|
||||||
returnType,
|
|
||||||
arity,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
xmlDoc,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
EqualsRange = None
|
|
||||||
WithKeyword = None
|
|
||||||
InlineKeyword = None
|
|
||||||
LeadingKeyword = SynLeadingKeyword.Abstract range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
SynMemberDefn.AbstractSlot (
|
|
||||||
slot,
|
|
||||||
interfaceMemberSlotFlags,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
GetSetKeywords = None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let staticMember (binding : SynBinding) : SynMemberDefn =
|
|
||||||
let binding = SynBinding.makeStaticMember binding
|
|
||||||
SynMemberDefn.Member (binding, range0)
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynPat =
|
|
||||||
|
|
||||||
let inline annotateType (ty : SynType) (pat : SynPat) =
|
|
||||||
SynPat.Paren (SynPat.Typed (pat, ty, range0), range0)
|
|
||||||
|
|
||||||
let inline named (s : string) : SynPat =
|
|
||||||
SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0)
|
|
||||||
|
|
||||||
let inline namedI (i : Ident) : SynPat =
|
|
||||||
SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0)
|
|
||||||
|
|
||||||
let inline identWithArgs (i : LongIdent) (args : SynArgPats) : SynPat =
|
|
||||||
SynPat.LongIdent (SynLongIdent.create i, None, None, args, None, range0)
|
|
||||||
|
|
||||||
let inline tupleNoParen (elements : SynPat list) : SynPat =
|
|
||||||
match elements with
|
|
||||||
| [] -> failwith "Can't tuple no elements in a pattern"
|
|
||||||
| [ p ] -> p
|
|
||||||
| elements -> SynPat.Tuple (false, elements, List.replicate (elements.Length - 1) range0, range0)
|
|
||||||
|
|
||||||
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
|
|
||||||
|
|
||||||
let inline tuple (elements : SynPat list) : SynPat = tupleNoParen elements |> paren
|
|
||||||
|
|
||||||
let unit = SynPat.Const (SynConst.Unit, range0)
|
|
||||||
|
|
||||||
let createNull = SynPat.Null range0
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynType =
|
|
||||||
let rec stripOptionalParen (ty : SynType) : SynType =
|
|
||||||
match ty with
|
|
||||||
| SynType.Paren (ty, _) -> stripOptionalParen ty
|
|
||||||
| ty -> ty
|
|
||||||
|
|
||||||
let inline createLongIdent (ident : LongIdent) : SynType =
|
|
||||||
SynType.LongIdent (SynLongIdent.create ident)
|
|
||||||
|
|
||||||
let inline createLongIdent' (ident : string list) : SynType =
|
|
||||||
SynType.LongIdent (SynLongIdent.createS' ident)
|
|
||||||
|
|
||||||
let inline named (name : string) = createLongIdent' [ name ]
|
|
||||||
|
|
||||||
let inline app' (name : SynType) (args : SynType list) : SynType =
|
|
||||||
if args.IsEmpty then
|
|
||||||
failwith "Type cannot be applied to no arguments"
|
|
||||||
|
|
||||||
SynType.App (name, Some range0, args, List.replicate (args.Length - 1) range0, Some range0, false, range0)
|
|
||||||
|
|
||||||
let inline app (name : string) (args : SynType list) : SynType = app' (named name) args
|
|
||||||
|
|
||||||
let inline appPostfix (name : string) (arg : SynType) : SynType =
|
|
||||||
SynType.App (named name, None, [ arg ], [], None, true, range0)
|
|
||||||
|
|
||||||
let inline funFromDomain (domain : SynType) (range : SynType) : SynType =
|
|
||||||
SynType.Fun (
|
|
||||||
domain,
|
|
||||||
range,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
ArrowRange = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let inline signatureParamOfType (ty : SynType) (name : Ident option) : SynType =
|
|
||||||
SynType.SignatureParameter ([], false, name, ty, range0)
|
|
||||||
|
|
||||||
let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0)
|
|
||||||
|
|
||||||
let unit : SynType = named "unit"
|
|
||||||
let int : SynType = named "int"
|
|
||||||
|
|
||||||
[<AutoOpen>]
|
|
||||||
module internal SynTypePatterns =
|
|
||||||
let (|OptionType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isOption ident ->
|
|
||||||
Some innerType
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident when SynLongIdent.isUnit ident -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|ListType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isList ident ->
|
|
||||||
Some innerType
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|ArrayType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isArray ident ->
|
|
||||||
Some innerType
|
|
||||||
| SynType.Array (1, innerType, _) -> Some innerType
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|RestEaseResponseType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isResponse ident ->
|
|
||||||
Some innerType
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|DictionaryType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isDictionary ident ->
|
|
||||||
Some (key, value)
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|IDictionaryType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isIDictionary ident ->
|
|
||||||
Some (key, value)
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
|
|
||||||
SynLongIdent.isReadOnlyDictionary ident
|
|
||||||
->
|
|
||||||
Some (key, value)
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|MapType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isMap ident ->
|
|
||||||
Some (key, value)
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|BigInt|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "bigint" ]
|
|
||||||
| [ "BigInteger" ]
|
|
||||||
| [ "Numerics" ; "BigInteger" ]
|
|
||||||
| [ "System" ; "Numerics" ; "BigInteger" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
/// Returns the type, qualified as in e.g. `System.Boolean`.
|
|
||||||
let (|PrimitiveType|_|) (fieldType : SynType) : LongIdent option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] -> Primitives.qualifyType i.idText
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|String|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] ->
|
|
||||||
[ "string" ]
|
|
||||||
|> List.tryFind (fun s -> s = i.idText)
|
|
||||||
|> Option.map ignore<string>
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|Byte|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|Guid|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "Guid" ]
|
|
||||||
| [ "Guid" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
|
|
||||||
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
|
|
||||||
| [ "Http" ; "HttpResponseMessage" ]
|
|
||||||
| [ "HttpResponseMessage" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|HttpContent|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
|
|
||||||
| [ "Net" ; "Http" ; "HttpContent" ]
|
|
||||||
| [ "Http" ; "HttpContent" ]
|
|
||||||
| [ "HttpContent" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|Stream|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "IO" ; "Stream" ]
|
|
||||||
| [ "IO" ; "Stream" ]
|
|
||||||
| [ "Stream" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|NumberType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent ident ->
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] -> [ "string" ; "float" ; "int" ; "bool" ] |> List.tryFind (fun s -> s = i.idText)
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|DateOnly|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "DateOnly" ]
|
|
||||||
| [ "DateOnly" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|DateTime|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "DateTime" ]
|
|
||||||
| [ "DateTime" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|Uri|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "Uri" ]
|
|
||||||
| [ "Uri" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|Task|_|) (fieldType : SynType) : SynType option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "Task" ]
|
|
||||||
| [ "Tasks" ; "Task" ]
|
|
||||||
| [ "Threading" ; "Tasks" ; "Task" ]
|
|
||||||
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
|
|
||||||
match args with
|
|
||||||
| [ arg ] -> Some arg
|
|
||||||
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynTypeDefn =
|
|
||||||
|
|
||||||
let inline create (componentInfo : SynComponentInfo) (repr : SynTypeDefnRepr) : SynTypeDefn =
|
|
||||||
SynTypeDefn.SynTypeDefn (
|
|
||||||
componentInfo,
|
|
||||||
repr,
|
|
||||||
[],
|
|
||||||
None,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
|
||||||
EqualsRange = Some range0
|
|
||||||
WithKeyword = None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let inline withMemberDefns (members : SynMemberDefn list) (r : SynTypeDefn) : SynTypeDefn =
|
|
||||||
match r with
|
|
||||||
| SynTypeDefn (typeInfo, typeRepr, _, ctor, range, trivia) ->
|
|
||||||
SynTypeDefn.SynTypeDefn (typeInfo, typeRepr, members, ctor, range, trivia)
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynTypeDefnRepr =
|
|
||||||
|
|
||||||
let inline interfaceType (mems : SynMemberDefns) : SynTypeDefnRepr =
|
|
||||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Unspecified, mems, range0)
|
|
||||||
|
|
||||||
/// Indicates the body of a `type Foo with {body}` extension type declaration.
|
|
||||||
let inline augmentation () : SynTypeDefnRepr =
|
|
||||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0)
|
|
||||||
|
|
||||||
let inline union (cases : SynUnionCase list) : SynTypeDefnRepr =
|
|
||||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (None, cases, range0), range0)
|
|
||||||
|
|
||||||
let inline record (fields : SynField list) : SynTypeDefnRepr =
|
|
||||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, fields, range0), range0)
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
type internal UnionCase<'Ident> =
|
|
||||||
{
|
|
||||||
Fields : SynFieldData<'Ident> list
|
|
||||||
Attrs : SynAttribute list
|
|
||||||
Ident : Ident
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal UnionCase =
|
|
||||||
let mapIdentFields<'a, 'b> (f : 'a -> 'b) (unionCase : UnionCase<'a>) : UnionCase<'b> =
|
|
||||||
{
|
|
||||||
Fields = unionCase.Fields |> List.map (SynField.mapIdent f)
|
|
||||||
Attrs = unionCase.Attrs
|
|
||||||
Ident = unionCase.Ident
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynUnionCase =
|
|
||||||
let extract (SynUnionCase (attrs, id, caseType, _, _, _, _)) : UnionCase<Ident option> =
|
|
||||||
match caseType with
|
|
||||||
| SynUnionCaseKind.FullType _ -> failwith "WoofWare.Myriad does not support FullType union cases."
|
|
||||||
| SynUnionCaseKind.Fields fields ->
|
|
||||||
|
|
||||||
let fields = fields |> List.map SynField.extract
|
|
||||||
|
|
||||||
let id =
|
|
||||||
match id with
|
|
||||||
| SynIdent.SynIdent (ident, _) -> ident
|
|
||||||
|
|
||||||
// As far as I can tell, there's no way to get any attributes here? :shrug:
|
|
||||||
let attrs = attrs |> List.collect (fun l -> l.Attributes)
|
|
||||||
|
|
||||||
{
|
|
||||||
Fields = fields
|
|
||||||
Attrs = attrs
|
|
||||||
Ident = id
|
|
||||||
}
|
|
||||||
10
WoofWare.Myriad.Plugins/SynType.fs
Normal file
10
WoofWare.Myriad.Plugins/SynType.fs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.Syntax
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynType =
|
||||||
|
let rec stripOptionalParen (ty : SynType) : SynType =
|
||||||
|
match ty with
|
||||||
|
| SynType.Paren (ty, _) -> stripOptionalParen ty
|
||||||
|
| ty -> ty
|
||||||
@@ -25,26 +25,11 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="List.fs"/>
|
<Compile Include="List.fs"/>
|
||||||
<Compile Include="Primitives.fs" />
|
<Compile Include="Ident.fs" />
|
||||||
<Compile Include="SynExpr\PreXmlDoc.fs" />
|
<Compile Include="AstHelper.fs"/>
|
||||||
<Compile Include="SynExpr\Ident.fs" />
|
<Compile Include="SynExpr.fs"/>
|
||||||
<Compile Include="SynExpr\SynLongIdent.fs" />
|
<Compile Include="SynType.fs"/>
|
||||||
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
|
<Compile Include="SynAttribute.fs"/>
|
||||||
<Compile Include="SynExpr\SynPat.fs" />
|
|
||||||
<Compile Include="SynExpr\SynBinding.fs" />
|
|
||||||
<Compile Include="SynExpr\SynType.fs" />
|
|
||||||
<Compile Include="SynExpr\SynMatchClause.fs" />
|
|
||||||
<Compile Include="SynExpr\CompExpr.fs" />
|
|
||||||
<Compile Include="SynExpr\SynExpr.fs" />
|
|
||||||
<Compile Include="SynExpr\SynArgPats.fs" />
|
|
||||||
<Compile Include="SynExpr\SynField.fs" />
|
|
||||||
<Compile Include="SynExpr\SynUnionCase.fs" />
|
|
||||||
<Compile Include="SynExpr\SynTypeDefnRepr.fs" />
|
|
||||||
<Compile Include="SynExpr\SynTypeDefn.fs" />
|
|
||||||
<Compile Include="SynExpr\SynComponentInfo.fs" />
|
|
||||||
<Compile Include="SynExpr\SynMemberDefn.fs" />
|
|
||||||
<Compile Include="SynExpr\SynAttribute.fs" />
|
|
||||||
<Compile Include="AstHelper.fs" />
|
|
||||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||||
<Compile Include="InterfaceMockGenerator.fs"/>
|
<Compile Include="InterfaceMockGenerator.fs"/>
|
||||||
<Compile Include="JsonSerializeGenerator.fs"/>
|
<Compile Include="JsonSerializeGenerator.fs"/>
|
||||||
|
|||||||
@@ -3,11 +3,5 @@
|
|||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
"pathFilters": [
|
"pathFilters": null
|
||||||
":/",
|
}
|
||||||
":^WoofWare.Myriad.Plugins.Test/",
|
|
||||||
":^WoofWare.Myriad.Plugins.Attributes/Test/",
|
|
||||||
":^/.github/",
|
|
||||||
":^/CHANGELOG.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.10.0]" />
|
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.8.0]" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
36
flake.nix
36
flake.nix
@@ -7,6 +7,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
flake-utils,
|
flake-utils,
|
||||||
...
|
...
|
||||||
@@ -45,19 +46,44 @@
|
|||||||
packages = {
|
packages = {
|
||||||
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
||||||
fsharp-analyzers = dotnetTool "FSharp.Analyzers.Cli" "fsharp-analyzers" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fsharp-analyzers.version (builtins.head (builtins.filter (elem: elem.pname == "fsharp-analyzers") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
fsharp-analyzers = dotnetTool "FSharp.Analyzers.Cli" "fsharp-analyzers" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fsharp-analyzers.version (builtins.head (builtins.filter (elem: elem.pname == "fsharp-analyzers") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
||||||
|
fetchDeps = let
|
||||||
|
flags = [];
|
||||||
|
runtimeIds = ["win-x64"] ++ map (system: pkgs.dotnetCorePackages.systemToDotnetRid system) dotnet-sdk.meta.platforms;
|
||||||
|
in
|
||||||
|
pkgs.writeShellScriptBin "fetch-${pname}-deps" (builtins.readFile (pkgs.substituteAll {
|
||||||
|
src = ./nix/fetchDeps.sh;
|
||||||
|
pname = pname;
|
||||||
|
binPath = pkgs.lib.makeBinPath [pkgs.coreutils dotnet-sdk (pkgs.nuget-to-nix.override {inherit dotnet-sdk;})];
|
||||||
|
projectFiles = toString ["./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj" "./ConsumePlugin/ConsumePlugin.fsproj" "./WoofWare.Myriad.Plugins.Attributes/WoofWare.Myriad.Plugins.Attributes.fsproj"];
|
||||||
|
testProjectFiles = ["./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj" "./WoofWare.Myriad.Plugins.Attributes/Test/Woofware.Myriad.Plugins.Attributes.Test.fsproj"];
|
||||||
|
rids = pkgs.lib.concatStringsSep "\" \"" runtimeIds;
|
||||||
|
packages = dotnet-sdk.packages;
|
||||||
|
storeSrc = pkgs.srcOnly {
|
||||||
|
src = ./.;
|
||||||
|
pname = pname;
|
||||||
|
version = version;
|
||||||
|
};
|
||||||
|
}));
|
||||||
default = pkgs.buildDotnetModule {
|
default = pkgs.buildDotnetModule {
|
||||||
inherit pname version dotnet-sdk dotnet-runtime;
|
pname = pname;
|
||||||
name = "WoofWare.Myriad.Plugins";
|
name = "WoofWare.Myriad.Plugins";
|
||||||
|
version = version;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj";
|
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj";
|
||||||
testProjectFile = "./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj";
|
nugetDeps = ./nix/deps.nix;
|
||||||
disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"];
|
|
||||||
nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result` and put the result here
|
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
|
dotnet-sdk = dotnet-sdk;
|
||||||
|
dotnet-runtime = dotnet-runtime;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell {
|
||||||
buildInputs = [dotnet-sdk];
|
buildInputs = with pkgs; [
|
||||||
|
(with dotnetCorePackages;
|
||||||
|
combinePackages [
|
||||||
|
dotnet-sdk_8
|
||||||
|
dotnetPackages.Nuget
|
||||||
|
])
|
||||||
|
];
|
||||||
packages = [
|
packages = [
|
||||||
pkgs.alejandra
|
pkgs.alejandra
|
||||||
pkgs.nodePackages.markdown-link-check
|
pkgs.nodePackages.markdown-link-check
|
||||||
|
|||||||
214
nix/deps.nix
214
nix/deps.nix
@@ -1,15 +1,25 @@
|
|||||||
# This file was automatically generated by passthru.fetch-deps.
|
# This file was automatically generated by passthru.fetch-deps.
|
||||||
# Please dont edit it manually, your changes might get overwritten!
|
# Please don't edit it manually, your changes might get overwritten!
|
||||||
{fetchNuGet}: [
|
{fetchNuGet}: [
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "ApiSurface";
|
pname = "fsharp-analyzers";
|
||||||
version = "4.0.40";
|
version = "0.24.0";
|
||||||
sha256 = "1c9z0b6minlripwrjmv4yd5w8zj4lcpak4x41izh7ygx8kgmbvx0";
|
sha256 = "sha256-cNaM/yHI28sHDGamKMrU237ltOyrR+8vPNUImB5RxjU=";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "fantomas";
|
pname = "fantomas";
|
||||||
version = "6.3.4";
|
version = "6.3.0-alpha-007";
|
||||||
sha256 = "1bf57pzvl0i1bgic2vf08mqlzzbd5kys1ip9klrhm4f155ksm9fm";
|
sha256 = "sha256-uZw6h6k/DS4BcYtK9cv8TLS0H8MZDO3WBaPPTdtTgu0=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "ApiSurface";
|
||||||
|
version = "4.0.28";
|
||||||
|
sha256 = "1gg0dqbgbb8aqn2lxi5gf2wq969kgskby5wph6m2b3hdkz7265ak";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "coverlet.collector";
|
||||||
|
version = "6.0.0";
|
||||||
|
sha256 = "12j34vrkmph8lspbafnqmfnj2qvysz1jcrks2khw798s6dwv0j90";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Fantomas.Core";
|
pname = "Fantomas.Core";
|
||||||
@@ -26,11 +36,6 @@
|
|||||||
version = "2.16.6";
|
version = "2.16.6";
|
||||||
sha256 = "176rwky6b5rk8dzldiz4068p7m9c5y9ygzbhadrs14jkl94pc56n";
|
sha256 = "176rwky6b5rk8dzldiz4068p7m9c5y9ygzbhadrs14jkl94pc56n";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "fsharp-analyzers";
|
|
||||||
version = "0.26.0";
|
|
||||||
sha256 = "0xgv5kvbwfdvcp6s8x7xagbbi4s3mqa4ixni6pazqvyflbgnah7b";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "FSharp.Core";
|
pname = "FSharp.Core";
|
||||||
version = "4.3.4";
|
version = "4.3.4";
|
||||||
@@ -56,26 +61,61 @@
|
|||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1d8nkz24vsm0iy2xm8y5ak2q1w1p99dxyz0y26acs6sfk2na0vm6";
|
sha256 = "1d8nkz24vsm0iy2xm8y5ak2q1w1p99dxyz0y26acs6sfk2na0vm6";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Ref";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0yaaiqq7mi6sclyrb1v0fyncanbx0ifmnnhv9whynqj8439jsdwh";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1za8lc52m4z54d68wd64c2nhzy05g3gx171k5cdlx73fbymiys9z";
|
sha256 = "1za8lc52m4z54d68wd64c2nhzy05g3gx171k5cdlx73fbymiys9z";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0dsdgqg7566qximmjfza4x9if3icy4kskq698ddj5apdia88h2mw";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1zpbmz6z8758gwywzg0bac8kx9x39sxxc9j4a4r2jl74l9ssw4vm";
|
sha256 = "1zpbmz6z8758gwywzg0bac8kx9x39sxxc9j4a4r2jl74l9ssw4vm";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "1gjz379y61ag9whi78qxx09bwkwcznkx2mzypgycibxk61g11da1";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1i8ydlwjzk7j0mzvn0rpljxfp1h50zwaqalnyvfxai1fwgigzgw5";
|
sha256 = "1i8ydlwjzk7j0mzvn0rpljxfp1h50zwaqalnyvfxai1fwgigzgw5";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0w3mrs4zdl9mfanl1j81759xwwrzmicsjxn6yfxv5yrxbxzq695n";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "02src68hd3213sd1a2ms1my7i92knfmdxclvv90il9cky2zsq8kw";
|
sha256 = "02src68hd3213sd1a2ms1my7i92knfmdxclvv90il9cky2zsq8kw";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0a9aljr4fy4haq6ndz2y723liv5hbfpss1rn45s88nmgcp27m15m";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Runtime.win-x64";
|
||||||
|
version = "6.0.26";
|
||||||
|
sha256 = "1gxlmfdkfzmhw9pac5jiv674nn6i1zymcp2hj81irjwhhjk01mf5";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Runtime.win-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "01kzndyqmsvcq49i2jrv7ymfp0l71yxfylv1cy3nhkdbprqz8ipx";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.Build.Tasks.Git";
|
pname = "Microsoft.Build.Tasks.Git";
|
||||||
version = "8.0.0";
|
version = "8.0.0";
|
||||||
@@ -83,59 +123,134 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.CodeCoverage";
|
pname = "Microsoft.CodeCoverage";
|
||||||
version = "17.10.0";
|
version = "17.8.0";
|
||||||
sha256 = "0s0v7jmrq85n356xv7zixvwa4z94fszjcr5vll8x4im1a2lp00f9";
|
sha256 = "173wjadp3gan4x2jfjchngnc4ca4mb95h1sbb28jydfkfw0z1zvj";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.CodeCoverage";
|
||||||
|
version = "17.9.0";
|
||||||
|
sha256 = "1gljgi69k0fz8vy8bn6xlyxabj6q4vls2zza9wz7ng6ix3irm89r";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NET.Test.Sdk";
|
pname = "Microsoft.NET.Test.Sdk";
|
||||||
version = "17.10.0";
|
version = "17.8.0";
|
||||||
sha256 = "13g8fwl09li8fc71nk13dgkb7gahd4qhamyg2xby7am63nlchhdf";
|
sha256 = "1syvl3g0hbrcgfi9rq6pld8s8hqqww4dflf1lxn59ccddyyx0gmv";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NET.Test.Sdk";
|
||||||
|
version = "17.9.0";
|
||||||
|
sha256 = "1lls1fly2gr1n9n1xyl9k33l2v4pwfmylyzkq8v4v5ldnwkl1zdb";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "19y6c6v20bgf7x7rrh4rx9y7s5fy8vp5m4j9b6gi1wp4rpb5mza4";
|
sha256 = "19y6c6v20bgf7x7rrh4rx9y7s5fy8vp5m4j9b6gi1wp4rpb5mza4";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0dhpdlcdz7adcfh9w01fc867051m35fqaxnvj3fqvqhgcm2n3143";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "0p7hhidaa3mnyiwnsijwy8578v843x8hh99255s69qwwyld6falv";
|
sha256 = "0p7hhidaa3mnyiwnsijwy8578v843x8hh99255s69qwwyld6falv";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "1aw6mc7zcmzs1grxz2wa9cw9kfj8pz7zpj417xnp1a9n4ix1bxgr";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1mq11xsv9g1vsasp6k80y7xlvwi9hrpk5dgm773fvy8538s01gfv";
|
sha256 = "1mq11xsv9g1vsasp6k80y7xlvwi9hrpk5dgm773fvy8538s01gfv";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "1dzg3prng9zfdzz7gcgywjdbwzhwm85j89z0jahynxx4q2dra4b9";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1chac9b4424ihrrnlzvc7qz6j4ymfjyv4kzyazzzw19yhymdkh2s";
|
sha256 = "1chac9b4424ihrrnlzvc7qz6j4ymfjyv4kzyazzzw19yhymdkh2s";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "010f8wn15s2kv7yyzgys3pv9i1mxw20hpv1ig2zhybjxs8lpj8jj";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.win-x64";
|
||||||
|
version = "6.0.26";
|
||||||
|
sha256 = "0i7g9fsqjnbh9rc6807m57r2idg5pkcw6xjfwhnxkcpgqm96258v";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.win-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "1ssj1cyam3nfidm8q82kvh4i3fzm2lzb3bxw6ck09hwhvwh909z4";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Ref";
|
pname = "Microsoft.NETCore.App.Ref";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "12gb52dhg5h9hgnyqh1zgj2w46paxv2pfh33pphl9ajhrdr7hlsb";
|
sha256 = "12gb52dhg5h9hgnyqh1zgj2w46paxv2pfh33pphl9ajhrdr7hlsb";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Ref";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "02r4jg4ha0qksix9v6s3cpmvavmz54gkawkxy9bvknw5ynxhhl1l";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "164hfrwqz5dxcbb441lridk4mzcqmarb0b7ckgvqhsvpawyjw88v";
|
sha256 = "164hfrwqz5dxcbb441lridk4mzcqmarb0b7ckgvqhsvpawyjw88v";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0353whnjgz3sqhzsfrviad3a3db4pk7hl7m4wwppv5mqdg9i9ri5";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "0islayddpnflviqpbq4djc4f3v9nhsa2y76k5x6il3csq5vdw2hq";
|
sha256 = "0islayddpnflviqpbq4djc4f3v9nhsa2y76k5x6il3csq5vdw2hq";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "1g5b30f4l8a1zjjr3b8pk9mcqxkxqwa86362f84646xaj4iw3a4d";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "1acn5zw1pxzmcg3c0pbf9hal36fbdh9mvbsiwra7simrk7hzqpdc";
|
sha256 = "1acn5zw1pxzmcg3c0pbf9hal36fbdh9mvbsiwra7simrk7hzqpdc";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "0cdrpdaq5sl3602anfx1p0z0ncx2sjjvl6mgsd6y38g47n7f95jc";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
||||||
version = "6.0.26";
|
version = "6.0.26";
|
||||||
sha256 = "00f9l9dkdz0zv5csaw8fkm6s8ckrj5n9k3ygz12daa22l3bcn6ii";
|
sha256 = "00f9l9dkdz0zv5csaw8fkm6s8ckrj5n9k3ygz12daa22l3bcn6ii";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "1fk1flqp6ji0l4c2gvh83ykndpx7a2nkkgrgkgql3c75j1k2v1s9";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Runtime.win-x64";
|
||||||
|
version = "6.0.26";
|
||||||
|
sha256 = "0i2p356phfc5y6qnr3vyrzjfi1mrbwfb6g85k4q37bbyxjfp7zl9";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Runtime.win-x64";
|
||||||
|
version = "8.0.1";
|
||||||
|
sha256 = "198576cdkl72xs29zznff9ls763p8pfr0zji7b74dqxd5ga0s3bd";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.Platforms";
|
pname = "Microsoft.NETCore.Platforms";
|
||||||
version = "1.1.0";
|
version = "1.1.0";
|
||||||
@@ -168,13 +283,23 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||||
version = "17.10.0";
|
version = "17.8.0";
|
||||||
sha256 = "07j69cw8r39533w4p39mnj00kahazz38760in3jfc45kmlcdb26x";
|
sha256 = "0b0i7lmkrcfvim8i3l93gwqvkhhhfzd53fqfnygdqvkg6np0cg7m";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||||
|
version = "17.9.0";
|
||||||
|
sha256 = "1kgsl9w9fganbm9wvlkqgk0ag9hfi58z88rkfybc6kvg78bx89ca";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.TestPlatform.TestHost";
|
pname = "Microsoft.TestPlatform.TestHost";
|
||||||
version = "17.10.0";
|
version = "17.8.0";
|
||||||
sha256 = "1bl471s7fx9jycr0cc8rylwf34mrvlg9qn1an6l86nisavfcyb7v";
|
sha256 = "0f5jah93kjkvxwmhwb78lw11m9pkkq9fvf135hpymmmpxqbdh97q";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.TestPlatform.TestHost";
|
||||||
|
version = "17.9.0";
|
||||||
|
sha256 = "19ffh31a1jxzn8j69m1vnk5hyfz3dbxmflq77b8x82zybiilh5nl";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Myriad.Core";
|
pname = "Myriad.Core";
|
||||||
@@ -191,6 +316,11 @@
|
|||||||
version = "3.6.133";
|
version = "3.6.133";
|
||||||
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
||||||
})
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "NETStandard.Library";
|
||||||
|
version = "2.0.0";
|
||||||
|
sha256 = "1bc4ba8ahgk15m8k4nd7x406nhi0kwqzbgjk2dmw52ss553xz7iy";
|
||||||
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NETStandard.Library";
|
pname = "NETStandard.Library";
|
||||||
version = "2.0.3";
|
version = "2.0.3";
|
||||||
@@ -208,38 +338,48 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Common";
|
pname = "NuGet.Common";
|
||||||
version = "6.10.0";
|
version = "6.8.0";
|
||||||
sha256 = "0nizrnilmlcqbm945293h8q3wfqfchb4xi8g50x4kjn0rbpd1kbh";
|
sha256 = "0l3ij8iwy7wj6s7f93lzi9168r4wz8zyin6a08iwgk7hvq44cia1";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Configuration";
|
pname = "NuGet.Configuration";
|
||||||
version = "6.10.0";
|
version = "6.8.0";
|
||||||
sha256 = "1aqaknaawnqx4mnvx9qw73wvj48jjzv0d78dzwl7m9zjlrl9myhz";
|
sha256 = "0x03p408smkmv1gv7pmvsia4lkn0xaj4wfrkl58pjf8bbv51y0yw";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Frameworks";
|
pname = "NuGet.Frameworks";
|
||||||
version = "6.10.0";
|
version = "6.5.0";
|
||||||
sha256 = "0hrd8y31zx9a0wps49czw0qgbrakb49zn3abfgylc9xrq990zkqk";
|
sha256 = "0s37d1p4md0k6d4cy6sq36f2dgkd9qfbzapxhkvi8awwh0vrynhj";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "NuGet.Frameworks";
|
||||||
|
version = "6.8.0";
|
||||||
|
sha256 = "0i2xvhgkjkjr496i3pg8hamwv6505fia45qhn7jg5m01wb3cvsjl";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Packaging";
|
pname = "NuGet.Packaging";
|
||||||
version = "6.10.0";
|
version = "6.8.0";
|
||||||
sha256 = "18s53cvrf51lihmaqqdf48p2qi6ky1l48jv0hvbp76cxwdg7rba4";
|
sha256 = "031z4s905bxi94h3f0qy4j1b6jxdxgqgpkzqvvpfxch07szxcbim";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Protocol";
|
pname = "NuGet.Protocol";
|
||||||
version = "6.10.0";
|
version = "6.7.0";
|
||||||
sha256 = "0hmv4q0ks9i34mfgpb13l01la9v3jjllfh1qd3aqv105xrqrdxac";
|
sha256 = "1v5ibnq2mp801vw68zyj169hkj3xm7h55824i33n1jxxj2vs3vbk";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Versioning";
|
pname = "NuGet.Versioning";
|
||||||
version = "6.10.0";
|
version = "6.8.0";
|
||||||
sha256 = "1x19njx4x0sw9fz8y5fibi15xfsrw5avir0cx0599yd7p3ykik5g";
|
sha256 = "1sd25h46fd12ng780r02q4ijcx1imkb53kj1y2y7cwg5myh537ks";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit";
|
pname = "NUnit";
|
||||||
version = "4.1.0";
|
version = "3.13.3";
|
||||||
sha256 = "0fj6xwgqaxq3mrai86bklclfmjkzf038mrslwfqf4ignaz9f7g5j";
|
sha256 = "0wdzfkygqnr73s6lpxg5b1pwaqz9f414fxpvpdmf72bvh4jaqzv6";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "NUnit";
|
||||||
|
version = "4.0.1";
|
||||||
|
sha256 = "0jgiq3dbwli5r70j0bw7021d69r7bhr58s8kphlpjmf7k47l5pcd";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit3TestAdapter";
|
pname = "NUnit3TestAdapter";
|
||||||
@@ -333,12 +473,12 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "System.Text.Encodings.Web";
|
pname = "System.Text.Encodings.Web";
|
||||||
version = "7.0.0";
|
version = "6.0.0";
|
||||||
sha256 = "1151hbyrcf8kyg1jz8k9awpbic98lwz9x129rg7zk1wrs6vjlpxl";
|
sha256 = "06n9ql3fmhpjl32g3492sj181zjml5dlcc5l76xq2h38c4f87sai";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "System.Text.Json";
|
pname = "System.Text.Json";
|
||||||
version = "7.0.3";
|
version = "6.0.0";
|
||||||
sha256 = "0zjrnc9lshagm6kdb9bdh45dmlnkpwcpyssa896sda93ngbmj8k9";
|
sha256 = "1si2my1g0q0qv1hiqnji4xh9wd05qavxnzj9dwgs23iqvgjky0gl";
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|||||||
73
nix/fetchDeps.sh
Normal file
73
nix/fetchDeps.sh
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This file was adapted from
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/b981d811453ab84fb3ea593a9b33b960f1ab9147/pkgs/build-support/dotnet/build-dotnet-module/default.nix#L173
|
||||||
|
set -euo pipefail
|
||||||
|
export PATH="@binPath@"
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--keep-sources|-k)
|
||||||
|
keepSources=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
echo "usage: $0 [--keep-sources] [--help] <output path>"
|
||||||
|
echo " <output path> The path to write the lockfile to. A temporary file is used if this is not set"
|
||||||
|
echo " --keep-sources Don't remove temporary directories upon exit, useful for debugging"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
tmp=$(mktemp -td "@pname@-tmp-XXXXXX")
|
||||||
|
export tmp
|
||||||
|
HOME=$tmp/home
|
||||||
|
exitTrap() {
|
||||||
|
test -n "${ranTrap-}" && return
|
||||||
|
ranTrap=1
|
||||||
|
if test -n "${keepSources-}"; then
|
||||||
|
echo -e "Path to the source: $tmp/src\nPath to the fake home: $tmp/home"
|
||||||
|
else
|
||||||
|
rm -rf "$tmp"
|
||||||
|
fi
|
||||||
|
# Since mktemp is used this will be empty if the script didnt succesfully complete
|
||||||
|
if ! test -s "$depsFile"; then
|
||||||
|
rm -rf "$depsFile"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap exitTrap EXIT INT TERM
|
||||||
|
dotnetRestore() {
|
||||||
|
local -r project="${1-}"
|
||||||
|
local -r rid="$2"
|
||||||
|
dotnet restore "${project-}" \
|
||||||
|
-p:ContinuousIntegrationBuild=true \
|
||||||
|
-p:Deterministic=true \
|
||||||
|
--packages "$tmp/nuget_pkgs" \
|
||||||
|
--runtime "$rid" \
|
||||||
|
--no-cache \
|
||||||
|
--force
|
||||||
|
}
|
||||||
|
declare -a projectFiles=( @projectFiles@ )
|
||||||
|
declare -a testProjectFiles=( @testProjectFiles@ )
|
||||||
|
export DOTNET_NOLOGO=1
|
||||||
|
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||||
|
depsFile=$(realpath "${1:-$(mktemp -t "@pname@-deps-XXXXXX.nix")}")
|
||||||
|
mkdir -p "$tmp/nuget_pkgs"
|
||||||
|
storeSrc="@storeSrc@"
|
||||||
|
src="$tmp/src"
|
||||||
|
cp -rT "$storeSrc" "$src"
|
||||||
|
chmod -R +w "$src"
|
||||||
|
cd "$src"
|
||||||
|
echo "Restoring project..."
|
||||||
|
rids=("@rids@")
|
||||||
|
for rid in "${rids[@]}"; do
|
||||||
|
(( ${#projectFiles[@]} == 0 )) && dotnetRestore "" "$rid"
|
||||||
|
for project in "${projectFiles[@]-}" "${testProjectFiles[@]-}"; do
|
||||||
|
dotnetRestore "$project" "$rid"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
echo "Successfully restored project"
|
||||||
|
echo "Writing lockfile..."
|
||||||
|
echo -e "# This file was automatically generated by passthru.fetch-deps.\n# Please don't edit it manually, your changes might get overwritten!\n" > "$depsFile"
|
||||||
|
nuget-to-nix "$tmp/nuget_pkgs" "@packages@" >> "$depsFile"
|
||||||
|
echo "Successfully wrote lockfile to $depsFile"
|
||||||
Reference in New Issue
Block a user