Giter VIP home page Giter VIP logo

jade4j's Introduction

Build Status

Attention: jade4j is now pug4j

In alignment with the javascript template engine we renamed jade4j to pug4j. You will find it under https://github.com/neuland/pug4j This is also a new release which supports almost the entire pug 2 syntax.

Please report pug4j issues in the new repository.

jade4j - a jade implementation written in Java

jade4j's intention is to be able to process jade templates in Java without the need of a JavaScript environment, while being fully compatible with the original jade syntax.

Contents

Example

index.jade

doctype html
html
  head
    title= pageName
  body
    ol#books
      for book in books
        if book.available
          li #{book.name} for #{book.price} €

Java model

List<Book> books = new ArrayList<Book>();
books.add(new Book("The Hitchhiker's Guide to the Galaxy", 5.70, true));
books.add(new Book("Life, the Universe and Everything", 5.60, false));
books.add(new Book("The Restaurant at the End of the Universe", 5.40, true));

Map<String, Object> model = new HashMap<String, Object>();
model.put("books", books);
model.put("pageName", "My Bookshelf");

Running the above code through String html = Jade4J.render("./index.jade", model) will result in the following output:

<!DOCTYPE html>
<html>
  <head>
    <title>My Bookshelf</title>
  </head>
  <body>
    <ol id="books">
      <li>The Hitchhiker's Guide to the Galaxy for 5,70 €</li>
      <li>The Restaurant at the End of the Universe for 5,40 €</li>
    </ol>
  </body>
</html>

Syntax

We have put up an interactive jade documentation.

See also the original visionmedia/jade documentation.

Usage

via Maven

As of release 0.4.1, we have changed maven hosting to sonatype. Using Github Maven Repository is no longer required.

Please be aware that we had to change the group id from 'de.neuland' to 'de.neuland-bfi' in order to meet sonatype conventions for group naming.

Just add following dependency definitions to your pom.xml.

<dependency>
  <groupId>de.neuland-bfi</groupId>
  <artifactId>jade4j</artifactId>
  <version>1.3.2</version>
</dependency>

Build it yourself

Clone this repository ...

git clone https://github.com/neuland/jade4j.git

... build it using maven ...

cd jade4j
mvn install

... and use the jade4j-1.x.x.jar located in your target directory.

Simple static API

Parsing template and generating template in one step.

String html = Jade4J.render("./index.jade", model);

If you use this in production you would probably do the template parsing only once per template and call the render method with different models.

JadeTemplate template = Jade4J.getTemplate("./index.jade");
String html = Jade4J.render(template, model);

Streaming output using a java.io.Writer

Jade4J.render(template, model, writer);

Full API

If you need more control you can instantiate a JadeConfiguration object.

JadeConfiguration config = new JadeConfiguration();

JadeTemplate template = config.getTemplate("index");

Map<String, Object> model = new HashMap<String, Object>();
model.put("company", "neuland");

config.renderTemplate(template, model);

Caching

The JadeConfiguration handles template caching for you. If you request the same unmodified template twice you'll get the same instance and avoid unnecessary parsing.

JadeTemplate t1 = config.getTemplate("index.jade");
JadeTemplate t2 = config.getTemplate("index.jade");
t1.equals(t2) // true

You can clear the template and expression cache by calling the following:

config.clearCache();

For development mode, you can also disable caching completely:

config.setCaching(false);

Output Formatting

By default, Jade4J produces compressed HTML without unneeded whitespace. You can change this behaviour by enabling PrettyPrint:

config.setPrettyPrint(true);

Jade detects if it has to generate (X)HTML or XML code by your specified doctype.

If you are rendering partial templates that don't include a doctype jade4j generates HTML code. You can also set the mode manually:

config.setMode(Jade4J.Mode.HTML);   // <input checked>
config.setMode(Jade4J.Mode.XHTML);  // <input checked="true" />
config.setMode(Jade4J.Mode.XML);    // <input checked="true"></input>

Filters

Filters allow embedding content like markdown or coffeescript into your jade template:

script
  :coffeescript
    sayHello -> alert "hello world"

will generate

<script>
  sayHello(function() {
    return alert("hello world");
  });
</script>

jade4j comes with a plain and cdata filter. plain takes your input to pass it directly through, cdata wraps your content in <![CDATA[...]]>. You can add your custom filters to your configuration.

config.setFilter("coffeescript", new CoffeeScriptFilter());

To implement your own filter, you have to implement the Filter Interface. If your filter doesn't use any data from the model you can inherit from the abstract CachingFilter and also get caching for free. See the neuland/jade4j-coffeescript-filter project as an example.

Helpers

If you need to call custom java functions the easiest way is to create helper classes and put an instance into the model.

