跳转至

Mini YAML Parser

从 0 行(CC 实际用第三方库 yaml)提炼到 ~150 行的 缩进敏感 递归下降 parser。 支持 mapping / sequence / scalar(string / number / bool / null)+ 注释 + 引号。

文件

mini-yaml-parser/
├── src/
│   ├── types.ts     解析器(~110 行,单文件含 preprocess + parseBlock + parseMapping + parseSequence + parseScalar)
│   └── cli.ts       CLI(~30 行,支持 stdin / file / --example)
└── README.md

npm install && npm start -- --example
# 或
echo "key: value" | npm start
# 或
npm start -- examples/config.yaml

支持的语法

# 注释
name: cc-claude-code           # string
version: 1.0.0                # number
enabled: true                 # bool
maxRetries: 3                 # integer
ratio: 1.5                    # float
missing: null                 # null / ~ / ""

# 引号字符串
title: "Hello, World"
single: 'no escape needed'

# 嵌套 mapping
server:
  host: localhost
  port: 8080
  tls: true

# sequence
features:
  - streaming
  - tool-use
  - mcp

# 复杂嵌套
env:
  PATH: /usr/local/bin
  DEBUG: null

不支持(vs 真实 YAML 1.2 规范)

  • ❌ 多行 block scalar(| >
  • ❌ flow style({a: 1, b: 2} / [1, 2, 3]
  • ❌ 锚点 & 引用(&anchor / *ref
  • ❌ 标签(!!str / !!int
  • ❌ Tab 缩进(只支持空格)
  • ❌ 混合 key 类型({a: 1, 2: b}
  • ❌ 日期 / 时间类型
  • ❌ 多文档(--- 分隔)

核心 4 件套

1️⃣ preprocess:source → Line[]

  • \n 切行
  • 算 indent(开头的空格数)
  • 去掉注释(注意引号内 # 不算)
  • 过滤空行

2️⃣ parseBlock = dispatch by first char

  • - 开头 → parseSequence
  • key: 开头 → parseMapping

3️⃣ 缩进 = 递归边界

parseBlock(lines, i, baseIndent) 解析 indent ≥ baseIndent 的所有行。indent 减小就 return。这天然支持任意深度嵌套。

4️⃣ parseScalar 6 路

"abc" | 'abc'      string (剥引号)
null | ~ | ""      null
true | True        boolean
123                integer
1.5                float
其他               string

真实代码对照

CC 实际用 yaml 库(外部依赖)。本 demo 是教学用自实现,理解原理后可换回官方库。

Demo 真实 yaml 库 简化
preprocess yaml/lib/lexer (~500 行) 30 行
parseBlock yaml/lib/parser (~2000 行) 80 行
parseScalar yaml/lib/schema (~500 行) 10 行

进阶练习

  1. 加 flow style{a: 1, b: 2} / [1, 2, 3]
  2. 加 block scalar\| 保留换行 / > 折叠换行
  3. 加锚点引用&anchor / *ref 实现递归数据
  4. 加错误恢复:解析失败给 line:col 定位
  5. 加 JSON 兼容输出:自动把 key 转为 JSON 兼容(不加引号)
  6. 加 type tag!!int "42" 强制转换

相关阅读