/* RFC-1051: test YAML frontmatter parsing and serialization helpers used by migrators. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1051: initial yaml-utils test. */ import { test, expect } from "vitest"; import { parseFrontmatter, parseSimpleYaml, serializeFrontmatter, stripQuotes, needsQuoting, yamlValue, escapeYamlString, getIndent, } from "../yaml-utils.ts"; test("parseFrontmatter extracts frontmatter and body", () => { const raw = "---\ntitle: Test\n---\nBody content"; const { frontmatter, body } = parseFrontmatter(raw); expect(frontmatter.title).toBe("Test"); expect(body).toBe("Body content"); }); test("parseFrontmatter returns empty frontmatter when no delimiter", () => { const { frontmatter, body } = parseFrontmatter("Just body"); expect(frontmatter).toEqual({}); expect(body).toBe("Just body"); }); test("parseSimpleYaml parses nested objects", () => { const yaml = "top:\n child: value\n num: 42"; const result = parseSimpleYaml(yaml); expect(result.top).toEqual({ child: "value", num: "42" }); }); test("parseSimpleYaml handles empty values and comments", () => { const yaml = "key1: value\n# comment\nkey2:"; const result = parseSimpleYaml(yaml); expect(result.key1).toBe("value"); }); test("stripQuotes removes surrounding quotes", () => { expect(stripQuotes('"hello"')).toBe("hello"); expect(stripQuotes("'hello'")).toBe("hello"); expect(stripQuotes("hello")).toBe("hello"); }); test("needsQuoting detects special characters", () => { expect(needsQuoting("normal")).toBe(false); expect(needsQuoting("with: colon")).toBe(true); expect(needsQuoting("with# hash")).toBe(true); expect(needsQuoting("")).toBe(true); expect(needsQuoting(" leading")).toBe(true); expect(needsQuoting("trailing ")).toBe(true); }); test("yamlValue quotes values that need quoting", () => { expect(yamlValue("normal")).toBe("normal"); expect(yamlValue("with: colon")).toBe('"with: colon"'); }); test("escapeYamlString escapes backslashes and quotes", () => { expect(escapeYamlString('hello "world"')).toBe('hello \\"world\\"'); expect(escapeYamlString("back\\slash")).toBe("back\\\\slash"); }); test("getIndent counts leading spaces", () => { expect(getIndent(" two")).toBe(2); expect(getIndent("zero")).toBe(0); expect(getIndent(" four")).toBe(4); }); test("serializeFrontmatter produces valid YAML with delimiters", () => { const result = serializeFrontmatter({ title: "Test", count: 3 }); expect(result.startsWith("---\n")).toBe(true); expect(result).toContain("---"); expect(result).toContain("title: Test"); expect(result).toContain("count: 3"); }); test("serializeFrontmatter skips null and undefined values", () => { const result = serializeFrontmatter({ a: "x", b: null, c: undefined, d: "y" }); expect(result).toContain("a: x"); expect(result).not.toContain("b:"); expect(result).not.toContain("c:"); expect(result).toContain("d: y"); }); test("serializeFrontmatter handles nested objects", () => { const result = serializeFrontmatter({ outer: { inner: "value" } }); expect(result).toContain("outer:"); expect(result).toContain(" inner: value"); }); test("round-trip: parse → serialize → parse preserves string data", () => { const original = "---\ntitle: Test\ncount: 42\n---\nBody"; const { frontmatter } = parseFrontmatter(original); const serialized = serializeFrontmatter(frontmatter); const { frontmatter: roundTripped } = parseFrontmatter(serialized); expect(roundTripped.title).toBe("Test"); expect(roundTripped.count).toBe("42"); });