mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
tpl/internal/go_templates: Revert formatting
Should make future fork synch easier.
This commit is contained in:
parent
d90e37e0c6
commit
718e09ed4b
21 changed files with 173 additions and 322 deletions
|
@ -6,12 +6,11 @@ package fmtsort_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var compareTests = [][]reflect.Value{
|
var compareTests = [][]reflect.Value{
|
||||||
|
|
|
@ -427,7 +427,7 @@ func TestStringer(t *testing.T) {
|
||||||
if err := tmpl.Execute(b, s); err != nil {
|
if err := tmpl.Execute(b, s); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
expect := "string=3"
|
var expect = "string=3"
|
||||||
if b.String() != expect {
|
if b.String() != expect {
|
||||||
t.Errorf("expected %q got %q", expect, b.String())
|
t.Errorf("expected %q got %q", expect, b.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,10 +210,8 @@ var cssReplacementTable = []string{
|
||||||
'}': `\7d`,
|
'}': `\7d`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var expressionBytes = []byte("expression")
|
||||||
expressionBytes = []byte("expression")
|
var mozBindingBytes = []byte("mozbinding")
|
||||||
mozBindingBytes = []byte("mozbinding")
|
|
||||||
)
|
|
||||||
|
|
||||||
// cssValueFilter allows innocuous CSS values in the output including CSS
|
// cssValueFilter allows innocuous CSS values in the output including CSS
|
||||||
// quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values
|
// quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values
|
||||||
|
|
|
@ -891,6 +891,7 @@ func TestEscapeSet(t *testing.T) {
|
||||||
t.Errorf("want\n\t%q\ngot\n\t%q", test.want, got)
|
t.Errorf("want\n\t%q\ngot\n\t%q", test.want, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrors(t *testing.T) {
|
func TestErrors(t *testing.T) {
|
||||||
|
@ -1087,6 +1088,7 @@ func TestErrors(t *testing.T) {
|
||||||
// Check that we get the same error if we call Execute again.
|
// Check that we get the same error if we call Execute again.
|
||||||
if err := tmpl.Execute(buf, nil); err == nil || err.Error() != got {
|
if err := tmpl.Execute(buf, nil); err == nil || err.Error() != got {
|
||||||
t.Errorf("input=%q: unexpected error on second call %q", test.input, err)
|
t.Errorf("input=%q: unexpected error on second call %q", test.input, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ func Example() {
|
||||||
// <div><strong>no rows</strong></div>
|
// <div><strong>no rows</strong></div>
|
||||||
// </body>
|
// </body>
|
||||||
// </html>
|
// </html>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Example_autoescaping() {
|
func Example_autoescaping() {
|
||||||
|
@ -122,6 +123,7 @@ func Example_escape() {
|
||||||
// \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
|
// \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
|
||||||
// \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E
|
// \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E
|
||||||
// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
|
// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleTemplate_Delims() {
|
func ExampleTemplate_Delims() {
|
||||||
|
|
|
@ -337,7 +337,6 @@ var jsStrNormReplacementTable = []string{
|
||||||
'<': `\u003c`,
|
'<': `\u003c`,
|
||||||
'>': `\u003e`,
|
'>': `\u003e`,
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsRegexpReplacementTable = []string{
|
var jsRegexpReplacementTable = []string{
|
||||||
0: `\u0000`,
|
0: `\u0000`,
|
||||||
'\t': `\t`,
|
'\t': `\t`,
|
||||||
|
|
|
@ -206,8 +206,7 @@ func TestJSStrEscaper(t *testing.T) {
|
||||||
{"<!--", `\u003c!--`},
|
{"<!--", `\u003c!--`},
|
||||||
{"-->", `--\u003e`},
|
{"-->", `--\u003e`},
|
||||||
// From https://code.google.com/p/doctype/wiki/ArticleUtf7
|
// From https://code.google.com/p/doctype/wiki/ArticleUtf7
|
||||||
{
|
{"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
|
||||||
"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
|
|
||||||
`\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`,
|
`\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`,
|
||||||
},
|
},
|
||||||
// Invalid UTF-8 sequence
|
// Invalid UTF-8 sequence
|
||||||
|
|
|
@ -41,10 +41,8 @@ var transitionFunc = [...]func(context, []byte) (context, int){
|
||||||
stateError: tError,
|
stateError: tError,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var commentStart = []byte("<!--")
|
||||||
commentStart = []byte("<!--")
|
var commentEnd = []byte("-->")
|
||||||
commentEnd = []byte("-->")
|
|
||||||
)
|
|
||||||
|
|
||||||
// tText is the context transition function for the text state.
|
// tText is the context transition function for the text state.
|
||||||
func tText(c context, s []byte) (context, int) {
|
func tText(c context, s []byte) (context, int) {
|
||||||
|
|
|
@ -42,6 +42,7 @@ func TestFindEndTag(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkTemplateSpecialTags(b *testing.B) {
|
func BenchmarkTemplateSpecialTags(b *testing.B) {
|
||||||
|
|
||||||
r := struct {
|
r := struct {
|
||||||
Name, Gift string
|
Name, Gift string
|
||||||
}{"Aunt Mildred", "bone china tea set"}
|
}{"Aunt Mildred", "bone china tea set"}
|
||||||
|
|
|
@ -13,6 +13,7 @@ package testenv
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"github.com/gohugoio/hugo/tpl/internal/go_templates/cfg"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -21,8 +22,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/tpl/internal/go_templates/cfg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Builder reports the name of the builder running this test
|
// Builder reports the name of the builder running this test
|
||||||
|
|
|
@ -12,10 +12,8 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var symlinkOnce sync.Once
|
||||||
symlinkOnce sync.Once
|
var winSymlinkErr error
|
||||||
winSymlinkErr error
|
|
||||||
)
|
|
||||||
|
|
||||||
func initWinHasSymlink() {
|
func initWinHasSymlink() {
|
||||||
tmpdir, err := ioutil.TempDir("", "symtest")
|
tmpdir, err := ioutil.TempDir("", "symtest")
|
||||||
|
|
|
@ -34,7 +34,7 @@ Josie
|
||||||
Name, Gift string
|
Name, Gift string
|
||||||
Attended bool
|
Attended bool
|
||||||
}
|
}
|
||||||
recipients := []Recipient{
|
var recipients = []Recipient{
|
||||||
{"Aunt Mildred", "bone china tea set", true},
|
{"Aunt Mildred", "bone china tea set", true},
|
||||||
{"Uncle John", "moleskin pants", false},
|
{"Uncle John", "moleskin pants", false},
|
||||||
{"Cousin Rodney", "", false},
|
{"Cousin Rodney", "", false},
|
||||||
|
|
|
@ -6,13 +6,12 @@ package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
|
||||||
|
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
|
|
||||||
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// maxExecDepth specifies the maximum stack depth of templates within
|
// maxExecDepth specifies the maximum stack depth of templates within
|
||||||
|
|
|
@ -318,16 +318,12 @@ var execTests = []execTest{
|
||||||
{"$.U.V", "{{$.U.V}}", "v", tVal, true},
|
{"$.U.V", "{{$.U.V}}", "v", tVal, true},
|
||||||
{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
|
{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
|
||||||
{"simple assignment", "{{$x := 2}}{{$x = 3}}{{$x}}", "3", tVal, true},
|
{"simple assignment", "{{$x := 2}}{{$x = 3}}{{$x}}", "3", tVal, true},
|
||||||
{
|
{"nested assignment",
|
||||||
"nested assignment",
|
|
||||||
"{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{$x}}",
|
"{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{$x}}",
|
||||||
"3", tVal, true,
|
"3", tVal, true},
|
||||||
},
|
{"nested assignment changes the last declaration",
|
||||||
{
|
|
||||||
"nested assignment changes the last declaration",
|
|
||||||
"{{$x := 1}}{{if true}}{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{end}}{{$x}}",
|
"{{$x := 1}}{{if true}}{{$x := 2}}{{if true}}{{$x = 3}}{{end}}{{end}}{{$x}}",
|
||||||
"1", tVal, true,
|
"1", tVal, true},
|
||||||
},
|
|
||||||
|
|
||||||
// Type with String method.
|
// Type with String method.
|
||||||
{"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
|
{"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
|
||||||
|
@ -374,21 +370,15 @@ var execTests = []execTest{
|
||||||
{".Method3(nil constant)", "-{{.Method3 nil}}-", "-Method3: <nil>-", tVal, true},
|
{".Method3(nil constant)", "-{{.Method3 nil}}-", "-Method3: <nil>-", tVal, true},
|
||||||
{".Method3(nil value)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
|
{".Method3(nil value)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
|
||||||
{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
|
{"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
|
||||||
{
|
{"method on chained var",
|
||||||
"method on chained var",
|
|
||||||
"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
|
"{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
|
||||||
"true", tVal, true,
|
"true", tVal, true},
|
||||||
},
|
{"chained method",
|
||||||
{
|
|
||||||
"chained method",
|
|
||||||
"{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
|
"{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
|
||||||
"true", tVal, true,
|
"true", tVal, true},
|
||||||
},
|
{"chained method on variable",
|
||||||
{
|
|
||||||
"chained method on variable",
|
|
||||||
"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
|
"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
|
||||||
"true", tVal, true,
|
"true", tVal, true},
|
||||||
},
|
|
||||||
{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
|
{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
|
||||||
{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
|
{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
|
||||||
{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
|
{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
|
||||||
|
@ -474,14 +464,10 @@ var execTests = []execTest{
|
||||||
{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
|
{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
|
||||||
|
|
||||||
// HTML.
|
// HTML.
|
||||||
{
|
{"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
|
||||||
"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
|
"<script>alert("XSS");</script>", nil, true},
|
||||||
"<script>alert("XSS");</script>", nil, true,
|
{"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
|
||||||
},
|
"<script>alert("XSS");</script>", nil, true},
|
||||||
{
|
|
||||||
"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
|
|
||||||
"<script>alert("XSS");</script>", nil, true,
|
|
||||||
},
|
|
||||||
{"html", `{{html .PS}}`, "a string", tVal, true},
|
{"html", `{{html .PS}}`, "a string", tVal, true},
|
||||||
{"html typed nil", `{{html .NIL}}`, "<nil>", tVal, true},
|
{"html typed nil", `{{html .NIL}}`, "<nil>", tVal, true},
|
||||||
{"html untyped nil", `{{html .Empty0}}`, "<no value>", tVal, true},
|
{"html untyped nil", `{{html .Empty0}}`, "<no value>", tVal, true},
|
||||||
|
@ -839,7 +825,7 @@ var delimPairs = []string{
|
||||||
|
|
||||||
func TestDelims(t *testing.T) {
|
func TestDelims(t *testing.T) {
|
||||||
const hello = "Hello, world"
|
const hello = "Hello, world"
|
||||||
value := struct{ Str string }{hello}
|
var value = struct{ Str string }{hello}
|
||||||
for i := 0; i < len(delimPairs); i += 2 {
|
for i := 0; i < len(delimPairs); i += 2 {
|
||||||
text := ".Str"
|
text := ".Str"
|
||||||
left := delimPairs[i+0]
|
left := delimPairs[i+0]
|
||||||
|
@ -862,7 +848,7 @@ func TestDelims(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("delim %q text %q parse err %s", left, text, err)
|
t.Fatalf("delim %q text %q parse err %s", left, text, err)
|
||||||
}
|
}
|
||||||
b := new(bytes.Buffer)
|
var b = new(bytes.Buffer)
|
||||||
err = tmpl.Execute(b, value)
|
err = tmpl.Execute(b, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("delim %q exec err %s", left, err)
|
t.Fatalf("delim %q exec err %s", left, err)
|
||||||
|
@ -963,7 +949,7 @@ const treeTemplate = `
|
||||||
`
|
`
|
||||||
|
|
||||||
func TestTree(t *testing.T) {
|
func TestTree(t *testing.T) {
|
||||||
tree := &Tree{
|
var tree = &Tree{
|
||||||
1,
|
1,
|
||||||
&Tree{
|
&Tree{
|
||||||
2, &Tree{
|
2, &Tree{
|
||||||
|
@ -1209,7 +1195,7 @@ var cmpTests = []cmpTest{
|
||||||
|
|
||||||
func TestComparison(t *testing.T) {
|
func TestComparison(t *testing.T) {
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
cmpStruct := struct {
|
var cmpStruct = struct {
|
||||||
Uthree, Ufour uint
|
Uthree, Ufour uint
|
||||||
NegOne, Three int
|
NegOne, Three int
|
||||||
Ptr, NilPtr *int
|
Ptr, NilPtr *int
|
||||||
|
|
|
@ -77,6 +77,7 @@ func (t *executer) Execute(p Preparer, wr io.Writer, data interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmpl.executeWithState(state, value)
|
return tmpl.executeWithState(state, value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare returns a template ready for execution.
|
// Prepare returns a template ready for execution.
|
||||||
|
|
|
@ -85,4 +85,5 @@ Method: {{ .Hello1 "v1" }}
|
||||||
c.Assert(got, qt.Contains, "hello hugo")
|
c.Assert(got, qt.Contains, "hello hugo")
|
||||||
c.Assert(got, qt.Contains, "Map: av")
|
c.Assert(got, qt.Contains, "Map: av")
|
||||||
c.Assert(got, qt.Contains, "Method: v2 v1")
|
c.Assert(got, qt.Contains, "Method: v2 v1")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,8 @@ package template
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
|
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -30,32 +29,22 @@ type multiParseTest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var multiParseTests = []multiParseTest{
|
var multiParseTests = []multiParseTest{
|
||||||
{
|
{"empty", "", noError,
|
||||||
"empty", "", noError,
|
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil},
|
||||||
},
|
{"one", `{{define "foo"}} FOO {{end}}`, noError,
|
||||||
{
|
|
||||||
"one", `{{define "foo"}} FOO {{end}}`, noError,
|
|
||||||
[]string{"foo"},
|
[]string{"foo"},
|
||||||
[]string{" FOO "},
|
[]string{" FOO "}},
|
||||||
},
|
{"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
|
||||||
{
|
|
||||||
"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
|
|
||||||
[]string{"foo", "bar"},
|
[]string{"foo", "bar"},
|
||||||
[]string{" FOO ", " BAR "},
|
[]string{" FOO ", " BAR "}},
|
||||||
},
|
|
||||||
// errors
|
// errors
|
||||||
{
|
{"missing end", `{{define "foo"}} FOO `, hasError,
|
||||||
"missing end", `{{define "foo"}} FOO `, hasError,
|
|
||||||
nil,
|
nil,
|
||||||
|
nil},
|
||||||
|
{"malformed name", `{{define "foo}} FOO `, hasError,
|
||||||
nil,
|
nil,
|
||||||
},
|
nil},
|
||||||
{
|
|
||||||
"malformed name", `{{define "foo}} FOO `, hasError,
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiParse(t *testing.T) {
|
func TestMultiParse(t *testing.T) {
|
||||||
|
@ -411,7 +400,7 @@ func TestIssue19294(t *testing.T) {
|
||||||
// by the contents of "stylesheet", but if the internal map associating
|
// by the contents of "stylesheet", but if the internal map associating
|
||||||
// names with templates is built in the wrong order, the empty block
|
// names with templates is built in the wrong order, the empty block
|
||||||
// looks non-empty and this doesn't happen.
|
// looks non-empty and this doesn't happen.
|
||||||
inlined := map[string]string{
|
var inlined = map[string]string{
|
||||||
"stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
|
"stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`,
|
||||||
"xhtml": `{{block "stylesheet" .}}{{end}}`,
|
"xhtml": `{{block "stylesheet" .}}{{end}}`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,6 +249,7 @@ func (a *ActionNode) tree() *Tree {
|
||||||
|
|
||||||
func (a *ActionNode) Copy() Node {
|
func (a *ActionNode) Copy() Node {
|
||||||
return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
|
return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandNode holds a command (a pipeline inside an evaluating action).
|
// CommandNode holds a command (a pipeline inside an evaluating action).
|
||||||
|
|
|
@ -453,7 +453,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int
|
||||||
var next Node
|
var next Node
|
||||||
list, next = t.itemList()
|
list, next = t.itemList()
|
||||||
switch next.Type() {
|
switch next.Type() {
|
||||||
case nodeEnd: // done
|
case nodeEnd: //done
|
||||||
case nodeElse:
|
case nodeElse:
|
||||||
if allowElseIf {
|
if allowElseIf {
|
||||||
// Special case for "else if". If the "else" is followed immediately by an "if",
|
// Special case for "else if". If the "else" is followed immediately by an "if",
|
||||||
|
|
|
@ -178,134 +178,70 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var parseTests = []parseTest{
|
var parseTests = []parseTest{
|
||||||
{
|
{"empty", "", noError,
|
||||||
"empty", "", noError,
|
``},
|
||||||
``,
|
{"comment", "{{/*\n\n\n*/}}", noError,
|
||||||
},
|
``},
|
||||||
{
|
{"spaces", " \t\n", noError,
|
||||||
"comment", "{{/*\n\n\n*/}}", noError,
|
`" \t\n"`},
|
||||||
``,
|
{"text", "some text", noError,
|
||||||
},
|
`"some text"`},
|
||||||
{
|
{"emptyAction", "{{}}", hasError,
|
||||||
"spaces", " \t\n", noError,
|
`{{}}`},
|
||||||
`" \t\n"`,
|
{"field", "{{.X}}", noError,
|
||||||
},
|
`{{.X}}`},
|
||||||
{
|
{"simple command", "{{printf}}", noError,
|
||||||
"text", "some text", noError,
|
`{{printf}}`},
|
||||||
`"some text"`,
|
{"$ invocation", "{{$}}", noError,
|
||||||
},
|
"{{$}}"},
|
||||||
{
|
{"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError,
|
||||||
"emptyAction", "{{}}", hasError,
|
"{{with $x := 3}}{{$x 23}}{{end}}"},
|
||||||
`{{}}`,
|
{"variable with fields", "{{$.I}}", noError,
|
||||||
},
|
"{{$.I}}"},
|
||||||
{
|
{"multi-word command", "{{printf `%d` 23}}", noError,
|
||||||
"field", "{{.X}}", noError,
|
"{{printf `%d` 23}}"},
|
||||||
`{{.X}}`,
|
{"pipeline", "{{.X|.Y}}", noError,
|
||||||
},
|
`{{.X | .Y}}`},
|
||||||
{
|
{"pipeline with decl", "{{$x := .X|.Y}}", noError,
|
||||||
"simple command", "{{printf}}", noError,
|
`{{$x := .X | .Y}}`},
|
||||||
`{{printf}}`,
|
{"nested pipeline", "{{.X (.Y .Z) (.A | .B .C) (.E)}}", noError,
|
||||||
},
|
`{{.X (.Y .Z) (.A | .B .C) (.E)}}`},
|
||||||
{
|
{"field applied to parentheses", "{{(.Y .Z).Field}}", noError,
|
||||||
"$ invocation", "{{$}}", noError,
|
`{{(.Y .Z).Field}}`},
|
||||||
"{{$}}",
|
{"simple if", "{{if .X}}hello{{end}}", noError,
|
||||||
},
|
`{{if .X}}"hello"{{end}}`},
|
||||||
{
|
{"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
|
||||||
"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError,
|
`{{if .X}}"true"{{else}}"false"{{end}}`},
|
||||||
"{{with $x := 3}}{{$x 23}}{{end}}",
|
{"if with else if", "{{if .X}}true{{else if .Y}}false{{end}}", noError,
|
||||||
},
|
`{{if .X}}"true"{{else}}{{if .Y}}"false"{{end}}{{end}}`},
|
||||||
{
|
{"if else chain", "+{{if .X}}X{{else if .Y}}Y{{else if .Z}}Z{{end}}+", noError,
|
||||||
"variable with fields", "{{$.I}}", noError,
|
`"+"{{if .X}}"X"{{else}}{{if .Y}}"Y"{{else}}{{if .Z}}"Z"{{end}}{{end}}{{end}}"+"`},
|
||||||
"{{$.I}}",
|
{"simple range", "{{range .X}}hello{{end}}", noError,
|
||||||
},
|
`{{range .X}}"hello"{{end}}`},
|
||||||
{
|
{"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
|
||||||
"multi-word command", "{{printf `%d` 23}}", noError,
|
`{{range .X.Y.Z}}"hello"{{end}}`},
|
||||||
"{{printf `%d` 23}}",
|
{"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
|
||||||
},
|
`{{range .X}}"hello"{{range .Y}}"goodbye"{{end}}{{end}}`},
|
||||||
{
|
{"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
|
||||||
"pipeline", "{{.X|.Y}}", noError,
|
`{{range .X}}"true"{{else}}"false"{{end}}`},
|
||||||
`{{.X | .Y}}`,
|
{"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
|
||||||
},
|
`{{range .X | .M}}"true"{{else}}"false"{{end}}`},
|
||||||
{
|
{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
|
||||||
"pipeline with decl", "{{$x := .X|.Y}}", noError,
|
`{{range .SI}}{{.}}{{end}}`},
|
||||||
`{{$x := .X | .Y}}`,
|
{"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
|
||||||
},
|
`{{range $x := .SI}}{{.}}{{end}}`},
|
||||||
{
|
{"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
|
||||||
"nested pipeline", "{{.X (.Y .Z) (.A | .B .C) (.E)}}", noError,
|
`{{range $x, $y := .SI}}{{.}}{{end}}`},
|
||||||
`{{.X (.Y .Z) (.A | .B .C) (.E)}}`,
|
{"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError,
|
||||||
},
|
`{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`},
|
||||||
{
|
{"template", "{{template `x`}}", noError,
|
||||||
"field applied to parentheses", "{{(.Y .Z).Field}}", noError,
|
`{{template "x"}}`},
|
||||||
`{{(.Y .Z).Field}}`,
|
{"template with arg", "{{template `x` .Y}}", noError,
|
||||||
},
|
`{{template "x" .Y}}`},
|
||||||
{
|
{"with", "{{with .X}}hello{{end}}", noError,
|
||||||
"simple if", "{{if .X}}hello{{end}}", noError,
|
`{{with .X}}"hello"{{end}}`},
|
||||||
`{{if .X}}"hello"{{end}}`,
|
{"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
|
||||||
},
|
`{{with .X}}"hello"{{else}}"goodbye"{{end}}`},
|
||||||
{
|
|
||||||
"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
|
|
||||||
`{{if .X}}"true"{{else}}"false"{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if with else if", "{{if .X}}true{{else if .Y}}false{{end}}", noError,
|
|
||||||
`{{if .X}}"true"{{else}}{{if .Y}}"false"{{end}}{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"if else chain", "+{{if .X}}X{{else if .Y}}Y{{else if .Z}}Z{{end}}+", noError,
|
|
||||||
`"+"{{if .X}}"X"{{else}}{{if .Y}}"Y"{{else}}{{if .Z}}"Z"{{end}}{{end}}{{end}}"+"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"simple range", "{{range .X}}hello{{end}}", noError,
|
|
||||||
`{{range .X}}"hello"{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
|
|
||||||
`{{range .X.Y.Z}}"hello"{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
|
|
||||||
`{{range .X}}"hello"{{range .Y}}"goodbye"{{end}}{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
|
|
||||||
`{{range .X}}"true"{{else}}"false"{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
|
|
||||||
`{{range .X | .M}}"true"{{else}}"false"{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range []int", "{{range .SI}}{{.}}{{end}}", noError,
|
|
||||||
`{{range .SI}}{{.}}{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
|
|
||||||
`{{range $x := .SI}}{{.}}{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
|
|
||||||
`{{range $x, $y := .SI}}{{.}}{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError,
|
|
||||||
`{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"template", "{{template `x`}}", noError,
|
|
||||||
`{{template "x"}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"template with arg", "{{template `x` .Y}}", noError,
|
|
||||||
`{{template "x" .Y}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"with", "{{with .X}}hello{{end}}", noError,
|
|
||||||
`{{with .X}}"hello"{{end}}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
|
|
||||||
`{{with .X}}"hello"{{else}}"goodbye"{{end}}`,
|
|
||||||
},
|
|
||||||
// Trimming spaces.
|
// Trimming spaces.
|
||||||
{"trim left", "x \r\n\t{{- 3}}", noError, `"x"{{3}}`},
|
{"trim left", "x \r\n\t{{- 3}}", noError, `"x"{{3}}`},
|
||||||
{"trim right", "{{3 -}}\n\n\ty", noError, `{{3}}"y"`},
|
{"trim right", "{{3 -}}\n\n\ty", noError, `{{3}}"y"`},
|
||||||
|
@ -314,10 +250,8 @@ var parseTests = []parseTest{
|
||||||
{"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"`},
|
{"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"`},
|
||||||
{"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `"y"`},
|
{"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `"y"`},
|
||||||
{"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`},
|
{"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`},
|
||||||
{
|
{"block definition", `{{block "foo" .}}hello{{end}}`, noError,
|
||||||
"block definition", `{{block "foo" .}}hello{{end}}`, noError,
|
`{{template "foo" .}}`},
|
||||||
`{{template "foo" .}}`,
|
|
||||||
},
|
|
||||||
// Errors.
|
// Errors.
|
||||||
{"unclosed action", "hello{{range", hasError, ""},
|
{"unclosed action", "hello{{range", hasError, ""},
|
||||||
{"unmatched end", "{{end}}", hasError, ""},
|
{"unmatched end", "{{end}}", hasError, ""},
|
||||||
|
@ -467,143 +401,89 @@ func TestErrorContextWithTreeCopy(t *testing.T) {
|
||||||
// All failures, and the result is a string that must appear in the error message.
|
// All failures, and the result is a string that must appear in the error message.
|
||||||
var errorTests = []parseTest{
|
var errorTests = []parseTest{
|
||||||
// Check line numbers are accurate.
|
// Check line numbers are accurate.
|
||||||
{
|
{"unclosed1",
|
||||||
"unclosed1",
|
|
||||||
"line1\n{{",
|
"line1\n{{",
|
||||||
hasError, `unclosed1:2: unexpected unclosed action in command`,
|
hasError, `unclosed1:2: unexpected unclosed action in command`},
|
||||||
},
|
{"unclosed2",
|
||||||
{
|
|
||||||
"unclosed2",
|
|
||||||
"line1\n{{define `x`}}line2\n{{",
|
"line1\n{{define `x`}}line2\n{{",
|
||||||
hasError, `unclosed2:3: unexpected unclosed action in command`,
|
hasError, `unclosed2:3: unexpected unclosed action in command`},
|
||||||
},
|
|
||||||
// Specific errors.
|
// Specific errors.
|
||||||
{
|
{"function",
|
||||||
"function",
|
|
||||||
"{{foo}}",
|
"{{foo}}",
|
||||||
hasError, `function "foo" not defined`,
|
hasError, `function "foo" not defined`},
|
||||||
},
|
{"comment",
|
||||||
{
|
|
||||||
"comment",
|
|
||||||
"{{/*}}",
|
"{{/*}}",
|
||||||
hasError, `unclosed comment`,
|
hasError, `unclosed comment`},
|
||||||
},
|
{"lparen",
|
||||||
{
|
|
||||||
"lparen",
|
|
||||||
"{{.X (1 2 3}}",
|
"{{.X (1 2 3}}",
|
||||||
hasError, `unclosed left paren`,
|
hasError, `unclosed left paren`},
|
||||||
},
|
{"rparen",
|
||||||
{
|
|
||||||
"rparen",
|
|
||||||
"{{.X 1 2 3)}}",
|
"{{.X 1 2 3)}}",
|
||||||
hasError, `unexpected ")"`,
|
hasError, `unexpected ")"`},
|
||||||
},
|
{"space",
|
||||||
{
|
|
||||||
"space",
|
|
||||||
"{{`x`3}}",
|
"{{`x`3}}",
|
||||||
hasError, `in operand`,
|
hasError, `in operand`},
|
||||||
},
|
{"idchar",
|
||||||
{
|
|
||||||
"idchar",
|
|
||||||
"{{a#}}",
|
"{{a#}}",
|
||||||
hasError, `'#'`,
|
hasError, `'#'`},
|
||||||
},
|
{"charconst",
|
||||||
{
|
|
||||||
"charconst",
|
|
||||||
"{{'a}}",
|
"{{'a}}",
|
||||||
hasError, `unterminated character constant`,
|
hasError, `unterminated character constant`},
|
||||||
},
|
{"stringconst",
|
||||||
{
|
|
||||||
"stringconst",
|
|
||||||
`{{"a}}`,
|
`{{"a}}`,
|
||||||
hasError, `unterminated quoted string`,
|
hasError, `unterminated quoted string`},
|
||||||
},
|
{"rawstringconst",
|
||||||
{
|
|
||||||
"rawstringconst",
|
|
||||||
"{{`a}}",
|
"{{`a}}",
|
||||||
hasError, `unterminated raw quoted string`,
|
hasError, `unterminated raw quoted string`},
|
||||||
},
|
{"number",
|
||||||
{
|
|
||||||
"number",
|
|
||||||
"{{0xi}}",
|
"{{0xi}}",
|
||||||
hasError, `number syntax`,
|
hasError, `number syntax`},
|
||||||
},
|
{"multidefine",
|
||||||
{
|
|
||||||
"multidefine",
|
|
||||||
"{{define `a`}}a{{end}}{{define `a`}}b{{end}}",
|
"{{define `a`}}a{{end}}{{define `a`}}b{{end}}",
|
||||||
hasError, `multiple definition of template`,
|
hasError, `multiple definition of template`},
|
||||||
},
|
{"eof",
|
||||||
{
|
|
||||||
"eof",
|
|
||||||
"{{range .X}}",
|
"{{range .X}}",
|
||||||
hasError, `unexpected EOF`,
|
hasError, `unexpected EOF`},
|
||||||
},
|
{"variable",
|
||||||
{
|
|
||||||
"variable",
|
|
||||||
// Declare $x so it's defined, to avoid that error, and then check we don't parse a declaration.
|
// Declare $x so it's defined, to avoid that error, and then check we don't parse a declaration.
|
||||||
"{{$x := 23}}{{with $x.y := 3}}{{$x 23}}{{end}}",
|
"{{$x := 23}}{{with $x.y := 3}}{{$x 23}}{{end}}",
|
||||||
hasError, `unexpected ":="`,
|
hasError, `unexpected ":="`},
|
||||||
},
|
{"multidecl",
|
||||||
{
|
|
||||||
"multidecl",
|
|
||||||
"{{$a,$b,$c := 23}}",
|
"{{$a,$b,$c := 23}}",
|
||||||
hasError, `too many declarations`,
|
hasError, `too many declarations`},
|
||||||
},
|
{"undefvar",
|
||||||
{
|
|
||||||
"undefvar",
|
|
||||||
"{{$a}}",
|
"{{$a}}",
|
||||||
hasError, `undefined variable`,
|
hasError, `undefined variable`},
|
||||||
},
|
{"wrongdot",
|
||||||
{
|
|
||||||
"wrongdot",
|
|
||||||
"{{true.any}}",
|
"{{true.any}}",
|
||||||
hasError, `unexpected . after term`,
|
hasError, `unexpected . after term`},
|
||||||
},
|
{"wrongpipeline",
|
||||||
{
|
|
||||||
"wrongpipeline",
|
|
||||||
"{{12|false}}",
|
"{{12|false}}",
|
||||||
hasError, `non executable command in pipeline`,
|
hasError, `non executable command in pipeline`},
|
||||||
},
|
{"emptypipeline",
|
||||||
{
|
|
||||||
"emptypipeline",
|
|
||||||
`{{ ( ) }}`,
|
`{{ ( ) }}`,
|
||||||
hasError, `missing value for parenthesized pipeline`,
|
hasError, `missing value for parenthesized pipeline`},
|
||||||
},
|
{"multilinerawstring",
|
||||||
{
|
|
||||||
"multilinerawstring",
|
|
||||||
"{{ $v := `\n` }} {{",
|
"{{ $v := `\n` }} {{",
|
||||||
hasError, `multilinerawstring:2: unexpected unclosed action`,
|
hasError, `multilinerawstring:2: unexpected unclosed action`},
|
||||||
},
|
{"rangeundefvar",
|
||||||
{
|
|
||||||
"rangeundefvar",
|
|
||||||
"{{range $k}}{{end}}",
|
"{{range $k}}{{end}}",
|
||||||
hasError, `undefined variable`,
|
hasError, `undefined variable`},
|
||||||
},
|
{"rangeundefvars",
|
||||||
{
|
|
||||||
"rangeundefvars",
|
|
||||||
"{{range $k, $v}}{{end}}",
|
"{{range $k, $v}}{{end}}",
|
||||||
hasError, `undefined variable`,
|
hasError, `undefined variable`},
|
||||||
},
|
{"rangemissingvalue1",
|
||||||
{
|
|
||||||
"rangemissingvalue1",
|
|
||||||
"{{range $k,}}{{end}}",
|
"{{range $k,}}{{end}}",
|
||||||
hasError, `missing value for range`,
|
hasError, `missing value for range`},
|
||||||
},
|
{"rangemissingvalue2",
|
||||||
{
|
|
||||||
"rangemissingvalue2",
|
|
||||||
"{{range $k, $v := }}{{end}}",
|
"{{range $k, $v := }}{{end}}",
|
||||||
hasError, `missing value for range`,
|
hasError, `missing value for range`},
|
||||||
},
|
{"rangenotvariable1",
|
||||||
{
|
|
||||||
"rangenotvariable1",
|
|
||||||
"{{range $k, .}}{{end}}",
|
"{{range $k, .}}{{end}}",
|
||||||
hasError, `range can only initialize variables`,
|
hasError, `range can only initialize variables`},
|
||||||
},
|
{"rangenotvariable2",
|
||||||
{
|
|
||||||
"rangenotvariable2",
|
|
||||||
"{{range $k, 123 := .}}{{end}}",
|
"{{range $k, 123 := .}}{{end}}",
|
||||||
hasError, `range can only initialize variables`,
|
hasError, `range can only initialize variables`},
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrors(t *testing.T) {
|
func TestErrors(t *testing.T) {
|
||||||
|
|
|
@ -5,10 +5,9 @@
|
||||||
package template
|
package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// common holds the information shared by related templates.
|
// common holds the information shared by related templates.
|
||||||
|
|
Loading…
Reference in a new issue