mirror of
				https://github.com/Smaug123/WoofWare.Myriad
				synced 2025-10-27 06:39:00 +00:00 
			
		
		
		
	Compare commits
	
		
			78 Commits
		
	
	
		
			f2922a37a4
			...
			WoofWare.M
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 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 | ||
|  | 6942ba42b9 | ||
|  | b98080690d | ||
|  | 81b7e5361d | ||
|  | 94b88a4143 | ||
|  | ed3ffecb52 | ||
|  | c696dcf31f | ||
|  | d5bb2726d3 | ||
|  | f17290d0f1 | ||
|  | 35cd94cba1 | ||
|  | 1b3eb03380 | ||
|  | b846ce08a3 | ||
|  | 4b9f63d374 | ||
|  | b9ba07a8a7 | ||
|  | e80ed51498 | ||
|  | 61b07ad802 | ||
|  | 59369bcb94 | ||
|  | 072169e4e3 | ||
|  | 91136a25ab | ||
|  | c51038448a | ||
|  | 09780efb07 | ||
|  | f562271c12 | ||
|  | e3081c3136 | ||
|  | 232d2ba5ec | ||
|  | f7458f521e | ||
|  | bfc25a672b | ||
|  | af7fcb3028 | ||
|  | 91853b1fff | ||
|  | 1144e93c1c | ||
|  | d899d77ae2 | ||
|  | a2ad430b2f | ||
|  | 9e36986bc7 | ||
|  | 679c66885d | ||
|  | 246da41672 | ||
|  | d07541c2c2 | ||
|  | 7b49505064 | 
| @@ -3,13 +3,13 @@ | ||||
|   "isRoot": true, | ||||
|   "tools": { | ||||
|     "fantomas": { | ||||
|       "version": "6.3.0-alpha-007", | ||||
|       "version": "6.3.10", | ||||
|       "commands": [ | ||||
|         "fantomas" | ||||
|       ] | ||||
|     }, | ||||
|     "fsharp-analyzers": { | ||||
|       "version": "0.24.0", | ||||
|       "version": "0.26.1", | ||||
|       "commands": [ | ||||
|         "fsharp-analyzers" | ||||
|       ] | ||||
|   | ||||
| @@ -2,7 +2,6 @@ root=true | ||||
|  | ||||
| [*] | ||||
| charset=utf-8 | ||||
| end_of_line=crlf | ||||
| trim_trailing_whitespace=true | ||||
| insert_final_newline=true | ||||
| indent_style=space | ||||
|   | ||||
							
								
								
									
										14
									
								
								.github/workflows/assert-contents.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/assert-contents.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| echo "Unzipping version from NuGet" | ||||
| ls from-nuget.nupkg | ||||
| mkdir from-nuget && cp from-nuget.nupkg from-nuget/zip.zip && cd from-nuget && unzip zip.zip && rm zip.zip && cd - || exit 1 | ||||
|  | ||||
| echo "Unzipping version from local build" | ||||
| ls packed/ | ||||
| mkdir from-local && cp packed/*.nupkg from-local/zip.zip && cd from-local && unzip zip.zip && rm zip.zip && cd - || exit 1 | ||||
|  | ||||
| cd from-local && find . -type f -exec sha256sum {} \; | sort > ../from-local.txt && cd .. || exit 1 | ||||
| cd from-nuget && find . -type f -and -not -name '.signature.p7s' -exec sha256sum {} \; | sort > ../from-nuget.txt && cd .. || exit 1 | ||||
|  | ||||
| diff from-local.txt from-nuget.txt | ||||
							
								
								
									
										223
									
								
								.github/workflows/dotnet.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										223
									
								
								.github/workflows/dotnet.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,4 @@ | ||||
| # yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json | ||||
| name: .NET | ||||
|  | ||||
| on: | ||||
| @@ -28,7 +29,7 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 0 # so that NerdBank.GitVersioning has access to history | ||||
|     - name: Install Nix | ||||
|       uses: cachix/install-nix-action@v25 | ||||
|       uses: cachix/install-nix-action@V27 | ||||
|       with: | ||||
|         extra_nix_config: | | ||||
|           access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -49,7 +50,7 @@ jobs: | ||||
|         with: | ||||
|           fetch-depth: 0 # so that NerdBank.GitVersioning has access to history | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -58,7 +59,7 @@ jobs: | ||||
|       - name: Build project | ||||
|         run: nix develop --command dotnet build ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj | ||||
|       - name: Run analyzers | ||||
|         run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/0.8.0/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001 GRA-DISPBEFOREASYNC-001 --exclude-analyzers PartialAppAnalyzer | ||||
|         run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/*/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001 GRA-DISPBEFOREASYNC-001 --exclude-analyzers PartialAppAnalyzer | ||||
|  | ||||
|   build-nix: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -66,12 +67,14 @@ jobs: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             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 | ||||
| @@ -79,20 +82,41 @@ jobs: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
|       - name: Run Fantomas | ||||
|         run: nix run .#fantomas -- --check . | ||||
|  | ||||
|   check-accurate-generations: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|         with: | ||||
|           fetch-depth: 0 # so that NerdBank.GitVersioning has access to history | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
|       - name: Whitespace change | ||||
|         run: "echo ' ' >> ConsumePlugin/List.fs" | ||||
|       - name: Generate code | ||||
|         run: nix develop --command dotnet build | ||||
|       - name: Run Fantomas | ||||
|         run: nix run .#fantomas -- . | ||||
|       - name: Verify there is no diff | ||||
|         run: git diff --name-only --no-color --exit-code | ||||
|  | ||||
|   check-nix-format: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4 | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -105,7 +129,7 @@ jobs: | ||||
|     steps: | ||||
|       - uses: actions/checkout@master | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -118,7 +142,7 @@ jobs: | ||||
|     steps: | ||||
|       - uses: actions/checkout@master | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -132,7 +156,7 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 0 # so that NerdBank.GitVersioning has access to history | ||||
|     - name: Install Nix | ||||
|       uses: cachix/install-nix-action@v25 | ||||
|       uses: cachix/install-nix-action@V27 | ||||
|       with: | ||||
|         extra_nix_config: | | ||||
|           access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -174,35 +198,174 @@ jobs: | ||||
|         # Verify that there is exactly one nupkg in the artifact that would be NuGet published | ||||
|         run: if [[ $(find packed-attribute -maxdepth 1 -name 'WoofWare.Myriad.Plugins.Attributes.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi | ||||
|  | ||||
|   all-required-checks-complete: | ||||
|     needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack] | ||||
|   github-release-plugin-dry-run: | ||||
|     needs: [nuget-pack] | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - run: echo "All required checks complete." | ||||
|  | ||||
|   nuget-publish: | ||||
|     runs-on: ubuntu-latest | ||||
|     if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }} | ||||
|     needs: [all-required-checks-complete] | ||||
|     environment: main-deploy | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@v25 | ||||
|         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) | ||||
|         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 | ||||
|       - name: Tag and release plugin | ||||
|         env: | ||||
|           DRY_RUN: 1 | ||||
|           GITHUB_TOKEN: mock-token | ||||
|         run: sh .github/workflows/tag.sh | ||||
|  | ||||
|   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: | ||||
|       - uses: Smaug123/all-required-checks-complete-action@05b40a8c47ef0b175ea326e9abb09802cb67b44e | ||||
|         with: | ||||
|           needs-context: ${{ toJSON(needs) }} | ||||
|  | ||||
|   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@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1 | ||||
|         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@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1 | ||||
|         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 | ||||
|         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-attribute | ||||
|           path: packed | ||||
|       - name: Publish to NuGet | ||||
|         id: publish-success | ||||
|         env: | ||||
|           NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} | ||||
|         run: 'nix develop --command bash ./.github/workflows/nuget-push.sh "packed/WoofWare.Myriad.Plugins.Attributes.*.nupkg"' | ||||
|       - name: Wait for availability | ||||
|         if: steps.publish-success.outputs.result == 'published' | ||||
|         env: | ||||
|           PACKAGE_VERSION: ${{ steps.publish-success.outputs.version }} | ||||
|         run: 'echo "$PACKAGE_VERSION" && while ! curl -L --fail -o from-nuget.nupkg "https://www.nuget.org/api/v2/package/WoofWare.Myriad.Plugins.Attributes/$PACKAGE_VERSION" ; do sleep 10; done' | ||||
|       # Astonishingly, NuGet.org considers it to be "more secure" to tamper with my package after upload (https://devblogs.microsoft.com/nuget/introducing-repository-signatures/). | ||||
|       # So we have to *re-attest* it after it's uploaded. Mind-blowing. | ||||
|       - name: Assert package contents | ||||
|         if: steps.publish-success.outputs.result == 'published' | ||||
|         run: 'bash ./.github/workflows/assert-contents.sh' | ||||
|       - name: Attest Build Provenance | ||||
|         if: steps.publish-success.outputs.result == 'published' | ||||
|         uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1 | ||||
|         with: | ||||
|           subject-path: "from-nuget.nupkg" | ||||
|  | ||||
|   nuget-publish-plugin: | ||||
|     runs-on: ubuntu-latest | ||||
|     if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }} | ||||
|     needs: [all-required-checks-complete] | ||||
|     environment: main-deploy | ||||
|     permissions: | ||||
|       id-token: write | ||||
|       attestations: write | ||||
|       contents: read | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - name: Install Nix | ||||
|         uses: cachix/install-nix-action@V27 | ||||
|         with: | ||||
|           extra_nix_config: | | ||||
|             access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} | ||||
|       - name: Download NuGet artifact | ||||
|         uses: actions/download-artifact@v4 | ||||
|         with: | ||||
|           name: nuget-package-plugin | ||||
|           path: packed | ||||
|       - name: Publish to NuGet | ||||
|         id: publish-success | ||||
|         env: | ||||
|           NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} | ||||
|         run: 'nix develop --command bash ./.github/workflows/nuget-push.sh "packed/WoofWare.Myriad.Plugins.*.nupkg"' | ||||
|       - name: Wait for availability | ||||
|         if: steps.publish-success.outputs.result == 'published' | ||||
|         env: | ||||
|           PACKAGE_VERSION: ${{ steps.publish-success.outputs.version }} | ||||
|         run: 'echo "$PACKAGE_VERSION" && while ! curl -L --fail -o from-nuget.nupkg "https://www.nuget.org/api/v2/package/WoofWare.Myriad.Plugins/$PACKAGE_VERSION" ; do sleep 10; done' | ||||
|       # Astonishingly, NuGet.org considers it to be "more secure" to tamper with my package after upload (https://devblogs.microsoft.com/nuget/introducing-repository-signatures/). | ||||
|       # So we have to *re-attest* it after it's uploaded. Mind-blowing. | ||||
|       - name: Assert package contents | ||||
|         if: steps.publish-success.outputs.result == 'published' | ||||
|         run: 'bash ./.github/workflows/assert-contents.sh' | ||||
|       - name: Attest Build Provenance | ||||
|         if: steps.publish-success.outputs.result == 'published' | ||||
|         uses: actions/attest-build-provenance@310b0a4a3b0b78ef57ecda988ee04b132db73ef8 # v1.4.1 | ||||
|         with: | ||||
|           subject-path: "from-nuget.nupkg" | ||||
|  | ||||
|   github-release-plugin: | ||||
|     runs-on: ubuntu-latest | ||||
|     if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }} | ||||
|     needs: [all-required-checks-complete] | ||||
|     environment: main-deploy | ||||
|     permissions: | ||||
|       contents: write | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - name: Download NuGet artifact (plugin) | ||||
|         uses: actions/download-artifact@v4 | ||||
|         with: | ||||
|           name: nuget-package-plugin | ||||
|       - name: Download NuGet artifact (attribute) | ||||
|         uses: actions/download-artifact@v4 | ||||
|         with: | ||||
|           name: nuget-package-attribute | ||||
|       - name: Tag and release plugin | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         run: sh .github/workflows/tag.sh | ||||
|   | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										24
									
								
								.github/workflows/nuget-push.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/nuget-push.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| SOURCE_NUPKG=$(find . -type f -name '*.nupkg') | ||||
|  | ||||
| PACKAGE_VERSION=$(basename "$SOURCE_NUPKG" | rev | cut -d '.' -f 2-4 | rev) | ||||
|  | ||||
| echo "version=$PACKAGE_VERSION" >> "$GITHUB_OUTPUT" | ||||
|  | ||||
| tmp=$(mktemp) | ||||
|  | ||||
| if ! dotnet nuget push "$SOURCE_NUPKG" --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json > "$tmp" ; then | ||||
|     cat "$tmp" | ||||
|     if grep 'already exists and cannot be modified' "$tmp" ; then | ||||
|         echo "result=skipped" >> "$GITHUB_OUTPUT" | ||||
|         exit 0 | ||||
|     else | ||||
|         echo "Unexpected failure to upload" | ||||
|         exit 1 | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| cat "$tmp" | ||||
|  | ||||
| echo "result=published" >> "$GITHUB_OUTPUT" | ||||
							
								
								
									
										120
									
								
								.github/workflows/tag.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								.github/workflows/tag.sh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| echo "Dry-run? $DRY_RUN!" | ||||
