Crate cookie_cutter

Crate cookie_cutter 

Source
Expand description

crates.io crates.io License actions-badge

§Introduction

A feature-rich template engine with context aware escaping and both run time and compile time compilation.

Designed to generate html / js / css documents based on trusted templates but using untrusted user data that are safe to be processed by a browser.

Unlike other template engines cookie cutter does not aim to be minimal or maximally performant instead opting for feature richness and developer experience.

It also does not require templates to be compiled into the application, enabling them to be loaded at run time from a filesystem for example. Compile time inclusion is however also possible and has the benefit of surfacing template errors directly at compile time as native rust compiler errors to catch mistakes as early as possible.

§Minimal “Hello World” example

hello.cctmpl

template hello() {
    Hello World!
}

hello.rs

use std::collections::{BTreeMap, HashMap};

use cookie_cutter::{
    builtins::{StandardContextWorker, StandardContextualizer, StandardEscaper},
    Templates, Value,
};

fn main() {
    let t: Templates<_> =
        Templates::<StandardEscaper>::new::<StandardContextualizer, StandardContextWorker>(
            [(
                "hello.ccmtmpl",
                include_str!("hello.cctmpl"),
            )],
            HashMap::new(),
        )
        .expect("failed to compile templates");

    assert_eq!(
        t.render("hello", Value::Struct(BTreeMap::new()))
            .expect("failed to render hello template"),
        "Hello World!".to_string()
    );
}

Further examples (also showcasing usage in an http server for example) can be found in the examples directory.

The testdata/source_files directory might also be of interest to you if want to see what the language is capable of.

§Feature Overview

§Type system

The template definition language is statically typed. It’s type system allows for text types as well as booleans, integers and floats. Struct and tuple like datatypes build on top of these primitive types and allow for complex data to be represented and used by the templates. The data type can also be omitted and in that case defaults to a specific text type (usually text). This is of further importance; for that see Contextualization.

It also permits recursive types as well sum types (like Rust enums).

§Values

Values can be created programmatically (by building up a Value enum) or via the value! macro allowing for JSON-like value literals.

Cookie cutter also has support for serde to serialize Rust values directly to values for use as template arguments.

§Indentation control

The templating language is indentation aware and automatically strips the longest common whitespace prefix of each line in a template / template literal.

If required this can be manually adjusted using a so called indentation marker which sets the minimum indentation level to a user defined level.

§Template literals (comparable to partials in other template engines)

Template literals allow you to write pieces of text in a specific context (text type) using local variables and pass them to other templates as arguments for example. This can be used to define a common site template which contains all the html boilerplate as well as other common elements like footers and headers and take the actual content of the page as a parameter to be included as the body.

§Comments

Template authors can included comments both in the source files directly (outside of any templates) using familiar C-style comments or inside templates using commands.

§Commands

Static and dynamic content is differentiated by use of commands. Everything outside of commands is literal (static) and everything inside gets computed at render time.

Commands can be expressions (to included dynamic content in templates), variable assignments or just comments.

Commands are started by a variable number of open curly braces to comfortably accommodate static content which commonly requires curly braces and avoids the constant use of escape sequences. The curly count is determined at the start of the template body.

§Escape sequences

Character sequences with a special meaning can be used literally (escaped) by being prefixed with a backslash.

Newlines can be escaped similar to multi line shell commands to write static content across multiple lines without the result having multiple lines as well.

§Variables

The language supports variable which need not be declared but are statically typed (like the rest of the langauge) and need to be assigned before usage.

These store arbitray values and can be reassigned.

§Direct array value inclusion a.k.a. freestanding expressions

Array values can also be directly included in a templates content (given that the two text types are compatible) and the array’s values will be included with the correct indentation and newline in the templates body.

§Control flow

The language supports if and each expressions.

The if expression allows values to be selected dynamically, for example to change a login button to logout button if the user is already logged in.

The each expression allows you to map over an array and produces a new array. This is commonly used to include a list of things in a templates output. Direct array value inclusion allows you to include this mapped output directly into your templates with the correct indentation and newlines.

§Functions

There are a few builtin functions available to template authors to suit common use cases. These are subject to be extended based on user feedback.

The function call syntax is reminiscent of Haskell and since pipelines of function calls are pretty common (where a function get’s called with the result of another function and so on) cookie cutter includes the dollar sign syntax to cut down on parentheses which Haskell users should find familiar.

Custom functions can be written to extend the capabilities of the template engine at render time. These take precendence over the builtin ones and allow you to alter their behaviour if needed.

§Contextualization

The text type is context aware and automatically ensures correct escaping based on the source and destination type. You can safely include a text piece into html or js.string.s (a single quote JS-String) and cookie cutter handles the escaping automatically.

Although web content generation is the primary focus of the project other types of text content can also be supported. For this you can implement your own Contextualizer instead of utizilizing the standard one. This provides custom text types and context detecting. You can also opt out of this feature entirely by using the NoopContextualizer which only supports the text type and does no context analysis.

§Output

Template output can be obtained as a String or be directly written to a fmt::Write implementor.

Modules§

builtins
Contains builtin functions and contextualizers.

Macros§

__internal__parse_include_str
Internal macro. Semver exempt. Do not use.
__internal__parse_with_path
Internal macro. Semver exempt. Do not use.
__internal__parser
Internal macro. Semver exempt. Do not use.
__internal__span_macro_include_str
Internal macro. Semver exempt. Do not use.
__internal__span_macro_with_path
Internal macro. Semver exempt. Do not use.
include_templates
Used to include templates at compile time and receive any errors as regular Rust compiler errors. You can provide a list of globs and the found files will all be added as source files to resulting Templates instance.
value
Constructs a Value using a literal syntax.

Structs§

Indentation
An amount of indentation. Typically of a template / template literal line.
Span
A span referencing a portion of template source code. Typically returned by errors to indicate the particular location of the problem.
Templates
The core struct of the templating engine. It represents fully type checked and ready to Templates::render templates.
TemplatesBuilder
The main way of obtaining Templates.

Enums§

ContextualizationError
An error that can happen when static text gets contextualized.
Error
The error type returned if building Templates failed.
ParseError
Represents a failure to parse a source file
RendertimeError
An error which can occur when attempting to render a template.
SerdeRenderError
The error type that gets returned in case a render using a serde argument fails.
SerializationError
An error that can occur when attempting to serialize a Rust value into a cookie cutter. crate::Value.
Type
The type of a cookie cutter crate::Value. Since this is used in earlier stages than the value more information is still available. For example the text type or whether it is a tuple or an array.
TypeCheckingError
An error which can occur in the type checking phase of the build process for a crate::Templates. Encountering this indicates the syntax of the source file(s) is correct since parsing errors would have ended the process early.
Value
A cookie cutter value used by the template engine to process data. Also used to provide data to templates in the form of paramters on the initial call to a render* function of a crate::Templates.

Traits§

ContextWorker
A trait to be implemented in tandem with Contextualizer by users wishing to change how static text is analysed to determine context and appropriate text type.
Contextualizer
A trait implemented by users wishing to change the way text types behave. This determines the default text type, how static text get’s analyzed and changes the context and how to escape text to safely get from one text type to another.
Escaper
A trait to be implemented in tandem with Contextualizer by users wishing to change how values are escaped to make it safe to include in a different context.
Function
A function to be used by template authors. There are several builtin ones. This can be implemented by users wishing to extend (or change) those.