@@ -231,11 +231,17 @@ 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+ return c .isWithPartial (pn .Cmds [0 ].Args )
238+ }
239+
240+ if id1 , ok := first .(* parse.IdentifierNode ); ok && (id1 .Ident == "partial" || id1 .Ident == "partialCached" ) {
235241 return true
236242 }
237243
238- if chain , ok := args [ 0 ] .(* parse.ChainNode ); ok {
244+ if chain , ok := first .(* parse.ChainNode ); ok {
239245 if id2 , ok := chain .Node .(* parse.IdentifierNode ); ! ok || (id2 .Ident != "partials" ) {
240246 return false
241247 }
@@ -266,12 +272,49 @@ const PartialDecoratorPrefix = "_internal/decorator_"
266272
267273var templatesInnerRe = regexp .MustCompile (`{{\s*(templates\.Inner\b|inner\b)` )
268274
275+ // hasBreakOrContinueNotInRange returns true if the given list node contains a break or continue statement without being nested in a range.
276+ func (c * templateTransformContext ) hasBreakOrContinueNotInRange (n * parse.ListNode ) bool {
277+ for _ , node := range n .Nodes {
278+ switch x := node .(type ) {
279+ case * parse.ListNode :
280+ if c .hasBreakOrContinueNotInRange (x ) {
281+ return true
282+ }
283+ case * parse.RangeNode :
284+ // skip
285+ case * parse.IfNode :
286+ if c .hasBreakOrContinueNotInRange (x .List ) {
287+ return true
288+ }
289+ if c .hasBreakOrContinueNotInRange (x .ElseList ) {
290+ return true
291+ }
292+ case * parse.WithNode :
293+ if c .hasBreakOrContinueNotInRange (x .List ) {
294+ return true
295+ }
296+ if c .hasBreakOrContinueNotInRange (x .ElseList ) {
297+ return true
298+ }
299+ case * parse.BreakNode , * parse.ContinueNode :
300+ return true
301+
302+ }
303+ }
304+ return false
305+ }
306+
269307func (c * templateTransformContext ) handleWithPartial (withNode * parse.WithNode ) {
270308 withNodeInnerString := withNode .List .String ()
271309 if templatesInnerRe .MatchString (withNodeInnerString ) {
272310 c .err = fmt .Errorf ("inner cannot be used inside a with block that wraps a partial decorator" )
273311 return
274312 }
313+
314+ // See #14333. That is a very odd construct, but we need to guard against it.
315+ if c .hasBreakOrContinueNotInRange (withNode .List ) {
316+ return
317+ }
275318 innerHash := hashing .XxHashFromStringHexEncoded (c .t .Name () + withNodeInnerString )
276319 internalPartialName := fmt .Sprintf ("_partials/%s%s" , PartialDecoratorPrefix , innerHash )
277320
@@ -321,6 +364,9 @@ func (c *templateTransformContext) handleWithPartial(withNode *parse.WithNode) {
321364 sn2 := setContext .(* parse.PipeNode ).Cmds [0 ].Args [1 ].(* parse.PipeNode ).Cmds [0 ].Args [0 ].(* parse.StringNode )
322365 sn2 .Text = innerHash
323366 sn2 .Quoted = fmt .Sprintf ("%q" , sn2 .Text )
367+ if pn , ok := withNode .Pipe .Cmds [0 ].Args [0 ].(* parse.PipeNode ); ok {
368+ withNode .Pipe .Cmds [0 ].Args = pn .Cmds [0 ].Args
369+ }
324370 withNode .Pipe .Cmds = append (orNode .Pipe .Cmds , withNode .Pipe .Cmds ... )
325371
326372 withNode .List = newInner
0 commit comments