mini_builder_rs/
lib.rs

1//! # mini-builder-rs
2//! A static website generator.
3//!
4//! Programming languages use functions to avoid rewriting similar logic.
5//! HTML doesn't have a similar features. This crate provides a simple language
6//! that can be inserted into HTML (or really any) files in order to
7//! programmatically generate new files.
8//!
9//! For example, consider the following HTML:
10//! ```html
11//! <section>
12//!     <a href="page 1" class="selected">Page1</a>  
13//!     <a href="page 2" class="">Page2</a>  
14//!     <a href="page 3" class="">Page3</a>  
15//! </section>
16//! ```
17//! Without a static website generator, this html snippet would have to be copied
18//! and pasted into each of the pages with a minor change of which `a` tag will have
19//! the `selected` class. However with a static website generator, this snippet
20//! could be stored in a file for example `navigation.html` and then reused in every
21//! page. For example:
22//!
23//! `navigation.html`
24//! ```html
25//! <section>
26//!     <a href="page 1" class="{{ if page == 'page 1' ? 'selected' : ''}}">Page1</a>  
27//!     <a href="page 2" class="{{ if page == 'page 2' ? 'selected' : ''}}">Page2</a>  
28//!     <a href="page 3" class="{{ if page == 'page 3' ? 'selected' : ''}}">Page3</a>  
29//! </section>
30//! ```
31//!
32//! `page1.html`
33//! ```html
34//! ...
35//! {{@ navigation(page = 'page 1')}}
36//! ...
37//! ```
38//!
39//! # Examples
40//! For some code examples check out the `examples` directory.
41//!
42//! # Builder
43//! The `Builder` handles
44//! ```rust
45//! mini_builder_rs::builder::Builder::new(
46//! 	// sources - the source for the pages that will be generated
47//! 	Some("./examples/example_site/sources".into()),
48//! 	// templates - the partial files that can be referenced
49//! 	//             from sources or other templates
50//! 	Some("./examples/example_site/templates".into()),
51//! 	// generated - where the transformed sources will be placed
52//! 	Some("./examples/example_site/generated".into()),
53//! 	// variables - a file containing global variables and their values
54//! 	Some("./examples/example_site/variables".into()),
55//! 	// see mini_builder_rs::builder::BuilderOptions
56//! 	Default::default(),
57//! )
58//! .unwrap()
59//! // variable that will be available for every source and template
60//! // (unless shadowed)
61//! .add_variable("title", Value::text("Website Title"))
62//! .add_variable(
63//! 	"files",
64//! 	Value::List(DATA.iter().map(|x| Value::text(x.0)).collect::<Vec<_>>()),
65//! )
66//! // functions that can be called from every source and template
67//! .add_function("get_file_size", Box::new(get_file_size) as _)
68//! // watch for changes in the sources and templates directories,
69//! // updating the generated directory live
70//! .watch()
71//! .unwrap();
72//!
73//! ...
74//!
75//! fn get_file_size(values: &[Value]) -> Value {
76//!     if let Some(Value::Text(name)) = values.get(0) {
77//!         for (file_name, file_size) in DATA {
78//!             if file_name == name {
79//!                 return Value::Number(*file_size);
80//!             }
81//!         }
82//!     }
83//!     Value::None
84//! }
85//! ```
86//!
87//! # Sources and Templates
88//! Sources the files that correspond to the output files. Templates are files that
89//! are used in order by sources or other templates to generate text. For example if
90//! the sources are `page_1.html`, `page_2.html` and the templates are
91//! `navigation.html`, and `footer.html`, then after the site has finished, the
92//! output will be the expanded versions of only `page_1.html` and `page_2.html`.
93//!
94//! Templates are called with the syntax `@ template(key1 = value1, ...)`.
95//!
96//! The name of the template is either given explicitly when passed as a string,
97//! or is the path of the file relative to the templates directory when it loaded
98//! from a file ignoring extensions (for example the template
99//! `template/sub_dir1/temp1.html` name would be `sub_dir1/tmp1`).
100//!
101//! # Variables and Functions
102//! Values are defined with the following enum:
103//! ```rust
104//! pub enum Value {
105//!     Number(f32),
106//!     Bool(bool),
107//!     Text(String),
108//!     List(Vec<Value>),
109//!     None,
110//! }
111//! ```
112//! Functions are defined by the type: `Box<dyn Fn(&[Value]) -> Value + 'static>`.
113//! Strings are delimited with the `'` character. In order to use the `'` inside
114//! a string, it can be delimited with multiple `'`s. For example:
115//! ```
116//! ''_'a'_'' // will result in the literal _'a'_
117//! '''_''a''_''' // will result in the literal _''a''_
118//! ```
119//!
120//! ## Directives
121//! A directive is a piece of code with the pattern `{{...}}` that adds logic to
122//! plain files. Control flow directives such as `if` statements use a slightly
123//! different pattern: `{{# ...}}`. The language used inside the directives can be
124//! summarized in a few examples:
125//! * Expressions:
126//! ```html
127//! <!-- if the variables `a` and `b` are defined, they will be added and returned
128//! -->
129//! <p> a + b = {{ a + b }} </p>
130//! ```
131//! * If statements:
132//! ```html
133//! {{# if page == 'page 1' }}
134//!     <!-- if the variable `page` exists and equals to 'page 1' this section will
135//! 	be evaluated  -->
136//!     ...
137//! {{# elif page == 'page 2'}}
138//!     <!-- elif is short for else if -->
139//!     ...
140//! {{# else }}
141//!     ....
142//! {{#}}
143//! ```
144//! * For loops:
145//! ```html
146//! <!-- the for each loop will be evaluated if the variable `files` exists and is
147//! a list -->
148//! {{# for file in files}}
149//!     <h2>{{ file }}</h2>
150//! {{#}}
151//! ```
152//! * Ternary:
153//! ```html
154//! {# if a != None && b != None}}
155//!     <p>a is{{ a > b ? 'greater than : a < b ? 'smaller than' : 'equals to'}} b</p>
156//! {{# else}}
157//!     <p>a or b are none</p>
158//! {{#}}
159//! ```
160//! * Templates:
161//! ```html
162//! <!-- Templates are not control flow, they are expressions and therefore can be
163//! with other expressions. if no variables are passed to a template then both the
164//! syntaxes `@ template` and `@ template()` are valid. -->
165//! {{ use_pretty_header ? @ pretty_header : @ normal_header}}
166//!
167//! <!-- call the `footer` template with a single variable called
168//! `use_pretty_footer` whose value equals to the variable `use_pretty_header`
169//! value's -->
170//! {{@ footer(use_pretty_footer = use_pretty_header)}}
171//! ```
172
173pub mod builder;
174pub mod evaluator;
175pub mod parser;
176pub mod tokenizer;
177pub mod value;