npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

joytpl

v0.0.21

Published

joy - js template engine with short syntax and modern features

Downloads

16

Readme

Joy

Template engine we use in Triggre.

This is an early release, use it at your own risk.

Summary:

  1. razor like minimal syntax
  2. precompilation oriented
  3. templates are modules
  4. templates and helpers are functions
  5. clear names collision solving
  6. 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! :)