Giter Club home page Giter Club logo

liqp's People

Contributors

bkiers avatar bmateusz avatar buwi avatar dependabot[bot] avatar github-actions[bot] avatar hartfelt avatar honglooker avatar jamesattentive avatar jd557 avatar jlitola avatar jvanzyl avatar kohlschuetter avatar mbaumbach avatar mosabua avatar msangel avatar pmenhart avatar ryfow avatar scott-seguno avatar sebastianopilla avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

liqp's Issues

Include tag preserving the flavor

Hi, in the develop branch the IncludeTag uses the Template.parse method without preserving the Flavor.JEKYLL, so if you use recursive includes the flavor will flip.

Also, will you merge the develop branch to master?

Allow escaping quotes in assign tags

Parsing a template with an escaped quote in an assign tag fails. So the following template does not work.

{% assign test = "f\"oo" %} Test: {{test}}

I have tested with the following java code:

Template.parse("{% assign test = \"f\\\"oo\" %} Test: {{test}}");

I would expect it to be possible to escape quotes in the assign tag. Please let me know if I have misunderstood something or you need more information.

Feature Question

First of all, love the library.

In our use case, we have a two-pass rendering. The first pass has a certain set of models, and the second pass has a different set. All the other filters are the same, but I could foresee a setup that used different filters based on the rendering mode.

What would be awesome is if we could tell the renderer/parser which items should be purposely ignored. If the parser encountered these items, it would leave those liquid expression in place.

Is this possible today? And could this be done without introducing a lot of complexity?

Round.java default is HALF_EVEN

Hi.
The "round" filter (Round.java) uses the default rounding in DecimalFormat.class which is HALF_EVEN.
I believe that HALF_UP may be the correct, but I have no data/reference to back this up.
HALF_UP rounds all numbers up when the decimal is higher or equal to .5, whereas HALF_EVEN rounds to the nearest neighbour (as do HALF_UP), but when equal distance to the neighbour, it rounds to the value that is even. So 10.5 becomes 10, and 11.5 becomes 12.
At least in Denmark the default rounding is always to round upwards when reached .5 in decimal.

Test \r\n in WhitespaceControlTest.java

Although with the current version that always removes all whitespaces it might not be a problem, for correctness, I think it would be better to also test Windows specific cases too.

This means doubling all tests that use \n with similar ones using \r\n.

In my fork that removes only one line terminator, the test file looks like this:

The adjusted parser that passes these tests is:

Setting locale

I'd like to somehow specify the locale which is used by the date filter.

In Date there is a function setLocale(), which is not in use. Also, as Date isn't public, I can't call the function myself.

Template.render() leaving Executor threads active

Template.render() method is creating a separate thread which is not getting closed explicitly. Method should ideally call executorService.shutdown() explicitly to properly close the thread.

Not closing threads explicitly is causing multiple threads to be alive in the system and causes problems at the time of closing the process.

0.7.6

@mosabua could you once again cut a new release to Maven Central from when you have the time? master is ready for a new release.

Tree parsing question

I have some custom formatting tags that I'm working with, that would look something like this

{%red%}{%bold%}This is red, and {%yellow%} this is yellow{%endyellow%}{%endbold%}{%endred%}

This is the tree that's generated, which seems off to me, but I'm wondering if I'm not understanding something. Specifically, I'm wondering why the "yellow" atom was embedded in the {%yellow%} tag, but the green atom wasn't.

