moiraesoftware / myriad Goto Github PK
View Code? Open in Web Editor NEWMyriad is a code generator for F#
Home Page: https://moiraesoftware.github.io/myriad/
License: Apache License 2.0
Myriad is a code generator for F#
Home Page: https://moiraesoftware.github.io/myriad/
License: Apache License 2.0
How can we do this?
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
This must be easy to do?
Let's say I wanted to generate a bunch of types defined in a json schema, how would I add "and" between the types to make sure they are all available?
The project I'm working on is builder generation for pulumi: https://github.com/mastoj/Pulumi.FSharp.Azure/tree/k8sversion
Where we need to generate types from: https://raw.githubusercontent.com/pulumi/pulumi-kubernetes/master/provider/cmd/pulumi-resource-kubernetes/schema.json
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).
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
Either PortaCode, or run on nuget restore are potentials.
Also we could type check the generated code as a debugging aid, not sure this is needed as pre-build step generates the code for the IDE to show errors.
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?
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.
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.
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?
Currently this can only be done at CLI so it limits the myriad.toml to the default location, currentdir + myriad.toml
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.
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?
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?
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:
Even better if the plugin project is already NuGet ready.
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?
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.
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>
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>
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.
When removing the extra parens in the attribute:
myriad/test/Myriad.IntegrationPluginTests/Input.fs
Lines 14 to 16 in 6d23793
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)"
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
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
.
cd myriad
dotnet tool restore
dotnet fake build
cd samples/Example
dotnet build
Project builds successfully
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)
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.
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?
There was a reported issue on Twitter where 127,000 types were being generated and it was taking 8 hours. Not necessarily a Myriad issue but it might be worth profiling the plugins to see where the hot areas might be if we start to generate a lot of types.
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
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.
I guess you could specify the options from the MyriadFile
and read them from the plugin
Any ideas @enricosada ?
Im sure we had something like this in Falanx?
This will cause Myriad to re-gen is the config is modified.
Hello,
I saw Krzysztof tweet about the "new" documentation for Myriad but I didn't find the link in the README or repo description.
It would be nice to add it somewhere :)
Currently the formatting is fixed via a Fantomas default, allow this to be specified either in config or a config file somewhere.
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
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?
Add the new bits to the docs...
Hello,
I'm working on plugin that heavily relies on abstract classes generation. There is blocking issue in the latest Fantomas release (3.3) resolved in fsprojects/fantomas#743 (and I hope in the latest Fantomas alpha).
Could you please update Myriad packages since #35 is merged?
Thank you in advance!
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.