diff --git a/tpl/tplimpl/template_ast_transformers.go b/tpl/tplimpl/template_ast_transformers.go index 68090497b..339e2264a 100644 --- a/tpl/tplimpl/template_ast_transformers.go +++ b/tpl/tplimpl/template_ast_transformers.go @@ -35,12 +35,21 @@ var paramsPaths = [][]string{ } type templateContext struct { - decl decl - templ *template.Template + decl decl + templ *template.Template + visited map[string]bool +} + +func (c templateContext) getIfNotVisited(name string) *template.Template { + if c.visited[name] { + return nil + } + c.visited[name] = true + return c.templ.Lookup(name) } func newTemplateContext(templ *template.Template) *templateContext { - return &templateContext{templ: templ, decl: make(map[string]string)} + return &templateContext{templ: templ, decl: make(map[string]string), visited: make(map[string]bool)} } @@ -59,7 +68,6 @@ func applyTemplateTransformers(templ *template.Template) error { // paramsKeysToLower is made purposely non-generic to make it not so tempting // to do more of these hard-to-maintain AST transformations. func (c *templateContext) paramsKeysToLower(n parse.Node) { - switch x := n.(type) { case *parse.ListNode: if x != nil { @@ -74,7 +82,7 @@ func (c *templateContext) paramsKeysToLower(n parse.Node) { case *parse.RangeNode: c.paramsKeysToLowerForNodes(x.Pipe, x.List, x.ElseList) case *parse.TemplateNode: - subTempl := c.templ.Lookup(x.Name) + subTempl := c.getIfNotVisited(x.Name) if subTempl != nil { c.paramsKeysToLowerForNodes(subTempl.Tree.Root) } diff --git a/tpl/tplimpl/template_ast_transformers_test.go b/tpl/tplimpl/template_ast_transformers_test.go index 048d52fee..deeeae0a7 100644 --- a/tpl/tplimpl/template_ast_transformers_test.go +++ b/tpl/tplimpl/template_ast_transformers_test.go @@ -267,3 +267,24 @@ P2: {{ .Params.LOWER }} require.Contains(t, result, "P1: P1L") require.Contains(t, result, "P2: P1L") } + +// Issue #2927 +func TestTransformRecursiveTemplate(t *testing.T) { + + recursive := ` +{{ define "menu-nodes" }} +{{ template "menu-node" }} +{{ end }} +{{ define "menu-node" }} +{{ template "menu-node" }} +{{ end }} +{{ template "menu-nodes" }} +` + + templ, err := template.New("foo").Parse(recursive) + require.NoError(t, err) + + c := newTemplateContext(templ) + c.paramsKeysToLower(templ.Tree.Root) + +}