'- Parse
   |- Block
   |  |- Atom_tag
   |  |  '- Tag
   |  |     '- Other_tag
   |  |        |- TagStart
   |  |        |  '- TerminalNodeImpl='{%'
   |  |        |- TerminalNodeImpl='red'
   |  |        |- TerminalNodeImpl='%}'
   |  |        '- Other_tag_block
   |  |           |- Atom_tag
   |  |           |  '- Tag
   |  |           |     '- Other_tag
   |  |           |        |- TagStart
   |  |           |        |  '- TerminalNodeImpl='{%'
   |  |           |        |- TerminalNodeImpl='bold'
   |  |           |        |- TerminalNodeImpl='%}'
   |  |           |        '- Other_tag_block
   |  |           |           |- Atom_others
   |  |           |           |  '- Other
   |  |           |           |     |- TerminalNodeImpl='R'
   |  |           |           |     |- TerminalNodeImpl='e'
   |  |           |           |     |- TerminalNodeImpl='d'
   |  |           |           |     |- TerminalNodeImpl=' '
   |  |           |           |     |- TerminalNodeImpl='a'
   |  |           |           |     |- TerminalNodeImpl='n'
   |  |           |           |     |- TerminalNodeImpl='d'
   |  |           |           |     '- TerminalNodeImpl=' '
   |  |           |           |- Atom_tag
   |  |           |           |  '- Tag
   |  |           |           |     '- Other_tag
   |  |           |           |        |- TagStart
   |  |           |           |        |  '- TerminalNodeImpl='{%'
   |  |           |           |        |- TerminalNodeImpl='yellow'
   |  |           |           |        |- TerminalNodeImpl='%}'
   |  |           |           |        '- Other_tag_block
   |  |           |           |           |- Atom_others
   |  |           |           |           |  '- Other
   |  |           |           |           |     |- TerminalNodeImpl='y'
   |  |           |           |           |     |- TerminalNodeImpl='e'
   |  |           |           |           |     |- TerminalNodeImpl='l'
   |  |           |           |           |     |- TerminalNodeImpl='l'
   |  |           |           |           |     |- TerminalNodeImpl='o'
   |  |           |           |           |     '- TerminalNodeImpl='w'
   |  |           |           |           |- TagStart
   |  |           |           |           |  '- TerminalNodeImpl='{%'
   |  |           |           |           |- TerminalNodeImpl='endyellow'
   |  |           |           |           '- TerminalNodeImpl='%}'
   |  |           |           |- Atom_others
   |  |           |           |  '- Other
   |  |           |           |     |- TerminalNodeImpl=' '
   |  |           |           |     |- TerminalNodeImpl='a'
   |  |           |           |     |- TerminalNodeImpl='n'
   |  |           |           |     |- TerminalNodeImpl='d'
   |  |           |           |     '- TerminalNodeImpl=' '
   |  |           |           |- Atom_tag
   |  |           |           |  '- Tag
   |  |           |           |     '- Other_tag
   |  |           |           |        |- TagStart
   |  |           |           |        |  '- TerminalNodeImpl='{%'
   |  |           |           |        |- TerminalNodeImpl='green'
   |  |           |           |        '- TerminalNodeImpl='%}'
   |  |           |           |- Atom_others
   |  |           |           |  '- Other
   |  |           |           |     |- TerminalNodeImpl='g'
   |  |           |           |     |- TerminalNodeImpl='r'
   |  |           |           |     |- TerminalNodeImpl='e'
   |  |           |           |     |- TerminalNodeImpl='e'
   |  |           |           |     '- TerminalNodeImpl='n'
   |  |           |           |- TagStart
   |  |           |           |  '- TerminalNodeImpl='{%'
   |  |           |           |- TerminalNodeImpl='endgreen'
   |  |           |           '- TerminalNodeImpl='%}'
   |  |           |- TagStart
   |  |           |  '- TerminalNodeImpl='{%'
   |  |           |- TerminalNodeImpl='endbold'
   |  |           '- TerminalNodeImpl='%}'
   |  '- Atom_tag
   |     '- Tag
   |        '- Other_tag
   |           |- TagStart
   |           |  '- TerminalNodeImpl='{%'
   |           |- TerminalNodeImpl='red'
   |           '- TerminalNodeImpl='%}'
   '- TerminalNodeImpl='<EOF>'

Allow variables with the include tag

We have a layout that works in Jekyll where there is an include that uses a variable defined in the front-matter to select which navigation to include. Here's an example:

---                                                                                                                                                                             
layout: default                                                                                                                                                             
---                                                                                                                                                                             
<div class="row margin-bottom-50">                                                                                                                                                                                                                                                                                                                              
  {% include {{page.side-navigation}} %}                                                                                                                                                                                                                                                                                                                        
</div>

Seems like the ANTRL grammar needs to be altered to allow {{XXX}}, and do a variable lookup in the include tag.

0.7.5 release

@mosabua could you cut a new release to Maven Central from master when you have the time?

Support `default` filter when `strictVariables` is enabled

Currently {{x | default: 1}} will fail if the strictVariables setting is enabled. I'm not sure if this is the intended behavior, since the template should work as expected when x is undefined.

It might be a PITA to refactor the code to support this, though.

What's your opinion on this?

Assign tag only allows one filter

The following code throws an exception parsing the template:

Template template = Template.parse("{% assign v = 1 | minus: 1 | plus: 1 %}");

The exception is:

MismatchedTokenException(85!=95)
        at liqp.parser.LiquidParser.reportError(LiquidParser.java:182)
        at liqp.parser.LiquidParser.assignment(LiquidParser.java:5187)
        at liqp.parser.LiquidParser.atom(LiquidParser.java:478)
        at liqp.parser.LiquidParser.block(LiquidParser.java:307)
        at liqp.parser.LiquidParser.parse(LiquidParser.java:213)
        at liqp.Template.<init>(Template.java:78)
        at liqp.Template.parse(Template.java:127)
Caused by: MismatchedTokenException(85!=95)
        at org.antlr.runtime.BaseRecognizer.recoverFromMismatchedToken(BaseRecognizer.java:617)
        at org.antlr.runtime.BaseRecognizer.match(BaseRecognizer.java:115)
        at liqp.parser.LiquidParser.assignment(LiquidParser.java:5139)

This template does parse with the Ruby version of Liquid.

A simple workaround is to use multiple assign statements for every filter you want to apply.

I'm not super familiar with ANTLR, but I assume the following assignment definition would fix the problem:

assignment
 : tagStart Assign Id EqSign expr filter? TagEnd
 ;
assignment
 : tagStart Assign Id EqSign expr filter* TagEnd
 ;

Thanks for the great library, the ANTLRv4 version is a great improvement too!

Suggestion: Reserve Java module name

I'm not sure what the effort is to adopt this library to the Java module system, but in doing this with my own work, I've found it's good to follow this advice and reserve a module name before even moving a library to be modular. This is as simple as modifying the main pom.xml:

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.0.2</version>
        <configuration>
          <archive>
            <manifest>
              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
            </manifest>
            <manifestEntries>
              <Automatic-Module-Name>liqp</Automatic-Module-Name>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>

This allows consumers using Java 9+ modules to depend on this library before it even adopts modules without concern that the module name will change.

I originally thought nl.big-o.liqp would be good a module name, but the hyphen is an invalid character in module names. Also, using just liqp would mean that if anybody is already using this library in Java 9 as an automatic module, they wouldn't break should you decide to add this change.

I'm also glad to help modularize the library if you need any assistance. This library has been great for me, so always happy to contribute back. 👍

0.7.4 performance

The latest release seems slower, I benchmarked with our project:
0.7.2: 20.49 secs
0.7.3: 21.162 secs
0.7.4: 48.954 secs

Anyone else experienced this? We don't use any advanced features.

Template.parse performance when lots of custom tags are in the content

We implemented a custom tag "snippet" to allow users to define reusable chunks of HTML. Works like a charm... Until there are > 20 tags present in the same content. Then it starts to drastically slow down the more tags are present.

Wrote the following unit test to demonstrate:

@Test
public void testCustomTags() {
    final StopWatch stopWatch = new StopWatch();

    for (int n=0; n<30; n++) {
        final String content = StringUtils.repeat("{% snippet \"face\" %}", n);

        stopWatch.start();
        Template.parse(content);
        stopWatch.stop();
        LOG.debug("{} tags -> {} milliseconds", n, stopWatch.getTime());
        stopWatch.reset();
    }
}

Here is some sample output when using custom tags:

1 tags -> 0 milliseconds
2 tags -> 0 milliseconds
3 tags -> 0 milliseconds
4 tags -> 0 milliseconds
5 tags -> 1 milliseconds
6 tags -> 6 milliseconds
7 tags -> 1 milliseconds
8 tags -> 2 milliseconds
9 tags -> 4 milliseconds
10 tags -> 6 milliseconds
11 tags -> 9 milliseconds
12 tags -> 11 milliseconds
13 tags -> 11 milliseconds
14 tags -> 17 milliseconds
15 tags -> 33 milliseconds
16 tags -> 61 milliseconds
17 tags -> 79 milliseconds
18 tags -> 134 milliseconds
19 tags -> 230 milliseconds
20 tags -> 464 milliseconds
21 tags -> 887 milliseconds
22 tags -> 1727 milliseconds
23 tags -> 3393 milliseconds
24 tags -> 6865 milliseconds
25 tags -> 13781 milliseconds
26 tags -> 28804 milliseconds
27 tags -> 56767 milliseconds

Fortunately, standard tags do not have the same problem. Wrote the following unit test to demonstrate:

@Test
public void testStandardTags() {
    final StopWatch stopWatch = new StopWatch();

    for (int n=0; n<30; n++) {
        final String content = StringUtils.repeat("{% if data.face == \"happy\" %}{% endif %}", n);

        stopWatch.start();
        Template.parse(content);
        stopWatch.stop();
        LOG.debug("{} tags -> {} milliseconds", n * 2, stopWatch.getTime());
        stopWatch.reset();
    }
}

And here is some sample output when using standard tags:

2 tags -> 1 milliseconds
4 tags -> 0 milliseconds
6 tags -> 0 milliseconds
8 tags -> 6 milliseconds
10 tags -> 1 milliseconds
12 tags -> 1 milliseconds
14 tags -> 1 milliseconds
16 tags -> 1 milliseconds
18 tags -> 1 milliseconds
20 tags -> 1 milliseconds
22 tags -> 1 milliseconds
24 tags -> 1 milliseconds
26 tags -> 1 milliseconds
28 tags -> 2 milliseconds
30 tags -> 2 milliseconds
32 tags -> 1 milliseconds
34 tags -> 1 milliseconds
36 tags -> 1 milliseconds
38 tags -> 1 milliseconds
40 tags -> 1 milliseconds
42 tags -> 1 milliseconds
44 tags -> 1 milliseconds
46 tags -> 1 milliseconds
48 tags -> 1 milliseconds
50 tags -> 1 milliseconds
52 tags -> 1 milliseconds
54 tags -> 1 milliseconds

Template parsing context?

I am checking out this library trying to call it directly from clojure. I noticed a that there is scope leaked into the parsing of a template for example parsing a template with a java keyword will result in something like:

(liqp.Template/parse "%{{case}}")
NoViableAltException   liqp.parser.LiquidParser.term (LiquidParser.java:5469)
java.lang.RuntimeException: NoViableAltException(21@[])
    at liqp.parser.LiquidParser.reportError(LiquidParser.java:163)
    at liqp.parser.LiquidParser.term(LiquidParser.java:5688)
    at liqp.parser.LiquidParser.rel_expr(LiquidParser.java:5307)
    at liqp.parser.LiquidParser.eq_expr(LiquidParser.java:5211)
    at liqp.parser.LiquidParser.contains_expr(LiquidParser.java:5128)
    at liqp.parser.LiquidParser.and_expr(LiquidParser.java:5039)
    at liqp.parser.LiquidParser.or_expr(LiquidParser.java:4950)
    at liqp.parser.LiquidParser.expr(LiquidParser.java:4894)
    at liqp.parser.LiquidParser.output(LiquidParser.java:4400)
    at liqp.parser.LiquidParser.atom(LiquidParser.java:445)
    at liqp.parser.LiquidParser.block(LiquidParser.java:288)
    at liqp.parser.LiquidParser.parse(LiquidParser.java:194)
    at liqp.Template.<init>(Template.java:65)
    at liqp.Template.parse(Template.java:111)
    at user$eval12727.invokeStatic(form-init1027659148715222265.clj:1)
    at user$eval12727.invoke(form-init1027659148715222265.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6927)
    at clojure.lang.Compiler.eval(Compiler.java:6890)
    at clojure.core$eval.invokeStatic(core.clj:3105)
    at clojure.core$eval.invoke(core.clj:3101)
    at clojure.main$repl$read_eval_print__7408$fn__7411.invoke(main.clj:240)
    at clojure.main$repl$read_eval_print__7408.invoke(main.clj:240)
    at clojure.main$repl$fn__7417.invoke(main.clj:258)
    at clojure.main$repl.invokeStatic(main.clj:258)
    at clojure.main$repl.doInvoke(main.clj:174)
    at clojure.lang.RestFn.invoke(RestFn.java:1523)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__12023.invoke(interruptible_eval.clj:87)
    at clojure.lang.AFn.applyToHelper(AFn.java:152)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invokeStatic(core.clj:646)
    at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1881)
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1881)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:85)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:55)
    at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__12068$fn__12071.invoke(interruptible_eval.clj:222)
    at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__12063.invoke(interruptible_eval.clj:190)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: NoViableAltException(21@[])
    at liqp.parser.LiquidParser.term(LiquidParser.java:5469)
    ... 39 more

