Files
obsidian-jekyll-publish/src/frontmatter.test.ts
Claude fb5d11dd6a
All checks were successful
CI / test (push) Successful in 16s
feat: unified, editable frontmatter editor in publish modal
- Preset fields (from settings) are now seeded as editable/deletable rows in
  the modal alongside custom ones, using one consistent row style.
- The note's own merged frontmatter is shown as read-only (disabled) rows at
  the top of the list (only when 'Merge document frontmatter' is on, and only
  for keys not overridden by an editable row).
- Drops the separate read-only 'resolved' text preview; the rows are the
  WYSIWYG result.

Adds pure, unit-tested composeFrontmatter()/docFrontmatterToPairs() and removes
the superseded resolveFrontmatter(). Editable rows are authoritative: on a key
collision they override the merged document field. Presets are deep-copied so
editing rows never mutates saved settings.

Co-Authored-By: Claude
2026-06-19 03:21:04 +00:00

108 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from "vitest";
import { composeFrontmatter, docFrontmatterToPairs, parseNote, 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("docFrontmatterToPairs", () => {
test("converts a record to ordered string pairs", () => {
const pairs = docFrontmatterToPairs({
title: "Hello",
date: new Date("2026-02-06T00:00:00Z"),
draft: true,
});
expect(pairs).toEqual([
{ key: "title", value: "Hello" },
{ key: "date", value: "2026-02-06" },
{ key: "draft", value: "true" },
]);
});
test("empty record yields an empty array", () => {
expect(docFrontmatterToPairs({})).toEqual([]);
});
});
describe("composeFrontmatter", () => {
const doc = [
{ key: "title", value: "Hello" },
{ key: "date", value: "2026-02-06" },
];
const editable = [
{ key: "layout", value: "post" },
{ key: "kind", value: "essay" },
];
test("merge on: document fields first, then editable rows", () => {
expect(composeFrontmatter(doc, editable, true)).toEqual([
{ key: "title", value: "Hello" },
{ key: "date", value: "2026-02-06" },
{ key: "layout", value: "post" },
{ key: "kind", value: "essay" },
]);
});
test("merge off: only the editable rows", () => {
expect(composeFrontmatter(doc, editable, false)).toEqual(editable);
});
test("an editable row overrides a document field with the same key (doc field dropped)", () => {
const ed = [
{ key: "title", value: "Override" },
{ key: "layout", value: "post" },
];
expect(composeFrontmatter(doc, ed, true)).toEqual([
{ key: "date", value: "2026-02-06" },
{ key: "title", value: "Override" },
{ key: "layout", value: "post" },
]);
});
test("blank-key editable rows are skipped", () => {
const ed = [
{ key: "", value: "" },
{ key: "layout", value: "post" },
{ key: " ", value: "x" },
];
expect(composeFrontmatter([], ed, true)).toEqual([{ key: "layout", value: "post" }]);
});
test("duplicate editable keys: last value wins at first position", () => {
const ed = [
{ key: "tag", value: "a" },
{ key: "tag", value: "b" },
];
expect(composeFrontmatter([], ed, false)).toEqual([{ key: "tag", value: "b" }]);
});
});
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`);
});
test("YAML-special boolean strings are quoted", () => {
expect(serializeFrontmatter([{ key: "draft", value: "true" }])).toBe(`---\ndraft: "true"\n---\n`);
expect(serializeFrontmatter([{ key: "published", value: "false" }])).toBe(`---\npublished: "false"\n---\n`);
});
test("numeric-looking strings are quoted", () => {
expect(serializeFrontmatter([{ key: "n", value: "42" }])).toBe(`---\nn: "42"\n---\n`);
});
test("ISO date strings remain bare (not quoted as numeric)", () => {
expect(serializeFrontmatter([{ key: "date", value: "2026-06-11" }])).toBe(`---\ndate: 2026-06-11\n---\n`);
});
});