public class MathHelper {
    public long round(double number) {
        return Math.round(number);
    }
}
model.put("math", new MathHelper());

Note: Helpers don't have their own namespace, so you have to be careful not to overwrite them with other variables.

p= math.round(1.44)

Model Defaults

If you are using multiple templates you might have the need for a set of default objects that are available in all templates.

Map<String, Object> defaults = new HashMap<String, Object>();
defaults.put("city", "Bremen");
defaults.put("country", "Germany");
defaults.put("url", new MyUrlHelper());
config.setSharedVariables(defaults);

Template Loader

By default, jade4j searches for template files in your work directory. By specifying your own FileTemplateLoader, you can alter that behavior. You can also implement the TemplateLoader interface to create your own.

TemplateLoader loader = new FileTemplateLoader("/templates/", "UTF-8");
config.setTemplateLoader(loader);

Expressions

The original jade implementation uses JavaScript for expression handling in if, unless, for, case commands, like this

- var book = {"price": 4.99, "title": "The Book"}
if book.price < 5.50 && !book.soldOut
  p.sale special offer: #{book.title}

each author in ["artur", "stefan", "michael"]
  h2= author

As of version 0.3.0, jade4j uses JEXL instead of OGNL for parsing and executing these expressions.

We decided to switch to JEXL because its syntax and behavior is more similar to ECMAScript/JavaScript and so closer to the original jade.js implementation. JEXL runs also much faster than OGNL. In our benchmark, it showed a performance increase by factor 3 to 4.

We are using a slightly modified JEXL version which to have better control of the exception handling. JEXL now runs in a semi-strict mode, where non existing values and properties silently evaluate to null/false where as invalid method calls lead to a JadeCompilerException.

Reserved Words

JEXL comes with the three builtin functions new, size and empty. For properties with this name the . notation does not work, but you can access them with [].

- var book = {size: 540}
book.size // does not work
book["size"] // works

You can read more about this in the JEXL documentation.

Framework Integrations

Breaking Changes

1.3.1

  • Fixed a mayor scoping bug in loops. Use this version and not 1.3.0

1.3.0

  • setBasePath has been removed from JadeConfiguration. Set folderPath on FileTemplateLoader instead.
  • Scoping of variables in loops changed, so its more in line with jade. This could break your template.

1.2.0

  • Breaking change in filter interface: if you use filters outside of the project, they need to be adapted to new interface

1.0.0

In Version 1.0.0 we added a lot of features of JadeJs 1.11. There are also some Breaking Changes:

  • Instead of 'id = 5' you must use '- var id = 5'
  • Instead of 'h1(attributes, class = "test")' you must use 'h1(class= "test")&attributes(attributes)'
  • Instead of '!!! 5' you must use 'doctype html'
  • Jade Syntax for Conditional Comments is not supported anymore
  • Thanks to rzara for contributing to issue-108

Authors

Special thanks to TJ Holowaychuk the creator of jade!

License

The MIT License

Copyright (C) 2011-2019 neuland Büro für Informatik, Bremen, Germany

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

jade4j's People

Contributors

atomiccoder avatar avalax avatar chbloemer avatar chrisjlee avatar code4craft avatar dependabot[bot] avatar dhavalsdoshi avatar edeustace avatar fabiangr avatar finalguy avatar gijoerg avatar jknack avatar kayr avatar krudolph avatar marlonbernardes avatar maxcom avatar md-5 avatar moio avatar naltatis avatar orthographic-pedant avatar planetk avatar propan avatar rzara avatar taher-ghaleb avatar wiiitek 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  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

jade4j's Issues

Spurious invalid indentation exception

When compiling the following template:

.sidebar-placeholder
    h1 Sidebar Empty
    p.lead
      | The sidebar is used when selecting certain objects or operations
      | in the main user interface. It will open when needed,
      | and can be closed using the
      button
        i.icon-chevron-left
      |  button.

which is (I believe) valid; I get an "invalid indentation" exception on line 4.

I've pasted the same text into http://naltatis.github.io/jade-syntax-docs/ and it generates my expected HTML output.

StringIndexOutOfBoundsException in Lexer.java: 569

Looking into this on my end, I'll try to get a little more info about what is causing this but looking at Lexer.java it seems that there is another exception that should be getting thrown with a more informative message.

StackTrace

