/*
RFC-0613: Regression tests for parseMarkdownTwinFrontmatter null handling
and buildMarkdownTwinFrontmatter null serialization.
- Do not test page.markdown.validate — that is covered in site-kernel-checks tests.
- RFC-0613: Added regression tests for null parsing and serialization in markdown twin provenance.
*/
import { describe, it, expect } from "vitest";
import {
parseMarkdownTwinFrontmatter,
buildMarkdownTwinFrontmatter,
type MarkdownTwinProvenance,
} from "../semantic/markdown-twin-provenance.ts";
const baseProvenance: MarkdownTwinProvenance = {
canonical: "https://example.com/page/",
language: "de",
lastModified: null,
license: "https://example.com/ai.txt",
generator: "test-generator",
sourceKind: "test",
};
describe("parseMarkdownTwinFrontmatter — null handling (RFC-0613)", () => {
it("parses bare YAML null as JS null for lastModified", () => {
const content = `---\nlastModified: null\ncanonical: "https://example.com/"\n---\n\nbody`;
const parsed = parseMarkdownTwinFrontmatter(content);
expect(parsed).not.toBeNull();
expect(parsed!.frontmatter.lastModified).toBeNull();
});
it('parses quoted YAML "null" as JS null (parser strips quotes before null check)', () => {
const content = `---\nlastModified: "null"\ncanonical: "https://example.com/"\n---\n\nbody`;
const parsed = parseMarkdownTwinFrontmatter(content);
expect(parsed).not.toBeNull();
expect(parsed!.frontmatter.lastModified).toBeNull();
});
it("parses valid date string as string", () => {
const content = `---\nlastModified: "2026-07-30"\ncanonical: "https://example.com/"\n---\n\nbody`;
const parsed = parseMarkdownTwinFrontmatter(content);
expect(parsed).not.toBeNull();
expect(parsed!.frontmatter.lastModified).toBe("2026-07-30");
});
it("parses invalid date string as string (not null)", () => {
const content = `---\nlastModified: "2026-7-4"\ncanonical: "https://example.com/"\n---\n\nbody`;
const parsed = parseMarkdownTwinFrontmatter(content);
expect(parsed).not.toBeNull();
expect(parsed!.frontmatter.lastModified).toBe("2026-7-4");
});
});
describe("buildMarkdownTwinFrontmatter — null serialization (RFC-0613)", () => {
it("serializes null lastModified as bare YAML null", () => {
const provenance: MarkdownTwinProvenance = { ...baseProvenance, lastModified: null };
const fm = buildMarkdownTwinFrontmatter(provenance, "sha256:abc");
expect(fm).toContain("lastModified: null");
expect(fm).not.toContain('lastModified: "null"');
});
it("serializes date string lastModified as quoted YAML", () => {
const provenance: MarkdownTwinProvenance = { ...baseProvenance, lastModified: "2026-07-30" };
const fm = buildMarkdownTwinFrontmatter(provenance, "sha256:abc");
expect(fm).toContain('lastModified: "2026-07-30"');
});
});
describe("round-trip: build → parse (RFC-0613)", () => {
it("null lastModified survives build → parse round-trip as JS null", () => {
const provenance: MarkdownTwinProvenance = { ...baseProvenance, lastModified: null };
const fm = buildMarkdownTwinFrontmatter(provenance, "sha256:abc");
const parsed = parseMarkdownTwinFrontmatter(
`${fm}## Summary\n\nTest.\n\n## Business context\n\nTest.`,
);
expect(parsed).not.toBeNull();
expect(parsed!.frontmatter.lastModified).toBeNull();
});
it("date string lastModified survives build → parse round-trip as string", () => {
const provenance: MarkdownTwinProvenance = { ...baseProvenance, lastModified: "2026-07-30" };
const fm = buildMarkdownTwinFrontmatter(provenance, "sha256:abc");
const parsed = parseMarkdownTwinFrontmatter(
`${fm}## Summary\n\nTest.\n\n## Business context\n\nTest.`,
);
expect(parsed).not.toBeNull();
expect(parsed!.frontmatter.lastModified).toBe("2026-07-30");
});
});