mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 01:19:20 +08:00 
			
		
		
		
	templates: Add support for dots to close yaml frontmatter (#3498)
* templates: Add support for dots to close yaml frontmatter * templates: Fix regression in body output
This commit is contained in:
		@ -34,25 +34,30 @@ func extractFrontMatter(input string) (map[string]interface{}, string, error) {
 | 
				
			|||||||
	firstLine = strings.TrimSpace(firstLine)
 | 
						firstLine = strings.TrimSpace(firstLine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// see what kind of front matter there is, if any
 | 
						// see what kind of front matter there is, if any
 | 
				
			||||||
	var closingFence string
 | 
						var closingFence []string
 | 
				
			||||||
	var fmParser func([]byte) (map[string]interface{}, error)
 | 
						var fmParser func([]byte) (map[string]interface{}, error)
 | 
				
			||||||
	switch firstLine {
 | 
						for _, fmType := range supportedFrontMatterTypes {
 | 
				
			||||||
	case yamlFrontMatterFenceOpen:
 | 
							if firstLine == fmType.FenceOpen {
 | 
				
			||||||
		fmParser = yamlFrontMatter
 | 
								closingFence = fmType.FenceClose
 | 
				
			||||||
		closingFence = yamlFrontMatterFenceClose
 | 
								fmParser = fmType.ParseFunc
 | 
				
			||||||
	case tomlFrontMatterFenceOpen:
 | 
							}
 | 
				
			||||||
		fmParser = tomlFrontMatter
 | 
						}
 | 
				
			||||||
		closingFence = tomlFrontMatterFenceClose
 | 
					
 | 
				
			||||||
	case jsonFrontMatterFenceOpen:
 | 
						if fmParser == nil {
 | 
				
			||||||
		fmParser = jsonFrontMatter
 | 
					 | 
				
			||||||
		closingFence = jsonFrontMatterFenceClose
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		// no recognized front matter; whole document is body
 | 
							// no recognized front matter; whole document is body
 | 
				
			||||||
		return nil, input, nil
 | 
							return nil, input, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// find end of front matter
 | 
						// find end of front matter
 | 
				
			||||||
	fmEndFenceStart := strings.Index(input[firstLineEnd:], "\n"+closingFence)
 | 
						var fmEndFence string
 | 
				
			||||||
 | 
						fmEndFenceStart := -1
 | 
				
			||||||
 | 
						for _, fence := range closingFence {
 | 
				
			||||||
 | 
							index := strings.Index(input[firstLineEnd:], "\n"+fence)
 | 
				
			||||||
 | 
							if index >= 0 {
 | 
				
			||||||
 | 
								fmEndFenceStart = index
 | 
				
			||||||
 | 
								fmEndFence = fence
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if fmEndFenceStart < 0 {
 | 
						if fmEndFenceStart < 0 {
 | 
				
			||||||
		return nil, "", fmt.Errorf("unterminated front matter")
 | 
							return nil, "", fmt.Errorf("unterminated front matter")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -66,7 +71,7 @@ func extractFrontMatter(input string) (map[string]interface{}, string, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// the rest is the body
 | 
						// the rest is the body
 | 
				
			||||||
	body := input[fmEndFenceStart+len(closingFence):]
 | 
						body := input[fmEndFenceStart+len(fmEndFence):]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fm, body, nil
 | 
						return fm, body, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -96,8 +101,26 @@ type parsedMarkdownDoc struct {
 | 
				
			|||||||
	Body string                 `json:"body,omitempty"`
 | 
						Body string                 `json:"body,omitempty"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					type frontMatterType struct {
 | 
				
			||||||
	yamlFrontMatterFenceOpen, yamlFrontMatterFenceClose = "---", "---"
 | 
						FenceOpen  string
 | 
				
			||||||
	tomlFrontMatterFenceOpen, tomlFrontMatterFenceClose = "+++", "+++"
 | 
						FenceClose []string
 | 
				
			||||||
	jsonFrontMatterFenceOpen, jsonFrontMatterFenceClose = "{", "}"
 | 
						ParseFunc  func(input []byte) (map[string]interface{}, error)
 | 
				
			||||||
)
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var supportedFrontMatterTypes = []frontMatterType{
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FenceOpen:  "---",
 | 
				
			||||||
 | 
							FenceClose: []string{"---", "..."},
 | 
				
			||||||
 | 
							ParseFunc:  yamlFrontMatter,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FenceOpen:  "+++",
 | 
				
			||||||
 | 
							FenceClose: []string{"+++"},
 | 
				
			||||||
 | 
							ParseFunc:  tomlFrontMatter,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FenceOpen:  "{",
 | 
				
			||||||
 | 
							FenceClose: []string{"}"},
 | 
				
			||||||
 | 
							ParseFunc:  jsonFrontMatter,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -290,11 +290,13 @@ func TestSplitFrontMatter(t *testing.T) {
 | 
				
			|||||||
	for i, test := range []struct {
 | 
						for i, test := range []struct {
 | 
				
			||||||
		input  string
 | 
							input  string
 | 
				
			||||||
		expect string
 | 
							expect string
 | 
				
			||||||
 | 
							body   string
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// yaml with windows newline
 | 
								// yaml with windows newline
 | 
				
			||||||
			input:  "---\r\ntitle: Welcome\r\n---\r\n# Test\\r\\n",
 | 
								input:  "---\r\ntitle: Welcome\r\n---\r\n# Test\\r\\n",
 | 
				
			||||||
			expect: `Welcome`,
 | 
								expect: `Welcome`,
 | 
				
			||||||
 | 
								body:   "\r\n# Test\\r\\n",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// yaml
 | 
								// yaml
 | 
				
			||||||
@ -303,6 +305,16 @@ title: Welcome
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
### Test`,
 | 
					### Test`,
 | 
				
			||||||
			expect: `Welcome`,
 | 
								expect: `Welcome`,
 | 
				
			||||||
 | 
								body:   "\n### Test",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// yaml with dots for closer
 | 
				
			||||||
 | 
								input: `---
 | 
				
			||||||
 | 
					title: Welcome
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					### Test`,
 | 
				
			||||||
 | 
								expect: `Welcome`,
 | 
				
			||||||
 | 
								body:   "\n### Test",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// toml
 | 
								// toml
 | 
				
			||||||
@ -311,6 +323,7 @@ title = "Welcome"
 | 
				
			|||||||
+++
 | 
					+++
 | 
				
			||||||
### Test`,
 | 
					### Test`,
 | 
				
			||||||
			expect: `Welcome`,
 | 
								expect: `Welcome`,
 | 
				
			||||||
 | 
								body:   "\n### Test",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// json
 | 
								// json
 | 
				
			||||||
@ -319,12 +332,16 @@ title = "Welcome"
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
### Test`,
 | 
					### Test`,
 | 
				
			||||||
			expect: `Welcome`,
 | 
								expect: `Welcome`,
 | 
				
			||||||
 | 
								body:   "\n### Test",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	} {
 | 
						} {
 | 
				
			||||||
		result, _ := context.funcSplitFrontMatter(test.input)
 | 
							result, _ := context.funcSplitFrontMatter(test.input)
 | 
				
			||||||
		if result.Meta["title"] != test.expect {
 | 
							if result.Meta["title"] != test.expect {
 | 
				
			||||||
			t.Errorf("Test %d: Expected %s, found %s. Input was SplitFrontMatter(%s)", i, test.expect, result.Meta["title"], test.input)
 | 
								t.Errorf("Test %d: Expected %s, found %s. Input was SplitFrontMatter(%s)", i, test.expect, result.Meta["title"], test.input)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if result.Body != test.body {
 | 
				
			||||||
 | 
								t.Errorf("Test %d: Expected body %s, found %s. Input was SplitFrontMatter(%s)", i, test.body, result.Body, test.input)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user