java.lang.StringIndexOutOfBoundsException: String index out of range: -1
        at java.lang.String.substring(String.java:1911) ~[na:1.7.0_11]
        at de.neuland.jade4j.lexer.Lexer.attributes(Lexer.java:569) ~[jade4j-0.3.15.jar:na]
        at de.neuland.jade4j.lexer.Lexer.next(Lexer.java:148) ~[jade4j-0.3.15.jar:na]
        at de.neuland.jade4j.lexer.Lexer.lookahead(Lexer.java:191) ~[jade4j-0.3.15.jar:na]
        at de.neuland.jade4j.parser.Parser.lookahead(Parser.java:697) ~[jade4j-0.3.15.jar:na]
        at de.neuland.jade4j.parser.Parser.peek(Parser.java:701) ~[jade4j-0.3.15.jar:na]

Cross cutting concern support

Hi,

I've started using Jade4j for my Spring MVC projects at work and I have to say that it is a pleasant experience compared to other templating frameworks.

But I feel there is one thing missing and that is cross cutting concern support (e.g internationalization or formatting). It would be wonderful if I could use Spring's conversion service to convert all my non-String values to String by default (if I choose to).
So that this:

p= format.currency(account.balance)
p= format.date(account.createdDate)

could look like this:

p= account.balance
p= account.createdDate

and still be formatted while leaving the template nicely readable.

Another use case could be as I mentioned internationalization. I am sick of Java's resource bundles and I would like to use gettext. This would allow me to have the text that I have in my Jade templates be the internationalization key.
So instead of this:

p= i18n['some.internationalization.key']

I could have something like this in my template:

p This is my not internationalized text //- i18n key

