Compare commits

..

3 Commits

Author SHA1 Message Date
Smaug123
3189143473 Merge branch 'main' into add-bit-of-myriad 2024-10-06 22:09:00 +01:00
Smaug123
21dfa77850 Deps 2024-10-06 22:04:51 +01:00
Smaug123
217ef138f6 Add a function from Myriad 2024-10-06 21:56:39 +01:00
37 changed files with 914 additions and 1806 deletions

View File

@@ -3,13 +3,13 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"fantomas": { "fantomas": {
"version": "7.0.1", "version": "6.3.15",
"commands": [ "commands": [
"fantomas" "fantomas"
] ]
}, },
"fsharp-analyzers": { "fsharp-analyzers": {
"version": "0.30.0", "version": "0.27.0",
"commands": [ "commands": [
"fsharp-analyzers" "fsharp-analyzers"
] ]

View File

@@ -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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
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@v31 uses: cachix/install-nix-action@v29
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -198,40 +198,27 @@ 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-dry-run: github-release-plugin-dry-run:
strategy:
matrix:
artifact:
- nuget-package-plugin
- nuget-package-attribute
runs-on: ubuntu-latest
needs: [nuget-pack] needs: [nuget-pack]
runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download NuGet artifact - name: Download NuGet artifact (plugin)
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: ${{ matrix.artifact }} name: nuget-package-plugin
- name: Compute package path - name: Download NuGet artifact (attribute)
id: compute-path uses: actions/download-artifact@v4
run: |
find . -maxdepth 1 -type f -name 'WoofWare.Myriad.*.nupkg' -exec sh -c 'echo "output=$(basename "$1")" >> $GITHUB_OUTPUT' shell {} \;
- name: Compute tag name
id: compute-tag
env:
NUPKG_PATH: ${{ steps.compute-path.outputs.output }}
run: echo "output=$(basename "$NUPKG_PATH" .nupkg)" >> $GITHUB_OUTPUT
- name: Tag and release
uses: G-Research/common-actions/github-release@19d7281a0f9f83e13c78f99a610dbc80fc59ba3b
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} name: nuget-package-attribute
target-commitish: ${{ github.sha }} - name: Tag and release plugin
tag: ${{ steps.compute-tag.outputs.output }} env:
binary-contents: ${{ steps.compute-path.outputs.output }} DRY_RUN: 1
dry-run: true GITHUB_TOKEN: mock-token
run: sh .github/workflows/tag.sh
all-required-checks-complete: all-required-checks-complete:
needs: [check-dotnet-format, check-nix-format, check-accurate-generations, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack, github-release-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-plugin-dry-run]
if: ${{ always() }} if: ${{ always() }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -254,7 +241,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@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
with: with:
subject-path: "packed/*.nupkg" subject-path: "packed/*.nupkg"
@@ -273,7 +260,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@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
with: with:
subject-path: "packed/*.nupkg" subject-path: "packed/*.nupkg"
@@ -289,7 +276,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v31 uses: cachix/install-nix-action@v29
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -322,7 +309,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v31 uses: cachix/install-nix-action@v29
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -343,12 +330,7 @@ jobs:
nupkg-dir: packed/ nupkg-dir: packed/
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }} dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
github-release: github-release-plugin:
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]
@@ -357,23 +339,15 @@ jobs:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download NuGet artifact - name: Download NuGet artifact (plugin)
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: ${{ matrix.artifact }} name: nuget-package-plugin
- name: Compute package path - name: Download NuGet artifact (attribute)
id: compute-path uses: actions/download-artifact@v4
run: |
find . -maxdepth 1 -type f -name 'WoofWare.Myriad.*.nupkg' -exec sh -c 'echo "output=$(basename "$1")" >> $GITHUB_OUTPUT' shell {} \;
- name: Compute tag name
id: compute-tag
env:
NUPKG_PATH: ${{ steps.compute-path.outputs.output }}
run: echo "output=$(basename "$NUPKG_PATH" .nupkg)" >> $GITHUB_OUTPUT
- name: Tag and release
uses: G-Research/common-actions/github-release@19d7281a0f9f83e13c78f99a610dbc80fc59ba3b
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} name: nuget-package-attribute
target-commitish: ${{ github.sha }} - name: Tag and release plugin
tag: ${{ steps.compute-tag.outputs.output }} env:
binary-contents: ${{ steps.compute-path.outputs.output }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: sh .github/workflows/tag.sh

View File

@@ -21,20 +21,20 @@ jobs:
- name: Update Nix flake - name: Update Nix flake
run: 'nix flake update' run: 'nix flake update'
- name: Build fetch-deps - name: Build passthru
run: 'nix build ".#default.fetch-deps"' run: 'nix build ".#default.passthru.fetch-deps"'
- name: Run fetch-deps - name: Run passthru
run: | run: |
set -o pipefail set -o pipefail
./result nix/deps.json ./result nix/deps.nix
- 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@v2 uses: actions/create-github-app-token@v1
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 Normal file
View File

@@ -0,0 +1,120 @@
#!/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

View File

@@ -1,10 +1,5 @@
Notable changes are recorded here. Notable changes are recorded here.
# WoofWare.Myriad.Plugins 5.0.1
We now enforce non-nullability on more types during JSON parse.
We have always expected you to consume nullable types wrapped in an `option`, but now we enforce this in more cases by throwing `ArgumentNullException`.
# WoofWare.Myriad.Plugins 3.0.1 # WoofWare.Myriad.Plugins 3.0.1
Semantics of `HttpClient`'s URI component composition changed: Semantics of `HttpClient`'s URI component composition changed:

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags> <OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags>
</PropertyGroup> </PropertyGroup>

File diff suppressed because it is too large Load Diff

View File

@@ -71,11 +71,7 @@ module JsonRecordType =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.Int32> ())
)
|> Array.ofSeq |> Array.ofSeq
let arg_4 = let arg_4 =
@@ -88,11 +84,7 @@ module JsonRecordType =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.String> ())
)
|> Array.ofSeq |> Array.ofSeq
let arg_3 = let arg_3 =
@@ -117,11 +109,7 @@ module JsonRecordType =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.Int32> ())
)
|> List.ofSeq |> List.ofSeq
let arg_1 = let arg_1 =

