summaryrefslogtreecommitdiffstats
path: root/tpl/internal
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-03-16 08:48:16 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-03-16 08:54:25 +0100
commit65a78cae1ecdcfcb0701d78fed812083a1a6e82b (patch)
treeb57295e36c91cbfb76bdd606657d0c1f6c7fdf2b /tpl/internal
parent4d6d1d08dad5538f4710fc4b56e09419aa0d854b (diff)
tpl: Sync go_templates for Go 1.18
Using Go tag go1.18 4aa1efed4853ea067d665a952eee77c52faac774 Updates #9677
Diffstat (limited to 'tpl/internal')
-rw-r--r--tpl/internal/go_templates/cfg/cfg.go3
-rw-r--r--tpl/internal/go_templates/fmtsort/sort.go2
-rw-r--r--tpl/internal/go_templates/fmtsort/sort_test.go27
-rw-r--r--tpl/internal/go_templates/htmltemplate/attr.go6
-rw-r--r--tpl/internal/go_templates/htmltemplate/clone_test.go1
-rw-r--r--tpl/internal/go_templates/htmltemplate/content.go12
-rw-r--r--tpl/internal/go_templates/htmltemplate/content_test.go5
-rw-r--r--tpl/internal/go_templates/htmltemplate/context.go9
-rw-r--r--tpl/internal/go_templates/htmltemplate/css.go4
-rw-r--r--tpl/internal/go_templates/htmltemplate/css_test.go1
-rw-r--r--tpl/internal/go_templates/htmltemplate/error.go2
-rw-r--r--tpl/internal/go_templates/htmltemplate/escape.go79
-rw-r--r--tpl/internal/go_templates/htmltemplate/escape_test.go37
-rw-r--r--tpl/internal/go_templates/htmltemplate/example_test.go3
-rw-r--r--tpl/internal/go_templates/htmltemplate/examplefiles_test.go1
-rw-r--r--tpl/internal/go_templates/htmltemplate/exec_test.go41
-rw-r--r--tpl/internal/go_templates/htmltemplate/html.go12
-rw-r--r--tpl/internal/go_templates/htmltemplate/html_test.go1
-rw-r--r--tpl/internal/go_templates/htmltemplate/js.go16
-rw-r--r--tpl/internal/go_templates/htmltemplate/js_test.go15
-rw-r--r--tpl/internal/go_templates/htmltemplate/multi_test.go1
-rw-r--r--tpl/internal/go_templates/htmltemplate/template.go8
-rw-r--r--tpl/internal/go_templates/htmltemplate/template_test.go3
-rw-r--r--tpl/internal/go_templates/htmltemplate/transition_test.go1
-rw-r--r--tpl/internal/go_templates/htmltemplate/url.go14
-rw-r--r--tpl/internal/go_templates/htmltemplate/url_test.go3
-rw-r--r--tpl/internal/go_templates/testenv/testenv.go58
-rw-r--r--tpl/internal/go_templates/testenv/testenv_cgo.go2
-rw-r--r--tpl/internal/go_templates/testenv/testenv_notunix.go13
-rw-r--r--tpl/internal/go_templates/testenv/testenv_notwin.go2
-rw-r--r--tpl/internal/go_templates/testenv/testenv_unix.go13
-rw-r--r--tpl/internal/go_templates/texttemplate/doc.go20
-rw-r--r--tpl/internal/go_templates/texttemplate/example_test.go1
-rw-r--r--tpl/internal/go_templates/texttemplate/examplefiles_test.go1
-rw-r--r--tpl/internal/go_templates/texttemplate/examplefunc_test.go1
-rw-r--r--tpl/internal/go_templates/texttemplate/exec.go116
-rw-r--r--tpl/internal/go_templates/texttemplate/exec_test.go151
-rw-r--r--tpl/internal/go_templates/texttemplate/funcs.go51
-rw-r--r--tpl/internal/go_templates/texttemplate/link_test.go7
-rw-r--r--tpl/internal/go_templates/texttemplate/multi_test.go11
-rw-r--r--tpl/internal/go_templates/texttemplate/option.go10
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/lex.go15
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/lex_test.go3
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/node.go36
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/parse.go59
-rw-r--r--tpl/internal/go_templates/texttemplate/parse/parse_test.go27
-rw-r--r--tpl/internal/go_templates/texttemplate/template.go11
47 files changed, 695 insertions, 220 deletions
diff --git a/tpl/internal/go_templates/cfg/cfg.go b/tpl/internal/go_templates/cfg/cfg.go
index 553021374..78664d7a9 100644
--- a/tpl/internal/go_templates/cfg/cfg.go
+++ b/tpl/internal/go_templates/cfg/cfg.go
@@ -33,12 +33,14 @@ const KnownEnv = `
GCCGO
GO111MODULE
GO386
+ GOAMD64
GOARCH
GOARM
GOBIN
GOCACHE
GOENV
GOEXE
+ GOEXPERIMENT
GOFLAGS
GOGCCFLAGS
GOHOSTARCH
@@ -60,6 +62,7 @@ const KnownEnv = `
GOTOOLDIR
GOVCS
GOWASM
+ GOWORK
GO_EXTLINK_ENABLED
PKG_CONFIG
`
diff --git a/tpl/internal/go_templates/fmtsort/sort.go b/tpl/internal/go_templates/fmtsort/sort.go
index 7127ba6ac..34c1f477f 100644
--- a/tpl/internal/go_templates/fmtsort/sort.go
+++ b/tpl/internal/go_templates/fmtsort/sort.go
@@ -130,7 +130,7 @@ func compare(aVal, bVal reflect.Value) int {
default:
return -1
}
- case reflect.Ptr, reflect.UnsafePointer:
+ case reflect.Pointer, reflect.UnsafePointer:
a, b := aVal.Pointer(), bVal.Pointer()
switch {
case a < b:
diff --git a/tpl/internal/go_templates/fmtsort/sort_test.go b/tpl/internal/go_templates/fmtsort/sort_test.go
index 5205a6413..a05e8a3c3 100644
--- a/tpl/internal/go_templates/fmtsort/sort_test.go
+++ b/tpl/internal/go_templates/fmtsort/sort_test.go
@@ -9,6 +9,7 @@ import (
"github.com/gohugoio/hugo/tpl/internal/go_templates/fmtsort"
"math"
"reflect"
+ "sort"
"strings"
"testing"
"unsafe"
@@ -37,12 +38,12 @@ var compareTests = [][]reflect.Value{
ct(reflect.TypeOf(chans[0]), chans[0], chans[1], chans[2]),
ct(reflect.TypeOf(toy{}), toy{0, 1}, toy{0, 2}, toy{1, -1}, toy{1, 1}),
ct(reflect.TypeOf([2]int{}), [2]int{1, 1}, [2]int{1, 2}, [2]int{2, 0}),
- ct(reflect.TypeOf(interface{}(interface{}(0))), iFace, 1, 2, 3),
+ ct(reflect.TypeOf(any(any(0))), iFace, 1, 2, 3),
}
-var iFace interface{}
+var iFace any
-func ct(typ reflect.Type, args ...interface{}) []reflect.Value {
+func ct(typ reflect.Type, args ...any) []reflect.Value {
value := make([]reflect.Value, len(args))
for i, v := range args {
x := reflect.ValueOf(v)
@@ -83,8 +84,8 @@ func TestCompare(t *testing.T) {
}
type sortTest struct {
- data interface{} // Always a map.
- print string // Printed result using our custom printer.
+ data any // Always a map.
+ print string // Printed result using our custom printer.
}
var sortTests = []sortTest{
@@ -134,7 +135,7 @@ var sortTests = []sortTest{
},
}
-func sprint(data interface{}) string {
+func sprint(data any) string {
om := fmtsort.Sort(reflect.ValueOf(data))
if om == nil {
return "nil"
@@ -188,9 +189,19 @@ func sprintKey(key reflect.Value) string {
var (
ints [3]int
- chans = [3]chan int{make(chan int), make(chan int), make(chan int)}
+ chans = makeChans()
)
+func makeChans() []chan int {
+ cs := []chan int{make(chan int), make(chan int), make(chan int)}
+ // Order channels by address. See issue #49431.
+ // TODO: pin these pointers once pinning is available (#46787).
+ sort.Slice(cs, func(i, j int) bool {
+ return uintptr(reflect.ValueOf(cs[i]).UnsafePointer()) < uintptr(reflect.ValueOf(cs[j]).UnsafePointer())
+ })
+ return cs
+}
+
func pointerMap() map[*int]string {
m := make(map[*int]string)
for i := 2; i >= 0; i-- {
@@ -233,7 +244,7 @@ func TestInterface(t *testing.T) {
// A map containing multiple concrete types should be sorted by type,
// then value. However, the relative ordering of types is unspecified,
// so test this by checking the presence of sorted subgroups.
- m := map[interface{}]string{
+ m := map[any]string{
[2]int{1, 0}: "",
[2]int{0, 1}: "",
true: "",
diff --git a/tpl/internal/go_templates/htmltemplate/attr.go b/tpl/internal/go_templates/htmltemplate/attr.go
index 22922e603..6c52211fe 100644
--- a/tpl/internal/go_templates/htmltemplate/attr.go
+++ b/tpl/internal/go_templates/htmltemplate/attr.go
@@ -143,12 +143,12 @@ func attrType(name string) contentType {
// widely applied.
// Treat data-action as URL below.
name = name[5:]
- } else if colon := strings.IndexRune(name, ':'); colon != -1 {
- if name[:colon] == "xmlns" {
+ } else if prefix, short, ok := strings.Cut(name, ":"); ok {
+ if prefix == "xmlns" {
return contentTypeURL
}
// Treat svg:href and xlink:href as href below.
- name = name[colon+1:]
+ name = short
}
if t, ok := attrTypeMap[name]; ok {
return t
diff --git a/tpl/internal/go_templates/htmltemplate/clone_test.go b/tpl/internal/go_templates/htmltemplate/clone_test.go
index 7c774e923..553f656b5 100644
--- a/tpl/internal/go_templates/htmltemplate/clone_test.go
+++ b/tpl/internal/go_templates/htmltemplate/clone_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.13 && !windows
// +build go1.13,!windows
package template
diff --git a/tpl/internal/go_templates/htmltemplate/content.go b/tpl/internal/go_templates/htmltemplate/content.go
index bc32dc813..65cc3086c 100644
--- a/tpl/internal/go_templates/htmltemplate/content.go
+++ b/tpl/internal/go_templates/htmltemplate/content.go
@@ -29,16 +29,16 @@ const (
// indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil).
-func indirect(a interface{}) interface{} {
+func indirect(a any) any {
if a == nil {
return nil
}
- if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
+ if t := reflect.TypeOf(a); t.Kind() != reflect.Pointer {
// Avoid creating a reflect.Value if it's not a pointer.
return a
}
v := reflect.ValueOf(a)
- for v.Kind() == reflect.Ptr && !v.IsNil() {
+ for v.Kind() == reflect.Pointer && !v.IsNil() {
v = v.Elem()
}
return v.Interface()
@@ -52,12 +52,12 @@ var (
// indirectToStringerOrError returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
// or error,
-func indirectToStringerOrError(a interface{}) interface{} {
+func indirectToStringerOrError(a any) any {
if a == nil {
return nil
}
v := reflect.ValueOf(a)
- for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+ for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Pointer && !v.IsNil() {
v = v.Elem()
}
return v.Interface()
@@ -65,7 +65,7 @@ func indirectToStringerOrError(a interface{}) interface{} {
// stringify converts its arguments to a string and the type of the content.
// All pointers are dereferenced, as in the text/template package.
-func stringify(args ...interface{}) (string, contentType) {
+func stringify(args ...any) (string, contentType) {
if len(args) == 1 {
switch s := indirect(args[0]).(type) {
case string:
diff --git a/tpl/internal/go_templates/htmltemplate/content_test.go b/tpl/internal/go_templates/htmltemplate/content_test.go
index 909a24bc0..29221a4ad 100644
--- a/tpl/internal/go_templates/htmltemplate/content_test.go
+++ b/tpl/internal/go_templates/htmltemplate/content_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.13 && !windows
// +build go1.13,!windows
package template
@@ -15,7 +16,7 @@ import (
)
func TestTypedContent(t *testing.T) {
- data := []interface{}{
+ data := []any{
`<b> "foo%" O'Reilly &bar;`,
htmltemplate.CSS(`a[href =~ "//example.com"]#foo`),
htmltemplate.HTML(`Hello, <b>World</b> &amp;tc!`),
@@ -452,7 +453,7 @@ func TestEscapingNilNonemptyInterfaces(t *testing.T) {
// A non-empty interface should print like an empty interface.
want := new(bytes.Buffer)
- data := struct{ E interface{} }{}
+ data := struct{ E any }{}
tmpl.Execute(want, data)
if !bytes.Equal(want.Bytes(), got.Bytes()) {
diff --git a/tpl/internal/go_templates/htmltemplate/context.go b/tpl/internal/go_templates/htmltemplate/context.go
index 006b870ec..c28e08dce 100644
--- a/tpl/internal/go_templates/htmltemplate/context.go
+++ b/tpl/internal/go_templates/htmltemplate/context.go
@@ -4,7 +4,11 @@
package template
-import "fmt"
+import (
+ "fmt"
+
+ "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
+)
// context describes the state an HTML parser must be in when it reaches the
// portion of HTML produced by evaluating a particular template node.
@@ -20,6 +24,7 @@ type context struct {
jsCtx jsCtx
attr attr
element element
+ n parse.Node // for range break/continue
err *Error
}
@@ -139,6 +144,8 @@ const (
// stateError is an infectious error state outside any valid
// HTML/CSS/JS construct.
stateError
+ // stateDead marks unreachable code after a {{break}} or {{continue}}.
+ stateDead
)
// isComment is true for any state that contains content meant for template
diff --git a/tpl/internal/go_templates/htmltemplate/css.go b/tpl/internal/go_templates/htmltemplate/css.go
index eb92fc92b..890a0c6b2 100644
--- a/tpl/internal/go_templates/htmltemplate/css.go
+++ b/tpl/internal/go_templates/htmltemplate/css.go
@@ -155,7 +155,7 @@ func isCSSSpace(b byte) bool {
}
// cssEscaper escapes HTML and CSS special characters using \<hex>+ escapes.
-func cssEscaper(args ...interface{}) string {
+func cssEscaper(args ...any) string {
s, _ := stringify(args...)
var b strings.Builder
r, w, written := rune(0), 0, 0
@@ -218,7 +218,7 @@ var mozBindingBytes = []byte("mozbinding")
// (inherit, blue), and colors (#888).
// It filters out unsafe values, such as those that affect token boundaries,
// and anything that might execute scripts.
-func cssValueFilter(args ...interface{}) string {
+func cssValueFilter(args ...any) string {
s, t := stringify(args...)
if t == contentTypeCSS {
return s
diff --git a/tpl/internal/go_templates/htmltemplate/css_test.go b/tpl/internal/go_templates/htmltemplate/css_test.go
index afed58c29..7d8ad8b59 100644
--- a/tpl/internal/go_templates/htmltemplate/css_test.go
+++ b/tpl/internal/go_templates/htmltemplate/css_test.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build go1.13 && !windows
// +build go1.13,!windows
package template
diff --git a/tpl/internal/go_templates/htmltemplate/error.go b/tpl/internal/go_templates/htmltemplate/error.go
index f8b3f1cea..21c86a9ef 100644
--- a/tpl/internal/go_templates/htmltemplate/error.go
+++ b/tpl/internal/go_templates/htmltemplate/error.go
@@ -229,6 +229,6 @@ func (e *Error) Error() string {
// errorf creates an error given a format string f and args.
// The template Name still needs to be supplied.
-func errorf(k ErrorCode, node parse.Node, line int, f string, args ...interface{}) *Error {
+func errorf(k ErrorCode, node parse.Node, line int, f string, args ...any) *Error {
return &Error{k, node, "", line, fmt.Sprintf(f, args...)}
}
diff --git a/tpl/internal/go_templates/htmltemplate/escape.go b/tpl/internal/go_templates/htmltemplate/escape.go
index 5f4c92a17..5382c4288 100644
--- a/tpl/internal/go_templates/htmltemplate/escape.go
+++ b/tpl/internal/go_templates/htmltemplate/escape.go
@@ -46,7 +46,7 @@ func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
// evalArgs formats the list of arguments into a string. It is equivalent to
// fmt.Sprint(args...), except that it deferences all pointers.
-func evalArgs(args ...interface{}) string {
+func evalArgs(args ...any) string {
// Optimization for simple common case of a single string argument.
if len(args) == 1 {
if s, ok := args[0].(string); ok {
@@ -98,6 +98,15 @@ type escaper struct {
actionNodeEdits map[*parse.ActionNode][]string
templateNodeEdits map[*parse.TemplateNode]string
textNodeEdits map[*parse.TextNode][]byte
+ // rangeContext holds context about the current range loop.
+ rangeContext *rangeContext
+}
+
+// rangeContext holds information about the current range loop.
+type rangeContext struct {
+ outer *rangeContext // outer loop
+ breaks []context // context at each break action
+ continues []context // context at each continue action
}
// makeEscaper creates a blank escaper for the given set.
@@ -110,6 +119,7 @@ func makeEscaper(n *nameSpace) escaper {
map[*parse.ActionNode][]string{},
map[*parse.TemplateNode]string{},
map[*parse.TextNode][]byte{},
+ nil,
}
}
@@ -125,8 +135,16 @@ func (e *escaper) escape(c context, n parse.Node) context {
switch n := n.(type) {
case *parse.ActionNode:
return e.escapeAction(c, n)
+ case *parse.BreakNode:
+ c.n = n
+ e.rangeContext.breaks = append(e.rangeContext.breaks, c)
+ return context{state: stateDead}
case *parse.CommentNode:
return c
+ case *parse.ContinueNode:
+ c.n = n
+ e.rangeContext.continues = append(e.rangeContext.breaks, c)
+ return context{state: stateDead}
case *parse.IfNode:
return e.escapeBranch(c, &n.BranchNode, "if")
case *parse.ListNode:
@@ -428,6 +446,12 @@ func join(a, b context, node parse.Node, nodeName string) context {
if b.state == stateError {
return b
}
+ if a.state == stateDead {
+ return b
+ }
+ if b.state == stateDead {
+ return a
+ }
if a.eq(b) {
return a
}
@@ -467,14 +491,27 @@ func join(a, b context, node parse.Node, nodeName string) context {
// escapeBranch escapes a branch template node: "if", "range" and "with".
func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context {
+ if nodeName == "range" {
+ e.rangeContext = &rangeContext{outer: e.rangeContext}
+ }
c0 := e.escapeList(c, n.List)
- if nodeName == "range" && c0.state != stateError {
+ if nodeName == "range" {
+ if c0.state != stateError {
+ c0 = joinRange(c0, e.rangeContext)
+ }
+ e.rangeContext = e.rangeContext.outer
+ if c0.state == stateError {
+ return c0
+ }
+
// The "true" branch of a "range" node can execute multiple times.
// We check that executing n.List once results in the same context
// as executing n.List twice.
+ e.rangeContext = &rangeContext{outer: e.rangeContext}
c1, _ := e.escapeListConditionally(c0, n.List, nil)
c0 = join(c0, c1, n, nodeName)
if c0.state == stateError {
+ e.rangeContext = e.rangeContext.outer
// Make clear that this is a problem on loop re-entry
// since developers tend to overlook that branch when
// debugging templates.
@@ -482,11 +519,39 @@ func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string)
c0.err.Description = "on range loop re-entry: " + c0.err.Description
return c0
}
+ c0 = joinRange(c0, e.rangeContext)
+ e.rangeContext = e.rangeContext.outer
+ if c0.state == stateError {
+ return c0
+ }
}
c1 := e.escapeList(c, n.ElseList)
return join(c0, c1, n, nodeName)
}
+func joinRange(c0 context, rc *rangeContext) context {
+ // Merge contexts at break and continue statements into overall body context.
+ // In theory we could treat breaks differently from continues, but for now it is
+ // enough to treat them both as going back to the start of the loop (which may then stop).
+ for _, c := range rc.breaks {
+ c0 = join(c0, c, c.n, "range")
+ if c0.state == stateError {
+ c0.err.Line = c.n.(*parse.BreakNode).Line
+ c0.err.Description = "at range loop break: " + c0.err.Description
+ return c0
+ }
+ }
+ for _, c := range rc.