And still have the template nicely internationalized with the correct syntax highlighting (I am using IDEA's Jade support and the readability really suffers once I internationalize my templates and all internationalized strings look like JavaScript expressions).

I think these use cases could be met by providing a way to get at the string and expression values and pre/post process them.

What do you think? Is this something that would align with the project's direction?
If that's the case I would like to help improve this amazing project.
Cheers!

Includes in templates in paths with spaces

Consider the following situation:

  • I have two files index.jade and head.jade
  • head.jade is called from index.jade by an include
  • Both are in a directory containing a space

In this case, trying to render index.jade will give an exception. The reason is that the include is parsed by taking the filename String used to create the parser for index.jade is translated to a URI using the method URI.create [Parser:313], which is assumed to accept only strictly legal URI string (ie. no spaces). The filename string used to create the parser for index.jade however, is passed (ultimately) to the constructor of a File object [FileTemplateLoader:37].

A quick fix would be to use new URI(...) in Parser:313, so the filename path is escaped. I think ultimately you may need to make a more consistent decision about how template paths are stored (eg. store them as URIs always, and use the 'file://' prefix for local files).

bean not completely accessible

I have a bean called User.java:

package com.example.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Transient;

import com.google.api.client.auth.oauth2.Credential;

@Entity(name="usertbl")
@NamedQueries({
    @NamedQuery(name="user.findAll", query="select u from usertbl u"),
    @NamedQuery(name="user.findUser", query="select u from usertbl u where u.username=:username")
})
public class User {

    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
    private String username;
    private String firstName;
    private String lastName;
    private String pictureurl;

    @Transient
    private Credential credential;

    public User() {
        // default constructor.
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public Credential getCredential() {
        return credential;
    }
    public void setCredential(Credential credential) {
        this.credential = credential;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getPictureurl() {
        return pictureurl;
    }
    public void setPictureurl(String pictureURL) {
        this.pictureurl = pictureURL;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((username == null) ? 0 : username.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof User)) {
            return false;
        }
        User other = (User) obj;
        if (username == null) {
            if (other.username != null) {
                return false;
            }
        } else if (!username.equals(other.username)) {
            return false;
        }
        return true;
    }

}

and as jade file:

each user in users
            ol
              li= user.username
              li= user.firstName

The jade renderer is called as:

        List<User> users = new ArrayList<User>();
        String[] parameterValues = request.getParameterValues("id");
        if (parameterValues.length>0) {
            System.out.println("id is "+parameterValues[0]);
            User user = repo.findUser(parameterValues[0]);
            users.add(user);
        }
        map.put("users", users);
        response.getWriter().write(engine.render("index", map));
    }

The User is found and the jade renderer will output the user.username. It will however not output the firstName or any other field from the User object showing the following message in the serverlog:
WARNING: de.neuland.jade4j.expression.ExpressionHandler.evaluateExpression@28![0,15]: 'user.firstName;' inaccessible or unknown property user

blockquote doesn't work , jade4j thinks it is a block

The first blockquote tag gets converted into a block, then subsequent blockquotes include the first block. Must be a parser bug with the word "block". To reproduce, just create a page with multiple blockquotes.

This happens in 0.3.10

block not outputted within conditional statement inside a mixin

I have a scenario where I have a mixin that outputs the block inside a conditional statement. This block is not getting outputted if within a condition (works as expected in the interactive jade documentation)

- alignment = "left"

mixin alignSimple()
  .wrapper.simple
    block

mixin alignConditional()
  if alignment == "left"
    .wrapper.conditional
      block

mixin nestedMixin()
  label.mixin-label= "label inside mixin"


+alignConditional
  label= "label passed directly"

+alignConditional
  +nestedMixin

+alignSimple
  label= "some text"

+alignSimple
  +nestedMixin

the output is:

<div class="wrapper conditional">
</div>
<div class="wrapper conditional">
</div>
<div class="wrapper simple">
        <label>some text</label>
</div>
<div class="wrapper simple">
        <label class="mixin-label">label inside mixin</label>
</div>

JadeParserException with simple template

With a jade template of:

a.myclass= user.name
  b.anotherclass

I get the following exception (assume I am passing in a valid value for user):

Exception in thread "main" class de.neuland.jade4j.exceptions.JadeParserException helloworld:2
expected class de.neuland.jade4j.lexer.token.Block but got class de.neuland.jade4j.lexer.token.Indent
    at de.neuland.jade4j.parser.Parser.expect(Parser.java:733)
    at de.neuland.jade4j.parser.Parser.parseBlock(Parser.java:245)
    at de.neuland.jade4j.parser.Parser.parseCode(Parser.java:635)
    at de.neuland.jade4j.parser.Parser.parseTag(Parser.java:481)
    at de.neuland.jade4j.parser.Parser.parseExpr(Parser.java:110)
    at de.neuland.jade4j.parser.Parser.parse(Parser.java:91)
    at de.neuland.jade4j.JadeConfiguration.createTemplate(JadeConfiguration.java:86)
    at de.neuland.jade4j.JadeConfiguration.getTemplate(JadeConfiguration.java:58)
    at JadeTest.main(JadeTest.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

The test runner for this is as basic as can be:

public static void main(String... args) throws Exception {
      final Map<String,Object> params = new HashMap<String, Object>();
      params.put("user", new User("Nesbitt", "23"));

      WL(Jade4J.render("z:/dev/jade/src/main/resources/templates/helloworld.jade", params));
   }

   public static void WL(String s) {
      System.out.println(s);
   }

Plain Text newline?

Is there a way to include newline characters in plain text output?

example:
| hello
| world

should produce (in plain text):
hello
world

but seems to produce:
helloworld

according to the Jade docs newline characters should be preserved in the rendered output:
http://naltatis.github.io/jade-syntax-docs/#text

Note: this occurs even with pretty print enabled.

Running in Apache Karaf (OSGi)

Greetings,

Primarily information only...

I had an issue running Jade4j in Karaf due to an apparent conflict with trying to load classes from org.apache.commons.jexl2, since it needs both internal and external resources from this package name. Refactoring the internal JadeJexl classes to a different package name, then specifying org.apache.commons.jexl2 as an Import-Package in the Manifest solved the issue. I tried using Embed-Dependency, but may not have had it configured properly.

Please let me know if I'm missing something here....Thanks

inaccessible or unknown property error shows wrong variable name

If you try to access a.b.c and c is null, the error will say "inaccessible or unknown property b"

likewise, if you try to access a.b , and b is null, the error will say "inaccessible or unknown property a" .

This is rather confusing, because it makes it sound like the parent object is null.

Ampersand character (&) not handled properly in text

There is an issue handling the ampersand character ("&") declaring the beginning of an entity reference. The ampersand itself is being converted to an entity reference.

As an example, the following the jade:

p &copy; 2012

Outputs as:

<p>&amp;copy; 2012</p>

Instead of:

<p>© 2012</p>

Position of include statements in relation to block relevant?

The following template threw parse excpetion:

extends ../layout

block styles
  +css("landingpage")
  +css("productlist")

block ticker
  if locals.ticker
    +ticker

mixin productlistHeader(prefix)
  if locals.teasers
    +teaserBlock(teasers, prefix)
  if locals.designer
    .pageHeadline
      h1= designer.name

block content
  include ../mixins/contentNavigation
  include ../mixins/teaser
  ...

because the mixin "productlistHeader" depends on seeing the content included by "include ../mixins/teaser".

When moving the include statements like this:

extends ../layout

block styles
  +css("landingpage")
  +css("productlist")

block ticker
  if locals.ticker
    +ticker

block content
  include ../mixins/contentNavigation
  include ../mixins/teaser

  mixin productlistHeader(prefix)
    if locals.teasers
      +teaserBlock(teasers, prefix)
    if locals.designer
      .pageHeadline
        h1= designer.name
    ...

everything'S fine

Should not depend on slf4j-log4j12

spring-jade4j uses slf4j for logging, but the implementation should be chosen by the user of the library. Dependency on slf4j-log12 should be removed. The project should on depend on slf4j-api.

Problem with parsing mixins arguments

There are some exceptions when parsing mixins. For example, I have mixins defined as follows:

mixin yyy(zzz)
| #{zzz}

mixin yyy2(zzz1, zzz2)
| #{zzz} #{zzz2}

And use of them in templates:

+yyy('blabla, sthsth')

here exception:

Caused by: class de.neuland.jade4j.exceptions.JadeCompilerException /D:/Projects/innuendo/server/frontend/app/views/index.jade:43
unable to evaluate ['blabla] - Tokenization de.neuland.jade4j.expression.ExpressionHandler.evaluateExpression@1:8 tokenization error in ''blabla'
at de.neuland.jade4j.parser.node.MixinInjectNode.writeVariables(MixinInjectNode.java:104)
at de.neuland.jade4j.parser.node.MixinInjectNode.execute(MixinInjectNode.java:42)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.compiler.Compiler.compile(Compiler.java:30)
at de.neuland.jade4j.template.JadeTemplate.process(JadeTemplate.java:23)
at de.neuland.jade4j.Jade4J.render(Jade4J.java:63)
at de.neuland.jade4j.Jade4J.render(Jade4J.java:58)
at de.neuland.jade4j.Jade4J$render.call(Unknown Source)
at de.neuland.jade4j.Jade4J$render.call(Unknown Source)

+yyy2('addApp(app)', 'deleteFromNewApps(app)')

here exception:

Caused by: class de.neuland.jade4j.exceptions.JadeCompilerException /D:/Projects/innuendo/server/frontend/app/views/index.jade:45
unable to evaluate ['addApp(app] - Tokenization de.neuland.jade4j.expression.ExpressionHandler.evaluateExpression@1:12 tokenization error near '... (app ...'
at de.neuland.jade4j.parser.node.MixinInjectNode.writeVariables(MixinInjectNode.java:104)
at de.neuland.jade4j.parser.node.MixinInjectNode.execute(MixinInjectNode.java:42)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.compiler.Compiler.compile(Compiler.java:30)
at de.neuland.jade4j.template.JadeTemplate.process(JadeTemplate.java:23)
at de.neuland.jade4j.Jade4J.render(Jade4J.java:63)
at de.neuland.jade4j.Jade4J.render(Jade4J.java:58)
at de.neuland.jade4j.Jade4J$render.call(Unknown Source)
at de.neuland.jade4j.Jade4J$render.call(Unknown Source)

Merged class attribute not using expression value

Using 0.2.15:

errorClass = 'error'
div(class=errorClass)
.test(class=errorClass)

Expected output:

<div class="error"></div>
<div class="test error"></div>

Actual output:

<div class="error"></div>
<div class="test de.neuland.jade4j.parser.node.ExpressionString@157aa53"></div>

XML encoding for special character does not work

Hi,

We are using Jade4j in our project both for HTML and XML generation. For XML generation, I have set the JadeTemplate mode to Jade4J.Mode.XML. But generated XML encodes special characters with HTML entity reference which XML parser does not understand. For e.g., Ch. & de la Mêlée 12 becomes "Ch. & de la Mêlée 12". ê and é are fine to HTML perspective but not XML.

I had downloaded the jade4j code to understand the problem and found even though we are setting the mode to XML but not used in the code. Utils.interpolate(List prepared, JadeModel model) method always uses StringEscapeUtils.escapeHtml4 to encode value.

Can you please fix this (OR) please let me know if I am missing something.

Thanks and lot.

Rgds - Sidd

NullPointerException due to race condition in mixing processing

I see some number of NPE in my logs, here is stack trace:

java.lang.NullPointerException
        at de.neuland.jade4j.compiler.Utils.interpolate(Utils.java:61)
        at de.neuland.jade4j.parser.node.TagNode.getInterpolatedAttributeValue(TagNode.java:171)
        at de.neuland.jade4j.parser.node.TagNode.getAttributeString(TagNode.java:110)
        at de.neuland.jade4j.parser.node.TagNode.attributes(TagNode.java:98)
        at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:56)
        at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
        at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
        at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
        at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
        at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
        at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
        at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
        at de.neuland.jade4j.parser.node.MixinInjectNode.execute(MixinInjectNode.java:44)
        at de.neuland.jade4j.parser.node.MixinNode.execute(MixinNode.java:28)
        at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
        at de.neuland.jade4j.compiler.Compiler.compile(Compiler.java:30)
        at de.neuland.jade4j.template.JadeTemplate.process(JadeTemplate.java:23)
        at de.neuland.jade4j.JadeConfiguration.renderTemplate(JadeConfiguration.java:75)
        at ru.org.linux.site.tags.CommentTag.doStartTag(CommentTag.java:81)

Expection raises on different input data and it goes away when I reload page.

I looked and the source code and I think that problem is in clone() method of AttributedNode:

    @Override
    public AttributedNode clone() throws CloneNotSupportedException {
        AttributedNode clone = (AttributedNode) super.clone();

        if (clone.attributes != null) {
            // shallow copy
            clone.attributes = new LinkedHashMap<String, Object>(clone.attributes);
        }

        // clear prepared attribute values, will be rebuilt on execute
        preparedAttributeValues = new HashMap<String, List<Object>>();

        return clone;
    }

That method actually resets preparedAttributeValue on source node, not on clone. That is why preparedAttributeValues.get(name) may return null when clone is called from another thread.

Handling of IF constructs with(out) NULL

I have a list/array:

mylist = [1,2,3] 

and try to check it with

IF locals.mylist && mylist.size()>0
  //- don't work

but its not working as expected. When I change it to

IF locals.mylist != NULL && mylist.size()>0
  //- works

or

IF locals.mylist
  IF mylist.size()>0
    //- works

it works as expected.

Please change it that the first statement also returns true

Meta tags with no content should not be rendered

If meta tag has a name/property, but no content, Jade4j still renders it. e.g. if someContent is null, meta(name='someName', content=someContent) yields <meta name="someName"/>. Meta tags with no content probably do not serve any purpose, and hence it may make more sense to omit the meta tag altogether in such cases.

Generated Attribute when value is NULL/Empty

Does Jade4J provide ability to trim any empty/null attributes like Jade for js,,
example of how currently jade4J generate output is like below, I added into model this
model.put("test", null)

.columns(test='#{test}')
  .portlet
    .portlet-header
      h3 Hello Portlet
    .portlet-content
      p Portlet Content

and generated output is like follow:

<div class="columns" test="">
  <div class="portlet">
    <div class="portlet-header">
      <h3>Hello Portlet</h3>
    </div>
    <div class="portlet-content">
      <p>Portlet Content</p>
    </div>
  </div>
</div>

size property name not works

{project.size} not displaying I think size is a protected keyword because other property names (for example id) in the same bean displaying. Both are int types.

Error trace:

de.neuland.jade4j.exceptions.ExpressionException: unable to evaluate [project.size] - Parsing de.neuland.jade4j.expression.ExpressionHandler.evaluateExpression@1:9 parsing error near '... ect.size ...'
de.neuland.jade4j.expression.ExpressionHandler.evaluateExpression(ExpressionHandler.java:31)
de.neuland.jade4j.expression.ExpressionHandler.evaluateStringExpression(ExpressionHandler.java:36)
de.neuland.jade4j.compiler.Utils.interpolate(Utils.java:67)
de.neuland.jade4j.parser.node.TextNode.execute(TextNode.java:39)
de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:71)
de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
de.neuland.jade4j.parser.node.EachNode.runIterator(EachNode.java:63)
de.neuland.jade4j.parser.node.EachNode.run(EachNode.java:41)

Can't build on Windows

I tried to build it on a windows computer, but the tests fails.
This is not an issue for me, but I just wanted to post it anyway.

It seems that the code relies somewhat on unix-paths - especially the ability to 1) concatenate 2 paths and 2) use the path directly in a URI.create() call.

1)
Concatenating windows paths become stuff like 'C:\folder\folder\C:\folder\folder\folder\file

