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//! [`Filter`](crate::filters::Filter)) 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//! - `key_interning`: if this feature is enabled the automatic string interning in
191//!   the value type is enabled.  This feature used to be turned on by default but
192//!   has negative performance effects in newer versions of MiniJinja since a lot of
193//!   the previous uses of key interning are no longer needed.  Enabling it however
194//!   cuts down on memory usage slightly in certain scenarios by interning all string
195//!   keys used in dynamic map values.
196//!
197//! Internals:
198//!
199//! - `unstable_machinery`: exposes an unstable internal API (no semver guarantees) to parse
200//!   templates and interact with the engine internals.  If you need this functionality, please
201//!   leave some feedback on GitHub.
202//!
203//! </details>
204#![allow(clippy::cognitive_complexity)]
205#![allow(clippy::get_first)]
206#![allow(clippy::default_constructed_unit_structs)]
207#![cfg_attr(docsrs, feature(doc_cfg))]
208#![deny(missing_docs)]
209#![doc(html_logo_url = "https://github.com/mitsuhiko/minijinja/raw/main/artwork/logo-square.png")]
210
211#[macro_use]
212mod macros;
213
214mod compiler;
215mod defaults;
216mod environment;
217mod error;
218mod expression;
219mod output;
220mod template;
221mod utils;
222mod vm;
223
224pub mod filters;
225pub mod functions;
226pub mod syntax;
227pub mod tests;
228pub mod value;
229
230#[cfg(feature = "loader")]
231mod loader;
232
233#[cfg(feature = "loader")]
234pub use loader::path_loader;
235
236#[cfg(feature = "debug")]
237mod debug;
238
239pub use self::defaults::{default_auto_escape_callback, escape_formatter};
240pub use self::environment::Environment;
241pub use self::error::{Error, ErrorKind};
242pub use self::expression::Expression;
243pub use self::output::Output;
244pub use self::template::Template;
245pub use self::utils::{AutoEscape, HtmlEscape, UndefinedBehavior};
246
247/// Re-export for convenience.
248pub use self::value::Value;
249
250pub use self::macros::__context;
251pub use self::vm::State;
252
253// fowards compatibility
254#[cfg(not(feature = "serde"))]
255const _: () = {
256    #[deprecated(
257        since = "2.0.4",
258        note = "Future versions of MiniJinja will require enabling \
259        the 'serde' feature to use serde types.  To silence this warning \
260        add 'serde' to the least of features of minijinja."
261    )]
262    #[allow(unused)]
263    fn enable_implicit_serde_support() {}
264
265    fn trigger_warning() {
266        enable_implicit_serde_support();
267    }
268};
269
270/// This module gives access to the low level machinery.
271///
272/// This module is only provided by the `unstable_machinery` feature and does not
273/// have a stable interface.  It mostly exists for internal testing purposes and
274/// for debugging.
275#[cfg(feature = "unstable_machinery")]
276#[cfg_attr(docsrs, doc(cfg(feature = "unstable_machinery")))]
277pub mod machinery {
278    #![allow(missing_docs)]
279    pub use crate::compiler::ast;
280    pub use crate::compiler::codegen::CodeGenerator;
281    pub use crate::compiler::instructions::{Instruction, Instructions};
282    pub use crate::compiler::lexer::{tokenize, Tokenizer, WhitespaceConfig};
283    pub use crate::compiler::parser::{parse, parse_expr};
284    pub use crate::compiler::tokens::{Span, Token};
285    pub use crate::template::{CompiledTemplate, TemplateConfig};
286    pub use crate::vm::Vm;
287
288    use crate::Output;
289
290    /// Returns a reference to a [`CompiledTemplate`] from a [`Template`](crate::Template).
291    pub fn get_compiled_template<'x, 'env>(
292        tmpl: &'x crate::Template<'env, 'env>,
293    ) -> &'x CompiledTemplate<'env> {
294        &tmpl.compiled
295    }
296
297    /// Creates an [`Output`] that writes into a string.
298    pub fn make_string_output(s: &mut String) -> Output<'_> {
299        Output::with_string(s)
300    }
301}