View File

@@ -206,34 +206,3 @@ 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 ()

View File

@@ -60,11 +60,7 @@ module GymOpeningHours =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.String> ())
)
|> List.ofSeq |> List.ofSeq
let arg_0 = let arg_0 =
@@ -1042,11 +1038,7 @@ module Sessions =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> Visit.jsonParse elt)
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> Visit.jsonParse elt)
)
|> List.ofSeq |> List.ofSeq
let arg_0 = let arg_0 =

View File

@@ -48,14 +48,7 @@ module PureGymApi =
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return return jsonNode.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq
jsonNode.AsArray ()
|> Seq.map (fun elt ->
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> Gym.jsonParse elt)
)
|> List.ofSeq
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
@@ -167,7 +160,8 @@ 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}".Replace ("{gym}", gym.ToString () |> System.Uri.EscapeDataString), "v1/gyms/{gym}"
.Replace ("{gym}", gym.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )

View File

@@ -408,11 +408,7 @@ module InnerTypeWithBothJsonParseExtension =
let value = let value =
(kvp.Value).AsArray () (kvp.Value).AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.Char> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.Char> ())
)
|> List.ofSeq |> List.ofSeq
key, value key, value
@@ -680,11 +676,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.Int32> ())
)
|> Array.ofSeq |> Array.ofSeq
let arg_4 = let arg_4 =
@@ -697,11 +689,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.String> ())
)
|> Array.ofSeq |> Array.ofSeq
let arg_3 = let arg_3 =
@@ -726,11 +714,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.Int32> ())
)
|> List.ofSeq |> List.ofSeq
let arg_1 = let arg_1 =

View File

@@ -94,11 +94,7 @@ module JwtVaultAuthResponse =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.String> ())
)
|> List.ofSeq |> List.ofSeq
let arg_3 = let arg_3 =
@@ -111,11 +107,7 @@ module JwtVaultAuthResponse =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.String> ())
)
|> List.ofSeq |> List.ofSeq
let arg_2 = let arg_2 =
@@ -128,11 +120,7 @@ module JwtVaultAuthResponse =
) )
| v -> v) | v -> v)
.AsArray () .AsArray ()
|> Seq.map (fun elt -> |> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
(match elt with
| null -> raise (System.ArgumentNullException ())
| elt -> elt.AsValue().GetValue<System.String> ())
)
|> List.ofSeq |> List.ofSeq
let arg_1 = let arg_1 =

View File

@@ -48,10 +48,3 @@ 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

View File

