mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-08 13:38:39 +00:00
Compare commits
8 Commits
WoofWare.M
...
WoofWare.M
Author | SHA1 | Date | |
---|---|---|---|
|
94b88a4143 | ||
|
ed3ffecb52 | ||
|
c696dcf31f | ||
|
d5bb2726d3 | ||
|
f17290d0f1 | ||
|
35cd94cba1 | ||
|
1b3eb03380 | ||
|
b846ce08a3 |
43
.github/workflows/dotnet.yaml
vendored
43
.github/workflows/dotnet.yaml
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json
|
||||||
name: .NET
|
name: .NET
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -86,6 +87,27 @@ jobs:
|
|||||||
- name: Run Fantomas
|
- name: Run Fantomas
|
||||||
run: nix run .#fantomas -- --check .
|
run: nix run .#fantomas -- --check .
|
||||||
|
|
||||||
|
check-accurate-generations:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@V27
|
||||||
|
with:
|
||||||
|
extra_nix_config: |
|
||||||
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Whitespace change
|
||||||
|
run: "echo ' ' >> ConsumePlugin/List.fs"
|
||||||
|
- name: Generate code
|
||||||
|
run: nix develop --command dotnet build
|
||||||
|
- name: Run Fantomas
|
||||||
|
run: nix run .#fantomas -- .
|
||||||
|
- name: Verify there is no diff
|
||||||
|
run: git diff --name-only --no-color --exit-code
|
||||||
|
|
||||||
check-nix-format:
|
check-nix-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -174,8 +196,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-plugin-dry-run:
|
||||||
|
needs: [nuget-pack]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Download NuGet artifact (plugin)
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nuget-package-plugin
|
||||||
|
- name: Download NuGet artifact (attribute)
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nuget-package-attribute
|
||||||
|
- name: Tag and release plugin
|
||||||
|
env:
|
||||||
|
DRY_RUN: 1
|
||||||
|
GITHUB_TOKEN: mock-token
|
||||||
|
run: sh .github/workflows/tag.sh
|
||||||
|
|
||||||
all-required-checks-complete:
|
all-required-checks-complete:
|
||||||
needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack]
|
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]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "All required checks complete."
|
- run: echo "All required checks complete."
|
||||||
|
109
.github/workflows/tag.sh
vendored
109
.github/workflows/tag.sh
vendored
@@ -1,6 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
find . -maxdepth 1 -type f -name '*.nupkg' -exec sh -c 'tag=$(basename "$1" .nupkg); git tag "$tag"; git push origin "$tag"' shell {} \;
|
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
|
export TAG
|
||||||
TAG=$(find . -maxdepth 1 -type f -name 'WoofWare.Myriad.Plugins.*.nupkg' -exec sh -c 'basename "$1" .nupkg' shell {} \; | grep -v Attributes)
|
TAG=$(find . -maxdepth 1 -type f -name 'WoofWare.Myriad.Plugins.*.nupkg' -exec sh -c 'basename "$1" .nupkg' shell {} \; | grep -v Attributes)
|
||||||
@@ -14,4 +21,100 @@ case "$TAG" in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
# target_commitish empty indicates the repo default branch
|
# target_commitish empty indicates the repo default branch
|
||||||
curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases -d '{"tag_name":"'"$TAG"'","target_commitish":"","name":"'"$TAG"'","draft":false,"prerelease":false,"generate_release_notes":false}'
|
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
|
||||||
|
@@ -60,7 +60,7 @@ module TreeCata =
|
|||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__TreeBuilder x ->
|
| Instruction.Process__TreeBuilder (x) ->
|
||||||
match x with
|
match x with
|
||||||
| TreeBuilder.Child (arg0_0) ->
|
| TreeBuilder.Child (arg0_0) ->
|
||||||
instructions.Add Instruction.TreeBuilder_Child
|
instructions.Add Instruction.TreeBuilder_Child
|
||||||
@@ -68,7 +68,7 @@ module TreeCata =
|
|||||||
| TreeBuilder.Parent (arg0_0) ->
|
| TreeBuilder.Parent (arg0_0) ->
|
||||||
instructions.Add Instruction.TreeBuilder_Parent
|
instructions.Add Instruction.TreeBuilder_Parent
|
||||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||||
| Instruction.Process__Tree x ->
|
| Instruction.Process__Tree (x) ->
|
||||||
match x with
|
match x with
|
||||||
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
||||||
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||||
|
@@ -41,7 +41,7 @@ module FileSystemItemCata =
|
|||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__FileSystemItem x ->
|
| Instruction.Process__FileSystemItem (x) ->
|
||||||
match x with
|
match x with
|
||||||
| FileSystemItem.Directory ({
|
| FileSystemItem.Directory ({
|
||||||
Name = name
|
Name = name
|
||||||
@@ -116,7 +116,7 @@ module GiftCata =
|
|||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__Gift x ->
|
| Instruction.Process__Gift (x) ->
|
||||||
match x with
|
match x with
|
||||||
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
|
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
|
||||||
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate arg0_0 |> giftStack.Add
|
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate arg0_0 |> giftStack.Add
|
||||||
|
@@ -149,6 +149,37 @@ module JsonRecordTypeWithBothJsonSerializeExtension =
|
|||||||
)
|
)
|
||||||
|
|
||||||
node :> _
|
node :> _
|
||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Collections.Generic
|
||||||
|
open System.Text.Json.Serialization
|
||||||
|
|
||||||
|
/// Module containing JSON serializing extension members for the FirstDu type
|
||||||
|
[<AutoOpen>]
|
||||||
|
module FirstDuJsonSerializeExtension =
|
||||||
|
/// Extension methods for JSON parsing
|
||||||
|
type FirstDu with
|
||||||
|
|
||||||
|
/// Serialize to a JSON node
|
||||||
|
static member toJsonNode (input : FirstDu) : System.Text.Json.Nodes.JsonNode =
|
||||||
|
let node = System.Text.Json.Nodes.JsonObject ()
|
||||||
|
|
||||||
|
match input with
|
||||||
|
| FirstDu.EmptyCase -> node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "emptyCase")
|
||||||
|
| FirstDu.Case1 (arg0) ->
|
||||||
|
node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case1")
|
||||||
|
let dataNode = System.Text.Json.Nodes.JsonObject ()
|
||||||
|
dataNode.Add ("data", System.Text.Json.Nodes.JsonValue.Create<string> arg0)
|
||||||
|
node.Add ("data", dataNode)
|
||||||
|
| FirstDu.Case2 (arg0, arg1) ->
|
||||||
|
node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case2")
|
||||||
|
let dataNode = System.Text.Json.Nodes.JsonObject ()
|
||||||
|
dataNode.Add ("record", JsonRecordTypeWithBoth.toJsonNode arg0)
|
||||||
|
dataNode.Add ("i", System.Text.Json.Nodes.JsonValue.Create<int> arg1)
|
||||||
|
node.Add ("data", dataNode)
|
||||||
|
|
||||||
|
node :> _
|
||||||
|
|
||||||
namespace ConsumePlugin
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ module MyListCata =
|
|||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__MyList x ->
|
| Instruction.Process__MyList (x) ->
|
||||||
match x with
|
match x with
|
||||||
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
||||||
| MyList.Cons ({
|
| MyList.Cons ({
|
||||||
@@ -97,7 +97,7 @@ module MyList2Cata =
|
|||||||
instructions.RemoveAt (instructions.Count - 1)
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
match currentInstruction with
|
match currentInstruction with
|
||||||
| Instruction.Process__MyList2 x ->
|
| Instruction.Process__MyList2 (x) ->
|
||||||
match x with
|
match x with
|
||||||
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
||||||
| MyList2.Cons (arg0_0, arg1_0) ->
|
| MyList2.Cons (arg0_0, arg1_0) ->
|
||||||
|
@@ -27,3 +27,9 @@ type JsonRecordTypeWithBoth =
|
|||||||
E : string array
|
E : string array
|
||||||
F : int[]
|
F : int[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||||
|
type FirstDu =
|
||||||
|
| EmptyCase
|
||||||
|
| Case1 of data : string
|
||||||
|
| Case2 of record : JsonRecordTypeWithBoth * i : int
|
||||||
|
@@ -143,6 +143,9 @@ module InnerTypeWithBoth =
|
|||||||
node
|
node
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Also includes an *opinionated* serializer for discriminated unions.
|
||||||
|
(Any such serializer must be opinionated, because JSON does not natively model DUs.)
|
||||||
|
|
||||||
As in `JsonParse`, you can optionally supply the boolean `true` to the attribute,
|
As in `JsonParse`, you can optionally supply the boolean `true` to the attribute,
|
||||||
which will cause Myriad to stamp out an extension method rather than a module with the same name as the type.
|
which will cause Myriad to stamp out an extension method rather than a module with the same name as the type.
|
||||||
|
|
||||||
|
@@ -12,8 +12,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.39" />
|
<PackageReference Include="ApiSurface" Version="4.0.40" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -3,5 +3,13 @@
|
|||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
"pathFilters": null
|
"pathFilters": [
|
||||||
}
|
":/README.md",
|
||||||
|
":/LICENSE",
|
||||||
|
":/WoofWare.Myriad.Plugins/logo.png",
|
||||||
|
":/Directory.Build.props",
|
||||||
|
":/global.json",
|
||||||
|
"./",
|
||||||
|
"^./Test"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@@ -33,10 +33,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.39"/>
|
<PackageReference Include="ApiSurface" Version="4.0.40"/>
|
||||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -1113,7 +1113,7 @@ module internal CataGenerator =
|
|||||||
analysis.AssociatedProcessInstruction,
|
analysis.AssociatedProcessInstruction,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
SynArgPats.Pats [ SynPat.CreateNamed (Ident.Create "x") ],
|
SynArgPats.create [ Ident.Create "x" ],
|
||||||
None,
|
None,
|
||||||
range0
|
range0
|
||||||
),
|
),
|
||||||
@@ -1162,22 +1162,16 @@ module internal CataGenerator =
|
|||||||
|> Seq.mapi (fun i x -> (i, x))
|
|> Seq.mapi (fun i x -> (i, x))
|
||||||
|> Seq.choose (fun (i, case) ->
|
|> Seq.choose (fun (i, case) ->
|
||||||
match case.Description with
|
match case.Description with
|
||||||
| FieldDescription.NonRecursive _ -> SynPat.CreateNamed case.ArgName |> Some
|
| FieldDescription.NonRecursive _ -> case.ArgName |> Some
|
||||||
| FieldDescription.ListSelf _ -> SynPat.CreateNamed case.ArgName |> Some
|
| FieldDescription.ListSelf _ -> case.ArgName |> Some
|
||||||
| FieldDescription.Self _ -> None
|
| FieldDescription.Self _ -> None
|
||||||
)
|
)
|
||||||
|> Seq.toList
|
|> Seq.toList
|
||||||
|
|
||||||
let lhs =
|
let lhs = SynArgPats.create lhsNames
|
||||||
match lhsNames with
|
|
||||||
| [] -> []
|
|
||||||
| lhsNames ->
|
|
||||||
SynPat.Tuple (false, lhsNames, List.replicate (lhsNames.Length - 1) range0, range0)
|
|
||||||
|> SynPat.CreateParen
|
|
||||||
|> List.singleton
|
|
||||||
|
|
||||||
let pat =
|
let pat =
|
||||||
SynPat.LongIdent (unionCase.AssociatedInstruction, None, None, SynArgPats.Pats lhs, None, range0)
|
SynPat.LongIdent (unionCase.AssociatedInstruction, None, None, lhs, None, range0)
|
||||||
|
|
||||||
let populateArgs =
|
let populateArgs =
|
||||||
unionCase.FlattenedFields
|
unionCase.FlattenedFields
|
||||||
|
@@ -357,7 +357,7 @@ module internal JsonParseGenerator =
|
|||||||
| [ _ ; "JsonNumberHandling" ; "Serialization" ; "Json" ; "Text" ; "System" ] -> true
|
| [ _ ; "JsonNumberHandling" ; "Serialization" ; "Json" ; "Text" ; "System" ] -> true
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
let createMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
let createMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynFieldData<Ident> list) =
|
||||||
let xmlDoc = PreXmlDoc.Create " Parse from a JSON node."
|
let xmlDoc = PreXmlDoc.Create " Parse from a JSON node."
|
||||||
|
|
||||||
let returnInfo =
|
let returnInfo =
|
||||||
@@ -391,22 +391,15 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
let assignments =
|
let assignments =
|
||||||
fields
|
fields
|
||||||
|> List.map (fun (SynField (attrs, _, id, fieldType, _, _, _, _, _)) ->
|
|> List.map (fun fieldData ->
|
||||||
let id =
|
|
||||||
match id with
|
|
||||||
| None -> failwith "didn't get an ID on field"
|
|
||||||
| Some id -> id
|
|
||||||
|
|
||||||
let attrs = attrs |> List.collect (fun l -> l.Attributes)
|
|
||||||
|
|
||||||
let propertyNameAttr =
|
let propertyNameAttr =
|
||||||
attrs
|
fieldData.Attrs
|
||||||
|> List.tryFind (fun attr ->
|
|> List.tryFind (fun attr ->
|
||||||
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||||
)
|
)
|
||||||
|
|
||||||
let options =
|
let options =
|
||||||
(JsonParseOption.None, attrs)
|
(JsonParseOption.None, fieldData.Attrs)
|
||||||
||> List.fold (fun options attr ->
|
||> List.fold (fun options attr ->
|
||||||
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
|
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
|
||||||
let qualifiedEnumValue =
|
let qualifiedEnumValue =
|
||||||
@@ -438,18 +431,18 @@ module internal JsonParseGenerator =
|
|||||||
let propertyName =
|
let propertyName =
|
||||||
match propertyNameAttr with
|
match propertyNameAttr with
|
||||||
| None ->
|
| None ->
|
||||||
let sb = StringBuilder id.idText.Length
|
let sb = StringBuilder fieldData.Ident.idText.Length
|
||||||
sb.Append (Char.ToLowerInvariant id.idText.[0]) |> ignore
|
sb.Append (Char.ToLowerInvariant fieldData.Ident.idText.[0]) |> ignore
|
||||||
|
|
||||||
if id.idText.Length > 1 then
|
if fieldData.Ident.idText.Length > 1 then
|
||||||
sb.Append id.idText.[1..] |> ignore
|
sb.Append fieldData.Ident.idText.[1..] |> ignore
|
||||||
|
|
||||||
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||||
| Some name -> name.ArgExpr
|
| Some name -> name.ArgExpr
|
||||||
|
|
||||||
let pattern =
|
let pattern =
|
||||||
SynPat.LongIdent (
|
SynPat.LongIdent (
|
||||||
SynLongIdent.CreateFromLongIdent [ id ],
|
SynLongIdent.CreateFromLongIdent [ fieldData.Ident ],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
SynArgPats.Empty,
|
SynArgPats.Empty,
|
||||||
@@ -460,7 +453,7 @@ module internal JsonParseGenerator =
|
|||||||
SynBinding.Let (
|
SynBinding.Let (
|
||||||
isInline = false,
|
isInline = false,
|
||||||
isMutable = false,
|
isMutable = false,
|
||||||
expr = createParseRhs options propertyName fieldType,
|
expr = createParseRhs options propertyName fieldData.Type,
|
||||||
valData = inputVal,
|
valData = inputVal,
|
||||||
pattern = pattern
|
pattern = pattern
|
||||||
)
|
)
|
||||||
@@ -468,14 +461,9 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
let finalConstruction =
|
let finalConstruction =
|
||||||
fields
|
fields
|
||||||
|> List.map (fun (SynField (_, _, id, _, _, _, _, _, _)) ->
|
|> List.map (fun fieldData ->
|
||||||
let id =
|
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true),
|
||||||
match id with
|
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ fieldData.Ident ]))
|
||||||
| None -> failwith "Expected record field to have an identifying name"
|
|
||||||
| Some id -> id
|
|
||||||
|
|
||||||
(SynLongIdent.CreateFromLongIdent [ id ], true),
|
|
||||||
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ id ]))
|
|
||||||
)
|
)
|
||||||
|> AstHelper.instantiateRecord
|
|> AstHelper.instantiateRecord
|
||||||
|
|
||||||
@@ -566,61 +554,65 @@ module internal JsonParseGenerator =
|
|||||||
|
|
||||||
SynModuleDecl.CreateLet [ binding ]
|
SynModuleDecl.CreateLet [ binding ]
|
||||||
|
|
||||||
let createRecordModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
||||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||||
typeDefn
|
typeDefn
|
||||||
|
|
||||||
let (SynComponentInfo (_attributes, _typeParams, _constraints, recordId, _, _preferPostfix, _access, _)) =
|
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, _access, _)) =
|
||||||
synComponentInfo
|
synComponentInfo
|
||||||
|
|
||||||
match synTypeDefnRepr with
|
let attributes =
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _recordRange), _) ->
|
if spec.ExtensionMethods then
|
||||||
|
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||||
|
else
|
||||||
|
[
|
||||||
|
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||||
|
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||||
|
]
|
||||||
|
|
||||||
let decls = [ createMaker spec recordId recordFields ]
|
let xmlDoc =
|
||||||
|
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||||
|
|
||||||
let attributes =
|
let description =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
"extension members"
|
||||||
else
|
else
|
||||||
[
|
"methods"
|
||||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
|
||||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
|
||||||
]
|
|
||||||
|
|
||||||
let xmlDoc =
|
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
||||||
let fullyQualified = recordId |> Seq.map (fun i -> i.idText) |> String.concat "."
|
|> PreXmlDoc.Create
|
||||||
|
|
||||||
let description =
|
let moduleName =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
"extension members"
|
match ident with
|
||||||
else
|
| [] -> failwith "unexpectedly got an empty identifier for record name"
|
||||||
"methods"
|
| ident ->
|
||||||
|
let expanded =
|
||||||
|
List.last ident
|
||||||
|
|> fun i -> i.idText
|
||||||
|
|> fun s -> s + "JsonParseExtension"
|
||||||
|
|> Ident.Create
|
||||||
|
|
||||||
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
List.take (List.length ident - 1) ident @ [ expanded ]
|
||||||
|> PreXmlDoc.Create
|
else
|
||||||
|
ident
|
||||||
|
|
||||||
let moduleName =
|
let info =
|
||||||
if spec.ExtensionMethods then
|
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||||
match recordId with
|
|
||||||
| [] -> failwith "unexpectedly got an empty identifier for record name"
|
|
||||||
| recordId ->
|
|
||||||
let expanded =
|
|
||||||
List.last recordId
|
|
||||||
|> fun i -> i.idText
|
|
||||||
|> fun s -> s + "JsonParseExtension"
|
|
||||||
|> Ident.Create
|
|
||||||
|
|
||||||
List.take (List.length recordId - 1) recordId @ [ expanded ]
|
let decls =
|
||||||
else
|
match synTypeDefnRepr with
|
||||||
recordId
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) ->
|
||||||
|
let fields = fields |> List.map SynField.extractWithIdent
|
||||||
|
[ createMaker spec ident fields ]
|
||||||
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) ->
|
||||||
|
// [ createMaker spec ident cases ]
|
||||||
|
failwith "Unions are not yet supported"
|
||||||
|
| _ -> failwithf "Not a record or union type"
|
||||||
|
|
||||||
let info =
|
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||||
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
|
||||||
|
|
||||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
|
||||||
| _ -> failwithf "Not a record type"
|
|
||||||
|
|
||||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||||
/// containing a JSON parse function.
|
/// containing a JSON parse function.
|
||||||
@@ -634,10 +626,20 @@ type JsonParseGenerator () =
|
|||||||
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 recordsAndUnions =
|
||||||
|
Ast.extractTypeDefn ast
|
||||||
|
|> List.map (fun (name, defns) ->
|
||||||
|
defns
|
||||||
|
|> List.choose (fun defn ->
|
||||||
|
if Ast.isRecord defn then Some defn
|
||||||
|
elif Ast.isDu defn then Some defn
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|> fun defns -> name, defns
|
||||||
|
)
|
||||||
|
|
||||||
let namespaceAndRecords =
|
let namespaceAndTypes =
|
||||||
records
|
recordsAndUnions
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.choose (fun (ns, types) ->
|
||||||
types
|
types
|
||||||
|> List.choose (fun typeDef ->
|
|> List.choose (fun typeDef ->
|
||||||
@@ -665,13 +667,9 @@ type JsonParseGenerator () =
|
|||||||
)
|
)
|
||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
namespaceAndRecords
|
namespaceAndTypes
|
||||||
|> List.collect (fun (ns, records) ->
|
|> List.collect (fun (ns, types) ->
|
||||||
records
|
types |> List.map (fun (ty, spec) -> JsonParseGenerator.createModule ns spec ty)
|
||||||
|> List.map (fun (record, spec) ->
|
|
||||||
let recordModule = JsonParseGenerator.createRecordModule ns spec record
|
|
||||||
recordModule
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Output.Ast modules
|
Output.Ast modules
|
||||||
|
@@ -117,15 +117,13 @@ module internal JsonSerializeGenerator =
|
|||||||
SynExpr.CreateIdentString "arr"
|
SynExpr.CreateIdentString "arr"
|
||||||
],
|
],
|
||||||
range0,
|
range0,
|
||||||
{
|
SynExprLetOrUseTrivia.empty
|
||||||
InKeyword = None
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|> SynExpr.createLambda "field"
|
|> SynExpr.createLambda "field"
|
||||||
| IDictionaryType (keyType, valueType)
|
| IDictionaryType (_keyType, valueType)
|
||||||
| DictionaryType (keyType, valueType)
|
| DictionaryType (_keyType, valueType)
|
||||||
| IReadOnlyDictionaryType (keyType, valueType)
|
| IReadOnlyDictionaryType (_keyType, valueType)
|
||||||
| MapType (keyType, valueType) ->
|
| MapType (_keyType, valueType) ->
|
||||||
// fun field ->
|
// fun field ->
|
||||||
// let ret = JsonObject ()
|
// let ret = JsonObject ()
|
||||||
// for (KeyValue(key, value)) in field do
|
// for (KeyValue(key, value)) in field do
|
||||||
@@ -188,9 +186,7 @@ module internal JsonSerializeGenerator =
|
|||||||
SynExpr.CreateIdentString "ret"
|
SynExpr.CreateIdentString "ret"
|
||||||
],
|
],
|
||||||
range0,
|
range0,
|
||||||
{
|
SynExprLetOrUseTrivia.empty
|
||||||
InKeyword = None
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|> SynExpr.createLambda "field"
|
|> SynExpr.createLambda "field"
|
||||||
| _ ->
|
| _ ->
|
||||||
@@ -204,22 +200,50 @@ module internal JsonSerializeGenerator =
|
|||||||
|
|
||||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||||
/// `node.Add ({propertyName}, {toJsonNode})`
|
/// `node.Add ({propertyName}, {toJsonNode})`
|
||||||
let createSerializeRhs (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
|
let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
|
||||||
let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "node" ; "Add" ])
|
let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "node" ; "Add" ])
|
||||||
|
|
||||||
let args =
|
let args =
|
||||||
SynExpr.CreateParenedTuple
|
[
|
||||||
[
|
propertyName
|
||||||
propertyName
|
SynExpr.CreateApp (
|
||||||
SynExpr.CreateApp (
|
serializeNode fieldType,
|
||||||
serializeNode fieldType,
|
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ Ident.Create "input" ; fieldId ])
|
||||||
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ Ident.Create "input" ; fieldId ])
|
)
|
||||||
)
|
]
|
||||||
]
|
|> SynExpr.CreateParenedTuple
|
||||||
|
|
||||||
SynExpr.CreateApp (func, args)
|
SynExpr.CreateApp (func, args)
|
||||||
|
|
||||||
let createMaker (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr =
|
||||||
|
let propertyNameAttr =
|
||||||
|
attrs
|
||||||
|
|> List.tryFind (fun attr -> attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal))
|
||||||
|
|
||||||
|
match propertyNameAttr with
|
||||||
|
| None ->
|
||||||
|
let sb = StringBuilder fieldId.idText.Length
|
||||||
|
sb.Append (Char.ToLowerInvariant fieldId.idText.[0]) |> ignore
|
||||||
|
|
||||||
|
if fieldId.idText.Length > 1 then
|
||||||
|
sb.Append fieldId.idText.[1..] |> ignore
|
||||||
|
|
||||||
|
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||||
|
| Some name -> name.ArgExpr
|
||||||
|
|
||||||
|
/// `populateNode` will be inserted before we return the `node` variable.
|
||||||
|
///
|
||||||
|
/// That is, we give you access to a `JsonObject` called `node`,
|
||||||
|
/// and you have access to a variable `inputArgName` which is of type `typeName`.
|
||||||
|
/// Your job is to provide a `populateNode` expression which has the side effect
|
||||||
|
/// of mutating `node` to faithfully reflect the value of `inputArgName`.
|
||||||
|
let scaffolding
|
||||||
|
(spec : JsonSerializeOutputSpec)
|
||||||
|
(typeName : LongIdent)
|
||||||
|
(inputArgName : Ident)
|
||||||
|
(populateNode : SynExpr)
|
||||||
|
: SynModuleDecl
|
||||||
|
=
|
||||||
let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node"
|
let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node"
|
||||||
|
|
||||||
let returnInfo =
|
let returnInfo =
|
||||||
@@ -227,7 +251,6 @@ module internal JsonSerializeGenerator =
|
|||||||
SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||||
)
|
)
|
||||||
|
|
||||||
let inputArg = Ident.Create "input"
|
|
||||||
let functionName = Ident.Create "toJsonNode"
|
let functionName = Ident.Create "toJsonNode"
|
||||||
|
|
||||||
let inputVal =
|
let inputVal =
|
||||||
@@ -245,7 +268,7 @@ module internal JsonSerializeGenerator =
|
|||||||
else
|
else
|
||||||
None
|
None
|
||||||
|
|
||||||
let thisIdOpt = if spec.ExtensionMethods then None else Some inputArg
|
let thisIdOpt = if spec.ExtensionMethods then None else Some inputArgName
|
||||||
|
|
||||||
SynValData.SynValData (
|
SynValData.SynValData (
|
||||||
memberFlags,
|
memberFlags,
|
||||||
@@ -253,62 +276,6 @@ module internal JsonSerializeGenerator =
|
|||||||
thisIdOpt
|
thisIdOpt
|
||||||
)
|
)
|
||||||
|
|
||||||
let assignments =
|
|
||||||
fields
|
|
||||||
|> List.map (fun (SynField (attrs, _, id, fieldType, _, _, _, _, _)) ->
|
|
||||||
let id =
|
|
||||||
match id with
|
|
||||||
| None -> failwith "didn't get an ID on field"
|
|
||||||
| Some id -> id
|
|
||||||
|
|
||||||
let attrs = attrs |> List.collect (fun l -> l.Attributes)
|
|
||||||
|
|
||||||
let propertyNameAttr =
|
|
||||||
attrs
|
|
||||||
|> List.tryFind (fun attr ->
|
|
||||||
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
|
||||||
)
|
|
||||||
|
|
||||||
let propertyName =
|
|
||||||
match propertyNameAttr with
|
|
||||||
| None ->
|
|
||||||
let sb = StringBuilder id.idText.Length
|
|
||||||
sb.Append (Char.ToLowerInvariant id.idText.[0]) |> ignore
|
|
||||||
|
|
||||||
if id.idText.Length > 1 then
|
|
||||||
sb.Append id.idText.[1..] |> ignore
|
|
||||||
|
|
||||||
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
|
||||||
| Some name -> name.ArgExpr
|
|
||||||
|
|
||||||
let pattern =
|
|
||||||
SynPat.LongIdent (
|
|
||||||
SynLongIdent.CreateFromLongIdent [ id ],
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
SynArgPats.Empty,
|
|
||||||
None,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
|
|
||||||
createSerializeRhs propertyName id fieldType
|
|
||||||
)
|
|
||||||
|
|
||||||
let finalConstruction =
|
|
||||||
fields
|
|
||||||
|> List.map (fun (SynField (_, _, id, _, _, _, _, _, _)) ->
|
|
||||||
let id =
|
|
||||||
match id with
|
|
||||||
| None -> failwith "Expected record field to have an identifying name"
|
|
||||||
| Some id -> id
|
|
||||||
|
|
||||||
(SynLongIdent.CreateFromLongIdent [ id ], true),
|
|
||||||
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ id ]))
|
|
||||||
)
|
|
||||||
|> AstHelper.instantiateRecord
|
|
||||||
|
|
||||||
let assignments = assignments |> SynExpr.CreateSequential
|
|
||||||
|
|
||||||
let assignments =
|
let assignments =
|
||||||
SynExpr.LetOrUse (
|
SynExpr.LetOrUse (
|
||||||
false,
|
false,
|
||||||
@@ -327,13 +294,11 @@ module internal JsonSerializeGenerator =
|
|||||||
],
|
],
|
||||||
SynExpr.CreateSequential
|
SynExpr.CreateSequential
|
||||||
[
|
[
|
||||||
SynExpr.Do (assignments, range0)
|
populateNode
|
||||||
SynExpr.Upcast (SynExpr.CreateIdentString "node", SynType.Anon range0, range0)
|
SynExpr.Upcast (SynExpr.CreateIdentString "node", SynType.Anon range0, range0)
|
||||||
],
|
],
|
||||||
range0,
|
range0,
|
||||||
{
|
SynExprLetOrUseTrivia.empty
|
||||||
InKeyword = None
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
let pattern =
|
let pattern =
|
||||||
@@ -344,7 +309,7 @@ module internal JsonSerializeGenerator =
|
|||||||
SynArgPats.Pats
|
SynArgPats.Pats
|
||||||
[
|
[
|
||||||
SynPat.CreateTyped (
|
SynPat.CreateTyped (
|
||||||
SynPat.CreateNamed inputArg,
|
SynPat.CreateNamed inputArgName,
|
||||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName)
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName)
|
||||||
)
|
)
|
||||||
|> SynPat.CreateParen
|
|> SynPat.CreateParen
|
||||||
@@ -406,7 +371,116 @@ module internal JsonSerializeGenerator =
|
|||||||
|
|
||||||
SynModuleDecl.CreateLet [ binding ]
|
SynModuleDecl.CreateLet [ binding ]
|
||||||
|
|
||||||
let createRecordModule
|
let recordModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
||||||
|
let inputArg = Ident.Create "input"
|
||||||
|
let fields = fields |> List.map SynField.extractWithIdent
|
||||||
|
|
||||||
|
fields
|
||||||
|
|> List.map (fun fieldData ->
|
||||||
|
let propertyName = getPropertyName fieldData.Ident fieldData.Attrs
|
||||||
|
createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type
|
||||||
|
)
|
||||||
|
|> SynExpr.CreateSequential
|
||||||
|
|> fun expr -> SynExpr.Do (expr, range0)
|
||||||
|
|> scaffolding spec typeName inputArg
|
||||||
|
|
||||||
|
let unionModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (cases : SynUnionCase list) =
|
||||||
|
let inputArg = Ident.Create "input"
|
||||||
|
let fields = cases |> List.map SynUnionCase.extract
|
||||||
|
|
||||||
|
fields
|
||||||
|
|> List.map (fun unionCase ->
|
||||||
|
let propertyName = getPropertyName unionCase.Ident unionCase.Attrs
|
||||||
|
|
||||||
|
let caseNames = unionCase.Fields |> List.mapi (fun i _ -> Ident.Create $"arg%i{i}")
|
||||||
|
|
||||||
|
let argPats = SynArgPats.create caseNames
|
||||||
|
|
||||||
|
let pattern =
|
||||||
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent (typeName @ [ unionCase.Ident ]),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
argPats,
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
let typeLine =
|
||||||
|
let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "node" ; "Add" ])
|
||||||
|
|
||||||
|
let args =
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[
|
||||||
|
SynExpr.CreateConstString "type"
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.CreateString "System.Text.Json.Nodes.JsonValue.Create"
|
||||||
|
),
|
||||||
|
propertyName
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
SynExpr.CreateApp (func, args)
|
||||||
|
|
||||||
|
let dataNode =
|
||||||
|
SynBinding.Let (
|
||||||
|
pattern = SynPat.CreateNamed (Ident.Create "dataNode"),
|
||||||
|
expr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||||
|
),
|
||||||
|
SynExpr.CreateConst SynConst.Unit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let dataBindings =
|
||||||
|
(unionCase.Fields, caseNames)
|
||||||
|
||> List.zip
|
||||||
|
|> List.map (fun (fieldData, caseName) ->
|
||||||
|
let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs
|
||||||
|
let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "dataNode" ; "Add" ])
|
||||||
|
|
||||||
|
let node =
|
||||||
|
SynExpr.CreateApp (serializeNode fieldData.Type, SynExpr.CreateIdent caseName)
|
||||||
|
|
||||||
|
SynExpr.CreateApp (func, SynExpr.CreateParenedTuple [ propertyName ; node ])
|
||||||
|
)
|
||||||
|
|
||||||
|
let assignToNode =
|
||||||
|
let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "node" ; "Add" ])
|
||||||
|
|
||||||
|
let args =
|
||||||
|
SynExpr.CreateParenedTuple
|
||||||
|
[ SynExpr.CreateConstString "data" ; SynExpr.CreateIdentString "dataNode" ]
|
||||||
|
|
||||||
|
SynExpr.CreateApp (func, args)
|
||||||
|
|
||||||
|
let dataNode =
|
||||||
|
SynExpr.LetOrUse (
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[ dataNode ],
|
||||||
|
SynExpr.CreateSequential (dataBindings @ [ assignToNode ]),
|
||||||
|
range0,
|
||||||
|
SynExprLetOrUseTrivia.empty
|
||||||
|
)
|
||||||
|
|
||||||
|
let action =
|
||||||
|
[
|
||||||
|
yield typeLine
|
||||||
|
if not dataBindings.IsEmpty then
|
||||||
|
yield dataNode
|
||||||
|
]
|
||||||
|
|> SynExpr.CreateSequential
|
||||||
|
|
||||||
|
SynMatchClause.Create (pattern, None, action)
|
||||||
|
)
|
||||||
|
|> fun clauses -> SynExpr.CreateMatch (SynExpr.CreateIdent inputArg, clauses)
|
||||||
|
|> scaffolding spec typeName inputArg
|
||||||
|
|
||||||
|
let createModule
|
||||||
(namespaceId : LongIdent)
|
(namespaceId : LongIdent)
|
||||||
(opens : SynOpenDeclTarget list)
|
(opens : SynOpenDeclTarget list)
|
||||||
(spec : JsonSerializeOutputSpec)
|
(spec : JsonSerializeOutputSpec)
|
||||||
@@ -415,60 +489,62 @@ module internal JsonSerializeGenerator =
|
|||||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||||
typeDefn
|
typeDefn
|
||||||
|
|
||||||
let (SynComponentInfo (_attributes, _typeParams, _constraints, recordId, _, _preferPostfix, _access, _)) =
|
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, _access, _)) =
|
||||||
synComponentInfo
|
synComponentInfo
|
||||||
|
|
||||||
match synTypeDefnRepr with
|
let attributes =
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _recordRange), _) ->
|
if spec.ExtensionMethods then
|
||||||
|
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||||
|
else
|
||||||
|
[
|
||||||
|
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||||
|
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||||
|
]
|
||||||
|
|
||||||
let decls = [ createMaker spec recordId recordFields ]
|
let xmlDoc =
|
||||||
|
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||||
|
|
||||||
let attributes =
|
let description =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
"extension members"
|
||||||
else
|
else
|
||||||
[
|
"methods"
|
||||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
|
||||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
|
||||||
]
|
|
||||||
|
|
||||||
let xmlDoc =
|
$" Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
||||||
let fullyQualified = recordId |> Seq.map (fun i -> i.idText) |> String.concat "."
|
|> PreXmlDoc.Create
|
||||||
|
|
||||||
let description =
|
let moduleName =
|
||||||
if spec.ExtensionMethods then
|
if spec.ExtensionMethods then
|
||||||
"extension members"
|
match ident with
|
||||||
else
|
| [] -> failwith "unexpectedly got an empty identifier for type name"
|
||||||
"methods"
|
| ident ->
|
||||||
|
let expanded =
|
||||||
|
List.last ident
|
||||||
|
|> fun i -> i.idText
|
||||||
|
|> fun s -> s + "JsonSerializeExtension"
|
||||||
|
|> Ident.Create
|
||||||
|
|
||||||
$" Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
List.take (List.length ident - 1) ident @ [ expanded ]
|
||||||
|> PreXmlDoc.Create
|
else
|
||||||
|
ident
|
||||||
|
|
||||||
let moduleName =
|
let info =
|
||||||
if spec.ExtensionMethods then
|
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||||
match recordId with
|
|
||||||
| [] -> failwith "unexpectedly got an empty identifier for record name"
|
|
||||||
| recordId ->
|
|
||||||
let expanded =
|
|
||||||
List.last recordId
|
|
||||||
|> fun i -> i.idText
|
|
||||||
|> fun s -> s + "JsonSerializeExtension"
|
|
||||||
|> Ident.Create
|
|
||||||
|
|
||||||
List.take (List.length recordId - 1) recordId @ [ expanded ]
|
let decls =
|
||||||
else
|
match synTypeDefnRepr with
|
||||||
recordId
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _range), _) ->
|
||||||
|
[ recordModule spec ident recordFields ]
|
||||||
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, unionFields, _range), _) ->
|
||||||
|
[ unionModule spec ident unionFields ]
|
||||||
|
| _ -> failwithf "Only record types currently supported."
|
||||||
|
|
||||||
let info =
|
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||||
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
|
||||||
|
|
||||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
|
namespaceId,
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
|
||||||
namespaceId,
|
)
|
||||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
|
|
||||||
)
|
|
||||||
| _ -> failwithf "Not a record type"
|
|
||||||
|
|
||||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||||
/// containing a JSON serialization function.
|
/// containing a JSON serialization function.
|
||||||
@@ -482,10 +558,20 @@ type JsonSerializeGenerator () =
|
|||||||
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 recordsAndUnions =
|
||||||
|
Ast.extractTypeDefn ast
|
||||||
|
|> List.map (fun (name, defns) ->
|
||||||
|
defns
|
||||||
|
|> List.choose (fun defn ->
|
||||||
|
if Ast.isRecord defn then Some defn
|
||||||
|
elif Ast.isDu defn then Some defn
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|> fun defns -> name, defns
|
||||||
|
)
|
||||||
|
|
||||||
let namespaceAndRecords =
|
let namespaceAndTypes =
|
||||||
records
|
recordsAndUnions
|
||||||
|> List.choose (fun (ns, types) ->
|
|> List.choose (fun (ns, types) ->
|
||||||
types
|
types
|
||||||
|> List.choose (fun typeDef ->
|
|> List.choose (fun typeDef ->
|
||||||
@@ -515,13 +601,10 @@ type JsonSerializeGenerator () =
|
|||||||
let opens = AstHelper.extractOpens ast
|
let opens = AstHelper.extractOpens ast
|
||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
namespaceAndRecords
|
namespaceAndTypes
|
||||||
|> List.collect (fun (ns, records) ->
|
|> List.collect (fun (ns, types) ->
|
||||||
records
|
types
|
||||||
|> List.map (fun (record, spec) ->
|
|> List.map (fun (ty, spec) -> JsonSerializeGenerator.createModule ns opens spec ty)
|
||||||
let recordModule = JsonSerializeGenerator.createRecordModule ns opens spec record
|
|
||||||
recordModule
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Output.Ast modules
|
Output.Ast modules
|
||||||
|
@@ -63,7 +63,7 @@ module internal RemoveOptionsGenerator =
|
|||||||
|
|
||||||
SynModuleDecl.Types ([ typeDecl ], range0)
|
SynModuleDecl.Types ([ typeDecl ], range0)
|
||||||
|
|
||||||
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynField list) =
|
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynFieldData<Ident> list) =
|
||||||
let xmlDoc = PreXmlDoc.Create " Remove the optional members of the input."
|
let xmlDoc = PreXmlDoc.Create " Remove the optional members of the input."
|
||||||
|
|
||||||
let returnInfo =
|
let returnInfo =
|
||||||
@@ -81,17 +81,17 @@ module internal RemoveOptionsGenerator =
|
|||||||
|
|
||||||
let body =
|
let body =
|
||||||
fields
|
fields
|
||||||
|> List.map (fun (SynField (_, _, id, fieldType, _, _, _, _, _)) ->
|
|> List.map (fun fieldData ->
|
||||||
let id =
|
|
||||||
match id with
|
|
||||||
| None -> failwith "Expected record field to have an identifying name"
|
|
||||||
| Some id -> id
|
|
||||||
|
|
||||||
let accessor =
|
let accessor =
|
||||||
SynExpr.LongIdent (false, SynLongIdent ([ inputArg ; id ], [ range0 ], []), None, range0)
|
SynExpr.LongIdent (
|
||||||
|
false,
|
||||||
|
SynLongIdent ([ inputArg ; fieldData.Ident ], [ range0 ], []),
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
let body =
|
let body =
|
||||||
match fieldType with
|
match fieldData.Type with
|
||||||
| OptionType _ ->
|
| OptionType _ ->
|
||||||
SynExpr.CreateApp (
|
SynExpr.CreateApp (
|
||||||
SynExpr.CreateAppInfix (
|
SynExpr.CreateAppInfix (
|
||||||
@@ -111,14 +111,15 @@ module internal RemoveOptionsGenerator =
|
|||||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "Option.defaultWith"),
|
SynExpr.CreateLongIdent (SynLongIdent.CreateString "Option.defaultWith"),
|
||||||
SynExpr.CreateLongIdent (
|
SynExpr.CreateLongIdent (
|
||||||
SynLongIdent.CreateFromLongIdent (
|
SynLongIdent.CreateFromLongIdent (
|
||||||
withoutOptionsType @ [ Ident.Create (sprintf "Default%s" id.idText) ]
|
withoutOptionsType
|
||||||
|
@ [ Ident.Create (sprintf "Default%s" fieldData.Ident.idText) ]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
| _ -> accessor
|
| _ -> accessor
|
||||||
|
|
||||||
(SynLongIdent.CreateFromLongIdent [ id ], true), Some body
|
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true), Some body
|
||||||
)
|
)
|
||||||
|> AstHelper.instantiateRecord
|
|> AstHelper.instantiateRecord
|
||||||
|
|
||||||
@@ -160,12 +161,13 @@ module internal RemoveOptionsGenerator =
|
|||||||
synComponentInfo
|
synComponentInfo
|
||||||
|
|
||||||
match synTypeDefnRepr with
|
match synTypeDefnRepr with
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (accessibility, recordFields, _recordRange), _) ->
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (accessibility, fields, _range), _) ->
|
||||||
|
let fieldData = fields |> List.map SynField.extractWithIdent
|
||||||
|
|
||||||
let decls =
|
let decls =
|
||||||
[
|
[
|
||||||
createType (Some doc) accessibility typeParams recordFields
|
createType (Some doc) accessibility typeParams fields
|
||||||
createMaker [ Ident.Create "Short" ] recordId recordFields
|
createMaker [ Ident.Create "Short" ] recordId fieldData
|
||||||
]
|
]
|
||||||
|
|
||||||
let attributes =
|
let attributes =
|
||||||
|
18
WoofWare.Myriad.Plugins/SynExpr/SynArgPats.fs
Normal file
18
WoofWare.Myriad.Plugins/SynExpr/SynArgPats.fs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.Syntax
|
||||||
|
open Fantomas.FCS.Text.Range
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynArgPats =
|
||||||
|
let create (caseNames : Ident list) : SynArgPats =
|
||||||
|
if caseNames.IsEmpty then
|
||||||
|
SynArgPats.Pats []
|
||||||
|
else
|
||||||
|
|
||||||
|
caseNames
|
||||||
|
|> List.map (fun ident -> SynPat.Named (SynIdent.SynIdent (ident, None), false, None, range0))
|
||||||
|
|> fun ps -> SynPat.Tuple (false, ps, List.replicate (ps.Length - 1) range0, range0)
|
||||||
|
|> fun p -> SynPat.Paren (p, range0)
|
||||||
|
|> List.singleton
|
||||||
|
|> SynArgPats.Pats
|
10
WoofWare.Myriad.Plugins/SynExpr/SynExprLetOrUseTrivia.fs
Normal file
10
WoofWare.Myriad.Plugins/SynExpr/SynExprLetOrUseTrivia.fs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynExprLetOrUseTrivia =
|
||||||
|
let empty : SynExprLetOrUseTrivia =
|
||||||
|
{
|
||||||
|
InKeyword = None
|
||||||
|
}
|
39
WoofWare.Myriad.Plugins/SynExpr/SynField.fs
Normal file
39
WoofWare.Myriad.Plugins/SynExpr/SynField.fs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.Syntax
|
||||||
|
|
||||||
|
type internal SynFieldData<'Ident> =
|
||||||
|
{
|
||||||
|
Attrs : SynAttribute list
|
||||||
|
Ident : 'Ident
|
||||||
|
Type : SynType
|
||||||
|
}
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynField =
|
||||||
|
/// Get the useful information out of a SynField.
|
||||||
|
let extract (SynField (attrs, _, id, fieldType, _, _, _, _, _)) : SynFieldData<Ident option> =
|
||||||
|
{
|
||||||
|
Attrs = attrs |> List.collect (fun l -> l.Attributes)
|
||||||
|
Ident = id
|
||||||
|
Type = fieldType
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapIdent<'a, 'b> (f : 'a -> 'b) (x : SynFieldData<'a>) : SynFieldData<'b> =
|
||||||
|
let ident = f x.Ident
|
||||||
|
|
||||||
|
{
|
||||||
|
Attrs = x.Attrs
|
||||||
|
Ident = ident
|
||||||
|
Type = x.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Throws if the field has no identifier.
|
||||||
|
let extractWithIdent (f : SynField) : SynFieldData<Ident> =
|
||||||
|
f
|
||||||
|
|> extract
|
||||||
|
|> mapIdent (fun ident ->
|
||||||
|
match ident with
|
||||||
|
| None -> failwith "expected field identifier to have a value, but it did not"
|
||||||
|
| Some i -> i
|
||||||
|
)
|
32
WoofWare.Myriad.Plugins/SynExpr/SynUnionCase.fs
Normal file
32
WoofWare.Myriad.Plugins/SynExpr/SynUnionCase.fs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open Fantomas.FCS.Syntax
|
||||||
|
|
||||||
|
type internal UnionCase<'Ident> =
|
||||||
|
{
|
||||||
|
Fields : SynFieldData<'Ident> list
|
||||||
|
Attrs : SynAttribute list
|
||||||
|
Ident : Ident
|
||||||
|
}
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module internal SynUnionCase =
|
||||||
|
let extract (SynUnionCase (attrs, id, caseType, _, _, _, _)) : UnionCase<Ident option> =
|
||||||
|
match caseType with
|
||||||
|
| SynUnionCaseKind.FullType _ -> failwith "WoofWare.Myriad does not support FullType union cases."
|
||||||
|
| SynUnionCaseKind.Fields fields ->
|
||||||
|
|
||||||
|
let fields = fields |> List.map SynField.extract
|
||||||
|
|
||||||
|
let id =
|
||||||
|
match id with
|
||||||
|
| SynIdent.SynIdent (ident, _) -> ident
|
||||||
|
|
||||||
|
// As far as I can tell, there's no way to get any attributes here? :shrug:
|
||||||
|
let attrs = attrs |> List.collect (fun l -> l.Attributes)
|
||||||
|
|
||||||
|
{
|
||||||
|
Fields = fields
|
||||||
|
Attrs = attrs
|
||||||
|
Ident = id
|
||||||
|
}
|
@@ -27,9 +27,13 @@
|
|||||||
<Compile Include="List.fs"/>
|
<Compile Include="List.fs"/>
|
||||||
<Compile Include="Ident.fs" />
|
<Compile Include="Ident.fs" />
|
||||||
<Compile Include="AstHelper.fs"/>
|
<Compile Include="AstHelper.fs"/>
|
||||||
<Compile Include="SynExpr.fs" />
|
<Compile Include="SynExpr\SynExpr.fs" />
|
||||||
<Compile Include="SynType.fs"/>
|
<Compile Include="SynExpr\SynType.fs" />
|
||||||
<Compile Include="SynAttribute.fs"/>
|
<Compile Include="SynExpr\SynAttribute.fs" />
|
||||||
|
<Compile Include="SynExpr\SynArgPats.fs" />
|
||||||
|
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
|
||||||
|
<Compile Include="SynExpr\SynField.fs" />
|
||||||
|
<Compile Include="SynExpr\SynUnionCase.fs" />
|
||||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||||
<Compile Include="InterfaceMockGenerator.fs"/>
|
<Compile Include="InterfaceMockGenerator.fs"/>
|
||||||
<Compile Include="JsonSerializeGenerator.fs"/>
|
<Compile Include="JsonSerializeGenerator.fs"/>
|
||||||
|
@@ -3,5 +3,10 @@
|
|||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
"pathFilters": null
|
"pathFilters": [
|
||||||
}
|
":/",
|
||||||
|
":^WoofWare.Myriad.Plugins.Test/",
|
||||||
|
":^WoofWare.Myriad.Plugins.Attributes/Test/",
|
||||||
|
":^/.github/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
52
nix/deps.nix
52
nix/deps.nix
@@ -13,8 +13,8 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "ApiSurface";
|
pname = "ApiSurface";
|
||||||
version = "4.0.39";
|
version = "4.0.40";
|
||||||
sha256 = "sha256-I4K5nJbltsfL/1r+KPTIo2wUd30zsCC2pkrnIRnsRHM=";
|
sha256 = "1c9z0b6minlripwrjmv4yd5w8zj4lcpak4x41izh7ygx8kgmbvx0";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Fantomas.Core";
|
pname = "Fantomas.Core";
|
||||||
@@ -118,13 +118,13 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.CodeCoverage";
|
pname = "Microsoft.CodeCoverage";
|
||||||
version = "17.9.0";
|
version = "17.10.0";
|
||||||
sha256 = "1gljgi69k0fz8vy8bn6xlyxabj6q4vls2zza9wz7ng6ix3irm89r";
|
sha256 = "0s0v7jmrq85n356xv7zixvwa4z94fszjcr5vll8x4im1a2lp00f9";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NET.Test.Sdk";
|
pname = "Microsoft.NET.Test.Sdk";
|
||||||
version = "17.9.0";
|
version = "17.10.0";
|
||||||
sha256 = "1lls1fly2gr1n9n1xyl9k33l2v4pwfmylyzkq8v4v5ldnwkl1zdb";
|
sha256 = "13g8fwl09li8fc71nk13dgkb7gahd4qhamyg2xby7am63nlchhdf";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
||||||
@@ -268,13 +268,13 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||||
version = "17.9.0";
|
version = "17.10.0";
|
||||||
sha256 = "1kgsl9w9fganbm9wvlkqgk0ag9hfi58z88rkfybc6kvg78bx89ca";
|
sha256 = "07j69cw8r39533w4p39mnj00kahazz38760in3jfc45kmlcdb26x";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.TestPlatform.TestHost";
|
pname = "Microsoft.TestPlatform.TestHost";
|
||||||
version = "17.9.0";
|
version = "17.10.0";
|
||||||
sha256 = "19ffh31a1jxzn8j69m1vnk5hyfz3dbxmflq77b8x82zybiilh5nl";
|
sha256 = "1bl471s7fx9jycr0cc8rylwf34mrvlg9qn1an6l86nisavfcyb7v";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Myriad.Core";
|
pname = "Myriad.Core";
|
||||||
@@ -308,33 +308,33 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Common";
|
pname = "NuGet.Common";
|
||||||
version = "6.9.1";
|
version = "6.10.0";
|
||||||
sha256 = "0ic3d46r9v05pkczpmskw86yzixm6iwshbw0ya8i2957nhhlymw8";
|
sha256 = "0nizrnilmlcqbm945293h8q3wfqfchb4xi8g50x4kjn0rbpd1kbh";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Configuration";
|
pname = "NuGet.Configuration";
|
||||||
version = "6.9.1";
|
version = "6.10.0";
|
||||||
sha256 = "07z4qgbibpg59j2r05ifnqdyqf2xinm33rx7gjyr1f73kzg01m33";
|
sha256 = "1aqaknaawnqx4mnvx9qw73wvj48jjzv0d78dzwl7m9zjlrl9myhz";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Frameworks";
|
pname = "NuGet.Frameworks";
|
||||||
version = "6.9.1";
|
version = "6.10.0";
|
||||||
sha256 = "0s3az3ac53icjnmb14hfjcmkvzscvrkm62jgqf48yvsbysyhqm5s";
|
sha256 = "0hrd8y31zx9a0wps49czw0qgbrakb49zn3abfgylc9xrq990zkqk";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Packaging";
|
pname = "NuGet.Packaging";
|
||||||
version = "6.9.1";
|
version = "6.10.0";
|
||||||
sha256 = "0w0arkmzg3qh1brq4vm10zrsjm7nw706ld4y5kqcmvjpd16f4b4y";
|
sha256 = "18s53cvrf51lihmaqqdf48p2qi6ky1l48jv0hvbp76cxwdg7rba4";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Protocol";
|
pname = "NuGet.Protocol";
|
||||||
version = "6.7.0";
|
version = "6.10.0";
|
||||||
sha256 = "1v5ibnq2mp801vw68zyj169hkj3xm7h55824i33n1jxxj2vs3vbk";
|
sha256 = "0hmv4q0ks9i34mfgpb13l01la9v3jjllfh1qd3aqv105xrqrdxac";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Versioning";
|
pname = "NuGet.Versioning";
|
||||||
version = "6.9.1";
|
version = "6.10.0";
|
||||||
sha256 = "0xrs82dydy9cgxf0qypr01wawwnq1nf6fc7rwisb4y5v4r259fdm";
|
sha256 = "1x19njx4x0sw9fz8y5fibi15xfsrw5avir0cx0599yd7p3ykik5g";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit";
|
pname = "NUnit";
|
||||||
@@ -433,12 +433,12 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "System.Text.Encodings.Web";
|
pname = "System.Text.Encodings.Web";
|
||||||
version = "6.0.0";
|
version = "7.0.0";
|
||||||
sha256 = "06n9ql3fmhpjl32g3492sj181zjml5dlcc5l76xq2h38c4f87sai";
|
sha256 = "1151hbyrcf8kyg1jz8k9awpbic98lwz9x129rg7zk1wrs6vjlpxl";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "System.Text.Json";
|
pname = "System.Text.Json";
|
||||||
version = "6.0.0";
|
version = "7.0.3";
|
||||||
sha256 = "1si2my1g0q0qv1hiqnji4xh9wd05qavxnzj9dwgs23iqvgjky0gl";
|
sha256 = "0zjrnc9lshagm6kdb9bdh45dmlnkpwcpyssa896sda93ngbmj8k9";
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user