I cant really trace this because the parser code seems to be generated so I was wondering if you had any idea what is going on. I cannot think that this would be safe to use without a way to it exploding on templates with legit var names like case

Comment blocks fail to parse if start or end tag is found inside

Based on the definition of a Comment tag, it appears that anything between a {% comment %} and {% endcomment %} should simply be omitted from the output:

Allows you to leave un-rendered code inside a Liquid template. Any text within the opening and closing comment blocks will not be output, and any Liquid code within will not be executed.

However, the following code fails to parse:

{% comment %}
    {% if true %}
        hello
    {% endif %}
{% endcomment %}

The exception generated:

at liquid.parser.v4.LiquidParser.comment_tag(LiquidParser.java:847)
        at liquid.parser.v4.LiquidParser.tag(LiquidParser.java:443)
        at liquid.parser.v4.LiquidParser.atom(LiquidParser.java:332)
        at liquid.parser.v4.LiquidParser.block(LiquidParser.java:211)
        at liquid.parser.v4.LiquidParser.parse(LiquidParser.java:154)
        at liqp.Template.parse(Template.java:138)
        at liqp.Template.<init>(Template.java:77)

I think the problem is the comment_body definition in LiquidParser.g4:

comment_tag
 : tagStart CommentStart TagEnd comment_body tagStart CommentEnd TagEnd
 ;

