Skip to content

Commit 3400aff

Browse files
gwattsbep
authored andcommitted
Allow cascade _target to work with non toml fm
The TOML lib unmarshals slices of string maps to []map[string]interface{} whereas YAML and JSON decode to []interface{} The existing tests only check for TOML working correctly, and _target with cascade did not work at all for frontmatter defined in other formats. Add a function to normalize those slices Fixes #7874
1 parent fdfa4a5 commit 3400aff

File tree

4 files changed

+108
-4
lines changed

4 files changed

+108
-4
lines changed

common/maps/maps.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package maps
1515

1616
import (
17+
"fmt"
1718
"strings"
1819

1920
"github.com/gobwas/glob"
@@ -64,6 +65,23 @@ func ToStringMap(in interface{}) map[string]interface{} {
6465
return m
6566
}
6667

68+
func ToSliceStringMap(in interface{}) ([]map[string]interface{}, error) {
69+
switch v := in.(type) {
70+
case []map[string]interface{}:
71+
return v, nil
72+
case []interface{}:
73+
var s []map[string]interface{}
74+
for _, entry := range v {
75+
if vv, ok := entry.(map[string]interface{}); ok {
76+
s = append(s, vv)
77+
}
78+
}
79+
return s, nil
80+
default:
81+
return nil, fmt.Errorf("unable to cast %#v of type %T to []map[string]interface{}", in, in)
82+
}
83+
}
84+
6785
type keyRename struct {
6886
pattern glob.Glob
6987
newKey string

common/maps/maps_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,39 @@ func TestToLower(t *testing.T) {
7575
}
7676
}
7777

78+
func TestToSliceStringMap(t *testing.T) {
79+
c := qt.New(t)
80+
81+
tests := []struct {
82+
input interface{}
83+
expected []map[string]interface{}
84+
}{
85+
{
86+
input: []map[string]interface{}{
87+
{"abc": 123},
88+
},
89+
expected: []map[string]interface{}{
90+
{"abc": 123},
91+
},
92+
}, {
93+
input: []interface{}{
94+
map[string]interface{}{
95+
"def": 456,
96+
},
97+
},
98+
expected: []map[string]interface{}{
99+
{"def": 456},
100+
},
101+
},
102+
}
103+
104+
for _, test := range tests {
105+
v, err := ToSliceStringMap(test.input)
106+
c.Assert(err, qt.IsNil)
107+
c.Assert(v, qt.DeepEquals, test.expected)
108+
}
109+
}
110+
78111
func TestRenameKeys(t *testing.T) {
79112
c := qt.New(t)
80113

hugolib/cascade_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,4 +459,58 @@ S1|p1:|p2:p2|
459459

460460
})
461461

462+
c.Run("slice with yaml _target", func(c *qt.C) {
463+
b := newBuilder(c)
464+
465+
b.WithContent("_index.md", `---
466+
title: "Home"
467+
cascade:
468+
- p1: p1
469+
_target:
470+
path: "**p1**"
471+
- p2: p2
472+
_target:
473+
kind: "section"
474+
---
475+
`)
476+
477+
b.Build(BuildCfg{})
478+
479+
b.AssertFileContent("public/index.html", `
480+
P1|p1:p1|p2:|
481+
S1|p1:|p2:p2|
482+
`)
483+
484+
})
485+
486+
c.Run("slice with json _target", func(c *qt.C) {
487+
b := newBuilder(c)
488+
489+
b.WithContent("_index.md", `{
490+
"title": "Home",
491+
"cascade": [
492+
{
493+
"p1": "p1",
494+
"_target": {
495+
"path": "**p1**"
496+
}
497+
},{
498+
"p2": "p2",
499+
"_target": {
500+
"kind": "section"
501+
}
502+
}
503+
]
504+
}
505+
`)
506+
507+
b.Build(BuildCfg{})
508+
509+
b.AssertFileContent("public/index.html", `
510+
P1|p1:p1|p2:|
511+
S1|p1:|p2:p2|
512+
`)
513+
514+
})
515+
462516
}

hugolib/page__meta.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,7 @@ func (pm *pageMeta) setMetadata(parentBucket *pagesMapBucket, p *pageState, fron
342342
if p.bucket != nil {
343343
// Check for any cascade define on itself.
344344
if cv, found := frontmatter["cascade"]; found {
345-
switch v := cv.(type) {
346-
case []map[string]interface{}:
345+
if v, err := maps.ToSliceStringMap(cv); err == nil {
347346
p.bucket.cascade = make(map[page.PageMatcher]maps.Params)
348347

349348
for _, vv := range v {
@@ -367,12 +366,12 @@ func (pm *pageMeta) setMetadata(parentBucket *pagesMapBucket, p *pageState, fron
367366
}
368367

369368
}
370-
default:
369+
} else {
371370
p.bucket.cascade = map[page.PageMatcher]maps.Params{
372371
page.PageMatcher{}: maps.ToStringMap(cv),
373372
}
374-
}
375373

374+
}
376375
}
377376
}
378377
} else {

0 commit comments

Comments
 (0)