# Beancount 语法覆盖率矩阵

> 本文档记录 `src/domain/ledger.ts` 解析器对 Beancount 语法的覆盖情况。
> 决策依据见 `plan.md`「已实现的核心功能」章节的 Tree-sitter 决策。

## 解析策略

- **写出的语法**：只生成 Beancount 标准语法的子集（见「写支持」列）
- **读入的语法**：尽量多识别真实用户账本的指令，不认识的记入 `unsupported`（只读保留），不阻断整体解析
- **只读保留**：`unsupported` 中的指令原样保留在 `LedgerIndex.files[].content`，导出时不变，桌面端可正常读取

## 覆盖率矩阵

### 指令（directive）

| 指令 | 读支持 | 写支持 | 说明 |
|------|--------|--------|------|
| `open` 账户 | ✅ | ✅ | `2026-01-01 open Assets:Alipay CNY` |
| `close` 账户 | ✅ | ✅ | `2026-01-01 close Assets:Old` |
| 交易（`*`/`!`） | ✅ | ✅ | header + postings + metadata |
| `balance` 断言 | ✅（只读） | ❌ | 记入 `balances`，用于诊断校验 |
| `option` | ✅（只读） | ❌ | 记入 `options`（如 operating_currency） |
| `pad` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `note` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `commodity` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `price` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `event` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `document` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `query` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `custom` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `plugin` | ⚠️ 只读保留 | ❌ | 记入 `unsupported` |
| `include` | ✅（文件级） | ❌ | 由调用方处理多文件传入 |

### 交易语法

| 语法 | 读支持 | 写支持 | 示例 |
|------|--------|--------|------|
| flag（`*` 已确认 / `!` 未确认） | ✅ | ✅（仅 `*`） | `2026-01-01 * "payee" "narration"` |
| payee + narration | ✅ | ✅ | 双引号 |
| 单 narration（无 payee） | ✅ | ✅ | |
| `#tag`（header 行） | ✅ | ✅ | `... "narration" #food #lunch` |
| `^link`（header 行） | ✅ | ❌ | |
| posting（account + amount + currency） | ✅ | ✅ | `  Assets:Alipay  -24.50 CNY` |
| posting（无金额，elided leg） | ✅ | ❌ | 自动平衡腿 |
| `#tag`（posting 行） | ✅（部分） | ❌ | |
| metadata（交易级） | ✅ | ✅ | `  key: "value"`（header 后、posting 前） |
| metadata（posting 级） | ✅ | ❌ | `  key: "value"`（紧跟 posting 后） |
| cost `{...}` | ✅（解析为 cost 字段） | ❌ | `  Assets:Stocks 10 STOCK {120.00 CNY}` |
| price `@` | ✅（解析为 price 字段） | ❌ | `  Assets:Stocks 10 STOCK @ 130.00 CNY` |
| 多行 posting | ✅ | ✅ | |
| 注释 `;` | ✅（跳过） | ❌ | |

### 其他

| 语法 | 读支持 | 说明 |
|------|--------|------|
| 行内注释 `; comment` | ✅ | 跳过 |
| 全行注释 `;` / `*` | ✅ | 跳过 |
| BOM | ✅ | parseLedger 逐文件处理，BOM 视为首字符（statements.ts 的 parseCsv 才显式去 BOM） |
| CRLF | ✅ | `replace(/\r\n/g, '\n')` |

## 不支持的进阶语法（需 Tree-sitter 时处理）

以下语法在当前正则方案下**不解析**（原样保留），若真实用户账本大量使用，考虑上 `tree-sitter-beancount`：

- `2026-01-01 *` 后的 multi-currency posting 复杂 cost 表达式
- `units()`、`convert()`、`value()` 等表达式
- `META` 全局元数据块
- 跨行字符串

## 测试

覆盖率回归测试见 `tests/ledger.test.ts`。
