Compare commits

..

81 Commits

Author SHA1 Message Date
Smaug123
f686109331 More 2025-04-18 15:08:20 +01:00
Smaug123
7b2c3d2168 Start on the union generator 2025-04-17 21:56:25 +01:00
Smaug123
3ed8d4db00 Add help text placeholder 2025-04-17 21:38:44 +01:00
Smaug123
75ce8c1f64 Fix test 2025-04-17 18:45:57 +01:00
Smaug123
01714aeba0 Fix all but the help text 2025-04-17 18:31:25 +01:00
Smaug123
2f266b052d Fix another test 2025-04-17 16:02:20 +01:00
Smaug123
d3d50cae7c Fix another test 2025-04-17 15:49:12 +01:00
Smaug123
573d410416 Fix another test 2025-04-17 12:47:48 +01:00
Smaug123
a82ece0f6c Plumb through indices 2025-04-17 12:41:55 +01:00
Smaug123
51991cab74 Fix another test 2025-04-17 11:45:34 +01:00
Smaug123
55a3876610 More 2025-04-17 11:13:37 +01:00
Smaug123
c14f89f807 Fix another test 2025-04-17 11:05:08 +01:00
Smaug123
54e3f17d9c It's sort of working 2025-04-17 00:18:53 +01:00
Smaug123
4013271254 More 2025-04-16 23:04:23 +01:00
Smaug123
aa2ef830c3 Add flags 2025-04-16 21:26:30 +01:00
Smaug123
4e62a154c0 Undo accidental revert 2025-04-15 22:51:43 +01:00
Smaug123
751e43eec4 More 2025-04-15 22:50:14 +01:00
Smaug123
fccc981045 WIP 2025-04-15 09:23:24 +01:00
Smaug123
f8a1505b99 Undo build-offline mode 2025-04-14 23:08:40 +01:00
Smaug123
eb25b9ccb8 Merge branch 'main' into du-parser 2025-04-14 23:07:34 +01:00
dependabot[bot]
325f8634a4 Bump FSharp.Core and WoofWare.Whippet.Fantomas (#361)
* Bump FsCheck and FSharp.Core

Bumps [FsCheck](https://github.com/Fscheck/fscheck) and [FSharp.Core](https://github.com/dotnet/fsharp). These dependencies needed to be updated together.

Updates `FsCheck` from 3.1.0 to 3.2.0
- [Release notes](https://github.com/Fscheck/fscheck/releases)
- [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md)
- [Commits](https://github.com/Fscheck/fscheck/compare/3.1.0...3.2.0)

Updates `FSharp.Core` from 4.3.4 to 5.0.2
- [Release notes](https://github.com/dotnet/fsharp/releases)
- [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md)
- [Commits](https://github.com/dotnet/fsharp/commits)

---
updated-dependencies:
- dependency-name: FsCheck
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: FSharp.Core
  dependency-version: 5.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump FSharp.Core and WoofWare.Whippet.Fantomas

Bumps [FSharp.Core](https://github.com/dotnet/fsharp) and [WoofWare.Whippet.Fantomas](https://github.com/Smaug123/WoofWare.Whippet). These dependencies needed to be updated together.

Updates `FSharp.Core` from 4.3.4 to 6.0.1
- [Release notes](https://github.com/dotnet/fsharp/releases)
- [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md)
- [Commits](https://github.com/dotnet/fsharp/commits)

Updates `WoofWare.Whippet.Fantomas` from 0.3.2 to 0.5.1
- [Commits](https://github.com/Smaug123/WoofWare.Whippet/commits)

---
updated-dependencies:
- dependency-name: FSharp.Core
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: WoofWare.Whippet.Fantomas
  dependency-version: 0.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-04-14 22:05:23 +00:00
Smaug123
34587b8dea Merge branch 'main' into du-parser 2025-04-14 23:02:19 +01:00
Patrick Stevens
3e5d663544 Better docs on PositionalArgsAttribute (#362) 2025-04-14 23:01:26 +01:00
Smaug123
963a097360 First line of implementation 2025-04-14 22:52:18 +01:00
Smaug123
67eb89cfc0 Getting there 2025-04-14 22:27:57 +01:00
Smaug123
0c5ddf9df7 WIP 2025-04-14 00:01:55 +01:00
Smaug123
8535481e0d Bump Whippet 2025-04-13 21:09:12 +01:00
Smaug123
df6079e763 WIP 2025-04-13 20:34:52 +01:00
Smaug123
4befdb93e5 WIP: define the helper types 2025-04-13 18:43:23 +01:00
Smaug123
17da7317e8 Merge branch 'main' into du-parser 2025-04-13 16:07:59 +01:00
Smaug123
fa022b75ea WIP: complete arg parser 2025-04-13 11:52:17 +01:00
patrick-conscriptus[bot]
bb88f80c85 Automated commit (#358)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-04-13 02:53:09 +00:00
dependabot[bot]
71f26930c6 Bump actions/create-github-app-token from 1 to 2 (#357) 2025-04-07 17:19:12 +01:00
patrick-conscriptus[bot]
680728a06e Automated commit (#356)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-04-06 01:29:18 +00:00
dependabot[bot]
cdc6f2d511 Bump fsharp-analyzers from 0.29.1 to 0.30.0 (#355)
* Bump fsharp-analyzers from 0.29.1 to 0.30.0

Bumps [fsharp-analyzers](https://github.com/ionide/FSharp.Analyzers.SDK) from 0.29.1 to 0.30.0.
- [Release notes](https://github.com/ionide/FSharp.Analyzers.SDK/releases)
- [Changelog](https://github.com/ionide/FSharp.Analyzers.SDK/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ionide/FSharp.Analyzers.SDK/compare/v0.29.1...v0.30.0)

---
updated-dependencies:
- dependency-name: fsharp-analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-04-01 08:23:43 +00:00
patrick-conscriptus[bot]
3be487c328 Automated commit (#354)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-03-30 01:30:44 +00:00
dependabot[bot]
a5f4d169ca Bump FSharp.Core and WoofWare.Whippet.Fantomas (#352)
* Bump FSharp.Core and WoofWare.Whippet.Fantomas

Bumps [FSharp.Core](https://github.com/dotnet/fsharp) and [WoofWare.Whippet.Fantomas](https://github.com/Smaug123/WoofWare.Whippet). These dependencies needed to be updated together.

Updates `FSharp.Core` from 4.3.4 to 6.0.1
- [Release notes](https://github.com/dotnet/fsharp/releases)
- [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md)
- [Commits](https://github.com/dotnet/fsharp/commits)

Updates `WoofWare.Whippet.Fantomas` from 0.3.1 to 0.3.2
- [Commits](https://github.com/Smaug123/WoofWare.Whippet/commits)

---
updated-dependencies:
- dependency-name: FSharp.Core
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: WoofWare.Whippet.Fantomas
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ApiSurface and FSharp.Core

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) and [FSharp.Core](https://github.com/Microsoft/visualfsharp). These dependencies needed to be updated together.

Updates `ApiSurface` from 4.1.17 to 4.1.20
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.17...ApiSurface.4.1.20)

Updates `FSharp.Core` from 4.3.4 to 4.3.4
- [Release notes](https://github.com/Microsoft/visualfsharp/releases)
- [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md)
- [Commits](https://github.com/Microsoft/visualfsharp/commits)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: FSharp.Core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-03-24 19:38:01 +00:00
patrick-conscriptus[bot]
ce634efff2 Automated commit (#351)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-03-23 01:28:44 +00:00
Patrick Stevens
1529dd1fb2 Bump NBGV (#350) 2025-03-21 14:33:32 +00:00
dependabot[bot]
59558b0766 Bump cachix/install-nix-action from 30 to 31 (#349)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 30 to 31.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v30...v31)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 19:56:20 +00:00
dependabot[bot]
8602894efc Bump fsharp-analyzers from 0.29.0 to 0.29.1 (#348)
* Bump fsharp-analyzers from 0.29.0 to 0.29.1

Bumps [fsharp-analyzers](https://github.com/ionide/FSharp.Analyzers.SDK) from 0.29.0 to 0.29.1.
- [Release notes](https://github.com/ionide/FSharp.Analyzers.SDK/releases)
- [Changelog](https://github.com/ionide/FSharp.Analyzers.SDK/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ionide/FSharp.Analyzers.SDK/compare/v0.29.0...v0.29.1)

---
updated-dependencies:
- dependency-name: fsharp-analyzers
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-03-10 18:41:51 +00:00
dependabot[bot]
51d349b365 Bump actions/attest-build-provenance from 2.2.2 to 2.2.3 (#347) 2025-03-10 12:13:39 +00:00
dependabot[bot]
120df84bbf Bump actions/attest-build-provenance from 2.2.0 to 2.2.2 (#345) 2025-03-03 11:24:42 +00:00
dependabot[bot]
603f875a12 Bump ApiSurface and FSharp.Core (#341)
* Automated commit

* Bump Microsoft.NET.Test.Sdk from 17.12.0 to 17.13.0

Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.12.0 to 17.13.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.12.0...v17.13.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ApiSurface and FSharp.Core

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) and [FSharp.Core](https://github.com/Microsoft/visualfsharp). These dependencies needed to be updated together.

Updates `ApiSurface` from 4.1.16 to 4.1.17
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.16...ApiSurface.4.1.17)

Updates `FSharp.Core` from 4.3.4 to 4.3.4
- [Release notes](https://github.com/Microsoft/visualfsharp/releases)
- [Changelog](https://github.com/dotnet/fsharp/blob/main/release-notes.md)
- [Commits](https://github.com/Microsoft/visualfsharp/commits)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: FSharp.Core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump fantomas from 7.0.0 to 7.0.1

Bumps [fantomas](https://github.com/fsprojects/fantomas) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/fsprojects/fantomas/releases)
- [Changelog](https://github.com/fsprojects/fantomas/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fsprojects/fantomas/compare/v7.0.0...v7.0.1)

---
updated-dependencies:
- dependency-name: fantomas
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump NUnit3TestAdapter from 4.6.0 to 5.0.0

Bumps [NUnit3TestAdapter](https://github.com/nunit/nunit3-vs-adapter) from 4.6.0 to 5.0.0.
- [Release notes](https://github.com/nunit/nunit3-vs-adapter/releases)
- [Commits](https://github.com/nunit/nunit3-vs-adapter/compare/V4.6.0...V5.0.0)

---
updated-dependencies:
- dependency-name: NUnit3TestAdapter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

* Suppress build warning

* Revert "Merge remote-tracking branch 'origin/auto_pr2025_02_23-01_20_56_533960' into dependabot/nuget/multi-be38daf731"

This reverts commit d2bb029b2b, reversing
changes made to 7a2fe4a014.

* Deps

* Revert

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-02-25 00:28:26 +00:00
dependabot[bot]
2df41555de Bump fsharp-analyzers from 0.28.0 to 0.29.0, and FsUnit (#338)
* Bump fsharp-analyzers from 0.28.0 to 0.29.0

Bumps [fsharp-analyzers](https://github.com/ionide/FSharp.Analyzers.SDK) from 0.28.0 to 0.29.0.
- [Release notes](https://github.com/ionide/FSharp.Analyzers.SDK/releases)
- [Changelog](https://github.com/ionide/FSharp.Analyzers.SDK/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ionide/FSharp.Analyzers.SDK/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: fsharp-analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump analysers

* Deps

* Upgrade

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-02-20 10:44:45 +00:00
patrick-conscriptus[bot]
49e31e52b5 Automated commit (#337)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-02-16 01:25:03 +00:00
Patrick Stevens
277a186fda Allow properties in mocked interfaces (#336) 2025-02-12 23:53:15 +00:00
patrick-conscriptus[bot]
129687ec1c Automated commit (#334)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-02-09 01:22:26 +00:00
dependabot[bot]
c7fea55e28 Bump FsCheck from 3.0.1 to 3.1.0 (#333)
* Bump FsCheck from 3.0.1 to 3.1.0

Bumps [FsCheck](https://github.com/Fscheck/fscheck) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/Fscheck/fscheck/releases)
- [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md)
- [Commits](https://github.com/Fscheck/fscheck/compare/3.0.1...3.1.0)

---
updated-dependencies:
- dependency-name: FsCheck
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-02-03 17:28:07 +00:00
patrick-conscriptus[bot]
ded7b32771 Automated commit (#332)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-02-02 01:21:17 +00:00
dependabot[bot]
b272f8b645 Bump FsCheck from 3.0.0 to 3.0.1 (#330)
* Bump FsCheck from 3.0.0 to 3.0.1

Bumps [FsCheck](https://github.com/Fscheck/fscheck) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/Fscheck/fscheck/releases)
- [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md)
- [Commits](https://github.com/Fscheck/fscheck/compare/3.0.0...3.0.1)

---
updated-dependencies:
- dependency-name: FsCheck
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-01-29 00:49:28 +00:00
dependabot[bot]
b8d60aec90 Bump actions/attest-build-provenance from 2.1.0 to 2.2.0 (#331) 2025-01-27 11:36:25 +00:00
patrick-conscriptus[bot]
0e3510e1e5 Automated commit (#329)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-01-26 01:19:46 +00:00
patrick-conscriptus[bot]
8a1edd90d5 Automated commit (#328)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-01-19 01:22:30 +00:00
dependabot[bot]
74fdd7c0a9 Bump fantomas from 6.3.16 to 7.0.0 (#326)
* Bump fantomas from 6.3.16 to 7.0.0

Bumps [fantomas](https://github.com/fsprojects/fantomas) from 6.3.16 to 7.0.0.
- [Release notes](https://github.com/fsprojects/fantomas/releases)
- [Changelog](https://github.com/fsprojects/fantomas/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fsprojects/fantomas/compare/v6.3.16...v7.0.0)

---
updated-dependencies:
- dependency-name: fantomas
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

* Format

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-01-14 10:35:58 +00:00
dependabot[bot]
23f55814f9 Bump ApiSurface from 4.1.15 to 4.1.16 (#325)
* Bump FsCheck from 2.16.6 to 3.0.0

Bumps [FsCheck](https://github.com/Fscheck/fscheck) from 2.16.6 to 3.0.0.
- [Release notes](https://github.com/Fscheck/fscheck/releases)
- [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md)
- [Commits](https://github.com/Fscheck/fscheck/compare/2.16.6...3.0.0)

---
updated-dependencies:
- dependency-name: FsCheck
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ApiSurface from 4.1.15 to 4.1.16

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) from 4.1.15 to 4.1.16.
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.15...ApiSurface.4.1.16)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump Nerdbank.GitVersioning from 3.7.112 to 3.7.115

Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.7.112 to 3.7.115.
- [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases)
- [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/commits)

---
updated-dependencies:
- dependency-name: Nerdbank.GitVersioning
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Lockfile

* Fix tests

* Fix

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-01-14 01:16:20 +00:00
Patrick Stevens
15c04bb373 Use GR's GitHub release action (#323) 2025-01-13 09:34:27 +00:00
patrick-conscriptus[bot]
a860a93f9c Automated commit (#322)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-01-12 01:25:56 +00:00
patrick-conscriptus[bot]
b056af348e Automated commit (#321)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-01-05 01:24:38 +00:00
dependabot[bot]
b44c8db6e9 Bump NUnit from 4.3.1 to 4.3.2 (#320)
* Bump NUnit from 4.3.1 to 4.3.2

Bumps [NUnit](https://github.com/nunit/nunit) from 4.3.1 to 4.3.2.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.3.1...4.3.2)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-12-30 22:43:17 +00:00
patrick-conscriptus[bot]
7d6a2cea01 Automated commit (#319)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-12-29 01:25:23 +00:00
Patrick Stevens
d779a602f4 Fix flake update after recent nixpkgs bump (#318) 2024-12-24 19:49:30 +00:00
Patrick Stevens
23cd5272fb Use non-deprecated nixpkgs methods (#317) 2024-12-24 19:32:39 +00:00
dependabot[bot]
93538ee6b4 Bump NUnit from 4.3.0 to 4.3.1 (#315)
* Bump NUnit from 4.3.0 to 4.3.1

Bumps [NUnit](https://github.com/nunit/nunit) from 4.3.0 to 4.3.1.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.3.0...4.3.1)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ApiSurface from 4.1.14 to 4.1.15

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) from 4.1.14 to 4.1.15.
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.14...ApiSurface.4.1.15)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-12-23 11:45:33 +00:00
patrick-conscriptus[bot]
8a29c2f444 Automated commit (#314)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-12-22 01:24:49 +00:00
dependabot[bot]
1367e00f34 Bump Nerdbank.GitVersioning from 3.6.146 to 3.7.112 (#311)
* Bump NUnit from 4.2.2 to 4.3.0

Bumps [NUnit](https://github.com/nunit/nunit) from 4.2.2 to 4.3.0.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/main/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/4.2.2...4.3.0)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump Nerdbank.GitVersioning from 3.6.146 to 3.7.112

Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.6.146 to 3.7.112.
- [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases)
- [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.6.146...v3.7.112)

---
updated-dependencies:
- dependency-name: Nerdbank.GitVersioning
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump ApiSurface from 4.1.12 to 4.1.14

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) from 4.1.12 to 4.1.14.
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.12...ApiSurface.4.1.14)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-12-16 11:21:31 +00:00
dependabot[bot]
bff08c90cd Bump actions/attest-build-provenance from 2.0.1 to 2.1.0 (#313)
Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 2.0.1 to 2.1.0.
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](c4fbc64884...7668571508)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 10:55:25 +00:00
Patrick Stevens
4136f7fe94 Update to net9 SDK (#302) 2024-12-15 22:13:30 +00:00
patrick-conscriptus[bot]
9fe2e3b1fa Automated commit (#309)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-12-15 01:31:17 +00:00
dependabot[bot]
13a597a365 Bump actions/attest-build-provenance from 1.4.4 to 2.0.1 (#308) 2024-12-09 13:45:39 +00:00
patrick-conscriptus[bot]
3acc492f22 Automated commit (#307)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-12-08 01:32:11 +00:00
patrick-conscriptus[bot]
eefe64f5a4 Automated commit (#306)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-12-01 01:44:12 +00:00
dependabot[bot]
93a2d92299 Bump fsharp-analyzers from 0.27.0 to 0.28.0 (#305)
* Bump ApiSurface from 4.1.11 to 4.1.12

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) from 4.1.11 to 4.1.12.
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.11...ApiSurface.4.1.12)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump Microsoft.NET.Test.Sdk from 17.11.1 to 17.12.0

Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.11.1 to 17.12.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.11.1...v17.12.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump fsharp-analyzers from 0.27.0 to 0.28.0

Bumps [fsharp-analyzers](https://github.com/ionide/FSharp.Analyzers.SDK) from 0.27.0 to 0.28.0.
- [Release notes](https://github.com/ionide/FSharp.Analyzers.SDK/releases)
- [Changelog](https://github.com/ionide/FSharp.Analyzers.SDK/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ionide/FSharp.Analyzers.SDK/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: fsharp-analyzers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

* Fix flake

* Fix analysers

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-11-25 16:38:14 +00:00
patrick-conscriptus[bot]
33793e8cbe Automated commit (#301)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-11-24 01:28:15 +00:00
dependabot[bot]
fa7ef1ffba Bump ApiSurface from 4.1.8 to 4.1.11 (#300)
* Bump ApiSurface from 4.1.8 to 4.1.11

Bumps [ApiSurface](https://github.com/G-Research/ApiSurface) from 4.1.8 to 4.1.11.
- [Release notes](https://github.com/G-Research/ApiSurface/releases)
- [Commits](https://github.com/G-Research/ApiSurface/compare/ApiSurface.4.1.8...ApiSurface.4.1.11)

---
updated-dependencies:
- dependency-name: ApiSurface
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-11-18 20:07:55 +00:00
patrick-conscriptus[bot]
a25c45dc3a Automated commit (#299)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-11-17 01:26:53 +00:00
dependabot[bot]
af5f2abdf8 Bump actions/attest-build-provenance from 1.4.3 to 1.4.4 (#298)
Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](1c608d11d6...ef244123eb)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 11:07:51 +00:00
patrick-conscriptus[bot]
0f89816432 Automated commit (#297)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-11-10 01:22:22 +00:00
dependabot[bot]
d571da6a22 Bump fantomas from 6.3.15 to 6.3.16 (#296)
* Bump fantomas from 6.3.15 to 6.3.16

Bumps [fantomas](https://github.com/fsprojects/fantomas) from 6.3.15 to 6.3.16.
- [Release notes](https://github.com/fsprojects/fantomas/releases)
- [Changelog](https://github.com/fsprojects/fantomas/blob/main/CHANGELOG.md)
- [Commits](https://github.com/fsprojects/fantomas/compare/v6.3.15...v6.3.16)

---
updated-dependencies:
- dependency-name: fantomas
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2024-11-04 17:42:25 +00:00
patrick-conscriptus[bot]
39a9e94ca5 Automated commit (#295)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-11-03 01:24:04 +00:00
patrick-conscriptus[bot]
487f73312a Automated commit (#294)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2024-10-27 01:24:19 +00:00
41 changed files with 9898 additions and 3978 deletions

View File

@@ -3,13 +3,13 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"fantomas": { "fantomas": {
"version": "6.3.15", "version": "7.0.1",
"commands": [ "commands": [
"fantomas" "fantomas"
] ]
}, },
"fsharp-analyzers": { "fsharp-analyzers": {
"version": "0.27.0", "version": "0.30.0",
"commands": [ "commands": [
"fsharp-analyzers" "fsharp-analyzers"
] ]

View File

@@ -29,7 +29,7 @@ jobs:
with: with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -50,7 +50,7 @@ jobs:
with: with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -67,7 +67,7 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -82,7 +82,7 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -97,7 +97,7 @@ jobs:
with: with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -116,7 +116,7 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -129,7 +129,7 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -142,7 +142,7 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -156,7 +156,7 @@ jobs:
with: with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -198,27 +198,40 @@ jobs:
# Verify that there is exactly one nupkg in the artifact that would be NuGet published # Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-attribute -maxdepth 1 -name 'WoofWare.Myriad.Plugins.Attributes.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi run: if [[ $(find packed-attribute -maxdepth 1 -name 'WoofWare.Myriad.Plugins.Attributes.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
github-release-plugin-dry-run: github-release-dry-run:
needs: [nuget-pack] strategy:
matrix:
artifact:
- nuget-package-plugin
- nuget-package-attribute
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [nuget-pack]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download NuGet artifact (plugin) - name: Download NuGet artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: nuget-package-plugin name: ${{ matrix.artifact }}
- name: Download NuGet artifact (attribute) - name: Compute package path
uses: actions/download-artifact@v4 id: compute-path
with: run: |
name: nuget-package-attribute find . -maxdepth 1 -type f -name 'WoofWare.Myriad.*.nupkg' -exec sh -c 'echo "output=$(basename "$1")" >> $GITHUB_OUTPUT' shell {} \;
- name: Tag and release plugin - name: Compute tag name
id: compute-tag
env: env:
DRY_RUN: 1 NUPKG_PATH: ${{ steps.compute-path.outputs.output }}
GITHUB_TOKEN: mock-token run: echo "output=$(basename "$NUPKG_PATH" .nupkg)" >> $GITHUB_OUTPUT
run: sh .github/workflows/tag.sh - name: Tag and release
uses: G-Research/common-actions/github-release@19d7281a0f9f83e13c78f99a610dbc80fc59ba3b
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
target-commitish: ${{ github.sha }}
tag: ${{ steps.compute-tag.outputs.output }}
binary-contents: ${{ steps.compute-path.outputs.output }}
dry-run: true
all-required-checks-complete: 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] needs: [check-dotnet-format, check-nix-format, check-accurate-generations, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack, github-release-dry-run]
if: ${{ always() }} if: ${{ always() }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -241,7 +254,7 @@ jobs:
name: nuget-package-attribute name: nuget-package-attribute
path: packed path: packed
- name: Attest Build Provenance - name: Attest Build Provenance
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
with: with:
subject-path: "packed/*.nupkg" subject-path: "packed/*.nupkg"
@@ -260,7 +273,7 @@ jobs:
name: nuget-package-plugin name: nuget-package-plugin
path: packed path: packed
- name: Attest Build Provenance - name: Attest Build Provenance
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
with: with:
subject-path: "packed/*.nupkg" subject-path: "packed/*.nupkg"
@@ -276,7 +289,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -309,7 +322,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v30 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@@ -330,7 +343,12 @@ jobs:
nupkg-dir: packed/ nupkg-dir: packed/
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }} dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
github-release-plugin: github-release:
strategy:
matrix:
artifact:
- nuget-package-attribute
- nuget-package-plugin
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }} if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
needs: [all-required-checks-complete] needs: [all-required-checks-complete]
@@ -339,15 +357,23 @@ jobs:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download NuGet artifact (plugin) - name: Download NuGet artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: nuget-package-plugin name: ${{ matrix.artifact }}
- name: Download NuGet artifact (attribute) - name: Compute package path
uses: actions/download-artifact@v4 id: compute-path
with: run: |
name: nuget-package-attribute find . -maxdepth 1 -type f -name 'WoofWare.Myriad.*.nupkg' -exec sh -c 'echo "output=$(basename "$1")" >> $GITHUB_OUTPUT' shell {} \;
- name: Tag and release plugin - name: Compute tag name
id: compute-tag
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NUPKG_PATH: ${{ steps.compute-path.outputs.output }}
run: sh .github/workflows/tag.sh run: echo "output=$(basename "$NUPKG_PATH" .nupkg)" >> $GITHUB_OUTPUT
- name: Tag and release
uses: G-Research/common-actions/github-release@19d7281a0f9f83e13c78f99a610dbc80fc59ba3b
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
target-commitish: ${{ github.sha }}
tag: ${{ steps.compute-tag.outputs.output }}
binary-contents: ${{ steps.compute-path.outputs.output }}

View File

@@ -21,20 +21,20 @@ jobs:
- name: Update Nix flake - name: Update Nix flake
run: 'nix flake update' run: 'nix flake update'
- name: Build passthru - name: Build fetch-deps
run: 'nix build ".#default.passthru.fetch-deps"' run: 'nix build ".#default.fetch-deps"'
- name: Run passthru - name: Run fetch-deps
run: | run: |
set -o pipefail set -o pipefail
./result nix/deps.nix ./result nix/deps.json
- name: Format - name: Format
run: 'nix develop --command alejandra .' run: 'nix develop --command alejandra .'
- name: Create token - name: Create token
id: generate-token id: generate-token
uses: actions/create-github-app-token@v1 uses: actions/create-github-app-token@v2
with: with:
# https://github.com/actions/create-github-app-token/issues/136 # https://github.com/actions/create-github-app-token/issues/136
app-id: ${{ secrets.APP_ID }} app-id: ${{ secrets.APP_ID }}

View File

@@ -1,120 +0,0 @@
#!/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

View File

@@ -235,3 +235,9 @@ type FlagsIntoPositionalArgs' =
[<PositionalArgs false>] [<PositionalArgs false>]
DontGrabEverything : string list DontGrabEverything : string list
} }
[<ArgParser true>]
type PassThru =
{
A : ParentRecordChildPos
}

View File

@@ -0,0 +1,35 @@
namespace ConsumePlugin.ArgsWithUnions
open System
open System.IO
open WoofWare.Myriad.Plugins
type BasicNoPositionals =
{
Foo : int
Bar : string
Baz : bool
Rest : int list
}
type UsernamePasswordAuth =
{
Username : string
Password : string
}
type TokenAuth =
{
Token : string
}
type AuthOptions =
| UsernamePassword of UsernamePasswordAuth
| Token of TokenAuth
[<ArgParser>]
type DoTheThing =
{
Basics : BasicNoPositionals
Auth : AuthOptions
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags> <OtherFlags>--reflectionfree $(OtherFlags)</OtherFlags>
</PropertyGroup> </PropertyGroup>
@@ -12,6 +12,7 @@
<ItemGroup> <ItemGroup>
<None Include="myriad.toml"/> <None Include="myriad.toml"/>
<Compile Include="AssemblyInfo.fs" /> <Compile Include="AssemblyInfo.fs" />
<!--
<Compile Include="RecordFile.fs"/> <Compile Include="RecordFile.fs"/>
<Compile Include="GeneratedRecord.fs"> <Compile Include="GeneratedRecord.fs">
<MyriadFile>RecordFile.fs</MyriadFile> <MyriadFile>RecordFile.fs</MyriadFile>
@@ -66,10 +67,16 @@
<Compile Include="ListCata.fs"> <Compile Include="ListCata.fs">
<MyriadFile>List.fs</MyriadFile> <MyriadFile>List.fs</MyriadFile>
</Compile> </Compile>
-->
<Compile Include="Args.fs" /> <Compile Include="Args.fs" />
<Compile Include="GeneratedArgs.fs"> <Compile Include="GeneratedArgs.fs">
<MyriadFile>Args.fs</MyriadFile> <MyriadFile>Args.fs</MyriadFile>
</Compile> </Compile>
<Compile Include="ArgsWithUnions.fs" />
<Compile Include="GeneratedArgsWithUnions.fs">
<MyriadFile>ArgsWithUnions.fs</MyriadFile>
</Compile>
<!--
<None Include="swagger-gitea.json" /> <None Include="swagger-gitea.json" />
<Compile Include="GeneratedSwaggerGitea.fs"> <Compile Include="GeneratedSwaggerGitea.fs">
<MyriadFile>swagger-gitea.json</MyriadFile> <MyriadFile>swagger-gitea.json</MyriadFile>
@@ -81,6 +88,7 @@
<Compile Include="Generated2SwaggerGitea.fs"> <Compile Include="Generated2SwaggerGitea.fs">
<MyriadFile>GeneratedSwaggerGitea.fs</MyriadFile> <MyriadFile>GeneratedSwaggerGitea.fs</MyriadFile>
</Compile> </Compile>
-->
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -26769,8 +26769,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"admin/cron/{task}" "admin/cron/{task}".Replace ("{task}", task.ToString () |> System.Uri.EscapeDataString),
.Replace ("{task}", task.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -26902,8 +26901,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"admin/hooks/{id}" "admin/hooks/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -26945,8 +26943,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"admin/hooks/{id}" "admin/hooks/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -27584,8 +27581,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"amdin/hooks/{id}" "amdin/hooks/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -28008,8 +28004,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"org/{org}/repos" "org/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -28292,8 +28287,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("orgs/{org}/hooks" ("orgs/{org}/hooks".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
+ (if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then + (if "orgs/{org}/hooks".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -28345,8 +28339,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"orgs/{org}/hooks" "orgs/{org}/hooks".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -28538,8 +28531,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("orgs/{org}/labels" ("orgs/{org}/labels".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
+ (if "orgs/{org}/labels".IndexOf (char 63) >= 0 then + (if "orgs/{org}/labels".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -28591,8 +28583,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"orgs/{org}/labels" "orgs/{org}/labels".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -28784,8 +28775,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("orgs/{org}/members" ("orgs/{org}/members".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
+ (if "orgs/{org}/members".IndexOf (char 63) >= 0 then + (if "orgs/{org}/members".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -29086,8 +29076,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("orgs/{org}/repos" ("orgs/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
+ (if "orgs/{org}/repos".IndexOf (char 63) >= 0 then + (if "orgs/{org}/repos".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -29142,8 +29131,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"orgs/{org}/repos" "orgs/{org}/repos".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -29197,8 +29185,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("orgs/{org}/teams" ("orgs/{org}/teams".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString)
+ (if "orgs/{org}/teams".IndexOf (char 63) >= 0 then + (if "orgs/{org}/teams".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -29250,8 +29237,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"orgs/{org}/teams" "orgs/{org}/teams".Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
.Replace ("{org}", org.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -39381,8 +39367,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"repositories/{id}" "repositories/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )
@@ -39745,8 +39730,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("teams/{id}/members" ("teams/{id}/members".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
+ (if "teams/{id}/members".IndexOf (char 63) >= 0 then + (if "teams/{id}/members".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -39918,8 +39902,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
("teams/{id}/repos" ("teams/{id}/repos".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString)
+ (if "teams/{id}/repos".IndexOf (char 63) >= 0 then + (if "teams/{id}/repos".IndexOf (char 63) >= 0 then
"&" "&"
else else
@@ -40807,8 +40790,7 @@ module Gitea =
System.Uri ("/api/v1/", System.UriKind.Relative) System.Uri ("/api/v1/", System.UriKind.Relative)
), ),
System.Uri ( System.Uri (
"user/gpg_keys/{id}" "user/gpg_keys/{id}".Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
.Replace ("{id}", id.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,686 @@
//------------------------------------------------------------------------------
// This code was generated by myriad.
// Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace ArgParserHelpers
/// Helper types for arg parsing
module internal ArgParseHelpers_ConsumePlugin_ArgsWithUnions =
open System
open System.IO
open WoofWare.Myriad.Plugins
open ConsumePlugin.ArgsWithUnions
/// A partially-parsed BasicNoPositionals.
type internal BasicNoPositionals_InProgress =
{
mutable Bar : string option
mutable Baz : bool option
mutable Foo : int option
mutable Rest : ResizeArray<int>
}
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
member this.Assemble_
(getEnvironmentVariable : string -> string)
(positionals : Choice<string * int, string * int> list)
: Result<BasicNoPositionals * string option, string list>
=
let errors = ResizeArray<string> ()
let positionalConsumers = ResizeArray<string> ()
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
let arg0 : int =
match this.Foo with
| Some result -> result
| None ->
errors.Add (sprintf "Required argument '--%s' received no value" "foo")
Unchecked.defaultof<_>
let arg1 : string =
match this.Bar with
| Some result -> result
| None ->
errors.Add (sprintf "Required argument '--%s' received no value" "bar")
Unchecked.defaultof<_>
let arg2 : bool =
match this.Baz with
| Some result -> result
| None ->
errors.Add (sprintf "Required argument '--%s' received no value" "baz")
Unchecked.defaultof<_>
let arg3 : int list = this.Rest |> Seq.toList
if positionalConsumers.Count <= 1 then
if outOfPlacePositionals.Count > 0 then
outOfPlacePositionals
|> String.concat " "
|> (fun x ->
if 0 = outOfPlacePositionals.Count then
"Unmatched args which look like they are meant to be flags. " + x
else
sprintf
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
positionalConsumers.[0]
x
)
|> errors.Add
else
()
if errors.Count = 0 then
Ok (
{
Foo = arg0
Bar = arg1
Baz = arg2
Rest = arg3
},
Seq.tryExactlyOne positionalConsumers
)
else
errors |> Seq.toList |> Error
else
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
+ String.concat ", " positionalConsumers)
|> List.singleton
|> Error
static member _Empty () : BasicNoPositionals_InProgress =
{
Bar = None
Baz = None
Foo = None
Rest = ResizeArray ()
}
/// Processes the key-value pair, returning Error if no key was matched.
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
member this.ProcessKeyValueSelf_
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
if System.String.Equals (key, sprintf "--%s" "rest", System.StringComparison.OrdinalIgnoreCase) then
value |> (fun x -> System.Int32.Parse x) |> (fun x -> x) |> this.Rest.Add
() |> Ok
else if System.String.Equals (key, sprintf "--%s" "foo", System.StringComparison.OrdinalIgnoreCase) then
match this.Foo with
| Some x ->
sprintf
"Argument '%s' was supplied multiple times: %s and %s"
(sprintf "--%s" "foo")
(x.ToString ())
(value.ToString ())
|> errors_.Add
Ok ()
| None ->
try
this.Foo <- value |> (fun x -> System.Int32.Parse x) |> Some
Ok ()
with _ as exc ->
exc.Message |> Some |> Error
else if System.String.Equals (key, sprintf "--%s" "baz", System.StringComparison.OrdinalIgnoreCase) then
match this.Baz with
| Some x ->
sprintf
"Argument '%s' was supplied multiple times: %s and %s"
(sprintf "--%s" "baz")
(x.ToString ())
(value.ToString ())
|> errors_.Add
Ok ()
| None ->
try
this.Baz <- value |> (fun x -> System.Boolean.Parse x) |> Some
Ok ()
with _ as exc ->
exc.Message |> Some |> Error
else if System.String.Equals (key, sprintf "--%s" "bar", System.StringComparison.OrdinalIgnoreCase) then
match this.Bar with
| Some x ->
sprintf
"Argument '%s' was supplied multiple times: %s and %s"
(sprintf "--%s" "bar")
(x.ToString ())
(value.ToString ())
|> errors_.Add
Ok ()
| None ->
try
this.Bar <- value |> (fun x -> x) |> Some
Ok ()
with _ as exc ->
exc.Message |> Some |> Error
else
Error None
member this.ProcessKeyValue
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
match this.ProcessKeyValueSelf_ argNum_ errors_ key value with
| Ok () -> Ok ()
| Error None -> Error None
| Error (Some errorFromLeaf) -> Error (Some errorFromLeaf)
/// Returns false if we didn't set a value.
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool =
if System.String.Equals (key, sprintf "--%s" "baz", System.StringComparison.OrdinalIgnoreCase) then
match this.Baz with
| Some _ ->
sprintf "Flag '%s' was supplied multiple times" (sprintf "--%s" "baz")
|> errors_.Add
true
| None ->
this.Baz <- true |> Some
true
else
false
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
/// A partially-parsed UsernamePasswordAuth.
type internal UsernamePasswordAuth_InProgress =
{
mutable Password : string option
mutable Username : string option
}
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
member this.Assemble_
(getEnvironmentVariable : string -> string)
(positionals : Choice<string * int, string * int> list)
: Result<UsernamePasswordAuth * string option, string list>
=
let errors = ResizeArray<string> ()
let positionalConsumers = ResizeArray<string> ()
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
let arg0 : string =
match this.Username with
| Some result -> result
| None ->
errors.Add (sprintf "Required argument '--%s' received no value" "username")
Unchecked.defaultof<_>
let arg1 : string =
match this.Password with
| Some result -> result
| None ->
errors.Add (sprintf "Required argument '--%s' received no value" "password")
Unchecked.defaultof<_>
if positionalConsumers.Count <= 1 then
if outOfPlacePositionals.Count > 0 then
outOfPlacePositionals
|> String.concat " "
|> (fun x ->
if 0 = outOfPlacePositionals.Count then
"Unmatched args which look like they are meant to be flags. " + x
else
sprintf
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
positionalConsumers.[0]
x
)
|> errors.Add
else
()
if errors.Count = 0 then
Ok (
{
Username = arg0
Password = arg1
},
Seq.tryExactlyOne positionalConsumers
)
else
errors |> Seq.toList |> Error
else
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
+ String.concat ", " positionalConsumers)
|> List.singleton
|> Error
static member _Empty () : UsernamePasswordAuth_InProgress =
{
Password = None
Username = None
}
/// Processes the key-value pair, returning Error if no key was matched.
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
member this.ProcessKeyValueSelf_
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
if System.String.Equals (key, sprintf "--%s" "username", System.StringComparison.OrdinalIgnoreCase) then
match this.Username with
| Some x ->
sprintf
"Argument '%s' was supplied multiple times: %s and %s"
(sprintf "--%s" "username")
(x.ToString ())
(value.ToString ())
|> errors_.Add
Ok ()
| None ->
try
this.Username <- value |> (fun x -> x) |> Some
Ok ()
with _ as exc ->
exc.Message |> Some |> Error
else if
System.String.Equals (key, sprintf "--%s" "password", System.StringComparison.OrdinalIgnoreCase)
then
match this.Password with
| Some x ->
sprintf
"Argument '%s' was supplied multiple times: %s and %s"
(sprintf "--%s" "password")
(x.ToString ())
(value.ToString ())
|> errors_.Add
Ok ()
| None ->
try
this.Password <- value |> (fun x -> x) |> Some
Ok ()
with _ as exc ->
exc.Message |> Some |> Error
else
Error None
member this.ProcessKeyValue
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
match this.ProcessKeyValueSelf_ argNum_ errors_ key value with
| Ok () -> Ok ()
| Error None -> Error None
| Error (Some errorFromLeaf) -> Error (Some errorFromLeaf)
/// Returns false if we didn't set a value.
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool = false
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
/// A partially-parsed TokenAuth.
type internal TokenAuth_InProgress =
{
mutable Token : string option
}
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
member this.Assemble_
(getEnvironmentVariable : string -> string)
(positionals : Choice<string * int, string * int> list)
: Result<TokenAuth * string option, string list>
=
let errors = ResizeArray<string> ()
let positionalConsumers = ResizeArray<string> ()
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
let arg0 : string =
match this.Token with
| Some result -> result
| None ->
errors.Add (sprintf "Required argument '--%s' received no value" "token")
Unchecked.defaultof<_>
if positionalConsumers.Count <= 1 then
if outOfPlacePositionals.Count > 0 then
outOfPlacePositionals
|> String.concat " "
|> (fun x ->
if 0 = outOfPlacePositionals.Count then
"Unmatched args which look like they are meant to be flags. " + x
else
sprintf
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
positionalConsumers.[0]
x
)
|> errors.Add
else
()
if errors.Count = 0 then
Ok (
{
Token = arg0
},
Seq.tryExactlyOne positionalConsumers
)
else
errors |> Seq.toList |> Error
else
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
+ String.concat ", " positionalConsumers)
|> List.singleton
|> Error
static member _Empty () : TokenAuth_InProgress =
{
Token = None
}
/// Processes the key-value pair, returning Error if no key was matched.
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
member this.ProcessKeyValueSelf_
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
if System.String.Equals (key, sprintf "--%s" "token", System.StringComparison.OrdinalIgnoreCase) then
match this.Token with
| Some x ->
sprintf
"Argument '%s' was supplied multiple times: %s and %s"
(sprintf "--%s" "token")
(x.ToString ())
(value.ToString ())
|> errors_.Add
Ok ()
| None ->
try
this.Token <- value |> (fun x -> x) |> Some
Ok ()
with _ as exc ->
exc.Message |> Some |> Error
else
Error None
member this.ProcessKeyValue
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
match this.ProcessKeyValueSelf_ argNum_ errors_ key value with
| Ok () -> Ok ()
| Error None -> Error None
| Error (Some errorFromLeaf) -> Error (Some errorFromLeaf)
/// Returns false if we didn't set a value.
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool = false
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
/// A partially-parsed AuthOptions.
type internal AuthOptions_InProgress =
{
Token : TokenAuth_InProgress
UsernamePassword : UsernamePasswordAuth_InProgress
}
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
member this.Assemble_
(getEnvironmentVariable : string -> string)
(positionals : Choice<string * int, string * int> list)
: Result<AuthOptions * string option, string list>
=
failwith "TODO"
static member _Empty () : AuthOptions_InProgress =
{
Token = TokenAuth_InProgress._Empty ()
UsernamePassword = UsernamePasswordAuth_InProgress._Empty ()
}
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
/// A partially-parsed DoTheThing.
type internal DoTheThing_InProgress =
{
mutable Auth : AuthOptions_InProgress
mutable Basics : BasicNoPositionals_InProgress
}
/// Freeze this in-progress type. On success, returns the frozen type and the arg (if any) which consumed the input positional args.
member this.Assemble_
(getEnvironmentVariable : string -> string)
(positionals : Choice<string * int, string * int> list)
: Result<DoTheThing * string option, string list>
=
let errors = ResizeArray<string> ()
let positionalConsumers = ResizeArray<string> ()
let outOfPlacePositionals : ResizeArray<string> = ResizeArray ()
let arg0 : BasicNoPositionals =
match this.Basics.Assemble_ getEnvironmentVariable positionals with
| Ok (result, consumedPositional) ->
match consumedPositional with
| None -> ()
| Some positionalConsumer -> positionalConsumers.Add positionalConsumer
result
| Error err ->
errors.AddRange err
Unchecked.defaultof<_>
let arg1 : AuthOptions =
match this.Auth.Assemble_ getEnvironmentVariable positionals with
| Ok (result, consumedPositional) ->
match consumedPositional with
| None -> ()
| Some positionalConsumer -> positionalConsumers.Add positionalConsumer
result
| Error err ->
errors.AddRange err
Unchecked.defaultof<_>
if positionalConsumers.Count <= 1 then
if outOfPlacePositionals.Count > 0 then
outOfPlacePositionals
|> String.concat " "
|> (fun x ->
if 0 = outOfPlacePositionals.Count then
"Unmatched args which look like they are meant to be flags. " + x
else
sprintf
"Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `%s=` syntax, or place them after a trailing `--`. %s"
positionalConsumers.[0]
x
)
|> errors.Add
else
()
if errors.Count = 0 then
Ok (
{
Basics = arg0
Auth = arg1
},
Seq.tryExactlyOne positionalConsumers
)
else
errors |> Seq.toList |> Error
else
("Multiple parsers consumed positional args; this is an error in the application, not an error by the user: "
+ String.concat ", " positionalConsumers)
|> List.singleton
|> Error
static member _Empty () : DoTheThing_InProgress =
{
Basics = BasicNoPositionals_InProgress._Empty ()
Auth = AuthOptions_InProgress._Empty ()
}
/// Passes the key-value pair to any child records, returning Error if no key was matched.
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
member this.ProcessKeyValueRecord_
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
let errors : ResizeArray<string> = ResizeArray ()
match this.Basics.ProcessKeyValue argNum_ errors_ key value with
| Ok () -> Ok ()
| Error e -> Error None
member this.ProcessKeyValue
(argNum_ : int)
(errors_ : ResizeArray<string>)
(key : string)
(value : string)
: Result<unit, string option>
=
match this.ProcessKeyValueRecord_ argNum_ errors_ key value with
| Ok () -> Ok ()
| Error errorFromRecord -> Error errorFromRecord
/// Returns false if we didn't set a value.
member this.SetFlagValue_ (errors_ : ResizeArray<string>) (key : string) : bool = false
/// Compute help text for this parser, optionally noting the given prefix on each argument and indenting each line by this many spaces.
static member HelpText_ (prefix : string option) (indent : int) : string = failwith "TODO"
namespace ConsumePlugin.ArgsWithUnions
open ArgParserHelpers
open System
open System.IO
open WoofWare.Myriad.Plugins
/// Methods to parse arguments for the type DoTheThing
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module DoTheThing =
type internal ParseState_DoTheThing =
/// Ready to consume a key or positional arg
| AwaitingKey
/// Waiting to receive a value for the key we've already consumed
| AwaitingValue of key : string
let parse' (getEnvironmentVariable : string -> string) (args : string list) : DoTheThing =
let inProgress =
ArgParseHelpers_ConsumePlugin_ArgsWithUnions.DoTheThing_InProgress._Empty ()
let positionals : ResizeArray<Choice<string * int, string * int>> = ResizeArray ()
let errors_ = ResizeArray ()
let rec go (argNum_ : int) (state : ParseState_DoTheThing) (args : string list) =
match args with
| [] ->
match state with
| ParseState_DoTheThing.AwaitingKey -> ()
| ParseState_DoTheThing.AwaitingValue key ->
if inProgress.SetFlagValue_ errors_ key then
()
else
sprintf
"Trailing argument %s had no value. Use a double-dash to separate positional args from key-value args."
key
|> errors_.Add
| "--" :: rest -> positionals.AddRange (rest |> Seq.map (fun x -> (x, argNum_ + 1)) |> Seq.map Choice2Of2)
| arg :: args ->
match state with
| ParseState_DoTheThing.AwaitingKey ->
if arg.StartsWith ("--", System.StringComparison.Ordinal) then
if arg = "--help" then
"TODO" |> failwithf "Help text requested.\n%s"
else
let equals = arg.IndexOf (char 61)
if equals < 0 then
go (argNum_ + 1) (ParseState_DoTheThing.AwaitingValue arg) args
else
let key = arg.[0 .. equals - 1]
let value = arg.[equals + 1 ..]
match inProgress.ProcessKeyValue argNum_ errors_ key value with
| Ok () -> go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
| Error x ->
match x with
| None ->
positionals.Add (Choice1Of2 (arg, argNum_))
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
| Some msg ->
sprintf "%s (at arg %s)" msg arg |> errors_.Add
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
else
(arg, argNum_) |> Choice1Of2 |> positionals.Add
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey args
| ParseState_DoTheThing.AwaitingValue key ->
match inProgress.ProcessKeyValue argNum_ errors_ key arg with
| Ok () -> go argNum_ ParseState_DoTheThing.AwaitingKey args
| Error exc ->
if inProgress.SetFlagValue_ errors_ key then
go argNum_ ParseState_DoTheThing.AwaitingKey (arg :: args)
else
(key, argNum_) |> Choice1Of2 |> positionals.Add
go (argNum_ + 1) ParseState_DoTheThing.AwaitingKey (arg :: args)
go 0 ParseState_DoTheThing.AwaitingKey args
if 0 = errors_.Count then
()
else
errors_
|> String.concat System.Environment.NewLine
|> (fun x -> "Errors during parse!\n" + x)
|> failwith
match inProgress.Assemble_ getEnvironmentVariable (positionals |> Seq.toList) with
| Ok (result, posConsumer) ->
if positionals.Count > 0 && posConsumer.IsNone then
positionals
|> Seq.map (fun choiceValue ->
match choiceValue with
| Choice1Of2 (arg, _) -> arg
| Choice2Of2 (arg, _) -> arg
)
|> String.concat " "
|> sprintf "Parse error: The following arguments were not consumed: %s"
|> failwith
else
result
| Error e ->
e
|> String.concat System.Environment.NewLine
|> (fun x -> "Errors during parse!\n" + x)
|> failwith
let parse (args : string list) : DoTheThing =
parse' System.Environment.GetEnvironmentVariable args

View File

@@ -206,3 +206,34 @@ type internal TypeWithInterfaceMock =
interface System.IDisposable with interface System.IDisposable with
member this.Dispose () : unit = this.Dispose () member this.Dispose () : unit = this.Dispose ()
namespace SomeNamespace
open System
open WoofWare.Myriad.Plugins
/// Mock record type for an interface
type internal TypeWithPropertiesMock =
{
/// Implementation of IDisposable.Dispose
Dispose : unit -> unit
Prop1 : unit -> int
Prop2 : unit -> unit Async
Mem1 : string option -> string[] Async
}
/// An implementation where every method throws.
static member Empty : TypeWithPropertiesMock =
{
Dispose = (fun () -> ())
Prop1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop1"))
Prop2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop2"))
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
}
interface TypeWithProperties with
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
member this.Prop1 = this.Prop1 ()
member this.Prop2 = this.Prop2 ()
interface System.IDisposable with
member this.Dispose () : unit = this.Dispose ()

View File

@@ -160,8 +160,7 @@ module PureGymApi =
| null -> System.Uri "https://whatnot.com/" | null -> System.Uri "https://whatnot.com/"
| v -> v), | v -> v),
System.Uri ( System.Uri (
"v1/gyms/{gym}" "v1/gyms/{gym}".Replace ("{gym}", gym.ToString () |> System.Uri.EscapeDataString),
.Replace ("{gym}", gym.ToString () |> System.Uri.EscapeDataString),
System.UriKind.Relative System.UriKind.Relative
) )
) )

View File

@@ -48,3 +48,10 @@ type TypeWithInterface =
inherit IDisposable inherit IDisposable
abstract Mem1 : string option -> string[] Async abstract Mem1 : string option -> string[] Async
abstract Mem2 : unit -> string[] Async abstract Mem2 : unit -> string[] Async
[<GenerateMock>]
type TypeWithProperties =
inherit IDisposable
abstract Mem1 : string option -> string[] Async
abstract Prop1 : int
abstract Prop2 : unit Async

View File

@@ -10,7 +10,7 @@
<WarnOn>FS3388,FS3559</WarnOn> <WarnOn>FS3388,FS3559</WarnOn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.146" PrivateAssets="all"/> <PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all"/>
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/> <SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''"> <PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">

47
Playground/Domain.fs Normal file
View File

@@ -0,0 +1,47 @@
namespace Playground
open System
open WoofWare.Myriad.Plugins
[<ArgParser>]
type SubMode1 =
{
Info1 : int
Info2 : string
Rest : string list
}
[<ArgParser>]
type SubMode2 =
{
Info1 : int
Info2 : string
Rest : int list
}
[<ArgParser>]
type Mode1 =
{
Things : SubMode1
Whatnot : int
}
[<ArgParser>]
type Mode2 =
{
Things : SubMode2
Whatnot : DateTime
}
[<ArgParser>]
type Modes =
| Mode1 of Mode1
| Mode2 of Mode2
[<ArgParser>]
type Args =
{
WhatToDo : Modes
[<PositionalArgs>]
OtherArgs : string list
}

563
Playground/Library.fs Normal file
View File

@@ -0,0 +1,563 @@
//------------------------------------------------------------------------------
// This code was generated by myriad.
// Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace Playground // Assuming a namespace
open System
open System.IO
open WoofWare.Myriad.Plugins // Assuming attributes are here
// Assume original type definitions are accessible here
// [<ArgParser>] type SubMode1 = { Info1 : int; Info2 : string; Rest : string list }
// [<ArgParser>] type SubMode2 = { Info1 : int; Info2 : string; Rest : int list }
// [<ArgParser>] type Mode1 = { Things : SubMode1; Whatnot : int }
// [<ArgParser>] type Mode2 = { Things : SubMode2; Whatnot : DateTime }
// [<ArgParser>] type Modes = | Mode1 of Mode1 | Mode2 of Mode2
// [<ArgParser>] type Args = { WhatToDo : Modes; [<PositionalArgs>] OtherArgs : string list }
/// Methods to parse arguments for the type Args
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Args =
//--------------------------------------------------------------------------
// Internal state definitions (Non-Flattened with combined Assemble/Validate)
//--------------------------------------------------------------------------
/// State representing the parse progress for SubMode1 record
type private State_SubMode1 =
{
mutable Info1 : int option
mutable Info2 : string option
Rest : ResizeArray<string> // Corresponds to --rest
}
static member Create () =
{
Info1 = None
Info2 = None
Rest = ResizeArray ()
}
/// Check completeness and assemble the SubMode1 record from state.
member this.Assemble () : Result<SubMode1, string list> =
let errors = ResizeArray<string> ()
let mutable complete = true
if this.Info1.IsNone then
complete <- false
errors.Add ("Argument '--info1' is required.")
if this.Info2.IsNone then
complete <- false
errors.Add ("Argument '--info2' is required.")
// Rest is list, always 'complete'
if complete then
Ok
{
Info1 = this.Info1.Value
Info2 = this.Info2.Value
Rest = this.Rest |> Seq.toList
}
else
Error (errors |> Seq.toList)
/// State representing the parse progress for SubMode2 record
type private State_SubMode2 =
{
mutable Info1 : int option
mutable Info2 : string option
Rest : ResizeArray<int> // Corresponds to --rest
}
static member Create () =
{
Info1 = None
Info2 = None
Rest = ResizeArray ()
}
/// Check completeness and assemble the SubMode2 record from state.
member this.Assemble () : Result<SubMode2, string list> =
let errors = ResizeArray<string> ()
if this.Info1.IsNone then
errors.Add ("Argument '--info1' is required.")
if this.Info2.IsNone then
errors.Add ("Argument '--info2' is required.")
// Rest is list, always 'complete'
if errors.Count = 0 then
Ok
{
Info1 = this.Info1.Value
Info2 = this.Info2.Value
Rest = this.Rest |> Seq.toList
}
else
Error (errors |> Seq.toList)
/// State representing the parse progress for Mode1 record (references SubMode1 state)
type private State_Mode1 =
{
ThingsState : State_SubMode1 // Holds state for the nested record
mutable Whatnot : int option
}
static member Create () =
{
ThingsState = State_SubMode1.Create ()
Whatnot = None
}
/// Check completeness and assemble the Mode1 record from state (including nested).
member this.Assemble () : Result<Mode1, string list> =
let errors = ResizeArray<string> ()
// Check direct fields
if this.Whatnot.IsNone then
errors.Add ("Argument '--whatnot' is required for Mode1.")
// Assemble nested state (which includes its own validation)
let thingsResult = this.ThingsState.Assemble ()
let mutable thingsValue = None
match thingsResult with
| Ok v -> thingsValue <- Some v
| Error nestedErrors -> errors.AddRange (nestedErrors |> List.map (sprintf "Things: %s")) // Add context
if errors.Count = 0 then
Ok
{
Things = thingsValue.Value
Whatnot = this.Whatnot.Value
}
else
Error (errors |> Seq.toList)
/// State representing the parse progress for Mode2 record (references SubMode2 state)
type private State_Mode2 =
{
ThingsState : State_SubMode2 // Holds state for the nested record
mutable Whatnot : DateTime option
}
static member Create () =
{
ThingsState = State_SubMode2.Create ()
Whatnot = None
}
/// Check completeness and assemble the Mode2 record from state (including nested).
member this.Assemble () : Result<Mode2, string list> =
let errors = ResizeArray<string> ()
// Check direct fields
if this.Whatnot.IsNone then
errors.Add ("Argument '--whatnot' is required for Mode2.")
// Assemble nested state (which includes its own validation)
let thingsResult = this.ThingsState.Assemble ()
let mutable thingsValue = Unchecked.defaultof<_>
match thingsResult with
| Ok v -> thingsValue <- v
| Error nestedErrors -> errors.AddRange (nestedErrors |> List.map (sprintf "Things: %s")) // Add context
if errors.Count = 0 then
{
Things = thingsValue
Whatnot = this.Whatnot.Value
}
|> Ok
else
Error (errors |> Seq.toList)
/// State for a single candidate parse path for the Modes DU (Structure unchanged)
type private CandidateParseState_Modes =
{
CaseName : string // "Mode1" or "Mode2"
mutable IsViable : bool
Errors : ResizeArray<string> // Errors specific to this candidate's path
ConsumedArgIndices : System.Collections.Generic.HashSet<int> // Indices consumed *by this candidate*
CaseState : obj // Holds either State_Mode1 or State_Mode2
}
static member CreateMode1 () =
{
CaseName = "Mode1"
IsViable = true
Errors = ResizeArray ()
ConsumedArgIndices = System.Collections.Generic.HashSet ()
CaseState = State_Mode1.Create () :> obj
}
static member CreateMode2 () =
{
CaseName = "Mode2"
IsViable = true
Errors = ResizeArray ()
ConsumedArgIndices = System.Collections.Generic.HashSet ()
CaseState = State_Mode2.Create () :> obj
}
//--------------------------------------------------------------------------
// Main Parser Logic
//--------------------------------------------------------------------------
type private ParseState_Args =
| AwaitingArg
| AwaitingValue of keyIndex : int * key : string
let parse' (getEnvironmentVariable : string -> string) (args : string list) : Args =
let ArgParser_errors = ResizeArray () // Global errors accumulator
let helpText () =
// Help text generation unchanged
[
(sprintf "%s int32%s%s" (sprintf "--%s" "info1") "" " (for Mode1/Mode2 Things)")
(sprintf "%s string%s%s" (sprintf "--%s" "info2") "" " (for Mode1/Mode2 Things)")
(sprintf "%s string%s%s" (sprintf "--%s" "rest") " (can be repeated)" " (for Mode1 Things)")
(sprintf "%s int32%s%s" (sprintf "--%s" "rest") " (can be repeated)" " (for Mode2 Things)")
(sprintf "%s int32%s%s" (sprintf "--%s" "whatnot") "" " (for Mode1)")
(sprintf "%s DateTime%s%s" (sprintf "--%s" "whatnot") "" " (for Mode2)")
(sprintf "%s string%s%s" (sprintf "--%s" "other-args") " (positional args) (can be repeated)" "")
]
|> String.concat "\n"
let arg_OtherArgs : string ResizeArray = ResizeArray ()
let mutable candidates_WhatToDo : CandidateParseState_Modes list =
[
CandidateParseState_Modes.CreateMode1 ()
CandidateParseState_Modes.CreateMode2 ()
]
let consumedArgIndices_WhatToDo = System.Collections.Generic.HashSet<int> ()
//----------------------------------------------------------------------
// Helper functions for applying args (applyKeyValueToSubModeXState unchanged)
//----------------------------------------------------------------------
let applyKeyValueToSubMode1State
(argIndex : int)
(keyIndex : int)
(key : string)
(value : string)
(subState : State_SubMode1)
(candidate : CandidateParseState_Modes)
: unit
=
// ... (Implementation identical to previous version) ...
if String.Equals (key, "--info1", StringComparison.OrdinalIgnoreCase) then
match subState.Info1 with
| Some _ ->
candidate.Errors.Add (sprintf "Argument '--info1' supplied multiple times (SubMode1)")
candidate.IsViable <- false
| None ->
try
subState.Info1 <- Some (Int32.Parse value)
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
with ex ->
candidate.Errors.Add (
sprintf "Failed to parse '%s' for --info1 (SubMode1): %s" value ex.Message
)
candidate.IsViable <- false
elif String.Equals (key, "--info2", StringComparison.OrdinalIgnoreCase) then
match subState.Info2 with
| Some _ ->
candidate.Errors.Add (sprintf "Argument '--info2' supplied multiple times (SubMode1)")
candidate.IsViable <- false
| None ->
subState.Info2 <- Some value
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
elif String.Equals (key, "--rest", StringComparison.OrdinalIgnoreCase) then
subState.Rest.Add value
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
else
()
let applyKeyValueToSubMode2State
(argIndex : int)
(keyIndex : int)
(key : string)
(value : string)
(subState : State_SubMode2)
(candidate : CandidateParseState_Modes)
: unit
=
// ... (Implementation identical to previous version) ...
if String.Equals (key, "--info1", StringComparison.OrdinalIgnoreCase) then
match subState.Info1 with
| Some _ ->
candidate.Errors.Add (sprintf "Argument '--info1' supplied multiple times (SubMode2)")
candidate.IsViable <- false
| None ->
try
subState.Info1 <- Some (Int32.Parse value)
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
with ex ->
candidate.Errors.Add (
sprintf "Failed to parse '%s' for --info1 (SubMode2): %s" value ex.Message
)
candidate.IsViable <- false
elif String.Equals (key, "--info2", StringComparison.OrdinalIgnoreCase) then
match subState.Info2 with
| Some _ ->
candidate.Errors.Add (sprintf "Argument '--info2' supplied multiple times (SubMode2)")
candidate.IsViable <- false
| None ->
subState.Info2 <- Some value
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
elif String.Equals (key, "--rest", StringComparison.OrdinalIgnoreCase) then
try
subState.Rest.Add (Int32.Parse value)
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
with ex ->
candidate.Errors.Add (
sprintf "Failed to parse '%s' as int32 for --rest (SubMode2): %s" value ex.Message
)
candidate.IsViable <- false
else
()
//----------------------------------------------------------------------
// Routing and Main Application Logic (applyKeyValueToCandidate unchanged)
//----------------------------------------------------------------------
let applyKeyValueToCandidate
(argIndex : int, keyIndex : int, key : string, value : string)
(candidate : CandidateParseState_Modes)
: unit
=
// ... (Implementation identical to previous version, calling sub-state helpers) ...
if not candidate.IsViable then
()
else
match candidate.CaseName with
| "Mode1" ->
let state = candidate.CaseState :?> State_Mode1
if String.Equals (key, "--whatnot", StringComparison.OrdinalIgnoreCase) then
match state.Whatnot with
| Some _ ->
candidate.Errors.Add (
sprintf "Argument '--whatnot' supplied multiple times for Mode1 candidate"
)
candidate.IsViable <- false
| None ->
try
state.Whatnot <- Some (Int32.Parse value)
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
with ex ->
candidate.Errors.Add (
sprintf "Failed to parse '%s' as int32 for --whatnot (Mode1): %s" value ex.Message
)
candidate.IsViable <- false
elif key = "--info1" || key = "--info2" || key = "--rest" then
applyKeyValueToSubMode1State argIndex keyIndex key value state.ThingsState candidate
else
()
| "Mode2" ->
let state = candidate.CaseState :?> State_Mode2
if String.Equals (key, "--whatnot", StringComparison.OrdinalIgnoreCase) then
match state.Whatnot with
| Some _ ->
candidate.Errors.Add (
sprintf "Argument '--whatnot' supplied multiple times for Mode2 candidate"
)
candidate.IsViable <- false
| None ->
try
state.Whatnot <- Some (DateTime.Parse value)
candidate.ConsumedArgIndices.Add argIndex |> ignore
candidate.ConsumedArgIndices.Add keyIndex |> ignore
with ex ->
candidate.Errors.Add (
sprintf "Failed to parse '%s' as DateTime for --whatnot (Mode2): %s" value ex.Message
)
candidate.IsViable <- false
elif key = "--info1" || key = "--info2" || key = "--rest" then
applyKeyValueToSubMode2State argIndex keyIndex key value state.ThingsState candidate
else
()
| _ -> failwith "Internal error: Unknown case name"
// processKeyValue, setFlagValue, and main loop `go` are identical to previous version
let processKeyValue (keyIndex : int, key : string, valueIndex : int, value : string) : bool =
let mutable handled = false
for candidate in candidates_WhatToDo do
let initialConsumedCount = candidate.ConsumedArgIndices.Count
if candidate.IsViable then
applyKeyValueToCandidate (valueIndex, keyIndex, key, value) candidate
if candidate.IsViable && candidate.ConsumedArgIndices.Count > initialConsumedCount then
handled <- true
consumedArgIndices_WhatToDo.Add keyIndex |> ignore
consumedArgIndices_WhatToDo.Add valueIndex |> ignore
handled
let setFlagValue (keyIndex : int) (key : string) : bool = false // No flags
let rec go (state : ParseState_Args) (args : (int * string) list) =
// ... (Implementation identical to previous version) ...
match args with
| [] ->
match state with
| ParseState_Args.AwaitingArg -> ()
| ParseState_Args.AwaitingValue (i, k) ->
if not (setFlagValue i k) then
ArgParser_errors.Add (sprintf "Trailing argument '%s' (at index %d) requires a value." k i)
| (idx, arg) :: rest ->
match state with
| ParseState_Args.AwaitingArg ->
if arg = "--" then
rest
|> List.iter (fun (i, v) ->
if not (consumedArgIndices_WhatToDo.Contains i) then
arg_OtherArgs.Add v
)
go ParseState_Args.AwaitingArg []
elif arg.StartsWith ("--") then
if arg = "--help" then
helpText () |> failwithf "Help text requested:\n%s"
else
let eq = arg.IndexOf ('=')
if eq > 0 then
let k = arg.[.. eq - 1]
let v = arg.[eq + 1 ..]
if not (processKeyValue (idx, k, idx, v)) then
if not (consumedArgIndices_WhatToDo.Contains idx) then
arg_OtherArgs.Add arg
go ParseState_Args.AwaitingArg rest
elif setFlagValue idx arg then
consumedArgIndices_WhatToDo.Add idx |> ignore
go ParseState_Args.AwaitingArg rest
else
go (ParseState_Args.AwaitingValue (idx, arg)) rest
else
if not (consumedArgIndices_WhatToDo.Contains idx) then
arg_OtherArgs.Add arg
go ParseState_Args.AwaitingArg rest
| ParseState_Args.AwaitingValue (keyIdx, key) ->
if processKeyValue (keyIdx, key, idx, arg) then
go ParseState_Args.AwaitingArg rest
elif setFlagValue keyIdx key then
consumedArgIndices_WhatToDo.Add keyIdx |> ignore<bool>
go ParseState_Args.AwaitingArg ((idx, arg) :: rest) // Reprocess arg
elif not (consumedArgIndices_WhatToDo.Contains keyIdx) then
arg_OtherArgs.Add key
if not (consumedArgIndices_WhatToDo.Contains idx) then
arg_OtherArgs.Add arg
go ParseState_Args.AwaitingArg rest
args |> List.mapi (fun i s -> (i, s)) |> go ParseState_Args.AwaitingArg
//----------------------------------------------------------------------
// Final Validation and Assembly (Uses new Assemble methods)
//----------------------------------------------------------------------
let viableWinners = candidates_WhatToDo |> List.filter (fun c -> c.IsViable)
// No longer filter based on IsComplete here; Assemble handles it.
// Still need to check for relative leftovers if that logic were implemented.
let whatToDoResult =
match viableWinners with
| [] ->
// Add specific errors from candidates that were viable *before* Assemble check
ArgParser_errors.Add ("No valid parse found for 'WhatToDo'.")
candidates_WhatToDo
|> List.iter (fun c ->
if c.Errors.Count <> 0 then
ArgParser_errors.Add (
sprintf " Candidate %s parse errors: %s" c.CaseName (String.concat "; " c.Errors)
)
// Potentially try to Assemble even non-viable ones to get completion errors? Maybe too complex.
)
Unchecked.defaultof<_> // Error path
| [ winner ] ->
// Assemble the winning case, checking the Result for completion errors
match winner.CaseName with
| "Mode1" ->
match (winner.CaseState :?> State_Mode1).Assemble () with
| Ok mode1Value -> Modes.Mode1 mode1Value
| Error completionErrors ->
ArgParser_errors.Add (sprintf "Validation failed for selected candidate Mode1:")
ArgParser_errors.AddRange completionErrors
Unchecked.defaultof<_> // Error path
| "Mode2" ->
match (winner.CaseState :?> State_Mode2).Assemble () with
| Ok mode2Value -> Modes.Mode2 mode2Value
| Error completionErrors ->
ArgParser_errors.Add (sprintf "Validation failed for selected candidate Mode2:")
ArgParser_errors.AddRange completionErrors
Unchecked.defaultof<_> // Error path
| _ -> failwith "Internal error: Unknown winning case name"
| winners -> // Ambiguous parse
ArgParser_errors.Add ("Ambiguous parse for 'WhatToDo'. Multiple modes potentially viable:")
winners
|> List.iter (fun c ->
ArgParser_errors.Add (
sprintf
" - %s (Initial Errors: %s)"
c.CaseName
(if c.Errors.Count = 0 then
"None"
else
String.concat "; " c.Errors)
)
)
Unchecked.defaultof<_> // Error path
// Finalize OtherArgs (unchanged)
let otherArgsResult = arg_OtherArgs |> Seq.toList
// Assemble Final Result or Fail (unchanged)
if ArgParser_errors.Count > 0 then
ArgParser_errors
|> String.concat "\n"
|> failwithf "Errors during parse!\n%s\n\nHelp Text:\n%s" (helpText ())
else
{
WhatToDo = whatToDoResult
OtherArgs = otherArgsResult
}
let parse (args : string list) : Args =
parse' System.Environment.GetEnvironmentVariable args

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<Compile Include="Domain.fs" />
<Compile Include="Library.fs"/>
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.Myriad.Plugins.Attributes\WoofWare.Myriad.Plugins.Attributes.fsproj" />
</ItemGroup>
</Project>

10
Playground/Program.fs Normal file
View File

@@ -0,0 +1,10 @@
namespace Playground
module Program =
[<EntryPoint>]
let main argv =
[ "--whatnot=2024-01-12" ; "--info1=4" ; "--info2=hi" ]
|> Args.parse
|> printfn "%O"
0

View File

@@ -26,6 +26,11 @@ type ArgParserAttribute (isExtensionMethod : bool) =
/// an argument which looks like a flag but which we don't recognise.) /// an argument which looks like a flag but which we don't recognise.)
/// We will still interpret `--help` as requesting help, unless it comes after /// We will still interpret `--help` as requesting help, unless it comes after
/// a standalone `--` separator. /// a standalone `--` separator.
///
/// If the type of the PositionalArgs field is `Choice<'a, 'a>`, then we will
/// tell you whether each arg came before or after a standalone `--` separator.
/// For example, `MyApp foo bar -- baz` with PositionalArgs of `Choice<string, string>`
/// would yield `Choice1Of2 foo, Choice1Of2 bar, Choice2Of2 baz`.
type PositionalArgsAttribute (includeFlagLike : bool) = type PositionalArgsAttribute (includeFlagLike : bool) =
inherit Attribute () inherit Attribute ()

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
@@ -17,10 +17,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ApiSurface" Version="4.1.8" /> <PackageReference Include="ApiSurface" Version="4.1.20" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
<PackageReference Include="NUnit" Version="4.2.2"/> <PackageReference Include="NUnit" Version="4.3.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/> <PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -79,11 +79,8 @@ module TestArgParser =
exc.Message exc.Message
|> shouldEqual |> shouldEqual
"""Unable to process supplied arg --non-existent. Help text follows. """Errors during parse!
--foo int32 : This is a foo! Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `--rest=` syntax, or place them after a trailing `--`. --non-existent"""
--bar string
--baz bool
--rest string (positional args) (can be repeated) : Here's where the rest of the args go"""
[<Test>] [<Test>]
let ``Can supply positional args with key`` () = let ``Can supply positional args with key`` () =
@@ -318,8 +315,7 @@ Required argument '--baz' received no value"""
exc.Message exc.Message
|> shouldEqual |> shouldEqual
"""Errors during parse! """Errors during parse!
Input string was not in a correct format. (at arg --invariant-exact=23:59) Input string was not in a correct format. (at arg --invariant-exact=23:59)"""
Required argument '--invariant-exact' received no value"""
let exc = let exc =
Assert.Throws<exn> (fun () -> Assert.Throws<exn> (fun () ->
@@ -337,8 +333,7 @@ Required argument '--invariant-exact' received no value"""
exc.Message exc.Message
|> shouldEqual |> shouldEqual
"""Errors during parse! """Errors during parse!
Input string was not in a correct format. (at arg --exact=11:34) Input string was not in a correct format. (at arg --exact=11:34)"""
Required argument '--exact' received no value"""
count.Value |> shouldEqual 0 count.Value |> shouldEqual 0
@@ -444,7 +439,7 @@ Required argument '--exact' received no value"""
] ]
|> List.map TestCaseData |> List.map TestCaseData
[<TestCaseSource(nameof (boolCases))>] [<TestCaseSource(nameof boolCases)>]
let ``Bool env vars can be populated`` (envValue : string, boolValue : bool) = let ``Bool env vars can be populated`` (envValue : string, boolValue : bool) =
let getEnvVar (s : string) = let getEnvVar (s : string) =
s |> shouldEqual "CONSUMEPLUGIN_THINGS" s |> shouldEqual "CONSUMEPLUGIN_THINGS"
@@ -604,7 +599,10 @@ Required argument '--exact' received no value"""
) )
exc.Message exc.Message
|> shouldEqual """Unable to process argument --do-the-thing=foo as key --do-the-thing and value foo""" |> shouldEqual
"""Errors during parse!
Required argument '--do-something-else' received no value
Required argument '--turn-it-on' received no value"""
[<Test>] [<Test>]
let ``Long-form args help text`` () = let ``Long-form args help text`` () =
@@ -692,7 +690,9 @@ Required argument '--exact' received no value"""
) )
exc.Message exc.Message
|> shouldEqual """Unable to process argument --b=false as key --b and value false""" |> shouldEqual
"""Errors during parse!
Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `--dont-grab-everything=` syntax, or place them after a trailing `--`. --b=false --c"""
let exc = let exc =
Assert.Throws<exn> (fun () -> Assert.Throws<exn> (fun () ->
@@ -703,4 +703,6 @@ Required argument '--exact' received no value"""
// Again perhaps eccentric! // Again perhaps eccentric!
// Again, we don't try to detect that the user has missed out the desired argument to `--a`. // Again, we don't try to detect that the user has missed out the desired argument to `--a`.
exc.Message exc.Message
|> shouldEqual """Unable to process argument --c=hi as key --c and value hi""" |> shouldEqual
"""Errors during parse!
Unmatched args which look like they are meant to be flags. If you intended them as positional args, explicitly pass them with the `--my-arg-name=` syntax, or place them after a trailing `--`. --c=hi"""

View File

@@ -0,0 +1,21 @@
namespace WoofWare.Myriad.Plugins.Test
open FsUnitTyped
open NUnit.Framework
open ConsumePlugin.ArgsWithUnions
[<TestFixture>]
module TestArgsWithUnions =
let argsWithUnionsCases =
[
["--token" ; "hello" ; "--foo" ; "3" ; "--bar=hi" ; "--baz"], { Auth = AuthOptions.Token { Token = "hello" } ; Basics = { Foo = 3 ; Bar = "hi" ; Baz = true ; Rest = [] } }
]
|> List.map TestCaseData
[<TestCaseSource (nameof argsWithUnionsCases)>]
let ``foo`` (args : string list, expected : DoTheThing) : unit =
args
|> DoTheThing.parse' (fun _ -> failwith "didn't expect env var")
|> shouldEqual expected

View File

@@ -3,7 +3,7 @@ namespace WoofWare.Myriad.Plugins.Test
open System open System
open System.Collections.Generic open System.Collections.Generic
open System.Text.Json.Nodes open System.Text.Json.Nodes
open FsCheck.Random open FsCheck.FSharp
open Microsoft.FSharp.Reflection open Microsoft.FSharp.Reflection
open NUnit.Framework open NUnit.Framework
open FsCheck open FsCheck
@@ -15,21 +15,21 @@ module TestJsonSerde =
let uriGen : Gen<Uri> = let uriGen : Gen<Uri> =
gen { gen {
let! suffix = Arb.generate<int> let! suffix = ArbMap.generate<int> ArbMap.defaults
return Uri $"https://example.com/%i{suffix}" return Uri $"https://example.com/%i{suffix}"
} }
let rec innerGen (count : int) : Gen<InnerTypeWithBoth> = let rec innerGen (count : int) : Gen<InnerTypeWithBoth> =
gen { gen {
let! guid = Arb.generate<Guid> let! guid = ArbMap.generate<Guid> ArbMap.defaults
let! mapKeys = Gen.listOf Arb.generate<NonNull<string>> let! mapKeys = Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
let mapKeys = mapKeys |> List.map _.Get |> List.distinct let mapKeys = mapKeys |> List.map _.Get |> List.distinct
let! mapValues = Gen.listOfLength mapKeys.Length uriGen let! mapValues = Gen.listOfLength mapKeys.Length uriGen
let map = List.zip mapKeys mapValues |> Map.ofList let map = List.zip mapKeys mapValues |> Map.ofList
let! concreteDictKeys = let! concreteDictKeys =
if count > 0 then if count > 0 then
Gen.listOf Arb.generate<NonNull<string>> Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
else else
Gen.constant [] Gen.constant []
@@ -50,13 +50,16 @@ module TestJsonSerde =
|> List.map KeyValuePair |> List.map KeyValuePair
|> Dictionary |> Dictionary
let! readOnlyDictKeys = Gen.listOf Arb.generate<NonNull<string>> let! readOnlyDictKeys = Gen.listOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
let readOnlyDictKeys = readOnlyDictKeys |> List.map _.Get |> List.distinct let readOnlyDictKeys = readOnlyDictKeys |> List.map _.Get |> List.distinct
let! readOnlyDictValues = Gen.listOfLength readOnlyDictKeys.Length (Gen.listOf Arb.generate<char>)
let! readOnlyDictValues =
Gen.listOfLength readOnlyDictKeys.Length (Gen.listOf (ArbMap.generate<char> ArbMap.defaults))
let readOnlyDict = List.zip readOnlyDictKeys readOnlyDictValues |> readOnlyDict let readOnlyDict = List.zip readOnlyDictKeys readOnlyDictValues |> readOnlyDict
let! dictKeys = Gen.listOf uriGen let! dictKeys = Gen.listOf uriGen
let! dictValues = Gen.listOfLength dictKeys.Length Arb.generate<bool> let! dictValues = Gen.listOfLength dictKeys.Length (ArbMap.generate<bool> ArbMap.defaults)
let dict = List.zip dictKeys dictValues |> dict let dict = List.zip dictKeys dictValues |> dict
return return
@@ -71,28 +74,38 @@ module TestJsonSerde =
let outerGen : Gen<JsonRecordTypeWithBoth> = let outerGen : Gen<JsonRecordTypeWithBoth> =
gen { gen {
let! a = Arb.generate<int> let! a = ArbMap.generate<int> ArbMap.defaults
let! b = Arb.generate<NonNull<string>> let! b = ArbMap.generate<NonNull<string>> ArbMap.defaults
let! c = Gen.listOf Arb.generate<int> let! c = Gen.listOf (ArbMap.generate<int> ArbMap.defaults)
let! depth = Gen.choose (0, 2) let! depth = Gen.choose (0, 2)
let! d = innerGen depth let! d = innerGen depth
let! e = Gen.arrayOf Arb.generate<NonNull<string>> let! e = Gen.arrayOf (ArbMap.generate<NonNull<string>> ArbMap.defaults)
let! arr = Gen.arrayOf Arb.generate<int> let! arr = Gen.arrayOf (ArbMap.generate<int> ArbMap.defaults)
let! byte = Arb.generate let! byte = ArbMap.generate ArbMap.defaults
let! sbyte = Arb.generate let! sbyte = ArbMap.generate ArbMap.defaults
let! i = Arb.generate let! i = ArbMap.generate ArbMap.defaults
let! i32 = Arb.generate let! i32 = ArbMap.generate ArbMap.defaults
let! i64 = Arb.generate let! i64 = ArbMap.generate ArbMap.defaults
let! u = Arb.generate let! u = ArbMap.generate ArbMap.defaults
let! u32 = Arb.generate let! u32 = ArbMap.generate ArbMap.defaults
let! u64 = Arb.generate let! u64 = ArbMap.generate ArbMap.defaults
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! f =
let! single = Arb.generate |> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>)) ArbMap.generate ArbMap.defaults
let! intMeasureOption = Arb.generate |> Gen.filter (fun s -> Double.IsFinite (s / 1.0<measure>))
let! intMeasureNullable = Arb.generate
let! f32 =
ArbMap.generate ArbMap.defaults
|> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
let! single =
ArbMap.generate ArbMap.defaults
|> Gen.filter (fun s -> Single.IsFinite (s / 1.0f<measure>))
let! intMeasureOption = ArbMap.generate ArbMap.defaults
let! intMeasureNullable = ArbMap.generate ArbMap.defaults
let! someEnum = Gen.choose (0, 1) let! someEnum = Gen.choose (0, 1)
let! timestamp = Arb.generate let! timestamp = ArbMap.generate ArbMap.defaults
return return
{ {
@@ -270,10 +283,10 @@ module TestJsonSerde =
match case with match case with
| 0 -> return FirstDu.EmptyCase | 0 -> return FirstDu.EmptyCase
| 1 -> | 1 ->
let! s = Arb.generate<NonNull<string>> let! s = ArbMap.generate<NonNull<string>> ArbMap.defaults
return FirstDu.Case1 s.Get return FirstDu.Case1 s.Get
| 2 -> | 2 ->
let! i = Arb.generate<int> let! i = ArbMap.generate<int> ArbMap.defaults
let! record = outerGen let! record = outerGen
return FirstDu.Case2 (record, i) return FirstDu.Case2 (record, i)
| _ -> return failwith $"unexpected: %i{case}" | _ -> return failwith $"unexpected: %i{case}"
@@ -293,7 +306,6 @@ module TestJsonSerde =
[<Test>] [<Test>]
let ``DU generator covers all cases`` () = let ``DU generator covers all cases`` () =
let rand = Random ()
let cases = FSharpType.GetUnionCases typeof<FirstDu> let cases = FSharpType.GetUnionCases typeof<FirstDu>
let counts = Array.zeroCreate<int> cases.Length let counts = Array.zeroCreate<int> cases.Length
@@ -301,11 +313,13 @@ module TestJsonSerde =
let mutable i = 0 let mutable i = 0
while i < 10_000 && Array.exists (fun i -> i = 0) counts do let property (du : FirstDu) =
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
let tag = decompose du let tag = decompose du
counts.[tag] <- counts.[tag] + 1 counts.[tag] <- counts.[tag] + 1
i <- i + 1 i <- i + 1
true
Check.One (Config.Quick, Prop.forAll (Arb.fromGen duGen) property)
for i in counts do for i in counts do
i |> shouldBeGreaterThan 0 i |> shouldBeGreaterThan 0

View File

@@ -34,3 +34,16 @@ module TestMockGenerator =
mock.Mem1 3 'a' |> shouldEqual "aaa" mock.Mem1 3 'a' |> shouldEqual "aaa"
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi" mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi" mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
[<Test>]
let ``Example of use: properties`` () =
let mock : TypeWithProperties =
{ TypeWithPropertiesMock.Empty with
Mem1 = fun i -> async { return Option.toArray i }
Prop1 = fun () -> 44
}
:> _
mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
mock.Prop1 |> shouldEqual 44

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
<!-- <!--
@@ -9,9 +9,11 @@
I have not yet seen a single instance where I care about this warning I have not yet seen a single instance where I care about this warning
--> -->
<NoWarn>$(NoWarn),NU1903</NoWarn> <NoWarn>$(NoWarn),NU1903</NoWarn>
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<!--
<Compile Include="HttpClient.fs"/> <Compile Include="HttpClient.fs"/>
<Compile Include="PureGymDtos.fs"/> <Compile Include="PureGymDtos.fs"/>
<Compile Include="TestJsonParse\TestJsonParse.fs" /> <Compile Include="TestJsonParse\TestJsonParse.fs" />
@@ -33,20 +35,24 @@
<Compile Include="TestCataGenerator\TestGift.fs" /> <Compile Include="TestCataGenerator\TestGift.fs" />
<Compile Include="TestCataGenerator\TestMyList.fs" /> <Compile Include="TestCataGenerator\TestMyList.fs" />
<Compile Include="TestCataGenerator\TestMyList2.fs" /> <Compile Include="TestCataGenerator\TestMyList2.fs" />
-->
<Compile Include="TestArgParser\TestArgParser.fs" /> <Compile Include="TestArgParser\TestArgParser.fs" />
<Compile Include="TestArgParser\TestArgsWithUnions.fs" />
<!--
<Compile Include="TestSwagger\TestSwaggerParse.fs" /> <Compile Include="TestSwagger\TestSwaggerParse.fs" />
<Compile Include="TestRemoveOptions.fs"/> <Compile Include="TestRemoveOptions.fs"/>
<Compile Include="TestSurface.fs"/> <Compile Include="TestSurface.fs"/>
-->
<None Include="../.github/workflows/dotnet.yaml" /> <None Include="../.github/workflows/dotnet.yaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ApiSurface" Version="4.1.8"/> <PackageReference Include="ApiSurface" Version="4.1.20"/>
<PackageReference Include="FsCheck" Version="2.16.6"/> <PackageReference Include="FsCheck" Version="3.2.0"/>
<PackageReference Include="FsUnit" Version="6.0.1"/> <PackageReference Include="FsUnit" Version="7.0.1"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
<PackageReference Include="NUnit" Version="4.2.2"/> <PackageReference Include="NUnit" Version="4.3.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/> <PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -7,82 +7,6 @@ open Fantomas.FCS.Text.Range
open TypeEquality open TypeEquality
open WoofWare.Whippet.Fantomas open WoofWare.Whippet.Fantomas
type internal ArgParserOutputSpec =
{
ExtensionMethods : bool
}
type internal FlagDu =
{
Name : Ident
Case1Name : Ident
Case2Name : Ident
/// Hopefully this is simply the const bool True or False, but it might e.g. be a literal
Case1Arg : SynExpr
/// Hopefully this is simply the const bool True or False, but it might e.g. be a literal
Case2Arg : SynExpr
}
static member FromBoolean (flagDu : FlagDu) (value : SynExpr) =
SynExpr.ifThenElse
(SynExpr.equals value flagDu.Case1Arg)
(SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case2Name ])
(SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case1Name ])
/// The default value of an argument which admits default values can be pulled from different sources.
/// This defines which source a particular default value comes from.
type private ArgumentDefaultSpec =
/// From parsing the environment variable with the given name (e.g. "WOOFWARE_DISABLE_FOO" or whatever).
| EnvironmentVariable of name : SynExpr
/// From calling the static member `{typeWeParseInto}.Default{name}()`
/// For example, if `type MyArgs = { Thing : Choice<int, int> }`, then
/// we would use `MyArgs.DefaultThing () : int`.
///
| FunctionCall of name : Ident
type private Accumulation<'choice> =
| Required
| Optional
| Choice of 'choice
| List of Accumulation<'choice>
type private ParseFunction<'acc> =
{
FieldName : Ident
TargetVariable : Ident
/// Any of the forms in this set are acceptable, but make sure they all start with a dash, or we might
/// get confused with positional args or something! I haven't thought that hard about this.
/// In the default case, this is `Const("arg-name")` for the `ArgName : blah` field; note that we have
/// omitted the initial `--` that will be required at runtime.
ArgForm : SynExpr list
/// If this is a boolean-like field (e.g. a bool or a flag DU), the help text should look a bit different:
/// we should lie to the user about the value of the cases there.
/// Similarly, if we're reading from an environment variable with the laxer parsing rules of accepting e.g.
/// "0" instead of "false", we need to know if we're reading a bool.
/// In that case, `boolCases` is Some, and contains the construction of the flag (or boolean, in which case
/// you get no data).
BoolCases : Choice<FlagDu, unit> option
Help : SynExpr option
/// A function string -> %TargetType%, where TargetVariable is probably a `%TargetType% option`.
/// (Depending on `Accumulation`, we'll remove the `option` at the end of the parse, asserting that the
/// argument was supplied.)
/// This is allowed to throw if it fails to parse.
Parser : SynExpr
/// If `Accumulation` is `List`, then this is the type of the list *element*; analogously for optionals
/// and choices and so on.
TargetType : SynType
Accumulation : 'acc
}
/// A SynExpr of type `string` which we can display to the user at generated-program runtime to display all
/// the ways they can refer to this arg.
member arg.HumanReadableArgForm : SynExpr =
let formatString = List.replicate arg.ArgForm.Length "--%s" |> String.concat " / "
(SynExpr.applyFunction (SynExpr.createIdent "sprintf") (SynExpr.CreateConst formatString), arg.ArgForm)
||> List.fold SynExpr.applyFunction
|> SynExpr.paren
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
type private ChoicePositional = type private ChoicePositional =
| Normal of includeFlagLike : SynExpr option | Normal of includeFlagLike : SynExpr option
@@ -114,14 +38,14 @@ type private ParseTree<'hasPositional> =
/// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in /// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in
/// the branch (e.g. each record field name), /// the branch (e.g. each record field name),
/// and composes them into a `SynExpr` (e.g. the record-typed object). /// and composes them into a `SynExpr` (e.g. the record-typed object).
| Branch of | DescendRecord of
fields : (Ident * ParseTree<HasNoPositional>) list * fields : (Ident * ParseTree<HasNoPositional>) list *
assemble : (Map<string, SynExpr> -> SynExpr) * assemble : (Map<string, SynExpr> -> SynExpr) *
Teq<'hasPositional, HasNoPositional> Teq<'hasPositional, HasNoPositional>
/// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in /// `assemble` takes the SynExpr's (e.g. each record field contents) corresponding to each `Ident` in
/// the branch (e.g. each record field name), /// the branch (e.g. each record field name),
/// and composes them into a `SynExpr` (e.g. the record-typed object). /// and composes them into a `SynExpr` (e.g. the record-typed object).
| BranchPos of | DescendRecordPos of
posField : Ident * posField : Ident *
fields : ParseTree<HasPositional> * fields : ParseTree<HasPositional> *
(Ident * ParseTree<HasNoPositional>) list * (Ident * ParseTree<HasNoPositional>) list *
@@ -184,63 +108,6 @@ module private ParseTree =
go None ([], None) subs go None ([], None) subs
let rec accumulatorsNonPos (tree : ParseTree<HasNoPositional>) : ParseFunctionNonPositional list =
match tree with
| ParseTree.PositionalLeaf (_, teq) -> exFalso teq
| ParseTree.BranchPos (_, _, _, _, teq) -> exFalso teq
| ParseTree.NonPositionalLeaf (pf, _) -> [ pf ]
| ParseTree.Branch (trees, _, _) -> trees |> List.collect (snd >> accumulatorsNonPos)
/// Returns the positional arg separately.
let rec accumulatorsPos
(tree : ParseTree<HasPositional>)
: ParseFunctionNonPositional list * ParseFunctionPositional
=
match tree with
| ParseTree.PositionalLeaf (pf, _) -> [], pf
| ParseTree.NonPositionalLeaf (_, teq) -> exFalso' teq
| ParseTree.Branch (_, _, teq) -> exFalso' teq
| ParseTree.BranchPos (_, tree, trees, _, _) ->
let nonPos = trees |> List.collect (snd >> accumulatorsNonPos)
let nonPos2, pos = accumulatorsPos tree
nonPos @ nonPos2, pos
/// Collect all the ParseFunctions which are necessary to define variables, throwing away
/// all information relevant to composing the resulting variables into records.
/// Returns the list of non-positional parsers, and any positional parser that exists.
let accumulators<'a> (tree : ParseTree<'a>) : ParseFunctionNonPositional list * ParseFunctionPositional option =
// Sad duplication of some code here, but it was the easiest way to make it type-safe :(
match tree with
| ParseTree.PositionalLeaf (pf, _) -> [], Some pf
| ParseTree.NonPositionalLeaf (pf, _) -> [ pf ], None
| ParseTree.Branch (trees, _, _) -> trees |> List.collect (snd >> accumulatorsNonPos) |> (fun i -> i, None)
| ParseTree.BranchPos (_, tree, trees, _, _) ->
let nonPos = trees |> List.collect (snd >> accumulatorsNonPos)
let nonPos2, pos = accumulatorsPos tree
nonPos @ nonPos2, Some pos
|> fun (nonPos, pos) ->
let duplicateArgs =
// This is best-effort. We can't necessarily detect all SynExprs here, but usually it'll be strings.
Option.toList (pos |> Option.map _.ArgForm) @ (nonPos |> List.map _.ArgForm)
|> Seq.concat
|> Seq.choose (fun expr ->
match expr |> SynExpr.stripOptionalParen with
| SynExpr.Const (SynConst.String (s, _, _), _) -> Some s
| _ -> None
)
|> List.ofSeq
|> List.groupBy id
|> List.choose (fun (key, v) -> if v.Length > 1 then Some key else None)
match duplicateArgs with
| [] -> nonPos, pos
| dups ->
let dups = dups |> String.concat " "
failwith $"Duplicate args detected! %s{dups}"
/// Build the return value. /// Build the return value.
let rec instantiate<'a> (tree : ParseTree<'a>) : SynExpr = let rec instantiate<'a> (tree : ParseTree<'a>) : SynExpr =
match tree with match tree with
@@ -673,7 +540,7 @@ module internal ArgParserGenerator =
args args
|> Map.toList |> Map.toList
|> List.map (fun (ident, expr) -> SynLongIdent.create [ Ident.create ident ], expr) |> List.map (fun (ident, expr) -> SynLongIdent.create [ Ident.create ident ], expr)
|> AstHelper.instantiateRecord |> SynExpr.createRecord None
) )
tree, counter tree, counter

View File

@@ -36,13 +36,6 @@ module internal AstHelper =
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Enum _, _) -> true
| _ -> false | _ -> false
let instantiateRecord (fields : (SynLongIdent * SynExpr) list) : SynExpr =
let fields =
fields
|> List.map (fun (rfn, synExpr) -> SynExprRecordField ((rfn, true), Some range0, Some synExpr, None))
SynExpr.Record (None, None, fields, range0)
let defineRecordType (record : RecordType) : SynTypeDefn = let defineRecordType (record : RecordType) : SynTypeDefn =
let name = let name =
SynComponentInfo.create record.Name SynComponentInfo.create record.Name

View File

@@ -89,7 +89,7 @@ module internal InterfaceMockGenerator =
[] []
else else
[ SynPat.unit ]) [ SynPat.unit ])
(AstHelper.instantiateRecord constructorFields) (SynExpr.createRecord None constructorFields)
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.") |> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|> SynBinding.withReturnAnnotation constructorReturnType |> SynBinding.withReturnAnnotation constructorReturnType
|> SynMemberDefn.staticMember |> SynMemberDefn.staticMember
@@ -159,6 +159,15 @@ module internal InterfaceMockGenerator =
|> SynMemberDefn.memberImplementation |> SynMemberDefn.memberImplementation
) )
let properties =
interfaceType.Properties
|> List.map (fun pi ->
SynExpr.createLongIdent' [ Ident.create "this" ; pi.Identifier ]
|> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic [ Ident.create "this" ; pi.Identifier ] []
|> SynMemberDefn.memberImplementation
)
let interfaceName = let interfaceName =
let baseName = SynType.createLongIdent interfaceType.Name let baseName = SynType.createLongIdent interfaceType.Name
@@ -174,7 +183,7 @@ module internal InterfaceMockGenerator =
SynType.app' baseName generics SynType.app' baseName generics
SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0) SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0)
let access = let access =
match interfaceType.Accessibility, spec.IsInternal with match interfaceType.Accessibility, spec.IsInternal with
@@ -248,6 +257,15 @@ module internal InterfaceMockGenerator =
|> SynField.make |> SynField.make
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty) |> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
let constructProperty (prop : PropertyInfo) : SynField =
{
Attrs = []
Ident = Some prop.Identifier
Type = SynType.toFun [ SynType.unit ] prop.Type
}
|> SynField.make
|> SynField.withDocString (prop.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
let createRecord let createRecord
(namespaceId : LongIdent) (namespaceId : LongIdent)
(opens : SynOpenDeclTarget list) (opens : SynOpenDeclTarget list)
@@ -255,7 +273,12 @@ module internal InterfaceMockGenerator =
: SynModuleOrNamespace : SynModuleOrNamespace
= =
let interfaceType = AstHelper.parseInterface interfaceType let interfaceType = AstHelper.parseInterface interfaceType
let fields = interfaceType.Members |> List.map constructMember
let fields =
interfaceType.Members
|> List.map constructMember
|> List.append (interfaceType.Properties |> List.map constructProperty)
let docString = PreXmlDoc.create "Mock record type for an interface" let docString = PreXmlDoc.create "Mock record type for an interface"
let name = let name =

View File

@@ -351,10 +351,7 @@ module internal JsonParseGenerator =
let getParseOptions (fieldAttrs : SynAttribute list) = let getParseOptions (fieldAttrs : SynAttribute list) =
(JsonParseOption.None, fieldAttrs) (JsonParseOption.None, fieldAttrs)
||> List.fold (fun options attr -> ||> List.fold (fun options attr ->
if if (SynLongIdent.toString attr.TypeName).EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then
(SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
then
let qualifiedEnumValue = let qualifiedEnumValue =
match SynExpr.stripOptionalParen attr.ArgExpr with match SynExpr.stripOptionalParen attr.ArgExpr with
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident -> | SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
@@ -384,15 +381,13 @@ module internal JsonParseGenerator =
let propertyNameAttr = let propertyNameAttr =
fieldData.Attrs fieldData.Attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName) (SynLongIdent.toString attr.TypeName).EndsWith ("JsonPropertyName", StringComparison.Ordinal)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
) )
let extensionDataAttr = let extensionDataAttr =
fieldData.Attrs fieldData.Attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName) (SynLongIdent.toString attr.TypeName).EndsWith ("JsonExtensionData", StringComparison.Ordinal)
.EndsWith ("JsonExtensionData", StringComparison.Ordinal)
) )
let propertyName = let propertyName =
@@ -485,7 +480,7 @@ module internal JsonParseGenerator =
let finalConstruction = let finalConstruction =
fields fields
|> List.mapi (fun i fieldData -> SynLongIdent.createI fieldData.Ident, SynExpr.createIdent $"arg_%i{i}") |> List.mapi (fun i fieldData -> SynLongIdent.createI fieldData.Ident, SynExpr.createIdent $"arg_%i{i}")
|> AstHelper.instantiateRecord |> SynExpr.createRecord None
(finalConstruction, assignments) (finalConstruction, assignments)
||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final) ||> List.fold (fun final assignment -> SynExpr.createLet [ assignment ] final)

View File

@@ -180,8 +180,7 @@ module internal JsonSerializeGenerator =
let propertyNameAttr = let propertyNameAttr =
attrs attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName) (SynLongIdent.toString attr.TypeName).EndsWith ("JsonPropertyName", StringComparison.Ordinal)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
) )
match propertyNameAttr with match propertyNameAttr with
@@ -198,8 +197,7 @@ module internal JsonSerializeGenerator =
let getIsJsonExtension (attrs : SynAttribute list) : bool = let getIsJsonExtension (attrs : SynAttribute list) : bool =
attrs attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName) (SynLongIdent.toString attr.TypeName).EndsWith ("JsonExtensionData", StringComparison.Ordinal)
.EndsWith ("JsonExtensionData", StringComparison.Ordinal)
) )
|> Option.isSome |> Option.isSome

View File

@@ -21,3 +21,13 @@ module private List =
| Some head :: tail -> go (head :: acc) tail | Some head :: tail -> go (head :: acc) tail
go [] l go [] l
/// Return the first error encountered, or the entire list.
let allOkOrError<'ok, 'err> (l : Result<'ok, 'err> list) : Result<'ok list, 'err> =
let rec go acc l =
match l with
| [] -> Ok (List.rev acc)
| Error e :: _ -> Error e
| Ok o :: rest -> go (o :: acc) rest
go [] l

View File

@@ -97,7 +97,7 @@ module internal RemoveOptionsGenerator =
SynLongIdent.createI fieldData.Ident, body SynLongIdent.createI fieldData.Ident, body
) )
|> AstHelper.instantiateRecord |> SynExpr.createRecord None
SynBinding.basic SynBinding.basic
[ functionName ] [ functionName ]

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Myriad.Core" Version="0.8.3" /> <PackageReference Include="Myriad.Core" Version="0.8.3" />
<PackageReference Include="TypeEquality" Version="0.3.0" /> <PackageReference Include="TypeEquality" Version="0.3.0" />
<PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.3.1" /> <PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.5.1" />
<!-- the lowest version allowed by Myriad.Core --> <!-- the lowest version allowed by Myriad.Core -->
<PackageReference Update="FSharp.Core" Version="6.0.1" PrivateAssets="all"/> <PackageReference Update="FSharp.Core" Version="6.0.1" PrivateAssets="all"/>
</ItemGroup> </ItemGroup>
@@ -40,7 +40,8 @@
<Compile Include="JsonParseGenerator.fs"/> <Compile Include="JsonParseGenerator.fs"/>
<Compile Include="HttpClientGenerator.fs"/> <Compile Include="HttpClientGenerator.fs"/>
<Compile Include="CataGenerator.fs" /> <Compile Include="CataGenerator.fs" />
<Compile Include="ArgParserGenerator.fs" /> <Compile Include="ShibaGenerator.fs" />
<None Include="ArgParserGenerator.fs" />
<Compile Include="Swagger.fs" /> <Compile Include="Swagger.fs" />
<Compile Include="SwaggerClientGenerator.fs" /> <Compile Include="SwaggerClientGenerator.fs" />
<None Include="ApacheLicence.txt" /> <None Include="ApacheLicence.txt" />

View File

@@ -10,6 +10,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Myriad.Plugins.Att
EndProject EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Myriad.Plugins.Attributes.Test", "WoofWare.Myriad.Plugins.Attributes\Test\WoofWare.Myriad.Plugins.Attributes.Test.fsproj", "{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}" Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Myriad.Plugins.Attributes.Test", "WoofWare.Myriad.Plugins.Attributes\Test\WoofWare.Myriad.Plugins.Attributes.Test.fsproj", "{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}"
EndProject EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Playground", "Playground\Playground.fsproj", "{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -36,5 +38,9 @@ Global
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU {26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.Build.0 = Release|Any CPU {26DC0C94-85F2-45B4-8FA1-1B27201F7AFB}.Release|Any CPU.Build.0 = Release|Any CPU
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DF8C756-DE59-4AFF-A4BB-2D05C74192A4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.11.0]" /> <PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.14.0]" />
</ItemGroup> </ItemGroup>
</Project> </Project>

12
flake.lock generated
View File

@@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1726560853, "lastModified": 1731533236,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1729265718, "lastModified": 1744502386,
"narHash": "sha256-4HQI+6LsO3kpWTYuVGIzhJs1cetFcwT7quWCk/6rqeo=", "narHash": "sha256-QAd1L37eU7ktL2WeLLLTmI6P9moz9+a/ONO8qNBYJgM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ccc0c2126893dd20963580b6478d1a10a4512185", "rev": "f6db44a8daa59c40ae41ba6e5823ec77fe0d2124",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -14,8 +14,8 @@
flake-utils.lib.eachDefaultSystem (system: let flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
pname = "WoofWare.Myriad.Plugins"; pname = "WoofWare.Myriad.Plugins";
dotnet-sdk = pkgs.dotnet-sdk_8; dotnet-sdk = pkgs.dotnetCorePackages.sdk_9_0;
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0; dotnet-runtime = pkgs.dotnetCorePackages.runtime_9_0;
version = "0.1"; version = "0.1";
dotnetTool = dllOverride: toolName: toolVersion: hash: dotnetTool = dllOverride: toolName: toolVersion: hash:
pkgs.stdenvNoCC.mkDerivation rec { pkgs.stdenvNoCC.mkDerivation rec {
@@ -26,25 +26,29 @@
pname = name; pname = name;
version = version; version = version;
hash = hash; hash = hash;
installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin''; installPhase = ''mkdir -p $out/bin && cp -r tools/net*/any/* $out/bin'';
}; };
installPhase = let installPhase = let
dll = dll =
if isNull dllOverride if isNull dllOverride
then name then name
else dllOverride; else dllOverride;
in '' in
runHook preInstall # fsharp-analyzers requires the .NET SDK at runtime, so we use that instead of dotnet-runtime.
mkdir -p "$out/lib" ''
cp -r ./bin/* "$out/lib" runHook preInstall
makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${dll}.dll" mkdir -p "$out/lib"
runHook postInstall cp -r ./bin/* "$out/lib"
''; makeWrapper "${dotnet-sdk}/bin/dotnet" "$out/bin/${name}" --set DOTNET_HOST_PATH "${dotnet-sdk}/bin/dotnet" --add-flags "$out/lib/${dll}.dll"
runHook postInstall
'';
}; };
in { in {
packages = { packages = let
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; deps = builtins.fromJSON (builtins.readFile ./nix/deps.json);
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; in {
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") deps)).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") deps)).hash;
default = pkgs.buildDotnetModule { default = pkgs.buildDotnetModule {
inherit pname version dotnet-sdk dotnet-runtime; inherit pname version dotnet-sdk dotnet-runtime;
name = "WoofWare.Myriad.Plugins"; name = "WoofWare.Myriad.Plugins";
@@ -52,7 +56,7 @@
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj"; projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj";
testProjectFile = "./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj"; testProjectFile = "./WoofWare.Myriad.Plugins.Test/WoofWare.Myriad.Plugins.Test.fsproj";
disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"]; disabledTests = ["WoofWare.Myriad.Plugins.Test.TestSurface.CheckVersionAgainstRemote"];
nugetDeps = ./nix/deps.nix; # `nix build .#default.passthru.fetch-deps && ./result nix/deps.nix` nugetDeps = ./nix/deps.json; # `nix build .#default.fetch-deps && ./result nix/deps.json`
doCheck = true; doCheck = true;
}; };
}; };

View File

@@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "8.0.100", "version": "9.0.100",
"rollForward": "latestMajor" "rollForward": "latestMajor"
} }
} }

387
nix/deps.json Normal file
View File

@@ -0,0 +1,387 @@
[
{
"pname": "ApiSurface",
"version": "4.1.20",
"hash": "sha256-koWgO9FC9ax+Ij56ug8kxeyknl0yhLqnNLOUdxtqqo4="
},
{
"pname": "fantomas",
"version": "7.0.1",
"hash": "sha256-2aGD6Kjh83gmssRqqZ/Uihi7VbNqNUelX4otIfCuhTI="
},
{
"pname": "Fantomas.Core",
"version": "6.1.1",
"hash": "sha256-FcTLHQFvKkQY/kV08jhhy/St/+FmXpp3epp/R3zUXMA="
},
{
"pname": "Fantomas.FCS",
"version": "6.1.1",
"hash": "sha256-NuZ8msPEHYA8T3EYREB28F1RcNgUU8V54eg2+UttYxw="
},
{
"pname": "FsCheck",
"version": "3.2.0",
"hash": "sha256-ksZ4vLgWwyQOzFuK2BczdtDtWWYmedG7UBAg4pYuI8g="
},
{
"pname": "fsharp-analyzers",
"version": "0.30.0",
"hash": "sha256-7oaSwpHAU1opzpz4szLU/gDaJC/ww9eiFkPu0nr4Mj4="
},
{
"pname": "FSharp.Core",
"version": "4.3.4",
"hash": "sha256-styyo+6mJy+yxE0NZG/b1hxkAjPOnJfMgd9zWzCJ5uk="
},
{
"pname": "FSharp.Core",
"version": "6.0.1",
"hash": "sha256-Ehsgt3nCJijpaVuJguC1TPVEKSkJd6PSc07D2ZQSemI="
},
{
"pname": "FSharp.Core",
"version": "9.0.202",
"hash": "sha256-64Gub0qemmCoMa1tDus6TeTuB1+5sHfE6KD2j4o84mA="
},
{
"pname": "FsUnit",
"version": "7.0.1",
"hash": "sha256-K85CIdxMeFSHEKZk6heIXp/oFjWAn7dBILKrw49pJUY="
},
{
"pname": "Microsoft.ApplicationInsights",
"version": "2.22.0",
"hash": "sha256-mUQ63atpT00r49ca50uZu2YCiLg3yd6r3HzTryqcuEA="
},
{
"pname": "Microsoft.AspNetCore.App.Ref",
"version": "6.0.36",
"hash": "sha256-9jDkWbjw/nd8yqdzVTagCuqr6owJ/DUMi4BlUZT4hWU="
},
{
"pname": "Microsoft.AspNetCore.App.Runtime.linux-arm64",
"version": "6.0.36",
"hash": "sha256-JQULJyF0ivLoUU1JaFfK/HHg+/qzpN7V2RR2Cc+WlQ4="
},
{
"pname": "Microsoft.AspNetCore.App.Runtime.linux-x64",
"version": "6.0.36",
"hash": "sha256-zUsVIpV481vMLAXaLEEUpEMA9/f1HGOnvaQnaWdzlyY="
},
{
"pname": "Microsoft.AspNetCore.App.Runtime.osx-arm64",
"version": "6.0.36",
"hash": "sha256-2seqZcz0JeUjkzh3QcGa9TcJ4LUafpFjTRk+Nm8T6T0="
},
{
"pname": "Microsoft.AspNetCore.App.Runtime.osx-x64",
"version": "6.0.36",
"hash": "sha256-yxLafxiBKkvfkDggPk0P9YZIHBkDJOsFTO7/V9mEHuU="
},
{
"pname": "Microsoft.CodeCoverage",
"version": "17.13.0",
"hash": "sha256-GKrIxeyQo5Az1mztfQgea1kGtJwonnNOrXK/0ULfu8o="
},
{
"pname": "Microsoft.NET.Test.Sdk",
"version": "17.13.0",
"hash": "sha256-sc2wvyV8cGm1FrNP2GGHEI584RCvRPu15erYCsgw5QY="
},
{
"pname": "Microsoft.NETCore.App.Host.linux-arm64",
"version": "6.0.36",
"hash": "sha256-9lC/LYnthYhjkWWz2kkFCvlA5LJOv11jdt59SDnpdy0="
},
{
"pname": "Microsoft.NETCore.App.Host.linux-x64",
"version": "6.0.36",
"hash": "sha256-VFRDzx7LJuvI5yzKdGmw/31NYVbwHWPKQvueQt5xc10="
},
{
"pname": "Microsoft.NETCore.App.Host.osx-arm64",
"version": "6.0.36",
"hash": "sha256-DaSWwYACJGolEBuMhzDVCj/rQTdDt061xCVi+gyQnuo="
},
{
"pname": "Microsoft.NETCore.App.Host.osx-x64",
"version": "6.0.36",
"hash": "sha256-FrRny9EI6HKCKQbu6mcLj5w4ooSRrODD4Vj2ZMGnMd4="
},
{
"pname": "Microsoft.NETCore.App.Ref",
"version": "6.0.36",
"hash": "sha256-9LZgVoIFF8qNyUu8kdJrYGLutMF/cL2K82HN2ywwlx8="
},
{
"pname": "Microsoft.NETCore.App.Runtime.linux-arm64",
"version": "6.0.36",
"hash": "sha256-k3rxvUhCEU0pVH8KgEMtkPiSOibn+nBh+0zT2xIfId8="
},
{
"pname": "Microsoft.NETCore.App.Runtime.linux-x64",
"version": "6.0.36",
"hash": "sha256-U8wJ2snSDFqeAgDVLXjnniidC7Cr5aJ1/h/BMSlyu0c="
},
{
"pname": "Microsoft.NETCore.App.Runtime.osx-arm64",
"version": "6.0.36",
"hash": "sha256-UfLcrL2Gj/OLz0s92Oo+OCJeDpZFAcQLPLiSNND8D5Y="
},
{
"pname": "Microsoft.NETCore.App.Runtime.osx-x64",
"version": "6.0.36",
"hash": "sha256-0xIJYFzxdMcnCj3wzkFRQZSnQcPHzPHMzePRIOA3oJs="
},
{
"pname": "Microsoft.NETCore.Platforms",
"version": "1.1.0",
"hash": "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM="
},
{
"pname": "Microsoft.NETCore.Platforms",
"version": "1.1.1",
"hash": "sha256-8hLiUKvy/YirCWlFwzdejD2Db3DaXhHxT7GSZx/znJg="
},
{
"pname": "Microsoft.NETCore.Platforms",
"version": "2.0.0",
"hash": "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro="
},
{
"pname": "Microsoft.NETCore.Targets",
"version": "1.1.0",
"hash": "sha256-0AqQ2gMS8iNlYkrD+BxtIg7cXMnr9xZHtKAuN4bjfaQ="
},
{
"pname": "Microsoft.NETCore.Targets",
"version": "1.1.3",
"hash": "sha256-WLsf1NuUfRWyr7C7Rl9jiua9jximnVvzy6nk2D2bVRc="
},
{
"pname": "Microsoft.Testing.Extensions.Telemetry",
"version": "1.5.3",
"hash": "sha256-bIXwPSa3jkr2b6xINOqMUs6/uj/r4oVFM7xq3uVIZDU="
},
{
"pname": "Microsoft.Testing.Extensions.TrxReport.Abstractions",
"version": "1.5.3",
"hash": "sha256-IfMRfcyaIKEMRtx326ICKtinDBEfGw/Sv8ZHawJ96Yc="
},
{
"pname": "Microsoft.Testing.Extensions.VSTestBridge",
"version": "1.5.3",
"hash": "sha256-XpM/yFjhLSsuzyDV+xKubs4V1zVVYiV05E0+N4S1h0g="
},
{
"pname": "Microsoft.Testing.Platform",
"version": "1.5.3",
"hash": "sha256-y61Iih6w5D79dmrj2V675mcaeIiHoj1HSa1FRit2BLM="
},
{
"pname": "Microsoft.Testing.Platform.MSBuild",
"version": "1.5.3",
"hash": "sha256-YspvjE5Jfi587TAfsvfDVJXNrFOkx1B3y1CKV6m7YLY="
},
{
"pname": "Microsoft.TestPlatform.ObjectModel",
"version": "17.12.0",
"hash": "sha256-3XBHBSuCxggAIlHXmKNQNlPqMqwFlM952Av6RrLw1/w="
},
{
"pname": "Microsoft.TestPlatform.ObjectModel",
"version": "17.13.0",
"hash": "sha256-6S0fjfj8vA+h6dJVNwLi6oZhYDO/I/6hBZaq2VTW+Uk="
},
{
"pname": "Microsoft.TestPlatform.TestHost",
"version": "17.13.0",
"hash": "sha256-L/CJzou7dhmShUgXq3aXL3CaLTJll17Q+JY2DBdUUpo="
},
{
"pname": "Myriad.Core",
"version": "0.8.3",
"hash": "sha256-vBOxfq8QriX/yUtaXN69rEQaY/psRNJWxqATLidrt2g="
},
{
"pname": "Myriad.Sdk",
"version": "0.8.3",
"hash": "sha256-7O397WKhskKOvE3MkJT37BvxorDWngDR6gTUogtDZ2M="
},
{
"pname": "Nerdbank.GitVersioning",
"version": "3.8.38-alpha",
"hash": "sha256-gPMrVbjOZxXoofczF/pn6eVkLhjVSJIyQrLO2oljrDc="
},
{
"pname": "NETStandard.Library",
"version": "2.0.3",
"hash": "sha256-Prh2RPebz/s8AzHb2sPHg3Jl8s31inv9k+Qxd293ybo="
},
{
"pname": "Newtonsoft.Json",
"version": "13.0.1",
"hash": "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo="
},
{
"pname": "Newtonsoft.Json",
"version": "13.0.3",
"hash": "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc="
},
{
"pname": "NuGet.Common",
"version": "6.13.2",
"hash": "sha256-ASLa/Jigg5Eop0ZrXPl98RW2rxnJRC7pbbxhuV74hFw="
},
{
"pname": "NuGet.Configuration",
"version": "6.13.2",
"hash": "sha256-z8VW1YdRDanyyRTDYRvRkSv/XPR3c/hMM1y8cNNjx0Y="
},
{
"pname": "NuGet.Frameworks",
"version": "6.13.2",
"hash": "sha256-caDyc+WgYOo43AUTjtbP0MyvYDb6JweEKDdIul61Cac="
},
{
"pname": "NuGet.Packaging",
"version": "6.13.2",
"hash": "sha256-lhO+SFwIYZ4aPHxIGm5ubkkE2a5Ve2xgtroRbNh7hpw="
},
{
"pname": "NuGet.Protocol",
"version": "6.13.2",
"hash": "sha256-5lnAHHZjy7A4vgv65AeBAs64mSNpuoUjxW3HnrMpuzY="
},
{
"pname": "NuGet.Versioning",
"version": "6.13.2",
"hash": "sha256-gmpyBpKnt+GHqgx/2uFKp+J2csbxEAy1E7WdVT117sw="
},
{
"pname": "NUnit",
"version": "4.3.2",
"hash": "sha256-0RWe8uFoxYp6qhPlDDEghOMcKJgyw2ybvEoAqBLebeE="
},
{
"pname": "NUnit3TestAdapter",
"version": "5.0.0",
"hash": "sha256-7jZM4qAbIzne3AcdFfMbvbgogqpxvVe6q2S7Ls8xQy0="
},
{
"pname": "RestEase",
"version": "1.6.4",
"hash": "sha256-FFmqFwlHhIln46k56Z8KM1G+xuPEh/bceKCQnJcdcdc="
},
{
"pname": "runtime.any.System.Runtime",
"version": "4.3.0",
"hash": "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM="
},
{
"pname": "runtime.native.System",
"version": "4.3.0",
"hash": "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y="
},
{
"pname": "runtime.unix.System.Private.Uri",
"version": "4.3.0",
"hash": "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs="
},
{
"pname": "System.Collections.Immutable",
"version": "8.0.0",
"hash": "sha256-F7OVjKNwpqbUh8lTidbqJWYi476nsq9n+6k0+QVRo3w="
},
{
"pname": "System.Diagnostics.DiagnosticSource",
"version": "5.0.0",
"hash": "sha256-6mW3N6FvcdNH/pB58pl+pFSCGWgyaP4hfVtC/SMWDV4="
},
{
"pname": "System.Diagnostics.DiagnosticSource",
"version": "7.0.0",
"hash": "sha256-9Wk8cHSkjKtqkN6xW7KnXoQVtF/VNbKeBq79WqDesMs="
},
{
"pname": "System.Formats.Asn1",
"version": "6.0.0",
"hash": "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8="
},
{
"pname": "System.Formats.Asn1",
"version": "8.0.1",
"hash": "sha256-may/Wg+esmm1N14kQTG4ESMBi+GQKPp0ZrrBo/o6OXM="
},
{
"pname": "System.IO.Abstractions",
"version": "4.2.13",
"hash": "sha256-nkC/PiqE6+c1HJ2yTwg3x+qdBh844Z8n3ERWDW8k6Gg="
},
{
"pname": "System.IO.FileSystem.AccessControl",
"version": "4.5.0",
"hash": "sha256-ck44YBQ0M+2Im5dw0VjBgFD1s0XuY54cujrodjjSBL8="
},
{
"pname": "System.Memory",
"version": "4.5.5",
"hash": "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI="
},
{
"pname": "System.Private.Uri",
"version": "4.3.0",
"hash": "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM="
},
{
"pname": "System.Reflection.Metadata",
"version": "1.6.0",
"hash": "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E="
},
{
"pname": "System.Runtime",
"version": "4.3.1",
"hash": "sha256-R9T68AzS1PJJ7v6ARz9vo88pKL1dWqLOANg4pkQjkA0="
},
{
"pname": "System.Runtime.CompilerServices.Unsafe",
"version": "6.0.0",
"hash": "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I="
},
{
"pname": "System.Security.AccessControl",
"version": "4.5.0",
"hash": "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM="
},
{
"pname": "System.Security.Cryptography.Pkcs",
"version": "6.0.4",
"hash": "sha256-2e0aRybote+OR66bHaNiYpF//4fCiaO3zbR2e9GABUI="
},
{
"pname": "System.Security.Cryptography.ProtectedData",
"version": "4.4.0",
"hash": "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE="
},
{
"pname": "System.Security.Principal.Windows",
"version": "4.5.0",
"hash": "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY="
},
{
"pname": "System.Text.Json",
"version": "8.0.5",
"hash": "sha256-yKxo54w5odWT6nPruUVsaX53oPRe+gKzGvLnnxtwP68="
},
{
"pname": "TypeEquality",
"version": "0.3.0",
"hash": "sha256-V50xAOzzyUJrY+MYPRxtnqW5MVeATXCes89wPprv1r4="
},
{
"pname": "WoofWare.Whippet.Fantomas",
"version": "0.5.1",
"hash": "sha256-59CwnOZQAq5ZJoUkd87OiP8KUwx8xYDLMimMMTlKeZA="
}
]

View File

@@ -1,339 +0,0 @@
# 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.8";
hash = "sha256-iU5v4SW2lNTMYN4uVj++nxbojgDsTCSQsowqGl75wXc=";
})
(fetchNuGet {
pname = "fantomas";
version = "6.3.15";
hash = "sha256-Gjw7MxjUNckMWSfnOye4UTe5fZWnor6RHCls3PNsuG8=";
})
(fetchNuGet {
pname = "Fantomas.Core";
version = "6.1.1";
hash = "sha256-FcTLHQFvKkQY/kV08jhhy/St/+FmXpp3epp/R3zUXMA=";
})
(fetchNuGet {
pname = "Fantomas.FCS";
version = "6.1.1";
hash = "sha256-NuZ8msPEHYA8T3EYREB28F1RcNgUU8V54eg2+UttYxw=";
})
(fetchNuGet {
pname = "FsCheck";
version = "2.16.6";
hash = "sha256-1hR2SaJTkqBzU3D955MvLNVzkQHkx0Z/QzOXZfzk2Zw=";
})
(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 = "6.0.1";
hash = "sha256-Ehsgt3nCJijpaVuJguC1TPVEKSkJd6PSc07D2ZQSemI=";
})
(fetchNuGet {
pname = "FSharp.Core";
version = "8.0.401";
hash = "sha256-+tp7/Ssr5lb55ZBTOjTuuH0rLCGfhe5Yjq4jvU5KML0=";
})
(fetchNuGet {
pname = "FsUnit";
version = "6.0.1";
hash = "sha256-vka/aAgWhDCl5tu+kgO7GtSaHOOvlSaWxG+tExwGXpI=";
})
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Ref";
version = "6.0.35";
hash = "sha256-BxvIeZIaBdC0wyDQqKW0E5axSRSrtQk3oEPsT287014=";
})
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64";
version = "6.0.35";
hash = "sha256-jM/HzLumZvI939DrNb8LHnEr/in1Lws0j/FAfdXSzbk=";
})
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.linux-x64";
version = "6.0.35";
hash = "sha256-2eUqoTcqTU3ebv53IV6yvN9EhkOqnyBRd2tz74HuSsE=";
})
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64";
version = "6.0.35";
hash = "sha256-6mY2uBhvKCpEFJLYX9+f1mpYrWdN69i+14DPjO4U8eo=";
})
(fetchNuGet {
pname = "Microsoft.AspNetCore.App.Runtime.osx-x64";
version = "6.0.35";
hash = "sha256-ljEkMgkgfEeqzRnmTubjSK2dzkph0cSQ7+2J986F7HI=";
})
(fetchNuGet {
pname = "Microsoft.CodeCoverage";
version = "17.11.1";
hash = "sha256-1dLlK3NGh88PuFYZiYpT+izA96etxhU3BSgixDgdtGA=";
})
(fetchNuGet {
pname = "Microsoft.NET.Test.Sdk";
version = "17.11.1";
hash = "sha256-0JUEucQ2lzaPgkrjm/NFLBTbqU1dfhvhN3Tl3moE6mI=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.linux-arm64";
version = "6.0.35";
hash = "sha256-yrtPCYD8skaWnfIoaUdQ1dns0YrypxDocskS2WGxF6g=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.linux-x64";
version = "6.0.35";
hash = "sha256-maNzxJQ5oCd86VI4ROzl4RqOV1RNXn3qWjrAfBjr2Y0=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.osx-arm64";
version = "6.0.35";
hash = "sha256-cBcfv7tnZa2xO5T5VOx3/7EvJ5u4/C4dFnV1Jj6VFPU=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Host.osx-x64";
version = "6.0.35";
hash = "sha256-05wMp5+etiV/vgktqGo8+4XB7FNYxwCUKpJsW48tgvQ=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Ref";
version = "6.0.35";
hash = "sha256-IcpSbsSHgYBbNVvbcXfmRRM9bdx3pogLncO4RuXEab0=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.linux-arm64";
version = "6.0.35";
hash = "sha256-jPUhSrzqnH1GNi/c7dSnZSQhFNVGdmlAQkDLdXVWBBc=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.linux-x64";
version = "6.0.35";
hash = "sha256-Gf3e0EdBEgq8GcZttTHbKGupFlDyB80nhYpBN0X9Kro=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.osx-arm64";
version = "6.0.35";
hash = "sha256-IGArFhlq3UzZY93lJ+WrB+zmuu/2o8lVwT7MJKpz6DE=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.App.Runtime.osx-x64";
version = "6.0.35";
hash = "sha256-EtFBg8yBNhAEQlL97oVGiu05rPMSKLd0wE44zTBT7FI=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "1.1.0";
hash = "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "1.1.1";
hash = "sha256-8hLiUKvy/YirCWlFwzdejD2Db3DaXhHxT7GSZx/znJg=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Platforms";
version = "2.0.0";
hash = "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro=";
})
(fetchNuGet {
pname = "Microsoft.NETCore.Targets";
version = "1.1.3";
hash = "sha256-WLsf1NuUfRWyr7C7Rl9jiua9jximnVvzy6nk2D2bVRc=";
})
(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 = "Myriad.Core";
version = "0.8.3";
hash = "sha256-vBOxfq8QriX/yUtaXN69rEQaY/psRNJWxqATLidrt2g=";
})
(fetchNuGet {
pname = "Myriad.Sdk";
version = "0.8.3";
hash = "sha256-7O397WKhskKOvE3MkJT37BvxorDWngDR6gTUogtDZ2M=";
})
(fetchNuGet {
pname = "Nerdbank.GitVersioning";
version = "3.6.146";
hash = "sha256-6lpjiwxVrwjNUhPQ6C7LzazKdBQlAbmyEQk/qxrmr8Y=";
})
(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.1";
hash = "sha256-UyZtDyTuymC+sKSX+ripOI6MmJZn11loVapVs4uzaGo=";
})
(fetchNuGet {
pname = "NuGet.Configuration";
version = "6.11.1";
hash = "sha256-JH2UCpjYg8pkqxQ4j4BrWiTKhGzgfn55NMr32wf6+FQ=";
})
(fetchNuGet {
pname = "NuGet.Frameworks";
version = "6.11.1";
hash = "sha256-p25Oa7wJjwF+2puIhBkZZkKSuk4jGq7xikYSCdfp9Vc=";
})
(fetchNuGet {
pname = "NuGet.Packaging";
version = "6.11.1";
hash = "sha256-1yY3p5hQwbUgYCyHnBcuGWiiIib1ppPYt2ntxwXSJW0=";
})
(fetchNuGet {
pname = "NuGet.Protocol";
version = "6.11.1";
hash = "sha256-/zFvBV83Q5oMNu68BjmrHtZMAxf/YkDJV8HSsl5GjsY=";
})
(fetchNuGet {
pname = "NuGet.Versioning";
version = "6.11.1";
hash = "sha256-fl8lyChMjV7Sp8keAP7CdXZh7ARN/mU39T3gG74jDWY=";
})
(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 = "RestEase";
version = "1.6.4";
hash = "sha256-FFmqFwlHhIln46k56Z8KM1G+xuPEh/bceKCQnJcdcdc=";
})
(fetchNuGet {
pname = "runtime.any.System.Runtime";
version = "4.3.0";
hash = "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM=";
})
(fetchNuGet {
pname = "runtime.native.System";
version = "4.3.0";
hash = "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y=";
})
(fetchNuGet {
pname = "runtime.unix.System.Private.Uri";
version = "4.3.0";
hash = "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs=";
})
(fetchNuGet {
pname = "System.Diagnostics.DiagnosticSource";
version = "7.0.0";
hash = "sha256-9Wk8cHSkjKtqkN6xW7KnXoQVtF/VNbKeBq79WqDesMs=";
})
(fetchNuGet {
pname = "System.Formats.Asn1";
version = "6.0.0";
hash = "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8=";
})
(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.5";
hash = "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI=";
})
(fetchNuGet {
pname = "System.Private.Uri";
version = "4.3.0";
hash = "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM=";
})
(fetchNuGet {
pname = "System.Reflection.Metadata";
version = "1.6.0";
hash = "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E=";
})
(fetchNuGet {
pname = "System.Runtime";
version = "4.3.1";
hash = "sha256-R9T68AzS1PJJ7v6ARz9vo88pKL1dWqLOANg4pkQjkA0=";
})
(fetchNuGet {
pname = "System.Runtime.CompilerServices.Unsafe";
version = "6.0.0";
hash = "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I=";
})
(fetchNuGet {
pname = "System.Security.AccessControl";
version = "4.5.0";
hash = "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM=";
})
(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.Principal.Windows";
version = "4.5.0";
hash = "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY=";
})
(fetchNuGet {
pname = "System.Text.Encodings.Web";
version = "7.0.0";
hash = "sha256-tF8qt9GZh/nPy0mEnj6nKLG4Lldpoi/D8xM5lv2CoYQ=";
})
(fetchNuGet {
pname = "System.Text.Json";
version = "7.0.3";
hash = "sha256-aSJZ17MjqaZNQkprfxm/09LaCoFtpdWmqU9BTROzWX4=";
})
(fetchNuGet {
pname = "TypeEquality";
version = "0.3.0";
hash = "sha256-V50xAOzzyUJrY+MYPRxtnqW5MVeATXCes89wPprv1r4=";
})
(fetchNuGet {
pname = "WoofWare.Whippet.Fantomas";
version = "0.3.1";
hash = "sha256-i5oiqcrxzM90Ocuq5MIu2Ha5lV0aYu5nCvuwmFqp6NA=";
})
]