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
//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! For feature highlights and a quick start, please review the
//! [README](https://github.com/djc/askama/blob/main/README.md).
//!
//! The primary documentation for this crate now lives in
//! [the book](https://djc.github.io/askama/).
//!
//! # Creating Askama templates
//!
//! An Askama template is a `struct` definition which provides the template
//! context combined with a UTF-8 encoded text file (or inline source, see
//! below). Askama can be used to generate any kind of text-based format.
//! The template file's extension may be used to provide content type hints.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## The `template()` attribute
//!
//! Askama works by generating one or more trait implementations for any
//! `struct` type decorated with the `#[derive(Template)]` attribute. The
//! code generation process takes some options that can be specified through
//! the `template()` attribute. The following sub-attributes are currently
//! recognized:
//!
//! * `path` (as `path = "foo.html"`): sets the path to the template file. The
//! path is interpreted as relative to the configured template directories
//! (by default, this is a `templates` directory next to your `Cargo.toml`).
//! The file name extension is used to infer an escape mode (see below). In
//! web framework integrations, the path's extension may also be used to
//! infer the content type of the resulting response.
//! Cannot be used together with `source`.
//! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
//! This can be useful for test cases or short templates. The generated path
//! is undefined, which generally makes it impossible to refer to this
//! template from other templates. If `source` is specified, `ext` must also
//! be specified (see below). Cannot be used together with `path`.
//! * `ext` (as `ext = "txt"`): lets you specify the content type as a file
//! extension. This is used to infer an escape mode (see below), and some
//! web framework integrations use it to determine the content type.
//! Cannot be used together with `path`.
//! * `print` (as `print = "code"`): enable debugging by printing nothing
//! (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
//! or `all` for both. The requested data will be printed to stdout at
//! compile time.
//! * `escape` (as `escape = "none"`): override the template's extension used for
//! the purpose of determining the escaper for this template. See the section
//! on configuring custom escapers for more information.
//! * `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
//! in the configuration file. The default syntax , "default", is the one
//! provided by Askama.
#![forbid(unsafe_code)]
#![deny(elided_lifetimes_in_paths)]
#![deny(unreachable_pub)]
pub use askama_shared as shared;
pub use askama_escape::{Html, Text};
/// Main `Template` trait; implementations are generally derived
///
/// If you need an object-safe template, use [`DynTemplate`].
pub trait Template {
/// Helper method which allocates a new `String` and renders into it
fn render(&self) -> Result<String> {
let mut buf = String::with_capacity(Self::SIZE_HINT);
self.render_into(&mut buf)?;
Ok(buf)
}
/// Renders the template to the given `writer` buffer
fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>;
/// The template's extension, if provided
const EXTENSION: Option<&'static str>;
/// Provides a conservative estimate of the expanded length of the rendered template
const SIZE_HINT: usize;
/// The MIME type (Content-Type) of the data that gets rendered by this Template
const MIME_TYPE: &'static str;
}
/// Object-safe wrapper trait around [`Template`] implementers
///
/// This trades reduced performance (mostly due to writing into `dyn Write`) for object safety.
pub trait DynTemplate {
/// Helper method which allocates a new `String` and renders into it
fn dyn_render(&self) -> Result<String>;
/// Renders the template to the given `writer` buffer
fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>;
/// Helper function to inspect the template's extension
fn extension(&self) -> Option<&'static str>;
/// Provides a conservative estimate of the expanded length of the rendered template
fn size_hint(&self) -> usize;
/// The MIME type (Content-Type) of the data that gets rendered by this Template
fn mime_type(&self) -> &'static str;
}
impl<T: Template> DynTemplate for T {
fn dyn_render(&self) -> Result<String> {
<Self as Template>::render(self)
}
fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()> {
<Self as Template>::render_into(self, writer)
}
fn extension(&self) -> Option<&'static str> {
Self::EXTENSION
}
fn size_hint(&self) -> usize {
Self::SIZE_HINT
}
fn mime_type(&self) -> &'static str {
Self::MIME_TYPE
}
}
pub use crate::shared::filters;
pub use crate::shared::helpers;
pub use crate::shared::{read_config_file, Error, MarkupDisplay, Result};
pub use askama_derive::*;
#[deprecated(since = "0.11.1", note = "The only function in this mod is deprecated")]
pub mod mime {
#[cfg(all(feature = "mime_guess", feature = "mime"))]
#[deprecated(since = "0.11.1", note = "Use Template::MIME_TYPE instead")]
pub use crate::shared::extension_to_mime_type;
}
/// Old build script helper to rebuild crates if contained templates have changed
///
/// This function is now deprecated and does nothing.
#[deprecated(
since = "0.8.1",
note = "file-level dependency tracking is handled automatically without build script"
)]
pub fn rerun_if_templates_changed() {}
#[cfg(test)]
mod tests {
use super::{DynTemplate, Template};
#[test]
fn dyn_template() {
struct Test;
impl Template for Test {
fn render_into(
&self,
writer: &mut (impl std::fmt::Write + ?Sized),
) -> askama_shared::Result<()> {
Ok(writer.write_str("test")?)
}
const EXTENSION: Option<&'static str> = Some("txt");
const SIZE_HINT: usize = 4;
const MIME_TYPE: &'static str = "text/plain; charset=utf-8";
}
fn render(t: &dyn DynTemplate) -> String {
t.dyn_render().unwrap()
}
assert_eq!(render(&Test), "test");
}
}