]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
tpl: Fix legacy section mappings
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 11 Apr 2025 09:20:03 +0000 (11:20 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 11 Apr 2025 16:23:51 +0000 (18:23 +0200)
Fixes #13584

tpl/templates/templates_integration_test.go
tpl/tplimpl/templates.go
tpl/tplimpl/templatestore.go
tpl/tplimpl/templatestore_integration_test.go

index 4150ec367db98e6e34aa5a37e7d4bced2a8d7119..93922b4c42b63e8a357a8cf4688a035fac5d91cb 100644 (file)
@@ -214,3 +214,18 @@ All.
        b.AssertFileContent("public/index.html", "All.")
        b.AssertFileContent("public/amp/index.html", "All.")
 }
+
+// Issue #13584.
+func TestLegacySectionSection(t *testing.T) {
+       t.Parallel()
+
+       files := `
+-- hugo.toml --
+-- content/mysection/_index.md --
+-- layouts/section/section.html --
+layouts/section/section.html
+
+`
+       b := hugolib.Test(t, files)
+       b.AssertFileContent("public/mysection/index.html", "layouts/section/section.html")
+}
index 1f911b9a58d515505774c95ed06365d7b10aa9d9..4c3ad3be1ab317cad96bf99cfa06cc6f641bf5c4 100644 (file)
@@ -3,7 +3,9 @@ package tplimpl
 import (
        "io"
        "regexp"
+       "strconv"
        "strings"
+       "sync/atomic"
        "unicode"
        "unicode/utf8"
 
@@ -49,11 +51,6 @@ func (t *templateNamespace) parseTemplate(ti *TemplInfo) error {
        }
        pi := ti.PathInfo
        name := pi.PathNoLeadingSlash()
-       if ti.isLegacyMapped {
-               // When mapping the old taxonomy structure to the new one, we may map the same path to multiple templates per kind.
-               // Append the kind here to make the name unique.
-               name += ("-" + ti.D.Kind)
-       }
 
        var (
                templ tpl.Template
@@ -62,12 +59,18 @@ func (t *templateNamespace) parseTemplate(ti *TemplInfo) error {
 
        if ti.D.IsPlainText {
                prototype := t.parseText
+               if prototype.Lookup(name) != nil {
+                       name += "-" + strconv.FormatUint(t.nameCounter.Add(1), 10)
+               }
                templ, err = prototype.New(name).Parse(ti.content)
                if err != nil {
                        return err
                }
        } else {
                prototype := t.parseHTML
+               if prototype.Lookup(name) != nil {
+                       name += "-" + strconv.FormatUint(t.nameCounter.Add(1), 10)
+               }
                templ, err = prototype.New(name).Parse(ti.content)
                if err != nil {
                        return err
@@ -296,6 +299,8 @@ type templateNamespace struct {
        prototypeText *texttemplate.Template
        prototypeHTML *htmltemplate.Template
 
+       nameCounter atomic.Uint64
+
        standaloneText *texttemplate.Template
 
        baseofTextClones []*texttemplate.Template
index 3c8c4abf23577e0ec2b6fcd3147c933a258b7dee..8fe89586d02d5a080baed03fb1e2482371fbbc1d 100644 (file)
@@ -690,7 +690,7 @@ func (t *TemplateStore) UnusedTemplates() []*TemplInfo {
        var unused []*TemplInfo
 
        for vv := range t.templates() {
-               if vv.subCategory != SubCategoryMain {
+               if vv.subCategory != SubCategoryMain || vv.isLegacyMapped {
                        // Skip inline partials and internal templates.
                        continue
                }
@@ -1169,8 +1169,8 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
                case containerPartials, containerShortcodes, containerMarkup:
                        // OK.
                default:
-                       applyLegacyMapping = true
                        pi = fromLegacyPath(pi)
+                       applyLegacyMapping = strings.Count(pi.Path(), "/") <= 2
                }
 
                if applyLegacyMapping {
@@ -1183,6 +1183,7 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
                                        ext:            pi.Ext(),
                                        outputFormat:   pi.OutputFormat(),
                                }
+
                                if m2, ok := legacyOrdinalMappings[key]; ok {
                                        if m1.ordinal < m2.m.ordinal {
                                                // Higher up == better match.
@@ -1208,26 +1209,74 @@ func (s *TemplateStore) insertTemplates(include func(fi hugofs.FileMetaInfo) boo
 
                        base := piOrig.PathBeforeLangAndOutputFormatAndExt()
                        identifiers := pi.IdentifiersUnknown()
+                       if pi.Kind() != "" {
+                               identifiers = append(identifiers, pi.Kind())
+                       }
+
+                       shouldIncludeSection := func(section string) bool {
+                               switch section {
+                               case containerShortcodes, containerPartials, containerMarkup:
+                                       return false
+                               case "taxonomy", "":
+                                       return false
+                               default:
+                                       for k, v := range s.opts.TaxonomySingularPlural {
+                                               if k == section || v == section {
+                                                       return false
+                                               }
+                                       }
+                                       return true
+                               }
+                       }
+                       if shouldIncludeSection(pi.Section()) {
+                               identifiers = append(identifiers, pi.Section())
+                       }
+
+                       identifiers = helpers.UniqueStrings(identifiers)
 
                        // Tokens on e.g. form /SECTIONKIND/THESECTION
-                       insertSectionTokens := func(section string, kindOnly bool) string {
-                               s := base
+                       insertSectionTokens := func(section string) []string {
+                               kindOnly := isLayoutStandard(section)
+                               var ss []string
+                               s1 := base
+                               if !kindOnly {
+                                       s1 = strings.ReplaceAll(s1, section, sectionToken)
+                               }
+                               s1 = strings.ReplaceAll(s1, kinds.KindSection, sectionKindToken)
+                               if s1 != base {
+                                       ss = append(ss, s1)
+                               }
+                               s1 = strings.ReplaceAll(base, kinds.KindSection, sectionKindToken)
                                if !kindOnly {
-                                       s = strings.Replace(s, section, sectionToken, 1)
+                                       s1 = strings.ReplaceAll(s1, section, sectionToken)
+                               }
+                               if s1 != base {
+                                       ss = append(ss, s1)
                                }
-                               s = strings.Replace(s, kinds.KindSection, sectionKindToken, 1)
-                               return s
+
+                               helpers.UniqueStringsReuse(ss)
+
+                               return ss
                        }
 
-                       for _, section := range identifiers {
-                               if section == baseNameBaseof {
+                       for _, id := range identifiers {
+                               if id == "" {
                                        continue
                                }
-                               kindOnly := isLayoutStandard(section)
-                               p := insertSectionTokens(section, kindOnly)
-                               if m1, ok := s.opts.legacyMappingSection[p]; ok {
-                                       m1.mapping.targetPath = strings.Replace(m1.mapping.targetPath, sectionToken, section, 1)
-                                       handleMapping(m1)
+
+                               p := insertSectionTokens(id)
+                               for _, ss := range p {
+                                       if m1, ok := s.opts.legacyMappingSection[ss]; ok {
+                                               targetPath := m1.mapping.targetPath
+
+                                               if targetPath != "" {
+                                                       targetPath = strings.ReplaceAll(targetPath, sectionToken, id)
+                                                       targetPath = strings.ReplaceAll(targetPath, sectionKindToken, id)
+                                                       targetPath = strings.ReplaceAll(targetPath, "//", "/")
+                                               }
+                                               m1.mapping.targetPath = targetPath
+                                               handleMapping(m1)
+                                       }
                                }
                        }
 
index 4f76626ad774f135b735f2afede521cb7283f68b..74abe58d0fdcf5a27e5fd87a69d82febe182f26b 100644 (file)
@@ -441,7 +441,7 @@ title: "P1"
 {{ define "main" }}FOO{{ end }}
 -- layouts/_default/single.json --
 -- layouts/_default/single.html --
-{{ define "main" }}MAIN{{ end }}
+{{ define "main" }}MAIN /_default/single.html{{ end }}
 -- layouts/post/single.html --
 {{ define "main" }}MAIN{{ end }}
 -- layouts/_partials/usedpartial.html --
@@ -461,6 +461,8 @@ title: "P1"
        )
        b.Build()
 
+       b.AssertFileContent("public/p1/index.html", "MAIN /_default/single.html")
+
        unused := b.H.GetTemplateStore().UnusedTemplates()
        var names []string
        for _, tmpl := range unused {
@@ -468,8 +470,9 @@ title: "P1"
                        names = append(names, fi.Meta().PathInfo.PathNoLeadingSlash())
                }
        }
-       b.Assert(len(unused), qt.Equals, 5, qt.Commentf("%#v", names))
+
        b.Assert(names, qt.DeepEquals, []string{"_partials/unusedpartial.html", "shortcodes/unusedshortcode.html", "baseof.json", "post/single.html", "_default/single.json"})
+       b.Assert(len(unused), qt.Equals, 5, qt.Commentf("%#v", names))
 }
 
 func TestCreateManyTemplateStores(t *testing.T) {