comment_body
 : other_than_tag_start
 ;

other_than_tag_start
 : ~( TagStart | TagStart2 )*
 ;

I would think this might be the correct definition:

comment_tag
 : tagStart CommentStart TagEnd other? tagStart CommentEnd TagEnd
 ;

I don't know enough about ANTLR to be confident in that answer though. 😂

Support Jekyll-like include tag

Ultimately where I'm trying to get is to have the equivalent of:

https://jekyllrb.com/docs/templates/#includes

In my implementation of Jekyll using Liqp I only needed to support the Jekyll case and not the general case which is what Jekyll does overriding the standard include tag. I had to change your grammar slightly which allows me to use standard Jekyll in Ruby and my Java implementation which is super handy. But I'm not sure if this will break your standard use case. Jekyll allows things like:

{% include header.html %}

Where you don't need quotes around the included resource.

I'm happy to implement a way to selectively register tags with the default behaviour as it currently is. I can also make the include grammar bits more flexible. But I do need to change the grammar to support the Jekyll style. I can do whatever you prefer.

NoViableAlt thrown when assign tag has another tag name in it

When an assign tag tries to assign a value from an object, but the name of the objects property matches the name of another liquid tag, a NoViableAltException is thrown.

Easy to replicate with the following AssignTag test case

    @Test
    public void assignTestWithOtherTagName() throws Exception {

        assertThat(
                Template.parse("var2:{{var2}} {%assign var2 = var.comment%} var2:{{var2}}")
                        .render(" { \"var\": { \"comment\": \"content\" } } "),
                is("var2:  var2:content"));

        assertThat(
                Template.parse("var2:{{var2}} {%assign var2 = var.end%} var2:{{var2}}")
                        .render(" { \"var\": { \"end\": \"content\" } } "),
                is("var2:  var2:content"));
    }

