frontmatter.spec.ts 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import { describe, expect, it } from 'vitest'
  2. import { parseDocument, serializeDocument, unwrap } from '../src/repo/frontmatter'
  3. describe('frontmatter 解析(B3/B4/B5)', () => {
  4. it('标准结构', () => {
  5. const r = parseDocument('---\n状态: 候选\n版本: 3\n---\n\n正文第一行\n')
  6. expect(r.ok).toBe(true)
  7. if (r.ok) {
  8. expect(r.data.fields['状态']).toBe('候选')
  9. expect(r.data.fields['版本']).toBe(3)
  10. expect(r.data.body).toContain('正文第一行')
  11. }
  12. })
  13. it('无 frontmatter=空字段(合法)', () => {
  14. const r = parseDocument('# 只有正文\n')
  15. expect(r.ok).toBe(true)
  16. if (r.ok) expect(Object.keys(r.data.fields)).toEqual([])
  17. })
  18. it('B5:未闭合→parse-error 带明细,不静默', () => {
  19. const r = parseDocument('---\n状态: 候选\n')
  20. expect(r.ok).toBe(false)
  21. if (!r.ok) {
  22. expect(r.reason).toBe('parse-error')
  23. expect(r.detail).toContain('未闭合')
  24. }
  25. })
  26. it('B5:YAML 语法错→parse-error 带明细', () => {
  27. const r = parseDocument('---\n状态: [未闭合\n---\nx\n')
  28. expect(r.ok).toBe(false)
  29. if (!r.ok) expect(r.reason).toBe('parse-error')
  30. })
  31. it('B4:unwrap 区分 missing 与 parse-error 的报错语义', () => {
  32. const missing: ReturnType<typeof parseDocument> = { ok: false, reason: 'missing', detail: '' }
  33. expect(() => unwrap(missing, '契约')).toThrow('没有数据')
  34. const broken: ReturnType<typeof parseDocument> = { ok: false, reason: 'parse-error', detail: 'YAML 解析失败:…' }
  35. expect(() => unwrap(broken, '契约')).toThrow('解析失败')
  36. })
  37. })
  38. describe('frontmatter 序列化(B9 稳定输出)', () => {
  39. it('键序稳定:定义序优先,其余按中文排序', () => {
  40. const a = serializeDocument({ 状态: '候选', 版本: 1 }, '正文')
  41. const b = serializeDocument({ 版本: 1, 状态: '候选' }, '正文')
  42. expect(a).toBe(b)
  43. })
  44. it('空字段省略 frontmatter', () => {
  45. expect(serializeDocument({}, '正文')).toBe('正文\n')
  46. })
  47. it('往返一致', () => {
  48. const text = serializeDocument({ 状态: '已确认', 来源引用: '大纲/卷规划/卷01/卷纲.md@5' }, '# 标题\n内容')
  49. const r = parseDocument(text)
  50. expect(r.ok).toBe(true)
  51. if (r.ok) {
  52. expect(r.data.fields['状态']).toBe('已确认')
  53. expect(r.data.body).toContain('# 标题')
  54. }
  55. })
  56. })