Coder Social home page Coder Social logo

mozilla / nunjucks Goto Github PK

View Code? Open in Web Editor NEW
8.5K 140.0 634.0 7.7 MB

A powerful templating engine with inheritance, asynchronous control, and more (jinja2 inspired)

Home Page: https://mozilla.github.io/nunjucks/

License: BSD 2-Clause "Simplified" License

HTML 4.93% Python 0.20% JavaScript 93.51% Batchfile 0.03% Nunjucks 1.34%

nunjucks's Introduction

Nunjucks

NPM Version NPM Downloads Linux Build Windows Build Test Codecov

Nunjucks is a full featured templating engine for javascript. It is heavily inspired by jinja2. View the docs here.

Installation

npm install nunjucks

To use the file watcher built-in to Nunjucks, Chokidar must be installed separately.

npm install nunjucks chokidar

(View the CHANGELOG)

Documentation

See here.

Browser Support

Supported in all modern browsers. For IE8 support, use es5-shim.

Tests

Run the tests with npm test.

Watch master branch's tests running in the browser.

Mailing List

Join our mailing list and get help with and issues you have: https://groups.google.com/forum/?fromgroups#!forum/nunjucks

Want to help?

Contributions are always welcome! Before you submit an issue or pull request, please read our contribution guidelines.

Contributors

nunjucks's People

Contributors

aarono avatar amyboyd avatar andrewhayward avatar arcanis avatar bhagany avatar carljm avatar daniele-rapagnani avatar devoidfury avatar dhendo avatar fdintino avatar fooby avatar forresst avatar garygreen avatar ixth avatar jbmoelker avatar jbuck avatar jlongster avatar mattbasta avatar maxnordlund avatar noahlange avatar novocaine avatar ogonkov avatar oyyd avatar popomore avatar rhengles avatar ricordisamoa avatar samypesse avatar shvaikalesh avatar tyler-johnson avatar vecmezoni 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  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

nunjucks's Issues

{% if var == 'someval' %} issue

{% if var == 'someval' %}

is being compiled to

