From c24a7e2a11264e4e6274a7aed93b212cf7568e0d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 19 Jun 2026 01:49:33 +0000 Subject: [PATCH] fix: quote YAML-special and numeric frontmatter values formatValue now detects YAML-special tokens (true/false/null/yes/no/on/off/y/n/~) and numeric-looking strings, quoting them via JSON.stringify so YAML parsers cannot misread them as booleans or numbers. ISO date strings (YYYY-MM-DD) are exempt and remain bare for readability. Adds four covering tests. Co-Authored-By: Claude --- src/frontmatter.test.ts | 10 ++++++++++ src/frontmatter.ts | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/frontmatter.test.ts b/src/frontmatter.test.ts index 0699ed2..626e287 100644 --- a/src/frontmatter.test.ts +++ b/src/frontmatter.test.ts @@ -51,4 +51,14 @@ describe("serializeFrontmatter", () => { 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`); + }); }); diff --git a/src/frontmatter.ts b/src/frontmatter.ts index abc5a4e..4f514cb 100644 --- a/src/frontmatter.ts +++ b/src/frontmatter.ts @@ -47,6 +47,10 @@ export function serializeFrontmatter(pairs: Pair[]): string { function formatValue(v: string): string { if (v === "") return '""'; + const yamlSpecial = /^(true|false|null|yes|no|on|off|y|n|~)$/i.test(v); + const isoDate = /^\d{4}-\d{2}-\d{2}$/.test(v); + const numericLike = !isoDate && /^[+-]?(\d|\.\d)/.test(v); + if (yamlSpecial || numericLike) return JSON.stringify(v); const bareSafe = /^[A-Za-z0-9_./-][A-Za-z0-9_./ -]*$/.test(v) && !/^\s|\s$/.test(v); return bareSafe ? v : JSON.stringify(v); }