mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-06 20:48:40 +00:00
Compare commits
55 Commits
WoofWare.M
...
WoofWare.M
Author | SHA1 | Date | |
---|---|---|---|
|
86b938c81e | ||
|
1832a57bdf | ||
|
38f4821fa4 | ||
|
70aaf8c408 | ||
|
417ca45c37 | ||
|
569b3cc553 | ||
|
20226b9da9 | ||
|
f800e53bff | ||
|
5358f5da0e | ||
|
a868b8c08e | ||
|
a4f945a3ee | ||
|
8434730ba7 | ||
|
811026996c | ||
|
25b2b160bb | ||
|
4679474604 | ||
|
e16e241785 | ||
|
a52e4a46b0 | ||
|
f40a368948 | ||
|
adaee61fbf | ||
|
d388660bfe | ||
|
d0e9ba0efd | ||
|
d7d6c57910 | ||
|
98e52743f5 | ||
|
896696e002 | ||
|
654f760f3a | ||
|
31bd9e22f2 | ||
|
b7a240bbb9 | ||
|
ebbe10ad81 | ||
|
8f9af9af67 | ||
|
2c7cd91cbc | ||
|
ffaa373da9 | ||
|
9f8459a7d3 | ||
|
362542d5ee | ||
|
18309becbd | ||
|
e96803e303 | ||
|
b53b410feb | ||
|
398cd04a2a | ||
|
434c042510 | ||
|
c590db2a65 | ||
|
6a81513a93 | ||
|
ba31689145 | ||
|
85929d49d5 | ||
|
db4694f6e7 | ||
|
669eccbdef | ||
|
1bb87e55da | ||
|
4901e7cdf4 | ||
|
68bd4bc1fd | ||
|
8da0fd01fe | ||
|
18c7a2e920 | ||
|
f371ee59fe | ||
|
f8296e54bc | ||
|
adf497c5db | ||
|
04ecbe6002 | ||
|
7b14e52e9d | ||
|
8e47f39efc |
@@ -3,13 +3,13 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fantomas": {
|
||||
"version": "6.3.4",
|
||||
"version": "6.3.11",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
},
|
||||
"fsharp-analyzers": {
|
||||
"version": "0.26.0",
|
||||
"version": "0.27.0",
|
||||
"commands": [
|
||||
"fsharp-analyzers"
|
||||
]
|
||||
|
108
.github/workflows/dotnet.yaml
vendored
108
.github/workflows/dotnet.yaml
vendored
@@ -73,6 +73,8 @@ jobs:
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build
|
||||
- name: Reproducibility check
|
||||
run: nix build --rebuild
|
||||
|
||||
check-dotnet-format:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -217,15 +219,60 @@ jobs:
|
||||
|
||||
all-required-checks-complete:
|
||||
needs: [check-dotnet-format, check-nix-format, check-accurate-generations, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack, github-release-plugin-dry-run]
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "All required checks complete."
|
||||
- uses: G-Research/common-actions/check-required-lite@2b7dc49cb14f3344fbe6019c14a31165e258c059
|
||||
with:
|
||||
needs-context: ${{ toJSON(needs) }}
|
||||
|
||||
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@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.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@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.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 +280,55 @@ 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: Identify `dotnet`
|
||||
id: dotnet-identify
|
||||
run: nix develop --command bash -c 'echo "dotnet=$(which dotnet)" >> $GITHUB_OUTPUT'
|
||||
- name: Publish to NuGet
|
||||
id: publish-success
|
||||
uses: G-Research/common-actions/publish-nuget@2b7dc49cb14f3344fbe6019c14a31165e258c059
|
||||
with:
|
||||
package-name: WoofWare.Myriad.Plugins.Attributes
|
||||
nuget-key: ${{ secrets.NUGET_API_KEY }}
|
||||
nupkg-dir: packed/
|
||||
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
|
||||
|
||||
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: Identify `dotnet`
|
||||
id: dotnet-identify
|
||||
run: nix develop --command bash -c 'echo "dotnet=$(which dotnet)" >> $GITHUB_OUTPUT'
|
||||
- name: Publish to NuGet
|
||||
id: publish-success
|
||||
uses: G-Research/common-actions/publish-nuget@2b7dc49cb14f3344fbe6019c14a31165e258c059
|
||||
with:
|
||||
package-name: WoofWare.Myriad.Plugins
|
||||
nuget-key: ${{ secrets.NUGET_API_KEY }}
|
||||
nupkg-dir: packed/
|
||||
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
|
||||
|
||||
github-release-plugin:
|
||||
runs-on: ubuntu-latest
|
||||
|
57
.github/workflows/flake_update.yaml
vendored
Normal file
57
.github/workflows/flake_update.yaml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json
|
||||
name: Weekly Nix Flake Update
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # Runs at 00:00 every Sunday
|
||||
workflow_dispatch: # Allows manual triggering
|
||||
|
||||
jobs:
|
||||
update-nix-flake:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update Nix flake
|
||||
run: 'nix flake update'
|
||||
|
||||
- name: Build passthru
|
||||
run: 'nix build ".#default.passthru.fetch-deps"'
|
||||
|
||||
- name: Run passthru
|
||||
run: |
|
||||
set -o pipefail
|
||||
./result | tee /tmp/passthru.txt
|
||||
cp /"$(cat /tmp/passthru.txt | grep " wrote lockfile to " | cut -d / -f 2-)" nix/deps.nix
|
||||
|
||||
- name: Format
|
||||
run: 'nix develop --command alejandra .'
|
||||
|
||||
- name: Create token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
# https://github.com/actions/create-github-app-token/issues/136
|
||||
app-id: ${{ secrets.APP_ID }}
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Raise pull request
|
||||
uses: Smaug123/commit-action@cc25e6d80a796c49669dda4a0aa36c54c573983d
|
||||
id: cpr
|
||||
with:
|
||||
bearer-token: ${{ steps.generate-token.outputs.token }}
|
||||
pr-title: "Upgrade Nix flake and deps"
|
||||
|
||||
- name: Enable Pull Request Automerge
|
||||
if: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
uses: peter-evans/enable-pull-request-automerge@v3
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
merge-method: squash
|
25
.gitignore
vendored
25
.gitignore
vendored
@@ -1,12 +1,13 @@
|
||||
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/
|
||||
.venv/
|
||||
|
@@ -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.
|
||||
|
95
ConsumePlugin/Args.fs
Normal file
95
ConsumePlugin/Args.fs
Normal file
@@ -0,0 +1,95 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<ArgParser>]
|
||||
type BasicNoPositionals =
|
||||
{
|
||||
Foo : int
|
||||
Bar : string
|
||||
Baz : bool
|
||||
Rest : int list
|
||||
}
|
||||
|
||||
[<ArgParser>]
|
||||
type Basic =
|
||||
{
|
||||
[<ArgumentHelpText "This is a foo!">]
|
||||
Foo : int
|
||||
Bar : string
|
||||
Baz : bool
|
||||
[<ArgumentHelpText "Here's where the rest of the args go">]
|
||||
[<PositionalArgs>]
|
||||
Rest : string list
|
||||
}
|
||||
|
||||
[<ArgParser>]
|
||||
type BasicWithIntPositionals =
|
||||
{
|
||||
Foo : int
|
||||
Bar : string
|
||||
Baz : bool
|
||||
[<PositionalArgs>]
|
||||
Rest : int list
|
||||
}
|
||||
|
||||
[<ArgParser>]
|
||||
type LoadsOfTypes =
|
||||
{
|
||||
Foo : int
|
||||
Bar : string
|
||||
Baz : bool
|
||||
SomeFile : FileInfo
|
||||
SomeDirectory : DirectoryInfo
|
||||
SomeList : DirectoryInfo list
|
||||
OptionalThingWithNoDefault : int option
|
||||
[<PositionalArgs>]
|
||||
Positionals : int list
|
||||
[<ArgumentDefaultFunction>]
|
||||
OptionalThing : Choice<bool, bool>
|
||||
[<ArgumentDefaultFunction>]
|
||||
AnotherOptionalThing : Choice<int, int>
|
||||
[<ArgumentDefaultEnvironmentVariable "CONSUMEPLUGIN_THINGS">]
|
||||
YetAnotherOptionalThing : Choice<string, string>
|
||||
}
|
||||
|
||||
static member DefaultOptionalThing () = true
|
||||
|
||||
static member DefaultAnotherOptionalThing () = 3
|
||||
|
||||
[<ArgParser>]
|
||||
type LoadsOfTypesNoPositionals =
|
||||
{
|
||||
Foo : int
|
||||
Bar : string
|
||||
Baz : bool
|
||||
SomeFile : FileInfo
|
||||
SomeDirectory : DirectoryInfo
|
||||
SomeList : DirectoryInfo list
|
||||
OptionalThingWithNoDefault : int option
|
||||
[<ArgumentDefaultFunction>]
|
||||
OptionalThing : Choice<bool, bool>
|
||||
[<ArgumentDefaultFunction>]
|
||||
AnotherOptionalThing : Choice<int, int>
|
||||
[<ArgumentDefaultEnvironmentVariable "CONSUMEPLUGIN_THINGS">]
|
||||
YetAnotherOptionalThing : Choice<string, string>
|
||||
}
|
||||
|
||||
static member DefaultOptionalThing () = false
|
||||
|
||||
static member DefaultAnotherOptionalThing () = 3
|
||||
|
||||
[<ArgParser true>]
|
||||
type DatesAndTimes =
|
||||
{
|
||||
Plain : TimeSpan
|
||||
[<InvariantCulture>]
|
||||
Invariant : TimeSpan
|
||||
[<ParseExact @"hh\:mm\:ss">]
|
||||
[<ArgumentHelpText "An exact time please">]
|
||||
Exact : TimeSpan
|
||||
[<InvariantCulture ; ParseExact @"hh\:mm\:ss">]
|
||||
InvariantExact : TimeSpan
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<MyriadSdkGenerator Include="$(MSBuildThisFileDirectory)..\WoofWare.Myriad.Plugins\bin\$(Configuration)\net6.0\WoofWare.Myriad.Plugins.dll"/>
|
||||
@@ -51,14 +52,17 @@
|
||||
<Compile Include="ListCata.fs">
|
||||
<MyriadFile>List.fs</MyriadFile>
|
||||
</Compile>
|
||||
<Compile Include="Args.fs" />
|
||||
<Compile Include="GeneratedArgs.fs">
|
||||
<MyriadFile>Args.fs</MyriadFile>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RestEase" Version="1.6.4"/>
|
||||
<ProjectReference Include="..\WoofWare.Myriad.Plugins.Attributes\WoofWare.Myriad.Plugins.Attributes.fsproj" />
|
||||
<ProjectReference Include="..\WoofWare.Myriad.Plugins\WoofWare.Myriad.Plugins.fsproj"/>
|
||||
<PackageReference Include="Myriad.Sdk" Version="0.8.3"/>
|
||||
<PackageReference Include="Myriad.Core" Version="0.8.3"/>
|
||||
<ProjectReference Include="..\WoofWare.Myriad.Plugins\WoofWare.Myriad.Plugins.fsproj" PrivateAssets="all" />
|
||||
<PackageReference Include="Myriad.Sdk" Version="0.8.3" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -30,6 +30,12 @@ type ChocolateType =
|
||||
| Milk
|
||||
| SeventyPercent
|
||||
|
||||
override this.ToString () =
|
||||
match this with
|
||||
| ChocolateType.Dark -> "Dark"
|
||||
| ChocolateType.Milk -> "Milk"
|
||||
| ChocolateType.SeventyPercent -> "SeventyPercent"
|
||||
|
||||
type Chocolate =
|
||||
{
|
||||
chocType : ChocolateType
|
||||
@@ -43,6 +49,12 @@ type WrappingPaperStyle =
|
||||
| HappyHolidays
|
||||
| SolidColor
|
||||
|
||||
override this.ToString () =
|
||||
match this with
|
||||
| WrappingPaperStyle.HappyBirthday -> "HappyBirthday"
|
||||
| WrappingPaperStyle.HappyHolidays -> "HappyHolidays"
|
||||
| WrappingPaperStyle.SolidColor -> "SolidColor"
|
||||
|
||||
[<CreateCatamorphism "GiftCata">]
|
||||
type Gift =
|
||||
| Book of Book
|
||||
|
1579
ConsumePlugin/GeneratedArgs.fs
Normal file
1579
ConsumePlugin/GeneratedArgs.fs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -60,7 +60,7 @@ module TreeCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__TreeBuilder (x) ->
|
||||
| Instruction.Process__TreeBuilder x ->
|
||||
match x with
|
||||
| TreeBuilder.Child (arg0_0) ->
|
||||
instructions.Add Instruction.TreeBuilder_Child
|
||||
@@ -68,7 +68,7 @@ module TreeCata =
|
||||
| TreeBuilder.Parent (arg0_0) ->
|
||||
instructions.Add Instruction.TreeBuilder_Parent
|
||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||
| Instruction.Process__Tree (x) ->
|
||||
| Instruction.Process__Tree x ->
|
||||
match x with
|
||||
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
||||
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||
@@ -92,13 +92,13 @@ module TreeCata =
|
||||
let arg0_0 = treeStack.[treeStack.Count - 1]
|
||||
treeStack.RemoveAt (treeStack.Count - 1)
|
||||
cata.TreeBuilder.Parent arg0_0 |> treeBuilderStack.Add
|
||||
| Instruction.Tree_Pair (arg2_0) ->
|
||||
| Instruction.Tree_Pair arg2_0 ->
|
||||
let arg0_0 = treeStack.[treeStack.Count - 1]
|
||||
treeStack.RemoveAt (treeStack.Count - 1)
|
||||
let arg1_0 = treeStack.[treeStack.Count - 1]
|
||||
treeStack.RemoveAt (treeStack.Count - 1)
|
||||
cata.Tree.Pair arg0_0 arg1_0 arg2_0 |> treeStack.Add
|
||||
| Instruction.Tree_Sequential (arg0_0) ->
|
||||
| Instruction.Tree_Sequential arg0_0 ->
|
||||
let arg0_0_len = arg0_0
|
||||
|
||||
let arg0_0 =
|
||||
|
@@ -41,7 +41,7 @@ module FileSystemItemCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__FileSystemItem (x) ->
|
||||
| Instruction.Process__FileSystemItem x ->
|
||||
match x with
|
||||
| FileSystemItem.Directory ({
|
||||
Name = name
|
||||
@@ -116,7 +116,7 @@ module GiftCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__Gift (x) ->
|
||||
| Instruction.Process__Gift x ->
|
||||
match x with
|
||||
| Gift.Book (arg0_0) -> cata.Gift.Book arg0_0 |> giftStack.Add
|
||||
| Gift.Chocolate (arg0_0) -> cata.Gift.Chocolate arg0_0 |> giftStack.Add
|
||||
@@ -129,7 +129,7 @@ module GiftCata =
|
||||
| Gift.WithACard (arg0_0, message) ->
|
||||
instructions.Add (Instruction.Gift_WithACard (message))
|
||||
instructions.Add (Instruction.Process__Gift arg0_0)
|
||||
| Instruction.Gift_Wrapped (arg1_0) ->
|
||||
| Instruction.Gift_Wrapped arg1_0 ->
|
||||
let arg0_0 = giftStack.[giftStack.Count - 1]
|
||||
giftStack.RemoveAt (giftStack.Count - 1)
|
||||
cata.Gift.Wrapped arg0_0 arg1_0 |> giftStack.Add
|
||||
@@ -137,7 +137,7 @@ module GiftCata =
|
||||
let arg0_0 = giftStack.[giftStack.Count - 1]
|
||||
giftStack.RemoveAt (giftStack.Count - 1)
|
||||
cata.Gift.Boxed arg0_0 |> giftStack.Add
|
||||
| Instruction.Gift_WithACard (message) ->
|
||||
| Instruction.Gift_WithACard message ->
|
||||
let arg0_0 = giftStack.[giftStack.Count - 1]
|
||||
giftStack.RemoveAt (giftStack.Count - 1)
|
||||
cata.Gift.WithACard arg0_0 message |> giftStack.Add
|
||||
|
@@ -4,12 +4,38 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
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), (input.InternalThing2 |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
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), (input.ExternalThing |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node :> _
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the InnerType type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module InnerType =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerType =
|
||||
@@ -23,7 +49,7 @@ module InnerType =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Thing = arg_0
|
||||
@@ -31,8 +57,7 @@ module InnerType =
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JsonRecordType type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JsonRecordType =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordType =
|
||||
@@ -46,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 =
|
||||
@@ -59,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 =
|
||||
@@ -84,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 =
|
||||
@@ -97,7 +122,7 @@ module JsonRecordType =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["a"] with
|
||||
@@ -109,7 +134,7 @@ module JsonRecordType =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
{
|
||||
A = arg_0
|
||||
@@ -121,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 =
|
||||
@@ -273,7 +345,7 @@ module ToGetExtensionMethodJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_7 =
|
||||
(match node.["hotel"] with
|
||||
@@ -345,7 +417,7 @@ module ToGetExtensionMethodJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<float> ()
|
||||
.GetValue<System.Double> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["bravo"] with
|
||||
@@ -370,7 +442,7 @@ module ToGetExtensionMethodJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Alpha = arg_0
|
||||
|
@@ -19,9 +19,9 @@ type internal PublicTypeMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
}
|
||||
|
||||
interface IPublicType with
|
||||
@@ -44,9 +44,9 @@ type public PublicTypeInternalFalseMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
}
|
||||
|
||||
interface IPublicTypeInternalFalse with
|
||||
@@ -68,8 +68,8 @@ type internal InternalTypeMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : InternalTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface InternalType with
|
||||
@@ -90,8 +90,8 @@ type private PrivateTypeMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateType with
|
||||
@@ -112,8 +112,8 @@ type private PrivateTypeInternalFalseMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateTypeInternalFalse with
|
||||
@@ -133,7 +133,7 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
}
|
||||
|
||||
interface VeryPublicType<'a, 'b> with
|
||||
@@ -157,12 +157,12 @@ type internal CurriedMock<'a> =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : CurriedMock<'a> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
|
||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
|
||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
|
||||
}
|
||||
|
||||
interface Curried<'a> with
|
||||
@@ -195,9 +195,9 @@ type internal TypeWithInterfaceMock =
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : TypeWithInterfaceMock =
|
||||
{
|
||||
Dispose = (fun _ -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface TypeWithInterface with
|
||||
|
@@ -20,29 +20,33 @@ module MemberJsonSerializeExtension =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add ("id", System.Text.Json.Nodes.JsonValue.Create<int> input.Id)
|
||||
node.Add ("compoundMemberId", System.Text.Json.Nodes.JsonValue.Create<string> input.CompoundMemberId)
|
||||
node.Add ("firstName", System.Text.Json.Nodes.JsonValue.Create<string> input.FirstName)
|
||||
node.Add ("lastName", System.Text.Json.Nodes.JsonValue.Create<string> input.LastName)
|
||||
node.Add ("homeGymId", System.Text.Json.Nodes.JsonValue.Create<int> input.HomeGymId)
|
||||
node.Add ("homeGymName", System.Text.Json.Nodes.JsonValue.Create<string> input.HomeGymName)
|
||||
node.Add ("emailAddress", System.Text.Json.Nodes.JsonValue.Create<string> input.EmailAddress)
|
||||
node.Add ("gymAccessPin", System.Text.Json.Nodes.JsonValue.Create<string> input.GymAccessPin)
|
||||
node.Add ("dateofBirth", System.Text.Json.Nodes.JsonValue.Create<DateOnly> input.DateOfBirth)
|
||||
node.Add ("mobileNumber", System.Text.Json.Nodes.JsonValue.Create<string> input.MobileNumber)
|
||||
node.Add ("postCode", System.Text.Json.Nodes.JsonValue.Create<string> input.Postcode)
|
||||
node.Add ("membershipName", System.Text.Json.Nodes.JsonValue.Create<string> input.MembershipName)
|
||||
node.Add ("membershipLevel", System.Text.Json.Nodes.JsonValue.Create<int> input.MembershipLevel)
|
||||
node.Add ("suspendedReason", System.Text.Json.Nodes.JsonValue.Create<int> input.SuspendedReason)
|
||||
node.Add ("memberStatus", System.Text.Json.Nodes.JsonValue.Create<int> input.MemberStatus)
|
||||
node.Add ("id", (input.Id |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
|
||||
node.Add (
|
||||
"compoundMemberId",
|
||||
(input.CompoundMemberId |> System.Text.Json.Nodes.JsonValue.Create<string>)
|
||||
)
|
||||
|
||||
node.Add ("firstName", (input.FirstName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("lastName", (input.LastName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("homeGymId", (input.HomeGymId |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("homeGymName", (input.HomeGymName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("emailAddress", (input.EmailAddress |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("gymAccessPin", (input.GymAccessPin |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("dateofBirth", (input.DateOfBirth |> System.Text.Json.Nodes.JsonValue.Create<DateOnly>))
|
||||
node.Add ("mobileNumber", (input.MobileNumber |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("postCode", (input.Postcode |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("membershipName", (input.MembershipName |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("membershipLevel", (input.MembershipLevel |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("suspendedReason", (input.SuspendedReason |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("memberStatus", (input.MemberStatus |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
|
||||
node :> _
|
||||
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymOpeningHours type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymOpeningHours =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymOpeningHours =
|
||||
@@ -56,7 +60,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 =
|
||||
@@ -69,7 +73,7 @@ module GymOpeningHours =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
{
|
||||
IsAlwaysOpen = arg_0
|
||||
@@ -78,8 +82,7 @@ module GymOpeningHours =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymAccessOptions type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymAccessOptions =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAccessOptions =
|
||||
@@ -93,7 +96,7 @@ module GymAccessOptions =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["pinAccess"] with
|
||||
@@ -105,7 +108,7 @@ module GymAccessOptions =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
{
|
||||
PinAccess = arg_0
|
||||
@@ -114,8 +117,7 @@ module GymAccessOptions =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymLocation type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymLocation =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymLocation =
|
||||
@@ -130,7 +132,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
|
||||
@@ -151,6 +153,7 @@ module GymLocation =
|
||||
reraise ()
|
||||
else
|
||||
reraise ()
|
||||
|> LanguagePrimitives.FloatWithMeasure
|
||||
|
||||
let arg_0 =
|
||||
try
|
||||
@@ -163,7 +166,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
|
||||
@@ -192,8 +195,7 @@ module GymLocation =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymAddress type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymAddress =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAddress =
|
||||
@@ -207,12 +209,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
|
||||
@@ -224,17 +226,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
|
||||
@@ -246,7 +248,7 @@ module GymAddress =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
AddressLine1 = arg_0
|
||||
@@ -259,8 +261,7 @@ module GymAddress =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the Gym type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module Gym =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Gym =
|
||||
@@ -274,7 +275,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_9 =
|
||||
(match node.["timeZone"] with
|
||||
@@ -286,7 +287,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_8 =
|
||||
GymLocation.jsonParse (
|
||||
@@ -334,7 +335,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_4 =
|
||||
(match node.["phoneNumber"] with
|
||||
@@ -346,7 +347,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_3 =
|
||||
GymAddress.jsonParse (
|
||||
@@ -370,7 +371,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["id"] with
|
||||
@@ -382,7 +383,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["name"] with
|
||||
@@ -394,7 +395,7 @@ module Gym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Name = arg_0
|
||||
@@ -429,7 +430,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_13 =
|
||||
(match node.["suspendedReason"] with
|
||||
@@ -441,7 +442,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_12 =
|
||||
(match node.["membershipLevel"] with
|
||||
@@ -453,7 +454,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_11 =
|
||||
(match node.["membershipName"] with
|
||||
@@ -465,7 +466,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_10 =
|
||||
(match node.["postCode"] with
|
||||
@@ -477,7 +478,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_9 =
|
||||
(match node.["mobileNumber"] with
|
||||
@@ -489,7 +490,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_8 =
|
||||
(match node.["dateofBirth"] with
|
||||
@@ -514,7 +515,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_6 =
|
||||
(match node.["emailAddress"] with
|
||||
@@ -526,7 +527,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_5 =
|
||||
(match node.["homeGymName"] with
|
||||
@@ -538,7 +539,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_4 =
|
||||
(match node.["homeGymId"] with
|
||||
@@ -550,7 +551,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_3 =
|
||||
(match node.["lastName"] with
|
||||
@@ -562,7 +563,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_2 =
|
||||
(match node.["firstName"] with
|
||||
@@ -574,7 +575,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["compoundMemberId"] with
|
||||
@@ -586,7 +587,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["id"] with
|
||||
@@ -598,7 +599,7 @@ module MemberJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
{
|
||||
Id = arg_0
|
||||
@@ -620,8 +621,7 @@ module MemberJsonParseExtension =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the GymAttendance type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module GymAttendance =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : GymAttendance =
|
||||
@@ -635,7 +635,7 @@ module GymAttendance =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_7 =
|
||||
(match node.["lastRefreshedPeopleInClasses"] with
|
||||
@@ -686,12 +686,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
|
||||
@@ -703,7 +703,7 @@ module GymAttendance =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["totalPeopleInGym"] with
|
||||
@@ -715,7 +715,7 @@ module GymAttendance =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["description"] with
|
||||
@@ -727,7 +727,7 @@ module GymAttendance =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Description = arg_0
|
||||
@@ -743,8 +743,7 @@ module GymAttendance =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the MemberActivityDto type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module MemberActivityDto =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : MemberActivityDto =
|
||||
@@ -771,7 +770,7 @@ module MemberActivityDto =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
let arg_3 =
|
||||
(match node.["totalClasses"] with
|
||||
@@ -783,7 +782,7 @@ module MemberActivityDto =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_2 =
|
||||
(match node.["totalVisits"] with
|
||||
@@ -795,7 +794,7 @@ module MemberActivityDto =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["averageDuration"] with
|
||||
@@ -807,7 +806,7 @@ module MemberActivityDto =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["totalDuration"] with
|
||||
@@ -819,7 +818,7 @@ module MemberActivityDto =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
{
|
||||
TotalDuration = arg_0
|
||||
@@ -832,8 +831,7 @@ module MemberActivityDto =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the SessionsAggregate type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module SessionsAggregate =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsAggregate =
|
||||
@@ -847,7 +845,7 @@ module SessionsAggregate =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["Visits"] with
|
||||
@@ -859,7 +857,7 @@ module SessionsAggregate =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["Activities"] with
|
||||
@@ -871,7 +869,7 @@ module SessionsAggregate =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
{
|
||||
Activities = arg_0
|
||||
@@ -881,8 +879,7 @@ module SessionsAggregate =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the VisitGym type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module VisitGym =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : VisitGym =
|
||||
@@ -896,7 +893,7 @@ module VisitGym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["Name"] with
|
||||
@@ -908,7 +905,7 @@ module VisitGym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["Id"] with
|
||||
@@ -920,7 +917,7 @@ module VisitGym =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
{
|
||||
Id = arg_0
|
||||
@@ -930,8 +927,7 @@ module VisitGym =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the Visit type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module Visit =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
|
||||
@@ -957,7 +953,7 @@ module Visit =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["StartTime"] with
|
||||
@@ -982,7 +978,7 @@ module Visit =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
{
|
||||
IsDurationEstimated = arg_0
|
||||
@@ -993,8 +989,7 @@ module Visit =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the SessionsSummary type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module SessionsSummary =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
|
||||
@@ -1029,8 +1024,7 @@ module SessionsSummary =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the Sessions type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module Sessions =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Sessions =
|
||||
@@ -1066,8 +1060,7 @@ module Sessions =
|
||||
namespace PureGym
|
||||
|
||||
/// Module containing JSON parsing methods for the UriThing type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module UriThing =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : UriThing =
|
||||
|
@@ -17,8 +17,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module PureGymApi =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IPureGymApi =
|
||||
@@ -303,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
|
||||
@@ -1055,8 +1054,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module internal ApiWithoutBaseAddress =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IApiWithoutBaseAddress =
|
||||
@@ -1107,8 +1105,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithBasePath =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IApiWithBasePath =
|
||||
@@ -1159,8 +1156,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithBasePathAndAddress =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IApiWithBasePathAndAddress =
|
||||
@@ -1205,8 +1201,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithHeaders =
|
||||
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||
let make
|
||||
@@ -1268,8 +1263,7 @@ open System.Net.Http
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module ApiWithHeaders2 =
|
||||
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||
let make
|
||||
|
@@ -21,69 +21,69 @@ module InnerTypeWithBothJsonSerializeExtension =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add (("it's-a-me"), System.Text.Json.Nodes.JsonValue.Create<Guid> input.Thing)
|
||||
node.Add (("it's-a-me"), (input.Thing |> System.Text.Json.Nodes.JsonValue.Create<Guid>))
|
||||
|
||||
node.Add (
|
||||
"map",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.Map
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<Uri> value)
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<Uri> value)
|
||||
|
||||
ret
|
||||
)
|
||||
input.Map
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"readOnlyDict",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.ReadOnlyDict
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (
|
||||
key.ToString (),
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (
|
||||
key.ToString (),
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<char> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<char> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
value
|
||||
)
|
||||
arr
|
||||
)
|
||||
value
|
||||
)
|
||||
|
||||
ret
|
||||
)
|
||||
input.ReadOnlyDict
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"dict",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.Dict
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<bool> value)
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), System.Text.Json.Nodes.JsonValue.Create<bool> value)
|
||||
|
||||
ret
|
||||
)
|
||||
input.Dict
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"concreteDict",
|
||||
(fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
(input.ConcreteDict
|
||||
|> (fun field ->
|
||||
let ret = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), InnerTypeWithBoth.toJsonNode value)
|
||||
for (KeyValue (key, value)) in field do
|
||||
ret.Add (key.ToString (), InnerTypeWithBoth.toJsonNode value)
|
||||
|
||||
ret
|
||||
)
|
||||
input.ConcreteDict
|
||||
ret
|
||||
))
|
||||
)
|
||||
|
||||
node :> _
|
||||
@@ -93,6 +93,24 @@ open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the SomeEnum type
|
||||
[<AutoOpen>]
|
||||
module SomeEnumJsonSerializeExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type SomeEnum with
|
||||
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : SomeEnum) : System.Text.Json.Nodes.JsonNode =
|
||||
match input with
|
||||
| SomeEnum.Blah -> System.Text.Json.Nodes.JsonValue.Create 1
|
||||
| SomeEnum.Thing -> System.Text.Json.Nodes.JsonValue.Create 0
|
||||
| v -> failwith (sprintf "Unrecognised value for enum: %O" v)
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the JsonRecordTypeWithBoth type
|
||||
[<AutoOpen>]
|
||||
module JsonRecordTypeWithBothJsonSerializeExtension =
|
||||
@@ -104,48 +122,92 @@ module JsonRecordTypeWithBothJsonSerializeExtension =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add ("a", System.Text.Json.Nodes.JsonValue.Create<int> input.A)
|
||||
node.Add ("b", System.Text.Json.Nodes.JsonValue.Create<string> input.B)
|
||||
node.Add ("a", (input.A |> System.Text.Json.Nodes.JsonValue.Create<int>))
|
||||
node.Add ("b", (input.B |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
|
||||
node.Add (
|
||||
"c",
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
(input.C
|
||||
|> (fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
input.C
|
||||
arr
|
||||
))
|
||||
)
|
||||
|
||||
node.Add ("d", InnerTypeWithBoth.toJsonNode input.D)
|
||||
node.Add ("d", (input.D |> InnerTypeWithBoth.toJsonNode))
|
||||
|
||||
node.Add (
|
||||
"e",
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
(input.E
|
||||
|> (fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<string> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<string> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
input.E
|
||||
arr
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"f",
|
||||
(fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
"arr",
|
||||
(input.Arr
|
||||
|> (fun field ->
|
||||
let arr = System.Text.Json.Nodes.JsonArray ()
|
||||
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
for mem in field do
|
||||
arr.Add (System.Text.Json.Nodes.JsonValue.Create<int> mem)
|
||||
|
||||
arr
|
||||
)
|
||||
input.F
|
||||
arr
|
||||
))
|
||||
)
|
||||
|
||||
node.Add ("byte", (input.Byte |> System.Text.Json.Nodes.JsonValue.Create<byte<measure>>))
|
||||
node.Add ("sbyte", (input.Sbyte |> System.Text.Json.Nodes.JsonValue.Create<sbyte<measure>>))
|
||||
node.Add ("i", (input.I |> System.Text.Json.Nodes.JsonValue.Create<int<measure>>))
|
||||
node.Add ("i32", (input.I32 |> System.Text.Json.Nodes.JsonValue.Create<int32<measure>>))
|
||||
node.Add ("i64", (input.I64 |> System.Text.Json.Nodes.JsonValue.Create<int64<measure>>))
|
||||
node.Add ("u", (input.U |> System.Text.Json.Nodes.JsonValue.Create<uint<measure>>))
|
||||
node.Add ("u32", (input.U32 |> System.Text.Json.Nodes.JsonValue.Create<uint32<measure>>))
|
||||
node.Add ("u64", (input.U64 |> System.Text.Json.Nodes.JsonValue.Create<uint64<measure>>))
|
||||
node.Add ("f", (input.F |> System.Text.Json.Nodes.JsonValue.Create<float<measure>>))
|
||||
node.Add ("f32", (input.F32 |> System.Text.Json.Nodes.JsonValue.Create<float32<measure>>))
|
||||
node.Add ("single", (input.Single |> System.Text.Json.Nodes.JsonValue.Create<single<measure>>))
|
||||
|
||||
node.Add (
|
||||
"intMeasureOption",
|
||||
(input.IntMeasureOption
|
||||
|> (fun field ->
|
||||
match field with
|
||||
| None -> null :> System.Text.Json.Nodes.JsonNode
|
||||
| Some field ->
|
||||
(System.Text.Json.Nodes.JsonValue.Create<int<measure>> field)
|
||||
:> System.Text.Json.Nodes.JsonNode
|
||||
))
|
||||
)
|
||||
|
||||
node.Add (
|
||||
"intMeasureNullable",
|
||||
(input.IntMeasureNullable
|
||||
|> (fun field ->
|
||||
if field.HasValue then
|
||||
System.Text.Json.Nodes.JsonValue.Create<int<measure>> field.Value
|
||||
:> System.Text.Json.Nodes.JsonNode
|
||||
else
|
||||
null :> System.Text.Json.Nodes.JsonNode
|
||||
))
|
||||
)
|
||||
|
||||
node.Add ("enum", (input.Enum |> SomeEnum.toJsonNode))
|
||||
|
||||
node.Add (
|
||||
"timestamp",
|
||||
(input.Timestamp
|
||||
|> (fun field -> field.ToString "o" |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
)
|
||||
|
||||
node :> _
|
||||
@@ -167,7 +229,7 @@ module FirstDuJsonSerializeExtension =
|
||||
|
||||
match input with
|
||||
| FirstDu.EmptyCase -> node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "emptyCase")
|
||||
| FirstDu.Case1 (arg0) ->
|
||||
| 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)
|
||||
@@ -180,6 +242,55 @@ module FirstDuJsonSerializeExtension =
|
||||
node.Add ("data", dataNode)
|
||||
|
||||
node :> _
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the HeaderAndValue type
|
||||
[<AutoOpen>]
|
||||
module HeaderAndValueJsonSerializeExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type HeaderAndValue with
|
||||
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : HeaderAndValue) : System.Text.Json.Nodes.JsonNode =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add ("header", (input.Header |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
node.Add ("value", (input.Value |> System.Text.Json.Nodes.JsonValue.Create<string>))
|
||||
|
||||
node :> _
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
/// Module containing JSON serializing extension members for the Foo type
|
||||
[<AutoOpen>]
|
||||
module FooJsonSerializeExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type Foo with
|
||||
|
||||
/// Serialize to a JSON node
|
||||
static member toJsonNode (input : Foo) : System.Text.Json.Nodes.JsonNode =
|
||||
let node = System.Text.Json.Nodes.JsonObject ()
|
||||
|
||||
do
|
||||
node.Add (
|
||||
"message",
|
||||
(input.Message
|
||||
|> (fun field ->
|
||||
match field with
|
||||
| None -> null :> System.Text.Json.Nodes.JsonNode
|
||||
| Some field -> HeaderAndValue.toJsonNode field
|
||||
))
|
||||
)
|
||||
|
||||
node :> _
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
@@ -221,7 +332,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
|
||||
@@ -287,6 +398,24 @@ module InnerTypeWithBothJsonParseExtension =
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the SomeEnum type
|
||||
[<AutoOpen>]
|
||||
module SomeEnumJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type SomeEnum with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : SomeEnum =
|
||||
match node.GetValueKind () with
|
||||
| System.Text.Json.JsonValueKind.Number -> node.AsValue().GetValue<int> () |> enum<SomeEnum>
|
||||
| System.Text.Json.JsonValueKind.String ->
|
||||
match node.AsValue().GetValue<string>().ToLowerInvariant () with
|
||||
| "blah" -> SomeEnum.Blah
|
||||
| "thing" -> SomeEnum.Thing
|
||||
| v -> failwith ("Unrecognised value for enum: %i" + v)
|
||||
| _ -> failwith ("Unrecognised kind for enum of type: " + "SomeEnum")
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the JsonRecordTypeWithBoth type
|
||||
[<AutoOpen>]
|
||||
module JsonRecordTypeWithBothJsonParseExtension =
|
||||
@@ -295,7 +424,74 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordTypeWithBoth =
|
||||
let arg_5 =
|
||||
let arg_20 =
|
||||
(match node.["timestamp"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("timestamp")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
|> System.DateTimeOffset.Parse
|
||||
|
||||
let arg_19 =
|
||||
SomeEnum.jsonParse (
|
||||
match node.["enum"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("enum")
|
||||
)
|
||||
)
|
||||
| v -> v
|
||||
)
|
||||
|
||||
let arg_18 =
|
||||
match node.["intMeasureNullable"] with
|
||||
| null -> System.Nullable ()
|
||||
| v ->
|
||||
v.AsValue().GetValue<System.Int32> ()
|
||||
|> LanguagePrimitives.Int32WithMeasure
|
||||
|> System.Nullable
|
||||
|
||||
let arg_17 =
|
||||
match node.["intMeasureOption"] with
|
||||
| null -> None
|
||||
| v ->
|
||||
v.AsValue().GetValue<System.Int32> ()
|
||||
|> LanguagePrimitives.Int32WithMeasure
|
||||
|> Some
|
||||
|
||||
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 +499,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 +631,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 +656,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 +669,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["a"] with
|
||||
@@ -368,7 +681,7 @@ module JsonRecordTypeWithBothJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
{
|
||||
A = arg_0
|
||||
@@ -376,7 +689,22 @@ 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
|
||||
IntMeasureOption = arg_17
|
||||
IntMeasureNullable = arg_18
|
||||
Enum = arg_19
|
||||
Timestamp = arg_20
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
@@ -422,7 +750,7 @@ module FirstDuJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
)
|
||||
| "case2" ->
|
||||
let node =
|
||||
@@ -455,6 +783,62 @@ module FirstDuJsonParseExtension =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
)
|
||||
| v -> failwith ("Unrecognised 'type' field value: " + v)
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the HeaderAndValue type
|
||||
[<AutoOpen>]
|
||||
module HeaderAndValueJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type HeaderAndValue with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : HeaderAndValue =
|
||||
let arg_1 =
|
||||
(match node.["value"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("value")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["header"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("header")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Header = arg_0
|
||||
Value = arg_1
|
||||
}
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing extension members for the Foo type
|
||||
[<AutoOpen>]
|
||||
module FooJsonParseExtension =
|
||||
/// Extension methods for JSON parsing
|
||||
type Foo with
|
||||
|
||||
/// Parse from a JSON node.
|
||||
static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : Foo =
|
||||
let arg_0 =
|
||||
match node.["message"] with
|
||||
| null -> None
|
||||
| v -> HeaderAndValue.jsonParse v |> Some
|
||||
|
||||
{
|
||||
Message = arg_0
|
||||
}
|
||||
|
@@ -8,8 +8,7 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JwtVaultAuthResponse =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultAuthResponse =
|
||||
@@ -23,7 +22,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_9 =
|
||||
(match node.["orphan"] with
|
||||
@@ -35,7 +34,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
let arg_8 =
|
||||
(match node.["entity_id"] with
|
||||
@@ -47,7 +46,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_7 =
|
||||
(match node.["token_type"] with
|
||||
@@ -59,7 +58,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_6 =
|
||||
(match node.["renewable"] with
|
||||
@@ -71,7 +70,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
let arg_5 =
|
||||
(match node.["lease_duration"] with
|
||||
@@ -83,7 +82,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_4 =
|
||||
(match node.["identity_policies"] with
|
||||
@@ -95,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 =
|
||||
@@ -108,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 =
|
||||
@@ -121,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 =
|
||||
@@ -134,7 +133,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["client_token"] with
|
||||
@@ -146,7 +145,7 @@ module JwtVaultAuthResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
ClientToken = arg_0
|
||||
@@ -164,8 +163,7 @@ module JwtVaultAuthResponse =
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtVaultResponse type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JwtVaultResponse =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtVaultResponse =
|
||||
@@ -191,7 +189,7 @@ module JwtVaultResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_2 =
|
||||
(match node.["renewable"] with
|
||||
@@ -203,7 +201,7 @@ module JwtVaultResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["lease_id"] with
|
||||
@@ -215,7 +213,7 @@ module JwtVaultResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["request_id"] with
|
||||
@@ -227,7 +225,7 @@ module JwtVaultResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
RequestId = arg_0
|
||||
@@ -239,8 +237,7 @@ module JwtVaultResponse =
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtSecretResponse type
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module JwtSecretResponse =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : JwtSecretResponse =
|
||||
@@ -274,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
|
||||
@@ -291,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
|
||||
@@ -308,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
|
||||
@@ -325,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
|
||||
@@ -342,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
|
||||
@@ -360,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
|
||||
@@ -377,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
|
||||
@@ -392,7 +389,7 @@ module JwtSecretResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<int> ()
|
||||
.GetValue<System.Int32> ()
|
||||
|
||||
let arg_2 =
|
||||
(match node.["renewable"] with
|
||||
@@ -404,7 +401,7 @@ module JwtSecretResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<bool> ()
|
||||
.GetValue<System.Boolean> ()
|
||||
|
||||
let arg_1 =
|
||||
(match node.["lease_id"] with
|
||||
@@ -416,7 +413,7 @@ module JwtSecretResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["request_id"] with
|
||||
@@ -428,7 +425,7 @@ module JwtSecretResponse =
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<string> ()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
RequestId = arg_0
|
||||
@@ -455,8 +452,7 @@ open System.Threading.Tasks
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module VaultClient =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IVaultClient =
|
||||
@@ -553,8 +549,7 @@ open System.Threading.Tasks
|
||||
open RestEase
|
||||
|
||||
/// Module for constructing a REST client.
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
|
||||
module VaultClientNonExtensionMethod =
|
||||
/// Create a REST client.
|
||||
let make (client : System.Net.Http.HttpClient) : IVaultClientNonExtensionMethod =
|
||||
|
@@ -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 =
|
||||
{
|
||||
|
@@ -41,7 +41,7 @@ module MyListCata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__MyList (x) ->
|
||||
| Instruction.Process__MyList x ->
|
||||
match x with
|
||||
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
||||
| MyList.Cons ({
|
||||
@@ -50,7 +50,7 @@ module MyListCata =
|
||||
}) ->
|
||||
instructions.Add (Instruction.MyList_Cons (head))
|
||||
instructions.Add (Instruction.Process__MyList tail)
|
||||
| Instruction.MyList_Cons (head) ->
|
||||
| Instruction.MyList_Cons head ->
|
||||
let tail = myListStack.[myListStack.Count - 1]
|
||||
myListStack.RemoveAt (myListStack.Count - 1)
|
||||
cata.MyList.Cons head tail |> myListStack.Add
|
||||
@@ -97,13 +97,13 @@ module MyList2Cata =
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__MyList2 (x) ->
|
||||
| Instruction.Process__MyList2 x ->
|
||||
match x with
|
||||
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
||||
| MyList2.Cons (arg0_0, arg1_0) ->
|
||||
instructions.Add (Instruction.MyList2_Cons (arg0_0))
|
||||
instructions.Add (Instruction.Process__MyList2 arg1_0)
|
||||
| Instruction.MyList2_Cons (arg0_0) ->
|
||||
| Instruction.MyList2_Cons arg0_0 ->
|
||||
let arg1_0 = myList2Stack.[myList2Stack.Count - 1]
|
||||
myList2Stack.RemoveAt (myList2Stack.Count - 1)
|
||||
cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add
|
||||
|
@@ -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>]
|
||||
|
@@ -1,9 +1,5 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
type ParseState =
|
||||
| AwaitingKey
|
||||
| AwaitingValue of string
|
||||
|
||||
/// My whatnot
|
||||
[<WoofWare.Myriad.Plugins.RemoveOptions>]
|
||||
type RecordType =
|
||||
|
@@ -16,6 +16,15 @@ type InnerTypeWithBoth =
|
||||
ConcreteDict : Dictionary<string, InnerTypeWithBoth>
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
type SomeEnum =
|
||||
| Blah = 1
|
||||
| Thing = 0
|
||||
|
||||
[<Measure>]
|
||||
type measure
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
type JsonRecordTypeWithBoth =
|
||||
@@ -25,7 +34,22 @@ 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>
|
||||
IntMeasureOption : int<measure> option
|
||||
IntMeasureNullable : int<measure> Nullable
|
||||
Enum : SomeEnum
|
||||
Timestamp : DateTimeOffset
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
@@ -34,3 +58,18 @@ type FirstDu =
|
||||
| EmptyCase
|
||||
| Case1 of data : string
|
||||
| Case2 of record : JsonRecordTypeWithBoth * i : int
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
type HeaderAndValue =
|
||||
{
|
||||
Header : string
|
||||
Value : string
|
||||
}
|
||||
|
||||
[<WoofWare.Myriad.Plugins.JsonSerialize true>]
|
||||
[<WoofWare.Myriad.Plugins.JsonParse true>]
|
||||
type Foo =
|
||||
{
|
||||
Message : HeaderAndValue option
|
||||
}
|
||||
|
@@ -10,19 +10,10 @@
|
||||
<WarnOn>FS3388,FS3559</WarnOn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.133" PrivateAssets="all"/>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.143" PrivateAssets="all"/>
|
||||
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
|
||||
</ItemGroup>
|
||||
<!--
|
||||
SourceLink doesn't support F# deterministic builds out of the box,
|
||||
so tell SourceLink that our source root is going to be remapped.
|
||||
-->
|
||||
<Target Name="MapSourceRoot" BeforeTargets="_GenerateSourceLinkFile" Condition="'$(SourceRootMappedPathsFeatureSupported)' != 'true'">
|
||||
<ItemGroup>
|
||||
<SourceRoot Update="@(SourceRoot)">
|
||||
<MappedPath>Z:\CheckoutRoot\WoofWare.Myriad\</MappedPath>
|
||||
</SourceRoot>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
87
README.md
87
README.md
@@ -8,23 +8,21 @@
|
||||
|
||||
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)).
|
||||
* `ArgParser` (to stamp out a basic argument parser)
|
||||
* `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:
|
||||
@@ -153,6 +151,73 @@ The same limitations generally apply to `JsonSerialize` as do to `JsonParse`.
|
||||
|
||||
For an example of using both `JsonParse` and `JsonSerialize` together with complex types, see [the type definitions](./ConsumePlugin/SerializationAndDeserialization.fs) and [tests](./WoofWare.Myriad.Plugins.Test/TestJsonSerialize/TestJsonSerde.fs).
|
||||
|
||||
## `ArgParser`
|
||||
|
||||
Takes a record like this:
|
||||
|
||||
```fsharp
|
||||
[<ArgParser>]
|
||||
type Foo =
|
||||
{
|
||||
[<ArgumentHelpText "Enable the frobnicator">]
|
||||
SomeFlag : bool
|
||||
A : int option
|
||||
[<ArgumentDefaultFunction>]
|
||||
B : Choice<int, int>
|
||||
[<ArgumentDefaultEnvironmentVariable "MY_ENV_VAR">]
|
||||
BWithEnv : Choice<int, int>
|
||||
C : float list
|
||||
// optionally:
|
||||
[<PositionalArgs>]
|
||||
Rest : string list // or e.g. `int list` if you want them parsed into a type too
|
||||
}
|
||||
static member DefaultB () = 4
|
||||
```
|
||||
|
||||
and stamps out a basic `parse` method of this signature:
|
||||
|
||||
```fsharp
|
||||
[<RequireQualifiedAccess>]
|
||||
module Foo =
|
||||
// in case you want to test it
|
||||
let parse' (getEnvVar : string -> string) (args : string list) : Foo = ...
|
||||
// the one we expect you actually want to use
|
||||
let parse (args : string list) : Foo = ...
|
||||
```
|
||||
|
||||
Default arguments are handled as `Choice<'a, 'a>`:
|
||||
you get a `Choice1Of2` if the user provided the input, or a `Choice2Of2` if the parser filled in your specified default value.
|
||||
|
||||
You can control `TimeSpan` and friends with the `[<InvariantCulture>]` and `[<ParseExact @"hh\:mm\:ss">]` attributes.
|
||||
|
||||
You can generate extension methods for the type, instead of a module with the type's name, using `[<ArgParser (* isExtensionMethod = *) true>]`.
|
||||
|
||||
If `--help` appears in a position where the parser is expecting a key (e.g. in the first position, or after a `--foo=bar`), the parser fails with help text.
|
||||
The parser also makes a limited effort to supply help text when encountering an invalid parse.
|
||||
|
||||
### What's the point?
|
||||
|
||||
I got fed up of waiting for us to find time to rewrite the in-house one at work.
|
||||
That one has a bunch of nice compositional properties, which my version lacks:
|
||||
I can basically only deal with primitive types, and e.g. you can't stack records and discriminated unions inside each other.
|
||||
|
||||
But I *do* want an F#-native argument parser suitable for AOT-compilation.
|
||||
|
||||
Why not [Argu](https://fsprojects.github.io/Argu/)?
|
||||
Answer: I got annoyed with having to construct my records by hand even after Argu returned and said the parsing was all "done".
|
||||
|
||||
### Limitations
|
||||
|
||||
This is very bare-bones, but do raise GitHub issues if you like (or if you find cases where the parser does the wrong thing).
|
||||
|
||||
* Help is signalled by throwing an exception, so you'll get an unsightly stack trace and a nonzero exit code.
|
||||
* Help doesn't take into account any arguments the user has entered. Ideally you'd get contextual information like an identification of which args the user has supplied at the point where the parse failed or help was requested.
|
||||
* I don't handle very many types, and in particular a real arg parser would handle DUs and records with nesting.
|
||||
* I don't try very hard to find a valid parse. It may well be possible to find a case where I fail to parse despite there existing a valid parse.
|
||||
* There's no subcommand support (you'll have to do that yourself).
|
||||
|
||||
It should work fine if you just want to compose a few primitive types, though.
|
||||
|
||||
## `RemoveOptions`
|
||||
|
||||
Takes a record like this:
|
||||
|
63
WoofWare.Myriad.Plugins.Attributes/ArgParserAttributes.fs
Normal file
63
WoofWare.Myriad.Plugins.Attributes/ArgParserAttributes.fs
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
|
||||
/// Attribute indicating a record type to which the "build arg parser" Myriad
|
||||
/// generator should apply during build.
|
||||
///
|
||||
/// If you supply isExtensionMethod = true, you will get extension methods.
|
||||
/// These can only be consumed from F#, but the benefit is that they don't use up the module name
|
||||
/// (since by default we create a module called "{TypeName}").
|
||||
type ArgParserAttribute (isExtensionMethod : bool) =
|
||||
inherit Attribute ()
|
||||
|
||||
/// The default value of `isExtensionMethod`, the optional argument to the ArgParserAttribute constructor.
|
||||
static member DefaultIsExtensionMethod = false
|
||||
|
||||
/// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details.
|
||||
new () = ArgParserAttribute ArgParserAttribute.DefaultIsExtensionMethod
|
||||
|
||||
/// Attribute indicating that this field shall accumulate all unmatched args,
|
||||
/// as well as any that appear after a bare `--`.
|
||||
type PositionalArgsAttribute () =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this field shall have a default value derived
|
||||
/// from calling an appropriately named static method on the type.
|
||||
///
|
||||
/// This attribute can only be placed on fields of type `Choice<_, _>` where both type parameters
|
||||
/// are the same.
|
||||
/// After a successful parse, the value is Choice1Of2 if the user supplied an input,
|
||||
/// or Choice2Of2 if the input was obtained by calling the default function.
|
||||
///
|
||||
/// The static method we call for field `FieldName : 'a` is `DefaultFieldName : unit -> 'a`.
|
||||
type ArgumentDefaultFunctionAttribute () =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this field shall have a default value derived
|
||||
/// from an environment variable (whose name you give in the attribute constructor).
|
||||
///
|
||||
/// This attribute can only be placed on fields of type `Choice<_, _>` where both type parameters
|
||||
/// are the same.
|
||||
/// After a successful parse, the value is Choice1Of2 if the user supplied an input,
|
||||
/// or Choice2Of2 if the input was obtained by pulling a value from `Environment.GetEnvironmentVariable`.
|
||||
type ArgumentDefaultEnvironmentVariableAttribute (envVar : string) =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this field shall have the given help text, when `--help` is invoked
|
||||
/// or when a parse error causes us to print help text.
|
||||
type ArgumentHelpTextAttribute (helpText : string) =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this field should be parsed with a ParseExact method on its type.
|
||||
/// For example, on a TimeSpan field, with [<ArgumentParseExact @"hh\:mm\:ss">], we will call
|
||||
/// `TimeSpan.ParseExact (s, @"hh\:mm\:ss", CultureInfo.CurrentCulture).
|
||||
type ParseExactAttribute (format : string) =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this field should be parsed in the invariant culture, rather than the
|
||||
/// default current culture.
|
||||
/// For example, on a TimeSpan field, with [<InvariantCulture>] and [<ArgumentParseExact @"hh\:mm\:ss">], we will call
|
||||
/// `TimeSpan.ParseExact (s, @"hh\:mm\:ss", CultureInfo.InvariantCulture).
|
||||
type InvariantCultureAttribute () =
|
||||
inherit Attribute ()
|
@@ -1,3 +1,14 @@
|
||||
WoofWare.Myriad.Plugins.ArgParserAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgParserAttribute..ctor [constructor]: bool
|
||||
WoofWare.Myriad.Plugins.ArgParserAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.ArgParserAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
||||
WoofWare.Myriad.Plugins.ArgParserAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||
WoofWare.Myriad.Plugins.ArgumentDefaultEnvironmentVariableAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentDefaultEnvironmentVariableAttribute..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.ArgumentDefaultFunctionAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentDefaultFunctionAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.ArgumentHelpTextAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentHelpTextAttribute..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismAttribute..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.GenerateMockAttribute inherit System.Attribute
|
||||
@@ -10,6 +21,8 @@ WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: bool
|
||||
WoofWare.Myriad.Plugins.HttpClientAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.HttpClientAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
||||
WoofWare.Myriad.Plugins.HttpClientAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||
WoofWare.Myriad.Plugins.InvariantCultureAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.InvariantCultureAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.JsonParseAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: bool
|
||||
WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: unit
|
||||
@@ -20,6 +33,10 @@ WoofWare.Myriad.Plugins.JsonSerializeAttribute..ctor [constructor]: bool
|
||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static property]: [read-only] bool
|
||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||
WoofWare.Myriad.Plugins.ParseExactAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ParseExactAttribute..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.PositionalArgsAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.PositionalArgsAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.RestEase inherit obj
|
||||
|
@@ -12,10 +12,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.40" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="ApiSurface" Version="4.1.5" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.2.2"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Attributes.fs"/>
|
||||
<Compile Include="ArgParserAttributes.fs" />
|
||||
<Compile Include="RestEase.fs" />
|
||||
<EmbeddedResource Include="version.json"/>
|
||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "3.1",
|
||||
"version": "3.2",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
@@ -10,6 +10,6 @@
|
||||
":/Directory.Build.props",
|
||||
":/global.json",
|
||||
"./",
|
||||
"^./Test"
|
||||
":^Test"
|
||||
]
|
||||
}
|
||||
|
@@ -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"
|
||||
|
343
WoofWare.Myriad.Plugins.Test/TestArgParser/TestArgParser.fs
Normal file
343
WoofWare.Myriad.Plugins.Test/TestArgParser/TestArgParser.fs
Normal file
@@ -0,0 +1,343 @@
|
||||
namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System
|
||||
open System.Threading
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open ConsumePlugin
|
||||
open FsCheck
|
||||
|
||||
[<TestFixture>]
|
||||
module TestArgParser =
|
||||
|
||||
[<TestCase true>]
|
||||
[<TestCase false>]
|
||||
let ``Positionals get parsed: they don't have to be strings`` (sep : bool) =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let property
|
||||
(fooSep : bool)
|
||||
(barSep : bool)
|
||||
(bazSep : bool)
|
||||
(pos0 : int list)
|
||||
(pos1 : int list)
|
||||
(pos2 : int list)
|
||||
(pos3 : int list)
|
||||
(pos4 : int list)
|
||||
=
|
||||
let args =
|
||||
[
|
||||
yield! pos0 |> List.map string<int>
|
||||
if fooSep then
|
||||
yield "--foo=3"
|
||||
else
|
||||
yield "--foo"
|
||||
yield "3"
|
||||
yield! pos1 |> List.map string<int>
|
||||
if barSep then
|
||||
yield "--bar=4"
|
||||
else
|
||||
yield "--bar"
|
||||
yield "4"
|
||||
yield! pos2 |> List.map string<int>
|
||||
if bazSep then
|
||||
yield "--baz=true"
|
||||
else
|
||||
yield "--baz"
|
||||
yield "true"
|
||||
yield! pos3 |> List.map string<int>
|
||||
if sep then
|
||||
yield "--"
|
||||
yield! pos4 |> List.map string<int>
|
||||
]
|
||||
|
||||
BasicWithIntPositionals.parse' getEnvVar args
|
||||
|> shouldEqual
|
||||
{
|
||||
Foo = 3
|
||||
Bar = "4"
|
||||
Baz = true
|
||||
Rest = pos0 @ pos1 @ pos2 @ pos3 @ pos4
|
||||
}
|
||||
|
||||
Check.QuickThrowOnFailure property
|
||||
|
||||
[<Test>]
|
||||
let ``Arg-like thing appearing before double dash`` () =
|
||||
let envCalls = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment envCalls |> ignore<int>
|
||||
""
|
||||
|
||||
let args = [ "--foo=3" ; "--non-existent" ; "--bar=4" ; "--baz=true" ]
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> Basic.parse' getEnvVar args |> ignore<Basic>)
|
||||
|
||||
envCalls.Value |> shouldEqual 0
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Unable to process supplied arg --non-existent. Help text follows.
|
||||
--foo int32 : This is a foo!
|
||||
--bar string
|
||||
--baz bool
|
||||
--rest string (positional args) (can be repeated) : Here's where the rest of the args go"""
|
||||
|
||||
[<Test>]
|
||||
let ``Can supply positional args with key`` () =
|
||||
let envCalls = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment envCalls |> ignore<int>
|
||||
""
|
||||
|
||||
let property (args : (int * bool) list) (afterDoubleDash : int list option) =
|
||||
let flatArgs =
|
||||
args
|
||||
|> List.collect (fun (value, sep) ->
|
||||
if sep then
|
||||
[ $"--rest=%i{value}" ]
|
||||
else
|
||||
[ "--rest" ; string<int> value ]
|
||||
)
|
||||
|> fun l -> l @ [ "--foo=3" ; "--bar=4" ; "--baz=true" ]
|
||||
|
||||
let flatArgs, expected =
|
||||
match afterDoubleDash with
|
||||
| None -> flatArgs, List.map fst args
|
||||
| Some rest -> flatArgs @ [ "--" ] @ (List.map string<int> rest), List.map fst args @ rest
|
||||
|
||||
BasicWithIntPositionals.parse' getEnvVar flatArgs
|
||||
|> shouldEqual
|
||||
{
|
||||
Foo = 3
|
||||
Bar = "4"
|
||||
Baz = true
|
||||
Rest = expected
|
||||
}
|
||||
|
||||
Check.QuickThrowOnFailure property
|
||||
envCalls.Value |> shouldEqual 0
|
||||
|
||||
[<Test>]
|
||||
let ``Consume multiple occurrences of required arg`` () =
|
||||
let envCalls = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment envCalls |> ignore<int>
|
||||
""
|
||||
|
||||
let args = [ "--foo=3" ; "--rest" ; "7" ; "--bar=4" ; "--baz=true" ; "--rest=8" ]
|
||||
|
||||
let result = BasicNoPositionals.parse' getEnvVar args
|
||||
|
||||
envCalls.Value |> shouldEqual 0
|
||||
|
||||
result
|
||||
|> shouldEqual
|
||||
{
|
||||
Foo = 3
|
||||
Bar = "4"
|
||||
Baz = true
|
||||
Rest = [ 7 ; 8 ]
|
||||
}
|
||||
|
||||
[<Test>]
|
||||
let ``Gracefully handle invalid multiple occurrences of required arg`` () =
|
||||
let envCalls = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment envCalls |> ignore<int>
|
||||
""
|
||||
|
||||
let args = [ "--foo=3" ; "--foo" ; "9" ; "--bar=4" ; "--baz=true" ; "--baz=false" ]
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> Basic.parse' getEnvVar args |> ignore<Basic>)
|
||||
|
||||
envCalls.Value |> shouldEqual 0
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Errors during parse!
|
||||
Argument '--foo' was supplied multiple times: 3 and 9
|
||||
Argument '--baz' was supplied multiple times: True and false"""
|
||||
|
||||
[<Test>]
|
||||
let ``Args appearing after double dash are positional`` () =
|
||||
let envCalls = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment envCalls |> ignore<int>
|
||||
""
|
||||
|
||||
let args = [ "--" ; "--foo=3" ; "--bar=4" ; "--baz=true" ]
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> Basic.parse' getEnvVar args |> ignore<Basic>)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Errors during parse!
|
||||
Required argument '--foo' received no value
|
||||
Required argument '--bar' received no value
|
||||
Required argument '--baz' received no value"""
|
||||
|
||||
envCalls.Value |> shouldEqual 0
|
||||
|
||||
[<Test>]
|
||||
let ``Help text`` () =
|
||||
let getEnvVar (s : string) =
|
||||
s |> shouldEqual "CONSUMEPLUGIN_THINGS"
|
||||
"hi!"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> Basic.parse' getEnvVar [ "--help" ] |> ignore<Basic>)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Help text requested.
|
||||
--foo int32 : This is a foo!
|
||||
--bar string
|
||||
--baz bool
|
||||
--rest string (positional args) (can be repeated) : Here's where the rest of the args go"""
|
||||
|
||||
[<Test>]
|
||||
let ``Help text, with default values`` () =
|
||||
let envVars = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment envVars |> ignore<int>
|
||||
""
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> LoadsOfTypes.parse' getEnvVar [ "--help" ] |> ignore<LoadsOfTypes>)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Help text requested.
|
||||
--foo int32
|
||||
--bar string
|
||||
--baz bool
|
||||
--some-file FileInfo
|
||||
--some-directory DirectoryInfo
|
||||
--some-list DirectoryInfo (can be repeated)
|
||||
--optional-thing-with-no-default int32 (optional)
|
||||
--optional-thing bool (default value: True)
|
||||
--another-optional-thing int32 (default value: 3)
|
||||
--yet-another-optional-thing string (default value populated from env var CONSUMEPLUGIN_THINGS)
|
||||
--positionals int32 (positional args) (can be repeated)"""
|
||||
|
||||
envVars.Value |> shouldEqual 0
|
||||
|
||||
[<Test>]
|
||||
let ``Default values`` () =
|
||||
let getEnvVar (s : string) =
|
||||
s |> shouldEqual "CONSUMEPLUGIN_THINGS"
|
||||
"hi!"
|
||||
|
||||
let args =
|
||||
[
|
||||
"--foo"
|
||||
"3"
|
||||
"--bar=some string"
|
||||
"--baz"
|
||||
"--some-file=/path/to/file"
|
||||
"--some-directory"
|
||||
"/a/dir"
|
||||
"--another-optional-thing"
|
||||
"3000"
|
||||
]
|
||||
|
||||
let result = LoadsOfTypes.parse' getEnvVar args
|
||||
|
||||
result.OptionalThing |> shouldEqual (Choice2Of2 true)
|
||||
result.OptionalThingWithNoDefault |> shouldEqual None
|
||||
result.AnotherOptionalThing |> shouldEqual (Choice1Of2 3000)
|
||||
result.YetAnotherOptionalThing |> shouldEqual (Choice2Of2 "hi!")
|
||||
|
||||
[<Test>]
|
||||
let ``ParseExact and help`` () =
|
||||
let count = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment count |> ignore<int>
|
||||
""
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> DatesAndTimes.parse' getEnvVar [ "--help" ] |> ignore<DatesAndTimes>)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
@"Help text requested.
|
||||
--plain TimeSpan
|
||||
--invariant TimeSpan
|
||||
--exact TimeSpan : An exact time please [Parse format (.NET): hh\:mm\:ss]
|
||||
--invariant-exact TimeSpan : [Parse format (.NET): hh\:mm\:ss]"
|
||||
|
||||
count.Value |> shouldEqual 0
|
||||
|
||||
[<Test>]
|
||||
let rec ``TimeSpans and their attributes`` () =
|
||||
let count = ref 0
|
||||
|
||||
let getEnvVar (_ : string) =
|
||||
Interlocked.Increment count |> ignore<int>
|
||||
""
|
||||
|
||||
let parsed =
|
||||
DatesAndTimes.parse'
|
||||
getEnvVar
|
||||
[
|
||||
"--exact=11:34:00"
|
||||
"--plain=1"
|
||||
"--invariant=23:59"
|
||||
"--invariant-exact=23:59:00"
|
||||
]
|
||||
|
||||
parsed.Plain |> shouldEqual (TimeSpan (1, 0, 0, 0))
|
||||
parsed.Invariant |> shouldEqual (TimeSpan (23, 59, 00))
|
||||
parsed.Exact |> shouldEqual (TimeSpan (11, 34, 00))
|
||||
parsed.InvariantExact |> shouldEqual (TimeSpan (23, 59, 00))
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
DatesAndTimes.parse'
|
||||
getEnvVar
|
||||
[
|
||||
"--exact=11:34:00"
|
||||
"--plain=1"
|
||||
"--invariant=23:59"
|
||||
"--invariant-exact=23:59"
|
||||
]
|
||||
|> ignore<DatesAndTimes>
|
||||
)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Errors during parse!
|
||||
Input string was not in a correct format. (at arg --invariant-exact=23:59)
|
||||
Required argument '--invariant-exact' received no value"""
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
DatesAndTimes.parse'
|
||||
getEnvVar
|
||||
[
|
||||
"--exact=11:34"
|
||||
"--plain=1"
|
||||
"--invariant=23:59"
|
||||
"--invariant-exact=23:59:00"
|
||||
]
|
||||
|> ignore<DatesAndTimes>
|
||||
)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Errors during parse!
|
||||
Input string was not in a correct format. (at arg --exact=11:34)
|
||||
Required argument '--exact' received no value"""
|
||||
|
||||
count.Value |> shouldEqual 0
|
@@ -43,7 +43,7 @@ module TestGift =
|
||||
member _.WithACard g message =
|
||||
$"%s{g} with a card saying '%s{message}'"
|
||||
|
||||
member _.Wrapped g paper = $"%s{g} wrapped in %A{paper} paper"
|
||||
member _.Wrapped g paper = $"%s{g} wrapped in %O{paper} paper"
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -49,3 +49,15 @@ module TestJsonParse =
|
||||
|
||||
let actual = s |> JsonNode.Parse |> InnerType.jsonParse
|
||||
actual |> shouldEqual expected
|
||||
|
||||
[<TestCase("thing", SomeEnum.Thing)>]
|
||||
[<TestCase("Thing", SomeEnum.Thing)>]
|
||||
[<TestCase("THING", SomeEnum.Thing)>]
|
||||
[<TestCase("blah", SomeEnum.Blah)>]
|
||||
[<TestCase("Blah", SomeEnum.Blah)>]
|
||||
[<TestCase("BLAH", SomeEnum.Blah)>]
|
||||
let ``Can deserialise enum`` (str : string, expected : SomeEnum) =
|
||||
sprintf "\"%s\"" str
|
||||
|> JsonNode.Parse
|
||||
|> SomeEnum.jsonParse
|
||||
|> shouldEqual expected
|
||||
|
@@ -77,7 +77,22 @@ 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>))
|
||||
let! intMeasureOption = Arb.generate
|
||||
let! intMeasureNullable = Arb.generate
|
||||
let! someEnum = Gen.choose (0, 1)
|
||||
let! timestamp = Arb.generate
|
||||
|
||||
return
|
||||
{
|
||||
@@ -86,7 +101,22 @@ 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
|
||||
IntMeasureOption = intMeasureOption
|
||||
IntMeasureNullable = intMeasureNullable
|
||||
Enum = enum<SomeEnum> someEnum
|
||||
Timestamp = timestamp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +134,80 @@ module TestJsonSerde =
|
||||
|
||||
property |> Prop.forAll (Arb.fromGen outerGen) |> Check.QuickThrowOnFailure
|
||||
|
||||
[<Test>]
|
||||
let ``Single example of big record`` () =
|
||||
let guid = Guid.Parse "dfe24db5-9f8d-447b-8463-4c0bcf1166d5"
|
||||
|
||||
let data =
|
||||
{
|
||||
A = 3
|
||||
B = "hello!"
|
||||
C = [ 1 ; -9 ]
|
||||
D =
|
||||
{
|
||||
Thing = guid
|
||||
Map = Map.ofList []
|
||||
ReadOnlyDict = readOnlyDict []
|
||||
Dict = dict []
|
||||
ConcreteDict = Dictionary ()
|
||||
}
|
||||
E = [| "I'm-a-string" |]
|
||||
Arr = [| -18883 ; 9100 |]
|
||||
Byte = 87uy<measure>
|
||||
Sbyte = 89y<measure>
|
||||
I = 199993345<measure>
|
||||
I32 = -485832<measure>
|
||||
I64 = -13458625689L<measure>
|
||||
U = 458582u<measure>
|
||||
U32 = 857362147u<measure>
|
||||
U64 = 1234567892123414596UL<measure>
|
||||
F = 8833345667.1<measure>
|
||||
F32 = 1000.98f<measure>
|
||||
Single = 0.334f<measure>
|
||||
IntMeasureOption = Some 981<measure>
|
||||
IntMeasureNullable = Nullable -883<measure>
|
||||
Enum = enum<SomeEnum> 1
|
||||
Timestamp = DateTimeOffset (2024, 07, 01, 17, 54, 00, TimeSpan.FromHours 1.0)
|
||||
}
|
||||
|
||||
let expected =
|
||||
"""{
|
||||
"a": 3,
|
||||
"b": "hello!",
|
||||
"c": [1, -9],
|
||||
"d": {
|
||||
"it\u0027s-a-me": "dfe24db5-9f8d-447b-8463-4c0bcf1166d5",
|
||||
"map": {},
|
||||
"readOnlyDict": {},
|
||||
"dict": {},
|
||||
"concreteDict": {}
|
||||
},
|
||||
"e": ["I\u0027m-a-string"],
|
||||
"arr": [-18883, 9100],
|
||||
"byte": 87,
|
||||
"sbyte": 89,
|
||||
"i": 199993345,
|
||||
"i32": -485832,
|
||||
"i64": -13458625689,
|
||||
"u": 458582,
|
||||
"u32": 857362147,
|
||||
"u64": 1234567892123414596,
|
||||
"f": 8833345667.1,
|
||||
"f32": 1000.98,
|
||||
"single": 0.334,
|
||||
"intMeasureOption": 981,
|
||||
"intMeasureNullable": -883,
|
||||
"enum": 1,
|
||||
"timestamp": "2024-07-01T17:54:00.0000000\u002B01:00"
|
||||
}
|
||||
"""
|
||||
|> fun s -> s.ToCharArray ()
|
||||
|> Array.filter (fun c -> not (Char.IsWhiteSpace c))
|
||||
|> fun s -> new String (s)
|
||||
|
||||
JsonRecordTypeWithBoth.toJsonNode(data).ToJsonString () |> shouldEqual expected
|
||||
JsonRecordTypeWithBoth.jsonParse (JsonNode.Parse expected) |> shouldEqual data
|
||||
|
||||
[<Test>]
|
||||
let ``Guids are treated just like strings`` () =
|
||||
let guidStr = "b1e7496e-6e79-4158-8579-a01de355d3b2"
|
||||
@@ -140,8 +244,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 +253,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 =
|
||||
@@ -193,12 +296,13 @@ module TestJsonSerde =
|
||||
|
||||
let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu>
|
||||
|
||||
Gen.listOf duGen
|
||||
|> Gen.eval 100 (StdGen.StdGen (rand.Next (), rand.Next ()))
|
||||
|> List.iter (fun du ->
|
||||
let mutable i = 0
|
||||
|
||||
while i < 10_000 && Array.exists (fun i -> i = 0) counts do
|
||||
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
|
||||
let tag = decompose du
|
||||
counts.[tag] <- counts.[tag] + 1
|
||||
)
|
||||
i <- i + 1
|
||||
|
||||
for i in counts do
|
||||
i |> shouldBeGreaterThan 0
|
||||
|
@@ -12,7 +12,8 @@ module TestSurface =
|
||||
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
||||
|
||||
[<Test>]
|
||||
let ``Check version against remote`` () =
|
||||
// https://github.com/nunit/nunit3-vs-adapter/issues/876
|
||||
let CheckVersionAgainstRemote () =
|
||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins"
|
||||
|
||||
[<Test ; Explicit>]
|
||||
|
@@ -27,18 +27,19 @@
|
||||
<Compile Include="TestCataGenerator\TestGift.fs" />
|
||||
<Compile Include="TestCataGenerator\TestMyList.fs" />
|
||||
<Compile Include="TestCataGenerator\TestMyList2.fs" />
|
||||
<Compile Include="TestArgParser\TestArgParser.fs" />
|
||||
<Compile Include="TestRemoveOptions.fs"/>
|
||||
<Compile Include="TestSurface.fs"/>
|
||||
<None Include="../.github/workflows/dotnet.yaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.0.40"/>
|
||||
<PackageReference Include="ApiSurface" Version="4.1.5"/>
|
||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0"/>
|
||||
<PackageReference Include="NUnit" Version="4.2.2"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
1214
WoofWare.Myriad.Plugins/ArgParserGenerator.fs
Normal file
1214
WoofWare.Myriad.Plugins/ArgParserGenerator.fs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,8 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core.AstExtensions
|
||||
|
||||
type internal ParameterInfo =
|
||||
{
|
||||
@@ -64,13 +62,46 @@ type internal InterfaceType =
|
||||
type internal RecordType =
|
||||
{
|
||||
Name : Ident
|
||||
Fields : SynField seq
|
||||
Fields : SynField list
|
||||
/// Any additional members which are not record fields.
|
||||
Members : SynMemberDefns option
|
||||
XmlDoc : PreXmlDoc option
|
||||
Generics : SynTyparDecls option
|
||||
Accessibility : SynAccess option
|
||||
Attributes : SynAttribute list
|
||||
}
|
||||
|
||||
/// Parse from the AST.
|
||||
static member OfRecord (record : SynTypeDefn) : RecordType =
|
||||
let sci, sdr, smd, smdo =
|
||||
match record with
|
||||
| SynTypeDefn.SynTypeDefn (sci, sdr, smd, smdo, _, _) -> sci, sdr, smd, smdo
|
||||
|
||||
let synAccessOption, recordFields =
|
||||
match sdr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (sa, fields, _), _) -> sa, fields
|
||||
| _ -> failwith $"expected a record; got: %+A{record}"
|
||||
|
||||
match sci with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, typars, _, longId, doc, _, access, _) ->
|
||||
if access <> synAccessOption then
|
||||
failwith
|
||||
$"TODO what's happened, two different accessibility modifiers: %O{access} and %O{synAccessOption}"
|
||||
|
||||
match smdo with
|
||||
| Some v -> failwith $"TODO what's happened, got a synMemberDefn of %O{v}"
|
||||
| None -> ()
|
||||
|
||||
{
|
||||
Name = List.last longId
|
||||
Fields = recordFields
|
||||
Members = if smd.IsEmpty then None else Some smd
|
||||
XmlDoc = if doc.IsEmpty then None else Some doc
|
||||
Generics = typars
|
||||
Accessibility = synAccessOption
|
||||
Attributes = attrs |> List.collect (fun l -> l.Attributes)
|
||||
}
|
||||
|
||||
/// Anything that is part of an ADT.
|
||||
/// A record is a product of stuff; this type represents one of those stuffs.
|
||||
type internal AdtNode =
|
||||
@@ -98,118 +129,30 @@ type internal AdtProduct =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal AstHelper =
|
||||
|
||||
/// Given e.g. "byte", returns "System.Byte".
|
||||
let qualifyPrimitiveType (typeName : string) : LongIdent option =
|
||||
match typeName with
|
||||
| "float32"
|
||||
| "single" -> [ "System" ; "Single" ] |> Some
|
||||
| "float"
|
||||
| "double" -> [ "System" ; "Double" ] |> Some
|
||||
| "byte"
|
||||
| "uint8" -> [ "System" ; "Byte" ] |> Some
|
||||
| "sbyte"
|
||||
| "int8" -> [ "System" ; "SByte" ] |> Some
|
||||
| "int16" -> [ "System" ; "Int16" ] |> Some
|
||||
| "int"
|
||||
| "int32" -> [ "System" ; "Int32" ] |> Some
|
||||
| "int64" -> [ "System" ; "Int64" ] |> Some
|
||||
| "uint16" -> [ "System" ; "UInt16" ] |> Some
|
||||
| "uint"
|
||||
| "uint32" -> [ "System" ; "UInt32" ] |> Some
|
||||
| "uint64" -> [ "System" ; "UInt64" ] |> Some
|
||||
| "char" -> [ "System" ; "Char" ] |> Some
|
||||
| "decimal" -> [ "System" ; "Decimal" ] |> Some
|
||||
| _ -> None
|
||||
|> Option.map (List.map Ident.Create)
|
||||
let isEnum (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : bool =
|
||||
match repr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true
|
||||
| _ -> false
|
||||
|
||||
let instantiateRecord (fields : (RecordFieldName * SynExpr option) list) : SynExpr =
|
||||
let instantiateRecord (fields : (SynLongIdent * SynExpr) list) : SynExpr =
|
||||
let fields =
|
||||
fields
|
||||
|> List.map (fun (rfn, synExpr) -> SynExprRecordField (rfn, Some range0, synExpr, None))
|
||||
|> List.map (fun (rfn, synExpr) -> SynExprRecordField ((rfn, true), Some range0, Some synExpr, None))
|
||||
|
||||
SynExpr.Record (None, None, fields, range0)
|
||||
|
||||
let defineRecordType (record : RecordType) : SynTypeDefn =
|
||||
let repr =
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, Seq.toList record.Fields, range0), range0)
|
||||
|
||||
let name =
|
||||
SynComponentInfo.Create (
|
||||
[ record.Name ],
|
||||
?xmldoc = record.XmlDoc,
|
||||
?parameters = record.Generics,
|
||||
access = record.Accessibility
|
||||
)
|
||||
SynComponentInfo.create record.Name
|
||||
|> SynComponentInfo.setAccessibility record.Accessibility
|
||||
|> match record.XmlDoc with
|
||||
| None -> id
|
||||
| Some doc -> SynComponentInfo.withDocString doc
|
||||
|> SynComponentInfo.setGenerics record.Generics
|
||||
|
||||
let trivia : SynTypeDefnTrivia =
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = Some range0
|
||||
WithKeyword = Some range0
|
||||
}
|
||||
|
||||
SynTypeDefn (name, repr, defaultArg record.Members SynMemberDefns.Empty, None, range0, trivia)
|
||||
|
||||
let isOptionIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isUnitIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
| _ -> false
|
||||
|
||||
let isListIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider FSharpList or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isArrayIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when
|
||||
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|
||||
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
|
||||
->
|
||||
true
|
||||
| _ -> false
|
||||
|
||||
let isResponseIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Response" ]
|
||||
| [ "RestEase" ; "Response" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isMapIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Map" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isReadOnlyDictionaryIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IReadOnlyDictionary" ]
|
||||
| [ "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isDictionaryIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Dictionary" ]
|
||||
| [ "Generic" ; "Dictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "Dictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isIDictionaryIdent (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IDictionary" ]
|
||||
| [ "Generic" ; "IDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
|
||||
| _ -> false
|
||||
SynTypeDefnRepr.record (Seq.toList record.Fields)
|
||||
|> SynTypeDefn.create name
|
||||
|> SynTypeDefn.withMemberDefns (defaultArg record.Members SynMemberDefns.Empty)
|
||||
|
||||
let rec private extractOpensFromDecl (moduleDecls : SynModuleDecl list) : SynOpenDeclTarget list =
|
||||
moduleDecls
|
||||
@@ -231,12 +174,12 @@ module internal AstHelper =
|
||||
| SynType.Paren (inner, _) ->
|
||||
let result, _ = convertSigParam inner
|
||||
result, true
|
||||
| SynType.LongIdent ident ->
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
{
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.CreateLongIdent ident
|
||||
Type = SynType.createLongIdent ident
|
||||
},
|
||||
false
|
||||
| SynType.SignatureParameter (attrs, opt, id, usedType, _) ->
|
||||
@@ -254,7 +197,7 @@ module internal AstHelper =
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.Var (typar, range0)
|
||||
Type = SynType.var typar
|
||||
},
|
||||
false
|
||||
| _ -> failwithf "expected SignatureParameter, got: %+A" ty
|
||||
@@ -283,10 +226,6 @@ module internal AstHelper =
|
||||
}
|
||||
| _ -> failwithf "Didn't have alternating type-and-star in interface member definition: %+A" tupleType
|
||||
|
||||
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
||||
(ret, List.rev inputs)
|
||||
||> List.fold (fun ty input -> SynType.CreateFun (input, ty))
|
||||
|
||||
/// Returns the args (where these are tuple types if curried) in order, and the return type.
|
||||
let rec getType (ty : SynType) : (SynType * bool) list * SynType =
|
||||
match ty with
|
||||
@@ -299,7 +238,7 @@ module internal AstHelper =
|
||||
| SynType.Paren (argType, _) -> getType argType, true
|
||||
| _ -> getType argType, false
|
||||
|
||||
((toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret
|
||||
((SynType.toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret
|
||||
| _ -> [], ty
|
||||
|
||||
let private parseMember (slotSig : SynValSig) (flags : SynMemberFlags) : Choice<MemberInfo, PropertyInfo> =
|
||||
@@ -356,7 +295,7 @@ module internal AstHelper =
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident)
|
||||
Type = SynType.createLongIdent ident
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
@@ -368,7 +307,7 @@ module internal AstHelper =
|
||||
Attributes = []
|
||||
IsOptional = false
|
||||
Id = None
|
||||
Type = SynType.Var (typar, range0)
|
||||
Type = SynType.var typar
|
||||
}
|
||||
|> List.singleton
|
||||
}
|
||||
@@ -522,190 +461,3 @@ module internal AstHelper =
|
||||
}
|
||||
)
|
||||
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
||||
|
||||
[<AutoOpen>]
|
||||
module internal SynTypePatterns =
|
||||
let (|OptionType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isOptionIdent ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident when AstHelper.isUnitIdent ident -> Some ()
|
||||
| _ -> None
|
||||
|
||||
let (|ListType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|ArrayType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isArrayIdent ident ->
|
||||
Some innerType
|
||||
| SynType.Array (1, innerType, _) -> Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|RestEaseResponseType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isResponseIdent ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|DictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isDictionaryIdent ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isIDictionaryIdent ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
|
||||
AstHelper.isReadOnlyDictionaryIdent ident
|
||||
->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|MapType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when AstHelper.isMapIdent ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|BigInt|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "bigint" ]
|
||||
| [ "BigInteger" ]
|
||||
| [ "Numerics" ; "BigInteger" ]
|
||||
| [ "System" ; "Numerics" ; "BigInteger" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Returns the type, qualified as in e.g. `System.Boolean`.
|
||||
let (|PrimitiveType|_|) (fieldType : SynType) : LongIdent option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> AstHelper.qualifyPrimitiveType i.idText
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|String|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] ->
|
||||
[ "string" ]
|
||||
|> List.tryFind (fun s -> s = i.idText)
|
||||
|> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Byte|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Guid|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Guid" ]
|
||||
| [ "Guid" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Http" ; "HttpResponseMessage" ]
|
||||
| [ "HttpResponseMessage" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpContent|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Http" ; "HttpContent" ]
|
||||
| [ "HttpContent" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Stream|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "IO" ; "Stream" ]
|
||||
| [ "IO" ; "Stream" ]
|
||||
| [ "Stream" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|NumberType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "string" ; "float" ; "int" ; "bool" ] |> List.tryFind (fun s -> s = i.idText)
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateOnly|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateOnly" ]
|
||||
| [ "DateOnly" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateTime|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateTime" ]
|
||||
| [ "DateTime" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Uri|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Uri" ]
|
||||
| [ "Uri" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Task|_|) (fieldType : SynType) : SynType option =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "Task" ]
|
||||
| [ "Tasks" ; "Task" ]
|
||||
| [ "Threading" ; "Tasks" ; "Task" ]
|
||||
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
|
||||
match args with
|
||||
| [ arg ] -> Some arg
|
||||
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,6 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System.Net.Http
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal HttpClientGeneratorOutputSpec =
|
||||
{
|
||||
@@ -14,7 +11,6 @@ type internal HttpClientGeneratorOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal HttpClientGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type PathSpec =
|
||||
@@ -82,7 +78,7 @@ module internal HttpClientGenerator =
|
||||
let matchingAttrs =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "Get"
|
||||
| "GetAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Get"
|
||||
@@ -144,7 +140,7 @@ module internal HttpClientGenerator =
|
||||
let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "Header"
|
||||
| "RestEase.Header"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Header" ->
|
||||
@@ -158,7 +154,7 @@ module internal HttpClientGenerator =
|
||||
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
|
||||
attrs
|
||||
|> List.exists (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "AllowAnyStatusCode"
|
||||
| "AllowAnyStatusCodeAttribute"
|
||||
| "RestEase.AllowAnyStatusCode"
|
||||
@@ -174,35 +170,6 @@ module internal HttpClientGenerator =
|
||||
(info : MemberInfo)
|
||||
: SynMemberDefn
|
||||
=
|
||||
let valInfo =
|
||||
SynValInfo.SynValInfo (
|
||||
[
|
||||
[ SynArgInfo.Empty ]
|
||||
[
|
||||
for arg in info.Args do
|
||||
match arg.Id with
|
||||
| None -> yield SynArgInfo.CreateIdString (failwith "TODO: create an arg name")
|
||||
| Some id -> yield SynArgInfo.CreateId id
|
||||
]
|
||||
],
|
||||
SynArgInfo.Empty
|
||||
)
|
||||
|
||||
let valData =
|
||||
SynValData (
|
||||
Some
|
||||
{
|
||||
IsInstance = true
|
||||
IsDispatchSlot = false
|
||||
IsOverrideOrExplicitImpl = true
|
||||
IsFinal = false
|
||||
GetterOrSetterIsCompilerGenerated = false
|
||||
MemberKind = SynMemberKind.Member
|
||||
},
|
||||
valInfo,
|
||||
None
|
||||
)
|
||||
|
||||
let args =
|
||||
info.Args
|
||||
|> List.map (fun arg ->
|
||||
@@ -213,15 +180,13 @@ module internal HttpClientGenerator =
|
||||
|
||||
let argType =
|
||||
if arg.IsOptional then
|
||||
SynType.CreateApp (
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateString "option"),
|
||||
[ arg.Type ],
|
||||
isPostfix = true
|
||||
)
|
||||
SynType.appPostfix "option" arg.Type
|
||||
else
|
||||
arg.Type
|
||||
|
||||
argName, SynPat.CreateTyped (SynPat.CreateNamed argName, argType)
|
||||
// We'll be tupling these up anyway, so don't need the parens
|
||||
// around the type annotations.
|
||||
argName, SynPat.annotateTypeNoParen argType (SynPat.namedI argName)
|
||||
)
|
||||
|
||||
let cancellationTokenArg =
|
||||
@@ -229,26 +194,6 @@ module internal HttpClientGenerator =
|
||||
| None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}"
|
||||
| Some (arg, _) -> arg
|
||||
|
||||
let argPats =
|
||||
let args = args |> List.map snd
|
||||
|
||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|> SynPat.CreateParen
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
|
||||
let headPat =
|
||||
let thisIdent = if variableHeaders.IsEmpty then "_" else "this"
|
||||
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ Ident.Create thisIdent ; info.Identifier ],
|
||||
None,
|
||||
None,
|
||||
argPats,
|
||||
None,
|
||||
range0
|
||||
)
|
||||
|
||||
let requestUriTrailer =
|
||||
(info.UrlTemplate, info.Args)
|
||||
||> List.fold (fun template arg ->
|
||||
@@ -269,10 +214,10 @@ module internal HttpClientGenerator =
|
||||
template
|
||||
|> SynExpr.callMethodArg
|
||||
"Replace"
|
||||
(SynExpr.CreateParenedTuple
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.CreateConstString ("{" + substituteId + "}")
|
||||
SynExpr.callMethod "ToString" (SynExpr.CreateIdent varName)
|
||||
SynExpr.CreateConst ("{" + substituteId + "}")
|
||||
SynExpr.callMethod "ToString" (SynExpr.createIdent' varName)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||
)
|
||||
@@ -312,32 +257,25 @@ module internal HttpClientGenerator =
|
||||
| Some id -> id
|
||||
|
||||
let urlSeparator =
|
||||
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
||||
let questionMark =
|
||||
SynExpr.CreateConst (SynConst.Int32 63)
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "char")
|
||||
|> SynExpr.CreateParen
|
||||
let questionMark = SynExpr.CreateConst '?'
|
||||
|
||||
let containsQuestion =
|
||||
info.UrlTemplate
|
||||
|> SynExpr.callMethodArg "IndexOf" questionMark
|
||||
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst (SynConst.Int32 0))
|
||||
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst 0)
|
||||
|
||||
SynExpr.ifThenElse
|
||||
containsQuestion
|
||||
(SynExpr.CreateConst (SynConst.CreateString "?"))
|
||||
(SynExpr.CreateConst (SynConst.CreateString "&"))
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.ifThenElse containsQuestion (SynExpr.CreateConst "?") (SynExpr.CreateConst "&")
|
||||
|> SynExpr.paren
|
||||
|
||||
let prefix =
|
||||
SynExpr.CreateIdent firstValueId
|
||||
SynExpr.createIdent' firstValueId
|
||||
|> SynExpr.toString firstValue.Type
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConstString (firstKey + "=")))
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConst (firstKey + "=")))
|
||||
|
||||
(prefix, queryParams)
|
||||
||> List.fold (fun uri (paramKey, paramValue) ->
|
||||
@@ -346,16 +284,16 @@ module internal HttpClientGenerator =
|
||||
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
||||
| Some id -> id
|
||||
|
||||
SynExpr.toString paramValue.Type (SynExpr.CreateIdent paramValueId)
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.toString paramValue.Type (SynExpr.createIdent' paramValueId)
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConstString ("&" + paramKey + "=")))
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.plus (SynExpr.plus uri (SynExpr.CreateConst ("&" + paramKey + "=")))
|
||||
)
|
||||
|> SynExpr.plus requestUriTrailer
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|
||||
let requestUri =
|
||||
let uriIdent = SynExpr.createLongIdent [ "System" ; "Uri" ]
|
||||
@@ -364,45 +302,37 @@ module internal HttpClientGenerator =
|
||||
|
||||
let baseAddress =
|
||||
[
|
||||
SynMatchClause.Create (
|
||||
SynPat.CreateNull,
|
||||
None,
|
||||
match info.BaseAddress with
|
||||
| None ->
|
||||
[
|
||||
SynExpr.CreateApp (SynExpr.CreateIdentString "nameof", SynExpr.CreateParen baseAddress)
|
||||
SynExpr.CreateConstString
|
||||
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise")
|
||||
| Some expr -> SynExpr.CreateApp (uriIdent, expr)
|
||||
)
|
||||
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v")
|
||||
SynMatchClause.create
|
||||
SynPat.createNull
|
||||
(match info.BaseAddress with
|
||||
| None ->
|
||||
[
|
||||
SynExpr.applyFunction (SynExpr.createIdent "nameof") (SynExpr.paren baseAddress)
|
||||
SynExpr.CreateConst
|
||||
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
| Some expr -> SynExpr.applyFunction uriIdent expr)
|
||||
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
|
||||
]
|
||||
|> SynExpr.createMatch baseAddress
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.paren
|
||||
|
||||
SynExpr.App (
|
||||
ExprAtomicFlag.Atomic,
|
||||
false,
|
||||
uriIdent,
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
baseAddress
|
||||
SynExpr.CreateApp (
|
||||
uriIdent,
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
requestUriTrailer
|
||||
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
|
||||
]
|
||||
)
|
||||
],
|
||||
range0
|
||||
)
|
||||
[
|
||||
baseAddress
|
||||
SynExpr.applyFunction
|
||||
uriIdent
|
||||
(SynExpr.tuple
|
||||
[
|
||||
requestUriTrailer
|
||||
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
|
||||
])
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction uriIdent
|
||||
|
||||
let bodyParams =
|
||||
info.Args
|
||||
@@ -436,56 +366,43 @@ module internal HttpClientGenerator =
|
||||
let httpReqMessageConstructor =
|
||||
[
|
||||
SynExpr.equals
|
||||
(SynExpr.CreateIdentString "Method")
|
||||
(SynExpr.createIdent "Method")
|
||||
(SynExpr.createLongIdent
|
||||
[ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ])
|
||||
SynExpr.equals (SynExpr.CreateIdentString "RequestUri") (SynExpr.CreateIdentString "uri")
|
||||
SynExpr.equals (SynExpr.createIdent "RequestUri") (SynExpr.createIdent "uri")
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tupleNoParen
|
||||
|
||||
let returnExpr =
|
||||
match info.TaskReturnType with
|
||||
| HttpResponseMessage -> SynExpr.CreateIdentString "response"
|
||||
| String -> SynExpr.CreateIdentString "responseString"
|
||||
| Stream -> SynExpr.CreateIdentString "responseStream"
|
||||
| HttpResponseMessage -> SynExpr.createIdent "response"
|
||||
| String -> SynExpr.createIdent "responseString"
|
||||
| Stream -> SynExpr.createIdent "responseStream"
|
||||
| RestEaseResponseType contents ->
|
||||
let deserialiser =
|
||||
SynExpr.CreateLambda (
|
||||
[ SynPat.CreateConst SynConst.Unit ],
|
||||
SynExpr.CreateParen (
|
||||
JsonParseGenerator.parseNode
|
||||
None
|
||||
JsonParseGenerator.JsonParseOption.None
|
||||
contents
|
||||
(SynExpr.CreateIdentString "jsonNode")
|
||||
)
|
||||
)
|
||||
JsonParseGenerator.parseNode
|
||||
None
|
||||
JsonParseGenerator.JsonParseOption.None
|
||||
contents
|
||||
(SynExpr.createIdent "jsonNode")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.createThunk
|
||||
|
||||
// new RestEase.Response (content : string, response : HttpResponseMessage, deserialiser : unit -> 'T)
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent (SynLongIdent.Create [ "RestEase" ; "Response" ]),
|
||||
Some range0,
|
||||
[ SynType.Anon range0 ],
|
||||
[],
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
),
|
||||
SynExpr.CreateParenedTuple
|
||||
SynExpr.createNew
|
||||
(SynType.app' (SynType.createLongIdent' [ "RestEase" ; "Response" ]) [ SynType.Anon range0 ])
|
||||
(SynExpr.tupleNoParen
|
||||
[
|
||||
SynExpr.CreateIdentString "responseString"
|
||||
SynExpr.CreateIdentString "response"
|
||||
SynExpr.CreateParen deserialiser
|
||||
],
|
||||
range0
|
||||
)
|
||||
SynExpr.createIdent "responseString"
|
||||
SynExpr.createIdent "response"
|
||||
deserialiser
|
||||
])
|
||||
| retType ->
|
||||
JsonParseGenerator.parseNode
|
||||
None
|
||||
JsonParseGenerator.JsonParseOption.None
|
||||
retType
|
||||
(SynExpr.CreateIdentString "jsonNode")
|
||||
(SynExpr.createIdent "jsonNode")
|
||||
|
||||
let handleBodyParams =
|
||||
match bodyParam with
|
||||
@@ -498,72 +415,50 @@ module internal HttpClientGenerator =
|
||||
[
|
||||
Let (
|
||||
"queryParams",
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create
|
||||
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ]
|
||||
),
|
||||
SynExpr.CreateParen (SynExpr.CreateIdent bodyParamName),
|
||||
range0
|
||||
)
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent'
|
||||
[ "System" ; "Net" ; "Http" ; (bodyParamType : BodyParamMethods).ToString () ])
|
||||
(SynExpr.createIdent' bodyParamName)
|
||||
)
|
||||
Do (
|
||||
SynExpr.LongIdentSet (
|
||||
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||
SynExpr.CreateIdentString "queryParams",
|
||||
range0
|
||||
)
|
||||
SynExpr.assign
|
||||
(SynLongIdent.createS' [ "httpMessage" ; "Content" ])
|
||||
(SynExpr.createIdent "queryParams")
|
||||
)
|
||||
]
|
||||
| BodyParamMethods.HttpContent ->
|
||||
[
|
||||
Do (
|
||||
SynExpr.LongIdentSet (
|
||||
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||
SynExpr.CreateIdent bodyParamName,
|
||||
range0
|
||||
)
|
||||
SynExpr.assign
|
||||
(SynLongIdent.createS' [ "httpMessage" ; "Content" ])
|
||||
(SynExpr.createIdent' bodyParamName)
|
||||
)
|
||||
]
|
||||
| BodyParamMethods.Serialise ty ->
|
||||
[
|
||||
Let (
|
||||
"queryParams",
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "StringContent" ]
|
||||
),
|
||||
SynExpr.CreateParen (
|
||||
SynExpr.CreateIdent bodyParamName
|
||||
|> SynExpr.pipeThroughFunction (JsonSerializeGenerator.serializeNode ty)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"node"
|
||||
(SynExpr.ifThenElse
|
||||
(SynExpr.CreateApp (
|
||||
SynExpr.CreateIdentString "isNull",
|
||||
SynExpr.CreateIdentString "node"
|
||||
))
|
||||
(SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "node" ; "ToJsonString" ]
|
||||
),
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
))
|
||||
(SynExpr.CreateConst (SynConst.CreateString "null")))
|
||||
)
|
||||
),
|
||||
range0
|
||||
)
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "StringContent" ])
|
||||
(SynExpr.createIdent' bodyParamName
|
||||
|> SynExpr.pipeThroughFunction (fst (JsonSerializeGenerator.serializeNode ty))
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"node"
|
||||
(SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "isNull")
|
||||
(SynExpr.createIdent "node"))
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "node" ; "ToJsonString" ])
|
||||
(SynExpr.CreateConst ()))
|
||||
(SynExpr.CreateConst "null"))
|
||||
))
|
||||
)
|
||||
Do (
|
||||
SynExpr.LongIdentSet (
|
||||
SynLongIdent.Create [ "httpMessage" ; "Content" ],
|
||||
SynExpr.CreateIdent (Ident.Create "queryParams"),
|
||||
range0
|
||||
)
|
||||
SynExpr.assign
|
||||
(SynLongIdent.createS' [ "httpMessage" ; "Content" ])
|
||||
(SynExpr.createIdent "queryParams")
|
||||
)
|
||||
]
|
||||
|
||||
@@ -572,10 +467,9 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"responseString",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ],
|
||||
SynExpr.CreateIdentString "ct"
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStringAsync" ])
|
||||
(SynExpr.createIdent "ct")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -583,10 +477,9 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"responseStream",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ],
|
||||
SynExpr.CreateIdentString "ct"
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "response" ; "Content" ; "ReadAsStreamAsync" ])
|
||||
(SynExpr.createIdent "ct")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -594,47 +487,39 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"jsonNode",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent
|
||||
[ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.CreateIdentString "responseStream"
|
||||
SynExpr.equals
|
||||
(SynExpr.CreateIdentString "cancellationToken")
|
||||
(SynExpr.CreateIdentString "ct")
|
||||
]
|
||||
)
|
||||
SynExpr.createIdent "responseStream"
|
||||
SynExpr.equals (SynExpr.createIdent "cancellationToken") (SynExpr.createIdent "ct")
|
||||
])
|
||||
)
|
||||
)
|
||||
|
||||
let setVariableHeaders =
|
||||
variableHeaders
|
||||
|> List.map (fun (headerName, callToGetValue) ->
|
||||
Do (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
headerName
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent'
|
||||
[ Ident.Create "this" ; callToGetValue ; Ident.Create "ToString" ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
[
|
||||
headerName
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent'
|
||||
[ Ident.create "this" ; callToGetValue ; Ident.create "ToString" ])
|
||||
(SynExpr.CreateConst ())
|
||||
]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|
||||
|> Do
|
||||
)
|
||||
|
||||
let setConstantHeaders =
|
||||
constantHeaders
|
||||
|> List.map (fun (headerName, headerValue) ->
|
||||
Do (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ],
|
||||
SynExpr.CreateParenedTuple [ headerName ; headerValue ]
|
||||
)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|
||||
(SynExpr.tuple [ headerName ; headerValue ])
|
||||
|> Do
|
||||
)
|
||||
|
||||
[
|
||||
@@ -643,14 +528,9 @@ module internal HttpClientGenerator =
|
||||
yield
|
||||
Use (
|
||||
"httpMessage",
|
||||
SynExpr.New (
|
||||
false,
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ]
|
||||
),
|
||||
httpReqMessageConstructor,
|
||||
range0
|
||||
)
|
||||
SynExpr.createNew
|
||||
(SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpRequestMessage" ])
|
||||
httpReqMessageConstructor
|
||||
)
|
||||
|
||||
yield! handleBodyParams
|
||||
@@ -662,21 +542,18 @@ module internal HttpClientGenerator =
|
||||
LetBang (
|
||||
"response",
|
||||
SynExpr.awaitTask (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "client" ; "SendAsync" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
[ SynExpr.CreateIdentString "httpMessage" ; SynExpr.CreateIdentString "ct" ]
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "client" ; "SendAsync" ])
|
||||
(SynExpr.tuple [ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ])
|
||||
)
|
||||
)
|
||||
if info.EnsureSuccessHttpCode then
|
||||
yield
|
||||
Let (
|
||||
"response",
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "response" ; "EnsureSuccessStatusCode" ])
|
||||
(SynExpr.CreateConst ())
|
||||
)
|
||||
match info.TaskReturnType with
|
||||
| HttpResponseMessage -> ()
|
||||
@@ -691,30 +568,22 @@ module internal HttpClientGenerator =
|
||||
yield jsonNode
|
||||
]
|
||||
|> SynExpr.createCompExpr "async" returnExpr
|
||||
|> SynExpr.startAsTask (SynLongIdent.CreateFromLongIdent [ cancellationTokenArg ])
|
||||
|> SynExpr.startAsTask cancellationTokenArg
|
||||
|
||||
SynBinding.SynBinding (
|
||||
None,
|
||||
SynBindingKind.Normal,
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
valData,
|
||||
headPat,
|
||||
None,
|
||||
implementation,
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
SynBinding.triviaZero true
|
||||
)
|
||||
let thisIdent =
|
||||
if variableHeaders.IsEmpty then "_" else "this"
|
||||
|> Ident.create
|
||||
|
||||
let args = args |> List.map snd |> SynPat.tuple |> List.singleton
|
||||
|
||||
SynBinding.basic [ thisIdent ; info.Identifier ] args implementation
|
||||
|> SynBinding.withAccessibility info.Accessibility
|
||||
|> fun b -> SynMemberDefn.Member (b, range0)
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list =
|
||||
attrs
|
||||
|> List.choose (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "RestEase.Query"
|
||||
| "RestEase.QueryAttribute"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.Query"
|
||||
@@ -755,7 +624,7 @@ module internal HttpClientGenerator =
|
||||
let extractBasePath (attrs : SynAttribute list) : SynExpr option =
|
||||
attrs
|
||||
|> List.tryPick (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "BasePath"
|
||||
| "RestEase.BasePath"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BasePath"
|
||||
@@ -768,7 +637,7 @@ module internal HttpClientGenerator =
|
||||
let extractBaseAddress (attrs : SynAttribute list) : SynExpr option =
|
||||
attrs
|
||||
|> List.tryPick (fun attr ->
|
||||
match attr.TypeName.AsString with
|
||||
match SynLongIdent.toString attr.TypeName with
|
||||
| "BaseAddress"
|
||||
| "RestEase.BaseAddress"
|
||||
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
|
||||
@@ -816,7 +685,7 @@ module internal HttpClientGenerator =
|
||||
let headerInfo =
|
||||
match extractHeaderInformation pi.Attributes with
|
||||
| [ [ x ] ] -> x
|
||||
| [ xs ] ->
|
||||
| [ _ ] ->
|
||||
failwith
|
||||
"Expected exactly one Header parameter on the member, with exactly one arg; got one Header parameter with non-1-many args"
|
||||
| [] ->
|
||||
@@ -883,46 +752,13 @@ module internal HttpClientGenerator =
|
||||
let propertyMembers =
|
||||
properties
|
||||
|> List.map (fun (_, pi) ->
|
||||
SynMemberDefn.Member (
|
||||
SynBinding.SynBinding (
|
||||
pi.Accessibility,
|
||||
SynBindingKind.Normal,
|
||||
pi.IsInline,
|
||||
false,
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
SynValData.SynValData (
|
||||
Some
|
||||
{
|
||||
IsInstance = true
|
||||
IsDispatchSlot = false
|
||||
IsOverrideOrExplicitImpl = true
|
||||
IsFinal = false
|
||||
GetterOrSetterIsCompilerGenerated = false
|
||||
MemberKind = SynMemberKind.Member
|
||||
},
|
||||
SynValInfo.SynValInfo ([ [ SynArgInfo.Empty ] ; [] ], SynArgInfo.Empty),
|
||||
None
|
||||
),
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ Ident.Create "_" ; pi.Identifier ],
|
||||
[]
|
||||
),
|
||||
Some (SynBindingReturnInfo.Create pi.Type),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent' [ Ident.lowerFirstLetter pi.Identifier ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
),
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
{
|
||||
LeadingKeyword = SynLeadingKeyword.Member range0
|
||||
InlineKeyword = if pi.IsInline then Some range0 else None
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
),
|
||||
range0
|
||||
)
|
||||
SynExpr.createLongIdent' [ Ident.lowerFirstLetter pi.Identifier ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "_" ; pi.Identifier ] []
|
||||
|> SynBinding.withReturnAnnotation pi.Type
|
||||
|> SynBinding.setInline pi.IsInline
|
||||
|> SynBinding.withAccessibility pi.Accessibility
|
||||
|> SynMemberDefn.memberImplementation
|
||||
)
|
||||
|
||||
let members = propertyMembers @ nonPropertyMembers
|
||||
@@ -932,12 +768,12 @@ module internal HttpClientGenerator =
|
||||
"Extension methods"
|
||||
else
|
||||
"Module")
|
||||
|> sprintf " %s for constructing a REST client."
|
||||
|> PreXmlDoc.Create
|
||||
|> sprintf "%s for constructing a REST client."
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let interfaceImpl =
|
||||
SynExpr.ObjExpr (
|
||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name),
|
||||
SynType.createLongIdent interfaceType.Name,
|
||||
None,
|
||||
Some range0,
|
||||
[],
|
||||
@@ -950,54 +786,26 @@ module internal HttpClientGenerator =
|
||||
let headerArgs =
|
||||
properties
|
||||
|> List.map (fun (_, pi) ->
|
||||
SynPat.CreateTyped (
|
||||
SynPat.CreateNamed (Ident.lowerFirstLetter pi.Identifier),
|
||||
SynType.CreateFun (SynType.CreateLongIdent "unit", pi.Type)
|
||||
)
|
||||
|> SynPat.CreateParen
|
||||
SynPat.namedI (Ident.lowerFirstLetter pi.Identifier)
|
||||
|> SynPat.annotateType (SynType.funFromDomain (SynType.named "unit") pi.Type)
|
||||
)
|
||||
|
||||
let clientCreationArg =
|
||||
SynPat.CreateTyped (
|
||||
SynPat.CreateNamed (Ident.Create "client"),
|
||||
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "Net" ; "Http" ; "HttpClient" ])
|
||||
)
|
||||
|> SynPat.CreateParen
|
||||
SynPat.named "client"
|
||||
|> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Net" ; "Http" ; "HttpClient" ])
|
||||
|
||||
let xmlDoc =
|
||||
if properties.IsEmpty then
|
||||
" Create a REST client."
|
||||
"Create a REST client."
|
||||
else
|
||||
" Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties."
|
||||
|> PreXmlDoc.Create
|
||||
"Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties."
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let functionName = Ident.Create "client"
|
||||
let functionName = Ident.create "client"
|
||||
|
||||
let valData =
|
||||
let memberFlags =
|
||||
if spec.ExtensionMethods then
|
||||
{
|
||||
SynMemberFlags.IsInstance = false
|
||||
SynMemberFlags.IsDispatchSlot = false
|
||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||
SynMemberFlags.IsFinal = false
|
||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||
}
|
||||
|> Some
|
||||
else
|
||||
None
|
||||
let pattern = SynLongIdent.createS "make"
|
||||
|
||||
SynValData.SynValData (
|
||||
memberFlags,
|
||||
SynValInfo.SynValInfo ([ [ SynArgInfo.SynArgInfo ([], false, Some functionName) ] ], SynArgInfo.Empty),
|
||||
None
|
||||
)
|
||||
|
||||
let pattern = SynLongIdent.CreateString "make"
|
||||
|
||||
let returnInfo =
|
||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
|
||||
let returnInfo = SynType.createLongIdent interfaceType.Name
|
||||
|
||||
let nameWithoutLeadingI =
|
||||
List.last interfaceType.Name
|
||||
@@ -1011,74 +819,54 @@ module internal HttpClientGenerator =
|
||||
let createFunc =
|
||||
if spec.ExtensionMethods then
|
||||
let binding =
|
||||
SynBinding.basic
|
||||
(SynLongIdent.CreateString "make")
|
||||
(headerArgs @ [ clientCreationArg ])
|
||||
interfaceImpl
|
||||
SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.makeStaticMember
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
let componentInfo =
|
||||
SynComponentInfo.create (Ident.create nameWithoutLeadingI)
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for HTTP clients")
|
||||
|
||||
let containingType =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.Create (
|
||||
[ Ident.Create nameWithoutLeadingI ],
|
||||
xmldoc = PreXmlDoc.Create " Extension methods for HTTP clients"
|
||||
),
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||
[ mem ],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ binding ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
SynModuleDecl.createTypes [ containingType ]
|
||||
|
||||
else
|
||||
SynBinding.basic (SynLongIdent.CreateString "make") (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
||||
SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> List.singleton
|
||||
|> SynModuleDecl.CreateLet
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let moduleName : LongIdent =
|
||||
let moduleName =
|
||||
if spec.ExtensionMethods then
|
||||
[ Ident.Create (nameWithoutLeadingI + "HttpClientExtension") ]
|
||||
Ident.create (nameWithoutLeadingI + "HttpClientExtension")
|
||||
else
|
||||
[ Ident.Create nameWithoutLeadingI ]
|
||||
Ident.create nameWithoutLeadingI
|
||||
|
||||
let attribs =
|
||||
if spec.ExtensionMethods then
|
||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||
[ SynAttribute.autoOpen ]
|
||||
else
|
||||
[
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
]
|
||||
[ SynAttribute.compilationRepresentation ; SynAttribute.requireQualifiedAccess ]
|
||||
|
||||
let modInfo =
|
||||
SynComponentInfo.Create (
|
||||
moduleName,
|
||||
attributes = attribs,
|
||||
xmldoc = docString,
|
||||
access = interfaceType.Accessibility
|
||||
)
|
||||
SynComponentInfo.create moduleName
|
||||
|> SynComponentInfo.withDocString docString
|
||||
|> SynComponentInfo.addAttributes attribs
|
||||
|> SynComponentInfo.setAccessibility interfaceType.Accessibility
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
ns,
|
||||
decls =
|
||||
[
|
||||
for openStatement in opens do
|
||||
yield SynModuleDecl.CreateOpen openStatement
|
||||
yield SynModuleDecl.CreateNestedModule (modInfo, [ createFunc ])
|
||||
]
|
||||
)
|
||||
[
|
||||
for openStatement in opens do
|
||||
yield SynModuleDecl.openAny openStatement
|
||||
yield SynModuleDecl.nestedModule modInfo [ createFunc ]
|
||||
]
|
||||
|> SynModuleOrNamespace.createNamespace ns
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that provides an HTTP client for an interface type using RestEase annotations.
|
||||
[<MyriadGenerator("http-client")>]
|
||||
|
@@ -2,9 +2,7 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal GenerateMockOutputSpec =
|
||||
{
|
||||
@@ -14,7 +12,6 @@ type internal GenerateMockOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal InterfaceMockGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
let private getName (SynField (_, _, id, _, _, _, _, _, _)) =
|
||||
match id with
|
||||
@@ -46,72 +43,67 @@ module internal InterfaceMockGenerator =
|
||||
)
|
||||
|> Set.ofSeq
|
||||
|
||||
let failwithFun =
|
||||
let failwithFun (SynField (_, _, idOpt, _, _, _, _, _, _)) =
|
||||
let failString =
|
||||
match idOpt with
|
||||
| None -> SynExpr.CreateConst "Unimplemented mock function"
|
||||
| Some ident -> SynExpr.CreateConst $"Unimplemented mock function: %s{ident.idText}"
|
||||
|
||||
SynExpr.createLongIdent [ "System" ; "NotImplementedException" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConstString "Unimplemented mock function")
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise")
|
||||
|> SynExpr.applyTo failString
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
|> SynExpr.createLambda "_"
|
||||
|
||||
let constructorReturnType =
|
||||
match interfaceType.Generics with
|
||||
| None -> SynType.CreateLongIdent name
|
||||
| None -> SynType.createLongIdent' [ name ]
|
||||
| Some generics ->
|
||||
|
||||
let generics =
|
||||
generics.TyparDecls
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.App (
|
||||
SynType.CreateLongIdent name,
|
||||
Some range0,
|
||||
generics,
|
||||
List.replicate (generics.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
)
|
||||
SynType.app name generics
|
||||
|
||||
let constructorFields =
|
||||
let extras =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
let unitFun = SynExpr.createLambda "_" SynExpr.CreateUnit
|
||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
||||
|
||||
[
|
||||
(SynLongIdent.CreateFromLongIdent [ Ident.Create "Dispose" ], true), Some unitFun
|
||||
]
|
||||
[ SynLongIdent.createS "Dispose", unitFun ]
|
||||
else
|
||||
[]
|
||||
|
||||
let nonExtras =
|
||||
fields
|
||||
|> List.map (fun field -> (SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
||||
|> List.map (fun field -> SynLongIdent.createI (getName field), failwithFun field)
|
||||
|
||||
extras @ nonExtras
|
||||
|
||||
let constructor =
|
||||
SynBinding.basic
|
||||
(SynLongIdent.CreateString "Empty")
|
||||
[ Ident.create "Empty" ]
|
||||
(if interfaceType.Generics.IsNone then
|
||||
[]
|
||||
else
|
||||
[ SynPat.CreateConst SynConst.Unit ])
|
||||
[ SynPat.unit ])
|
||||
(AstHelper.instantiateRecord constructorFields)
|
||||
|> SynBinding.makeStaticMember
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.Create " An implementation where every method throws.")
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|
||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
||||
|> fun m -> SynMemberDefn.Member (m, range0)
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let fields =
|
||||
let extras =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
[
|
||||
SynField.Create (
|
||||
SynType.CreateFun (SynType.CreateUnit, SynType.CreateUnit),
|
||||
Ident.Create "Dispose",
|
||||
xmldoc = PreXmlDoc.Create " Implementation of IDisposable.Dispose"
|
||||
)
|
||||
]
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (Ident.create "Dispose")
|
||||
Type = SynType.funFromDomain SynType.unit SynType.unit
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (PreXmlDoc.create "Implementation of IDisposable.Dispose")
|
||||
|> List.singleton
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -121,47 +113,6 @@ module internal InterfaceMockGenerator =
|
||||
let members =
|
||||
interfaceType.Members
|
||||
|> List.map (fun memberInfo ->
|
||||
|
||||
let synValData =
|
||||
SynValData.SynValData (
|
||||
Some
|
||||
{
|
||||
IsInstance = true
|
||||
IsDispatchSlot = false
|
||||
IsOverrideOrExplicitImpl = true
|
||||
IsFinal = false
|
||||
GetterOrSetterIsCompilerGenerated = false
|
||||
MemberKind = SynMemberKind.Member
|
||||
},
|
||||
valInfo =
|
||||
SynValInfo.SynValInfo (
|
||||
curriedArgInfos =
|
||||
[
|
||||
yield
|
||||
[
|
||||
SynArgInfo.SynArgInfo (
|
||||
attributes = [],
|
||||
optional = false,
|
||||
ident = None
|
||||
)
|
||||
]
|
||||
yield!
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i arg ->
|
||||
arg.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynArgInfo.SynArgInfo ([], false, None)
|
||||
| _ -> SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
)
|
||||
],
|
||||
returnInfo =
|
||||
SynArgInfo.SynArgInfo (attributes = [], optional = false, ident = None)
|
||||
),
|
||||
thisIdOpt = None
|
||||
)
|
||||
|
||||
let headArgs =
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i tupledArgs ->
|
||||
@@ -169,27 +120,15 @@ module internal InterfaceMockGenerator =
|
||||
tupledArgs.Args
|
||||
|> List.mapi (fun j ty ->
|
||||
match ty.Type with
|
||||
| UnitType -> SynPat.Const (SynConst.Unit, range0)
|
||||
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}")
|
||||
| UnitType -> SynPat.unit
|
||||
| _ -> SynPat.named $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|
||||
match args with
|
||||
| [] -> failwith "somehow got no args at all"
|
||||
| [ arg ] -> arg
|
||||
| args ->
|
||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|> SynPat.CreateParen
|
||||
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
||||
)
|
||||
|
||||
let headPat =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ],
|
||||
None,
|
||||
None,
|
||||
SynArgPats.Pats headArgs,
|
||||
None,
|
||||
range0
|
||||
| args -> SynPat.tuple args
|
||||
|> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
|
||||
)
|
||||
|
||||
let body =
|
||||
@@ -199,10 +138,10 @@ module internal InterfaceMockGenerator =
|
||||
args.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynExpr.CreateConst SynConst.Unit
|
||||
| _ -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}"
|
||||
| UnitType -> SynExpr.CreateConst ()
|
||||
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
)
|
||||
|
||||
match tuples |> List.rev with
|
||||
@@ -210,38 +149,17 @@ module internal InterfaceMockGenerator =
|
||||
| last :: rest ->
|
||||
|
||||
(last, rest)
|
||||
||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail))
|
||||
||> List.fold SynExpr.applyTo
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent' [ Ident.Create "this" ; memberInfo.Identifier ]
|
||||
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
|
||||
)
|
||||
|
||||
SynMemberDefn.Member (
|
||||
SynBinding.SynBinding (
|
||||
None,
|
||||
SynBindingKind.Normal,
|
||||
false,
|
||||
false,
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
synValData,
|
||||
headPat,
|
||||
None,
|
||||
body,
|
||||
range0,
|
||||
DebugPointAtBinding.Yes range0,
|
||||
{
|
||||
LeadingKeyword = SynLeadingKeyword.Member range0
|
||||
InlineKeyword = None
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
),
|
||||
range0
|
||||
)
|
||||
SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body
|
||||
|> SynMemberDefn.memberImplementation
|
||||
)
|
||||
|
||||
let interfaceName =
|
||||
let baseName =
|
||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent interfaceType.Name)
|
||||
let baseName = SynType.createLongIdent interfaceType.Name
|
||||
|
||||
match interfaceType.Generics with
|
||||
| None -> baseName
|
||||
@@ -251,17 +169,9 @@ module internal InterfaceMockGenerator =
|
||||
| SynTyparDecls.PostfixList (decls, _, _) -> decls
|
||||
| SynTyparDecls.PrefixList (decls, _) -> decls
|
||||
| SynTyparDecls.SinglePrefix (decl, _) -> [ decl ]
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.App (
|
||||
baseName,
|
||||
Some range0,
|
||||
generics,
|
||||
List.replicate (generics.Length - 1) range0,
|
||||
Some range0,
|
||||
false,
|
||||
range0
|
||||
)
|
||||
SynType.app' baseName generics
|
||||
|
||||
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
|
||||
|
||||
@@ -279,18 +189,15 @@ module internal InterfaceMockGenerator =
|
||||
|> Seq.map (fun inheritance ->
|
||||
match inheritance with
|
||||
| KnownInheritance.IDisposable ->
|
||||
let binding =
|
||||
SynBinding.basic
|
||||
(SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; Ident.Create "Dispose" ])
|
||||
[ SynPat.CreateConst SynConst.Unit ]
|
||||
(SynExpr.CreateApp (SynExpr.createLongIdent [ "this" ; "Dispose" ], SynExpr.CreateUnit))
|
||||
|> SynBinding.withReturnAnnotation (SynType.Unit ())
|
||||
|> SynBinding.makeInstanceMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
let mem =
|
||||
SynExpr.createLongIdent [ "this" ; "Dispose" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "this" ; Ident.create "Dispose" ] [ SynPat.unit ]
|
||||
|> SynBinding.withReturnAnnotation SynType.unit
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
SynMemberDefn.Interface (
|
||||
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "IDisposable" ]),
|
||||
SynType.createLongIdent' [ "System" ; "IDisposable" ],
|
||||
Some range0,
|
||||
Some [ mem ],
|
||||
range0
|
||||
@@ -300,12 +207,13 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let record =
|
||||
{
|
||||
Name = Ident.Create name
|
||||
Name = Ident.create name
|
||||
Fields = fields
|
||||
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
|
||||
XmlDoc = Some xmlDoc
|
||||
Generics = interfaceType.Generics
|
||||
Accessibility = Some access
|
||||
Attributes = []
|
||||
}
|
||||
|
||||
let typeDecl = AstHelper.defineRecordType record
|
||||
@@ -314,7 +222,7 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let private buildType (x : ParameterInfo) : SynType =
|
||||
if x.IsOptional then
|
||||
SynType.App (SynType.CreateLongIdent "option", Some range0, [ x.Type ], [], Some range0, false, range0)
|
||||
SynType.app "option" [ x.Type ]
|
||||
else
|
||||
x.Type
|
||||
|
||||
@@ -331,19 +239,15 @@ module internal InterfaceMockGenerator =
|
||||
let constructMember (mem : MemberInfo) : SynField =
|
||||
let inputType = mem.Args |> List.map constructMemberSinglePlace
|
||||
|
||||
let funcType = AstHelper.toFun inputType mem.ReturnType
|
||||
let funcType = SynType.toFun inputType mem.ReturnType
|
||||
|
||||
SynField.SynField (
|
||||
[],
|
||||
false,
|
||||
Some mem.Identifier,
|
||||
funcType,
|
||||
false,
|
||||
mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty,
|
||||
None,
|
||||
range0,
|
||||
SynFieldTrivia.Zero
|
||||
)
|
||||
{
|
||||
Type = funcType
|
||||
Attrs = []
|
||||
Ident = Some mem.Identifier
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
|
||||
|
||||
let createRecord
|
||||
(namespaceId : LongIdent)
|
||||
@@ -353,7 +257,7 @@ module internal InterfaceMockGenerator =
|
||||
=
|
||||
let interfaceType = AstHelper.parseInterface interfaceType
|
||||
let fields = interfaceType.Members |> List.map constructMember
|
||||
let docString = PreXmlDoc.Create " Mock record type for an interface"
|
||||
let docString = PreXmlDoc.create "Mock record type for an interface"
|
||||
|
||||
let name =
|
||||
List.last interfaceType.Name
|
||||
@@ -367,10 +271,10 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let typeDecl = createType spec name interfaceType docString fields
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
namespaceId,
|
||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
||||
)
|
||||
[ yield! opens |> List.map SynModuleDecl.openAny ; yield typeDecl ]
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that creates a record which implements the given interface,
|
||||
/// but with every field mocked out.
|
||||
|
@@ -4,8 +4,6 @@ open System
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal JsonParseOutputSpec =
|
||||
{
|
||||
@@ -15,7 +13,6 @@ type internal JsonParseOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal JsonParseGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
type JsonParseOption =
|
||||
{
|
||||
@@ -27,33 +24,26 @@ module internal JsonParseGenerator =
|
||||
JsonNumberHandlingArg = None
|
||||
}
|
||||
|
||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ()) | v -> v)
|
||||
/// (match {indexed} with | null -> raise (System.Collections.Generic.KeyNotFoundException ({propertyName} not found)) | v -> v)
|
||||
let assertNotNull (propertyName : SynExpr) (indexed : SynExpr) =
|
||||
let raiseExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateIdentString "sprintf",
|
||||
SynExpr.CreateConstString "Required key '%s' not found on JSON object"
|
||||
),
|
||||
SynExpr.CreateParen propertyName
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "Required key '%s' not found on JSON object")
|
||||
|> SynExpr.applyTo (SynExpr.paren propertyName)
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
|
||||
)
|
||||
SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "raise")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
|
||||
SynExpr.CreateMatch (
|
||||
indexed,
|
||||
[
|
||||
SynMatchClause.Create (SynPat.CreateNull, None, raiseExpr)
|
||||
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, SynExpr.CreateIdentString "v")
|
||||
]
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
[
|
||||
SynMatchClause.create SynPat.createNull raiseExpr
|
||||
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
|
||||
]
|
||||
|> SynExpr.createMatch indexed
|
||||
|> SynExpr.paren
|
||||
|
||||
/// {node}.AsValue().GetValue<{typeName}> ()
|
||||
/// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`.
|
||||
@@ -81,10 +71,8 @@ module internal JsonParseGenerator =
|
||||
|
||||
/// {type}.jsonParse {node}
|
||||
let typeJsonParse (typeName : LongIdent) (node : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (typeName @ [ Ident.Create "jsonParse" ])),
|
||||
node
|
||||
)
|
||||
node
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ Ident.create "jsonParse" ]))
|
||||
|
||||
/// collectionType is e.g. "List"; we'll be calling `ofSeq` on it.
|
||||
/// body is the body of a lambda which takes a parameter `elt`.
|
||||
@@ -103,51 +91,24 @@ module internal JsonParseGenerator =
|
||||
| Some propertyName -> assertNotNull propertyName node
|
||||
|> SynExpr.callMethod "AsArray"
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
SynExpr.createLambda "elt" body
|
||||
)
|
||||
SynExpr.applyFunction (SynExpr.createLongIdent [ "Seq" ; "map" ]) (SynExpr.createLambda "elt" body)
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ collectionType ; "ofSeq" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ collectionType ; "ofSeq" ])
|
||||
|
||||
/// match {node} with | null -> None | v -> {body} |> Some
|
||||
/// Use the variable `v` to get access to the `Some`.
|
||||
let createParseLineOption (node : SynExpr) (body : SynExpr) : SynExpr =
|
||||
let body = SynExpr.pipeThroughFunction (SynExpr.CreateIdentString "Some") body
|
||||
|
||||
SynExpr.CreateMatch (
|
||||
node,
|
||||
[
|
||||
SynMatchClause.Create (SynPat.CreateNull, None, SynExpr.CreateIdent (Ident.Create "None"))
|
||||
SynMatchClause.Create (SynPat.CreateNamed (Ident.Create "v"), None, body)
|
||||
]
|
||||
)
|
||||
|
||||
/// Given e.g. "float", returns "System.Double.Parse"
|
||||
let parseFunction (typeName : string) : LongIdent =
|
||||
let qualified =
|
||||
match AstHelper.qualifyPrimitiveType 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.
|
||||
let dictionaryMapper (key : SynExpr -> SynExpr) (value : SynExpr -> SynExpr) : SynExpr =
|
||||
let keyArg = SynExpr.createLongIdent [ "kvp" ; "Key" ] |> SynExpr.CreateParen
|
||||
let keyArg = SynExpr.createLongIdent [ "kvp" ; "Key" ] |> SynExpr.paren
|
||||
|
||||
let valueArg = SynExpr.createLongIdent [ "kvp" ; "Value" ] |> SynExpr.CreateParen
|
||||
let valueArg = SynExpr.createLongIdent [ "kvp" ; "Value" ] |> SynExpr.paren
|
||||
|
||||
SynExpr.CreateTuple [ SynExpr.CreateIdentString "key" ; SynExpr.CreateIdentString "value" ]
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "value"), expr = value valueArg)
|
||||
]
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "key"), expr = key keyArg)
|
||||
]
|
||||
// No need to paren here, we're on the LHS of a `let`
|
||||
SynExpr.tupleNoParen [ SynExpr.createIdent "key" ; SynExpr.createIdent "value" ]
|
||||
|> SynExpr.createLet [ SynBinding.basic [ Ident.create "value" ] [] (value valueArg) ]
|
||||
|> SynExpr.createLet [ SynBinding.basic [ Ident.create "key" ] [] (key keyArg) ]
|
||||
|> SynExpr.createLambda "kvp"
|
||||
|
||||
/// A conforming JSON object has only strings as keys. But it would be reasonable to allow the user
|
||||
@@ -157,11 +118,52 @@ module internal JsonParseGenerator =
|
||||
| String -> key
|
||||
| Uri ->
|
||||
key
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ])
|
||||
| _ ->
|
||||
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".
|
||||
@@ -190,115 +192,93 @@ 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.CreateIdentString "exc",
|
||||
range0,
|
||||
SynLongIdent.CreateString "Message",
|
||||
range0
|
||||
)
|
||||
|> SynExpr.callMethodArg
|
||||
"Contains"
|
||||
(SynExpr.CreateConst (SynConst.CreateString "cannot be converted to"))
|
||||
|
||||
let handler =
|
||||
asValueGetValue propertyName "string" node
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent' (parseFunction typeName))
|
||||
|> SynExpr.ifThenElse
|
||||
(SynExpr.equals
|
||||
option
|
||||
(SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create
|
||||
[
|
||||
"System"
|
||||
"Text"
|
||||
"Json"
|
||||
"Serialization"
|
||||
"JsonNumberHandling"
|
||||
"AllowReadingFromString"
|
||||
]
|
||||
)))
|
||||
SynExpr.reraise
|
||||
|> SynExpr.ifThenElse cond SynExpr.reraise
|
||||
|
||||
basic
|
||||
|> SynExpr.pipeThroughTryWith
|
||||
(SynPat.IsInst (
|
||||
SynType.LongIdent (SynLongIdent.Create [ "System" ; "InvalidOperationException" ]),
|
||||
range0
|
||||
))
|
||||
handler
|
||||
| DateTimeOffset ->
|
||||
node
|
||||
|> asValueGetValue propertyName "string"
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTimeOffset" ; "Parse" ])
|
||||
| NumberType typeName -> parseNumberType options propertyName node typeName
|
||||
| PrimitiveType typeName -> asValueGetValueIdent propertyName typeName node
|
||||
| OptionType ty ->
|
||||
parseNode None options ty (SynExpr.CreateIdentString "v")
|
||||
|> createParseLineOption node
|
||||
let someClause =
|
||||
parseNode None options ty (SynExpr.createIdent "v")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynMatchClause.create (SynPat.named "v")
|
||||
|
||||
[
|
||||
SynMatchClause.create SynPat.createNull (SynExpr.createIdent "None")
|
||||
someClause
|
||||
]
|
||||
|> SynExpr.createMatch node
|
||||
| NullableType ty ->
|
||||
let someClause =
|
||||
parseNode None options ty (SynExpr.createIdent "v")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Nullable" ])
|
||||
|> SynMatchClause.create (SynPat.named "v")
|
||||
|
||||
[
|
||||
SynMatchClause.create
|
||||
SynPat.createNull
|
||||
(SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Nullable" ]) (SynExpr.CreateConst ()))
|
||||
someClause
|
||||
]
|
||||
|> SynExpr.createMatch node
|
||||
| ListType ty ->
|
||||
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt"))
|
||||
parseNode None options ty (SynExpr.createIdent "elt")
|
||||
|> asArrayMapped propertyName "List" node
|
||||
| ArrayType ty ->
|
||||
parseNode None options ty (SynExpr.CreateLongIdent (SynLongIdent.CreateString "elt"))
|
||||
parseNode None options ty (SynExpr.createIdent "elt")
|
||||
|> asArrayMapped propertyName "Array" node
|
||||
| IDictionaryType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "dict" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "dict")
|
||||
| DictionaryType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ]
|
||||
)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "KeyValuePair" ])
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "Dictionary" ])
|
||||
SynExpr.createLongIdent [ "System" ; "Collections" ; "Generic" ; "Dictionary" ]
|
||||
)
|
||||
| IReadOnlyDictionaryType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "readOnlyDict" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "readOnlyDict")
|
||||
| MapType (keyType, valueType) ->
|
||||
node
|
||||
|> asObject propertyName
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "map" ]),
|
||||
dictionaryMapper (parseKeyString keyType) (parseNode None options valueType)
|
||||
)
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Seq" ; "map" ])
|
||||
(dictionaryMapper (parseKeyString keyType) (parseNode None options valueType))
|
||||
)
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Map" ; "ofSeq" ]))
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Map" ; "ofSeq" ])
|
||||
| BigInt ->
|
||||
node
|
||||
|> SynExpr.callMethod "ToJsonString"
|
||||
|> SynExpr.CreateParen
|
||||
|> 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 =
|
||||
@@ -314,7 +294,7 @@ module internal JsonParseGenerator =
|
||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||
/// The result of this function is the body of a let-binding (not including the LHS of that let-binding).
|
||||
let createParseRhs (options : JsonParseOption) (propertyName : SynExpr) (fieldType : SynType) : SynExpr =
|
||||
let objectToParse = SynExpr.CreateIdentString "node" |> SynExpr.index propertyName
|
||||
let objectToParse = SynExpr.createIdent "node" |> SynExpr.index propertyName
|
||||
parseNode (Some propertyName) options fieldType objectToParse
|
||||
|
||||
let isJsonNumberHandling (literal : LongIdent) : bool =
|
||||
@@ -331,54 +311,47 @@ module internal JsonParseGenerator =
|
||||
/// That is, we give you access to a `JsonNode` called `node`,
|
||||
/// and you must return a `typeName`.
|
||||
let scaffolding (spec : JsonParseOutputSpec) (typeName : LongIdent) (functionBody : SynExpr) : SynModuleDecl =
|
||||
let xmlDoc = PreXmlDoc.Create " Parse from a JSON node."
|
||||
let xmlDoc = PreXmlDoc.create "Parse from a JSON node."
|
||||
|
||||
let returnInfo = SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName)
|
||||
let returnInfo = SynType.createLongIdent typeName
|
||||
|
||||
let inputArg = Ident.Create "node"
|
||||
let functionName = Ident.Create "jsonParse"
|
||||
let inputArg = "node"
|
||||
let functionName = Ident.create "jsonParse"
|
||||
|
||||
let arg =
|
||||
SynPat.CreateNamed inputArg
|
||||
|> SynPat.annotateType (
|
||||
SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
)
|
||||
SynPat.named inputArg
|
||||
|> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|
||||
if spec.ExtensionMethods then
|
||||
let binding =
|
||||
SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ arg ] functionBody
|
||||
|> SynBinding.makeStaticMember
|
||||
SynBinding.basic [ functionName ] [ arg ] functionBody
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
let componentInfo =
|
||||
SynComponentInfo.createLong typeName
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
||||
|
||||
let containingType =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"),
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||
[ mem ],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ binding ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
else
|
||||
SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ arg ] functionBody
|
||||
SynBinding.basic [ functionName ] [ arg ] functionBody
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> List.singleton
|
||||
|> SynModuleDecl.CreateLet
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let getParseOptions (fieldAttrs : SynAttribute list) =
|
||||
(JsonParseOption.None, fieldAttrs)
|
||||
||> List.fold (fun options attr ->
|
||||
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
|
||||
if
|
||||
(SynLongIdent.toString attr.TypeName)
|
||||
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
|
||||
then
|
||||
let qualifiedEnumValue =
|
||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
||||
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
|
||||
@@ -401,15 +374,15 @@ module internal JsonParseGenerator =
|
||||
options
|
||||
)
|
||||
|
||||
|
||||
let createRecordMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynFieldData<Ident> list) =
|
||||
let createRecordMaker (spec : JsonParseOutputSpec) (fields : SynFieldData<Ident> list) =
|
||||
let assignments =
|
||||
fields
|
||||
|> List.mapi (fun i fieldData ->
|
||||
let propertyNameAttr =
|
||||
fieldData.Attrs
|
||||
|> List.tryFind (fun attr ->
|
||||
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||
(SynLongIdent.toString attr.TypeName)
|
||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||
)
|
||||
|
||||
let options = getParseOptions fieldData.Attrs
|
||||
@@ -425,19 +398,16 @@ module internal JsonParseGenerator =
|
||||
if fieldData.Ident.idText.Length > 1 then
|
||||
sb.Append (fieldData.Ident.idText.Substring 1) |> ignore<StringBuilder>
|
||||
|
||||
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||
sb.ToString () |> SynExpr.CreateConst
|
||||
| Some name -> name.ArgExpr
|
||||
|
||||
createParseRhs options propertyName fieldData.Type
|
||||
|> SynBinding.basic (SynLongIdent.CreateString $"arg_%i{i}") []
|
||||
|> SynBinding.basic [ Ident.create $"arg_%i{i}" ] []
|
||||
)
|
||||
|
||||
let finalConstruction =
|
||||
fields
|
||||
|> List.mapi (fun i fieldData ->
|
||||
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true),
|
||||
Some (SynExpr.CreateLongIdent (SynLongIdent.CreateString $"arg_%i{i}"))
|
||||
)
|
||||
|> List.mapi (fun i fieldData -> SynLongIdent.createI fieldData.Ident, SynExpr.createIdent $"arg_%i{i}")
|
||||
|> AstHelper.instantiateRecord
|
||||
|
||||
(finalConstruction, assignments)
|
||||
@@ -458,19 +428,19 @@ module internal JsonParseGenerator =
|
||||
let options = getParseOptions field.Attrs
|
||||
createParseRhs options propertyName field.Type
|
||||
)
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ]))
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.index (SynExpr.CreateConstString "data") (SynExpr.CreateIdentString "node")
|
||||
|> assertNotNull (SynExpr.CreateConstString "data")
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "node") []
|
||||
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|
||||
|> assertNotNull (SynExpr.CreateConst "data")
|
||||
|> SynBinding.basic [ Ident.create "node" ] []
|
||||
]
|
||||
|
||||
match propertyName with
|
||||
| SynExpr.Const (synConst, _) ->
|
||||
SynMatchClause.SynMatchClause (
|
||||
SynPat.CreateConst synConst,
|
||||
SynPat.createConst synConst,
|
||||
None,
|
||||
body,
|
||||
range0,
|
||||
@@ -481,30 +451,19 @@ module internal JsonParseGenerator =
|
||||
}
|
||||
)
|
||||
| _ ->
|
||||
SynMatchClause.SynMatchClause (
|
||||
SynPat.CreateNamed (Ident.Create "x"),
|
||||
Some (SynExpr.equals (SynExpr.CreateIdentString "x") propertyName),
|
||||
body,
|
||||
range0,
|
||||
DebugPointAtTarget.Yes,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
BarRange = Some range0
|
||||
}
|
||||
)
|
||||
SynMatchClause.create (SynPat.named "x") body
|
||||
|> SynMatchClause.withWhere (SynExpr.equals (SynExpr.createIdent "x") propertyName)
|
||||
)
|
||||
|> fun l ->
|
||||
l
|
||||
@ [
|
||||
let fail =
|
||||
SynExpr.plus
|
||||
(SynExpr.CreateConstString "Unrecognised 'type' field value: ")
|
||||
(SynExpr.CreateIdentString "v")
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.applyFunction (SynExpr.CreateIdentString "failwith")
|
||||
SynExpr.plus (SynExpr.CreateConst "Unrecognised 'type' field value: ") (SynExpr.createIdent "v")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
SynMatchClause.SynMatchClause (
|
||||
SynPat.CreateNamed (Ident.Create "v"),
|
||||
SynPat.named "v",
|
||||
None,
|
||||
fail,
|
||||
range0,
|
||||
@@ -515,50 +474,87 @@ module internal JsonParseGenerator =
|
||||
}
|
||||
)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.CreateIdentString "ty")
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "ty")
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
let property = SynExpr.CreateConstString "type"
|
||||
let property = SynExpr.CreateConst "type"
|
||||
|
||||
SynExpr.CreateIdentString "node"
|
||||
SynExpr.createIdent "node"
|
||||
|> SynExpr.index property
|
||||
|> assertNotNull property
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLambda
|
||||
"v"
|
||||
(SynExpr.callGenericMethod "GetValue" [ Ident.Create "string" ] (SynExpr.CreateIdentString "v"))
|
||||
(SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v"))
|
||||
)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "ty") []
|
||||
|> SynBinding.basic [ Ident.create "ty" ] []
|
||||
]
|
||||
(*
|
||||
let ty =
|
||||
match node.["type"] with
|
||||
| null -> raise (System.Collections.Generic.KeyNotFoundException ())
|
||||
| v -> v.GetValue<string> ()
|
||||
match ty with
|
||||
| "emptyCase" -> FirstDu.EmptyCase
|
||||
| "case1" ->
|
||||
FirstDu.Case1
|
||||
| "case2" -> FirstDu.Case2
|
||||
| _ -> failwithf "Unrecognised case name: %s" ty
|
||||
*)
|
||||
|
||||
let createEnumMaker
|
||||
(spec : JsonParseOutputSpec)
|
||||
(typeName : LongIdent)
|
||||
(fields : (Ident * SynExpr) list)
|
||||
: SynExpr
|
||||
=
|
||||
let numberKind =
|
||||
[ "System" ; "Text" ; "Json" ; "JsonValueKind" ; "Number" ]
|
||||
|> List.map Ident.create
|
||||
|
||||
let stringKind =
|
||||
[ "System" ; "Text" ; "Json" ; "JsonValueKind" ; "String" ]
|
||||
|> List.map Ident.create
|
||||
|
||||
let fail =
|
||||
SynExpr.plus
|
||||
(SynExpr.CreateConst "Unrecognised kind for enum of type: ")
|
||||
(SynExpr.CreateConst (typeName |> List.map _.idText |> String.concat "."))
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
let failString =
|
||||
SynExpr.plus (SynExpr.CreateConst "Unrecognised value for enum: %i") (SynExpr.createIdent "v")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
let parseString =
|
||||
fields
|
||||
|> List.map (fun (ident, _) ->
|
||||
SynMatchClause.create
|
||||
(SynPat.createConst (
|
||||
SynConst.String (ident.idText.ToLowerInvariant (), SynStringKind.Regular, range0)
|
||||
))
|
||||
(SynExpr.createLongIdent' (typeName @ [ ident ]))
|
||||
)
|
||||
|> fun l -> l @ [ SynMatchClause.create (SynPat.named "v") failString ]
|
||||
|> SynExpr.createMatch (
|
||||
asValueGetValue None "string" (SynExpr.createIdent "node")
|
||||
|> SynExpr.callMethod "ToLowerInvariant"
|
||||
)
|
||||
|
||||
[
|
||||
SynMatchClause.create
|
||||
(SynPat.identWithArgs numberKind (SynArgPats.create []))
|
||||
(asValueGetValue None "int" (SynExpr.createIdent "node")
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.typeApp [ SynType.createLongIdent typeName ] (SynExpr.createIdent "enum")
|
||||
))
|
||||
SynMatchClause.create (SynPat.identWithArgs stringKind (SynArgPats.create [])) parseString
|
||||
SynMatchClause.create (SynPat.named "_") fail
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.callMethod "GetValueKind" (SynExpr.createIdent "node"))
|
||||
|
||||
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
|
||||
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 =
|
||||
if spec.ExtensionMethods then
|
||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||
[ SynAttribute.autoOpen ]
|
||||
else
|
||||
[
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
]
|
||||
[ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
|
||||
|
||||
let xmlDoc =
|
||||
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||
@@ -569,8 +565,8 @@ module internal JsonParseGenerator =
|
||||
else
|
||||
"methods"
|
||||
|
||||
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.Create
|
||||
$"Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let moduleName =
|
||||
if spec.ExtensionMethods then
|
||||
@@ -581,39 +577,47 @@ module internal JsonParseGenerator =
|
||||
List.last ident
|
||||
|> fun i -> i.idText
|
||||
|> fun s -> s + "JsonParseExtension"
|
||||
|> Ident.Create
|
||||
|> Ident.create
|
||||
|
||||
List.take (List.length ident - 1) ident @ [ expanded ]
|
||||
else
|
||||
ident
|
||||
|
||||
let info =
|
||||
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||
SynComponentInfo.createLong moduleName
|
||||
|> SynComponentInfo.withDocString xmlDoc
|
||||
|> SynComponentInfo.setAccessibility access
|
||||
|> SynComponentInfo.addAttributes attributes
|
||||
|
||||
let decl =
|
||||
match synTypeDefnRepr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) ->
|
||||
let fields = fields |> List.map SynField.extractWithIdent
|
||||
createRecordMaker spec ident fields
|
||||
fields |> List.map SynField.extractWithIdent |> createRecordMaker spec
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) ->
|
||||
let optionGet (i : Ident option) =
|
||||
match i with
|
||||
| None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field."
|
||||
| Some i -> i
|
||||
|
||||
let cases =
|
||||
cases
|
||||
|> List.map SynUnionCase.extract
|
||||
|> List.map (UnionCase.mapIdentFields optionGet)
|
||||
|
||||
createUnionMaker spec ident cases
|
||||
cases
|
||||
|> List.map SynUnionCase.extract
|
||||
|> List.map (UnionCase.mapIdentFields optionGet)
|
||||
|> createUnionMaker spec ident
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum (cases, _range), _) ->
|
||||
cases
|
||||
|> List.map (fun c ->
|
||||
match c with
|
||||
| SynEnumCase.SynEnumCase (_, SynIdent.SynIdent (ident, _), value, _, _, _) -> ident, value
|
||||
)
|
||||
|> createEnumMaker spec ident
|
||||
| _ -> failwithf "Not a record or union type"
|
||||
|
||||
let mdl =
|
||||
[ scaffolding spec ident decl ]
|
||||
|> fun d -> SynModuleDecl.CreateNestedModule (info, d)
|
||||
[ scaffolding spec ident decl ]
|
||||
|> SynModuleDecl.nestedModule info
|
||||
|> List.singleton
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||
/// containing a JSON parse function.
|
||||
@@ -627,20 +631,21 @@ type JsonParseGenerator () =
|
||||
let ast, _ =
|
||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||
|
||||
let recordsAndUnions =
|
||||
let relevantTypes =
|
||||
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
|
||||
elif AstHelper.isEnum defn then Some defn
|
||||
else None
|
||||
)
|
||||
|> fun defns -> name, defns
|
||||
)
|
||||
|
||||
let namespaceAndTypes =
|
||||
recordsAndUnions
|
||||
relevantTypes
|
||||
|> List.choose (fun (ns, types) ->
|
||||
types
|
||||
|> List.choose (fun typeDef ->
|
||||
|
@@ -3,9 +3,6 @@ namespace WoofWare.Myriad.Plugins
|
||||
open System
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
type internal JsonSerializeOutputSpec =
|
||||
{
|
||||
@@ -15,63 +12,72 @@ type internal JsonSerializeOutputSpec =
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal JsonSerializeGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
|
||||
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
|
||||
// identically equal to null. We have to work around this later, but we might as well just
|
||||
// be efficient here and whip up the null directly.
|
||||
let private jsonNull () =
|
||||
SynExpr.createNull ()
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|
||||
/// Given `input.Ident`, for example, choose how to add it to the ambient `node`.
|
||||
/// The result is a line like `(fun ident -> InnerType.toJsonNode ident)` or `(fun ident -> JsonValue.Create ident)`.
|
||||
let rec serializeNode (fieldType : SynType) : SynExpr =
|
||||
/// Returns also a bool which is true if the resulting SynExpr represents something of type JsonNode.
|
||||
let rec serializeNode (fieldType : SynType) : SynExpr * bool =
|
||||
// TODO: serialization format for DateTime etc
|
||||
match fieldType with
|
||||
| DateOnly
|
||||
| DateTime
|
||||
| NumberType _
|
||||
| Measure _
|
||||
| PrimitiveType _
|
||||
| Guid
|
||||
| Uri ->
|
||||
// JsonValue.Create<type>
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ],
|
||||
range0,
|
||||
[ fieldType ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||
|> SynExpr.typeApp [ fieldType ]
|
||||
|> fun e -> e, false
|
||||
| DateTimeOffset ->
|
||||
// fun field -> field.ToString("o") |> JsonValue.Create<string>
|
||||
let create =
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||
|> SynExpr.typeApp [ SynType.named "string" ]
|
||||
|
||||
SynExpr.createIdent "field"
|
||||
|> SynExpr.callMethodArg "ToString" (SynExpr.CreateConst "o")
|
||||
|> SynExpr.pipeThroughFunction create
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, false
|
||||
| NullableType ty ->
|
||||
// fun field -> if field.HasValue then {serializeNode ty} field.Value else JsonValue.Create null
|
||||
let inner, innerIsJsonNode = serializeNode ty
|
||||
|
||||
SynExpr.applyFunction inner (SynExpr.createLongIdent [ "field" ; "Value" ])
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|> SynExpr.ifThenElse (SynExpr.createLongIdent [ "field" ; "HasValue" ]) (jsonNull ())
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, innerIsJsonNode
|
||||
| OptionType ty ->
|
||||
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
|
||||
[
|
||||
SynMatchClause.Create (
|
||||
SynPat.CreateLongIdent (SynLongIdent.CreateString "None", []),
|
||||
None,
|
||||
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
|
||||
// identically equal to null. We have to work around this later, but we might as well just
|
||||
// be efficient here and whip up the null directly.
|
||||
SynExpr.CreateNull
|
||||
|> SynExpr.upcast' (
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
)
|
||||
)
|
||||
)
|
||||
let noneClause = jsonNull () |> SynMatchClause.create (SynPat.named "None")
|
||||
|
||||
SynMatchClause.Create (
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateString "Some",
|
||||
[ SynPat.CreateNamed (Ident.Create "field") ]
|
||||
),
|
||||
None,
|
||||
SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "field")
|
||||
|> SynExpr.CreateParen
|
||||
|> SynExpr.upcast' (
|
||||
SynType.CreateLongIdent (
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.CreateIdentString "field")
|
||||
let someClause =
|
||||
let inner, innerIsJsonNode = serializeNode ty
|
||||
let target = SynExpr.applyFunction inner (SynExpr.createIdent "field")
|
||||
|
||||
if innerIsJsonNode then
|
||||
target
|
||||
else
|
||||
target
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|
||||
|> SynMatchClause.create (SynPat.nameWithArgs "Some" [ SynPat.named "field" ])
|
||||
|
||||
[ noneClause ; someClause ]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "field")
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, true
|
||||
| ArrayType ty
|
||||
| ListType ty ->
|
||||
// fun field ->
|
||||
@@ -84,24 +90,24 @@ module internal JsonSerializeGenerator =
|
||||
DebugPointAtInOrTo.Yes range0,
|
||||
SeqExprOnly.SeqExprOnly false,
|
||||
true,
|
||||
SynPat.CreateNamed (Ident.Create "mem"),
|
||||
SynExpr.CreateIdent (Ident.Create "field"),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "arr" ; "Add" ]),
|
||||
SynExpr.CreateParen (SynExpr.CreateApp (serializeNode ty, SynExpr.CreateIdentString "mem"))
|
||||
),
|
||||
SynPat.named "mem",
|
||||
SynExpr.createIdent "field",
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "arr" ; "Add" ])
|
||||
(SynExpr.paren (SynExpr.applyFunction (fst (serializeNode ty)) (SynExpr.createIdent "mem"))),
|
||||
range0
|
||||
)
|
||||
SynExpr.CreateIdentString "arr"
|
||||
SynExpr.createIdent "arr"
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "arr") []
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "arr" ] []
|
||||
]
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, false
|
||||
| IDictionaryType (_keyType, valueType)
|
||||
| DictionaryType (_keyType, valueType)
|
||||
| IReadOnlyDictionaryType (_keyType, valueType)
|
||||
@@ -117,48 +123,29 @@ module internal JsonSerializeGenerator =
|
||||
DebugPointAtInOrTo.Yes range0,
|
||||
SeqExprOnly.SeqExprOnly false,
|
||||
true,
|
||||
SynPat.CreateParen (
|
||||
SynPat.CreateLongIdent (
|
||||
SynLongIdent.CreateString "KeyValue",
|
||||
SynPat.paren (SynPat.nameWithArgs "KeyValue" [ SynPat.named "key" ; SynPat.named "value" ]),
|
||||
SynExpr.createIdent "field",
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "ret" ; "Add" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynPat.CreateParen (
|
||||
SynPat.Tuple (
|
||||
false,
|
||||
[
|
||||
SynPat.CreateNamed (Ident.Create "key")
|
||||
SynPat.CreateNamed (Ident.Create "value")
|
||||
],
|
||||
[ range0 ],
|
||||
range0
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
),
|
||||
SynExpr.CreateIdent (Ident.Create "field"),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "ret" ; "Add" ],
|
||||
SynExpr.CreateParenedTuple
|
||||
[
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "key" ; "ToString" ],
|
||||
SynExpr.CreateConst SynConst.Unit
|
||||
)
|
||||
SynExpr.CreateApp (serializeNode valueType, SynExpr.CreateIdentString "value")
|
||||
]
|
||||
),
|
||||
SynExpr.createLongIdent [ "key" ; "ToString" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
SynExpr.applyFunction (fst (serializeNode valueType)) (SynExpr.createIdent "value")
|
||||
]),
|
||||
range0
|
||||
)
|
||||
SynExpr.CreateIdentString "ret"
|
||||
SynExpr.createIdent "ret"
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "ret") []
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "ret" ] []
|
||||
]
|
||||
|> SynExpr.createLambda "field"
|
||||
|> fun e -> e, false
|
||||
| _ ->
|
||||
// {type}.toJsonNode
|
||||
let typeName =
|
||||
@@ -166,22 +153,28 @@ module internal JsonSerializeGenerator =
|
||||
| SynType.LongIdent ident -> ident.LongIdent
|
||||
| _ -> failwith $"Unrecognised type: %+A{fieldType}"
|
||||
|
||||
SynExpr.createLongIdent' (typeName @ [ Ident.Create "toJsonNode" ])
|
||||
SynExpr.createLongIdent' (typeName @ [ Ident.create "toJsonNode" ]), true
|
||||
|
||||
/// propertyName is probably a string literal, but it could be a [<Literal>] variable
|
||||
/// `node.Add ({propertyName}, {toJsonNode})`
|
||||
let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr =
|
||||
[
|
||||
propertyName
|
||||
SynExpr.CreateApp (serializeNode fieldType, SynExpr.createLongIdent' [ Ident.Create "input" ; fieldId ])
|
||||
SynExpr.pipeThroughFunction
|
||||
(fst (serializeNode fieldType))
|
||||
(SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ])
|
||||
|> SynExpr.paren
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
|
||||
let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr =
|
||||
let propertyNameAttr =
|
||||
attrs
|
||||
|> List.tryFind (fun attr -> attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal))
|
||||
|> List.tryFind (fun attr ->
|
||||
(SynLongIdent.toString attr.TypeName)
|
||||
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
|
||||
)
|
||||
|
||||
match propertyNameAttr with
|
||||
| None ->
|
||||
@@ -191,7 +184,7 @@ module internal JsonSerializeGenerator =
|
||||
if fieldId.idText.Length > 1 then
|
||||
sb.Append fieldId.idText.[1..] |> ignore
|
||||
|
||||
sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst
|
||||
sb.ToString () |> SynExpr.CreateConst
|
||||
| Some name -> name.ArgExpr
|
||||
|
||||
/// `populateNode` will be inserted before we return the `node` variable.
|
||||
@@ -207,67 +200,57 @@ module internal JsonSerializeGenerator =
|
||||
(populateNode : SynExpr)
|
||||
: SynModuleDecl
|
||||
=
|
||||
let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node"
|
||||
let xmlDoc = PreXmlDoc.create "Serialize to a JSON node"
|
||||
|
||||
let returnInfo =
|
||||
SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
|> SynType.LongIdent
|
||||
|
||||
let functionName = Ident.Create "toJsonNode"
|
||||
let functionName = Ident.create "toJsonNode"
|
||||
|
||||
let assignments =
|
||||
[
|
||||
populateNode
|
||||
SynExpr.Upcast (SynExpr.CreateIdentString "node", SynType.Anon range0, range0)
|
||||
SynExpr.Upcast (SynExpr.createIdent "node", SynType.Anon range0, range0)
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> SynExpr.createLet
|
||||
[
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|> SynBinding.basic (SynLongIdent.CreateString "node") []
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "node" ] []
|
||||
]
|
||||
|
||||
let pattern =
|
||||
SynPat.CreateNamed inputArgName
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName))
|
||||
SynPat.namedI inputArgName
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName))
|
||||
|
||||
if spec.ExtensionMethods then
|
||||
let binding =
|
||||
let componentInfo =
|
||||
SynComponentInfo.createLong typeName
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
||||
|
||||
let memberDef =
|
||||
assignments
|
||||
|> SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ pattern ]
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.makeStaticMember
|
||||
|
||||
let mem = SynMemberDefn.Member (binding, range0)
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let containingType =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
SynComponentInfo.Create (typeName, xmldoc = PreXmlDoc.Create " Extension methods for JSON parsing"),
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0),
|
||||
[ mem ],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ memberDef ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
else
|
||||
let binding =
|
||||
assignments
|
||||
|> SynBinding.basic (SynLongIdent.CreateFromLongIdent [ functionName ]) [ pattern ]
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
assignments
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
SynModuleDecl.CreateLet [ binding ]
|
||||
|
||||
let recordModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) =
|
||||
let inputArg = Ident.Create "input"
|
||||
let recordModule (spec : JsonSerializeOutputSpec) (_typeName : LongIdent) (fields : SynField list) =
|
||||
let fields = fields |> List.map SynField.extractWithIdent
|
||||
|
||||
fields
|
||||
@@ -275,25 +258,24 @@ module internal JsonSerializeGenerator =
|
||||
let propertyName = getPropertyName fieldData.Ident fieldData.Attrs
|
||||
createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type
|
||||
)
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|> fun expr -> SynExpr.Do (expr, range0)
|
||||
|> scaffolding spec typeName inputArg
|
||||
|
||||
let unionModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (cases : SynUnionCase list) =
|
||||
let inputArg = Ident.Create "input"
|
||||
let 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 caseNames = unionCase.Fields |> List.mapi (fun i _ -> $"arg%i{i}")
|
||||
|
||||
let argPats = SynArgPats.create caseNames
|
||||
let argPats = SynArgPats.createNamed caseNames
|
||||
|
||||
let pattern =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent (typeName @ [ unionCase.Ident ]),
|
||||
SynLongIdent.create (typeName @ [ unionCase.Ident ]),
|
||||
None,
|
||||
None,
|
||||
argPats,
|
||||
@@ -303,26 +285,18 @@ module internal JsonSerializeGenerator =
|
||||
|
||||
let typeLine =
|
||||
[
|
||||
SynExpr.CreateConstString "type"
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ],
|
||||
SynExpr.CreateConst "type"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ])
|
||||
propertyName
|
||||
)
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "dataNode" ] []
|
||||
|
||||
let dataBindings =
|
||||
(unionCase.Fields, caseNames)
|
||||
@@ -331,20 +305,20 @@ module internal JsonSerializeGenerator =
|
||||
let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs
|
||||
|
||||
let node =
|
||||
SynExpr.CreateApp (serializeNode fieldData.Type, SynExpr.CreateIdent caseName)
|
||||
SynExpr.applyFunction (fst (serializeNode fieldData.Type)) (SynExpr.createIdent caseName)
|
||||
|
||||
[ propertyName ; node ]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ])
|
||||
)
|
||||
|
||||
let assignToNode =
|
||||
[ SynExpr.CreateConstString "data" ; SynExpr.CreateIdentString "dataNode" ]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
[ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ]
|
||||
|> SynExpr.tuple
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
|
||||
|
||||
let dataNode =
|
||||
SynExpr.CreateSequential (dataBindings @ [ assignToNode ])
|
||||
SynExpr.sequential (dataBindings @ [ assignToNode ])
|
||||
|> SynExpr.createLet [ dataNode ]
|
||||
|
||||
let action =
|
||||
@@ -353,12 +327,73 @@ module internal JsonSerializeGenerator =
|
||||
if not dataBindings.IsEmpty then
|
||||
yield dataNode
|
||||
]
|
||||
|> SynExpr.CreateSequential
|
||||
|> SynExpr.sequential
|
||||
|
||||
SynMatchClause.Create (pattern, None, action)
|
||||
SynMatchClause.create pattern action
|
||||
)
|
||||
|> fun clauses -> SynExpr.CreateMatch (SynExpr.CreateIdent inputArg, clauses)
|
||||
|> scaffolding spec typeName inputArg
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' inputArg)
|
||||
|
||||
let enumModule
|
||||
(spec : JsonSerializeOutputSpec)
|
||||
(typeName : LongIdent)
|
||||
(cases : (Ident * SynExpr) list)
|
||||
: SynModuleDecl
|
||||
=
|
||||
let fail =
|
||||
SynExpr.CreateConst "Unrecognised value for enum: %O"
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "sprintf")
|
||||
|> SynExpr.applyTo (SynExpr.createIdent "v")
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "failwith")
|
||||
|
||||
let body =
|
||||
cases
|
||||
|> List.map (fun (caseName, value) ->
|
||||
value
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]
|
||||
)
|
||||
|> SynMatchClause.create (SynPat.identWithArgs (typeName @ [ caseName ]) (SynArgPats.create []))
|
||||
)
|
||||
|> fun l -> l @ [ SynMatchClause.create (SynPat.named "v") fail ]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent "input")
|
||||
|
||||
let xmlDoc = PreXmlDoc.create "Serialize to a JSON node"
|
||||
|
||||
let returnInfo =
|
||||
SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
|
||||
|> SynType.LongIdent
|
||||
|
||||
let functionName = Ident.create "toJsonNode"
|
||||
|
||||
let pattern =
|
||||
SynPat.named "input"
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName))
|
||||
|
||||
if spec.ExtensionMethods then
|
||||
let componentInfo =
|
||||
SynComponentInfo.createLong typeName
|
||||
|> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
|
||||
|
||||
let memberDef =
|
||||
body
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let containingType =
|
||||
SynTypeDefnRepr.augmentation ()
|
||||
|> SynTypeDefn.create componentInfo
|
||||
|> SynTypeDefn.withMemberDefns [ memberDef ]
|
||||
|
||||
SynModuleDecl.Types ([ containingType ], range0)
|
||||
else
|
||||
body
|
||||
|> SynBinding.basic [ functionName ] [ pattern ]
|
||||
|> SynBinding.withReturnAnnotation returnInfo
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let createModule
|
||||
(namespaceId : LongIdent)
|
||||
@@ -369,17 +404,14 @@ 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 =
|
||||
if spec.ExtensionMethods then
|
||||
[ SynAttributeList.Create SynAttribute.autoOpen ]
|
||||
[ SynAttribute.autoOpen ]
|
||||
else
|
||||
[
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
]
|
||||
[ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
|
||||
|
||||
let xmlDoc =
|
||||
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
|
||||
@@ -390,8 +422,8 @@ module internal JsonSerializeGenerator =
|
||||
else
|
||||
"methods"
|
||||
|
||||
$" Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.Create
|
||||
$"Module containing JSON serializing %s{description} for the %s{fullyQualified} type"
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let moduleName =
|
||||
if spec.ExtensionMethods then
|
||||
@@ -402,29 +434,42 @@ module internal JsonSerializeGenerator =
|
||||
List.last ident
|
||||
|> fun i -> i.idText
|
||||
|> fun s -> s + "JsonSerializeExtension"
|
||||
|> Ident.Create
|
||||
|> Ident.create
|
||||
|
||||
List.take (List.length ident - 1) ident @ [ expanded ]
|
||||
else
|
||||
ident
|
||||
|
||||
let info =
|
||||
SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc)
|
||||
SynComponentInfo.createLong moduleName
|
||||
|> SynComponentInfo.addAttributes attributes
|
||||
|> SynComponentInfo.setAccessibility access
|
||||
|> SynComponentInfo.withDocString xmlDoc
|
||||
|
||||
let decls =
|
||||
match synTypeDefnRepr with
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _range), _) ->
|
||||
[ recordModule spec ident recordFields ]
|
||||
recordModule spec ident recordFields
|
||||
|> scaffolding spec ident (Ident.create "input")
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, unionFields, _range), _) ->
|
||||
[ unionModule spec ident unionFields ]
|
||||
| _ -> failwithf "Only record types currently supported."
|
||||
unionModule spec ident unionFields
|
||||
|> scaffolding spec ident (Ident.create "input")
|
||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum (cases, _range), _) ->
|
||||
cases
|
||||
|> List.map (fun c ->
|
||||
match c with
|
||||
| SynEnumCase.SynEnumCase (_, SynIdent.SynIdent (ident, _), value, _, _, _) -> ident, value
|
||||
)
|
||||
|> enumModule spec ident
|
||||
| ty -> failwithf "Unsupported type: got %O" ty
|
||||
|
||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||
[
|
||||
yield! opens |> List.map SynModuleDecl.openAny
|
||||
yield decls |> List.singleton |> SynModuleDecl.nestedModule info
|
||||
]
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (
|
||||
namespaceId,
|
||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ]
|
||||
)
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that provides a method (possibly an extension method) for a record type,
|
||||
/// containing a JSON serialization function.
|
||||
@@ -438,20 +483,21 @@ type JsonSerializeGenerator () =
|
||||
let ast, _ =
|
||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||
|
||||
let recordsAndUnions =
|
||||
let relevantTypes =
|
||||
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
|
||||
elif AstHelper.isEnum defn then Some defn
|
||||
else None
|
||||
)
|
||||
|> fun defns -> name, defns
|
||||
)
|
||||
|
||||
let namespaceAndTypes =
|
||||
recordsAndUnions
|
||||
relevantTypes
|
||||
|> List.choose (fun (ns, types) ->
|
||||
types
|
||||
|> List.choose (fun typeDef ->
|
||||
|
24
WoofWare.Myriad.Plugins/Measure.fs
Normal file
24
WoofWare.Myriad.Plugins/Measure.fs
Normal 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
|
32
WoofWare.Myriad.Plugins/Primitives.fs
Normal file
32
WoofWare.Myriad.Plugins/Primitives.fs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Primitives =
|
||||
/// Given e.g. "byte", returns "System.Byte".
|
||||
let qualifyType (typeName : string) : LongIdent option =
|
||||
match typeName with
|
||||
| "float32"
|
||||
| "single" -> [ "System" ; "Single" ] |> Some
|
||||
| "float"
|
||||
| "double" -> [ "System" ; "Double" ] |> Some
|
||||
| "byte"
|
||||
| "uint8" -> [ "System" ; "Byte" ] |> Some
|
||||
| "sbyte"
|
||||
| "int8" -> [ "System" ; "SByte" ] |> Some
|
||||
| "int16" -> [ "System" ; "Int16" ] |> Some
|
||||
| "int"
|
||||
| "int32" -> [ "System" ; "Int32" ] |> Some
|
||||
| "int64" -> [ "System" ; "Int64" ] |> Some
|
||||
| "uint16" -> [ "System" ; "UInt16" ] |> Some
|
||||
| "uint"
|
||||
| "uint32" -> [ "System" ; "UInt32" ] |> Some
|
||||
| "uint64" -> [ "System" ; "UInt64" ] |> Some
|
||||
| "char" -> [ "System" ; "Char" ] |> Some
|
||||
| "decimal" -> [ "System" ; "Decimal" ] |> Some
|
||||
| "string" -> [ "System" ; "String" ] |> Some
|
||||
| "bool" -> [ "System" ; "Boolean" ] |> Some
|
||||
| _ -> None
|
||||
|> Option.map (List.map (fun i -> (Ident (i, range0))))
|
@@ -1,14 +1,11 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Myriad.Core
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal RemoveOptionsGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core.Ast
|
||||
|
||||
let private removeOption (s : SynField) : SynField =
|
||||
let (SynField.SynField (synAttributeLists,
|
||||
@@ -45,9 +42,10 @@ module internal RemoveOptionsGenerator =
|
||||
(accessibility : SynAccess option)
|
||||
(generics : SynTyparDecls option)
|
||||
(fields : SynField list)
|
||||
: SynModuleDecl
|
||||
=
|
||||
let fields : SynField list = fields |> List.map removeOption
|
||||
let name = Ident.Create "Short"
|
||||
let name = Ident.create "Short"
|
||||
|
||||
let record =
|
||||
{
|
||||
@@ -57,6 +55,7 @@ module internal RemoveOptionsGenerator =
|
||||
XmlDoc = xmlDoc
|
||||
Generics = generics
|
||||
Accessibility = accessibility
|
||||
Attributes = []
|
||||
}
|
||||
|
||||
let typeDecl = AstHelper.defineRecordType record
|
||||
@@ -64,20 +63,10 @@ module internal RemoveOptionsGenerator =
|
||||
SynModuleDecl.Types ([ typeDecl ], range0)
|
||||
|
||||
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 =
|
||||
SynBindingReturnInfo.Create (SynType.LongIdent (SynLongIdent.CreateFromLongIdent withOptionsType))
|
||||
|
||||
let inputArg = Ident.Create "input"
|
||||
let functionName = Ident.Create "shorten"
|
||||
|
||||
let inputVal =
|
||||
SynValData.SynValData (
|
||||
None,
|
||||
SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty),
|
||||
Some inputArg
|
||||
)
|
||||
let inputArg = Ident.create "input"
|
||||
let functionName = Ident.create "shorten"
|
||||
|
||||
let body =
|
||||
fields
|
||||
@@ -93,65 +82,31 @@ module internal RemoveOptionsGenerator =
|
||||
let body =
|
||||
match fieldData.Type with
|
||||
| OptionType _ ->
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.LongIdent (
|
||||
false,
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_PipeRight" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "|>") ]
|
||||
),
|
||||
None,
|
||||
range0
|
||||
),
|
||||
accessor
|
||||
),
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "Option.defaultWith"),
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.CreateFromLongIdent (
|
||||
withoutOptionsType
|
||||
@ [ Ident.Create (sprintf "Default%s" fieldData.Ident.idText) ]
|
||||
)
|
||||
)
|
||||
)
|
||||
accessor
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "Option" ; "defaultWith" ])
|
||||
(SynExpr.createLongIdent' (
|
||||
withoutOptionsType
|
||||
@ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ]
|
||||
))
|
||||
)
|
||||
| _ -> accessor
|
||||
|
||||
(SynLongIdent.CreateFromLongIdent [ fieldData.Ident ], true), Some body
|
||||
SynLongIdent.createI fieldData.Ident, body
|
||||
)
|
||||
|> AstHelper.instantiateRecord
|
||||
|
||||
let pattern =
|
||||
SynPat.LongIdent (
|
||||
SynLongIdent.CreateFromLongIdent [ functionName ],
|
||||
None,
|
||||
None,
|
||||
SynArgPats.Pats
|
||||
[
|
||||
SynPat.CreateTyped (
|
||||
SynPat.CreateNamed inputArg,
|
||||
SynType.LongIdent (SynLongIdent.CreateFromLongIdent withoutOptionsType)
|
||||
)
|
||||
|> SynPat.CreateParen
|
||||
],
|
||||
None,
|
||||
range0
|
||||
)
|
||||
|
||||
let binding =
|
||||
SynBinding.Let (
|
||||
isInline = false,
|
||||
isMutable = false,
|
||||
xmldoc = xmlDoc,
|
||||
returnInfo = returnInfo,
|
||||
expr = body,
|
||||
valData = inputVal,
|
||||
pattern = pattern
|
||||
)
|
||||
|
||||
SynModuleDecl.CreateLet [ binding ]
|
||||
SynBinding.basic
|
||||
[ functionName ]
|
||||
[
|
||||
SynPat.named inputArg.idText
|
||||
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create withoutOptionsType))
|
||||
]
|
||||
body
|
||||
|> SynBinding.withXmlDoc xmlDoc
|
||||
|> SynBinding.withReturnAnnotation (SynType.LongIdent (SynLongIdent.create withOptionsType))
|
||||
|> SynModuleDecl.createLet
|
||||
|
||||
let createRecordModule (namespaceId : LongIdent) (typeDefn : SynTypeDefn) =
|
||||
let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) =
|
||||
@@ -167,30 +122,29 @@ module internal RemoveOptionsGenerator =
|
||||
let decls =
|
||||
[
|
||||
createType (Some doc) accessibility typeParams fields
|
||||
createMaker [ Ident.Create "Short" ] recordId fieldData
|
||||
]
|
||||
|
||||
let attributes =
|
||||
[
|
||||
SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ())
|
||||
SynAttributeList.Create SynAttribute.compilationRepresentation
|
||||
createMaker [ Ident.create "Short" ] recordId fieldData
|
||||
]
|
||||
|
||||
let xmlDoc =
|
||||
recordId
|
||||
|> Seq.map (fun i -> i.idText)
|
||||
|> String.concat "."
|
||||
|> sprintf " Module containing an option-truncated version of the %s type"
|
||||
|> PreXmlDoc.Create
|
||||
|> sprintf "Module containing an option-truncated version of the %s type"
|
||||
|> PreXmlDoc.create
|
||||
|
||||
let info =
|
||||
SynComponentInfo.Create (recordId, attributes = attributes, xmldoc = xmlDoc)
|
||||
SynComponentInfo.createLong recordId
|
||||
|> SynComponentInfo.withDocString xmlDoc
|
||||
|> SynComponentInfo.addAttributes [ SynAttribute.compilationRepresentation ]
|
||||
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
|
||||
|
||||
let mdl = SynModuleDecl.CreateNestedModule (info, decls)
|
||||
|
||||
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
|
||||
SynModuleDecl.nestedModule info decls
|
||||
|> List.singleton
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
| _ -> failwithf "Not a record type"
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that stamps out a record with option types stripped
|
||||
/// from the fields at the top level.
|
||||
[<MyriadGenerator("remove-options")>]
|
||||
|
@@ -1,3 +1,5 @@
|
||||
WoofWare.Myriad.Plugins.ArgParserGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
WoofWare.Myriad.Plugins.ArgParserGenerator..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismGenerator..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.HttpClientGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
|
49
WoofWare.Myriad.Plugins/SynExpr/CompExpr.fs
Normal file
49
WoofWare.Myriad.Plugins/SynExpr/CompExpr.fs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
|
||||
type internal CompExprBinding =
|
||||
| LetBang of varName : string * rhs : SynExpr
|
||||
| Let of varName : string * rhs : SynExpr
|
||||
| Use of varName : string * rhs : SynExpr
|
||||
| Do of body : SynExpr
|
||||
|
||||
(*
|
||||
Potential API!
|
||||
type internal CompExprBindings =
|
||||
private
|
||||
{
|
||||
/// These are stored in reverse.
|
||||
Bindings : CompExprBinding list
|
||||
CompExprName : string
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal CompExprBindings =
|
||||
let make (name : string) : CompExprBindings =
|
||||
{
|
||||
Bindings = []
|
||||
CompExprName = name
|
||||
}
|
||||
|
||||
let thenDo (body : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (Do body :: bindings.Bindings)
|
||||
}
|
||||
|
||||
let thenLet (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (Let (varName, value) :: bindings.Bindings)
|
||||
}
|
||||
|
||||
let thenLetBang (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (LetBang (varName, value) :: bindings.Bindings)
|
||||
}
|
||||
|
||||
|
||||
let thenUse (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
|
||||
{ bindings with
|
||||
Bindings = (LetBang (varName, value) :: bindings.Bindings)
|
||||
}
|
||||
*)
|
@@ -3,12 +3,14 @@ namespace WoofWare.Myriad.Plugins
|
||||
open System
|
||||
open System.Text
|
||||
open Fantomas.FCS.Syntax
|
||||
open Myriad.Core
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Ident =
|
||||
let inline create (s : string) = Ident (s, range0)
|
||||
|
||||
let lowerFirstLetter (x : Ident) : Ident =
|
||||
let result = StringBuilder x.idText.Length
|
||||
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
|
||||
result.Append x.idText.[1..] |> ignore
|
||||
Ident.Create ((result : StringBuilder).ToString ())
|
||||
create ((result : StringBuilder).ToString ())
|
12
WoofWare.Myriad.Plugins/SynExpr/PreXmlDoc.fs
Normal file
12
WoofWare.Myriad.Plugins/SynExpr/PreXmlDoc.fs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PreXmlDoc =
|
||||
let create (s : string) : PreXmlDoc =
|
||||
PreXmlDoc.Create ([| " " + s |], range0)
|
||||
|
||||
let create' (s : string seq) : PreXmlDoc =
|
||||
PreXmlDoc.Create (Array.ofSeq s, range0)
|
@@ -5,14 +5,26 @@ open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynArgPats =
|
||||
let create (caseNames : Ident list) : SynArgPats =
|
||||
if caseNames.IsEmpty then
|
||||
SynArgPats.Pats []
|
||||
else
|
||||
let createNamed (caseNames : string list) : SynArgPats =
|
||||
match caseNames.Length with
|
||||
| 0 -> SynArgPats.Pats []
|
||||
| 1 ->
|
||||
SynPat.Named (SynIdent.SynIdent (Ident.create caseNames.[0], None), false, None, range0)
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
| len ->
|
||||
caseNames
|
||||
|> List.map (fun name -> SynPat.Named (SynIdent.SynIdent (Ident.create name, None), false, None, range0))
|
||||
|> fun t -> SynPat.Tuple (false, t, List.replicate (len - 1) range0, range0)
|
||||
|> fun t -> SynPat.Paren (t, range0)
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
|
||||
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
|
||||
let create (pats : SynPat list) : SynArgPats =
|
||||
match pats.Length with
|
||||
| 0 -> SynArgPats.Pats []
|
||||
| 1 -> [ pats.[0] ] |> SynArgPats.Pats
|
||||
| len ->
|
||||
SynPat.Paren (SynPat.Tuple (false, pats, List.replicate (len - 1) range0, range0), range0)
|
||||
|> List.singleton
|
||||
|> SynArgPats.Pats
|
||||
|
@@ -2,20 +2,25 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Myriad.Core
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynAttribute =
|
||||
let internal compilationRepresentation : SynAttribute =
|
||||
{
|
||||
TypeName = SynLongIdent.CreateString "CompilationRepresentation"
|
||||
TypeName = SynLongIdent.createS "CompilationRepresentation"
|
||||
ArgExpr =
|
||||
SynExpr.CreateLongIdent (
|
||||
false,
|
||||
SynLongIdent.Create [ "CompilationRepresentationFlags" ; "ModuleSuffix" ],
|
||||
None
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
[ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
|
||||
|> SynExpr.createLongIdent
|
||||
|> SynExpr.paren
|
||||
Target = None
|
||||
AppliesToGetterAndSetter = false
|
||||
Range = range0
|
||||
}
|
||||
|
||||
let internal requireQualifiedAccess : SynAttribute =
|
||||
{
|
||||
TypeName = SynLongIdent.createS "RequireQualifiedAccess"
|
||||
ArgExpr = SynExpr.CreateConst ()
|
||||
Target = None
|
||||
AppliesToGetterAndSetter = false
|
||||
Range = range0
|
||||
@@ -23,8 +28,8 @@ module internal SynAttribute =
|
||||
|
||||
let internal autoOpen : SynAttribute =
|
||||
{
|
||||
TypeName = SynLongIdent.CreateString "AutoOpen"
|
||||
ArgExpr = SynExpr.CreateConst SynConst.Unit
|
||||
TypeName = SynLongIdent.createS "AutoOpen"
|
||||
ArgExpr = SynExpr.CreateConst ()
|
||||
Target = None
|
||||
AppliesToGetterAndSetter = false
|
||||
Range = range0
|
||||
|
15
WoofWare.Myriad.Plugins/SynExpr/SynAttributes.fs
Normal file
15
WoofWare.Myriad.Plugins/SynExpr/SynAttributes.fs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynAttributes =
|
||||
let ofAttrs (attrs : SynAttribute list) : SynAttributes =
|
||||
attrs
|
||||
|> List.map (fun a ->
|
||||
{
|
||||
Attributes = [ a ]
|
||||
Range = range0
|
||||
}
|
||||
)
|
@@ -16,14 +16,18 @@ module internal SynBinding =
|
||||
let rec private getName (pat : SynPat) : Ident option =
|
||||
match stripParen pat with
|
||||
| SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name
|
||||
| SynPat.Wild _ -> None
|
||||
| SynPat.Typed (pat, _, _) -> getName pat
|
||||
| SynPat.Const _ -> None
|
||||
| SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) ->
|
||||
match longIdent with
|
||||
| [ x ] -> Some x
|
||||
| _ -> failwithf "got long ident %O ; can only get the name of a long ident with one component" longIdent
|
||||
| _ -> failwithf "unrecognised pattern: %+A" pat
|
||||
| _ -> None
|
||||
|
||||
let private getArgInfo (pat : SynPat) : SynArgInfo list =
|
||||
// TODO: this only copes with one layer of tupling
|
||||
match stripParen pat with
|
||||
| SynPat.Tuple (_, pats, _, _) -> pats |> List.map (fun pat -> SynArgInfo.SynArgInfo ([], false, getName pat))
|
||||
| pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ]
|
||||
|
||||
let triviaZero (isMember : bool) =
|
||||
{
|
||||
@@ -36,10 +40,10 @@ module internal SynBinding =
|
||||
SynLeadingKeyword.Let range0
|
||||
}
|
||||
|
||||
let basic (name : SynLongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
|
||||
let basic (name : LongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
|
||||
let valInfo : SynValInfo =
|
||||
args
|
||||
|> List.map (fun pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ])
|
||||
|> List.map getArgInfo
|
||||
|> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None))
|
||||
|
||||
SynBinding.SynBinding (
|
||||
@@ -50,7 +54,7 @@ module internal SynBinding =
|
||||
[],
|
||||
PreXmlDoc.Empty,
|
||||
SynValData.SynValData (None, valInfo, None),
|
||||
SynPat.LongIdent (name, None, None, SynArgPats.Pats args, None, range0),
|
||||
SynPat.identWithArgs name (SynArgPats.Pats args),
|
||||
None,
|
||||
body,
|
||||
range0,
|
||||
@@ -58,6 +62,35 @@ module internal SynBinding =
|
||||
triviaZero false
|
||||
)
|
||||
|
||||
let withMutability (mut : bool) (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (pat, kind, inl, _, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
||||
SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
|
||||
|
||||
let withRecursion (isRec : bool) (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
||||
let trivia =
|
||||
{ trivia with
|
||||
LeadingKeyword =
|
||||
match trivia.LeadingKeyword with
|
||||
| SynLeadingKeyword.Let _ ->
|
||||
if isRec then
|
||||
SynLeadingKeyword.LetRec (range0, range0)
|
||||
else
|
||||
trivia.LeadingKeyword
|
||||
| SynLeadingKeyword.LetRec _ ->
|
||||
if isRec then
|
||||
trivia.LeadingKeyword
|
||||
else
|
||||
trivia.LeadingKeyword
|
||||
| existing ->
|
||||
failwith
|
||||
$"WoofWare.Myriad doesn't yet let you adjust the recursion modifier on a binding with modifier %O{existing}"
|
||||
}
|
||||
|
||||
SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
|
||||
|
||||
let withAccessibility (acc : SynAccess option) (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (_, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
|
||||
@@ -103,7 +136,7 @@ module internal SynBinding =
|
||||
trivia
|
||||
)
|
||||
|
||||
let makeInline (binding : SynBinding) : SynBinding =
|
||||
let inline makeInline (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
||||
SynBinding (
|
||||
@@ -124,6 +157,33 @@ module internal SynBinding =
|
||||
}
|
||||
)
|
||||
|
||||
let inline makeNotInline (binding : SynBinding) : SynBinding =
|
||||
match binding with
|
||||
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
|
||||
SynBinding (
|
||||
acc,
|
||||
kind,
|
||||
false,
|
||||
mut,
|
||||
attrs,
|
||||
doc,
|
||||
valData,
|
||||
headPat,
|
||||
ret,
|
||||
expr,
|
||||
range,
|
||||
debugPoint,
|
||||
{ trivia with
|
||||
InlineKeyword = None
|
||||
}
|
||||
)
|
||||
|
||||
let inline setInline (isInline : bool) (binding : SynBinding) : SynBinding =
|
||||
if isInline then
|
||||
makeInline binding
|
||||
else
|
||||
makeNotInline binding
|
||||
|
||||
let makeStaticMember (binding : SynBinding) : SynBinding =
|
||||
let memberFlags =
|
||||
{
|
||||
|
50
WoofWare.Myriad.Plugins/SynExpr/SynComponentInfo.fs
Normal file
50
WoofWare.Myriad.Plugins/SynExpr/SynComponentInfo.fs
Normal file
@@ -0,0 +1,50 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynComponentInfo =
|
||||
let inline createLong (name : LongIdent) =
|
||||
SynComponentInfo.SynComponentInfo ([], None, [], name, PreXmlDoc.Empty, false, None, range0)
|
||||
|
||||
let inline create (name : Ident) = createLong [ name ]
|
||||
|
||||
let inline withDocString (doc : PreXmlDoc) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, _, postfix, access, range) ->
|
||||
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
|
||||
|
||||
let inline setGenerics (typars : SynTyparDecls option) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, _, constraints, name, doc, postfix, access, range) ->
|
||||
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
|
||||
|
||||
let inline withGenerics (typars : SynTyparDecl list) (i : SynComponentInfo) : SynComponentInfo =
|
||||
let inner =
|
||||
if typars.IsEmpty then
|
||||
None
|
||||
else
|
||||
Some (SynTyparDecls.PostfixList (typars, [], range0))
|
||||
|
||||
setGenerics inner i
|
||||
|
||||
let inline setAccessibility (acc : SynAccess option) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, _, range) ->
|
||||
SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, acc, range)
|
||||
|
||||
let inline withAccessibility (acc : SynAccess) (i : SynComponentInfo) : SynComponentInfo =
|
||||
setAccessibility (Some acc) i
|
||||
|
||||
let inline addAttributes (attrs : SynAttribute list) (i : SynComponentInfo) : SynComponentInfo =
|
||||
match i with
|
||||
| SynComponentInfo.SynComponentInfo (oldAttrs, typars, constraints, name, doc, postfix, acc, range) ->
|
||||
let attrs =
|
||||
{
|
||||
SynAttributeList.Attributes = attrs
|
||||
SynAttributeList.Range = range0
|
||||
}
|
||||
|
||||
SynComponentInfo.SynComponentInfo ((attrs :: oldAttrs), typars, constraints, name, doc, postfix, acc, range)
|
@@ -3,14 +3,25 @@ namespace WoofWare.Myriad.Plugins
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Myriad.Core
|
||||
open Myriad.Core.Ast
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
type internal CompExprBinding =
|
||||
| LetBang of varName : string * rhs : SynExpr
|
||||
| Let of varName : string * rhs : SynExpr
|
||||
| Use of varName : string * rhs : SynExpr
|
||||
| Do of body : SynExpr
|
||||
[<AutoOpen>]
|
||||
module internal SynExprExtensions =
|
||||
type SynExpr with
|
||||
static member CreateConst (s : string) : SynExpr =
|
||||
SynExpr.Const (SynConst.String (s, SynStringKind.Regular, range0), range0)
|
||||
|
||||
static member CreateConst () : SynExpr = SynExpr.Const (SynConst.Unit, range0)
|
||||
|
||||
static member CreateConst (b : bool) : SynExpr = SynExpr.Const (SynConst.Bool b, range0)
|
||||
|
||||
static member CreateConst (c : char) : SynExpr =
|
||||
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
||||
SynExpr.CreateApp (SynExpr.Ident (Ident.Create "char"), SynExpr.CreateConst (int c))
|
||||
|> fun e -> SynExpr.Paren (e, range0, Some range0, range0)
|
||||
|
||||
static member CreateConst (i : int32) : SynExpr =
|
||||
SynExpr.Const (SynConst.Int32 i, range0)
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynExpr =
|
||||
@@ -19,20 +30,11 @@ module internal SynExpr =
|
||||
let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
|
||||
|
||||
/// {f} {x}
|
||||
let applyTo (x : SynExpr) (f : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
|
||||
let inline applyTo (x : SynExpr) (f : SynExpr) : SynExpr = applyFunction f x
|
||||
|
||||
/// {expr} |> {func}
|
||||
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_PipeRight" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "|>") ]
|
||||
)
|
||||
),
|
||||
expr
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.pipe, expr)
|
||||
|> applyTo func
|
||||
|
||||
/// if {cond} then {trueBranch} else {falseBranch}
|
||||
@@ -58,7 +60,7 @@ module internal SynExpr =
|
||||
/// try {body} with | {exc} as exc -> {handler}
|
||||
let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr =
|
||||
let clause =
|
||||
SynMatchClause.Create (SynPat.As (exc, SynPat.CreateNamed (Ident.Create "exc"), range0), None, handler)
|
||||
SynMatchClause.create (SynPat.As (exc, SynPat.named "exc", range0)) handler
|
||||
|
||||
SynExpr.TryWith (
|
||||
body,
|
||||
@@ -76,17 +78,7 @@ module internal SynExpr =
|
||||
|
||||
/// {a} = {b}
|
||||
let equals (a : SynExpr) (b : SynExpr) =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
Ident.CreateLong "op_Equality",
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "=") ]
|
||||
)
|
||||
),
|
||||
a
|
||||
)
|
||||
|> applyTo b
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.eq, a) |> applyTo b
|
||||
|
||||
/// {a} + {b}
|
||||
let plus (a : SynExpr) (b : SynExpr) =
|
||||
@@ -102,56 +94,71 @@ 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
|
||||
| expr -> expr
|
||||
|
||||
/// {obj}.{meth} {arg}
|
||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
let dotGet (field : string) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.DotGet (
|
||||
obj,
|
||||
range0,
|
||||
SynLongIdent.SynLongIdent (id = [ Ident.Create meth ], dotRanges = [], trivia = [ None ]),
|
||||
SynLongIdent.SynLongIdent (id = [ Ident.create field ], dotRanges = [], trivia = [ None ]),
|
||||
range0
|
||||
)
|
||||
|> applyTo arg
|
||||
|
||||
/// {obj}.{meth} {arg}
|
||||
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr = dotGet meth obj |> applyTo arg
|
||||
|
||||
/// {obj}.{meth}()
|
||||
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
|
||||
callMethodArg meth (SynExpr.CreateConst SynConst.Unit) obj
|
||||
callMethodArg meth (SynExpr.CreateConst ()) obj
|
||||
|
||||
let typeApp (types : SynType list) (operand : SynExpr) =
|
||||
SynExpr.TypeApp (operand, range0, types, List.replicate (types.Length - 1) range0, Some range0, range0, range0)
|
||||
|
||||
let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||
range0,
|
||||
[ SynType.LongIdent (SynLongIdent.CreateFromLongIdent ty) ],
|
||||
[],
|
||||
Some range0,
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
|> applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0)
|
||||
|> typeApp [ SynType.LongIdent (SynLongIdent.create ty) ]
|
||||
|> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
/// {obj}.{meth}<ty>()
|
||||
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.TypeApp (
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0),
|
||||
range0,
|
||||
[ SynType.CreateLongIdent ty ],
|
||||
[],
|
||||
Some range0,
|
||||
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0)
|
||||
|> typeApp [ SynType.createLongIdent' [ ty ] ]
|
||||
|> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.DotIndexedGet (obj, property, range0, range0)
|
||||
|
||||
let inline arrayIndexRange (start : SynExpr option) (endRange : SynExpr option) (arr : SynExpr) : SynExpr =
|
||||
SynExpr.DotIndexedGet (
|
||||
arr,
|
||||
(SynExpr.IndexRange (start, range0, endRange, range0, range0, range0)),
|
||||
range0,
|
||||
range0
|
||||
)
|
||||
|> applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
|
||||
let index (property : SynExpr) (obj : SynExpr) : SynExpr =
|
||||
SynExpr.DotIndexedGet (obj, property, range0, range0)
|
||||
let inline paren (e : SynExpr) : SynExpr =
|
||||
SynExpr.Paren (e, range0, Some range0, range0)
|
||||
|
||||
/// (fun {varName} -> {body})
|
||||
let createLambda (varName : string) (body : SynExpr) : SynExpr =
|
||||
let parsedDataPat = [ SynPat.CreateNamed (Ident.Create varName) ]
|
||||
let parsedDataPat = [ SynPat.named varName ]
|
||||
|
||||
SynExpr.Lambda (
|
||||
false,
|
||||
@@ -164,39 +171,100 @@ module internal SynExpr =
|
||||
ArrowRange = Some range0
|
||||
}
|
||||
)
|
||||
|> SynExpr.CreateParen
|
||||
|> paren
|
||||
|
||||
let reraise : SynExpr =
|
||||
SynExpr.CreateIdent (Ident.Create "reraise")
|
||||
|> applyTo (SynExpr.CreateConst SynConst.Unit)
|
||||
let createThunk (body : SynExpr) : SynExpr =
|
||||
SynExpr.Lambda (
|
||||
false,
|
||||
false,
|
||||
SynSimplePats.Create [],
|
||||
body,
|
||||
Some ([ SynPat.unit ], body),
|
||||
range0,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
}
|
||||
)
|
||||
|> paren
|
||||
|
||||
let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0))
|
||||
|
||||
let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i
|
||||
|
||||
let inline createLongIdent' (ident : Ident list) : SynExpr =
|
||||
SynExpr.LongIdent (false, SynLongIdent.create ident, None, range0)
|
||||
|
||||
let inline createLongIdent (ident : string list) : SynExpr =
|
||||
createLongIdent' (ident |> List.map Ident.create)
|
||||
|
||||
let tupleNoParen (args : SynExpr list) : SynExpr =
|
||||
SynExpr.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||
|
||||
let inline tuple (args : SynExpr list) = args |> tupleNoParen |> paren
|
||||
|
||||
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
|
||||
let startAsTask (ct : SynLongIdent) (body : SynExpr) =
|
||||
let startAsTask (ct : Ident) (body : SynExpr) =
|
||||
let lambda =
|
||||
[
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "a")
|
||||
createIdent "a"
|
||||
equals
|
||||
(SynExpr.LongIdent (true, SynLongIdent.CreateString "cancellationToken", None, range0))
|
||||
(SynExpr.CreateLongIdent ct)
|
||||
(SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
|
||||
(createIdent' ct)
|
||||
]
|
||||
|> SynExpr.CreateParenedTuple
|
||||
|> applyFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "StartAsTask" ]))
|
||||
|> tuple
|
||||
|> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ])
|
||||
|> createLambda "a"
|
||||
|
||||
pipeThroughFunction lambda body
|
||||
|
||||
let createLongIdent (ident : string list) : SynExpr =
|
||||
SynExpr.CreateLongIdent (SynLongIdent.Create ident)
|
||||
let inline createForEach (pat : SynPat) (enumExpr : SynExpr) (body : SynExpr) : SynExpr =
|
||||
SynExpr.ForEach (
|
||||
DebugPointAtFor.No,
|
||||
DebugPointAtInOrTo.No,
|
||||
SeqExprOnly.SeqExprOnly false,
|
||||
true,
|
||||
pat,
|
||||
enumExpr,
|
||||
body,
|
||||
range0
|
||||
)
|
||||
|
||||
let createLongIdent' (ident : Ident list) : SynExpr =
|
||||
SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident)
|
||||
|
||||
let createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
|
||||
let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
|
||||
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty)
|
||||
|
||||
let createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr = SynExpr.CreateMatch (matchOn, cases)
|
||||
let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr =
|
||||
SynExpr.Match (
|
||||
DebugPointAtBinding.Yes range0,
|
||||
matchOn,
|
||||
cases,
|
||||
range0,
|
||||
{
|
||||
MatchKeyword = range0
|
||||
WithKeyword = range0
|
||||
}
|
||||
)
|
||||
|
||||
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.CreateTyped (expr, ty)
|
||||
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.Typed (expr, ty, range0)
|
||||
|
||||
let inline createNew (ty : SynType) (args : SynExpr) : SynExpr =
|
||||
SynExpr.New (false, ty, paren args, range0)
|
||||
|
||||
let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr =
|
||||
SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0)
|
||||
|
||||
let inline createNull () : SynExpr = SynExpr.Null range0
|
||||
|
||||
let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ())
|
||||
|
||||
let sequential (exprs : SynExpr list) : SynExpr =
|
||||
exprs
|
||||
|> List.reduce (fun a b -> SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, a, b, range0))
|
||||
|
||||
let listLiteral (elts : SynExpr list) : SynExpr =
|
||||
SynExpr.ArrayOrListComputed (false, sequential elts, range0)
|
||||
|
||||
let arrayLiteral (elts : SynExpr list) : SynExpr =
|
||||
SynExpr.ArrayOrListComputed (true, sequential elts, range0)
|
||||
|
||||
/// {compExpr} { {lets} ; return {ret} }
|
||||
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
|
||||
@@ -211,7 +279,7 @@ module internal SynExpr =
|
||||
DebugPointAtBinding.Yes range0,
|
||||
false,
|
||||
true,
|
||||
SynPat.CreateNamed (Ident.Create lhs),
|
||||
SynPat.named lhs,
|
||||
rhs,
|
||||
[],
|
||||
state,
|
||||
@@ -220,90 +288,78 @@ module internal SynExpr =
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
)
|
||||
| Let (lhs, rhs) ->
|
||||
createLet [ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ] state
|
||||
| Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state
|
||||
| Use (lhs, rhs) ->
|
||||
SynExpr.LetOrUse (
|
||||
false,
|
||||
true,
|
||||
[ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ],
|
||||
[ SynBinding.basic [ Ident.create lhs ] [] rhs ],
|
||||
state,
|
||||
range0,
|
||||
{
|
||||
SynExprLetOrUseTrivia.InKeyword = None
|
||||
}
|
||||
)
|
||||
| Do body -> SynExpr.CreateSequential [ SynExpr.Do (body, range0) ; state ]
|
||||
| Do body -> sequential [ SynExpr.Do (body, range0) ; state ]
|
||||
)
|
||||
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateIdent (Ident.Create compExpr),
|
||||
SynExpr.ComputationExpr (false, contents, range0)
|
||||
)
|
||||
applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0))
|
||||
|
||||
/// {expr} |> Async.AwaitTask
|
||||
let awaitTask (expr : SynExpr) : SynExpr =
|
||||
expr
|
||||
|> pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "AwaitTask" ]))
|
||||
expr |> pipeThroughFunction (createLongIdent [ "Async" ; "AwaitTask" ])
|
||||
|
||||
/// {ident}.ToString ()
|
||||
/// with special casing for some types like DateTime
|
||||
let toString (ty : SynType) (ident : SynExpr) =
|
||||
match ty with
|
||||
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-dd")
|
||||
| DateTime ->
|
||||
ident
|
||||
|> callMethodArg "ToString" (SynExpr.CreateConstString "yyyy-MM-ddTHH:mm:ss")
|
||||
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-dd")
|
||||
| DateTime -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-ddTHH:mm:ss")
|
||||
| _ -> callMethod "ToString" ident
|
||||
|
||||
let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0)
|
||||
|
||||
/// {ident} - {rhs}
|
||||
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_Subtraction" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "-") ]
|
||||
)
|
||||
),
|
||||
SynExpr.CreateLongIdent ident
|
||||
),
|
||||
rhs
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.sub, SynExpr.CreateLongIdent ident)
|
||||
|> applyTo rhs
|
||||
|
||||
/// {ident} - {n}
|
||||
let minusN (ident : SynLongIdent) (n : int) : SynExpr =
|
||||
minus ident (SynExpr.CreateConst (SynConst.Int32 n))
|
||||
let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n)
|
||||
|
||||
/// {y} > {x}
|
||||
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateApp (
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_GreaterThan" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation ">") ]
|
||||
)
|
||||
),
|
||||
y
|
||||
),
|
||||
x
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.gt, y) |> applyTo x
|
||||
|
||||
/// {y} < {x}
|
||||
let lessThan (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.lt, y) |> applyTo x
|
||||
|
||||
/// {y} >= {x}
|
||||
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.CreateLongIdent (
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.Create "op_GreaterThanOrEqual" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
||||
)
|
||||
),
|
||||
y
|
||||
)
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.geq, y)
|
||||
|> applyTo x
|
||||
|
||||
/// {y} <= {x}
|
||||
let lessThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.leq, y)
|
||||
|> applyTo x
|
||||
|
||||
/// {x} :: {y}
|
||||
let listCons (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||
SynExpr.CreateAppInfix (
|
||||
SynExpr.LongIdent (
|
||||
false,
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.create "op_ColonColon" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "::") ]
|
||||
),
|
||||
None,
|
||||
range0
|
||||
),
|
||||
tupleNoParen [ x ; y ]
|
||||
)
|
||||
|> paren
|
||||
|
||||
let assign (lhs : SynLongIdent) (rhs : SynExpr) : SynExpr = SynExpr.LongIdentSet (lhs, rhs, range0)
|
||||
|
@@ -1,6 +1,9 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
|
||||
type internal SynFieldData<'Ident> =
|
||||
{
|
||||
@@ -37,3 +40,30 @@ module internal SynField =
|
||||
| None -> failwith "expected field identifier to have a value, but it did not"
|
||||
| Some i -> i
|
||||
)
|
||||
|
||||
let make (data : SynFieldData<Ident option>) : SynField =
|
||||
let attrs : SynAttributeList list =
|
||||
data.Attrs
|
||||
|> List.map (fun l ->
|
||||
{
|
||||
Attributes = [ l ]
|
||||
Range = range0
|
||||
}
|
||||
)
|
||||
|
||||
SynField.SynField (
|
||||
attrs,
|
||||
false,
|
||||
data.Ident,
|
||||
data.Type,
|
||||
false,
|
||||
PreXmlDoc.Empty,
|
||||
None,
|
||||
range0,
|
||||
SynFieldTrivia.Zero
|
||||
)
|
||||
|
||||
let withDocString (doc : PreXmlDoc) (f : SynField) : SynField =
|
||||
match f with
|
||||
| SynField (attributes, isStatic, idOpt, fieldType, isMutable, _, accessibility, range, trivia) ->
|
||||
SynField (attributes, isStatic, idOpt, fieldType, isMutable, doc, accessibility, range, trivia)
|
||||
|
128
WoofWare.Myriad.Plugins/SynExpr/SynLongIdent.fs
Normal file
128
WoofWare.Myriad.Plugins/SynExpr/SynLongIdent.fs
Normal file
@@ -0,0 +1,128 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Syntax
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynLongIdent =
|
||||
|
||||
let geq =
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.create "op_GreaterThanOrEqual" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
||||
)
|
||||
|
||||
let leq =
|
||||
SynLongIdent.SynLongIdent (
|
||||
[ Ident.create "op_LessThanOrEqual" ],
|
||||
[],
|
||||
[ Some (IdentTrivia.OriginalNotation "<=") ]
|
||||
)
|
||||
|
||||
let gt =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ Some (IdentTrivia.OriginalNotation ">") ])
|
||||
|
||||
let lt =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_LessThan" ], [], [ Some (IdentTrivia.OriginalNotation "<") ])
|
||||
|
||||
let sub =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Subtraction" ], [], [ Some (IdentTrivia.OriginalNotation "-") ])
|
||||
|
||||
let eq =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_Equality" ], [], [ Some (IdentTrivia.OriginalNotation "=") ])
|
||||
|
||||
let pipe =
|
||||
SynLongIdent.SynLongIdent ([ Ident.create "op_PipeRight" ], [], [ Some (IdentTrivia.OriginalNotation "|>") ])
|
||||
|
||||
let toString (sli : SynLongIdent) : string =
|
||||
sli.LongIdent |> List.map _.idText |> String.concat "."
|
||||
|
||||
let create (ident : LongIdent) : SynLongIdent =
|
||||
let commas =
|
||||
match ident with
|
||||
| [] -> []
|
||||
| _ :: commas -> commas |> List.map (fun _ -> range0)
|
||||
|
||||
SynLongIdent.SynLongIdent (ident, commas, List.replicate ident.Length None)
|
||||
|
||||
let inline createI (i : Ident) : SynLongIdent = create [ i ]
|
||||
|
||||
let inline createS (s : string) : SynLongIdent = createI (Ident (s, range0))
|
||||
|
||||
let inline createS' (s : string list) : SynLongIdent =
|
||||
create (s |> List.map (fun i -> Ident (i, range0)))
|
||||
|
||||
let isUnit (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
| _ -> false
|
||||
|
||||
let isList (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider FSharpList or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isArray (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when
|
||||
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|
||||
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
|
||||
->
|
||||
true
|
||||
| _ -> false
|
||||
|
||||
let isOption (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isChoice (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent with
|
||||
| [ i ] when System.String.Equals (i.idText, "Choice", System.StringComparison.Ordinal) -> true
|
||||
// TODO: consider Microsoft.FSharp.Choice or whatever it is
|
||||
| _ -> false
|
||||
|
||||
let isNullable (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "System" ; "Nullable" ]
|
||||
| [ "Nullable" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isResponse (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Response" ]
|
||||
| [ "RestEase" ; "Response" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isMap (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Map" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isReadOnlyDictionary (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IReadOnlyDictionary" ]
|
||||
| [ "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isDictionary (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "Dictionary" ]
|
||||
| [ "Generic" ; "Dictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "Dictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
|
||||
| _ -> false
|
||||
|
||||
let isIDictionary (ident : SynLongIdent) : bool =
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "IDictionary" ]
|
||||
| [ "Generic" ; "IDictionary" ]
|
||||
| [ "Collections" ; "Generic" ; "IDictionary" ]
|
||||
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
|
||||
| _ -> false
|
24
WoofWare.Myriad.Plugins/SynExpr/SynMatchClause.fs
Normal file
24
WoofWare.Myriad.Plugins/SynExpr/SynMatchClause.fs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynMatchClause =
|
||||
let create (lhs : SynPat) (rhs : SynExpr) : SynMatchClause =
|
||||
SynMatchClause.SynMatchClause (
|
||||
lhs,
|
||||
None,
|
||||
rhs,
|
||||
range0,
|
||||
DebugPointAtTarget.Yes,
|
||||
{
|
||||
ArrowRange = Some range0
|
||||
BarRange = Some range0
|
||||
}
|
||||
)
|
||||
|
||||
let withWhere (where : SynExpr) (m : SynMatchClause) : SynMatchClause =
|
||||
match m with
|
||||
| SynMatchClause (synPat, _, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia) ->
|
||||
SynMatchClause (synPat, Some where, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia)
|
65
WoofWare.Myriad.Plugins/SynExpr/SynMemberDefn.fs
Normal file
65
WoofWare.Myriad.Plugins/SynExpr/SynMemberDefn.fs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Xml
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynMemberDefn =
|
||||
let private interfaceMemberSlotFlags =
|
||||
{
|
||||
SynMemberFlags.IsInstance = true
|
||||
SynMemberFlags.IsDispatchSlot = true
|
||||
SynMemberFlags.IsOverrideOrExplicitImpl = false
|
||||
SynMemberFlags.IsFinal = false
|
||||
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
|
||||
SynMemberFlags.MemberKind = SynMemberKind.Member
|
||||
}
|
||||
|
||||
|
||||
let abstractMember
|
||||
(ident : SynIdent)
|
||||
(typars : SynTyparDecls option)
|
||||
(arity : SynValInfo)
|
||||
(xmlDoc : PreXmlDoc)
|
||||
(returnType : SynType)
|
||||
: SynMemberDefn
|
||||
=
|
||||
let slot =
|
||||
SynValSig.SynValSig (
|
||||
[],
|
||||
ident,
|
||||
SynValTyparDecls.SynValTyparDecls (typars, true),
|
||||
returnType,
|
||||
arity,
|
||||
false,
|
||||
false,
|
||||
xmlDoc,
|
||||
None,
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
EqualsRange = None
|
||||
WithKeyword = None
|
||||
InlineKeyword = None
|
||||
LeadingKeyword = SynLeadingKeyword.Abstract range0
|
||||
}
|
||||
)
|
||||
|
||||
SynMemberDefn.AbstractSlot (
|
||||
slot,
|
||||
interfaceMemberSlotFlags,
|
||||
range0,
|
||||
{
|
||||
GetSetKeywords = None
|
||||
}
|
||||
)
|
||||
|
||||
let staticMember (binding : SynBinding) : SynMemberDefn =
|
||||
let binding = SynBinding.makeStaticMember binding
|
||||
SynMemberDefn.Member (binding, range0)
|
||||
|
||||
let memberImplementation (binding : SynBinding) : SynMemberDefn =
|
||||
let binding = SynBinding.makeInstanceMember binding
|
||||
SynMemberDefn.Member (binding, range0)
|
30
WoofWare.Myriad.Plugins/SynExpr/SynModuleDecl.fs
Normal file
30
WoofWare.Myriad.Plugins/SynExpr/SynModuleDecl.fs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynModuleDecl =
|
||||
|
||||
let inline openAny (ident : SynOpenDeclTarget) : SynModuleDecl = SynModuleDecl.Open (ident, range0)
|
||||
|
||||
let inline createLets (bindings : SynBinding list) : SynModuleDecl =
|
||||
SynModuleDecl.Let (false, bindings, range0)
|
||||
|
||||
let inline createLet (binding : SynBinding) : SynModuleDecl = createLets [ binding ]
|
||||
|
||||
let inline createTypes (tys : SynTypeDefn list) : SynModuleDecl = SynModuleDecl.Types (tys, range0)
|
||||
|
||||
let nestedModule (info : SynComponentInfo) (decls : SynModuleDecl list) : SynModuleDecl =
|
||||
SynModuleDecl.NestedModule (
|
||||
info,
|
||||
false,
|
||||
decls,
|
||||
false,
|
||||
range0,
|
||||
{
|
||||
ModuleKeyword = Some range0
|
||||
EqualsRange = Some range0
|
||||
}
|
||||
)
|
24
WoofWare.Myriad.Plugins/SynExpr/SynModuleOrNamespace.fs
Normal file
24
WoofWare.Myriad.Plugins/SynExpr/SynModuleOrNamespace.fs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynModuleOrNamespace =
|
||||
|
||||
let createNamespace (name : LongIdent) (decls : SynModuleDecl list) =
|
||||
SynModuleOrNamespace.SynModuleOrNamespace (
|
||||
name,
|
||||
false,
|
||||
SynModuleOrNamespaceKind.DeclaredNamespace,
|
||||
decls,
|
||||
PreXmlDoc.Empty,
|
||||
[],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.Namespace range0
|
||||
}
|
||||
)
|
@@ -5,6 +5,50 @@ open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynPat =
|
||||
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
|
||||
|
||||
let annotateType (ty : SynType) (pat : SynPat) =
|
||||
SynPat.Paren (SynPat.Typed (pat, ty, range0), range0)
|
||||
let anon : SynPat = SynPat.Wild range0
|
||||
|
||||
let inline annotateTypeNoParen (ty : SynType) (pat : SynPat) = SynPat.Typed (pat, ty, range0)
|
||||
|
||||
let inline annotateType (ty : SynType) (pat : SynPat) = paren (annotateTypeNoParen ty pat)
|
||||
|
||||
let inline named (s : string) : SynPat =
|
||||
SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0)
|
||||
|
||||
let inline namedI (i : Ident) : SynPat =
|
||||
SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0)
|
||||
|
||||
let inline identWithArgs (i : LongIdent) (args : SynArgPats) : SynPat =
|
||||
SynPat.LongIdent (SynLongIdent.create i, None, None, args, None, range0)
|
||||
|
||||
let inline nameWithArgs (i : string) (args : SynPat list) : SynPat =
|
||||
identWithArgs [ Ident.create i ] (SynArgPats.create args)
|
||||
|
||||
let inline tupleNoParen (elements : SynPat list) : SynPat =
|
||||
match elements with
|
||||
| [] -> failwith "Can't tuple no elements in a pattern"
|
||||
| [ p ] -> p
|
||||
| elements -> SynPat.Tuple (false, elements, List.replicate (elements.Length - 1) range0, range0)
|
||||
|
||||
let inline tuple (elements : SynPat list) : SynPat = tupleNoParen elements |> paren
|
||||
|
||||
let inline createConst (c : SynConst) = SynPat.Const (c, range0)
|
||||
|
||||
let unit = createConst SynConst.Unit
|
||||
|
||||
let createNull = SynPat.Null range0
|
||||
|
||||
let emptyList = SynPat.ArrayOrList (false, [], range0)
|
||||
|
||||
let listCons (lhs : SynPat) (rhs : SynPat) =
|
||||
SynPat.ListCons (
|
||||
lhs,
|
||||
rhs,
|
||||
range0,
|
||||
{
|
||||
ColonColonRange = range0
|
||||
}
|
||||
)
|
||||
|
||||
let emptyArray = SynPat.ArrayOrList (true, [], range0)
|
||||
|
@@ -1,6 +1,264 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<AutoOpen>]
|
||||
module internal SynTypePatterns =
|
||||
let (|OptionType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isOption ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|ChoiceType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, inner, _, _, _, _) when SynLongIdent.isChoice ident -> Some inner
|
||||
| _ -> None
|
||||
|
||||
let (|NullableType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isNullable ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident when SynLongIdent.isUnit ident -> Some ()
|
||||
| _ -> None
|
||||
|
||||
let (|ListType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isList ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|ArrayType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isArray ident ->
|
||||
Some innerType
|
||||
| SynType.Array (1, innerType, _) -> Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|RestEaseResponseType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isResponse ident ->
|
||||
Some innerType
|
||||
| _ -> None
|
||||
|
||||
let (|DictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isDictionary ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isIDictionary ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
|
||||
SynLongIdent.isReadOnlyDictionary ident
|
||||
->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|MapType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isMap ident ->
|
||||
Some (key, value)
|
||||
| _ -> None
|
||||
|
||||
let (|BigInt|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map _.idText with
|
||||
| [ "bigint" ]
|
||||
| [ "BigInteger" ]
|
||||
| [ "Numerics" ; "BigInteger" ]
|
||||
| [ "System" ; "Numerics" ; "BigInteger" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Returns the type, qualified as in e.g. `System.Boolean`.
|
||||
let (|PrimitiveType|_|) (fieldType : SynType) : LongIdent option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> Primitives.qualifyType i.idText
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|String|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] ->
|
||||
[ "string" ]
|
||||
|> List.tryFind (fun s -> s = i.idText)
|
||||
|> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Byte|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Guid|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Guid" ]
|
||||
| [ "Guid" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
|
||||
| [ "Http" ; "HttpResponseMessage" ]
|
||||
| [ "HttpResponseMessage" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|HttpContent|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Net" ; "Http" ; "HttpContent" ]
|
||||
| [ "Http" ; "HttpContent" ]
|
||||
| [ "HttpContent" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Stream|_|) (fieldType : SynType) : unit option =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "IO" ; "Stream" ]
|
||||
| [ "IO" ; "Stream" ]
|
||||
| [ "Stream" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|NumberType|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent ident ->
|
||||
match ident.LongIdent with
|
||||
| [ i ] ->
|
||||
// We won't bother with the case that the user has done e.g. `Single` (relying on `System` being open).
|
||||
match Primitives.qualifyType i.idText with
|
||||
| Some qualified ->
|
||||
match i.idText with
|
||||
| "char"
|
||||
| "string" -> None
|
||||
| _ -> Some qualified
|
||||
| None -> None
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Returns the name of the measure, and the outer type.
|
||||
let (|Measure|_|) (fieldType : SynType) : (Ident * LongIdent) option =
|
||||
match fieldType with
|
||||
| SynType.App (NumberType outer,
|
||||
_,
|
||||
[ SynType.LongIdent (SynLongIdent.SynLongIdent ([ ident ], _, _)) ],
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_) -> Some (ident, outer)
|
||||
| _ -> None
|
||||
|
||||
let (|DateOnly|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateOnly" ]
|
||||
| [ "DateOnly" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateTime|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateTime" ]
|
||||
| [ "DateTime" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DateTimeOffset|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "DateTimeOffset" ]
|
||||
| [ "DateTimeOffset" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Uri|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "Uri" ]
|
||||
| [ "Uri" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|Task|_|) (fieldType : SynType) : SynType option =
|
||||
match fieldType with
|
||||
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "Task" ]
|
||||
| [ "Tasks" ; "Task" ]
|
||||
| [ "Threading" ; "Tasks" ; "Task" ]
|
||||
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
|
||||
match args with
|
||||
| [ arg ] -> Some arg
|
||||
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|DirectoryInfo|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "IO" ; "DirectoryInfo" ]
|
||||
| [ "IO" ; "DirectoryInfo" ]
|
||||
| [ "DirectoryInfo" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|FileInfo|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "IO" ; "FileInfo" ]
|
||||
| [ "IO" ; "FileInfo" ]
|
||||
| [ "FileInfo" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|TimeSpan|_|) (fieldType : SynType) =
|
||||
match fieldType with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
|
||||
match ident |> List.map (fun i -> i.idText) with
|
||||
| [ "System" ; "TimeSpan" ]
|
||||
| [ "TimeSpan" ] -> Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynType =
|
||||
@@ -8,3 +266,192 @@ module internal SynType =
|
||||
match ty with
|
||||
| SynType.Paren (ty, _) -> stripOptionalParen ty
|
||||
| ty -> ty
|
||||
|
||||
let inline createLongIdent (ident : LongIdent) : SynType =
|
||||
SynType.LongIdent (SynLongIdent.create ident)
|
||||
|
||||
let inline createLongIdent' (ident : string list) : SynType =
|
||||
SynType.LongIdent (SynLongIdent.createS' ident)
|
||||
|
||||
let inline named (name : string) = createLongIdent' [ name ]
|
||||
|
||||
let inline app' (name : SynType) (args : SynType list) : SynType =
|
||||
if args.IsEmpty then
|
||||
failwith "Type cannot be applied to no arguments"
|
||||
|
||||
SynType.App (name, Some range0, args, List.replicate (args.Length - 1) range0, Some range0, false, range0)
|
||||
|
||||
let inline app (name : string) (args : SynType list) : SynType = app' (named name) args
|
||||
|
||||
let inline appPostfix (name : string) (arg : SynType) : SynType =
|
||||
SynType.App (named name, None, [ arg ], [], None, true, range0)
|
||||
|
||||
let inline appPostfix' (name : string list) (arg : SynType) : SynType =
|
||||
SynType.App (createLongIdent' name, None, [ arg ], [], None, true, range0)
|
||||
|
||||
let inline funFromDomain (domain : SynType) (range : SynType) : SynType =
|
||||
SynType.Fun (
|
||||
domain,
|
||||
range,
|
||||
range0,
|
||||
{
|
||||
ArrowRange = range0
|
||||
}
|
||||
)
|
||||
|
||||
let inline signatureParamOfType (ty : SynType) (name : Ident option) : SynType =
|
||||
SynType.SignatureParameter ([], false, name, ty, range0)
|
||||
|
||||
let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0)
|
||||
|
||||
let unit : SynType = named "unit"
|
||||
let int : SynType = named "int"
|
||||
|
||||
let anon : SynType = SynType.Anon range0
|
||||
|
||||
let string : SynType = named "string"
|
||||
|
||||
/// Given ['a1, 'a2] and 'ret, returns 'a1 -> 'a2 -> 'ret.
|
||||
let toFun (inputs : SynType list) (ret : SynType) : SynType =
|
||||
(ret, List.rev inputs) ||> List.fold (fun ty input -> funFromDomain input ty)
|
||||
|
||||
let primitiveToHumanReadableString (name : LongIdent) : string =
|
||||
match name |> List.map _.idText with
|
||||
| [ "System" ; "Single" ] -> "single"
|
||||
| [ "System" ; "Double" ] -> "double"
|
||||
| [ "System" ; "Byte" ] -> "byte"
|
||||
| [ "System" ; "SByte" ] -> "signed byte"
|
||||
| [ "System" ; "Int16" ] -> "int16"
|
||||
| [ "System" ; "Int32" ] -> "int32"
|
||||
| [ "System" ; "Int64" ] -> "int64"
|
||||
| [ "System" ; "UInt16" ] -> "uint16"
|
||||
| [ "System" ; "UInt32" ] -> "uint32"
|
||||
| [ "System" ; "UInt64" ] -> "uint64"
|
||||
| [ "System" ; "Char" ] -> "char"
|
||||
| [ "System" ; "Decimal" ] -> "decimal"
|
||||
| [ "System" ; "String" ] -> "string"
|
||||
| [ "System" ; "Boolean" ] -> "bool"
|
||||
| ty ->
|
||||
ty
|
||||
|> String.concat "."
|
||||
|> failwithf "could not create human-readable string for primitive type %s"
|
||||
|
||||
let rec toHumanReadableString (ty : SynType) : string =
|
||||
match ty with
|
||||
| PrimitiveType t1 -> primitiveToHumanReadableString t1
|
||||
| OptionType t1 -> toHumanReadableString t1 + " option"
|
||||
| NullableType t1 -> toHumanReadableString t1 + " Nullable"
|
||||
| ChoiceType ts ->
|
||||
ts
|
||||
|> List.map toHumanReadableString
|
||||
|> String.concat ", "
|
||||
|> sprintf "Choice<%s>"
|
||||
| MapType (k, v)
|
||||
| DictionaryType (k, v)
|
||||
| IDictionaryType (k, v)
|
||||
| IReadOnlyDictionaryType (k, v) -> sprintf "map<%s, %s>" (toHumanReadableString k) (toHumanReadableString v)
|
||||
| ListType t1 -> toHumanReadableString t1 + " list"
|
||||
| ArrayType t1 -> toHumanReadableString t1 + " array"
|
||||
| Task t1 -> toHumanReadableString t1 + " Task"
|
||||
| UnitType -> "unit"
|
||||
| FileInfo -> "FileInfo"
|
||||
| DirectoryInfo -> "DirectoryInfo"
|
||||
| Uri -> "URI"
|
||||
| Stream -> "Stream"
|
||||
| Guid -> "GUID"
|
||||
| BigInt -> "bigint"
|
||||
| DateTimeOffset -> "DateTimeOffset"
|
||||
| DateOnly -> "DateOnly"
|
||||
| TimeSpan -> "TimeSpan"
|
||||
| ty -> failwithf "could not compute human-readable string for type: %O" ty
|
||||
|
||||
/// Guess whether the types are equal. We err on the side of saying "no, they're different".
|
||||
let rec provablyEqual (ty1 : SynType) (ty2 : SynType) : bool =
|
||||
if Object.ReferenceEquals (ty1, ty2) then
|
||||
true
|
||||
else
|
||||
|
||||
match ty1 with
|
||||
| PrimitiveType t1 ->
|
||||
match ty2 with
|
||||
| PrimitiveType t2 -> (t1 |> List.map _.idText) = (t2 |> List.map _.idText)
|
||||
| _ -> false
|
||||
| OptionType t1 ->
|
||||
match ty2 with
|
||||
| OptionType t2 -> provablyEqual t1 t2
|
||||
| _ -> false
|
||||
| NullableType t1 ->
|
||||
match ty2 with
|
||||
| NullableType t2 -> provablyEqual t1 t2
|
||||
| _ -> false
|
||||
| ChoiceType t1 ->
|
||||
match ty2 with
|
||||
| ChoiceType t2 ->
|
||||
t1.Length = t2.Length
|
||||
&& List.forall (fun (a, b) -> provablyEqual a b) (List.zip t1 t2)
|
||||
| _ -> false
|
||||
| DictionaryType (k1, v1) ->
|
||||
match ty2 with
|
||||
| DictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
||||
| _ -> false
|
||||
| IDictionaryType (k1, v1) ->
|
||||
match ty2 with
|
||||
| IDictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
||||
| _ -> false
|
||||
| IReadOnlyDictionaryType (k1, v1) ->
|
||||
match ty2 with
|
||||
| IReadOnlyDictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
||||
| _ -> false
|
||||
| MapType (k1, v1) ->
|
||||
match ty2 with
|
||||
| MapType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
|
||||
| _ -> false
|
||||
| ListType t1 ->
|
||||
match ty2 with
|
||||
| ListType t2 -> provablyEqual t1 t2
|
||||
| _ -> false
|
||||
| ArrayType t1 ->
|
||||
match ty2 with
|
||||
| ArrayType t2 -> provablyEqual t1 t2
|
||||
| _ -> false
|
||||
| Task t1 ->
|
||||
match ty2 with
|
||||
| Task t2 -> provablyEqual t1 t2
|
||||
| _ -> false
|
||||
| UnitType ->
|
||||
match ty2 with
|
||||
| UnitType -> true
|
||||
| _ -> false
|
||||
| FileInfo ->
|
||||
match ty2 with
|
||||
| FileInfo -> true
|
||||
| _ -> false
|
||||
| DirectoryInfo ->
|
||||
match ty2 with
|
||||
| DirectoryInfo -> true
|
||||
| _ -> false
|
||||
| Uri ->
|
||||
match ty2 with
|
||||
| Uri -> true
|
||||
| _ -> false
|
||||
| Stream ->
|
||||
match ty2 with
|
||||
| Stream -> true
|
||||
| _ -> false
|
||||
| Guid ->
|
||||
match ty2 with
|
||||
| Guid -> true
|
||||
| _ -> false
|
||||
| BigInt ->
|
||||
match ty2 with
|
||||
| BigInt -> true
|
||||
| _ -> false
|
||||
| DateTimeOffset ->
|
||||
match ty2 with
|
||||
| DateTimeOffset -> true
|
||||
| _ -> false
|
||||
| DateOnly ->
|
||||
match ty2 with
|
||||
| DateOnly -> true
|
||||
| _ -> false
|
||||
| _ -> false
|
||||
|
27
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefn.fs
Normal file
27
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefn.fs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynTypeDefn =
|
||||
|
||||
let inline create (componentInfo : SynComponentInfo) (repr : SynTypeDefnRepr) : SynTypeDefn =
|
||||
SynTypeDefn.SynTypeDefn (
|
||||
componentInfo,
|
||||
repr,
|
||||
[],
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
|
||||
EqualsRange = Some range0
|
||||
WithKeyword = None
|
||||
}
|
||||
)
|
||||
|
||||
let inline withMemberDefns (members : SynMemberDefn list) (r : SynTypeDefn) : SynTypeDefn =
|
||||
match r with
|
||||
| SynTypeDefn (typeInfo, typeRepr, _, ctor, range, trivia) ->
|
||||
SynTypeDefn.SynTypeDefn (typeInfo, typeRepr, members, ctor, range, trivia)
|
20
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefnRepr.fs
Normal file
20
WoofWare.Myriad.Plugins/SynExpr/SynTypeDefnRepr.fs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal SynTypeDefnRepr =
|
||||
|
||||
let inline interfaceType (mems : SynMemberDefns) : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Unspecified, mems, range0)
|
||||
|
||||
/// Indicates the body of a `type Foo with {body}` extension type declaration.
|
||||
let inline augmentation () : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0)
|
||||
|
||||
let inline union (cases : SynUnionCase list) : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (None, cases, range0), range0)
|
||||
|
||||
let inline record (fields : SynField list) : SynTypeDefnRepr =
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (None, fields, range0), range0)
|
@@ -1,6 +1,9 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Text.Range
|
||||
open Fantomas.FCS.Xml
|
||||
open Fantomas.FCS.SyntaxTrivia
|
||||
|
||||
type internal UnionCase<'Ident> =
|
||||
{
|
||||
@@ -39,3 +42,34 @@ module internal SynUnionCase =
|
||||
Attrs = attrs
|
||||
Ident = id
|
||||
}
|
||||
|
||||
let create (case : UnionCase<Ident>) : SynUnionCase =
|
||||
let fields =
|
||||
case.Fields
|
||||
|> List.map (fun field ->
|
||||
SynField.SynField (
|
||||
SynAttributes.ofAttrs field.Attrs,
|
||||
false,
|
||||
Some field.Ident,
|
||||
field.Type,
|
||||
false,
|
||||
PreXmlDoc.Empty,
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
LeadingKeyword = None
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
SynUnionCase.SynUnionCase (
|
||||
SynAttributes.ofAttrs case.Attrs,
|
||||
SynIdent.SynIdent (case.Ident, None),
|
||||
SynUnionCaseKind.Fields fields,
|
||||
PreXmlDoc.Empty,
|
||||
None,
|
||||
range0,
|
||||
{
|
||||
BarRange = Some range0
|
||||
}
|
||||
)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
@@ -18,30 +18,44 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Myriad.Core" Version="0.8.3" PrivateAssets="all"/>
|
||||
<PackageReference Include="Myriad.Core" Version="0.8.3" />
|
||||
<!-- the lowest version allowed by Myriad.Core -->
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.1" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="List.fs"/>
|
||||
<Compile Include="Ident.fs" />
|
||||
<Compile Include="AstHelper.fs"/>
|
||||
<Compile Include="Primitives.fs" />
|
||||
<Compile Include="SynExpr\SynAttributes.fs" />
|
||||
<Compile Include="SynExpr\PreXmlDoc.fs" />
|
||||
<Compile Include="SynExpr\Ident.fs" />
|
||||
<Compile Include="SynExpr\SynLongIdent.fs" />
|
||||
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
|
||||
<Compile Include="SynExpr\SynBinding.fs" />
|
||||
<Compile Include="SynExpr\SynExpr.fs" />
|
||||
<Compile Include="SynExpr\SynType.fs" />
|
||||
<Compile Include="SynExpr\SynAttribute.fs" />
|
||||
<Compile Include="SynExpr\SynArgPats.fs" />
|
||||
<Compile Include="SynExpr\SynPat.fs" />
|
||||
<Compile Include="SynExpr\SynBinding.fs" />
|
||||
<Compile Include="SynExpr\SynType.fs" />
|
||||
<Compile Include="SynExpr\SynMatchClause.fs" />
|
||||
<Compile Include="SynExpr\CompExpr.fs" />
|
||||
<Compile Include="SynExpr\SynExpr.fs" />
|
||||
<Compile Include="SynExpr\SynField.fs" />
|
||||
<Compile Include="SynExpr\SynUnionCase.fs" />
|
||||
<Compile Include="SynExpr\SynPat.fs" />
|
||||
<Compile Include="SynExpr\SynTypeDefnRepr.fs" />
|
||||
<Compile Include="SynExpr\SynTypeDefn.fs" />
|
||||
<Compile Include="SynExpr\SynComponentInfo.fs" />
|
||||
<Compile Include="SynExpr\SynMemberDefn.fs" />
|
||||
<Compile Include="SynExpr\SynAttribute.fs" />
|
||||
<Compile Include="SynExpr\SynModuleDecl.fs" />
|
||||
<Compile Include="SynExpr\SynModuleOrNamespace.fs" />
|
||||
<Compile Include="Measure.fs" />
|
||||
<Compile Include="AstHelper.fs" />
|
||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||
<Compile Include="InterfaceMockGenerator.fs"/>
|
||||
<Compile Include="JsonSerializeGenerator.fs"/>
|
||||
<Compile Include="JsonParseGenerator.fs"/>
|
||||
<Compile Include="HttpClientGenerator.fs"/>
|
||||
<Compile Include="CataGenerator.fs" />
|
||||
<Compile Include="ArgParserGenerator.fs" />
|
||||
<EmbeddedResource Include="version.json"/>
|
||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||
<None Include="..\README.md">
|
||||
|
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"version": "2.1",
|
||||
"version": "2.2",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
"pathFilters": [
|
||||
":/",
|
||||
":^WoofWare.Myriad.Plugins.Test/",
|
||||
":^WoofWare.Myriad.Plugins.Attributes/Test/",
|
||||
":^/.github/",
|
||||
":^/CHANGELOG.md"
|
||||
"./",
|
||||
":/WoofWare.Myriad.Plugins.Attributes",
|
||||
":^/WoofWare.Myriad.Plugins.Attributes/Test",
|
||||
":/global.json",
|
||||
":/README.md",
|
||||
":/Directory.Build.props"
|
||||
]
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.10.0]" />
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.11.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
12
flake.lock
generated
12
flake.lock
generated
@@ -5,11 +5,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -20,11 +20,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1706367331,
|
||||
"narHash": "sha256-AqgkGHRrI6h/8FWuVbnkfFmXr4Bqsr4fV23aISqj/xg=",
|
||||
"lastModified": 1725099143,
|
||||
"narHash": "sha256-CHgumPZaC7z+WYx72WgaLt2XF0yUVzJS60rO4GZ7ytY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "160b762eda6d139ac10ae081f8f78d640dd523eb",
|
||||
"rev": "5629520edecb69630a3f4d17d3d33fc96c13f6fe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
43
flake.nix
43
flake.nix
@@ -17,7 +17,7 @@
|
||||
dotnet-sdk = pkgs.dotnet-sdk_8;
|
||||
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
|
||||
version = "0.1";
|
||||
dotnetTool = dllOverride: toolName: toolVersion: sha256:
|
||||
dotnetTool = dllOverride: toolName: toolVersion: hash:
|
||||
pkgs.stdenvNoCC.mkDerivation rec {
|
||||
name = toolName;
|
||||
version = toolVersion;
|
||||
@@ -25,7 +25,7 @@
|
||||
src = pkgs.fetchNuGet {
|
||||
pname = name;
|
||||
version = version;
|
||||
sha256 = sha256;
|
||||
hash = hash;
|
||||
installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin'';
|
||||
};
|
||||
installPhase = let
|
||||
@@ -43,46 +43,21 @@
|
||||
};
|
||||
in {
|
||||
packages = {
|
||||
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
||||
fsharp-analyzers = dotnetTool "FSharp.Analyzers.Cli" "fsharp-analyzers" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fsharp-analyzers.version (builtins.head (builtins.filter (elem: elem.pname == "fsharp-analyzers") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).sha256;
|
||||
fetchDeps = let
|
||||
flags = [];
|
||||
runtimeIds = ["win-x64"] ++ map (system: pkgs.dotnetCorePackages.systemToDotnetRid system) dotnet-sdk.meta.platforms;
|
||||
in
|
||||
pkgs.writeShellScriptBin "fetch-${pname}-deps" (builtins.readFile (pkgs.substituteAll {
|
||||
src = ./nix/fetchDeps.sh;
|
||||
pname = pname;
|
||||
binPath = pkgs.lib.makeBinPath [pkgs.coreutils dotnet-sdk (pkgs.nuget-to-nix.override {inherit dotnet-sdk;})];
|
||||
projectFiles = toString ["./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj" "./ConsumePlugin/ConsumePlugin.fsproj" "./WoofWare.Myriad.Plugins.Attributes/WoofWare.Myriad.Plugins.Attributes.fsproj"];
|
||||
testProjectFiles = ["./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj" "./WoofWare.Myriad.Plugins.Attributes/Test/Woofware.Myriad.Plugins.Attributes.Test.fsproj"];
|
||||
rids = pkgs.lib.concatStringsSep "\" \"" runtimeIds;
|
||||
packages = dotnet-sdk.packages;
|
||||
storeSrc = pkgs.srcOnly {
|
||||
src = ./.;
|
||||
pname = pname;
|
||||
version = version;
|
||||
};
|
||||
}));
|
||||
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).hash;
|
||||
fsharp-analyzers = dotnetTool "FSharp.Analyzers.Cli" "fsharp-analyzers" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fsharp-analyzers.version (builtins.head (builtins.filter (elem: elem.pname == "fsharp-analyzers") ((import ./nix/deps.nix) {fetchNuGet = x: x;}))).hash;
|
||||
default = pkgs.buildDotnetModule {
|
||||
pname = pname;
|
||||
inherit pname version dotnet-sdk dotnet-runtime;
|
||||
name = "WoofWare.Myriad.Plugins";
|
||||
version = version;
|
||||
src = ./.;
|
||||
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj";
|
||||
nugetDeps = ./nix/deps.nix;
|
||||
testProjectFile = "./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj";
|
||||
disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"];
|
||||
nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result` and put the result here
|
||||
doCheck = true;
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
dotnet-runtime = dotnet-runtime;
|
||||
};
|
||||
};
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
(with dotnetCorePackages;
|
||||
combinePackages [
|
||||
dotnet-sdk_8
|
||||
dotnetPackages.Nuget
|
||||
])
|
||||
];
|
||||
buildInputs = [dotnet-sdk];
|
||||
packages = [
|
||||
pkgs.alejandra
|
||||
pkgs.nodePackages.markdown-link-check
|
||||
|
317
nix/deps.nix
317
nix/deps.nix
@@ -1,444 +1,329 @@
|
||||
# This file was automatically generated by passthru.fetch-deps.
|
||||
# Please don't edit it manually, your changes might get overwritten!
|
||||
# Please dont edit it manually, your changes might get overwritten!
|
||||
{fetchNuGet}: [
|
||||
(fetchNuGet {
|
||||
pname = "fsharp-analyzers";
|
||||
version = "0.26.0";
|
||||
sha256 = "sha256-60Bl36LOb/zVNdH2SBSuQ5O41lP9dKTNZbs5vvYs+3U=";
|
||||
pname = "ApiSurface";
|
||||
version = "4.1.5";
|
||||
hash = "sha256-Kbt18XLk1gvZfzGca885HaXZB119APay85KzI546PYM=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "fantomas";
|
||||
version = "6.3.4";
|
||||
sha256 = "sha256-1aWqZynBkQoznenGoP0sbf1PcUXAbcHiWyECuv89xa0=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "ApiSurface";
|
||||
version = "4.0.40";
|
||||
sha256 = "1c9z0b6minlripwrjmv4yd5w8zj4lcpak4x41izh7ygx8kgmbvx0";
|
||||
version = "6.3.11";
|
||||
hash = "sha256-11bHGEAZTNtdp2pTg5zqLrQiyI/j/AT7GGL/2CR4+dw=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Fantomas.Core";
|
||||
version = "6.1.1";
|
||||
sha256 = "1h2wsiy4fzwsg9vrlpk6w7zsvx6bc4wg4x25zqc48akg04fwpi0m";
|
||||
hash = "sha256-FcTLHQFvKkQY/kV08jhhy/St/+FmXpp3epp/R3zUXMA=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Fantomas.FCS";
|
||||
version = "6.1.1";
|
||||
sha256 = "0733dm5zjdp8w5wwalqlv1q52pghfr04863i9wy807f4qfd7rrin";
|
||||
hash = "sha256-NuZ8msPEHYA8T3EYREB28F1RcNgUU8V54eg2+UttYxw=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FsCheck";
|
||||
version = "2.16.6";
|
||||
sha256 = "176rwky6b5rk8dzldiz4068p7m9c5y9ygzbhadrs14jkl94pc56n";
|
||||
hash = "sha256-1hR2SaJTkqBzU3D955MvLNVzkQHkx0Z/QzOXZfzk2Zw=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "fsharp-analyzers";
|
||||
version = "0.27.0";
|
||||
hash = "sha256-QhLi2veTY1wZlQKJLTyVPgx/ImkaZugQNjSN5VJCNEA=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FSharp.Core";
|
||||
version = "4.3.4";
|
||||
sha256 = "1sg6i4q5nwyzh769g76f6c16876nvdpn83adqjr2y9x6xsiv5p5j";
|
||||
hash = "sha256-styyo+6mJy+yxE0NZG/b1hxkAjPOnJfMgd9zWzCJ5uk=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FSharp.Core";
|
||||
version = "6.0.1";
|
||||
sha256 = "0qks2aadkhsffg9a6xq954ll9xacnph852avd7ljh9n2g6vj06qj";
|
||||
hash = "sha256-Ehsgt3nCJijpaVuJguC1TPVEKSkJd6PSc07D2ZQSemI=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FSharp.Core";
|
||||
version = "8.0.101";
|
||||
sha256 = "0prgcnki6s0rlrfbarrcv50w1bbhaalsyhhw5gsnjs2is7qrjbii";
|
||||
version = "8.0.400";
|
||||
hash = "sha256-wlrcAjjvI5YtnHR7kFH8uRUA4GomJYmqr41K5LYjCGs=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "FsUnit";
|
||||
version = "6.0.0";
|
||||
sha256 = "18q3p0z155znwj1l0qq3vq9nh9wl2i4mlfx4pmrnia4czr0xdkmb";
|
||||
hash = "sha256-q87WQf6MqGhzvaQ7WkkUlCdoE94DY0CD5PaXEj64A6M=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Ref";
|
||||
version = "6.0.26";
|
||||
sha256 = "1d8nkz24vsm0iy2xm8y5ak2q1w1p99dxyz0y26acs6sfk2na0vm6";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Ref";
|
||||
version = "8.0.1";
|
||||
sha256 = "0yaaiqq7mi6sclyrb1v0fyncanbx0ifmnnhv9whynqj8439jsdwh";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-GcPiO+iI0JsHYlqURAmzWjOnDX2jDCUY4jYaIwr8ojs=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1za8lc52m4z54d68wd64c2nhzy05g3gx171k5cdlx73fbymiys9z";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0dsdgqg7566qximmjfza4x9if3icy4kskq698ddj5apdia88h2mw";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-g5zbB1DnCSKuCOWtF09GEqGn1uJLdlTN6kqdnSCzRjQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1zpbmz6z8758gwywzg0bac8kx9x39sxxc9j4a4r2jl74l9ssw4vm";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1gjz379y61ag9whi78qxx09bwkwcznkx2mzypgycibxk61g11da1";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-ToaiqVy5qonomAVBg5PO1GgrPKL4Cc1BZTJ0z/2LquA=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1i8ydlwjzk7j0mzvn0rpljxfp1h50zwaqalnyvfxai1fwgigzgw5";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0w3mrs4zdl9mfanl1j81759xwwrzmicsjxn6yfxv5yrxbxzq695n";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-OY/vdqAzZ99I4lEZbOOQw12TE0AIb5pXxKTvDxO2M2Q=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "02src68hd3213sd1a2ms1my7i92knfmdxclvv90il9cky2zsq8kw";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0a9aljr4fy4haq6ndz2y723liv5hbfpss1rn45s88nmgcp27m15m";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.win-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1gxlmfdkfzmhw9pac5jiv674nn6i1zymcp2hj81irjwhhjk01mf5";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.AspNetCore.App.Runtime.win-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "01kzndyqmsvcq49i2jrv7ymfp0l71yxfylv1cy3nhkdbprqz8ipx";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.Build.Tasks.Git";
|
||||
version = "8.0.0";
|
||||
sha256 = "0055f69q3hbagqp8gl3nk0vfn4qyqyxsxyy7pd0g7wm3z28byzmx";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-53MAV3RO1kXzy5IpdZDZIOhoUzFqWHn7+A3aWwdTONQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.CodeCoverage";
|
||||
version = "17.10.0";
|
||||
sha256 = "0s0v7jmrq85n356xv7zixvwa4z94fszjcr5vll8x4im1a2lp00f9";
|
||||
version = "17.11.0";
|
||||
hash = "sha256-XglInnx5GePUYHG7n2NLX+WfK7kJnornsWOW/5FnOXE=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NET.Test.Sdk";
|
||||
version = "17.10.0";
|
||||
sha256 = "13g8fwl09li8fc71nk13dgkb7gahd4qhamyg2xby7am63nlchhdf";
|
||||
version = "17.11.0";
|
||||
hash = "sha256-WjyA78+PG9ZloWTt9Hf1ek3VVj2FfJ9fAjqklnN+fWw=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "19y6c6v20bgf7x7rrh4rx9y7s5fy8vp5m4j9b6gi1wp4rpb5mza4";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0dhpdlcdz7adcfh9w01fc867051m35fqaxnvj3fqvqhgcm2n3143";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-rwWOpf2Pdg84c8bKIUcMYuDTI0kXUELL/nl9psSmX+E=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0p7hhidaa3mnyiwnsijwy8578v843x8hh99255s69qwwyld6falv";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1aw6mc7zcmzs1grxz2wa9cw9kfj8pz7zpj417xnp1a9n4ix1bxgr";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-5iYNZATXOePDsLA9lI80o1Gjxw4E+B4bJbwdYJJHcZY=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1mq11xsv9g1vsasp6k80y7xlvwi9hrpk5dgm773fvy8538s01gfv";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1dzg3prng9zfdzz7gcgywjdbwzhwm85j89z0jahynxx4q2dra4b9";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-k3LenomOlacyzq4FlBY/TwV7+ClbK4U0A/O9r0pZHT4=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1chac9b4424ihrrnlzvc7qz6j4ymfjyv4kzyazzzw19yhymdkh2s";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.osx-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "010f8wn15s2kv7yyzgys3pv9i1mxw20hpv1ig2zhybjxs8lpj8jj";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.win-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0i7g9fsqjnbh9rc6807m57r2idg5pkcw6xjfwhnxkcpgqm96258v";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Host.win-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1ssj1cyam3nfidm8q82kvh4i3fzm2lzb3bxw6ck09hwhvwh909z4";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-tu72AwDH1+oAIXjOJcNbeyKm1s4pncYp0avbMSBrcJQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Ref";
|
||||
version = "6.0.26";
|
||||
sha256 = "12gb52dhg5h9hgnyqh1zgj2w46paxv2pfh33pphl9ajhrdr7hlsb";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Ref";
|
||||
version = "8.0.1";
|
||||
sha256 = "02r4jg4ha0qksix9v6s3cpmvavmz54gkawkxy9bvknw5ynxhhl1l";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-BiGUcXo1FQTlZdR6ndhUQ8lrYG3KaGXNXRVF+Fc3L28=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "164hfrwqz5dxcbb441lridk4mzcqmarb0b7ckgvqhsvpawyjw88v";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0353whnjgz3sqhzsfrviad3a3db4pk7hl7m4wwppv5mqdg9i9ri5";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-obRKiJEVpZ5E3TE7q2oHaYwFYhI23rMiHwp+8ORkwXY=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0islayddpnflviqpbq4djc4f3v9nhsa2y76k5x6il3csq5vdw2hq";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1g5b30f4l8a1zjjr3b8pk9mcqxkxqwa86362f84646xaj4iw3a4d";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-2xdhvnKsFc8utDWN09zeXzZ5op+WUqkoWLuzdtQAkrA=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
||||
version = "6.0.26";
|
||||
sha256 = "1acn5zw1pxzmcg3c0pbf9hal36fbdh9mvbsiwra7simrk7hzqpdc";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
|
||||
version = "8.0.1";
|
||||
sha256 = "0cdrpdaq5sl3602anfx1p0z0ncx2sjjvl6mgsd6y38g47n7f95jc";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-9KHubWicibZOcixiByzuBKPnJM2u5DSQC9jR3MAR1bI=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "00f9l9dkdz0zv5csaw8fkm6s8ckrj5n9k3ygz12daa22l3bcn6ii";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "1fk1flqp6ji0l4c2gvh83ykndpx7a2nkkgrgkgql3c75j1k2v1s9";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.win-x64";
|
||||
version = "6.0.26";
|
||||
sha256 = "0i2p356phfc5y6qnr3vyrzjfi1mrbwfb6g85k4q37bbyxjfp7zl9";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.App.Runtime.win-x64";
|
||||
version = "8.0.1";
|
||||
sha256 = "198576cdkl72xs29zznff9ls763p8pfr0zji7b74dqxd5ga0s3bd";
|
||||
version = "6.0.33";
|
||||
hash = "sha256-smh6SiTtCAuFglqWrXiGGsoIDP9dhGuIKdYjmw+xCyY=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.Platforms";
|
||||
version = "1.1.0";
|
||||
sha256 = "08vh1r12g6ykjygq5d3vq09zylgb84l63k49jc4v8faw9g93iqqm";
|
||||
hash = "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.Platforms";
|
||||
version = "1.1.1";
|
||||
sha256 = "164wycgng4mi9zqi2pnsf1pq6gccbqvw6ib916mqizgjmd8f44pj";
|
||||
hash = "sha256-8hLiUKvy/YirCWlFwzdejD2Db3DaXhHxT7GSZx/znJg=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.Platforms";
|
||||
version = "2.0.0";
|
||||
sha256 = "1fk2fk2639i7nzy58m9dvpdnzql4vb8yl8vr19r2fp8lmj9w2jr0";
|
||||
hash = "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.NETCore.Targets";
|
||||
version = "1.1.3";
|
||||
sha256 = "05smkcyxir59rgrmp7d6327vvrlacdgldfxhmyr1azclvga1zfsq";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.SourceLink.Common";
|
||||
version = "8.0.0";
|
||||
sha256 = "0xrr8yd34ij7dqnyddkp2awfmf9qn3c89xmw2f3npaa4wnajmx81";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.SourceLink.GitHub";
|
||||
version = "8.0.0";
|
||||
sha256 = "1gdx7n45wwia3yvang3ls92sk3wrymqcx9p349j8wba2lyjf9m44";
|
||||
hash = "sha256-WLsf1NuUfRWyr7C7Rl9jiua9jximnVvzy6nk2D2bVRc=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||
version = "17.10.0";
|
||||
sha256 = "07j69cw8r39533w4p39mnj00kahazz38760in3jfc45kmlcdb26x";
|
||||
version = "17.11.0";
|
||||
hash = "sha256-mCI3MCV6nyrGLrBat5VvK5LrXTEKlsdp9NkpZyJYwVg=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Microsoft.TestPlatform.TestHost";
|
||||
version = "17.10.0";
|
||||
sha256 = "1bl471s7fx9jycr0cc8rylwf34mrvlg9qn1an6l86nisavfcyb7v";
|
||||
version = "17.11.0";
|
||||
hash = "sha256-gViDLobza22kuLvB4JdlGtbANqwBHRwf1wLmIHMw9Eo=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Myriad.Core";
|
||||
version = "0.8.3";
|
||||
sha256 = "0s5pdckjw4x0qrbd4i3cz9iili5cppg5qnjbr7zjbbhhmxzb24xw";
|
||||
hash = "sha256-vBOxfq8QriX/yUtaXN69rEQaY/psRNJWxqATLidrt2g=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Myriad.Sdk";
|
||||
version = "0.8.3";
|
||||
sha256 = "0qv78c5s5m04xb8h17nnn2ig26zcyya91k2dpj745cm1cbnzvvgc";
|
||||
hash = "sha256-7O397WKhskKOvE3MkJT37BvxorDWngDR6gTUogtDZ2M=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Nerdbank.GitVersioning";
|
||||
version = "3.6.133";
|
||||
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
||||
version = "3.6.143";
|
||||
hash = "sha256-OhOtMzP+2obDIR+npR7SsoXo0KrmcsL+VCE8Z3t5gzQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NETStandard.Library";
|
||||
version = "2.0.3";
|
||||
sha256 = "1fn9fxppfcg4jgypp2pmrpr6awl3qz1xmnri0cygpkwvyx27df1y";
|
||||
hash = "sha256-Prh2RPebz/s8AzHb2sPHg3Jl8s31inv9k+Qxd293ybo=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Newtonsoft.Json";
|
||||
version = "13.0.1";
|
||||
sha256 = "0fijg0w6iwap8gvzyjnndds0q4b8anwxxvik7y8vgq97dram4srb";
|
||||
hash = "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "Newtonsoft.Json";
|
||||
version = "13.0.3";
|
||||
sha256 = "0xrwysmrn4midrjal8g2hr1bbg38iyisl0svamb11arqws4w2bw7";
|
||||
hash = "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Common";
|
||||
version = "6.10.0";
|
||||
sha256 = "0nizrnilmlcqbm945293h8q3wfqfchb4xi8g50x4kjn0rbpd1kbh";
|
||||
version = "6.11.0";
|
||||
hash = "sha256-eb7G07RyZv4AQT6ItRqdBuUf9e9BXcQygsy5RNEXfNE=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Configuration";
|
||||
version = "6.10.0";
|
||||
sha256 = "1aqaknaawnqx4mnvx9qw73wvj48jjzv0d78dzwl7m9zjlrl9myhz";
|
||||
version = "6.11.0";
|
||||
hash = "sha256-2SNZkX64SB15glzQx3k+vI7btr8Yqg4CayaaaK1B0AQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Frameworks";
|
||||
version = "6.10.0";
|
||||
sha256 = "0hrd8y31zx9a0wps49czw0qgbrakb49zn3abfgylc9xrq990zkqk";
|
||||
version = "6.11.0";
|
||||
hash = "sha256-8DC7V2IlCjiMDQ9yWbl7QQHia6OpBrbWh5rL0qa0Opw=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Packaging";
|
||||
version = "6.10.0";
|
||||
sha256 = "18s53cvrf51lihmaqqdf48p2qi6ky1l48jv0hvbp76cxwdg7rba4";
|
||||
version = "6.11.0";
|
||||
hash = "sha256-LVLvxcB6SMdayxAsrc5bCuLLt25fqPr6KfYcYoWWIQk=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Protocol";
|
||||
version = "6.10.0";
|
||||
sha256 = "0hmv4q0ks9i34mfgpb13l01la9v3jjllfh1qd3aqv105xrqrdxac";
|
||||
version = "6.11.0";
|
||||
hash = "sha256-3vdB/8IiJ2LMHhFXLWOzf0H59Ow/zcoq6W4uCHbihCQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NuGet.Versioning";
|
||||
version = "6.10.0";
|
||||
sha256 = "1x19njx4x0sw9fz8y5fibi15xfsrw5avir0cx0599yd7p3ykik5g";
|
||||
version = "6.11.0";
|
||||
hash = "sha256-03edgWvbqUtbzpBBTIxTwsSRoj1T2muGVL+vTuIHXag=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit";
|
||||
version = "4.1.0";
|
||||
sha256 = "0fj6xwgqaxq3mrai86bklclfmjkzf038mrslwfqf4ignaz9f7g5j";
|
||||
version = "4.2.2";
|
||||
hash = "sha256-+0OS67ITalmG9arYCgQF/+YbmPRnB3pIIykew0kvoCc=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "NUnit3TestAdapter";
|
||||
version = "4.5.0";
|
||||
sha256 = "1srx1629s0k1kmf02nmz251q07vj6pv58mdafcr5dr0bbn1fh78i";
|
||||
version = "4.6.0";
|
||||
hash = "sha256-9Yav2fYhC4w0OgsyUwU4/5rDy4FVDTpKnWHuwl/uKJQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "RestEase";
|
||||
version = "1.6.4";
|
||||
sha256 = "1mvi3nbrr450g3fgd1y4wg3bwl9k1agyjfd9wdkqk12714bsln8l";
|
||||
hash = "sha256-FFmqFwlHhIln46k56Z8KM1G+xuPEh/bceKCQnJcdcdc=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "runtime.any.System.Runtime";
|
||||
version = "4.3.0";
|
||||
sha256 = "1cqh1sv3h5j7ixyb7axxbdkqx6cxy00p4np4j91kpm492rf4s25b";
|
||||
hash = "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "runtime.native.System";
|
||||
version = "4.3.0";
|
||||
sha256 = "15hgf6zaq9b8br2wi1i3x0zvmk410nlmsmva9p0bbg73v6hml5k4";
|
||||
hash = "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "runtime.unix.System.Private.Uri";
|
||||
version = "4.3.0";
|
||||
sha256 = "1jx02q6kiwlvfksq1q9qr17fj78y5v6mwsszav4qcz9z25d5g6vk";
|
||||
hash = "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Diagnostics.DiagnosticSource";
|
||||
version = "7.0.0";
|
||||
sha256 = "1jxhvsh5mzdf0sgb4dfmbys1b12ylyr5pcfyj1map354fiq3qsgm";
|
||||
hash = "sha256-9Wk8cHSkjKtqkN6xW7KnXoQVtF/VNbKeBq79WqDesMs=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Formats.Asn1";
|
||||
version = "6.0.0";
|
||||
sha256 = "1vvr7hs4qzjqb37r0w1mxq7xql2b17la63jwvmgv65s1hj00g8r9";
|
||||
hash = "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.IO.Abstractions";
|
||||
version = "4.2.13";
|
||||
sha256 = "0s784iphsmj4vhkrzq9q3w39vsn76w44zclx3hsygsw458zbyh4y";
|
||||
hash = "sha256-nkC/PiqE6+c1HJ2yTwg3x+qdBh844Z8n3ERWDW8k6Gg=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.IO.FileSystem.AccessControl";
|
||||
version = "4.5.0";
|
||||
sha256 = "1gq4s8w7ds1sp8f9wqzf8nrzal40q5cd2w4pkf4fscrl2ih3hkkj";
|
||||
hash = "sha256-ck44YBQ0M+2Im5dw0VjBgFD1s0XuY54cujrodjjSBL8=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Memory";
|
||||
version = "4.5.5";
|
||||
sha256 = "08jsfwimcarfzrhlyvjjid61j02irx6xsklf32rv57x2aaikvx0h";
|
||||
hash = "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Private.Uri";
|
||||
version = "4.3.0";
|
||||
sha256 = "04r1lkdnsznin0fj4ya1zikxiqr0h6r6a1ww2dsm60gqhdrf0mvx";
|
||||
hash = "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Reflection.Metadata";
|
||||
version = "1.6.0";
|
||||
sha256 = "1wdbavrrkajy7qbdblpbpbalbdl48q3h34cchz24gvdgyrlf15r4";
|
||||
hash = "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Runtime";
|
||||
version = "4.3.1";
|
||||
sha256 = "03ch4d2acf6q037a4njxpll2kkx3dwzlg07yxr4z5m6j1kqgmm27";
|
||||
hash = "sha256-R9T68AzS1PJJ7v6ARz9vo88pKL1dWqLOANg4pkQjkA0=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Runtime.CompilerServices.Unsafe";
|
||||
version = "6.0.0";
|
||||
sha256 = "0qm741kh4rh57wky16sq4m0v05fxmkjjr87krycf5vp9f0zbahbc";
|
||||
hash = "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Security.AccessControl";
|
||||
version = "4.5.0";
|
||||
sha256 = "1wvwanz33fzzbnd2jalar0p0z3x0ba53vzx1kazlskp7pwyhlnq0";
|
||||
hash = "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Security.Cryptography.Pkcs";
|
||||
version = "6.0.4";
|
||||
sha256 = "0hh5h38pnxmlrnvs72f2hzzpz4b2caiiv6xf8y7fzdg84r3imvfr";
|
||||
hash = "sha256-2e0aRybote+OR66bHaNiYpF//4fCiaO3zbR2e9GABUI=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Security.Cryptography.ProtectedData";
|
||||
version = "4.4.0";
|
||||
sha256 = "1q8ljvqhasyynp94a1d7jknk946m20lkwy2c3wa8zw2pc517fbj6";
|
||||
hash = "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Security.Principal.Windows";
|
||||
version = "4.5.0";
|
||||
sha256 = "0rmj89wsl5yzwh0kqjgx45vzf694v9p92r4x4q6yxldk1cv1hi86";
|
||||
hash = "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Text.Encodings.Web";
|
||||
version = "7.0.0";
|
||||
sha256 = "1151hbyrcf8kyg1jz8k9awpbic98lwz9x129rg7zk1wrs6vjlpxl";
|
||||
hash = "sha256-tF8qt9GZh/nPy0mEnj6nKLG4Lldpoi/D8xM5lv2CoYQ=";
|
||||
})
|
||||
(fetchNuGet {
|
||||
pname = "System.Text.Json";
|
||||
version = "7.0.3";
|
||||
sha256 = "0zjrnc9lshagm6kdb9bdh45dmlnkpwcpyssa896sda93ngbmj8k9";
|
||||
hash = "sha256-aSJZ17MjqaZNQkprfxm/09LaCoFtpdWmqU9BTROzWX4=";
|
||||
})
|
||||
]
|
||||
|
@@ -1,73 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This file was adapted from
|
||||
# https://github.com/NixOS/nixpkgs/blob/b981d811453ab84fb3ea593a9b33b960f1ab9147/pkgs/build-support/dotnet/build-dotnet-module/default.nix#L173
|
||||
set -euo pipefail
|
||||
export PATH="@binPath@"
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--keep-sources|-k)
|
||||
keepSources=1
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
echo "usage: $0 [--keep-sources] [--help] <output path>"
|
||||
echo " <output path> The path to write the lockfile to. A temporary file is used if this is not set"
|
||||
echo " --keep-sources Don't remove temporary directories upon exit, useful for debugging"
|
||||
echo " --help Show this help message"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
done
|
||||
tmp=$(mktemp -td "@pname@-tmp-XXXXXX")
|
||||
export tmp
|
||||
HOME=$tmp/home
|
||||
exitTrap() {
|
||||
test -n "${ranTrap-}" && return
|
||||
ranTrap=1
|
||||
if test -n "${keepSources-}"; then
|
||||
echo -e "Path to the source: $tmp/src\nPath to the fake home: $tmp/home"
|
||||
else
|
||||
rm -rf "$tmp"
|
||||
fi
|
||||
# Since mktemp is used this will be empty if the script didnt succesfully complete
|
||||
if ! test -s "$depsFile"; then
|
||||
rm -rf "$depsFile"
|
||||
fi
|
||||
}
|
||||
trap exitTrap EXIT INT TERM
|
||||
dotnetRestore() {
|
||||
local -r project="${1-}"
|
||||
local -r rid="$2"
|
||||
dotnet restore "${project-}" \
|
||||
-p:ContinuousIntegrationBuild=true \
|
||||
-p:Deterministic=true \
|
||||
--packages "$tmp/nuget_pkgs" \
|
||||
--runtime "$rid" \
|
||||
--no-cache \
|
||||
--force
|
||||
}
|
||||
declare -a projectFiles=( @projectFiles@ )
|
||||
declare -a testProjectFiles=( @testProjectFiles@ )
|
||||
export DOTNET_NOLOGO=1
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
depsFile=$(realpath "${1:-$(mktemp -t "@pname@-deps-XXXXXX.nix")}")
|
||||
mkdir -p "$tmp/nuget_pkgs"
|
||||
storeSrc="@storeSrc@"
|
||||
src="$tmp/src"
|
||||
cp -rT "$storeSrc" "$src"
|
||||
chmod -R +w "$src"
|
||||
cd "$src"
|
||||
echo "Restoring project..."
|
||||
rids=("@rids@")
|
||||
for rid in "${rids[@]}"; do
|
||||
(( ${#projectFiles[@]} == 0 )) && dotnetRestore "" "$rid"
|
||||
for project in "${projectFiles[@]-}" "${testProjectFiles[@]-}"; do
|
||||
dotnetRestore "$project" "$rid"
|
||||
done
|
||||
done
|
||||
echo "Successfully restored project"
|
||||
echo "Writing lockfile..."
|
||||
echo -e "# This file was automatically generated by passthru.fetch-deps.\n# Please don't edit it manually, your changes might get overwritten!\n" > "$depsFile"
|
||||
nuget-to-nix "$tmp/nuget_pkgs" "@packages@" >> "$depsFile"
|
||||
echo "Successfully wrote lockfile to $depsFile"
|
Reference in New Issue
Block a user