if(context.lookup("var") || frame.lookup("var") || "" == "someval") {

Due to this, if var is exists and is a truthy value, it always evaluates to true.

real-world template code:

<select name="filter">
    <option value="">All</option>
    <option value="pending"{% if filter == 'pending' %} selected="selected"{% endif %}>Pending</option>
    <option value="rejected"{% if filter == 'rejected' %} selected="selected"{% endif %}>Rejected</option>
    <option value="approved"{% if filter == 'approved' %} selected="selected"{% endif %}>Approved</option>
    <option value="suspended"{% if filter == 'suspended' %} selected="selected"{% endif %}>Suspended</option>
    <option value="complete"{% if filter == 'complete' %} selected="selected"{% endif %}>Complete</option>
</select>

Generated code snipped [from compiler.compile(src)]:

output += "<select name=\"filter\">\n    <option value=\"\">All</option>\n    <option value=\"pending\"";
if(context.lookup("filter") || frame.lookup("filter") || "" == "pending") {
    output += " selected=\"selected\"";
}
output += ">Pending</option>\n    <option value=\"rejected\"";
if(context.lookup("filter") || frame.lookup("filter") || "" == "rejected") {
    output += " selected=\"selected\"";
}
output += ">Rejected</option>\n    <option value=\"approved\"";
if(context.lookup("filter") || frame.lookup("filter") || "" == "approved") {
    output += " selected=\"selected\"";
}
output += ">Approved</option>\n    <option value=\"suspended\"";
if(context.lookup("filter") || frame.lookup("filter") || "" == "suspended") {
    output += " selected=\"selected\"";
}
output += ">Suspended</option>\n    <option value=\"complete\"";
if(context.lookup("filter") || frame.lookup("filter") || "" == "complete") {
    output += " selected=\"selected\"";
}
output += ">Complete</option>\n</select>";

Wrapping the var in parens is a workaround.

<select name="filter">
    <option value="">All</option>
    <option value="pending"{% if (filter) == 'pending' %} selected="selected"{% endif %}>Pending</option>
    <option value="rejected"{% if (filter) == 'rejected' %} selected="selected"{% endif %}>Rejected</option>
    <option value="approved"{% if (filter) == 'approved' %} selected="selected"{% endif %}>Approved</option>
    <option value="suspended"{% if (filter) == 'suspended' %} selected="selected"{% endif %}>Suspended</option>
    <option value="complete"{% if (filter) == 'complete' %} selected="selected"{% endif %}>Complete</option>
</select>

... and output:

output += "<select name=\"filter\">\n    <option value=\"\">All</option>\n    <option value=\"pending\"";
if((context.lookup("filter") || frame.lookup("filter") || "") == "pending") {
    output += " selected=\"selected\"";
}
output += ">Pending</option>\n    <option value=\"rejected\"";
if((context.lookup("filter") || frame.lookup("filter") || "") == "rejected") {
    output += " selected=\"selected\"";
}
output += ">Rejected</option>\n    <option value=\"approved\"";
if((context.lookup("filter") || frame.lookup("filter") || "") == "approved") {
    output += " selected=\"selected\"";
}
output += ">Approved</option>\n    <option value=\"suspended\"";
if((context.lookup("filter") || frame.lookup("filter") || "") == "suspended") {
    output += " selected=\"selected\"";
}
output += ">Suspended</option>\n    <option value=\"complete\"";
if((context.lookup("filter") || frame.lookup("filter") || "") == "complete") {
    output += " selected=\"selected\"";
}
output += ">Complete</option>\n</select>";

{% set %} performs tuple unpacking in Jinja

While researching the fix for #68, I discovered that Jinja's {% set %} with multiple variables actually does tuple unpacking, as opposed to nunjucks' multiple assignment.

>>> from jinja2 import Template
>>> t = 'Test {% set x,y = hello %} X is: {{ x }} Y is: {{ y }}'
>>> Template(t).render({'hello': (5, 10)})
u'Test  X is: 5 Y is: 10'
>>> Template(t).render({'hello': [42, 52]})
u'Test  X is: 42 Y is: 52'
>>> Template(t).render({'hello': [42, 52,23]})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27Orig\lib\site-packages\jinja2\environment.py", line 894, in render
    return self.environment.handle_exception(exc_info, True)
  File "<template>", line 1, in top-level template code
ValueError: too many values to unpack
>>> Template(t).render({'hello': 234})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27Orig\lib\site-packages\jinja2\environment.py", line 894, in render
    return self.environment.handle_exception(exc_info, True)
  File "<template>", line 1, in top-level template code
TypeError: 'int' object is not iterable

Do you think it would be a good idea to adopt this behaviour, especially given that we already have unpacking for {% for %}?

If so, I wouldn't mind coming up with a patch when I have time.

Value of "this" for variable function calls changed to global scope in 1.6

I have a template that is being passed a "form" object as a variable, which has several utility functions for rendering a form. I use it like this:

{{ form.as_div() }}

After updating nunjucks to 0.1.6, it looks like the "this" keyword in all of my functions calls has changed to the global scope rather than the object itself.

Breaking change between 0.1.4 and 0.1.5?

Given these templates:

<!-- layout.html -->

<!DOCTYPE html>
<html>
  <head>
    <title>Bootstrap 101 Template</title>
    <!-- Bootstrap -->
    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
  </head>
  <body>
    {% block "body" %}{% endblock %}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
  </body>
</html>
<!-- index.html -->

{% extends "layout.html" %}
{% block "body" %}
 OH hi
{% endblock %}

and this express setup:

var express = require('express');
var app = express();

var nunjucks = require('nunjucks');
var env = new nunjucks.Environment(new nunjucks.FileSystemLoader('views'));
env.express(app);
app.configure(function(){
  app.set('port', process.env.PORT || 3000);
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});
app.get('/', exports.index = function index (req, res) {
  res.render('index.html');
};

I have no problems on 0.1.4, but on 0.1.5 I get the following:

Error: [Line 2, Column 15] variable name expected
    at Object.extend.fail (/Users/brian/dev/wutlol/node_modules/nunjucks/src/parser.js:62:15)
    at Object.extend.parseBlock (/Users/brian/dev/wutlol/node_modules/nunjucks/src/parser.js:271:18)
    at Object.extend.parseStatement (/Users/brian/dev/wutlol/node_modules/nunjucks/src/parser.js:392:35)
    at Object.extend.parseNodes (/Users/brian/dev/wutlol/node_modules/nunjucks/src/parser.js:915:30)
    at Object.extend.parseAsRoot (/Users/brian/dev/wutlol/node_modules/nunjucks/src/parser.js:941:42)
    at Object.module.exports.parse (/Users/brian/dev/wutlol/node_modules/nunjucks/src/parser.js:960:18)
    at Object.module.exports.compile (/Users/brian/dev/wutlol/node_modules/nunjucks/src/compiler.js:633:26)
    at Object.extend._compile (/Users/brian/dev/wutlol/node_modules/nunjucks/src/environment.js:237:46)
    at Object.extend.render (/Users/brian/dev/wutlol/node_modules/nunjucks/src/environment.js:202:18)
    at Object.extend.render (/Users/brian/dev/wutlol/node_modules/nunjucks/src/environment.js:103:39)

What am I doing wrong?

Escaping a number should work

Escaping a number with the "e" filter should work, as it's common to pass both numbers and strings to templates and the template designer shouldn't have to worry about the difference but should be encouraged to just do the right thing and escape stuff if there is any doubt.

Current behavior:

TypeError: Object 5 has no method 'replace'] name: 'Template render error' }

