73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
package parser
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// frontmatterDelim is the delimiter line that opens and closes a YAML
|
|
// frontmatter block at the top of a slide file.
|
|
var frontmatterDelim = []byte("---")
|
|
|
|
// frontmatter holds the metadata fields recognized in a slide's YAML
|
|
// frontmatter block.
|
|
type frontmatter struct {
|
|
Title string `yaml:"title"`
|
|
Class string `yaml:"class"`
|
|
Notes string `yaml:"notes"`
|
|
Skip bool `yaml:"skip"`
|
|
Incremental bool `yaml:"incremental"`
|
|
}
|
|
|
|
// splitFrontmatter separates a leading YAML frontmatter block (delimited by
|
|
// "---" lines) from the remaining Markdown body. If data has no frontmatter
|
|
// block, it returns a nil frontmatter slice and the original data as body.
|
|
func splitFrontmatter(data []byte) (fm []byte, body []byte) {
|
|
rest := bytes.TrimLeft(data, "\r\n")
|
|
if !bytes.HasPrefix(rest, frontmatterDelim) {
|
|
return nil, data
|
|
}
|
|
afterOpen := rest[len(frontmatterDelim):]
|
|
afterOpen = bytes.TrimLeft(afterOpen, " \t")
|
|
if len(afterOpen) > 0 && afterOpen[0] != '\n' && afterOpen[0] != '\r' {
|
|
// The "---" is followed by other content on the same line, so it is
|
|
// not a frontmatter delimiter.
|
|
return nil, data
|
|
}
|
|
nlIdx := bytes.IndexByte(afterOpen, '\n')
|
|
if nlIdx == -1 {
|
|
return nil, data
|
|
}
|
|
remainder := afterOpen[nlIdx+1:]
|
|
|
|
closeIdx := bytes.Index(remainder, []byte("\n---"))
|
|
if closeIdx == -1 {
|
|
return nil, data
|
|
}
|
|
fm = remainder[:closeIdx]
|
|
|
|
after := remainder[closeIdx+len("\n---"):]
|
|
after = bytes.TrimLeft(after, "\r")
|
|
if nl := bytes.IndexByte(after, '\n'); nl != -1 {
|
|
after = after[nl+1:]
|
|
} else {
|
|
after = nil
|
|
}
|
|
return fm, after
|
|
}
|
|
|
|
// parseFrontmatter extracts and parses the frontmatter block from data,
|
|
// returning the parsed metadata and the remaining Markdown body.
|
|
func parseFrontmatter(data []byte) (frontmatter, []byte, error) {
|
|
raw, body := splitFrontmatter(data)
|
|
var fm frontmatter
|
|
if raw == nil {
|
|
return fm, body, nil
|
|
}
|
|
if err := yaml.Unmarshal(raw, &fm); err != nil {
|
|
return fm, body, fmt.Errorf("parsing frontmatter: %w", err)
|
|
}
|
|
return fm, body, nil
|
|
}
|