Initial MVP

This commit is contained in:
Smaug123
2024-10-02 23:25:20 +01:00
parent 2e6d2ded51
commit 0dad74819e
23 changed files with 1491 additions and 0 deletions

18
.config/dotnet-tools.json Normal file
View File

@@ -0,0 +1,18 @@
{
"version": 1,
"isRoot": true,
"tools": {
"fantomas": {
"version": "6.3.15",
"commands": [
"fantomas"
]
},
"fsharp-analyzers": {
"version": "0.27.0",
"commands": [
"fsharp-analyzers"
]
}
}
}

40
.editorconfig Normal file
View File

@@ -0,0 +1,40 @@
root=true
[*]
charset=utf-8
trim_trailing_whitespace=true
insert_final_newline=true
indent_style=space
indent_size=4
# ReSharper properties
resharper_xml_indent_size=2
resharper_xml_max_line_length=100
resharper_xml_tab_width=2
[*.{csproj,fsproj,sqlproj,targets,props,ts,tsx,css,json}]
indent_style=space
indent_size=2
[*.{fs,fsi}]
fsharp_bar_before_discriminated_union_declaration=true
fsharp_space_before_uppercase_invocation=true
fsharp_space_before_class_constructor=true
fsharp_space_before_member=true
fsharp_space_before_colon=true
fsharp_space_before_semicolon=true
fsharp_multiline_bracket_style=aligned
fsharp_newline_between_type_definition_and_members=true
fsharp_align_function_signature_to_indentation=true
fsharp_alternative_long_member_definitions=true
fsharp_multi_line_lambda_closing_newline=true
fsharp_experimental_keep_indent_in_branch=true
fsharp_max_value_binding_width=80
fsharp_max_record_width=0
max_line_length=120
end_of_line=lf
[*.{appxmanifest,build,dtd,nuspec,xaml,xamlx,xoml,xsd}]
indent_style=space
indent_size=2
tab_width=2

187
.github/workflows/dotnet.yaml vendored Normal file
View File

@@ -0,0 +1,187 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json
name: .NET
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
NUGET_XMLDOC_MODE: ''
DOTNET_MULTILEVEL_LOOKUP: 0
jobs:
build:
strategy:
matrix:
config:
- Release
- Debug
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Restore dependencies
run: nix develop --command dotnet restore
- name: Build
run: nix develop --command dotnet build --no-restore --configuration ${{matrix.config}}
- name: Test
run: nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}}
analyzers:
runs-on: ubuntu-latest
permissions:
security-events: write
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@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Prepare analyzers
run: nix develop --command dotnet restore analyzers/analyzers.fsproj
- name: Build project
run: nix develop --command dotnet build ./WoofWare.Whippet/WoofWare.Whippet.fsproj
- name: Run analyzers
run: nix run .#fsharp-analyzers -- --project ./WoofWare.Whippet/WoofWare.Whippet.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
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v29
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
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Run Fantomas
run: nix run .#fantomas -- --check .
check-nix-format:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Run Alejandra
run: nix develop --command alejandra --check .
linkcheck:
name: Check links
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Run link checker
run: nix develop --command markdown-link-check README.md CONTRIBUTING.md
flake-check:
name: Check flake
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Flake check
run: nix flake check
nuget-pack:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Restore dependencies
run: nix develop --command dotnet restore
- name: Build
run: nix develop --command dotnet build --no-restore --configuration Release
- name: Pack
run: nix develop --command dotnet pack --configuration Release
- name: Upload NuGet artifact (runner)
uses: actions/upload-artifact@v4
with:
name: nuget-package-runner
path: WoofWare.Whippet/bin/Release/WoofWare.Whippet.*.nupkg
- name: Upload NuGet artifact (core)
uses: actions/upload-artifact@v4
with:
name: nuget-package-core
path: WoofWare.Whippet.Core/bin/Release/WoofWare.Whippet.Core.*.nupkg
expected-pack:
needs: [nuget-pack]
runs-on: ubuntu-latest
steps:
- name: Download NuGet artifact (runner)
uses: actions/download-artifact@v4
with:
name: nuget-package-runner
path: packed-runner
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-runner -maxdepth 1 -name 'WoofWare.Whippet.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
- name: Download NuGet artifact (core)
uses: actions/download-artifact@v4
with:
name: nuget-package-core
path: packed-core
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-core -maxdepth 1 -name 'WoofWare.Whippet.Core.*.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, nuget-pack, expected-pack, analyzers]
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- uses: G-Research/common-actions/check-required-lite@2b7dc49cb14f3344fbe6019c14a31165e258c059
with:
needs-context: ${{ toJSON(needs) }}

14
.gitignore vendored Normal file
View File

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