2)
URI.create does not like uri's like 'C:\folder\file' unless it is prepended with something like 'file:/' resulting in file:/C:/folder/file

I tried on windows XP with JDK 1.6.24.

Self Closing tags

I was wondering if there was a way to create a self closing tag when generating my XML...

ex.

I would expect to write something like this in my template (with a trailing forward slash)

Person(firstName='Bob')(lastName='Smith')/

but it outputs:

/

Blocks in mixins

Hi.

Im wondering how I would come about to create a mixin with subnodes?

Fx.

include mixins

mixin container
    .component
        mixin component
    .component
        mixin component

Potential indentation issue

I'm not sure if this is a bug or just me doing something wrong. I have a Jade template that uses tabs and I've verified that there are no spaces. The first line is not indented at all. When the template gets parsed, I get an error:

class de.neuland.jade4j.exceptions.JadeLexerException layout:3
invalid indentation; expecting 0 spaces
at de.neuland.jade4j.lexer.Lexer.indent(Lexer.java:652)
at de.neuland.jade4j.lexer.Lexer.next(Lexer.java:152)
at de.neuland.jade4j.lexer.Lexer.lookahead(Lexer.java:192)
at de.neuland.jade4j.parser.Parser.lookahead(Parser.java:726)
at de.neuland.jade4j.parser.Parser.parseTag(Parser.java:462)
at de.neuland.jade4j.parser.Parser.parseExpr(Parser.java:116)
at de.neuland.jade4j.parser.Parser.parse(Parser.java:97)
at de.neuland.jade4j.parser.Parser.parse(Parser.java:105)
at de.neuland.jade4j.JadeConfiguration.createTemplate(JadeConfiguration.java:88)
at de.neuland.jade4j.JadeConfiguration.getTemplate(JadeConfiguration.java:60)

