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 }