Giter Site home page Giter Site logo

myriad's Introduction

Myriad

Myriad is a code generator. It takes input from files or data sources and the library provides different mechanisms to allow F# code to be produced in response to the file, whether that file be an F# source file or a simple text file.

Myriad can be used from either an MSBuild extension or from its CLI tool.

The idea behind Myriad is to un-complicate, as far as possible, the ability to do meta-programming in F#. By meta-programming in F# I mean generating idiomatic F# code using F# native types like discriminated unions and records, this is something that is not possible with F# Type Providers etc. which just output basic .NET classes.

Myriad is an evolution of the ideas I developed while working with F#'s type providers and other meta-programming functionality like quotations and AST manipulation. Myriad aims to make it easy to extend the compiler via Myriad plugins. Myriad provides an approach to compiler extension that isn't modifying or adjusting Type Providers or waiting a long time for other F# language improvements. You write a Myriad plugin that works on a fragment of AST input, and the plugin supplies AST output with the final form being source code that is built into your project. This lets the compiler optimise generated output in addition to allowing tooling to operate effectively.

If you want to help and contribute code than thats great check out the issues and make a PR.

If you enjoy this repo and wanted to shown your appriciation etc then I do have Ko-fi:

ko-fi

Usage via MSBuild

To use Myriad via its MSBuild support you add the Myriad.Core and Myriad.Sdk package references:

    <ItemGroup>
      <PackageReference Include="Myriad.Core" Version="0.5.0" />
      <PackageReference Include="Myriad.Sdk" Version="0.5.0" />
    </ItemGroup>

An input file is specified by using the usual Compile element:

<Compile Include="Library.fs"/>
<Compile Include="Generated.fs">
    <MyriadFile>Library.fs</MyriadFile>
</Compile>

This is configuring Myriad so that a file called Generated.fs will be included in the build using Library.fs as input to the Myriad.

It is also possible to append the generated content to the input file.

<Compile Include="Library.fs">
    <MyriadInlineGeneration>true</MyriadInlineGeneration>
</Compile>

Myriad works by using plugins to generate code. A plugin called fields is included with Myriad which takes inspiration from OCaml's ppx_fields_conv plugin of the same name.

The input file in this example Library.fs looks like this:

namespace Example
open Myriad.Plugins

[<Generator.Fields "fields">]
type Test1 = { one: int; two: string; three: float; four: float32 }
type Test2 = { one: Test1; two: string }

Attribute's are use so that the code generator knows which parts of the input AST are to be processed by the plugin. If you had several records and you only want the fields plugin to operate on Test1 then the attribute would be used like in the example to only apply Generator.Fields to Test1. Note, if you wanted a plugin that just needs the whole input AST then there is no need to provide an input. Myriad aims to be a library rather than a full framework that ties you to the mechanism used to input and generate code. The parameter passed to the attribute "fields" specifies the configuration section that is used for the plugin in the myriad.toml file. In this instance fields is used and the myriad.toml file is as follows:

[fields]
namespace = "TestFields"

This specifies the namespace that is used for the plugin, which in this case is "TestFields".

The fields plugin in this example will generate the following code at pre-build time and compile the code into your assembly:

//------------------------------------------------------------------------------
//        This code was generated by myriad.
//        Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace rec TestFields