Please see test project:

https://github.com/punkave/nunjucks-debug

Thanks!

Better Errors

Currently, the errors are obscure and could use improvement; see example below.

I propose that (at least partial) template filename, line number, and a raw sample of the line in the template be added to the error message.

I'd be happy to help implement this; what direction would you like to take it?

undefined:224
ookup("project") || frame.lookup("project") || "")["some_property"])[(t_13)["a
                                                                ^
TypeError: Cannot read property '1' of undefined
at b_main (eval at <anonymous>             ($PROJ_DIR/node_modules/nunjucks/src/environment.js:237:24))
at root [as rootRenderFunc] (eval at <anonymous> ($PROJ_DIR/node_modules/nunjucks/src/environment.js:237:24))
at Object.extend.render ($PROJ_DIR/node_modules/nunjucks/src/environment.js:206:21)
at Object.extend.render ($PROJ_DIR/node_modules/nunjucks/src/environment.js:103:39)
at module.exports.render ($PROJ_DIR/lib/middleware/template.js:53:20)

macros should support 'caller' arg

Note this use of the special caller implicit variable available to macros:

{% macro render_dialog(title, class='dialog') -%}
    <div class="{{ class }}">
        <h2>{{ title }}</h2>
        <div class="contents">
            {{ caller() }}
        </div>
    </div>
{%- endmacro %}
{% call render_dialog('Hello World') %}
    This is a simple dialog rendered by using a macro and
    a call block.
{% endcall %}

This support is currently missing and would be immensely useful. In jinja you can also pass arguments to the caller function, I can live without that, but I really cant live without caller.

Maybe this can be a path for you to feel better about how custom tags are coded?

extending with "../layout.html" results in "template not found"

I'm using express and have my templates set up as:

views/
  layout.html
  account/
    create.html

Attempting to render account/create.html from express results in Error: template not found: ../layout.html at Object.extend.getTemplate (/Users/zcarter/moz/gombot/node_modules/nunjucks/src/environment.js:54:23)

It seems like this should work.

"use strict";

Use the strict mode of javascript on all the files: "use strict";

template inclusion from parent template location

It might be a nice idea to allow (through an env setting) template inclusion relative to the parent's template, so something like

./index.html
./templates/viewX.html
./templates/viewY.html

where index.html loads viewX.html, which in turn includes viewY.html. These could then use the following include syntax:

index.html: {% include "templates/viewX.html" %}
viewX.html: {% include "viewY.html" %}

that way, moving templates around in clusters would not require changing the inclusion paths except for in the ancestral parent template.

Not sure if jinja2 supports that, come to think of it... if it doesn't, it should! O_O

Official way to pass variables to templates

According to several sources on the net, one should not use "res.locals" or "dynamic helpers". The preferred method is to use middleware as in something like this:

app.configure(function(){

app.use(function(req, res, next){
res.locals.user = req.session.user;
res.locals.csrf = 'req.session._csrf';
res.locals.flash = req.session.flash();
next();
});
});

What is the official opinion on this? Are there working examples somehwere? The middleware method does not work with the Nunjucks version in the NPM repo. Thanks

{% set... %} does not respect {% if %} statement context

{% set %} statements always execute, even if they are inside an {% if %} statement whose condition is not true. In fact, a set statement appearing in both the main and else branches of an "if" is run both times, so else always wins.

Problems using form objects in a Nunjuck template

How do I stop a form object from being rendered immediately? Let me explain, using Swig and Jade templates, I can iterate over a form object::

{% for field in form %}
{{ field.errors }} {{ field.label_tag }}: {{ field }}
{% endfor %}

Nunjucks renders the form immediately, maybe calling an internal toString() func. Any ideas? Thanks

Asynchronous API

I know that nunjucks is a direct port of jinja2, so probably due to this internally it is using some sync methods of nodejs to access files, etc. However I think that having an asynchronous API would bring better performance. For example inside FileSystemLoader there are calls to fs.existsSync, fs.readFileSync and fs.statSync. This blocks the whole javascript execution so it causes a scability problem.

I know that this could be a big change, but would be a big step forwards.

Allow different delimiters (or document existing ability)

I write an app that uses Python jinja2 templates and Javascript underscore.js templates. I'm interested in switching to nunjucks, but I really want my JS and Python templates to use different syntax, and it's not practical for me to convert my Python templates. I'd like to be able to configure nunjucks to use [[ instead of {{, etc.

Conditional extends should work, no?

I'm trying to return html fragments and figured that I could achieve this by conditionally setting a template to extend from. The true case works, but the false case throws an exception.

   it('should allow extends blocks inside of if blocks', function(){
        var s = render( '{% if true %}'+
                        '{% extends "base.html" %}'+
                        '{% endif %}'+
                        '{% block block1 %}fragment{% endblock %}');
        s.should.equal('FoofragmentBazFizzle');

        s = render( '{% if false %}'+
                    '{% extends "base.html" %}'+
                    '{% endif %}'+
                    '{% block block1 %}fragment{% endblock %}');
        s.should.equal('fragment');
    });

Error

TypeError: Cannot call method 'rootRenderFunc' of undefined
      at [object Object].root [as rootRenderFunc] (eval at <anonymous> (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/src/environment.js:273:24))
      at [object Object].render (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/src/environment.js:242:21)
      at render (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/tests/util.js:9:14)
      at Context.<anonymous> (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/tests/compiler.js:325:13)
      at Test.run (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runnable.js:213:32)
      at Runner.runTest (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runner.js:343:10)
      at /Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runner.js:389:12
      at next (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runner.js:269:14)
      at /Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runner.js:278:7
      at next (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runner.js:226:23)
      at Array.0 (/Users/aschaar/programming/xtags-org/node_modules/nunjucks/node_modules/mocha/lib/runner.js:246:5)
      at EventEmitter._tickCallback (node.js:192:40)
make: *** [test] Error 1

fix missing line numbers in error messages

Hi,

Looking through parser.js there are a fair few exceptions being thrown that don't pass a lineno/colno and so when the error is reported there is no line number.

I am happy to go through and fix these but i wanted to first ask whether I should actually just convert the throws to fail(), and what the differences are supposed to be between throwing Error, throwing TemplateError, and invoking fail()

Fix express integration

The current implementation is breaking template rendering profiling (WIP) in express-debug by hijacking app.render.

I'll submit a PR this week to correct this issue.

{% set ... %} doesn't behave in macros

The following lines of code all throw compilation errors:

{% set tag = 1 if link else 2 %}
{% set tag = 'a' %}
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}

The last example is taken from jinja2's documentation.

Uncaught TypeError: Cannot read property 'FileSystemLoader' of undefined

Hi again,

I've come across this problem when going from dev to pre-compiled on browser nunjucks.
I've precompiled all my templates into a js file, referenced them in my index.html, but before those are even loaded, attempting to include the nunjucks.min.js or nunjucks.js results in:

Uncaught TypeError: Cannot read property 'FileSystemLoader' of undefined

After trawling through the code, it seems like the only module attribute to be defined is environment.

Could you shed some light on any pitfalls that I might be succumbing too? Or if there's an issue with nunjucks?

Thanks,

David.

[Macros] TypeError: Cannot read property '__keywords' of undefined

I found the issue I was having before. Test case:

s = render('{% macro foo(x, y) %}{{ x.x }}{{ y.x }}{% endmacro %}' +
    '{{ foo(bar, baz) }}');
s.should.equal('');

The error is TypeError: Cannot read property '__keywords' of undefined

Macros should have the same behavior with undefined names as regular templates.

(Edit: I don't have this issue in v0.1.7)

Should render nested blocks defined in inheriting templates

jlongster@10ac70f changed how nunjucks handles nested blocks, which now differs slightly from jinja2. See this gist for an example of what jinja2 does. For the same templates, nunjucks outputs nothing but blank lines.

Based on that, I think this is a (failing) test that captures the problem:

diff --git a/tests/compiler.js b/tests/compiler.js
index aede527..98b6e14 100644
--- a/tests/compiler.js
+++ b/tests/compiler.js
@@ -326,6 +326,12 @@ describe('compiler', function() {
         s.should.equal('Foo**Bar**BazFizzle');
     });

+    it('should render nested blocks defined in inheriting template', function() {
+      var s = render('{% extends "base.html" %}' +
+                     '{% block block1 %}{% block nested %}BAR{% endblock %}{% endblock %}');
+      s.should.equal('FooBARBazFizzle');
+    });
+
     it('should include templates', function() {
         var s = render('hello world {% include "include.html" %}');
         s.should.equal('hello world FooInclude ');

unclosed path string in include causes request to hang

{% include "include.html %} will cause your request to never complete.

Maybe I deserved it, but its probably a bug.

   it('should not hang when parsing unclosed quotes', function(){
      var s = render('hello world {% include "include.html %}');
      s.should.equal('hello world FooInclude ');
   });

IE8 Support for Nunjucks

There is a few issues with nunjucks and cross-browser compatability, namely, IE8 holds no support for Object.create(), so code crashes on line 8

(function() {
var modules = {};
(function() {

// A simple class system, more documentation to come

function extend(cls, name, props) {
    // not supported in IE8
    var prototype = Object.create(cls.prototype);
    var fnTest = /xyz/.test(function(){ xyz; }) ? /\bparent\b/ : /.*/;
    props = props || {};

I've made a few changes myself, but nothing to warrant a pull request, all my solutions seem to concern with implementing a custom Object.create method to put in place instead of what Nunjucks is expecting to find in Object.create.

Like so:

if (!Object.create) {
    Object.create = function (o) {
        if (arguments.length > 1) {
            throw new Error('Object.create implementation only accepts the first parameter.');
        }
        function F() {}
        F.prototype = o;
        return new F();
    };
}

However, this just produces "NaN" in my template when rendered.

Thanks,

David.

TypeError: String.prototype.indexOf called on null or undefined

I just want to use indexOf in an if block, but nunjucks doesn't seem to like it for some reason.

var data = { url: "/about" };
var broken = new nunjucks.Template("{% if url.indexOf('/about')==0 %} selected {% endif %}");
console.log(broken.render(data));
//TypeError: String.prototype.indexOf called on null or undefined
var works = new nunjucks.Template("{% if url == '/about' %} selected {% endif %}");
console.log(works.render(data));

Discussion: should "undefined" be returned to the template when things are undefined?

For (a contrived) example:

res.render('index.html', {user: { first: 'Brian' }})
Hi, {{ user.first }} {{ user.last }}

Will show "Hi, Brian undefined"

I don't know what the jinja2 behavior is, but mustache would return "Hi Brian ". I would definitely prefer that, but if the jinja2 behavior is to spit out "undefined" I suppose it makes more sense to stay true to that?

define() call should pass name

The call to define() for AMD support should pass the name "nunjucks" to define() as the first parameter. This is standard in most (all?) AMD implementations, and enables the runtime to be used in compiled projects (a la r.js) that aren't file/path aware.

Parent block yield

When using the extends tag for layouts defining blocks becomes quite messy. Would it be/is it possible to create a cleaner syntax similar to the usage of yield in Ruby template engines. For instance the following usage of a layout feels quite cluttered:

### layout.html:
<html lang="en">
<head>
  <title>{{ title }}</title>
</head>
<body>

  {% block body %}{% endblock %}

</body>
</html>

### page.html
{% set title = 'Hello World' %}
{% extends 'default.html' %}

{% block body %}
  <p>
    Hello World
  </p>
{% endblock %}

A more transparent, implied way of doing it would be much cleaner:

### layout.html:
<html lang="en">
<head>
  <title>{{ title }}</title>
</head>
<body>

  {% parent %}

</body>
</html>

### page.html
{% set title = 'Hello World' %}
{% extends 'default.html' %}

<p>
  Hello World
</p>

I have taken a look through both the Jinja and Django template documentation and while I sometimes feel this functionality is implied it doesn't seem to exist.

Safe method calling

If a method is undefined, output an empty string (or at the very least show lineno/colno in error).

This has been causing some debugging trouble for me.

{% include }% always adds contents in newline?

Hi,

In my template I have

<a href="{% include 'snippet.html' %}">test</a>

But then the generated HTML is like:

<a href="
the included content goes here...
">test</a>

How can I make it inline? Thanks!

CALL FOR INPUT: mailing list?

For those of you seeing this, I'm considering creating a mailing list to facilitate discussion on nunjucks features/bug. Do you think this would be useful?

I'm seeing more and more people using nunjucks which is exciting to me and I want to establish a community, even if it's small. The next major version will have a custom tag API so we could even start seeing lots of cool tags (as extensions).

Google Groups seems to be the only feasible way to do this.

"if" should consider an empty array to be false

nunjucks currently considers an empty array to be true. It is common practice in jinja and its other derivatives to test for an empty array by just writing {% if arrayname %}.

From the jinja documentation:

The if statement in Jinja is comparable with the if statements of Python. In the simplest form you can use it to test if a variable is defined, not empty or not false:

{% if users %}
<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}

{% set %} broken with expressions

actual behavior:

var nunjucks = require('nunjucks'),
    t = new nunjucks.Template("{% set x = 1 + 1 %}{{ x }}");

console.log( t.render({}) );

.

$node test.js
throw new Error("invalid type: " + node.typename);
              ^
Error: invalid type: Add
  at Object.extend.assertType (../node_modules/nunjucks/src/compiler.js:125:19)
  at Object.extend._compileExpression (../node_modules/nunjucks/src/compiler.js:98:14)
  at Object.extend.compileSet (../node_modules/nunjucks/src/compiler.js:278:14)

expected behavior:

from jinja2 import Template
template = Template('{% set x = 1 + 1 %}{{ x }}')
print template.render()

.

$ python test.py
2

Two levels of super() do not work

Please see this test project, I minimized it as much as possible:

https://github.com/punkave/nunjucks-debug

If you declare a block in layout1.html, extend that from layout2.html (calling super() in the extension of the block), and then extend layout2.html in test.html (calling super() again in your second extension of the block), you get:

Error: no super block available for "footer"

If layout2.html does not call super(), then test.html is able to successfully call super(), but of course the content output by layout1.html is lost.

The bug seems specific to more than one use of super() for the same block in the inheritance tree.

Thanks!

nunjucks exception handling obscures the throw site for exceptions not thrown by nunjucks itself

Hey,

when an error is thrown during tryTemplate we have a fairly reasonable try/catch block that rethrows the error so some error information is recorded.

unfortunately this is often quite cryptic, and often it is better to see the exact point in generated template code where it was thrown, particularly if it is a js error thrown during rendering rather than an error explicitly thrown by nunjucks (theres no line, col info).

in chrome I can get the behaviour i want if i enable 'pause on exceptions' and then comment out the try/catch block. this causes a pause in the generated code itself, even though its a dynamically created Function(). quite nice.

Screen Shot 2013-02-04 at 12 35 47 PM

would you accept a patch that makes a dont_catch variable available (similar to .dev), which causes thrown exceptions to not be caught the nunjucks handler?

Express.js res.locals

Love the syntax and general usage of this library.

I've stumbled on an issue when using it with Express 3.x:

Data is not passed to the template when using the res.locals Express 3.x feature.

For instance, using res.locals.current_user = user and then {{ current_user }} is blank, most likely, non-existent.

Hopefully this is a quick fix.

Whitespace control

Implement proper whitespace control ({% for item in seq -%}). Reference implementation found here.

(I know this is on the missing features list, but its always good to have a specific issue for each case)

Invoke functions with no arguments in variable tags when accessed like property

This is minor really. More of an aesthetics/readability issue and there might be a solution I'm missing. I'm working on a "form factory" for models in a mongoose/express config and I have Form objects with child Field objects that have properties like this.

this.label = function() {
    return this.widget.type === 'hidden' ? '' :
        '<label for="id_' + this._name + '">' + (this._label || this._name.humanize()) + '</label>';
}

I'm aiming for something similar to Django's form tools, so I am trying to use these objects in a template like this.

<form method="post" ....>
    {{form.username.errors}}
    {{form.username.label}}
    {{form.username}}
    ....

At the moment the username input is working by overriding the "toString" prototype, but the two child properties of username are printing [object Object] because I don't have the invoking parenthesis "()". I tried using self invoking functions to get around it, but then I run into scoping issues.

I imagine having all 0-argument functions invoked on template render could cause some issues with JavaScript. Would it be possible to add "flags" or something similar to objects that effect the rendering process? Or is there some other way around this already?

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.