55
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,55 @@
# Contributing
The main project fork lives [on GitHub](https://github.com/Smaug123/WoofWare.Whippet).
Contributions are welcome, but I am generally very opinionated about both style and content.
I also can't commit to looking at anything in a particularly timely manner (or at all, though I expect I will try).
In general my aesthetics lead me to accept correctness fixes much more readily than other changes.
## Issues
Please raise bug reports and feature requests as Issues on [the main GitHub project](https://github.com/Smaug123/WoofWare.Whippet/issues).
## Pull requests
Before embarking on a large change, I strongly recommend checking via a GitHub Issue first that I'm likely to accept it.
You may find that the following guidelines will help you produce a change that I accept:
* Keep your change as small and focused as is practical.
* Ensure that your change is thoroughly tested.
* Document any choices you make which are not immediately obvious.
* Explain why your change is necessary or desirable.
## On your first checkout
There are pull request checks on this repo, enforcing [Fantomas](https://github.com/fsprojects/fantomas/)-compliant formatting according to the [G-Research style guidelines](https://github.com/G-Research/fsharp-formatting-conventions/).
After checking out the repo, you may wish to add a pre-push hook to ensure locally that formatting is complete, rather than having to wait for the CI checks to tell you that you haven't formatted your code.
Consider performing the following command to set this up in the repo:
```bash
git config core.hooksPath hooks/
```
Before your first push (but only once), you will need to install the [.NET local tools](https://docs.microsoft.com/en-us/dotnet/core/tools/local-tools-how-to-use) which form part of the pre-push hook:
```bash
dotnet tool restore
```
In future, some commits (such as big-bang formatting commits) may be recorded for convenience in `.git-blame-ignore-revs`.
Consider performing the following command to have `git blame` ignore these commits, when we ever create any:
```bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
## Dependencies
I try to keep this repository's dependencies as few as possible, because (for example) any consumer of the source generator will also consume this project via the attributes.
When adding dependencies, you will need to `nix run .#fetchDeps` to obtain a new copy of [the dependency lockfile](./nix/deps.nix).
## Branch strategy
Releases are made from the `main` branch.
## License
This project is licensed with the MIT license, a copy of which you can find at the repository root.

19
Directory.Build.props Normal file
View File

@@ -0,0 +1,19 @@
<Project>
<PropertyGroup>
<DebugType Condition=" '$(DebugType)' == '' ">embedded</DebugType>
<Deterministic>true</Deterministic>
<NetCoreTargetingPackRoot>[UNDEFINED]</NetCoreTargetingPackRoot>
<DisableImplicitLibraryPacksFolder>true</DisableImplicitLibraryPacksFolder>
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DebugType>embedded</DebugType>
<WarnOn>FS3388,FS3559</WarnOn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.143" PrivateAssets="all"/>
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
</ItemGroup>
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
</Project>

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Patrick Stevens
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

13
README.md Normal file
View File

@@ -0,0 +1,13 @@
# WoofWare.Whippet
Whippet is a source generator for F#, inspired by [Myriad](https://github.com/MoiraeSoftware/myriad).
It is currently vapourware; please do not use it.
With some modest changes to [WoofWare.Myriad.Plugins](https://github.com/Smaug123/WoofWare.Myriad/) I was able to use Whippet to generate source files in that repo.
However, it currently lacks any of Myriad's ease of invocation, and indeed any of the future features intended to distinguish Whippet from Myriad.
Differentiating features:
* Whippet expands the range of information available to a source-generating plugin. Eventually we intend for it to supply type-checking information.
* Whippet will eventually support the Fantomas [Oak](https://fsprojects.github.io/fantomas/docs/end-users/GeneratingCode.html) format, rather than just a plain AST.
* Whippet is intended to be more modular, providing various different helper assemblies a plugin author can optionally use depending on what features they want.

View File

@@ -0,0 +1,28 @@
namespace WoofWare.Whippet.Core
(*
These types should take no dependencies and should only change additively; otherwise consumers will break!
*)
/// When decorating a type, indicates that the type contains Whippet generators.
///
/// If you don't want to take a dependency on WoofWare.Whippet.Core, you can define your own attribute with this name,
/// and we'll detect it happily when running the plugin.
type WhippetGeneratorAttribute () =
inherit System.Attribute ()
/// The arguments we'll give you (a plugin) when we call you to generate some code from raw file input.
type RawSourceGenerationArgs =
{
/// Full path to the file, on disk, which you're taking as input.
FilePath : string
/// Contents of the file; you might want to `System.Text.Encoding.UTF8.GetString` this.
FileContents : byte[]
}
/// We provide this interface as a helper to give you compile-time safety, but you don't have to use it.
/// At runtime, we'll find any member with the right name and signature.
/// You must use `RawSourceGenerationArgs`, though!
type IGenerateRawFromRaw =
/// Return `null` to indicate "I don't want to do any updates".
abstract member GenerateRawFromRaw : RawSourceGenerationArgs -> string

View File

@@ -0,0 +1,19 @@
# WoofWare.Whippet.Core
This library defines the types you will need to create a plugin that works with the WoofWare.Whippet source generator,
as well as some types which you may find convenient for this purpose.
To the greatest extent possible, WoofWare.Whippet is structured so that if you wish, you do not need to use this library.
However, there are some types you *must* use.
## Mandatory types
When defining any method which performs source generation, you must use the appropriate input type
(such as `RawSourceGenerationArgs`).
We try *very hard* to ensure we never break backward compatibility, so you should safely be able to use old versions of
WoofWare.Whippet.Core even with new versions of the WoofWare.Whippet generator.
## Optional types
* You must decorate your plugin types with an attribute named `[<WhippetGenerator>]`. We supply one you can use.
* We supply interfaces from which you can inherit, to ensure that you are providing members of the right type signature.

View File

@@ -0,0 +1,11 @@
WoofWare.Whippet.Core.IGenerateRawFromRaw - interface with 1 member(s)
WoofWare.Whippet.Core.IGenerateRawFromRaw.GenerateRawFromRaw [method]: WoofWare.Whippet.Core.RawSourceGenerationArgs -> string
WoofWare.Whippet.Core.RawSourceGenerationArgs inherit obj, implements WoofWare.Whippet.Core.RawSourceGenerationArgs System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.Whippet.Core.RawSourceGenerationArgs System.IComparable, System.IComparable, System.Collections.IStructuralComparable
WoofWare.Whippet.Core.RawSourceGenerationArgs..ctor [constructor]: (string, System.Byte [])
WoofWare.Whippet.Core.RawSourceGenerationArgs.Equals [method]: (WoofWare.Whippet.Core.RawSourceGenerationArgs, System.Collections.IEqualityComparer) -> bool
WoofWare.Whippet.Core.RawSourceGenerationArgs.FileContents [property]: [read-only] System.Byte []
WoofWare.Whippet.Core.RawSourceGenerationArgs.FilePath [property]: [read-only] string
WoofWare.Whippet.Core.RawSourceGenerationArgs.get_FileContents [method]: unit -> System.Byte []
WoofWare.Whippet.Core.RawSourceGenerationArgs.get_FilePath [method]: unit -> string
WoofWare.Whippet.Core.WhippetGeneratorAttribute inherit System.Attribute
WoofWare.Whippet.Core.WhippetGeneratorAttribute..ctor [constructor]: unit

View File

@@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Authors>Patrick Stevens</Authors>
<Copyright>Copyright (c) Patrick Stevens 2024</Copyright>
<Description>Core library types to allow you to use the WoofWare.Whippet source generator.</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Smaug123/WoofWare.Whippet</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>fsharp;source-generator;source-gen</PackageTags>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
<PackageId>WoofWare.Whippet.Core</PackageId>
</PropertyGroup>
<ItemGroup>
<Compile Include="Domain.fs" />
<EmbeddedResource Include="SurfaceBaseline.txt" />
<None Include="version.json" />
<None Include="README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.3.4" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,11 @@
{
"version": "0.1",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],
"pathFilters": [
"./",
":/global.json",
":/Directory.Build.props"
]
}

View File

@@ -0,0 +1,28 @@
namespace WoofWare.Whippet.Test
open NUnit.Framework
open WoofWare.Whippet.Core
open ApiSurface
[<TestFixture>]
module TestSurface =
let coreAssembly = typeof<RawSourceGenerationArgs>.Assembly
[<Test>]
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical coreAssembly
(*
[<Test>]
// https://github.com/nunit/nunit3-vs-adapter/issues/876
let CheckVersionAgainstRemote () =
MonotonicVersion.validate assembly "WoofWare.Myriad.Core"
*)
[<Test ; Explicit>]
let ``Update API surface: core`` () =
ApiSurface.writeAssemblyBaseline coreAssembly
[<Test>]
let ``Ensure public API is fully documented: core`` () =
DocCoverage.assertFullyDocumented coreAssembly

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<Compile Include="TestSurface.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ApiSurface" Version="4.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
<PackageReference Include="FsUnit" Version="6.0.1"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.Whippet.Core\WoofWare.Whippet.Core.fsproj" />
</ItemGroup>
</Project>

28
WoofWare.Whippet.sln Normal file
View File

@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet", "WoofWare.Whippet\WoofWare.Whippet.fsproj", "{85B34488-847A-4784-8001-E4D1715F5ADD}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Core", "WoofWare.Whippet.Core\WoofWare.Whippet.Core.fsproj", "{BFBE848C-E9C0-4152-B956-B8A25DFFDA9C}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Test", "WoofWare.Whippet.Test\WoofWare.Whippet.Test.fsproj", "{A2E2A639-D17D-426D-B424-0139B4DBCF8F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{85B34488-847A-4784-8001-E4D1715F5ADD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85B34488-847A-4784-8001-E4D1715F5ADD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85B34488-847A-4784-8001-E4D1715F5ADD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85B34488-847A-4784-8001-E4D1715F5ADD}.Release|Any CPU.Build.0 = Release|Any CPU
{BFBE848C-E9C0-4152-B956-B8A25DFFDA9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFBE848C-E9C0-4152-B956-B8A25DFFDA9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFBE848C-E9C0-4152-B956-B8A25DFFDA9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFBE848C-E9C0-4152-B956-B8A25DFFDA9C}.Release|Any CPU.Build.0 = Release|Any CPU
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

175
WoofWare.Whippet/Program.fs Normal file
View File

@@ -0,0 +1,175 @@
namespace WoofWare.Whippet
open System
open System.IO
open System.Reflection
open Ionide.ProjInfo
open Ionide.ProjInfo.Types
open WoofWare.Whippet.Core
type Args =
{
PluginDll : FileInfo
InputFile : FileInfo
}
type WhippetTarget =
{
InputSource : FileInfo
GeneratedDest : FileInfo
}
module Program =
let parseArgs (argv : string array) =
let inputFile = argv.[0] |> FileInfo
let pluginDll = argv.[1] |> FileInfo
{
InputFile = inputFile
PluginDll = pluginDll
}
let getGenerateRawFromRaw (host : obj) : (RawSourceGenerationArgs -> string) option =
let pluginType = host.GetType ()
let generateRawFromRaw =
match
pluginType.GetMethod (
"GenerateRawFromRaw",
BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.FlattenHierarchy
)
|> Option.ofObj
with
| None ->
pluginType.GetInterfaces ()
|> Array.tryPick (fun interf ->
interf.GetMethod (
"GenerateRawFromRaw",
BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.FlattenHierarchy
)
|> Option.ofObj
)
| Some generateRawFromRaw -> Some generateRawFromRaw
match generateRawFromRaw with
| None -> None
| Some generateRawFromRaw ->
let pars = generateRawFromRaw.GetParameters ()
if pars.Length <> 1 then
failwith
$"Expected GenerateRawFromRaw to take exactly one parameter: a RawSourceGenerationArgs. Got %i{pars.Length}"
if pars.[0].ParameterType <> typeof<RawSourceGenerationArgs> then
failwith
$"Expected GenerateRawFromRaw to take exactly one parameter: a RawSourceGenerationArgs. Got %s{pars.[0].ParameterType.FullName}"
let retType = generateRawFromRaw.ReturnType
if retType <> typeof<string> then
failwith
$"Expected GenerateRawFromRaw method to have return type `string`, but was: %s{retType.FullName}"
fun args -> generateRawFromRaw.Invoke (host, [| args |]) |> unbox<string>
|> Some
[<EntryPoint>]
let main argv =
let args = parseArgs argv
let projectDirectory = args.InputFile.Directory
let toolsPath = Init.init projectDirectory None
let defaultLoader = WorkspaceLoader.Create (toolsPath, [])
use subscription =
defaultLoader.Notifications.Subscribe (fun msg ->
match msg with
| WorkspaceProjectState.Loading projectFilePath ->
Console.Error.WriteLine $"Loading: %s{projectFilePath}"
| WorkspaceProjectState.Loaded (loadedProject, _knownProjects, fromCache) ->
let fromCache = if fromCache then " (from cache)" else ""
Console.Error.WriteLine $"Loaded %s{loadedProject.ProjectFileName}%s{fromCache}"
| WorkspaceProjectState.Failed (projectFilePath, errors) ->
let errors = errors.ToString ()
failwith $"Failed to load project %s{projectFilePath}: %s{errors}"
)
let projectOptions =
defaultLoader.LoadProjects ([ args.InputFile.FullName ]) |> Seq.toArray
let desiredProject =
projectOptions
|> Array.find (fun po -> po.ProjectFileName = args.InputFile.FullName)
let toGenerate =
desiredProject.Items
|> List.choose (fun (ProjectItem.Compile (name, fullPath, metadata)) ->
match metadata with
| None -> None
| Some metadata ->
match Map.tryFind "WhippetFile" metadata with
| None -> None
| Some myriadFile ->
{
GeneratedDest = FileInfo fullPath
InputSource =
FileInfo (Path.Combine (Path.GetDirectoryName desiredProject.ProjectFileName, myriadFile))
}
|> Some
)
Console.Error.WriteLine $"Loading plugin: %s{args.PluginDll.FullName}"
let pluginAssembly = Assembly.LoadFrom args.PluginDll.FullName
// We will look up any member called GenerateRawFromRaw and/or GenerateFromRaw.
// It's your responsibility to decide whether to do anything with this call; you return null if you don't want
// to do anything.
// Alternatively, return the text you want to output.
// We provide you with the input file contents.
// GenerateRawFromRaw should return plain text.
// GenerateFromRaw should return a Fantomas AST.
let applicablePlugins =
pluginAssembly.ExportedTypes
|> Seq.choose (fun ty ->
if
ty.CustomAttributes
|> Seq.exists (fun attr -> attr.AttributeType.Name = typeof<WhippetGeneratorAttribute>.Name)
then
Some (ty, Activator.CreateInstance ty)
else
None
)
|> Seq.toList
for item in toGenerate do
use output = item.GeneratedDest.Open (FileMode.Create, FileAccess.Write)
use outputWriter = new StreamWriter (output, leaveOpen = true)
for plugin, hostClass in applicablePlugins do
match getGenerateRawFromRaw hostClass with
| None -> ()
| Some generateRawFromRaw ->
let fileContents = File.ReadAllBytes item.InputSource.FullName
let args =
{
RawSourceGenerationArgs.FilePath = item.InputSource.FullName
FileContents = fileContents
}
let result = generateRawFromRaw args
match result with
| null -> ()
| result ->
Console.Error.WriteLine
$"Writing output for generator %s{plugin.Name} to file %s{item.GeneratedDest.FullName}"
outputWriter.Write result
outputWriter.Write "\n"
()
0

View File

@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Authors>Patrick Stevens</Authors>
<Copyright>Copyright (c) Patrick Stevens 2024</Copyright>
<Description>A source generator for F#.</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Smaug123/WoofWare.Whippet</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>fsharp;source-generator;source-gen</PackageTags>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
<PackageId>WoofWare.Whippet</PackageId>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs"/>
<None Include="../README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<!--<PackageReference Include="Fantomas.FCS" Version="6.3.15" />-->
<PackageReference Include="Ionide.ProjInfo" Version="0.67.0" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.2.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="NuGet.Frameworks" Version="6.11.1" ExcludeAssets="runtime" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.Whippet.Core\WoofWare.Whippet.Core.fsproj" />
</ItemGroup>
<ItemGroup>
<Content Include="version.json" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
{
"version": "0.1",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],
"pathFilters": [
"./",
":/WoofWare.Whippet.Core/",
":/global.json",
":/Directory.Build.props"
]
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.Build.NoTargets/1.0.80"> <!-- This is not a project we want to build. -->
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
<RestorePackagesPath>../.analyzerpackages/</RestorePackagesPath>
<TargetFramework>net6.0</TargetFramework>
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
<AutomaticallyUseReferenceAssemblyPackages>false</AutomaticallyUseReferenceAssemblyPackages> <!-- We don't want to build this project, so we do not need the reference assemblies for the framework we chose.-->
</PropertyGroup>
<ItemGroup>
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.11.0]" />
</ItemGroup>
</Project>

61
flake.lock generated Normal file
View File

@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1727811607,
"narHash": "sha256-2ByOBflaIUJKeF9q6efVcYHljZXGZ7MnCWtseRvmpm8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1839883cd0068572aed75fb9442b508bbd9ef09c",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

68
flake.nix Normal file
View File

@@ -0,0 +1,68 @@
{
description = "Source generators for F#";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs = {
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system};
pname = "WoofWare.Whippet";
dotnet-sdk = pkgs.dotnet-sdk_8;
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
version = "0.1";
dotnetTool = dllOverride: toolName: toolVersion: hash:
pkgs.stdenvNoCC.mkDerivation rec {
name = toolName;
version = toolVersion;
nativeBuildInputs = [pkgs.makeWrapper];
src = pkgs.fetchNuGet {
pname = name;
version = version;
hash = hash;
installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin'';
};
installPhase = let
dll =
if isNull dllOverride
then name
else dllOverride;
in ''
runHook preInstall
mkdir -p "$out/lib"
cp -r ./bin/* "$out/lib"
makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${dll}.dll"
runHook postInstall
'';
};
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;}))).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 {
inherit pname version dotnet-sdk dotnet-runtime;
name = "WoofWare.Whippet";
src = ./.;
projectFile = "./WoofWare.Whippet/WoofWare.Whippet.fsproj";
testProjectFile = "./WoofWare.Whippet.Test/WoofWare.Whippet.Test.fsproj";
disabledTests = ["WoofWare.Whippet.Test.TestSurface.CheckVersionAgainstRemote"];
nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result nix/deps.nix`
doCheck = true;
};
};
devShell = pkgs.mkShell {
buildInputs = [dotnet-sdk];
packages = [
pkgs.alejandra
pkgs.nodePackages.markdown-link-check
pkgs.shellcheck
];
};
});
}

569
nix/deps.nix Normal file
View File

@@ -0,0 +1,569 @@
# This file was automatically generated by passthru.fetch-deps.
# Please dont edit it manually, your changes might get overwritten!
{fetchNuGet}: [
(fetchNuGet {
pname = "ApiSurface";
version = "4.1.5";
hash = "sha256-Kbt18XLk1gvZfzGca885HaXZB119APay85KzI546PYM=";
})
(fetchNuGet {
pname = "fantomas";
version = "6.3.15";
hash = "sha256-Gjw7MxjUNckMWSfnOye4UTe5fZWnor6RHCls3PNsuG8=";
})
(fetchNuGet {
pname = "fsharp-analyzers";
version = "0.27.0";
hash = "sha256-QhLi2veTY1wZlQKJLTyVPgx/ImkaZugQNjSN5VJCNEA=";
})
(fetchNuGet {
pname = "FSharp.Core";
version = "4.3.4";
hash = "sha256-styyo+6mJy+yxE0NZG/b1hxkAjPOnJfMgd9zWzCJ5uk=";
})
(fetchNuGet {
pname = "FSharp.Core";
version = "8.0.400";
hash = "sha256-wlrcAjjvI5YtnHR7kFH8uRUA4GomJYmqr41K5LYjCGs=";
})
(fetchNuGet {
pname = "FsUnit";
version = "6.0.1";
hash = "sha256-vka/aAgWhDCl5tu+kgO7GtSaHOOvlSaWxG+tExwGXpI=";
})
(fetchNuGet {
pname = "Ionide.ProjInfo";
version = "0.67.0";
hash = "sha256-brgOnch4WuVe5TLx0RCa0wLDs3/Vu4HZP04YZyuAFYM=";
})
(fetchNuGet {
pname = "Ionide.ProjInfo.Sln";
version = "0.67.0";
hash = "sha256-PyDq0Efv/vussW2Bgy+xl05SuyELH5NcYUMfSks4bT0=";
})
(fetchNuGet {
pname = "Microsoft.Build";
version = "17.2.0";
hash = "sha256-JzPqbxFyotNhSr5tokVevdqB9+nJKx4YH2hPkC05GiY=";
})
(fetchNuGet {
pname = "Microsoft.Build.Framework";
version = "17.2.0";
hash = "sha256-jG+p2tlyX5nWT4pcmgIC4M8LNruKLSZ2+I29S/ZI/yE=";
})
(fetchNuGet {
pname = "Microsoft.CodeCoverage";
version = "17.11.1";
hash = "sha256-1dLlK3NGh88PuFYZiYpT+izA96etxhU3BSgixDgdtGA=";
})
(fetchNuGet {
pname = "Microsoft.NET.StringTools";
version = "1.0.0";
hash = "sha256-smmwm1XbKsk0SPW74rd2uDubWzfd7RhfSkPr932cyhs=";
})
(fetchNuGet {
pname = "Microsoft.NET.Test.Sdk";
version = "17.11.1";
hash = "sha256-0JUEucQ2lzaPgkrjm/NFLBTbqU1dfhvhN3Tl3moE6mI=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "1.0.1";
hash = "sha256-mZotlGZqtrqDSoBrZhsxFe6fuOv5/BIo0w2Z2x0zVAU=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "1.1.0";
hash = "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "2.0.0";
hash = "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "3.1.0";
hash = "sha256-cnygditsEaU86bnYtIthNMymAHqaT/sf9Gjykhzqgb0=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Targets";
version = "1.0.1";
hash = "sha256-lxxw/Gy32xHi0fLgFWNj4YTFBSBkjx5l6ucmbTyf7V4=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Targets";
version = "1.1.0";
hash = "sha256-0AqQ2gMS8iNlYkrD+BxtIg7cXMnr9xZHtKAuN4bjfaQ=";
})
(fetchNuGet {
pname = "Microsoft.TestPlatform.ObjectModel";
version = "17.11.1";
hash = "sha256-5vX+vCzFY3S7xfMVIv8OlMMFtdedW9UIJzc0WEc+vm4=";
})
(fetchNuGet {
pname = "Microsoft.TestPlatform.TestHost";
version = "17.11.1";
hash = "sha256-wSkY0H1fQAq0H3LcKT4u7Y5RzhAAPa6yueVN84g8HxU=";
})
(fetchNuGet {
pname = "Microsoft.Win32.Registry";
version = "4.3.0";
hash = "sha256-50XwFbyRfZkTD/bBn76WV/NIpOy/mzXD3MMEVFX/vr8=";
})
(fetchNuGet {
pname = "Microsoft.Win32.SystemEvents";
version = "4.7.0";
hash = "sha256-GHxnD1Plb32GJWVWSv0Y51Kgtlb+cdKgOYVBYZSgVF4=";
})
(fetchNuGet {
pname = "Nerdbank.GitVersioning";
version = "3.6.143";
hash = "sha256-OhOtMzP+2obDIR+npR7SsoXo0KrmcsL+VCE8Z3t5gzQ=";
})
(fetchNuGet {
pname = "NETStandard.Library";
version = "2.0.3";
hash = "sha256-Prh2RPebz/s8AzHb2sPHg3Jl8s31inv9k+Qxd293ybo=";
})
(fetchNuGet {
pname = "Newtonsoft.Json";
version = "13.0.1";
hash = "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo=";
})
(fetchNuGet {
pname = "Newtonsoft.Json";
version = "13.0.3";
hash = "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc=";
})
(fetchNuGet {
pname = "NuGet.Common";
version = "6.11.0";
hash = "sha256-eb7G07RyZv4AQT6ItRqdBuUf9e9BXcQygsy5RNEXfNE=";
})
(fetchNuGet {
pname = "NuGet.Configuration";
version = "6.11.0";
hash = "sha256-2SNZkX64SB15glzQx3k+vI7btr8Yqg4CayaaaK1B0AQ=";
})
(fetchNuGet {
pname = "NuGet.Frameworks";
version = "6.11.0";
hash = "sha256-8DC7V2IlCjiMDQ9yWbl7QQHia6OpBrbWh5rL0qa0Opw=";
})
(fetchNuGet {
pname = "NuGet.Frameworks";
version = "6.11.1";
hash = "sha256-p25Oa7wJjwF+2puIhBkZZkKSuk4jGq7xikYSCdfp9Vc=";
})
(fetchNuGet {
pname = "NuGet.Packaging";
version = "6.11.0";
hash = "sha256-LVLvxcB6SMdayxAsrc5bCuLLt25fqPr6KfYcYoWWIQk=";
})
(fetchNuGet {
pname = "NuGet.Protocol";
version = "6.11.0";
hash = "sha256-3vdB/8IiJ2LMHhFXLWOzf0H59Ow/zcoq6W4uCHbihCQ=";
})
(fetchNuGet {
pname = "NuGet.Versioning";
version = "6.11.0";
hash = "sha256-03edgWvbqUtbzpBBTIxTwsSRoj1T2muGVL+vTuIHXag=";
})
(fetchNuGet {
pname = "NUnit";
version = "4.2.2";
hash = "sha256-+0OS67ITalmG9arYCgQF/+YbmPRnB3pIIykew0kvoCc=";
})
(fetchNuGet {
pname = "NUnit3TestAdapter";
version = "4.6.0";
hash = "sha256-9Yav2fYhC4w0OgsyUwU4/5rDy4FVDTpKnWHuwl/uKJQ=";
})
(fetchNuGet {
pname = "runtime.any.System.Collections";
version = "4.3.0";
hash = "sha256-4PGZqyWhZ6/HCTF2KddDsbmTTjxs2oW79YfkberDZS8=";
})
(fetchNuGet {
pname = "runtime.any.System.Globalization";
version = "4.3.0";
hash = "sha256-PaiITTFI2FfPylTEk7DwzfKeiA/g/aooSU1pDcdwWLU=";
})
(fetchNuGet {
pname = "runtime.any.System.IO";
version = "4.3.0";
hash = "sha256-vej7ySRhyvM3pYh/ITMdC25ivSd0WLZAaIQbYj/6HVE=";
})
(fetchNuGet {
pname = "runtime.any.System.Reflection";
version = "4.3.0";
hash = "sha256-ns6f++lSA+bi1xXgmW1JkWFb2NaMD+w+YNTfMvyAiQk=";
})
(fetchNuGet {
pname = "runtime.any.System.Reflection.Primitives";
version = "4.3.0";
hash = "sha256-LkPXtiDQM3BcdYkAm5uSNOiz3uF4J45qpxn5aBiqNXQ=";
})
(fetchNuGet {
pname = "runtime.any.System.Resources.ResourceManager";
version = "4.3.0";
hash = "sha256-9EvnmZslLgLLhJ00o5MWaPuJQlbUFcUF8itGQNVkcQ4=";
})
(fetchNuGet {
pname = "runtime.any.System.Runtime";
version = "4.3.0";
hash = "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM=";
})
(fetchNuGet {
pname = "runtime.any.System.Runtime.Handles";
version = "4.3.0";
hash = "sha256-PQRACwnSUuxgVySO1840KvqCC9F8iI9iTzxNW0RcBS4=";
})
(fetchNuGet {
pname = "runtime.any.System.Runtime.InteropServices";
version = "4.3.0";
hash = "sha256-Kaw5PnLYIiqWbsoF3VKJhy7pkpoGsUwn4ZDCKscbbzA=";
})
(fetchNuGet {
pname = "runtime.any.System.Text.Encoding";
version = "4.3.0";
hash = "sha256-Q18B9q26MkWZx68exUfQT30+0PGmpFlDgaF0TnaIGCs=";
})
(fetchNuGet {
pname = "runtime.any.System.Threading.Tasks";
version = "4.3.0";
hash = "sha256-agdOM0NXupfHbKAQzQT8XgbI9B8hVEh+a/2vqeHctg4=";
})
(fetchNuGet {
pname = "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-LXUPLX3DJxsU1Pd3UwjO1PO9NM2elNEDXeu2Mu/vNps=";
})
(fetchNuGet {
pname = "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-qeSqaUI80+lqw5MK4vMpmO0CZaqrmYktwp6L+vQAb0I=";
})
(fetchNuGet {
pname = "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-SrHqT9wrCBsxILWtaJgGKd6Odmxm8/Mh7Kh0CUkZVzA=";
})
(fetchNuGet {
pname = "runtime.native.System";
version = "4.3.0";
hash = "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y=";
})
(fetchNuGet {
pname = "runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-Jy01KhtcCl2wjMpZWH+X3fhHcVn+SyllWFY8zWlz/6I=";
})
(fetchNuGet {
pname = "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-wyv00gdlqf8ckxEdV7E+Ql9hJIoPcmYEuyeWb5Oz3mM=";
})
(fetchNuGet {
pname = "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-zi+b4sCFrA9QBiSGDD7xPV27r3iHGlV99gpyVUjRmc4=";
})
(fetchNuGet {
pname = "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-gybQU6mPgaWV3rBG2dbH6tT3tBq8mgze3PROdsuWnX0=";
})
(fetchNuGet {
pname = "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-VsP72GVveWnGUvS/vjOQLv1U80H2K8nZ4fDAmI61Hm4=";
})
(fetchNuGet {
pname = "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-4yKGa/IrNCKuQ3zaDzILdNPD32bNdy6xr5gdJigyF5g=";
})
(fetchNuGet {
pname = "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-HmdJhhRsiVoOOCcUvAwdjpMRiyuSwdcgEv2j9hxi+Zc=";
})
(fetchNuGet {
pname = "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl";
version = "4.3.0";
hash = "sha256-pVFUKuPPIx0edQKjzRon3zKq8zhzHEzko/lc01V/jdw=";
})
(fetchNuGet {
pname = "runtime.unix.System.Private.Uri";
version = "4.3.0";
hash = "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs=";
})
(fetchNuGet {
pname = "runtime.unix.System.Runtime.Extensions";
version = "4.3.0";
hash = "sha256-l8S9gt6dk3qYG6HYonHtdlYtBKyPb29uQ6NDjmrt3V4=";
})
(fetchNuGet {
pname = "SemanticVersioning";
version = "2.0.2";
hash = "sha256-d5tUJshDHk/rhNqt7Rl9S/Fg526el1faeanNHKcqtAg=";
})
(fetchNuGet {
pname = "System.Collections";
version = "4.0.11";
hash = "sha256-puoFMkx4Z55C1XPxNw3np8nzNGjH+G24j43yTIsDRL0=";
})
(fetchNuGet {
pname = "System.Collections";
version = "4.3.0";
hash = "sha256-afY7VUtD6w/5mYqrce8kQrvDIfS2GXDINDh73IjxJKc=";
})
(fetchNuGet {
pname = "System.Collections.Immutable";
version = "5.0.0";
hash = "sha256-GdwSIjLMM0uVfE56VUSLVNgpW0B//oCeSFj8/hSlbM8=";
})
(fetchNuGet {
pname = "System.Configuration.ConfigurationManager";
version = "4.7.0";
hash = "sha256-rYjp/UmagI4ZULU1ocia/AiXxLNL8uhMV8LBF4QFW10=";
})
(fetchNuGet {
pname = "System.Drawing.Common";
version = "4.7.0";
hash = "sha256-D3qG+xAe78lZHvlco9gHK2TEAM370k09c6+SQi873Hk=";
})
(fetchNuGet {
pname = "System.Formats.Asn1";
version = "6.0.0";
hash = "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8=";
})
(fetchNuGet {
pname = "System.Globalization";
version = "4.0.11";
hash = "sha256-rbSgc2PIEc2c2rN6LK3qCREAX3DqA2Nq1WcLrZYsDBw=";
})
(fetchNuGet {
pname = "System.Globalization";
version = "4.3.0";
hash = "sha256-caL0pRmFSEsaoeZeWN5BTQtGrAtaQPwFi8YOZPZG5rI=";
})
(fetchNuGet {
pname = "System.IO";
version = "4.1.0";
hash = "sha256-V6oyQFwWb8NvGxAwvzWnhPxy9dKOfj/XBM3tEC5aHrw=";
})
(fetchNuGet {
pname = "System.IO";
version = "4.3.0";
hash = "sha256-ruynQHekFP5wPrDiVyhNiRIXeZ/I9NpjK5pU+HPDiRY=";
})
(fetchNuGet {
pname = "System.IO.Abstractions";
version = "4.2.13";
hash = "sha256-nkC/PiqE6+c1HJ2yTwg3x+qdBh844Z8n3ERWDW8k6Gg=";
})
(fetchNuGet {
pname = "System.IO.FileSystem.AccessControl";
version = "4.5.0";
hash = "sha256-ck44YBQ0M+2Im5dw0VjBgFD1s0XuY54cujrodjjSBL8=";
})
(fetchNuGet {
pname = "System.Memory";
version = "4.5.4";
hash = "sha256-3sCEfzO4gj5CYGctl9ZXQRRhwAraMQfse7yzKoRe65E=";
})
(fetchNuGet {
pname = "System.Private.Uri";
version = "4.3.0";
hash = "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM=";
})
(fetchNuGet {
pname = "System.Reflection";
version = "4.1.0";
hash = "sha256-idZHGH2Yl/hha1CM4VzLhsaR8Ljo/rV7TYe7mwRJSMs=";
})
(fetchNuGet {
pname = "System.Reflection";
version = "4.3.0";
hash = "sha256-NQSZRpZLvtPWDlvmMIdGxcVuyUnw92ZURo0hXsEshXY=";
})
(fetchNuGet {
pname = "System.Reflection.Metadata";
version = "1.6.0";
hash = "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E=";
})
(fetchNuGet {
pname = "System.Reflection.Primitives";
version = "4.0.1";
hash = "sha256-SFSfpWEyCBMAOerrMCOiKnpT+UAWTvRcmoRquJR6Vq0=";
})
(fetchNuGet {
pname = "System.Reflection.Primitives";
version = "4.3.0";
hash = "sha256-5ogwWB4vlQTl3jjk1xjniG2ozbFIjZTL9ug0usZQuBM=";
})
(fetchNuGet {
pname = "System.Resources.ResourceManager";
version = "4.0.1";
hash = "sha256-cZ2/3/fczLjEpn6j3xkgQV9ouOVjy4Kisgw5xWw9kSw=";
})
(fetchNuGet {
pname = "System.Resources.ResourceManager";
version = "4.3.0";
hash = "sha256-idiOD93xbbrbwwSnD4mORA9RYi/D/U48eRUsn/WnWGo=";
})
(fetchNuGet {
pname = "System.Runtime";
version = "4.1.0";
hash = "sha256-FViNGM/4oWtlP6w0JC0vJU+k9efLKZ+yaXrnEeabDQo=";
})
(fetchNuGet {
pname = "System.Runtime";
version = "4.3.0";
hash = "sha256-51813WXpBIsuA6fUtE5XaRQjcWdQ2/lmEokJt97u0Rg=";
})
(fetchNuGet {
pname = "System.Runtime.CompilerServices.Unsafe";
version = "5.0.0";
hash = "sha256-neARSpLPUzPxEKhJRwoBzhPxK+cKIitLx7WBYncsYgo=";
})
(fetchNuGet {
pname = "System.Runtime.CompilerServices.Unsafe";
version = "6.0.0";
hash = "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I=";
})
(fetchNuGet {
pname = "System.Runtime.Extensions";
version = "4.1.0";
hash = "sha256-X7DZ5CbPY7jHs20YZ7bmcXs9B5Mxptu/HnBUvUnNhGc=";
})
(fetchNuGet {
pname = "System.Runtime.Extensions";
version = "4.3.0";
hash = "sha256-wLDHmozr84v1W2zYCWYxxj0FR0JDYHSVRaRuDm0bd/o=";
})
(fetchNuGet {
pname = "System.Runtime.Handles";
version = "4.0.1";
hash = "sha256-j2QgVO9ZOjv7D1het98CoFpjoYgxjupuIhuBUmLLH7w=";
})
(fetchNuGet {
pname = "System.Runtime.Handles";
version = "4.3.0";
hash = "sha256-KJ5aXoGpB56Y6+iepBkdpx/AfaJDAitx4vrkLqR7gms=";
})
(fetchNuGet {
pname = "System.Runtime.InteropServices";
version = "4.1.0";
hash = "sha256-QceAYlJvkPRJc/+5jR+wQpNNI3aqGySWWSO30e/FfQY=";
})
(fetchNuGet {
pname = "System.Runtime.InteropServices";
version = "4.3.0";
hash = "sha256-8sDH+WUJfCR+7e4nfpftj/+lstEiZixWUBueR2zmHgI=";
})
(fetchNuGet {
pname = "System.Security.AccessControl";
version = "4.5.0";
hash = "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM=";
})
(fetchNuGet {
pname = "System.Security.AccessControl";
version = "4.7.0";
hash = "sha256-/9ZCPIHLdhzq7OW4UKqTsR0O93jjHd6BRG1SRwgHE1g=";
})
(fetchNuGet {
pname = "System.Security.Cryptography.Pkcs";
version = "6.0.4";
hash = "sha256-2e0aRybote+OR66bHaNiYpF//4fCiaO3zbR2e9GABUI=";
})
(fetchNuGet {
pname = "System.Security.Cryptography.ProtectedData";
version = "4.4.0";
hash = "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE=";
})
(fetchNuGet {
pname = "System.Security.Cryptography.ProtectedData";
version = "4.7.0";
hash = "sha256-dZfs5q3Ij1W1eJCfYjxI2o+41aSiFpaAugpoECaCOug=";
})
(fetchNuGet {
pname = "System.Security.Permissions";
version = "4.7.0";
hash = "sha256-BGgXMLUi5rxVmmChjIhcXUxisJjvlNToXlyaIbUxw40=";
})
(fetchNuGet {
pname = "System.Security.Principal.Windows";
version = "4.5.0";
hash = "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY=";
})
(fetchNuGet {
pname = "System.Security.Principal.Windows";
version = "4.7.0";
hash = "sha256-rWBM2U8Kq3rEdaa1MPZSYOOkbtMGgWyB8iPrpIqmpqg=";
})
(fetchNuGet {
pname = "System.Text.Encoding";
version = "4.0.11";
hash = "sha256-PEailOvG05CVgPTyKLtpAgRydlSHmtd5K0Y8GSHY2Lc=";
})
(fetchNuGet {
pname = "System.Text.Encoding";
version = "4.3.0";
hash = "sha256-GctHVGLZAa/rqkBNhsBGnsiWdKyv6VDubYpGkuOkBLg=";
})
(fetchNuGet {
pname = "System.Text.Encoding.CodePages";
version = "4.0.1";
hash = "sha256-wxtwWQSTv5tuFP79KhUAhaL6bL4d8lSzSWkCn9aolwM=";
})
(fetchNuGet {
pname = "System.Text.Encodings.Web";
version = "6.0.0";
hash = "sha256-UemDHGFoQIG7ObQwRluhVf6AgtQikfHEoPLC6gbFyRo=";
})
(fetchNuGet {
pname = "System.Text.Encodings.Web";
version = "7.0.0";
hash = "sha256-tF8qt9GZh/nPy0mEnj6nKLG4Lldpoi/D8xM5lv2CoYQ=";
})
(fetchNuGet {
pname = "System.Text.Json";
version = "6.0.0";
hash = "sha256-9AE/5ds4DqEfb0l+27fCBTSeYCdRWhxh2Bhg8IKvIuo=";
})
(fetchNuGet {
pname = "System.Text.Json";
version = "7.0.3";
hash = "sha256-aSJZ17MjqaZNQkprfxm/09LaCoFtpdWmqU9BTROzWX4=";
})
(fetchNuGet {
pname = "System.Threading";
version = "4.0.11";
hash = "sha256-mob1Zv3qLQhQ1/xOLXZmYqpniNUMCfn02n8ZkaAhqac=";
})
(fetchNuGet {
pname = "System.Threading.Tasks";
version = "4.0.11";
hash = "sha256-5SLxzFg1df6bTm2t09xeI01wa5qQglqUwwJNlQPJIVs=";
})
(fetchNuGet {
pname = "System.Threading.Tasks";
version = "4.3.0";
hash = "sha256-Z5rXfJ1EXp3G32IKZGiZ6koMjRu0n8C1NGrwpdIen4w=";
})
(fetchNuGet {
pname = "System.Threading.Tasks.Dataflow";
version = "6.0.0";
hash = "sha256-bEx7t8jvo7HEkqexhyYyrgFojiMVYyd2nG2mHJv0m6w=";
})
(fetchNuGet {
pname = "System.Windows.Extensions";
version = "4.7.0";
hash = "sha256-yW+GvQranReaqPw5ZFv+mSjByQ5y1pRLl05JIEf3tYU=";
})
]