Skip to content

noahlange/superjucks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

{% superjucks %} [WIP]

Build Status Coverage Status

Superjucks is an extremely work-in-progress Jinja-style templating engine based on the Nunjucks codebase. With a flexible parser capable of emulating a variety of Jinja dialects and async-aware compilation, it hopes to (eventually) be a versatile and flexible iteration on Mozilla's excellent Nunjucks templating engine.

{% extends 'default.sjk' %}
{% import * as forms from 'forms.sjk' %}

{% macro input(name, value, type = 'text') %}
  <input type="{{ type }}" name="{{ name }}" value="{{ value }}" />
{% endmacro %}

{% block content %}
  <form method="POST" action="/submit">
    {{ input('_method', 'PUT', 'hidden') | safe }}
    {% set { fields } = await forms(model) %}
    {% for f of fields %}
      {% switch f.type %}
        {% case 'select' %}
          <select name="{{ f.name }}">
            {% for await o of f.options() %}
              <option value="{{ o.value }}">
                {{ o.label }}
              </option>
            {% endfor %}
          </select>
        {% default %}
          {{ input(f.name) | safe }}
      {% endswitch %}
    {% endfor %}
  </form>
{% endblock %}

{% export { input as default } %}

Overview

Superjucks aims to be largely compatible with Nunjucks, and semi-compatible with Jinja, Twig and Liquid.

Moreover, Superjucks hopes to provide several preset configurations that emulate the syntax, filters, blocks and tests of these other Jinja dialects. These are semi-implemented works-in-progress, but are (at least the jinja, Nunjucks and Nunjucks+ flavors) release-blocking priorities.

Entirely new, incompletely-tested features include:

  • async/await support
  • ES6-esque imports and exports (aliased imports/exports are forthcoming)
  • default macro parameters
  • in for inclusion
  • for-of for iteration for object literals and objects implementing a [Symbol.iterator] method
  • for-await-of for iteration on async generators (you'll need to precompile and transpile to use this feature)
  • tests
  • additional filters from Liquid, Twig and Jinja
  • Liquid/Twig-style inclusive/exclusive range operator (.., ...)
  • new blocks ported from Liquid/Jinja/Twig (switch, unless)

Imports

{# star imports #}
{% import * as foo from 'bar' %}

{# named imports #}
{% import { bar } from 'baz' %}

{# default imports #}
{% import baz from 'foo' %}

Exports

{% macro foo(one, two, three = 'four') %}
{% endmacro %}

{# default exports #}
{% export default foo %}

{# named exports #}
{% export { foo } %}

{# multiple exports #}
{% export { foo, bar } %}

Variables and Macros

{# destructuring #}
{% set { foo, bar } = baz %}
{% set [ one, two ] = bar %}

{# default macro parameters #}
{% macro input(name, value, type = 'text') %}
  <input type="{{ type }}" name="{{ name }}" value="{{ value }}" />
{% endmacro

Tests

{% if foo is defined %}
<p>Foo is defined!</p>
{% else %}
<p>Foo is undefined!</p>
{% endif %}

Keywords

await

<ul>
  {% for { foo, bar } of iterable %}
    <li>{{ foo }}: {{ await bar() }}</li>
  {% endfor %}
</ul>

Blocks

unless

{% unless foo or baz %}
  foo {{ bar }} baz
{% endunless %}

switch/case

{% switch foo %}
  {% case 'bar' %}
    bar
  {% case 'baz' %}
    baz
  {% default %}
    neither foo nor bar
{% endswitch %}

Operators

  1. Ternary
{% set foo = bar ? 'bar' : 'baz' %}
{% set foo = bar ? 'bar' %}
  1. Elvis
{% set foo = bar ?: 'baz' %}
  1. Null-coalescing
{% set foo = bar ?? 'baz' %}

Notable changes

Operator precedence

  1. Filters now have dead-last precedence. This means that if you want filters take only the nearest left parameter, you'd best put them in parens. This may be a controversial change, but I haven't been convinced that Jinja got this one right. This is, of course, customizable based on your config - the Nunjucks/ Nunjucks+/Twig/Jinja/Liquid presets feature filter-first precedence.
{# correct  #}
{% 1..5 | join %}

{# correct #}
{% 1..(5 | minus(2)) %}

{# incorrect, can't join number #}
{% 1..(5 | join) %}

{# incorrect, can't subtract from array #}
{% 1..5 | minus(2) %}

Operators

  1. inof
{# iteration #}
{% for foo of bar %}
{% endfor %}

{# async iteration #}
{% for await foo of bar() %}
{% endfor %}

{# inclusion #}
{% if foo in bar %}
{% endif %}

Blocks

  1. verbatimraw

Filters

  1. slicechunk

Releases

No releases published

Packages

No packages published