Skip to content

Commit 323ab52

Browse files
hs-lsongclaude
andcommitted
feat: Preserve block tags when extends path is undefined
When extends tag path is undefined in PreserveUndefinedExecutionMode, block tags were being processed normally causing their content to be extracted without the block wrapper. This fix adds an isExtendsDeferred flag that gets set when ExtendsTag throws DeferredValueException, allowing BlockTag to also defer and preserve its original syntax. This enables proper multi-pass rendering where templates with undefined extends paths preserve both the extends and block tags for later resolution. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 43fb172 commit 323ab52

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

src/main/java/com/hubspot/jinjava/interpret/Context.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,14 @@ public void setPreserveComments(boolean preserveComments) {
900900
contextConfiguration = contextConfiguration.withPreserveComments(preserveComments);
901901
}
902902

903+
public boolean isExtendsDeferred() {
904+
return contextConfiguration.isExtendsDeferred();
905+
}
906+
907+
public void setExtendsDeferred(boolean extendsDeferred) {
908+
contextConfiguration = contextConfiguration.withExtendsDeferred(extendsDeferred);
909+
}
910+
903911
public TemporaryValueClosable<Boolean> withUnwrapRawOverride() {
904912
TemporaryValueClosable<Boolean> temporaryValueClosable = new TemporaryValueClosable<>(
905913
isUnwrapRawOverride(),

src/main/java/com/hubspot/jinjava/interpret/ContextConfigurationIF.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ default boolean isPreserveComments() {
5353
return false;
5454
}
5555

56+
@Default
57+
default boolean isExtendsDeferred() {
58+
return false;
59+
}
60+
5661
@Default
5762
default ErrorHandlingStrategy getErrorHandlingStrategy() {
5863
return ErrorHandlingStrategy.of();

src/main/java/com/hubspot/jinjava/lib/tag/BlockTag.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.hubspot.jinjava.doc.annotations.JinjavaParam;
2121
import com.hubspot.jinjava.doc.annotations.JinjavaSnippet;
2222
import com.hubspot.jinjava.doc.annotations.JinjavaTextMateSnippet;
23+
import com.hubspot.jinjava.interpret.DeferredValueException;
2324
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
2425
import com.hubspot.jinjava.interpret.TemplateSyntaxException;
2526
import com.hubspot.jinjava.tree.TagNode;
@@ -60,6 +61,14 @@ public class BlockTag implements Tag {
6061

6162
@Override
6263
public OutputNode interpretOutput(TagNode tagNode, JinjavaInterpreter interpreter) {
64+
if (interpreter.getContext().isExtendsDeferred()) {
65+
throw new DeferredValueException(
66+
"block tag",
67+
tagNode.getLineNumber(),
68+
tagNode.getStartPosition()
69+
);
70+
}
71+
6372
HelperStringTokenizer tagData = new HelperStringTokenizer(tagNode.getHelpers());
6473
if (!tagData.hasNext()) {
6574
throw new TemplateSyntaxException(

src/main/java/com/hubspot/jinjava/lib/tag/ExtendsTag.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public class ExtendsTag implements Tag {
8989
@Override
9090
public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) {
9191
if (interpreter.getContext().isDeferredExecutionMode()) {
92+
interpreter.getContext().setExtendsDeferred(true);
9293
throw new DeferredValueException("extends tag");
9394
}
9495
HelperStringTokenizer tokenizer = new HelperStringTokenizer(tagNode.getHelpers());
@@ -101,11 +102,18 @@ public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) {
101102
);
102103
}
103104

104-
String path = interpreter.resolveString(
105-
tokenizer.next(),
106-
tagNode.getLineNumber(),
107-
tagNode.getStartPosition()
108-
);
105+
String path;
106+
try {
107+
path =
108+
interpreter.resolveString(
109+
tokenizer.next(),
110+
tagNode.getLineNumber(),
111+
tagNode.getStartPosition()
112+
);
113+
} catch (DeferredValueException e) {
114+
interpreter.getContext().setExtendsDeferred(true);
115+
throw e;
116+
}
109117
path = interpreter.resolveResourceLocation(path);
110118
interpreter
111119
.getContext()

0 commit comments

Comments
 (0)