@@ -10,7 +10,7 @@
<WarnOn>FS3388,FS3559</WarnOn> <WarnOn>FS3388,FS3559</WarnOn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all"/> <PackageReference Include="Nerdbank.GitVersioning" Version="3.6.143" 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)' != ''">

View File

@@ -26,11 +26,6 @@ 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 ()

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.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.20" /> <PackageReference Include="ApiSurface" Version="4.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="NUnit" Version="4.3.2"/> <PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -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.FSharp open FsCheck.Random
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 = ArbMap.generate<int> ArbMap.defaults let! suffix = Arb.generate<int>
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 = ArbMap.generate<Guid> ArbMap.defaults let! guid = Arb.generate<Guid>
let! mapKeys = Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults) let! mapKeys = Gen.listOf Arb.generate<NonNull<string>>
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 (ArbMap.generate<NonNull<string>> ArbMap.defaults) Gen.listOf Arb.generate<NonNull<string>>
else else
Gen.constant [] Gen.constant []
@@ -50,16 +50,13 @@ module TestJsonSerde =
|> List.map KeyValuePair |> List.map KeyValuePair
|> Dictionary |> Dictionary
let! readOnlyDictKeys = Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults) let! readOnlyDictKeys = Gen.listOf Arb.generate<NonNull<string>>
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 (ArbMap.generate<bool> ArbMap.defaults) let! dictValues = Gen.listOfLength dictKeys.Length Arb.generate<bool>
let dict = List.zip dictKeys dictValues |> dict let dict = List.zip dictKeys dictValues |> dict
return return
@@ -74,38 +71,28 @@ module TestJsonSerde =
let outerGen : Gen<JsonRecordTypeWithBoth> = let outerGen : Gen<JsonRecordTypeWithBoth> =
gen { gen {
let! a = ArbMap.generate<int> ArbMap.defaults let! a = Arb.generate<int>
let! b = ArbMap.generate<NonNull<string>> ArbMap.defaults let! b = Arb.generate<NonNull<string>>
let! c = Gen.listOf (ArbMap.generate<int> ArbMap.defaults) let! c = Gen.listOf Arb.generate<int>
let! depth = Gen.choose (0, 2) let! depth = Gen.choose (0, 2)
let! d = innerGen depth let! d = innerGen depth
let! e = Gen.arrayOf (ArbMap.generate<NonNull<string>> ArbMap.defaults) let! e = Gen.arrayOf Arb.generate<NonNull<string>>
let! arr = Gen.arrayOf (ArbMap.generate<int> ArbMap.defaults) let! arr = Gen.arrayOf Arb.generate<int>
let! byte = ArbMap.generate ArbMap.defaults let! byte = Arb.generate
let! sbyte = ArbMap.generate ArbMap.defaults let! sbyte = Arb.generate
let! i = ArbMap.generate ArbMap.defaults let! i = Arb.generate
let! i32 = ArbMap.generate ArbMap.defaults let! i32 = Arb.generate
let! i64 = ArbMap.generate ArbMap.defaults let! i64 = Arb.generate
let! u = ArbMap.generate ArbMap.defaults let! u = Arb.generate
let! u32 = ArbMap.generate ArbMap.defaults let! u32 = Arb.generate
let! u64 = ArbMap.generate ArbMap.defaults let! u64 = Arb.generate
let! f = Arb.generate |> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>))
let! f = let! f32 = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
ArbMap.generate ArbMap.defaults let! single = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
|> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>)) let! intMeasureOption = Arb.generate
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 = ArbMap.generate ArbMap.defaults let! timestamp = Arb.generate
return return
{ {
@@ -283,10 +270,10 @@ module TestJsonSerde =
match case with match case with
| 0 -> return FirstDu.EmptyCase | 0 -> return FirstDu.EmptyCase
| 1 -> | 1 ->
let! s = ArbMap.generate<NonNull<string>> ArbMap.defaults let! s = Arb.generate<NonNull<string>>
return FirstDu.Case1 s.Get return FirstDu.Case1 s.Get
| 2 -> | 2 ->
let! i = ArbMap.generate<int> ArbMap.defaults let! i = Arb.generate<int>
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}"
@@ -306,6 +293,7 @@ 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
@@ -313,13 +301,11 @@ module TestJsonSerde =
let mutable i = 0 let mutable i = 0
let property (du : FirstDu) = while i < 10_000 && Array.exists (fun i -> i = 0) counts do
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
let tag = decompose du let tag = decompose du
counts.[tag] <- counts.[tag] + 1 counts.[tag] <- counts.[tag] + 1
i <- i + 1 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

View File

@@ -34,16 +34,3 @@ 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

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
<!-- <!--
@@ -9,7 +9,6 @@
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>
@@ -42,12 +41,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ApiSurface" Version="4.1.20"/> <PackageReference Include="ApiSurface" Version="4.1.5"/>
<PackageReference Include="FsCheck" Version="3.2.0"/> <PackageReference Include="FsCheck" Version="2.16.6"/>
<PackageReference Include="FsUnit" Version="7.0.1"/> <PackageReference Include="FsUnit" Version="6.0.1"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="NUnit" Version="4.3.2"/> <PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -673,7 +673,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)
|> SynExpr.createRecord None |> AstHelper.instantiateRecord
) )
tree, counter tree, counter
@@ -1758,7 +1758,10 @@ type ArgParserGenerator () =
let ast, _ = let ast, _ =
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
let types = Ast.getTypes ast let types =
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

