step/frontmatter.go

47 lines
1.4 KiB
Go

package step
import "strings"
const frontMatterRule = "---"
// FrontMatter represents optional metadata that can occur at the very start of
// a document.
type FrontMatter = map[string] string
// SplitFrontMatter parses the front matter (if it exists), returning a map
// representing it along with the rest of the input as a string. If there is no
// front matter, an empty map will be returned.
func SplitFrontMatter (input string) (FrontMatter, string, error) {
if !strings.HasPrefix(input, frontMatterRule + "\n") {
// no front matter at all
return FrontMatter { }, input, nil
}
input = strings.TrimPrefix(input, frontMatterRule)
index := strings.Index(input, "\n" + frontMatterRule + "\n")
if index < 0 {
return nil, "", ErrFrontMatterNeverClosed
}
frontMatterRaw := input[:index]
body := input[index + len(frontMatterRule) + 2:]
frontMatter := make(FrontMatter)
for _, line := range strings.Split(frontMatterRaw, "\n") {
line = strings.TrimSpace(line)
if line == "" { continue }
key, value, ok := strings.Cut(line, ":")
if !ok {
return nil, "", ErrFrontMatterMalformed
}
key = strings.ToLower(strings.TrimSpace(key))
value = strings.TrimSpace(value)
if key == "" {
return nil, "", ErrFrontMatterMalformed
}
if _, exists := frontMatter[key]; exists {
return nil, "", ErrFrontMatterDuplicateKey
}
frontMatter[key] = value
}
return frontMatter, body, nil
}