common/hmaps: Merge slice-valued module config into site config

When a module provides a config key whose value is a slice (e.g.
cascade or permalinks), and the site config declares the same key as a
map with only a merge strategy marker (_merge = 'deep'), the types do
not match and Params.merge silently dropped the module's value, leaving
the site with no effective cascade or permalink config from the module.

Fix Params.merge so that when the destination value is an empty Params
(IsZero — only the _merge key is present) and the source value is a
non-Params type, the source value is used provided the user-declared
merge strategy is not 'none'. This honours the explicit _merge
directive regardless of the surrounding shallow-merge context.

Closes #13869

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Joe Mooring
2026-05-15 09:22:52 -07:00
committed by Bjørn Erik Pedersen
parent 97f990cc4f
commit 5559263326
3 changed files with 64 additions and 1 deletions
+27
View File
@@ -544,6 +544,33 @@ cascade:
b.AssertFileExists("public/s2/p3/index.html", false)
}
// Issue 13869
func TestCascadeSliceFromModule13869(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
theme = 'foo'
[cascade]
_merge = 'deep'
-- content/_index.md --
---
title: home
---
-- layouts/home.html --
color: {{ .Params.color }}
-- themes/foo/hugo.toml --
[[cascade]]
[cascade.params]
color = 'red'
`
b := Test(t, files)
b.AssertFileContent("public/index.html", "color: red")
}
// Issue 14848
func TestCascadeParamsLangIssue14848(t *testing.T) {
t.Parallel()
+29 -1
View File
@@ -75,7 +75,7 @@ canonifyURLs = %t
---
title: Page
slug: %q
url: %q
url: %q
output: ["HTML"]
---
`, test.base, test.uglyURLs, test.canonifyURLs, test.file, test.slug, test.url)
@@ -173,3 +173,31 @@ Some content.
b.AssertFileContent("public/myblog/p2/index.html", "Single: A page|Hello|en|RelPermalink: /myblog/p2/|Permalink: https://example.com/myblog/p2/|")
b.AssertFileContent("public/myblog/p3/index.html", "Single: A page|Hello|en|RelPermalink: /myblog/p3/|Permalink: https://example.com/myblog/p3/|")
}
// Issue 13869
func TestPermalinksSliceFromModule13869(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
disableKinds = ['home','rss','section','sitemap','taxonomy','term']
theme = 'foo'
[permalinks]
_merge = 'deep'
-- content/books/my-book.md --
---
title: My Book
---
-- layouts/page.html --
RelPermalink: {{ .RelPermalink }}
-- themes/foo/hugo.toml --
[[permalinks]]
pattern = '/shelf/:slug/'
[permalinks.target]
path = '/books/**'
`
b := Test(t, files)
b.AssertFileContent("public/shelf/my-book/index.html", "RelPermalink: /shelf/my-book/")
}