Skip to content

Commit 75f608a

Browse files
committed
Fix intersect and similar for term entryt page collections
Fixes gohugoio#12254
1 parent f038a51 commit 75f608a

File tree

7 files changed

+76
-12
lines changed

7 files changed

+76
-12
lines changed

common/types/types.go

+8
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ type Unwrapper interface {
9999
Unwrapv() any
100100
}
101101

102+
// Unwrap returns the underlying value of v if it implements Unwrapper, otherwise v is returned.
103+
func Unwrapv(v any) any {
104+
if u, ok := v.(Unwrapper); ok {
105+
return u.Unwrapv()
106+
}
107+
return v
108+
}
109+
102110
// LowHigh is typically used to represent a slice boundary.
103111
type LowHigh struct {
104112
Low int

hugolib/page.go

+7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636

3737
"github.com/gohugoio/hugo/common/herrors"
3838
"github.com/gohugoio/hugo/common/maps"
39+
"github.com/gohugoio/hugo/common/types"
3940

4041
"github.com/gohugoio/hugo/source"
4142

@@ -731,3 +732,9 @@ func (p pageWithWeight0) Weight0() int {
731732
func (p pageWithWeight0) page() page.Page {
732733
return p.pageState
733734
}
735+
736+
var _ types.Unwrapper = (*pageWithWeight0)(nil)
737+
738+
func (p pageWithWeight0) Unwrapv() any {
739+
return p.pageState
740+
}

tpl/collections/collections.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ func (ns *Namespace) In(l any, v any) (bool, error) {
281281
lv := reflect.ValueOf(l)
282282
vv := reflect.ValueOf(v)
283283

284-
vvk := normalize(vv)
284+
vvk := normalizeMapKey(vv)
285285

286286
switch lv.Kind() {
287287
case reflect.Array, reflect.Slice:
@@ -291,7 +291,7 @@ func (ns *Namespace) In(l any, v any) (bool, error) {
291291
continue
292292
}
293293

294-
lvvk := normalize(lvv)
294+
lvvk := normalizeMapKey(lvv)
295295

296296
if lvvk == vvk {
297297
return true, nil
@@ -617,10 +617,10 @@ type intersector struct {
617617
}
618618

619619
func (i *intersector) appendIfNotSeen(v reflect.Value) {
620-
vi := v.Interface()
621-
if !i.seen[vi] {
620+
k := normalizeMapKey(v)
621+
if !i.seen[k] {
622622
i.r = reflect.Append(i.r, v)
623-
i.seen[vi] = true
623+
i.seen[k] = true
624624
}
625625
}
626626

@@ -638,7 +638,7 @@ func (i *intersector) handleValuePair(l1vv, l2vv reflect.Value) {
638638
i.appendIfNotSeen(l1vv)
639639
}
640640
case kind == reflect.Ptr, kind == reflect.Struct:
641-
if l1vv.Interface() == l2vv.Interface() {
641+
if types.Unwrapv(l1vv.Interface()) == types.Unwrapv(l2vv.Interface()) {
642642
i.appendIfNotSeen(l1vv)
643643
}
644644
case kind == reflect.Interface:
@@ -755,7 +755,7 @@ func (ns *Namespace) Uniq(l any) (any, error) {
755755
for i := 0; i < v.Len(); i++ {
756756
ev, _ := indirectInterface(v.Index(i))
757757

758-
key := normalize(ev)
758+
key := normalizeMapKey(ev)
759759

760760
if _, found := seen[key]; !found {
761761
slice = reflect.Append(slice, ev)

tpl/collections/collections_integration_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,51 @@ boolf = false
230230
"false",
231231
)
232232
}
233+
234+
func TestTermEntriesCollectionsIssue12254(t *testing.T) {
235+
t.Parallel()
236+
237+
files := `
238+
-- hugo.toml --
239+
capitalizeListTitles = false
240+
disableKinds = ['rss','sitemap']
241+
-- content/p1.md --
242+
---
243+
title: p1
244+
categories: [cat-a]
245+
tags: ['tag-b','tag-a','tag-c']
246+
---
247+
-- content/p2.md --
248+
---
249+
title: p2
250+
categories: [cat-a]
251+
tags: ['tag-b','tag-a']
252+
---
253+
-- content/p3.md --
254+
---
255+
title: p3
256+
categories: [cat-a]
257+
tags: ['tag-b']
258+
---
259+
-- layouts/_default/term.html --
260+
{{ $list1 := .Pages }}
261+
{{ range $i, $e := site.Taxonomies.tags.ByCount }}
262+
{{ $list2 := .Pages }}
263+
{{ $i }}: List1: {{ len $list1 }}|
264+
{{ $i }}: List2: {{ len $list2 }}|
265+
{{ $i }}: Intersect: {{ intersect $.Pages .Pages | len }}|
266+
{{ $i }}: Union: {{ union $.Pages .Pages | len }}|
267+
{{ $i }}: SymDiff: {{ symdiff $.Pages .Pages | len }}|
268+
{{ $i }}: Uniq: {{ append $.Pages .Pages | uniq | len }}|
269+
{{ end }}
270+
271+
272+
`
273+
b := hugolib.Test(t, files)
274+
275+
b.AssertFileContent("public/categories/cat-a/index.html",
276+
"0: List1: 3|\n0: List2: 3|\n0: Intersect: 3|\n0: Union: 3|\n0: SymDiff: 0|\n0: Uniq: 3|\n\n\n1: List1: 3|",
277+
"1: List2: 2|\n1: Intersect: 2|\n1: Union: 3|\n1: SymDiff: 1|\n1: Uniq: 3|\n\n\n2: List1: 3|\n2: List2: 1|",
278+
"2: Intersect: 1|\n2: Union: 3|\n2: SymDiff: 2|\n2: Uniq: 3|",
279+
)
280+
}

tpl/collections/complement.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (ns *Namespace) Complement(ls ...any) (any, error) {
4646
sl := reflect.MakeSlice(v.Type(), 0, 0)
4747
for i := 0; i < v.Len(); i++ {
4848
ev, _ := indirectInterface(v.Index(i))
49-
if _, found := aset[normalize(ev)]; !found {
49+
if _, found := aset[normalizeMapKey(ev)]; !found {
5050
sl = reflect.Append(sl, ev)
5151
}
5252
}

tpl/collections/reflect_helpers.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"fmt"
1919
"reflect"
2020

21+
"github.com/gohugoio/hugo/common/types"
2122
"github.com/mitchellh/hashstructure"
2223
)
2324

@@ -44,7 +45,7 @@ func numberToFloat(v reflect.Value) (float64, error) {
4445
// normalizes different numeric types if isNumber
4546
// or get the hash values if not Comparable (such as map or struct)
4647
// to make them comparable
47-
func normalize(v reflect.Value) any {
48+
func normalizeMapKey(v reflect.Value) any {
4849
k := v.Kind()
4950

5051
switch {
@@ -60,7 +61,7 @@ func normalize(v reflect.Value) any {
6061
return f
6162
}
6263
}
63-
return v.Interface()
64+
return types.Unwrapv(v.Interface())
6465
}
6566

6667
// collects identities from the slices in seqs into a set. Numeric values are normalized,
@@ -78,7 +79,7 @@ func collectIdentities(seqs ...any) (map[any]bool, error) {
7879
return nil, errors.New("elements must be comparable")
7980
}
8081

81-
seen[normalize(ev)] = true
82+
seen[normalizeMapKey(ev)] = true
8283
}
8384
default:
8485
return nil, fmt.Errorf("arguments must be slices or arrays")

tpl/collections/symdiff.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (ns *Namespace) SymDiff(s2, s1 any) (any, error) {
4646

4747
for i := 0; i < v.Len(); i++ {
4848
ev, _ := indirectInterface(v.Index(i))
49-
key := normalize(ev)
49+
key := normalizeMapKey(ev)
5050

5151
// Append if the key is not in their intersection.
5252
if ids1[key] != ids2[key] {

0 commit comments

Comments
 (0)