parent
ccff4e56c0
commit
380a5b9223
@ -101,24 +101,24 @@ func (this *Environment) parse (name string, modTime time.Time, input io.Reader)
|
||||
// read entire file and split into front matter and body
|
||||
buffer, err := io.ReadAll(input)
|
||||
if err != nil { return nil, err }
|
||||
frontMatter, body, err := SplitMeta(string(buffer))
|
||||
meta, body, err := SplitMeta(string(buffer))
|
||||
if err != nil { return nil, err }
|
||||
|
||||
// assemble the document struct
|
||||
document := &Document {
|
||||
Meta: frontMatter,
|
||||
Meta: meta,
|
||||
environment: this,
|
||||
name: name,
|
||||
parseTime: time.Now(),
|
||||
template: template.New(name),
|
||||
}
|
||||
if author, ok := frontMatter["author"]; ok {
|
||||
if author := meta.Get("author"); author != "" {
|
||||
document.Author = author
|
||||
}
|
||||
if title, ok := frontMatter["title"]; ok {
|
||||
if title := meta.Get("title"); title != "" {
|
||||
document.Title = title
|
||||
}
|
||||
if extends, ok := frontMatter["extends"]; ok {
|
||||
if extends := meta.Get("extends"); extends != "" {
|
||||
document.Extends = extends
|
||||
}
|
||||
|
||||
|
1
error.go
1
error.go
@ -5,7 +5,6 @@ type Error string; const (
|
||||
ErrCircularInheritance Error = "circular inheritance"
|
||||
ErrMetaMalformed Error = "metadata is malformed"
|
||||
ErrMetaNeverClosed Error = "metadata is never closed"
|
||||
ErrMetaDuplicateKey Error = "duplicate key in front matter"
|
||||
ErrTypeMismatch Error = "type mismatch"
|
||||
)
|
||||
|
||||
|
@ -112,10 +112,10 @@ func (this *Handler) serveDocument (
|
||||
recorder.Reset()
|
||||
recorder.Head = res.Header().Clone()
|
||||
}
|
||||
if contentType, ok := document.Meta["content-type"]; ok {
|
||||
if contentType := document.Meta.Get("content-type"); contentType != "" {
|
||||
recorder.Header().Set("Content-Type", contentType)
|
||||
}
|
||||
if status, ok := document.Meta["status"]; ok {
|
||||
if status := document.Meta.Get("status"); status != "" {
|
||||
if status, err := strconv.Atoi(status); err == nil {
|
||||
recorder.Status = status
|
||||
}
|
||||
|
53
meta.go
53
meta.go
@ -1,6 +1,7 @@
|
||||
package step
|
||||
|
||||
import "io"
|
||||
import "slices"
|
||||
import "strconv"
|
||||
import "strings"
|
||||
|
||||
@ -8,7 +9,7 @@ const metaRule = "---"
|
||||
|
||||
// Meta represents optional metadata that can occur at the very start of
|
||||
// a document.
|
||||
type Meta = map[string] string
|
||||
type Meta map[string] []string
|
||||
|
||||
// SplitMeta parses the metadata (if it exists), returning a map representing it
|
||||
// along with the rest of the input as a string. If there is no metadata, an
|
||||
@ -52,7 +53,7 @@ func ParseMeta (input string) (Meta, error) {
|
||||
if !ok {
|
||||
return nil, ErrMetaMalformed
|
||||
}
|
||||
key = strings.ToLower(strings.TrimSpace(key))
|
||||
key = strings.TrimSpace(key)
|
||||
value = strings.TrimSpace(value)
|
||||
if strings.HasPrefix(value, "\"") || strings.HasPrefix(value, "'") {
|
||||
unquoted, err := strconv.Unquote(value)
|
||||
@ -64,10 +65,7 @@ func ParseMeta (input string) (Meta, error) {
|
||||
if key == "" {
|
||||
return nil, ErrMetaMalformed
|
||||
}
|
||||
if _, exists := meta[key]; exists {
|
||||
return nil, ErrMetaDuplicateKey
|
||||
}
|
||||
meta[key] = value
|
||||
meta.Add(key, value)
|
||||
}
|
||||
return meta, nil
|
||||
}
|
||||
@ -78,3 +76,46 @@ func DecodeMeta (input io.Reader) (Meta, error) {
|
||||
if err != nil { return nil, err }
|
||||
return ParseMeta(string(buffer))
|
||||
}
|
||||
|
||||
// Add adds the key/value pair to the metadata. It appends to any existing
|
||||
// values associated with the key. The key is case insensitive.
|
||||
func (meta Meta) Add (key, value string) {
|
||||
key = canonicalMetaKey(key)
|
||||
meta[key] = append(meta[key], value)
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the metadata.
|
||||
func (meta Meta) Clone () Meta {
|
||||
clone := make(Meta, len(meta))
|
||||
for key, value := range meta {
|
||||
clone[key] = slices.Clone(value)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
// Del deletes the values associated with the key. The key is case insensitive.
|
||||
func (meta Meta) Del (key string) {
|
||||
key = canonicalMetaKey(key)
|
||||
delete(meta, key)
|
||||
}
|
||||
|
||||
// Get gets the first value associated with the key. The key is case
|
||||
// insensitive.
|
||||
func (meta Meta) Get (key string) string {
|
||||
key = canonicalMetaKey(key)
|
||||
slice, ok := meta[key]
|
||||
if !ok { return "" }
|
||||
if len(slice) == 0 { return "" }
|
||||
return slice[0]
|
||||
}
|
||||
|
||||
// Set replaces all values currently associated with key with the single element
|
||||
// value. The key is case insensitive.
|
||||
func (meta Meta) Set (key, value string) {
|
||||
key = canonicalMetaKey(key)
|
||||
meta[key] = []string { value }
|
||||
}
|
||||
|
||||
func canonicalMetaKey (key string) string {
|
||||
return strings.ToLower(key)
|
||||
}
|
||||
|
86
meta_test.go
86
meta_test.go
@ -13,7 +13,7 @@ theres another hr that shouldnt
|
||||
break anything
|
||||
break: anything
|
||||
`
|
||||
frontMatter, body, err := SplitMeta(
|
||||
meta, body, err := SplitMeta(
|
||||
`---
|
||||
FOO: baR
|
||||
fOoo: Bar
|
||||
@ -34,27 +34,27 @@ Sentence: ` + quickBrownFox + `
|
||||
}
|
||||
|
||||
test.Log("META:")
|
||||
test.Log(frontMatter)
|
||||
value0, ok := frontMatter["foo"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value1, ok := frontMatter["fooo"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value2, ok := frontMatter["shouldn't break anything"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value3, ok := frontMatter["this"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value4, ok := frontMatter["sentence"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
if value0 != "baR" { test.Fatal("value is not correct") }
|
||||
if value1 != "Bar" { test.Fatal("value is not correct") }
|
||||
if value2 != "---" { test.Fatal("value is not correct") }
|
||||
if value3 != "that" { test.Fatal("value is not correct") }
|
||||
if value4 != quickBrownFox { test.Fatal("value is not correct") }
|
||||
test.Log(meta)
|
||||
if meta.Get("foo") != "baR" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("fooo") != "Bar" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("shouldn't break anything") != "---" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("this") != "that" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("sentence") != quickBrownFox {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitMetaCRLF (test *testing.T) {
|
||||
correctBody := "this is some sample text\r\n---\r\ntheres another hr that shouldnt\r\nbreak anything\r\nbreak: anything\r\n"
|
||||
frontMatter, body, err := SplitMeta(
|
||||
meta, body, err := SplitMeta(
|
||||
"---\r\nFOO: baR\r\n fOoo: Bar\r\nShouldn't break anything: ---\r\n\r\nthis : that\r\nSentence: " + quickBrownFox + "\r\n---\r\n" + correctBody)
|
||||
if err != nil {
|
||||
test.Fatal(err)
|
||||
@ -68,22 +68,22 @@ func TestSplitMetaCRLF (test *testing.T) {
|
||||
}
|
||||
|
||||
test.Log("META:")
|
||||
test.Log(frontMatter)
|
||||
value0, ok := frontMatter["foo"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value1, ok := frontMatter["fooo"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value2, ok := frontMatter["shouldn't break anything"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value3, ok := frontMatter["this"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value4, ok := frontMatter["sentence"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
if value0 != "baR" { test.Fatal("value is not correct") }
|
||||
if value1 != "Bar" { test.Fatal("value is not correct") }
|
||||
if value2 != "---" { test.Fatal("value is not correct") }
|
||||
if value3 != "that" { test.Fatal("value is not correct") }
|
||||
if value4 != quickBrownFox { test.Fatal("value is not correct") }
|
||||
test.Log(meta)
|
||||
if meta.Get("foo") != "baR" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("fooo") != "Bar" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("shouldn't break anything") != "---" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("this") != "that" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("sentence") != quickBrownFox {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMeta (test *testing.T) {
|
||||
@ -99,13 +99,13 @@ number: 3849
|
||||
|
||||
test.Log("META:")
|
||||
test.Log(meta)
|
||||
value0, ok := meta["thing"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value1, ok := meta["other-thing"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
value2, ok := meta["number"]
|
||||
if !ok { test.Fatal("missing key") }
|
||||
if value0 != "\tQuoted string!!!!!m " { test.Fatal("value is not correct") }
|
||||
if value1 != "askdjlksajd" { test.Fatal("value is not correct") }
|
||||
if value2 != "3849" { test.Fatal("value is not correct") }
|
||||
if meta.Get("thing") != "\tQuoted string!!!!! " {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("other-thing") != "askdjlksajd" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
if meta.Get("number") != "3849" {
|
||||
test.Fatal("value is not correct")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user