runty

Extensible conditional string micro templates.

Usage no npm install needed!

<script type="module">
  import runty from 'https://cdn.skypack.dev/runty';
</script>

README

runty

Extensible conditional string micro templates.


Features

  • Simple, but powerful template syntax
  • Conditional string rendering with support for nested expressions
  • Variable (interpolation / subsitution / expansion) with support for property accessor chaining
  • Parse/compile your templates once, execute them multiple times with different values
  • Support for array output, allowing substitution of non-string values (such as React components)
  • Extensible with custom functions (or use our Standard Library (fns))
  • Bundle-bloat friendly. Small, tree-shakeable library with zero dependencies

Documentation

Documentation and a demo are available at https://runty.js.org


Installation

$ npm install runty

or

$ yarn add runty

Or import the library directly in your browser or deno:

import { runty } from 'https://cdn.skypack.dev/runty';

Quick Examples

Conditional Interpolations

This example uses simple conditional variable interpolations.

import { runty } from 'runty';

// create a parser
const runt = runty();

// compile a template
const template = runt('Now Playing: {%artist?{%artist} - }{%song}');

// execute a template and pass it a dictionary of variables
console.log(template({ artist: 'Weird Al Yankovic', song: 'Albuquerque' }));
// "Now Playing: Weird Al Yankovic - Albuquerque"

console.log(template({ song: 'Albuquerque' }));
// "Now Playing: Albuquerque"

// using an array as a variable dictionary
const anotherTemplate = runt('{%1?{%1}:Unknown Artist} - {%0}');

console.log(anotherTemplate(['Albuquerque', 'Weird Al Yankovic']));
// "Weird Al Yankovic - Albuquerque"

console.log(anotherTemplate(['Albuquerque']));
// "Unknown Artist - Albuquerque"

Using Functions

This example uses standard library fns.

import { runty, fns } from 'runty';

const runt = runty({ fns });

const template = runt('{$gt(%count,0)?There {$eq(%count,1)?is:are} {%count} item{$not($eq(%count,1))?s} in your cart:Your cart is empty}.');

console.log(template({ count: 0 }));
// "Your cart is empty."

console.log(template({ count: 1 }));
// "There is 1 item in your cart."

console.log(template({ count: 2 }));
// "There are 2 items in your cart."

Extending With Custom Functions

This example defines it's own custom functions to make available to templates.

import { runty } from 'runty';

const runt = runty({
  fns: {
    plural: ([number]) => number !== 1,
    fooOrBar: ([defaultValue], { bar, foo }) => bar ?? foo ?? defaultValue
  }
});

const template = runt('There {$plural(%count)?are:is} {%count} item{$plural(%count)?s} in your cart.');

console.log(template({ count: 1 }));
// "There is 1 item in your cart."

console.log(template({ count: 3 }));
// "There are 3 items in your cart."


const anotherTemplate = runt('This is {$fooOrBar(neither)}.');

console.log(anotherTemplate({ foo: 'Foo' }));
// This is Foo.

console.log(anotherTemplate({ bar: 'Bar' }));
// This is Bar.

console.log(anotherTemplate());
// This is neither.

Getting Template Result As An Array

In some cases, it may be useful to interpolate non-stringifiable values in a string template. For example, it may be useful to insert a React component into a string template.

import React from 'react';
import { runty } from 'runty';

// trigger an array result while initializing runty:
const runt = runty({ asArray: true });

const template = runt('Drop a react component {%component} into your template.');

const Component = () => {
  const values = template({ component: <button key="foo" /> });

  return (
    <div>
      {values} // renders: ['Drop a react component ', <button key="foo" />, ' into your template.']
    </div>
  );
};

// or get an array result at time of template compilation:
runt('Drop a react component {%component} into your template.', true);

// or at the time of execution:
template({ component: <button key="foo" /> }, true);