mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
markdown: remove identifier from Json metadata
This commit is contained in:
parent
6ce83aad2b
commit
2f5e2f39cb
3 changed files with 90 additions and 59 deletions
|
@ -51,8 +51,10 @@ type MetadataParser interface {
|
|||
// Closing identifier
|
||||
Closing() []byte
|
||||
|
||||
// Parse the metadata
|
||||
Parse([]byte) error
|
||||
// Parse the metadata.
|
||||
// Returns the remaining page contents (Markdown)
|
||||
// after extracting metadata
|
||||
Parse([]byte) ([]byte, error)
|
||||
|
||||
// Parsed metadata.
|
||||
// Should be called after a call to Parse returns no error
|
||||
|
@ -65,13 +67,25 @@ type JSONMetadataParser struct {
|
|||
}
|
||||
|
||||
// Parse the metadata
|
||||
func (j *JSONMetadataParser) Parse(b []byte) error {
|
||||
func (j *JSONMetadataParser) Parse(b []byte) ([]byte, error) {
|
||||
m := make(map[string]interface{})
|
||||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
|
||||
// Read the preceding JSON object
|
||||
decoder := json.NewDecoder(bytes.NewReader(b))
|
||||
if err := decoder.Decode(&m); err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
j.metadata.load(m)
|
||||
return nil
|
||||
|
||||
// Retrieve remaining bytes after decoding
|
||||
buf := make([]byte, len(b))
|
||||
n, err := decoder.Buffered().Read(buf)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
return buf[:n], nil
|
||||
}
|
||||
|
||||
// Parsed metadata.
|
||||
|
@ -82,12 +96,12 @@ func (j *JSONMetadataParser) Metadata() Metadata {
|
|||
|
||||
// Opening returns the opening identifier JSON metadata
|
||||
func (j *JSONMetadataParser) Opening() []byte {
|
||||
return []byte(":::")
|
||||
return []byte("{")
|
||||
}
|
||||
|
||||
// Closing returns the closing identifier JSON metadata
|
||||
func (j *JSONMetadataParser) Closing() []byte {
|
||||
return []byte(":::")
|
||||
return []byte("}")
|
||||
}
|
||||
|
||||
// TOMLMetadataParser is the MetadataParser for TOML
|
||||
|
@ -96,13 +110,17 @@ type TOMLMetadataParser struct {
|
|||
}
|
||||
|
||||
// Parse the metadata
|
||||
func (t *TOMLMetadataParser) Parse(b []byte) error {
|
||||
func (t *TOMLMetadataParser) Parse(b []byte) ([]byte, error) {
|
||||
b, markdown, err := extractMetadata(t, b)
|
||||
if err != nil {
|
||||
return markdown, err
|
||||
}
|
||||
m := make(map[string]interface{})
|
||||
if err := toml.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
return markdown, err
|
||||
}
|
||||
t.metadata.load(m)
|
||||
return nil
|
||||
return markdown, nil
|
||||
}
|
||||
|
||||
// Parsed metadata.
|
||||
|
@ -127,13 +145,17 @@ type YAMLMetadataParser struct {
|
|||
}
|
||||
|
||||
// Parse the metadata
|
||||
func (y *YAMLMetadataParser) Parse(b []byte) error {
|
||||
func (y *YAMLMetadataParser) Parse(b []byte) ([]byte, error) {
|
||||
b, markdown, err := extractMetadata(y, b)
|
||||
if err != nil {
|
||||
return markdown, err
|
||||
}
|
||||
m := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
return markdown, err
|
||||
}
|
||||
y.metadata.load(m)
|
||||
return nil
|
||||
return markdown, nil
|
||||
}
|
||||
|
||||
// Parsed metadata.
|
||||
|
@ -154,26 +176,23 @@ func (y *YAMLMetadataParser) Closing() []byte {
|
|||
|
||||
// extractMetadata extracts metadata content from a page.
|
||||
// it returns the metadata, the remaining bytes (markdown),
|
||||
// and an error if any
|
||||
func extractMetadata(b []byte) (metadata Metadata, markdown []byte, err error) {
|
||||
// and an error if any.
|
||||
// Useful for MetadataParser with defined identifiers (YAML, TOML)
|
||||
func extractMetadata(parser MetadataParser, b []byte) (metadata []byte, markdown []byte, err error) {
|
||||
b = bytes.TrimSpace(b)
|
||||
reader := bytes.NewBuffer(b)
|
||||
scanner := bufio.NewScanner(reader)
|
||||
var parser MetadataParser
|
||||
|
||||
// Read first line
|
||||
if !scanner.Scan() {
|
||||
// if no line is read,
|
||||
// assume metadata not present
|
||||
return metadata, b, nil
|
||||
return nil, b, nil
|
||||
}
|
||||
|
||||
line := scanner.Bytes()
|
||||
parser = findParser(line)
|
||||
// if no parser found,
|
||||
// assume metadata not present
|
||||
if parser == nil {
|
||||
return metadata, b, nil
|
||||
line := bytes.TrimSpace(scanner.Bytes())
|
||||
if !bytes.Equal(line, parser.Opening()) {
|
||||
return nil, b, fmt.Errorf("Wrong identifier")
|
||||
}
|
||||
|
||||
// buffer for metadata contents
|
||||
|
@ -185,11 +204,7 @@ func extractMetadata(b []byte) (metadata Metadata, markdown []byte, err error) {
|
|||
|
||||
// if closing identifier found
|
||||
if bytes.Equal(bytes.TrimSpace(line), parser.Closing()) {
|
||||
// parse the metadata
|
||||
err := parser.Parse(buf.Bytes())
|
||||
if err != nil {
|
||||
return metadata, nil, err
|
||||
}
|
||||
|
||||
// get the scanner to return remaining bytes
|
||||
scanner.Split(func(data []byte, atEOF bool) (int, []byte, error) {
|
||||
return len(data), data, nil
|
||||
|
@ -197,18 +212,23 @@ func extractMetadata(b []byte) (metadata Metadata, markdown []byte, err error) {
|
|||
// scan the remaining bytes
|
||||
scanner.Scan()
|
||||
|
||||
return parser.Metadata(), scanner.Bytes(), nil
|
||||
return buf.Bytes(), scanner.Bytes(), nil
|
||||
}
|
||||
buf.Write(line)
|
||||
buf.WriteString("\r\n")
|
||||
}
|
||||
|
||||
// closing identifier not found
|
||||
return metadata, nil, fmt.Errorf("Metadata not closed. '%v' not found", string(parser.Closing()))
|
||||
return buf.Bytes(), nil, fmt.Errorf("Metadata not closed. '%v' not found", string(parser.Closing()))
|
||||
}
|
||||
|
||||
// findParser finds the parser using line that contains opening identifier
|
||||
func findParser(line []byte) MetadataParser {
|
||||
func findParser(b []byte) MetadataParser {
|
||||
var line []byte
|
||||
// Read first line
|
||||
if _, err := fmt.Fscanln(bytes.NewReader(b), &line); err != nil {
|
||||
return nil
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
for _, parser := range parsers {
|
||||
if bytes.Equal(parser.Opening(), line) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -19,6 +20,7 @@ template = "default"
|
|||
[variables]
|
||||
name = "value"
|
||||
+++
|
||||
Page content
|
||||
`,
|
||||
`+++
|
||||
title = "A title"
|
||||
|
@ -41,6 +43,7 @@ template : default
|
|||
variables :
|
||||
- name : value
|
||||
---
|
||||
Page content
|
||||
`,
|
||||
`---
|
||||
title : A title
|
||||
|
@ -51,34 +54,30 @@ variables :
|
|||
`title : A title template : default variables : name : value`,
|
||||
}
|
||||
var JSON = [4]string{`
|
||||
{
|
||||
"title" : "A title",
|
||||
"template" : "default",
|
||||
"variables" : {
|
||||
"name" : "value"
|
||||
}
|
||||
}
|
||||
`,
|
||||
`:::
|
||||
{
|
||||
"title" : "A title",
|
||||
"template" : "default",
|
||||
"variables" : {
|
||||
"name" : "value"
|
||||
}
|
||||
}
|
||||
:::`,
|
||||
`:::
|
||||
{
|
||||
`{
|
||||
"title" : "A title",
|
||||
"template" : "default",
|
||||
"variables" : {
|
||||
"name" : "value"
|
||||
}
|
||||
}
|
||||
Page content
|
||||
`,
|
||||
`
|
||||
{
|
||||
"title" : "A title",
|
||||
"template" : "default",
|
||||
"variables" : {
|
||||
"name" : "value"
|
||||
}
|
||||
`,
|
||||
`
|
||||
:::
|
||||
{{
|
||||
"title" : "A title",
|
||||
"template" : "default",
|
||||
|
@ -86,7 +85,6 @@ var JSON = [4]string{`
|
|||
"name" : "value"
|
||||
}
|
||||
}
|
||||
:::
|
||||
`,
|
||||
}
|
||||
|
||||
|
@ -129,17 +127,18 @@ func TestParsers(t *testing.T) {
|
|||
|
||||
for _, v := range data {
|
||||
// metadata without identifiers
|
||||
err := v.parser.Parse([]byte(v.testData[0]))
|
||||
if _, err := v.parser.Parse([]byte(v.testData[0])); err == nil {
|
||||
t.Fatalf("Expected error for invalid metadata for %v", v.name)
|
||||
}
|
||||
|
||||
// metadata with identifiers
|
||||
md, err := v.parser.Parse([]byte(v.testData[1]))
|
||||
check(t, err)
|
||||
if !compare(v.parser.Metadata()) {
|
||||
t.Fatalf("Expected %v, found %v for %v", expected, v.parser.Metadata().Variables, v.name)
|
||||
}
|
||||
|
||||
// metadata with identifiers
|
||||
metadata, _, err := extractMetadata([]byte(v.testData[1]))
|
||||
check(t, err)
|
||||
if !compare(metadata) {
|
||||
t.Fatalf("Expected %v, found %v for %v", expected, metadata.Variables, v.name)
|
||||
if "Page content" != strings.TrimSpace(string(md)) {
|
||||
t.Fatalf("Expected %v, found %v for %v", "Page content", string(md), v.name)
|
||||
}
|
||||
|
||||
var line []byte
|
||||
|
@ -153,12 +152,12 @@ func TestParsers(t *testing.T) {
|
|||
}
|
||||
|
||||
// metadata without closing identifier
|
||||
if _, _, err := extractMetadata([]byte(v.testData[2])); err == nil {
|
||||
if _, err := v.parser.Parse([]byte(v.testData[2])); err == nil {
|
||||
t.Fatalf("Expected error for missing closing identifier for %v", v.name)
|
||||
}
|
||||
|
||||
// invalid metadata
|
||||
if err := v.parser.Parse([]byte(v.testData[3])); err == nil {
|
||||
if md, err = v.parser.Parse([]byte(v.testData[3])); err == nil {
|
||||
t.Fatalf("Expected error for invalid metadata for %v", v.name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,22 @@ const (
|
|||
// process processes the contents of a page.
|
||||
// It parses the metadata (if any) and uses the template (if found)
|
||||
func (md Markdown) process(c Config, requestPath string, b []byte) ([]byte, error) {
|
||||
metadata, markdown, err := extractMetadata(b)
|
||||
var metadata = Metadata{}
|
||||
var markdown []byte
|
||||
var err error
|
||||
|
||||
// find parser compatible with page contents
|
||||
parser := findParser(b)
|
||||
|
||||
// if found, assume metadata present and parse.
|
||||
if parser != nil {
|
||||
markdown, err = parser.Parse(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metadata = parser.Metadata()
|
||||
}
|
||||
|
||||
// if template is not specified, check if Default template is set
|
||||
if metadata.Template == "" {
|
||||
if _, ok := c.Templates[DefaultTemplate]; ok {
|
||||
|
|
Loading…
Reference in a new issue