Text templates with a small, forgiving language
Texl fills any text, from Markdown and HTML to configuration files and e-mails, with values computed by Swan: an expression language that is quick to learn and never stops with an error.
<% order = {id: 1042, items: ["pen", "ink"], total: 18.5}
%>Order #<% order.id %>
Items: <% list.enum order.items %>
Total: $<% order.total %><% order.total > 15 ? " (free shipping)" %>
Order #1042
Items: pen, ink
Total: $18.5 (free shipping)
Why Texl
Texl keeps templates readable: plain text, with a few tags where values go.
Any text format
Only the <% %> tags are special. Everything else
is copied exactly, so Texl works for Markdown, HTML, YAML, source code
and plain prose alike.
Expressions, not statements
Every tag is one Swan expression: values, functions, namespaces and
tuples, with conditions and mapping instead of if and
for.
Errors are values
An invalid operation produces an Undefined value
instead of stopping the rendering, and tells you what went wrong when
you inspect it.
Imports and libraries
Templates import other templates by relative path or URL, to share headers, footers and libraries of functions. Each one loads once.
Waits for data
A tag can return a promise, such as a document being fetched or an
async host function, and the rendering waits for it.
One engine, many hosts
The engine is written in Rust and runs on the command line, in the browser through WebAssembly, and inside Python and Rust programs.
Meet Swan
Swan is the language inside the tags. It is small enough to learn in an afternoon.
- Functions are values:
double = x -> x * 2. - Tuples apply an operation to many values at once.
cond ? a ; bis all the branching you need.- Namespaces group data and functions.
- A built-in library for text, lists, math and dates.
double = x -> x * 2
(1, 2, 3) => double # => (2, 4, 6)
greet = name -> "Hi " + (name ; "there")
greet "Ada" # => "Hi Ada"
greet () # => "Hi there"
point = {x: 3, y: 4}
math.hypot point.x point.y # => 5
"a" - 1 # => Undefined
Use it from
The template language is the same everywhere. Pick the host that fits your project.
The command line
Render template files from a terminal or a build script.
cargo install --git https://github.com/onlabsorg/texl texl-cli
texl report.texl -o report.md
JavaScript
Render templates in a web page, with your data and functions.
import init, { TexlEngine } from "@onlabsorg/texl";
await init();
const engine = new TexlEngine({ user: "Ada" });
await engine.render("Hi <% user %>!");
Python
Render templates in Python, with your data and async functions.
import asyncio, pytexl
engine = pytexl.Engine({"user": "Ada"})
asyncio.run(engine.render("Hi <% user %>!"))
Rust
Embed the engine, with your own loaders and host functions.
let engine = Engine::new(spawner);
engine.add_builtin("user", Value::Text("Ada".into()));
let text = engine.render("Hi <% user %>!").await;
A Node.js library is coming soon
Documentation
Everything you need, from your first template to the engine's internals.
Getting started
Install the texl command and render your first template.
Writing templates
Tags, data, conditions, repetition, imports and troubleshooting.
The Swan language
The complete language manual, from syntax to promises.
Built-in library
Every function of text, list,
math, time and the rest.
Hosts and APIs
Where Texl runs, and how to pick the host that fits your project.
Command line
The texl command, its options and exit codes.
JavaScript API
TexlEngine, contexts, documents and value conversion.
Python API
pytexl.Engine, contexts, loaders and value conversion.
Rust API
The texl_core and swan_core crates.