View File

@@ -36,6 +36,13 @@ 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

View File

@@ -996,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.getTypes ast let types = Ast.extractTypeDefn ast
let opens = AstHelper.extractOpens ast let opens = AstHelper.extractOpens ast

View File

@@ -89,7 +89,7 @@ module internal InterfaceMockGenerator =
[] []
else else
[ SynPat.unit ]) [ SynPat.unit ])
(SynExpr.createRecord None constructorFields) (AstHelper.instantiateRecord 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
@@ -159,15 +159,6 @@ 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
@@ -183,7 +174,7 @@ module internal InterfaceMockGenerator =
SynType.app' baseName generics SynType.app' baseName generics
SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0) SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
let access = let access =
match interfaceType.Accessibility, spec.IsInternal with match interfaceType.Accessibility, spec.IsInternal with
@@ -257,15 +248,6 @@ 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)
@@ -273,12 +255,7 @@ 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 =
@@ -314,14 +291,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.getTypes ast let types = Ast.extractTypeDefn 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 SynTypeDefn.getAttribute typeof<GenerateMockAttribute>.Name typeDef with match Ast.getAttribute<GenerateMockAttribute> typeDef with
| None -> | None ->
let name = SynTypeDefn.getName typeDef |> List.map _.idText |> String.concat "." let name = SynTypeDefn.getName typeDef |> List.map _.idText |> String.concat "."

View File

