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

#[macro_use]
mod macros;

mod compiler;
mod defaults;
mod environment;
mod error;
mod expression;
mod output;
mod template;
mod utils;
mod vm;

pub mod filters;
pub mod functions;
pub mod syntax;
pub mod tests;
pub mod value;

#[cfg(feature = "loader")]
mod loader;

#[cfg(feature = "loader")]
pub use loader::path_loader;

#[cfg(feature = "debug")]
mod debug;

pub use self::defaults::{default_auto_escape_callback, escape_formatter};
pub use self::environment::Environment;
pub use self::error::{Error, ErrorKind};
pub use self::expression::Expression;
pub use self::output::Output;
pub use self::template::Template;
pub use self::utils::{AutoEscape, HtmlEscape, UndefinedBehavior};

/// Re-export for convenience.
pub use self::value::Value;

pub use self::macros::__context;
pub use self::vm::State;

// fowards compatibility
#[cfg(not(feature = "serde"))]
const _: () = {
    #[deprecated(
        since = "2.0.4",
        note = "Future versions of MiniJinja will require enabling \
        the 'serde' feature to use serde types.  To silence this warning \
        add 'serde' to the least of features of minijinja."
    )]
    #[allow(unused)]
    fn enable_implicit_serde_support() {}

    fn trigger_warning() {
        enable_implicit_serde_support();
    }
};

/// This module gives access to the low level machinery.
///
/// This module is only provided by the `unstable_machinery` feature and does not
/// have a stable interface.  It mostly exists for internal testing purposes and
/// for debugging.
#[cfg(feature = "unstable_machinery")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable_machinery")))]
pub mod machinery {
    #![allow(missing_docs)]
    pub use crate::compiler::ast;
    pub use crate::compiler::codegen::CodeGenerator;
    pub use crate::compiler::instructions::{Instruction, Instructions};
    pub use crate::compiler::lexer::{tokenize, Tokenizer, WhitespaceConfig};
    pub use crate::compiler::parser::{parse, parse_expr};
    pub use crate::compiler::tokens::{Span, Token};
    pub use crate::template::{CompiledTemplate, TemplateConfig};
    pub use crate::vm::Vm;

    use crate::Output;

    /// Returns a reference to a [`CompiledTemplate`] from a [`Template`](crate::Template).
    pub fn get_compiled_template<'x, 'env>(
        tmpl: &'x crate::Template<'env, 'env>,
    ) -> &'x CompiledTemplate<'env> {
        &tmpl.compiled
    }

    /// Creates an [`Output`] that writes into a string.
    pub fn make_string_output(s: &mut String) -> Output<'_> {
        Output::with_string(s)
    }
}