mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-07 04:58:41 +00:00
Compare commits
94 Commits
WoofWare.M
...
du-parser
Author | SHA1 | Date | |
---|---|---|---|
|
f686109331 | ||
|
7b2c3d2168 | ||
|
3ed8d4db00 | ||
|
75ce8c1f64 | ||
|
01714aeba0 | ||
|
2f266b052d | ||
|
d3d50cae7c | ||
|
573d410416 | ||
|
a82ece0f6c | ||
|
51991cab74 | ||
|
55a3876610 | ||
|
c14f89f807 | ||
|
54e3f17d9c | ||
|
4013271254 | ||
|
aa2ef830c3 | ||
|
4e62a154c0 | ||
|
751e43eec4 | ||
|
fccc981045 | ||
|
f8a1505b99 | ||
|
eb25b9ccb8 | ||
|
325f8634a4 | ||
|
34587b8dea | ||
|
3e5d663544 | ||
|
963a097360 | ||
|
67eb89cfc0 | ||
|
0c5ddf9df7 | ||
|
8535481e0d | ||
|
df6079e763 | ||
|
4befdb93e5 | ||
|
17da7317e8 | ||
|
fa022b75ea | ||
|
bb88f80c85 | ||
|
71f26930c6 | ||
|
680728a06e | ||
|
cdc6f2d511 | ||
|
3be487c328 | ||
|
a5f4d169ca | ||
|
ce634efff2 | ||
|
1529dd1fb2 | ||
|
59558b0766 | ||
|
8602894efc | ||
|
51d349b365 | ||
|
120df84bbf | ||
|
603f875a12 | ||
|
2df41555de | ||
|
49e31e52b5 | ||
|
277a186fda | ||
|
129687ec1c | ||
|
c7fea55e28 | ||
|
ded7b32771 | ||
|
b272f8b645 | ||
|
b8d60aec90 | ||
|
0e3510e1e5 | ||
|
8a1edd90d5 | ||
|
74fdd7c0a9 | ||
|
23f55814f9 | ||
|
15c04bb373 | ||
|
a860a93f9c | ||
|
b056af348e | ||
|
b44c8db6e9 | ||
|
7d6a2cea01 | ||
|
d779a602f4 | ||
|
23cd5272fb | ||
|
93538ee6b4 | ||
|
8a29c2f444 | ||
|
1367e00f34 | ||
|
bff08c90cd | ||
|
4136f7fe94 | ||
|
9fe2e3b1fa | ||
|
13a597a365 | ||
|
3acc492f22 | ||
|
eefe64f5a4 | ||
|
93a2d92299 | ||
|
33793e8cbe | ||
|
fa7ef1ffba | ||
|
a25c45dc3a | ||
|
af5f2abdf8 | ||
|
0f89816432 | ||
|
d571da6a22 | ||
|
39a9e94ca5 | ||
|
487f73312a | ||
|
b7aa564306 | ||
|
a34dee0a1c | ||
|
44506f3650 | ||
|
ca7134cfb8 | ||
|
773fd088a7 | ||
|
6e5c0332cd | ||
|
aece186424 | ||
|
827e9aa3ec | ||
|
d59ebdfccb | ||
|
5319a33b7b | ||
|
29b93b2f20 | ||
|
40106d8aa3 | ||
|
4d641b0662 |
@@ -3,13 +3,13 @@
|
|||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"fantomas": {
|
"fantomas": {
|
||||||
"version": "6.3.15",
|
"version": "7.0.1",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fantomas"
|
"fantomas"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fsharp-analyzers": {
|
"fsharp-analyzers": {
|
||||||
"version": "0.27.0",
|
"version": "0.30.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fsharp-analyzers"
|
"fsharp-analyzers"
|
||||||
]
|
]
|
||||||
|
98
.github/workflows/dotnet.yaml
vendored
98
.github/workflows/dotnet.yaml
vendored
@@ -29,7 +29,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -50,7 +50,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -67,7 +67,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -82,7 +82,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -97,7 +97,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -116,7 +116,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -129,7 +129,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -142,7 +142,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -156,7 +156,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@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -198,27 +198,40 @@ 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:
|
github-release-dry-run:
|
||||||
needs: [nuget-pack]
|
strategy:
|
||||||
|
matrix:
|
||||||
|
artifact:
|
||||||
|
- nuget-package-plugin
|
||||||
|
- nuget-package-attribute
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: [nuget-pack]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Download NuGet artifact (plugin)
|
- name: Download NuGet artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: nuget-package-plugin
|
name: ${{ matrix.artifact }}
|
||||||
- name: Download NuGet artifact (attribute)
|
- name: Compute package path
|
||||||
uses: actions/download-artifact@v4
|
id: compute-path
|
||||||
with:
|
run: |
|
||||||
name: nuget-package-attribute
|
find . -maxdepth 1 -type f -name 'WoofWare.Myriad.*.nupkg' -exec sh -c 'echo "output=$(basename "$1")" >> $GITHUB_OUTPUT' shell {} \;
|
||||||
- name: Tag and release plugin
|
- name: Compute tag name
|
||||||
|
id: compute-tag
|
||||||
env:
|
env:
|
||||||
DRY_RUN: 1
|
NUPKG_PATH: ${{ steps.compute-path.outputs.output }}
|
||||||
GITHUB_TOKEN: mock-token
|
run: echo "output=$(basename "$NUPKG_PATH" .nupkg)" >> $GITHUB_OUTPUT
|
||||||
run: sh .github/workflows/tag.sh
|
- name: Tag and release
|
||||||
|
uses: G-Research/common-actions/github-release@19d7281a0f9f83e13c78f99a610dbc80fc59ba3b
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
target-commitish: ${{ github.sha }}
|
||||||
|
tag: ${{ steps.compute-tag.outputs.output }}
|
||||||
|
binary-contents: ${{ steps.compute-path.outputs.output }}
|
||||||
|
dry-run: true
|
||||||
|
|
||||||
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, check-accurate-generations, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack, github-release-dry-run]
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -241,7 +254,7 @@ jobs:
|
|||||||
name: nuget-package-attribute
|
name: nuget-package-attribute
|
||||||
path: packed
|
path: packed
|
||||||
- name: Attest Build Provenance
|
- name: Attest Build Provenance
|
||||||
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
|
uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
|
||||||
with:
|
with:
|
||||||
subject-path: "packed/*.nupkg"
|
subject-path: "packed/*.nupkg"
|
||||||
|
|
||||||
@@ -260,7 +273,7 @@ jobs:
|
|||||||
name: nuget-package-plugin
|
name: nuget-package-plugin
|
||||||
path: packed
|
path: packed
|
||||||
- name: Attest Build Provenance
|
- name: Attest Build Provenance
|
||||||
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
|
uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
|
||||||
with:
|
with:
|
||||||
subject-path: "packed/*.nupkg"
|
subject-path: "packed/*.nupkg"
|
||||||
|
|
||||||
@@ -276,7 +289,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -309,7 +322,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v29
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -330,7 +343,12 @@ jobs:
|
|||||||
nupkg-dir: packed/
|
nupkg-dir: packed/
|
||||||
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
|
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
|
||||||
|
|
||||||
github-release-plugin:
|
github-release:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
artifact:
|
||||||
|
- nuget-package-attribute
|
||||||
|
- nuget-package-plugin
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
|
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
|
||||||
needs: [all-required-checks-complete]
|
needs: [all-required-checks-complete]
|
||||||
@@ -339,15 +357,23 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Download NuGet artifact (plugin)
|
- name: Download NuGet artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: nuget-package-plugin
|
name: ${{ matrix.artifact }}
|
||||||
- name: Download NuGet artifact (attribute)
|
- name: Compute package path
|
||||||
uses: actions/download-artifact@v4
|
id: compute-path
|
||||||
with:
|
run: |
|
||||||
name: nuget-package-attribute
|
find . -maxdepth 1 -type f -name 'WoofWare.Myriad.*.nupkg' -exec sh -c 'echo "output=$(basename "$1")" >> $GITHUB_OUTPUT' shell {} \;
|
||||||
- name: Tag and release plugin
|
- name: Compute tag name
|
||||||
|
id: compute-tag
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
NUPKG_PATH: ${{ steps.compute-path.outputs.output }}
|
||||||
run: sh .github/workflows/tag.sh
|
run: echo "output=$(basename "$NUPKG_PATH" .nupkg)" >> $GITHUB_OUTPUT
|
||||||
|
- name: Tag and release
|
||||||
|
uses: G-Research/common-actions/github-release@19d7281a0f9f83e13c78f99a610dbc80fc59ba3b
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
target-commitish: ${{ github.sha }}
|
||||||
|
tag: ${{ steps.compute-tag.outputs.output }}
|
||||||
|
binary-contents: ${{ steps.compute-path.outputs.output }}
|
||||||
|
10
.github/workflows/flake_update.yaml
vendored
10
.github/workflows/flake_update.yaml
vendored
@@ -21,20 +21,20 @@ jobs:
|
|||||||
- name: Update Nix flake
|
- name: Update Nix flake
|
||||||
run: 'nix flake update'
|
run: 'nix flake update'
|
||||||
|
|
||||||
- name: Build passthru
|
- name: Build fetch-deps
|
||||||
run: 'nix build ".#default.passthru.fetch-deps"'
|
run: 'nix build ".#default.fetch-deps"'
|
||||||
|
|
||||||
- name: Run passthru
|
- name: Run fetch-deps
|
||||||
run: |
|
run: |
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
./result nix/deps.nix
|
./result nix/deps.json
|
||||||
|
|
||||||
- name: Format
|
- name: Format
|
||||||
run: 'nix develop --command alejandra .'
|
run: 'nix develop --command alejandra .'
|
||||||
|
|
||||||
- name: Create token
|
- name: Create token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v1
|
uses: actions/create-github-app-token@v2
|
||||||
with:
|
with:
|
||||||
# https://github.com/actions/create-github-app-token/issues/136
|
# https://github.com/actions/create-github-app-token/issues/136
|
||||||
app-id: ${{ secrets.APP_ID }}
|
app-id: ${{ secrets.APP_ID }}
|
||||||
|
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
|
|
@@ -235,3 +235,9 @@ type FlagsIntoPositionalArgs' =
|
|||||||
[<PositionalArgs false>]
|
[<PositionalArgs false>]
|
||||||
DontGrabEverything : string list
|
DontGrabEverything : string list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[<ArgParser true>]
|
||||||
|
type PassThru =
|
||||||
|
{
|
||||||
|
A : ParentRecordChildPos
|
||||||
|
}
|
||||||
|
35
ConsumePlugin/ArgsWithUnions.fs
Normal file
35
ConsumePlugin/ArgsWithUnions.fs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
namespace ConsumePlugin.ArgsWithUnions
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
type BasicNoPositionals =
|
||||||
|
{
|
||||||
|
Foo : int
|
||||||
|
Bar : string
|
||||||
|
Baz : bool
|
||||||
|
Rest : int list
|
||||||
|
}
|
||||||
|
|
||||||
|
type UsernamePasswordAuth =
|
||||||
|
{
|
||||||
|
Username : string
|
||||||
|
Password : string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenAuth =
|
||||||
|
{
|
||||||
|
Token : string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthOptions =
|
||||||
|
| UsernamePassword of UsernamePasswordAuth
|
||||||
|
| Token of TokenAuth
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type DoTheThing =
|
||||||
|
{
|
||||||
|
Basics : BasicNoPositionals
|
||||||
|
Auth : AuthOptions
|
||||||
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags>
|
<OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="myriad.toml"/>
|
<None Include="myriad.toml"/>
|
||||||
<Compile Include="AssemblyInfo.fs" />
|
<Compile Include="AssemblyInfo.fs" />
|
||||||
|
<!--
|
||||||
<Compile Include="RecordFile.fs"/>
|
<Compile Include="RecordFile.fs"/>
|
||||||
<Compile Include="GeneratedRecord.fs">
|
<Compile Include="GeneratedRecord.fs">
|
||||||
<MyriadFile>RecordFile.fs</MyriadFile>
|
<MyriadFile>RecordFile.fs</MyriadFile>
|
||||||
@@ -66,10 +67,16 @@
|
|||||||
<Compile Include="ListCata.fs">
|
<Compile Include="ListCata.fs">
|
||||||
<MyriadFile>List.fs</MyriadFile>
|
<MyriadFile>List.fs</MyriadFile>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
-->
|
||||||
<Compile Include="Args.fs" />
|
<Compile Include="Args.fs" />
|
||||||
<Compile Include="GeneratedArgs.fs">
|
<Compile Include="GeneratedArgs.fs">
|
||||||
<MyriadFile>Args.fs</MyriadFile>
|
<MyriadFile>Args.fs</MyriadFile>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="ArgsWithUnions.fs" />
|
||||||
|
<Compile Include="GeneratedArgsWithUnions.fs">
|
||||||
|
<MyriadFile>ArgsWithUnions.fs</MyriadFile>
|
||||||
|
</Compile>
|
||||||
|
<!--
|
||||||
<None Include="swagger-gitea.json" />
|
<None Include="swagger-gitea.json" />
|
||||||
<Compile Include="GeneratedSwaggerGitea.fs">
|
<Compile Include="GeneratedSwaggerGitea.fs">
|
||||||
<MyriadFile>swagger-gitea.json</MyriadFile>
|
<MyriadFile>swagger-gitea.json</MyriadFile>
|
||||||
@@ -81,6 +88,7 @@
|
|||||||
<Compile Include="Generated2SwaggerGitea.fs">
|
<Compile Include="Generated2SwaggerGitea.fs">
|
||||||
<MyriadFile>GeneratedSwaggerGitea.fs</MyriadFile>
|
<MyriadFile>GeneratedSwaggerGitea.fs</MyriadFile>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -26769,8 +26769,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"admin/cron/{task}"
|
"admin/cron/{task}".Replace ("{task}", task.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{task}", task.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -26902,8 +26901,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"admin/hooks/{id}"
|
"admin/hooks/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -26945,8 +26943,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"admin/hooks/{id}"
|
"admin/hooks/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -27584,8 +27581,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"amdin/hooks/{id}"
|
"amdin/hooks/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -28008,8 +28004,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"org/{org}/repos"
|
"org/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -28292,8 +28287,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("orgs/{org}/hooks"
|
("orgs/{org}/hooks".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then
|
+ (if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -28345,8 +28339,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"orgs/{org}/hooks"
|
"orgs/{org}/hooks".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -28538,8 +28531,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("orgs/{org}/labels"
|
("orgs/{org}/labels".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "orgs/{org}/labels".IndexOf (char 63) >= 0 then
|
+ (if "orgs/{org}/labels".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -28591,8 +28583,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"orgs/{org}/labels"
|
"orgs/{org}/labels".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -28784,8 +28775,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("orgs/{org}/members"
|
("orgs/{org}/members".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "orgs/{org}/members".IndexOf (char 63) >= 0 then
|
+ (if "orgs/{org}/members".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -29086,8 +29076,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("orgs/{org}/repos"
|
("orgs/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "orgs/{org}/repos".IndexOf (char 63) >= 0 then
|
+ (if "orgs/{org}/repos".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -29142,8 +29131,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"orgs/{org}/repos"
|
"orgs/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -29197,8 +29185,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("orgs/{org}/teams"
|
("orgs/{org}/teams".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "orgs/{org}/teams".IndexOf (char 63) >= 0 then
|
+ (if "orgs/{org}/teams".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -29250,8 +29237,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"orgs/{org}/teams"
|
"orgs/{org}/teams".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -39381,8 +39367,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"repositories/{id}"
|
"repositories/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -39745,8 +39730,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("teams/{id}/members"
|
("teams/{id}/members".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "teams/{id}/members".IndexOf (char 63) >= 0 then
|
+ (if "teams/{id}/members".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -39918,8 +39902,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("teams/{id}/repos"
|
("teams/{id}/repos".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
|
|
||||||
+ (if "teams/{id}/repos".IndexOf (char 63) >= 0 then
|
+ (if "teams/{id}/repos".IndexOf (char 63) >= 0 then
|
||||||
"&"
|
"&"
|
||||||
else
|
else
|
||||||
@@ -40807,8 +40790,7 @@ module Gitea =
|
|||||||
System.Uri ("/api/v1/", System.UriKind.Relative)
|
System.Uri ("/api/v1/", System.UriKind.Relative)
|
||||||
),
|
),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"user/gpg_keys/{id}"
|
"user/gpg_keys/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
File diff suppressed because it is too large
Load Diff
686
ConsumePlugin/GeneratedArgsWithUnions.fs
Normal file
686
ConsumePlugin/GeneratedArgsWithUnions.fs
Normal file
@@ -0,0 +1,686 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This code was generated by myriad.
|
||||||
|
// Changes to this file will be lost when the code is regenerated.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ArgParserHelpers
|
||||||
|
|
||||||
|
/// Helper types for arg parsing
|
||||||
|
module internal ArgParseHelpers_ConsumePlugin_ArgsWithUnions =
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
open ConsumePlugin.ArgsWithUnions
|
||||||
|
|
||||||
|
/// A partially-parsed BasicNoPositionals.
|
||||||
|
type internal BasicNoPositionals_InProgress =
|
||||||
|
{
|
||||||
|
mutable Bar : string option
|
||||||
|
mutable Baz : bool option
|
||||||
|
mutable Foo : int option
|
||||||
|
mutable Rest : ResizeArray<int>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
|
||||||
|
member this.Assemble_
|
||||||
|
(getEnvironmentVariable : string -> string)
|
||||||
|
(positionals : Choice<string * int, string * int> list)
|
||||||
|
: Result<BasicNoPositionals * string option, string list>
|
||||||
|
=
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
let positionalConsumers = ResizeArray<string> ()
|
||||||
|
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
|
||||||
|
|
||||||
|
let arg0 : int =
|
||||||
|
match this.Foo with
|
||||||
|
| Some result -> result
|
||||||
|
| None ->
|
||||||
|
errors.Add (sprintf "Required argument '--%s' received no value" "foo")
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
let arg1 : string =
|
||||||
|
match this.Bar with
|
||||||
|
| Some result -> result
|
||||||
|
| None ->
|
||||||
|
errors.Add (sprintf "Required argument '--%s' received no value" "bar")
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
let arg2 : bool =
|
||||||
|
match this.Baz with
|
||||||
|
| Some result -> result
|
||||||
|
| None ->
|
||||||
|
errors.Add (sprintf "Required argument '--%s' received no value" "baz")
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
let arg3 : int list = this.Rest |> Seq.toList
|
||||||
|
|
||||||
|
if positionalConsumers.Count <= 1 then
|
||||||
|
if outOfPlacePositionals.Count > 0 then
|
||||||
|
outOfPlacePositionals
|
||||||
|
|> String.concat " "
|
||||||
|
|> (fun x ->
|
||||||
|
if 0 = outOfPlacePositionals.Count then
|
||||||
|
"Unmatched args which look like they are meant to be flags. " + x
|
||||||
|
else
|
||||||
|
sprintf
|
||||||
|
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
|
||||||
|
positionalConsumers.[0]
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|> errors.Add
|
||||||
|
else
|
||||||
|
()
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
Ok (
|
||||||
|
{
|
||||||
|
Foo = arg0
|
||||||
|
Bar = arg1
|
||||||
|
Baz = arg2
|
||||||
|
Rest = arg3
|
||||||
|
},
|
||||||
|
Seq.tryExactlyOne positionalConsumers
|
||||||
|
)
|
||||||
|
else
|
||||||
|
errors |> Seq.toList |> Error
|
||||||
|
else
|
||||||
|
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
|
||||||
|
+ String.concat ", " positionalConsumers)
|
||||||
|
|> List.singleton
|
||||||
|
|> Error
|
||||||
|
|
||||||
|
static member _Empty () : BasicNoPositionals_InProgress =
|
||||||
|
{
|
||||||
|
Bar = None
|
||||||
|
Baz = None
|
||||||
|
Foo = None
|
||||||
|
Rest = ResizeArray ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processes the key-value pair, returning Error if no key was matched.
|
||||||
|
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||||
|
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||||
|
member this.ProcessKeyValueSelf_
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
if System.String.Equals (key, sprintf "--%s" "rest", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
value |> (fun x -> System.Int32.Parse x) |> (fun x -> x) |> this.Rest.Add
|
||||||
|
() |> Ok
|
||||||
|
else if System.String.Equals (key, sprintf "--%s" "foo", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match this.Foo with
|
||||||
|
| Some x ->
|
||||||
|
sprintf
|
||||||
|
"Argument '%s' was supplied multiple times: %s and %s"
|
||||||
|
(sprintf "--%s" "foo")
|
||||||
|
(x.ToString ())
|
||||||
|
(value.ToString ())
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
Ok ()
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
this.Foo <- value |> (fun x -> System.Int32.Parse x) |> Some
|
||||||
|
Ok ()
|
||||||
|
with _ as exc ->
|
||||||
|
exc.Message |> Some |> Error
|
||||||
|
else if System.String.Equals (key, sprintf "--%s" "baz", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match this.Baz with
|
||||||
|
| Some x ->
|
||||||
|
sprintf
|
||||||
|
"Argument '%s' was supplied multiple times: %s and %s"
|
||||||
|
(sprintf "--%s" "baz")
|
||||||
|
(x.ToString ())
|
||||||
|
(value.ToString ())
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
Ok ()
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
this.Baz <- value |> (fun x -> System.Boolean.Parse x) |> Some
|
||||||
|
Ok ()
|
||||||
|
with _ as exc ->
|
||||||
|
exc.Message |> Some |> Error
|
||||||
|
else if System.String.Equals (key, sprintf "--%s" "bar", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match this.Bar with
|
||||||
|
| Some x ->
|
||||||
|
sprintf
|
||||||
|
"Argument '%s' was supplied multiple times: %s and %s"
|
||||||
|
(sprintf "--%s" "bar")
|
||||||
|
(x.ToString ())
|
||||||
|
(value.ToString ())
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
Ok ()
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
this.Bar <- value |> (fun x -> x) |> Some
|
||||||
|
Ok ()
|
||||||
|
with _ as exc ->
|
||||||
|
exc.Message |> Some |> Error
|
||||||
|
else
|
||||||
|
Error None
|
||||||
|
|
||||||
|
member this.ProcessKeyValue
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
match this.ProcessKeyValueSelf_ argNum_ errors_ key value with
|
||||||
|
| Ok () -> Ok ()
|
||||||
|
| Error None -> Error None
|
||||||
|
| Error (Some errorFromLeaf) -> Error (Some errorFromLeaf)
|
||||||
|
|
||||||
|
/// Returns false if we didn't set a value.
|
||||||
|
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool =
|
||||||
|
if System.String.Equals (key, sprintf "--%s" "baz", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match this.Baz with
|
||||||
|
| Some _ ->
|
||||||
|
sprintf "Flag '%s' was supplied multiple times" (sprintf "--%s" "baz")
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
true
|
||||||
|
| None ->
|
||||||
|
this.Baz <- true |> Some
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
|
||||||
|
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
|
||||||
|
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
|
||||||
|
|
||||||
|
/// A partially-parsed UsernamePasswordAuth.
|
||||||
|
type internal UsernamePasswordAuth_InProgress =
|
||||||
|
{
|
||||||
|
mutable Password : string option
|
||||||
|
mutable Username : string option
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
|
||||||
|
member this.Assemble_
|
||||||
|
(getEnvironmentVariable : string -> string)
|
||||||
|
(positionals : Choice<string * int, string * int> list)
|
||||||
|
: Result<UsernamePasswordAuth * string option, string list>
|
||||||
|
=
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
let positionalConsumers = ResizeArray<string> ()
|
||||||
|
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
|
||||||
|
|
||||||
|
let arg0 : string =
|
||||||
|
match this.Username with
|
||||||
|
| Some result -> result
|
||||||
|
| None ->
|
||||||
|
errors.Add (sprintf "Required argument '--%s' received no value" "username")
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
let arg1 : string =
|
||||||
|
match this.Password with
|
||||||
|
| Some result -> result
|
||||||
|
| None ->
|
||||||
|
errors.Add (sprintf "Required argument '--%s' received no value" "password")
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
if positionalConsumers.Count <= 1 then
|
||||||
|
if outOfPlacePositionals.Count > 0 then
|
||||||
|
outOfPlacePositionals
|
||||||
|
|> String.concat " "
|
||||||
|
|> (fun x ->
|
||||||
|
if 0 = outOfPlacePositionals.Count then
|
||||||
|
"Unmatched args which look like they are meant to be flags. " + x
|
||||||
|
else
|
||||||
|
sprintf
|
||||||
|
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
|
||||||
|
positionalConsumers.[0]
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|> errors.Add
|
||||||
|
else
|
||||||
|
()
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
Ok (
|
||||||
|
{
|
||||||
|
Username = arg0
|
||||||
|
Password = arg1
|
||||||
|
},
|
||||||
|
Seq.tryExactlyOne positionalConsumers
|
||||||
|
)
|
||||||
|
else
|
||||||
|
errors |> Seq.toList |> Error
|
||||||
|
else
|
||||||
|
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
|
||||||
|
+ String.concat ", " positionalConsumers)
|
||||||
|
|> List.singleton
|
||||||
|
|> Error
|
||||||
|
|
||||||
|
static member _Empty () : UsernamePasswordAuth_InProgress =
|
||||||
|
{
|
||||||
|
Password = None
|
||||||
|
Username = None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processes the key-value pair, returning Error if no key was matched.
|
||||||
|
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||||
|
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||||
|
member this.ProcessKeyValueSelf_
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
if System.String.Equals (key, sprintf "--%s" "username", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match this.Username with
|
||||||
|
| Some x ->
|
||||||
|
sprintf
|
||||||
|
"Argument '%s' was supplied multiple times: %s and %s"
|
||||||
|
(sprintf "--%s" "username")
|
||||||
|
(x.ToString ())
|
||||||
|
(value.ToString ())
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
Ok ()
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
this.Username <- value |> (fun x -> x) |> Some
|
||||||
|
Ok ()
|
||||||
|
with _ as exc ->
|
||||||
|
exc.Message |> Some |> Error
|
||||||
|
else if
|
||||||
|
System.String.Equals (key, sprintf "--%s" "password", System.StringComparison.OrdinalIgnoreCase)
|
||||||
|
then
|
||||||
|
match this.Password with
|
||||||
|
| Some x ->
|
||||||
|
sprintf
|
||||||
|
"Argument '%s' was supplied multiple times: %s and %s"
|
||||||
|
(sprintf "--%s" "password")
|
||||||
|
(x.ToString ())
|
||||||
|
(value.ToString ())
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
Ok ()
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
this.Password <- value |> (fun x -> x) |> Some
|
||||||
|
Ok ()
|
||||||
|
with _ as exc ->
|
||||||
|
exc.Message |> Some |> Error
|
||||||
|
else
|
||||||
|
Error None
|
||||||
|
|
||||||
|
member this.ProcessKeyValue
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
match this.ProcessKeyValueSelf_ argNum_ errors_ key value with
|
||||||
|
| Ok () -> Ok ()
|
||||||
|
| Error None -> Error None
|
||||||
|
| Error (Some errorFromLeaf) -> Error (Some errorFromLeaf)
|
||||||
|
|
||||||
|
/// Returns false if we didn't set a value.
|
||||||
|
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool = false
|
||||||
|
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
|
||||||
|
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
|
||||||
|
|
||||||
|
/// A partially-parsed TokenAuth.
|
||||||
|
type internal TokenAuth_InProgress =
|
||||||
|
{
|
||||||
|
mutable Token : string option
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
|
||||||
|
member this.Assemble_
|
||||||
|
(getEnvironmentVariable : string -> string)
|
||||||
|
(positionals : Choice<string * int, string * int> list)
|
||||||
|
: Result<TokenAuth * string option, string list>
|
||||||
|
=
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
let positionalConsumers = ResizeArray<string> ()
|
||||||
|
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
|
||||||
|
|
||||||
|
let arg0 : string =
|
||||||
|
match this.Token with
|
||||||
|
| Some result -> result
|
||||||
|
| None ->
|
||||||
|
errors.Add (sprintf "Required argument '--%s' received no value" "token")
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
if positionalConsumers.Count <= 1 then
|
||||||
|
if outOfPlacePositionals.Count > 0 then
|
||||||
|
outOfPlacePositionals
|
||||||
|
|> String.concat " "
|
||||||
|
|> (fun x ->
|
||||||
|
if 0 = outOfPlacePositionals.Count then
|
||||||
|
"Unmatched args which look like they are meant to be flags. " + x
|
||||||
|
else
|
||||||
|
sprintf
|
||||||
|
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
|
||||||
|
positionalConsumers.[0]
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|> errors.Add
|
||||||
|
else
|
||||||
|
()
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
Ok (
|
||||||
|
{
|
||||||
|
Token = arg0
|
||||||
|
},
|
||||||
|
Seq.tryExactlyOne positionalConsumers
|
||||||
|
)
|
||||||
|
else
|
||||||
|
errors |> Seq.toList |> Error
|
||||||
|
else
|
||||||
|
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
|
||||||
|
+ String.concat ", " positionalConsumers)
|
||||||
|
|> List.singleton
|
||||||
|
|> Error
|
||||||
|
|
||||||
|
static member _Empty () : TokenAuth_InProgress =
|
||||||
|
{
|
||||||
|
Token = None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processes the key-value pair, returning Error if no key was matched.
|
||||||
|
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||||
|
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||||
|
member this.ProcessKeyValueSelf_
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
if System.String.Equals (key, sprintf "--%s" "token", System.StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match this.Token with
|
||||||
|
| Some x ->
|
||||||
|
sprintf
|
||||||
|
"Argument '%s' was supplied multiple times: %s and %s"
|
||||||
|
(sprintf "--%s" "token")
|
||||||
|
(x.ToString ())
|
||||||
|
(value.ToString ())
|
||||||
|
|> errors_.Add
|
||||||
|
|
||||||
|
Ok ()
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
this.Token <- value |> (fun x -> x) |> Some
|
||||||
|
Ok ()
|
||||||
|
with _ as exc ->
|
||||||
|
exc.Message |> Some |> Error
|
||||||
|
else
|
||||||
|
Error None
|
||||||
|
|
||||||
|
member this.ProcessKeyValue
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
match this.ProcessKeyValueSelf_ argNum_ errors_ key value with
|
||||||
|
| Ok () -> Ok ()
|
||||||
|
| Error None -> Error None
|
||||||
|
| Error (Some errorFromLeaf) -> Error (Some errorFromLeaf)
|
||||||
|
|
||||||
|
/// Returns false if we didn't set a value.
|
||||||
|
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool = false
|
||||||
|
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
|
||||||
|
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
|
||||||
|
|
||||||
|
/// A partially-parsed AuthOptions.
|
||||||
|
type internal AuthOptions_InProgress =
|
||||||
|
{
|
||||||
|
Token : TokenAuth_InProgress
|
||||||
|
UsernamePassword : UsernamePasswordAuth_InProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
|
||||||
|
member this.Assemble_
|
||||||
|
(getEnvironmentVariable : string -> string)
|
||||||
|
(positionals : Choice<string * int, string * int> list)
|
||||||
|
: Result<AuthOptions * string option, string list>
|
||||||
|
=
|
||||||
|
failwith "TODO"
|
||||||
|
|
||||||
|
static member _Empty () : AuthOptions_InProgress =
|
||||||
|
{
|
||||||
|
Token = TokenAuth_InProgress._Empty ()
|
||||||
|
UsernamePassword = UsernamePasswordAuth_InProgress._Empty ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
|
||||||
|
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
|
||||||
|
|
||||||
|
/// A partially-parsed DoTheThing.
|
||||||
|
type internal DoTheThing_InProgress =
|
||||||
|
{
|
||||||
|
mutable Auth : AuthOptions_InProgress
|
||||||
|
mutable Basics : BasicNoPositionals_InProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
|
||||||
|
member this.Assemble_
|
||||||
|
(getEnvironmentVariable : string -> string)
|
||||||
|
(positionals : Choice<string * int, string * int> list)
|
||||||
|
: Result<DoTheThing * string option, string list>
|
||||||
|
=
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
let positionalConsumers = ResizeArray<string> ()
|
||||||
|
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
|
||||||
|
|
||||||
|
let arg0 : BasicNoPositionals =
|
||||||
|
match this.Basics.Assemble_ getEnvironmentVariable positionals with
|
||||||
|
| Ok (result, consumedPositional) ->
|
||||||
|
match consumedPositional with
|
||||||
|
| None -> ()
|
||||||
|
| Some positionalConsumer -> positionalConsumers.Add positionalConsumer
|
||||||
|
|
||||||
|
result
|
||||||
|
| Error err ->
|
||||||
|
errors.AddRange err
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
let arg1 : AuthOptions =
|
||||||
|
match this.Auth.Assemble_ getEnvironmentVariable positionals with
|
||||||
|
| Ok (result, consumedPositional) ->
|
||||||
|
match consumedPositional with
|
||||||
|
| None -> ()
|
||||||
|
| Some positionalConsumer -> positionalConsumers.Add positionalConsumer
|
||||||
|
|
||||||
|
result
|
||||||
|
| Error err ->
|
||||||
|
errors.AddRange err
|
||||||
|
Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
if positionalConsumers.Count <= 1 then
|
||||||
|
if outOfPlacePositionals.Count > 0 then
|
||||||
|
outOfPlacePositionals
|
||||||
|
|> String.concat " "
|
||||||
|
|> (fun x ->
|
||||||
|
if 0 = outOfPlacePositionals.Count then
|
||||||
|
"Unmatched args which look like they are meant to be flags. " + x
|
||||||
|
else
|
||||||
|
sprintf
|
||||||
|
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
|
||||||
|
positionalConsumers.[0]
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|> errors.Add
|
||||||
|
else
|
||||||
|
()
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
Ok (
|
||||||
|
{
|
||||||
|
Basics = arg0
|
||||||
|
Auth = arg1
|
||||||
|
},
|
||||||
|
Seq.tryExactlyOne positionalConsumers
|
||||||
|
)
|
||||||
|
else
|
||||||
|
errors |> Seq.toList |> Error
|
||||||
|
else
|
||||||
|
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
|
||||||
|
+ String.concat ", " positionalConsumers)
|
||||||
|
|> List.singleton
|
||||||
|
|> Error
|
||||||
|
|
||||||
|
static member _Empty () : DoTheThing_InProgress =
|
||||||
|
{
|
||||||
|
Basics = BasicNoPositionals_InProgress._Empty ()
|
||||||
|
Auth = AuthOptions_InProgress._Empty ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Passes the key-value pair to any child records, returning Error if no key was matched.
|
||||||
|
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||||
|
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||||
|
member this.ProcessKeyValueRecord_
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
let errors : ResizeArray<string> = ResizeArray ()
|
||||||
|
|
||||||
|
match this.Basics.ProcessKeyValue argNum_ errors_ key value with
|
||||||
|
| Ok () -> Ok ()
|
||||||
|
| Error e -> Error None
|
||||||
|
|
||||||
|
member this.ProcessKeyValue
|
||||||
|
(argNum_ : int)
|
||||||
|
(errors_ : ResizeArray<string>)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
: Result<unit, string option>
|
||||||
|
=
|
||||||
|
match this.ProcessKeyValueRecord_ argNum_ errors_ key value with
|
||||||
|
| Ok () -> Ok ()
|
||||||
|
| Error errorFromRecord -> Error errorFromRecord
|
||||||
|
|
||||||
|
/// Returns false if we didn't set a value.
|
||||||
|
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool = false
|
||||||
|
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
|
||||||
|
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
|
||||||
|
namespace ConsumePlugin.ArgsWithUnions
|
||||||
|
|
||||||
|
open ArgParserHelpers
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Methods to parse arguments for the type DoTheThing
|
||||||
|
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
module DoTheThing =
|
||||||
|
type internal ParseState_DoTheThing =
|
||||||
|
/// Ready to consume a key or positional arg
|
||||||
|
| AwaitingKey
|
||||||
|
/// Waiting to receive a value for the key we've already consumed
|
||||||
|
| AwaitingValue of key : string
|
||||||
|
|
||||||
|
let parse' (getEnvironmentVariable : string -> string) (args : string list) : DoTheThing =
|
||||||
|
let inProgress =
|
||||||
|
ArgParseHelpers_ConsumePlugin_ArgsWithUnions.DoTheThing_InProgress._Empty ()
|
||||||
|
|
||||||
|
let positionals : ResizeArray<Choice<string * int, string * int>> = ResizeArray ()
|
||||||
|
let errors_ = ResizeArray ()
|
||||||
|
|
||||||
|
let rec go (argNum_ : int) (state : ParseState_DoTheThing) (args : string list) =
|
||||||
|
match args with
|
||||||
|
| [] ->
|
||||||
|
match state with
|
||||||
|
| ParseState_DoTheThing.AwaitingKey -> ()
|
||||||
|
| ParseState_DoTheThing.AwaitingValue key ->
|
||||||
|
if inProgress.SetFlagValue_ errors_ key then
|
||||||
|
()
|
||||||
|
else
|
||||||
|
sprintf
|
||||||
|
"Trailing argument %s had no value. Use a double-dash to separate positional args from key-value args."
|
||||||
|
key
|
||||||
|
|> errors_.Add
|
||||||
|
| "--" :: rest -> positionals.AddRange (rest |> Seq.map (fun x -> (x, argNum_ + 1)) |> Seq.map Choice2Of2)
|
||||||
|
| arg :: args ->
|
||||||
|
match state with
|
||||||
|
| ParseState_DoTheThing.AwaitingKey ->
|
||||||
|
if arg.StartsWith ("--", System.StringComparison.Ordinal) then
|
||||||
|
if arg = "--help" then
|
||||||
|
"TODO" |> failwithf "Help text requested.\n%s"
|
||||||
|
else
|
||||||
|
let equals = arg.IndexOf (char 61)
|
||||||
|
|
||||||
|
if equals < 0 then
|
||||||
|
go (argNum_ + 1) (ParseState_DoTheThing.AwaitingValue arg) args
|
||||||
|
else
|
||||||
|
let key = arg.[0 .. equals - 1]
|
||||||
|
let value = arg.[equals + 1 ..]
|
||||||
|
|
||||||
|
match inProgress.ProcessKeyValue argNum_ errors_ key value with
|
||||||
|
| Ok () -> go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
|
||||||
|
| Error x ->
|
||||||
|
match x with
|
||||||
|
| None ->
|
||||||
|
positionals.Add (Choice1Of2 (arg, argNum_))
|
||||||
|
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
|
||||||
|
| Some msg ->
|
||||||
|
sprintf "%s (at arg %s)" msg arg |> errors_.Add
|
||||||
|
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
|
||||||
|
else
|
||||||
|
(arg, argNum_) |> Choice1Of2 |> positionals.Add
|
||||||
|
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
|
||||||
|
| ParseState_DoTheThing.AwaitingValue key ->
|
||||||
|
match inProgress.ProcessKeyValue argNum_ errors_ key arg with
|
||||||
|
| Ok () -> go argNum_ ParseState_DoTheThing.AwaitingKey args
|
||||||
|
| Error exc ->
|
||||||
|
if inProgress.SetFlagValue_ errors_ key then
|
||||||
|
go argNum_ ParseState_DoTheThing.AwaitingKey (arg :: args)
|
||||||
|
else
|
||||||
|
(key, argNum_) |> Choice1Of2 |> positionals.Add
|
||||||
|
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey (arg :: args)
|
||||||
|
|
||||||
|
go 0 ParseState_DoTheThing.AwaitingKey args
|
||||||
|
|
||||||
|
if 0 = errors_.Count then
|
||||||
|
()
|
||||||
|
else
|
||||||
|
errors_
|
||||||
|
|> String.concat System.Environment.NewLine
|
||||||
|
|> (fun x -> "Errors during parse!\n" + x)
|
||||||
|
|> failwith
|
||||||
|
|
||||||
|
match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with
|
||||||
|
| Ok (result, posConsumer) ->
|
||||||
|
if positionals.Count > 0 && posConsumer.IsNone then
|
||||||
|
positionals
|
||||||
|
|> Seq.map (fun choiceValue ->
|
||||||
|
match choiceValue with
|
||||||
|
| Choice1Of2 (arg, _) -> arg
|
||||||
|
| Choice2Of2 (arg, _) -> arg
|
||||||
|
)
|
||||||
|
|> String.concat " "
|
||||||
|
|> sprintf "Parse error: The following arguments were not consumed: %s"
|
||||||
|
|> failwith
|
||||||
|
else
|
||||||
|
result
|
||||||
|
| Error e ->
|
||||||
|
e
|
||||||
|
|> String.concat System.Environment.NewLine
|
||||||
|
|> (fun x -> "Errors during parse!\n" + x)
|
||||||
|
|> failwith
|
||||||
|
|
||||||
|
let parse (args : string list) : DoTheThing =
|
||||||
|
parse' System.Environment.GetEnvironmentVariable args
|
@@ -206,3 +206,34 @@ type internal TypeWithInterfaceMock =
|
|||||||
|
|
||||||
interface System.IDisposable with
|
interface System.IDisposable with
|
||||||
member this.Dispose () : unit = this.Dispose ()
|
member this.Dispose () : unit = this.Dispose ()
|
||||||
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Mock record type for an interface
|
||||||
|
type internal TypeWithPropertiesMock =
|
||||||
|
{
|
||||||
|
/// Implementation of IDisposable.Dispose
|
||||||
|
Dispose : unit -> unit
|
||||||
|
Prop1 : unit -> int
|
||||||
|
Prop2 : unit -> unit Async
|
||||||
|
Mem1 : string option -> string[] Async
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An implementation where every method throws.
|
||||||
|
static member Empty : TypeWithPropertiesMock =
|
||||||
|
{
|
||||||
|
Dispose = (fun () -> ())
|
||||||
|
Prop1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop1"))
|
||||||
|
Prop2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop2"))
|
||||||
|
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeWithProperties with
|
||||||
|
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||||
|
member this.Prop1 = this.Prop1 ()
|
||||||
|
member this.Prop2 = this.Prop2 ()
|
||||||
|
|
||||||
|
interface System.IDisposable with
|
||||||
|
member this.Dispose () : unit = this.Dispose ()
|
||||||
|
@@ -160,8 +160,7 @@ module PureGymApi =
|
|||||||
| null -> System.Uri "https://whatnot.com/"
|
| null -> System.Uri "https://whatnot.com/"
|
||||||
| v -> v),
|
| v -> v),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
"v1/gyms/{gym}"
|
"v1/gyms/{gym}".Replace ("{gym}", gym.ToString () |> System.Uri.EscapeDataString),
|
||||||
.Replace ("{gym}", gym.ToString () |> System.Uri.EscapeDataString),
|
|
||||||
System.UriKind.Relative
|
System.UriKind.Relative
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@@ -48,3 +48,10 @@ type TypeWithInterface =
|
|||||||
inherit IDisposable
|
inherit IDisposable
|
||||||
abstract Mem1 : string option -> string[] Async
|
abstract Mem1 : string option -> string[] Async
|
||||||
abstract Mem2 : unit -> string[] Async
|
abstract Mem2 : unit -> string[] Async
|
||||||
|
|
||||||
|
[<GenerateMock>]
|
||||||
|
type TypeWithProperties =
|
||||||
|
inherit IDisposable
|
||||||
|
abstract Mem1 : string option -> string[] Async
|
||||||
|
abstract Prop1 : int
|
||||||
|
abstract Prop2 : unit Async
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
<WarnOn>FS3388,FS3559</WarnOn>
|
<WarnOn>FS3388,FS3559</WarnOn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.143" PrivateAssets="all"/>
|
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all"/>
|
||||||
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
|
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
||||||
|
47
Playground/Domain.fs
Normal file
47
Playground/Domain.fs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
namespace Playground
|
||||||
|
|
||||||
|
open System
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type SubMode1 =
|
||||||
|
{
|
||||||
|
Info1 : int
|
||||||
|
Info2 : string
|
||||||
|
Rest : string list
|
||||||
|
}
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type SubMode2 =
|
||||||
|
{
|
||||||
|
Info1 : int
|
||||||
|
Info2 : string
|
||||||
|
Rest : int list
|
||||||
|
}
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type Mode1 =
|
||||||
|
{
|
||||||
|
Things : SubMode1
|
||||||
|
Whatnot : int
|
||||||
|
}
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type Mode2 =
|
||||||
|
{
|
||||||
|
Things : SubMode2
|
||||||
|
Whatnot : DateTime
|
||||||
|
}
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type Modes =
|
||||||
|
| Mode1 of Mode1
|
||||||
|
| Mode2 of Mode2
|
||||||
|
|
||||||
|
[<ArgParser>]
|
||||||
|
type Args =
|
||||||
|
{
|
||||||
|
WhatToDo : Modes
|
||||||
|
[<PositionalArgs>]
|
||||||
|
OtherArgs : string list
|
||||||
|
}
|
563
Playground/Library.fs
Normal file
563
Playground/Library.fs
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This code was generated by myriad.
|
||||||
|
// Changes to this file will be lost when the code is regenerated.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Playground // Assuming a namespace
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open WoofWare.Myriad.Plugins // Assuming attributes are here
|
||||||
|
|
||||||
|
// Assume original type definitions are accessible here
|
||||||
|
// [<ArgParser>] type SubMode1 = { Info1 : int; Info2 : string; Rest : string list }
|
||||||
|
// [<ArgParser>] type SubMode2 = { Info1 : int; Info2 : string; Rest : int list }
|
||||||
|
// [<ArgParser>] type Mode1 = { Things : SubMode1; Whatnot : int }
|
||||||
|
// [<ArgParser>] type Mode2 = { Things : SubMode2; Whatnot : DateTime }
|
||||||
|
// [<ArgParser>] type Modes = | Mode1 of Mode1 | Mode2 of Mode2
|
||||||
|
// [<ArgParser>] type Args = { WhatToDo : Modes; [<PositionalArgs>] OtherArgs : string list }
|
||||||
|
|
||||||
|
|
||||||
|
/// Methods to parse arguments for the type Args
|
||||||
|
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
module Args =
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Internal state definitions (Non-Flattened with combined Assemble/Validate)
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// State representing the parse progress for SubMode1 record
|
||||||
|
type private State_SubMode1 =
|
||||||
|
{
|
||||||
|
mutable Info1 : int option
|
||||||
|
mutable Info2 : string option
|
||||||
|
Rest : ResizeArray<string> // Corresponds to --rest
|
||||||
|
}
|
||||||
|
|
||||||
|
static member Create () =
|
||||||
|
{
|
||||||
|
Info1 = None
|
||||||
|
Info2 = None
|
||||||
|
Rest = ResizeArray ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check completeness and assemble the SubMode1 record from state.
|
||||||
|
member this.Assemble () : Result<SubMode1, string list> =
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
let mutable complete = true
|
||||||
|
|
||||||
|
if this.Info1.IsNone then
|
||||||
|
complete <- false
|
||||||
|
errors.Add ("Argument '--info1' is required.")
|
||||||
|
|
||||||
|
if this.Info2.IsNone then
|
||||||
|
complete <- false
|
||||||
|
errors.Add ("Argument '--info2' is required.")
|
||||||
|
// Rest is list, always 'complete'
|
||||||
|
|
||||||
|
if complete then
|
||||||
|
Ok
|
||||||
|
{
|
||||||
|
Info1 = this.Info1.Value
|
||||||
|
Info2 = this.Info2.Value
|
||||||
|
Rest = this.Rest |> Seq.toList
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Error (errors |> Seq.toList)
|
||||||
|
|
||||||
|
/// State representing the parse progress for SubMode2 record
|
||||||
|
type private State_SubMode2 =
|
||||||
|
{
|
||||||
|
mutable Info1 : int option
|
||||||
|
mutable Info2 : string option
|
||||||
|
Rest : ResizeArray<int> // Corresponds to --rest
|
||||||
|
}
|
||||||
|
|
||||||
|
static member Create () =
|
||||||
|
{
|
||||||
|
Info1 = None
|
||||||
|
Info2 = None
|
||||||
|
Rest = ResizeArray ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check completeness and assemble the SubMode2 record from state.
|
||||||
|
member this.Assemble () : Result<SubMode2, string list> =
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
|
||||||
|
if this.Info1.IsNone then
|
||||||
|
errors.Add ("Argument '--info1' is required.")
|
||||||
|
|
||||||
|
if this.Info2.IsNone then
|
||||||
|
errors.Add ("Argument '--info2' is required.")
|
||||||
|
// Rest is list, always 'complete'
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
Ok
|
||||||
|
{
|
||||||
|
Info1 = this.Info1.Value
|
||||||
|
Info2 = this.Info2.Value
|
||||||
|
Rest = this.Rest |> Seq.toList
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Error (errors |> Seq.toList)
|
||||||
|
|
||||||
|
|
||||||
|
/// State representing the parse progress for Mode1 record (references SubMode1 state)
|
||||||
|
type private State_Mode1 =
|
||||||
|
{
|
||||||
|
ThingsState : State_SubMode1 // Holds state for the nested record
|
||||||
|
mutable Whatnot : int option
|
||||||
|
}
|
||||||
|
|
||||||
|
static member Create () =
|
||||||
|
{
|
||||||
|
ThingsState = State_SubMode1.Create ()
|
||||||
|
Whatnot = None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check completeness and assemble the Mode1 record from state (including nested).
|
||||||
|
member this.Assemble () : Result<Mode1, string list> =
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
|
||||||
|
// Check direct fields
|
||||||
|
if this.Whatnot.IsNone then
|
||||||
|
errors.Add ("Argument '--whatnot' is required for Mode1.")
|
||||||
|
|
||||||
|
// Assemble nested state (which includes its own validation)
|
||||||
|
let thingsResult = this.ThingsState.Assemble ()
|
||||||
|
let mutable thingsValue = None
|
||||||
|
|
||||||
|
match thingsResult with
|
||||||
|
| Ok v -> thingsValue <- Some v
|
||||||
|
| Error nestedErrors -> errors.AddRange (nestedErrors |> List.map (sprintf "Things: %s")) // Add context
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
Ok
|
||||||
|
{
|
||||||
|
Things = thingsValue.Value
|
||||||
|
Whatnot = this.Whatnot.Value
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Error (errors |> Seq.toList)
|
||||||
|
|
||||||
|
|
||||||
|
/// State representing the parse progress for Mode2 record (references SubMode2 state)
|
||||||
|
type private State_Mode2 =
|
||||||
|
{
|
||||||
|
ThingsState : State_SubMode2 // Holds state for the nested record
|
||||||
|
mutable Whatnot : DateTime option
|
||||||
|
}
|
||||||
|
|
||||||
|
static member Create () =
|
||||||
|
{
|
||||||
|
ThingsState = State_SubMode2.Create ()
|
||||||
|
Whatnot = None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check completeness and assemble the Mode2 record from state (including nested).
|
||||||
|
member this.Assemble () : Result<Mode2, string list> =
|
||||||
|
let errors = ResizeArray<string> ()
|
||||||
|
|
||||||
|
// Check direct fields
|
||||||
|
if this.Whatnot.IsNone then
|
||||||
|
errors.Add ("Argument '--whatnot' is required for Mode2.")
|
||||||
|
|
||||||
|
// Assemble nested state (which includes its own validation)
|
||||||
|
let thingsResult = this.ThingsState.Assemble ()
|
||||||
|
let mutable thingsValue = Unchecked.defaultof<_>
|
||||||
|
|
||||||
|
match thingsResult with
|
||||||
|
| Ok v -> thingsValue <- v
|
||||||
|
| Error nestedErrors -> errors.AddRange (nestedErrors |> List.map (sprintf "Things: %s")) // Add context
|
||||||
|
|
||||||
|
if errors.Count = 0 then
|
||||||
|
{
|
||||||
|
Things = thingsValue
|
||||||
|
Whatnot = this.Whatnot.Value
|
||||||
|
}
|
||||||
|
|> Ok
|
||||||
|
else
|
||||||
|
Error (errors |> Seq.toList)
|
||||||
|
|
||||||
|
|
||||||
|
/// State for a single candidate parse path for the Modes DU (Structure unchanged)
|
||||||
|
type private CandidateParseState_Modes =
|
||||||
|
{
|
||||||
|
CaseName : string // "Mode1" or "Mode2"
|
||||||
|
mutable IsViable : bool
|
||||||
|
Errors : ResizeArray<string> // Errors specific to this candidate's path
|
||||||
|
ConsumedArgIndices : System.Collections.Generic.HashSet<int> // Indices consumed *by this candidate*
|
||||||
|
CaseState : obj // Holds either State_Mode1 or State_Mode2
|
||||||
|
}
|
||||||
|
|
||||||
|
static member CreateMode1 () =
|
||||||
|
{
|
||||||
|
CaseName = "Mode1"
|
||||||
|
IsViable = true
|
||||||
|
Errors = ResizeArray ()
|
||||||
|
ConsumedArgIndices = System.Collections.Generic.HashSet ()
|
||||||
|
CaseState = State_Mode1.Create () :> obj
|
||||||
|
}
|
||||||
|
|
||||||
|
static member CreateMode2 () =
|
||||||
|
{
|
||||||
|
CaseName = "Mode2"
|
||||||
|
IsViable = true
|
||||||
|
Errors = ResizeArray ()
|
||||||
|
ConsumedArgIndices = System.Collections.Generic.HashSet ()
|
||||||
|
CaseState = State_Mode2.Create () :> obj
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Main Parser Logic
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type private ParseState_Args =
|
||||||
|
| AwaitingArg
|
||||||
|
| AwaitingValue of keyIndex : int * key : string
|
||||||
|
|
||||||
|
let parse' (getEnvironmentVariable : string -> string) (args : string list) : Args =
|
||||||
|
let ArgParser_errors = ResizeArray () // Global errors accumulator
|
||||||
|
|
||||||
|
let helpText () =
|
||||||
|
// Help text generation unchanged
|
||||||
|
[
|
||||||
|
(sprintf "%s int32%s%s" (sprintf "--%s" "info1") "" " (for Mode1/Mode2 Things)")
|
||||||
|
(sprintf "%s string%s%s" (sprintf "--%s" "info2") "" " (for Mode1/Mode2 Things)")
|
||||||
|
(sprintf "%s string%s%s" (sprintf "--%s" "rest") " (can be repeated)" " (for Mode1 Things)")
|
||||||
|
(sprintf "%s int32%s%s" (sprintf "--%s" "rest") " (can be repeated)" " (for Mode2 Things)")
|
||||||
|
(sprintf "%s int32%s%s" (sprintf "--%s" "whatnot") "" " (for Mode1)")
|
||||||
|
(sprintf "%s DateTime%s%s" (sprintf "--%s" "whatnot") "" " (for Mode2)")
|
||||||
|
(sprintf "%s string%s%s" (sprintf "--%s" "other-args") " (positional args) (can be repeated)" "")
|
||||||
|
]
|
||||||
|
|> String.concat "\n"
|
||||||
|
|
||||||
|
let arg_OtherArgs : string ResizeArray = ResizeArray ()
|
||||||
|
|
||||||
|
let mutable candidates_WhatToDo : CandidateParseState_Modes list =
|
||||||
|
[
|
||||||
|
CandidateParseState_Modes.CreateMode1 ()
|
||||||
|
CandidateParseState_Modes.CreateMode2 ()
|
||||||
|
]
|
||||||
|
|
||||||
|
let consumedArgIndices_WhatToDo = System.Collections.Generic.HashSet<int> ()
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Helper functions for applying args (applyKeyValueToSubModeXState unchanged)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
let applyKeyValueToSubMode1State
|
||||||
|
(argIndex : int)
|
||||||
|
(keyIndex : int)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
(subState : State_SubMode1)
|
||||||
|
(candidate : CandidateParseState_Modes)
|
||||||
|
: unit
|
||||||
|
=
|
||||||
|
// ... (Implementation identical to previous version) ...
|
||||||
|
if String.Equals (key, "--info1", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match subState.Info1 with
|
||||||
|
| Some _ ->
|
||||||
|
candidate.Errors.Add (sprintf "Argument '--info1' supplied multiple times (SubMode1)")
|
||||||
|
candidate.IsViable <- false
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
subState.Info1 <- Some (Int32.Parse value)
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
with ex ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Failed to parse '%s' for --info1 (SubMode1): %s" value ex.Message
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
elif String.Equals (key, "--info2", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match subState.Info2 with
|
||||||
|
| Some _ ->
|
||||||
|
candidate.Errors.Add (sprintf "Argument '--info2' supplied multiple times (SubMode1)")
|
||||||
|
candidate.IsViable <- false
|
||||||
|
| None ->
|
||||||
|
subState.Info2 <- Some value
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
elif String.Equals (key, "--rest", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
subState.Rest.Add value
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
else
|
||||||
|
()
|
||||||
|
|
||||||
|
let applyKeyValueToSubMode2State
|
||||||
|
(argIndex : int)
|
||||||
|
(keyIndex : int)
|
||||||
|
(key : string)
|
||||||
|
(value : string)
|
||||||
|
(subState : State_SubMode2)
|
||||||
|
(candidate : CandidateParseState_Modes)
|
||||||
|
: unit
|
||||||
|
=
|
||||||
|
// ... (Implementation identical to previous version) ...
|
||||||
|
if String.Equals (key, "--info1", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match subState.Info1 with
|
||||||
|
| Some _ ->
|
||||||
|
candidate.Errors.Add (sprintf "Argument '--info1' supplied multiple times (SubMode2)")
|
||||||
|
candidate.IsViable <- false
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
subState.Info1 <- Some (Int32.Parse value)
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
with ex ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Failed to parse '%s' for --info1 (SubMode2): %s" value ex.Message
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
elif String.Equals (key, "--info2", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match subState.Info2 with
|
||||||
|
| Some _ ->
|
||||||
|
candidate.Errors.Add (sprintf "Argument '--info2' supplied multiple times (SubMode2)")
|
||||||
|
candidate.IsViable <- false
|
||||||
|
| None ->
|
||||||
|
subState.Info2 <- Some value
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
elif String.Equals (key, "--rest", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
try
|
||||||
|
subState.Rest.Add (Int32.Parse value)
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
with ex ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Failed to parse '%s' as int32 for --rest (SubMode2): %s" value ex.Message
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
else
|
||||||
|
()
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Routing and Main Application Logic (applyKeyValueToCandidate unchanged)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
let applyKeyValueToCandidate
|
||||||
|
(argIndex : int, keyIndex : int, key : string, value : string)
|
||||||
|
(candidate : CandidateParseState_Modes)
|
||||||
|
: unit
|
||||||
|
=
|
||||||
|
// ... (Implementation identical to previous version, calling sub-state helpers) ...
|
||||||
|
if not candidate.IsViable then
|
||||||
|
()
|
||||||
|
else
|
||||||
|
|
||||||
|
match candidate.CaseName with
|
||||||
|
| "Mode1" ->
|
||||||
|
let state = candidate.CaseState :?> State_Mode1
|
||||||
|
|
||||||
|
if String.Equals (key, "--whatnot", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match state.Whatnot with
|
||||||
|
| Some _ ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Argument '--whatnot' supplied multiple times for Mode1 candidate"
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
state.Whatnot <- Some (Int32.Parse value)
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
with ex ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Failed to parse '%s' as int32 for --whatnot (Mode1): %s" value ex.Message
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
elif key = "--info1" || key = "--info2" || key = "--rest" then
|
||||||
|
applyKeyValueToSubMode1State argIndex keyIndex key value state.ThingsState candidate
|
||||||
|
else
|
||||||
|
()
|
||||||
|
| "Mode2" ->
|
||||||
|
let state = candidate.CaseState :?> State_Mode2
|
||||||
|
|
||||||
|
if String.Equals (key, "--whatnot", StringComparison.OrdinalIgnoreCase) then
|
||||||
|
match state.Whatnot with
|
||||||
|
| Some _ ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Argument '--whatnot' supplied multiple times for Mode2 candidate"
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
| None ->
|
||||||
|
try
|
||||||
|
state.Whatnot <- Some (DateTime.Parse value)
|
||||||
|
candidate.ConsumedArgIndices.Add argIndex |> ignore
|
||||||
|
candidate.ConsumedArgIndices.Add keyIndex |> ignore
|
||||||
|
with ex ->
|
||||||
|
candidate.Errors.Add (
|
||||||
|
sprintf "Failed to parse '%s' as DateTime for --whatnot (Mode2): %s" value ex.Message
|
||||||
|
)
|
||||||
|
|
||||||
|
candidate.IsViable <- false
|
||||||
|
elif key = "--info1" || key = "--info2" || key = "--rest" then
|
||||||
|
applyKeyValueToSubMode2State argIndex keyIndex key value state.ThingsState candidate
|
||||||
|
else
|
||||||
|
()
|
||||||
|
| _ -> failwith "Internal error: Unknown case name"
|
||||||
|
|
||||||
|
// processKeyValue, setFlagValue, and main loop `go` are identical to previous version
|
||||||
|
let processKeyValue (keyIndex : int, key : string, valueIndex : int, value : string) : bool =
|
||||||
|
let mutable handled = false
|
||||||
|
|
||||||
|
for candidate in candidates_WhatToDo do
|
||||||
|
let initialConsumedCount = candidate.ConsumedArgIndices.Count
|
||||||
|
|
||||||
|
if candidate.IsViable then
|
||||||
|
applyKeyValueToCandidate (valueIndex, keyIndex, key, value) candidate
|
||||||
|
|
||||||
|
if candidate.IsViable && candidate.ConsumedArgIndices.Count > initialConsumedCount then
|
||||||
|
handled <- true
|
||||||
|
consumedArgIndices_WhatToDo.Add keyIndex |> ignore
|
||||||
|
consumedArgIndices_WhatToDo.Add valueIndex |> ignore
|
||||||
|
|
||||||
|
handled
|
||||||
|
|
||||||
|
let setFlagValue (keyIndex : int) (key : string) : bool = false // No flags
|
||||||
|
|
||||||
|
let rec go (state : ParseState_Args) (args : (int * string) list) =
|
||||||
|
// ... (Implementation identical to previous version) ...
|
||||||
|
match args with
|
||||||
|
| [] ->
|
||||||
|
match state with
|
||||||
|
| ParseState_Args.AwaitingArg -> ()
|
||||||
|
| ParseState_Args.AwaitingValue (i, k) ->
|
||||||
|
if not (setFlagValue i k) then
|
||||||
|
ArgParser_errors.Add (sprintf "Trailing argument '%s' (at index %d) requires a value." k i)
|
||||||
|
| (idx, arg) :: rest ->
|
||||||
|
match state with
|
||||||
|
| ParseState_Args.AwaitingArg ->
|
||||||
|
if arg = "--" then
|
||||||
|
rest
|
||||||
|
|> List.iter (fun (i, v) ->
|
||||||
|
if not (consumedArgIndices_WhatToDo.Contains i) then
|
||||||
|
arg_OtherArgs.Add v
|
||||||
|
)
|
||||||
|
|
||||||
|
go ParseState_Args.AwaitingArg []
|
||||||
|
elif arg.StartsWith ("--") then
|
||||||
|
if arg = "--help" then
|
||||||
|
helpText () |> failwithf "Help text requested:\n%s"
|
||||||
|
else
|
||||||
|
let eq = arg.IndexOf ('=')
|
||||||
|
|
||||||
|
if eq > 0 then
|
||||||
|
let k = arg.[.. eq - 1]
|
||||||
|
let v = arg.[eq + 1 ..]
|
||||||
|
|
||||||
|
if not (processKeyValue (idx, k, idx, v)) then
|
||||||
|
if not (consumedArgIndices_WhatToDo.Contains idx) then
|
||||||
|
arg_OtherArgs.Add arg
|
||||||
|
|
||||||
|
go ParseState_Args.AwaitingArg rest
|
||||||
|
elif setFlagValue idx arg then
|
||||||
|
consumedArgIndices_WhatToDo.Add idx |> ignore
|
||||||
|
go ParseState_Args.AwaitingArg rest
|
||||||
|
else
|
||||||
|
go (ParseState_Args.AwaitingValue (idx, arg)) rest
|
||||||
|
else
|
||||||
|
if not (consumedArgIndices_WhatToDo.Contains idx) then
|
||||||
|
arg_OtherArgs.Add arg
|
||||||
|
|
||||||
|
go ParseState_Args.AwaitingArg rest
|
||||||
|
| ParseState_Args.AwaitingValue (keyIdx, key) ->
|
||||||
|
if processKeyValue (keyIdx, key, idx, arg) then
|
||||||
|
go ParseState_Args.AwaitingArg rest
|
||||||
|
elif setFlagValue keyIdx key then
|
||||||
|
consumedArgIndices_WhatToDo.Add keyIdx |> ignore<bool>
|
||||||
|
go ParseState_Args.AwaitingArg ((idx, arg) :: rest) // Reprocess arg
|
||||||
|
elif not (consumedArgIndices_WhatToDo.Contains keyIdx) then
|
||||||
|
arg_OtherArgs.Add key
|
||||||
|
|
||||||
|
if not (consumedArgIndices_WhatToDo.Contains idx) then
|
||||||
|
arg_OtherArgs.Add arg
|
||||||
|
|
||||||
|
go ParseState_Args.AwaitingArg rest
|
||||||
|
|
||||||
|
args |> List.mapi (fun i s -> (i, s)) |> go ParseState_Args.AwaitingArg
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Final Validation and Assembly (Uses new Assemble methods)
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
let viableWinners = candidates_WhatToDo |> List.filter (fun c -> c.IsViable)
|
||||||
|
// No longer filter based on IsComplete here; Assemble handles it.
|
||||||
|
// Still need to check for relative leftovers if that logic were implemented.
|
||||||
|
|
||||||
|
let whatToDoResult =
|
||||||
|
match viableWinners with
|
||||||
|
| [] ->
|
||||||
|
// Add specific errors from candidates that were viable *before* Assemble check
|
||||||
|
ArgParser_errors.Add ("No valid parse found for 'WhatToDo'.")
|
||||||
|
|
||||||
|
candidates_WhatToDo
|
||||||
|
|> List.iter (fun c ->
|
||||||
|
if c.Errors.Count <> 0 then
|
||||||
|
ArgParser_errors.Add (
|
||||||
|
sprintf " Candidate %s parse errors: %s" c.CaseName (String.concat "; " c.Errors)
|
||||||
|
)
|
||||||
|
// Potentially try to Assemble even non-viable ones to get completion errors? Maybe too complex.
|
||||||
|
)
|
||||||
|
|
||||||
|
Unchecked.defaultof<_> // Error path
|
||||||
|
|
||||||
|
| [ winner ] ->
|
||||||
|
// Assemble the winning case, checking the Result for completion errors
|
||||||
|
match winner.CaseName with
|
||||||
|
| "Mode1" ->
|
||||||
|
match (winner.CaseState :?> State_Mode1).Assemble () with
|
||||||
|
| Ok mode1Value -> Modes.Mode1 mode1Value
|
||||||
|
| Error completionErrors ->
|
||||||
|
ArgParser_errors.Add (sprintf "Validation failed for selected candidate Mode1:")
|
||||||
|
ArgParser_errors.AddRange completionErrors
|
||||||
|
Unchecked.defaultof<_> // Error path
|
||||||
|
| "Mode2" ->
|
||||||
|
match (winner.CaseState :?> State_Mode2).Assemble () with
|
||||||
|
| Ok mode2Value -> Modes.Mode2 mode2Value
|
||||||
|
| Error completionErrors ->
|
||||||
|
ArgParser_errors.Add (sprintf "Validation failed for selected candidate Mode2:")
|
||||||
|
ArgParser_errors.AddRange completionErrors
|
||||||
|
Unchecked.defaultof<_> // Error path
|
||||||
|
| _ -> failwith "Internal error: Unknown winning case name"
|
||||||
|
|
||||||
|
| winners -> // Ambiguous parse
|
||||||
|
ArgParser_errors.Add ("Ambiguous parse for 'WhatToDo'. Multiple modes potentially viable:")
|
||||||
|
|
||||||
|
winners
|
||||||
|
|> List.iter (fun c ->
|
||||||
|
ArgParser_errors.Add (
|
||||||
|
sprintf
|
||||||
|
" - %s (Initial Errors: %s)"
|
||||||
|
c.CaseName
|
||||||
|
(if c.Errors.Count = 0 then
|
||||||
|
"None"
|
||||||
|
else
|
||||||
|
String.concat "; " c.Errors)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Unchecked.defaultof<_> // Error path
|
||||||
|
|
||||||
|
// Finalize OtherArgs (unchanged)
|
||||||
|
let otherArgsResult = arg_OtherArgs |> Seq.toList
|
||||||
|
|
||||||
|
// Assemble Final Result or Fail (unchanged)
|
||||||
|
if ArgParser_errors.Count > 0 then
|
||||||
|
ArgParser_errors
|
||||||
|
|> String.concat "\n"
|
||||||
|
|> failwithf "Errors during parse!\n%s\n\nHelp Text:\n%s" (helpText ())
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WhatToDo = whatToDoResult
|
||||||
|
OtherArgs = otherArgsResult
|
||||||
|
}
|
||||||
|
|
||||||
|
let parse (args : string list) : Args =
|
||||||
|
parse' System.Environment.GetEnvironmentVariable args
|
19
Playground/Playground.fsproj
Normal file
19
Playground/Playground.fsproj
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Domain.fs" />
|
||||||
|
<Compile Include="Library.fs"/>
|
||||||
|
<Compile Include="Program.fs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WoofWare.Myriad.Plugins.Attributes\WoofWare.Myriad.Plugins.Attributes.fsproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
10
Playground/Program.fs
Normal file
10
Playground/Program.fs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Playground
|
||||||
|
|
||||||
|
module Program =
|
||||||
|
[<EntryPoint>]
|
||||||
|
let main argv =
|
||||||
|
[ "--whatnot=2024-01-12" ; "--info1=4" ; "--info2=hi" ]
|
||||||
|
|> Args.parse
|
||||||
|
|> printfn "%O"
|
||||||
|
|
||||||
|
0
|
@@ -26,6 +26,11 @@ type ArgParserAttribute (isExtensionMethod : bool) =
|
|||||||
/// an argument which looks like a flag but which we don't recognise.)
|
/// an argument which looks like a flag but which we don't recognise.)
|
||||||
/// We will still interpret `--help` as requesting help, unless it comes after
|
/// We will still interpret `--help` as requesting help, unless it comes after
|
||||||
/// a standalone `--` separator.
|
/// a standalone `--` separator.
|
||||||
|
///
|
||||||
|
/// If the type of the PositionalArgs field is `Choice<'a, 'a>`, then we will
|
||||||
|
/// tell you whether each arg came before or after a standalone `--` separator.
|
||||||
|
/// For example, `MyApp foo bar -- baz` with PositionalArgs of `Choice<string, string>`
|
||||||
|
/// would yield `Choice1Of2 foo, Choice1Of2 bar, Choice2Of2 baz`.
|
||||||
type PositionalArgsAttribute (includeFlagLike : bool) =
|
type PositionalArgsAttribute (includeFlagLike : bool) =
|
||||||
inherit Attribute ()
|
inherit Attribute ()
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<IsTestProject>true</IsTestProject>
|
<IsTestProject>true</IsTestProject>
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.1.5" />
|
<PackageReference Include="ApiSurface" Version="4.1.20" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.2.2"/>
|
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -79,11 +79,8 @@ module TestArgParser =
|
|||||||
|
|
||||||
exc.Message
|
exc.Message
|
||||||
|> shouldEqual
|
|> shouldEqual
|
||||||
"""Unable to process supplied arg --non-existent. Help text follows.
|
"""Errors during parse!
|
||||||
--foo int32 : This is a foo!
|
Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `--rest=` syntax, or place them after a trailing `--`. --non-existent"""
|
||||||
--bar string
|
|
||||||
--baz bool
|
|
||||||
--rest string (positional args) (can be repeated) : Here's where the rest of the args go"""
|
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Can supply positional args with key`` () =
|
let ``Can supply positional args with key`` () =
|
||||||
@@ -318,8 +315,7 @@ Required argument '--baz' received no value"""
|
|||||||
exc.Message
|
exc.Message
|
||||||
|> shouldEqual
|
|> shouldEqual
|
||||||
"""Errors during parse!
|
"""Errors during parse!
|
||||||
Input string was not in a correct format. (at arg --invariant-exact=23:59)
|
Input string was not in a correct format. (at arg --invariant-exact=23:59)"""
|
||||||
Required argument '--invariant-exact' received no value"""
|
|
||||||
|
|
||||||
let exc =
|
let exc =
|
||||||
Assert.Throws<exn> (fun () ->
|
Assert.Throws<exn> (fun () ->
|
||||||
@@ -337,8 +333,7 @@ Required argument '--invariant-exact' received no value"""
|
|||||||
exc.Message
|
exc.Message
|
||||||
|> shouldEqual
|
|> shouldEqual
|
||||||
"""Errors during parse!
|
"""Errors during parse!
|
||||||
Input string was not in a correct format. (at arg --exact=11:34)
|
Input string was not in a correct format. (at arg --exact=11:34)"""
|
||||||
Required argument '--exact' received no value"""
|
|
||||||
|
|
||||||
count.Value |> shouldEqual 0
|
count.Value |> shouldEqual 0
|
||||||
|
|
||||||
@@ -444,7 +439,7 @@ Required argument '--exact' received no value"""
|
|||||||
]
|
]
|
||||||
|> List.map TestCaseData
|
|> List.map TestCaseData
|
||||||
|
|
||||||
[<TestCaseSource(nameof (boolCases))>]
|
[<TestCaseSource(nameof boolCases)>]
|
||||||
let ``Bool env vars can be populated`` (envValue : string, boolValue : bool) =
|
let ``Bool env vars can be populated`` (envValue : string, boolValue : bool) =
|
||||||
let getEnvVar (s : string) =
|
let getEnvVar (s : string) =
|
||||||
s |> shouldEqual "CONSUMEPLUGIN_THINGS"
|
s |> shouldEqual "CONSUMEPLUGIN_THINGS"
|
||||||
@@ -604,7 +599,10 @@ Required argument '--exact' received no value"""
|
|||||||
)
|
)
|
||||||
|
|
||||||
exc.Message
|
exc.Message
|
||||||
|> shouldEqual """Unable to process argument --do-the-thing=foo as key --do-the-thing and value foo"""
|
|> shouldEqual
|
||||||
|
"""Errors during parse!
|
||||||
|
Required argument '--do-something-else' received no value
|
||||||
|
Required argument '--turn-it-on' received no value"""
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Long-form args help text`` () =
|
let ``Long-form args help text`` () =
|
||||||
@@ -692,7 +690,9 @@ Required argument '--exact' received no value"""
|
|||||||
)
|
)
|
||||||
|
|
||||||
exc.Message
|
exc.Message
|
||||||
|> shouldEqual """Unable to process argument --b=false as key --b and value false"""
|
|> shouldEqual
|
||||||
|
"""Errors during parse!
|
||||||
|
Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `--dont-grab-everything=` syntax, or place them after a trailing `--`. --b=false --c"""
|
||||||
|
|
||||||
let exc =
|
let exc =
|
||||||
Assert.Throws<exn> (fun () ->
|
Assert.Throws<exn> (fun () ->
|
||||||
@@ -703,4 +703,6 @@ Required argument '--exact' received no value"""
|
|||||||
// Again perhaps eccentric!
|
// Again perhaps eccentric!
|
||||||
// Again, we don't try to detect that the user has missed out the desired argument to `--a`.
|
// Again, we don't try to detect that the user has missed out the desired argument to `--a`.
|
||||||
exc.Message
|
exc.Message
|
||||||
|> shouldEqual """Unable to process argument --c=hi as key --c and value hi"""
|
|> shouldEqual
|
||||||
|
"""Errors during parse!
|
||||||
|
Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `--my-arg-name=` syntax, or place them after a trailing `--`. --c=hi"""
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins.Test
|
||||||
|
|
||||||
|
open FsUnitTyped
|
||||||
|
open NUnit.Framework
|
||||||
|
open ConsumePlugin.ArgsWithUnions
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestArgsWithUnions =
|
||||||
|
|
||||||
|
let argsWithUnionsCases =
|
||||||
|
[
|
||||||
|
["--token" ; "hello" ; "--foo" ; "3" ; "--bar=hi" ; "--baz"], { Auth = AuthOptions.Token { Token = "hello" } ; Basics = { Foo = 3 ; Bar = "hi" ; Baz = true ; Rest = [] } }
|
||||||
|
]
|
||||||
|
|> List.map TestCaseData
|
||||||
|
|
||||||
|
[<TestCaseSource (nameof argsWithUnionsCases)>]
|
||||||
|
let ``foo`` (args : string list, expected : DoTheThing) : unit =
|
||||||
|
args
|
||||||
|
|> DoTheThing.parse' (fun _ -> failwith "didn't expect env var")
|
||||||
|
|> shouldEqual expected
|
||||||
|
|
@@ -3,7 +3,7 @@ namespace WoofWare.Myriad.Plugins.Test
|
|||||||
open System
|
open System
|
||||||
open System.Collections.Generic
|
open System.Collections.Generic
|
||||||
open System.Text.Json.Nodes
|
open System.Text.Json.Nodes
|
||||||
open FsCheck.Random
|
open FsCheck.FSharp
|
||||||
open Microsoft.FSharp.Reflection
|
open Microsoft.FSharp.Reflection
|
||||||
open NUnit.Framework
|
open NUnit.Framework
|
||||||
open FsCheck
|
open FsCheck
|
||||||
@@ -15,21 +15,21 @@ module TestJsonSerde =
|
|||||||
|
|
||||||
let uriGen : Gen<Uri> =
|
let uriGen : Gen<Uri> =
|
||||||
gen {
|
gen {
|
||||||
let! suffix = Arb.generate<int>
|
let! suffix = ArbMap.generate<int> ArbMap.defaults
|
||||||
return Uri $"https://example.com/%i{suffix}"
|
return Uri $"https://example.com/%i{suffix}"
|
||||||
}
|
}
|
||||||
|
|
||||||
let rec innerGen (count : int) : Gen<InnerTypeWithBoth> =
|
let rec innerGen (count : int) : Gen<InnerTypeWithBoth> =
|
||||||
gen {
|
gen {
|
||||||
let! guid = Arb.generate<Guid>
|
let! guid = ArbMap.generate<Guid> ArbMap.defaults
|
||||||
let! mapKeys = Gen.listOf Arb.generate<NonNull<string>>
|
let! mapKeys = Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
|
||||||
let mapKeys = mapKeys |> List.map _.Get |> List.distinct
|
let mapKeys = mapKeys |> List.map _.Get |> List.distinct
|
||||||
let! mapValues = Gen.listOfLength mapKeys.Length uriGen
|
let! mapValues = Gen.listOfLength mapKeys.Length uriGen
|
||||||
let map = List.zip mapKeys mapValues |> Map.ofList
|
let map = List.zip mapKeys mapValues |> Map.ofList
|
||||||
|
|
||||||
let! concreteDictKeys =
|
let! concreteDictKeys =
|
||||||
if count > 0 then
|
if count > 0 then
|
||||||
Gen.listOf Arb.generate<NonNull<string>>
|
Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
|
||||||
else
|
else
|
||||||
Gen.constant []
|
Gen.constant []
|
||||||
|
|
||||||
@@ -50,13 +50,16 @@ module TestJsonSerde =
|
|||||||
|> List.map KeyValuePair
|
|> List.map KeyValuePair
|
||||||
|> Dictionary
|
|> Dictionary
|
||||||
|
|
||||||
let! readOnlyDictKeys = Gen.listOf Arb.generate<NonNull<string>>
|
let! readOnlyDictKeys = Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
|
||||||
let readOnlyDictKeys = readOnlyDictKeys |> List.map _.Get |> List.distinct
|
let readOnlyDictKeys = readOnlyDictKeys |> List.map _.Get |> List.distinct
|
||||||
let! readOnlyDictValues = Gen.listOfLength readOnlyDictKeys.Length (Gen.listOf Arb.generate<char>)
|
|
||||||
|
let! readOnlyDictValues =
|
||||||
|
Gen.listOfLength readOnlyDictKeys.Length (Gen.listOf (ArbMap.generate<char> ArbMap.defaults))
|
||||||
|
|
||||||
let readOnlyDict = List.zip readOnlyDictKeys readOnlyDictValues |> readOnlyDict
|
let readOnlyDict = List.zip readOnlyDictKeys readOnlyDictValues |> readOnlyDict
|
||||||
|
|
||||||
let! dictKeys = Gen.listOf uriGen
|
let! dictKeys = Gen.listOf uriGen
|
||||||
let! dictValues = Gen.listOfLength dictKeys.Length Arb.generate<bool>
|
let! dictValues = Gen.listOfLength dictKeys.Length (ArbMap.generate<bool> ArbMap.defaults)
|
||||||
let dict = List.zip dictKeys dictValues |> dict
|
let dict = List.zip dictKeys dictValues |> dict
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -71,28 +74,38 @@ module TestJsonSerde =
|
|||||||
|
|
||||||
let outerGen : Gen<JsonRecordTypeWithBoth> =
|
let outerGen : Gen<JsonRecordTypeWithBoth> =
|
||||||
gen {
|
gen {
|
||||||
let! a = Arb.generate<int>
|
let! a = ArbMap.generate<int> ArbMap.defaults
|
||||||
let! b = Arb.generate<NonNull<string>>
|
let! b = ArbMap.generate<NonNull<string>> ArbMap.defaults
|
||||||
let! c = Gen.listOf Arb.generate<int>
|
let! c = Gen.listOf (ArbMap.generate<int> ArbMap.defaults)
|
||||||
let! depth = Gen.choose (0, 2)
|
let! depth = Gen.choose (0, 2)
|
||||||
let! d = innerGen depth
|
let! d = innerGen depth
|
||||||
let! e = Gen.arrayOf Arb.generate<NonNull<string>>
|
let! e = Gen.arrayOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
|
||||||
let! arr = Gen.arrayOf Arb.generate<int>
|
let! arr = Gen.arrayOf (ArbMap.generate<int> ArbMap.defaults)
|
||||||
let! byte = Arb.generate
|
let! byte = ArbMap.generate ArbMap.defaults
|
||||||
let! sbyte = Arb.generate
|
let! sbyte = ArbMap.generate ArbMap.defaults
|
||||||
let! i = Arb.generate
|
let! i = ArbMap.generate ArbMap.defaults
|
||||||
let! i32 = Arb.generate
|
let! i32 = ArbMap.generate ArbMap.defaults
|
||||||
let! i64 = Arb.generate
|
let! i64 = ArbMap.generate ArbMap.defaults
|
||||||
let! u = Arb.generate
|
let! u = ArbMap.generate ArbMap.defaults
|
||||||
let! u32 = Arb.generate
|
let! u32 = ArbMap.generate ArbMap.defaults
|
||||||
let! u64 = Arb.generate
|
let! u64 = ArbMap.generate ArbMap.defaults
|
||||||
let! f = Arb.generate |> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>))
|
|
||||||
let! f32 = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|
let! f =
|
||||||
let! single = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|
ArbMap.generate ArbMap.defaults
|
||||||
let! intMeasureOption = Arb.generate
|
|> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>))
|
||||||
let! intMeasureNullable = Arb.generate
|
|
||||||
|
let! f32 =
|
||||||
|
ArbMap.generate ArbMap.defaults
|
||||||
|
|> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|
||||||
|
|
||||||
|
let! single =
|
||||||
|
ArbMap.generate ArbMap.defaults
|
||||||
|
|> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|
||||||
|
|
||||||
|
let! intMeasureOption = ArbMap.generate ArbMap.defaults
|
||||||
|
let! intMeasureNullable = ArbMap.generate ArbMap.defaults
|
||||||
let! someEnum = Gen.choose (0, 1)
|
let! someEnum = Gen.choose (0, 1)
|
||||||
let! timestamp = Arb.generate
|
let! timestamp = ArbMap.generate ArbMap.defaults
|
||||||
|
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
@@ -270,10 +283,10 @@ module TestJsonSerde =
|
|||||||
match case with
|
match case with
|
||||||
| 0 -> return FirstDu.EmptyCase
|
| 0 -> return FirstDu.EmptyCase
|
||||||
| 1 ->
|
| 1 ->
|
||||||
let! s = Arb.generate<NonNull<string>>
|
let! s = ArbMap.generate<NonNull<string>> ArbMap.defaults
|
||||||
return FirstDu.Case1 s.Get
|
return FirstDu.Case1 s.Get
|
||||||
| 2 ->
|
| 2 ->
|
||||||
let! i = Arb.generate<int>
|
let! i = ArbMap.generate<int> ArbMap.defaults
|
||||||
let! record = outerGen
|
let! record = outerGen
|
||||||
return FirstDu.Case2 (record, i)
|
return FirstDu.Case2 (record, i)
|
||||||
| _ -> return failwith $"unexpected: %i{case}"
|
| _ -> return failwith $"unexpected: %i{case}"
|
||||||
@@ -293,7 +306,6 @@ module TestJsonSerde =
|
|||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``DU generator covers all cases`` () =
|
let ``DU generator covers all cases`` () =
|
||||||
let rand = Random ()
|
|
||||||
let cases = FSharpType.GetUnionCases typeof<FirstDu>
|
let cases = FSharpType.GetUnionCases typeof<FirstDu>
|
||||||
let counts = Array.zeroCreate<int> cases.Length
|
let counts = Array.zeroCreate<int> cases.Length
|
||||||
|
|
||||||
@@ -301,11 +313,13 @@ module TestJsonSerde =
|
|||||||
|
|
||||||
let mutable i = 0
|
let mutable i = 0
|
||||||
|
|
||||||
while i < 10_000 && Array.exists (fun i -> i = 0) counts do
|
let property (du : FirstDu) =
|
||||||
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
|
|
||||||
let tag = decompose du
|
let tag = decompose du
|
||||||
counts.[tag] <- counts.[tag] + 1
|
counts.[tag] <- counts.[tag] + 1
|
||||||
i <- i + 1
|
i <- i + 1
|
||||||
|
true
|
||||||
|
|
||||||
|
Check.One (Config.Quick, Prop.forAll (Arb.fromGen duGen) property)
|
||||||
|
|
||||||
for i in counts do
|
for i in counts do
|
||||||
i |> shouldBeGreaterThan 0
|
i |> shouldBeGreaterThan 0
|
||||||
|
@@ -34,3 +34,16 @@ module TestMockGenerator =
|
|||||||
mock.Mem1 3 'a' |> shouldEqual "aaa"
|
mock.Mem1 3 'a' |> shouldEqual "aaa"
|
||||||
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
||||||
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Example of use: properties`` () =
|
||||||
|
let mock : TypeWithProperties =
|
||||||
|
{ TypeWithPropertiesMock.Empty with
|
||||||
|
Mem1 = fun i -> async { return Option.toArray i }
|
||||||
|
Prop1 = fun () -> 44
|
||||||
|
}
|
||||||
|
:> _
|
||||||
|
|
||||||
|
mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
|
||||||
|
|
||||||
|
mock.Prop1 |> shouldEqual 44
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<IsTestProject>true</IsTestProject>
|
<IsTestProject>true</IsTestProject>
|
||||||
<!--
|
<!--
|
||||||
@@ -9,9 +9,11 @@
|
|||||||
I have not yet seen a single instance where I care about this warning
|
I have not yet seen a single instance where I care about this warning
|
||||||
-->
|
-->
|
||||||
<NoWarn>$(NoWarn),NU1903</NoWarn>
|
<NoWarn>$(NoWarn),NU1903</NoWarn>
|
||||||
|
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<!--
|
||||||
<Compile Include="HttpClient.fs"/>
|
<Compile Include="HttpClient.fs"/>
|
||||||
<Compile Include="PureGymDtos.fs"/>
|
<Compile Include="PureGymDtos.fs"/>
|
||||||
<Compile Include="TestJsonParse\TestJsonParse.fs" />
|
<Compile Include="TestJsonParse\TestJsonParse.fs" />
|
||||||
@@ -33,20 +35,24 @@
|
|||||||
<Compile Include="TestCataGenerator\TestGift.fs" />
|
<Compile Include="TestCataGenerator\TestGift.fs" />
|
||||||
<Compile Include="TestCataGenerator\TestMyList.fs" />
|
<Compile Include="TestCataGenerator\TestMyList.fs" />
|
||||||
<Compile Include="TestCataGenerator\TestMyList2.fs" />
|
<Compile Include="TestCataGenerator\TestMyList2.fs" />
|
||||||
|
-->
|
||||||
<Compile Include="TestArgParser\TestArgParser.fs" />
|
<Compile Include="TestArgParser\TestArgParser.fs" />
|
||||||
|
<Compile Include="TestArgParser\TestArgsWithUnions.fs" />
|
||||||
|
<!--
|
||||||
<Compile Include="TestSwagger\TestSwaggerParse.fs" />
|
<Compile Include="TestSwagger\TestSwaggerParse.fs" />
|
||||||
<Compile Include="TestRemoveOptions.fs"/>
|
<Compile Include="TestRemoveOptions.fs"/>
|
||||||
<Compile Include="TestSurface.fs"/>
|
<Compile Include="TestSurface.fs"/>
|
||||||
|
-->
|
||||||
<None Include="../.github/workflows/dotnet.yaml" />
|
<None Include="../.github/workflows/dotnet.yaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.1.5"/>
|
<PackageReference Include="ApiSurface" Version="4.1.20"/>
|
||||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
<PackageReference Include="FsCheck" Version="3.2.0"/>
|
||||||
<PackageReference Include="FsUnit" Version="6.0.1"/>
|
<PackageReference Include="FsUnit" Version="7.0.1"/>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.2.2"/>
|
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -4,82 +4,8 @@ open System
|
|||||||
open System.Text
|
open System.Text
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.Text.Range
|
open Fantomas.FCS.Text.Range
|
||||||
|
open TypeEquality
|
||||||
type internal ArgParserOutputSpec =
|
open WoofWare.Whippet.Fantomas
|
||||||
{
|
|
||||||
ExtensionMethods : bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type internal FlagDu =
|
|
||||||
{
|
|
||||||
Name : Ident
|
|
||||||
Case1Name : Ident
|
|
||||||
Case2Name : Ident
|
|
||||||
/// Hopefully this is simply the const bool True or False, but it might e.g. be a literal
|
|
||||||
Case1Arg : SynExpr
|
|
||||||
/// Hopefully this is simply the const bool True or False, but it might e.g. be a literal
|
|
||||||
Case2Arg : SynExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
static member FromBoolean (flagDu : FlagDu) (value : SynExpr) =
|
|
||||||
SynExpr.ifThenElse
|
|
||||||
(SynExpr.equals value flagDu.Case1Arg)
|
|
||||||
(SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case2Name ])
|
|
||||||
(SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case1Name ])
|
|
||||||
|
|
||||||
/// The default value of an argument which admits default values can be pulled from different sources.
|
|
||||||
/// This defines which source a particular default value comes from.
|
|
||||||
type private ArgumentDefaultSpec =
|
|
||||||
/// From parsing the environment variable with the given name (e.g. "WOOFWARE_DISABLE_FOO" or whatever).
|
|
||||||
| EnvironmentVariable of name : SynExpr
|
|
||||||
/// From calling the static member `{typeWeParseInto}.Default{name}()`
|
|
||||||
/// For example, if `type MyArgs = { Thing : Choice<int, int> }`, then
|
|
||||||
/// we would use `MyArgs.DefaultThing () : int`.
|
|
||||||
///
|
|
||||||
| FunctionCall of name : Ident
|
|
||||||
|
|
||||||
type private Accumulation<'choice> =
|
|
||||||
| Required
|
|
||||||
| Optional
|
|
||||||
| Choice of 'choice
|
|
||||||
| List of Accumulation<'choice>
|
|
||||||
|
|
||||||
type private ParseFunction<'acc> =
|
|
||||||
{
|
|
||||||
FieldName : Ident
|
|
||||||
TargetVariable : Ident
|
|
||||||
/// Any of the forms in this set are acceptable, but make sure they all start with a dash, or we might
|
|
||||||
/// get confused with positional args or something! I haven't thought that hard about this.
|
|
||||||
/// In the default case, this is `Const("arg-name")` for the `ArgName : blah` field; note that we have
|
|
||||||
/// omitted the initial `--` that will be required at runtime.
|
|
||||||
ArgForm : SynExpr list
|
|
||||||
/// If this is a boolean-like field (e.g. a bool or a flag DU), the help text should look a bit different:
|
|
||||||
/// we should lie to the user about the value of the cases there.
|
|
||||||
/// Similarly, if we're reading from an environment variable with the laxer parsing rules of accepting e.g.
|
|
||||||
/// "0" instead of "false", we need to know if we're reading a bool.
|
|
||||||
/// In that case, `boolCases` is Some, and contains the construction of the flag (or boolean, in which case
|
|
||||||
/// you get no data).
|
|
||||||
BoolCases : Choice<FlagDu, unit> option
|
|
||||||
Help : SynExpr option
|
|
||||||
/// A function string -> %TargetType%, where TargetVariable is probably a `%TargetType% option`.
|
|
||||||
/// (Depending on `Accumulation`, we'll remove the `option` at the end of the parse, asserting that the
|
|
||||||
/// argument was supplied.)
|
|
||||||
/// This is allowed to throw if it fails to parse.
|
|
||||||
Parser : SynExpr
|
|
||||||
/// If `Accumulation` is `List`, then this is the type of the list *element*; analogously for optionals
|
|
||||||
/// and choices and so on.
|
|
||||||
TargetType : SynType
|
|
||||||
Accumulation : 'acc
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A SynExpr of type `string` which we can display to the user at generated-program runtime to display all
|
|
||||||
/// the ways they can refer to this arg.
|
|
||||||
member arg.HumanReadableArgForm : SynExpr =
|
|
||||||
let formatString = List.replicate arg.ArgForm.Length "--%s" |> String.concat " / "
|
|
||||||
|
|
||||||
(SynExpr.applyFunction (SynExpr.createIdent "sprintf") (SynExpr.CreateConst formatString), arg.ArgForm)
|
|
||||||
||> List.fold SynExpr.applyFunction
|
|
||||||
|> SynExpr.paren
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
type private ChoicePositional =
|
type private ChoicePositional =
|
||||||
@@ -112,14 +38,14 @@ type private ParseTree<'hasPositional> =
|
|||||||
/// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in
|
/// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in
|
||||||
/// the branch (e.g. each record field name),
|
/// the branch (e.g. each record field name),
|
||||||
/// and composes them into a `SynExpr` (e.g. the record-typed object).
|
/// and composes them into a `SynExpr` (e.g. the record-typed object).
|
||||||
| Branch of
|
| DescendRecord of
|
||||||
fields : (Ident * ParseTree<HasNoPositional>) list *
|
fields : (Ident * ParseTree<HasNoPositional>) list *
|
||||||
assemble : (Map<string, SynExpr> -> SynExpr) *
|
assemble : (Map<string, SynExpr> -> SynExpr) *
|
||||||
Teq<'hasPositional, HasNoPositional>
|
Teq<'hasPositional, HasNoPositional>
|
||||||
/// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in
|
/// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in
|
||||||
/// the branch (e.g. each record field name),
|
/// the branch (e.g. each record field name),
|
||||||
/// and composes them into a `SynExpr` (e.g. the record-typed object).
|
/// and composes them into a `SynExpr` (e.g. the record-typed object).
|
||||||
| BranchPos of
|
| DescendRecordPos of
|
||||||
posField : Ident *
|
posField : Ident *
|
||||||
fields : ParseTree<HasPositional> *
|
fields : ParseTree<HasPositional> *
|
||||||
(Ident * ParseTree<HasNoPositional>) list *
|
(Ident * ParseTree<HasNoPositional>) list *
|
||||||
@@ -182,63 +108,6 @@ module private ParseTree =
|
|||||||
|
|
||||||
go None ([], None) subs
|
go None ([], None) subs
|
||||||
|
|
||||||
let rec accumulatorsNonPos (tree : ParseTree<HasNoPositional>) : ParseFunctionNonPositional list =
|
|
||||||
match tree with
|
|
||||||
| ParseTree.PositionalLeaf (_, teq) -> exFalso teq
|
|
||||||
| ParseTree.BranchPos (_, _, _, _, teq) -> exFalso teq
|
|
||||||
| ParseTree.NonPositionalLeaf (pf, _) -> [ pf ]
|
|
||||||
| ParseTree.Branch (trees, _, _) -> trees |> List.collect (snd >> accumulatorsNonPos)
|
|
||||||
|
|
||||||
/// Returns the positional arg separately.
|
|
||||||
let rec accumulatorsPos
|
|
||||||
(tree : ParseTree<HasPositional>)
|
|
||||||
: ParseFunctionNonPositional list * ParseFunctionPositional
|
|
||||||
=
|
|
||||||
match tree with
|
|
||||||
| ParseTree.PositionalLeaf (pf, _) -> [], pf
|
|
||||||
| ParseTree.NonPositionalLeaf (_, teq) -> exFalso' teq
|
|
||||||
| ParseTree.Branch (_, _, teq) -> exFalso' teq
|
|
||||||
| ParseTree.BranchPos (_, tree, trees, _, _) ->
|
|
||||||
let nonPos = trees |> List.collect (snd >> accumulatorsNonPos)
|
|
||||||
|
|
||||||
let nonPos2, pos = accumulatorsPos tree
|
|
||||||
nonPos @ nonPos2, pos
|
|
||||||
|
|
||||||
/// Collect all the ParseFunctions which are necessary to define variables, throwing away
|
|
||||||
/// all information relevant to composing the resulting variables into records.
|
|
||||||
/// Returns the list of non-positional parsers, and any positional parser that exists.
|
|
||||||
let accumulators<'a> (tree : ParseTree<'a>) : ParseFunctionNonPositional list * ParseFunctionPositional option =
|
|
||||||
// Sad duplication of some code here, but it was the easiest way to make it type-safe :(
|
|
||||||
match tree with
|
|
||||||
| ParseTree.PositionalLeaf (pf, _) -> [], Some pf
|
|
||||||
| ParseTree.NonPositionalLeaf (pf, _) -> [ pf ], None
|
|
||||||
| ParseTree.Branch (trees, _, _) -> trees |> List.collect (snd >> accumulatorsNonPos) |> (fun i -> i, None)
|
|
||||||
| ParseTree.BranchPos (_, tree, trees, _, _) ->
|
|
||||||
let nonPos = trees |> List.collect (snd >> accumulatorsNonPos)
|
|
||||||
|
|
||||||
let nonPos2, pos = accumulatorsPos tree
|
|
||||||
nonPos @ nonPos2, Some pos
|
|
||||||
|
|
||||||
|> fun (nonPos, pos) ->
|
|
||||||
let duplicateArgs =
|
|
||||||
// This is best-effort. We can't necessarily detect all SynExprs here, but usually it'll be strings.
|
|
||||||
Option.toList (pos |> Option.map _.ArgForm) @ (nonPos |> List.map _.ArgForm)
|
|
||||||
|> Seq.concat
|
|
||||||
|> Seq.choose (fun expr ->
|
|
||||||
match expr |> SynExpr.stripOptionalParen with
|
|
||||||
| SynExpr.Const (SynConst.String (s, _, _), _) -> Some s
|
|
||||||
| _ -> None
|
|
||||||
)
|
|
||||||
|> List.ofSeq
|
|
||||||
|> List.groupBy id
|
|
||||||
|> List.choose (fun (key, v) -> if v.Length > 1 then Some key else None)
|
|
||||||
|
|
||||||
match duplicateArgs with
|
|
||||||
| [] -> nonPos, pos
|
|
||||||
| dups ->
|
|
||||||
let dups = dups |> String.concat " "
|
|
||||||
failwith $"Duplicate args detected! %s{dups}"
|
|
||||||
|
|
||||||
/// Build the return value.
|
/// Build the return value.
|
||||||
let rec instantiate<'a> (tree : ParseTree<'a>) : SynExpr =
|
let rec instantiate<'a> (tree : ParseTree<'a>) : SynExpr =
|
||||||
match tree with
|
match tree with
|
||||||
@@ -671,7 +540,7 @@ module internal ArgParserGenerator =
|
|||||||
args
|
args
|
||||||
|> Map.toList
|
|> Map.toList
|
||||||
|> List.map (fun (ident, expr) -> SynLongIdent.create [ Ident.create ident ], expr)
|
|> List.map (fun (ident, expr) -> SynLongIdent.create [ Ident.create ident ], expr)
|
||||||
|> AstHelper.instantiateRecord
|
|> SynExpr.createRecord None
|
||||||
)
|
)
|
||||||
|
|
||||||
tree, counter
|
tree, counter
|
||||||
@@ -1756,10 +1625,7 @@ type ArgParserGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let types =
|
let types = Ast.getTypes ast
|
||||||
Ast.extractTypeDefn ast
|
|
||||||
|> List.groupBy (fst >> List.map _.idText >> String.concat ".")
|
|
||||||
|> List.map (fun (_, v) -> fst (List.head v), List.collect snd v)
|
|
||||||
|
|
||||||
let opens = AstHelper.extractOpens ast
|
let opens = AstHelper.extractOpens ast
|
||||||
|
|
||||||
|
@@ -2,173 +2,7 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.Text.Range
|
open Fantomas.FCS.Text.Range
|
||||||
open Fantomas.FCS.Xml
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
type internal ParameterInfo =
|
|
||||||
{
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
IsOptional : bool
|
|
||||||
Id : Ident option
|
|
||||||
Type : SynType
|
|
||||||
}
|
|
||||||
|
|
||||||
type internal TupledArg =
|
|
||||||
{
|
|
||||||
HasParen : bool
|
|
||||||
Args : ParameterInfo list
|
|
||||||
}
|
|
||||||
|
|
||||||
type internal MemberInfo =
|
|
||||||
{
|
|
||||||
ReturnType : SynType
|
|
||||||
Accessibility : SynAccess option
|
|
||||||
/// Each element of this list is a list of args in a tuple, or just one arg if not a tuple.
|
|
||||||
Args : TupledArg list
|
|
||||||
Identifier : Ident
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
XmlDoc : PreXmlDoc option
|
|
||||||
IsInline : bool
|
|
||||||
IsMutable : bool
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
type internal PropertyAccessors =
|
|
||||||
| Get
|
|
||||||
| Set
|
|
||||||
| GetSet
|
|
||||||
|
|
||||||
type internal PropertyInfo =
|
|
||||||
{
|
|
||||||
Type : SynType
|
|
||||||
Accessibility : SynAccess option
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
XmlDoc : PreXmlDoc option
|
|
||||||
Accessors : PropertyAccessors
|
|
||||||
IsInline : bool
|
|
||||||
Identifier : Ident
|
|
||||||
}
|
|
||||||
|
|
||||||
type internal InterfaceType =
|
|
||||||
{
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
Name : LongIdent
|
|
||||||
Inherits : SynType list
|
|
||||||
Members : MemberInfo list
|
|
||||||
Properties : PropertyInfo list
|
|
||||||
Generics : SynTyparDecls option
|
|
||||||
Accessibility : SynAccess option
|
|
||||||
}
|
|
||||||
|
|
||||||
type internal RecordType =
|
|
||||||
{
|
|
||||||
Name : Ident
|
|
||||||
Fields : SynField list
|
|
||||||
/// Any additional members which are not record fields.
|
|
||||||
Members : SynMemberDefns option
|
|
||||||
XmlDoc : PreXmlDoc option
|
|
||||||
Generics : SynTyparDecls option
|
|
||||||
TypeAccessibility : SynAccess option
|
|
||||||
ImplAccessibility : SynAccess option
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse from the AST.
|
|
||||||
static member OfRecord
|
|
||||||
(sci : SynComponentInfo)
|
|
||||||
(smd : SynMemberDefns)
|
|
||||||
(access : SynAccess option)
|
|
||||||
(recordFields : SynField list)
|
|
||||||
: RecordType
|
|
||||||
=
|
|
||||||
match sci with
|
|
||||||
| SynComponentInfo.SynComponentInfo (attrs, typars, _, longId, doc, _, implAccess, _) ->
|
|
||||||
{
|
|
||||||
Name = List.last longId
|
|
||||||
Fields = recordFields
|
|
||||||
Members = if smd.IsEmpty then None else Some smd
|
|
||||||
XmlDoc = if doc.IsEmpty then None else Some doc
|
|
||||||
Generics = typars
|
|
||||||
ImplAccessibility = implAccess
|
|
||||||
TypeAccessibility = access
|
|
||||||
Attributes = attrs |> List.collect (fun l -> l.Attributes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Methods for manipulating UnionCase.
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module UnionCase =
|
|
||||||
/// Construct our structured `UnionCase` from an FCS `SynUnionCase`: extract everything
|
|
||||||
/// we care about from the AST representation.
|
|
||||||
let ofSynUnionCase (case : SynUnionCase) : UnionCase<Ident option> =
|
|
||||||
match case with
|
|
||||||
| SynUnionCase.SynUnionCase (attributes, ident, caseType, xmlDoc, access, _, _) ->
|
|
||||||
|
|
||||||
let ident =
|
|
||||||
match ident with
|
|
||||||
| SynIdent.SynIdent (ident, _) -> ident
|
|
||||||
|
|
||||||
let fields =
|
|
||||||
match caseType with
|
|
||||||
| SynUnionCaseKind.Fields cases -> cases
|
|
||||||
| SynUnionCaseKind.FullType _ -> failwith "unexpected FullType union"
|
|
||||||
|
|
||||||
{
|
|
||||||
Name = ident
|
|
||||||
XmlDoc = if xmlDoc.IsEmpty then None else Some xmlDoc
|
|
||||||
Access = access
|
|
||||||
Attributes = attributes |> List.collect (fun t -> t.Attributes)
|
|
||||||
Fields = fields |> List.map SynField.extract
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Functorial `map`.
|
|
||||||
let mapIdentFields<'a, 'b> (f : 'a -> 'b) (unionCase : UnionCase<'a>) : UnionCase<'b> =
|
|
||||||
{
|
|
||||||
Attributes = unionCase.Attributes
|
|
||||||
Name = unionCase.Name
|
|
||||||
Access = unionCase.Access
|
|
||||||
XmlDoc = unionCase.XmlDoc
|
|
||||||
Fields = unionCase.Fields |> List.map (SynField.mapIdent f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Everything you need to know about a discriminated union definition.
|
|
||||||
type internal UnionType =
|
|
||||||
{
|
|
||||||
/// The name of the DU: for example, `type Foo = | Blah` has this being `Foo`.
|
|
||||||
Name : Ident
|
|
||||||
/// Any additional members which are not union cases.
|
|
||||||
Members : SynMemberDefns option
|
|
||||||
/// Any docstring associated with the DU itself (not its cases).
|
|
||||||
XmlDoc : PreXmlDoc option
|
|
||||||
/// Generic type parameters this DU takes: `type Foo<'a> = | ...`.
|
|
||||||
Generics : SynTyparDecls option
|
|
||||||
/// Attributes of the DU (not its cases): `[<Attr>] type Foo = | ...`
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
/// Accessibility modifier of the DU: `type private Foo = ...`
|
|
||||||
TypeAccessibility : SynAccess option
|
|
||||||
/// Accessibility modifier of the DU's implementation: `type Foo = private | ...`
|
|
||||||
ImplAccessibility : SynAccess option
|
|
||||||
/// The actual DU cases themselves.
|
|
||||||
Cases : UnionCase<Ident option> list
|
|
||||||
}
|
|
||||||
|
|
||||||
static member OfUnion
|
|
||||||
(sci : SynComponentInfo)
|
|
||||||
(smd : SynMemberDefns)
|
|
||||||
(access : SynAccess option)
|
|
||||||
(cases : SynUnionCase list)
|
|
||||||
: UnionType
|
|
||||||
=
|
|
||||||
match sci with
|
|
||||||
| SynComponentInfo.SynComponentInfo (attrs, typars, _, longId, doc, _, implAccess, _) ->
|
|
||||||
{
|
|
||||||
Name = List.last longId
|
|
||||||
Members = if smd.IsEmpty then None else Some smd
|
|
||||||
XmlDoc = if doc.IsEmpty then None else Some doc
|
|
||||||
Generics = typars
|
|
||||||
Attributes = attrs |> List.collect (fun l -> l.Attributes)
|
|
||||||
TypeAccessibility = access
|
|
||||||
ImplAccessibility = implAccess
|
|
||||||
Cases = cases |> List.map UnionCase.ofSynUnionCase
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Anything that is part of an ADT.
|
/// Anything that is part of an ADT.
|
||||||
/// A record is a product of stuff; this type represents one of those stuffs.
|
/// A record is a product of stuff; this type represents one of those stuffs.
|
||||||
@@ -202,13 +36,6 @@ module internal AstHelper =
|
|||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
let instantiateRecord (fields : (SynLongIdent * SynExpr) list) : SynExpr =
|
|
||||||
let fields =
|
|
||||||
fields
|
|
||||||
|> List.map (fun (rfn, synExpr) -> SynExprRecordField ((rfn, true), Some range0, Some synExpr, None))
|
|
||||||
|
|
||||||
SynExpr.Record (None, None, fields, range0)
|
|
||||||
|
|
||||||
let defineRecordType (record : RecordType) : SynTypeDefn =
|
let defineRecordType (record : RecordType) : SynTypeDefn =
|
||||||
let name =
|
let name =
|
||||||
SynComponentInfo.create record.Name
|
SynComponentInfo.create record.Name
|
||||||
|
@@ -3,11 +3,11 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
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 WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal CataGenerator =
|
module internal CataGenerator =
|
||||||
open Fantomas.FCS.Text.Range
|
open Fantomas.FCS.Text.Range
|
||||||
open Myriad.Core.Ast
|
|
||||||
|
|
||||||
/// The user-provided DU contains cases, each of which contains fields.
|
/// The user-provided DU contains cases, each of which contains fields.
|
||||||
/// We have a hard-coded set of things we know how to deal with as field contents.
|
/// We have a hard-coded set of things we know how to deal with as field contents.
|
||||||
@@ -174,20 +174,14 @@ module internal CataGenerator =
|
|||||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "exactlyOne" ])
|
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "exactlyOne" ])
|
||||||
|> SynExpr.createLet
|
|> SynExpr.createLet
|
||||||
[
|
[
|
||||||
SynBinding.Let (
|
SynBinding.basicTuple
|
||||||
valData = SynValData.SynValData (None, SynValInfo.empty, None),
|
(allArtificialTyparNames
|
||||||
pattern =
|
|> List.map (fun (t : Ident) ->
|
||||||
SynPat.tupleNoParen (
|
SynPat.namedI (Ident.create (t.idText + "Stack") |> Ident.lowerFirstLetter)
|
||||||
allArtificialTyparNames
|
))
|
||||||
|> List.map (fun (t : Ident) ->
|
(SynExpr.applyFunction
|
||||||
SynPat.namedI (Ident.create (t.idText + "Stack") |> Ident.lowerFirstLetter)
|
(SynExpr.applyFunction (SynExpr.createIdent "loop") (SynExpr.createIdent "cata"))
|
||||||
)
|
(SynExpr.createIdent "instructions"))
|
||||||
),
|
|
||||||
expr =
|
|
||||||
SynExpr.applyFunction
|
|
||||||
(SynExpr.applyFunction (SynExpr.createIdent "loop") (SynExpr.createIdent "cata"))
|
|
||||||
(SynExpr.createIdent "instructions")
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|> SynExpr.sequential
|
|> SynExpr.sequential
|
||||||
@@ -1180,6 +1174,29 @@ module internal CataGenerator =
|
|||||||
]
|
]
|
||||||
|> SynModuleOrNamespace.createNamespace ns
|
|> SynModuleOrNamespace.createNamespace ns
|
||||||
|
|
||||||
|
/// This function comes from Myriad, and is therefore derived from an Apache 2.0-licenced work.
|
||||||
|
/// https://github.com/MoiraeSoftware/myriad/blob/3c9818faabf9d508c10c28d5ecd26e66fafb48a1/src/Myriad.Core/Ast.fs#L160
|
||||||
|
/// A copy of the Apache 2.0 licence is at ApacheLicence.txt.
|
||||||
|
let groupedTypeDefns (ast : ParsedInput) : (LongIdent * SynTypeDefn list) list =
|
||||||
|
let rec extractTypes (moduleDecls : SynModuleDecl list) (ns : LongIdent) =
|
||||||
|
[
|
||||||
|
for moduleDecl in moduleDecls do
|
||||||
|
match moduleDecl with
|
||||||
|
| SynModuleDecl.Types (types, _) -> yield (ns, types)
|
||||||
|
| SynModuleDecl.NestedModule (SynComponentInfo (_, _, _, longId, _, _, _, _), _, decls, _, _, _) ->
|
||||||
|
let combined = longId |> List.append ns
|
||||||
|
yield! (extractTypes decls combined)
|
||||||
|
| _ -> ()
|
||||||
|
]
|
||||||
|
|
||||||
|
[
|
||||||
|
match ast with
|
||||||
|
| ParsedInput.ImplFile (ParsedImplFileInput (_, _, _, _, _, modules, _, _, _)) ->
|
||||||
|
for SynModuleOrNamespace (namespaceId, _, _, moduleDecls, _, _, _, _, _) in modules do
|
||||||
|
yield! extractTypes moduleDecls namespaceId
|
||||||
|
| _ -> ()
|
||||||
|
]
|
||||||
|
|
||||||
open Myriad.Core
|
open Myriad.Core
|
||||||
|
|
||||||
/// Myriad generator that provides a catamorphism for an algebraic data type.
|
/// Myriad generator that provides a catamorphism for an algebraic data type.
|
||||||
@@ -1193,7 +1210,7 @@ type CreateCatamorphismGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let types = Ast.extractTypeDefn ast
|
let types = CataGenerator.groupedTypeDefns ast
|
||||||
|
|
||||||
let opens = AstHelper.extractOpens ast
|
let opens = AstHelper.extractOpens ast
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
open System.IO
|
open System.IO
|
||||||
open System.Net.Http
|
open System.Net.Http
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
type internal HttpClientGeneratorOutputSpec =
|
type internal HttpClientGeneratorOutputSpec =
|
||||||
{
|
{
|
||||||
@@ -643,7 +644,7 @@ module internal HttpClientGenerator =
|
|||||||
yield jsonNode
|
yield jsonNode
|
||||||
| String -> yield responseString
|
| String -> yield responseString
|
||||||
| Stream -> yield responseStream
|
| Stream -> yield responseStream
|
||||||
| Unit ->
|
| UnitType ->
|
||||||
// What we're returning doesn't depend on the content, so don't bother!
|
// What we're returning doesn't depend on the content, so don't bother!
|
||||||
()
|
()
|
||||||
| _ ->
|
| _ ->
|
||||||
@@ -995,7 +996,7 @@ type HttpClientGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let types = Ast.extractTypeDefn ast
|
let types = Ast.getTypes ast
|
||||||
|
|
||||||
let opens = AstHelper.extractOpens ast
|
let opens = AstHelper.extractOpens ast
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
open System
|
open System
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
type internal GenerateMockOutputSpec =
|
type internal GenerateMockOutputSpec =
|
||||||
{
|
{
|
||||||
@@ -88,7 +89,7 @@ module internal InterfaceMockGenerator =
|
|||||||
[]
|
[]
|
||||||
else
|
else
|
||||||
[ SynPat.unit ])
|
[ SynPat.unit ])
|
||||||
(AstHelper.instantiateRecord constructorFields)
|
(SynExpr.createRecord None constructorFields)
|
||||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|
||||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
|> SynBinding.withReturnAnnotation constructorReturnType
|
||||||
|> SynMemberDefn.staticMember
|
|> SynMemberDefn.staticMember
|
||||||
@@ -158,6 +159,15 @@ module internal InterfaceMockGenerator =
|
|||||||
|> SynMemberDefn.memberImplementation
|
|> SynMemberDefn.memberImplementation
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let properties =
|
||||||
|
interfaceType.Properties
|
||||||
|
|> List.map (fun pi ->
|
||||||
|
SynExpr.createLongIdent' [ Ident.create "this" ; pi.Identifier ]
|
||||||
|
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||||
|
|> SynBinding.basic [ Ident.create "this" ; pi.Identifier ] []
|
||||||
|
|> SynMemberDefn.memberImplementation
|
||||||
|
)
|
||||||
|
|
||||||
let interfaceName =
|
let interfaceName =
|
||||||
let baseName = SynType.createLongIdent interfaceType.Name
|
let baseName = SynType.createLongIdent interfaceType.Name
|
||||||
|
|
||||||
@@ -173,7 +183,7 @@ module internal InterfaceMockGenerator =
|
|||||||
|
|
||||||
SynType.app' baseName generics
|
SynType.app' baseName generics
|
||||||
|
|
||||||
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
|
SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0)
|
||||||
|
|
||||||
let access =
|
let access =
|
||||||
match interfaceType.Accessibility, spec.IsInternal with
|
match interfaceType.Accessibility, spec.IsInternal with
|
||||||
@@ -247,6 +257,15 @@ module internal InterfaceMockGenerator =
|
|||||||
|> SynField.make
|
|> SynField.make
|
||||||
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
|
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
|
||||||
|
|
||||||
|
let constructProperty (prop : PropertyInfo) : SynField =
|
||||||
|
{
|
||||||
|
Attrs = []
|
||||||
|
Ident = Some prop.Identifier
|
||||||
|
Type = SynType.toFun [ SynType.unit ] prop.Type
|
||||||
|
}
|
||||||
|
|> SynField.make
|
||||||
|
|> SynField.withDocString (prop.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
|
||||||
|
|
||||||
let createRecord
|
let createRecord
|
||||||
(namespaceId : LongIdent)
|
(namespaceId : LongIdent)
|
||||||
(opens : SynOpenDeclTarget list)
|
(opens : SynOpenDeclTarget list)
|
||||||
@@ -254,7 +273,12 @@ module internal InterfaceMockGenerator =
|
|||||||
: SynModuleOrNamespace
|
: SynModuleOrNamespace
|
||||||
=
|
=
|
||||||
let interfaceType = AstHelper.parseInterface interfaceType
|
let interfaceType = AstHelper.parseInterface interfaceType
|
||||||
let fields = interfaceType.Members |> List.map constructMember
|
|
||||||
|
let fields =
|
||||||
|
interfaceType.Members
|
||||||
|
|> List.map constructMember
|
||||||
|
|> List.append (interfaceType.Properties |> List.map constructProperty)
|
||||||
|
|
||||||
let docString = PreXmlDoc.create "Mock record type for an interface"
|
let docString = PreXmlDoc.create "Mock record type for an interface"
|
||||||
|
|
||||||
let name =
|
let name =
|
||||||
@@ -290,14 +314,14 @@ type InterfaceMockGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let types = Ast.extractTypeDefn ast
|
let types = Ast.getTypes ast
|
||||||
|
|
||||||
let namespaceAndInterfaces =
|
let namespaceAndInterfaces =
|
||||||
types
|
types
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.choose (fun (ns, types) ->
|
||||||
types
|
types
|
||||||
|> List.choose (fun typeDef ->
|
|> List.choose (fun typeDef ->
|
||||||
match Ast.getAttribute<GenerateMockAttribute> typeDef with
|
match SynTypeDefn.getAttribute typeof<GenerateMockAttribute>.Name typeDef with
|
||||||
| None ->
|
| None ->
|
||||||
let name = SynTypeDefn.getName typeDef |> List.map _.idText |> String.concat "."
|
let name = SynTypeDefn.getName typeDef |> List.map _.idText |> String.concat "."
|
||||||
|
|
||||||
|
@@ -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 WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
type internal JsonParseOutputSpec =
|
type internal JsonParseOutputSpec =
|
||||||
{
|
{
|
||||||
@@ -280,7 +281,7 @@ module internal JsonParseGenerator =
|
|||||||
parseNumberType options propertyName node primType
|
parseNumberType options propertyName node primType
|
||||||
|> SynExpr.pipeThroughFunction (Measure.getLanguagePrimitivesMeasure primType)
|
|> SynExpr.pipeThroughFunction (Measure.getLanguagePrimitivesMeasure primType)
|
||||||
| JsonNode -> node
|
| JsonNode -> node
|
||||||
| Unit -> SynExpr.CreateConst ()
|
| UnitType -> SynExpr.CreateConst ()
|
||||||
| _ ->
|
| _ ->
|
||||||
// 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 =
|
||||||
@@ -350,10 +351,7 @@ module internal JsonParseGenerator =
|
|||||||
let getParseOptions (fieldAttrs : SynAttribute list) =
|
let getParseOptions (fieldAttrs : SynAttribute list) =
|
||||||
(JsonParseOption.None, fieldAttrs)
|
(JsonParseOption.None, fieldAttrs)
|
||||||
||> List.fold (fun options attr ->
|
||> List.fold (fun options attr ->
|
||||||
if
|
if (SynLongIdent.toString attr.TypeName).EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
|
||||||
(SynLongIdent.toString attr.TypeName)
|
|
||||||
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
|
|
||||||
then
|
|
||||||
let qualifiedEnumValue =
|
let qualifiedEnumValue =
|
||||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
match SynExpr.stripOptionalParen attr.ArgExpr with
|
||||||
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
|
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
|
||||||
@@ -383,15 +381,13 @@ module internal JsonParseGenerator =
|
|||||||
let propertyNameAttr =
|
let propertyNameAttr =
|
||||||
fieldData.Attrs
|
fieldData.Attrs
|
||||||
|> List.tryFind (fun attr ->
|
|> List.tryFind (fun attr ->
|
||||||
(SynLongIdent.toString attr.TypeName)
|
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let extensionDataAttr =
|
let extensionDataAttr =
|
||||||
fieldData.Attrs
|
fieldData.Attrs
|
||||||
|> List.tryFind (fun attr ->
|
|> List.tryFind (fun attr ->
|
||||||
(SynLongIdent.toString attr.TypeName)
|
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonExtensionData", StringComparison.Ordinal)
|
||||||
.EndsWith ("JsonExtensionData", StringComparison.Ordinal)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let propertyName =
|
let propertyName =
|
||||||
@@ -484,7 +480,7 @@ module internal JsonParseGenerator =
|
|||||||
let finalConstruction =
|
let finalConstruction =
|
||||||
fields
|
fields
|
||||||
|> List.mapi (fun i fieldData -> SynLongIdent.createI fieldData.Ident, SynExpr.createIdent $"arg_%i{i}")
|
|> List.mapi (fun i fieldData -> SynLongIdent.createI fieldData.Ident, SynExpr.createIdent $"arg_%i{i}")
|
||||||
|> AstHelper.instantiateRecord
|
|> SynExpr.createRecord None
|
||||||
|
|
||||||
(finalConstruction, assignments)
|
(finalConstruction, assignments)
|
||||||
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)
|
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)
|
||||||
@@ -710,13 +706,13 @@ type JsonParseGenerator () =
|
|||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let relevantTypes =
|
let relevantTypes =
|
||||||
Ast.extractTypeDefn ast
|
Ast.getTypes ast
|
||||||
|> List.map (fun (name, defns) ->
|
|> List.map (fun (name, defns) ->
|
||||||
defns
|
defns
|
||||||
|> List.choose (fun defn ->
|
|> List.choose (fun defn ->
|
||||||
if Ast.isRecord defn then Some defn
|
if SynTypeDefn.isRecord defn then Some defn
|
||||||
elif Ast.isDu defn then Some defn
|
elif SynTypeDefn.isDu defn then Some defn
|
||||||
elif AstHelper.isEnum defn then Some defn
|
elif SynTypeDefn.isEnum defn then Some defn
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|> fun defns -> name, defns
|
|> fun defns -> name, defns
|
||||||
|
@@ -3,6 +3,7 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
open System
|
open System
|
||||||
open System.Text
|
open System.Text
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
type internal JsonSerializeOutputSpec =
|
type internal JsonSerializeOutputSpec =
|
||||||
{
|
{
|
||||||
@@ -147,7 +148,7 @@ module internal JsonSerializeGenerator =
|
|||||||
|> SynExpr.createLambda "field"
|
|> SynExpr.createLambda "field"
|
||||||
|> fun e -> e, false
|
|> fun e -> e, false
|
||||||
| JsonNode -> SynExpr.createIdent "id", true
|
| JsonNode -> SynExpr.createIdent "id", true
|
||||||
| Unit ->
|
| UnitType ->
|
||||||
SynExpr.createLambda
|
SynExpr.createLambda
|
||||||
"value"
|
"value"
|
||||||
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||||
@@ -179,8 +180,7 @@ module internal JsonSerializeGenerator =
|
|||||||
let propertyNameAttr =
|
let propertyNameAttr =
|
||||||
attrs
|
attrs
|
||||||
|> List.tryFind (fun attr ->
|
|> List.tryFind (fun attr ->
|
||||||
(SynLongIdent.toString attr.TypeName)
|
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
match propertyNameAttr with
|
match propertyNameAttr with
|
||||||
@@ -197,8 +197,7 @@ module internal JsonSerializeGenerator =
|
|||||||
let getIsJsonExtension (attrs : SynAttribute list) : bool =
|
let getIsJsonExtension (attrs : SynAttribute list) : bool =
|
||||||
attrs
|
attrs
|
||||||
|> List.tryFind (fun attr ->
|
|> List.tryFind (fun attr ->
|
||||||
(SynLongIdent.toString attr.TypeName)
|
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonExtensionData", StringComparison.Ordinal)
|
||||||
.EndsWith ("JsonExtensionData", StringComparison.Ordinal)
|
|
||||||
)
|
)
|
||||||
|> Option.isSome
|
|> Option.isSome
|
||||||
|
|
||||||
@@ -527,13 +526,13 @@ type JsonSerializeGenerator () =
|
|||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let relevantTypes =
|
let relevantTypes =
|
||||||
Ast.extractTypeDefn ast
|
Ast.getTypes ast
|
||||||
|> List.map (fun (name, defns) ->
|
|> List.map (fun (name, defns) ->
|
||||||
defns
|
defns
|
||||||
|> List.choose (fun defn ->
|
|> List.choose (fun defn ->
|
||||||
if Ast.isRecord defn then Some defn
|
if SynTypeDefn.isRecord defn then Some defn
|
||||||
elif Ast.isDu defn then Some defn
|
elif SynTypeDefn.isDu defn then Some defn
|
||||||
elif AstHelper.isEnum defn then Some defn
|
elif SynTypeDefn.isEnum defn then Some defn
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|> fun defns -> name, defns
|
|> fun defns -> name, defns
|
||||||
|
@@ -21,3 +21,13 @@ module private List =
|
|||||||
| Some head :: tail -> go (head :: acc) tail
|
| Some head :: tail -> go (head :: acc) tail
|
||||||
|
|
||||||
go [] l
|
go [] l
|
||||||
|
|
||||||
|
/// Return the first error encountered, or the entire list.
|
||||||
|
let allOkOrError<'ok, 'err> (l : Result<'ok, 'err> list) : Result<'ok list, 'err> =
|
||||||
|
let rec go acc l =
|
||||||
|
match l with
|
||||||
|
| [] -> Ok (List.rev acc)
|
||||||
|
| Error e :: _ -> Error e
|
||||||
|
| Ok o :: rest -> go (o :: acc) rest
|
||||||
|
|
||||||
|
go [] l
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal Measure =
|
module internal Measure =
|
||||||
@@ -20,5 +21,4 @@ module internal Measure =
|
|||||||
| l ->
|
| l ->
|
||||||
let l = String.concat "." l
|
let l = String.concat "." l
|
||||||
failwith $"unrecognised type for measure: %s{l}"
|
failwith $"unrecognised type for measure: %s{l}"
|
||||||
|
|
||||||
|> SynExpr.createLongIdent
|
|> SynExpr.createLongIdent
|
||||||
|
@@ -2,28 +2,6 @@ namespace WoofWare.Myriad.Plugins
|
|||||||
|
|
||||||
open System.Collections.Generic
|
open System.Collections.Generic
|
||||||
|
|
||||||
type internal DesiredGenerator =
|
|
||||||
| InterfaceMock of isInternal : bool option
|
|
||||||
| JsonParse of extensionMethod : bool option
|
|
||||||
| JsonSerialize of extensionMethod : bool option
|
|
||||||
| HttpClient of extensionMethod : bool option
|
|
||||||
|
|
||||||
static member Parse (s : string) =
|
|
||||||
match s with
|
|
||||||
| "GenerateMock" -> DesiredGenerator.InterfaceMock None
|
|
||||||
| "GenerateMock(true)" -> DesiredGenerator.InterfaceMock (Some true)
|
|
||||||
| "GenerateMock(false)" -> DesiredGenerator.InterfaceMock (Some false)
|
|
||||||
| "JsonParse" -> DesiredGenerator.JsonParse None
|
|
||||||
| "JsonParse(true)" -> DesiredGenerator.JsonParse (Some true)
|
|
||||||
| "JsonParse(false)" -> DesiredGenerator.JsonParse (Some false)
|
|
||||||
| "JsonSerialize" -> DesiredGenerator.JsonSerialize None
|
|
||||||
| "JsonSerialize(true)" -> DesiredGenerator.JsonSerialize (Some true)
|
|
||||||
| "JsonSerialize(false)" -> DesiredGenerator.JsonSerialize (Some false)
|
|
||||||
| "HttpClient" -> DesiredGenerator.HttpClient None
|
|
||||||
| "HttpClient(true)" -> DesiredGenerator.HttpClient (Some true)
|
|
||||||
| "HttpClient(false)" -> DesiredGenerator.HttpClient (Some false)
|
|
||||||
| _ -> failwith $"Failed to parse as a generator specification: %s{s}"
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal MyriadParamParser =
|
module internal MyriadParamParser =
|
||||||
(*
|
(*
|
||||||
|
23
WoofWare.Myriad.Plugins/Parameters.fs
Normal file
23
WoofWare.Myriad.Plugins/Parameters.fs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
type internal DesiredGenerator =
|
||||||
|
| InterfaceMock of isInternal : bool option
|
||||||
|
| JsonParse of extensionMethod : bool option
|
||||||
|
| JsonSerialize of extensionMethod : bool option
|
||||||
|
| HttpClient of extensionMethod : bool option
|
||||||
|
|
||||||
|
static member Parse (s : string) =
|
||||||
|
match s with
|
||||||
|
| "GenerateMock" -> DesiredGenerator.InterfaceMock None
|
||||||
|
| "GenerateMock(true)" -> DesiredGenerator.InterfaceMock (Some true)
|
||||||
|
| "GenerateMock(false)" -> DesiredGenerator.InterfaceMock (Some false)
|
||||||
|
| "JsonParse" -> DesiredGenerator.JsonParse None
|
||||||
|
| "JsonParse(true)" -> DesiredGenerator.JsonParse (Some true)
|
||||||
|
| "JsonParse(false)" -> DesiredGenerator.JsonParse (Some false)
|
||||||
|
| "JsonSerialize" -> DesiredGenerator.JsonSerialize None
|
||||||
|
| "JsonSerialize(true)" -> DesiredGenerator.JsonSerialize (Some true)
|
||||||
|
| "JsonSerialize(false)" -> DesiredGenerator.JsonSerialize (Some false)
|
||||||
|
| "HttpClient" -> DesiredGenerator.HttpClient None
|
||||||
|
| "HttpClient(true)" -> DesiredGenerator.HttpClient (Some true)
|
||||||
|
| "HttpClient(false)" -> DesiredGenerator.HttpClient (Some false)
|
||||||
|
| _ -> failwith $"Failed to parse as a generator specification: %s{s}"
|
@@ -1,32 +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
|
|
||||||
| "string" -> [ "System" ; "String" ] |> Some
|
|
||||||
| "bool" -> [ "System" ; "Boolean" ] |> Some
|
|
||||||
| _ -> None
|
|
||||||
|> Option.map (List.map (fun i -> (Ident (i, range0))))
|
|
@@ -1,7 +1,9 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open System
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module internal RemoveOptionsGenerator =
|
module internal RemoveOptionsGenerator =
|
||||||
@@ -58,7 +60,7 @@ module internal RemoveOptionsGenerator =
|
|||||||
Attributes = []
|
Attributes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
let typeDecl = AstHelper.defineRecordType record
|
let typeDecl = RecordType.ToAst record
|
||||||
|
|
||||||
SynModuleDecl.Types ([ typeDecl ], range0)
|
SynModuleDecl.Types ([ typeDecl ], range0)
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ module internal RemoveOptionsGenerator =
|
|||||||
|
|
||||||
SynLongIdent.createI fieldData.Ident, body
|
SynLongIdent.createI fieldData.Ident, body
|
||||||
)
|
)
|
||||||
|> AstHelper.instantiateRecord
|
|> SynExpr.createRecord None
|
||||||
|
|
||||||
SynBinding.basic
|
SynBinding.basic
|
||||||
[ functionName ]
|
[ functionName ]
|
||||||
@@ -145,44 +147,31 @@ type RemoveOptionsGenerator () =
|
|||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
let records = Ast.extractRecords ast
|
let records = Ast.getRecords ast
|
||||||
|
|
||||||
let namespaceAndRecords =
|
let namespaceAndRecords =
|
||||||
records
|
records
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.collect (fun (ns, ty) ->
|
||||||
match
|
ty
|
||||||
types
|
|> List.filter (fun record ->
|
||||||
|> List.filter (SynTypeDefn.hasAttribute typeof<RemoveOptionsAttribute>.Name)
|
record.Attributes
|
||||||
with
|
|> List.exists (fun attr ->
|
||||||
| [] -> None
|
attr.TypeName.LongIdent
|
||||||
| types ->
|
|> List.last
|
||||||
let types =
|
|> _.idText
|
||||||
types
|
|> fun s ->
|
||||||
|> List.map (fun ty ->
|
if s.EndsWith ("Attribute", StringComparison.Ordinal) then
|
||||||
match ty with
|
s
|
||||||
| SynTypeDefn.SynTypeDefn (sci,
|
else
|
||||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (access,
|
$"%s{s}Attribute"
|
||||||
fields,
|
|> (=) typeof<RemoveOptionsAttribute>.Name
|
||||||
_),
|
)
|
||||||
_),
|
)
|
||||||
smd,
|
|> List.map (fun ty -> ns, ty)
|
||||||
smdo,
|
|
||||||
_,
|
|
||||||
_) -> RecordType.OfRecord sci smd access fields
|
|
||||||
| _ -> failwith "unexpectedly not a record"
|
|
||||||
)
|
|
||||||
|
|
||||||
Some (ns, types)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
namespaceAndRecords
|
namespaceAndRecords
|
||||||
|> List.collect (fun (ns, records) ->
|
|> List.map (fun (ns, record) -> RemoveOptionsGenerator.createRecordModule ns record)
|
||||||
records
|
|
||||||
|> List.map (fun record ->
|
|
||||||
let recordModule = RemoveOptionsGenerator.createRecordModule ns record
|
|
||||||
recordModule
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
Output.Ast modules
|
Output.Ast modules
|
||||||
|
2659
WoofWare.Myriad.Plugins/ShibaGenerator.fs
Normal file
2659
WoofWare.Myriad.Plugins/ShibaGenerator.fs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -292,27 +292,4 @@ WoofWare.Myriad.Plugins.SwaggerParameter.In [property]: [read-only] WoofWare.Myr
|
|||||||
WoofWare.Myriad.Plugins.SwaggerParameter.Name [property]: [read-only] string
|
WoofWare.Myriad.Plugins.SwaggerParameter.Name [property]: [read-only] string
|
||||||
WoofWare.Myriad.Plugins.SwaggerParameter.Parse [static method]: System.Text.Json.Nodes.JsonObject -> WoofWare.Myriad.Plugins.SwaggerParameter
|
WoofWare.Myriad.Plugins.SwaggerParameter.Parse [static method]: System.Text.Json.Nodes.JsonObject -> WoofWare.Myriad.Plugins.SwaggerParameter
|
||||||
WoofWare.Myriad.Plugins.SwaggerParameter.Required [property]: [read-only] bool option
|
WoofWare.Myriad.Plugins.SwaggerParameter.Required [property]: [read-only] bool option
|
||||||
WoofWare.Myriad.Plugins.SwaggerParameter.Type [property]: [read-only] WoofWare.Myriad.Plugins.Definition
|
WoofWare.Myriad.Plugins.SwaggerParameter.Type [property]: [read-only] WoofWare.Myriad.Plugins.Definition
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1 inherit obj
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1..ctor [constructor]: (Fantomas.FCS.Syntax.SynAttribute list, 'Ident, Fantomas.FCS.Syntax.SynType)
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1.Attrs [property]: [read-only] Fantomas.FCS.Syntax.SynAttribute list
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1.get_Attrs [method]: unit -> Fantomas.FCS.Syntax.SynAttribute list
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1.get_Ident [method]: unit -> 'Ident
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1.get_Type [method]: unit -> Fantomas.FCS.Syntax.SynType
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1.Ident [property]: [read-only] 'Ident
|
|
||||||
WoofWare.Myriad.Plugins.SynFieldData`1.Type [property]: [read-only] Fantomas.FCS.Syntax.SynType
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase inherit obj
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase.mapIdentFields [static method]: ('a -> 'b) -> 'a WoofWare.Myriad.Plugins.UnionCase -> 'b WoofWare.Myriad.Plugins.UnionCase
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase.ofSynUnionCase [static method]: Fantomas.FCS.Syntax.SynUnionCase -> Fantomas.FCS.Syntax.Ident option WoofWare.Myriad.Plugins.UnionCase
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1 inherit obj
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1..ctor [constructor]: (Fantomas.FCS.Syntax.Ident, Fantomas.FCS.Xml.PreXmlDoc option, Fantomas.FCS.Syntax.SynAccess option, Fantomas.FCS.Syntax.SynAttribute list, 'ident WoofWare.Myriad.Plugins.SynFieldData list)
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.Access [property]: [read-only] Fantomas.FCS.Syntax.SynAccess option
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.Attributes [property]: [read-only] Fantomas.FCS.Syntax.SynAttribute list
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.Fields [property]: [read-only] 'ident WoofWare.Myriad.Plugins.SynFieldData list
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.get_Access [method]: unit -> Fantomas.FCS.Syntax.SynAccess option
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.get_Attributes [method]: unit -> Fantomas.FCS.Syntax.SynAttribute list
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.get_Fields [method]: unit -> 'ident WoofWare.Myriad.Plugins.SynFieldData list
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.get_Name [method]: unit -> Fantomas.FCS.Syntax.Ident
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.get_XmlDoc [method]: unit -> Fantomas.FCS.Xml.PreXmlDoc option
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.Name [property]: [read-only] Fantomas.FCS.Syntax.Ident
|
|
||||||
WoofWare.Myriad.Plugins.UnionCase`1.XmlDoc [property]: [read-only] Fantomas.FCS.Xml.PreXmlDoc option
|
|
@@ -6,6 +6,7 @@ open System.Threading
|
|||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
open Fantomas.FCS.Text.Range
|
open Fantomas.FCS.Text.Range
|
||||||
|
open WoofWare.Whippet.Fantomas
|
||||||
|
|
||||||
type internal SwaggerClientConfig =
|
type internal SwaggerClientConfig =
|
||||||
{
|
{
|
||||||
|
@@ -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,65 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Text
|
|
||||||
open System.Text.RegularExpressions
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal Ident =
|
|
||||||
let inline create (s : string) = Ident (s, range0)
|
|
||||||
|
|
||||||
/// Fantomas bug, perhaps? "type" is not rendered as ``type``, although the ASTs are identical
|
|
||||||
/// apart from the ranges?
|
|
||||||
/// Awful hack: here is a function that does this sort of thing.
|
|
||||||
let createSanitisedParamName (s : string) =
|
|
||||||
match s with
|
|
||||||
| "type" -> create "type'"
|
|
||||||
| "private" -> create "private'"
|
|
||||||
| _ ->
|
|
||||||
|
|
||||||
let result = StringBuilder ()
|
|
||||||
|
|
||||||
for i = 0 to s.Length - 1 do
|
|
||||||
if Char.IsLetter s.[i] then
|
|
||||||
result.Append s.[i] |> ignore<StringBuilder>
|
|
||||||
elif Char.IsNumber s.[i] then
|
|
||||||
if result.Length > 0 then
|
|
||||||
result.Append s.[i] |> ignore<StringBuilder>
|
|
||||||
elif s.[i] = '_' || s.[i] = '-' then
|
|
||||||
result.Append '_' |> ignore<StringBuilder>
|
|
||||||
else
|
|
||||||
failwith $"could not convert to ident: %s{s}"
|
|
||||||
|
|
||||||
create (result.ToString ())
|
|
||||||
|
|
||||||
let private alnum = Regex @"^[a-zA-Z][a-zA-Z0-9]*$"
|
|
||||||
|
|
||||||
let createSanitisedTypeName (s : string) =
|
|
||||||
let result = StringBuilder ()
|
|
||||||
let mutable capitalize = true
|
|
||||||
|
|
||||||
for i = 0 to s.Length - 1 do
|
|
||||||
if Char.IsLetter s.[i] then
|
|
||||||
if capitalize then
|
|
||||||
result.Append (Char.ToUpperInvariant s.[i]) |> ignore<StringBuilder>
|
|
||||||
capitalize <- false
|
|
||||||
else
|
|
||||||
result.Append s.[i] |> ignore<StringBuilder>
|
|
||||||
elif Char.IsNumber s.[i] then
|
|
||||||
if result.Length > 0 then
|
|
||||||
result.Append s.[i] |> ignore<StringBuilder>
|
|
||||||
elif s.[i] = '_' then
|
|
||||||
capitalize <- true
|
|
||||||
|
|
||||||
if result.Length = 0 then
|
|
||||||
failwith $"String %s{s} was not suitable as a type identifier"
|
|
||||||
|
|
||||||
Ident (result.ToString (), range0)
|
|
||||||
|
|
||||||
let lowerFirstLetter (x : Ident) : Ident =
|
|
||||||
let result = StringBuilder x.idText.Length
|
|
||||||
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
|
|
||||||
result.Append x.idText.[1..] |> ignore
|
|
||||||
create ((result : StringBuilder).ToString ())
|
|
@@ -1,17 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal PreXmlDoc =
|
|
||||||
let create (s : string) : PreXmlDoc =
|
|
||||||
let s = s.Split "\n"
|
|
||||||
|
|
||||||
for i = 0 to s.Length - 1 do
|
|
||||||
s.[i] <- " " + s.[i]
|
|
||||||
|
|
||||||
PreXmlDoc.Create (s, range0)
|
|
||||||
|
|
||||||
let create' (s : string seq) : PreXmlDoc =
|
|
||||||
PreXmlDoc.Create (Array.ofSeq s, range0)
|
|
@@ -1,7 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynArgInfo =
|
|
||||||
let empty = SynArgInfo.SynArgInfo ([], false, None)
|
|
@@ -1,30 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynArgPats =
|
|
||||||
let createNamed (caseNames : string list) : SynArgPats =
|
|
||||||
match caseNames.Length with
|
|
||||||
| 0 -> SynArgPats.Pats []
|
|
||||||
| 1 ->
|
|
||||||
SynPat.Named (SynIdent.createS caseNames.[0], false, None, range0)
|
|
||||||
|> List.singleton
|
|
||||||
|> SynArgPats.Pats
|
|
||||||
| len ->
|
|
||||||
caseNames
|
|
||||||
|> List.map (fun name -> SynPat.Named (SynIdent.createS name, false, None, range0))
|
|
||||||
|> fun t -> SynPat.Tuple (false, t, List.replicate (len - 1) range0, range0)
|
|
||||||
|> fun t -> SynPat.Paren (t, range0)
|
|
||||||
|> List.singleton
|
|
||||||
|> SynArgPats.Pats
|
|
||||||
|
|
||||||
let create (pats : SynPat list) : SynArgPats =
|
|
||||||
match pats.Length with
|
|
||||||
| 0 -> SynArgPats.Pats []
|
|
||||||
| 1 -> [ pats.[0] ] |> SynArgPats.Pats
|
|
||||||
| len ->
|
|
||||||
SynPat.Paren (SynPat.Tuple (false, pats, List.replicate (len - 1) range0, range0), range0)
|
|
||||||
|> List.singleton
|
|
||||||
|> SynArgPats.Pats
|
|
@@ -1,27 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynAttribute =
|
|
||||||
let inline create (typeName : SynLongIdent) (arg : SynExpr) : SynAttribute =
|
|
||||||
{
|
|
||||||
TypeName = typeName
|
|
||||||
ArgExpr = arg
|
|
||||||
Target = None
|
|
||||||
AppliesToGetterAndSetter = false
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
|
|
||||||
let internal compilationRepresentation : SynAttribute =
|
|
||||||
[ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
|
|
||||||
|> SynExpr.createLongIdent
|
|
||||||
|> SynExpr.paren
|
|
||||||
|> create (SynLongIdent.createS "CompilationRepresentation")
|
|
||||||
|
|
||||||
let internal requireQualifiedAccess : SynAttribute =
|
|
||||||
create (SynLongIdent.createS "RequireQualifiedAccess") (SynExpr.CreateConst ())
|
|
||||||
|
|
||||||
let internal autoOpen : SynAttribute =
|
|
||||||
create (SynLongIdent.createS "AutoOpen") (SynExpr.CreateConst ())
|
|
@@ -1,15 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynAttributes =
|
|
||||||
let ofAttrs (attrs : SynAttribute list) : SynAttributes =
|
|
||||||
attrs
|
|
||||||
|> List.map (fun a ->
|
|
||||||
{
|
|
||||||
Attributes = [ a ]
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
)
|
|
@@ -1,233 +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.Typed (pat, _, _) -> getName pat
|
|
||||||
| 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
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let private getArgInfo (pat : SynPat) : SynArgInfo list =
|
|
||||||
// TODO: this only copes with one layer of tupling
|
|
||||||
match stripParen pat with
|
|
||||||
| SynPat.Tuple (_, pats, _, _) -> pats |> List.map (fun pat -> SynArgInfo.SynArgInfo ([], false, getName pat))
|
|
||||||
| pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ]
|
|
||||||
|
|
||||||
let triviaZero (isMember : bool) =
|
|
||||||
{
|
|
||||||
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 getArgInfo
|
|
||||||
|> 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 withMutability (mut : bool) (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (pat, kind, inl, _, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
|
||||||
SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
|
|
||||||
|
|
||||||
let withRecursion (isRec : bool) (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
|
||||||
let trivia =
|
|
||||||
{ trivia with
|
|
||||||
LeadingKeyword =
|
|
||||||
match trivia.LeadingKeyword with
|
|
||||||
| SynLeadingKeyword.Let _ ->
|
|
||||||
if isRec then
|
|
||||||
SynLeadingKeyword.LetRec (range0, range0)
|
|
||||||
else
|
|
||||||
trivia.LeadingKeyword
|
|
||||||
| SynLeadingKeyword.LetRec _ ->
|
|
||||||
if isRec then
|
|
||||||
trivia.LeadingKeyword
|
|
||||||
else
|
|
||||||
trivia.LeadingKeyword
|
|
||||||
| existing ->
|
|
||||||
failwith
|
|
||||||
$"WoofWare.Myriad doesn't yet let you adjust the recursion modifier on a binding with modifier %O{existing}"
|
|
||||||
}
|
|
||||||
|
|
||||||
SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
|
|
||||||
|
|
||||||
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 inline 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 inline makeNotInline (binding : SynBinding) : SynBinding =
|
|
||||||
match binding with
|
|
||||||
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
|
||||||
SynBinding (
|
|
||||||
acc,
|
|
||||||
kind,
|
|
||||||
false,
|
|
||||||
mut,
|
|
||||||
attrs,
|
|
||||||
doc,
|
|
||||||
valData,
|
|
||||||
headPat,
|
|
||||||
ret,
|
|
||||||
expr,
|
|
||||||
range,
|
|
||||||
debugPoint,
|
|
||||||
{ trivia with
|
|
||||||
InlineKeyword = None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let inline setInline (isInline : bool) (binding : SynBinding) : SynBinding =
|
|
||||||
if isInline then
|
|
||||||
makeInline binding
|
|
||||||
else
|
|
||||||
makeNotInline binding
|
|
||||||
|
|
||||||
let makeStaticMember (binding : SynBinding) : SynBinding =
|
|
||||||
let memberFlags =
|
|
||||||
{
|
|
||||||
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,10 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<AutoOpen>]
|
|
||||||
module internal SynConstExt =
|
|
||||||
type SynConst with
|
|
||||||
static member Create (s : string) : SynConst =
|
|
||||||
SynConst.String (s, SynStringKind.Regular, range0)
|
|
@@ -1,365 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<AutoOpen>]
|
|
||||||
module internal SynExprExtensions =
|
|
||||||
type SynExpr with
|
|
||||||
static member CreateConst (s : string) : SynExpr =
|
|
||||||
SynExpr.Const (SynConst.Create s, range0)
|
|
||||||
|
|
||||||
static member CreateConst () : SynExpr = SynExpr.Const (SynConst.Unit, range0)
|
|
||||||
|
|
||||||
static member CreateConst (b : bool) : SynExpr = SynExpr.Const (SynConst.Bool b, range0)
|
|
||||||
|
|
||||||
static member CreateConst (c : char) : SynExpr =
|
|
||||||
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
|
||||||
SynExpr.App (
|
|
||||||
ExprAtomicFlag.NonAtomic,
|
|
||||||
false,
|
|
||||||
SynExpr.Ident (Ident.create "char"),
|
|
||||||
SynExpr.CreateConst (int c),
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|> fun e -> SynExpr.Paren (e, range0, Some range0, 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.App (ExprAtomicFlag.NonAtomic, false, f, x, range0)
|
|
||||||
|
|
||||||
/// {f} {x}
|
|
||||||
let inline applyTo (x : SynExpr) (f : SynExpr) : SynExpr = applyFunction f x
|
|
||||||
|
|
||||||
let inline private createAppInfix (f : SynExpr) (x : SynExpr) =
|
|
||||||
SynExpr.App (ExprAtomicFlag.NonAtomic, true, f, x, range0)
|
|
||||||
|
|
||||||
let inline createLongIdent'' (ident : SynLongIdent) : SynExpr =
|
|
||||||
SynExpr.LongIdent (false, ident, None, range0)
|
|
||||||
|
|
||||||
let inline createLongIdent' (ident : Ident list) : SynExpr =
|
|
||||||
createLongIdent'' (SynLongIdent.create ident)
|
|
||||||
|
|
||||||
let inline createLongIdent (ident : string list) : SynExpr =
|
|
||||||
createLongIdent' (ident |> List.map Ident.create)
|
|
||||||
|
|
||||||
/// {expr} |> {func}
|
|
||||||
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
|
|
||||||
createAppInfix (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) =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.eq) a |> applyTo b
|
|
||||||
|
|
||||||
/// {a} && {b}
|
|
||||||
let booleanAnd (a : SynExpr) (b : SynExpr) =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.booleanAnd) a |> applyTo b
|
|
||||||
|
|
||||||
/// {a} || {b}
|
|
||||||
let booleanOr (a : SynExpr) (b : SynExpr) =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.booleanOr) a |> applyTo b
|
|
||||||
|
|
||||||
/// {a} + {b}
|
|
||||||
let plus (a : SynExpr) (b : SynExpr) =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.plus) a |> applyTo b
|
|
||||||
|
|
||||||
/// {a} * {b}
|
|
||||||
let times (a : SynExpr) (b : SynExpr) =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.times) a |> applyTo b
|
|
||||||
|
|
||||||
let rec stripOptionalParen (expr : SynExpr) : SynExpr =
|
|
||||||
match expr with
|
|
||||||
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr
|
|
||||||
| expr -> expr
|
|
||||||
|
|
||||||
let dotGet (field : string) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotGet (
|
|
||||||
obj,
|
|
||||||
range0,
|
|
||||||
SynLongIdent.SynLongIdent (id = [ Ident.create field ], dotRanges = [], trivia = [ None ]),
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
/// {obj}.{meth} {arg}
|
|
||||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr = dotGet meth obj |> applyTo arg
|
|
||||||
|
|
||||||
/// {obj}.{meth}()
|
|
||||||
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
|
||||||
callMethodArg meth (SynExpr.CreateConst ()) obj
|
|
||||||
|
|
||||||
let typeApp (types : SynType list) (operand : SynExpr) =
|
|
||||||
SynExpr.TypeApp (operand, range0, types, List.replicate (types.Length - 1) range0, Some range0, range0, range0)
|
|
||||||
|
|
||||||
/// {obj}.{meth}<types,...>()
|
|
||||||
let callGenericMethod (meth : SynLongIdent) (types : SynType list) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotGet (obj, range0, meth, range0)
|
|
||||||
|> typeApp types
|
|
||||||
|> applyTo (SynExpr.CreateConst ())
|
|
||||||
|
|
||||||
/// {obj}.{meth}<ty>()
|
|
||||||
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
|
||||||
callGenericMethod (SynLongIdent.createS meth) [ SynType.createLongIdent' [ ty ] ] obj
|
|
||||||
|
|
||||||
let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotIndexedGet (obj, property, range0, range0)
|
|
||||||
|
|
||||||
let inline arrayIndexRange (start : SynExpr option) (endRange : SynExpr option) (arr : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotIndexedGet (
|
|
||||||
arr,
|
|
||||||
(SynExpr.IndexRange (start, range0, endRange, range0, range0, range0)),
|
|
||||||
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 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 createForEach (pat : SynPat) (enumExpr : SynExpr) (body : SynExpr) : SynExpr =
|
|
||||||
SynExpr.ForEach (
|
|
||||||
DebugPointAtFor.No,
|
|
||||||
DebugPointAtInOrTo.No,
|
|
||||||
SeqExprOnly.SeqExprOnly false,
|
|
||||||
true,
|
|
||||||
pat,
|
|
||||||
enumExpr,
|
|
||||||
body,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
|
|
||||||
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty)
|
|
||||||
|
|
||||||
let inline createDo (body : SynExpr) : SynExpr = SynExpr.Do (body, range0)
|
|
||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
let listLiteral (elts : SynExpr list) : SynExpr =
|
|
||||||
SynExpr.ArrayOrListComputed (false, sequential elts, range0)
|
|
||||||
|
|
||||||
let arrayLiteral (elts : SynExpr list) : SynExpr =
|
|
||||||
SynExpr.ArrayOrListComputed (true, sequential elts, 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 =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.sub) (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 =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.gt) y |> applyTo x
|
|
||||||
|
|
||||||
/// {y} < {x}
|
|
||||||
let lessThan (x : SynExpr) (y : SynExpr) : SynExpr =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.lt) y |> applyTo x
|
|
||||||
|
|
||||||
/// {y} >= {x}
|
|
||||||
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.geq) y |> applyTo x
|
|
||||||
|
|
||||||
/// {y} <= {x}
|
|
||||||
let lessThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
|
||||||
createAppInfix (createLongIdent'' SynLongIdent.leq) y |> applyTo x
|
|
||||||
|
|
||||||
/// {x} :: {y}
|
|
||||||
let listCons (x : SynExpr) (y : SynExpr) : SynExpr =
|
|
||||||
createAppInfix
|
|
||||||
(SynExpr.LongIdent (
|
|
||||||
false,
|
|
||||||
SynLongIdent.SynLongIdent (
|
|
||||||
[ Ident.create "op_ColonColon" ],
|
|
||||||
[],
|
|
||||||
[ Some (IdentTrivia.OriginalNotation "::") ]
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
range0
|
|
||||||
))
|
|
||||||
(tupleNoParen [ x ; y ])
|
|
||||||
|> paren
|
|
||||||
|
|
||||||
let assign (lhs : SynLongIdent) (rhs : SynExpr) : SynExpr = SynExpr.LongIdentSet (lhs, rhs, range0)
|
|
||||||
|
|
||||||
let assignIndex (lhs : SynExpr) (index : SynExpr) (rhs : SynExpr) : SynExpr =
|
|
||||||
SynExpr.DotIndexedSet (lhs, index, rhs, range0, range0, range0)
|
|
@@ -1,10 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynExprLetOrUseTrivia =
|
|
||||||
let empty : SynExprLetOrUseTrivia =
|
|
||||||
{
|
|
||||||
InKeyword = None
|
|
||||||
}
|
|
@@ -1,76 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
|
|
||||||
/// The data needed to reconstitute a single piece of data within a union field, or a single record field.
|
|
||||||
/// This is generic on whether the field is identified. For example, in `type Foo = Blah of int`, the `int`
|
|
||||||
/// field is not identified; whereas in `type Foo = Blah of baz : int`, it is identified.
|
|
||||||
type SynFieldData<'Ident> =
|
|
||||||
{
|
|
||||||
/// Attributes on this field. I think you can only get these if this is a *record* field.
|
|
||||||
Attrs : SynAttribute list
|
|
||||||
/// The identifier of this field (see docstring for SynFieldData).
|
|
||||||
Ident : 'Ident
|
|
||||||
/// The type of the data contained in this field. For example, `type Foo = { Blah : int }`
|
|
||||||
/// has this being `int`.
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
let make (data : SynFieldData<Ident option>) : SynField =
|
|
||||||
let attrs : SynAttributeList list =
|
|
||||||
data.Attrs
|
|
||||||
|> List.map (fun l ->
|
|
||||||
{
|
|
||||||
Attributes = [ l ]
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
SynField.SynField (
|
|
||||||
attrs,
|
|
||||||
false,
|
|
||||||
data.Ident,
|
|
||||||
data.Type,
|
|
||||||
false,
|
|
||||||
PreXmlDoc.Empty,
|
|
||||||
None,
|
|
||||||
range0,
|
|
||||||
SynFieldTrivia.Zero
|
|
||||||
)
|
|
||||||
|
|
||||||
let withDocString (doc : PreXmlDoc) (f : SynField) : SynField =
|
|
||||||
match f with
|
|
||||||
| SynField (attributes, isStatic, idOpt, fieldType, isMutable, _, accessibility, range, trivia) ->
|
|
||||||
SynField (attributes, isStatic, idOpt, fieldType, isMutable, doc, accessibility, range, trivia)
|
|
@@ -1,10 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynIdent =
|
|
||||||
let inline createI (i : Ident) : SynIdent = SynIdent.SynIdent (i, None)
|
|
||||||
|
|
||||||
let inline createS (i : string) : SynIdent =
|
|
||||||
SynIdent.SynIdent (Ident.create i, None)
|
|
@@ -1,140 +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 leq =
|
|
||||||
SynLongIdent.SynLongIdent (
|
|
||||||
[ Ident.create "op_LessThanOrEqual" ],
|
|
||||||
[],
|
|
||||||
[ Some (IdentTrivia.OriginalNotation "<=") ]
|
|
||||||
)
|
|
||||||
|
|
||||||
let gt =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ Some (IdentTrivia.OriginalNotation ">") ])
|
|
||||||
|
|
||||||
let lt =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_LessThan" ], [], [ 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 booleanAnd =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_BooleanAnd" ], [], [ Some (IdentTrivia.OriginalNotation "&&") ])
|
|
||||||
|
|
||||||
let booleanOr =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_BooleanOr" ], [], [ Some (IdentTrivia.OriginalNotation "||") ])
|
|
||||||
|
|
||||||
let plus =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Addition" ], [], [ Some (IdentTrivia.OriginalNotation "+") ])
|
|
||||||
|
|
||||||
let times =
|
|
||||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Multiply" ], [], [ 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 isChoice (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent with
|
|
||||||
| [ i ] when System.String.Equals (i.idText, "Choice", System.StringComparison.Ordinal) -> true
|
|
||||||
// TODO: consider Microsoft.FSharp.Choice or whatever it is
|
|
||||||
| _ -> false
|
|
||||||
|
|
||||||
let isNullable (ident : SynLongIdent) : bool =
|
|
||||||
match ident.LongIdent |> List.map _.idText with
|
|
||||||
| [ "System" ; "Nullable" ]
|
|
||||||
| [ "Nullable" ] -> true
|
|
||||||
| _ -> 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,71 +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
|
|
||||||
(attrs : SynAttribute list)
|
|
||||||
(ident : SynIdent)
|
|
||||||
(typars : SynTyparDecls option)
|
|
||||||
(arity : SynValInfo)
|
|
||||||
(xmlDoc : PreXmlDoc)
|
|
||||||
(returnType : SynType)
|
|
||||||
: SynMemberDefn
|
|
||||||
=
|
|
||||||
let slot =
|
|
||||||
SynValSig.SynValSig (
|
|
||||||
attrs
|
|
||||||
|> List.map (fun attr ->
|
|
||||||
{
|
|
||||||
Attributes = [ attr ]
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
),
|
|
||||||
ident,
|
|
||||||
SynValTyparDecls.SynValTyparDecls (typars, true),
|
|
||||||
returnType,
|
|
||||||
arity,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
xmlDoc,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
EqualsRange = None
|
|
||||||
WithKeyword = None
|
|
||||||
InlineKeyword = None
|
|
||||||
LeadingKeyword = SynLeadingKeyword.Abstract range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
SynMemberDefn.AbstractSlot (
|
|
||||||
slot,
|
|
||||||
interfaceMemberSlotFlags,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
GetSetKeywords = None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let staticMember (binding : SynBinding) : SynMemberDefn =
|
|
||||||
let binding = SynBinding.makeStaticMember binding
|
|
||||||
SynMemberDefn.Member (binding, range0)
|
|
||||||
|
|
||||||
let memberImplementation (binding : SynBinding) : SynMemberDefn =
|
|
||||||
let binding = SynBinding.makeInstanceMember binding
|
|
||||||
SynMemberDefn.Member (binding, range0)
|
|
@@ -1,30 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynModuleDecl =
|
|
||||||
|
|
||||||
let inline openAny (ident : SynOpenDeclTarget) : SynModuleDecl = SynModuleDecl.Open (ident, range0)
|
|
||||||
|
|
||||||
let inline createLets (bindings : SynBinding list) : SynModuleDecl =
|
|
||||||
SynModuleDecl.Let (false, bindings, range0)
|
|
||||||
|
|
||||||
let inline createLet (binding : SynBinding) : SynModuleDecl = createLets [ binding ]
|
|
||||||
|
|
||||||
let inline createTypes (tys : SynTypeDefn list) : SynModuleDecl = SynModuleDecl.Types (tys, range0)
|
|
||||||
|
|
||||||
let nestedModule (info : SynComponentInfo) (decls : SynModuleDecl list) : SynModuleDecl =
|
|
||||||
SynModuleDecl.NestedModule (
|
|
||||||
info,
|
|
||||||
false,
|
|
||||||
decls,
|
|
||||||
false,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
ModuleKeyword = Some range0
|
|
||||||
EqualsRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
@@ -1,24 +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 SynModuleOrNamespace =
|
|
||||||
|
|
||||||
let createNamespace (name : LongIdent) (decls : SynModuleDecl list) =
|
|
||||||
SynModuleOrNamespace.SynModuleOrNamespace (
|
|
||||||
name,
|
|
||||||
false,
|
|
||||||
SynModuleOrNamespaceKind.DeclaredNamespace,
|
|
||||||
decls,
|
|
||||||
PreXmlDoc.Empty,
|
|
||||||
[],
|
|
||||||
None,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.Namespace range0
|
|
||||||
}
|
|
||||||
)
|
|
@@ -1,54 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynPat =
|
|
||||||
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
|
|
||||||
|
|
||||||
let anon : SynPat = SynPat.Wild range0
|
|
||||||
|
|
||||||
let inline annotateTypeNoParen (ty : SynType) (pat : SynPat) = SynPat.Typed (pat, ty, range0)
|
|
||||||
|
|
||||||
let inline annotateType (ty : SynType) (pat : SynPat) = paren (annotateTypeNoParen ty pat)
|
|
||||||
|
|
||||||
let inline named (s : string) : SynPat =
|
|
||||||
SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0)
|
|
||||||
|
|
||||||
let inline namedI (i : Ident) : SynPat =
|
|
||||||
SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0)
|
|
||||||
|
|
||||||
let inline identWithArgs (i : LongIdent) (args : SynArgPats) : SynPat =
|
|
||||||
SynPat.LongIdent (SynLongIdent.create i, None, None, args, None, range0)
|
|
||||||
|
|
||||||
let inline nameWithArgs (i : string) (args : SynPat list) : SynPat =
|
|
||||||
identWithArgs [ Ident.create i ] (SynArgPats.create args)
|
|
||||||
|
|
||||||
let inline tupleNoParen (elements : SynPat list) : SynPat =
|
|
||||||
match elements with
|
|
||||||
| [] -> failwith "Can't tuple no elements in a pattern"
|
|
||||||
| [ p ] -> p
|
|
||||||
| elements -> SynPat.Tuple (false, elements, List.replicate (elements.Length - 1) range0, range0)
|
|
||||||
|
|
||||||
let inline tuple (elements : SynPat list) : SynPat = tupleNoParen elements |> paren
|
|
||||||
|
|
||||||
let inline createConst (c : SynConst) = SynPat.Const (c, range0)
|
|
||||||
|
|
||||||
let unit = createConst SynConst.Unit
|
|
||||||
|
|
||||||
let createNull = SynPat.Null range0
|
|
||||||
|
|
||||||
let emptyList = SynPat.ArrayOrList (false, [], range0)
|
|
||||||
|
|
||||||
let listCons (lhs : SynPat) (rhs : SynPat) =
|
|
||||||
SynPat.ListCons (
|
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
ColonColonRange = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let emptyArray = SynPat.ArrayOrList (true, [], range0)
|
|
@@ -1,10 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynSimplePat =
|
|
||||||
|
|
||||||
let createId (id : Ident) : SynSimplePat =
|
|
||||||
SynSimplePat.Id (id, None, false, false, false, range0)
|
|
@@ -1,12 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynSimplePats =
|
|
||||||
|
|
||||||
let create (pats : SynSimplePat list) : SynSimplePats =
|
|
||||||
match pats with
|
|
||||||
| [] -> SynSimplePats.SimplePats ([], [], range0)
|
|
||||||
| pats -> SynSimplePats.SimplePats (pats, List.replicate (pats.Length - 1) range0, range0)
|
|
@@ -1,539 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open System
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
|
|
||||||
[<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 (|ChoiceType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, inner, _, _, _, _) when SynLongIdent.isChoice ident -> Some inner
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|NullableType|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isNullable 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 ] ->
|
|
||||||
// We won't bother with the case that the user has done e.g. `Single` (relying on `System` being open).
|
|
||||||
match Primitives.qualifyType i.idText with
|
|
||||||
| Some qualified ->
|
|
||||||
match i.idText with
|
|
||||||
| "char"
|
|
||||||
| "string" -> None
|
|
||||||
| _ -> Some qualified
|
|
||||||
| None -> None
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
/// Returns the name of the measure, and the outer type.
|
|
||||||
let (|Measure|_|) (fieldType : SynType) : (Ident * LongIdent) option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.App (NumberType outer,
|
|
||||||
_,
|
|
||||||
[ SynType.LongIdent (SynLongIdent.SynLongIdent ([ ident ], _, _)) ],
|
|
||||||
_,
|
|
||||||
_,
|
|
||||||
_,
|
|
||||||
_) -> Some (ident, outer)
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|JsonNode|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
|
||||||
| [ "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
|
||||||
| [ "Json" ; "Nodes" ; "JsonNode" ]
|
|
||||||
| [ "Nodes" ; "JsonNode" ]
|
|
||||||
| [ "JsonNode" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|Unit|_|) (fieldType : SynType) : unit option =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText.ToLowerInvariant ()) with
|
|
||||||
| [ "microsoft" ; "fsharp" ; "core" ; "unit" ]
|
|
||||||
| [ "fsharp" ; "core" ; "unit" ]
|
|
||||||
| [ "core" ; "unit" ]
|
|
||||||
| [ "unit" ] -> Some ()
|
|
||||||
| _ -> 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 (|DateTimeOffset|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "DateTimeOffset" ]
|
|
||||||
| [ "DateTimeOffset" ] -> 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
|
|
||||||
|
|
||||||
let (|DirectoryInfo|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "IO" ; "DirectoryInfo" ]
|
|
||||||
| [ "IO" ; "DirectoryInfo" ]
|
|
||||||
| [ "DirectoryInfo" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|FileInfo|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "IO" ; "FileInfo" ]
|
|
||||||
| [ "IO" ; "FileInfo" ]
|
|
||||||
| [ "FileInfo" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
let (|TimeSpan|_|) (fieldType : SynType) =
|
|
||||||
match fieldType with
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
|
||||||
match ident |> List.map (fun i -> i.idText) with
|
|
||||||
| [ "System" ; "TimeSpan" ]
|
|
||||||
| [ "TimeSpan" ] -> Some ()
|
|
||||||
| _ -> None
|
|
||||||
| _ -> None
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynType =
|
|
||||||
let rec stripOptionalParen (ty : SynType) : SynType =
|
|
||||||
match ty with
|
|
||||||
| SynType.Paren (ty, _) -> stripOptionalParen ty
|
|
||||||
| ty -> ty
|
|
||||||
|
|
||||||
let inline paren (ty : SynType) : SynType = SynType.Paren (ty, range0)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
/// Returns None if the input list was empty.
|
|
||||||
let inline tupleNoParen (ty : SynType list) : SynType option =
|
|
||||||
match List.rev ty with
|
|
||||||
| [] -> None
|
|
||||||
| [ t ] -> Some t
|
|
||||||
| t :: rest ->
|
|
||||||
([ SynTupleTypeSegment.Type t ], rest)
|
|
||||||
||> List.fold (fun ty nextArg -> SynTupleTypeSegment.Type nextArg :: SynTupleTypeSegment.Star range0 :: ty)
|
|
||||||
|> fun segs -> SynType.Tuple (false, segs, range0)
|
|
||||||
|> Some
|
|
||||||
|
|
||||||
let inline appPostfix (name : string) (arg : SynType) : SynType =
|
|
||||||
SynType.App (named name, None, [ arg ], [], None, true, range0)
|
|
||||||
|
|
||||||
let inline appPostfix' (name : string list) (arg : SynType) : SynType =
|
|
||||||
SynType.App (createLongIdent' name, None, [ arg ], [], None, true, range0)
|
|
||||||
|
|
||||||
let inline funFromDomain (domain : SynType) (range : SynType) : SynType =
|
|
||||||
SynType.Fun (
|
|
||||||
domain,
|
|
||||||
range,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
ArrowRange = range0
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let inline signatureParamOfType
|
|
||||||
(attrs : SynAttribute list)
|
|
||||||
(ty : SynType)
|
|
||||||
(optional : bool)
|
|
||||||
(name : Ident option)
|
|
||||||
: SynType
|
|
||||||
=
|
|
||||||
SynType.SignatureParameter (
|
|
||||||
attrs
|
|
||||||
|> List.map (fun attr ->
|
|
||||||
{
|
|
||||||
Attributes = [ attr ]
|
|
||||||
Range = range0
|
|
||||||
}
|
|
||||||
),
|
|
||||||
optional,
|
|
||||||
name,
|
|
||||||
ty,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0)
|
|
||||||
|
|
||||||
let unit : SynType = named "unit"
|
|
||||||
let obj : SynType = named "obj"
|
|
||||||
let bool : SynType = named "bool"
|
|
||||||
let int : SynType = named "int"
|
|
||||||
let array (elt : SynType) : SynType = SynType.Array (1, elt, range0)
|
|
||||||
|
|
||||||
let list (elt : SynType) : SynType =
|
|
||||||
SynType.App (named "list", None, [ elt ], [], None, true, range0)
|
|
||||||
|
|
||||||
let option (elt : SynType) : SynType =
|
|
||||||
SynType.App (named "option", None, [ elt ], [], None, true, range0)
|
|
||||||
|
|
||||||
let anon : SynType = SynType.Anon range0
|
|
||||||
|
|
||||||
let task (elt : SynType) : SynType =
|
|
||||||
SynType.App (
|
|
||||||
createLongIdent' [ "System" ; "Threading" ; "Tasks" ; "Task" ],
|
|
||||||
None,
|
|
||||||
[ elt ],
|
|
||||||
[],
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
let string : SynType = named "string"
|
|
||||||
|
|
||||||
/// Given ['a1, 'a2] and 'ret, returns 'a1 -> 'a2 -> 'ret.
|
|
||||||
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
|
||||||
(ret, List.rev inputs) ||> List.fold (fun ty input -> funFromDomain input ty)
|
|
||||||
|
|
||||||
let primitiveToHumanReadableString (name : LongIdent) : string =
|
|
||||||
match name |> List.map _.idText with
|
|
||||||
| [ "System" ; "Single" ] -> "single"
|
|
||||||
| [ "System" ; "Double" ] -> "double"
|
|
||||||
| [ "System" ; "Byte" ] -> "byte"
|
|
||||||
| [ "System" ; "SByte" ] -> "signed byte"
|
|
||||||
| [ "System" ; "Int16" ] -> "int16"
|
|
||||||
| [ "System" ; "Int32" ] -> "int32"
|
|
||||||
| [ "System" ; "Int64" ] -> "int64"
|
|
||||||
| [ "System" ; "UInt16" ] -> "uint16"
|
|
||||||
| [ "System" ; "UInt32" ] -> "uint32"
|
|
||||||
| [ "System" ; "UInt64" ] -> "uint64"
|
|
||||||
| [ "System" ; "Char" ] -> "char"
|
|
||||||
| [ "System" ; "Decimal" ] -> "decimal"
|
|
||||||
| [ "System" ; "String" ] -> "string"
|
|
||||||
| [ "System" ; "Boolean" ] -> "bool"
|
|
||||||
| ty ->
|
|
||||||
ty
|
|
||||||
|> String.concat "."
|
|
||||||
|> failwithf "could not create human-readable string for primitive type %s"
|
|
||||||
|
|
||||||
let rec toHumanReadableString (ty : SynType) : string =
|
|
||||||
match ty with
|
|
||||||
| PrimitiveType t1 -> primitiveToHumanReadableString t1
|
|
||||||
| OptionType t1 -> toHumanReadableString t1 + " option"
|
|
||||||
| NullableType t1 -> toHumanReadableString t1 + " Nullable"
|
|
||||||
| ChoiceType ts ->
|
|
||||||
ts
|
|
||||||
|> List.map toHumanReadableString
|
|
||||||
|> String.concat ", "
|
|
||||||
|> sprintf "Choice<%s>"
|
|
||||||
| MapType (k, v)
|
|
||||||
| DictionaryType (k, v)
|
|
||||||
| IDictionaryType (k, v)
|
|
||||||
| IReadOnlyDictionaryType (k, v) -> sprintf "map<%s, %s>" (toHumanReadableString k) (toHumanReadableString v)
|
|
||||||
| ListType t1 -> toHumanReadableString t1 + " list"
|
|
||||||
| ArrayType t1 -> toHumanReadableString t1 + " array"
|
|
||||||
| Task t1 -> toHumanReadableString t1 + " Task"
|
|
||||||
| UnitType -> "unit"
|
|
||||||
| FileInfo -> "FileInfo"
|
|
||||||
| DirectoryInfo -> "DirectoryInfo"
|
|
||||||
| Uri -> "URI"
|
|
||||||
| Stream -> "Stream"
|
|
||||||
| Guid -> "GUID"
|
|
||||||
| BigInt -> "bigint"
|
|
||||||
| DateTimeOffset -> "DateTimeOffset"
|
|
||||||
| DateOnly -> "DateOnly"
|
|
||||||
| TimeSpan -> "TimeSpan"
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) -> ident |> List.map _.idText |> String.concat "."
|
|
||||||
| ty -> failwithf "could not compute human-readable string for type: %O" ty
|
|
||||||
|
|
||||||
/// Guess whether the types are equal. We err on the side of saying "no, they're different".
|
|
||||||
let rec provablyEqual (ty1 : SynType) (ty2 : SynType) : bool =
|
|
||||||
if Object.ReferenceEquals (ty1, ty2) then
|
|
||||||
true
|
|
||||||
else
|
|
||||||
|
|
||||||
match ty1 with
|
|
||||||
| PrimitiveType t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| PrimitiveType t2 -> (t1 |> List.map _.idText) = (t2 |> List.map _.idText)
|
|
||||||
| _ -> false
|
|
||||||
| OptionType t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| OptionType t2 -> provablyEqual t1 t2
|
|
||||||
| _ -> false
|
|
||||||
| NullableType t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| NullableType t2 -> provablyEqual t1 t2
|
|
||||||
| _ -> false
|
|
||||||
| ChoiceType t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| ChoiceType t2 ->
|
|
||||||
t1.Length = t2.Length
|
|
||||||
&& List.forall (fun (a, b) -> provablyEqual a b) (List.zip t1 t2)
|
|
||||||
| _ -> false
|
|
||||||
| DictionaryType (k1, v1) ->
|
|
||||||
match ty2 with
|
|
||||||
| DictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
|
||||||
| _ -> false
|
|
||||||
| IDictionaryType (k1, v1) ->
|
|
||||||
match ty2 with
|
|
||||||
| IDictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
|
||||||
| _ -> false
|
|
||||||
| IReadOnlyDictionaryType (k1, v1) ->
|
|
||||||
match ty2 with
|
|
||||||
| IReadOnlyDictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
|
||||||
| _ -> false
|
|
||||||
| MapType (k1, v1) ->
|
|
||||||
match ty2 with
|
|
||||||
| MapType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
|
||||||
| _ -> false
|
|
||||||
| ListType t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| ListType t2 -> provablyEqual t1 t2
|
|
||||||
| _ -> false
|
|
||||||
| ArrayType t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| ArrayType t2 -> provablyEqual t1 t2
|
|
||||||
| _ -> false
|
|
||||||
| Task t1 ->
|
|
||||||
match ty2 with
|
|
||||||
| Task t2 -> provablyEqual t1 t2
|
|
||||||
| _ -> false
|
|
||||||
| UnitType ->
|
|
||||||
match ty2 with
|
|
||||||
| UnitType -> true
|
|
||||||
| _ -> false
|
|
||||||
| FileInfo ->
|
|
||||||
match ty2 with
|
|
||||||
| FileInfo -> true
|
|
||||||
| _ -> false
|
|
||||||
| DirectoryInfo ->
|
|
||||||
match ty2 with
|
|
||||||
| DirectoryInfo -> true
|
|
||||||
| _ -> false
|
|
||||||
| Uri ->
|
|
||||||
match ty2 with
|
|
||||||
| Uri -> true
|
|
||||||
| _ -> false
|
|
||||||
| Stream ->
|
|
||||||
match ty2 with
|
|
||||||
| Stream -> true
|
|
||||||
| _ -> false
|
|
||||||
| Guid ->
|
|
||||||
match ty2 with
|
|
||||||
| Guid -> true
|
|
||||||
| _ -> false
|
|
||||||
| BigInt ->
|
|
||||||
match ty2 with
|
|
||||||
| BigInt -> true
|
|
||||||
| _ -> false
|
|
||||||
| DateTimeOffset ->
|
|
||||||
match ty2 with
|
|
||||||
| DateTimeOffset -> true
|
|
||||||
| _ -> false
|
|
||||||
| DateOnly ->
|
|
||||||
match ty2 with
|
|
||||||
| DateOnly -> true
|
|
||||||
| _ -> false
|
|
||||||
| _ ->
|
|
||||||
|
|
||||||
match ty1, ty2 with
|
|
||||||
| SynType.LongIdent (SynLongIdent (ident1, _, _)), SynType.LongIdent (SynLongIdent (ident2, _, _)) ->
|
|
||||||
let ident1 = ident1 |> List.map _.idText
|
|
||||||
let ident2 = ident2 |> List.map _.idText
|
|
||||||
ident1 = ident2
|
|
||||||
| _, _ -> false
|
|
@@ -1,46 +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)
|
|
||||||
|
|
||||||
let getName (defn : SynTypeDefn) : LongIdent =
|
|
||||||
match defn with
|
|
||||||
| SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id
|
|
||||||
|
|
||||||
let getAttribute (attrName : string) (defn : SynTypeDefn) : SynAttribute option =
|
|
||||||
match defn with
|
|
||||||
| SynTypeDefn (SynComponentInfo.SynComponentInfo (attrs, _, _, _, _, _, _, _), _, _, _, _, _) ->
|
|
||||||
attrs
|
|
||||||
|> List.collect (fun a -> a.Attributes)
|
|
||||||
|> List.tryFind (fun i ->
|
|
||||||
match i.TypeName with
|
|
||||||
| SynLongIdent.SynLongIdent (id, _, _) ->
|
|
||||||
let name = List.last(id).idText
|
|
||||||
name = attrName || name + "Attribute" = attrName
|
|
||||||
)
|
|
||||||
|
|
||||||
let hasAttribute (attrName : string) (defn : SynTypeDefn) : bool =
|
|
||||||
getAttribute attrName defn |> Option.isSome
|
|
@@ -1,24 +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 unionWithAccess (implAccess : SynAccess option) (cases : SynUnionCase list) : SynTypeDefnRepr =
|
|
||||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (implAccess, cases, range0), range0)
|
|
||||||
|
|
||||||
let inline union (cases : SynUnionCase list) : SynTypeDefnRepr = unionWithAccess None cases
|
|
||||||
|
|
||||||
let inline recordWithAccess (implAccess : SynAccess option) (fields : SynField list) : SynTypeDefnRepr =
|
|
||||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (implAccess, fields, range0), range0)
|
|
||||||
|
|
||||||
let inline record (fields : SynField list) : SynTypeDefnRepr = recordWithAccess None fields
|
|
@@ -1,55 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
open Fantomas.FCS.Text.Range
|
|
||||||
open Fantomas.FCS.Xml
|
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
|
||||||
|
|
||||||
/// Represents everything you need to know about a union case.
|
|
||||||
/// This is generic on whether each field of this case must be named.
|
|
||||||
type UnionCase<'ident> =
|
|
||||||
{
|
|
||||||
/// The name of the case: e.g. `| Foo of blah` has this being `Foo`.
|
|
||||||
Name : Ident
|
|
||||||
/// Any docstring associated with this case.
|
|
||||||
XmlDoc : PreXmlDoc option
|
|
||||||
/// Any accessibility modifier: e.g. `type Foo = private | Blah`.
|
|
||||||
Access : SynAccess option
|
|
||||||
/// Attributes on the case: for example, `| [<Attr>] Foo of blah`.
|
|
||||||
Attributes : SynAttribute list
|
|
||||||
/// The data contained within the case: for example, `[blah]` in `| Foo of blah`.
|
|
||||||
Fields : SynFieldData<'ident> list
|
|
||||||
}
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynUnionCase =
|
|
||||||
let create (case : UnionCase<Ident option>) : SynUnionCase =
|
|
||||||
let fields =
|
|
||||||
case.Fields
|
|
||||||
|> List.map (fun field ->
|
|
||||||
SynField.SynField (
|
|
||||||
SynAttributes.ofAttrs field.Attrs,
|
|
||||||
false,
|
|
||||||
field.Ident,
|
|
||||||
field.Type,
|
|
||||||
false,
|
|
||||||
PreXmlDoc.Empty,
|
|
||||||
None,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
LeadingKeyword = None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
SynUnionCase.SynUnionCase (
|
|
||||||
SynAttributes.ofAttrs case.Attributes,
|
|
||||||
SynIdent.createI case.Name,
|
|
||||||
SynUnionCaseKind.Fields fields,
|
|
||||||
case.XmlDoc |> Option.defaultValue PreXmlDoc.Empty,
|
|
||||||
case.Access,
|
|
||||||
range0,
|
|
||||||
{
|
|
||||||
BarRange = Some range0
|
|
||||||
}
|
|
||||||
)
|
|
@@ -1,7 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
open Fantomas.FCS.Syntax
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal SynValInfo =
|
|
||||||
let empty = SynValInfo.SynValInfo ([], SynArgInfo.empty)
|
|
@@ -1,18 +0,0 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
|
||||||
|
|
||||||
// Extracted from https://github.com/G-Research/TypeEquality
|
|
||||||
// which is Apache-2.0 licenced. See `TeqLicence.txt`.
|
|
||||||
// We inline this code because Myriad doesn't seem to reliably load package references in the generator.
|
|
||||||
// I have reformatted a little, and stripped out all the code I don't use.
|
|
||||||
|
|
||||||
type internal Teq<'a, 'b> = private | Teq of ('a -> 'b) * ('b -> 'a)
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module internal Teq =
|
|
||||||
|
|
||||||
let refl<'a> : Teq<'a, 'a> = Teq (id, id)
|
|
||||||
let cast (Teq (f, _)) a = f a
|
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
|
||||||
module Cong =
|
|
||||||
let believeMe<'a, 'b, 'a2, 'b2> (_ : Teq<'a, 'b>) : Teq<'a2, 'b2> = unbox <| (refl : Teq<'a2, 'a2>)
|
|
@@ -15,10 +15,14 @@
|
|||||||
<WarnOn>FS3559</WarnOn>
|
<WarnOn>FS3559</WarnOn>
|
||||||
<PackageId>WoofWare.Myriad.Plugins</PackageId>
|
<PackageId>WoofWare.Myriad.Plugins</PackageId>
|
||||||
<PackageIcon>logo.png</PackageIcon>
|
<PackageIcon>logo.png</PackageIcon>
|
||||||
|
<NoWarn>NU5118</NoWarn>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Myriad.Core" Version="0.8.3" />
|
<PackageReference Include="Myriad.Core" Version="0.8.3" />
|
||||||
|
<PackageReference Include="TypeEquality" Version="0.3.0" />
|
||||||
|
<PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.5.1" />
|
||||||
<!-- the lowest version allowed by Myriad.Core -->
|
<!-- the lowest version allowed by Myriad.Core -->
|
||||||
<PackageReference Update="FSharp.Core" Version="6.0.1" PrivateAssets="all"/>
|
<PackageReference Update="FSharp.Core" Version="6.0.1" PrivateAssets="all"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -26,37 +30,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="List.fs"/>
|
<Compile Include="List.fs"/>
|
||||||
<Compile Include="Text.fs" />
|
<Compile Include="Text.fs" />
|
||||||
<Compile Include="Teq.fs" />
|
|
||||||
<Compile Include="Primitives.fs" />
|
|
||||||
<Compile Include="SynExpr\SynAttributes.fs" />
|
|
||||||
<Compile Include="SynExpr\SynConst.fs" />
|
|
||||||
<Compile Include="SynExpr\SynArgInfo.fs" />
|
|
||||||
<Compile Include="SynExpr\SynValInfo.fs" />
|
|
||||||
<Compile Include="SynExpr\PreXmlDoc.fs" />
|
|
||||||
<Compile Include="SynExpr\Ident.fs" />
|
|
||||||
<Compile Include="SynExpr\SynSimplePat.fs" />
|
|
||||||
<Compile Include="SynExpr\SynSimplePats.fs" />
|
|
||||||
<Compile Include="SynExpr\SynIdent.fs" />
|
|
||||||
<Compile Include="SynExpr\SynLongIdent.fs" />
|
|
||||||
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
|
|
||||||
<Compile Include="SynExpr\SynArgPats.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\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="SynExpr\SynModuleDecl.fs" />
|
|
||||||
<Compile Include="SynExpr\SynModuleOrNamespace.fs" />
|
|
||||||
<Compile Include="Measure.fs" />
|
<Compile Include="Measure.fs" />
|
||||||
<Compile Include="AstHelper.fs" />
|
<Compile Include="AstHelper.fs" />
|
||||||
|
<Compile Include="Parameters.fs" />
|
||||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||||
<Compile Include="MyriadParamParser.fs" />
|
<Compile Include="MyriadParamParser.fs" />
|
||||||
<Compile Include="InterfaceMockGenerator.fs"/>
|
<Compile Include="InterfaceMockGenerator.fs"/>
|
||||||
@@ -64,10 +40,11 @@
|
|||||||
<Compile Include="JsonParseGenerator.fs"/>
|
<Compile Include="JsonParseGenerator.fs"/>
|
||||||
<Compile Include="HttpClientGenerator.fs"/>
|
<Compile Include="HttpClientGenerator.fs"/>
|
||||||
<Compile Include="CataGenerator.fs" />
|
<Compile Include="CataGenerator.fs" />
|
||||||
<Compile Include="ArgParserGenerator.fs" />
|
<Compile Include="ShibaGenerator.fs" />
|
||||||
|
<None Include="ArgParserGenerator.fs" />
|
||||||
<Compile Include="Swagger.fs" />
|
<Compile Include="Swagger.fs" />
|
||||||
<Compile Include="SwaggerClientGenerator.fs" />
|
<Compile Include="SwaggerClientGenerator.fs" />
|
||||||
<None Include="TeqLicence.txt" />
|
<None Include="ApacheLicence.txt" />
|
||||||
<EmbeddedResource Include="version.json"/>
|
<EmbeddedResource Include="version.json"/>
|
||||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||||
<None Include="..\README.md">
|
<None Include="..\README.md">
|
||||||
@@ -84,7 +61,7 @@
|
|||||||
<ProjectReference Include="..\WoofWare.Myriad.Plugins.Attributes\WoofWare.Myriad.Plugins.Attributes.fsproj"/>
|
<ProjectReference Include="..\WoofWare.Myriad.Plugins.Attributes\WoofWare.Myriad.Plugins.Attributes.fsproj"/>
|
||||||
<!-- NuGet is such a clown package manager! Get the DLLs into the Nupkg artefact, I have no idea why this is needed,
|
<!-- NuGet is such a clown package manager! Get the DLLs into the Nupkg artefact, I have no idea why this is needed,
|
||||||
but without this line, we don't get any dependency at all packaged into the resulting artefact. -->
|
but without this line, we don't get any dependency at all packaged into the resulting artefact. -->
|
||||||
<None Include="$(OutputPath)\WoofWare.Myriad.Plugins.Attributes.dll" Pack="true" PackagePath="lib\$(TargetFramework)"/>
|
<None Include="$(OutputPath)\*.dll" Pack="true" PackagePath="lib\$(TargetFramework)"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "3.1",
|
"version": "4.0",
|
||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
|
@@ -10,6 +10,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Myriad.Plugins.Att
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Myriad.Plugins.Attributes.Test", "WoofWare.Myriad.Plugins.Attributes\Test\WoofWare.Myriad.Plugins.Attributes.Test.fsproj", "{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}"
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Myriad.Plugins.Attributes.Test", "WoofWare.Myriad.Plugins.Attributes\Test\WoofWare.Myriad.Plugins.Attributes.Test.fsproj", "{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Playground", "Playground\Playground.fsproj", "{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -36,5 +38,9 @@ Global
|
|||||||
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.Build.0 = Release|Any CPU
|
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.11.0]" />
|
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.14.0]" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
12
flake.lock
generated
12
flake.lock
generated
@@ -5,11 +5,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1726560853,
|
"lastModified": 1731533236,
|
||||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -20,11 +20,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1727524699,
|
"lastModified": 1744502386,
|
||||||
"narHash": "sha256-k6YxGj08voz9NvuKExojiGXAVd69M8COtqWSKr6sQS4=",
|
"narHash": "sha256-QAd1L37eU7ktL2WeLLLTmI6P9moz9+a/ONO8qNBYJgM=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "b5b2fecd0cadd82ef107c9583018f381ae70f222",
|
"rev": "f6db44a8daa59c40ae41ba6e5823ec77fe0d2124",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
32
flake.nix
32
flake.nix
@@ -14,8 +14,8 @@
|
|||||||
flake-utils.lib.eachDefaultSystem (system: let
|
flake-utils.lib.eachDefaultSystem (system: let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
pname = "WoofWare.Myriad.Plugins";
|
pname = "WoofWare.Myriad.Plugins";
|
||||||
dotnet-sdk = pkgs.dotnet-sdk_8;
|
dotnet-sdk = pkgs.dotnetCorePackages.sdk_9_0;
|
||||||
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
|
dotnet-runtime = pkgs.dotnetCorePackages.runtime_9_0;
|
||||||
version = "0.1";
|
version = "0.1";
|
||||||
dotnetTool = dllOverride: toolName: toolVersion: hash:
|
dotnetTool = dllOverride: toolName: toolVersion: hash:
|
||||||
pkgs.stdenvNoCC.mkDerivation rec {
|
pkgs.stdenvNoCC.mkDerivation rec {
|
||||||
@@ -26,25 +26,29 @@
|
|||||||
pname = name;
|
pname = name;
|
||||||
version = version;
|
version = version;
|
||||||
hash = hash;
|
hash = hash;
|
||||||
installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin'';
|
installPhase = ''mkdir -p $out/bin && cp -r tools/net*/any/* $out/bin'';
|
||||||
};
|
};
|
||||||
installPhase = let
|
installPhase = let
|
||||||
dll =
|
dll =
|
||||||
if isNull dllOverride
|
if isNull dllOverride
|
||||||
then name
|
then name
|
||||||
else dllOverride;
|
else dllOverride;
|
||||||
in ''
|
in
|
||||||
runHook preInstall
|
# fsharp-analyzers requires the .NET SDK at runtime, so we use that instead of dotnet-runtime.
|
||||||
mkdir -p "$out/lib"
|
''
|
||||||
cp -r ./bin/* "$out/lib"
|
runHook preInstall
|
||||||
makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${dll}.dll"
|
mkdir -p "$out/lib"
|
||||||
runHook postInstall
|
cp -r ./bin/* "$out/lib"
|
||||||
'';
|
makeWrapper "${dotnet-sdk}/bin/dotnet" "$out/bin/${name}" --set DOTNET_HOST_PATH "${dotnet-sdk}/bin/dotnet" --add-flags "$out/lib/${dll}.dll"
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
packages = {
|
packages = let
|
||||||
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;}))).hash;
|
deps = builtins.fromJSON (builtins.readFile ./nix/deps.json);
|
||||||
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;}))).hash;
|
in {
|
||||||
|
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") deps)).hash;
|
||||||
|
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") deps)).hash;
|
||||||
default = pkgs.buildDotnetModule {
|
default = pkgs.buildDotnetModule {
|
||||||
inherit pname version dotnet-sdk dotnet-runtime;
|
inherit pname version dotnet-sdk dotnet-runtime;
|
||||||
name = "WoofWare.Myriad.Plugins";
|
name = "WoofWare.Myriad.Plugins";
|
||||||
@@ -52,7 +56,7 @@
|
|||||||
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";
|
testProjectFile = "./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj";
|
||||||
disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"];
|
disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"];
|
||||||
nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result nix/deps.nix`
|
nugetDeps = ./nix/deps.json; # `nix build .#default.fetch-deps && ./result nix/deps.json`
|
||||||
doCheck = true;
|
doCheck = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
12
global.json
12
global.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "8.0.100",
|
"version": "9.0.100",
|
||||||
"rollForward": "latestMajor"
|
"rollForward": "latestMajor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
387
nix/deps.json
Normal file
387
nix/deps.json
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"pname": "ApiSurface",
|
||||||
|
"version": "4.1.20",
|
||||||
|
"hash": "sha256-koWgO9FC9ax+Ij56ug8kxeyknl0yhLqnNLOUdxtqqo4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "fantomas",
|
||||||
|
"version": "7.0.1",
|
||||||
|
"hash": "sha256-2aGD6Kjh83gmssRqqZ/Uihi7VbNqNUelX4otIfCuhTI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Fantomas.Core",
|
||||||
|
"version": "6.1.1",
|
||||||
|
"hash": "sha256-FcTLHQFvKkQY/kV08jhhy/St/+FmXpp3epp/R3zUXMA="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Fantomas.FCS",
|
||||||
|
"version": "6.1.1",
|
||||||
|
"hash": "sha256-NuZ8msPEHYA8T3EYREB28F1RcNgUU8V54eg2+UttYxw="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "FsCheck",
|
||||||
|
"version": "3.2.0",
|
||||||
|
"hash": "sha256-ksZ4vLgWwyQOzFuK2BczdtDtWWYmedG7UBAg4pYuI8g="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "fsharp-analyzers",
|
||||||
|
"version": "0.30.0",
|
||||||
|
"hash": "sha256-7oaSwpHAU1opzpz4szLU/gDaJC/ww9eiFkPu0nr4Mj4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "FSharp.Core",
|
||||||
|
"version": "4.3.4",
|
||||||
|
"hash": "sha256-styyo+6mJy+yxE0NZG/b1hxkAjPOnJfMgd9zWzCJ5uk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "FSharp.Core",
|
||||||
|
"version": "6.0.1",
|
||||||
|
"hash": "sha256-Ehsgt3nCJijpaVuJguC1TPVEKSkJd6PSc07D2ZQSemI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "FSharp.Core",
|
||||||
|
"version": "9.0.202",
|
||||||
|
"hash": "sha256-64Gub0qemmCoMa1tDus6TeTuB1+5sHfE6KD2j4o84mA="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "FsUnit",
|
||||||
|
"version": "7.0.1",
|
||||||
|
"hash": "sha256-K85CIdxMeFSHEKZk6heIXp/oFjWAn7dBILKrw49pJUY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.ApplicationInsights",
|
||||||
|
"version": "2.22.0",
|
||||||
|
"hash": "sha256-mUQ63atpT00r49ca50uZu2YCiLg3yd6r3HzTryqcuEA="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.AspNetCore.App.Ref",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-9jDkWbjw/nd8yqdzVTagCuqr6owJ/DUMi4BlUZT4hWU="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.AspNetCore.App.Runtime.linux-arm64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-JQULJyF0ivLoUU1JaFfK/HHg+/qzpN7V2RR2Cc+WlQ4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.AspNetCore.App.Runtime.linux-x64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-zUsVIpV481vMLAXaLEEUpEMA9/f1HGOnvaQnaWdzlyY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.AspNetCore.App.Runtime.osx-arm64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-2seqZcz0JeUjkzh3QcGa9TcJ4LUafpFjTRk+Nm8T6T0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.AspNetCore.App.Runtime.osx-x64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-yxLafxiBKkvfkDggPk0P9YZIHBkDJOsFTO7/V9mEHuU="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.CodeCoverage",
|
||||||
|
"version": "17.13.0",
|
||||||
|
"hash": "sha256-GKrIxeyQo5Az1mztfQgea1kGtJwonnNOrXK/0ULfu8o="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NET.Test.Sdk",
|
||||||
|
"version": "17.13.0",
|
||||||
|
"hash": "sha256-sc2wvyV8cGm1FrNP2GGHEI584RCvRPu15erYCsgw5QY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Host.linux-arm64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-9lC/LYnthYhjkWWz2kkFCvlA5LJOv11jdt59SDnpdy0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Host.linux-x64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-VFRDzx7LJuvI5yzKdGmw/31NYVbwHWPKQvueQt5xc10="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Host.osx-arm64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-DaSWwYACJGolEBuMhzDVCj/rQTdDt061xCVi+gyQnuo="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Host.osx-x64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-FrRny9EI6HKCKQbu6mcLj5w4ooSRrODD4Vj2ZMGnMd4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Ref",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-9LZgVoIFF8qNyUu8kdJrYGLutMF/cL2K82HN2ywwlx8="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Runtime.linux-arm64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-k3rxvUhCEU0pVH8KgEMtkPiSOibn+nBh+0zT2xIfId8="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Runtime.linux-x64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-U8wJ2snSDFqeAgDVLXjnniidC7Cr5aJ1/h/BMSlyu0c="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Runtime.osx-arm64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-UfLcrL2Gj/OLz0s92Oo+OCJeDpZFAcQLPLiSNND8D5Y="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.App.Runtime.osx-x64",
|
||||||
|
"version": "6.0.36",
|
||||||
|
"hash": "sha256-0xIJYFzxdMcnCj3wzkFRQZSnQcPHzPHMzePRIOA3oJs="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.Platforms",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"hash": "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.Platforms",
|
||||||
|
"version": "1.1.1",
|
||||||
|
"hash": "sha256-8hLiUKvy/YirCWlFwzdejD2Db3DaXhHxT7GSZx/znJg="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.Platforms",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"hash": "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.Targets",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"hash": "sha256-0AqQ2gMS8iNlYkrD+BxtIg7cXMnr9xZHtKAuN4bjfaQ="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.NETCore.Targets",
|
||||||
|
"version": "1.1.3",
|
||||||
|
"hash": "sha256-WLsf1NuUfRWyr7C7Rl9jiua9jximnVvzy6nk2D2bVRc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.Testing.Extensions.Telemetry",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"hash": "sha256-bIXwPSa3jkr2b6xINOqMUs6/uj/r4oVFM7xq3uVIZDU="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.Testing.Extensions.TrxReport.Abstractions",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"hash": "sha256-IfMRfcyaIKEMRtx326ICKtinDBEfGw/Sv8ZHawJ96Yc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.Testing.Extensions.VSTestBridge",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"hash": "sha256-XpM/yFjhLSsuzyDV+xKubs4V1zVVYiV05E0+N4S1h0g="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.Testing.Platform",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"hash": "sha256-y61Iih6w5D79dmrj2V675mcaeIiHoj1HSa1FRit2BLM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.Testing.Platform.MSBuild",
|
||||||
|
"version": "1.5.3",
|
||||||
|
"hash": "sha256-YspvjE5Jfi587TAfsvfDVJXNrFOkx1B3y1CKV6m7YLY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.TestPlatform.ObjectModel",
|
||||||
|
"version": "17.12.0",
|
||||||
|
"hash": "sha256-3XBHBSuCxggAIlHXmKNQNlPqMqwFlM952Av6RrLw1/w="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.TestPlatform.ObjectModel",
|
||||||
|
"version": "17.13.0",
|
||||||
|
"hash": "sha256-6S0fjfj8vA+h6dJVNwLi6oZhYDO/I/6hBZaq2VTW+Uk="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Microsoft.TestPlatform.TestHost",
|
||||||
|
"version": "17.13.0",
|
||||||
|
"hash": "sha256-L/CJzou7dhmShUgXq3aXL3CaLTJll17Q+JY2DBdUUpo="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Myriad.Core",
|
||||||
|
"version": "0.8.3",
|
||||||
|
"hash": "sha256-vBOxfq8QriX/yUtaXN69rEQaY/psRNJWxqATLidrt2g="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Myriad.Sdk",
|
||||||
|
"version": "0.8.3",
|
||||||
|
"hash": "sha256-7O397WKhskKOvE3MkJT37BvxorDWngDR6gTUogtDZ2M="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Nerdbank.GitVersioning",
|
||||||
|
"version": "3.8.38-alpha",
|
||||||
|
"hash": "sha256-gPMrVbjOZxXoofczF/pn6eVkLhjVSJIyQrLO2oljrDc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NETStandard.Library",
|
||||||
|
"version": "2.0.3",
|
||||||
|
"hash": "sha256-Prh2RPebz/s8AzHb2sPHg3Jl8s31inv9k+Qxd293ybo="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Newtonsoft.Json",
|
||||||
|
"version": "13.0.1",
|
||||||
|
"hash": "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "Newtonsoft.Json",
|
||||||
|
"version": "13.0.3",
|
||||||
|
"hash": "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NuGet.Common",
|
||||||
|
"version": "6.13.2",
|
||||||
|
"hash": "sha256-ASLa/Jigg5Eop0ZrXPl98RW2rxnJRC7pbbxhuV74hFw="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NuGet.Configuration",
|
||||||
|
"version": "6.13.2",
|
||||||
|
"hash": "sha256-z8VW1YdRDanyyRTDYRvRkSv/XPR3c/hMM1y8cNNjx0Y="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NuGet.Frameworks",
|
||||||
|
"version": "6.13.2",
|
||||||
|
"hash": "sha256-caDyc+WgYOo43AUTjtbP0MyvYDb6JweEKDdIul61Cac="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NuGet.Packaging",
|
||||||
|
"version": "6.13.2",
|
||||||
|
"hash": "sha256-lhO+SFwIYZ4aPHxIGm5ubkkE2a5Ve2xgtroRbNh7hpw="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NuGet.Protocol",
|
||||||
|
"version": "6.13.2",
|
||||||
|
"hash": "sha256-5lnAHHZjy7A4vgv65AeBAs64mSNpuoUjxW3HnrMpuzY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NuGet.Versioning",
|
||||||
|
"version": "6.13.2",
|
||||||
|
"hash": "sha256-gmpyBpKnt+GHqgx/2uFKp+J2csbxEAy1E7WdVT117sw="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NUnit",
|
||||||
|
"version": "4.3.2",
|
||||||
|
"hash": "sha256-0RWe8uFoxYp6qhPlDDEghOMcKJgyw2ybvEoAqBLebeE="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "NUnit3TestAdapter",
|
||||||
|
"version": "5.0.0",
|
||||||
|
"hash": "sha256-7jZM4qAbIzne3AcdFfMbvbgogqpxvVe6q2S7Ls8xQy0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "RestEase",
|
||||||
|
"version": "1.6.4",
|
||||||
|
"hash": "sha256-FFmqFwlHhIln46k56Z8KM1G+xuPEh/bceKCQnJcdcdc="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "runtime.any.System.Runtime",
|
||||||
|
"version": "4.3.0",
|
||||||
|
"hash": "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "runtime.native.System",
|
||||||
|
"version": "4.3.0",
|
||||||
|
"hash": "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "runtime.unix.System.Private.Uri",
|
||||||
|
"version": "4.3.0",
|
||||||
|
"hash": "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Collections.Immutable",
|
||||||
|
"version": "8.0.0",
|
||||||
|
"hash": "sha256-F7OVjKNwpqbUh8lTidbqJWYi476nsq9n+6k0+QVRo3w="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Diagnostics.DiagnosticSource",
|
||||||
|
"version": "5.0.0",
|
||||||
|
"hash": "sha256-6mW3N6FvcdNH/pB58pl+pFSCGWgyaP4hfVtC/SMWDV4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Diagnostics.DiagnosticSource",
|
||||||
|
"version": "7.0.0",
|
||||||
|
"hash": "sha256-9Wk8cHSkjKtqkN6xW7KnXoQVtF/VNbKeBq79WqDesMs="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Formats.Asn1",
|
||||||
|
"version": "6.0.0",
|
||||||
|
"hash": "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Formats.Asn1",
|
||||||
|
"version": "8.0.1",
|
||||||
|
"hash": "sha256-may/Wg+esmm1N14kQTG4ESMBi+GQKPp0ZrrBo/o6OXM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.IO.Abstractions",
|
||||||
|
"version": "4.2.13",
|
||||||
|
"hash": "sha256-nkC/PiqE6+c1HJ2yTwg3x+qdBh844Z8n3ERWDW8k6Gg="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.IO.FileSystem.AccessControl",
|
||||||
|
"version": "4.5.0",
|
||||||
|
"hash": "sha256-ck44YBQ0M+2Im5dw0VjBgFD1s0XuY54cujrodjjSBL8="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Memory",
|
||||||
|
"version": "4.5.5",
|
||||||
|
"hash": "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Private.Uri",
|
||||||
|
"version": "4.3.0",
|
||||||
|
"hash": "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Reflection.Metadata",
|
||||||
|
"version": "1.6.0",
|
||||||
|
"hash": "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Runtime",
|
||||||
|
"version": "4.3.1",
|
||||||
|
"hash": "sha256-R9T68AzS1PJJ7v6ARz9vo88pKL1dWqLOANg4pkQjkA0="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Runtime.CompilerServices.Unsafe",
|
||||||
|
"version": "6.0.0",
|
||||||
|
"hash": "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Security.AccessControl",
|
||||||
|
"version": "4.5.0",
|
||||||
|
"hash": "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Security.Cryptography.Pkcs",
|
||||||
|
"version": "6.0.4",
|
||||||
|
"hash": "sha256-2e0aRybote+OR66bHaNiYpF//4fCiaO3zbR2e9GABUI="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Security.Cryptography.ProtectedData",
|
||||||
|
"version": "4.4.0",
|
||||||
|
"hash": "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Security.Principal.Windows",
|
||||||
|
"version": "4.5.0",
|
||||||
|
"hash": "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "System.Text.Json",
|
||||||
|
"version": "8.0.5",
|
||||||
|
"hash": "sha256-yKxo54w5odWT6nPruUVsaX53oPRe+gKzGvLnnxtwP68="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "TypeEquality",
|
||||||
|
"version": "0.3.0",
|
||||||
|
"hash": "sha256-V50xAOzzyUJrY+MYPRxtnqW5MVeATXCes89wPprv1r4="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pname": "WoofWare.Whippet.Fantomas",
|
||||||
|
"version": "0.5.1",
|
||||||
|
"hash": "sha256-59CwnOZQAq5ZJoUkd87OiP8KUwx8xYDLMimMMTlKeZA="
|
||||||
|
}
|
||||||
|
]
|
329
nix/deps.nix
329
nix/deps.nix
@@ -1,329 +0,0 @@
|
|||||||
# This file was automatically generated by passthru.fetch-deps.
|
|
||||||
# Please dont edit it manually, your changes might get overwritten!
|
|
||||||
{fetchNuGet}: [
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "ApiSurface";
|
|
||||||
version = "4.1.5";
|
|
||||||
hash = "sha256-Kbt18XLk1gvZfzGca885HaXZB119APay85KzI546PYM=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "fantomas";
|
|
||||||
version = "6.3.15";
|
|
||||||
hash = "sha256-Gjw7MxjUNckMWSfnOye4UTe5fZWnor6RHCls3PNsuG8=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Fantomas.Core";
|
|
||||||
version = "6.1.1";
|
|
||||||
hash = "sha256-FcTLHQFvKkQY/kV08jhhy/St/+FmXpp3epp/R3zUXMA=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Fantomas.FCS";
|
|
||||||
version = "6.1.1";
|
|
||||||
hash = "sha256-NuZ8msPEHYA8T3EYREB28F1RcNgUU8V54eg2+UttYxw=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "FsCheck";
|
|
||||||
version = "2.16.6";
|
|
||||||
hash = "sha256-1hR2SaJTkqBzU3D955MvLNVzkQHkx0Z/QzOXZfzk2Zw=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "fsharp-analyzers";
|
|
||||||
version = "0.27.0";
|
|
||||||
hash = "sha256-QhLi2veTY1wZlQKJLTyVPgx/ImkaZugQNjSN5VJCNEA=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "FSharp.Core";
|
|
||||||
version = "4.3.4";
|
|
||||||
hash = "sha256-styyo+6mJy+yxE0NZG/b1hxkAjPOnJfMgd9zWzCJ5uk=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "FSharp.Core";
|
|
||||||
version = "6.0.1";
|
|
||||||
hash = "sha256-Ehsgt3nCJijpaVuJguC1TPVEKSkJd6PSc07D2ZQSemI=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "FSharp.Core";
|
|
||||||
version = "8.0.400";
|
|
||||||
hash = "sha256-wlrcAjjvI5YtnHR7kFH8uRUA4GomJYmqr41K5LYjCGs=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "FsUnit";
|
|
||||||
version = "6.0.1";
|
|
||||||
hash = "sha256-vka/aAgWhDCl5tu+kgO7GtSaHOOvlSaWxG+tExwGXpI=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.AspNetCore.App.Ref";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-GcPiO+iI0JsHYlqURAmzWjOnDX2jDCUY4jYaIwr8ojs=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-g5zbB1DnCSKuCOWtF09GEqGn1uJLdlTN6kqdnSCzRjQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-ToaiqVy5qonomAVBg5PO1GgrPKL4Cc1BZTJ0z/2LquA=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-OY/vdqAzZ99I4lEZbOOQw12TE0AIb5pXxKTvDxO2M2Q=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-53MAV3RO1kXzy5IpdZDZIOhoUzFqWHn7+A3aWwdTONQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.CodeCoverage";
|
|
||||||
version = "17.11.1";
|
|
||||||
hash = "sha256-1dLlK3NGh88PuFYZiYpT+izA96etxhU3BSgixDgdtGA=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NET.Test.Sdk";
|
|
||||||
version = "17.11.1";
|
|
||||||
hash = "sha256-0JUEucQ2lzaPgkrjm/NFLBTbqU1dfhvhN3Tl3moE6mI=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-rwWOpf2Pdg84c8bKIUcMYuDTI0kXUELL/nl9psSmX+E=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-5iYNZATXOePDsLA9lI80o1Gjxw4E+B4bJbwdYJJHcZY=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-k3LenomOlacyzq4FlBY/TwV7+ClbK4U0A/O9r0pZHT4=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-tu72AwDH1+oAIXjOJcNbeyKm1s4pncYp0avbMSBrcJQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Ref";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-BiGUcXo1FQTlZdR6ndhUQ8lrYG3KaGXNXRVF+Fc3L28=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-obRKiJEVpZ5E3TE7q2oHaYwFYhI23rMiHwp+8ORkwXY=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-2xdhvnKsFc8utDWN09zeXzZ5op+WUqkoWLuzdtQAkrA=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-9KHubWicibZOcixiByzuBKPnJM2u5DSQC9jR3MAR1bI=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
|
||||||
version = "6.0.33";
|
|
||||||
hash = "sha256-smh6SiTtCAuFglqWrXiGGsoIDP9dhGuIKdYjmw+xCyY=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.Platforms";
|
|
||||||
version = "1.1.0";
|
|
||||||
hash = "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.Platforms";
|
|
||||||
version = "1.1.1";
|
|
||||||
hash = "sha256-8hLiUKvy/YirCWlFwzdejD2Db3DaXhHxT7GSZx/znJg=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.Platforms";
|
|
||||||
version = "2.0.0";
|
|
||||||
hash = "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NETCore.Targets";
|
|
||||||
version = "1.1.3";
|
|
||||||
hash = "sha256-WLsf1NuUfRWyr7C7Rl9jiua9jximnVvzy6nk2D2bVRc=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
|
||||||
version = "17.11.1";
|
|
||||||
hash = "sha256-5vX+vCzFY3S7xfMVIv8OlMMFtdedW9UIJzc0WEc+vm4=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.TestPlatform.TestHost";
|
|
||||||
version = "17.11.1";
|
|
||||||
hash = "sha256-wSkY0H1fQAq0H3LcKT4u7Y5RzhAAPa6yueVN84g8HxU=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Myriad.Core";
|
|
||||||
version = "0.8.3";
|
|
||||||
hash = "sha256-vBOxfq8QriX/yUtaXN69rEQaY/psRNJWxqATLidrt2g=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Myriad.Sdk";
|
|
||||||
version = "0.8.3";
|
|
||||||
hash = "sha256-7O397WKhskKOvE3MkJT37BvxorDWngDR6gTUogtDZ2M=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Nerdbank.GitVersioning";
|
|
||||||
version = "3.6.143";
|
|
||||||
hash = "sha256-OhOtMzP+2obDIR+npR7SsoXo0KrmcsL+VCE8Z3t5gzQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NETStandard.Library";
|
|
||||||
version = "2.0.3";
|
|
||||||
hash = "sha256-Prh2RPebz/s8AzHb2sPHg3Jl8s31inv9k+Qxd293ybo=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Newtonsoft.Json";
|
|
||||||
version = "13.0.1";
|
|
||||||
hash = "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Newtonsoft.Json";
|
|
||||||
version = "13.0.3";
|
|
||||||
hash = "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Common";
|
|
||||||
version = "6.11.0";
|
|
||||||
hash = "sha256-eb7G07RyZv4AQT6ItRqdBuUf9e9BXcQygsy5RNEXfNE=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Configuration";
|
|
||||||
version = "6.11.0";
|
|
||||||
hash = "sha256-2SNZkX64SB15glzQx3k+vI7btr8Yqg4CayaaaK1B0AQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Frameworks";
|
|
||||||
version = "6.11.0";
|
|
||||||
hash = "sha256-8DC7V2IlCjiMDQ9yWbl7QQHia6OpBrbWh5rL0qa0Opw=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Packaging";
|
|
||||||
version = "6.11.0";
|
|
||||||
hash = "sha256-LVLvxcB6SMdayxAsrc5bCuLLt25fqPr6KfYcYoWWIQk=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Protocol";
|
|
||||||
version = "6.11.0";
|
|
||||||
hash = "sha256-3vdB/8IiJ2LMHhFXLWOzf0H59Ow/zcoq6W4uCHbihCQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Versioning";
|
|
||||||
version = "6.11.0";
|
|
||||||
hash = "sha256-03edgWvbqUtbzpBBTIxTwsSRoj1T2muGVL+vTuIHXag=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NUnit";
|
|
||||||
version = "4.2.2";
|
|
||||||
hash = "sha256-+0OS67ITalmG9arYCgQF/+YbmPRnB3pIIykew0kvoCc=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NUnit3TestAdapter";
|
|
||||||
version = "4.6.0";
|
|
||||||
hash = "sha256-9Yav2fYhC4w0OgsyUwU4/5rDy4FVDTpKnWHuwl/uKJQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "RestEase";
|
|
||||||
version = "1.6.4";
|
|
||||||
hash = "sha256-FFmqFwlHhIln46k56Z8KM1G+xuPEh/bceKCQnJcdcdc=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "runtime.any.System.Runtime";
|
|
||||||
version = "4.3.0";
|
|
||||||
hash = "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "runtime.native.System";
|
|
||||||
version = "4.3.0";
|
|
||||||
hash = "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "runtime.unix.System.Private.Uri";
|
|
||||||
version = "4.3.0";
|
|
||||||
hash = "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Diagnostics.DiagnosticSource";
|
|
||||||
version = "7.0.0";
|
|
||||||
hash = "sha256-9Wk8cHSkjKtqkN6xW7KnXoQVtF/VNbKeBq79WqDesMs=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Formats.Asn1";
|
|
||||||
version = "6.0.0";
|
|
||||||
hash = "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.IO.Abstractions";
|
|
||||||
version = "4.2.13";
|
|
||||||
hash = "sha256-nkC/PiqE6+c1HJ2yTwg3x+qdBh844Z8n3ERWDW8k6Gg=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.IO.FileSystem.AccessControl";
|
|
||||||
version = "4.5.0";
|
|
||||||
hash = "sha256-ck44YBQ0M+2Im5dw0VjBgFD1s0XuY54cujrodjjSBL8=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Memory";
|
|
||||||
version = "4.5.5";
|
|
||||||
hash = "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Private.Uri";
|
|
||||||
version = "4.3.0";
|
|
||||||
hash = "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Reflection.Metadata";
|
|
||||||
version = "1.6.0";
|
|
||||||
hash = "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Runtime";
|
|
||||||
version = "4.3.1";
|
|
||||||
hash = "sha256-R9T68AzS1PJJ7v6ARz9vo88pKL1dWqLOANg4pkQjkA0=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Runtime.CompilerServices.Unsafe";
|
|
||||||
version = "6.0.0";
|
|
||||||
hash = "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Security.AccessControl";
|
|
||||||
version = "4.5.0";
|
|
||||||
hash = "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Security.Cryptography.Pkcs";
|
|
||||||
version = "6.0.4";
|
|
||||||
hash = "sha256-2e0aRybote+OR66bHaNiYpF//4fCiaO3zbR2e9GABUI=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Security.Cryptography.ProtectedData";
|
|
||||||
version = "4.4.0";
|
|
||||||
hash = "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Security.Principal.Windows";
|
|
||||||
version = "4.5.0";
|
|
||||||
hash = "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Text.Encodings.Web";
|
|
||||||
version = "7.0.0";
|
|
||||||
hash = "sha256-tF8qt9GZh/nPy0mEnj6nKLG4Lldpoi/D8xM5lv2CoYQ=";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "System.Text.Json";
|
|
||||||
version = "7.0.3";
|
|
||||||
hash = "sha256-aSJZ17MjqaZNQkprfxm/09LaCoFtpdWmqU9BTROzWX4=";
|
|
||||||
})
|
|
||||||
]
|
|
Reference in New Issue
Block a user