Presumably some form of escaping needs to happen to not treat that value as a tag? Or maybe its something else entirely?

Parse Exception

{{ 'general.meta.tags' | t: tags: meta_tags }}

Seeing exceptions on any tags with that t: tags: meta_tags sorta structure.

Any ideas?

Some of the older filters are not public classes

Some of the older filters are not public classes - this means that we cannot use them for testing, nor extend their functionality.
In our case, we have a String-like class (called "SafeString"), which sometimes is used and passed into the filters. We'd like to accommodate for this by extending some of the currently non-public filter classes by extracting the "non-safe" (and original String.class) value (mySafeString.getRaw() -> String.class) and pass it further down to a parent filter.

public class OurSlizeFilter extends Slice {
	@Override
	public final Object apply(Object value, Object... params) {
		if(value instanceof SafeString){
			super.apply(((SafeString) value).getRaw(), params);
		} else {
			super.apply(value, params);
		}
	}
 [...]

But currently above is not possible.

Non-public classes are:

  • Append.java
  • Capitalize.java
  • Divided_By.java
  • Downcase.java
  • Escape.java
  • Escape_Once.java
  • First.java
  • H.java
  • Join.java
  • Last.java
  • Map.java
  • Minus.java
  • Modulo.java
  • Newline_To_Br.java
  • Plus.java
  • Prepend.java
  • Remove.java
  • Remove_First.java
  • Replace.java
  • Replace_First.java
  • Size.java
  • Sort.java
  • Split.java
  • Strip_HTML.java
  • Strip_Newlines.java
  • Times.java
  • Truncate.java
  • Truncatewords.java
  • Upcase.java

Grammars are in two locations

I forked this project a long while back to add support for a Java implementation of Jekyll, and I'm trying to sync up my changes but you have the ANTRL grammars in duplicated in two places. Is IDEA using them in a different place than the Maven plugin? Just wanted to check before making pull requests as I have grammar changes and don't want to alter the wrong set.

[Question]Is it possible to implement a Django-like block inheritance?

I've seen this gem for the official Liquid engine in Ruby https://github.com/danwrong/liquid-inheritance which provides such functionality. I would like to implement it in this library. Is that possible?

I think it is possible but I'm not sure. To implement this we need 2 new tags: extends and block. The block tag will be just a custom block to mark inheritable blocks and provide the ability to call the parent block (we also would need to support the {{ block.super }} syntax somehow. Maybe by injecting a special variable in the context). With the extends tag we need to parse the parent template, render any content outside of an inheritable block, and inject the inheritable blocks in the current template.

I think that just using Tag.registerTag() with the mentioned new tags will not be enough. Probably we would need to change something else in the codebase.

Includes with path characters appear invalid

Exception in thread "main" java.lang.RuntimeException: could not parse input: {% include wmt/html-head.html %}

{% include wmt/header.html %}
{{content}}

{% include wmt/footer.html %}

I took a cursory look at the grammar and appears that allowing the '/' in there would fix this?

Make Include tag Jekyll friendly

One of the additions I made in my fork was to create an IncludeJekyll tag that took the source directory of the includes from the context and didn't assume a default extension.

Would you mind a pull request that uses a source directory for the includes if one is provided in the context and uses the included resources name as-is if it has an extension? I will preserve the existing behaviour of using the snippets directory if a source directory is not provided and defaulting to the .liquid extension for included resources if one isn't provided.

capture tag always evaluates to a string

The contents inside a capture tag is evaluated as a block, causing it to become a string. But the following:

{% capture n %}{{ username | size }}{% endcapture %}

should be captured as a number.

Accessing dot notation if a Map is passed to render.

A peculiar issue here. I see that there is #66 on a similar topic. However, I want to pass in a Map<String,Object> instead, as there might be plenty of variables I want to access.. In this case, using dot notation does not work for me.

Example:

-snip-
public static Site site;
	
