yaml-enumgen
v0.1.1
Published
Generate Go enums and OpenAPI schemas from YAML; native Rust CLI bundled for Linux, macOS and Windows
Readme
enumgen
Rust 编写的 YAML → Go enum / OpenAPI 生成器。
使用
需要 Rust stable。生成的 Go 代码要求 Go 1.24+(encoding.TextAppender);启用 JSON v2 时要求支持 encoding/json/v2 的 Go 工具链,并开启对应实验(例如 Go 1.25 的 GOEXPERIMENT=jsonv2)。
cargo test
cargo run -- validate --config examples/config.yaml
cargo run -- generate --config examples/config.yaml
cargo run -- check --config examples/config.yaml
# 显式 flag 覆盖配置文件,包括 false;位置参数替换文件中的全部 inputs
cargo run -- generate --config examples/config.yaml --json-v2=false --oas-layout single
cargo run -- generate enums/common.yaml enums/order.yaml --go-package enums配置优先级:显式 flag > 配置文件 > 默认值。配置文件不自动发现,使用 --config 指定。文件配置中的路径相对配置文件目录,flag 和位置参数中的路径相对工作目录。运行 cargo run -- --help 查看所有 flag。
示例:枚举定义、配置。未知字段和不合法配置会报错。单个或多个 YAML 输入统一校验,枚举 ID 全局唯一。字段支持多行 YAML 文本。
检查与减少写入
# 只读检查:内容一致退出 0;缺失或过期退出 1,适合 CI
enumgen check --config enumgen.yaml
# 默认先读取现有文件;逐字节一致则跳过,保持修改时间不变
enumgen generate --config enumgen.yaml
# 显式启用,或关闭预读比较以强制重写
enumgen generate --config enumgen.yaml --skip-unchanged
enumgen generate --config enumgen.yaml --skip-unchanged=false配置文件中可设置(显式 flag 优先):
write:
skip_unchanged: true # 默认 true;false 表示每次都写该选项统一作用于 Go 和 OAS 输出。跳过的文件不会被打开写入,也不会重建父目录;实际发生变化或缺失的文件才会写入。读取失败(缺失除外)会返回错误。generate 汇报写入/跳过数量。check 始终只读,不受 skip_unchanged 配置影响,也不会创建输出目录。
定义
version: 1
enums:
- id: OrderStatus
description: 订单状态
go:
underlying: int16 # 可选:auto、int8、int16
database:
enabled: true
representation: integer # text、integer-string、integer
items:
- id: InProgress
integer: 20
text: in_progress
description: 正在处理枚举 ID 使用 PascalCase;成员 ID 匹配 [A-Za-z_][A-Za-z0-9_]*;文本索引匹配 [a-z][a-z0-9]*(?:_[a-z0-9]+)*。同一枚举内成员 ID、整数值、文本值分别唯一;不要求整数连续或从零开始。注释不能为空。生成顺序保留成员声明顺序。
Go
每个 enum 一个文件,不生成顶层函数。常量为 <EnumID><ItemID>。底层类型 auto 选择 int8 或 int16,越界在生成前报错。
func (v OrderStatus) Int() int
func (v OrderStatus) Valid() bool
func (v OrderStatus) EnumName() string
func (v OrderStatus) EnumValues() []OrderStatus
func (v *OrderStatus) SetInt(n int) bool
func (v *OrderStatus) SetString(s string) boolsetter 失败不改变原值;SetInt 先匹配合法整数再转换,不会截断。SetString 精确匹配文本索引,不接受数字字符串。EnumValues 返回独立切片。Int 可用于未定义值,Valid 单独判断合法性。
实现并生成编译期接口断言:
- fmt.Stringer / Formatter:s、v 输出文本;q 输出带引号文本;b、d、o、O、x、X 输出整数,支持格式标志、宽度和精度。
- encoding.TextMarshaler / TextUnmarshaler / TextAppender:始终使用文本索引,非法值返回普通 error。AppendText 失败保留原缓冲区。
- JSON v1:默认输出和接受文本;encode 可选 text、integer-string、integer,accept 可组合三种表示,或用 oneof 代表三种。拒绝 null、未知值、多余 JSON 数据。数字字符串必须是规范十进制表示。
- JSON v2:MarshalJSONTo / UnmarshalJSONFrom,枚举转换失败返回 SemanticError,语法和 I/O 错误交由底层处理。
- flag.Value / Getter:Set 委托 SetString,Get 返回枚举值。
- 按枚举启用 sql.Scanner / driver.Valuer。integer 接受数据库 int64,另外两种接受 string / []byte。拒绝 NULL 和未知值。SQL 接口所要求的 int64 不影响公开 Int/SetInt 使用 int。
全部解码/Scan 失败保留原值。不生成公开错误类型。未定义值 String 输出 OrderStatus(123),协议编码返回 error。
OAS
mode 四种模式:
| 模式 | 允许的值 |
| --- | --- |
| text | "in_progress" |
| integer | 20 |
| integer-string | "20" |
| oneof | 上述三种 |
oneof 的 string 分支合并文本和数字字符串,integer 分支包含整数,两者不重叠。description 包含完整成员表,并转义单元格内的换行和竖线。
layout: single 输出 openapi.yaml,所有枚举放在 components.schemas。multiple 额外为每个枚举输出独立 Schema YAML,入口通过相对 $ref 引用。支持 OpenAPI 3.0.3 和 3.1.0。
OAS 模式独立配置:使用者应按 API 的真实请求或响应形式选择;当前不自动拆分请求/响应 Schema。
验证
已使用 Rust 1.99.1、Go 1.27.3 验证:Rust 单元测试、Clippy(warnings 视为错误)、生成 Go 的行为测试及 race 检查,JSON/数据库表示配置矩阵,以及 OAS 两个版本 × 四种模式 × 两种布局的 16 种组合。
cargo test
cargo clippy --all-targets -- -D warnings
# 启用生成 Go 的集成测试(包括 JSON v2 和 race)
ENUMGEN_GO=/path/to/go cargo test
# 验证 OAS,包括外部 $ref 与允许/拒绝的具体值
python3 -m pip install openapi-spec-validator
cargo build
python3 tests/validate_oas.py未设置 ENUMGEN_GO 时跳过 Go 集成测试。当前验证基于 Go 1.27,较早版本的 JSON v2 实验接口兼容性未验证。生成文件采用确定性的原始排版,可在生成后执行 gofmt -w generated/go;check 按生成原文比较,因此格式化后会被视为修改。
生成器只写入自己本次生成的路径,不删除旧文件;删除或改名 enum 后请清理旧输出。check 检测本次应生成的文件是否缺失或过期。输出不包含时间戳。
在其他仓库中使用
先 checkout 调用方仓库,再引用本 Action。使用发布 tag 时自动下载对应平台的 Release 二进制并校验 SHA-256,无需安装 Rust。引用分支或 commit SHA 时从该版本源码编译;也可用 version 显式选择发布版本或 source。
name: Generate enums
on: [push, pull_request]
permissions:
contents: read
jobs:
enums:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: iseki0/[email protected]
with:
config: enumgen.yaml
command: generate
# args: --oas-layout multiple --json-v2=false
# 如果已提交生成文件,可将 command 改为 check,或检查生成后的差异:
- run: git diff --exit-codeargs 使用 shell 风格引号拆分为参数,不作为 shell 脚本执行。config: '' 可完全通过 args 指定输入文件与选项。Action 本身不会提交、推送或修改调用方 GitHub 设置。
也可以直接安装固定 tag:
cargo install --git https://github.com/iseki0/yaml-enumgen --tag v0.1.0 --locked enumgenCI 与 Release
CI 在 Linux、macOS、Windows 上检查 Rust 编译、格式及 Clippy;Linux 额外运行生成 Go 的行为/race 测试、OAS 16 种组合校验和本地 composite Action。
将 Cargo.toml 中的版本更新并提交后,推送匹配的 vX.Y.Z tag 触发 Release:
git tag v0.1.0
git push origin v0.1.0Release 自动提供:
- Linux x86_64 / ARM64:通过 Zig 交叉编译的 musl 静态二进制。
- macOS ARM64 / x86_64:在 macOS runner 上编译,x86_64 使用交叉目标。
- Windows x86_64:在 Windows runner 上编译。
每个压缩包附带 .sha256 校验文件,全部平台构建成功后才发布 GitHub Release。下载见 Releases。
npm / npx
npm 包名为 yaml-enumgen,同时提供 enumgen 和 yaml-enumgen 两个命令:
npx [email protected] generate --config enumgen.yaml
npm install --save-dev yaml-enumgen
npx enumgen check --config enumgen.yaml
npm install --global yaml-enumgen
enumgen --help要求 Node.js 18+。npm 包直接包含五个平台的 Rust 二进制,不依赖 Rust 工具链、Python 或安装脚本,也不会在安装/运行时另行下载。Linux 支持 glibc/musl 的 x86_64、ARM64,macOS 支持 Intel、Apple Silicon,Windows 支持 x86_64。
npm 发布工作流会下载同版本 GitHub Release、验证 SHA-256、打包并测试实际 npm tarball,再发布。首次发布需登录 npm;之后可在 npm 包设置中将此仓库的 npm-publish.yml 配为 GitHub Actions trusted publisher。Release 成功后通过 workflow_run 自动触发该工作流,也可以手动选择已有 release tag 发布。npm/Cargo 版本必须一致。
