all repos — vite @ d3cb74b6d1df9cca082c7fab84325b36c0bce969

a fast (this time, actually) and minimal static site generator

markdown/frontmatter.go (view raw)

 1package markdown
 2
 3import (
 4	"bufio"
 5	"bytes"
 6	"errors"
 7	"fmt"
 8
 9	"gopkg.in/yaml.v3"
10)
11
12type Matter map[string]string
13
14type MarkdownDoc struct {
15	Frontmatter Matter
16	Body        []byte
17}
18
19const (
20	yamlDelim = "---"
21)
22
23func (md *MarkdownDoc) Extract(source []byte) error {
24	bufsize := 1024 * 1024
25	buf := make([]byte, bufsize)
26
27	input := bytes.NewReader(source)
28	s := bufio.NewScanner(input)
29	s.Buffer(buf, bufsize)
30
31	matter := []byte{}
32	body := []byte{}
33
34	s.Split(splitFunc)
35	n := 0
36	for s.Scan() {
37		if n == 0 {
38			matter = s.Bytes()
39		} else if n == 1 {
40			body = s.Bytes()
41		}
42		n++
43	}
44	if err := s.Err(); err != nil {
45		return fmt.Errorf("error: failed to scan text")
46	}
47	if err := yaml.Unmarshal(matter, &md.Frontmatter); err != nil {
48		return fmt.Errorf("error: failed to parse yaml")
49	}
50	md.Body = body
51	return nil
52}
53
54func splitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
55	if atEOF && len(data) == 0 {
56		return 0, nil, nil
57	}
58	delim, err := sniffDelim(data)
59	if err != nil {
60		return 0, nil, err
61	}
62	if delim != yamlDelim {
63		return 0, nil, fmt.Errorf("error: %s is not a supported delimiter", delim)
64	}
65	if x := bytes.Index(data, []byte(delim)); x >= 0 {
66		if next := bytes.Index(data[x+len(delim):], []byte(delim)); next > 0 {
67			return next + len(delim), bytes.TrimSpace(data[:next+len(delim)]), nil
68		}
69		return len(data), bytes.TrimSpace(data[x+len(delim):]), nil
70	}
71	if atEOF {
72		return len(data), data, nil
73	}
74	return 0, nil, nil
75}
76
77func sniffDelim(input []byte) (string, error) {
78	if len(input) < 4 {
79		return "", errors.New("error: input is empty")
80	}
81	return string(input[:3]), nil
82}