/** 匹配以 --- 开头/结尾的 YAML front matter(全文开头) */ const FRONT_MATTER_RE = /^---[\t ]*\r?\n([\s\S]*?)\r?\n---[\t ]*(?:\r?\n|$)([\s\S]*)$/ export function splitFrontMatter(markdown: string): { front: string | null; body: string } { const s = markdown.replace(/^\uFEFF/, "") const m = FRONT_MATTER_RE.exec(s) if (!m) { return { front: null, body: markdown } } return { front: m[1].trim(), body: m[2] } } /** 正文渲染用:去掉 front matter,避免把元数据块排进 HTML */ export function stripFrontMatter(markdown: string): string { return splitFrontMatter(markdown).body } function pickYamlScalar(block: string, key: string): string { const lines = block.split(/\r?\n/) const prefix = `${key}:` for (const line of lines) { const t = line.trim() if (!t.startsWith(prefix)) { continue } let v = t.slice(prefix.length).trim() if (!v) { return "" } if ( (v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'")) ) { return v.slice(1, -1) } return v } return "" } /** 列表摘要:优先 `desc`,其次 `description`(简单标量行) */ export function extractFrontMatterDesc(markdown: string): string { const { front } = splitFrontMatter(markdown) if (!front) { return "" } const d = pickYamlScalar(front, "desc") || pickYamlScalar(front, "description") return d.trim() } export function listCardSummaryFromPostBody(bodyMarkdown: string, dbExcerpt: string): string { const fromFm = extractFrontMatterDesc(bodyMarkdown) if (fromFm) { return fromFm } return (dbExcerpt ?? "").trim() }