在日常开发中,经常需要在 JSON 和 YAML 两种格式之间切来切去——配置文件是 YAML,API 返回的是 JSON。今天我们用 OpenCode 写一个命令行工具 jsonyaml,能智能检测输入格式并自动转换。
全程不用手敲代码,只需要用自然语言指挥 OpenCode 干活。
先让 OpenCode 帮我们搭好脚手架:
我对 OpenCode 说:
> 帮我创建一个 Go 项目目录 jsonyaml,初始化 go mod,module 名称为 jsonyaml
OpenCode 一键完成:
mkdir jsonyaml && cd jsonyaml && go mod init jsonyaml
终端输出 go: creating new go.mod: module jsonyaml,脚手架就位。
我对 OpenCode 说:
> 帮我写一个 main.go,实现 JSON 和 YAML 之间的互相转换。读取命令行参数作为文件名,根据文件扩展名判断转换方向:.json 文件转成 YAML 输出,.yaml/.yml 文件转成 JSON 输出。使用 gopkg.in/yaml.v3 库。
OpenCode 生成代码后,自动执行 go mod tidy 拉取依赖。它理解了我的意图——通过文件扩展名自动判断转换方向,不需要手动指定。
关键要点:
go mod tidy,无需我们手动下载依赖这个工具只能读文件不够灵活,让我加上管道输入支持。
我对 OpenCode 说:
> 当没有提供命令行参数时,从标准输入读取内容,这样就能用管道 cat a.json | jsonyaml 的方式使用。同时添加 -h 帮助选项和 -t 选项强制指定目标格式。
OpenCode 引入了 flag 包,写了 io.ReadAll(os.Stdin) 处理管道,还加了一个 detectTarget 函数:当未指定 -t 时,先用 json.Unmarshal 试探——成功说明是 JSON,就转 YAML;失败就当 YAML 处理转 JSON。
关键要点:
detectTarget 函数体现了"先试 JSON,不行再试 YAML"的容错策略我对 OpenCode 说:
> JSON 输出默认是一行,不太好看。加一个 -indent 参数控制缩进,默认用两个空格。同时重构一下,把转换逻辑抽成 toJSON 和 toYAML 两个独立函数。
OpenCode 用 json.MarshalIndent 替代了 json.Marshal,默认缩进两个空格。同时把转换逻辑拆成了 toJSON 和 toYAML,代码结构更清晰。
关键要点:
-indent " " 就能改成 4 空格我对 OpenCode 说:
> 帮我创建测试数据,先用 jsonyaml 把 JSON 转成 YAML,再转回来验证一致。
OpenCode 创建了 test.json,然后运行转换:
go run main.go test.json # 输出 YAML 格式的结果 go run main.go test.json | go run main.go -t json # 把 YAML 结果管道传回去转成 JSON,验证数据一致
输出完全一致,转换无损。
我对 OpenCode 说:
> 帮我编译成可执行文件,输出到当前目录
go build -o jsonyaml.exe .
一个 3MB 左右的独立可执行文件就生成了,无需 Go 环境也能跑。
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"os"
"strings"
"gopkg.in/yaml.v3"
)
var (
toFormat = flag.String("t", "", "目标格式: json 或 yaml")
indent = flag.String("indent", " ", "JSON 缩进")
help = flag.Bool("h", false, "显示帮助")
)
func main() {
flag.Parse()
if *help {
printHelp()
return
}
var input []byte
var err error
if flag.NArg() > 0 {
input, err = os.ReadFile(flag.Arg(0))
} else {
input, err = io.ReadAll(os.Stdin)
}
if err != nil {
fmt.Fprintf(os.Stderr, "读取输入失败: %v\n", err)
os.Exit(1)
}
target := strings.ToLower(*toFormat)
if target == "" {
target = detectTarget(input)
}
var result []byte
switch target {
case "json":
result, err = toJSON(input, *indent)
case "yaml", "yml":
result, err = toYAML(input)
default:
fmt.Fprintf(os.Stderr, "未知目标格式: %s (支持 json / yaml)\n", target)
os.Exit(1)
}
if err != nil {
fmt.Fprintf(os.Stderr, "转换失败: %v\n", err)
os.Exit(1)
}
fmt.Print(string(result))
}
func detectTarget(data []byte) string {
var obj interface{}
if json.Unmarshal(data, &obj) == nil {
return "yaml"
}
return "json"
}
func toJSON(data []byte, indent string) ([]byte, error) {
var obj interface{}
if err := yaml.Unmarshal(data, &obj); err != nil {
return nil, fmt.Errorf("YAML 解析失败: %w", err)
}
return json.MarshalIndent(obj, "", indent)
}
func toYAML(data []byte) ([]byte, error) {
var obj interface{}
if err := json.Unmarshal(data, &obj); err != nil {
return nil, fmt.Errorf("JSON 解析失败: %w", err)
}
return yaml.Marshal(obj)
}
func printHelp() {
fmt.Println(`jsonyaml - JSON 与 YAML 格式互转工具
用法:
jsonyaml [选项] [文件]
选项:
-t 指定目标格式 (json 或 yaml),不指定则自动检测
-indent JSON 缩进字符串 (默认: " ")
-h 显示此帮助信息
示例:
jsonyaml data.json # JSON → YAML
jsonyaml config.yaml # YAML → JSON
cat data.json | jsonyaml # 管道输入
jsonyaml -t json config.yml # 强制转换为 JSON`)
}
这个小工具从头到尾没写一行代码,全程用自然语言和 OpenCode 对话完成:
| 过程 | 传统开发 | 用 OpenCode |
|------|---------|------------|
| 初始化项目 | 手动敲命令 | 一句话 |
| 核心逻辑 | 查文档、写代码、调 Bug | 描述需求 |
| 添加功能 | 改多处、担心遗漏 | 追加描述 |
| 测试验证 | 手动构造数据 | 让它帮你做 |
| 编译部署 | 记命令参数 | 一句话 |
4 分钟,90 行 Go,一个立刻能用的 JSON/YAML 互转工具。用 OpenCode 开发就像有个高级工程师坐旁边——你只需要把脑子里的需求说清楚,代码、测试、编译它全包了。