Skip to content

Commit 3b99a0a

Browse files
authored
Merge pull request #1124 from HubSpot/legacy-text-merging
Legacy text merging
2 parents 264ac2b + a66b0ab commit 3b99a0a

4 files changed

Lines changed: 71 additions & 2 deletions

File tree

src/main/java/com/hubspot/jinjava/LegacyOverrides.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,28 @@
33
/**
44
* This class allows Jinjava to be configured to override legacy behaviour.
55
* LegacyOverrides.NONE signifies that none of the legacy functionality will be overridden.
6+
* LegacyOverrides.ALL signifies that all new functionality will be used; avoid legacy "bugs".
67
*/
78
public class LegacyOverrides {
89
public static final LegacyOverrides NONE = new LegacyOverrides.Builder().build();
10+
public static final LegacyOverrides ALL = new LegacyOverrides.Builder()
11+
.withEvaluateMapKeys(true)
12+
.withIterateOverMapKeys(true)
13+
.withUsePyishObjectMapper(true)
14+
.withUseSnakeCasePropertyNaming(true)
15+
.withWhitespaceRequiredWithinTokens(true)
16+
.withUseNaturalOperatorPrecedence(true)
17+
.withParseWhitespaceControlStrictly(true)
18+
.withAllowAdjacentTextNodes(true)
19+
.build();
920
private final boolean evaluateMapKeys;
1021
private final boolean iterateOverMapKeys;
1122
private final boolean usePyishObjectMapper;
1223
private final boolean useSnakeCasePropertyNaming;
1324
private final boolean whitespaceRequiredWithinTokens;
1425
private final boolean useNaturalOperatorPrecedence;
1526
private final boolean parseWhitespaceControlStrictly;
27+
private final boolean allowAdjacentTextNodes;
1628

1729
private LegacyOverrides(Builder builder) {
1830
evaluateMapKeys = builder.evaluateMapKeys;
@@ -22,6 +34,7 @@ private LegacyOverrides(Builder builder) {
2234
whitespaceRequiredWithinTokens = builder.whitespaceRequiredWithinTokens;
2335
useNaturalOperatorPrecedence = builder.useNaturalOperatorPrecedence;
2436
parseWhitespaceControlStrictly = builder.parseWhitespaceControlStrictly;
37+
allowAdjacentTextNodes = builder.allowAdjacentTextNodes;
2538
}
2639

2740
public static Builder newBuilder() {
@@ -56,6 +69,10 @@ public boolean isParseWhitespaceControlStrictly() {
5669
return parseWhitespaceControlStrictly;
5770
}
5871

72+
public boolean isAllowAdjacentTextNodes() {
73+
return allowAdjacentTextNodes;
74+
}
75+
5976
public static class Builder {
6077
private boolean evaluateMapKeys = false;
6178
private boolean iterateOverMapKeys = false;
@@ -64,6 +81,7 @@ public static class Builder {
6481
private boolean whitespaceRequiredWithinTokens = false;
6582
private boolean useNaturalOperatorPrecedence = false;
6683
private boolean parseWhitespaceControlStrictly = false;
84+
private boolean allowAdjacentTextNodes = false;
6785

6886
private Builder() {}
6987

@@ -83,7 +101,8 @@ public static Builder from(LegacyOverrides legacyOverrides) {
83101
.withUseNaturalOperatorPrecedence(legacyOverrides.useNaturalOperatorPrecedence)
84102
.withParseWhitespaceControlStrictly(
85103
legacyOverrides.parseWhitespaceControlStrictly
86-
);
104+
)
105+
.withAllowAdjacentTextNodes(legacyOverrides.allowAdjacentTextNodes);
87106
}
88107

89108
public Builder withEvaluateMapKeys(boolean evaluateMapKeys) {
@@ -126,5 +145,10 @@ public Builder withParseWhitespaceControlStrictly(
126145
this.parseWhitespaceControlStrictly = parseWhitespaceControlStrictly;
127146
return this;
128147
}
148+
149+
public Builder withAllowAdjacentTextNodes(boolean allowAdjacentTextNodes) {
150+
this.allowAdjacentTextNodes = allowAdjacentTextNodes;
151+
return this;
152+
}
129153
}
130154
}

src/main/java/com/hubspot/jinjava/tree/TreeParser.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,18 @@ public Node buildTree() {
6262
Node node = nextNode();
6363

6464
if (node != null) {
65-
parent.getChildren().add(node);
65+
if (
66+
node instanceof TextNode &&
67+
getLastSibling() instanceof TextNode &&
68+
!interpreter.getConfig().getLegacyOverrides().isAllowAdjacentTextNodes()
69+
) {
70+
// merge adjacent text nodes so whitespace control properly applies
71+
((TextToken) getLastSibling().getMaster()).mergeImageAndContent(
72+
(TextToken) node.getMaster()
73+
);
74+
} else {
75+
parent.getChildren().add(node);
76+
}
6677
}
6778
}
6879

src/main/java/com/hubspot/jinjava/tree/parse/TextToken.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ public TextToken(
2929
super(image, lineNumber, startPosition, symbols);
3030
}
3131

32+
public void mergeImageAndContent(TextToken otherToken) {
33+
String thisOutput = output();
34+
String otherTokenOutput = otherToken.output();
35+
this.image = thisOutput + otherTokenOutput;
36+
this.content = image;
37+
}
38+
3239
@Override
3340
public int getType() {
3441
return getSymbols().getFixed();

src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.hubspot.jinjava.BaseInterpretingTest;
77
import com.hubspot.jinjava.Jinjava;
88
import com.hubspot.jinjava.JinjavaConfig;
9+
import com.hubspot.jinjava.LegacyOverrides;
910
import com.hubspot.jinjava.interpret.TemplateError.ErrorType;
1011
import java.nio.charset.StandardCharsets;
1112
import org.junit.Test;
@@ -231,13 +232,39 @@ public void itTrimsNotes() {
231232
assertThat(interpreter.render(tree)).isEqualTo("AB");
232233
}
233234

235+
@Test
236+
public void itMergesTextNodesWhileRespectingTrim() {
237+
String expression = "{% print 'A' -%}\n{#- note -#}\nB\n{%- print 'C' %}";
238+
final Node tree = new TreeParser(interpreter, expression).buildTree();
239+
assertThat(interpreter.render(tree)).isEqualTo("ABC");
240+
}
241+
234242
@Test
235243
public void itTrimsExpressions() {
236244
String expression = "A\n{{- 'B' -}}\nC";
237245
final Node tree = new TreeParser(interpreter, expression).buildTree();
238246
assertThat(interpreter.render(tree)).isEqualTo("ABC");
239247
}
240248

249+
@Test
250+
public void itDoesNotMergeAdjacentTextNodesWhenLegacyOverrideIsApplied() {
251+
String expression = "A\n{%- if true -%}\n{# comment #}\nB{% endif %}";
252+
final Node tree = new TreeParser(interpreter, expression).buildTree();
253+
assertThat(interpreter.render(tree)).isEqualTo("AB");
254+
interpreter =
255+
new Jinjava(
256+
JinjavaConfig
257+
.newBuilder()
258+
.withLegacyOverrides(
259+
LegacyOverrides.newBuilder().withAllowAdjacentTextNodes(true).build()
260+
)
261+
.build()
262+
)
263+
.newInterpreter();
264+
final Node overriddenTree = new TreeParser(interpreter, expression).buildTree();
265+
assertThat(interpreter.render(overriddenTree)).isEqualTo("A\nB");
266+
}
267+
241268
Node parse(String fixture) {
242269
try {
243270
return new TreeParser(

0 commit comments

Comments
 (0)