summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/templates/frontmatter.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-12-23 12:56:41 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2019-12-23 12:56:41 -0700
commit82bebfab8a6528f24f23dac99ce5b11efab27761 (patch)
tree70d9d4a15b1475a3d9f01cad9a8f60556f9552cd /modules/caddyhttp/templates/frontmatter.go
parentbe3849c2671e74c461e1885d3a15e7e97b967895 (diff)
templates: Change functions, add front matter support, better markdown
Diffstat (limited to 'modules/caddyhttp/templates/frontmatter.go')
-rw-r--r--modules/caddyhttp/templates/frontmatter.go100
1 files changed, 100 insertions, 0 deletions
diff --git a/modules/caddyhttp/templates/frontmatter.go b/modules/caddyhttp/templates/frontmatter.go
new file mode 100644
index 0000000..730cfd1
--- /dev/null
+++ b/modules/caddyhttp/templates/frontmatter.go
@@ -0,0 +1,100 @@
+package templates
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+ "unicode"
+
+ "github.com/naoina/toml"
+ "gopkg.in/yaml.v2"
+)
+
+func extractFrontMatter(input string) (map[string]interface{}, string, error) {
+ // get the bounds of the first non-empty line
+ var firstLineStart, firstLineEnd int
+ lineEmpty := true
+ for i, b := range input {
+ if b == '\n' {
+ firstLineStart = firstLineEnd
+ if firstLineStart > 0 {
+ firstLineStart++ // skip newline character
+ }
+ firstLineEnd = i
+ if !lineEmpty {
+ break
+ }
+ continue
+ }
+ lineEmpty = lineEmpty && unicode.IsSpace(b)
+ }
+ firstLine := input[firstLineStart:firstLineEnd]
+
+ // see what kind of front matter there is, if any
+ var closingFence string
+ var fmParser func([]byte) (map[string]interface{}, error)
+ switch string(firstLine) {
+ case yamlFrontMatterFenceOpen:
+ fmParser = yamlFrontMatter
+ closingFence = yamlFrontMatterFenceClose
+ case tomlFrontMatterFenceOpen:
+ fmParser = tomlFrontMatter
+ closingFence = tomlFrontMatterFenceClose
+ case jsonFrontMatterFenceOpen:
+ fmParser = jsonFrontMatter
+ closingFence = jsonFrontMatterFenceClose
+ default:
+ // no recognized front matter; whole document is body
+ return nil, input, nil
+ }
+
+ // find end of front matter
+ fmEndFenceStart := strings.Index(input[firstLineEnd:], "\n"+closingFence)
+ if fmEndFenceStart < 0 {
+ return nil, "", fmt.Errorf("unterminated front matter")
+ }
+ fmEndFenceStart += firstLineEnd + 1 // add 1 to account for newline
+
+ // extract and parse front matter
+ frontMatter := input[firstLineEnd:fmEndFenceStart]
+ fm, err := fmParser([]byte(frontMatter))
+ if err != nil {
+ return nil, "", err
+ }
+
+ // the rest is the body
+ body := input[fmEndFenceStart+len(closingFence):]
+
+ return fm, body, nil
+}
+
+func yamlFrontMatter(input []byte) (map[string]interface{}, error) {
+ m := make(map[string]interface{})
+ err := yaml.Unmarshal(input, &m)
+ return m, err
+}
+
+func tomlFrontMatter(input []byte) (map[string]interface{}, error) {
+ m := make(map[string]interface{})
+ err := toml.Unmarshal(input, &m)
+ return m, err
+}
+
+func jsonFrontMatter(input []byte) (map[string]interface{}, error) {
+ input = append([]byte{'{'}, input...)
+ input = append(input, '}')
+ m := make(map[string]interface{})
+ err := json.Unmarshal(input, &m)
+ return m, err
+}
+
+type parsedMarkdownDoc struct {
+ Meta map[string]interface{} `json:"meta,omitempty"`
+ Body string `json:"body,omitempty"`
+}
+
+const (
+ yamlFrontMatterFenceOpen, yamlFrontMatterFenceClose = "---", "---"
+ tomlFrontMatterFenceOpen, tomlFrontMatterFenceClose = "+++", "+++"
+ jsonFrontMatterFenceOpen, jsonFrontMatterFenceClose = "{", "}"
+)