54 lines
1.6 KiB
Go
54 lines
1.6 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) {
|
|
// i hate crlf!!!!! uwehhh!!!
|
|
input = strings.ReplaceAll(input, "\r\n", "\n")
|
|
|
|
// stop if there is no front matter
|
|
if !strings.HasPrefix(input, frontMatterRule + "\n") {
|
|
return FrontMatter { }, input, nil
|
|
}
|
|
|
|
// get the start and the end of the front matter
|
|
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)
|
|
|
|
// iterate over the lines
|
|
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
|
|
}
|