Files
WoofWare.Myriad/WoofWare.Myriad.Plugins/RemoveOptionsGenerator.fs
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

178 lines
6.1 KiB
Forth

namespace WoofWare.Myriad.Plugins
open System
open Fantomas.FCS.Syntax
open Fantomas.FCS.Xml
open WoofWare.Whippet.Fantomas
[<RequireQualifiedAccess>]
module internal RemoveOptionsGenerator =
open Fantomas.FCS.Text.Range
let private removeOption (s : SynField) : SynField =
let (SynField.SynField (synAttributeLists,
isStatic,
identOption,
fieldType,
isMutable,
preXmlDoc,
synAccessOption,
range,
trivia)) =
s
let newType =
match fieldType with
| OptionType innerType -> innerType
| _ -> fieldType
SynField.SynField (
synAttributeLists,
isStatic,
identOption,
newType,
isMutable,
preXmlDoc,
synAccessOption,
range,
trivia
)
let createType
(xmlDoc : PreXmlDoc option)
(accessibility : SynAccess option)
(generics : SynTyparDecls option)
(fields : SynField list)
: SynModuleDecl
=
let fields : SynField list = fields |> List.map removeOption
let name = Ident.create "Short"
let record =
{
Name = name
Fields = fields
Members = None
XmlDoc = xmlDoc
Generics = generics
TypeAccessibility = accessibility
ImplAccessibility = None
Attributes = []
}
let typeDecl = RecordType.ToAst record
SynModuleDecl.Types ([ typeDecl ], range0)
let createMaker (withOptionsType : LongIdent) (withoutOptionsType : Ident) (fields : SynFieldData<Ident> list) =
let xmlDoc = PreXmlDoc.create "Remove the optional members of the input."
let inputArg = Ident.create "input"
let functionName = Ident.create "shorten"
let body =
fields
|> List.map (fun fieldData ->
let accessor =
SynExpr.LongIdent (
false,
SynLongIdent ([ inputArg ; fieldData.Ident ], [ range0 ], []),
None,
range0
)
let body =
match fieldData.Type with
| OptionType _ ->
accessor
|> SynExpr.pipeThroughFunction (
SynExpr.applyFunction
(SynExpr.createLongIdent [ "Option" ; "defaultWith" ])
(SynExpr.createLongIdent' (
[ withoutOptionsType ]
@ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ]
))
)
| _ -> accessor
SynLongIdent.createI fieldData.Ident, body
)
|> SynExpr.createRecord None
SynBinding.basic
[ functionName ]
[
SynPat.named inputArg.idText
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.createI withoutOptionsType))
]
body
|> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation (SynType.LongIdent (SynLongIdent.create withOptionsType))
|> SynModuleDecl.createLet
let createRecordModule (namespaceId : LongIdent) (typeDefn : RecordType) =
let fieldData = typeDefn.Fields |> List.map SynField.extractWithIdent
let decls =
[
createType typeDefn.XmlDoc typeDefn.TypeAccessibility typeDefn.Generics typeDefn.Fields
createMaker [ Ident.create "Short" ] typeDefn.Name fieldData
]
let xmlDoc =
sprintf "Module containing an option-truncated version of the %s type" typeDefn.Name.idText
|> PreXmlDoc.create
let info =
SynComponentInfo.create typeDefn.Name
|> SynComponentInfo.withDocString xmlDoc
|> SynComponentInfo.addAttributes [ SynAttribute.compilationRepresentation ]
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
SynModuleDecl.nestedModule info decls
|> List.singleton
|> SynModuleOrNamespace.createNamespace namespaceId
open Myriad.Core
/// Myriad generator that stamps out a record with option types stripped
/// from the fields at the top level.
[<MyriadGenerator("remove-options")>]
type RemoveOptionsGenerator () =
interface IMyriadGenerator with
member _.ValidInputExtensions = [ ".fs" ]
member _.Generate (context : GeneratorContext) =
let ast, _ =
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
let records = Ast.getRecords ast
let namespaceAndRecords =
records
|> List.collect (fun (ns, ty) ->
ty
|> List.filter (fun record ->
record.Attributes
|> List.exists (fun attr ->
attr.TypeName.LongIdent
|> List.last
|> _.idText
|> fun s ->
if s.EndsWith ("Attribute", StringComparison.Ordinal) then
s
else
$"%s{s}Attribute"
|> (=) typeof<RemoveOptionsAttribute>.Name
)
)
|> List.map (fun ty -> ns, ty)
)
let modules =
namespaceAndRecords
|> List.map (fun (ns, record) -> RemoveOptionsGenerator.createRecordModule ns record)
Output.Ast modules