]> git.proxmox.com Git - rustc.git/blob - vendor/askama/src/lib.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / vendor / askama / src / lib.rs
1 //! Askama implements a type-safe compiler for Jinja-like templates.
2 //! It lets you write templates in a Jinja-like syntax,
3 //! which are linked to a `struct` defining the template context.
4 //! This is done using a custom derive implementation (implemented
5 //! in [`askama_derive`](https://crates.io/crates/askama_derive)).
6 //!
7 //! For feature highlights and a quick start, please review the
8 //! [README](https://github.com/djc/askama/blob/main/README.md).
9 //!
10 //! The primary documentation for this crate now lives in
11 //! [the book](https://djc.github.io/askama/).
12 //!
13 //! # Creating Askama templates
14 //!
15 //! An Askama template is a `struct` definition which provides the template
16 //! context combined with a UTF-8 encoded text file (or inline source, see
17 //! below). Askama can be used to generate any kind of text-based format.
18 //! The template file's extension may be used to provide content type hints.
19 //!
20 //! A template consists of **text contents**, which are passed through as-is,
21 //! **expressions**, which get replaced with content while being rendered, and
22 //! **tags**, which control the template's logic.
23 //! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
24 //! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
25 //! [Tera](https://github.com/Keats/tera).
26 //!
27 //! ## The `template()` attribute
28 //!
29 //! Askama works by generating one or more trait implementations for any
30 //! `struct` type decorated with the `#[derive(Template)]` attribute. The
31 //! code generation process takes some options that can be specified through
32 //! the `template()` attribute. The following sub-attributes are currently
33 //! recognized:
34 //!
35 //! * `path` (as `path = "foo.html"`): sets the path to the template file. The
36 //! path is interpreted as relative to the configured template directories
37 //! (by default, this is a `templates` directory next to your `Cargo.toml`).
38 //! The file name extension is used to infer an escape mode (see below). In
39 //! web framework integrations, the path's extension may also be used to
40 //! infer the content type of the resulting response.
41 //! Cannot be used together with `source`.
42 //! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
43 //! This can be useful for test cases or short templates. The generated path
44 //! is undefined, which generally makes it impossible to refer to this
45 //! template from other templates. If `source` is specified, `ext` must also
46 //! be specified (see below). Cannot be used together with `path`.
47 //! * `ext` (as `ext = "txt"`): lets you specify the content type as a file
48 //! extension. This is used to infer an escape mode (see below), and some
49 //! web framework integrations use it to determine the content type.
50 //! Cannot be used together with `path`.
51 //! * `print` (as `print = "code"`): enable debugging by printing nothing
52 //! (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
53 //! or `all` for both. The requested data will be printed to stdout at
54 //! compile time.
55 //! * `escape` (as `escape = "none"`): override the template's extension used for
56 //! the purpose of determining the escaper for this template. See the section
57 //! on configuring custom escapers for more information.
58 //! * `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
59 //! in the configuration file. The default syntax , "default", is the one
60 //! provided by Askama.
61
62 #![allow(unused_imports)]
63 #![deny(elided_lifetimes_in_paths)]
64
65 #[macro_use]
66 extern crate askama_derive;
67 pub use askama_shared as shared;
68
69 use std::fs::{self, DirEntry};
70 use std::io;
71 use std::path::Path;
72
73 pub use askama_escape::{Html, Text};
74
75 /// Main `Template` trait; implementations are generally derived
76 ///
77 /// If you need an object-safe template, use [`DynTemplate`].
78 pub trait Template {
79 /// Helper method which allocates a new `String` and renders into it
80 fn render(&self) -> Result<String> {
81 let mut buf = String::with_capacity(Self::SIZE_HINT);
82 self.render_into(&mut buf)?;
83 Ok(buf)
84 }
85
86 /// Renders the template to the given `writer` buffer
87 fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>;
88
89 /// The template's extension, if provided
90 const EXTENSION: Option<&'static str>;
91
92 /// Provides a conservative estimate of the expanded length of the rendered template
93 const SIZE_HINT: usize;
94 }
95
96 /// Object-safe wrapper trait around [`Template`] implementers
97 ///
98 /// This trades reduced performance (mostly due to writing into `dyn Write`) for object safety.
99 pub trait DynTemplate {
100 /// Helper method which allocates a new `String` and renders into it
101 fn dyn_render(&self) -> Result<String>;
102
103 /// Renders the template to the given `writer` buffer
104 fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>;
105
106 /// Helper function to inspect the template's extension
107 fn extension(&self) -> Option<&'static str>;
108
109 /// Provides a conservative estimate of the expanded length of the rendered template
110 fn size_hint(&self) -> usize;
111 }
112
113 impl<T: Template> DynTemplate for T {
114 fn dyn_render(&self) -> Result<String> {
115 <Self as Template>::render(self)
116 }
117
118 fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()> {
119 <Self as Template>::render_into(self, writer)
120 }
121
122 fn extension(&self) -> Option<&'static str> {
123 Self::EXTENSION
124 }
125
126 fn size_hint(&self) -> usize {
127 Self::SIZE_HINT
128 }
129 }
130
131 pub use crate::shared::filters;
132 pub use crate::shared::helpers;
133 pub use crate::shared::{read_config_file, Error, MarkupDisplay, Result};
134 pub use askama_derive::*;
135
136 pub mod mime {
137 #[cfg(all(feature = "mime_guess", feature = "mime"))]
138 pub fn extension_to_mime_type(ext: &str) -> mime_guess::Mime {
139 let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();
140 for (simple, utf_8) in &TEXT_TYPES {
141 if &basic_type == simple {
142 return utf_8.clone();
143 }
144 }
145 basic_type
146 }
147
148 #[cfg(all(feature = "mime_guess", feature = "mime"))]
149 const TEXT_TYPES: [(mime_guess::Mime, mime_guess::Mime); 6] = [
150 (mime::TEXT_PLAIN, mime::TEXT_PLAIN_UTF_8),
151 (mime::TEXT_HTML, mime::TEXT_HTML_UTF_8),
152 (mime::TEXT_CSS, mime::TEXT_CSS_UTF_8),
153 (mime::TEXT_CSV, mime::TEXT_CSV_UTF_8),
154 (
155 mime::TEXT_TAB_SEPARATED_VALUES,
156 mime::TEXT_TAB_SEPARATED_VALUES_UTF_8,
157 ),
158 (
159 mime::APPLICATION_JAVASCRIPT,
160 mime::APPLICATION_JAVASCRIPT_UTF_8,
161 ),
162 ];
163 }
164
165 /// Old build script helper to rebuild crates if contained templates have changed
166 ///
167 /// This function is now deprecated and does nothing.
168 #[deprecated(
169 since = "0.8.1",
170 note = "file-level dependency tracking is handled automatically without build script"
171 )]
172 pub fn rerun_if_templates_changed() {}
173
174 #[cfg(test)]
175 mod tests {
176 use super::{DynTemplate, Template};
177
178 #[test]
179 fn dyn_template() {
180 struct Test;
181 impl Template for Test {
182 fn render_into(
183 &self,
184 writer: &mut (impl std::fmt::Write + ?Sized),
185 ) -> askama_shared::Result<()> {
186 Ok(writer.write_str("test")?)
187 }
188
189 const EXTENSION: Option<&'static str> = Some("txt");
190
191 const SIZE_HINT: usize = 4;
192 }
193
194 fn render(t: &dyn DynTemplate) -> String {
195 t.dyn_render().unwrap()
196 }
197
198 assert_eq!(render(&Test), "test");
199 }
200 }