mirror of
https://github.com/danog/liquid.git
synced 2024-11-27 06:24:39 +01:00
Chunk regex wasn't sufficiently non-greedy
This commit is contained in:
parent
43bedef367
commit
f8b55032f4
@ -69,7 +69,8 @@ func Parse(chunks []Chunk) (ASTNode, error) {
|
||||
ap = &n.Body
|
||||
case cd.isEndTag:
|
||||
f := stack[len(stack)-1]
|
||||
ccd, ccn, ap, stack = f.cd, f.cn, f.ap, stack[:len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
ccd, ccn, ap = f.cd, f.cn, f.ap
|
||||
}
|
||||
} else if td, ok := FindTagDefinition(c.Tag); ok {
|
||||
f, err := td(c.Args)
|
||||
|
52
chunks/parser_test.go
Normal file
52
chunks/parser_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package chunks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func init() {
|
||||
DefineControlTag("case").Branch("when")
|
||||
DefineControlTag("comment")
|
||||
DefineControlTag("for").Governs([]string{"break"})
|
||||
DefineControlTag("if").Branch("else").Branch("elsif")
|
||||
DefineControlTag("raw")
|
||||
}
|
||||
|
||||
var parseErrorTests = []struct{ in, expected string }{
|
||||
{"{%unknown_tag%}", "unknown tag"},
|
||||
{"{%if test%}", "unterminated if tag"},
|
||||
// {"{%if syntax error%}{%endif%}", "parse error"},
|
||||
}
|
||||
|
||||
var parserTests = []struct{ in string }{
|
||||
{`{% for item in list %}{% endfor %}`},
|
||||
{`{% if test %}{% else %}{% endif %}`},
|
||||
{`{% if test %}{% if test %}{% endif %}{% endif %}`},
|
||||
{`{% for item in list %}{% if test %}{% else %}{% endif x %}{% endfor %}`},
|
||||
}
|
||||
|
||||
func TestParseErrors(t *testing.T) {
|
||||
for i, test := range parseErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
|
||||
tokens := Scan(test.in, "")
|
||||
ast, err := Parse(tokens)
|
||||
require.Nilf(t, ast, test.in)
|
||||
require.Errorf(t, err, test.in)
|
||||
require.Containsf(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParser(t *testing.T) {
|
||||
for i, test := range parserTests {
|
||||
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
|
||||
tokens := Scan(test.in, "")
|
||||
_, err := Parse(tokens)
|
||||
require.NoError(t, err, test.in)
|
||||
// require.Containsf(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
}
|
||||
}
|
@ -8,12 +8,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var parseErrorTests = []struct{ in, expected string }{
|
||||
{"{%unknown_tag%}", "unknown tag"},
|
||||
// {"{%if syntax error%}", "unterminated if tag"},
|
||||
// {"{%if syntax error%}{%endif%}", "parse error"},
|
||||
}
|
||||
|
||||
var renderTests = []struct{ in, expected string }{
|
||||
// {"{%if syntax error%}{%endif%}", "parse error"},
|
||||
{"{{12}}", "12"},
|
||||
@ -50,17 +44,6 @@ var renderTestContext = Context{map[string]interface{}{
|
||||
},
|
||||
}
|
||||
|
||||
func TestParseErrors(t *testing.T) {
|
||||
for i, test := range parseErrorTests {
|
||||
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
|
||||
tokens := Scan(test.in, "")
|
||||
ast, err := Parse(tokens)
|
||||
require.Nilf(t, ast, test.in)
|
||||
require.Errorf(t, err, test.in)
|
||||
require.Containsf(t, err.Error(), test.expected, test.in)
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestRender(t *testing.T) {
|
||||
for i, test := range renderTests {
|
||||
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
|
||||
|
@ -3,6 +3,7 @@
|
||||
package chunks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
@ -15,6 +16,19 @@ type Chunk struct {
|
||||
Args string // Args is the tag arguments of a tag Chunk. E.g. the tag arguments of "{% if 1 %}" is "1".
|
||||
}
|
||||
|
||||
func (c Chunk) String() string {
|
||||
switch c.Type {
|
||||
case TextChunkType:
|
||||
return fmt.Sprintf("%s{%#v}", c.Type, c.Source)
|
||||
case TagChunkType:
|
||||
return fmt.Sprintf("%s{Tag:%#v, Args:%#v}", c.Type, c.Tag, c.Args)
|
||||
case ObjChunkType:
|
||||
return fmt.Sprintf("%s{%#v}", c.Type, c.Args)
|
||||
default:
|
||||
return fmt.Sprintf("%s{%#v}", c.Type, c.Source)
|
||||
}
|
||||
}
|
||||
|
||||
// SourceInfo contains a Chunk's source information
|
||||
type SourceInfo struct {
|
||||
Pathname string
|
||||
@ -30,7 +44,7 @@ const (
|
||||
ObjChunkType // TextChunkType is the type of an object Chunk "{{…}}"
|
||||
)
|
||||
|
||||
var chunkMatcher = regexp.MustCompile(`{{\s*(.+?)\s*}}|{%\s*(\w+)(?:\s+(.+?))?\s*%}`)
|
||||
var chunkMatcher = regexp.MustCompile(`{{\s*(.+?)\s*}}|{%\s*(\w+)(?:\s+((?:[^%]|%[^}])+?))?\s*%}`)
|
||||
|
||||
// Scan breaks a string into a sequence of Chunks.
|
||||
func Scan(data string, pathname string) []Chunk {
|
||||
|
@ -1,11 +1,27 @@
|
||||
package chunks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var scannerCountTests = []struct {
|
||||
in string
|
||||
len int
|
||||
}{
|
||||
{`{% tag arg %}`, 1},
|
||||
{`{% tag arg %}{% tag %}`, 2},
|
||||
{`{% tag arg %}{% tag arg %}{% tag %}`, 3},
|
||||
{`{% tag %}{% tag %}`, 2},
|
||||
{`{% tag arg %}{% tag arg %}{% tag %}{% tag %}`, 4},
|
||||
{`{{ expr }}`, 1},
|
||||
{`{{ expr arg }}`, 1},
|
||||
{`{{ expr }}{{ expr }}`, 2},
|
||||
{`{{ expr arg }}{{ expr arg }}`, 2},
|
||||
}
|
||||
|
||||
func TestScanner(t *testing.T) {
|
||||
tokens := Scan("12", "")
|
||||
require.NotNil(t, tokens)
|
||||
@ -38,4 +54,11 @@ func TestScanner(t *testing.T) {
|
||||
require.Equal(t, TagChunkType, tokens[0].Type)
|
||||
require.Equal(t, "tag", tokens[0].Tag)
|
||||
require.Equal(t, "args", tokens[0].Args)
|
||||
|
||||
for i, test := range scannerCountTests {
|
||||
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
|
||||
tokens := Scan(test.in, "")
|
||||
require.Len(t, tokens, test.len)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ func genericCompare(a, b reflect.Value) int {
|
||||
return 0
|
||||
}
|
||||
if a.Type() == b.Type() {
|
||||
fmt.Println("cf", a, b, a.Type(), b.Type())
|
||||
return genericSameTypeCompare(a.Interface(), b.Interface())
|
||||
}
|
||||
ak, bk := a.Kind(), b.Kind()
|
||||
|
Loading…
Reference in New Issue
Block a user