Refactor FrontMatter parsing to better fit hugo requirements
This commit is contained in:
parent
724cf6c23e
commit
2295594970
2 changed files with 38 additions and 26 deletions
|
@ -30,6 +30,7 @@ type Writer interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node interface{}
|
type Node interface{}
|
||||||
|
type FrontMatter = map[string]interface{}
|
||||||
|
|
||||||
type lexFn = func(line string) (t token, ok bool)
|
type lexFn = func(line string) (t token, ok bool)
|
||||||
type parseFn = func(*Document, int, stopFn) (int, Node)
|
type parseFn = func(*Document, int, stopFn) (int, Node)
|
||||||
|
@ -57,13 +58,14 @@ var lexFns = []lexFn{
|
||||||
|
|
||||||
var nilToken = token{"nil", -1, "", nil}
|
var nilToken = token{"nil", -1, "", nil}
|
||||||
|
|
||||||
var DefaultFrontMatterHandler = func(k, v string) interface{} {
|
func FrontMatterHandler(fm FrontMatter, k, v string) error {
|
||||||
switch k {
|
switch k := strings.ToLower(k); k {
|
||||||
case "TAGS", "CATEGORIES", "ALIASES":
|
case "tags", "categories", "aliases":
|
||||||
return strings.Fields(v)
|
fm[k] = strings.Fields(v)
|
||||||
default:
|
default:
|
||||||
return v
|
fm[k] = v
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDocument() *Document {
|
func NewDocument() *Document {
|
||||||
|
@ -118,9 +120,9 @@ func (d *Document) SetPath(path string) *Document {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface{}) (_ map[string]interface{}, err error) {
|
func GetFrontMatter(input io.Reader, f func(FrontMatter, string, string) error) (_ FrontMatter, err error) {
|
||||||
|
d := NewDocument()
|
||||||
defer func() {
|
defer func() {
|
||||||
d.tokens = nil
|
|
||||||
if recovered := recover(); recovered != nil {
|
if recovered := recover(); recovered != nil {
|
||||||
err = fmt.Errorf("could not parse input: %s", recovered)
|
err = fmt.Errorf("could not parse input: %s", recovered)
|
||||||
}
|
}
|
||||||
|
@ -133,9 +135,12 @@ func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface
|
||||||
t := d.tokens[i]
|
t := d.tokens[i]
|
||||||
return t.kind != "keyword" && !(t.kind == "text" && t.content == "")
|
return t.kind != "keyword" && !(t.kind == "text" && t.content == "")
|
||||||
})
|
})
|
||||||
frontMatter := make(map[string]interface{}, len(d.BufferSettings))
|
frontMatter := make(FrontMatter, len(d.BufferSettings))
|
||||||
for k, v := range d.BufferSettings {
|
for k, v := range d.BufferSettings {
|
||||||
frontMatter[k] = f(k, v)
|
err := f(frontMatter, k, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return frontMatter, err
|
return frontMatter, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,18 @@ import (
|
||||||
type frontMatterTest struct {
|
type frontMatterTest struct {
|
||||||
name string
|
name string
|
||||||
input string
|
input string
|
||||||
handler func(string, string) interface{}
|
handler func(FrontMatter, string, string) error
|
||||||
expected map[string]interface{}
|
expected map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var frontMatterTests = []frontMatterTest{
|
var frontMatterTests = []frontMatterTest{
|
||||||
{`basic`,
|
{`basic`,
|
||||||
`#+TITLE: The Title`,
|
`#+TITLE: The Title`,
|
||||||
DefaultFrontMatterHandler,
|
FrontMatterHandler,
|
||||||
map[string]interface{}{"TITLE": "The Title"}},
|
map[string]interface{}{"title": "The Title"}},
|
||||||
{`empty`,
|
{`empty`,
|
||||||
`* No frontmatter here`,
|
`* No frontmatter here`,
|
||||||
DefaultFrontMatterHandler,
|
FrontMatterHandler,
|
||||||
map[string]interface{}{}},
|
map[string]interface{}{}},
|
||||||
{`custom handler`,
|
{`custom handler`,
|
||||||
`
|
`
|
||||||
|
@ -29,17 +29,18 @@ var frontMatterTests = []frontMatterTest{
|
||||||
#+TAGS: foo bar
|
#+TAGS: foo bar
|
||||||
|
|
||||||
`,
|
`,
|
||||||
func(k, v string) interface{} {
|
func(fm FrontMatter, k, v string) error {
|
||||||
switch k {
|
switch k := strings.ToLower(k); k {
|
||||||
case "TITLE":
|
case "title":
|
||||||
return "Thanks For All The Fish"
|
fm[k] = "Thanks For All The Fish"
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
return DefaultFrontMatterHandler(k, v)
|
return FrontMatterHandler(fm, k, v)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"TITLE": "Thanks For All The Fish",
|
"title": "Thanks For All The Fish",
|
||||||
"TAGS": []string{"foo", "bar"},
|
"tags": []string{"foo", "bar"},
|
||||||
}},
|
}},
|
||||||
{`multiple + ignored keyword`,
|
{`multiple + ignored keyword`,
|
||||||
`
|
`
|
||||||
|
@ -49,22 +50,28 @@ var frontMatterTests = []frontMatterTest{
|
||||||
#+OTHER: some other keyword
|
#+OTHER: some other keyword
|
||||||
#+TAGS: this will become []string
|
#+TAGS: this will become []string
|
||||||
|
|
||||||
|
#+ALIASES: foo bar
|
||||||
|
#+ALIASES: baz bam
|
||||||
|
#+categories: foo bar
|
||||||
|
|
||||||
something that's not a keyword or a text line without content
|
something that's not a keyword or a text line without content
|
||||||
|
|
||||||
#+SUBTITLE: The Subtitle`,
|
#+SUBTITLE: The Subtitle`,
|
||||||
DefaultFrontMatterHandler,
|
FrontMatterHandler,
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"TITLE": "The Title",
|
"title": "The Title",
|
||||||
"AUTHOR": "The Author",
|
"author": "The Author",
|
||||||
"OTHER": "some other keyword",
|
"other": "some other keyword",
|
||||||
"TAGS": []string{"this", "will", "become", "[]string"},
|
"tags": []string{"this", "will", "become", "[]string"},
|
||||||
|
"aliases": []string{"foo", "bar", "baz", "bam"},
|
||||||
|
"categories": []string{"foo", "bar"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseFrontMatter(t *testing.T) {
|
func TestParseFrontMatter(t *testing.T) {
|
||||||
for _, test := range frontMatterTests {
|
for _, test := range frontMatterTests {
|
||||||
actual, err := NewDocument().FrontMatter(strings.NewReader(test.input), test.handler)
|
actual, err := GetFrontMatter(strings.NewReader(test.input), test.handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s\n got error: %s", test.name, err)
|
t.Errorf("%s\n got error: %s", test.name, err)
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue