step/meta.go

65 lines
1.8 KiB
Go

package step
import "strings"
const metaRule = "---"
// Meta represents optional metadata that can occur at the very start of
// a document.
type Meta = map[string] string
// SplitMeta parses the metadata (if it exists), returning a map representing it
// along with the rest of the input as a string. If there is no metadata, an
// empty map will be returned.
func SplitMeta (input string) (Meta, string, error) {
// i hate crlf!!!!! uwehhh!!! TODO remove
input = strings.ReplaceAll(input, "\r\n", "\n")
// TODO call internal function that takes in an io.Reader and scans it
// by line instead of operating directly on the string. have that call
// yet another function which will solve #11
// stop if there is no metadata
if !strings.HasPrefix(input, metaRule + "\n") {
return Meta { }, input, nil
}
// get the start and the end of the metadata
input = strings.TrimPrefix(input, metaRule)
index := strings.Index(input, "\n" + metaRule + "\n")
if index < 0 {
return nil, "", ErrMetaNeverClosed
}
metaStr := input[:index]
bodyStr := input[index + len(metaRule) + 2:]
// parse metadata
meta, err := ParseMeta(metaStr)
if err != nil { return Meta { }, "", err }
return meta, bodyStr, nil
}
// ParseMeta parses isolated metadata (without the horizontal starting and
// ending rules).
func ParseMeta (input string) (Meta, error) {
meta := make(Meta)
for _, line := range strings.Split(input, "\n") {
line = strings.TrimSpace(line)
if line == "" { continue }
key, value, ok := strings.Cut(line, ":")
if !ok {
return nil, ErrMetaMalformed
}
key = strings.ToLower(strings.TrimSpace(key))
value = strings.TrimSpace(value)
if key == "" {
return nil, ErrMetaMalformed
}
if _, exists := meta[key]; exists {
return nil, ErrMetaDuplicateKey
}
meta[key] = value
}
return meta, nil
}