Compare commits

..

6 Commits

Author SHA1 Message Date
Patrick Stevens
ba31689145 Also allow serialising units of measure (#171) 2024-06-25 00:04:56 +01:00
Patrick Stevens
85929d49d5 Support units of measure in JsonParse (#170) 2024-06-24 23:23:23 +01:00
dependabot[bot]
db4694f6e7 Bump actions/attest-build-provenance from 1.0.0 to 1.3.2 (#169)
Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 1.0.0 to 1.3.2.
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](897ed5eab6...bdd51370e0)

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 18:55:05 +01:00
Patrick Stevens
669eccbdef Nudge README to bump the pipeline (#168) 2024-06-17 23:17:34 +01:00
Patrick Stevens
1bb87e55da Attest contents of packages (#167) 2024-06-17 23:08:36 +01:00
Patrick Stevens
4901e7cdf4 Add visibility modifiers in JsonParse/Serialize (#165) 2024-06-15 21:03:59 +01:00
24 changed files with 701 additions and 196 deletions

14
.github/workflows/assert-contents.sh vendored Normal file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
echo "Unzipping version from NuGet"
ls from-nuget.nupkg
mkdir from-nuget && cp from-nuget.nupkg from-nuget/zip.zip && cd from-nuget && unzip zip.zip && rm zip.zip && cd - || exit 1
echo "Unzipping version from local build"
ls packed/
mkdir from-local && cp packed/*.nupkg from-local/zip.zip && cd from-local && unzip zip.zip && rm zip.zip && cd - || exit 1
cd from-local && find . -type f -exec sha256sum {} \; | sort > ../from-local.txt && cd .. || exit 1
cd from-nuget && find . -type f -and -not -name '.signature.p7s' -exec sha256sum {} \; | sort > ../from-nuget.txt && cd .. || exit 1
diff from-local.txt from-nuget.txt

View File

@@ -221,11 +221,53 @@ jobs:
steps:
- run: echo "All required checks complete."
nuget-publish:
attestation-attribute:
runs-on: ubuntu-latest
needs: [all-required-checks-complete]
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
permissions:
id-token: write
attestations: write
contents: read
steps:
- name: Download NuGet artifact
uses: actions/download-artifact@v4
with:
name: nuget-package-attribute
path: packed
- name: Attest Build Provenance
uses: actions/attest-build-provenance@bdd51370e0416ac948727f861e03c2f05d32d78e # v1.3.2
with:
subject-path: "packed/*.nupkg"
attestation-plugin:
runs-on: ubuntu-latest
needs: [all-required-checks-complete]
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
permissions:
id-token: write
attestations: write
contents: read
steps:
- name: Download NuGet artifact
uses: actions/download-artifact@v4
with:
name: nuget-package-plugin
path: packed
- name: Attest Build Provenance
uses: actions/attest-build-provenance@bdd51370e0416ac948727f861e03c2f05d32d78e # v1.3.2
with:
subject-path: "packed/*.nupkg"
nuget-publish-attribute:
runs-on: ubuntu-latest
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
needs: [all-required-checks-complete]
environment: main-deploy
permissions:
id-token: write
attestations: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Install Nix
@@ -233,20 +275,73 @@ jobs:
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Download NuGet artifact (plugin)
uses: actions/download-artifact@v4
with:
name: nuget-package-plugin
path: packed-plugin
- name: Publish to NuGet (plugin)
run: nix develop --command dotnet nuget push "packed-plugin/WoofWare.Myriad.Plugins.*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Download NuGet artifact (attribute)
- name: Download NuGet artifact
uses: actions/download-artifact@v4
with:
name: nuget-package-attribute
path: packed-attribute
- name: Publish to NuGet (attribute)
run: nix develop --command dotnet nuget push "packed-attribute/WoofWare.Myriad.Plugins.Attributes.*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
path: packed
- name: Publish to NuGet
id: publish-success
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: 'nix develop --command bash ./.github/workflows/nuget-push.sh "packed/WoofWare.Myriad.Plugins.Attributes.*.nupkg"'
- name: Wait for availability
if: steps.publish-success.outputs.result == 'published'
env:
PACKAGE_VERSION: ${{ steps.publish-success.outputs.version }}
run: 'echo "$PACKAGE_VERSION" && while ! curl -L --fail -o from-nuget.nupkg "https://www.nuget.org/api/v2/package/WoofWare.Myriad.Plugins.Attributes/$PACKAGE_VERSION" ; do sleep 10; done'
# Astonishingly, NuGet.org considers it to be "more secure" to tamper with my package after upload (https://devblogs.microsoft.com/nuget/introducing-repository-signatures/).
# So we have to *re-attest* it after it's uploaded. Mind-blowing.
- name: Assert package contents
if: steps.publish-success.outputs.result == 'published'
run: 'bash ./.github/workflows/assert-contents.sh'
- name: Attest Build Provenance
if: steps.publish-success.outputs.result == 'published'
uses: actions/attest-build-provenance@bdd51370e0416ac948727f861e03c2f05d32d78e # v1.3.2
with:
subject-path: "from-nuget.nupkg"
nuget-publish-plugin:
runs-on: ubuntu-latest
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
needs: [all-required-checks-complete]
environment: main-deploy
permissions:
id-token: write
attestations: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@V27
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Download NuGet artifact
uses: actions/download-artifact@v4
with:
name: nuget-package-plugin
path: packed
- name: Publish to NuGet
id: publish-success
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: 'nix develop --command bash ./.github/workflows/nuget-push.sh "packed/WoofWare.Myriad.Plugins.*.nupkg"'
- name: Wait for availability
if: steps.publish-success.outputs.result == 'published'
env:
PACKAGE_VERSION: ${{ steps.publish-success.outputs.version }}
run: 'echo "$PACKAGE_VERSION" && while ! curl -L --fail -o from-nuget.nupkg "https://www.nuget.org/api/v2/package/WoofWare.Myriad.Plugins/$PACKAGE_VERSION" ; do sleep 10; done'
# Astonishingly, NuGet.org considers it to be "more secure" to tamper with my package after upload (https://devblogs.microsoft.com/nuget/introducing-repository-signatures/).
# So we have to *re-attest* it after it's uploaded. Mind-blowing.
- name: Assert package contents
if: steps.publish-success.outputs.result == 'published'
run: 'bash ./.github/workflows/assert-contents.sh'
- name: Attest Build Provenance
if: steps.publish-success.outputs.result == 'published'
uses: actions/attest-build-provenance@bdd51370e0416ac948727f861e03c2f05d32d78e # v1.3.2
with:
subject-path: "from-nuget.nupkg"
github-release-plugin:
runs-on: ubuntu-latest

24
.github/workflows/nuget-push.sh vendored Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
SOURCE_NUPKG=$(find . -type f -name '*.nupkg')
PACKAGE_VERSION=$(basename "$SOURCE_NUPKG" | rev | cut -d '.' -f 2-4 | rev)
echo "version=$PACKAGE_VERSION" >> "$GITHUB_OUTPUT"
tmp=$(mktemp)
if ! dotnet nuget push "$SOURCE_NUPKG" --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json > "$tmp" ; then
cat "$tmp"
if grep 'already exists and cannot be modified' "$tmp" ; then
echo "result=skipped" >> "$GITHUB_OUTPUT"
exit 0
else
echo "Unexpected failure to upload"
exit 1
fi
fi
cat "$tmp"
echo "result=published" >> "$GITHUB_OUTPUT"

24
.gitignore vendored
View File

@@ -1,12 +1,12 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
.idea/
*.sln.DotSettings.user
.DS_Store
result
.analyzerpackages/
analysis.sarif
.direnv/
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
.idea/
*.sln.DotSettings.user
.DS_Store
result
.analyzerpackages/
analysis.sarif
.direnv/

View File

@@ -1,5 +1,10 @@
Notable changes are recorded here.
# WoofWare.Myriad.Plugins 2.1.45, WoofWare.Myriad.Plugins.Attributes 3.1.7
The NuGet packages are now attested to through [GitHub Attestations](https://github.blog/2024-05-02-introducing-artifact-attestations-now-in-public-beta/).
You can run `gh attestation verify ~/.nuget/packages/woofware.myriad.plugins/2.1.45/woofware.myriad.plugins.2.1.45.nupkg -o Smaug123`, for example, to verify with GitHub that the GitHub Actions pipeline on this repository produced a nupkg file with the same hash as the one you were served from NuGet.
# WoofWare.Myriad.Plugins 2.1.33
`JsonParse` can now deserialize the discriminated unions which `JsonSerialize` wrote out.

View File

@@ -4,6 +4,33 @@
//------------------------------------------------------------------------------
namespace ConsumePlugin
open System.Text.Json.Serialization
/// Module containing JSON serializing methods for the InternalTypeNotExtensionSerial type
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module internal InternalTypeNotExtensionSerial =
/// Serialize to a JSON node
let toJsonNode (input : InternalTypeNotExtensionSerial) : System.Text.Json.Nodes.JsonNode =
let node = System.Text.Json.Nodes.JsonObject ()
do node.Add ((Literals.something), System.Text.Json.Nodes.JsonValue.Create<string> input.InternalThing2)
node :> _
namespace ConsumePlugin
open System.Text.Json.Serialization
/// Module containing JSON serializing extension members for the InternalTypeExtension type
[<AutoOpen>]
module internal InternalTypeExtensionJsonSerializeExtension =
/// Extension methods for JSON parsing
type InternalTypeExtension with
/// Serialize to a JSON node
static member toJsonNode (input : InternalTypeExtension) : System.Text.Json.Nodes.JsonNode =
let node = System.Text.Json.Nodes.JsonObject ()
do node.Add ((Literals.something), System.Text.Json.Nodes.JsonValue.Create<string> input.ExternalThing)
node :> _
namespace ConsumePlugin
@@ -22,7 +49,7 @@ module InnerType =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
Thing = arg_0
@@ -44,7 +71,7 @@ module JsonRecordType =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|> Array.ofSeq
let arg_4 =
@@ -57,7 +84,7 @@ module JsonRecordType =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|> Array.ofSeq
let arg_3 =
@@ -82,7 +109,7 @@ module JsonRecordType =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|> List.ofSeq
let arg_1 =
@@ -95,7 +122,7 @@ module JsonRecordType =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["a"] with
@@ -107,7 +134,7 @@ module JsonRecordType =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
{
A = arg_0
@@ -119,6 +146,53 @@ module JsonRecordType =
}
namespace ConsumePlugin
/// Module containing JSON parsing methods for the InternalTypeNotExtension type
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module internal InternalTypeNotExtension =
/// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InternalTypeNotExtension =
let arg_0 =
(match node.[(Literals.something)] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ((Literals.something))
)
)
| v -> v)
.AsValue()
.GetValue<System.String> ()
{
InternalThing = arg_0
}
namespace ConsumePlugin
/// Module containing JSON parsing extension members for the InternalTypeExtension type
[<AutoOpen>]
module internal InternalTypeExtensionJsonParseExtension =
/// Extension methods for JSON parsing
type InternalTypeExtension with
/// Parse from a JSON node.
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : InternalTypeExtension =
let arg_0 =
(match node.[(Literals.something)] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ((Literals.something))
)
)
| v -> v)
.AsValue()
.GetValue<System.String> ()
{
ExternalThing = arg_0
}
namespace ConsumePlugin
/// Module containing JSON parsing extension members for the ToGetExtensionMethod type
[<AutoOpen>]
module ToGetExtensionMethodJsonParseExtension =
@@ -271,7 +345,7 @@ module ToGetExtensionMethodJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_7 =
(match node.["hotel"] with
@@ -343,7 +417,7 @@ module ToGetExtensionMethodJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<float> ()
.GetValue<System.Double> ()
let arg_1 =
(match node.["bravo"] with
@@ -368,7 +442,7 @@ module ToGetExtensionMethodJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
Alpha = arg_0

View File

@@ -55,7 +55,7 @@ module GymOpeningHours =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|> List.ofSeq
let arg_0 =
@@ -68,7 +68,7 @@ module GymOpeningHours =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
{
IsAlwaysOpen = arg_0
@@ -91,7 +91,7 @@ module GymAccessOptions =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_0 =
(match node.["pinAccess"] with
@@ -103,7 +103,7 @@ module GymAccessOptions =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
{
PinAccess = arg_0
@@ -127,7 +127,7 @@ module GymLocation =
)
| v -> v)
.AsValue()
.GetValue<float> ()
.GetValue<System.Double> ()
with :? System.InvalidOperationException as exc ->
if exc.Message.Contains "cannot be converted to" then
if
@@ -148,6 +148,7 @@ module GymLocation =
reraise ()
else
reraise ()
|> LanguagePrimitives.FloatWithMeasure
let arg_0 =
try
@@ -160,7 +161,7 @@ module GymLocation =
)
| v -> v)
.AsValue()
.GetValue<float> ()
.GetValue<System.Double> ()
with :? System.InvalidOperationException as exc ->
if exc.Message.Contains "cannot be converted to" then
if
@@ -203,12 +204,12 @@ module GymAddress =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_4 =
match node.["county"] with
| null -> None
| v -> v.AsValue().GetValue<string> () |> Some
| v -> v.AsValue().GetValue<System.String> () |> Some
let arg_3 =
(match node.["town"] with
@@ -220,17 +221,17 @@ module GymAddress =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_2 =
match node.["addressLine3"] with
| null -> None
| v -> v.AsValue().GetValue<string> () |> Some
| v -> v.AsValue().GetValue<System.String> () |> Some
let arg_1 =
match node.["addressLine2"] with
| null -> None
| v -> v.AsValue().GetValue<string> () |> Some
| v -> v.AsValue().GetValue<System.String> () |> Some
let arg_0 =
(match node.["addressLine1"] with
@@ -242,7 +243,7 @@ module GymAddress =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
AddressLine1 = arg_0
@@ -269,7 +270,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_9 =
(match node.["timeZone"] with
@@ -281,7 +282,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_8 =
GymLocation.jsonParse (
@@ -329,7 +330,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_4 =
(match node.["phoneNumber"] with
@@ -341,7 +342,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_3 =
GymAddress.jsonParse (
@@ -365,7 +366,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_1 =
(match node.["id"] with
@@ -377,7 +378,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_0 =
(match node.["name"] with
@@ -389,7 +390,7 @@ module Gym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
Name = arg_0
@@ -424,7 +425,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_13 =
(match node.["suspendedReason"] with
@@ -436,7 +437,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_12 =
(match node.["membershipLevel"] with
@@ -448,7 +449,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_11 =
(match node.["membershipName"] with
@@ -460,7 +461,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_10 =
(match node.["postCode"] with
@@ -472,7 +473,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_9 =
(match node.["mobileNumber"] with
@@ -484,7 +485,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_8 =
(match node.["dateofBirth"] with
@@ -509,7 +510,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_6 =
(match node.["emailAddress"] with
@@ -521,7 +522,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_5 =
(match node.["homeGymName"] with
@@ -533,7 +534,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_4 =
(match node.["homeGymId"] with
@@ -545,7 +546,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_3 =
(match node.["lastName"] with
@@ -557,7 +558,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_2 =
(match node.["firstName"] with
@@ -569,7 +570,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_1 =
(match node.["compoundMemberId"] with
@@ -581,7 +582,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["id"] with
@@ -593,7 +594,7 @@ module MemberJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
{
Id = arg_0
@@ -629,7 +630,7 @@ module GymAttendance =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_7 =
(match node.["lastRefreshedPeopleInClasses"] with
@@ -680,12 +681,12 @@ module GymAttendance =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_3 =
match node.["totalPeopleSuffix"] with
| null -> None
| v -> v.AsValue().GetValue<string> () |> Some
| v -> v.AsValue().GetValue<System.String> () |> Some
let arg_2 =
(match node.["totalPeopleInClasses"] with
@@ -697,7 +698,7 @@ module GymAttendance =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_1 =
(match node.["totalPeopleInGym"] with
@@ -709,7 +710,7 @@ module GymAttendance =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_0 =
(match node.["description"] with
@@ -721,7 +722,7 @@ module GymAttendance =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
Description = arg_0
@@ -764,7 +765,7 @@ module MemberActivityDto =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_3 =
(match node.["totalClasses"] with
@@ -776,7 +777,7 @@ module MemberActivityDto =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_2 =
(match node.["totalVisits"] with
@@ -788,7 +789,7 @@ module MemberActivityDto =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_1 =
(match node.["averageDuration"] with
@@ -800,7 +801,7 @@ module MemberActivityDto =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_0 =
(match node.["totalDuration"] with
@@ -812,7 +813,7 @@ module MemberActivityDto =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
{
TotalDuration = arg_0
@@ -839,7 +840,7 @@ module SessionsAggregate =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_1 =
(match node.["Visits"] with
@@ -851,7 +852,7 @@ module SessionsAggregate =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_0 =
(match node.["Activities"] with
@@ -863,7 +864,7 @@ module SessionsAggregate =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
{
Activities = arg_0
@@ -887,7 +888,7 @@ module VisitGym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_1 =
(match node.["Name"] with
@@ -899,7 +900,7 @@ module VisitGym =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["Id"] with
@@ -911,7 +912,7 @@ module VisitGym =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
{
Id = arg_0
@@ -947,7 +948,7 @@ module Visit =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_1 =
(match node.["StartTime"] with
@@ -972,7 +973,7 @@ module Visit =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
{
IsDurationEstimated = arg_0

View File

@@ -302,7 +302,7 @@ module PureGymApi =
v.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key)
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> Map.ofSeq

View File

@@ -136,7 +136,7 @@ module JsonRecordTypeWithBothJsonSerializeExtension =
)
node.Add (
"f",
"arr",
(fun field ->
let arr = System.Text.Json.Nodes.JsonArray ()
@@ -145,9 +145,21 @@ module JsonRecordTypeWithBothJsonSerializeExtension =
arr
)
input.F
input.Arr
)
node.Add ("byte", System.Text.Json.Nodes.JsonValue.Create<byte<measure>> input.Byte)
node.Add ("sbyte", System.Text.Json.Nodes.JsonValue.Create<sbyte<measure>> input.Sbyte)
node.Add ("i", System.Text.Json.Nodes.JsonValue.Create<int<measure>> input.I)
node.Add ("i32", System.Text.Json.Nodes.JsonValue.Create<int32<measure>> input.I32)
node.Add ("i64", System.Text.Json.Nodes.JsonValue.Create<int64<measure>> input.I64)
node.Add ("u", System.Text.Json.Nodes.JsonValue.Create<uint<measure>> input.U)
node.Add ("u32", System.Text.Json.Nodes.JsonValue.Create<uint32<measure>> input.U32)
node.Add ("u64", System.Text.Json.Nodes.JsonValue.Create<uint64<measure>> input.U64)
node.Add ("f", System.Text.Json.Nodes.JsonValue.Create<float<measure>> input.F)
node.Add ("f32", System.Text.Json.Nodes.JsonValue.Create<float32<measure>> input.F32)
node.Add ("single", System.Text.Json.Nodes.JsonValue.Create<single<measure>> input.Single)
node :> _
namespace ConsumePlugin
@@ -221,7 +233,7 @@ module InnerTypeWithBothJsonParseExtension =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key) |> System.Uri
let value = (kvp.Value).AsValue().GetValue<bool> ()
let value = (kvp.Value).AsValue().GetValue<System.Boolean> ()
key, value
)
|> dict
@@ -295,7 +307,33 @@ module JsonRecordTypeWithBothJsonParseExtension =
/// Parse from a JSON node.
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordTypeWithBoth =
let arg_5 =
let arg_16 =
(match node.["single"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("single")
)
)
| v -> v)
.AsValue()
.GetValue<System.Single> ()
|> LanguagePrimitives.Float32WithMeasure
let arg_15 =
(match node.["f32"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("f32")
)
)
| v -> v)
.AsValue()
.GetValue<System.Single> ()
|> LanguagePrimitives.Float32WithMeasure
let arg_14 =
(match node.["f"] with
| null ->
raise (
@@ -303,9 +341,126 @@ module JsonRecordTypeWithBothJsonParseExtension =
sprintf "Required key '%s' not found on JSON object" ("f")
)
)
| v -> v)
.AsValue()
.GetValue<System.Double> ()
|> LanguagePrimitives.FloatWithMeasure
let arg_13 =
(match node.["u64"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("u64")
)
)
| v -> v)
.AsValue()
.GetValue<System.UInt64> ()
|> LanguagePrimitives.UInt64WithMeasure
let arg_12 =
(match node.["u32"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("u32")
)
)
| v -> v)
.AsValue()
.GetValue<System.UInt32> ()
|> LanguagePrimitives.UInt32WithMeasure
let arg_11 =
(match node.["u"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("u")
)
)
| v -> v)
.AsValue()
.GetValue<System.UInt32> ()
|> LanguagePrimitives.UInt32WithMeasure
let arg_10 =
(match node.["i64"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("i64")
)
)
| v -> v)
.AsValue()
.GetValue<System.Int64> ()
|> LanguagePrimitives.Int64WithMeasure
let arg_9 =
(match node.["i32"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("i32")
)
)
| v -> v)
.AsValue()
.GetValue<System.Int32> ()
|> LanguagePrimitives.Int32WithMeasure
let arg_8 =
(match node.["i"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("i")
)
)
| v -> v)
.AsValue()
.GetValue<System.Int32> ()
|> LanguagePrimitives.Int32WithMeasure
let arg_7 =
(match node.["sbyte"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("sbyte")
)
)
| v -> v)
.AsValue()
.GetValue<System.SByte> ()
|> LanguagePrimitives.SByteWithMeasure
let arg_6 =
(match node.["byte"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("byte")
)
)
| v -> v)
.AsValue()
.GetValue<System.Byte> ()
|> LanguagePrimitives.ByteWithMeasure
let arg_5 =
(match node.["arr"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("arr")
)
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|> Array.ofSeq
let arg_4 =
@@ -318,7 +473,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|> Array.ofSeq
let arg_3 =
@@ -343,7 +498,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<int> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.Int32> ())
|> List.ofSeq
let arg_1 =
@@ -356,7 +511,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["a"] with
@@ -368,7 +523,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
{
A = arg_0
@@ -376,7 +531,18 @@ module JsonRecordTypeWithBothJsonParseExtension =
C = arg_2
D = arg_3
E = arg_4
F = arg_5
Arr = arg_5
Byte = arg_6
Sbyte = arg_7
I = arg_8
I32 = arg_9
I64 = arg_10
U = arg_11
U32 = arg_12
U64 = arg_13
F = arg_14
F32 = arg_15
Single = arg_16
}
namespace ConsumePlugin
@@ -422,7 +588,7 @@ module FirstDuJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
)
| "case2" ->
let node =
@@ -455,6 +621,6 @@ module FirstDuJsonParseExtension =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
)
| v -> failwith ("Unrecognised 'type' field value: " + v)

View File

@@ -22,7 +22,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_9 =
(match node.["orphan"] with
@@ -34,7 +34,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_8 =
(match node.["entity_id"] with
@@ -46,7 +46,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_7 =
(match node.["token_type"] with
@@ -58,7 +58,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_6 =
(match node.["renewable"] with
@@ -70,7 +70,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_5 =
(match node.["lease_duration"] with
@@ -82,7 +82,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_4 =
(match node.["identity_policies"] with
@@ -94,7 +94,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|> List.ofSeq
let arg_3 =
@@ -107,7 +107,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|> List.ofSeq
let arg_2 =
@@ -120,7 +120,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsArray ()
|> Seq.map (fun elt -> elt.AsValue().GetValue<string> ())
|> Seq.map (fun elt -> elt.AsValue().GetValue<System.String> ())
|> List.ofSeq
let arg_1 =
@@ -133,7 +133,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["client_token"] with
@@ -145,7 +145,7 @@ module JwtVaultAuthResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
ClientToken = arg_0
@@ -189,7 +189,7 @@ module JwtVaultResponse =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_2 =
(match node.["renewable"] with
@@ -201,7 +201,7 @@ module JwtVaultResponse =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_1 =
(match node.["lease_id"] with
@@ -213,7 +213,7 @@ module JwtVaultResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["request_id"] with
@@ -225,7 +225,7 @@ module JwtVaultResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
RequestId = arg_0
@@ -271,7 +271,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key)
let value = (kvp.Value).AsValue().GetValue<int> ()
let value = (kvp.Value).AsValue().GetValue<System.Int32> ()
key, value
)
|> Map.ofSeq
@@ -288,7 +288,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key) |> System.Uri
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> dict
@@ -305,7 +305,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key) |> System.Uri
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> readOnlyDict
@@ -322,7 +322,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key)
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> Map.ofSeq
@@ -339,7 +339,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key)
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> Seq.map System.Collections.Generic.KeyValuePair
@@ -357,7 +357,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key)
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> dict
@@ -374,7 +374,7 @@ module JwtSecretResponse =
.AsObject ()
|> Seq.map (fun kvp ->
let key = (kvp.Key)
let value = (kvp.Value).AsValue().GetValue<string> ()
let value = (kvp.Value).AsValue().GetValue<System.String> ()
key, value
)
|> readOnlyDict
@@ -389,7 +389,7 @@ module JwtSecretResponse =
)
| v -> v)
.AsValue()
.GetValue<int> ()
.GetValue<System.Int32> ()
let arg_2 =
(match node.["renewable"] with
@@ -401,7 +401,7 @@ module JwtSecretResponse =
)
| v -> v)
.AsValue()
.GetValue<bool> ()
.GetValue<System.Boolean> ()
let arg_1 =
(match node.["lease_id"] with
@@ -413,7 +413,7 @@ module JwtSecretResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
let arg_0 =
(match node.["request_id"] with
@@ -425,7 +425,7 @@ module JwtSecretResponse =
)
| v -> v)
.AsValue()
.GetValue<string> ()
.GetValue<System.String> ()
{
RequestId = arg_0

View File

@@ -29,6 +29,28 @@ type JsonRecordType =
F : int[]
}
[<WoofWare.Myriad.Plugins.JsonParse>]
type internal InternalTypeNotExtension =
{
[<JsonPropertyName(Literals.something)>]
InternalThing : string
}
[<WoofWare.Myriad.Plugins.JsonSerialize>]
type internal InternalTypeNotExtensionSerial =
{
[<JsonPropertyName(Literals.something)>]
InternalThing2 : string
}
[<WoofWare.Myriad.Plugins.JsonParse true>]
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
type internal InternalTypeExtension =
{
[<JsonPropertyName(Literals.something)>]
ExternalThing : string
}
[<WoofWare.Myriad.Plugins.JsonParse true>]
type ToGetExtensionMethod =
{

View File

@@ -19,13 +19,16 @@ type GymAccessOptions =
QrCodeAccess : bool
}
[<Measure>]
type measure
[<WoofWare.Myriad.Plugins.JsonParse>]
type GymLocation =
{
[<JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)>]
Longitude : float
[<JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)>]
Latitude : float
Latitude : float<measure>
}
[<WoofWare.Myriad.Plugins.JsonParse>]

View File

@@ -16,6 +16,9 @@ type InnerTypeWithBoth =
ConcreteDict : Dictionary<string, InnerTypeWithBoth>
}
[<Measure>]
type measure
[<WoofWare.Myriad.Plugins.JsonParse true>]
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
type JsonRecordTypeWithBoth =
@@ -25,7 +28,18 @@ type JsonRecordTypeWithBoth =
C : int list
D : InnerTypeWithBoth
E : string array
F : int[]
Arr : int[]
Byte : byte<measure>
Sbyte : sbyte<measure>
I : int<measure>
I32 : int32<measure>
I64 : int64<measure>
U : uint<measure>
U32 : uint32<measure>
U64 : uint64<measure>
F : float<measure>
F32 : float32<measure>
Single : single<measure>
}
[<WoofWare.Myriad.Plugins.JsonSerialize true>]

View File

@@ -8,23 +8,20 @@
Some helpers in [Myriad](https://github.com/MoiraeSoftware/myriad/) which might be useful.
These are currently somewhat experimental, and I personally am their primary customer.
The `RemoveOptions` generator in particular is extremely half-baked.
Currently implemented:
* `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods).
* `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods).
* `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client).
* `GenerateMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)).
* `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union).
* `RemoveOptions` (to strip `option` modifiers from a type) - this one is particularly half-baked!
If you would like to ensure that your particular use-case remains unbroken, please do contribute tests to this repository.
The `ConsumePlugin` assembly contains a number of invocations of these source generators,
so you just need to add copies of your types to that assembly to ensure that I will at least notice if I break the build;
and if you add tests to `WoofWare.Myriad.Plugins.Test` then I will also notice if I break the runtime semantics of the generated code.
Currently implemented:
* `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods);
* `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods);
* `RemoveOptions` (to strip `option` modifiers from a type).
* `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client).
* `GenerateMock` (to stamp out a record type corresponding to an interface).
* `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union).
## `JsonParse`
Takes records like this:

View File

@@ -58,7 +58,7 @@ module PureGymDtos =
[
"""{"latitude": 1.0, "longitude": 3.0}""",
{
GymLocation.Latitude = 1.0
GymLocation.Latitude = 1.0<measure>
Longitude = 3.0
}
]
@@ -96,7 +96,7 @@ module PureGymDtos =
Location =
{
Longitude = -0.110252
Latitude = 51.480401
Latitude = 51.480401<measure>
}
TimeZone = "Europe/London"
ReopenDate = "2021-04-12T00:00:00+01 Europe/London"

View File

@@ -77,7 +77,18 @@ module TestJsonSerde =
let! depth = Gen.choose (0, 2)
let! d = innerGen depth
let! e = Gen.arrayOf Arb.generate<NonNull<string>>
let! f = Gen.arrayOf Arb.generate<int>
let! arr = Gen.arrayOf Arb.generate<int>
let! byte = Arb.generate
let! sbyte = Arb.generate
let! i = Arb.generate
let! i32 = Arb.generate
let! i64 = Arb.generate
let! u = Arb.generate
let! u32 = Arb.generate
let! u64 = Arb.generate
let! f = Arb.generate |> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>))
let! f32 = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
let! single = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
return
{
@@ -86,7 +97,18 @@ module TestJsonSerde =
C = c
D = d
E = e |> Array.map _.Get
Arr = arr
Byte = byte
Sbyte = sbyte
I = i
I32 = i32
I64 = i64
U = u
U32 = u32
U64 = u64
F = f
F32 = f32
Single = single
}
}
@@ -140,8 +162,7 @@ module TestJsonSerde =
}
let sanitiseRec (r : JsonRecordTypeWithBoth) : JsonRecordTypeWithBoth =
{
A = r.A
{ r with
B = if isNull r.B then "<null>" else r.B
C =
if Object.ReferenceEquals (r.C, (null : obj)) then
@@ -150,11 +171,11 @@ module TestJsonSerde =
r.C
D = sanitiseInner r.D
E = if isNull r.E then [||] else r.E
F =
if Object.ReferenceEquals (r.F, (null : obj)) then
Arr =
if Object.ReferenceEquals (r.Arr, (null : obj)) then
[||]
else
r.F
r.Arr
}
let duGen =

View File

@@ -106,14 +106,8 @@ module internal JsonParseGenerator =
]
|> SynExpr.createMatch node
/// Given e.g. "float", returns "System.Double.Parse"
let parseFunction (typeName : string) : LongIdent =
let qualified =
match Primitives.qualifyType typeName with
| Some x -> x
| None -> failwith $"Could not recognise type %s{typeName} as a primitive."
List.append qualified [ Ident.create "Parse" ]
let dotParse (typeName : LongIdent) : LongIdent =
List.append typeName [ Ident.create "Parse" ]
/// fun kvp -> let key = {key(kvp)} in let value = {value(kvp)} in (key, value))
/// The inputs will be fed with appropriate SynExprs to apply them to the `kvp.Key` and `kvp.Value` args.
@@ -140,6 +134,47 @@ module internal JsonParseGenerator =
failwithf
$"Unable to parse the key type %+A{desiredType} of a JSON object. Keys are strings, and this plugin does not know how to convert to that from a string."
let private parseNumberType
(options : JsonParseOption)
(propertyName : SynExpr option)
(node : SynExpr)
(typeName : LongIdent)
=
let basic = asValueGetValueIdent propertyName typeName node
match options.JsonNumberHandlingArg with
| None -> basic
| Some option ->
let cond =
SynExpr.DotGet (SynExpr.createIdent "exc", range0, SynLongIdent.createS "Message", range0)
|> SynExpr.callMethodArg "Contains" (SynExpr.CreateConst "cannot be converted to")
let handler =
asValueGetValue propertyName "string" node
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent' (typeName |> dotParse))
|> SynExpr.ifThenElse
(SynExpr.equals
option
(SynExpr.createLongIdent
[
"System"
"Text"
"Json"
"Serialization"
"JsonNumberHandling"
"AllowReadingFromString"
]))
SynExpr.reraise
|> SynExpr.ifThenElse cond SynExpr.reraise
basic
|> SynExpr.pipeThroughTryWith
(SynPat.IsInst (
SynType.LongIdent (SynLongIdent.createS' [ "System" ; "InvalidOperationException" ]),
range0
))
handler
/// Given `node.["town"]`, for example, choose how to obtain a JSON value from it.
/// The property name is used in error messages at runtime to show where a JSON
/// parse error occurred; supply `None` to indicate "don't validate".
@@ -168,41 +203,7 @@ module internal JsonParseGenerator =
node
|> asValueGetValue propertyName "string"
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ])
| NumberType typeName ->
let basic = asValueGetValue propertyName typeName node
match options.JsonNumberHandlingArg with
| None -> basic
| Some option ->
let cond =
SynExpr.DotGet (SynExpr.createIdent "exc", range0, SynLongIdent.createS "Message", range0)
|> SynExpr.callMethodArg "Contains" (SynExpr.CreateConst "cannot be converted to")
let handler =
asValueGetValue propertyName "string" node
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent' (parseFunction typeName))
|> SynExpr.ifThenElse
(SynExpr.equals
option
(SynExpr.createLongIdent
[
"System"
"Text"
"Json"
"Serialization"
"JsonNumberHandling"
"AllowReadingFromString"
]))
SynExpr.reraise
|> SynExpr.ifThenElse cond SynExpr.reraise
basic
|> SynExpr.pipeThroughTryWith
(SynPat.IsInst (
SynType.LongIdent (SynLongIdent.createS' [ "System" ; "InvalidOperationException" ]),
range0
))
handler
| NumberType typeName -> parseNumberType options propertyName node typeName
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
| OptionType ty ->
parseNode None options ty (SynExpr.createIdent "v")
@@ -261,6 +262,9 @@ module internal JsonParseGenerator =
|> SynExpr.callMethod "ToJsonString"
|> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Numerics" ; "BigInteger" ; "Parse" ])
| Measure (_measure, primType) ->
parseNumberType options propertyName node primType
|> SynExpr.pipeThroughFunction (Measure.getLanguagePrimitivesMeasure primType)
| _ ->
// Let's just hope that we've also got our own type annotation!
let typeName =
@@ -478,7 +482,7 @@ module internal JsonParseGenerator =
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
typeDefn
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, _access, _)) =
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, access, _)) =
synComponentInfo
let attributes =
@@ -517,6 +521,7 @@ module internal JsonParseGenerator =
let info =
SynComponentInfo.createLong moduleName
|> SynComponentInfo.withDocString xmlDoc
|> SynComponentInfo.setAccessibility access
|> SynComponentInfo.addAttributes attributes
let decl =

View File

@@ -21,6 +21,7 @@ module internal JsonSerializeGenerator =
| DateOnly
| DateTime
| NumberType _
| Measure _
| PrimitiveType _
| Guid
| Uri ->
@@ -323,7 +324,7 @@ module internal JsonSerializeGenerator =
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
typeDefn
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, _access, _)) =
let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, access, _)) =
synComponentInfo
let attributes =
@@ -362,6 +363,7 @@ module internal JsonSerializeGenerator =
let info =
SynComponentInfo.createLong moduleName
|> SynComponentInfo.addAttributes attributes
|> SynComponentInfo.setAccessibility access
|> SynComponentInfo.withDocString xmlDoc
let decls =

View File

@@ -0,0 +1,24 @@
namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax
[<RequireQualifiedAccess>]
module internal Measure =
let getLanguagePrimitivesMeasure (typeName : LongIdent) : SynExpr =
match typeName |> List.map _.idText with
| [ "System" ; "Single" ] -> [ "LanguagePrimitives" ; "Float32WithMeasure" ]
| [ "System" ; "Double" ] -> [ "LanguagePrimitives" ; "FloatWithMeasure" ]
| [ "System" ; "Byte" ] -> [ "LanguagePrimitives" ; "ByteWithMeasure" ]
| [ "System" ; "SByte" ] -> [ "LanguagePrimitives" ; "SByteWithMeasure" ]
| [ "System" ; "Int16" ] -> [ "LanguagePrimitives" ; "Int16WithMeasure" ]
| [ "System" ; "Int32" ] -> [ "LanguagePrimitives" ; "Int32WithMeasure" ]
| [ "System" ; "Int64" ] -> [ "LanguagePrimitives" ; "Int64WithMeasure" ]
| [ "System" ; "UInt16" ] -> [ "LanguagePrimitives" ; "UInt16WithMeasure" ]
| [ "System" ; "UInt32" ] -> [ "LanguagePrimitives" ; "UInt32WithMeasure" ]
| [ "System" ; "UInt64" ] -> [ "LanguagePrimitives" ; "UInt64WithMeasure" ]
| l ->
let l = String.concat "." l
failwith $"unrecognised type for measure: %s{l}"
|> SynExpr.createLongIdent

View File

@@ -26,5 +26,7 @@ module internal Primitives =
| "uint64" -> [ "System" ; "UInt64" ] |> Some
| "char" -> [ "System" ; "Char" ] |> Some
| "decimal" -> [ "System" ; "Decimal" ] |> Some
| "string" -> [ "System" ; "String" ] |> Some
| "bool" -> [ "System" ; "Boolean" ] |> Some
| _ -> None
|> Option.map (List.map (fun i -> (Ident (i, range0))))

View File

@@ -87,6 +87,20 @@ module internal SynExpr =
)
|> applyTo b
/// {a} * {b}
let times (a : SynExpr) (b : SynExpr) =
SynExpr.CreateAppInfix (
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
Ident.CreateLong "op_Multiply",
[],
[ Some (IdentTrivia.OriginalNotation "*") ]
)
),
a
)
|> applyTo b
let rec stripOptionalParen (expr : SynExpr) : SynExpr =
match expr with
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr

View File

@@ -193,10 +193,30 @@ module internal SynTypePatterns =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent with
| [ i ] -> [ "string" ; "float" ; "int" ; "bool" ] |> List.tryFind (fun s -> s = i.idText)
| [ i ] ->
// We won't bother with the case that the user has done e.g. `Single` (relying on `System` being open).
match Primitives.qualifyType i.idText with
| Some qualified ->
match i.idText with
| "char"
| "string" -> None
| _ -> Some qualified
| None -> None
| _ -> None
| _ -> None
/// Returns the name of the measure, and the outer type.
let (|Measure|_|) (fieldType : SynType) : (Ident * LongIdent) option =
match fieldType with
| SynType.App (NumberType outer,
_,
[ SynType.LongIdent (SynLongIdent.SynLongIdent ([ ident ], _, _)) ],
_,
_,
_,
_) -> Some (ident, outer)
| _ -> None
let (|DateOnly|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->

View File

@@ -46,6 +46,7 @@
<Compile Include="SynExpr\SynAttribute.fs" />
<Compile Include="SynExpr\SynModuleDecl.fs" />
<Compile Include="SynExpr\SynModuleOrNamespace.fs" />
<Compile Include="Measure.fs" />
<Compile Include="AstHelper.fs" />
<Compile Include="RemoveOptionsGenerator.fs"/>
<Compile Include="InterfaceMockGenerator.fs"/>

View File

@@ -4,10 +4,11 @@
"^refs/heads/main$"
],
"pathFilters": [
":/",
":^WoofWare.Myriad.Plugins.Test/",
":^WoofWare.Myriad.Plugins.Attributes/Test/",
":^/.github/",
":^/CHANGELOG.md"
"./",
":/WoofWare.Myriad.Plugins.Attributes",
"^:/WoofWare.Myriad.Plugins.Attributes/WoofWare.Myriad.Plugins.Attributes.Test",
":/global.json",
":/README.md",
":/Directory.Build.props"
]
}