diff --git a/src/main/java/liqp/TemplateContext.java b/src/main/java/liqp/TemplateContext.java index b6e56fff..fd89ca0c 100644 --- a/src/main/java/liqp/TemplateContext.java +++ b/src/main/java/liqp/TemplateContext.java @@ -30,7 +30,7 @@ public class TemplateContext { private Map environmentMap; private Map registry; - private List errors; + private final List errors; private final Template template; public TemplateContext() { diff --git a/src/main/java/liqp/nodes/OutputNode.java b/src/main/java/liqp/nodes/OutputNode.java index d712bf42..2ea9be05 100644 --- a/src/main/java/liqp/nodes/OutputNode.java +++ b/src/main/java/liqp/nodes/OutputNode.java @@ -2,6 +2,7 @@ import liqp.TemplateContext; import liqp.TemplateParser; +import liqp.exceptions.LiquidException; import org.jsoup.internal.StringUtil; import java.util.ArrayList; @@ -11,12 +12,14 @@ public class OutputNode implements LNode { private LNode expression; private String unparsed; + private Integer unparsedline; private Integer unparsedPosition; private List filters; - public OutputNode(LNode expression, String unparsed, Integer unparsedPosition) { + public OutputNode(LNode expression, String unparsed, Integer unparsedline, Integer unparsedPosition) { this.expression = expression; this.unparsed = unparsed; + this.unparsedline = unparsedline; this.unparsedPosition = unparsedPosition; this.filters = new ArrayList<>(); } @@ -39,7 +42,13 @@ public Object render(TemplateContext context) { if (localUnparsed.length() > 30) { localUnparsed = localUnparsed.substring(0, 30) + "..."; } - context.addError(new RuntimeException("unexpected output: " + localUnparsed + " at position " + unparsedPosition)); + if (unparsedline == null) { + unparsedline = -1; + } + if (unparsedPosition == null) { + unparsedPosition = -1; + } + context.addError(new LiquidException("unexpected output: " + localUnparsed, unparsedline, unparsedPosition, null)); } } diff --git a/src/main/java/liqp/parser/Flavor.java b/src/main/java/liqp/parser/Flavor.java index a29f1e0f..a18963e7 100644 --- a/src/main/java/liqp/parser/Flavor.java +++ b/src/main/java/liqp/parser/Flavor.java @@ -8,7 +8,7 @@ public enum Flavor { LIQUID("snippets", Filters.DEFAULT_FILTERS, Insertions.STANDARD_INSERTIONS, - TemplateParser.ErrorMode.LAX, + TemplateParser.ErrorMode.STRICT, true, true, false diff --git a/src/main/java/liqp/parser/v4/NodeVisitor.java b/src/main/java/liqp/parser/v4/NodeVisitor.java index 582d37a6..4873346b 100644 --- a/src/main/java/liqp/parser/v4/NodeVisitor.java +++ b/src/main/java/liqp/parser/v4/NodeVisitor.java @@ -532,15 +532,17 @@ public LNode visitFilename(FilenameContext ctx) { public LNode visitOutput(OutputContext ctx) { OutputNode node; if (ctx.evaluate != null) { - node = new OutputNode(visit(ctx.expr()), null, null); + node = new OutputNode(visit(ctx.expr()), null, null, null); } else { String unparsed = null; + Integer unparsedLine = null; Integer unparsedStart = null; if (ctx.unparsed != null) { unparsed = ctx.unparsed.getText(); - unparsedStart = ctx.unparsed.getStart().getStartIndex(); + unparsedLine = ctx.unparsed.getStart().getLine(); + unparsedStart = ctx.unparsed.getStart().getCharPositionInLine(); } - node = new OutputNode(visit(ctx.term()), unparsed, unparsedStart); + node = new OutputNode(visit(ctx.term()), unparsed, unparsedLine, unparsedStart); } for (FilterContext child : ctx.filter()) { diff --git a/src/test/java/liqp/nodes/GtNodeTest.java b/src/test/java/liqp/nodes/GtNodeTest.java index 8c0b20fb..40a4b837 100644 --- a/src/test/java/liqp/nodes/GtNodeTest.java +++ b/src/test/java/liqp/nodes/GtNodeTest.java @@ -3,6 +3,8 @@ import static junit.framework.TestCase.assertEquals; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.time.Instant; import java.time.LocalDateTime; @@ -10,8 +12,11 @@ import java.time.ZonedDateTime; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; +import liqp.exceptions.LiquidException; +import liqp.parser.Flavor; import org.antlr.v4.runtime.RecognitionException; import org.junit.Test; @@ -80,4 +85,31 @@ public void testComparableTypes() { value = TemplateParser.DEFAULT.parse("{% if a >= c %}yes{% else %}no{% endif %}").render(data); assertEquals("no", value); } + + @Test + public void testBug267AsLiquid() { + try { + new TemplateParser.Builder().withFlavor(Flavor.LIQUID).build().parse("{{ 98 > 97 }}").render(); + fail(); + } catch (LiquidException e) { + assertTrue(e.getMessage().contains("parser error")); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testBug267AsJekyll() { + Template.ContextHolder contextHolder = new Template.ContextHolder(); + String res = new TemplateParser.Builder() + .withFlavor(Flavor.JEKYLL) + .build() + .parse("{{ 98 > 97 }}") + .withContextHolder(contextHolder) + .render(); + assertEquals("98", res); + List errors = contextHolder.getContext().errors(); + assertEquals(1, errors.size()); + assertTrue(errors.get(0).getMessage().contains("unexpected output")); + } }