Skip to content

Commit 65a76a1

Browse files
committed
Merge branch 'master' of https://github.com/HubSpot/jinjava into keep-undefined
2 parents d18c8cf + 0b610c9 commit 65a76a1

File tree

18 files changed

+189
-46
lines changed

18 files changed

+189
-46
lines changed

pom.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<dep.hubspot-immutables.version>1.9</dep.hubspot-immutables.version>
2424
<dep.algebra.version>1.5</dep.algebra.version>
2525
<dep.mockito.version>5.20.0</dep.mockito.version>
26-
26+
<dep.jackson.version>2.20.1</dep.jackson.version>
2727

2828
<basepom.test.add.opens>
2929
--add-opens=java.base/java.lang=ALL-UNNAMED
@@ -72,27 +72,27 @@
7272
<dependency>
7373
<groupId>com.fasterxml.jackson.core</groupId>
7474
<artifactId>jackson-annotations</artifactId>
75-
<version>2.14.0</version>
75+
<version>2.20</version>
7676
</dependency>
7777
<dependency>
7878
<groupId>com.fasterxml.jackson.core</groupId>
7979
<artifactId>jackson-databind</artifactId>
80-
<version>2.14.0</version>
80+
<version>${dep.jackson.version}</version>
8181
</dependency>
8282
<dependency>
8383
<groupId>com.fasterxml.jackson.core</groupId>
8484
<artifactId>jackson-core</artifactId>
85-
<version>2.14.0</version>
85+
<version>${dep.jackson.version}</version>
8686
</dependency>
8787
<dependency>
8888
<groupId>com.fasterxml.jackson.dataformat</groupId>
8989
<artifactId>jackson-dataformat-yaml</artifactId>
90-
<version>2.14.0</version>
90+
<version>${dep.jackson.version}</version>
9191
</dependency>
9292
<dependency>
9393
<groupId>com.fasterxml.jackson.datatype</groupId>
9494
<artifactId>jackson-datatype-jdk8</artifactId>
95-
<version>2.14.0</version>
95+
<version>${dep.jackson.version}</version>
9696
</dependency>
9797
<dependency>
9898
<groupId>com.hubspot.immutables</groupId>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.hubspot.jinjava.lib.tag.eager;
2+
3+
import com.google.common.annotations.Beta;
4+
import com.hubspot.jinjava.interpret.DeferredValue;
5+
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
6+
import com.hubspot.jinjava.lib.tag.ContinueTag;
7+
import com.hubspot.jinjava.lib.tag.ForTag;
8+
import com.hubspot.jinjava.tree.parse.TagToken;
9+
10+
/**
11+
* Eager decorator for the continue tag that handles reconstruction when the continue
12+
* is inside a deferred context (e.g., when in deferred execution mode such as
13+
* inside a deferred if condition within a for loop).
14+
*/
15+
@Beta
16+
public class EagerContinueTag extends EagerTagDecorator<ContinueTag> {
17+
18+
public EagerContinueTag() {
19+
super(new ContinueTag());
20+
}
21+
22+
public EagerContinueTag(ContinueTag continueTag) {
23+
super(continueTag);
24+
}
25+
26+
@Override
27+
public String getEagerTagImage(TagToken tagToken, JinjavaInterpreter interpreter) {
28+
if (!(interpreter.getContext().get(ForTag.LOOP) instanceof DeferredValue)) {
29+
interpreter.getContext().replace(ForTag.LOOP, DeferredValue.instance());
30+
}
31+
return super.getEagerTagImage(tagToken, interpreter);
32+
}
33+
}

