minijinja/
lib.rs

1//! <div align=center>
2//!   <img src="https://github.com/mitsuhiko/minijinja/raw/main/artwork/logo.png" alt="" width=320>
3//!   <p><strong>MiniJinja: a powerful template engine for Rust with minimal dependencies</strong></p>
4//! </div>
5//!
6//! MiniJinja is a powerful but minimal dependency template engine for Rust which
7//! is based on the syntax and behavior of the
8//! [Jinja2](https://jinja.palletsprojects.com/) template engine for Python.  It's
9//! implemented on top of [`serde`].  The goal is to be able to render a large
10//! chunk of the Jinja2 template ecosystem from Rust with a minimal engine and to
11//! leverage an already existing ecosystem of editor integrations.
12//!
13//! ```jinja
14//! {% for user in users %}
15//!   <li>{{ user.name }}</li>
16//! {% endfor %}
17//! ```
18//!
19//! You can play with MiniJinja online [in the browser
20//! playground](https://mitsuhiko.github.io/minijinja-playground/) powered by a
21//! WASM build of MiniJinja.
22//!
23//! # Why MiniJinja
24//!
25//! MiniJinja by its name wants to be a good default choice if you need a little
26//! bit of templating with minimal dependencies.  It has the following goals:
27//!
28//! * Well documented, compact API
29//! * Minimal dependencies, reasonable compile times and decent runtime performance
30//! * Stay close as possible to Jinja2
31//! * Support for expression evaluation
32//! * Support for all `serde` compatible types
33//! * Excellent test coverage
34//! * Support for dynamic runtime objects with methods and dynamic attributes
35//!
36//! # Template Usage
37//!
38//! To use MiniJinja one needs to create an [`Environment`] and populate it with
39//! templates.  Afterwards templates can be loaded and rendered.  To pass data
40//! one can pass any serde serializable value.  The [`context!`] macro can be
41//! used to quickly construct a template context:
42//!
43//! ```
44//! use minijinja::{Environment, context};
45//!
46//! let mut env = Environment::new();
47//! env.add_template("hello", "Hello {{ name }}!").unwrap();
48//! let tmpl = env.get_template("hello").unwrap();
49//! println!("{}", tmpl.render(context!(name => "John")).unwrap());
50//! ```
51//!
52//! ```plain
53//! Hello John!
54//! ```
55//!
56//! For super trivial cases where you need to render a string once, you can
57//! also use the [`render!`] macro which acts a bit like a replacement
58//! for the [`format!`] macro.
59//!
60//! # Expression Usage
61//!
62//! MiniJinja — like Jinja2 — allows to be used as expression language.  This can be
63//! useful to express logic in configuration files or similar things.  For this
64//! purpose the [`Environment::compile_expression`] method can be used.  It returns
65//! an expression object that can then be evaluated, returning the result:
66//!
67//! ```
68//! use minijinja::{Environment, context};
69//!
70//! let env = Environment::new();
71//! let expr = env.compile_expression("number < 42").unwrap();
72//! let result = expr.eval(context!(number => 23)).unwrap();
73//! assert_eq!(result.is_true(), true);
74//! ```
75//!
76//! This becomes particularly powerful when [dynamic objects](crate::value::Object) are
77//! exposed to templates.
78//!
79//! # Custom Filters
80//!
81//! MiniJinja lets you register functions as filter functions (see
82//! [`Function`](crate::functions::Function)) with the engine.  These can then be
83//! invoked directly from the template:
84//!
85//! ```
86//! use minijinja::{Environment, context};
87//!
88//! let mut env = Environment::new();
89//! env.add_filter("repeat", str::repeat);
90//! env.add_template("hello", "{{ 'Na '|repeat(3) }} {{ name }}!").unwrap();
91//! let tmpl = env.get_template("hello").unwrap();
92//! println!("{}", tmpl.render(context!(name => "Batman")).unwrap());
93//! ```
94//!
95//! ```plain
96//! Na Na Na Batman!
97//! ```
98//!
99//! # Learn more
100//!
101//! - [`Environment`]: the main API entry point.  Teaches you how to configure the environment.
102//! - [`Template`]: the template object API.  Shows you how templates can be rendered.
103//! - [`syntax`]: provides documentation of the template engine syntax.
104//! - [`filters`]: teaches you how to write custom filters and to see the list of built-in filters.
105//! - [`tests`]: teaches you how to write custom test functions and to see the list of built-in tests.
106//! - [`functions`]: teaches how to write custom functions and to see the list of built-in functions.
107//! - For auto reloading use the [`minijinja-autoreload`](https://docs.rs/minijinja-autoreload) crate.
108//! - For simpler embedding of templates use the [`minijinja-embed`](https://docs.rs/minijinja-embed) crate.
109//!
110//! Additionally there is an [list of examples](https://github.com/mitsuhiko/minijinja/tree/main/examples)
111//! with many different small example programs on GitHub to explore.
112//!
113//! # Error Handling
114//!
115//! MiniJinja tries to give you good errors out of the box.  However if you use includes or
116//! template inheritance your experience will improve greatly if you ensure to render chained
117//! errors.  For more information see [`Error`] with an example.
118//!
119//! # Size and Compile Times
120//!
121//! MiniJinja attempts to compile fast so it can be used as a sensible template engine choice
122//! when compile times matter.  Because of this it's internally modular so unnecessary bits and
123//! pieces can be removed.  The default set of features tries to strike a balance but in
124//! situations where only a subset is needed (eg: `build.rs`) all default features can be
125//! be disabled.
126//!
127//! # Optional Features
128//!
129//! MiniJinja comes with a lot of optional features, some of which are turned on by
130//! default.  If you plan on using MiniJinja in a library, please consider turning
131//! off all default features and to opt-in explicitly into the ones you actually
132//! need.
133//!
134//! <details><summary><strong style="cursor: pointer">Configurable Features</strong></summary>
135//!
136//! To cut down on size of the engine some default functionality can be removed:
137//!
138//! - **Engine Features:**
139//!
140//!   - `builtins`: if this feature is removed the default filters, tests and
141//!     functions are not implemented.
142//!   - `macros`: when removed the `{% macro %}` tag is not included.
143//!   - `multi_template`: when removed the templates related to imports and extends
144//!     are removed (`{% from %}`, `{% import %}`, `{% include %}`, and `{% extends %}`
145//!     as well as `{% block %}`).
146//!   - `adjacent_loop_items`: when removed the `previtem` and `nextitem` attributes of
147//!     the `loop` object no longer exist.  Removing this feature can provide faster
148//!     template execution when a lot of loops are involved.
149//!   - `unicode`: when added unicode identifiers are supported and the `sort`
150//!     filter's case insensitive comparison changes to using unicode and not
151//!     ASCII rules.  Without this features only ASCII identifiers can be used
152//!     for variable names and attributes.
153//!   - `serde`: enables or disables serde support.  In current versions of MiniJinja
154//!     it's not possible to disable serde but it will become possible.  To prevent
155//!     breakage, MiniJinja warns if this feature is disabled.
156//!
157//! - **Rust Functionality:**
158//!
159//!   - `debug`: if this feature is removed some debug functionality of the engine is
160//!     removed as well.  This mainly affects the quality of error reporting.
161//!   - `deserialization`: when removed this disables deserialization support for
162//!     the [`Value`] type, removes the `ViaDeserialize` type and the error type
163//!     no longer implements `serde::de::Error`.
164//!   - `std_collections`: if this feature is removed some [`Object`](crate::value::Object)
165//!     implementations for standard library collections are removed.  Only the
166//!     ones needed for the engine to function itself are retained.
167//!
168//! There are some additional features that provide extra functionality:
169//!
170//! - `fuel`: enables the `fuel` feature which makes the engine track fuel consumption which
171//!   can be used to better protect against expensive templates.
172//! - `loader`: enables owned and dynamic template loading of templates.
173//! - `custom_syntax`: when this feature is enabled, custom delimiters are supported by
174//!   the parser.
175//! - `preserve_order`: When enable the internal value implementation uses an indexmap
176//!   which preserves the original order of maps and structs.
177//! - `json`: When enabled the `tojson` filter is added as builtin filter as well as
178//!   the ability to auto escape via `AutoEscape::Json`.
179//! - `urlencode`: When enabled the `urlencode` filter is added as builtin filter.
180//! - `loop_controls`: enables the `{% break %}` and `{% continue %}` loop control flow
181//!   tags.
182//!
183//! Performance and memory related features:
184//!
185//! - `stacker`: enables automatic stack growth which permits much larger levels of recursion
186//!   at runtime.  This does not affect the maximum recursion at parsing time which is always
187//!   limited.
188//! - `speedups`: enables all speedups, in particular it turns on the `v_htmlescape` dependency
189//!   for faster HTML escaping.
190//!
191//! Internals:
192//!
193//! - `unstable_machinery`: exposes an unstable internal API (no semver guarantees) to parse
194//!   templates and interact with the engine internals.  If you need this functionality, please
195//!   leave some feedback on GitHub.
196//!
197//! </details>
198#![allow(clippy::cognitive_complexity)]
199#![allow(clippy::get_first)]
200#![allow(clippy::default_constructed_unit_structs)]
201#![allow(clippy::needless_borrowed_reference)]
202#![allow(clippy::vec_init_then_push)]
203#![cfg_attr(docsrs, feature(doc_cfg))]
204#![deny(missing_docs)]
205#![doc(html_logo_url = "https://github.com/mitsuhiko/minijinja/raw/main/artwork/logo-square.png")]
206
207#[macro_use]
208mod macros;
209
210mod compiler;
211mod defaults;
212mod environment;
213mod error;
214mod expression;
215mod output;
216mod template;
217mod utils;
218mod vm;
219
220pub mod filters;
221pub mod functions;
222pub mod syntax;
223pub mod tests;
224pub mod value;
225
226#[cfg(feature = "loader")]
227mod loader;
228
229#[cfg(feature = "loader")]
230pub use loader::path_loader;
231
232#[cfg(feature = "debug")]
233mod debug;
234
235pub use self::defaults::{default_auto_escape_callback, escape_formatter};
236pub use self::environment::Environment;
237pub use self::error::{Error, ErrorKind};
238pub use self::expression::Expression;
239pub use self::output::Output;
240pub use self::template::Template;
241pub use self::utils::{AutoEscape, HtmlEscape, UndefinedBehavior};
242
243/// Re-export for convenience.
244pub use self::value::Value;
245
246pub use self::macros::__context;
247pub use self::vm::State;
248
249/// This module gives access to the low level machinery.
250///
251/// This module is only provided by the `unstable_machinery` feature and does not
252/// have a stable interface.  It mostly exists for internal testing purposes and
253/// for debugging.
254#[cfg(feature = "unstable_machinery")]
255#[cfg_attr(docsrs, doc(cfg(feature = "unstable_machinery")))]
256pub mod machinery {
257    #![allow(missing_docs)]
258    pub use crate::compiler::ast;
259    pub use crate::compiler::codegen::CodeGenerator;
260    pub use crate::compiler::instructions::{Instruction, Instructions};
261    pub use crate::compiler::lexer::{tokenize, Tokenizer, WhitespaceConfig};
262    pub use crate::compiler::parser::{parse, parse_expr};
263    pub use crate::compiler::tokens::{Span, Token};
264    pub use crate::template::{CompiledTemplate, TemplateConfig};
265    pub use crate::vm::Vm;
266
267    use crate::Output;
268
269    /// Returns a reference to a [`CompiledTemplate`] from a [`Template`](crate::Template).
270    pub fn get_compiled_template<'x, 'env>(
271        tmpl: &'x crate::Template<'env, 'env>,
272    ) -> &'x CompiledTemplate<'env> {
273        &tmpl.compiled
274    }
275
276    /// Creates an [`Output`] that writes into a string.
277    pub fn make_string_output(s: &mut String) -> Output<'_> {
278        Output::new(s)
279    }
280}