All checks were successful
CI / test (push) Successful in 16s
- 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
108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
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`);
|
||
});
|
||
});
|