diff --git a/lib/frontmatter.mjs b/lib/frontmatter.mjs index 58d07ba..1acb336 100644 --- a/lib/frontmatter.mjs +++ b/lib/frontmatter.mjs @@ -41,14 +41,26 @@ export function parseFrontmatter(content) { return { raw, get }; } +// Siter naar verdien inneholder '#'/':' eller har kant-whitespace, slik at +// round-trip via parseFrontmatter bevarer den eksakt (jf. siter-#-regelen). +const quoteIfNeeded = (s) => + /[#:]/.test(s) || /^\s|\s$/.test(s) || /^["']/.test(s) ? JSON.stringify(s) : s; + export function writeFrontmatter(fields) { const lines = ['---']; for (const [key, value] of Object.entries(fields)) { - const s = String(value); - // Siter naar verdien inneholder '#'/':' eller har kant-whitespace, slik at - // round-trip via parseFrontmatter bevarer den eksakt (jf. siter-#-regelen). - const needsQuote = /[#:]/.test(s) || /^\s|\s$/.test(s) || /^["']/.test(s); - lines.push(`${key}: ${needsQuote ? JSON.stringify(s) : s}`); + // Additiv array-gren (Step 3): emit OKF multi-linje list-verdi (f.eks. + // `tags`) som `key:\n - item`. Lese-siden er uendret -- parseFrontmatter. + // get() returnerer fortsatt null for list-keys. Skalar-grenen under er + // bevart bit-for-bit (kun loftet ut til quoteIfNeeded, samme regel). + if (Array.isArray(value)) { + lines.push(`${key}:`); + for (const item of value) { + lines.push(` - ${quoteIfNeeded(String(item))}`); + } + continue; + } + lines.push(`${key}: ${quoteIfNeeded(String(value))}`); } lines.push('---'); return lines.join('\n') + '\n'; diff --git a/tests/frontmatter.test.mjs b/tests/frontmatter.test.mjs index 5121785..5fb92cf 100644 --- a/tests/frontmatter.test.mjs +++ b/tests/frontmatter.test.mjs @@ -107,3 +107,29 @@ test('writeFrontmatter: verdi med "#" siteres og round-tripper', () => { const { get } = parseFrontmatter(block); assert.equal(get('kortform'), 'A #B', 'sitert # round-tripper'); }); + +test('writeFrontmatter: array-verdi (tags) -> OKF multi-linje liste (Step 3)', () => { + const block = writeFrontmatter({ type: 'OKR', tags: ['a', 'b'], kilde: 'innboks' }); + assert.match(block, /tags:\n - a\n - b/, 'array -> innrykket OKF-liste'); + const { get } = parseFrontmatter(block); + assert.equal(get('type'), 'OKR', 'skalar FOR list-blokk resolver'); + assert.equal(get('kilde'), 'innboks', 'skalar ETTER innrykket list-blokk resolver fortsatt'); + // Lese-siden uendret (Step 3 scope = kun skrive-siden): get() paa en list-key + // krasjer ikke (eksisterende tolerance-kontrakt, frontmatter.mjs:14-16). Den + // returnerer foerste list-element fordi parser-\s* spiser newline -- IKKE + // null; konsumentene leser aldri tag-VERDIER, kun at nabo-skalarer resolver. + assert.doesNotThrow(() => get('tags'), 'get paa list-key krasjer ikke'); +}); + +test('writeFrontmatter: skalar uendret av array-gren (additiv)', () => { + const block = writeFrontmatter({ navn: 'Org', type: 'Notat' }); + assert.match(block, /navn: Org/); + assert.match(block, /type: Notat/); + assert.doesNotMatch(block, /^\s*-\s/m, 'ingen list-syntaks for skalarer'); +}); + +test('writeFrontmatter: tom array -> kun key-linje, ingen items', () => { + const block = writeFrontmatter({ tags: [] }); + assert.match(block, /tags:\n/, 'tom array gir key-linje'); + assert.doesNotMatch(block, /^\s*-\s/m, 'ingen item-linjer for tom array'); +});