feat: frontmatter parse/resolve/serialize

Co-Authored-By: Claude
This commit is contained in:
2026-06-19 01:44:24 +00:00
parent b321633421
commit f2edd9b0ab
2 changed files with 106 additions and 0 deletions

54
src/frontmatter.test.ts Normal file
View File

@@ -0,0 +1,54 @@
import { describe, expect, test } from "vitest";
import { parseNote, resolveFrontmatter, serializeFrontmatter } from "./frontmatter";
describe("parseNote", () => {
test("splits frontmatter and body, strips BOM", () => {
const { frontmatter, body } = parseNote("---\ntitle: Hi\n---\nHello\n");
expect(frontmatter).toEqual({ title: "Hi" });
expect(body).toBe("Hello\n");
});
test("no frontmatter returns empty object and full body", () => {
expect(parseNote("Just text")).toEqual({ frontmatter: {}, body: "Just text" });
});
});
describe("resolveFrontmatter", () => {
const presets = [{ key: "layout", value: "post" }, { key: "kind", value: "essay" }];
test("presets only when mergeDoc is false", () => {
expect(resolveFrontmatter(presets, { title: "X" }, [], false)).toEqual(presets);
});
test("merge appends doc keys and doc overrides preset value", () => {
const r = resolveFrontmatter(presets, { kind: "note", title: "X" }, [], true);
expect(r).toEqual([
{ key: "layout", value: "post" },
{ key: "kind", value: "note" },
{ key: "title", value: "X" },
]);
});
test("custom rows come last and override everything", () => {
const r = resolveFrontmatter(presets, {}, [{ key: "layout", value: "page" }], false);
expect(r[0]).toEqual({ key: "layout", value: "page" });
expect(r).toHaveLength(2);
});
test("date object is rendered as YYYY-MM-DD", () => {
const r = resolveFrontmatter([], { date: new Date("2026-06-11T00:00:00Z") }, [], true);
expect(r).toEqual([{ key: "date", value: "2026-06-11" }]);
});
});
describe("serializeFrontmatter", () => {
test("bare-safe values unquoted, others JSON-quoted", () => {
const out = serializeFrontmatter([
{ key: "layout", value: "post" },
{ key: "date", value: "2026-06-11" },
{ key: "title", value: "On making a game" },
{ key: "description", value: "And how it's different" },
]);
expect(out).toBe(
`---\nlayout: post\ndate: 2026-06-11\ntitle: On making a game\ndescription: "And how it's different"\n---\n`
);
});
test("empty value becomes quoted empty string", () => {
expect(serializeFrontmatter([{ key: "tags", value: "" }])).toBe(`---\ntags: ""\n---\n`);
});
});