Expressions passed to mixins as attributes are not evaluated

Hi,

I have noticed that when using variables to pass attributes to a mixin the expressions do not get evaluated:

For example this:

variable = 'abc'
mixin link(href, name)
  a(class=attributes.class, href=href)= name

+link('/foo', 'foo')(class=variable)

Evaluates to this:

<a class="de.neuland.jade4j.parser.node.ExpressionString@75b1ff70" href="/foo">foo</a>

Dynamic Include

Is their such a way in Jade4J to enable dynamic include so we write something like
include #{portlet.template}?

jade4j compilation issue

Hi,

Environment: Windows 7.

I have downloaded jade4j code. But when I build the code even without change "de.neuland.jade4j.compiler.OriginalJadeTest" test case fails with error

Caused by: java.net.URISyntaxException: Illegal character in opaque part at index 2.

Rgds - Sidd

Invalid Markup shows StringIndexOutOfBoundsExceptionange instead of JadeCompilerException

When create a new jade file and write an uncomplete tag in it, I get an StringIndexOutOfBoundsException instead of Jade Compiler Exception with line number

index.jade

a(

Stacktrace:
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1949)
at de.neuland.jade4j.lexer.Lexer.attributes(Lexer.java:567)
at de.neuland.jade4j.lexer.Lexer.next(Lexer.java:148)
at de.neuland.jade4j.lexer.Lexer.lookahead(Lexer.java:191)
at de.neuland.jade4j.parser.Parser.lookahead(Parser.java:697)
at de.neuland.jade4j.parser.Parser.parseTag(Parser.java:433)
at de.neuland.jade4j.parser.Parser.parseExpr(Parser.java:110)
at de.neuland.jade4j.parser.Parser.parse(Parser.java:91)
at de.neuland.jade4j.JadeConfiguration.createTemplate(JadeConfiguration.java:86)
at de.neuland.jade4j.JadeConfiguration.getTemplate(JadeConfiguration.java:64)
at de.neuland.jade4j.spring.view.JadeView.getTemplate(JadeView.java:63)
at de.neuland.jade4j.spring.view.JadeView.renderMergedOutputModel(JadeView.java:41)