@@ -26,7 +26,7 @@ module internal JsonParseGenerator =
} }
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ({propertyName} not found)) | v -> v) /// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ({propertyName} not found)) | v -> v)
let assertPropertyExists (propertyName : SynExpr) (indexed : SynExpr) = let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
let raiseExpr = let raiseExpr =
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.createIdent "sprintf") (SynExpr.createIdent "sprintf")
@@ -46,42 +46,28 @@ module internal JsonParseGenerator =
|> SynExpr.createMatch indexed |> SynExpr.createMatch indexed
|> SynExpr.paren |> SynExpr.paren
let assertNotNull (body : SynExpr) (boundIdent : Ident) : SynExpr =
let raiseExpr =
SynExpr.CreateConst ()
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
[
SynMatchClause.create SynPat.createNull raiseExpr
SynMatchClause.create (SynPat.namedI boundIdent) body
]
|> SynExpr.createMatch (SynExpr.createIdent' boundIdent)
|> SynExpr.paren
/// {node}.AsValue().GetValue<{typeName}> () /// {node}.AsValue().GetValue<{typeName}> ()
/// If `propertyName` is Some, uses `assertPropertyExists {node}` instead of `{node}`. /// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr = let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr =
match propertyName with match propertyName with
| None -> node | None -> node
| Some propertyName -> assertPropertyExists propertyName node | Some propertyName -> assertNotNull propertyName node
|> SynExpr.callMethod "AsValue" |> SynExpr.callMethod "AsValue"
|> SynExpr.callGenericMethod' "GetValue" typeName |> SynExpr.callGenericMethod' "GetValue" typeName
let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr = let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr =
match propertyName with match propertyName with
| None -> node | None -> node
| Some propertyName -> assertPropertyExists propertyName node | Some propertyName -> assertNotNull propertyName node
|> SynExpr.callMethod "AsValue" |> SynExpr.callMethod "AsValue"
|> SynExpr.callGenericMethod (SynLongIdent.createS "GetValue") [ SynType.createLongIdent typeName ] |> SynExpr.callGenericMethod (SynLongIdent.createS "GetValue") [ SynType.createLongIdent typeName ]
/// {node}.AsObject() /// {node}.AsObject()
/// If `propertyName` is Some, uses `assertPropertyExists {node}` instead of `{node}`. /// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
let asObject (propertyName : SynExpr option) (node : SynExpr) : SynExpr = let asObject (propertyName : SynExpr option) (node : SynExpr) : SynExpr =
match propertyName with match propertyName with
| None -> node | None -> node
| Some propertyName -> assertPropertyExists propertyName node | Some propertyName -> assertNotNull propertyName node
|> SynExpr.callMethod "AsObject" |> SynExpr.callMethod "AsObject"
/// {type}.jsonParse {node} /// {type}.jsonParse {node}
@@ -91,8 +77,8 @@ module internal JsonParseGenerator =
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it. /// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
/// body is the body of a lambda which takes a parameter `elt`. /// body is the body of a lambda which takes a parameter `elt`.
/// {assertPropertyExists node}.AsArray() /// {assertNotNull node}.AsArray()
/// |> Seq.map (fun elt -> {assertNotNull} {body}) /// |> Seq.map (fun elt -> {body})
/// |> {collectionType}.ofSeq /// |> {collectionType}.ofSeq
let asArrayMapped let asArrayMapped
(propertyName : SynExpr option) (propertyName : SynExpr option)
@@ -103,12 +89,10 @@ module internal JsonParseGenerator =
= =
match propertyName with match propertyName with
| None -> node | None -> node
| Some propertyName -> assertPropertyExists propertyName node | Some propertyName -> assertNotNull propertyName node
|> SynExpr.callMethod "AsArray" |> SynExpr.callMethod "AsArray"
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.applyFunction SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "elt" body)
(SynExpr.createLongIdent [ "Seq" ; "map" ])
(SynExpr.createLambda "elt" (assertNotNull body (Ident.create "elt")))
) )
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ]) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ])
@@ -193,29 +177,27 @@ module internal JsonParseGenerator =
= =
// TODO: parsing format for DateTime etc // TODO: parsing format for DateTime etc
match fieldType with match fieldType with
// Struct types
| DateOnly -> | DateOnly ->
node node
|> asValueGetValue propertyName "string" |> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateOnly" ; "Parse" ]) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateOnly" ; "Parse" ])
| DateTime ->
node
|> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
| NumberType typeName -> parseNumberType options propertyName node typeName
| Guid ->
node
|> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Guid" ; "Parse" ])
// Reference types
| Uri -> | Uri ->
node node
|> asValueGetValue propertyName "string" |> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ]) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
| Guid ->
node
|> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Guid" ; "Parse" ])
| DateTime ->
node
|> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
| DateTimeOffset -> | DateTimeOffset ->
node node
|> asValueGetValue propertyName "string" |> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTimeOffset" ; "Parse" ]) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTimeOffset" ; "Parse" ])
| NumberType typeName -> parseNumberType options propertyName node typeName
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node | PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
| OptionType ty -> | OptionType ty ->
let someClause = let someClause =
@@ -309,7 +291,7 @@ module internal JsonParseGenerator =
match propertyName with match propertyName with
| None -> node | None -> node
| Some propertyName -> assertPropertyExists propertyName node | Some propertyName -> assertNotNull propertyName node
|> typeJsonParse typeName |> typeJsonParse typeName
/// propertyName is probably a string literal, but it could be a [<Literal>] variable /// propertyName is probably a string literal, but it could be a [<Literal>] variable
@@ -369,7 +351,10 @@ 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 (SynLongIdent.toString attr.TypeName).EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then if
(SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
then
let qualifiedEnumValue = let qualifiedEnumValue =
match SynExpr.stripOptionalParen attr.ArgExpr with match SynExpr.stripOptionalParen attr.ArgExpr with
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident -> | SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
@@ -399,13 +384,15 @@ module internal JsonParseGenerator =
let propertyNameAttr = let propertyNameAttr =
fieldData.Attrs fieldData.Attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonPropertyName", StringComparison.Ordinal) (SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
) )
let extensionDataAttr = let extensionDataAttr =
fieldData.Attrs fieldData.Attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonExtensionData", StringComparison.Ordinal) (SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonExtensionData", StringComparison.Ordinal)
) )
let propertyName = let propertyName =
@@ -498,7 +485,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}")
|> SynExpr.createRecord None |> AstHelper.instantiateRecord
(finalConstruction, assignments) (finalConstruction, assignments)
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final) ||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)
@@ -523,7 +510,7 @@ module internal JsonParseGenerator =
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node") SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|> assertPropertyExists (SynExpr.CreateConst "data") |> assertNotNull (SynExpr.CreateConst "data")
|> SynBinding.basic [ Ident.create "node" ] [] |> SynBinding.basic [ Ident.create "node" ] []
] ]
@@ -571,7 +558,7 @@ module internal JsonParseGenerator =
SynExpr.createIdent "node" SynExpr.createIdent "node"
|> SynExpr.index property |> SynExpr.index property
|> assertPropertyExists property |> assertNotNull property
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.createLambda "v" (SynExpr.callGenericMethod' "GetValue" "string" (SynExpr.createIdent "v")) SynExpr.createLambda "v" (SynExpr.callGenericMethod' "GetValue" "string" (SynExpr.createIdent "v"))
) )
@@ -724,13 +711,13 @@ type JsonParseGenerator () =
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
let relevantTypes = let relevantTypes =
Ast.getTypes ast Ast.extractTypeDefn ast
|> List.map (fun (name, defns) -> |> List.map (fun (name, defns) ->
defns defns
|> List.choose (fun defn -> |> List.choose (fun defn ->
if SynTypeDefn.isRecord defn then Some defn if Ast.isRecord defn then Some defn
elif SynTypeDefn.isDu defn then Some defn elif Ast.isDu defn then Some defn
elif SynTypeDefn.isEnum defn then Some defn elif AstHelper.isEnum defn then Some defn
else None else None
) )
|> fun defns -> name, defns |> fun defns -> name, defns

View File

@@ -180,7 +180,8 @@ module internal JsonSerializeGenerator =
let propertyNameAttr = let propertyNameAttr =
attrs attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName).EndsWith ("JsonPropertyName", StringComparison.Ordinal) (SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
) )
match propertyNameAttr with match propertyNameAttr with
@@ -197,7 +198,8 @@ 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).EndsWith ("JsonExtensionData", StringComparison.Ordinal) (SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonExtensionData", StringComparison.Ordinal)
) )
|> Option.isSome |> Option.isSome
@@ -526,13 +528,13 @@ type JsonSerializeGenerator () =
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
let relevantTypes = let relevantTypes =
Ast.getTypes ast Ast.extractTypeDefn ast
|> List.map (fun (name, defns) -> |> List.map (fun (name, defns) ->
defns defns
|> List.choose (fun defn -> |> List.choose (fun defn ->
if SynTypeDefn.isRecord defn then Some defn if Ast.isRecord defn then Some defn
elif SynTypeDefn.isDu defn then Some defn elif Ast.isDu defn then Some defn
elif SynTypeDefn.isEnum defn then Some defn elif AstHelper.isEnum defn then Some defn
else None else None
) )
|> fun defns -> name, defns |> fun defns -> name, defns

View File

@@ -2,6 +2,28 @@ 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 =
(* (*

View File

@@ -1,23 +0,0 @@
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}"

View File

@@ -1,6 +1,5 @@
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 open WoofWare.Whippet.Fantomas
@@ -60,7 +59,7 @@ module internal RemoveOptionsGenerator =
Attributes = [] Attributes = []
} }
let typeDecl = RecordType.ToAst record let typeDecl = AstHelper.defineRecordType record
SynModuleDecl.Types ([ typeDecl ], range0) SynModuleDecl.Types ([ typeDecl ], range0)
@@ -97,7 +96,7 @@ module internal RemoveOptionsGenerator =
SynLongIdent.createI fieldData.Ident, body SynLongIdent.createI fieldData.Ident, body
) )
|> SynExpr.createRecord None |> AstHelper.instantiateRecord
SynBinding.basic SynBinding.basic
[ functionName ] [ functionName ]
@@ -147,31 +146,44 @@ 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.getRecords ast let records = Ast.extractRecords ast
let namespaceAndRecords = let namespaceAndRecords =
records records
|> List.collect (fun (ns, ty) -> |> List.choose (fun (ns, types) ->
ty match
|> List.filter (fun record -> types
record.Attributes |> List.filter (SynTypeDefn.hasAttribute typeof<RemoveOptionsAttribute>.Name)
|> List.exists (fun attr -> with
attr.TypeName.LongIdent | [] -> None
|> List.last | types ->
|> _.idText let types =
|> fun s -> types
if s.EndsWith ("Attribute", StringComparison.Ordinal) then |> List.map (fun ty ->
s match ty with
else | SynTypeDefn.SynTypeDefn (sci,
$"%s{s}Attribute" SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (access,
|> (=) typeof<RemoveOptionsAttribute>.Name fields,
) _),
) _),
|> List.map (fun ty -> ns, ty) smd,
smdo,
_,
_) -> RecordType.OfRecord sci smd access fields
| _ -> failwith "unexpectedly not a record"
)
Some (ns, types)
) )
let modules = let modules =
namespaceAndRecords namespaceAndRecords
|> List.map (fun (ns, record) -> RemoveOptionsGenerator.createRecordModule ns record) |> List.collect (fun (ns, records) ->
records
|> List.map (fun record ->
let recordModule = RemoveOptionsGenerator.createRecordModule ns record
recordModule
)
)
Output.Ast modules Output.Ast modules

