
FrontMatter.pudu
Pudu42 lines1.8 KB
1/** @Docgen.Markdown.FrontMatter — YAML header split from article body lines */2module PuduLangDocgen.Markdown.FrontMatter34import Std.Text as Text5import PuduLangDocgen as Docgen6import PuduLangDocgen.Yaml as Yaml78/** @Docgen.Markdown.Line — one body line with its one-based source number */9export type Line = { text: Str, number: Int }1011/** @Docgen.Markdown.Header — metadata and the body lines after it */12export type Header = { meta: Array[(Str, Docgen.Meta)], lines: Array[Line] }13141516export fn split(text: Str) -> Result[Header, (Int, Str)] {17 let unmarked = if text.startsWith("\u{feff}") { text.drop(1) } else { text }18 let all = unmarked.replace("\r\n", "\n").replace("\r", "\n").split("\n")19 if Text.trimEnd(all[0]) != "---" { return Ok(Header{meta: [], lines: numbered(&all, 0)}) }20 var close = 121 while close < all.length() && Text.trimEnd(all[close]) != "---" && Text.trimEnd(all[close]) != "..." { close = close + 1 }22 if close >= all.length() { return Err((1, "front matter is not closed")) }23 let header = all.slice(1, close).join("\n")24 let body = numbered(&all, close + 1)25 if header.trim().isEmpty() { return Ok(Header{meta: [], lines: body}) }26 let parsed = match Yaml.decode(header) {27 case Ok(found) => found28 case Err(reason) => { return Err((2, "front matter: " + reason)) }29 }30 match parsed {31 case Docgen.Fields(fields) => Ok(Header{meta: fields, lines: body})32 case _ => Err((2, "front matter must be a mapping of keys to values"))33 }34}353637fn numbered(all: &Array[Str], from: Int) -> Array[Line] {38 var result: Array[Line] = []39 for index in from..all.length() { result = result.push(Line{text: all[index], number: index + 1}) }40 result41}42