Stack overflow with nested mixins

mixin a
   a
     block

mixin b
   b
     block
+a
   +b
     test

Produces the following output:

at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.MixinInjectNode.execute(MixinInjectNode.java:36)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:98)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.TagNode.execute(TagNode.java:98)
at de.neuland.jade4j.parser.node.BlockNode.execute(BlockNode.java:16)
at de.neuland.jade4j.parser.node.MixinInjectNode.execute(MixinInjectNode.java:36)

Mixins with blocks repeat content from first use of a mixin

Given the following Jade template from the mixin.blocks.jade test case from visionmedia/jade

mixin form(method, action)
  form(method=method, action=action)
    csrf_token_from_somewhere = 'hey'
    input(type='hidden', name='_csrf', value=csrf_token_from_somewhere)
    block

html
  body
    +form('GET', '/search')
      input(type='text', name='query', placeholder='Search1')
      input(type='submit', value='Search1')

html
  body
    +form('POST', '/search')
      input(type='text', name='query', placeholder='Search')
      input(type='submit', value='Search')

html
  body
    +form('POST', '/search')

mixin bar()
  #bar
    block

mixin foo()
  #foo
    +bar
      block

+foo
  p one
  p two
  p three

jade4j produces the following output (note repeated block contents from first use of a mixin):

<html>
  <body>
    <form action="/search" method="GET">
      <input name="_csrf" value="hey" type="hidden"/>
      <input placeholder="Search1" name="query" type="text"/>
      <input value="Search1" type="submit"/>
    </form>
  </body>
</html>
<html>
  <body>
    <form action="/search" method="POST">
      <input name="_csrf" value="hey" type="hidden"/>
      <input placeholder="Search1" name="query" type="text"/>
      <input value="Search1" type="submit"/>
    </form>
  </body>
</html>
<html>
  <body>
    <form action="/search" method="POST">
      <input name="_csrf" value="hey" type="hidden"/>
      <input placeholder="Search1" name="query" type="text"/>
      <input value="Search1" type="submit"/>
    </form>
  </body>
