mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-26 02:09:47 +08:00
Fixup tests and move metadata into own package
This commit is contained in:
parent
48d294a695
commit
7c9867917a
|
@ -70,9 +70,26 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
|
|||
continue
|
||||
}
|
||||
|
||||
var dirents []os.FileInfo
|
||||
fpath := r.URL.Path
|
||||
if idx, ok := middleware.IndexFile(md.FileSys, fpath, md.IndexFiles); ok {
|
||||
// We're serving a directory index file, which may be a markdown
|
||||
// file with a template. Let's grab a list of files this directory
|
||||
// URL points to, and pass that in to any possible template invocations,
|
||||
// so that templates can customize the look and feel of a directory.
|
||||
|
||||
fdp, err := md.FileSys.Open(fpath)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
dirents, err = fdp.Readdir(-1)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
// Set path to found index file
|
||||
fpath = idx
|
||||
_ = dirents
|
||||
}
|
||||
|
||||
// If supported extension, process it
|
||||
|
@ -100,11 +117,16 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
|
|||
Req: r,
|
||||
URL: r.URL,
|
||||
}
|
||||
html, err := md.Process(cfg, fpath, body, ctx)
|
||||
html, err := cfg.Markdown(fpath, body, ctx)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
// html, err = md.doTemplate(cfg, html, ctx)
|
||||
// if err != nil {
|
||||
// return http.StatusInternalServerError, err
|
||||
// }
|
||||
|
||||
middleware.SetLastModifiedHeader(w, fs.ModTime())
|
||||
w.Write(html)
|
||||
return http.StatusOK, nil
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package markdown
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
@ -64,20 +65,23 @@ func (m *Metadata) load(parsedMap map[string]interface{}) {
|
|||
|
||||
// MetadataParser is a an interface that must be satisfied by each parser
|
||||
type MetadataParser interface {
|
||||
// Initialize a parser
|
||||
Init(b *bytes.Buffer) bool
|
||||
|
||||
// Type of metadata
|
||||
Type() string
|
||||
|
||||
// Opening identifier
|
||||
Opening() []byte
|
||||
|
||||
// Closing identifier
|
||||
Closing() []byte
|
||||
|
||||
// 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
|
||||
Metadata() Metadata
|
||||
|
||||
// Raw markdown.
|
||||
Markdown() []byte
|
||||
}
|
||||
|
||||
// extractMetadata separates metadata content from from markdown content in b.
|
||||
|
@ -109,8 +113,19 @@ func extractMetadata(parser MetadataParser, b []byte) (metadata []byte, markdown
|
|||
return metadata, markdown, nil
|
||||
}
|
||||
|
||||
func GetParser(buf []byte) MetadataParser {
|
||||
for _, p := range parsers() {
|
||||
b := bytes.NewBuffer(buf)
|
||||
if p.Init(b) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findParser finds the parser using line that contains opening identifier
|
||||
func findParser(b []byte) MetadataParser {
|
||||
func FindParser(b []byte) MetadataParser {
|
||||
var line []byte
|
||||
// Read first line
|
||||
if _, err := fmt.Fscanln(bytes.NewReader(b), &line); err != nil {
|
||||
|
@ -125,7 +140,7 @@ func findParser(b []byte) MetadataParser {
|
|||
return nil
|
||||
}
|
||||
|
||||
func newMetadata() Metadata {
|
||||
func NewMetadata() Metadata {
|
||||
return Metadata{
|
||||
Variables: make(map[string]string),
|
||||
Flags: make(map[string]bool),
|
||||
|
@ -135,8 +150,53 @@ func newMetadata() Metadata {
|
|||
// parsers returns all available parsers
|
||||
func parsers() []MetadataParser {
|
||||
return []MetadataParser{
|
||||
&JSONMetadataParser{metadata: newMetadata()},
|
||||
&TOMLMetadataParser{metadata: newMetadata()},
|
||||
&YAMLMetadataParser{metadata: newMetadata()},
|
||||
&TOMLMetadataParser{},
|
||||
&YAMLMetadataParser{metadata: NewMetadata()},
|
||||
&JSONMetadataParser{},
|
||||
&NoneMetadataParser{},
|
||||
}
|
||||
}
|
||||
|
||||
// Split out "normal" metadata with given delimiter
|
||||
func splitBuffer(b *bytes.Buffer, delim string) (*bytes.Buffer, *bytes.Buffer) {
|
||||
scanner := bufio.NewScanner(b)
|
||||
|
||||
// Read and check first line
|
||||
if !scanner.Scan() {
|
||||
return nil, nil
|
||||
}
|
||||
if string(bytes.TrimSpace(scanner.Bytes())) != delim {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Accumulate metadata, until delimiter
|
||||
meta := bytes.NewBuffer(nil)
|
||||
for scanner.Scan() {
|
||||
if string(bytes.TrimSpace(scanner.Bytes())) == delim {
|
||||
break
|
||||
}
|
||||
if _, err := meta.Write(scanner.Bytes()); err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
if _, err := meta.WriteRune('\n'); err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
// Make sure we saw closing delimiter
|
||||
if string(bytes.TrimSpace(scanner.Bytes())) != delim {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// The rest is markdown
|
||||
markdown := new(bytes.Buffer)
|
||||
for scanner.Scan() {
|
||||
if _, err := markdown.Write(scanner.Bytes()); err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
if _, err := markdown.WriteRune('\n'); err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return meta, markdown
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package markdown
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -8,6 +8,39 @@ import (
|
|||
// JSONMetadataParser is the MetadataParser for JSON
|
||||
type JSONMetadataParser struct {
|
||||
metadata Metadata
|
||||
markdown *bytes.Buffer
|
||||
}
|
||||
|
||||
func (j *JSONMetadataParser) Type() string {
|
||||
return "JSON"
|
||||
}
|
||||
|
||||
// Parse metadata/markdown file
|
||||
func (j *JSONMetadataParser) Init(b *bytes.Buffer) bool {
|
||||
m := make(map[string]interface{})
|
||||
|
||||
err := json.Unmarshal(b.Bytes(), &m)
|
||||
if err != nil {
|
||||
var offset int
|
||||
|
||||
if jerr, ok := err.(*json.SyntaxError); !ok {
|
||||
return false
|
||||
} else {
|
||||
offset = int(jerr.Offset)
|
||||
}
|
||||
|
||||
m = make(map[string]interface{})
|
||||
err = json.Unmarshal(b.Next(offset-1), &m)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
j.metadata = NewMetadata()
|
||||
j.metadata.load(m)
|
||||
j.markdown = bytes.NewBuffer(b.Bytes())
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Parse the metadata
|
||||
|
@ -34,6 +67,10 @@ func (j *JSONMetadataParser) Metadata() Metadata {
|
|||
return j.metadata
|
||||
}
|
||||
|
||||
func (j *JSONMetadataParser) Markdown() []byte {
|
||||
return j.markdown.Bytes()
|
||||
}
|
||||
|
||||
// Opening returns the opening identifier JSON metadata
|
||||
func (j *JSONMetadataParser) Opening() []byte {
|
||||
return []byte("{")
|
50
middleware/markdown/metadata/metadata_none.go
Normal file
50
middleware/markdown/metadata/metadata_none.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// TOMLMetadataParser is the MetadataParser for TOML
|
||||
type NoneMetadataParser struct {
|
||||
metadata Metadata
|
||||
markdown *bytes.Buffer
|
||||
}
|
||||
|
||||
func (n *NoneMetadataParser) Type() string {
|
||||
return "None"
|
||||
}
|
||||
|
||||
// Parse metadata/markdown file
|
||||
func (n *NoneMetadataParser) Init(b *bytes.Buffer) bool {
|
||||
m := make(map[string]interface{})
|
||||
n.metadata = NewMetadata()
|
||||
n.metadata.load(m)
|
||||
n.markdown = bytes.NewBuffer(b.Bytes())
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Parse the metadata
|
||||
func (n *NoneMetadataParser) Parse(b []byte) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Metadata returns parsed metadata. It should be called
|
||||
// only after a call to Parse returns without error.
|
||||
func (n *NoneMetadataParser) Metadata() Metadata {
|
||||
return n.metadata
|
||||
}
|
||||
|
||||
func (n *NoneMetadataParser) Markdown() []byte {
|
||||
return n.markdown.Bytes()
|
||||
}
|
||||
|
||||
// Opening returns the opening identifier TOML metadata
|
||||
func (n *NoneMetadataParser) Opening() []byte {
|
||||
return []byte("...")
|
||||
}
|
||||
|
||||
// Closing returns the closing identifier TOML metadata
|
||||
func (n *NoneMetadataParser) Closing() []byte {
|
||||
return []byte("...")
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
package markdown
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
@ -164,56 +162,52 @@ func TestParsers(t *testing.T) {
|
|||
testData [5]string
|
||||
name string
|
||||
}{
|
||||
{&JSONMetadataParser{metadata: newMetadata()}, JSON, "json"},
|
||||
{&YAMLMetadataParser{metadata: newMetadata()}, YAML, "yaml"},
|
||||
{&TOMLMetadataParser{metadata: newMetadata()}, TOML, "toml"},
|
||||
{&JSONMetadataParser{}, JSON, "JSON"},
|
||||
{&YAMLMetadataParser{}, YAML, "YAML"},
|
||||
{&TOMLMetadataParser{}, TOML, "TOML"},
|
||||
}
|
||||
|
||||
for _, v := range data {
|
||||
// metadata without identifiers
|
||||
if _, err := v.parser.Parse([]byte(v.testData[0])); err == nil {
|
||||
if v.parser.Init(bytes.NewBufferString(v.testData[0])) {
|
||||
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 !v.parser.Init(bytes.NewBufferString(v.testData[1])) {
|
||||
t.Fatalf("Metadata failed to initialize, type %v", v.parser.Type())
|
||||
}
|
||||
md := v.parser.Markdown()
|
||||
if !compare(v.parser.Metadata()) {
|
||||
t.Fatalf("Expected %v, found %v for %v", expected, v.parser.Metadata(), 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
|
||||
fmt.Fscanln(bytes.NewReader([]byte(v.testData[1])), &line)
|
||||
if parser := findParser(line); parser == nil {
|
||||
t.Fatalf("Parser must be found for %v", v.name)
|
||||
} else {
|
||||
if reflect.TypeOf(parser) != reflect.TypeOf(v.parser) {
|
||||
t.Fatalf("parsers not equal. %v != %v", reflect.TypeOf(parser), reflect.TypeOf(v.parser))
|
||||
}
|
||||
// Check that we find the correct metadata parser type
|
||||
if p := GetParser([]byte(v.testData[1])); p.Type() != v.name {
|
||||
t.Fatalf("Wrong parser found, expected %v, found %v", v.name, p.Type())
|
||||
}
|
||||
|
||||
// metadata without closing identifier
|
||||
if _, err := v.parser.Parse([]byte(v.testData[2])); err == nil {
|
||||
t.Fatalf("Expected error for missing closing identifier for %v", v.name)
|
||||
if v.parser.Init(bytes.NewBufferString(v.testData[2])) {
|
||||
t.Fatalf("Expected error for missing closing identifier for %v parser", v.name)
|
||||
}
|
||||
|
||||
// invalid metadata
|
||||
if _, err = v.parser.Parse([]byte(v.testData[3])); err == nil {
|
||||
if v.parser.Init(bytes.NewBufferString(v.testData[3])) {
|
||||
t.Fatalf("Expected error for invalid metadata for %v", v.name)
|
||||
}
|
||||
|
||||
// front matter but no body
|
||||
if _, err = v.parser.Parse([]byte(v.testData[4])); err != nil {
|
||||
if !v.parser.Init(bytes.NewBufferString(v.testData[4])) {
|
||||
t.Fatalf("Unexpected error for valid metadata but no body for %v", v.name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLargeBody(t *testing.T) {
|
||||
|
||||
var JSON = `{
|
||||
"template": "chapter"
|
||||
}
|
||||
|
@ -232,24 +226,36 @@ Mycket olika byggnader har man i de nordiska rikena: pyramidformiga, kilformiga,
|
|||
template : chapter
|
||||
---
|
||||
|
||||
Mycket olika byggnader har man i de nordiska rikena: pyramidformiga, kilformiga, välvda, runda och fyrkantiga. De pyramidformiga består helt enkelt av träribbor, som upptill löper samman och nedtill bildar en vidare krets; de är avsedda att användas av hantverkarna under sommaren, för att de inte ska plågas av solen, på samma gång som de besväras av rök och eld. De kilformiga husen är i regel försedda med höga tak, för att de täta och tunga snömassorna fortare ska kunna blåsa av och inte tynga ned taken. Dessa är täckta av björknäver, tegel eller kluvet spån av furu - för kådans skull -, gran, ek eller bok; taken på de förmögnas hus däremot med plåtar av koppar eller bly, i likhet med kyrktaken. Valvbyggnaderna uppförs ganska konstnärligt till skydd mot våldsamma vindar och snöfall, görs av sten eller trä, och är avsedda för olika alldagliga viktiga ändamål. Liknande byggnader kan finnas i stormännens gårdar där de används som förvaringsrum för husgeråd och jordbruksredskap. De runda byggnaderna - som för övrigt är de högst sällsynta - används av konstnärer, som vid sitt arbete behöver ett jämnt fördelat ljus från taket. Vanligast är de fyrkantiga husen, vars grova bjälkar är synnerligen väl hopfogade i hörnen - ett sant mästerverk av byggnadskonst; även dessa har fönster högt uppe i taken, för att dagsljuset skall kunna strömma in och ge alla därinne full belysning. Stenhusen har dörröppningar i förhållande till byggnadens storlek, men smala fönstergluggar, som skydd mot den stränga kölden, frosten och snön. Vore de större och vidare, såsom fönstren i Italien, skulle husen i följd av den fint yrande snön, som röres upp av den starka blåsten, precis som dammet av virvelvinden, snart nog fyllas med massor av snö och inte kunna stå emot dess tryck, utan störta samman.
|
||||
|
||||
`
|
||||
var NONE = `
|
||||
|
||||
Mycket olika byggnader har man i de nordiska rikena: pyramidformiga, kilformiga, välvda, runda och fyrkantiga. De pyramidformiga består helt enkelt av träribbor, som upptill löper samman och nedtill bildar en vidare krets; de är avsedda att användas av hantverkarna under sommaren, för att de inte ska plågas av solen, på samma gång som de besväras av rök och eld. De kilformiga husen är i regel försedda med höga tak, för att de täta och tunga snömassorna fortare ska kunna blåsa av och inte tynga ned taken. Dessa är täckta av björknäver, tegel eller kluvet spån av furu - för kådans skull -, gran, ek eller bok; taken på de förmögnas hus däremot med plåtar av koppar eller bly, i likhet med kyrktaken. Valvbyggnaderna uppförs ganska konstnärligt till skydd mot våldsamma vindar och snöfall, görs av sten eller trä, och är avsedda för olika alldagliga viktiga ändamål. Liknande byggnader kan finnas i stormännens gårdar där de används som förvaringsrum för husgeråd och jordbruksredskap. De runda byggnaderna - som för övrigt är de högst sällsynta - används av konstnärer, som vid sitt arbete behöver ett jämnt fördelat ljus från taket. Vanligast är de fyrkantiga husen, vars grova bjälkar är synnerligen väl hopfogade i hörnen - ett sant mästerverk av byggnadskonst; även dessa har fönster högt uppe i taken, för att dagsljuset skall kunna strömma in och ge alla därinne full belysning. Stenhusen har dörröppningar i förhållande till byggnadens storlek, men smala fönstergluggar, som skydd mot den stränga kölden, frosten och snön. Vore de större och vidare, såsom fönstren i Italien, skulle husen i följd av den fint yrande snön, som röres upp av den starka blåsten, precis som dammet av virvelvinden, snart nog fyllas med massor av snö och inte kunna stå emot dess tryck, utan störta samman.
|
||||
|
||||
`
|
||||
var expectedBody = `Mycket olika byggnader har man i de nordiska rikena: pyramidformiga, kilformiga, välvda, runda och fyrkantiga. De pyramidformiga består helt enkelt av träribbor, som upptill löper samman och nedtill bildar en vidare krets; de är avsedda att användas av hantverkarna under sommaren, för att de inte ska plågas av solen, på samma gång som de besväras av rök och eld. De kilformiga husen är i regel försedda med höga tak, för att de täta och tunga snömassorna fortare ska kunna blåsa av och inte tynga ned taken. Dessa är täckta av björknäver, tegel eller kluvet spån av furu - för kådans skull -, gran, ek eller bok; taken på de förmögnas hus däremot med plåtar av koppar eller bly, i likhet med kyrktaken. Valvbyggnaderna uppförs ganska konstnärligt till skydd mot våldsamma vindar och snöfall, görs av sten eller trä, och är avsedda för olika alldagliga viktiga ändamål. Liknande byggnader kan finnas i stormännens gårdar där de används som förvaringsrum för husgeråd och jordbruksredskap. De runda byggnaderna - som för övrigt är de högst sällsynta - används av konstnärer, som vid sitt arbete behöver ett jämnt fördelat ljus från taket. Vanligast är de fyrkantiga husen, vars grova bjälkar är synnerligen väl hopfogade i hörnen - ett sant mästerverk av byggnadskonst; även dessa har fönster högt uppe i taken, för att dagsljuset skall kunna strömma in och ge alla därinne full belysning. Stenhusen har dörröppningar i förhållande till byggnadens storlek, men smala fönstergluggar, som skydd mot den stränga kölden, frosten och snön. Vore de större och vidare, såsom fönstren i Italien, skulle husen i följd av den fint yrande snön, som röres upp av den starka blåsten, precis som dammet av virvelvinden, snart nog fyllas med massor av snö och inte kunna stå emot dess tryck, utan störta samman.
|
||||
`
|
||||
|
||||
data := []struct {
|
||||
parser MetadataParser
|
||||
pType string
|
||||
testData string
|
||||
name string
|
||||
}{
|
||||
{&JSONMetadataParser{metadata: newMetadata()}, JSON, "json"},
|
||||
{&YAMLMetadataParser{metadata: newMetadata()}, YAML, "yaml"},
|
||||
{&TOMLMetadataParser{metadata: newMetadata()}, TOML, "toml"},
|
||||
{"JSON", JSON},
|
||||
{"TOML", TOML},
|
||||
{"YAML", YAML},
|
||||
{"None", NONE},
|
||||
}
|
||||
for _, v := range data {
|
||||
// metadata without identifiers
|
||||
if md, err := v.parser.Parse([]byte(v.testData)); err != nil || strings.TrimSpace(string(md)) != strings.TrimSpace(expectedBody) {
|
||||
t.Fatalf("Error not expected and/or markdown not equal for %v", v.name)
|
||||
p := GetParser([]byte(v.testData))
|
||||
if v.pType != p.Type() {
|
||||
t.Fatalf("Wrong parser type, expected %v, got %v", v.pType, p.Type())
|
||||
}
|
||||
md := p.Markdown()
|
||||
if strings.TrimSpace(string(md)) != strings.TrimSpace(expectedBody) {
|
||||
t.Log("Provided:", v.testData)
|
||||
t.Log("Returned:", p.Markdown())
|
||||
t.Fatalf("Error, mismatched body in expected type %v, matched type %v", v.pType, p.Type())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,37 @@
|
|||
package markdown
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
// TOMLMetadataParser is the MetadataParser for TOML
|
||||
type TOMLMetadataParser struct {
|
||||
metadata Metadata
|
||||
markdown *bytes.Buffer
|
||||
}
|
||||
|
||||
func (t *TOMLMetadataParser) Type() string {
|
||||
return "TOML"
|
||||
}
|
||||
|
||||
// Parse metadata/markdown file
|
||||
func (t *TOMLMetadataParser) Init(b *bytes.Buffer) bool {
|
||||
meta, data := splitBuffer(b, "+++")
|
||||
if meta == nil || data == nil {
|
||||
return false
|
||||
}
|
||||
t.markdown = data
|
||||
|
||||
m := make(map[string]interface{})
|
||||
if err := toml.Unmarshal(meta.Bytes(), &m); err != nil {
|
||||
return false
|
||||
}
|
||||
t.metadata = NewMetadata()
|
||||
t.metadata.load(m)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Parse the metadata
|
||||
|
@ -15,6 +40,7 @@ func (t *TOMLMetadataParser) Parse(b []byte) ([]byte, error) {
|
|||
if err != nil {
|
||||
return markdown, err
|
||||
}
|
||||
|
||||
m := make(map[string]interface{})
|
||||
if err := toml.Unmarshal(b, &m); err != nil {
|
||||
return markdown, err
|
||||
|
@ -29,6 +55,10 @@ func (t *TOMLMetadataParser) Metadata() Metadata {
|
|||
return t.metadata
|
||||
}
|
||||
|
||||
func (t *TOMLMetadataParser) Markdown() []byte {
|
||||
return t.markdown.Bytes()
|
||||
}
|
||||
|
||||
// Opening returns the opening identifier TOML metadata
|
||||
func (t *TOMLMetadataParser) Opening() []byte {
|
||||
return []byte("+++")
|
|
@ -1,12 +1,36 @@
|
|||
package markdown
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// YAMLMetadataParser is the MetadataParser for YAML
|
||||
type YAMLMetadataParser struct {
|
||||
metadata Metadata
|
||||
markdown *bytes.Buffer
|
||||
}
|
||||
|
||||
func (y *YAMLMetadataParser) Type() string {
|
||||
return "YAML"
|
||||
}
|
||||
|
||||
func (y *YAMLMetadataParser) Init(b *bytes.Buffer) bool {
|
||||
meta, data := splitBuffer(b, "---")
|
||||
if meta == nil || data == nil {
|
||||
return false
|
||||
}
|
||||
y.markdown = data
|
||||
|
||||
m := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal(meta.Bytes(), &m); err != nil {
|
||||
return false
|
||||
}
|
||||
y.metadata = NewMetadata()
|
||||
y.metadata.load(m)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Parse the metadata
|
||||
|
@ -30,6 +54,10 @@ func (y *YAMLMetadataParser) Metadata() Metadata {
|
|||
return y.metadata
|
||||
}
|
||||
|
||||
func (y *YAMLMetadataParser) Markdown() []byte {
|
||||
return y.markdown.Bytes()
|
||||
}
|
||||
|
||||
// Opening returns the opening identifier YAML metadata
|
||||
func (y *YAMLMetadataParser) Opening() []byte {
|
||||
return []byte("---")
|
|
@ -1,49 +1,19 @@
|
|||
package markdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mholt/caddy/middleware"
|
||||
"github.com/mholt/caddy/middleware/markdown/metadata"
|
||||
"github.com/russross/blackfriday"
|
||||
)
|
||||
|
||||
// Data represents a markdown document.
|
||||
type Data struct {
|
||||
middleware.Context
|
||||
Doc map[string]string
|
||||
DocFlags map[string]bool
|
||||
Styles []string
|
||||
Scripts []string
|
||||
}
|
||||
|
||||
// Include "overrides" the embedded middleware.Context's Include()
|
||||
// method so that included files have access to d's fields.
|
||||
func (d Data) Include(filename string) (string, error) {
|
||||
return middleware.ContextInclude(filename, d, d.Root)
|
||||
}
|
||||
|
||||
// Process processes the contents of a page in b. It parses the metadata
|
||||
// Markdown processes the contents of a page in b. It parses the metadata
|
||||
// (if any) and uses the template (if found).
|
||||
func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middleware.Context) ([]byte, error) {
|
||||
var metadata = newMetadata()
|
||||
var markdown []byte
|
||||
var err error
|
||||
|
||||
// find parser compatible with page contents
|
||||
parser := findParser(b)
|
||||
|
||||
if parser == nil {
|
||||
// if not found, assume whole file is markdown (no front matter)
|
||||
markdown = b
|
||||
} else {
|
||||
// if found, assume metadata present and parse.
|
||||
markdown, err = parser.Parse(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metadata = parser.Metadata()
|
||||
}
|
||||
func (c *Config) Markdown(requestPath string, b []byte, ctx middleware.Context) ([]byte, error) {
|
||||
parser := metadata.GetParser(b)
|
||||
markdown := parser.Markdown()
|
||||
mdata := parser.Metadata()
|
||||
|
||||
// process markdown
|
||||
extns := 0
|
||||
|
@ -54,33 +24,14 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa
|
|||
markdown = blackfriday.Markdown(markdown, c.Renderer, extns)
|
||||
|
||||
// set it as body for template
|
||||
metadata.Variables["body"] = string(markdown)
|
||||
title := metadata.Title
|
||||
mdata.Variables["body"] = string(markdown)
|
||||
title := mdata.Title
|
||||
if title == "" {
|
||||
title = filepath.Base(requestPath)
|
||||
var extension = filepath.Ext(requestPath)
|
||||
title = title[0 : len(title)-len(extension)]
|
||||
}
|
||||
metadata.Variables["title"] = title
|
||||
mdata.Variables["title"] = title
|
||||
|
||||
// return md.processTemplate(c, requestPath, metadata, ctx)
|
||||
return md.doTemplate(c, requestPath, metadata, ctx)
|
||||
}
|
||||
|
||||
// doTemplate executes a template given a requestPath, template, and metadata
|
||||
func (md Markdown) doTemplate(c *Config, reqPath string, metadata Metadata, ctx middleware.Context) ([]byte, error) {
|
||||
mdData := Data{
|
||||
Context: ctx,
|
||||
Doc: metadata.Variables,
|
||||
DocFlags: metadata.Flags,
|
||||
Styles: c.Styles,
|
||||
Scripts: c.Scripts,
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
if err := c.Template.ExecuteTemplate(b, metadata.Template, mdData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
return execTemplate(c, mdata, ctx)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,50 @@
|
|||
package markdown
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/mholt/caddy/middleware"
|
||||
"github.com/mholt/caddy/middleware/markdown/metadata"
|
||||
)
|
||||
|
||||
// Data represents a markdown document.
|
||||
type Data struct {
|
||||
middleware.Context
|
||||
Doc map[string]string
|
||||
DocFlags map[string]bool
|
||||
Styles []string
|
||||
Scripts []string
|
||||
Files []os.FileInfo
|
||||
}
|
||||
|
||||
// Include "overrides" the embedded middleware.Context's Include()
|
||||
// method so that included files have access to d's fields.
|
||||
// Note: using {{template 'template-name' .}} instead might be better.
|
||||
func (d Data) Include(filename string) (string, error) {
|
||||
return middleware.ContextInclude(filename, d, d.Root)
|
||||
}
|
||||
|
||||
// execTemplate executes a template given a requestPath, template, and metadata
|
||||
func execTemplate(c *Config, mdata metadata.Metadata, ctx middleware.Context) ([]byte, error) {
|
||||
mdData := Data{
|
||||
Context: ctx,
|
||||
Doc: mdata.Variables,
|
||||
DocFlags: mdata.Flags,
|
||||
Styles: c.Styles,
|
||||
Scripts: c.Scripts,
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
if err := c.Template.ExecuteTemplate(b, mdata.Template, mdData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func setDefaultTemplate(filename string) *template.Template {
|
||||
buf, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue
Block a user