joytpl
v0.0.21
Published
joy - js template engine with short syntax and modern features
Downloads
16
Maintainers
Readme
Joy
Template engine we use in Triggre.
This is an early release, use it at your own risk.
Summary:
- razor like minimal syntax
- precompilation oriented
- templates are modules
- templates and helpers are functions
- clear names collision solving
- compression in mind
Usage
Bash
npm i joytpl -g
joytpl -h
Usage: joytpl [options] <file ...>
Options:
-V, --version output the version number
-t, --charset <charset> files charset (default: utf8)
-m, --modules <modules> module system (default: es6)
-p, --runtime-path <runtimePath> runtime path (default: joytpl/runtime)
-s, --short-runtime <shortRuntime> short runtime (default: false)
-j, --js <jsVersion> js version (default: es6)
-b, --beautify <beautify> formatted code (default: false)
-h, --help output usage information
- modules: es6, commonjs, amd
- jsVersion: es5, es6
Write result in an output file:
joytpl path/to/input/file > output/file
Express
npm i joytpl
app.set('view engine', 'joytpl');
To avoid suffix:
const joy = require('joytpl');
// ...
app.engine('joy', joy.express);
app.set('view engine', 'joy');
// ...
U can't use imports within express views. If u need imports plz use precompilation. In Triggre we use express support just for initial template of SPA which is usually pretty simple.
Code
npm i joytpl
const joy = require('joytpl');
joy.build(inputText, options, function(err, result) {
if (err) {
console.error(err);
return;
}
// result.content - result text of the module
// result.extracted - object that contains all extractions
});
Beyond same options available in bash there are advanced ones:
{
extractors: {NodeType: [(node, exported, options) => {...}], ...},
validators: {NodeType: [(node, exported, options) => {...}], ...}
}
You can add custom extractors or validators to specific AST node type(look processor module for the types).
Want to forbid some variables names or extract all l10n text to single JSON file? No problem.
Dev Tools
Syntax
Comments
@* you will never recall what this code is for *@
Imports
@import * as foo from 'bar/foo'
@import foo from 'bar/foo'
Two exact import types currently supported.
Based on modules option it goes to:
import * as foo from 'bar/foo';
const foo = require('bar/foo');
define(['bar/foo'], function(foo) {});
Escape
Start sequence escape:
big.boss@@gmail.com
Escape unpaired brackets in blocks:
... {
\}
\{
}
Paired brackets may stay unescaped:
... {
<script type="application/json">
{
"foo": "bar"
}
</script>
}
Variables
All variables passed in a tpl function via object can be used with data prefix like:
Hello, @data.name!
Some more examples:
@data.htmlEscaped @* escape utility by default *@
@!data.foo.htmlRaw @* raw html *@
@(data.hello)world together @* with borders *@
@!(data.hello)again
Functions
@formField(additionalClasses='size-' + data.size) {
<input type="text" name="fullName" />
}
Joy has function calls not function definitions. Arguments in this calls are expressions with any supported types. Optional block after ")" is also specific argument. Treat it as an easy form of passing big chunk of text(html). It's also so called named argument(it has reserved name content) like additionalClasses in example. There is a rule in joy for functions: if u have a single named argument then all arguments in call must be named.
In case text in block is JSON it's parsed and passed to the function as a data object ignoring other arguments.
So in general there are two usage scenarios:
We have raw js function(imported or global) and want to use it as a tpl helper:
@Math.pow(7, 2)
We want to use a tpl from other one:
@import * as card from 'foo/card'
@import * as fullName from 'bar/fullName'
@!card() {
@fullName(name=data.name, surname=data.surname)
}
or
@import * as card from 'foo/card'
@import * as fullName from 'bar/fullName'
@!card() {
@fullName() {{
"name": "@data.name",
"surname": "@data.surname"
}}
}
Conditions
@if data.n < 1 {
less
}
else if data.n > 1 && data.n < 100 {
in range
}
else {
more
}
Put parentheses to distinguish functions bodies from conditional:
@if foo() {
@* function argument *@
} {
@* conditional body *@
}
@if (bar()) {
@* conditional body *@
}
Loops
<ul>
@each item in data.items {
<li>@item</li>
}
<ul>
<ul>
@each key:value in data.items {
<li class="@if key % 2 == 0 {even} else {odd}">@value</li>
}
<ul>
Types
Types that can be used in expressions:
- bool(true/false)
- number(1/1.0)
- null
- undefined
- string("q"/'q')
- variable
- function
Objects and arrays are not supported yet.
Operators
Operators that can be used in expressions:
- unary ! + -
- && ||
- < > <= >= == === != !==
- + -
- * / %
Other operators are not supported yet.
For more details see examples directory.
Enjoy! :)