|  | ||||
| find . -maxdepth 1 -type f ! -name "$(printf "*\n*")" -name '*.nupkg' | while IFS= read -r file | ||||
| do | ||||
|     tag=$(basename "$file" .nupkg) | ||||
|     git tag "$tag" | ||||
|     ${DRY_RUN:+echo} git push origin "$tag" | ||||
| done | ||||
|  | ||||
| export TAG | ||||
| TAG=$(find . -maxdepth 1 -type f -name 'WoofWare.Myriad.Plugins.*.nupkg' -exec sh -c 'basename "$1" .nupkg' shell {} \; | grep -v Attributes) | ||||
|  | ||||
| case "$TAG" in | ||||
|   *" | ||||
| "*) | ||||
|     echo "Error: TAG contains a newline; multiple plugins found." | ||||
|     exit 1 | ||||
|     ;; | ||||
| esac | ||||
|  | ||||
| # target_commitish empty indicates the repo default branch | ||||
| curl_body='{"tag_name":"'"$TAG"'","target_commitish":"","name":"'"$TAG"'","draft":false,"prerelease":false,"generate_release_notes":false}' | ||||
|  | ||||
| echo "cURL body: $curl_body" | ||||
|  | ||||
| failed_output=$(cat <<'EOF' | ||||
| { | ||||
|   "message": "Validation Failed", | ||||
|   "errors": [ | ||||
|     { | ||||
|       "resource": "Release", | ||||
|       "code": "already_exists", | ||||
|       "field": "tag_name" | ||||
|     } | ||||
|   ], | ||||
|   "documentation_url": "https://docs.github.com/rest/releases/releases#create-a-release" | ||||
| } | ||||
| EOF | ||||
| ) | ||||
|  | ||||
| success_output=$(cat <<'EOF' | ||||
| { | ||||
|   "url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases/158152116", | ||||
|   "assets_url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases/158152116/assets", | ||||
|   "upload_url": "https://uploads.github.com/repos/Smaug123/WoofWare.Myriad/releases/158152116/assets{?name,label}", | ||||
|   "html_url": "https://github.com/Smaug123/WoofWare.Myriad/releases/tag/WoofWare.Myriad.Plugins.2.1.30", | ||||
|   "id": 158152116, | ||||
|   "author": { | ||||
|     "login": "github-actions[bot]", | ||||
|     "id": 41898282, | ||||
|     "node_id": "MDM6Qm90NDE4OTgyODI=", | ||||
|     "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", | ||||
|     "gravatar_id": "", | ||||
|     "url": "https://api.github.com/users/github-actions%5Bbot%5D", | ||||
|     "html_url": "https://github.com/apps/github-actions", | ||||
|     "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", | ||||
|     "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", | ||||
|     "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", | ||||
|     "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", | ||||
|     "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", | ||||
|     "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", | ||||
|     "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", | ||||
|     "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", | ||||
|     "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", | ||||
|     "type": "Bot", | ||||
|     "site_admin": false | ||||
|   }, | ||||
|   "node_id": "RE_kwDOJfksgc4JbTW0", | ||||
|   "tag_name": "WoofWare.Myriad.Plugins.2.1.30", | ||||
|   "target_commitish": "main", | ||||
|   "name": "WoofWare.Myriad.Plugins.2.1.30", | ||||
|   "draft": false, | ||||
|   "prerelease": false, | ||||
|   "created_at": "2024-05-30T11:00:55Z", | ||||
|   "published_at": "2024-05-30T11:03:02Z", | ||||
|   "assets": [ | ||||
|  | ||||
|   ], | ||||
|   "tarball_url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/tarball/WoofWare.Myriad.Plugins.2.1.30", | ||||
|   "zipball_url": "https://api.github.com/repos/Smaug123/WoofWare.Myriad/zipball/WoofWare.Myriad.Plugins.2.1.30", | ||||
|   "body": null | ||||
| } | ||||
| EOF | ||||
| ) | ||||
|  | ||||
| HANDLE_OUTPUT='' | ||||
| handle_error() { | ||||
|     ERROR_OUTPUT="$1" | ||||
|     exit_message=$(echo "$ERROR_OUTPUT" | jq -r --exit-status 'if .errors | length == 1 then .errors[0].code else null end') | ||||
|     if [ "$exit_message" = "already_exists" ] ; then | ||||
|         HANDLE_OUTPUT="Did not create GitHub release because it already exists at this version." | ||||
|     else | ||||
|         echo "Unexpected error output from curl: $(cat curl_output.json)" | ||||
|         echo "JQ output: $(exit_message)" | ||||
|         exit 2 | ||||
|     fi | ||||
| } | ||||
|  | ||||
| run_tests() { | ||||
|     handle_error "$failed_output" | ||||
|     if [ "$HANDLE_OUTPUT" != "Did not create GitHub release because it already exists at this version." ]; then | ||||
|         echo "Bad output from handler: $HANDLE_OUTPUT" | ||||
|         exit 3 | ||||
|     fi | ||||
|     HANDLE_OUTPUT='' | ||||
|     echo "Tests passed." | ||||
| } | ||||
|  | ||||
| run_tests | ||||
|  | ||||
| if [ "$DRY_RUN" != 1 ] ; then | ||||
|     if curl --fail-with-body -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases -d "$curl_body" > curl_output.json; then | ||||
|         echo "Curl succeeded." | ||||
|     else | ||||
|         handle_error "$(cat curl_output.json)" | ||||
|         echo "$HANDLE_OUTPUT" | ||||
|     fi | ||||
| fi | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -10,3 +10,4 @@ result | ||||
| .analyzerpackages/ | ||||
| analysis.sarif | ||||
| .direnv/ | ||||
| .venv/ | ||||
|   | ||||
							
								
								
									
										28
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,6 +1,32 @@ | ||||
| Notable changes are recorded here. | ||||
|  | ||||
| # WoofWare.Myriad.Plugins 1.4 -> 2.0 | ||||
| # 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. | ||||
|  | ||||
| # WoofWare.Myriad.Plugins 2.1.32, WoofWare.Myriad.Plugins.Attributes 3.1.4 | ||||
|  | ||||
| `JsonSerialize` can now serialize many discriminated unions. | ||||
| (This operation is inherently opinionated, because JSON does not model discriminated unions.) | ||||
|  | ||||
| # WoofWare.Myriad.Plugins 2.1.20, WoofWare.Myriad.Plugins.Attributes 3.0.1 | ||||
|  | ||||
| We now bundle copies of the RestEase attributes in `WoofWare.Myriad.Plugins.Attributes`, in case you don't want to take a dependency on RestEase. | ||||
|  | ||||
| # WoofWare.Myriad.Plugins 2.1.15 | ||||
|  | ||||
| The `GenerateMock` generator now permits a limited amount of inheritance in the record we're mocking out (specifically, `IDisposable`). | ||||
|  | ||||
| # WoofWare.Myriad.Plugins 2.1.8 | ||||
|  | ||||
| No change to the packages, but this is when we started creating and tagging GitHub releases, which are a better source of truth than this file. | ||||
|  | ||||
| # WoofWare.Myriad.Plugins 2.0 | ||||
|  | ||||
| This transition split the attributes (e.g. `[<JsonParseAttribute>]`) into their own assembly, WoofWare.Myriad.Plugins.Attributes. | ||||
| The new assembly has minimal dependencies, so you may safely use it from your own code. | ||||
|   | ||||
| @@ -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 = | ||||
|   | ||||
| @@ -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,16 +4,42 @@ | ||||
| //------------------------------------------------------------------------------ | ||||
|  | ||||
|  | ||||
| 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 = | ||||
|         let Thing = | ||||
|         let arg_0 = | ||||
|             (match node.[(Literals.something)] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -23,20 +49,19 @@ module InnerType = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         { | ||||
|             Thing = Thing | ||||
|             Thing = arg_0 | ||||
|         } | ||||
| 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 = | ||||
|         let F = | ||||
|         let arg_5 = | ||||
|             (match node.["f"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -46,10 +71,10 @@ 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 E = | ||||
|         let arg_4 = | ||||
|             (match node.["e"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -59,10 +84,10 @@ 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 D = | ||||
|         let arg_3 = | ||||
|             InnerType.jsonParse ( | ||||
|                 match node.["d"] with | ||||
|                 | null -> | ||||
| @@ -74,7 +99,7 @@ module JsonRecordType = | ||||
|                 | v -> v | ||||
|             ) | ||||
|  | ||||
|         let C = | ||||
|         let arg_2 = | ||||
|             (match node.["hi"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -84,10 +109,10 @@ 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 B = | ||||
|         let arg_1 = | ||||
|             (match node.["another-thing"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -97,9 +122,9 @@ module JsonRecordType = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         let A = | ||||
|         let arg_0 = | ||||
|             (match node.["a"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -109,15 +134,62 @@ module JsonRecordType = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<int> () | ||||
|                 .GetValue<System.Int32> () | ||||
|  | ||||
|         { | ||||
|             A = A | ||||
|             B = B | ||||
|             C = C | ||||
|             D = D | ||||
|             E = E | ||||
|             F = F | ||||
|             A = arg_0 | ||||
|             B = arg_1 | ||||
|             C = arg_2 | ||||
|             D = arg_3 | ||||
|             E = arg_4 | ||||
|             F = arg_5 | ||||
|         } | ||||
| 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 | ||||
|  | ||||
| @@ -129,24 +201,230 @@ module ToGetExtensionMethodJsonParseExtension = | ||||
|  | ||||
|         /// Parse from a JSON node. | ||||
|         static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : ToGetExtensionMethod = | ||||
|             let Sailor = | ||||
|                 (match node.["sailor"] with | ||||
|             let arg_20 = System.Numerics.BigInteger.Parse (node.["whiskey"].ToJsonString ()) | ||||
|  | ||||
|             let arg_19 = | ||||
|                 (match node.["victor"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("sailor") | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("victor") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<float> () | ||||
|                     .GetValue<System.Char> () | ||||
|  | ||||
|             let Soldier = | ||||
|                 (match node.["soldier"] with | ||||
|             let arg_18 = | ||||
|                 (match node.["uniform"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("soldier") | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("uniform") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Decimal> () | ||||
|  | ||||
|             let arg_17 = | ||||
|                 (match node.["tango"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("tango") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.SByte> () | ||||
|  | ||||
|             let arg_16 = | ||||
|                 (match node.["quebec"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("quebec") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Byte> () | ||||
|  | ||||
|             let arg_15 = | ||||
|                 (match node.["papa"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("papa") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Byte> () | ||||
|  | ||||
|             let arg_14 = | ||||
|                 (match node.["oscar"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("oscar") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.SByte> () | ||||
|  | ||||
|             let arg_13 = | ||||
|                 (match node.["november"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("november") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.UInt16> () | ||||
|  | ||||
|             let arg_12 = | ||||
|                 (match node.["mike"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("mike") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Int16> () | ||||
|  | ||||
|             let arg_11 = | ||||
|                 (match node.["lima"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("lima") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.UInt32> () | ||||
|  | ||||
|             let arg_10 = | ||||
|                 (match node.["kilo"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("kilo") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Int32> () | ||||
|  | ||||
|             let arg_9 = | ||||
|                 (match node.["juliette"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("juliette") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.UInt32> () | ||||
|  | ||||
|             let arg_8 = | ||||
|                 (match node.["india"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("india") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Int32> () | ||||
|  | ||||
|             let arg_7 = | ||||
|                 (match node.["hotel"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("hotel") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.UInt64> () | ||||
|  | ||||
|             let arg_6 = | ||||
|                 (match node.["golf"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("golf") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Int64> () | ||||
|  | ||||
|             let arg_5 = | ||||
|                 (match node.["foxtrot"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("foxtrot") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Double> () | ||||
|  | ||||
|             let arg_4 = | ||||
|                 (match node.["echo"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("echo") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Single> () | ||||
|  | ||||
|             let arg_3 = | ||||
|                 (match node.["delta"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("delta") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Single> () | ||||
|  | ||||
|             let arg_2 = | ||||
|                 (match node.["charlie"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("charlie") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<System.Double> () | ||||
|  | ||||
|             let arg_1 = | ||||
|                 (match node.["bravo"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("bravo") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
| @@ -154,33 +432,38 @@ module ToGetExtensionMethodJsonParseExtension = | ||||
|                     .GetValue<string> () | ||||
|                 |> System.Uri | ||||
|  | ||||
|             let Tailor = | ||||
|                 (match node.["tailor"] with | ||||
|             let arg_0 = | ||||
|                 (match node.["alpha"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("tailor") | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("alpha") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<int> () | ||||
|  | ||||
|             let Tinker = | ||||
|                 (match node.["tinker"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("tinker") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<string> () | ||||
|                     .GetValue<System.String> () | ||||
|  | ||||
|             { | ||||
|                 Tinker = Tinker | ||||
|                 Tailor = Tailor | ||||
|                 Soldier = Soldier | ||||
|                 Sailor = Sailor | ||||
|                 Alpha = arg_0 | ||||
|                 Bravo = arg_1 | ||||
|                 Charlie = arg_2 | ||||
|                 Delta = arg_3 | ||||
|                 Echo = arg_4 | ||||
|                 Foxtrot = arg_5 | ||||
|                 Golf = arg_6 | ||||
|                 Hotel = arg_7 | ||||
|                 India = arg_8 | ||||
|                 Juliette = arg_9 | ||||
|                 Kilo = arg_10 | ||||
|                 Lima = arg_11 | ||||
|                 Mike = arg_12 | ||||
|                 November = arg_13 | ||||
|                 Oscar = arg_14 | ||||
|                 Papa = arg_15 | ||||
|                 Quebec = arg_16 | ||||
|                 Tango = arg_17 | ||||
|                 Uniform = arg_18 | ||||
|                 Victor = arg_19 | ||||
|                 Whiskey = arg_20 | ||||
|             } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -18,17 +19,18 @@ type internal PublicTypeMock = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty : PublicTypeMock = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem3 = (fun x -> 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 | ||||
|         member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) | ||||
|         member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0) | ||||
|         member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) | ||||
|         member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -42,17 +44,18 @@ type public PublicTypeInternalFalseMock = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty : PublicTypeInternalFalseMock = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem3 = (fun x -> 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 | ||||
|         member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) | ||||
|         member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0) | ||||
|         member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) | ||||
|         member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -65,15 +68,16 @@ type internal InternalTypeMock = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty : InternalTypeMock = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem2 = (fun x -> 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 | ||||
|         member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) | ||||
|         member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0) | ||||
|         member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -86,15 +90,16 @@ type private PrivateTypeMock = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty : PrivateTypeMock = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem2 = (fun x -> 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 | ||||
|         member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) | ||||
|         member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0) | ||||
|         member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -107,15 +112,16 @@ type private PrivateTypeInternalFalseMock = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty : PrivateTypeInternalFalseMock = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem2 = (fun x -> 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 | ||||
|         member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) | ||||
|         member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0) | ||||
|         member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -127,13 +133,14 @@ type internal VeryPublicTypeMock<'a, 'b> = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty () : VeryPublicTypeMock<'a, 'b> = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) | ||||
|         } | ||||
|  | ||||
|     interface VeryPublicType<'a, 'b> with | ||||
|         member this.Mem1 (arg_0_0) = this.Mem1 (arg_0_0) | ||||
|         member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| @@ -150,18 +157,18 @@ type internal CurriedMock<'a> = | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty () : CurriedMock<'a> = | ||||
|         { | ||||
|             Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem3 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem4 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem5 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function")) | ||||
|             Mem6 = (fun x -> 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 | ||||
|         member this.Mem1 (arg_0_0) (arg_1_0) = this.Mem1 (arg_0_0) (arg_1_0) | ||||
|         member this.Mem2 (arg_0_0, arg_0_1) (arg_1_0) = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0) | ||||
|         member this.Mem3 ((arg_0_0, arg_0_1)) (arg_1_0) = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0) | ||||
|         member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0) | ||||
|         member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0) | ||||
|         member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0) | ||||
|  | ||||
|         member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) = | ||||
|             this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) | ||||
| @@ -171,3 +178,31 @@ type internal CurriedMock<'a> = | ||||
|  | ||||
|         member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) = | ||||
|             this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| /// Mock record type for an interface | ||||
| type internal TypeWithInterfaceMock = | ||||
|     { | ||||
|         /// Implementation of IDisposable.Dispose | ||||
|         Dispose : unit -> unit | ||||
|         Mem1 : string option -> string[] Async | ||||
|         Mem2 : unit -> string[] Async | ||||
|     } | ||||
|  | ||||
|     /// An implementation where every method throws. | ||||
|     static member Empty : TypeWithInterfaceMock = | ||||
|         { | ||||
|             Dispose = (fun () -> ()) | ||||
|             Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) | ||||
|             Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) | ||||
|         } | ||||
|  | ||||
|     interface TypeWithInterface with | ||||
|         member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) | ||||
|         member this.Mem2 () = this.Mem2 (()) | ||||
|  | ||||
|     interface System.IDisposable with | ||||
|         member this.Dispose () : unit = this.Dispose () | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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 = | ||||
| @@ -87,6 +86,40 @@ module PureGymApi = | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|  | ||||
|             member _.GetGymAttendance' (gymId : int, ct : CancellationToken option) = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
|  | ||||
|                     let uri = | ||||
|                         System.Uri ( | ||||
|                             (match client.BaseAddress with | ||||
|                              | null -> System.Uri "https://whatnot.com" | ||||
|                              | v -> v), | ||||
|                             System.Uri ( | ||||
|                                 "v1/gyms/{gym_id}/attendance" | ||||
|                                     .Replace ("{gym_id}", gymId.ToString () |> System.Web.HttpUtility.UrlEncode), | ||||
|                                 System.UriKind.Relative | ||||
|                             ) | ||||
|                         ) | ||||
|  | ||||
|                     let httpMessage = | ||||
|                         new System.Net.Http.HttpRequestMessage ( | ||||
|                             Method = System.Net.Http.HttpMethod.Get, | ||||
|                             RequestUri = uri | ||||
|                         ) | ||||
|  | ||||
|                     let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                     let response = response.EnsureSuccessStatusCode () | ||||
|                     let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask | ||||
|  | ||||
|                     let! jsonNode = | ||||
|                         System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) | ||||
|                         |> Async.AwaitTask | ||||
|  | ||||
|                     return GymAttendance.jsonParse jsonNode | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|  | ||||
|             member _.GetMember (ct : CancellationToken option) = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
| @@ -269,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 | ||||
| @@ -288,7 +321,52 @@ module PureGymApi = | ||||
|                              | v -> v), | ||||
|                             System.Uri ( | ||||
|                                 ("/v2/gymSessions/member" | ||||
|                                  + "?fromDate=" | ||||
|                                  + (if "/v2/gymSessions/member".IndexOf (char 63) >= 0 then | ||||
|                                         "&" | ||||
|                                     else | ||||
|                                         "?") | ||||
|                                  + "fromDate=" | ||||
|                                  + ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode) | ||||
|                                  + "&toDate=" | ||||
|                                  + ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)), | ||||
|                                 System.UriKind.Relative | ||||
|                             ) | ||||
|                         ) | ||||
|  | ||||
|                     let httpMessage = | ||||
|                         new System.Net.Http.HttpRequestMessage ( | ||||
|                             Method = System.Net.Http.HttpMethod.Get, | ||||
|                             RequestUri = uri | ||||
|                         ) | ||||
|  | ||||
|                     let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                     let response = response.EnsureSuccessStatusCode () | ||||
|                     let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask | ||||
|  | ||||
|                     let! jsonNode = | ||||
|                         System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) | ||||
|                         |> Async.AwaitTask | ||||
|  | ||||
|                     return Sessions.jsonParse jsonNode | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|  | ||||
|             member _.GetSessionsWithQuery (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
|  | ||||
|                     let uri = | ||||
|                         System.Uri ( | ||||
|                             (match client.BaseAddress with | ||||
|                              | null -> System.Uri "https://whatnot.com" | ||||
|                              | v -> v), | ||||
|                             System.Uri ( | ||||
|                                 ("/v2/gymSessions/member?foo=1" | ||||
|                                  + (if "/v2/gymSessions/member?foo=1".IndexOf (char 63) >= 0 then | ||||
|                                         "&" | ||||
|                                     else | ||||
|                                         "?") | ||||
|                                  + "fromDate=" | ||||
|                                  + ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode) | ||||
|                                  + "&toDate=" | ||||
|                                  + ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)), | ||||
| @@ -976,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 = | ||||
| @@ -1028,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 = | ||||
| @@ -1080,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 = | ||||
| @@ -1126,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 | ||||
| @@ -1140,6 +1214,68 @@ module ApiWithHeaders = | ||||
|             member _.SomeHeader : string = someHeader () | ||||
|             member _.SomeOtherHeader : int = someOtherHeader () | ||||
|  | ||||
|             member this.GetPathParam (parameter : string, ct : CancellationToken option) = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
|  | ||||
|                     let uri = | ||||
|                         System.Uri ( | ||||
|                             (match client.BaseAddress with | ||||
|                              | null -> | ||||
|                                  raise ( | ||||
|                                      System.ArgumentNullException ( | ||||
|                                          nameof (client.BaseAddress), | ||||
|                                          "No base address was supplied on the type, and no BaseAddress was on the HttpClient." | ||||
|                                      ) | ||||
|                                  ) | ||||
|                              | v -> v), | ||||
|                             System.Uri ( | ||||
|                                 "endpoint/{param}" | ||||
|                                     .Replace ("{param}", parameter.ToString () |> System.Web.HttpUtility.UrlEncode), | ||||
|                                 System.UriKind.Relative | ||||
|                             ) | ||||
|                         ) | ||||
|  | ||||
|                     let httpMessage = | ||||
|                         new System.Net.Http.HttpRequestMessage ( | ||||
|                             Method = System.Net.Http.HttpMethod.Get, | ||||
|                             RequestUri = uri | ||||
|                         ) | ||||
|  | ||||
|                     do httpMessage.Headers.Add ("X-Foo", this.SomeHeader.ToString ()) | ||||
|                     do httpMessage.Headers.Add ("Authorization", this.SomeOtherHeader.ToString ()) | ||||
|                     do httpMessage.Headers.Add ("Header-Name", "Header-Value") | ||||
|                     let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                     let response = response.EnsureSuccessStatusCode () | ||||
|                     let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask | ||||
|                     return responseString | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|         } | ||||
| namespace PureGym | ||||
|  | ||||
| open System | ||||
| open System.Threading | ||||
| open System.Threading.Tasks | ||||
| open System.IO | ||||
| open System.Net | ||||
| open System.Net.Http | ||||
| open RestEase | ||||
|  | ||||
| /// Module for constructing a REST client. | ||||
| [<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 | ||||
|         (someHeader : unit -> string) | ||||
|         (someOtherHeader : unit -> int) | ||||
|         (client : System.Net.Http.HttpClient) | ||||
|         : IApiWithHeaders2 | ||||
|         = | ||||
|         { new IApiWithHeaders2 with | ||||
|             member _.SomeHeader : string = someHeader () | ||||
|             member _.SomeOtherHeader : int = someOtherHeader () | ||||
|  | ||||
|             member this.GetPathParam (parameter : string, ct : CancellationToken option) = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
|   | ||||
| @@ -21,24 +21,25 @@ 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 -> | ||||
|                     (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) | ||||
|  | ||||
|                          ret | ||||
|                     ) | ||||
|                         input.Map | ||||
|                      )) | ||||
|                 ) | ||||
|  | ||||
|                 node.Add ( | ||||
|                     "readOnlyDict", | ||||
|                     (fun field -> | ||||
|                     (input.ReadOnlyDict | ||||
|                      |> (fun field -> | ||||
|                          let ret = System.Text.Json.Nodes.JsonObject () | ||||
|  | ||||
|                          for (KeyValue (key, value)) in field do | ||||
| @@ -56,34 +57,33 @@ module InnerTypeWithBothJsonSerializeExtension = | ||||
|                              ) | ||||
|  | ||||
|                          ret | ||||
|                     ) | ||||
|                         input.ReadOnlyDict | ||||
|                      )) | ||||
|                 ) | ||||
|  | ||||
|                 node.Add ( | ||||
|                     "dict", | ||||
|                     (fun field -> | ||||
|                     (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) | ||||
|  | ||||
|                          ret | ||||
|                     ) | ||||
|                         input.Dict | ||||
|                      )) | ||||
|                 ) | ||||
|  | ||||
|                 node.Add ( | ||||
|                     "concreteDict", | ||||
|                     (fun field -> | ||||
|                     (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) | ||||
|  | ||||
|                          ret | ||||
|                     ) | ||||
|                         input.ConcreteDict | ||||
|                      )) | ||||
|                 ) | ||||
|  | ||||
|             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,172 @@ 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 -> | ||||
|                     (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) | ||||
|  | ||||
|                          arr | ||||
|                     ) | ||||
|                         input.C | ||||
|                      )) | ||||
|                 ) | ||||
|  | ||||
|                 node.Add ("d", InnerTypeWithBoth.toJsonNode input.D) | ||||
|                 node.Add ("d", (input.D |> InnerTypeWithBoth.toJsonNode)) | ||||
|  | ||||
|                 node.Add ( | ||||
|                     "e", | ||||
|                     (fun field -> | ||||
|                     (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) | ||||
|  | ||||
|                          arr | ||||
|                     ) | ||||
|                         input.E | ||||
|                      )) | ||||
|                 ) | ||||
|  | ||||
|                 node.Add ( | ||||
|                     "f", | ||||
|                     (fun field -> | ||||
|                     "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) | ||||
|  | ||||
|                          arr | ||||
|                      )) | ||||
|                 ) | ||||
|                         input.F | ||||
|  | ||||
|                 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 :> _ | ||||
| namespace ConsumePlugin | ||||
|  | ||||
| open System | ||||
| open System.Collections.Generic | ||||
| open System.Text.Json.Serialization | ||||
|  | ||||
| /// Module containing JSON serializing extension members for the FirstDu type | ||||
| [<AutoOpen>] | ||||
| module FirstDuJsonSerializeExtension = | ||||
|     /// Extension methods for JSON parsing | ||||
|     type FirstDu with | ||||
|  | ||||
|         /// Serialize to a JSON node | ||||
|         static member toJsonNode (input : FirstDu) : System.Text.Json.Nodes.JsonNode = | ||||
|             let node = System.Text.Json.Nodes.JsonObject () | ||||
|  | ||||
|             match input with | ||||
|             | FirstDu.EmptyCase -> node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "emptyCase") | ||||
|             | FirstDu.Case1 arg0 -> | ||||
|                 node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case1") | ||||
|                 let dataNode = System.Text.Json.Nodes.JsonObject () | ||||
|                 dataNode.Add ("data", System.Text.Json.Nodes.JsonValue.Create<string> arg0) | ||||
|                 node.Add ("data", dataNode) | ||||
|             | FirstDu.Case2 (arg0, arg1) -> | ||||
|                 node.Add ("type", System.Text.Json.Nodes.JsonValue.Create "case2") | ||||
|                 let dataNode = System.Text.Json.Nodes.JsonObject () | ||||
|                 dataNode.Add ("record", JsonRecordTypeWithBoth.toJsonNode arg0) | ||||
|                 dataNode.Add ("i", System.Text.Json.Nodes.JsonValue.Create<int> arg1) | ||||
|                 node.Add ("data", dataNode) | ||||
|  | ||||
|             node :> _ | ||||
| namespace ConsumePlugin | ||||
|  | ||||
| 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 :> _ | ||||
| @@ -160,7 +302,7 @@ module InnerTypeWithBothJsonParseExtension = | ||||
|  | ||||
|         /// Parse from a JSON node. | ||||
|         static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : InnerTypeWithBoth = | ||||
|             let ConcreteDict = | ||||
|             let arg_4 = | ||||
|                 (match node.["concreteDict"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -178,7 +320,7 @@ module InnerTypeWithBothJsonParseExtension = | ||||
|                 |> Seq.map System.Collections.Generic.KeyValuePair | ||||
|                 |> System.Collections.Generic.Dictionary | ||||
|  | ||||
|             let Dict = | ||||
|             let arg_3 = | ||||
|                 (match node.["dict"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -190,12 +332,12 @@ 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 | ||||
|  | ||||
|             let ReadOnlyDict = | ||||
|             let arg_2 = | ||||
|                 (match node.["readOnlyDict"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -210,14 +352,14 @@ module InnerTypeWithBothJsonParseExtension = | ||||
|  | ||||
|                     let value = | ||||
|                         (kvp.Value).AsArray () | ||||
|                         |> Seq.map (fun elt -> elt.AsValue().GetValue<char> ()) | ||||
|                         |> Seq.map (fun elt -> elt.AsValue().GetValue<System.Char> ()) | ||||
|                         |> List.ofSeq | ||||
|  | ||||
|                     key, value | ||||
|                 ) | ||||
|                 |> readOnlyDict | ||||
|  | ||||
|             let Map = | ||||
|             let arg_1 = | ||||
|                 (match node.["map"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -234,7 +376,7 @@ module InnerTypeWithBothJsonParseExtension = | ||||
|                 ) | ||||
|                 |> Map.ofSeq | ||||
|  | ||||
|             let Thing = | ||||
|             let arg_0 = | ||||
|                 (match node.[("it's-a-me")] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -248,14 +390,32 @@ module InnerTypeWithBothJsonParseExtension = | ||||
|                 |> System.Guid.Parse | ||||
|  | ||||
|             { | ||||
|                 Thing = Thing | ||||
|                 Map = Map | ||||
|                 ReadOnlyDict = ReadOnlyDict | ||||
|                 Dict = Dict | ||||
|                 ConcreteDict = ConcreteDict | ||||
|                 Thing = arg_0 | ||||
|                 Map = arg_1 | ||||
|                 ReadOnlyDict = arg_2 | ||||
|                 Dict = arg_3 | ||||
|                 ConcreteDict = arg_4 | ||||
|             } | ||||
| 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 = | ||||
| @@ -264,7 +424,74 @@ module JsonRecordTypeWithBothJsonParseExtension = | ||||
|  | ||||
|         /// Parse from a JSON node. | ||||
|         static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : JsonRecordTypeWithBoth = | ||||
|             let F = | ||||
|             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 ( | ||||
| @@ -272,12 +499,129 @@ 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 E = | ||||
|             let arg_4 = | ||||
|                 (match node.["e"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -287,10 +631,10 @@ 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 D = | ||||
|             let arg_3 = | ||||
|                 InnerTypeWithBoth.jsonParse ( | ||||
|                     match node.["d"] with | ||||
|                     | null -> | ||||
| @@ -302,7 +646,7 @@ module JsonRecordTypeWithBothJsonParseExtension = | ||||
|                     | v -> v | ||||
|                 ) | ||||
|  | ||||
|             let C = | ||||
|             let arg_2 = | ||||
|                 (match node.["c"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -312,10 +656,10 @@ 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 B = | ||||
|             let arg_1 = | ||||
|                 (match node.["b"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -325,9 +669,9 @@ module JsonRecordTypeWithBothJsonParseExtension = | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<string> () | ||||
|                     .GetValue<System.String> () | ||||
|  | ||||
|             let A = | ||||
|             let arg_0 = | ||||
|                 (match node.["a"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
| @@ -337,13 +681,164 @@ module JsonRecordTypeWithBothJsonParseExtension = | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                     .AsValue() | ||||
|                     .GetValue<int> () | ||||
|                     .GetValue<System.Int32> () | ||||
|  | ||||
|             { | ||||
|                 A = A | ||||
|                 B = B | ||||
|                 C = C | ||||
|                 D = D | ||||
|                 E = E | ||||
|                 F = F | ||||
|                 A = arg_0 | ||||
|                 B = arg_1 | ||||
|                 C = arg_2 | ||||
|                 D = arg_3 | ||||
|                 E = arg_4 | ||||
|                 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 | ||||
|  | ||||
| /// Module containing JSON parsing extension members for the FirstDu type | ||||
| [<AutoOpen>] | ||||
| module FirstDuJsonParseExtension = | ||||
|     /// Extension methods for JSON parsing | ||||
|     type FirstDu with | ||||
|  | ||||
|         /// Parse from a JSON node. | ||||
|         static member jsonParse (node : System.Text.Json.Nodes.JsonNode) : FirstDu = | ||||
|             let ty = | ||||
|                 (match node.["type"] with | ||||
|                  | null -> | ||||
|                      raise ( | ||||
|                          System.Collections.Generic.KeyNotFoundException ( | ||||
|                              sprintf "Required key '%s' not found on JSON object" ("type") | ||||
|                          ) | ||||
|                      ) | ||||
|                  | v -> v) | ||||
|                 |> (fun v -> v.GetValue<string> ()) | ||||
|  | ||||
|             match ty with | ||||
|             | "emptyCase" -> FirstDu.EmptyCase | ||||
|             | "case1" -> | ||||
|                 let node = | ||||
|                     (match node.["data"] with | ||||
|                      | null -> | ||||
|                          raise ( | ||||
|                              System.Collections.Generic.KeyNotFoundException ( | ||||
|                                  sprintf "Required key '%s' not found on JSON object" ("data") | ||||
|                              ) | ||||
|                          ) | ||||
|                      | v -> v) | ||||
|  | ||||
|                 FirstDu.Case1 ( | ||||
|                     (match node.["data"] with | ||||
|                      | null -> | ||||
|                          raise ( | ||||
|                              System.Collections.Generic.KeyNotFoundException ( | ||||
|                                  sprintf "Required key '%s' not found on JSON object" ("data") | ||||
|                              ) | ||||
|                          ) | ||||
|                      | v -> v) | ||||
|                         .AsValue() | ||||
|                         .GetValue<System.String> () | ||||
|                 ) | ||||
|             | "case2" -> | ||||
|                 let node = | ||||
|                     (match node.["data"] with | ||||
|                      | null -> | ||||
|                          raise ( | ||||
|                              System.Collections.Generic.KeyNotFoundException ( | ||||
|                                  sprintf "Required key '%s' not found on JSON object" ("data") | ||||
|                              ) | ||||
|                          ) | ||||
|                      | v -> v) | ||||
|  | ||||
|                 FirstDu.Case2 ( | ||||
|                     JsonRecordTypeWithBoth.jsonParse ( | ||||
|                         match node.["record"] with | ||||
|                         | null -> | ||||
|                             raise ( | ||||
|                                 System.Collections.Generic.KeyNotFoundException ( | ||||
|                                     sprintf "Required key '%s' not found on JSON object" ("record") | ||||
|                                 ) | ||||
|                             ) | ||||
|                         | v -> v | ||||
|                     ), | ||||
|                     (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> () | ||||
|                 ) | ||||
|             | 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,12 +8,11 @@ | ||||
| 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 = | ||||
|         let NumUses = | ||||
|         let arg_10 = | ||||
|             (match node.["num_uses"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -23,9 +22,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<int> () | ||||
|                 .GetValue<System.Int32> () | ||||
|  | ||||
|         let Orphan = | ||||
|         let arg_9 = | ||||
|             (match node.["orphan"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -35,9 +34,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<bool> () | ||||
|                 .GetValue<System.Boolean> () | ||||
|  | ||||
|         let EntityId = | ||||
|         let arg_8 = | ||||
|             (match node.["entity_id"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -47,9 +46,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         let TokenType = | ||||
|         let arg_7 = | ||||
|             (match node.["token_type"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -59,9 +58,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         let Renewable = | ||||
|         let arg_6 = | ||||
|             (match node.["renewable"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -71,9 +70,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<bool> () | ||||
|                 .GetValue<System.Boolean> () | ||||
|  | ||||
|         let LeaseDuration = | ||||
|         let arg_5 = | ||||
|             (match node.["lease_duration"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -83,9 +82,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<int> () | ||||
|                 .GetValue<System.Int32> () | ||||
|  | ||||
|         let IdentityPolicies = | ||||
|         let arg_4 = | ||||
|             (match node.["identity_policies"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -95,10 +94,10 @@ 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 TokenPolicies = | ||||
|         let arg_3 = | ||||
|             (match node.["token_policies"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -108,10 +107,10 @@ 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 Policies = | ||||
|         let arg_2 = | ||||
|             (match node.["policies"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -121,10 +120,10 @@ 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 Accessor = | ||||
|         let arg_1 = | ||||
|             (match node.["accessor"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -134,9 +133,9 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         let ClientToken = | ||||
|         let arg_0 = | ||||
|             (match node.["client_token"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -146,30 +145,29 @@ module JwtVaultAuthResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         { | ||||
|             ClientToken = ClientToken | ||||
|             Accessor = Accessor | ||||
|             Policies = Policies | ||||
|             TokenPolicies = TokenPolicies | ||||
|             IdentityPolicies = IdentityPolicies | ||||
|             LeaseDuration = LeaseDuration | ||||
|             Renewable = Renewable | ||||
|             TokenType = TokenType | ||||
|             EntityId = EntityId | ||||
|             Orphan = Orphan | ||||
|             NumUses = NumUses | ||||
|             ClientToken = arg_0 | ||||
|             Accessor = arg_1 | ||||
|             Policies = arg_2 | ||||
|             TokenPolicies = arg_3 | ||||
|             IdentityPolicies = arg_4 | ||||
|             LeaseDuration = arg_5 | ||||
|             Renewable = arg_6 | ||||
|             TokenType = arg_7 | ||||
|             EntityId = arg_8 | ||||
|             Orphan = arg_9 | ||||
|             NumUses = arg_10 | ||||
|         } | ||||
| 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 = | ||||
|         let Auth = | ||||
|         let arg_4 = | ||||
|             JwtVaultAuthResponse.jsonParse ( | ||||
|                 match node.["auth"] with | ||||
|                 | null -> | ||||
| @@ -181,7 +179,7 @@ module JwtVaultResponse = | ||||
|                 | v -> v | ||||
|             ) | ||||
|  | ||||
|         let LeaseDuration = | ||||
|         let arg_3 = | ||||
|             (match node.["lease_duration"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -191,9 +189,9 @@ module JwtVaultResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<int> () | ||||
|                 .GetValue<System.Int32> () | ||||
|  | ||||
|         let Renewable = | ||||
|         let arg_2 = | ||||
|             (match node.["renewable"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -203,9 +201,9 @@ module JwtVaultResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<bool> () | ||||
|                 .GetValue<System.Boolean> () | ||||
|  | ||||
|         let LeaseId = | ||||
|         let arg_1 = | ||||
|             (match node.["lease_id"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -215,9 +213,9 @@ module JwtVaultResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         let RequestId = | ||||
|         let arg_0 = | ||||
|             (match node.["request_id"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -227,24 +225,23 @@ module JwtVaultResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         { | ||||
|             RequestId = RequestId | ||||
|             LeaseId = LeaseId | ||||
|             Renewable = Renewable | ||||
|             LeaseDuration = LeaseDuration | ||||
|             Auth = Auth | ||||
|             RequestId = arg_0 | ||||
|             LeaseId = arg_1 | ||||
|             Renewable = arg_2 | ||||
|             LeaseDuration = arg_3 | ||||
|             Auth = arg_4 | ||||
|         } | ||||
| 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 = | ||||
|         let Data8 = | ||||
|         let arg_11 = | ||||
|             (match node.["data8"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -262,7 +259,7 @@ module JwtSecretResponse = | ||||
|             |> Seq.map System.Collections.Generic.KeyValuePair | ||||
|             |> System.Collections.Generic.Dictionary | ||||
|  | ||||
|         let Data7 = | ||||
|         let arg_10 = | ||||
|             (match node.["data7"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -274,12 +271,12 @@ 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 | ||||
|  | ||||
|         let Data6 = | ||||
|         let arg_9 = | ||||
|             (match node.["data6"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -291,12 +288,12 @@ 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 | ||||
|  | ||||
|         let Data5 = | ||||
|         let arg_8 = | ||||
|             (match node.["data5"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -308,12 +305,12 @@ 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 | ||||
|  | ||||
|         let Data4 = | ||||
|         let arg_7 = | ||||
|             (match node.["data4"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -325,12 +322,12 @@ 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 | ||||
|  | ||||
|         let Data3 = | ||||
|         let arg_6 = | ||||
|             (match node.["data3"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -342,13 +339,13 @@ 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 | ||||
|             |> System.Collections.Generic.Dictionary | ||||
|  | ||||
|         let Data2 = | ||||
|         let arg_5 = | ||||
|             (match node.["data2"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -360,12 +357,12 @@ 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 | ||||
|  | ||||
|         let Data = | ||||
|         let arg_4 = | ||||
|             (match node.["data"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -377,12 +374,12 @@ 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 | ||||
|  | ||||
|         let LeaseDuration = | ||||
|         let arg_3 = | ||||
|             (match node.["lease_duration"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -392,9 +389,9 @@ module JwtSecretResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<int> () | ||||
|                 .GetValue<System.Int32> () | ||||
|  | ||||
|         let Renewable = | ||||
|         let arg_2 = | ||||
|             (match node.["renewable"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -404,9 +401,9 @@ module JwtSecretResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<bool> () | ||||
|                 .GetValue<System.Boolean> () | ||||
|  | ||||
|         let LeaseId = | ||||
|         let arg_1 = | ||||
|             (match node.["lease_id"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -416,9 +413,9 @@ module JwtSecretResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         let RequestId = | ||||
|         let arg_0 = | ||||
|             (match node.["request_id"] with | ||||
|              | null -> | ||||
|                  raise ( | ||||
| @@ -428,21 +425,21 @@ module JwtSecretResponse = | ||||
|                  ) | ||||
|              | v -> v) | ||||
|                 .AsValue() | ||||
|                 .GetValue<string> () | ||||
|                 .GetValue<System.String> () | ||||
|  | ||||
|         { | ||||
|             RequestId = RequestId | ||||
|             LeaseId = LeaseId | ||||
|             Renewable = Renewable | ||||
|             LeaseDuration = LeaseDuration | ||||
|             Data = Data | ||||
|             Data2 = Data2 | ||||
|             Data3 = Data3 | ||||
|             Data4 = Data4 | ||||
|             Data5 = Data5 | ||||
|             Data6 = Data6 | ||||
|             Data7 = Data7 | ||||
|             Data8 = Data8 | ||||
|             RequestId = arg_0 | ||||
|             LeaseId = arg_1 | ||||
|             Renewable = arg_2 | ||||
|             LeaseDuration = arg_3 | ||||
|             Data = arg_4 | ||||
|             Data2 = arg_5 | ||||
|             Data3 = arg_6 | ||||
|             Data4 = arg_7 | ||||
|             Data5 = arg_8 | ||||
|             Data6 = arg_9 | ||||
|             Data7 = arg_10 | ||||
|             Data8 = arg_11 | ||||
|         } | ||||
|  | ||||
| namespace ConsumePlugin | ||||
| @@ -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 = | ||||
| @@ -543,3 +539,200 @@ module VaultClient = | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|         } | ||||
| namespace ConsumePlugin | ||||
|  | ||||
| open System | ||||
| open System.Collections.Generic | ||||
| open System.Text.Json.Serialization | ||||
| open System.Threading | ||||
| open System.Threading.Tasks | ||||
| open RestEase | ||||
|  | ||||
| /// Module for constructing a REST client. | ||||
| [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>] | ||||
| module VaultClientNonExtensionMethod = | ||||
|     /// Create a REST client. | ||||
|     let make (client : System.Net.Http.HttpClient) : IVaultClientNonExtensionMethod = | ||||
|         { new IVaultClientNonExtensionMethod with | ||||
|             member _.GetSecret | ||||
|                 (jwt : JwtVaultResponse, path : string, mountPoint : string, ct : CancellationToken option) | ||||
|                 = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
|  | ||||
|                     let uri = | ||||
|                         System.Uri ( | ||||
|                             (match client.BaseAddress with | ||||
|                              | null -> | ||||
|                                  raise ( | ||||
|                                      System.ArgumentNullException ( | ||||
|                                          nameof (client.BaseAddress), | ||||
|                                          "No base address was supplied on the type, and no BaseAddress was on the HttpClient." | ||||
|                                      ) | ||||
|                                  ) | ||||
|                              | v -> v), | ||||
|                             System.Uri ( | ||||
|                                 "v1/{mountPoint}/{path}" | ||||
|                                     .Replace("{path}", path.ToString () |> System.Web.HttpUtility.UrlEncode) | ||||
|                                     .Replace ( | ||||
|                                         "{mountPoint}", | ||||
|                                         mountPoint.ToString () |> System.Web.HttpUtility.UrlEncode | ||||
|                                     ), | ||||
|                                 System.UriKind.Relative | ||||
|                             ) | ||||
|                         ) | ||||
|  | ||||
|                     let httpMessage = | ||||
|                         new System.Net.Http.HttpRequestMessage ( | ||||
|                             Method = System.Net.Http.HttpMethod.Get, | ||||
|                             RequestUri = uri | ||||
|                         ) | ||||
|  | ||||
|                     let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                     let response = response.EnsureSuccessStatusCode () | ||||
|                     let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask | ||||
|  | ||||
|                     let! jsonNode = | ||||
|                         System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) | ||||
|                         |> Async.AwaitTask | ||||
|  | ||||
|                     return JwtSecretResponse.jsonParse jsonNode | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|  | ||||
|             member _.GetJwt (role : string, jwt : string, ct : CancellationToken option) = | ||||
|                 async { | ||||
|                     let! ct = Async.CancellationToken | ||||
|  | ||||
|                     let uri = | ||||
|                         System.Uri ( | ||||
|                             (match client.BaseAddress with | ||||
|                              | null -> | ||||
|                                  raise ( | ||||
|                                      System.ArgumentNullException ( | ||||
|                                          nameof (client.BaseAddress), | ||||
|                                          "No base address was supplied on the type, and no BaseAddress was on the HttpClient." | ||||
|                                      ) | ||||
|                                  ) | ||||
|                              | v -> v), | ||||
|                             System.Uri ("v1/auth/jwt/login", System.UriKind.Relative) | ||||
|                         ) | ||||
|  | ||||
|                     let httpMessage = | ||||
|                         new System.Net.Http.HttpRequestMessage ( | ||||
|                             Method = System.Net.Http.HttpMethod.Get, | ||||
|                             RequestUri = uri | ||||
|                         ) | ||||
|  | ||||
|                     let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                     let response = response.EnsureSuccessStatusCode () | ||||
|                     let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask | ||||
|  | ||||
|                     let! jsonNode = | ||||
|                         System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) | ||||
|                         |> Async.AwaitTask | ||||
|  | ||||
|                     return JwtVaultResponse.jsonParse jsonNode | ||||
|                 } | ||||
|                 |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|         } | ||||
| namespace ConsumePlugin | ||||
|  | ||||
| open System | ||||
| open System.Collections.Generic | ||||
| open System.Text.Json.Serialization | ||||
| open System.Threading | ||||
| open System.Threading.Tasks | ||||
| open RestEase | ||||
|  | ||||
| /// Extension methods for constructing a REST client. | ||||
| [<AutoOpen>] | ||||
| module VaultClientExtensionMethodHttpClientExtension = | ||||
|     /// Extension methods for HTTP clients | ||||
|     type VaultClientExtensionMethod with | ||||
|  | ||||
|         /// Create a REST client. | ||||
|         static member make (client : System.Net.Http.HttpClient) : IVaultClientExtensionMethod = | ||||
|             { new IVaultClientExtensionMethod with | ||||
|                 member _.GetSecret | ||||
|                     (jwt : JwtVaultResponse, path : string, mountPoint : string, ct : CancellationToken option) | ||||
|                     = | ||||
|                     async { | ||||
|                         let! ct = Async.CancellationToken | ||||
|  | ||||
|                         let uri = | ||||
|                             System.Uri ( | ||||
|                                 (match client.BaseAddress with | ||||
|                                  | null -> | ||||
|                                      raise ( | ||||
|                                          System.ArgumentNullException ( | ||||
|                                              nameof (client.BaseAddress), | ||||
|                                              "No base address was supplied on the type, and no BaseAddress was on the HttpClient." | ||||
|                                          ) | ||||
|                                      ) | ||||
|                                  | v -> v), | ||||
|                                 System.Uri ( | ||||
|                                     "v1/{mountPoint}/{path}" | ||||
|                                         .Replace("{path}", path.ToString () |> System.Web.HttpUtility.UrlEncode) | ||||
|                                         .Replace ( | ||||
|                                             "{mountPoint}", | ||||
|                                             mountPoint.ToString () |> System.Web.HttpUtility.UrlEncode | ||||
|                                         ), | ||||
|                                     System.UriKind.Relative | ||||
|                                 ) | ||||
|                             ) | ||||
|  | ||||
|                         let httpMessage = | ||||
|                             new System.Net.Http.HttpRequestMessage ( | ||||
|                                 Method = System.Net.Http.HttpMethod.Get, | ||||
|                                 RequestUri = uri | ||||
|                             ) | ||||
|  | ||||
|                         let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                         let response = response.EnsureSuccessStatusCode () | ||||
|                         let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask | ||||
|  | ||||
|                         let! jsonNode = | ||||
|                             System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) | ||||
|                             |> Async.AwaitTask | ||||
|  | ||||
|                         return JwtSecretResponse.jsonParse jsonNode | ||||
|                     } | ||||
|                     |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|  | ||||
|                 member _.GetJwt (role : string, jwt : string, ct : CancellationToken option) = | ||||
|                     async { | ||||
|                         let! ct = Async.CancellationToken | ||||
|  | ||||
|                         let uri = | ||||
|                             System.Uri ( | ||||
|                                 (match client.BaseAddress with | ||||
|                                  | null -> | ||||
|                                      raise ( | ||||
|                                          System.ArgumentNullException ( | ||||
|                                              nameof (client.BaseAddress), | ||||
|                                              "No base address was supplied on the type, and no BaseAddress was on the HttpClient." | ||||
|                                          ) | ||||
|                                      ) | ||||
|                                  | v -> v), | ||||
|                                 System.Uri ("v1/auth/jwt/login", System.UriKind.Relative) | ||||
|                             ) | ||||
|  | ||||
|                         let httpMessage = | ||||
|                             new System.Net.Http.HttpRequestMessage ( | ||||
|                                 Method = System.Net.Http.HttpMethod.Get, | ||||
|                                 RequestUri = uri | ||||
|                             ) | ||||
|  | ||||
|                         let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask | ||||
|                         let response = response.EnsureSuccessStatusCode () | ||||
|                         let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask | ||||
|  | ||||
|                         let! jsonNode = | ||||
|                             System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct) | ||||
|                             |> Async.AwaitTask | ||||
|  | ||||
|                         return JwtVaultResponse.jsonParse jsonNode | ||||
|                     } | ||||
|                     |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) | ||||
|             } | ||||
|   | ||||
| @@ -29,13 +29,52 @@ 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 = | ||||
|     { | ||||
|         Tinker : string | ||||
|         Tailor : int | ||||
|         Soldier : System.Uri | ||||
|         Sailor : float | ||||
|         Alpha : string | ||||
|         Bravo : System.Uri | ||||
|         Charlie : float | ||||
|         Delta : float32 | ||||
|         Echo : single | ||||
|         Foxtrot : double | ||||
|         Golf : int64 | ||||
|         Hotel : uint64 | ||||
|         India : int | ||||
|         Juliette : uint | ||||
|         Kilo : int32 | ||||
|         Lima : uint32 | ||||
|         Mike : int16 | ||||
|         November : uint16 | ||||
|         Oscar : int8 | ||||
|         Papa : uint8 | ||||
|         Quebec : byte | ||||
|         Tango : sbyte | ||||
|         Uniform : decimal | ||||
|         Victor : char | ||||
|         Whiskey : bigint | ||||
|     } | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
|   | ||||
| @@ -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 | ||||
| @@ -103,7 +103,7 @@ module MyList2Cata = | ||||
|                 | 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 | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| namespace SomeNamespace | ||||
|  | ||||
| open System | ||||
| open WoofWare.Myriad.Plugins | ||||
|  | ||||
| [<GenerateMock>] | ||||
| @@ -41,3 +42,9 @@ type Curried<'a> = | ||||
|     abstract Mem4 : (int * string) -> ('a * int) -> string | ||||
|     abstract Mem5 : x : int * string -> ('a * int) -> string | ||||
|     abstract Mem6 : int * string -> y : 'a * int -> string | ||||
|  | ||||
| [<GenerateMock>] | ||||
| type TypeWithInterface = | ||||
|     inherit IDisposable | ||||
|     abstract Mem1 : string option -> string[] Async | ||||
|     abstract Mem2 : unit -> string[] Async | ||||
|   | ||||
| @@ -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>] | ||||
|   | ||||
| @@ -17,6 +17,9 @@ type IPureGymApi = | ||||
|     [<Get "v1/gyms/{gym_id}/attendance">] | ||||
|     abstract GetGymAttendance : [<Path "gym_id">] gymId : int * ?ct : CancellationToken -> Task<GymAttendance> | ||||
|  | ||||
|     [<Get "v1/gyms/{gym_id}/attendance">] | ||||
|     abstract GetGymAttendance' : [<Path("gym_id")>] gymId : int * ?ct : CancellationToken -> Task<GymAttendance> | ||||
|  | ||||
|     [<RestEase.GetAttribute "v1/member">] | ||||
|     abstract GetMember : ?ct : CancellationToken -> Member Task | ||||
|  | ||||
| @@ -38,6 +41,10 @@ type IPureGymApi = | ||||
|     abstract GetSessions : | ||||
|         [<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions> | ||||
|  | ||||
|     [<Get "/v2/gymSessions/member?foo=1">] | ||||
|     abstract GetSessionsWithQuery : | ||||
|         [<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions> | ||||
|  | ||||
|     // An example from RestEase's own docs | ||||
|     [<Post "users/new">] | ||||
|     abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string> | ||||
| @@ -120,7 +127,8 @@ type internal IApiWithoutBaseAddress = | ||||
| [<WoofWare.Myriad.Plugins.HttpClient>] | ||||
| [<BasePath "foo">] | ||||
| type IApiWithBasePath = | ||||
|     [<Get "endpoint/{param}">] | ||||
|     // Example where we use the bundled attributes rather than RestEase's | ||||
|     [<WoofWare.Myriad.Plugins.RestEase.Get "endpoint/{param}">] | ||||
|     abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string> | ||||
|  | ||||
| [<WoofWare.Myriad.Plugins.HttpClient>] | ||||
| @@ -141,3 +149,16 @@ type IApiWithHeaders = | ||||
|  | ||||
|     [<Get "endpoint/{param}">] | ||||
|     abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string> | ||||
|  | ||||
| [<WoofWare.Myriad.Plugins.HttpClient>] | ||||
| [<WoofWare.Myriad.Plugins.RestEase.Header("Header-Name", "Header-Value")>] | ||||
| type IApiWithHeaders2 = | ||||
|     [<WoofWare.Myriad.Plugins.RestEase.Header "X-Foo">] | ||||
|     abstract SomeHeader : string | ||||
|  | ||||
|     [<WoofWare.Myriad.Plugins.RestEase.Header "Authorization">] | ||||
|     abstract SomeOtherHeader : int | ||||
|  | ||||
|     [<Get "endpoint/{param}">] | ||||
|     abstract GetPathParam : | ||||
|         [<WoofWare.Myriad.Plugins.RestEase.Path "param">] parameter : string * ?ct : CancellationToken -> Task<string> | ||||
|   | ||||
| @@ -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,5 +34,42 @@ 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>] | ||||
| [<WoofWare.Myriad.Plugins.JsonParse true>] | ||||
| 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 | ||||
|     } | ||||
|   | ||||
| @@ -76,3 +76,33 @@ type IVaultClient = | ||||
|  | ||||
|     [<Get "v1/auth/jwt/login">] | ||||
|     abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse> | ||||
|  | ||||
| [<WoofWare.Myriad.Plugins.HttpClient false>] | ||||
| type IVaultClientNonExtensionMethod = | ||||
|     [<Get "v1/{mountPoint}/{path}">] | ||||
|     abstract GetSecret : | ||||
|         jwt : JwtVaultResponse * | ||||
|         [<Path "path">] path : string * | ||||
|         [<Path "mountPoint">] mountPoint : string * | ||||
|         ?ct : CancellationToken -> | ||||
|             Task<JwtSecretResponse> | ||||
|  | ||||
|     [<Get "v1/auth/jwt/login">] | ||||
|     abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse> | ||||
|  | ||||
| [<WoofWare.Myriad.Plugins.HttpClient(true)>] | ||||
| type IVaultClientExtensionMethod = | ||||
|     [<Get "v1/{mountPoint}/{path}">] | ||||
|     abstract GetSecret : | ||||
|         jwt : JwtVaultResponse * | ||||
|         [<Path "path">] path : string * | ||||
|         [<Path "mountPoint">] mountPoint : string * | ||||
|         ?ct : CancellationToken -> | ||||
|             Task<JwtSecretResponse> | ||||
|  | ||||
|     [<Get "v1/auth/jwt/login">] | ||||
|     abstract GetJwt : role : string * jwt : string * ?ct : CancellationToken -> Task<JwtVaultResponse> | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| type VaultClientExtensionMethod = | ||||
|     static member thisClashes = 99 | ||||
|   | ||||
| @@ -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.141" 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> | ||||
|   | ||||
							
								
								
									
										22
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								README.md
									
									
									
									
									
								
							| @@ -8,23 +8,20 @@ | ||||
|  | ||||
| Some helpers in [Myriad](https://github.com/MoiraeSoftware/myriad/) which might be useful. | ||||
|  | ||||
| These are currently somewhat experimental, and I personally am their primary customer. | ||||
| The `RemoveOptions` generator in particular is extremely half-baked. | ||||
| Currently implemented: | ||||
|  | ||||
| * `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods). | ||||
| * `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods). | ||||
| * `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client). | ||||
| * `GenerateMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)). | ||||
| * `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union). | ||||
| * `RemoveOptions` (to strip `option` modifiers from a type) - this one is particularly half-baked! | ||||
|  | ||||
| If you would like to ensure that your particular use-case remains unbroken, please do contribute tests to this repository. | ||||
| The `ConsumePlugin` assembly contains a number of invocations of these source generators, | ||||
| so you just need to add copies of your types to that assembly to ensure that I will at least notice if I break the build; | ||||
| and if you add tests to `WoofWare.Myriad.Plugins.Test` then I will also notice if I break the runtime semantics of the generated code. | ||||
|  | ||||
| Currently implemented: | ||||
|  | ||||
| * `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods); | ||||
| * `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods); | ||||
| * `RemoveOptions` (to strip `option` modifiers from a type). | ||||
| * `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client). | ||||
| * `GenerateMock` (to stamp out a record type corresponding to an interface). | ||||
| * `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union). | ||||
|  | ||||
| ## `JsonParse` | ||||
|  | ||||
| Takes records like this: | ||||
| @@ -143,6 +140,9 @@ module InnerTypeWithBoth = | ||||
|         node | ||||
| ``` | ||||
|  | ||||
| Also includes an *opinionated* serializer for discriminated unions. | ||||
| (Any such serializer must be opinionated, because JSON does not natively model DUs.) | ||||
|  | ||||
| As in `JsonParse`, you can optionally supply the boolean `true` to the attribute, | ||||
| which will cause Myriad to stamp out an extension method rather than a module with the same name as the type. | ||||
|  | ||||
|   | ||||
| @@ -60,8 +60,17 @@ type JsonParseAttribute (isExtensionMethod : bool) = | ||||
| /// generator should apply during build. | ||||
| /// This generator is intended to replicate much of the functionality of RestEase, | ||||
| /// i.e. to stamp out HTTP REST clients from interfaces defining the API. | ||||
| type HttpClientAttribute () = | ||||
| /// | ||||
| /// 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 HttpClientAttribute (isExtensionMethod : bool) = | ||||
|     inherit Attribute () | ||||
|     /// The default value of `isExtensionMethod`, the optional argument to the HttpClientAttribute constructor. | ||||
|     static member DefaultIsExtensionMethod = false | ||||
|  | ||||
|     /// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details. | ||||
|     new () = HttpClientAttribute HttpClientAttribute.DefaultIsExtensionMethod | ||||
|  | ||||
| /// Attribute indicating a DU type to which the "create catamorphism" Myriad | ||||
| /// generator should apply during build. | ||||
|   | ||||
							
								
								
									
										63
									
								
								WoofWare.Myriad.Plugins.Attributes/RestEase.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								WoofWare.Myriad.Plugins.Attributes/RestEase.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open System | ||||
|  | ||||
| /// Module containing duplicates of the supported RestEase attributes, in case you don't want | ||||
| /// to take a dependency on RestEase. | ||||
| [<RequireQualifiedAccess>] | ||||
| module RestEase = | ||||
|     /// Indicates that a method represents an HTTP Get query to the specified endpoint. | ||||
|     type GetAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Post query to the specified endpoint. | ||||
|     type PostAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Delete query to the specified endpoint. | ||||
|     type DeleteAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Head query to the specified endpoint. | ||||
|     type HeadAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Options query to the specified endpoint. | ||||
|     type OptionsAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Put query to the specified endpoint. | ||||
|     type PutAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Patch query to the specified endpoint. | ||||
|     type PatchAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that a method represents an HTTP Trace query to the specified endpoint. | ||||
|     type TraceAttribute (path : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that this argument to a method is interpolated into the HTTP request at runtime | ||||
|     /// by setting a query parameter (with the given name) to the value of the annotated argument. | ||||
|     type QueryAttribute (paramName : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that this interface represents a REST client which accesses an API whose paths are | ||||
|     /// all relative to the given address. | ||||
|     type BaseAddressAttribute (addr : string) = | ||||
|         inherit Attribute () | ||||
|  | ||||
|     /// Indicates that this interface member causes the interface to set a header with the given name, | ||||
|     /// whose value is obtained whenever required by a fresh call to the interface member. | ||||
|     type HeaderAttribute (header : string, value : string option) = | ||||
|         inherit Attribute () | ||||
|         new (header : string) = HeaderAttribute (header, None) | ||||
|         new (header : string, value : string) = HeaderAttribute (header, Some value) | ||||
|  | ||||
|     /// Indicates that this argument to a method is interpolated into the request path at runtime | ||||
|     /// by writing it into the templated string that specifies the HTTP query e.g. in the `[<Get "/foo/{template}">]`. | ||||
|     type PathAttribute (path : string option) = | ||||
|         inherit Attribute () | ||||
|         new (path : string) = PathAttribute (Some path) | ||||
|         new () = PathAttribute None | ||||
| @@ -6,7 +6,10 @@ WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: unit | ||||
| WoofWare.Myriad.Plugins.GenerateMockAttribute.DefaultIsInternal [static property]: [read-only] bool | ||||
| WoofWare.Myriad.Plugins.GenerateMockAttribute.get_DefaultIsInternal [static method]: unit -> bool | ||||
| WoofWare.Myriad.Plugins.HttpClientAttribute inherit System.Attribute | ||||
| 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.JsonParseAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: bool | ||||
| WoofWare.Myriad.Plugins.JsonParseAttribute..ctor [constructor]: unit | ||||
| @@ -19,3 +22,32 @@ WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static | ||||
| WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool | ||||
| WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit | ||||
| WoofWare.Myriad.Plugins.RestEase inherit obj | ||||
| WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+DeleteAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+DeleteAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+GetAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+GetAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+HeadAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+HeadAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+HeaderAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string option) | ||||
| WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string) | ||||
| WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+OptionsAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+OptionsAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+PatchAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+PatchAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+PathAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string option | ||||
| WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: unit | ||||
| WoofWare.Myriad.Plugins.RestEase+PostAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+PostAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+PutAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+PutAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+QueryAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+QueryAttribute..ctor [constructor]: string | ||||
| WoofWare.Myriad.Plugins.RestEase+TraceAttribute inherit System.Attribute | ||||
| WoofWare.Myriad.Plugins.RestEase+TraceAttribute..ctor [constructor]: string | ||||
| @@ -11,11 +11,9 @@ module TestSurface = | ||||
|     [<Test>] | ||||
|     let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly | ||||
|  | ||||
|     (* | ||||
|     [<Test>] | ||||
|     let ``Check version against remote`` () = | ||||
|         MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes" | ||||
|     *) | ||||
|  | ||||
|     [<Test ; Explicit>] | ||||
|     let ``Update API surface`` () = | ||||
|   | ||||
| @@ -12,10 +12,10 @@ | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|         <PackageReference Include="ApiSurface" Version="4.0.28" /> | ||||
|         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/> | ||||
|         <PackageReference Include="NUnit" Version="3.13.3"/> | ||||
|         <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> | ||||
|         <PackageReference Include="ApiSurface" Version="4.0.43" /> | ||||
|         <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/> | ||||
|         <PackageReference Include="NUnit" Version="4.1.0"/> | ||||
|         <PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <Compile Include="Attributes.fs"/> | ||||
|     <Compile Include="RestEase.fs" /> | ||||
|     <EmbeddedResource Include="version.json"/> | ||||
|     <EmbeddedResource Include="SurfaceBaseline.txt"/> | ||||
|     <None Include="..\README.md"> | ||||
|   | ||||
| @@ -1,7 +1,15 @@ | ||||
| { | ||||
|   "version": "2.2", | ||||
|   "version": "3.1", | ||||
|   "publicReleaseRefSpec": [ | ||||
|     "^refs/heads/main$" | ||||
|   ], | ||||
|   "pathFilters": null | ||||
|   "pathFilters": [ | ||||
|     ":/README.md", | ||||
|     ":/LICENSE", | ||||
|     ":/WoofWare.Myriad.Plugins/logo.png", | ||||
|     ":/Directory.Build.props", | ||||
|     ":/global.json", | ||||
|     "./", | ||||
|     ":^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" | ||||
|   | ||||
| @@ -89,6 +89,7 @@ module TestPureGymRestApi = | ||||
|         let api = PureGymApi.make client | ||||
|  | ||||
|         api.GetGymAttendance(requestedGym).Result |> shouldEqual expected | ||||
|         api.GetGymAttendance'(requestedGym).Result |> shouldEqual expected | ||||
|  | ||||
|     let memberCases = | ||||
|         PureGymDtos.memberCases |> List.allPairs baseUris |> List.map TestCaseData | ||||
| @@ -234,6 +235,33 @@ module TestPureGymRestApi = | ||||
|  | ||||
|         api.GetSessions(startDate, endDate).Result |> shouldEqual expected | ||||
|  | ||||
|     [<TestCaseSource(nameof sessionsCases)>] | ||||
|     let ``Test GetSessionsWithQuery`` | ||||
|         (baseUri : Uri, (startDate : DateOnly, (endDate : DateOnly, (json : string, expected : Sessions)))) | ||||
|         = | ||||
|         let proc (message : HttpRequestMessage) : HttpResponseMessage Async = | ||||
|             async { | ||||
|                 message.Method |> shouldEqual HttpMethod.Get | ||||
|  | ||||
|                 // This one is specified as being absolute, in its attribute on the IPureGymApi type | ||||
|                 let expectedUri = | ||||
|                     let fromDate = dateOnlyToString startDate | ||||
|                     let toDate = dateOnlyToString endDate | ||||
|                     $"https://example.com/v2/gymSessions/member?foo=1&fromDate=%s{fromDate}&toDate=%s{toDate}" | ||||
|  | ||||
|                 message.RequestUri.ToString () |> shouldEqual expectedUri | ||||
|  | ||||
|                 let content = new StringContent (json) | ||||
|                 let resp = new HttpResponseMessage (HttpStatusCode.OK) | ||||
|                 resp.Content <- content | ||||
|                 return resp | ||||
|             } | ||||
|  | ||||
|         use client = HttpClientMock.make baseUri proc | ||||
|         let api = PureGymApi.make client | ||||
|  | ||||
|         api.GetSessionsWithQuery(startDate, endDate).Result |> shouldEqual expected | ||||
|  | ||||
|     [<Test>] | ||||
|     let ``URI example`` () = | ||||
|         let proc (message : HttpRequestMessage) : HttpResponseMessage Async = | ||||
|   | ||||
| @@ -87,8 +87,10 @@ module TestVaultClient = | ||||
|     } | ||||
| }""" | ||||
|  | ||||
|     [<Test>] | ||||
|     let ``URI example`` () = | ||||
|     [<TestCase 1>] | ||||
|     [<TestCase 2>] | ||||
|     [<TestCase 3>] | ||||
|     let ``URI example`` (vaultClientId : int) = | ||||
|         let proc (message : HttpRequestMessage) : HttpResponseMessage Async = | ||||
|             async { | ||||
|                 message.Method |> shouldEqual HttpMethod.Get | ||||
| @@ -112,10 +114,25 @@ module TestVaultClient = | ||||
|             } | ||||
|  | ||||
|         use client = HttpClientMock.make (Uri "https://my-vault.com") proc | ||||
|         let api = VaultClient.make client | ||||
|  | ||||
|         let value = | ||||
|             match vaultClientId with | ||||
|             | 1 -> | ||||
|                 let api = VaultClient.make client | ||||
|                 let vaultResponse = api.GetJwt("role", "jwt").Result | ||||
|                 let value = api.GetSecret(vaultResponse, "path", "mount").Result | ||||
|                 value | ||||
|             | 2 -> | ||||
|                 let api = VaultClientNonExtensionMethod.make client | ||||
|                 let vaultResponse = api.GetJwt("role", "jwt").Result | ||||
|                 let value = api.GetSecret(vaultResponse, "path", "mount").Result | ||||
|                 value | ||||
|             | 3 -> | ||||
|                 let api = VaultClientExtensionMethod.make client | ||||
|                 let vaultResponse = api.GetJwt("role", "jwt").Result | ||||
|                 let value = api.GetSecret(vaultResponse, "path", "mount").Result | ||||
|                 value | ||||
|             | _ -> failwith $"Unrecognised ID: %i{vaultClientId}" | ||||
|  | ||||
|         value.Data | ||||
|         |> Seq.toList | ||||
| @@ -168,3 +185,5 @@ module TestVaultClient = | ||||
|                 "key8_1", "https://example.com/data8/1" | ||||
|                 "key8_2", "https://example.com/data8/2" | ||||
|             ] | ||||
|  | ||||
|     let _canSeePastExtensionMethod = VaultClientExtensionMethod.thisClashes | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| namespace WoofWare.Myriad.Plugins.Test | ||||
|  | ||||
| open System | ||||
| open System.Numerics | ||||
| open System.Text.Json.Nodes | ||||
| open ConsumePlugin | ||||
| open NUnit.Framework | ||||
| @@ -12,15 +13,62 @@ module TestExtensionMethod = | ||||
|     [<Test>] | ||||
|     let ``Parse via extension method`` () = | ||||
|         let json = | ||||
|             """{"tinker": "job", "tailor": 3, "soldier": "https://example.com", "sailor": 3.1}""" | ||||
|             """{ | ||||
|     "alpha": "hello!", | ||||
|     "bravo": "https://example.com", | ||||
|     "charlie": 0.3341, | ||||
|     "delta": 110033.4, | ||||
|     "echo": -0.000993, | ||||
|     "foxtrot": -999999999999, | ||||
|     "golf": -123456789101112, | ||||
|     "hotel": 18446744073709551615, | ||||
|     "india": 99884, | ||||
|     "juliette": 12223334, | ||||
|     "kilo": -2147483642, | ||||
|     "lima": 4294967293, | ||||
|     "mike": -32767, | ||||
|     "november": 65533, | ||||
|     "oscar": -125, | ||||
|     "papa": 253, | ||||
|     "quebec": 254, | ||||
|     "tango": -3, | ||||
|     "uniform": 1004443.300988393349583009, | ||||
|     "victor": "x", | ||||
|     "whiskey": 123456123456123456123456123456123456123456 | ||||
| }""" | ||||
|             |> JsonNode.Parse | ||||
|  | ||||
|         let expected = | ||||
|             { | ||||
|                 Tinker = "job" | ||||
|                 Tailor = 3 | ||||
|                 Soldier = Uri "https://example.com" | ||||
|                 Sailor = 3.1 | ||||
|                 Alpha = "hello!" | ||||
|                 Bravo = Uri "https://example.com" | ||||
|                 Charlie = 0.3341 | ||||
|                 Delta = 110033.4f | ||||
|                 Echo = -0.000993f | ||||
|                 Foxtrot = -999999999999.0 | ||||
|                 Golf = -123456789101112L | ||||
|                 Hotel = 18446744073709551615UL | ||||
|                 India = 99884 | ||||
|                 Juliette = 12223334u | ||||
|                 Kilo = -2147483642 | ||||
|                 Lima = 4294967293u | ||||
|                 Mike = -32767s | ||||
|                 November = 65533us | ||||
|                 Oscar = -125y | ||||
|                 Papa = 253uy | ||||
|                 Quebec = 254uy | ||||
|                 Tango = -3y | ||||
|                 Uniform = 1004443.300988393349583009m | ||||
|                 Victor = 'x' | ||||
|                 Whiskey = | ||||
|                     let mutable i = BigInteger 0 | ||||
|  | ||||
|                     for _ = 0 to 6 do | ||||
|                         i <- i * BigInteger 1000000 + BigInteger 123456 | ||||
|  | ||||
|                     i | ||||
|             } | ||||
|  | ||||
|         ToGetExtensionMethod.jsonParse json |> shouldEqual expected | ||||
|         let actual = ToGetExtensionMethod.jsonParse json | ||||
|  | ||||
|         actual |> shouldEqual expected | ||||
|   | ||||
| @@ -7,6 +7,8 @@ open FsUnitTyped | ||||
|  | ||||
| [<TestFixture>] | ||||
| module TestJsonParse = | ||||
|     let _canSeePastExtensionMethod = ToGetExtensionMethod.thisModuleWouldClash | ||||
|  | ||||
|     [<Test>] | ||||
|     let ``Single example`` () = | ||||
|         let s = | ||||
| @@ -47,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 | ||||
|   | ||||
| @@ -2,10 +2,9 @@ namespace WoofWare.Myriad.Plugins.Test | ||||
|  | ||||
| open System | ||||
| open System.Collections.Generic | ||||
| open System.IO | ||||
| open System.Text | ||||
| open System.Text.Json | ||||
| open System.Text.Json.Nodes | ||||
| open FsCheck.Random | ||||
| open Microsoft.FSharp.Reflection | ||||
| open NUnit.Framework | ||||
| open FsCheck | ||||
| open FsUnitTyped | ||||
| @@ -78,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 | ||||
|                 { | ||||
| @@ -87,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 | ||||
|                 } | ||||
|         } | ||||
|  | ||||
| @@ -105,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" | ||||
| @@ -124,3 +227,82 @@ module TestJsonSerde = | ||||
|         |> shouldEqual ( | ||||
|             sprintf """{"it\u0027s-a-me":"%s","map":{},"readOnlyDict":{},"dict":{},"concreteDict":{}}""" guidStr | ||||
|         ) | ||||
|  | ||||
|     type Generators = | ||||
|         static member TestCase () = | ||||
|             { new Arbitrary<InnerTypeWithBoth>() with | ||||
|                 override x.Generator = innerGen 5 | ||||
|             } | ||||
|  | ||||
|     let sanitiseInner (r : InnerTypeWithBoth) : InnerTypeWithBoth = | ||||
|         { | ||||
|             Thing = r.Thing | ||||
|             Map = r.Map | ||||
|             ReadOnlyDict = r.ReadOnlyDict | ||||
|             Dict = r.Dict | ||||
|             ConcreteDict = r.ConcreteDict | ||||
|         } | ||||
|  | ||||
|     let sanitiseRec (r : JsonRecordTypeWithBoth) : JsonRecordTypeWithBoth = | ||||
|         { r with | ||||
|             B = if isNull r.B then "<null>" else r.B | ||||
|             C = | ||||
|                 if Object.ReferenceEquals (r.C, (null : obj)) then | ||||
|                     [] | ||||
|                 else | ||||
|                     r.C | ||||
|             D = sanitiseInner r.D | ||||
|             E = if isNull r.E then [||] else r.E | ||||
|             Arr = | ||||
|                 if Object.ReferenceEquals (r.Arr, (null : obj)) then | ||||
|                     [||] | ||||
|                 else | ||||
|                     r.Arr | ||||
|         } | ||||
|  | ||||
|     let duGen = | ||||
|         gen { | ||||
|             let! case = Gen.choose (0, 2) | ||||
|  | ||||
|             match case with | ||||
|             | 0 -> return FirstDu.EmptyCase | ||||
|             | 1 -> | ||||
|                 let! s = Arb.generate<NonNull<string>> | ||||
|                 return FirstDu.Case1 s.Get | ||||
|             | 2 -> | ||||
|                 let! i = Arb.generate<int> | ||||
|                 let! record = outerGen | ||||
|                 return FirstDu.Case2 (record, i) | ||||
|             | _ -> return failwith $"unexpected: %i{case}" | ||||
|         } | ||||
|  | ||||
|     [<Test>] | ||||
|     let ``Discriminated union works`` () = | ||||
|         let property (du : FirstDu) : unit = | ||||
|             du | ||||
|             |> FirstDu.toJsonNode | ||||
|             |> fun s -> s.ToJsonString () | ||||
|             |> JsonNode.Parse | ||||
|             |> FirstDu.jsonParse | ||||
|             |> shouldEqual du | ||||
|  | ||||
|         property |> Prop.forAll (Arb.fromGen duGen) |> Check.QuickThrowOnFailure | ||||
|  | ||||
|     [<Test>] | ||||
|     let ``DU generator covers all cases`` () = | ||||
|         let rand = Random () | ||||
|         let cases = FSharpType.GetUnionCases typeof<FirstDu> | ||||
|         let counts = Array.zeroCreate<int> cases.Length | ||||
|  | ||||
|         let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu> | ||||
|  | ||||
|         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>] | ||||
|   | ||||
| @@ -33,13 +33,12 @@ | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="ApiSurface" Version="4.0.28"/> | ||||
|     <PackageReference Include="ApiSurface" Version="4.0.43"/> | ||||
|     <PackageReference Include="FsCheck" Version="2.16.6"/> | ||||
|     <PackageReference Include="FsUnit" Version="6.0.0"/> | ||||
|     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/> | ||||
|     <PackageReference Include="NUnit" Version="4.0.1"/> | ||||
|     <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> | ||||
|     <PackageReference Include="coverlet.collector" 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.6.0"/> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|   | ||||
| @@ -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 = | ||||
|     { | ||||
| @@ -54,6 +52,7 @@ type internal InterfaceType = | ||||
|     { | ||||
|         Attributes : SynAttribute list | ||||
|         Name : LongIdent | ||||
|         Inherits : SynType list | ||||
|         Members : MemberInfo list | ||||
|         Properties : PropertyInfo list | ||||
|         Generics : SynTyparDecls option | ||||
| @@ -97,6 +96,11 @@ type internal AdtProduct = | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal AstHelper = | ||||
|  | ||||
|     let isEnum (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : bool = | ||||
|         match repr with | ||||
|         | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true | ||||
|         | _ -> false | ||||
|  | ||||
|     let instantiateRecord (fields : (RecordFieldName * SynExpr option) list) : SynExpr = | ||||
|         let fields = | ||||
|             fields | ||||
| @@ -105,81 +109,17 @@ module internal AstHelper = | ||||
|         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 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 | ||||
| @@ -201,12 +141,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, _) -> | ||||
| @@ -224,7 +164,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 | ||||
| @@ -253,10 +193,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 | ||||
| @@ -269,7 +205,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> = | ||||
| @@ -326,7 +262,7 @@ module internal AstHelper = | ||||
|                                     Attributes = [] | ||||
|                                     IsOptional = false | ||||
|                                     Id = None | ||||
|                                     Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent ident) | ||||
|                                     Type = SynType.createLongIdent ident | ||||
|                                 } | ||||
|                                 |> List.singleton | ||||
|                         } | ||||
| @@ -338,11 +274,22 @@ module internal AstHelper = | ||||
|                                     Attributes = [] | ||||
|                                     IsOptional = false | ||||
|                                     Id = None | ||||
|                                     Type = SynType.Var (typar, range0) | ||||
|                                     Type = SynType.var typar | ||||
|                                 } | ||||
|                                 |> List.singleton | ||||
|                         } | ||||
|                     | arg -> | ||||
|                         { | ||||
|                             HasParen = false | ||||
|                             Args = | ||||
|                                 { | ||||
|                                     Attributes = [] | ||||
|                                     IsOptional = false | ||||
|                                     Id = None | ||||
|                                     Type = arg | ||||
|                                 } | ||||
|                                 |> List.singleton | ||||
|                         } | ||||
|                     | _ -> failwith $"Unrecognised args in interface method declaration: %+A{args}" | ||||
|                     |> fun ty -> | ||||
|                         { ty with | ||||
|                             HasParen = ty.HasParen || hasParen | ||||
| @@ -386,22 +333,26 @@ module internal AstHelper = | ||||
|  | ||||
|         let attrs = attrs |> List.collect (fun s -> s.Attributes) | ||||
|  | ||||
|         let members, properties = | ||||
|         let members, inherits = | ||||
|             match synTypeDefnRepr with | ||||
|             | SynTypeDefnRepr.ObjectModel (_kind, members, _) -> | ||||
|                 members | ||||
|                 |> List.map (fun defn -> | ||||
|                     match defn with | ||||
|                     | SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> parseMember slotSig flags | ||||
|                     | SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> Choice1Of2 (parseMember slotSig flags) | ||||
|                     | SynMemberDefn.Inherit (baseType, _asIdent, _) -> Choice2Of2 baseType | ||||
|                     | _ -> failwith $"Unrecognised member definition: %+A{defn}" | ||||
|                 ) | ||||
|             | _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}" | ||||
|             |> List.partitionChoice | ||||
|  | ||||
|         let members, properties = members |> List.partitionChoice | ||||
|  | ||||
|         { | ||||
|             Members = members | ||||
|             Properties = properties | ||||
|             Name = interfaceName | ||||
|             Inherits = inherits | ||||
|             Attributes = attrs | ||||
|             Generics = typars | ||||
|             Accessibility = accessibility | ||||
| @@ -477,176 +428,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 (|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 | ||||
|  | ||||
|     /// Returns the string name of the type. | ||||
|     let (|PrimitiveType|_|) (fieldType : SynType) = | ||||
|         match fieldType with | ||||
|         | SynType.LongIdent ident -> | ||||
|             match ident.LongIdent with | ||||
|             | [ i ] -> | ||||
|                 [ "string" ; "float" ; "int" ; "bool" ; "char" ] | ||||
|                 |> List.tryFind (fun s -> s = 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
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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,13 +12,15 @@ type internal GenerateMockOutputSpec = | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal InterfaceMockGenerator = | ||||
|     open Fantomas.FCS.Text.Range | ||||
|     open Myriad.Core.Ast | ||||
|  | ||||
|     let private getName (SynField (_, _, id, _, _, _, _, _, _)) = | ||||
|         match id with | ||||
|         | None -> failwith "Expected record field to have a name, but it was somehow anonymous" | ||||
|         | Some id -> id | ||||
|  | ||||
|     [<RequireQualifiedAccess>] | ||||
|     type private KnownInheritance = | IDisposable | ||||
|  | ||||
|     let createType | ||||
|         (spec : GenerateMockOutputSpec) | ||||
|         (name : string) | ||||
| @@ -29,157 +29,106 @@ module internal InterfaceMockGenerator = | ||||
|         (fields : SynField list) | ||||
|         : SynModuleDecl | ||||
|         = | ||||
|         let synValData = | ||||
|             { | ||||
|                 SynMemberFlags.IsInstance = false | ||||
|                 SynMemberFlags.IsDispatchSlot = false | ||||
|                 SynMemberFlags.IsOverrideOrExplicitImpl = false | ||||
|                 SynMemberFlags.IsFinal = false | ||||
|                 SynMemberFlags.GetterOrSetterIsCompilerGenerated = false | ||||
|                 SynMemberFlags.MemberKind = SynMemberKind.Member | ||||
|             } | ||||
|  | ||||
|         let failwithFun = | ||||
|             SynExpr.createLambda | ||||
|                 "x" | ||||
|                 (SynExpr.CreateApp ( | ||||
|                     SynExpr.CreateIdentString "raise", | ||||
|                     SynExpr.CreateParen ( | ||||
|                         SynExpr.CreateApp ( | ||||
|                             SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "NotImplementedException" ]), | ||||
|                             SynExpr.CreateConstString "Unimplemented mock function" | ||||
|         let inherits = | ||||
|             interfaceType.Inherits | ||||
|             |> Seq.map (fun ty -> | ||||
|                 match ty with | ||||
|                 | SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> | ||||
|                     match name |> List.map _.idText with | ||||
|                     | [] -> failwith "Unexpected empty identifier in inheritance declaration" | ||||
|                     | [ "IDisposable" ] | ||||
|                     | [ "System" ; "IDisposable" ] -> KnownInheritance.IDisposable | ||||
|                     | _ -> failwithf "Unrecognised inheritance identifier: %+A" name | ||||
|                 | x -> failwithf "Unrecognised type in inheritance: %+A" x | ||||
|             ) | ||||
|                     ) | ||||
|                 )) | ||||
|             |> Set.ofSeq | ||||
|  | ||||
|         let constructorIdent = | ||||
|             let generics = | ||||
|                 interfaceType.Generics | ||||
|                 |> Option.map (fun generics -> SynValTyparDecls (Some generics, false)) | ||||
|         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}" | ||||
|  | ||||
|             SynPat.LongIdent ( | ||||
|                 SynLongIdent.CreateString "Empty", | ||||
|                 None, | ||||
|                 None, // no generics on the "Empty", only on the return type | ||||
|                 SynArgPats.Pats ( | ||||
|                     if generics.IsNone then | ||||
|                         [] | ||||
|                     else | ||||
|                         [ SynPat.CreateParen (SynPat.CreateConst SynConst.Unit) ] | ||||
|                 ), | ||||
|                 None, | ||||
|                 range0 | ||||
|             ) | ||||
|             SynExpr.createLongIdent [ "System" ; "NotImplementedException" ] | ||||
|             |> 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 | ||||
|                 ) | ||||
|             |> SynBindingReturnInfo.Create | ||||
|             SynType.app name generics | ||||
|  | ||||
|         let constructorFields = | ||||
|             let extras = | ||||
|                 if inherits.Contains KnownInheritance.IDisposable then | ||||
|                     let unitFun = SynExpr.createThunk (SynExpr.CreateConst ()) | ||||
|  | ||||
|                     [ (SynLongIdent.createS "Dispose", true), Some unitFun ] | ||||
|                 else | ||||
|                     [] | ||||
|  | ||||
|             let nonExtras = | ||||
|                 fields | ||||
|                 |> List.map (fun field -> (SynLongIdent.createI (getName field), true), Some (failwithFun field)) | ||||
|  | ||||
|             extras @ nonExtras | ||||
|  | ||||
|         let constructor = | ||||
|             SynMemberDefn.Member ( | ||||
|                 SynBinding.SynBinding ( | ||||
|                     None, | ||||
|                     SynBindingKind.Normal, | ||||
|                     false, | ||||
|                     false, | ||||
|                     [], | ||||
|                     PreXmlDoc.Create " An implementation where every method throws.", | ||||
|                     SynValData.SynValData (Some synValData, SynValInfo.Empty, None), | ||||
|                     constructorIdent, | ||||
|                     Some constructorReturnType, | ||||
|                     AstHelper.instantiateRecord ( | ||||
|                         fields | ||||
|                         |> List.map (fun field -> | ||||
|                             ((SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun) | ||||
|                         ) | ||||
|                     ), | ||||
|                     range0, | ||||
|                     DebugPointAtBinding.Yes range0, | ||||
|                     { SynExpr.synBindingTriviaZero true with | ||||
|                         LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0) | ||||
|             SynBinding.basic | ||||
|                 [ Ident.create "Empty" ] | ||||
|                 (if interfaceType.Generics.IsNone then | ||||
|                      [] | ||||
|                  else | ||||
|                      [ SynPat.unit ]) | ||||
|                 (AstHelper.instantiateRecord constructorFields) | ||||
|             |> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.") | ||||
|             |> SynBinding.withReturnAnnotation constructorReturnType | ||||
|             |> SynMemberDefn.staticMember | ||||
|  | ||||
|         let fields = | ||||
|             let extras = | ||||
|                 if inherits.Contains KnownInheritance.IDisposable then | ||||
|                     { | ||||
|                         Attrs = [] | ||||
|                         Ident = Some (Ident.create "Dispose") | ||||
|                         Type = SynType.funFromDomain SynType.unit SynType.unit | ||||
|                     } | ||||
|                 ), | ||||
|                 range0 | ||||
|             ) | ||||
|                     |> SynField.make | ||||
|                     |> SynField.withDocString (PreXmlDoc.create "Implementation of IDisposable.Dispose") | ||||
|                     |> List.singleton | ||||
|                 else | ||||
|                     [] | ||||
|  | ||||
|             extras @ fields | ||||
|  | ||||
|         let interfaceMembers = | ||||
|             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 -> | ||||
|                                                         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 -> | ||||
|                             let args = | ||||
|                                 tupledArgs.Args | ||||
|                                 |> List.mapi (fun j _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}")) | ||||
|  | ||||
|                             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 | ||||
|                                 |> List.mapi (fun j ty -> | ||||
|                                     match ty.Type with | ||||
|                                     | UnitType -> SynPat.unit | ||||
|                                     | _ -> SynPat.named $"arg_%i{i}_%i{j}" | ||||
|                                 ) | ||||
|  | ||||
|                     let headPat = | ||||
|                         SynPat.LongIdent ( | ||||
|                             SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ], | ||||
|                             None, | ||||
|                             None, | ||||
|                             SynArgPats.Pats headArgs, | ||||
|                             None, | ||||
|                             range0 | ||||
|                             match args with | ||||
|                             | [] -> failwith "somehow got no args at all" | ||||
|                             | [ arg ] -> arg | ||||
|                             | args -> SynPat.tuple args | ||||
|                             |> fun i -> if tupledArgs.HasParen then SynPat.paren i else i | ||||
|                         ) | ||||
|  | ||||
|                     let body = | ||||
| @@ -187,8 +136,12 @@ module internal InterfaceMockGenerator = | ||||
|                             memberInfo.Args | ||||
|                             |> List.mapi (fun i args -> | ||||
|                                 args.Args | ||||
|                                 |> List.mapi (fun j args -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}") | ||||
|                                 |> SynExpr.CreateParenedTuple | ||||
|                                 |> List.mapi (fun j arg -> | ||||
|                                     match arg.Type with | ||||
|                                     | UnitType -> SynExpr.CreateConst () | ||||
|                                     | _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}" | ||||
|                                 ) | ||||
|                                 |> SynExpr.tuple | ||||
|                             ) | ||||
|  | ||||
|                         match tuples |> List.rev with | ||||
| @@ -196,42 +149,17 @@ module internal InterfaceMockGenerator = | ||||
|                         | last :: rest -> | ||||
|  | ||||
|                         (last, rest) | ||||
|                         ||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail)) | ||||
|                         |> fun args -> | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateLongIdent ( | ||||
|                                     SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ] | ||||
|                                 ), | ||||
|                                 args | ||||
|                         ||> List.fold SynExpr.applyTo | ||||
|                         |> SynExpr.applyFunction ( | ||||
|                             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 | ||||
| @@ -241,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) | ||||
|  | ||||
| @@ -264,11 +184,32 @@ module internal InterfaceMockGenerator = | ||||
|             | Some (SynAccess.Internal _), _ -> SynAccess.Internal range0 | ||||
|             | Some (SynAccess.Private _), _ -> SynAccess.Private range0 | ||||
|  | ||||
|         let extraInterfaces = | ||||
|             inherits | ||||
|             |> Seq.map (fun inheritance -> | ||||
|                 match inheritance with | ||||
|                 | KnownInheritance.IDisposable -> | ||||
|                     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' [ "System" ; "IDisposable" ], | ||||
|                         Some range0, | ||||
|                         Some [ mem ], | ||||
|                         range0 | ||||
|                     ) | ||||
|             ) | ||||
|             |> Seq.toList | ||||
|  | ||||
|         let record = | ||||
|             { | ||||
|                 Name = Ident.Create name | ||||
|                 Name = Ident.create name | ||||
|                 Fields = fields | ||||
|                 Members = Some [ constructor ; interfaceMembers ] | ||||
|                 Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces) | ||||
|                 XmlDoc = Some xmlDoc | ||||
|                 Generics = interfaceType.Generics | ||||
|                 Accessibility = Some access | ||||
| @@ -280,7 +221,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 | ||||
|  | ||||
| @@ -297,19 +238,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) | ||||
| @@ -319,25 +256,24 @@ 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 | ||||
|             |> _.idText | ||||
|             |> fun s -> | ||||
|                 if s.StartsWith 'I' && s.Length > 1 && Char.IsUpper s.[1] then | ||||
|                     s.[1..] | ||||
|                     s.Substring 1 | ||||
|                 else | ||||
|                     s | ||||
|             |> fun s -> s + "Mock" | ||||
|  | ||||
|         let typeDecl = createType spec name interfaceType docString fields | ||||
|  | ||||
|         [ yield! opens |> List.map SynModuleDecl.openAny ; yield typeDecl ] | ||||
|         |> SynModuleOrNamespace.createNamespace namespaceId | ||||
|  | ||||
|         SynModuleOrNamespace.CreateNamespace ( | ||||
|             namespaceId, | ||||
|             decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ] | ||||
|         ) | ||||
| 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,41 +24,37 @@ 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.CreateIdentString "raise", | ||||
|                 SynExpr.CreateParen ( | ||||
|                     SynExpr.CreateApp ( | ||||
|                         SynExpr.CreateLongIdent ( | ||||
|                             SynLongIdent.Create [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ] | ||||
|                         ), | ||||
|                         SynExpr.CreateParen ( | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateApp ( | ||||
|                                     SynExpr.CreateIdentString "sprintf", | ||||
|                                     SynExpr.CreateConstString "Required key '%s' not found on JSON object" | ||||
|                                 ), | ||||
|                                 SynExpr.CreateParen propertyName | ||||
|                             ) | ||||
|                         ) | ||||
|                     ) | ||||
|                 ) | ||||
|             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 [ "System" ; "Collections" ; "Generic" ; "KeyNotFoundException" ] | ||||
|             ) | ||||
|             |> 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") | ||||
|             SynMatchClause.create SynPat.createNull raiseExpr | ||||
|             SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v") | ||||
|         ] | ||||
|         ) | ||||
|         |> SynExpr.CreateParen | ||||
|         |> SynExpr.createMatch indexed | ||||
|         |> SynExpr.paren | ||||
|  | ||||
|     /// {node}.AsValue().GetValue<{typeName}> () | ||||
|     /// If `propertyName` is Some, uses `assertNotNull {node}` instead of `{node}`. | ||||
|     let asValueGetValue (propertyName : SynExpr option) (typeName : string) (node : SynExpr) : SynExpr = | ||||
|         match propertyName with | ||||
|         | None -> node | ||||
|         | Some propertyName -> assertNotNull propertyName node | ||||
|         |> SynExpr.callMethod "AsValue" | ||||
|         |> SynExpr.callGenericMethod' "GetValue" typeName | ||||
|  | ||||
|     let asValueGetValueIdent (propertyName : SynExpr option) (typeName : LongIdent) (node : SynExpr) : SynExpr = | ||||
|         match propertyName with | ||||
|         | None -> node | ||||
|         | Some propertyName -> assertNotNull propertyName node | ||||
| @@ -78,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 | ||||
|         ) | ||||
|         |> 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`. | ||||
| @@ -100,64 +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 = | ||||
|         List.append (SynExpr.qualifyPrimitiveType typeName) [ 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 (SynLongIdent.Create [ "kvp" ; "Key" ]) | ||||
|             |> SynExpr.CreateParen | ||||
|         let keyArg = SynExpr.createLongIdent [ "kvp" ; "Key" ] |> SynExpr.paren | ||||
|  | ||||
|         let valueArg = | ||||
|             SynExpr.CreateLongIdent (SynLongIdent.Create [ "kvp" ; "Value" ]) | ||||
|             |> SynExpr.CreateParen | ||||
|         let valueArg = SynExpr.createLongIdent [ "kvp" ; "Value" ] |> SynExpr.paren | ||||
|  | ||||
|         SynExpr.LetOrUse ( | ||||
|             false, | ||||
|             false, | ||||
|             [ | ||||
|                 SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "key"), expr = key keyArg) | ||||
|             ], | ||||
|             SynExpr.LetOrUse ( | ||||
|                 false, | ||||
|                 false, | ||||
|                 [ | ||||
|                     SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create "value"), expr = value valueArg) | ||||
|                 ], | ||||
|                 SynExpr.CreateTuple [ SynExpr.CreateIdentString "key" ; SynExpr.CreateIdentString "value" ], | ||||
|                 range0, | ||||
|                 { | ||||
|                     InKeyword = None | ||||
|                 } | ||||
|             ), | ||||
|             range0, | ||||
|             { | ||||
|                 InKeyword = None | ||||
|             } | ||||
|         ) | ||||
|         // 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 | ||||
| @@ -167,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". | ||||
| @@ -187,131 +179,106 @@ module internal JsonParseGenerator = | ||||
|         | DateOnly -> | ||||
|             node | ||||
|             |> asValueGetValue propertyName "string" | ||||
|             |> SynExpr.pipeThroughFunction ( | ||||
|                 SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "DateOnly" ; "Parse" ]) | ||||
|             ) | ||||
|             |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateOnly" ; "Parse" ]) | ||||
|         | Uri -> | ||||
|             node | ||||
|             |> asValueGetValue propertyName "string" | ||||
|             |> SynExpr.pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Uri" ])) | ||||
|             |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Uri" ]) | ||||
|         | Guid -> | ||||
|             node | ||||
|             |> asValueGetValue propertyName "string" | ||||
|             |> SynExpr.pipeThroughFunction ( | ||||
|                 SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Guid" ; "Parse" ]) | ||||
|             ) | ||||
|             |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "Guid" ; "Parse" ]) | ||||
|         | DateTime -> | ||||
|             node | ||||
|             |> asValueGetValue propertyName "string" | ||||
|             |> SynExpr.pipeThroughFunction ( | ||||
|                 SynExpr.CreateLongIdent (SynLongIdent.Create [ "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 (SynLongIdent.CreateFromLongIdent (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 | ||||
|         | PrimitiveType typeName -> asValueGetValue propertyName typeName node | ||||
|             |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "System" ; "DateTime" ; "Parse" ]) | ||||
|         | 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.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 = | ||||
| @@ -327,9 +294,8 @@ 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 = | ||||
|         SynExpr.CreateIdentString "node" | ||||
|         |> SynExpr.index propertyName | ||||
|         |> parseNode (Some propertyName) options fieldType | ||||
|         let objectToParse = SynExpr.createIdent "node" |> SynExpr.index propertyName | ||||
|         parseNode (Some propertyName) options fieldType objectToParse | ||||
|  | ||||
|     let isJsonNumberHandling (literal : LongIdent) : bool = | ||||
|         match List.rev literal |> List.map (fun ident -> ident.idText) with | ||||
| @@ -340,66 +306,57 @@ module internal JsonParseGenerator = | ||||
|         | [ _ ; "JsonNumberHandling" ; "Serialization" ; "Json" ; "Text" ; "System" ] -> true | ||||
|         | _ -> false | ||||
|  | ||||
|     let createMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynField list) = | ||||
|         let xmlDoc = PreXmlDoc.Create " Parse from a JSON node." | ||||
|     /// `populateNode` will be inserted before we return the `node` variable. | ||||
|     /// | ||||
|     /// 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 returnInfo = | ||||
|             SynBindingReturnInfo.Create (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.named inputArg | ||||
|             |> SynPat.annotateType (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]) | ||||
|  | ||||
|         let inputVal = | ||||
|             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 | ||||
|             let binding = | ||||
|                 SynBinding.basic [ functionName ] [ arg ] functionBody | ||||
|                 |> SynBinding.withXmlDoc xmlDoc | ||||
|                 |> SynBinding.withReturnAnnotation returnInfo | ||||
|                 |> SynMemberDefn.staticMember | ||||
|  | ||||
|             let componentInfo = | ||||
|                 SynComponentInfo.createLong typeName | ||||
|                 |> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing") | ||||
|  | ||||
|             let containingType = | ||||
|                 SynTypeDefnRepr.augmentation () | ||||
|                 |> SynTypeDefn.create componentInfo | ||||
|                 |> SynTypeDefn.withMemberDefns [ binding ] | ||||
|  | ||||
|             SynModuleDecl.Types ([ containingType ], range0) | ||||
|         else | ||||
|                     None | ||||
|             SynBinding.basic [ functionName ] [ arg ] functionBody | ||||
|             |> SynBinding.withXmlDoc xmlDoc | ||||
|             |> SynBinding.withReturnAnnotation returnInfo | ||||
|             |> SynModuleDecl.createLet | ||||
|  | ||||
|             let thisIdOpt = if spec.ExtensionMethods then None else Some inputArg | ||||
|  | ||||
|             SynValData.SynValData ( | ||||
|                 memberFlags, | ||||
|                 SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty), | ||||
|                 thisIdOpt | ||||
|             ) | ||||
|  | ||||
|         let assignments = | ||||
|             fields | ||||
|             |> List.map (fun (SynField (attrs, _, id, fieldType, _, _, _, _, _)) -> | ||||
|                 let id = | ||||
|                     match id with | ||||
|                     | None -> failwith "didn't get an ID on field" | ||||
|                     | Some id -> id | ||||
|  | ||||
|                 let attrs = attrs |> List.collect (fun l -> l.Attributes) | ||||
|  | ||||
|                 let propertyNameAttr = | ||||
|                     attrs | ||||
|                     |> List.tryFind (fun attr -> | ||||
|                         attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal) | ||||
|                     ) | ||||
|  | ||||
|                 let options = | ||||
|                     (JsonParseOption.None, attrs) | ||||
|     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 | ||||
|                                     -> | ||||
|                     | SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident -> | ||||
|                         // Make sure it's fully qualified | ||||
|                                     SynExpr.CreateLongIdent ( | ||||
|                                         SynLongIdent.Create | ||||
|                         SynExpr.createLongIdent | ||||
|                             [ | ||||
|                                 "System" | ||||
|                                 "Text" | ||||
| @@ -408,7 +365,6 @@ module internal JsonParseGenerator = | ||||
|                                 "JsonNumberHandling" | ||||
|                                 "AllowReadingFromString" | ||||
|                             ] | ||||
|                                     ) | ||||
|                     | _ -> attr.ArgExpr | ||||
|  | ||||
|                 { | ||||
| @@ -418,160 +374,192 @@ module internal JsonParseGenerator = | ||||
|                 options | ||||
|         ) | ||||
|  | ||||
|     let createRecordMaker (spec : JsonParseOutputSpec) (fields : SynFieldData<Ident> list) = | ||||
|         let assignments = | ||||
|             fields | ||||
|             |> List.mapi (fun i fieldData -> | ||||
|                 let propertyNameAttr = | ||||
|                     fieldData.Attrs | ||||
|                     |> List.tryFind (fun attr -> | ||||
|                         (SynLongIdent.toString attr.TypeName) | ||||
|                             .EndsWith ("JsonPropertyName", StringComparison.Ordinal) | ||||
|                     ) | ||||
|  | ||||
|                 let options = getParseOptions fieldData.Attrs | ||||
|  | ||||
|                 let propertyName = | ||||
|                     match propertyNameAttr with | ||||
|                     | None -> | ||||
|                         let sb = StringBuilder id.idText.Length | ||||
|                         sb.Append (Char.ToLowerInvariant id.idText.[0]) |> ignore | ||||
|                         let sb = StringBuilder fieldData.Ident.idText.Length | ||||
|  | ||||
|                         if id.idText.Length > 1 then | ||||
|                             sb.Append id.idText.[1..] |> ignore | ||||
|                         sb.Append (Char.ToLowerInvariant fieldData.Ident.idText.[0]) | ||||
|                         |> ignore<StringBuilder> | ||||
|  | ||||
|                         sb.ToString () |> SynConst.CreateString |> SynExpr.CreateConst | ||||
|                         if fieldData.Ident.idText.Length > 1 then | ||||
|                             sb.Append (fieldData.Ident.idText.Substring 1) |> ignore<StringBuilder> | ||||
|  | ||||
|                         sb.ToString () |> SynExpr.CreateConst | ||||
|                     | Some name -> name.ArgExpr | ||||
|  | ||||
|                 let pattern = | ||||
|                     SynPat.LongIdent ( | ||||
|                         SynLongIdent.CreateFromLongIdent [ id ], | ||||
|                         None, | ||||
|                         None, | ||||
|                         SynArgPats.Empty, | ||||
|                         None, | ||||
|                         range0 | ||||
|                     ) | ||||
|  | ||||
|                 SynBinding.Let ( | ||||
|                     isInline = false, | ||||
|                     isMutable = false, | ||||
|                     expr = createParseRhs options propertyName fieldType, | ||||
|                     valData = inputVal, | ||||
|                     pattern = pattern | ||||
|                 ) | ||||
|                 createParseRhs options propertyName fieldData.Type | ||||
|                 |> SynBinding.basic [ Ident.create $"arg_%i{i}" ] [] | ||||
|             ) | ||||
|  | ||||
|         let finalConstruction = | ||||
|             fields | ||||
|             |> List.map (fun (SynField (_, _, id, _, _, _, _, _, _)) -> | ||||
|                 let id = | ||||
|                     match id with | ||||
|                     | None -> failwith "Expected record field to have an identifying name" | ||||
|                     | Some id -> id | ||||
|  | ||||
|                 (SynLongIdent.CreateFromLongIdent [ id ], true), | ||||
|                 Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ id ])) | ||||
|             |> List.mapi (fun i fieldData -> | ||||
|                 (SynLongIdent.createI fieldData.Ident, true), Some (SynExpr.createIdent $"arg_%i{i}") | ||||
|             ) | ||||
|             |> AstHelper.instantiateRecord | ||||
|  | ||||
|         let assignments = | ||||
|         (finalConstruction, assignments) | ||||
|             ||> List.fold (fun final assignment -> | ||||
|                 SynExpr.LetOrUse ( | ||||
|                     false, | ||||
|                     false, | ||||
|                     [ assignment ], | ||||
|                     final, | ||||
|                     range0, | ||||
|                     { | ||||
|                         InKeyword = None | ||||
|                     } | ||||
|                 ) | ||||
|             ) | ||||
|         ||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final) | ||||
|  | ||||
|         let pattern = | ||||
|             SynPat.LongIdent ( | ||||
|                 SynLongIdent.CreateFromLongIdent [ functionName ], | ||||
|                 None, | ||||
|                 None, | ||||
|                 SynArgPats.Pats | ||||
|                     [ | ||||
|                         SynPat.CreateTyped ( | ||||
|                             SynPat.CreateNamed inputArg, | ||||
|                             SynType.LongIdent ( | ||||
|                                 SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ] | ||||
|                             ) | ||||
|                         ) | ||||
|                         |> SynPat.CreateParen | ||||
|                     ], | ||||
|                 None, | ||||
|                 range0 | ||||
|             ) | ||||
|     let createUnionMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : UnionCase<Ident> list) = | ||||
|         fields | ||||
|         |> List.map (fun case -> | ||||
|             let propertyName = JsonSerializeGenerator.getPropertyName case.Ident case.Attrs | ||||
|  | ||||
|         if spec.ExtensionMethods then | ||||
|             let binding = | ||||
|                 SynBinding.SynBinding ( | ||||
|                     None, | ||||
|                     SynBindingKind.Normal, | ||||
|                     false, | ||||
|                     false, | ||||
|                     [], | ||||
|                     xmlDoc, | ||||
|                     inputVal, | ||||
|                     pattern, | ||||
|                     Some returnInfo, | ||||
|                     assignments, | ||||
|                     range0, | ||||
|                     DebugPointAtBinding.NoneAtInvisible, | ||||
|                     { | ||||
|                         LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0) | ||||
|                         InlineKeyword = None | ||||
|                         EqualsRange = Some range0 | ||||
|                     } | ||||
|                 ) | ||||
|  | ||||
|             let mem = SynMemberDefn.Member (binding, range0) | ||||
|  | ||||
|             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 | ||||
|                     } | ||||
|                 ) | ||||
|  | ||||
|             SynModuleDecl.Types ([ containingType ], range0) | ||||
|             let body = | ||||
|                 if case.Fields.IsEmpty then | ||||
|                     SynExpr.createLongIdent' (typeName @ [ case.Ident ]) | ||||
|                 else | ||||
|             let binding = | ||||
|                 SynBinding.Let ( | ||||
|                     isInline = false, | ||||
|                     isMutable = false, | ||||
|                     xmldoc = xmlDoc, | ||||
|                     returnInfo = returnInfo, | ||||
|                     expr = assignments, | ||||
|                     valData = inputVal, | ||||
|                     pattern = pattern | ||||
|                     case.Fields | ||||
|                     |> List.map (fun field -> | ||||
|                         let propertyName = JsonSerializeGenerator.getPropertyName field.Ident field.Attrs | ||||
|                         let options = getParseOptions field.Attrs | ||||
|                         createParseRhs options propertyName field.Type | ||||
|                     ) | ||||
|                     |> SynExpr.tuple | ||||
|                     |> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ])) | ||||
|                     |> SynExpr.createLet | ||||
|                         [ | ||||
|                             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, | ||||
|                     None, | ||||
|                     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.CreateConst "Unrecognised 'type' field value: ") (SynExpr.createIdent "v") | ||||
|                     |> SynExpr.paren | ||||
|                     |> SynExpr.applyFunction (SynExpr.createIdent "failwith") | ||||
|  | ||||
|                 SynMatchClause.SynMatchClause ( | ||||
|                     SynPat.named "v", | ||||
|                     None, | ||||
|                     fail, | ||||
|                     range0, | ||||
|                     DebugPointAtTarget.Yes, | ||||
|                     { | ||||
|                         ArrowRange = Some range0 | ||||
|                         BarRange = Some range0 | ||||
|                     } | ||||
|                 ) | ||||
|             ] | ||||
|         |> SynExpr.createMatch (SynExpr.createIdent "ty") | ||||
|         |> SynExpr.createLet | ||||
|             [ | ||||
|                 let property = SynExpr.CreateConst "type" | ||||
|  | ||||
|                 SynExpr.createIdent "node" | ||||
|                 |> SynExpr.index property | ||||
|                 |> assertNotNull property | ||||
|                 |> SynExpr.pipeThroughFunction ( | ||||
|                     SynExpr.createLambda | ||||
|                         "v" | ||||
|                         (SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v")) | ||||
|                 ) | ||||
|                 |> SynBinding.basic [ Ident.create "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" | ||||
|             ) | ||||
|  | ||||
|             SynModuleDecl.CreateLet [ binding ] | ||||
|         [ | ||||
|             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 createRecordModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) = | ||||
|     let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) = | ||||
|         let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) = | ||||
|             typeDefn | ||||
|  | ||||
|         let (SynComponentInfo (_attributes, _typeParams, _constraints, recordId, _, _preferPostfix, _access, _)) = | ||||
|         let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, access, _)) = | ||||
|             synComponentInfo | ||||
|  | ||||
|         match synTypeDefnRepr with | ||||
|         | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _recordRange), _) -> | ||||
|  | ||||
|             let decls = [ createMaker spec recordId recordFields ] | ||||
|  | ||||
|         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 = recordId |> Seq.map (fun i -> i.idText) |> String.concat "." | ||||
|             let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "." | ||||
|  | ||||
|             let description = | ||||
|                 if spec.ExtensionMethods then | ||||
| @@ -579,31 +567,59 @@ 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 | ||||
|                     match recordId with | ||||
|                 match ident with | ||||
|                 | [] -> failwith "unexpectedly got an empty identifier for record name" | ||||
|                     | recordId -> | ||||
|                 | ident -> | ||||
|                     let expanded = | ||||
|                             List.last recordId | ||||
|                         List.last ident | ||||
|                         |> fun i -> i.idText | ||||
|                         |> fun s -> s + "JsonParseExtension" | ||||
|                             |> Ident.Create | ||||
|                         |> Ident.create | ||||
|  | ||||
|                         List.take (List.length recordId - 1) recordId @ [ expanded ] | ||||
|                     List.take (List.length ident - 1) ident @ [ expanded ] | ||||
|             else | ||||
|                     recordId | ||||
|                 ident | ||||
|  | ||||
|         let info = | ||||
|                 SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc) | ||||
|             SynComponentInfo.createLong moduleName | ||||
|             |> SynComponentInfo.withDocString xmlDoc | ||||
|             |> SynComponentInfo.setAccessibility access | ||||
|             |> SynComponentInfo.addAttributes attributes | ||||
|  | ||||
|             let mdl = SynModuleDecl.CreateNestedModule (info, decls) | ||||
|         let decl = | ||||
|             match synTypeDefnRepr with | ||||
|             | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) -> | ||||
|                 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 | ||||
|  | ||||
|             SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ]) | ||||
|         | _ -> failwithf "Not a record type" | ||||
|                 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" | ||||
|  | ||||
|         [ scaffolding spec ident decl ] | ||||
|         |> SynModuleDecl.nestedModule info | ||||
|         |> List.singleton | ||||
|         |> SynModuleOrNamespace.createNamespace namespaceId | ||||
|  | ||||
| open Myriad.Core | ||||
|  | ||||
| /// Myriad generator that provides a method (possibly an extension method) for a record type, | ||||
| /// containing a JSON parse function. | ||||
| @@ -617,10 +633,21 @@ type JsonParseGenerator () = | ||||
|             let ast, _ = | ||||
|                 Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head | ||||
|  | ||||
|             let records = Ast.extractRecords ast | ||||
|             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 namespaceAndRecords = | ||||
|                 records | ||||
|             let namespaceAndTypes = | ||||
|                 relevantTypes | ||||
|                 |> List.choose (fun (ns, types) -> | ||||
|                     types | ||||
|                     |> List.choose (fun typeDef -> | ||||
| @@ -648,13 +675,9 @@ type JsonParseGenerator () = | ||||
|                 ) | ||||
|  | ||||
|             let modules = | ||||
|                 namespaceAndRecords | ||||
|                 |> List.collect (fun (ns, records) -> | ||||
|                     records | ||||
|                     |> List.map (fun (record, spec) -> | ||||
|                         let recordModule = JsonParseGenerator.createRecordModule ns spec record | ||||
|                         recordModule | ||||
|                     ) | ||||
|                 namespaceAndTypes | ||||
|                 |> List.collect (fun (ns, types) -> | ||||
|                     types |> List.map (fun (ty, spec) -> JsonParseGenerator.createModule ns spec ty) | ||||
|                 ) | ||||
|  | ||||
|             Output.Ast modules | ||||
|   | ||||
| @@ -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,184 +12,146 @@ 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 ( | ||||
|                     SynLongIdent.Create [ "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 | ||||
|             SynExpr.CreateMatch ( | ||||
|                 SynExpr.CreateIdentString "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") | ||||
|  | ||||
|             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.identWithArgs [ Ident.create "Some" ] (SynArgPats.create [ Ident.create "field" ]) | ||||
|                 ) | ||||
|  | ||||
|                     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" ] | ||||
|                             ) | ||||
|                         ) | ||||
|                     ) | ||||
|                 ] | ||||
|             ) | ||||
|             [ noneClause ; someClause ] | ||||
|             |> SynExpr.createMatch (SynExpr.createIdent "field") | ||||
|             |> SynExpr.createLambda "field" | ||||
|             |> fun e -> e, true | ||||
|         | ArrayType ty | ||||
|         | ListType ty -> | ||||
|             // fun field -> | ||||
|             //     let arr = JsonArray () | ||||
|             //     for mem in field do arr.Add ({serializeNode} mem) | ||||
|             //     arr | ||||
|             SynExpr.LetOrUse ( | ||||
|                 false, | ||||
|                 false, | ||||
|                 [ | ||||
|                     SynBinding.Let ( | ||||
|                         pattern = SynPat.CreateNamed (Ident.Create "arr"), | ||||
|                         expr = | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateLongIdent ( | ||||
|                                     SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ] | ||||
|                                 ), | ||||
|                                 SynExpr.CreateConst SynConst.Unit | ||||
|                             ) | ||||
|                     ) | ||||
|                 ], | ||||
|                 SynExpr.CreateSequential | ||||
|             [ | ||||
|                 SynExpr.ForEach ( | ||||
|                     DebugPointAtFor.Yes range0, | ||||
|                     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" | ||||
|                     ], | ||||
|                 range0, | ||||
|                 { | ||||
|                     InKeyword = None | ||||
|                 } | ||||
|             ) | ||||
|                 SynExpr.createIdent "arr" | ||||
|             ] | ||||
|             |> SynExpr.sequential | ||||
|             |> SynExpr.createLet | ||||
|                 [ | ||||
|                     SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ] | ||||
|                     |> SynExpr.applyTo (SynExpr.CreateConst ()) | ||||
|                     |> SynBinding.basic [ Ident.create "arr" ] [] | ||||
|                 ] | ||||
|             |> SynExpr.createLambda "field" | ||||
|         | IDictionaryType (keyType, valueType) | ||||
|         | DictionaryType (keyType, valueType) | ||||
|         | IReadOnlyDictionaryType (keyType, valueType) | ||||
|         | MapType (keyType, valueType) -> | ||||
|             |> fun e -> e, false | ||||
|         | IDictionaryType (_keyType, valueType) | ||||
|         | DictionaryType (_keyType, valueType) | ||||
|         | IReadOnlyDictionaryType (_keyType, valueType) | ||||
|         | MapType (_keyType, valueType) -> | ||||
|             // fun field -> | ||||
|             //    let ret = JsonObject () | ||||
|             //    for (KeyValue(key, value)) in field do | ||||
|             //        ret.Add (key.ToString (), {serializeNode} value) | ||||
|             //    ret | ||||
|             SynExpr.LetOrUse ( | ||||
|                 false, | ||||
|                 false, | ||||
|                 [ | ||||
|                     SynBinding.Let ( | ||||
|                         pattern = SynPat.CreateNamed (Ident.Create "ret"), | ||||
|                         expr = | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateLongIdent ( | ||||
|                                     SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] | ||||
|                                 ), | ||||
|                                 SynExpr.CreateConst SynConst.Unit | ||||
|                             ) | ||||
|                     ) | ||||
|                 ], | ||||
|                 SynExpr.CreateSequential | ||||
|             [ | ||||
|                 SynExpr.ForEach ( | ||||
|                     DebugPointAtFor.Yes range0, | ||||
|                     DebugPointAtInOrTo.Yes range0, | ||||
|                     SeqExprOnly.SeqExprOnly false, | ||||
|                     true, | ||||
|                             SynPat.CreateParen ( | ||||
|                                 SynPat.CreateLongIdent ( | ||||
|                                     SynLongIdent.CreateString "KeyValue", | ||||
|                     SynPat.paren ( | ||||
|                         SynPat.identWithArgs | ||||
|                             [ Ident.create "KeyValue" ] | ||||
|                             (SynArgPats.create [ Ident.create "key" ; Ident.create "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 ], | ||||
|                                 SynExpr.createLongIdent [ "key" ; "ToString" ] | ||||
|                                 |> SynExpr.applyTo (SynExpr.CreateConst ()) | ||||
|                                 SynExpr.applyFunction (fst (serializeNode valueType)) (SynExpr.createIdent "value") | ||||
|                             ]), | ||||
|                     range0 | ||||
|                 ) | ||||
|                                         ) | ||||
|                 SynExpr.createIdent "ret" | ||||
|             ] | ||||
|                                 ) | ||||
|                             ), | ||||
|                             SynExpr.CreateIdent (Ident.Create "field"), | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateLongIdent (SynLongIdent.Create [ "ret" ; "Add" ]), | ||||
|                                 SynExpr.CreateParenedTuple | ||||
|             |> SynExpr.sequential | ||||
|             |> SynExpr.createLet | ||||
|                 [ | ||||
|                                         SynExpr.CreateApp ( | ||||
|                                             SynExpr.CreateLongIdent (SynLongIdent.Create [ "key" ; "ToString" ]), | ||||
|                                             SynExpr.CreateConst SynConst.Unit | ||||
|                                         ) | ||||
|                                         SynExpr.CreateApp (serializeNode valueType, SynExpr.CreateIdentString "value") | ||||
|                     SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] | ||||
|                     |> SynExpr.applyTo (SynExpr.CreateConst ()) | ||||
|                     |> SynBinding.basic [ Ident.create "ret" ] [] | ||||
|                 ] | ||||
|                             ), | ||||
|                             range0 | ||||
|                         ) | ||||
|                         SynExpr.CreateIdentString "ret" | ||||
|                     ], | ||||
|                 range0, | ||||
|                 { | ||||
|                     InKeyword = None | ||||
|                 } | ||||
|             ) | ||||
|             |> SynExpr.createLambda "field" | ||||
|             |> fun e -> e, false | ||||
|         | _ -> | ||||
|             // {type}.toJsonNode | ||||
|             let typeName = | ||||
| @@ -200,213 +159,249 @@ module internal JsonSerializeGenerator = | ||||
|                 | SynType.LongIdent ident -> ident.LongIdent | ||||
|                 | _ -> failwith $"Unrecognised type: %+A{fieldType}" | ||||
|  | ||||
|             SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent (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 createSerializeRhs (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr = | ||||
|         let func = SynExpr.CreateLongIdent (SynLongIdent.Create [ "node" ; "Add" ]) | ||||
|  | ||||
|         let args = | ||||
|             SynExpr.CreateParenedTuple | ||||
|     let createSerializeRhsRecord (propertyName : SynExpr) (fieldId : Ident) (fieldType : SynType) : SynExpr = | ||||
|         [ | ||||
|             propertyName | ||||
|                     SynExpr.CreateApp ( | ||||
|                         serializeNode fieldType, | ||||
|                         SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ Ident.Create "input" ; fieldId ]) | ||||
|                     ) | ||||
|             SynExpr.pipeThroughFunction | ||||
|                 (fst (serializeNode fieldType)) | ||||
|                 (SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ]) | ||||
|             |> SynExpr.paren | ||||
|         ] | ||||
|         |> SynExpr.tuple | ||||
|         |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) | ||||
|  | ||||
|         SynExpr.CreateApp (func, args) | ||||
|  | ||||
|     let createMaker (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (fields : SynField list) = | ||||
|         let xmlDoc = PreXmlDoc.Create " Serialize to a JSON node" | ||||
|  | ||||
|         let returnInfo = | ||||
|             SynBindingReturnInfo.Create ( | ||||
|                 SynType.LongIdent (SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]) | ||||
|             ) | ||||
|  | ||||
|         let inputArg = Ident.Create "input" | ||||
|         let functionName = Ident.Create "toJsonNode" | ||||
|  | ||||
|         let inputVal = | ||||
|             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 thisIdOpt = if spec.ExtensionMethods then None else Some inputArg | ||||
|  | ||||
|             SynValData.SynValData ( | ||||
|                 memberFlags, | ||||
|                 SynValInfo.SynValInfo ([ [ SynArgInfo.CreateId functionName ] ], SynArgInfo.Empty), | ||||
|                 thisIdOpt | ||||
|             ) | ||||
|  | ||||
|         let assignments = | ||||
|             fields | ||||
|             |> List.map (fun (SynField (attrs, _, id, fieldType, _, _, _, _, _)) -> | ||||
|                 let id = | ||||
|                     match id with | ||||
|                     | None -> failwith "didn't get an ID on field" | ||||
|                     | Some id -> id | ||||
|  | ||||
|                 let attrs = attrs |> List.collect (fun l -> l.Attributes) | ||||
|  | ||||
|     let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr = | ||||
|         let propertyNameAttr = | ||||
|             attrs | ||||
|             |> List.tryFind (fun attr -> | ||||
|                         attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal) | ||||
|                 (SynLongIdent.toString attr.TypeName) | ||||
|                     .EndsWith ("JsonPropertyName", StringComparison.Ordinal) | ||||
|             ) | ||||
|  | ||||
|                 let propertyName = | ||||
|         match propertyNameAttr with | ||||
|         | None -> | ||||
|                         let sb = StringBuilder id.idText.Length | ||||
|                         sb.Append (Char.ToLowerInvariant id.idText.[0]) |> ignore | ||||
|             let sb = StringBuilder fieldId.idText.Length | ||||
|             sb.Append (Char.ToLowerInvariant fieldId.idText.[0]) |> ignore | ||||
|  | ||||
|                         if id.idText.Length > 1 then | ||||
|                             sb.Append id.idText.[1..] |> ignore | ||||
|             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 | ||||
|  | ||||
|                 let pattern = | ||||
|                     SynPat.LongIdent ( | ||||
|                         SynLongIdent.CreateFromLongIdent [ id ], | ||||
|                         None, | ||||
|                         None, | ||||
|                         SynArgPats.Empty, | ||||
|                         None, | ||||
|                         range0 | ||||
|                     ) | ||||
|     /// `populateNode` will be inserted before we return the `node` variable. | ||||
|     /// | ||||
|     /// That is, we give you access to a `JsonObject` called `node`, | ||||
|     /// and you have access to a variable `inputArgName` which is of type `typeName`. | ||||
|     /// Your job is to provide a `populateNode` expression which has the side effect | ||||
|     /// of mutating `node` to faithfully reflect the value of `inputArgName`. | ||||
|     let scaffolding | ||||
|         (spec : JsonSerializeOutputSpec) | ||||
|         (typeName : LongIdent) | ||||
|         (inputArgName : Ident) | ||||
|         (populateNode : SynExpr) | ||||
|         : SynModuleDecl | ||||
|         = | ||||
|         let xmlDoc = PreXmlDoc.create "Serialize to a JSON node" | ||||
|  | ||||
|                 createSerializeRhs propertyName id fieldType | ||||
|             ) | ||||
|         let returnInfo = | ||||
|             SynLongIdent.createS' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ] | ||||
|             |> SynType.LongIdent | ||||
|  | ||||
|         let finalConstruction = | ||||
|             fields | ||||
|             |> List.map (fun (SynField (_, _, id, _, _, _, _, _, _)) -> | ||||
|                 let id = | ||||
|                     match id with | ||||
|                     | None -> failwith "Expected record field to have an identifying name" | ||||
|                     | Some id -> id | ||||
|  | ||||
|                 (SynLongIdent.CreateFromLongIdent [ id ], true), | ||||
|                 Some (SynExpr.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ id ])) | ||||
|             ) | ||||
|             |> AstHelper.instantiateRecord | ||||
|  | ||||
|         let assignments = assignments |> SynExpr.CreateSequential | ||||
|         let functionName = Ident.create "toJsonNode" | ||||
|  | ||||
|         let assignments = | ||||
|             SynExpr.LetOrUse ( | ||||
|                 false, | ||||
|                 false, | ||||
|             [ | ||||
|                     SynBinding.Let ( | ||||
|                         pattern = SynPat.CreateNamed (Ident.Create "node"), | ||||
|                         expr = | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateLongIdent ( | ||||
|                                     SynLongIdent.Create [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] | ||||
|                                 ), | ||||
|                                 SynExpr.CreateConst SynConst.Unit | ||||
|                             ) | ||||
|                     ) | ||||
|                 ], | ||||
|                 SynExpr.CreateSequential | ||||
|                 populateNode | ||||
|                 SynExpr.Upcast (SynExpr.createIdent "node", SynType.Anon range0, range0) | ||||
|             ] | ||||
|             |> SynExpr.sequential | ||||
|             |> SynExpr.createLet | ||||
|                 [ | ||||
|                         SynExpr.Do (assignments, range0) | ||||
|                         SynExpr.Upcast (SynExpr.CreateIdentString "node", SynType.Anon range0, range0) | ||||
|                     ], | ||||
|                 range0, | ||||
|                 { | ||||
|                     InKeyword = None | ||||
|                 } | ||||
|             ) | ||||
|                     SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] | ||||
|                     |> SynExpr.applyTo (SynExpr.CreateConst ()) | ||||
|                     |> SynBinding.basic [ Ident.create "node" ] [] | ||||
|                 ] | ||||
|  | ||||
|         let pattern = | ||||
|             SynPat.LongIdent ( | ||||
|                 SynLongIdent.CreateFromLongIdent [ functionName ], | ||||
|                 None, | ||||
|                 None, | ||||
|                 SynArgPats.Pats | ||||
|                     [ | ||||
|                         SynPat.CreateTyped ( | ||||
|                             SynPat.CreateNamed inputArg, | ||||
|                             SynType.LongIdent (SynLongIdent.CreateFromLongIdent typeName) | ||||
|                         ) | ||||
|                         |> SynPat.CreateParen | ||||
|                     ], | ||||
|                 None, | ||||
|                 range0 | ||||
|             ) | ||||
|             SynPat.namedI inputArgName | ||||
|             |> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create typeName)) | ||||
|  | ||||
|         if spec.ExtensionMethods then | ||||
|             let binding = | ||||
|                 SynBinding.SynBinding ( | ||||
|                     None, | ||||
|                     SynBindingKind.Normal, | ||||
|                     false, | ||||
|                     false, | ||||
|                     [], | ||||
|                     xmlDoc, | ||||
|                     inputVal, | ||||
|                     pattern, | ||||
|                     Some returnInfo, | ||||
|                     assignments, | ||||
|                     range0, | ||||
|                     DebugPointAtBinding.NoneAtInvisible, | ||||
|                     { | ||||
|                         LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0) | ||||
|                         InlineKeyword = None | ||||
|                         EqualsRange = Some range0 | ||||
|                     } | ||||
|                 ) | ||||
|             let componentInfo = | ||||
|                 SynComponentInfo.createLong typeName | ||||
|                 |> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing") | ||||
|  | ||||
|             let mem = SynMemberDefn.Member (binding, range0) | ||||
|             let memberDef = | ||||
|                 assignments | ||||
|                 |> SynBinding.basic [ functionName ] [ pattern ] | ||||
|                 |> SynBinding.withXmlDoc xmlDoc | ||||
|                 |> SynBinding.withReturnAnnotation returnInfo | ||||
|                 |> 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 = | ||||
|                 SynBinding.Let ( | ||||
|                     isInline = false, | ||||
|                     isMutable = false, | ||||
|                     xmldoc = xmlDoc, | ||||
|                     returnInfo = returnInfo, | ||||
|                     expr = assignments, | ||||
|                     valData = inputVal, | ||||
|                     pattern = pattern | ||||
|             assignments | ||||
|             |> SynBinding.basic [ functionName ] [ pattern ] | ||||
|             |> SynBinding.withReturnAnnotation returnInfo | ||||
|             |> SynBinding.withXmlDoc xmlDoc | ||||
|             |> SynModuleDecl.createLet | ||||
|  | ||||
|     let recordModule (spec : JsonSerializeOutputSpec) (_typeName : LongIdent) (fields : SynField list) = | ||||
|         let fields = fields |> List.map SynField.extractWithIdent | ||||
|  | ||||
|         fields | ||||
|         |> List.map (fun fieldData -> | ||||
|             let propertyName = getPropertyName fieldData.Ident fieldData.Attrs | ||||
|             createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type | ||||
|         ) | ||||
|         |> SynExpr.sequential | ||||
|         |> fun expr -> SynExpr.Do (expr, range0) | ||||
|  | ||||
|     let unionModule (spec : JsonSerializeOutputSpec) (typeName : LongIdent) (cases : SynUnionCase list) = | ||||
|         let inputArg = Ident.create "input" | ||||
|         let fields = cases |> List.map SynUnionCase.extract | ||||
|  | ||||
|         fields | ||||
|         |> List.map (fun unionCase -> | ||||
|             let propertyName = getPropertyName unionCase.Ident unionCase.Attrs | ||||
|  | ||||
|             let caseNames = unionCase.Fields |> List.mapi (fun i _ -> Ident.create $"arg%i{i}") | ||||
|  | ||||
|             let argPats = SynArgPats.create caseNames | ||||
|  | ||||
|             let pattern = | ||||
|                 SynPat.LongIdent ( | ||||
|                     SynLongIdent.create (typeName @ [ unionCase.Ident ]), | ||||
|                     None, | ||||
|                     None, | ||||
|                     argPats, | ||||
|                     None, | ||||
|                     range0 | ||||
|                 ) | ||||
|  | ||||
|             SynModuleDecl.CreateLet [ binding ] | ||||
|             let typeLine = | ||||
|                 [ | ||||
|                     SynExpr.CreateConst "type" | ||||
|                     SynExpr.applyFunction | ||||
|                         (SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]) | ||||
|                         propertyName | ||||
|                 ] | ||||
|                 |> SynExpr.tuple | ||||
|                 |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) | ||||
|  | ||||
|     let createRecordModule | ||||
|             let dataNode = | ||||
|                 SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] | ||||
|                 |> SynExpr.applyTo (SynExpr.CreateConst ()) | ||||
|                 |> SynBinding.basic [ Ident.create "dataNode" ] [] | ||||
|  | ||||
|             let dataBindings = | ||||
|                 (unionCase.Fields, caseNames) | ||||
|                 ||> List.zip | ||||
|                 |> List.map (fun (fieldData, caseName) -> | ||||
|                     let propertyName = getPropertyName (Option.get fieldData.Ident) fieldData.Attrs | ||||
|  | ||||
|                     let node = | ||||
|                         SynExpr.applyFunction (fst (serializeNode fieldData.Type)) (SynExpr.createIdent' caseName) | ||||
|  | ||||
|                     [ propertyName ; node ] | ||||
|                     |> SynExpr.tuple | ||||
|                     |> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ]) | ||||
|                 ) | ||||
|  | ||||
|             let assignToNode = | ||||
|                 [ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ] | ||||
|                 |> SynExpr.tuple | ||||
|                 |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) | ||||
|  | ||||
|             let dataNode = | ||||
|                 SynExpr.sequential (dataBindings @ [ assignToNode ]) | ||||
|                 |> SynExpr.createLet [ dataNode ] | ||||
|  | ||||
|             let action = | ||||
|                 [ | ||||
|                     yield typeLine | ||||
|                     if not dataBindings.IsEmpty then | ||||
|                         yield dataNode | ||||
|                 ] | ||||
|                 |> SynExpr.sequential | ||||
|  | ||||
|             SynMatchClause.create pattern action | ||||
|         ) | ||||
|         |> 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) | ||||
|         (opens : SynOpenDeclTarget list) | ||||
|         (spec : JsonSerializeOutputSpec) | ||||
| @@ -415,25 +410,17 @@ module internal JsonSerializeGenerator = | ||||
|         let (SynTypeDefn (synComponentInfo, synTypeDefnRepr, _members, _implicitCtor, _, _)) = | ||||
|             typeDefn | ||||
|  | ||||
|         let (SynComponentInfo (_attributes, _typeParams, _constraints, recordId, _, _preferPostfix, _access, _)) = | ||||
|         let (SynComponentInfo (_attributes, _typeParams, _constraints, ident, _, _preferPostfix, access, _)) = | ||||
|             synComponentInfo | ||||
|  | ||||
|         match synTypeDefnRepr with | ||||
|         | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _recordRange), _) -> | ||||
|  | ||||
|             let decls = [ createMaker spec recordId recordFields ] | ||||
|  | ||||
|         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 = recordId |> Seq.map (fun i -> i.idText) |> String.concat "." | ||||
|             let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "." | ||||
|  | ||||
|             let description = | ||||
|                 if spec.ExtensionMethods then | ||||
| @@ -441,34 +428,54 @@ 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 | ||||
|                     match recordId with | ||||
|                     | [] -> failwith "unexpectedly got an empty identifier for record name" | ||||
|                     | recordId -> | ||||
|                 match ident with | ||||
|                 | [] -> failwith "unexpectedly got an empty identifier for type name" | ||||
|                 | ident -> | ||||
|                     let expanded = | ||||
|                             List.last recordId | ||||
|                         List.last ident | ||||
|                         |> fun i -> i.idText | ||||
|                         |> fun s -> s + "JsonSerializeExtension" | ||||
|                             |> Ident.Create | ||||
|                         |> Ident.create | ||||
|  | ||||
|                         List.take (List.length recordId - 1) recordId @ [ expanded ] | ||||
|                     List.take (List.length ident - 1) ident @ [ expanded ] | ||||
|             else | ||||
|                     recordId | ||||
|                 ident | ||||
|  | ||||
|         let info = | ||||
|                 SynComponentInfo.Create (moduleName, attributes = attributes, xmldoc = xmlDoc) | ||||
|             SynComponentInfo.createLong moduleName | ||||
|             |> SynComponentInfo.addAttributes attributes | ||||
|             |> SynComponentInfo.setAccessibility access | ||||
|             |> SynComponentInfo.withDocString xmlDoc | ||||
|  | ||||
|             let mdl = SynModuleDecl.CreateNestedModule (info, decls) | ||||
|  | ||||
|             SynModuleOrNamespace.CreateNamespace ( | ||||
|                 namespaceId, | ||||
|                 decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ mdl ] | ||||
|         let decls = | ||||
|             match synTypeDefnRepr with | ||||
|             | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, recordFields, _range), _) -> | ||||
|                 recordModule spec ident recordFields | ||||
|                 |> scaffolding spec ident (Ident.create "input") | ||||
|             | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, unionFields, _range), _) -> | ||||
|                 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 | ||||
|                 ) | ||||
|         | _ -> failwithf "Not a record type" | ||||
|                 |> enumModule spec ident | ||||
|             | ty -> failwithf "Unsupported type: got %O" ty | ||||
|  | ||||
|         [ | ||||
|             yield! opens |> List.map SynModuleDecl.openAny | ||||
|             yield decls |> List.singleton |> SynModuleDecl.nestedModule info | ||||
|         ] | ||||
|         |> SynModuleOrNamespace.createNamespace namespaceId | ||||
|  | ||||
| open Myriad.Core | ||||
|  | ||||
| /// Myriad generator that provides a method (possibly an extension method) for a record type, | ||||
| /// containing a JSON serialization function. | ||||
| @@ -482,10 +489,21 @@ type JsonSerializeGenerator () = | ||||
|             let ast, _ = | ||||
|                 Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head | ||||
|  | ||||
|             let records = Ast.extractRecords ast | ||||
|             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 namespaceAndRecords = | ||||
|                 records | ||||
|             let namespaceAndTypes = | ||||
|                 relevantTypes | ||||
|                 |> List.choose (fun (ns, types) -> | ||||
|                     types | ||||
|                     |> List.choose (fun typeDef -> | ||||
| @@ -515,13 +533,10 @@ type JsonSerializeGenerator () = | ||||
|             let opens = AstHelper.extractOpens ast | ||||
|  | ||||
|             let modules = | ||||
|                 namespaceAndRecords | ||||
|                 |> List.collect (fun (ns, records) -> | ||||
|                     records | ||||
|                     |> List.map (fun (record, spec) -> | ||||
|                         let recordModule = JsonSerializeGenerator.createRecordModule ns opens spec record | ||||
|                         recordModule | ||||
|                     ) | ||||
|                 namespaceAndTypes | ||||
|                 |> List.collect (fun (ns, types) -> | ||||
|                     types | ||||
|                     |> List.map (fun (ty, spec) -> JsonSerializeGenerator.createModule ns opens spec ty) | ||||
|                 ) | ||||
|  | ||||
|             Output.Ast modules | ||||
|   | ||||
							
								
								
									
										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, | ||||
| @@ -47,7 +44,7 @@ module internal RemoveOptionsGenerator = | ||||
|         (fields : SynField list) | ||||
|         = | ||||
|         let fields : SynField list = fields |> List.map removeOption | ||||
|         let name = Ident.Create "Short" | ||||
|         let name = Ident.create "Short" | ||||
|  | ||||
|         let record = | ||||
|             { | ||||
| @@ -63,94 +60,51 @@ module internal RemoveOptionsGenerator = | ||||
|  | ||||
|         SynModuleDecl.Types ([ typeDecl ], range0) | ||||
|  | ||||
|     let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynField list) = | ||||
|         let xmlDoc = PreXmlDoc.Create " Remove the optional members of the input." | ||||
|     let createMaker (withOptionsType : LongIdent) (withoutOptionsType : LongIdent) (fields : SynFieldData<Ident> list) = | ||||
|         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 | ||||
|             |> List.map (fun (SynField (_, _, id, fieldType, _, _, _, _, _)) -> | ||||
|                 let id = | ||||
|                     match id with | ||||
|                     | None -> failwith "Expected record field to have an identifying name" | ||||
|                     | Some id -> id | ||||
|  | ||||
|             |> List.map (fun fieldData -> | ||||
|                 let accessor = | ||||
|                     SynExpr.LongIdent (false, SynLongIdent ([ inputArg ; id ], [ range0 ], []), None, range0) | ||||
|  | ||||
|                 let body = | ||||
|                     match fieldType with | ||||
|                     | OptionType _ -> | ||||
|                         SynExpr.CreateApp ( | ||||
|                             SynExpr.CreateAppInfix ( | ||||
|                     SynExpr.LongIdent ( | ||||
|                         false, | ||||
|                                     SynLongIdent.SynLongIdent ( | ||||
|                                         [ Ident.Create "op_PipeRight" ], | ||||
|                                         [], | ||||
|                                         [ Some (IdentTrivia.OriginalNotation "|>") ] | ||||
|                                     ), | ||||
|                         SynLongIdent ([ inputArg ; fieldData.Ident ], [ range0 ], []), | ||||
|                         None, | ||||
|                         range0 | ||||
|                                 ), | ||||
|                     ) | ||||
|  | ||||
|                 let body = | ||||
|                     match fieldData.Type with | ||||
|                     | OptionType _ -> | ||||
|                         accessor | ||||
|                             ), | ||||
|                             SynExpr.CreateApp ( | ||||
|                                 SynExpr.CreateLongIdent (SynLongIdent.CreateString "Option.defaultWith"), | ||||
|                                 SynExpr.CreateLongIdent ( | ||||
|                                     SynLongIdent.CreateFromLongIdent ( | ||||
|                                         withoutOptionsType @ [ Ident.Create (sprintf "Default%s" id.idText) ] | ||||
|                                     ) | ||||
|                                 ) | ||||
|                             ) | ||||
|                         |> SynExpr.pipeThroughFunction ( | ||||
|                             SynExpr.applyFunction | ||||
|                                 (SynExpr.createLongIdent [ "Option" ; "defaultWith" ]) | ||||
|                                 (SynExpr.createLongIdent' ( | ||||
|                                     withoutOptionsType | ||||
|                                     @ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ] | ||||
|                                 )) | ||||
|                         ) | ||||
|                     | _ -> accessor | ||||
|  | ||||
|                 (SynLongIdent.CreateFromLongIdent [ id ], true), Some body | ||||
|                 (SynLongIdent.createI fieldData.Ident, true), Some body | ||||
|             ) | ||||
|             |> AstHelper.instantiateRecord | ||||
|  | ||||
|         let pattern = | ||||
|             SynPat.LongIdent ( | ||||
|                 SynLongIdent.CreateFromLongIdent [ functionName ], | ||||
|                 None, | ||||
|                 None, | ||||
|                 SynArgPats.Pats | ||||
|         SynBinding.basic | ||||
|             [ functionName ] | ||||
|             [ | ||||
|                         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 ] | ||||
|                 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, _, _)) = | ||||
| @@ -160,35 +114,35 @@ module internal RemoveOptionsGenerator = | ||||
|             synComponentInfo | ||||
|  | ||||
|         match synTypeDefnRepr with | ||||
|         | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (accessibility, recordFields, _recordRange), _) -> | ||||
|         | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (accessibility, fields, _range), _) -> | ||||
|             let fieldData = fields |> List.map SynField.extractWithIdent | ||||
|  | ||||
|             let decls = | ||||
|                 [ | ||||
|                     createType (Some doc) accessibility typeParams recordFields | ||||
|                     createMaker [ Ident.Create "Short" ] recordId recordFields | ||||
|                 ] | ||||
|  | ||||
|             let attributes = | ||||
|                 [ | ||||
|                     SynAttributeList.Create (SynAttribute.RequireQualifiedAccess ()) | ||||
|                     SynAttributeList.Create SynAttribute.compilationRepresentation | ||||
|                     createType (Some doc) accessibility typeParams fields | ||||
|                     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,31 +0,0 @@ | ||||
| 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" | ||||
|             ArgExpr = | ||||
|                 SynExpr.CreateLongIdent ( | ||||
|                     false, | ||||
|                     SynLongIdent.Create [ "CompilationRepresentationFlags" ; "ModuleSuffix" ], | ||||
|                     None | ||||
|                 ) | ||||
|                 |> SynExpr.CreateParen | ||||
|             Target = None | ||||
|             AppliesToGetterAndSetter = false | ||||
|             Range = range0 | ||||
|         } | ||||
|  | ||||
|     let internal autoOpen : SynAttribute = | ||||
|         { | ||||
|             TypeName = SynLongIdent.CreateString "AutoOpen" | ||||
|             ArgExpr = SynExpr.CreateConst SynConst.Unit | ||||
|             Target = None | ||||
|             AppliesToGetterAndSetter = false | ||||
|             Range = range0 | ||||
|         } | ||||
| @@ -1,313 +0,0 @@ | ||||
| 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 | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynExpr = | ||||
|  | ||||
|     /// {expr} |> {func} | ||||
|     let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr = | ||||
|         SynExpr.CreateApp ( | ||||
|             SynExpr.CreateAppInfix ( | ||||
|                 SynExpr.CreateLongIdent ( | ||||
|                     SynLongIdent.SynLongIdent ( | ||||
|                         [ Ident.Create "op_PipeRight" ], | ||||
|                         [], | ||||
|                         [ Some (IdentTrivia.OriginalNotation "|>") ] | ||||
|                     ) | ||||
|                 ), | ||||
|                 expr | ||||
|             ), | ||||
|             func | ||||
|         ) | ||||
|  | ||||
|     /// if {cond} then {trueBranch} else {falseBranch} | ||||
|     /// Note that this function puts the trueBranch last, for pipelining convenience: | ||||
|     /// we assume that the `else` branch is more like an error case and is less interesting. | ||||
|     let ifThenElse (cond : SynExpr) (falseBranch : SynExpr) (trueBranch : SynExpr) : SynExpr = | ||||
|         SynExpr.IfThenElse ( | ||||
|             cond, | ||||
|             trueBranch, | ||||
|             Some falseBranch, | ||||
|             DebugPointAtBinding.Yes range0, | ||||
|             false, | ||||
|             range0, | ||||
|             { | ||||
|                 IfKeyword = range0 | ||||
|                 IsElif = false | ||||
|                 ThenKeyword = range0 | ||||
|                 ElseKeyword = Some range0 | ||||
|                 IfToThenRange = range0 | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|     /// try {body} with | {exc} as exc -> {handler} | ||||
|     let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr = | ||||
|         let clause = | ||||
|             SynMatchClause.Create (SynPat.As (exc, SynPat.CreateNamed (Ident.Create "exc"), range0), None, handler) | ||||
|  | ||||
|         SynExpr.TryWith ( | ||||
|             body, | ||||
|             [ clause ], | ||||
|             range0, | ||||
|             DebugPointAtTry.Yes range0, | ||||
|             DebugPointAtWith.Yes range0, | ||||
|             { | ||||
|                 TryKeyword = range0 | ||||
|                 TryToWithRange = range0 | ||||
|                 WithKeyword = range0 | ||||
|                 WithToEndRange = range0 | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|     /// {a} = {b} | ||||
|     let equals (a : SynExpr) (b : SynExpr) = | ||||
|         SynExpr.CreateApp ( | ||||
|             SynExpr.CreateAppInfix ( | ||||
|                 SynExpr.CreateLongIdent ( | ||||
|                     SynLongIdent.SynLongIdent ( | ||||
|                         Ident.CreateLong "op_Equality", | ||||
|                         [], | ||||
|                         [ Some (IdentTrivia.OriginalNotation "=") ] | ||||
|                     ) | ||||
|                 ), | ||||
|                 a | ||||
|             ), | ||||
|             b | ||||
|         ) | ||||
|  | ||||
|     /// {a} + {b} | ||||
|     let plus (a : SynExpr) (b : SynExpr) = | ||||
|         SynExpr.CreateApp ( | ||||
|             SynExpr.CreateAppInfix ( | ||||
|                 SynExpr.CreateLongIdent ( | ||||
|                     SynLongIdent.SynLongIdent ( | ||||
|                         Ident.CreateLong "op_Addition", | ||||
|                         [], | ||||
|                         [ Some (IdentTrivia.OriginalNotation "+") ] | ||||
|                     ) | ||||
|                 ), | ||||
|                 a | ||||
|             ), | ||||
|             b | ||||
|         ) | ||||
|  | ||||
|     let rec stripOptionalParen (expr : SynExpr) : SynExpr = | ||||
|         match expr with | ||||
|         | SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr | ||||
|         | expr -> expr | ||||
|  | ||||
|     /// Given e.g. "byte", returns "System.Byte". | ||||
|     let qualifyPrimitiveType (typeName : string) : LongIdent = | ||||
|         match typeName with | ||||
|         | "float32" -> [ "System" ; "Single" ] | ||||
|         | "float" -> [ "System" ; "Double" ] | ||||
|         | "byte" | ||||
|         | "uint8" -> [ "System" ; "Byte" ] | ||||
|         | "sbyte" -> [ "System" ; "SByte" ] | ||||
|         | "int16" -> [ "System" ; "Int16" ] | ||||
|         | "int" -> [ "System" ; "Int32" ] | ||||
|         | "int64" -> [ "System" ; "Int64" ] | ||||
|         | "uint16" -> [ "System" ; "UInt16" ] | ||||
|         | "uint" | ||||
|         | "uint32" -> [ "System" ; "UInt32" ] | ||||
|         | "uint64" -> [ "System" ; "UInt64" ] | ||||
|         | _ -> failwith $"Unable to identify a parsing function `string -> %s{typeName}`" | ||||
|         |> List.map Ident.Create | ||||
|  | ||||
|     /// {obj}.{meth} {arg} | ||||
|     let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr = | ||||
|         SynExpr.CreateApp ( | ||||
|             SynExpr.DotGet ( | ||||
|                 obj, | ||||
|                 range0, | ||||
|                 SynLongIdent.SynLongIdent (id = [ Ident.Create meth ], dotRanges = [], trivia = [ None ]), | ||||
|                 range0 | ||||
|             ), | ||||
|             arg | ||||
|         ) | ||||
|  | ||||
|     /// {obj}.{meth}() | ||||
|     let callMethod (meth : string) (obj : SynExpr) : SynExpr = | ||||
|         callMethodArg meth (SynExpr.CreateConst SynConst.Unit) obj | ||||
|  | ||||
|     /// {obj}.{meth}<ty>() | ||||
|     let callGenericMethod (meth : string) (ty : string) (obj : SynExpr) : SynExpr = | ||||
|         SynExpr.CreateApp ( | ||||
|             SynExpr.TypeApp ( | ||||
|                 SynExpr.DotGet (obj, range0, SynLongIdent.Create [ meth ], range0), | ||||
|                 range0, | ||||
|                 [ SynType.CreateLongIdent ty ], | ||||
|                 [], | ||||
|                 Some range0, | ||||
|                 range0, | ||||
|                 range0 | ||||
|             ), | ||||
|             SynExpr.CreateConst SynConst.Unit | ||||
|         ) | ||||
|  | ||||
|     let index (property : SynExpr) (obj : SynExpr) : SynExpr = | ||||
|         SynExpr.DotIndexedGet (obj, property, range0, range0) | ||||
|  | ||||
|     /// (fun {varName} -> {body}) | ||||
|     let createLambda (varName : string) (body : SynExpr) : SynExpr = | ||||
|         let parsedDataPat = [ SynPat.CreateNamed (Ident.Create varName) ] | ||||
|  | ||||
|         SynExpr.Lambda ( | ||||
|             false, | ||||
|             false, | ||||
|             SynSimplePats.Create [ SynSimplePat.CreateId (Ident.Create varName) ], | ||||
|             body, | ||||
|             Some (parsedDataPat, body), | ||||
|             range0, | ||||
|             { | ||||
|                 ArrowRange = Some range0 | ||||
|             } | ||||
|         ) | ||||
|         |> SynExpr.CreateParen | ||||
|  | ||||
|     let reraise : SynExpr = | ||||
|         SynExpr.CreateApp (SynExpr.CreateIdent (Ident.Create "reraise"), SynExpr.CreateConst SynConst.Unit) | ||||
|  | ||||
|     /// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct) | ||||
|     let startAsTask (ct : SynLongIdent) (body : SynExpr) = | ||||
|         let lambda = | ||||
|             SynExpr.CreateApp ( | ||||
|                 SynExpr.CreateLongIdent (SynLongIdent.Create [ "Async" ; "StartAsTask" ]), | ||||
|                 SynExpr.CreateParenedTuple | ||||
|                     [ | ||||
|                         SynExpr.CreateLongIdent (SynLongIdent.CreateString "a") | ||||
|                         equals | ||||
|                             (SynExpr.LongIdent (true, SynLongIdent.CreateString "cancellationToken", None, range0)) | ||||
|                             (SynExpr.CreateLongIdent ct) | ||||
|                     ] | ||||
|             ) | ||||
|             |> createLambda "a" | ||||
|  | ||||
|         pipeThroughFunction lambda body | ||||
|  | ||||
|     /// {compExpr} { {lets} ; return {ret} } | ||||
|     let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr = | ||||
|         let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0) | ||||
|  | ||||
|         let contents : SynExpr = | ||||
|             (retStatement, List.rev lets) | ||||
|             ||> List.fold (fun state binding -> | ||||
|                 match binding with | ||||
|                 | LetBang (lhs, rhs) -> | ||||
|                     SynExpr.LetOrUseBang ( | ||||
|                         DebugPointAtBinding.Yes range0, | ||||
|                         false, | ||||
|                         true, | ||||
|                         SynPat.CreateNamed (Ident.Create lhs), | ||||
|                         rhs, | ||||
|                         [], | ||||
|                         state, | ||||
|                         range0, | ||||
|                         { | ||||
|                             EqualsRange = Some range0 | ||||
|                         } | ||||
|                     ) | ||||
|                 | Let (lhs, rhs) -> | ||||
|                     SynExpr.LetOrUse ( | ||||
|                         false, | ||||
|                         false, | ||||
|                         [ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ], | ||||
|                         state, | ||||
|                         range0, | ||||
|                         { | ||||
|                             SynExprLetOrUseTrivia.InKeyword = None | ||||
|                         } | ||||
|                     ) | ||||
|                 | Use (lhs, rhs) -> | ||||
|                     SynExpr.LetOrUse ( | ||||
|                         false, | ||||
|                         true, | ||||
|                         [ SynBinding.Let (pattern = SynPat.CreateNamed (Ident.Create lhs), expr = rhs) ], | ||||
|                         state, | ||||
|                         range0, | ||||
|                         { | ||||
|                             SynExprLetOrUseTrivia.InKeyword = None | ||||
|                         } | ||||
|                     ) | ||||
|                 | Do body -> SynExpr.CreateSequential [ SynExpr.Do (body, range0) ; state ] | ||||
|             ) | ||||
|  | ||||
|         SynExpr.CreateApp ( | ||||
|             SynExpr.CreateIdent (Ident.Create compExpr), | ||||
|             SynExpr.ComputationExpr (false, contents, range0) | ||||
|         ) | ||||
|  | ||||
|     /// {expr} |> Async.AwaitTask | ||||
|     let awaitTask (expr : SynExpr) : SynExpr = | ||||
|         expr | ||||
|         |> pipeThroughFunction (SynExpr.CreateLongIdent (SynLongIdent.Create [ "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") | ||||
|         | _ -> callMethod "ToString" ident | ||||
|  | ||||
|     let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0) | ||||
|  | ||||
|     let synBindingTriviaZero (isMember : bool) = | ||||
|         { | ||||
|             SynBindingTrivia.EqualsRange = Some range0 | ||||
|             InlineKeyword = None | ||||
|             LeadingKeyword = | ||||
|                 if isMember then | ||||
|                     SynLeadingKeyword.Member range0 | ||||
|                 else | ||||
|                     SynLeadingKeyword.Let 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 | ||||
|         ) | ||||
|  | ||||
|     /// {ident} - {n} | ||||
|     let minusN (ident : SynLongIdent) (n : int) : SynExpr = | ||||
|         minus ident (SynExpr.CreateConst (SynConst.Int32 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 | ||||
|         ) | ||||
							
								
								
									
										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 ()) | ||||
							
								
								
									
										9
									
								
								WoofWare.Myriad.Plugins/SynExpr/PreXmlDoc.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								WoofWare.Myriad.Plugins/SynExpr/PreXmlDoc.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| 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) | ||||
							
								
								
									
										16
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynArgPats.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynArgPats.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynArgPats = | ||||
|     let create (caseNames : Ident list) : SynArgPats = | ||||
|         match caseNames.Length with | ||||
|         | 0 -> SynArgPats.Pats [] | ||||
|         | 1 -> [ SynPat.named caseNames.[0].idText ] |> SynArgPats.Pats | ||||
|         | _ -> | ||||
|             caseNames | ||||
|             |> List.map (fun i -> SynPat.named i.idText) | ||||
|             |> SynPat.tuple | ||||
|             |> List.singleton | ||||
|             |> SynArgPats.Pats | ||||
							
								
								
									
										36
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynAttribute.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynAttribute.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
| open Fantomas.FCS.Text.Range | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynAttribute = | ||||
|     let internal compilationRepresentation : SynAttribute = | ||||
|         { | ||||
|             TypeName = SynLongIdent.createS "CompilationRepresentation" | ||||
|             ArgExpr = | ||||
|                 [ "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 | ||||
|         } | ||||
|  | ||||
|     let internal autoOpen : SynAttribute = | ||||
|         { | ||||
|             TypeName = SynLongIdent.createS "AutoOpen" | ||||
|             ArgExpr = SynExpr.CreateConst () | ||||
|             Target = None | ||||
|             AppliesToGetterAndSetter = false | ||||
|             Range = range0 | ||||
|         } | ||||
							
								
								
									
										204
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynBinding.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynBinding.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
| open Fantomas.FCS.SyntaxTrivia | ||||
| open Fantomas.FCS.Xml | ||||
| open Fantomas.FCS.Text.Range | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynBinding = | ||||
|  | ||||
|     let rec private stripParen (pat : SynPat) = | ||||
|         match pat with | ||||
|         | SynPat.Paren (p, _) -> stripParen p | ||||
|         | _ -> pat | ||||
|  | ||||
|     let rec private getName (pat : SynPat) : Ident option = | ||||
|         match stripParen pat with | ||||
|         | SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name | ||||
|         | SynPat.Typed (pat, _, _) -> getName pat | ||||
|         | SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) -> | ||||
|             match longIdent with | ||||
|             | [ x ] -> Some x | ||||
|             | _ -> failwithf "got long ident %O ; can only get the name of a long ident with one component" longIdent | ||||
|         | _ -> None | ||||
|  | ||||
|     let private getArgInfo (pat : SynPat) : SynArgInfo list = | ||||
|         // TODO: this only copes with one layer of tupling | ||||
|         match stripParen pat with | ||||
|         | SynPat.Tuple (_, pats, _, _) -> pats |> List.map (fun pat -> SynArgInfo.SynArgInfo ([], false, getName pat)) | ||||
|         | pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ] | ||||
|  | ||||
|     let triviaZero (isMember : bool) = | ||||
|         { | ||||
|             SynBindingTrivia.EqualsRange = Some range0 | ||||
|             InlineKeyword = None | ||||
|             LeadingKeyword = | ||||
|                 if isMember then | ||||
|                     SynLeadingKeyword.Member range0 | ||||
|                 else | ||||
|                     SynLeadingKeyword.Let range0 | ||||
|         } | ||||
|  | ||||
|     let basic (name : LongIdent) (args : SynPat list) (body : SynExpr) : SynBinding = | ||||
|         let valInfo : SynValInfo = | ||||
|             args | ||||
|             |> List.map getArgInfo | ||||
|             |> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None)) | ||||
|  | ||||
|         SynBinding.SynBinding ( | ||||
|             None, | ||||
|             SynBindingKind.Normal, | ||||
|             false, | ||||
|             false, | ||||
|             [], | ||||
|             PreXmlDoc.Empty, | ||||
|             SynValData.SynValData (None, valInfo, None), | ||||
|             SynPat.identWithArgs name (SynArgPats.Pats args), | ||||
|             None, | ||||
|             body, | ||||
|             range0, | ||||
|             DebugPointAtBinding.Yes range0, | ||||
|             triviaZero false | ||||
|         ) | ||||
|  | ||||
|     let withAccessibility (acc : SynAccess option) (binding : SynBinding) : SynBinding = | ||||
|         match binding with | ||||
|         | SynBinding (_, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) -> | ||||
|             let headPat = | ||||
|                 match headPat with | ||||
|                 | SynPat.LongIdent (ident, extra, options, argPats, _, range) -> | ||||
|                     SynPat.LongIdent (ident, extra, options, argPats, acc, range) | ||||
|                 | _ -> failwithf "unrecognised head pattern: %O" headPat | ||||
|  | ||||
|             SynBinding (acc, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) | ||||
|  | ||||
|     let withXmlDoc (doc : PreXmlDoc) (binding : SynBinding) : SynBinding = | ||||
|         match binding with | ||||
|         | SynBinding (acc, kind, inl, mut, attrs, _, valData, headPat, returnInfo, expr, range, debugPoint, trivia) -> | ||||
|             SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, returnInfo, expr, range, debugPoint, trivia) | ||||
|  | ||||
|     let withReturnAnnotation (ty : SynType) (binding : SynBinding) : SynBinding = | ||||
|         match binding with | ||||
|         | SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, _, expr, range, debugPoint, trivia) -> | ||||
|             let retInfo = | ||||
|                 SynBindingReturnInfo.SynBindingReturnInfo ( | ||||
|                     ty, | ||||
|                     range0, | ||||
|                     [], | ||||
|                     { | ||||
|                         ColonRange = Some range0 | ||||
|                     } | ||||
|                 ) | ||||
|  | ||||
|             SynBinding ( | ||||
|                 acc, | ||||
|                 kind, | ||||
|                 inl, | ||||
|                 mut, | ||||
|                 attrs, | ||||
|                 doc, | ||||
|                 valData, | ||||
|                 headPat, | ||||
|                 Some retInfo, | ||||
|                 expr, | ||||
|                 range, | ||||
|                 debugPoint, | ||||
|                 trivia | ||||
|             ) | ||||
|  | ||||
|     let inline makeInline (binding : SynBinding) : SynBinding = | ||||
|         match binding with | ||||
|         | SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) -> | ||||
|             SynBinding ( | ||||
|                 acc, | ||||
|                 kind, | ||||
|                 true, | ||||
|                 mut, | ||||
|                 attrs, | ||||
|                 doc, | ||||
|                 valData, | ||||
|                 headPat, | ||||
|                 ret, | ||||
|                 expr, | ||||
|                 range, | ||||
|                 debugPoint, | ||||
|                 { trivia with | ||||
|                     InlineKeyword = Some range0 | ||||
|                 } | ||||
|             ) | ||||
|  | ||||
|     let inline makeNotInline (binding : SynBinding) : SynBinding = | ||||
|         match binding with | ||||
|         | SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) -> | ||||
|             SynBinding ( | ||||
|                 acc, | ||||
|                 kind, | ||||
|                 false, | ||||
|                 mut, | ||||
|                 attrs, | ||||
|                 doc, | ||||
|                 valData, | ||||
|                 headPat, | ||||
|                 ret, | ||||
|                 expr, | ||||
|                 range, | ||||
|                 debugPoint, | ||||
|                 { trivia with | ||||
|                     InlineKeyword = None | ||||
|                 } | ||||
|             ) | ||||
|  | ||||
|     let inline setInline (isInline : bool) (binding : SynBinding) : SynBinding = | ||||
|         if isInline then | ||||
|             makeInline binding | ||||
|         else | ||||
|             makeNotInline binding | ||||
|  | ||||
|     let makeStaticMember (binding : SynBinding) : SynBinding = | ||||
|         let memberFlags = | ||||
|             { | ||||
|                 SynMemberFlags.IsInstance = false | ||||
|                 SynMemberFlags.IsDispatchSlot = false | ||||
|                 SynMemberFlags.IsOverrideOrExplicitImpl = false | ||||
|                 SynMemberFlags.IsFinal = false | ||||
|                 SynMemberFlags.GetterOrSetterIsCompilerGenerated = false | ||||
|                 SynMemberFlags.MemberKind = SynMemberKind.Member | ||||
|             } | ||||
|  | ||||
|         match binding with | ||||
|         | SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) -> | ||||
|             let valData = | ||||
|                 match valData with | ||||
|                 | SynValData.SynValData (_, valInfo, _) -> SynValData.SynValData (Some memberFlags, valInfo, None) | ||||
|  | ||||
|             let trivia = | ||||
|                 { trivia with | ||||
|                     LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0) | ||||
|                 } | ||||
|  | ||||
|             SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) | ||||
|  | ||||
|     let makeInstanceMember (binding : SynBinding) : SynBinding = | ||||
|         let memberFlags = | ||||
|             { | ||||
|                 SynMemberFlags.IsInstance = true | ||||
|                 SynMemberFlags.IsDispatchSlot = false | ||||
|                 SynMemberFlags.IsOverrideOrExplicitImpl = true | ||||
|                 SynMemberFlags.IsFinal = false | ||||
|                 SynMemberFlags.GetterOrSetterIsCompilerGenerated = false | ||||
|                 SynMemberFlags.MemberKind = SynMemberKind.Member | ||||
|             } | ||||
|  | ||||
|         match binding with | ||||
|         | SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) -> | ||||
|             let valData = | ||||
|                 match valData with | ||||
|                 | SynValData.SynValData (_, valInfo, _) -> SynValData.SynValData (Some memberFlags, valInfo, None) | ||||
|  | ||||
|             let trivia = | ||||
|                 { trivia with | ||||
|                     LeadingKeyword = SynLeadingKeyword.Member range0 | ||||
|                 } | ||||
|  | ||||
|             SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) | ||||
							
								
								
									
										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) | ||||
							
								
								
									
										304
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynExpr.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynExpr.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
| open Fantomas.FCS.SyntaxTrivia | ||||
| open Myriad.Core | ||||
| open Fantomas.FCS.Text.Range | ||||
|  | ||||
| [<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 (i : int32) : SynExpr = | ||||
|             SynExpr.Const (SynConst.Int32 i, range0) | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynExpr = | ||||
|  | ||||
|     /// {f} {x} | ||||
|     let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x) | ||||
|  | ||||
|     /// {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.pipe, expr) | ||||
|         |> applyTo func | ||||
|  | ||||
|     /// if {cond} then {trueBranch} else {falseBranch} | ||||
|     /// Note that this function puts the trueBranch last, for pipelining convenience: | ||||
|     /// we assume that the `else` branch is more like an error case and is less interesting. | ||||
|     let ifThenElse (cond : SynExpr) (falseBranch : SynExpr) (trueBranch : SynExpr) : SynExpr = | ||||
|         SynExpr.IfThenElse ( | ||||
|             cond, | ||||
|             trueBranch, | ||||
|             Some falseBranch, | ||||
|             DebugPointAtBinding.Yes range0, | ||||
|             false, | ||||
|             range0, | ||||
|             { | ||||
|                 IfKeyword = range0 | ||||
|                 IsElif = false | ||||
|                 ThenKeyword = range0 | ||||
|                 ElseKeyword = Some range0 | ||||
|                 IfToThenRange = range0 | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|     /// try {body} with | {exc} as exc -> {handler} | ||||
|     let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr = | ||||
|         let clause = | ||||
|             SynMatchClause.create (SynPat.As (exc, SynPat.named "exc", range0)) handler | ||||
|  | ||||
|         SynExpr.TryWith ( | ||||
|             body, | ||||
|             [ clause ], | ||||
|             range0, | ||||
|             DebugPointAtTry.Yes range0, | ||||
|             DebugPointAtWith.Yes range0, | ||||
|             { | ||||
|                 TryKeyword = range0 | ||||
|                 TryToWithRange = range0 | ||||
|                 WithKeyword = range0 | ||||
|                 WithToEndRange = range0 | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|     /// {a} = {b} | ||||
|     let equals (a : SynExpr) (b : SynExpr) = | ||||
|         SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.eq, a) |> applyTo b | ||||
|  | ||||
|     /// {a} + {b} | ||||
|     let plus (a : SynExpr) (b : SynExpr) = | ||||
|         SynExpr.CreateAppInfix ( | ||||
|             SynExpr.CreateLongIdent ( | ||||
|                 SynLongIdent.SynLongIdent ( | ||||
|                     Ident.CreateLong "op_Addition", | ||||
|                     [], | ||||
|                     [ Some (IdentTrivia.OriginalNotation "+") ] | ||||
|                 ) | ||||
|             ), | ||||
|             a | ||||
|         ) | ||||
|         |> 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 | ||||
|  | ||||
|     let dotGet (field : string) (obj : SynExpr) : SynExpr = | ||||
|         SynExpr.DotGet ( | ||||
|             obj, | ||||
|             range0, | ||||
|             SynLongIdent.SynLongIdent (id = [ Ident.create field ], dotRanges = [], trivia = [ None ]), | ||||
|             range0 | ||||
|         ) | ||||
|  | ||||
|     /// {obj}.{meth} {arg} | ||||
|     let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr = dotGet meth obj |> applyTo arg | ||||
|  | ||||
|     /// {obj}.{meth}() | ||||
|     let callMethod (meth : string) (obj : SynExpr) : SynExpr = | ||||
|         callMethodArg meth (SynExpr.CreateConst ()) obj | ||||
|  | ||||
|     let typeApp (types : SynType list) (operand : SynExpr) = | ||||
|         SynExpr.TypeApp (operand, range0, types, List.replicate (types.Length - 1) range0, Some range0, range0, range0) | ||||
|  | ||||
|     let callGenericMethod (meth : string) (ty : LongIdent) (obj : SynExpr) : SynExpr = | ||||
|         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.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 paren (e : SynExpr) : SynExpr = | ||||
|         SynExpr.Paren (e, range0, Some range0, range0) | ||||
|  | ||||
|     /// (fun {varName} -> {body}) | ||||
|     let createLambda (varName : string) (body : SynExpr) : SynExpr = | ||||
|         let parsedDataPat = [ SynPat.named varName ] | ||||
|  | ||||
|         SynExpr.Lambda ( | ||||
|             false, | ||||
|             false, | ||||
|             SynSimplePats.Create [ SynSimplePat.CreateId (Ident.Create varName) ], | ||||
|             body, | ||||
|             Some (parsedDataPat, body), | ||||
|             range0, | ||||
|             { | ||||
|                 ArrowRange = Some range0 | ||||
|             } | ||||
|         ) | ||||
|         |> paren | ||||
|  | ||||
|     let createThunk (body : SynExpr) : SynExpr = | ||||
|         SynExpr.Lambda ( | ||||
|             false, | ||||
|             false, | ||||
|             SynSimplePats.Create [], | ||||
|             body, | ||||
|             Some ([ SynPat.unit ], body), | ||||
|             range0, | ||||
|             { | ||||
|                 ArrowRange = Some range0 | ||||
|             } | ||||
|         ) | ||||
|         |> paren | ||||
|  | ||||
|     let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0)) | ||||
|  | ||||
|     let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i | ||||
|  | ||||
|     let 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 : Ident) (body : SynExpr) = | ||||
|         let lambda = | ||||
|             [ | ||||
|                 createIdent "a" | ||||
|                 equals | ||||
|                     (SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0)) | ||||
|                     (createIdent' ct) | ||||
|             ] | ||||
|             |> tuple | ||||
|             |> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ]) | ||||
|             |> createLambda "a" | ||||
|  | ||||
|         pipeThroughFunction lambda body | ||||
|  | ||||
|     let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr = | ||||
|         SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty) | ||||
|  | ||||
|     let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr = | ||||
|         SynExpr.Match ( | ||||
|             DebugPointAtBinding.Yes range0, | ||||
|             matchOn, | ||||
|             cases, | ||||
|             range0, | ||||
|             { | ||||
|                 MatchKeyword = range0 | ||||
|                 WithKeyword = range0 | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|     let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.Typed (expr, ty, range0) | ||||
|  | ||||
|     let inline createNew (ty : SynType) (args : SynExpr) : SynExpr = | ||||
|         SynExpr.New (false, ty, paren args, range0) | ||||
|  | ||||
|     let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr = | ||||
|         SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0) | ||||
|  | ||||
|     let inline createNull () : SynExpr = SynExpr.Null range0 | ||||
|  | ||||
|     let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ()) | ||||
|  | ||||
|     let sequential (exprs : SynExpr list) : SynExpr = | ||||
|         exprs | ||||
|         |> List.reduce (fun a b -> SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, a, b, range0)) | ||||
|  | ||||
|     /// {compExpr} { {lets} ; return {ret} } | ||||
|     let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr = | ||||
|         let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0) | ||||
|  | ||||
|         let contents : SynExpr = | ||||
|             (retStatement, List.rev lets) | ||||
|             ||> List.fold (fun state binding -> | ||||
|                 match binding with | ||||
|                 | LetBang (lhs, rhs) -> | ||||
|                     SynExpr.LetOrUseBang ( | ||||
|                         DebugPointAtBinding.Yes range0, | ||||
|                         false, | ||||
|                         true, | ||||
|                         SynPat.named lhs, | ||||
|                         rhs, | ||||
|                         [], | ||||
|                         state, | ||||
|                         range0, | ||||
|                         { | ||||
|                             EqualsRange = Some range0 | ||||
|                         } | ||||
|                     ) | ||||
|                 | Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state | ||||
|                 | Use (lhs, rhs) -> | ||||
|                     SynExpr.LetOrUse ( | ||||
|                         false, | ||||
|                         true, | ||||
|                         [ SynBinding.basic [ Ident.create lhs ] [] rhs ], | ||||
|                         state, | ||||
|                         range0, | ||||
|                         { | ||||
|                             SynExprLetOrUseTrivia.InKeyword = None | ||||
|                         } | ||||
|                     ) | ||||
|                 | Do body -> sequential [ SynExpr.Do (body, range0) ; state ] | ||||
|             ) | ||||
|  | ||||
|         applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0)) | ||||
|  | ||||
|     /// {expr} |> Async.AwaitTask | ||||
|     let awaitTask (expr : SynExpr) : SynExpr = | ||||
|         expr |> pipeThroughFunction (createLongIdent [ "Async" ; "AwaitTask" ]) | ||||
|  | ||||
|     /// {ident}.ToString () | ||||
|     /// with special casing for some types like DateTime | ||||
|     let toString (ty : SynType) (ident : SynExpr) = | ||||
|         match ty with | ||||
|         | DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-dd") | ||||
|         | DateTime -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-ddTHH:mm:ss") | ||||
|         | _ -> callMethod "ToString" ident | ||||
|  | ||||
|     let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0) | ||||
|  | ||||
|     /// {ident} - {rhs} | ||||
|     let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr = | ||||
|         SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.sub, SynExpr.CreateLongIdent ident) | ||||
|         |> applyTo rhs | ||||
|  | ||||
|     /// {ident} - {n} | ||||
|     let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n) | ||||
|  | ||||
|     /// {y} > {x} | ||||
|     let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr = | ||||
|         SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.ge, y) |> applyTo x | ||||
|  | ||||
|     /// {y} >= {x} | ||||
|     let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr = | ||||
|         SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.geq, y) | ||||
|         |> applyTo x | ||||
							
								
								
									
										10
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynExprLetOrUseTrivia.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynExprLetOrUseTrivia.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.SyntaxTrivia | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynExprLetOrUseTrivia = | ||||
|     let empty : SynExprLetOrUseTrivia = | ||||
|         { | ||||
|             InKeyword = None | ||||
|         } | ||||
							
								
								
									
										69
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynField.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynField.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| 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> = | ||||
|     { | ||||
|         Attrs : SynAttribute list | ||||
|         Ident : 'Ident | ||||
|         Type : SynType | ||||
|     } | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynField = | ||||
|     /// Get the useful information out of a SynField. | ||||
|     let extract (SynField (attrs, _, id, fieldType, _, _, _, _, _)) : SynFieldData<Ident option> = | ||||
|         { | ||||
|             Attrs = attrs |> List.collect (fun l -> l.Attributes) | ||||
|             Ident = id | ||||
|             Type = fieldType | ||||
|         } | ||||
|  | ||||
|     let mapIdent<'a, 'b> (f : 'a -> 'b) (x : SynFieldData<'a>) : SynFieldData<'b> = | ||||
|         let ident = f x.Ident | ||||
|  | ||||
|         { | ||||
|             Attrs = x.Attrs | ||||
|             Ident = ident | ||||
|             Type = x.Type | ||||
|         } | ||||
|  | ||||
|     /// Throws if the field has no identifier. | ||||
|     let extractWithIdent (f : SynField) : SynFieldData<Ident> = | ||||
|         f | ||||
|         |> extract | ||||
|         |> mapIdent (fun ident -> | ||||
|             match ident with | ||||
|             | None -> failwith "expected field identifier to have a value, but it did not" | ||||
|             | Some i -> i | ||||
|         ) | ||||
|  | ||||
|     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) | ||||
							
								
								
									
										112
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynLongIdent.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynLongIdent.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| 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 ge = | ||||
|         SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ 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 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) | ||||
							
								
								
									
										28
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynModuleDecl.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynModuleDecl.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| 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 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 | ||||
|             } | ||||
|         ) | ||||
							
								
								
									
										35
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynPat.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynPat.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
| open Fantomas.FCS.Text.Range | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynPat = | ||||
|     let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0) | ||||
|  | ||||
|     let 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 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 | ||||
							
								
								
									
										274
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynType.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynType.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,274 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
| open Fantomas.FCS.Text.Range | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynType = | ||||
|     let rec stripOptionalParen (ty : SynType) : 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 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" | ||||
|  | ||||
|     /// 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) | ||||
|  | ||||
| [<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 (|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 | ||||
							
								
								
									
										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) | ||||
							
								
								
									
										41
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynUnionCase.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								WoofWare.Myriad.Plugins/SynExpr/SynUnionCase.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
|  | ||||
| type internal UnionCase<'Ident> = | ||||
|     { | ||||
|         Fields : SynFieldData<'Ident> list | ||||
|         Attrs : SynAttribute list | ||||
|         Ident : Ident | ||||
|     } | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal UnionCase = | ||||
|     let mapIdentFields<'a, 'b> (f : 'a -> 'b) (unionCase : UnionCase<'a>) : UnionCase<'b> = | ||||
|         { | ||||
|             Fields = unionCase.Fields |> List.map (SynField.mapIdent f) | ||||
|             Attrs = unionCase.Attrs | ||||
|             Ident = unionCase.Ident | ||||
|         } | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynUnionCase = | ||||
|     let extract (SynUnionCase (attrs, id, caseType, _, _, _, _)) : UnionCase<Ident option> = | ||||
|         match caseType with | ||||
|         | SynUnionCaseKind.FullType _ -> failwith "WoofWare.Myriad does not support FullType union cases." | ||||
|         | SynUnionCaseKind.Fields fields -> | ||||
|  | ||||
|         let fields = fields |> List.map SynField.extract | ||||
|  | ||||
|         let id = | ||||
|             match id with | ||||
|             | SynIdent.SynIdent (ident, _) -> ident | ||||
|  | ||||
|         // As far as I can tell, there's no way to get any attributes here? :shrug: | ||||
|         let attrs = attrs |> List.collect (fun l -> l.Attributes) | ||||
|  | ||||
|         { | ||||
|             Fields = fields | ||||
|             Attrs = attrs | ||||
|             Ident = id | ||||
|         } | ||||
| @@ -1,10 +0,0 @@ | ||||
| namespace WoofWare.Myriad.Plugins | ||||
|  | ||||
| open Fantomas.FCS.Syntax | ||||
|  | ||||
| [<RequireQualifiedAccess>] | ||||
| module internal SynType = | ||||
|     let rec stripOptionalParen (ty : SynType) : SynType = | ||||
|         match ty with | ||||
|         | SynType.Paren (ty, _) -> stripOptionalParen ty | ||||
|         | ty -> ty | ||||
| @@ -25,11 +25,29 @@ | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <Compile Include="List.fs"/> | ||||
|     <Compile Include="Ident.fs" /> | ||||
|     <Compile Include="AstHelper.fs"/> | ||||
|     <Compile Include="SynExpr.fs"/> | ||||
|     <Compile Include="SynType.fs"/> | ||||
|     <Compile Include="SynAttribute.fs"/> | ||||
|     <Compile Include="Primitives.fs" /> | ||||
|     <Compile Include="SynExpr\PreXmlDoc.fs" /> | ||||
|     <Compile Include="SynExpr\Ident.fs" /> | ||||
|     <Compile Include="SynExpr\SynLongIdent.fs" /> | ||||
|     <Compile Include="SynExpr\SynExprLetOrUseTrivia.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\SynArgPats.fs" /> | ||||
|     <Compile Include="SynExpr\SynField.fs" /> | ||||
|     <Compile Include="SynExpr\SynUnionCase.fs" /> | ||||
|     <Compile Include="SynExpr\SynTypeDefnRepr.fs" /> | ||||
|     <Compile Include="SynExpr\SynTypeDefn.fs" /> | ||||
|     <Compile Include="SynExpr\SynComponentInfo.fs" /> | ||||
|     <Compile Include="SynExpr\SynMemberDefn.fs" /> | ||||
|     <Compile Include="SynExpr\SynAttribute.fs" /> | ||||
|     <Compile Include="SynExpr\SynModuleDecl.fs" /> | ||||
|     <Compile Include="SynExpr\SynModuleOrNamespace.fs" /> | ||||
|     <Compile Include="Measure.fs" /> | ||||
|     <Compile Include="AstHelper.fs" /> | ||||
|     <Compile Include="RemoveOptionsGenerator.fs"/> | ||||
|     <Compile Include="InterfaceMockGenerator.fs"/> | ||||
|     <Compile Include="JsonSerializeGenerator.fs"/> | ||||
|   | ||||
| @@ -3,5 +3,12 @@ | ||||
|   "publicReleaseRefSpec": [ | ||||
|     "^refs/heads/main$" | ||||
|   ], | ||||
|   "pathFilters": null | ||||
|   "pathFilters": [ | ||||
|     "./", | ||||
|     ":/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.8.0]" /> | ||||
|     <PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.10.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": 1723221148, | ||||
|         "narHash": "sha256-7pjpeQlZUNQ4eeVntytU3jkw9dFK3k1Htgk2iuXjaD8=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "160b762eda6d139ac10ae081f8f78d640dd523eb", | ||||
|         "rev": "154bcb95ad51bc257c2ce4043a725de6ca700ef6", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|   | ||||
							
								
								
									
										44
									
								
								flake.nix
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								flake.nix
									
									
									
									
									
								
							| @@ -7,7 +7,6 @@ | ||||
|   }; | ||||
|  | ||||
|   outputs = { | ||||
|     self, | ||||
|     nixpkgs, | ||||
|     flake-utils, | ||||
|     ... | ||||
| @@ -18,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; | ||||
| @@ -26,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 | ||||
| @@ -44,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 | ||||
|   | ||||
							
								
								
									
										361
									
								
								nix/deps.nix
									
									
									
									
									
								
							
							
						
						
									
										361
									
								
								nix/deps.nix
									
									
									
									
									
								
							| @@ -1,484 +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.24.0"; | ||||
|     sha256 = "sha256-cNaM/yHI28sHDGamKMrU237ltOyrR+8vPNUImB5RxjU="; | ||||
|     pname = "ApiSurface"; | ||||
|     version = "4.0.43"; | ||||
|     hash = "sha256-CO5a0ZCWvD4fZXQL9l0At0y0vqmN3TT2+TuUw4ZNoC8="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "fantomas"; | ||||
|     version = "6.3.0-alpha-007"; | ||||
|     sha256 = "sha256-uZw6h6k/DS4BcYtK9cv8TLS0H8MZDO3WBaPPTdtTgu0="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "ApiSurface"; | ||||
|     version = "4.0.28"; | ||||
|     sha256 = "1gg0dqbgbb8aqn2lxi5gf2wq969kgskby5wph6m2b3hdkz7265ak"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "coverlet.collector"; | ||||
|     version = "6.0.0"; | ||||
|     sha256 = "12j34vrkmph8lspbafnqmfnj2qvysz1jcrks2khw798s6dwv0j90"; | ||||
|     version = "6.3.10"; | ||||
|     hash = "sha256-2m4YevDp9CRm/Ci2hguDXd6DUMElRg3hNAne9LHntWM="; | ||||
|   }) | ||||
|   (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.26.1"; | ||||
|     hash = "sha256-UqSK8PoXRJMZWKphMmWpl5klVn82EM1VczNZ1AOZ6Sw="; | ||||
|   }) | ||||
|   (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.301"; | ||||
|     hash = "sha256-LyP+zHxXFNksSQ/ExQ9CGkQYGvld8W6JNmxMg6lTRCs="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-1mQTxwruzhm20YdlZefrYuy7xrBs17pH4Vo0K3Tl7Fc="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-cIe0F+7rgwYSmh0VuFuQsUI9iEW5hn2KCD2H8Cs/k2g="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-TkYv7h9NBr3I+FIaXeLU4MawJtgT2RWhs35ewGRDKx8="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-RaC37ZQcJn7ykXJrtV7ibxh0GcalRyPKncxlqOLou+I="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-vh/e46xM/HbhbBvL5eP5/DCHwCP2Bg7WoMS28nBXWV0="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.CodeCoverage"; | ||||
|     version = "17.8.0"; | ||||
|     sha256 = "173wjadp3gan4x2jfjchngnc4ca4mb95h1sbb28jydfkfw0z1zvj"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.CodeCoverage"; | ||||
|     version = "17.9.0"; | ||||
|     sha256 = "1gljgi69k0fz8vy8bn6xlyxabj6q4vls2zza9wz7ng6ix3irm89r"; | ||||
|     version = "17.10.0"; | ||||
|     hash = "sha256-yQFwqVChRtIRpbtkJr92JH2i+O7xn91NGbYgnKs8G2g="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.NET.Test.Sdk"; | ||||
|     version = "17.8.0"; | ||||
|     sha256 = "1syvl3g0hbrcgfi9rq6pld8s8hqqww4dflf1lxn59ccddyyx0gmv"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.NET.Test.Sdk"; | ||||
|     version = "17.9.0"; | ||||
|     sha256 = "1lls1fly2gr1n9n1xyl9k33l2v4pwfmylyzkq8v4v5ldnwkl1zdb"; | ||||
|     version = "17.10.0"; | ||||
|     hash = "sha256-rkHIqB2mquNXF89XBTFpUL2z5msjTBsOcyjSBCh36I0="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-yDOkSHEGuGG6u+rB5u+IC3rc2tQwvbjdqmgHcl7Gkn4="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-2aDGkn0QqXXHUUSAwtQQbjKl5I6S0fcQWPciqPnOiM4="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-n6hks4j88TRelq1O6SCeUH5GmxoSm5BWXGwnpnYJibI="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-nBBq4RYAgimBYOn/bN6JTFvJFYaqYXMHae2pmCzRaS8="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-Fm3RUZNcro434rIu3c7unGviGeGBjXj2dGnr2mmrM2g="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-kdj8ia/2du2oKGg4MJdO2XytpT3gQ9UOiHVCyfiX2V8="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-/Hti30Ba12NDJQcG8pFTg6REVUDIrxZ/hRtEZNDlgxE="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-A8MFGOMXFROH1QGUE7xzq5b5EskDyIQCQt7SLfGdSbU="; | ||||
|   }) | ||||
|   (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.32"; | ||||
|     hash = "sha256-y5YB62WlMrK10bR/+nNpI8luVRlD9W9ZG3GsX7AXzUM="; | ||||
|   }) | ||||
|   (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.8.0"; | ||||
|     sha256 = "0b0i7lmkrcfvim8i3l93gwqvkhhhfzd53fqfnygdqvkg6np0cg7m"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.TestPlatform.ObjectModel"; | ||||
|     version = "17.9.0"; | ||||
|     sha256 = "1kgsl9w9fganbm9wvlkqgk0ag9hfi58z88rkfybc6kvg78bx89ca"; | ||||
|     version = "17.10.0"; | ||||
|     hash = "sha256-3YjVGK2zEObksBGYg8b/CqoJgLQ1jUv4GCWNjDhLRh4="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.TestPlatform.TestHost"; | ||||
|     version = "17.8.0"; | ||||
|     sha256 = "0f5jah93kjkvxwmhwb78lw11m9pkkq9fvf135hpymmmpxqbdh97q"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "Microsoft.TestPlatform.TestHost"; | ||||
|     version = "17.9.0"; | ||||
|     sha256 = "19ffh31a1jxzn8j69m1vnk5hyfz3dbxmflq77b8x82zybiilh5nl"; | ||||
|     version = "17.10.0"; | ||||
|     hash = "sha256-+yzP3FY6WoOosSpYnB7duZLhOPUZMQYy8zJ1d3Q4hK4="; | ||||
|   }) | ||||
|   (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"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NETStandard.Library"; | ||||
|     version = "2.0.0"; | ||||
|     sha256 = "1bc4ba8ahgk15m8k4nd7x406nhi0kwqzbgjk2dmw52ss553xz7iy"; | ||||
|     version = "3.6.141"; | ||||
|     hash = "sha256-i1pBJ12vlPmde6qSQK4PG2QLSpjaUCoY+odTi24R5XI="; | ||||
|   }) | ||||
|   (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.8.0"; | ||||
|     sha256 = "0l3ij8iwy7wj6s7f93lzi9168r4wz8zyin6a08iwgk7hvq44cia1"; | ||||
|     version = "6.10.1"; | ||||
|     hash = "sha256-2gZe1zwSaZsr0nipaMBJixLEVOvR7vp75kwecSSYyfw="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NuGet.Configuration"; | ||||
|     version = "6.8.0"; | ||||
|     sha256 = "0x03p408smkmv1gv7pmvsia4lkn0xaj4wfrkl58pjf8bbv51y0yw"; | ||||
|     version = "6.10.1"; | ||||
|     hash = "sha256-RmjvlbtJssxuWEiOcVJLtUVT0nPn7IUPb878NmJbwmM="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NuGet.Frameworks"; | ||||
|     version = "6.5.0"; | ||||
|     sha256 = "0s37d1p4md0k6d4cy6sq36f2dgkd9qfbzapxhkvi8awwh0vrynhj"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NuGet.Frameworks"; | ||||
|     version = "6.8.0"; | ||||
|     sha256 = "0i2xvhgkjkjr496i3pg8hamwv6505fia45qhn7jg5m01wb3cvsjl"; | ||||
|     version = "6.10.1"; | ||||
|     hash = "sha256-AdfpuVDDy9zYAGgcMZoTf/fkFCJJVrxRFhsv6AI4Dd0="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NuGet.Packaging"; | ||||
|     version = "6.8.0"; | ||||
|     sha256 = "031z4s905bxi94h3f0qy4j1b6jxdxgqgpkzqvvpfxch07szxcbim"; | ||||
|     version = "6.10.1"; | ||||
|     hash = "sha256-ogsVjOao+LKUOMhGir1flDuMPjOeR2OpkNGHtr/riH4="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NuGet.Protocol"; | ||||
|     version = "6.7.0"; | ||||
|     sha256 = "1v5ibnq2mp801vw68zyj169hkj3xm7h55824i33n1jxxj2vs3vbk"; | ||||
|     version = "6.10.1"; | ||||
|     hash = "sha256-UeS/10z1EqswbeB0c7QgBIVOp0VGlN5ZDQqTY2/AhX8="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NuGet.Versioning"; | ||||
|     version = "6.8.0"; | ||||
|     sha256 = "1sd25h46fd12ng780r02q4ijcx1imkb53kj1y2y7cwg5myh537ks"; | ||||
|     version = "6.10.1"; | ||||
|     hash = "sha256-jOh27AORk0TIhVePDVAgVhh6FuUo2v3oh/Xapcw7UVI="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NUnit"; | ||||
|     version = "3.13.3"; | ||||
|     sha256 = "0wdzfkygqnr73s6lpxg5b1pwaqz9f414fxpvpdmf72bvh4jaqzv6"; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "NUnit"; | ||||
|     version = "4.0.1"; | ||||
|     sha256 = "0jgiq3dbwli5r70j0bw7021d69r7bhr58s8kphlpjmf7k47l5pcd"; | ||||
|     version = "4.1.0"; | ||||
|     hash = "sha256-srzj0lf2ReKw41TnigZwf8rqKKNzGRRVrgN3hR/vRjo="; | ||||
|   }) | ||||
|   (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 = "6.0.0"; | ||||
|     sha256 = "06n9ql3fmhpjl32g3492sj181zjml5dlcc5l76xq2h38c4f87sai"; | ||||
|     version = "7.0.0"; | ||||
|     hash = "sha256-tF8qt9GZh/nPy0mEnj6nKLG4Lldpoi/D8xM5lv2CoYQ="; | ||||
|   }) | ||||
|   (fetchNuGet { | ||||
|     pname = "System.Text.Json"; | ||||
|     version = "6.0.0"; | ||||
|     sha256 = "1si2my1g0q0qv1hiqnji4xh9wd05qavxnzj9dwgs23iqvgjky0gl"; | ||||
|     version = "7.0.3"; | ||||
|     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