Skip to content

Commit

Permalink
Merge pull request #1124 from HubSpot/legacy-text-merging
Browse files Browse the repository at this point in the history
Legacy text merging
  • Loading branch information
jasmith-hs authored Oct 30, 2023
2 parents 264ac2b + a66b0ab commit 3b99a0a
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
26 changes: 25 additions & 1 deletion src/main/java/com/hubspot/jinjava/LegacyOverrides.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@
/**
* This class allows Jinjava to be configured to override legacy behaviour.
* LegacyOverrides.NONE signifies that none of the legacy functionality will be overridden.
* LegacyOverrides.ALL signifies that all new functionality will be used; avoid legacy "bugs".
*/
public class LegacyOverrides {
public static final LegacyOverrides NONE = new LegacyOverrides.Builder().build();
public static final LegacyOverrides ALL = new LegacyOverrides.Builder()
.withEvaluateMapKeys(true)
.withIterateOverMapKeys(true)
.withUsePyishObjectMapper(true)
.withUseSnakeCasePropertyNaming(true)
.withWhitespaceRequiredWithinTokens(true)
.withUseNaturalOperatorPrecedence(true)
.withParseWhitespaceControlStrictly(true)
.withAllowAdjacentTextNodes(true)
.build();
private final boolean evaluateMapKeys;
private final boolean iterateOverMapKeys;
private final boolean usePyishObjectMapper;
private final boolean useSnakeCasePropertyNaming;
private final boolean whitespaceRequiredWithinTokens;
private final boolean useNaturalOperatorPrecedence;
private final boolean parseWhitespaceControlStrictly;
private final boolean allowAdjacentTextNodes;

private LegacyOverrides(Builder builder) {
evaluateMapKeys = builder.evaluateMapKeys;
Expand All @@ -22,6 +34,7 @@ private LegacyOverrides(Builder builder) {
whitespaceRequiredWithinTokens = builder.whitespaceRequiredWithinTokens;
useNaturalOperatorPrecedence = builder.useNaturalOperatorPrecedence;
parseWhitespaceControlStrictly = builder.parseWhitespaceControlStrictly;
allowAdjacentTextNodes = builder.allowAdjacentTextNodes;
}

public static Builder newBuilder() {
Expand Down Expand Up @@ -56,6 +69,10 @@ public boolean isParseWhitespaceControlStrictly() {
return parseWhitespaceControlStrictly;
}

public boolean isAllowAdjacentTextNodes() {
return allowAdjacentTextNodes;
}

public static class Builder {
private boolean evaluateMapKeys = false;
private boolean iterateOverMapKeys = false;
Expand All @@ -64,6 +81,7 @@ public static class Builder {
private boolean whitespaceRequiredWithinTokens = false;
private boolean useNaturalOperatorPrecedence = false;
private boolean parseWhitespaceControlStrictly = false;
private boolean allowAdjacentTextNodes = false;

private Builder() {}

Expand All @@ -83,7 +101,8 @@ public static Builder from(LegacyOverrides legacyOverrides) {
.withUseNaturalOperatorPrecedence(legacyOverrides.useNaturalOperatorPrecedence)
.withParseWhitespaceControlStrictly(
legacyOverrides.parseWhitespaceControlStrictly
);
)
.withAllowAdjacentTextNodes(legacyOverrides.allowAdjacentTextNodes);
}

public Builder withEvaluateMapKeys(boolean evaluateMapKeys) {
Expand Down Expand Up @@ -126,5 +145,10 @@ public Builder withParseWhitespaceControlStrictly(
this.parseWhitespaceControlStrictly = parseWhitespaceControlStrictly;
return this;
}

public Builder withAllowAdjacentTextNodes(boolean allowAdjacentTextNodes) {
this.allowAdjacentTextNodes = allowAdjacentTextNodes;
return this;
}
}
}
13 changes: 12 additions & 1 deletion src/main/java/com/hubspot/jinjava/tree/TreeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,18 @@ public Node buildTree() {
Node node = nextNode();

if (node != null) {
parent.getChildren().add(node);
if (
node instanceof TextNode &&
getLastSibling() instanceof TextNode &&
!interpreter.getConfig().getLegacyOverrides().isAllowAdjacentTextNodes()
) {
// merge adjacent text nodes so whitespace control properly applies
((TextToken) getLastSibling().getMaster()).mergeImageAndContent(
(TextToken) node.getMaster()
);
} else {
parent.getChildren().add(node);
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/hubspot/jinjava/tree/parse/TextToken.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ public TextToken(
super(image, lineNumber, startPosition, symbols);
}

public void mergeImageAndContent(TextToken otherToken) {
String thisOutput = output();
String otherTokenOutput = otherToken.output();
this.image = thisOutput + otherTokenOutput;
this.content = image;
}

@Override
public int getType() {
return getSymbols().getFixed();
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.hubspot.jinjava.BaseInterpretingTest;
import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.LegacyOverrides;
import com.hubspot.jinjava.interpret.TemplateError.ErrorType;
import java.nio.charset.StandardCharsets;
import org.junit.Test;
Expand Down Expand Up @@ -231,13 +232,39 @@ public void itTrimsNotes() {
assertThat(interpreter.render(tree)).isEqualTo("AB");
}

@Test
public void itMergesTextNodesWhileRespectingTrim() {
String expression = "{% print 'A' -%}\n{#- note -#}\nB\n{%- print 'C' %}";
final Node tree = new TreeParser(interpreter, expression).buildTree();
assertThat(interpreter.render(tree)).isEqualTo("ABC");
}

@Test
public void itTrimsExpressions() {
String expression = "A\n{{- 'B' -}}\nC";
final Node tree = new TreeParser(interpreter, expression).buildTree();
assertThat(interpreter.render(tree)).isEqualTo("ABC");
}

@Test
public void itDoesNotMergeAdjacentTextNodesWhenLegacyOverrideIsApplied() {
String expression = "A\n{%- if true -%}\n{# comment #}\nB{% endif %}";
final Node tree = new TreeParser(interpreter, expression).buildTree();
assertThat(interpreter.render(tree)).isEqualTo("AB");
interpreter =
new Jinjava(
JinjavaConfig
.newBuilder()
.withLegacyOverrides(
LegacyOverrides.newBuilder().withAllowAdjacentTextNodes(true).build()
)
.build()
)
.newInterpreter();
final Node overriddenTree = new TreeParser(interpreter, expression).buildTree();
assertThat(interpreter.render(overriddenTree)).isEqualTo("A\nB");
}

Node parse(String fixture) {
try {
return new TreeParser(
Expand Down

0 comments on commit 3b99a0a

Please sign in to comment.