mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
tpl/collections: Fix append when appending a slice to a slice of slices
Fixes #11093
This commit is contained in:
parent
732dcb848f
commit
d178fe94fe
3 changed files with 101 additions and 4 deletions
|
@ -22,6 +22,9 @@ import (
|
||||||
// If length of from is one and the only element is a slice of same type as to,
|
// If length of from is one and the only element is a slice of same type as to,
|
||||||
// it will be appended.
|
// it will be appended.
|
||||||
func Append(to any, from ...any) (any, error) {
|
func Append(to any, from ...any) (any, error) {
|
||||||
|
if len(from) == 0 {
|
||||||
|
return to, nil
|
||||||
|
}
|
||||||
tov, toIsNil := indirect(reflect.ValueOf(to))
|
tov, toIsNil := indirect(reflect.ValueOf(to))
|
||||||
|
|
||||||
toIsNil = toIsNil || to == nil
|
toIsNil = toIsNil || to == nil
|
||||||
|
@ -33,18 +36,39 @@ func Append(to any, from ...any) (any, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tot = tov.Type().Elem()
|
tot = tov.Type().Elem()
|
||||||
|
if tot.Kind() == reflect.Slice {
|
||||||
|
totvt := tot.Elem()
|
||||||
|
fromvs := make([]reflect.Value, len(from))
|
||||||
|
for i, f := range from {
|
||||||
|
fromv := reflect.ValueOf(f)
|
||||||
|
fromt := fromv.Type()
|
||||||
|
if fromt.Kind() == reflect.Slice {
|
||||||
|
fromt = fromt.Elem()
|
||||||
|
}
|
||||||
|
if totvt != fromt {
|
||||||
|
return nil, fmt.Errorf("cannot append slice of %s to slice of %s", fromt, totvt)
|
||||||
|
} else {
|
||||||
|
fromvs[i] = fromv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reflect.Append(tov, fromvs...).Interface(), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
toIsNil = tov.Len() == 0
|
toIsNil = tov.Len() == 0
|
||||||
|
|
||||||
if len(from) == 1 {
|
if len(from) == 1 {
|
||||||
fromv := reflect.ValueOf(from[0])
|
fromv := reflect.ValueOf(from[0])
|
||||||
|
fromt := fromv.Type()
|
||||||
|
if fromt.Kind() == reflect.Slice {
|
||||||
|
fromt = fromt.Elem()
|
||||||
|
}
|
||||||
if fromv.Kind() == reflect.Slice {
|
if fromv.Kind() == reflect.Slice {
|
||||||
if toIsNil {
|
if toIsNil {
|
||||||
// If we get nil []string, we just return the []string
|
// If we get nil []string, we just return the []string
|
||||||
return from[0], nil
|
return from[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fromt := reflect.TypeOf(from[0]).Elem()
|
|
||||||
|
|
||||||
// If we get []string []string, we append the from slice to to
|
// If we get []string []string, we append the from slice to to
|
||||||
if tot == fromt {
|
if tot == fromt {
|
||||||
return reflect.AppendSlice(tov, fromv).Interface(), nil
|
return reflect.AppendSlice(tov, fromv).Interface(), nil
|
||||||
|
@ -52,6 +76,7 @@ func Append(to any, from ...any) (any, error) {
|
||||||
// Fall back to a []interface{} slice.
|
// Fall back to a []interface{} slice.
|
||||||
return appendToInterfaceSliceFromValues(tov, fromv)
|
return appendToInterfaceSliceFromValues(tov, fromv)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestAppend(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
for _, test := range []struct {
|
for i, test := range []struct {
|
||||||
start any
|
start any
|
||||||
addend []any
|
addend []any
|
||||||
expected any
|
expected any
|
||||||
|
@ -84,7 +84,48 @@ func TestAppend(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Assert(err, qt.IsNil)
|
||||||
|
c.Assert(result, qt.DeepEquals, test.expected, qt.Commentf("test: [%d] %v", i, test))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #11093
|
||||||
|
func TestAppendToMultiDimensionalSlice(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
for _, test := range []struct {
|
||||||
|
to any
|
||||||
|
from []any
|
||||||
|
expected any
|
||||||
|
}{
|
||||||
|
{[][]string{{"a", "b"}},
|
||||||
|
[]any{[]string{"c", "d"}},
|
||||||
|
[][]string{
|
||||||
|
{"a", "b"},
|
||||||
|
{"c", "d"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{[][]string{{"a", "b"}},
|
||||||
|
[]any{[]string{"c", "d"}, []string{"e", "f"}},
|
||||||
|
[][]string{
|
||||||
|
{"a", "b"},
|
||||||
|
{"c", "d"},
|
||||||
|
{"e", "f"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{[][]string{{"a", "b"}},
|
||||||
|
[]any{[]int{1, 2}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
result, err := Append(test.to, test.from...)
|
||||||
|
if b, ok := test.expected.(bool); ok && !b {
|
||||||
|
c.Assert(err, qt.Not(qt.IsNil))
|
||||||
|
} else {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(result, qt.DeepEquals, test.expected)
|
c.Assert(result, qt.DeepEquals, test.expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -73,3 +73,34 @@ Desc: [map[a:3 b:3] map[a:3 b:1] map[a:3 b:1] map[a:3 b:1] map[a:3 b:0] map[a:3
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #11004.
|
||||||
|
func TestAppendSliceToASliceOfSlices(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- hugo.toml --
|
||||||
|
-- layouts/index.html --
|
||||||
|
{{ $obj := slice (slice "a") }}
|
||||||
|
{{ $obj = $obj | append (slice "b") }}
|
||||||
|
{{ $obj = $obj | append (slice "c") }}
|
||||||
|
|
||||||
|
{{ $obj }}
|
||||||
|
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
|
||||||
|
b := hugolib.NewIntegrationTestBuilder(
|
||||||
|
hugolib.IntegrationTestConfig{
|
||||||
|
T: t,
|
||||||
|
TxtarString: files,
|
||||||
|
},
|
||||||
|
).Build()
|
||||||
|
|
||||||
|
b.AssertFileContent("public/index.html", "[[a] [b] [c]]")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue