- lib/product-doc-parser.ts: parseProductDocMd(md) → {ok, frontmatter, body}
| {ok:false, errors[]} met line-info bij YAML-fouten. Pattern gespiegeld
uit lib/idea-plan-parser.ts.
- lib/product-doc-frontmatter.ts: setProductDocFrontmatterFields(md, patch)
laat de server `last_updated` server-side normaliseren (P2-review-fix
uit docs/recommendations/product-docs-storage-system-review-2026-05-16).
Gebruikt yaml.parseDocument om field-ordering best-effort te behouden.
- todayIsoDate() helper voor 'yyyy-mm-dd' string.
- __tests__: 19 nieuwe tests groen — parse-success/fail-paden, en
expliciete P2-coverage (vervangen + toevoegen last_updated, behoud
overige velden + body).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
59 lines
2 KiB
TypeScript
59 lines
2 KiB
TypeScript
// Server-side serializer die individuele frontmatter-velden bijwerkt in
|
|
// een al-gevalideerde markdown-doc. P2-review-fix uit
|
|
// docs/recommendations/product-docs-storage-system-review-2026-05-16.md
|
|
// (last_updated moet door de server worden gezet, niet door de user).
|
|
//
|
|
// Caller MOET parseProductDocMd al hebben aangeroepen voor pre-validatie
|
|
// — deze functie throwed bij parse-fouten.
|
|
|
|
import { parseDocument } from 'yaml'
|
|
|
|
const FRONTMATTER_RE =
|
|
/^(---\r?\n)([\s\S]*?)(\r?\n---\r?\n?)([\s\S]*)$/
|
|
|
|
/**
|
|
* Mutates de YAML-frontmatter van `md` met de gegeven `patch`-keys
|
|
* (bv. `{ last_updated: '2026-05-16' }`) en geeft de nieuwe markdown
|
|
* terug. Behoudt body en frontmatter-delimiters; overige velden blijven
|
|
* staan (best-effort op ordering en whitespace via yaml-lib).
|
|
*/
|
|
export function setProductDocFrontmatterFields(
|
|
md: string,
|
|
patch: Record<string, unknown>,
|
|
): string {
|
|
const match = md.match(FRONTMATTER_RE)
|
|
if (!match) {
|
|
throw new Error(
|
|
'setProductDocFrontmatterFields: input mist yaml-frontmatter (geen `---` opener gevonden)',
|
|
)
|
|
}
|
|
|
|
const [, openMarker, frontmatterRaw, closeMarker, body] = match
|
|
|
|
const doc = parseDocument(frontmatterRaw)
|
|
if (doc.errors.length > 0) {
|
|
throw new Error(
|
|
`setProductDocFrontmatterFields: yaml parse-error op regel ${
|
|
doc.errors[0].linePos?.[0]?.line ?? '?'
|
|
}: ${doc.errors[0].message}`,
|
|
)
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(patch)) {
|
|
doc.set(key, value)
|
|
}
|
|
|
|
// yaml.Document.toString() voegt vaak een trailing newline toe —
|
|
// strippen voorkomt dubbele newlines vóór de afsluitende `---`.
|
|
const newFrontmatter = doc.toString().replace(/\r?\n$/, '')
|
|
|
|
return `${openMarker}${newFrontmatter}${closeMarker}${body}`
|
|
}
|
|
|
|
/**
|
|
* ISO-date (yyyy-mm-dd) van vandaag — handige helper voor de server om
|
|
* `last_updated` mee te zetten bij elke save.
|
|
*/
|
|
export function todayIsoDate(now: Date = new Date()): string {
|
|
return now.toISOString().slice(0, 10)
|
|
}
|