Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add whitespace trimming functionality for notes and expressions #1122

Merged
merged 1 commit into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 22 additions & 36 deletions src/main/java/com/hubspot/jinjava/tree/TreeParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,7 @@ public Node buildTree() {
Node node = nextNode();

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

Expand Down Expand Up @@ -96,6 +91,12 @@ public Node buildTree() {

private Node nextNode() {
Token token = scanner.next();
if (token.isLeftTrim()) {
final Node lastSibling = getLastSibling();
if (lastSibling instanceof TextNode) {
lastSibling.getMaster().setRightTrim(true);
}
}

if (token.getType() == symbols.getFixed()) {
if (token instanceof UnclosedToken) {
Expand Down Expand Up @@ -170,7 +171,7 @@ private Node text(TextToken textToken) {
final Node lastSibling = getLastSibling();

// if last sibling was a tag and has rightTrimAfterEnd, strip whitespace
if (lastSibling instanceof TagNode && isRightTrim((TagNode) lastSibling)) {
if (lastSibling != null && isRightTrim(lastSibling)) {
textToken.setLeftTrim(true);
}

Expand All @@ -186,18 +187,21 @@ private Node text(TextToken textToken) {
return n;
}

private boolean isRightTrim(TagNode lastSibling) {
return (
lastSibling.getEndName() == null ||
(
lastSibling.getTag() instanceof FlexibleTag &&
!((FlexibleTag) lastSibling.getTag()).hasEndTag(
(TagToken) lastSibling.getMaster()
)
private boolean isRightTrim(Node lastSibling) {
if (lastSibling instanceof TagNode) {
return (
((TagNode) lastSibling).getEndName() == null ||
(
((TagNode) lastSibling).getTag() instanceof FlexibleTag &&
!((FlexibleTag) ((TagNode) lastSibling).getTag()).hasEndTag(
(TagToken) lastSibling.getMaster()
)
)
)
)
? lastSibling.getMaster().isRightTrim()
: lastSibling.getMaster().isRightTrimAfterEnd();
? lastSibling.getMaster().isRightTrim()
: lastSibling.getMaster().isRightTrimAfterEnd();
}
return lastSibling.getMaster().isRightTrim();
}

private Node expression(ExpressionToken expressionToken) {
Expand Down Expand Up @@ -242,14 +246,6 @@ private Node tag(TagToken tagToken) {
if (tag instanceof EndTag) {
endTag(tag, tagToken);
return null;
} else {
// if a tag has left trim, mark the last sibling to trim right whitespace
if (tagToken.isLeftTrim()) {
final Node lastSibling = getLastSibling();
if (lastSibling instanceof TextNode) {
lastSibling.getMaster().setRightTrim(true);
}
}
}

TagNode node = new TagNode(tag, tagToken, symbols);
Expand All @@ -268,16 +264,6 @@ private Node tag(TagToken tagToken) {
}

private void endTag(Tag tag, TagToken tagToken) {
final Node lastSibling = getLastSibling();

if (
parent instanceof TagNode &&
tagToken.isLeftTrim() &&
lastSibling instanceof TextNode
) {
lastSibling.getMaster().setRightTrim(true);
}

if (parent.getMaster() != null) { // root node
parent.getMaster().setRightTrimAfterEnd(tagToken.isRightTrim());
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/hubspot/jinjava/tree/parse/NoteToken.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
**********************************************************************/
package com.hubspot.jinjava.tree.parse;

import org.apache.commons.lang3.StringUtils;

public class NoteToken extends Token {
private static final long serialVersionUID = -3859011447900311329L;

Expand All @@ -37,6 +39,9 @@ public int getType() {
*/
@Override
protected void parse() {
if (StringUtils.isNotEmpty(image)) {
handleTrim(image.substring(2, image.length() - 2));
}
content = "";
}

Expand Down
5 changes: 0 additions & 5 deletions src/main/java/com/hubspot/jinjava/tree/parse/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ public String getImage() {
return image;
}

public void mergeImageAndContent(Token otherToken) {
this.image = image + otherToken.image;
this.content = content + otherToken.content;
}

public int getLineNumber() {
return lineNumber;
}
Expand Down
14 changes: 14 additions & 0 deletions src/test/java/com/hubspot/jinjava/tree/TreeParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,20 @@ public void itWarnsTwiceAgainstUnclosedBlockTag() {
assertThat(interpreter.getErrors().get(1).getLineno()).isEqualTo(1);
}

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

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

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