dotnet add package Myriad.Sdk --version 0.8.3                
NuGet\Install-Package Myriad.Sdk -Version 0.8.3                
<PackageReference Include="Myriad.Sdk" Version="0.8.3" />                
paket add Myriad.Sdk --version 0.8.3                
#r "nuget: Myriad.Sdk, 0.8.3"                
// Install Myriad.Sdk as a Cake Addin
#addin nuget:?package=Myriad.Sdk&version=0.8.3

// Install Myriad.Sdk as a Cake Tool
#tool nuget:?package=Myriad.Sdk&version=0.8.3                

Myriad

Myriad是一个代码生成器。它接受任意文件,并提供不同的机制来允许在响应文件时生成F#代码,无论该文件是F#源文件还是简单的文本文件。

可以从MSBuild扩展或从其CLI工具使用Myriad。

Myriad的理念尽可能简化F#中的元编程能力。在这里,我所说的元编程是在F#中使用F#原生类型(如区分联合和记录)生成惯用F#代码,这是使用仅输出基本.NET类的F# Type Providers等不可能做到的。

Myriad是我与F#的类型提供者和其他元编程功能(如引言和AST操作)一起工作时开发的思想的进化。Myriad旨在通过Myriad插件轻松扩展编译器。Myriad提供了一种编译器扩展方法,不需要修改或调整Type Providers或等待其他F#语言改进。您编写一个用于处理AST输入片段的Myriad插件,然后插件提供AST输出,最终形式是构建到项目中的源代码。这可以使编译器优化输出,同时允许工具有效地运行。

如果您想要帮助和贡献代码,那么 đó thực sự rất tốt; 请检查问题并通过创建PR来进行。

如果您喜欢这个仓库并想表达您的感激之情等,那么我有Ko-fi。

ko-fi

通过MSBuild使用

要使用Myriad的MSBuild支持,请添加 Myriad.CoreMyriad.Sdk 包引用。

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

通过使用通常的Compile元素指定输入文件。

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

本教程通过配置Myriad,将名为 Generated.fs 的文件包含在构建中,并将 Library.fs 作为Myriad的输入。

还可以将生成的内容追加到输入文件中。

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

Myriad通过使用插件来生成代码来工作。Myriad附带了一个名为fields的插件,它从同名的OCaml ppx_fields_conv 插件中汲取灵感。

本示例中的输入文件 Library.fs 看起来如下所示

namespace Example
open Myriad.Plugins

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

使用属性是为了让代码生成器知道哪些输入AST的部分将被插件处理。如果您有多个记录并且只想让fields插件处理Test1,则可以使用示例中的属性来仅将Generator.Fields应用于Test1。注意,如果您需要一个只需要整个输入AST的插件,那么没有必要提供输入。Myriad旨在成为一个库,而不是一个完整的框架,该框架绑定到输入和生成代码的机制。传递给"fields"属性的参数指定了在myriad.toml文件中表示的配置部分。在本例中,使用了fields,而myriad.toml文件如下所示

[fields]
namespace = "TestFields"

这指定了用于插件的命名空间,在这种情况下是“TestFields”。

在本例中,fields插件将在预构建时生成以下代码并将其编译到您的程序集

//------------------------------------------------------------------------------
//        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 }

fields插件为输入记录中的每个字段生成一个map,一个接受每个字段的create函数,以及一个接受输入记录中的每个字段的一个函数的map函数。

对于每个字段使用的map函数在只需要从记录中使用单个字段的地方非常有用,例如记录的列表

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插件

Myriad还可以为记录和单案例判别联合生成lenses。Lens是一个pair,包含一个类型的单个属性的gettersetter。给定对象Lens后,您可以获取属性的值或更新它,创建一个新的对象。lenses的优点是能够将它们组合起来读取或更新对象的嵌套字段。

要为您的类型创建lenses,首先使用Generator.Lenses属性注释您希望生成lenses的类型

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

Myriad将生成以下代码

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 })

通常,lenses被定义为一个单案例联合,其中包含getter和setter对。Myriad还可以添加调用此类DU构造函数的调用。

为了实现这一点,请使用Lens属性装饰您的类型,指定DU构造函数的名称:[<Generator.Lenses("Lens")>],Myriad将生成以下代码

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 }))

您可以通过几种方式提供DU构造函数的名称

  • 作为字符串:[<Generator.Lenses("lens", "Lens")>]
  • 或作为类型:[<Generator.Lenses("lens", typedefof<Lens<_, _>>)>][<Generator.Lenses(typeof<Lens<_, _>>)>]

如果Lens类型与带属性装饰的类型在不同的命名空间/模块中,提供Lens构造函数的完整名称:[<Generator.Lenses("Namespace.And.Module.Of.Lens")>]


完整的fsproj细节如下所示

<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>

插件

为Myriad提供的插件是通过将nuget包包含在您的项目中。nuget基础设施提供必要的MSBuild props和targets,这样插件就可以自动由Myriad使用。有关fields插件的源可以使用作参考,直到有关创建插件的更多详细信息创建出来。

