Skip to content

Commit 09a8168

Browse files
committed
Detect inner loop
1 parent 8d7efac commit 09a8168

File tree

4 files changed

+39
-12
lines changed

4 files changed

+39
-12
lines changed

‎tpl/templates/decorator_integration_test.go‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ Home.
117117
b.AssertFileContent("public/index.html", "<a><b><c>warning</c></b></b>")
118118
}
119119

120-
// TODO1 detect inner usage inside with partial. That' a bite in the tail.
121120
func TestDecoratorNested2(t *testing.T) {
122121
t.Parallel()
123122

@@ -296,3 +295,24 @@ Sum: {{ with partial "add.html" $v }}
296295
// 1 + 2 + 4 + 6 = 13
297296
b.AssertFileContent("public/index.html", "Sum: 13$")
298297
}
298+
299+
func TestDecoratorFailOnInnerInWith(t *testing.T) {
300+
t.Parallel()
301+
302+
filesTemplate := `
303+
-- hugo.toml --
304+
-- layouts/_partials/b.html --
305+
<b>{{ inner . }}</b>
306+
-- layouts/home.html --
307+
{{ with partial "b.html" "hello" }}
308+
This construct creates a loop: {{PLACEHOLDER . }}
309+
{{ end }}$
310+
`
311+
for _, placeholder := range []string{"inner", "templates.Inner", " inner", "\ninner"} {
312+
files := strings.ReplaceAll(filesTemplate, "PLACEHOLDER", placeholder)
313+
b, err := hugolib.TestE(t, files)
314+
315+
b.Assert(err, qt.Not(qt.IsNil))
316+
b.Assert(err.Error(), qt.Contains, "inner cannot be used inside a with block that wraps a partial decorator")
317+
}
318+
}

‎tpl/tplimpl/templates.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,16 @@ func (s *TemplateStore) parseTemplate(ti *TemplInfo, replace bool) error {
5353
return err
5454
}
5555

56-
func (t *templateNamespace) newBlankTemplate(ti *TemplInfo, name string) tpl.Template {
56+
func (t *templateNamespace) newBlankTemplate(ti *TemplInfo) tpl.Template {
5757
if ti.D.IsPlainText {
58-
tt, err := t.parseText.New(name).Parse("")
58+
tt, err := t.parseText.New(ti.Name()).Parse("")
5959
if err != nil {
6060
panic(err)
6161
}
6262
return tt
6363

6464
}
65-
tt, err := t.parseHTML.New(name).Parse("")
65+
tt, err := t.parseHTML.New(ti.Name()).Parse("")
6666
if err != nil {
6767
panic(err)
6868
}

‎tpl/tplimpl/templatestore.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,7 +1581,7 @@ func (s *TemplateStore) createTemplatesSnapshot() error {
15811581
return nil
15821582
}
15831583

1584-
func (s *TemplateStore) addTransformedTemplateRootStep1(name string, subCategory SubCategory) (*TemplInfo, error) {
1584+
func (s *TemplateStore) addTransformedTemplateInsert(name string, subCategory SubCategory) (*TemplInfo, error) {
15851585
pi := s.opts.PathParser.Parse(files.ComponentFolderLayouts, name)
15861586
ti, err := s.insertTemplate(pi, nil, subCategory, true, s.treeMain)
15871587
if err != nil {
@@ -1590,8 +1590,8 @@ func (s *TemplateStore) addTransformedTemplateRootStep1(name string, subCategory
15901590
return ti, nil
15911591
}
15921592

1593-
func (s *TemplateStore) addTransformedTemplateRoot(owner, this *TemplInfo, name string, subCategory SubCategory, root *parse.ListNode) (*parse.Tree, error) {
1594-
templ := s.tns.newBlankTemplate(owner, name)
1593+
func (s *TemplateStore) addTransformedTemplateSetTree(this *TemplInfo, root *parse.ListNode) (*parse.Tree, error) {
1594+
templ := s.tns.newBlankTemplate(this)
15951595
tree := getParseTree(templ)
15961596
tree.Root = root
15971597
this.Template = templ

‎tpl/tplimpl/templatetransform.go‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tplimpl
33
import (
44
"errors"
55
"fmt"
6+
"regexp"
67
"slices"
78
"strings"
89

@@ -84,7 +85,7 @@ func applyTemplateTransformers(
8485
}
8586

8687
if err := c.applyTransformationsAndSetReturnWrapper(tree); err != nil {
87-
return c, fmt.Errorf("failed to transform template %q: %w", t.Name, err)
88+
return c, fmt.Errorf("failed to transform template %q: %w", t.Name(), err)
8889
}
8990

9091
return c, c.err
@@ -263,19 +264,25 @@ func (c *templateTransformContext) isWithDefer(idArg parse.Node) bool {
263264
// PartialDecoratorPrefix is the prefix for internal partial decorator templates.
264265
const PartialDecoratorPrefix = "_internal/decorator_"
265266

267+
var templatesInnerRe = regexp.MustCompile(`{{\s*(templates\.Inner\b|inner\b)`)
268+
266269
func (c *templateTransformContext) handleWithPartial(withNode *parse.WithNode) {
267-
innerHash := hashing.XxHashFromStringHexEncoded(withNode.List.String())
270+
withNodeInnerString := withNode.List.String()
271+
if templatesInnerRe.MatchString(withNodeInnerString) {
272+
c.err = fmt.Errorf("inner cannot be used inside a with block that wraps a partial decorator")
273+
return
274+
}
275+
innerHash := hashing.XxHashFromStringHexEncoded(withNodeInnerString)
268276
internalPartialName := fmt.Sprintf("_partials/%s%s", PartialDecoratorPrefix, innerHash)
269277

270278
if c.lookupFn(internalPartialName, c.t) == nil {
271279
innerCopy := withNode.List.CopyList()
272-
// TODO1 rework to support return.
273-
ti, err := c.store.addTransformedTemplateRootStep1(internalPartialName, SubCategoryInline)
280+
ti, err := c.store.addTransformedTemplateInsert(internalPartialName, SubCategoryInline)
274281
cc := newTemplateTransformContext(ti, c.store, c.lookupFn)
275282
if err != nil {
276283
c.err = fmt.Errorf("failed to create internal partial decorator template %q: %w", internalPartialName, err)
277284
}
278-
tree, err := c.store.addTransformedTemplateRoot(c.t, ti, internalPartialName, SubCategoryInline, innerCopy)
285+
tree, err := c.store.addTransformedTemplateSetTree(ti, innerCopy)
279286
if err != nil {
280287
c.err = fmt.Errorf("failed to add internal partial decorator template %q: %w", internalPartialName, err)
281288
return

0 commit comments

Comments
 (0)