module Test1 =
    open Example

    let one (x : Test1) = x.one
    let two (x : Test1) = x.two
    let three (x : Test1) = x.three
    let four (x : Test1) = x.four

    let create (one : int) (two : string) (three : float) (four : float32) : Test1 =
        { one = one
          two = two
          three = three
          four = four }

    let map (mapone : int -> int) (maptwo : string -> string) (mapthree : float -> float) (mapfour : float32 -> float32) (record': Test1) =
      { record' with
          one = mapone record'.one
          two = maptwo record'.two
          three = mapthree record'.three
          four = mapfour record'.four }

The fields plugin generates a map for each field in the input record, a create function taking each field, and a map function that takes one function per field in the input record.

The map functions for each field are useful in situations where you just want to use a single field from a record in a lambda like a list of records:

let records = [{one = "a"; two = "aa"; three = 42.0; four = 172.0f}
               {one = "b"; two = "bb"; three = 42.0; four = 172.0f}]
 records |> List.sortBy Test1.one

Lens plugin

Myriad can also generate lenses for records and single-case discriminated unions. Lens is a pair of a getter and a setter for one property of the type. Given the object Lens allows you to get the value of the property or to update it, creating a new object. The advantage of lenses is an ability to combine them to read or update nested fields of the object.

To create lenses for your type, first annotate the type for which you want lenses to be generated with Generator.Lenses attribute:

[<Generator.Lenses("lens")>]
type Record =
    { one: int
      two: string }

Myriad will generate the following code:

module RecordLenses =
    let one = (fun (x: Test1) -> x.one), (fun (x: Test1) (value: int) -> { x with one = value })
    let two = (fun (x: Test1) -> x.two), (fun (x: Test1) (value: string) -> { x with two = value })

Often lenses are defined as a single-case union around a pair of getter and setter. Myriad is also capable of adding the invocation of such DU's constructor.

To achieve this, decorate your type with the Lens attribute, specifying the name of the DU constructor: [<Generator.Lenses("Lens")>], and Myriad will generate this code:

module RecordLenses =
    let one = Lens((fun (x: Test1) -> x.one), (fun (x: Test1) (value: int) -> { x with one = value }))
    let two = Lens((fun (x: Test1) -> x.two), (fun (x: Test1) (value: string) -> { x with two = value }))

You can provide the name of DU constructor in several ways:

  • As a string: [<Generator.Lenses("lens", "Lens")>];
  • Or as a type: [<Generator.Lenses("lens", typedefof<Lens<_, _>>)>] or [<Generator.Lenses(typeof<Lens<_, _>>)>].

If the Lens type is in different namespace/module than the type decorated with the attribute, provide the full name of the Lens constructor: [<Generator.Lenses("Namespace.And.Module.Of.Lens")>].


The full fsproj is detail below:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <Compile Include="Library.fs" />
        <Compile Include="Generated.fs">
            <MyriadFile>Library.fs</MyriadFile>
        </Compile>
    </ItemGroup>
    <ItemGroup>
      <PackageReference Include="Myriad.Core" Version="0.5.0" />
      <PackageReference Include="Myriad.Sdk" Version="0.5.0" />
    </ItemGroup>
</Project>

Plugins

Plugins for Myriad are supplied by including the nuget package in your project. The nuget infrastructure supplies the necessary MSBuild props and targets so that the plugin is used by Myriad automatically. Following the source for the fields plugin can be used as reference until more details about authoring plugins is created.

Naming of plugins

If you make a plugin the an informal naming convention is to use is: {{OwnerNamespace}}.Myriad.Plugin

Using external Plugins

To consume external plugins that aren't included in the Myriad.Plugins package, you must register them with Myriad. If you are using the CLI tool then the way to do this is by passing in the --plugin <path to dll> command-line argument. If you are using MSBuild then this can be done by adding to the MyriadSdkGenerator property to your project file:

<ItemGroup>
    <MyriadSdkGenerator Include="<path to plugin dll>" />
</ItemGroup>

For example, if you had a project layout like this:

\src
-\GeneratorLib
 - Generator.fs
 - Generator.fsproj
-\GeneratorTests
 - Tests.fs
 - GeneratorTests.fsproj

You would add the following to Generator.fsproj:

  <ItemGroup>
    <Content Include="build\Generator.props">
      <Pack>true</Pack>
      <PackagePath>%(Identity)</PackagePath>
      <Visible>true</Visible>
    </Content>
  </ItemGroup>

Then add a new folder build with the Generator.props file within:

<Project>
    <ItemGroup>
        <MyriadSdkGenerator Include="$(MSBuildThisFileDirectory)/../lib/netstandard2.1/Generator.dll" />
    </ItemGroup>
</Project>

Often an additional props file (In this sample the file would be Generator.InTest.props) is used to make testing easier. The matching element for the tests .fsproj would be something like this:

<Project>
    <ItemGroup>
        <MyriadSdkGenerator Include="$(MSBuildThisFileDirectory)/../bin/$(Configuration)/netstandard2.1/Generator.dll" />
    </ItemGroup>
</Project>

Notice the Include path is pointing locally rather than within the packaged nuget folder structure.

In your testing fsproj you would add the following to allow the plugin to be used locally rather that having to consume a nuget package:

<!-- include plugin -->
<Import Project="<Path to Generator plugin location>\build\Myriad.Plugins.InTest.props" />

Debugging

To debug Myriad, you can use the following two command line options:

  • --verbose โ€” write diagnostic logs out to standard out
  • --wait-for-debugger โ€” causes Myriad to wait for a debugger to attach to the Myriad process

These can be triggered from MSBuild by the <MyriadSdkVerboseOutput>true</MyriadSdkVerboseOutput> and <MyriadSdkWaitForDebugger>true</MyriadSdkWaitForDebugger> properties, respectively.

Nuget

The nuget package for Myriad can be found here: Nuget package.

Dotnet template

A dotnet template for a Myriad plugin/generator is available here:

#install dotnet template
dotnet new -i Myriad.Templates

#create myriad generator from the template
dotnet new myriadgenerator -n myMyriadPlugin

How to build and test

  1. Make sure you have .Net Core SDK installed - check required version in global.json
  2. Run dotnet tool restore
  3. Run dotnet build -c Release -t:Build

How to release new version

  1. Update CHANGELOG.md by adding new entry (## [0.X.X]) and commit it.
  2. Create version tag (git tag v0.X.X)
  3. Update the VersionPrefix in Directory.Build.props to match the tag above.
  4. Run dotnet build -t:Pack to create the nuget package and test/examine it locally.
  5. Push the tag to the repo git push origin v0.X.X - this will start CI process that will create GitHub release and put generated NuGet packages in it
  6. Upload generated packages into NuGet.org

Also see

External plugins

Here is a list of external plugins that have been built

SqlHyra JsonWrapper TypeSafeInternals

myriad's People

Contributors

7sharp9 avatar alexeyraga avatar auduchinok avatar baronfel avatar brettrowberry avatar enricosada avatar fornever avatar jaggerjo avatar krzysztof-cieslak avatar lucasteles avatar matthewcrews avatar mlaily avatar nickdarvey avatar nicoviii avatar smaug123 avatar smoothdeveloper avatar theangrybyrd avatar thecentury avatar zaymonfc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

myriad's Issues

Using reflection in plugin causes error

Thank you for this library.

I am successfully generating code using a plugin. As soon as I add

            let t =
                Assembly.GetAssembly(typeof<Pulumi.Azure.Config>)

or a typeof<T> in a plugin file, I get the following error:

ERROR: inputfile Pulumi.Azure, Version=3.11.0.0, Culture=neutral, PublicKeyToken=null doesn not exist

Is there anything I am missing or is it not supported?

EDIT: Same happens using a type provider (E.G. FSharp.Data.JsonProvider)

Thank you

Plugin loading third party dependencies

When trying to load information from a third party dependency in a plugin, I'm getting the error:

EXEC : error : inputfile Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed doesn not exist

How do you think we should go about finding the place to load these 3rd party dependencies?

Latest version does not show call stack for exceptions

I have recently upgraded from 0.2.8 to 0.4.0.

I used to get the full stack trace in the logs on exceptions, now, even with --verbose, I only get the error message.

I also tried to attach the debugger and didn't hit the exception (but that may be an issue with JetBrains Rider, I need to investigate)

Thank you for this library.

How to use this goodness from my project?

I am looking around the repo and I not entirely sure how to use this in my project.

I see that Myriad.Sdk is available as a nuget package which I I can install and add to my project's (.fsproj) file, along with that I give it the input file that contains the type definitions and the path of the output file where the generated code will be located.

However, what confuses me is where do I write the code that converts the input file and generates the output file?

Inaccuracy in README.md

Hi. Maybe is there an error in the code?

instead of
csharp create (one : Test1) (two : string) (three : float) (four : float32) : Test1
should be
csharp create (one : int) (two : string) (three : float) (four : float32) : Test1

Allow control of Lens generator style to match Aether style

Currently, myriad produces lens setter with signature 'b -> 'a -> 'b. Aether provides a bunch of utilities for working with Lenses, but does not actually create the Lenses. It assumes setters have the signature 'a -> 'b -> 'b.
I would be nice if I could use myriad to generate Lenses which can be used by Aether.
Maybe an additional attribute to indicate the lens style?

Namespace repeating in Generated.fs

The Generated.fs file seems to create a namespace for each plugin, even if the plugin has not run.

//------------------------------------------------------------------------------
//        This code was generated by myriad.
//        Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------
namespace rec DataSchema


namespace rec DataSchema


namespace rec DataSchema

{{ My generated code }}

Is this intentional?

Myriad.Plugin.Template

Discussed in https://github.com/MoiraeSoftware/myriad/discussions/117

Originally posted by JordanMarr August 27, 2021
I think that one of the biggest hurdles to Myriad development is just getting started.

A dotnet template could go a long way in making it super easy for interested developers to start tinkering immediately without having to get their projects wired up properly. Ideally, it would provide a project for their plugin with a really basic plugin implementation that they can modify, and a test project that allows them to tinker with it out of the box without having to wire anything up.

Something like this:

dotnet new -i Myriad.Plugin.Template
dotnet new Myriad -o Templatron.Plugin

Creates:

  • Templatron.sln
  • Templatron.Plugin.fsproj
  • Templatron.Plugin.Tests.fsproj

Even better if the plugin project is already NuGet ready.

RFC 001 - Design Proposal for plugin config

I propose that myriad adds a configuration system where the Generator attribute takes either a location of a myriad-config.toml file or in-line configuration. Either way the key/value pairs will be passed to the plugin along with the input AST.

This will mean that the current namespace parameter will move to the configuration, no changes will have to be made to the CLI tool apart from depreciating the namespace parameter. This will simply the fsproj changes needed and add flexibility to the plugins to define their own key value pairs

Feature: propagate options to the plugin context?

It would awesome to have the ability to get configure options / parameters for the generation, i.e.

<Compile Include="Generated.fs">
     <MyriadOptions>
        <LowerCaseFunctions>true</LowerCaseFunctions>
        <ServerEndpoint>http://localhost:5000</ServerEndpoint>
     </MyriadOptions>
     <MyriadFile>Library.fs</MyriadFile>
     <MyriadNameSpace>Test</MyriadNameSpace>
 </Compile>

There parameters would then be available from the plugin context during code generation, even starting with Map<string, string> would be tremendously helpful.

Workaround

I guess you could specify the options from the MyriadFile and read them from the plugin

Plugin naming convention

I'm assuming you don't want to have every plugin written for Myriad under this repository. What naming convention do you think Myriad should recommend to naming of packages? Something like {{OwnerNamespace}}.Myriad.Plugin.{{PluginName}}? This would give people the ability to search for these relatively quickly on nuget but it would be (somewhat) clear it's not coming from Myriad directly.

Getting value from Literal/Const

Let's say I have the following code in my Types.fs file.

module A = 
    let [<Literal>] MyConst = "Hello"
    type MyAttribute(thing : string) =
        inherit System.Attribute()
        let _thing = thing
    type Thing = {
        [<MyAttribute(MyConst)>]
        Foo : string
    }

When looking at the AST of this code, the attributes for the field Foo:

{ Attributes =
   [{ TypeName =
                LongIdentWithDots
                  ([MyAttribute],
                   [])
      ArgExpr =
               Paren
                 (Ident MyConst,
                  tmp.fsx (8,25--8,26) IsSynthetic=false,
                  Some
                    tmp.fsx (8,33--8,34) IsSynthetic=false,
                  tmp.fsx (8,25--8,34) IsSynthetic=false)
      Target = None
      AppliesToGetterAndSetter =
                                false
      Range =
             tmp.fsx (8,14--8,25) IsSynthetic=false }]
   Range =
          tmp.fsx (8,12--8,36) IsSynthetic=false }

I get told that the data in the Attribute is MyConst. Do you know if there is a way I'd be able to get the value from that?

Generate multiple files

Is there a way to generate multiple files? If not, can you please consider adding this feature?

In my project I'm using Myriad to generate a bunch of computational expression builders from a JSON containing cloud resources (using Pulumi).

This ends up generating a 120000 lines file. It gets quite ugly for the IDE to process that single file.

Thank you.

Removing redundant parens Lenses attribute generates incorrect code

When removing the extra parens in the attribute:

[<Generator.Lenses ("lens")>]
type RecordWithEmptyWrapperName =
{ one_empty_wrapper_name: int }

The following code is produced:

namespace rec globalmodule LensesGeneratorFailure =
    let (!CompilationError) =
        "Unsupported syntax of specifying the wrapper name for type [RecordWithEmptyWrapperName].
Expr: Const
  (String
     (\"lens\",
      C:\Developer\solutions\myriad\test\Myriad.IntegrationPluginTests\Input.fs (14,19--14,25) IsSynthetic=false),
   C:\Developer\solutions\myriad\test\Myriad.IntegrationPluginTests\Input.fs (14,19--14,25) IsSynthetic=false)"

The namespace 'Plugins' is not defined (building sample project in repo)

Hi! I'm looking to try out Myriad in a project, and currently the sample project in the repo + instructions on how to use it both produce build errors due to the missing namespace Plugins.

Steps to reproduce

cd myriad
dotnet tool restore
dotnet fake build
cd samples/Example
dotnet build

Expected Behavior

Project builds successfully

Resulting Behavior

C:\Users\dthorpe\code\myriad\samples\Example\Library.fs(4,3): error FS0039: The namespace or module 'Generator' is not defined. [C:\Users\dthorpe\code\myriad\samples\Example\Example.fsproj]

Build FAILED.

C:\Users\dthorpe\code\myriad\samples\Example\Library.fs(2,13): error FS0039: The namespace 'Plugins' is not defined. [C:\Users\dthorpe\code\myriad\samples\Example\Example.fsproj]
C:\Users\dthorpe\code\myriad\samples\Example\Library.fs(4,3): error FS0039: The namespace or module 'Generator' is not defined. [C:\Users\dthorpe\code\myriad\samples\Example\Example.fsproj]
    0 Warning(s)
    2 Error(s)

Support for generic types

Using Myriad I noticed that when the records have a generic type parameter the generated code does not include the type parameter, so it fails to compile.

Input code:

[<Generator.Fields "fields">]
[<Generator.Lenses("lenses")>]
type InputType<'T> = {
    Field1: int
    Field2: 'T
}

Generated:

module InputTypeLenses =
    open Myr
    let Field1 =
        (fun (x: InputType) -> x.Field1), (fun (x: InputType) (value: int) -> { x with Field1 = value })

    let Field2 =
        (fun (x: InputType) -> x.Field2), (fun (x: InputType) (value: 'T) -> { x with Field2 = value })

module InputType =
    open Myr
    let Field1 (x: InputType) = x.Field1
    let Field2 (x: InputType) = x.Field2
    let create (field1: int) (field2: 'T): InputType = { Field1 = field1; Field2 = field2 }
    let map (mapField1: int -> int) (mapField2: 'T -> 'T) (record': InputType) =
        { record' with
              Field1 = mapField1 record'.Field1
              Field2 = mapField2 record'.Field2 }

Am I missing something or is this feature missing?

Would it be possible to make Myriad a dotnet tool?

I recently thought about this, because with Myriad I'm adding some dependencies to my projects which I don't really need for runtime, only for buildtime. This is something a "dotnet tool" is there for in my mind. E.g. in most of my projects I have "paket" as a development dependency but not runtime dependency and it is a dotnet tool too.

Do you think it would be possible to make myriad a dotnet tool too? Are there reasons to avoid doing that? What do you think?

Update the NuGet package

Hi @7sharp9!

Could you please update the NuGet package so that it now targets the netstandard2.0?
This would allow me to use the myriad in my .net48 project.

Question about packaging of Myriad dlls

When a user installs a Myriad plugin, my understanding is that they need to have "Myriad.Core.dll" and "Myriad.Sdk.dll" installed into their project for the plugin to work (please correct me if I am wrong).

I'm wondering if it is possible to pull down those dependencies as "dev" dependencies only so that they are not included in the release. I think this is possible with Paket, but not with regular NuGet. (Maybe this isn't so much of a Myriad question, but I thought I'd ask anyway).

Current version not on nuget

This is not an issue with Myriad itself but with its deployment.

As far as I can see the Changelog was not updated and therefore the automatic release tried to release the 0.3.1 (tag) as 0.2.8 (changelog) which already existed and was therefore not accepted by nuget.

It would be cool if someone could fix that and release the current version also on nuget.

Lens generator: implement prisms for multi case discriminated unions

The way Aether deals with this is to assume the following optics are defined

type MyUnion =
    | First of int
    | Second of string

    (* Prism<MyUnion,int> *)
    static member First_ =
        (fun m ->
            match m with 
            | First i -> Some i
            | _ -> None),
        (fun i m ->
            match m with
            | First _ -> First i
            | m -> m)

If Myriad could generate these automatically for me, along with #103, then I think it completes support for Aether.

Have a way to exclude certain plugins from running on certain files (in proj files)

e.g.

    <Compile Include="Generated.fs">
      <MyriadFile>Input.fs</MyriadFile> 
      <MyriadNameSpace>Test</MyriadNameSpace>
      <MyriadExcludePlugins>lenses</MyriadExcludePlugins >
    </Compile>

or maybe:

    <Compile Include="Generated.fs">
      <MyriadFile>myRecords.toml</MyriadFile> 
      <MyriadNameSpace>Test</MyriadNameSpace>
      <MyriadOnlyIncludePlugins>toml</MyriadOnlyIncludePlugins >
    </Compile>
Thoughts?

@baronfel , @Krzysztof-Cieslak , @TheAngryByrd 

Plugin activation

I think that the way I am activating my "ssdt" Myriad plugin for SqlHydra is a little different from your examples.
For example, you usually activate your plugin by marking an F# object with an attribute (i.e. [<Generator.DuCases>]).

But in the case of SqlHydra "ssdt" plugin, my source <MyriadFile> is a .dacpac file.
So far this has worked fine because I only have one plugin in SqlHydra.dll.
The issue is that, currently, my plugin will only work if it is the only plugin.

Last night I had some problems when I started creating a second plugin.
For starters, the new plugin doesn't even require an input file at all. Really just needs to get some stuff out of the .toml config and then run on build. But there is no workflow currently to handle this kind of plugin since the <MyriadFile> usually points an fs file containing an attribute that will activate a named plugin. In my scenario, I had two plugins, one that points to a .dacpac file, and another that doesn't need an input file at all, and Myriad seemed to be just using the first plugin it could find.
(I was able to comment one out which would then allow me to use the other).

So I'm thinking that perhaps both my plugin workflows could be accommodated with an additions to the MSBuild configuration.

Plugin Activation: non-fsharp MyriadFile

This style of plugin relies on a non-fsharp file (i.e. dacpac), and so it needs a way to specify the name of the plugin to run from the MSBuild config. Maybe something like this:

    <ItemGroup>
         <!-- Specify the .fs output file (to be generated by Myriad) -->
        <Compile Include="AdventureWorks.fs">
            <!-- Specify the .dacpac input  file -->
            <MyriadFile>../AdventureWorks/bin/Debug/AdventureWorks.dacpac</MyriadFile>
            <MyriadPlugin>ssdt<MyriadPlugin>
        </Compile>
    </ItemGroup>

Plugin Activation: no MyriadFile

This style of plugin can get all the input information it needs via a toml config section; it does not need an input MyriadFile at all.
Maybe this case would just need:

    <ItemGroup>
         <!-- Specify the .fs output file (to be generated by Myriad) -->
        <Compile Include="Generated.fs">
            <!-- No input file needed - just specify the plugin only -->
            <MyriadPlugin>newplugin<MyriadPlugin>
        </Compile>
    </ItemGroup>

DU with RequireQualifiedAccess attribute not being qualified

When using the DU Generation plugin, the [<RequireQualifiedAccess>] attribute on DUs is not being honored in the outputted code.

Example DU

[<RequireQualifiedAccess; Generator.DuCases "ducases">]
type MyNewDU =
    | A
    | B

Generates the following

module MyNewDU =
    open Test.Domain
    let toString (x: MyNewDU) =
        match x with
        | A -> "A"
        | B -> "B"

    let fromString (x: string) =
        match x with
        | "A" -> Some A
        | "B" -> Some B
        | _ -> None

    let toTag (x: MyNewDU) =
        match x with
        | A -> 0
        | B -> 1

    let isA (x: MyNewDU) =
        match x with
        | A -> true
        | _ -> false

    let isB (x: MyNewDU) =
        match x with
        | B -> true
        | _ -> false

But I believe should generate

module MyNewDU =
    open Test.Domain
    let toString (x: MyNewDU) =
        match x with
        | MyNewDU.A -> "A"
        | MyNewDU.B -> "B"

    let fromString (x: string) =
        match x with
        | "A" -> Some MyNewDU.A
        | "B" -> Some MyNewDU.B
        | _ -> None

    let toTag (x: MyNewDU) =
        match x with
        | MyNewDU.A -> 0
        | MyNewDU.B -> 1

    let isA (x: MyNewDU) =
        match x with
        | MyNewDU.A -> true
        | _ -> false

    let isB (x: MyNewDU) =
        match x with
        | MyNewDU.B -> true
        | _ -> false

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.