插件命名

如果您创建了一个插件,非正式的命名约定是使用:{{OwnerNamespace}}.Myriad.Plugin

使用外部插件

为了使用不包含在"Myriad.Plugins"包中的外部插件,您必须在"Myriad"中注册它们。如果您正在使用CLI工具,那么可以通过传递--plugin <dll文件路径>命令行参数来完成此操作。如果您使用MSBuild,则可以通过将MyriadSdkGenerator属性添加到您的项目文件中来实现。

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

例如,如果您有一个如图所示的项目布局

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

您将需要在Generator.fsproj中添加以下内容

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

然后在其中添加一个名为build的新文件夹,并在其中包含Generator.props文件。

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

通常还会使用一个额外的props文件(在本示例中,该文件为Generator.InTest.props)来简化测试。匹配测试.fsproj的元素可能如下所示

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

请注意,包含路径是指向本地而不是打包的nuget文件夹结构。

在您的测试fsproj中,您将需要添加以下内容以允许在本地使用插件而不是消耗nuget包


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

调试

要调试"Myriad",您可以使用以下两个命令行选项

  • --verbose — 将诊断日志写入标准输出
  • --wait-for-debugger — 使"Myriad"等待调试器附加到"Myriad"进程

这些可以通过通过<MyriadSdkVerboseOutput>true</MyriadSdkVerboseOutput><MyriadSdkWaitForDebugger>true</MyriadSdkWaitForDebugger>属性分别在MSBuild中触发。

Nuget

"Myriad"的nuget包可以在这里找到:Nuget包

Dotnet模板

Myriad插件/生成器的dotnet模板可在以下位置找到

#install dotnet template
dotnet new -i Myriad.Templates

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

如何构建和测试

  1. 请确保您已安装.Net Core SDK - 在global.json中检查所需版本
  2. 运行dotnet tool restore
  3. 运行dotnet build -c Release -t:Build

如何发布新版本

  1. 通过添加新条目(## [0.X.X])并提交来更新CHANGELOG.md
  2. 创建版本标签(git tag v0.X.X
  3. Directory.Build.props中更新VersionPrefix以与上述标签匹配。
  4. 运行dotnet build -t:Pack以创建nuget包并在本地测试/检查它。
  5. 将标签推送到仓库(git push origin v0.X.X) - 这将启动CI过程,将创建GitHub发布并在此发布中放入生成的NuGet包
  6. 将生成的包上传到NuGet.org

此外,还可以参考

外部插件

以下是已构建的外部插件列表

SqlHyra JsonWrapper TypeSafeInternals

此包中没有受支持的框架资产。

了解更多关于目标框架.NET Standard的信息。

此包没有依赖项。

Nuget包 (4)

显示依赖于Myriad.Sdk的前4个Nuget包

下载
BinaryDefense.Myriad.Plugins.JsonWrapper

为[Myriad](https://github.com/MoiraeSoftware/myriad)生成的插件,可围绕给定的模式生成关于JToken的静态类型无损耗包装器。

AndreasDorfer.BehaviorTestGenerator

一个Myriad插件,可从行为生成测试类。

TheAngryByrd.Myriad.Plugins.TypeSafeInternals

TheAngryByrd.Myriad.Plugins.TypeSafeInternals使用Myriad生成对内部函数/属性/方法的类型安全反射调用。

Godot.FSharp.SourceGenerators

包描述

GitHub 仓库

此包未被任何流行的GitHub仓库使用。

版本 下载 最后更新
0.8.3 6,378 9/8/2023
0.8.2 1,473 2/10/2023
0.8.1 4,718 5/13/2022
0.8.0 568 5/4/2022
0.7.4 1,615 10/29/2021
0.7.3 342 10/28/2021
0.7.3-alpha 261 10/28/2021
0.7.2 352 10/28/2021
0.7.1 316 10/26/2021
0.7.0 307 10/21/2021
0.6.4 340 10/11/2021
0.6.3 450 9/22/2021
0.6.2 334 9/17/2021
0.6.1 303 9/17/2021
0.6.0 364 9/9/2021
0.5.4 348 9/2/2021
0.5.3 2,858 5/21/2021
0.5.1 665 4/15/2021
0.5.0 1,096 12/22/2020
0.4.1 765 9/23/2020
0.4.0 785 7/21/2020
0.2.8 1,129 6/5/2020
0.2.7 1,061 5/18/2020
0.2.6 503 5/13/2020
0.2.4 647 11/3/2019
0.2.3 560 11/3/2019
0.2.2 495 11/2/2019
0.2.1 519 11/2/2019
0.2.0 539 10/23/2019
0.1.0 714 4/19/2019
0.0.5 614 4/18/2019
0.0.4 544 4/17/2019
0.0.3 572 4/17/2019
0.0.2 564 4/17/2019
0.0.1 547 4/16/2019
0.0.1-master-0000006 435 4/16/2019