	public String buildPage(Request request, Response response) throws SQLException, ClassNotFoundException {
		Page build_target = Page.get(request.pathInfo(), site.id);
		
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("site", site);
		
		Template template;
		
		try {
			template = Template.parse(new File("sites/"+site.id+"/templates/"+build_target.template+".liquid"));
			return template.render(params);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return "Template rendering failed";
	}
-snip-

When I then try doing {{site.name}} in the template, I get out nothing. Doing {{site}} gives me the string representation of the Site object.

Breadcrumb related parsing problems

I have a include file in Jekyll that add breadcrumbs which looks like this

{% assign crumbs = page.url | split: '/' %}
<div style="font-size: 12px;">
  <p><a href="/">Home</a> >
  {% for crumb in crumbs offset: 1 %}
    {% if forloop.last %}
      <span style="font-weight: bold;">{{ page.title }}</span>
    {% else %}
      <a href="{% assign crumb_limit = forloop.index | plus: 1 %}{% for crumb in crumbs limit: crumb_limit %}{{ crumb | append: '/' }}{% endfor %}"
        style="text-transform: capitalize"
      >{{ crumb | replace:'-',' '}}</a> > 
    {% endif %}
  {% endfor %}</p>
</div>

This works fine with Jekyll 3.3.1. When using my liqp based parsing in a java jekyll impl the order of the crumbs is messed up. E.g. instead of

Home > Docs > Getting Started > Getting Started

I get

Home > Getting Started > /Docs >

Any idea where to start looking to figure out where the problem is?

Better whitespace processing proposal

Whitespace processing was always tricky in template engines, and the Shopify Liquid makes no exception.

The specifications (https://shopify.github.io/liquid/basics/whitespace/) mention that adding hyphen in the tag syntax will strip whitespace, but it does not give more details.

The first approach to this rule is to strip as many whitespaces (spaces, tabs, CR, LF) as possible.

Unfortunately this behaviour is too greedy, and makes impossible to generate some content (for example conditional lines that need to preserve empty lines at the end or at the beginning).

In my opinion, after working with various template engines, striping should not go past the next line terminator, i.e. it should not eat previous/following empty lines.

I made a fork of the project and experimented with different strategies. The one I ended with was to alter the behaviour when the stripSpacesAroundTags option is enabled; the new behaviour is:

  • strip only spaces and tabs before the tags
  • strip spaces, tabs and maximum one line terminator after the tags

When explicit hyphens are used, the behaviour is the one you implemented, i.e. a very greedy strip of all whitespaces.

My commit with these changes is eclipse-embed-cdt@98ef5b2

An actual template file using this new configuration is https://github.com/gnu-mcu-eclipse/eclipse-plugins/blob/templates/bundles/ilg.gnumcueclipse.templates.sifive/templates/sifive_exe_c_project/src/main-liquid.c.cpp

As you can see, there are no explicit hyphens, and the syntax is natural, and the empty lines are passed as expected.

Releases to Maven Central

I'm happy to coordinate and do releases to Maven Central if you don't have time. I'm about to do a first release of my Jekyll-clone and I'd like to get Liqp into Maven Central so Idiom will build. Thanks.

Protection against malicious users

I'm planning of using Liqp for a user-facing app where users can create templates and I've been thinking about security and I couldn't really see how the following cases are handled in the codebase:

  1. Limiting of the maximum number of iterations per render run (i.e. don't allow a malicious user to loop infinitely or create very long loops)
  2. Having a circuit breaker for how large of a template output can be rendered. (i.e. don't create a massive string)
  3. Having a timeout on how long should template generation take

Also, are there any other scenarios that I left out?

Allow expressions as custom tag parameters

In liqp 0.6 it was possible to use a custom tag foo like this:

{% foo a.b.c %}

But since #46 the parameter is always parsed as the string "a.b.c", and there seems to be no built-in way to parse and evaluate the expression in this string. The following does not work either (parsing fails with a NoViableAltException):

{% foo {{ a.b.c }} %}

Is there an alternative to this? The documentation generator of the next-gen Scala compiler currently relies on this: scala/scala3#3859

0.7.4 has many more dependencies than 0.7.3

Maybe some build/test dependencies are accidentally being included in compile scope? This has implications for dependency convergence, especially for people on newer versions of maven.

tree generated using mvn dependency:tree

0.7.3 tree:

[INFO] +- nl.big-o:liqp:jar:0.7.3:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-core:jar:2.9.6:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.6:compile
[INFO] |  \- org.jsoup:jsoup:jar:1.10.3:compile

0.7.4 tree:

[INFO] +- nl.big-o:liqp:jar:0.7.4:compile
[INFO] |  +- org.antlr:antlr4-runtime:jar:4.7.1:compile
[INFO] |  +- org.antlr:antlr4-maven-plugin:jar:4.7.1:compile
[INFO] |  |  +- org.apache.maven:maven-plugin-api:jar:3.0.5:compile
[INFO] |  |  |  +- org.apache.maven:maven-model:jar:3.0.5:compile
[INFO] |  |  |  +- org.apache.maven:maven-artifact:jar:3.0.5:compile
[INFO] |  |  |  \- org.sonatype.sisu:sisu-inject-plexus:jar:2.3.0:compile
[INFO] |  |  |     +- org.codehaus.plexus:plexus-component-annotations:jar:1.5.5:compile
[INFO] |  |  |     +- org.codehaus.plexus:plexus-classworlds:jar:2.4:compile
[INFO] |  |  |     \- org.sonatype.sisu:sisu-inject-bean:jar:2.3.0:compile
[INFO] |  |  |        \- org.sonatype.sisu:sisu-guice:jar:no_aop:3.1.0:compile
[INFO] |  |  |           \- org.sonatype.sisu:sisu-guava:jar:0.9.9:compile
[INFO] |  |  +- org.codehaus.plexus:plexus-compiler-api:jar:2.2:compile
[INFO] |  |  |  \- org.codehaus.plexus:plexus-utils:jar:3.0.8:compile
[INFO] |  |  +- org.sonatype.plexus:plexus-build-api:jar:0.0.7:compile
[INFO] |  |  +- org.antlr:antlr4:jar:4.7.1:compile
[INFO] |  |  |  +- org.abego.treelayout:org.abego.treelayout.core:jar:1.0.3:compile
[INFO] |  |  |  +- org.glassfish:javax.json:jar:1.0.4:compile
[INFO] |  |  |  \- com.ibm.icu:icu4j:jar:58.2:compile
[INFO] |  |  \- org.apache.maven:maven-project:jar:2.2.1:compile
[INFO] |  |     +- org.apache.maven:maven-settings:jar:2.2.1:compile
[INFO] |  |     +- org.apache.maven:maven-profile:jar:2.2.1:compile
[INFO] |  |     +- org.apache.maven:maven-artifact-manager:jar:2.2.1:compile
[INFO] |  |     |  +- org.apache.maven:maven-repository-metadata:jar:2.2.1:compile
[INFO] |  |     |  +- org.apache.maven.wagon:wagon-provider-api:jar:1.0-beta-6:compile
[INFO] |  |     |  \- backport-util-concurrent:backport-util-concurrent:jar:3.1:compile
[INFO] |  |     +- org.apache.maven:maven-plugin-registry:jar:2.2.1:compile
[INFO] |  |     +- org.codehaus.plexus:plexus-interpolation:jar:1.11:compile
[INFO] |  |     \- org.codehaus.plexus:plexus-container-default:jar:1.0-alpha-9-stable-1:compile
[INFO] |  |        +- junit:junit:jar:4.12:compile
[INFO] |  |        |  \- org.hamcrest:hamcrest-core:jar:1.3:compile
[INFO] |  |        \- classworlds:classworlds:jar:1.1-alpha-2:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-core:jar:2.9.6:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.6:compile
[INFO] |  \- org.jsoup:jsoup:jar:1.10.3:compile

Does dotted attribute notation work when using actual objects instead of JSON?

We're trying to directly put an object into the render context like this:

template.render("some_top_level_name", someComplexObject);

And in the actual template, we can access the root object via {{ some_top_level_name }} but not any of its attributes, like {{ some_top_level_name.snake_case_attribute }} or {{ some_top_level_name.camelCaseAttribute }}

Does this work? Are we doing it wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.