</html>
<div id="foo">
  <div id="bar">
    <input placeholder="Search1" name="query" type="text"/>
    <input value="Search1" type="submit"/>
  </div>
</div>

Actual output should be:

<html>
  <body>
    <form action="/search" method="GET">
      <input name="_csrf" value="hey" type="hidden"/>
      <input placeholder="Search1" name="query" type="text"/>
      <input value="Search1" type="submit"/>
    </form>
  </body>
</html>
<html>
  <body>
    <form action="/search" method="POST">
      <input name="_csrf" value="hey" type="hidden"/>
      <input placeholder="Search" name="query" type="text"/>
      <input value="Search" type="submit"/>
    </form>
  </body>
</html>
<html>
  <body>
    <form action="/search" method="POST">
      <input name="_csrf" value="hey" type="hidden"/>
    </form>
  </body>
</html>
<div id="foo">
  <div id="bar">
    <p>one</p>
    <p>two</p>
    <p>three</p>
  </div>
</div>

I have fixed the issue and will submit a pull request.

Blocks being misinterpreted as blockquotes

When a block quote is present in an extended file, any and all blocks are rendered as block tags by jade4j.

E.g.:

layout.jade is extended via index.jade:

layout.jade

!!! 5
html
    head
        title Block quote test
    body
        block title

        blockquote this is the block quote

index.jade

extends ../partials/layout.jade

block title
    h1 block quote test

With the blockquote present in layout.jade, the page is rendered like so:

screen shot 2013-07-16 at 12 04 44 1

When it should be rendered like this:

screen shot 2013-07-16 at 12 06 42


Update:

This actually applies even when a blockquote is not used; a div with a class of .blockquote will result in the same error, as will mentioning the words 'blockquote' anywhere within a sentence.

Variables defined inside jade templates are not evaluated

For instance this fails with,
WARN jexl2.JexlEngine: de.neuland.jade4j.expression.ExpressionHandler.evaluateExpression@28![0,4]: 'name;' undefined variable name

!!! 5
html
head
title my jade
body
- var name='IronMan'
h1 Hello #{name}

it would be really nice if this could be added, I already see support for template inheritance , block etc.

Thanks

Multi-Line Strings include the trailing slash

First off, I'm not sure that Jade itself supports multi-line strings by intention:

pugjs/pug#1447

But assuming it does, Jade4J messs up slightly:

div(attr="foo \
  bar \
  baz")

compiles to

<div attr="foo \  bar \  baz"></div>

... that is, the slashes are being included.

Jade4J should make it easier to compile when you have an InputStream

In my scenario, I have an InputStream (that I can easily wrap as a Reader) but I have to jump through hoops to create the necessary objects, since key methods of Jade4J are private:

(defn- ^TemplateLoader create-template-loader 
  [source ^String name]
  (let [^Reader reader (->
                         (open source)
                         InputStreamReader.
                         BufferedReader.)]
    (ReaderTemplateLoader. reader name)))

(defn compile-jade
  [source]
  (let [name (source-name source)]
    (tracker/log-time
      #(format "Compiled `%s' to HTML in %.2f ms" name %)
      (tracker/trace
        #(format "Compiling `%s' from Jade to HTML" name)
        (try
          (let [loader (create-template-loader source name)
                parser (Parser. name loader)
                rootNode (.parse parser)
                ^JadeTemplate template (doto (JadeTemplate.)
                                         (.setRootNode rootNode)
                                         (.setTemplateLoader loader))
                ;; Need a way in the future to turn pretty to false for production
                ^String compiled (Jade4J/render template {} true)]
            (assoc source
              :source-name (str "Compiled " name)
              :content-type "text/html"
              :content (.getBytes compiled utf-8)))
          (catch JadeException e
            (throw (RuntimeException.
                     (format "Jade Compilation exception on line %d: %s"
                             (.getLineNumber e)
                             (or (.getMessage e) (-> e .getClass .getName))
                             )
                     e))))))))

I'd like the option to pass a Reader, Map, boolean and get back a String ... or better yet, pass an InputStream, Map, boolean and get back a String.

Allow null to be handled as empty string

I'm working on a Grails plugin to render Jade templates (https://github.com/jgritman/grails-jade). When using a null value in an expression, I've noticed that expression [bean.name] returned null exceptions are thrown and the page won't render.

To work around this, I added expressions like #(projectInstance.name != null ? projectInstance.name : ''} all over my code, which is somewhat ugly next to all the nice concise Jade syntax. It would be nice, if either as the default or through a configuration option, that any nulls could just be treated as empty strings for rendering.

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.