@@ -231,11 +231,20 @@ func (c *templateTransformContext) isWithPartial(args []parse.Node) bool {
231231 return false
232232 }
233233
234- if id1 , ok := args [0 ].(* parse.IdentifierNode ); ok && (id1 .Ident == "partial" || id1 .Ident == "partialCached" ) {
234+ first := args [0 ]
235+
236+ if pn , ok := first .(* parse.PipeNode ); ok {
237+ if len (pn .Cmds ) == 0 || pn .Cmds [0 ] == nil {
238+ return false
239+ }
240+ return c .isWithPartial (pn .Cmds [0 ].Args )
241+ }
242+
243+ if id1 , ok := first .(* parse.IdentifierNode ); ok && (id1 .Ident == "partial" || id1 .Ident == "partialCached" ) {
235244 return true
236245 }
237246
238- if chain , ok := args [ 0 ] .(* parse.ChainNode ); ok {
247+ if chain , ok := first .(* parse.ChainNode ); ok {
239248 if id2 , ok := chain .Node .(* parse.IdentifierNode ); ! ok || (id2 .Ident != "partials" ) {
240249 return false
241250 }
@@ -266,12 +275,52 @@ const PartialDecoratorPrefix = "_internal/decorator_"
266275
267276var templatesInnerRe = regexp .MustCompile (`{{\s*(templates\.Inner\b|inner\b)` )
268277
278+ // hasBreakOrContinueOutsideRange returns true if the given list node contains a break or continue statement without being nested in a range.
279+ func (c * templateTransformContext ) hasBreakOrContinueOutsideRange (n * parse.ListNode ) bool {
280+ if n == nil {
281+ return false
282+ }
283+ for _ , node := range n .Nodes {
284+ switch x := node .(type ) {
285+ case * parse.ListNode :
286+ if c .hasBreakOrContinueOutsideRange (x ) {
287+ return true
288+ }
289+ case * parse.RangeNode :
290+ // skip
291+ case * parse.IfNode :
292+ if c .hasBreakOrContinueOutsideRange (x .List ) {
293+ return true
294+ }
295+ if c .hasBreakOrContinueOutsideRange (x .ElseList ) {
296+ return true
297+ }
298+ case * parse.WithNode :
299+ if c .hasBreakOrContinueOutsideRange (x .List ) {
300+ return true
301+ }
302+ if c .hasBreakOrContinueOutsideRange (x .ElseList ) {
303+ return true
304+ }
305+ case * parse.BreakNode , * parse.ContinueNode :
306+ return true
307+
308+ }
309+ }
310+ return false
311+ }
312+
269313func (c * templateTransformContext ) handleWithPartial (withNode * parse.WithNode ) {
270314 withNodeInnerString := withNode .List .String ()
271315 if templatesInnerRe .MatchString (withNodeInnerString ) {
272316 c .err = fmt .Errorf ("inner cannot be used inside a with block that wraps a partial decorator" )
273317 return
274318 }
319+
320+ // See #14333. That is a very odd construct, but we need to guard against it.
321+ if c .hasBreakOrContinueOutsideRange (withNode .List ) {
322+ return
323+ }
275324 innerHash := hashing .XxHashFromStringHexEncoded (c .t .Name () + withNodeInnerString )
276325 internalPartialName := fmt .Sprintf ("_partials/%s%s" , PartialDecoratorPrefix , innerHash )
277326
@@ -321,6 +370,9 @@ func (c *templateTransformContext) handleWithPartial(withNode *parse.WithNode) {
321370 sn2 := setContext .(* parse.PipeNode ).Cmds [0 ].Args [1 ].(* parse.PipeNode ).Cmds [0 ].Args [0 ].(* parse.StringNode )
322371 sn2 .Text = innerHash
323372 sn2 .Quoted = fmt .Sprintf ("%q" , sn2 .Text )
373+ if pn , ok := withNode .Pipe .Cmds [0 ].Args [0 ].(* parse.PipeNode ); ok {
374+ withNode .Pipe .Cmds [0 ].Args = pn .Cmds [0 ].Args
375+ }
324376 withNode .Pipe .Cmds = append (orNode .Pipe .Cmds , withNode .Pipe .Cmds ... )
325377
326378 withNode .List = newInner
0 commit comments