Skip to content

Latest commit

 

History

History
134 lines (93 loc) · 3.47 KB

File metadata and controls

134 lines (93 loc) · 3.47 KB

Template Language

NHP templates are HTML files with a .nhp extension. Expressions use moustache delimiters; control statements use XML-style processing instructions.

Expressions

Use JavaScript expressions inside moustaches:

<h1>{{title}}</h1>
<p>{{user.name || "Guest"}}</p>

Expression results are awaited automatically:

<textarea>{{fs.readFile(__filename, "utf8")}}</textarea>

For example, passing require("fs").promises as fs reads the template asynchronously. __filename and __dirname are exposed in the environment.

Normal moustaches escape <, >, and attribute quotes:

<a title="{{title}}">{{title}}</a>

Use triple moustaches only for trusted HTML that should be written without escaping:

<section>{{{trustedHtml}}}</section>

The object passed to render() supplies expression variables. All template values live in the per-render env object; VMC helper functions are kept separate. Variables use live proxies, so changes made by state directives are visible to later expressions.

State directives

set awaits an expression and stores its result in env:

<?set heading "News"?>
<h1>{{env.heading}}</h1>

add awaits a value and appends it to an array, creating it when needed:

<?add tags "node"?>
<?add tags "templates"?>
{{env.tags.join(", ")}}

map awaits a value and stores it under a key, creating an object when needed:

<?map metadata "author" "NexusTools"?>
{{env.metadata.author}}

json awaits an expression and writes it as JSON:

<script type="application/json"><?json data?></script>

exec runs trusted JavaScript inside the generated async function. It can use await and write output using __out.write():

<?exec __out.write("<!-- generated -->")?>

Conditions

Use if, elseif, else, and endif for conditional output:

<?if user.admin?>
  <p>Administrator</p>
<?elseif user?>
  <p>Signed in</p>
<?else?>
  <p>Guest</p>
<?endif?>

Each condition is awaited. Use env.name for values created with set, add, or map.

Iteration

each awaits its collection and iterates arrays and objects asynchronously in series. Expressions inside the loop are also awaited. Close every loop with done:

<ul>
<?each entries?>
  <li>{{entry}}</li>
<?done?>
</ul>

When iterating an object, entry has key and value properties:

<?each env.metadata?>
  <dt>{{entry.key}}</dt><dd>{{entry.value}}</dd>
<?done?>

Includes

include renders another template relative to the current template's directory:

<?include "partials/header"?>
<main>{{content}}</main>
<?include "partials/footer"?>

The .nhp extension is optional. Included templates share the same render locals and env object.

When the include path is a plain string literal (as above), it is resolved and compiled directly into the including template at compile time, so no filesystem access or template lookup happens at render time. An include whose path is a dynamic expression (e.g. <?include partial?> where partial is a variable) can't be resolved until render time and is looked up then instead.

Translation

Plain text that contains letters is passed to the render-local __ function. Its result is awaited, so translation may be asynchronous:

nhp.render("page.nhp", {
    async __(text) {
      return await lookupTranslation(text) || text;
    }
}, callback);

When no __ function is supplied, text is returned unchanged.