src/main/java/com/hubspot/jinjava/lib/tag/eager/EagerTagFactory.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.google.common.collect.ImmutableMap;
66
import com.google.common.collect.ImmutableSet;
77
import com.hubspot.jinjava.lib.tag.BlockTag;
8-
import com.hubspot.jinjava.lib.tag.BreakTag;
98
import com.hubspot.jinjava.lib.tag.CallTag;
109
import com.hubspot.jinjava.lib.tag.ContinueTag;
1110
import com.hubspot.jinjava.lib.tag.CycleTag;
@@ -46,6 +45,7 @@ public class EagerTagFactory {
4645
.put(IfTag.class, EagerIfTag.class)
4746
.put(UnlessTag.class, EagerUnlessTag.class)
4847
.put(CallTag.class, EagerCallTag.class)
48+
.put(ContinueTag.class, EagerContinueTag.class)
4949
.build();
5050
// These classes don't need an eager decorator.
5151
public static final Set<Class<? extends Tag>> TAG_CLASSES_TO_SKIP = ImmutableSet
@@ -56,8 +56,6 @@ public class EagerTagFactory {
5656
.add(ElseTag.class)
5757
.add(RawTag.class)
5858
.add(ExtendsTag.class) // TODO support reconstructing extends tags
59-
.add(BreakTag.class) // TODO support eager break tag
60-
.add(ContinueTag.class) // TODO support eager continue tag
6159
.build();
6260

6361
@SuppressWarnings("unchecked")

src/main/java/com/hubspot/jinjava/util/EagerExpressionResolver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,12 @@ public static Set<String> findDeferredWords(
175175
);
176176
prevQuotePos = curPos;
177177
}
178-
prevChar = c;
178+
if (prevChar == '\\') {
179+
// Double escapes cancel out.
180+
prevChar = 0;
181+
} else {
182+
prevChar = c;
183+
}
179184
curPos++;
180185
}
181186
words.addAll(

src/test/java/com/hubspot/jinjava/EagerTest.java

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.Collections;
2626
import java.util.HashMap;
27+
import java.util.List;
2728
import java.util.Map;
2829
import java.util.Optional;
2930
import java.util.Set;
@@ -1647,42 +1648,74 @@ public void itWrapsMacroThatWouldChangeCurrentPathInChildScope() {
16471648

16481649
@Test
16491650
public void itHandlesDeferredBreakInForLoop() {
1650-
String input = expectedTemplateInterpreter.getFixtureTemplate(
1651+
expectedTemplateInterpreter.assertExpectedOutput(
16511652
"handles-deferred-break-in-for-loop/test"
16521653
);
1653-
interpreter.render(input);
1654-
// We don't support this yet
1655-
assertThat(interpreter.getContext().getDeferredNodes()).isNotEmpty();
1654+
}
1655+
1656+
@Test
1657+
public void itHandlesDeferredBreakInForLoopSecondPass() {
1658+
localContext.put("deferred", 1);
1659+
expectedTemplateInterpreter.assertExpectedOutput(
1660+
"handles-deferred-break-in-for-loop/test.expected"
1661+
);
1662+
expectedTemplateInterpreter.assertExpectedNonEagerOutput(
1663+
"handles-deferred-break-in-for-loop/test.expected"
1664+
);
16561665
}
16571666

16581667
@Test
16591668
public void itHandlesBreakInDeferredForLoop() {
1660-
String input = expectedTemplateInterpreter.getFixtureTemplate(
1669+
expectedTemplateInterpreter.assertExpectedOutput(
16611670
"handles-break-in-deferred-for-loop/test"
16621671
);
1663-
interpreter.render(input);
1664-
// We don't support this yet
1665-
assertThat(interpreter.getContext().getDeferredNodes()).isNotEmpty();
1672+
}
1673+
1674+
@Test
1675+
public void itHandlesBreakInDeferredForLoopSecondPass() {
1676+
localContext.put("deferred", List.of(0, 1, 2, 3, 4, 5));
1677+
expectedTemplateInterpreter.assertExpectedOutput(
1678+
"handles-break-in-deferred-for-loop/test.expected"
1679+
);
1680+
expectedTemplateInterpreter.assertExpectedNonEagerOutput(
1681+
"handles-break-in-deferred-for-loop/test.expected"
1682+
);
16661683
}
16671684

16681685
@Test
16691686
public void itHandlesDeferredContinueInForLoop() {
1670-
String input = expectedTemplateInterpreter.getFixtureTemplate(
1687+
expectedTemplateInterpreter.assertExpectedOutput(
16711688
"handles-deferred-continue-in-for-loop/test"
16721689
);
1673-
interpreter.render(input);
1674-
// We don't support this yet
1675-
assertThat(interpreter.getContext().getDeferredNodes()).isNotEmpty();
1690+
}
1691+
1692+
@Test
1693+
public void itHandlesDeferredContinueInForLoopSecondPass() {
1694+
localContext.put("deferred", 2);
1695+
expectedTemplateInterpreter.assertExpectedOutput(
1696+
"handles-deferred-continue-in-for-loop/test.expected"
1697+
);
1698+
expectedTemplateInterpreter.assertExpectedNonEagerOutput(
1699+
"handles-deferred-continue-in-for-loop/test.expected"
1700+
);
16761701
}
16771702

16781703
@Test
16791704
public void itHandlesContinueInDeferredForLoop() {
1680-
String input = expectedTemplateInterpreter.getFixtureTemplate(
1705+
expectedTemplateInterpreter.assertExpectedOutput(
16811706
"handles-continue-in-deferred-for-loop/test"
16821707
);
1683-
interpreter.render(input);
1684-
// We don't support this yet
1685-
assertThat(interpreter.getContext().getDeferredNodes()).isNotEmpty();
1708+
}
1709+
1710+
@Test
1711+
public void itHandlesContinueInDeferredForLoopSecondPass() {
1712+
localContext.put("deferred", List.of(0, 1, 2, 3, 4, 5));
1713+
expectedTemplateInterpreter.assertExpectedOutput(
1714+
"handles-continue-in-deferred-for-loop/test.expected"
1715+
);
1716+
expectedTemplateInterpreter.assertExpectedNonEagerOutput(
1717+
"handles-continue-in-deferred-for-loop/test.expected"
1718+
);
16861719
}
16871720

16881721
@Test

src/test/java/com/hubspot/jinjava/util/EagerExpressionResolverTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ public void itHandlesSingleQuotes() {
357357
.isEqualTo("' & ' & '\"");
358358
}
359359

360+
@Test
361+
public void itHandlesEscapedSlashBeforeQuoteProperly() {
362+
EagerExpressionResult eagerExpressionResult = eagerResolveExpression(
363+
"deferred|replace('\\\\', '.')"
364+
);
365+
assertThat(eagerExpressionResult.getDeferredWords())
366+
.containsExactlyInAnyOrder("deferred", "replace.filter");
367+
}
368+
360369
@Test
361370
public void itHandlesNewlines() {
362371
context.put("foo", "\n");
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Start loop
2+
i is: 0
3+
i is: 1
4+
End loop
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Start loop
2+
{% for i in deferred %}\
3+
{% if i > 1 %}\
4+
{% break '' %}\
5+
{% endif %}\
6+
i is: {{ i }}
7+
{% endfor %}\
8+
End loop
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Start loop
2-
{% for i in deferred %}
3-
{% if i %}
4-
{% break %}
5-
{% endif %}
2+
{% for i in deferred -%}
3+
{% if i > 1 -%}
4+
{% break -%}
5+
{% endif -%}
66
i is: {{ i }}
7-
{% endfor %}
7+
{% endfor -%}
88
End loop
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Start loop
2+
i is: 1
3+
i is: 3
4+
i is: 5
5+
End loop

0 commit comments

Comments
 (0)