NETool.Generator
4.3.0
See the version list below for details.
dotnet add package NETool.Generator --version 4.3.0
NuGet\Install-Package NETool.Generator -Version 4.3.0
<PackageReference Include="NETool.Generator" Version="4.3.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="NETool.Generator" Version="4.3.0" />
<PackageReference Include="NETool.Generator"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add NETool.Generator --version 4.3.0
#r "nuget: NETool.Generator, 4.3.0"
#:package NETool.Generator@4.3.0
#addin nuget:?package=NETool.Generator&version=4.3.0
#tool nuget:?package=NETool.Generator&version=4.3.0
NETool.Generator
介绍
NETool.Generator 是 NETool 的适用于 C# 的零编码二进制序列化程序。
参考 MemoryPack,支持的类型不及其丰富,但足以满足大部分需求。
NETool.Pack 速度之所以如此之快,是由于其特定于 C# 优化的二进制格式,利用 .NET 8+ 和 C# 13 以及增量源生成器 IIncrementalGenerator(.NET Standard 2.0),另外包括 Span, ReadOnlySpan 以及内存池 ArrayPool 的使用。
除了二进制序列化,基于源生成还实现了与 Windows API 无关的 Ini 格式的配置文件读写, 方便用户可通过文本工具进行配置的修改。
软件架构
.NETFramework 4.7.2, .NET8, .NET10
安装教程
从 Nuget 安装最新版本。
Install-Package NETool.Generator
快速入门
定义要二进制序列化的类,并使用属性和关键字对其进行注释。[NEToolPackable] partial
定义要 Ini 格式序列化的类,并使用属性和关键字对其进行注释。[IniConfig(string fileName)] partial
using System.NETool;
[NEToolPackable]
[IniConfig("Person.ini")]
public partial class Person
{
public int Age { get; set; }
public string Name { get; set; }
[NEToolIgnore]
public string Address { get; set; }
}
注:NEToolPackable 与 IniConfig 特性可以单独按需要使用。
源生成的代码实现了 INEToolPackMembers 接口:
/// <summary>
/// NETool 序列化成员说明接口
/// </summary>
public interface INEToolPackMembers
{
/// <summary>
/// 排除数据字段
/// </summary>
string ExcludedMembers();
/// <summary>
/// 未知数据字段
/// </summary>
string UnknownMembers();
}
源生成的代码实现了 INEToolPackable 接口,用于二进制序列化:
/// <summary>
/// NETool 序列化接口
/// </summary>
public interface INEToolPackable
{
/// <summary>
/// NETool 序列化方法
/// </summary>
/// <param name="endian">字节序: Little 为小端字节(低字节序),Big 为大端字节序(高字节序)</param>
/// <param name="encoding">字符编码</param>
/// <param name="zipType">压缩及加密算法类型</param>
/// <param name="password">密码</param>
/// <returns>字节数组对象</returns>
ByteArray Serialize(Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null);
/// <summary>
/// NETool 反序列化方法
/// </summary>
/// <param name="span">数据</param>
/// <param name="endian">字节序: Little 为小端字节(低字节序),Big 为大端字节序(高字节序)</param>
/// <param name="encoding">字符编码</param>
/// <param name="zipType">压缩及加密算法类型</param>
/// <param name="password">密码</param>
void Deserialize(scoped ReadOnlySpan<byte> span, Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null);
}
另外还实现了两个深度拷贝函数:
/// <summary>
/// 获取已有 Sunny.Serialization.Demo.Person 对象的副本,需有默认的无参构造函数
/// </summary>
/// <returns>Sunny.Serialization.Demo.Person 副本</returns>
public Sunny.Serialization.Demo.Person DeepCopy()
/// <summary>
/// 将已有 Sunny.Serialization.Demo.Person 对象深度拷贝到另一个不为空的 Sunny.Serialization.Demo.Person 对象
/// </summary>
/// <param name="other">另一个 Sunny.Serialization.Demo.Person 对象</param>
public void DeepCopyTo(Sunny.Serialization.Demo.Person other)
源生成的代码实现了 IIniConfig 接口,用于 Ini 格式配置文件加载和保存:
/// <summary>
/// 定义一个接口,用于 Ini 格式配置文件加载和保存
/// </summary>
public interface IIniConfig
{
/// <summary>
/// 从文件加载配置
/// </summary>
void LoadIni();
/// <summary>
/// 保存配置到文件
/// </summary>
void SaveIni();
/// <summary>
/// 异步从文件加载配置
/// </summary>
Task LoadIniAsync();
/// <summary>
/// 异步保存配置到文件
/// </summary>
Task SaveIniAsync();
/// <summary>
/// 从文件加载配置
/// </summary>
/// <param name="fileName">文件名</param>
void LoadIni(string fileName);
/// <summary>
/// 保存配置到文件
/// </summary>
/// <param name="fileName">文件名</param>
void SaveIni(string fileName);
/// <summary>
/// 异步从文件加载配置
/// </summary>
/// <param name="fileName">文件名</param>
Task LoadIniAsync(string fileName);
/// <summary>
/// 异步保存配置到文件
/// </summary>
/// <param name="fileName">文件名</param>
Task SaveIniAsync(string fileName);
}
序列化代码由实现接口的 C# 源生成器功能生成。
- 在 Visual Studio 中,可以使用类名称上的快捷方式 F12 检查生成的代码,然后选择 *.Person.Pack.Properties.g.cs,此为二进制序列化生成代码:
// <auto-generated by NETool.Generator 2025-08-21 14:14:31/>
// ReSharper disable once InconsistentNaming
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.NETool;
using System.Runtime.CompilerServices;
using System.Text;
namespace Sunny.Serialization.Demo;
/// <summary>
/// Sunny.Serialization.Demo.Person 显示排除与未知的成员
/// </summary>
public partial class Person : INEToolPackMembers
{
/// <summary>
/// 排除的成员 1 个
/// </summary>
public string ExcludedMembers()
{
var sb = new ValueStringBuilder();
sb.AppendLine("忽略类型: string Address [标记 Ignore 特性;];");
return sb.ToString();
}
/// <summary>
/// 未知的成员 0 个
/// </summary>
public string UnknownMembers()
{
return string.Empty;
}
}
/// <summary>
/// Sunny.Serialization.Demo.Person 二进制序列化扩展
/// </summary>
public partial class Person : INEToolPackable
{
///<inheritdoc/>
public ByteArray Serialize(Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null)
{
var writer = new ByteArray(endian, encoding);
#region 序列化
// int Age
writer.WriteInt32(this.Age);
// string Name
writer.WriteString(this.Name);
#endregion 序列化
var result = zipType.Compress(writer.Span, password);
writer.Dispose();
return result;
}
///<inheritdoc/>
public void Deserialize(scoped ReadOnlySpan<byte> span, Endian endian = Endian.Little, StringEncoding encoding = StringEncoding.UTF8, ZipType zipType = ZipType.None, string password = null)
{
var unZipped = zipType.Decompress(span, password);
var reader = new ByteArray(unZipped.Span, endian, encoding);
#region 反序列化
// int Age
this.Age = reader.ReadInt32();
// string Name
this.Name = reader.ReadString();
#endregion 反序列化
unZipped.Dispose();
}
/// <summary>
/// 获取已有 Sunny.Serialization.Demo.Person 对象的副本,需有默认的无参构造函数
/// </summary>
/// <returns>Sunny.Serialization.Demo.Person 副本</returns>
public Sunny.Serialization.Demo.Person DeepCopy()
{
using var writer = this.Serialize();
var copy = new Sunny.Serialization.Demo.Person();
copy.Deserialize(writer.Span);
return copy;
}
/// <summary>
/// 将已有 Sunny.Serialization.Demo.Person 对象深度拷贝到另一个不为空的 Sunny.Serialization.Demo.Person 对象
/// </summary>
/// <param name="other">另一个 Sunny.Serialization.Demo.Person 对象</param>
public void DeepCopyTo(Sunny.Serialization.Demo.Person other)
{
if (other is null) return;
using var writer = this.Serialize();
other.Deserialize(writer.Span);
}
}
调用序列化/反序列化对象实例:
var person = new Person
{
Age = 30,
Name = "Sunny"
};
// 序列化
var byteArray = person.Serialize();
Console.WriteLine($"Serialized Person: {byteArray.Span.ToHexString()}");
// 反序列化
person.Deserialize(byteArray.Span);
Console.WriteLine($"Deserialized Person: Age={person.Age}, Name={person.Name}");
byteArray.Dispose();
// 深拷贝
Person other = person.DeepCopy();
Console.WriteLine($"Deep Copied Person: Age={other.Age}, Name={other.Name}");
输出结果:
Serialized Person: 1E0000000553756E6E79
Deserialized Person: Age=30, Name=Sunny
Deep Copied Person: Age=30, Name=Sunny
- 在 Visual Studio 中,可以使用类名称上的快捷方式 F12 检查生成的代码,然后选择 *.Person.Ini.Properties.g.cs,此为 Ini 格式配置文件生成代码:
// <auto-generated by NETool.Generator 2025-10-18 10:53:34/>
// ReSharper disable once InconsistentNaming
using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.NETool;
using System.Runtime.CompilerServices;
using System.Text;
namespace Sunny.Serialization.Demo;
/// <summary>
/// Sunny.Serialization.Demo.Person Ini 配置文件序列化扩展
/// </summary>
public partial class Person : IIniConfig
{
/// <summary>
/// Sunny.Serialization.Demo.Person 单例对象
/// </summary>
[NEToolIgnore]
public static Sunny.Serialization.Demo.Person Instance = Singleton<Sunny.Serialization.Demo.Person>.Instance;
/// <summary>
/// Ini 配置文件名称
/// </summary>
[NEToolIgnore]
private const string __IniFileName = "Person.ini";
/// <summary>
/// Ini 配置文件全路径
/// </summary>
[NEToolIgnore]
public string IniFileName => FileEx.VerifyFileName(__IniFileName);
///<inheritdoc/>
public void InitIni(){}
///<inheritdoc/>
public void SaveIni(string fileName = __IniFileName)
{
var writer = new IniFile(fileName, Encoding.UTF8, false);
__IniWriting(writer);
writer.SaveAs(fileName);
}
///<inheritdoc/>
public Task SaveIniAsync(string fileName = __IniFileName)
{
var writer = new IniFile(fileName, Encoding.UTF8, false);
__IniWriting(writer);
return writer.SaveAsAsync(fileName);
}
///<inheritdoc/>
public void LoadIni(string fileName = __IniFileName)
{
if (fileName == __IniFileName && !File.Exists(IniFileName))
{
InitIni();
SaveIni();
}
var reader = new IniFile(fileName, Encoding.UTF8, false);
reader.Load();
__IniReading(reader);
}
///<inheritdoc/>
public async Task LoadIniAsync(string fileName = __IniFileName)
{
if (fileName == __IniFileName && !File.Exists(IniFileName))
{
InitIni();
await SaveIniAsync().ConfigureAwait(false);
}
var reader = new IniFile(fileName, Encoding.UTF8, false);
await reader.LoadAsync().ConfigureAwait(false);
__IniReading(reader);
}
/// <summary>
/// 写入数据
/// </summary>
/// <param name="writer">IniFile 写入器</param>
private IniFile __IniWriting(IniFile writer)
{
#region 序列化
const string __header = $"count";
var section = "Person";
// int Age
writer.WriteInt32(section, "Age", this.Age, "年龄");
// string Name
writer.WriteString(section, "Name", this.Name, "姓名");
#endregion 序列化
return writer;
}
/// <summary>
/// 读取数据
/// </summary>
/// <param name="reader">IniFile 读取器</param>
private void __IniReading(IniFile reader)
{
#region 反序列化
const string __header = $"count";
var section = "Person";
// int Age
this.Age = reader.ReadInt32(section, "Age", this.Age);
// string Name
this.Name = reader.ReadString(section, "Name", this.Name);
#endregion 反序列化
}
}
调用 Ini 读写序列化/反序列化对象实例:
var person = new Person
{
Age = 30,
Name = "Sunny"
};
await person.SaveIniAsync();
var other2 = new Person();
await other2.LoadIniAsync().ConfigureAwait(false);
Console.WriteLine($"Ini load Person: Age={other2.Age}, Name={other2.Name}");
输出结果:
Ini load Person: Age=30, Name=Sunny
保存的配置文件 Person.ini 在运行程序的根目录:
;<?Ini Version="NETool IniFile V1.0.1" Encoding="utf-8" Updated="2025-08-21 10:50:07"?>
[Sunny.Serialization.Demo.Person]
Age=30
Name=Sunny
内置支持的类型
1 基础类型: bool, byte, sbyte, short, ushort, int, uint, long, ulong, System.Half, float, double, decimal, char;
2 扩展类型: 原生的 string, DateTime, DateTimeOffset, Point, PointF, Size, SizeF, Color, Rectangle, RectangleF, TimeSpan, Guid, Version, Uri, TimeZoneInfo, CultureInfo 类型,System.NETool 扩展的 IpV4, IpV4Port, GuidV7, LngLat, SystemTime, SystemTime2 类型;
3 枚举类型: enum;
4 结构类型: struct, 标记为 [InlineArray(n)] 特性的结构体;
5 结构类型: struct, 标记为 [StructLayout(LayoutKind.Explicit)] 特性的结构体;
6 可序列化类: class, 标记为 [NEToolPackable] 特性的类,类必须增加 partial 关键字,并有无参数的构造函数;
7 一维数组:
T[], 其中 T 是上述 1、2、3、4、5 、6类型之一;8 列表:
List<T>,ConcurrentList<T>, 其中 T 是上述 1、2、3、4、5 、6类型之一;9 字典:
Dictionary<TKey, TValue>,ConcurrentDictionary<TKey, TValue>, 其中 TKey 和 TValue 是上述 1、2、3、4、5、6 类型之一;
类只有1 基础类型时,序列化与原生的 System.IO.BinaryWriter 完全一致
定义 [NEToolPackable] [IniConfig] class
[NEToolPackable] 和 [IniConfig] 特性注释 class 类,定义为 public 或者 internal,类必须增加 partial 关键字,并有无参数的构造函数。类不能为继承的子类。
类序列化的字段包含:
- 字段 (filed) ,必须标记为 public,
- 属性 (Property),必须标记为 public,并且有公开的 get;set;
标记为 [NEToolIgnore] 或者 [IgnoreDataMember] 或者带有其他 Ignore 特性的,序列化时将会忽略。
枚举生成 Description 扩展方法
NETool.Pack 会通过源生成 打上 EnumDescription 特性的枚举类的 Description 扩展方法,例如:
[EnumDescription]
public enum TestEnum : byte
{
[Description("Excellent")]
A = 0,
[Description("Perfect")]
B = 1,
[Description("Good")]
C = 2,
[Description("Average")]
D = 3,
[Description("Failure")]
E = 4,
F = 5,
}
源生成的代码在 *.TestEnum.Desc.g.cs
/// <summary>
/// Sunny.Serialization.Demo.TestEnum 枚举的描述扩展方法
/// </summary>
public static class Sunny_Serialization_Demo_TestEnum_Description_Extensions
{
/// <summary>
/// 获取 Sunny.Serialization.Demo.TestEnum 枚举值的描述
/// </summary>
/// <param name="value">枚举值</param>
/// <returns>枚举值的描述</returns>
public static string Description(this Sunny.Serialization.Demo.TestEnum value)
{
return value switch
{
Sunny.Serialization.Demo.TestEnum.A => "Excellent",
Sunny.Serialization.Demo.TestEnum.B => "Perfect",
Sunny.Serialization.Demo.TestEnum.C => "Good",
Sunny.Serialization.Demo.TestEnum.D => "Average",
Sunny.Serialization.Demo.TestEnum.E => "Failure",
Sunny.Serialization.Demo.TestEnum.F => "F",
_ => string.Empty
};
}
}
枚举条目有 [Description] 特性的,输出特性描述文本。没有此特性的,输出枚举名称。
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on NETool.Generator:
| Package | Downloads |
|---|---|
|
NETool.Pack
NETool.Pack 是 NETool 的二进制序列化器。 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.3.1 | 0 | 2/11/2026 |
| 4.3.0 | 0 | 2/11/2026 |
| 4.2.2 | 16 | 2/10/2026 |
| 4.2.1 | 35 | 2/9/2026 |
| 4.2.0 | 36 | 2/9/2026 |
| 4.1.9 | 34 | 2/6/2026 |
| 4.1.8 | 40 | 2/6/2026 |
| 4.1.7 | 40 | 2/6/2026 |
| 4.1.6 | 93 | 2/4/2026 |
| 4.1.5 | 93 | 2/3/2026 |
| 4.1.4 | 94 | 2/3/2026 |
| 4.1.3 | 95 | 2/2/2026 |
| 4.1.2 | 102 | 2/2/2026 |
| 4.0.7 | 101 | 2/2/2026 |
| 4.0.6 | 97 | 2/1/2026 |
| 4.0.5 | 109 | 2/1/2026 |
| 4.0.4 | 107 | 2/1/2026 |
| 4.0.3 | 96 | 1/30/2026 |
| 4.0.2 | 103 | 1/30/2026 |
| 4.0.1 | 143 | 1/30/2026 |
| 4.0.0 | 105 | 1/28/2026 |
| 3.9.5 | 100 | 1/28/2026 |
| 3.9.4 | 99 | 1/27/2026 |
| 3.9.3 | 102 | 1/25/2026 |
| 3.9.2 | 100 | 1/25/2026 |
| 3.9.1 | 101 | 1/24/2026 |
| 3.9.0 | 102 | 1/23/2026 |
| 3.8.9 | 97 | 1/23/2026 |
| 3.8.8 | 102 | 1/23/2026 |
| 3.8.7 | 112 | 1/22/2026 |
| 3.8.6 | 101 | 1/22/2026 |
| 3.8.5 | 101 | 1/22/2026 |
| 3.8.4 | 107 | 1/22/2026 |
| 3.8.3 | 99 | 1/21/2026 |
| 3.8.2 | 98 | 1/21/2026 |
| 3.8.1 | 100 | 1/21/2026 |
| 3.8.0 | 95 | 1/21/2026 |
| 3.7.1 | 101 | 1/21/2026 |
| 3.7.0 | 100 | 1/19/2026 |
| 3.6.9 | 103 | 1/19/2026 |
| 3.6.8 | 101 | 1/17/2026 |
| 3.6.7 | 117 | 1/17/2026 |
| 3.6.5 | 104 | 1/17/2026 |
| 3.6.4 | 107 | 1/17/2026 |
| 3.6.3 | 102 | 1/17/2026 |
| 3.6.2 | 94 | 1/17/2026 |
| 3.6.1 | 105 | 1/15/2026 |
| 3.6.0 | 107 | 12/31/2025 |
| 3.5.9 | 113 | 12/28/2025 |
| 3.5.8 | 113 | 12/27/2025 |
| 3.5.7 | 192 | 12/25/2025 |
| 3.5.6 | 191 | 12/24/2025 |
| 3.5.5 | 188 | 12/23/2025 |
| 3.5.4 | 190 | 12/23/2025 |
| 3.5.3 | 248 | 12/15/2025 |
| 3.5.2 | 166 | 12/14/2025 |
| 3.5.1 | 433 | 12/11/2025 |
| 3.5.0 | 448 | 12/10/2025 |
| 3.4.9 | 438 | 12/8/2025 |
| 3.4.8 | 440 | 12/8/2025 |
| 3.4.7 | 363 | 12/8/2025 |
| 3.4.6 | 197 | 12/5/2025 |
| 3.4.5 | 216 | 12/5/2025 |
| 3.4.4 | 220 | 12/4/2025 |
| 3.4.3 | 681 | 12/3/2025 |
| 3.4.2 | 696 | 12/3/2025 |
| 3.4.1 | 689 | 12/2/2025 |
| 3.4.0 | 189 | 11/28/2025 |
| 3.3.9 | 193 | 11/28/2025 |
| 3.3.8 | 202 | 11/27/2025 |
| 3.3.7 | 205 | 11/25/2025 |
| 3.3.6 | 392 | 11/21/2025 |
| 3.3.5 | 423 | 11/18/2025 |
| 3.3.4 | 359 | 11/17/2025 |
| 3.3.3 | 356 | 11/17/2025 |
| 3.3.2 | 181 | 11/15/2025 |
| 3.3.1 | 276 | 11/14/2025 |
| 3.3.0 | 303 | 11/12/2025 |
| 3.2.6 | 295 | 11/11/2025 |
| 3.2.5 | 252 | 11/10/2025 |
| 3.2.4 | 215 | 11/7/2025 |
| 3.2.3 | 224 | 11/6/2025 |
| 3.2.2 | 174 | 10/31/2025 |
| 3.2.1 | 214 | 10/30/2025 |
| 3.2.0 | 226 | 10/30/2025 |
| 3.1.4 | 215 | 10/30/2025 |
| 3.1.3 | 221 | 10/29/2025 |
| 3.1.2 | 211 | 10/29/2025 |
| 3.1.1 | 210 | 10/28/2025 |
| 3.1.0 | 202 | 10/28/2025 |
| 3.0.9 | 210 | 10/28/2025 |
| 3.0.8 | 168 | 10/24/2025 |
| 3.0.7 | 216 | 10/19/2025 |
| 3.0.6 | 151 | 10/18/2025 |
| 3.0.5 | 143 | 10/18/2025 |
| 3.0.4 | 155 | 10/17/2025 |
| 3.0.3 | 203 | 10/16/2025 |
| 3.0.2 | 194 | 10/15/2025 |
| 3.0.1 | 207 | 10/13/2025 |
| 3.0.0 | 184 | 10/12/2025 |
| 2.9.9 | 150 | 10/12/2025 |
| 2.9.8 | 148 | 10/11/2025 |
| 2.9.7 | 179 | 10/10/2025 |
| 2.9.6 | 197 | 10/10/2025 |
| 2.9.5 | 202 | 10/8/2025 |
| 2.9.4 | 203 | 10/8/2025 |
| 2.9.3 | 219 | 10/7/2025 |
| 2.9.2 | 208 | 9/29/2025 |
| 2.9.1 | 178 | 9/28/2025 |
| 2.9.0 | 176 | 9/28/2025 |
| 2.8.9 | 184 | 9/28/2025 |
| 2.8.8 | 140 | 9/27/2025 |
| 2.8.7 | 208 | 9/26/2025 |
| 2.8.6 | 212 | 9/25/2025 |
| 2.8.5 | 196 | 9/24/2025 |
| 2.8.4 | 209 | 9/24/2025 |
| 2.8.3 | 202 | 9/24/2025 |
| 2.8.2 | 198 | 9/23/2025 |
| 2.8.1 | 196 | 9/23/2025 |
| 2.8.0 | 216 | 9/23/2025 |
| 2.7.9 | 217 | 9/20/2025 |
| 2.7.8 | 271 | 9/19/2025 |
| 2.7.7 | 340 | 9/18/2025 |
| 2.7.6 | 320 | 9/17/2025 |
| 2.7.5 | 336 | 9/17/2025 |
| 2.7.4 | 323 | 9/17/2025 |
| 2.7.3 | 339 | 9/17/2025 |
| 2.7.2 | 288 | 9/15/2025 |
| 2.7.1 | 279 | 9/15/2025 |
| 2.7.0 | 198 | 9/11/2025 |
| 2.6.9 | 188 | 9/10/2025 |
| 2.6.8 | 183 | 9/10/2025 |
| 2.6.7 | 185 | 9/8/2025 |
| 2.6.6 | 182 | 9/8/2025 |
| 2.6.5 | 165 | 9/5/2025 |
| 2.6.3 | 168 | 9/5/2025 |
| 2.6.2 | 200 | 9/4/2025 |
| 2.6.1 | 192 | 9/2/2025 |
| 2.6.0 | 189 | 9/1/2025 |
| 2.5.9 | 223 | 8/29/2025 |
| 2.5.8 | 243 | 8/29/2025 |
| 2.5.7 | 227 | 8/28/2025 |
| 2.5.6 | 297 | 8/25/2025 |
| 2.5.5 | 140 | 8/22/2025 |
| 2.5.3 | 194 | 8/21/2025 |
| 1.0.2 | 181 | 8/21/2025 |
| 1.0.1 | 183 | 8/21/2025 |
| 1.0.0 | 190 | 8/21/2025 |
| 0.8.0 | 184 | 8/20/2025 |
| 0.7.2 | 165 | 8/20/2025 |
| 0.7.1 | 187 | 8/19/2025 |
| 0.7.0 | 190 | 8/14/2025 |
| 0.6.3 | 190 | 8/14/2025 |
| 0.6.2 | 194 | 8/12/2025 |
| 0.6.1 | 187 | 8/12/2025 |
| 0.6.0 | 193 | 8/12/2025 |
| 0.5.5 | 191 | 8/11/2025 |
| 0.5.3 | 199 | 8/11/2025 |
| 0.5.2 | 173 | 8/9/2025 |
| 0.5.1 | 254 | 8/7/2025 |
| 0.5.0 | 269 | 8/7/2025 |
| 0.4.0 | 269 | 8/6/2025 |
| 0.3.0 | 266 | 8/5/2025 |
| 0.2.0 | 268 | 8/5/2025 |
| 0.1.0 | 211 | 8/4/2025 |