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
|
// read entire file and split into front matter and body
|
||||||
buffer, err := io.ReadAll(input)
|
buffer, err := io.ReadAll(input)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
frontMatter, body, err := SplitMeta(string(buffer))
|
meta, body, err := SplitMeta(string(buffer))
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
// assemble the document struct
|
// assemble the document struct
|
||||||
document := &Document {
|
document := &Document {
|
||||||
Meta: frontMatter,
|
Meta: meta,
|
||||||
environment: this,
|
environment: this,
|
||||||
name: name,
|
name: name,
|
||||||
parseTime: time.Now(),
|
parseTime: time.Now(),
|
||||||
template: template.New(name),
|
template: template.New(name),
|
||||||
}
|
}
|
||||||
if author, ok := frontMatter["author"]; ok {
|
if author := meta.Get("author"); author != "" {
|
||||||
document.Author = author
|
document.Author = author
|
||||||
}
|
}
|
||||||
if title, ok := frontMatter["title"]; ok {
|
if title := meta.Get("title"); title != "" {
|
||||||
document.Title = title
|
document.Title = title
|
||||||
}
|
}
|
||||||
if extends, ok := frontMatter["extends"]; ok {
|
if extends := meta.Get("extends"); extends != "" {
|
||||||
document.Extends = extends
|
document.Extends = extends
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
error.go
1
error.go
@ -5,7 +5,6 @@ type Error string; const (
|
|||||||
ErrCircularInheritance Error = "circular inheritance"
|
ErrCircularInheritance Error = "circular inheritance"
|
||||||
ErrMetaMalformed Error = "metadata is malformed"
|
ErrMetaMalformed Error = "metadata is malformed"
|
||||||
ErrMetaNeverClosed Error = "metadata is never closed"
|
ErrMetaNeverClosed Error = "metadata is never closed"
|
||||||
ErrMetaDuplicateKey Error = "duplicate key in front matter"
|
|
||||||
ErrTypeMismatch Error = "type mismatch"
|
ErrTypeMismatch Error = "type mismatch"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -112,10 +112,10 @@ func (this *Handler) serveDocument (
|
|||||||
recorder.Reset()
|
recorder.Reset()
|
||||||
recorder.Head = res.Header().Clone()
|
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)
|
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 {
|
if status, err := strconv.Atoi(status); err == nil {
|
||||||
recorder.Status = status
|
recorder.Status = status
|
||||||
}
|
}
|
||||||
|
53
meta.go
53
meta.go
@ -1,6 +1,7 @@
|
|||||||
package step
|
package step
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
import "slices"
|
||||||
import "strconv"
|
import "strconv"
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
@ -8,7 +9,7 @@ const metaRule = "---"
|
|||||||
|
|
||||||
// Meta represents optional metadata that can occur at the very start of
|
// Meta represents optional metadata that can occur at the very start of
|
||||||
// a document.
|
// a document.
|
||||||
type Meta = map[string] string
|
type Meta map[string] []string
|
||||||
|
|
||||||
// SplitMeta parses the metadata (if it exists), returning a map representing it
|
// 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
|
// 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 {
|
if !ok {
|
||||||
return nil, ErrMetaMalformed
|
return nil, ErrMetaMalformed
|
||||||
}
|
}
|
||||||
key = strings.ToLower(strings.TrimSpace(key))
|
key = strings.TrimSpace(key)
|
||||||
value = strings.TrimSpace(value)
|
value = strings.TrimSpace(value)
|
||||||
if strings.HasPrefix(value, "\"") || strings.HasPrefix(value, "'") {
|
if strings.HasPrefix(value, "\"") || strings.HasPrefix(value, "'") {
|
||||||
unquoted, err := strconv.Unquote(value)
|
unquoted, err := strconv.Unquote(value)
|
||||||
@ -64,10 +65,7 @@ func ParseMeta (input string) (Meta, error) {
|
|||||||
if key == "" {
|
if key == "" {
|
||||||
return nil, ErrMetaMalformed
|
return nil, ErrMetaMalformed
|
||||||
}
|
}
|
||||||
if _, exists := meta[key]; exists {
|
meta.Add(key, value)
|
||||||
return nil, ErrMetaDuplicateKey
|
|
||||||
}
|
|
||||||
meta[key] = value
|
|
||||||
}
|
}
|
||||||
return meta, nil
|
return meta, nil
|
||||||
}
|
}
|
||||||
@ -78,3 +76,46 @@ func DecodeMeta (input io.Reader) (Meta, error) {
|
|||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
return ParseMeta(string(buffer))
|
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
|
||||||
break: anything
|
break: anything
|
||||||
`
|
`
|
||||||
frontMatter, body, err := SplitMeta(
|
meta, body, err := SplitMeta(
|
||||||
`---
|
`---
|
||||||
FOO: baR
|
FOO: baR
|
||||||
fOoo: Bar
|
fOoo: Bar
|
||||||
@ -34,27 +34,27 @@ Sentence: ` + quickBrownFox + `
|
|||||||
}
|
}
|
||||||
|
|
||||||
test.Log("META:")
|
test.Log("META:")
|
||||||
test.Log(frontMatter)
|
test.Log(meta)
|
||||||
value0, ok := frontMatter["foo"]
|
if meta.Get("foo") != "baR" {
|
||||||
if !ok { test.Fatal("missing key") }
|
test.Fatal("value is not correct")
|
||||||
value1, ok := frontMatter["fooo"]
|
}
|
||||||
if !ok { test.Fatal("missing key") }
|
if meta.Get("fooo") != "Bar" {
|
||||||
value2, ok := frontMatter["shouldn't break anything"]
|
test.Fatal("value is not correct")
|
||||||
if !ok { test.Fatal("missing key") }
|
}
|
||||||
value3, ok := frontMatter["this"]
|
if meta.Get("shouldn't break anything") != "---" {
|
||||||
if !ok { test.Fatal("missing key") }
|
test.Fatal("value is not correct")
|
||||||
value4, ok := frontMatter["sentence"]
|
}
|
||||||
if !ok { test.Fatal("missing key") }
|
if meta.Get("this") != "that" {
|
||||||
if value0 != "baR" { test.Fatal("value is not correct") }
|
test.Fatal("value is not correct")
|
||||||
if value1 != "Bar" { test.Fatal("value is not correct") }
|
}
|
||||||
if value2 != "---" { test.Fatal("value is not correct") }
|
if meta.Get("sentence") != quickBrownFox {
|
||||||
if value3 != "that" { test.Fatal("value is not correct") }
|
test.Fatal("value is not correct")
|
||||||
if value4 != quickBrownFox { test.Fatal("value is not correct") }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSplitMetaCRLF (test *testing.T) {
|
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"
|
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)
|
"---\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 {
|
if err != nil {
|
||||||
test.Fatal(err)
|
test.Fatal(err)
|
||||||
@ -68,22 +68,22 @@ func TestSplitMetaCRLF (test *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test.Log("META:")
|
test.Log("META:")
|
||||||
test.Log(frontMatter)
|
test.Log(meta)
|
||||||
value0, ok := frontMatter["foo"]
|
if meta.Get("foo") != "baR" {
|
||||||
if !ok { test.Fatal("missing key") }
|
test.Fatal("value is not correct")
|
||||||
value1, ok := frontMatter["fooo"]
|
}
|
||||||
if !ok { test.Fatal("missing key") }
|
if meta.Get("fooo") != "Bar" {
|
||||||
value2, ok := frontMatter["shouldn't break anything"]
|
test.Fatal("value is not correct")
|
||||||
if !ok { test.Fatal("missing key") }
|
}
|
||||||
value3, ok := frontMatter["this"]
|
if meta.Get("shouldn't break anything") != "---" {
|
||||||
if !ok { test.Fatal("missing key") }
|
test.Fatal("value is not correct")
|
||||||
value4, ok := frontMatter["sentence"]
|
}
|
||||||
if !ok { test.Fatal("missing key") }
|
if meta.Get("this") != "that" {
|
||||||
if value0 != "baR" { test.Fatal("value is not correct") }
|
test.Fatal("value is not correct")
|
||||||
if value1 != "Bar" { test.Fatal("value is not correct") }
|
}
|
||||||
if value2 != "---" { test.Fatal("value is not correct") }
|
if meta.Get("sentence") != quickBrownFox {
|
||||||
if value3 != "that" { test.Fatal("value is not correct") }
|
test.Fatal("value is not correct")
|
||||||
if value4 != quickBrownFox { test.Fatal("value is not correct") }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseMeta (test *testing.T) {
|
func TestParseMeta (test *testing.T) {
|
||||||
@ -99,13 +99,13 @@ number: 3849
|
|||||||
|
|
||||||
test.Log("META:")
|
test.Log("META:")
|
||||||
test.Log(meta)
|
test.Log(meta)
|
||||||
value0, ok := meta["thing"]
|
if meta.Get("thing") != "\tQuoted string!!!!! " {
|
||||||
if !ok { test.Fatal("missing key") }
|
test.Fatal("value is not correct")
|
||||||
value1, ok := meta["other-thing"]
|
}
|
||||||
if !ok { test.Fatal("missing key") }
|
if meta.Get("other-thing") != "askdjlksajd" {
|
||||||
value2, ok := meta["number"]
|
test.Fatal("value is not correct")
|
||||||
if !ok { test.Fatal("missing key") }
|
}
|
||||||
if value0 != "\tQuoted string!!!!!m " { test.Fatal("value is not correct") }
|
if meta.Get("number") != "3849" {
|
||||||
if value1 != "askdjlksajd" { test.Fatal("value is not correct") }
|
test.Fatal("value is not correct")
|
||||||
if value2 != "3849" { test.Fatal("value is not correct") }
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user