View File

@@ -15,14 +15,13 @@
<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> <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="TypeEquality" Version="0.3.0" />
<PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.5.1" /> <PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.2.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>
@@ -32,7 +31,6 @@
<Compile Include="Text.fs" /> <Compile Include="Text.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"/>
@@ -60,7 +58,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)\*.dll" Pack="true" PackagePath="lib\$(TargetFramework)"/> <None Include="$(OutputPath)\WoofWare.Myriad.Plugins.Attributes.dll" Pack="true" PackagePath="lib\$(TargetFramework)"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,5 +1,5 @@
{ {
"version": "5.0", "version": "4.0",
"publicReleaseRefSpec": [ "publicReleaseRefSpec": [
"^refs/heads/main$" "^refs/heads/main$"
], ],
@@ -11,4 +11,4 @@
":/README.md", ":/README.md",
":/Directory.Build.props" ":/Directory.Build.props"
] ]
} }

View File

@@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.14.0]" /> <PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.11.0]" />
</ItemGroup> </ItemGroup>
</Project> </Project>

12
flake.lock generated
View File

@@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1726560853,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1744868846, "lastModified": 1728093190,
"narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=", "narHash": "sha256-CAZF2NRuHmqTtRTNAruWpHA43Gg2UvuCNEIzabP0l6M=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c", "rev": "e2f08f4d8b3ecb5cf5c9fd9cb2d53bb3c71807da",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -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.dotnetCorePackages.sdk_9_0; dotnet-sdk = pkgs.dotnet-sdk_8;
dotnet-runtime = pkgs.dotnetCorePackages.runtime_9_0; dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_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,29 +26,25 @@
pname = name; pname = name;
version = version; version = version;
hash = hash; hash = hash;
installPhase = ''mkdir -p $out/bin && cp -r tools/net*/any/* $out/bin''; installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/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 ''
# fsharp-analyzers requires the .NET SDK at runtime, so we use that instead of dotnet-runtime. runHook preInstall
'' mkdir -p "$out/lib"
runHook preInstall cp -r ./bin/* "$out/lib"
mkdir -p "$out/lib" makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${dll}.dll"
cp -r ./bin/* "$out/lib" runHook postInstall
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 = let packages = {
deps = builtins.fromJSON (builtins.readFile ./nix/deps.json); 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;
in { 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;
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";
@@ -56,7 +52,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.json; # `nix build .#default.fetch-deps && ./result nix/deps.json` nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result nix/deps.nix`
doCheck = true; doCheck = true;
}; };
}; };

View File

@@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "9.0.100", "version": "8.0.100",
"rollForward": "latestMajor" "rollForward": "latestMajor"
} }
} }

View File

@@ -1,387 +0,0 @@
[
{
"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="
}
]

339
nix/deps.nix Normal file
View File

@@ -0,0 +1,339 @@
# 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=";
})
(fetchNuGet {
pname = "TypeEquality";
version = "0.3.0";
hash = "sha256-V50xAOzzyUJrY+MYPRxtnqW5MVeATXCes89wPprv1r4=";
})
(fetchNuGet {
pname = "WoofWare.Whippet.Fantomas";
version = "0.2.1";
hash = "sha256-38LPop5tQ14oqzi0dSzBp2m53fugIMyWed67xnZmJqk=";
})
]