2020-04-05 19:12:48 -04:00
|
|
|
extern crate nom;
|
2020-04-10 19:07:02 -04:00
|
|
|
|
2020-04-12 21:54:15 -04:00
|
|
|
use parser::Filter;
|
2020-04-10 20:27:27 -04:00
|
|
|
use renderer::compile_template;
|
|
|
|
use renderer::CompiledTemplate;
|
2020-04-11 22:47:31 -04:00
|
|
|
use renderer::ContextElement;
|
2020-04-10 20:58:55 -04:00
|
|
|
use renderer::DustRenderer;
|
2020-04-28 19:34:52 -04:00
|
|
|
use renderer::Loopable;
|
2020-04-12 18:29:40 -04:00
|
|
|
use renderer::RenderError;
|
2020-04-11 19:11:14 -04:00
|
|
|
use renderer::Renderable;
|
2020-04-11 22:47:31 -04:00
|
|
|
use renderer::Walkable;
|
2020-04-10 20:27:27 -04:00
|
|
|
use std::env;
|
|
|
|
use std::fs;
|
2020-04-10 19:07:02 -04:00
|
|
|
use std::io::{self, Read};
|
2020-04-10 20:27:27 -04:00
|
|
|
use std::path::Path;
|
2020-04-05 19:12:48 -04:00
|
|
|
|
|
|
|
mod parser;
|
2020-04-10 20:27:27 -04:00
|
|
|
mod renderer;
|
2020-04-05 19:12:48 -04:00
|
|
|
|
|
|
|
fn main() {
|
2020-04-10 19:07:02 -04:00
|
|
|
let context = read_context_from_stdin();
|
2020-04-10 20:27:27 -04:00
|
|
|
|
|
|
|
let argv: Vec<String> = env::args().collect();
|
|
|
|
if argv.len() < 2 {
|
|
|
|
panic!("Need to pass templates");
|
|
|
|
}
|
|
|
|
let template_paths = &argv[1..];
|
|
|
|
let template_contents: Vec<(String, String)> = template_paths
|
|
|
|
.iter()
|
|
|
|
.map(|p| {
|
|
|
|
let template_content = fs::read_to_string(&p).unwrap();
|
|
|
|
(p.to_string(), template_content)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let compiled_templates: Vec<CompiledTemplate> = template_contents
|
|
|
|
.iter()
|
|
|
|
.map(|(p, contents)| template_from_file(p, contents))
|
|
|
|
.collect();
|
2020-04-11 18:25:48 -04:00
|
|
|
let mut dust_renderer = DustRenderer::new();
|
2020-04-10 20:55:44 -04:00
|
|
|
compiled_templates.iter().for_each(|template| {
|
2020-04-11 18:25:48 -04:00
|
|
|
dust_renderer.load_source(template);
|
2020-04-10 20:55:44 -04:00
|
|
|
});
|
2020-04-11 18:25:48 -04:00
|
|
|
let main_template_name = &compiled_templates
|
|
|
|
.first()
|
|
|
|
.expect("There should be more than 1 template")
|
|
|
|
.name;
|
|
|
|
println!(
|
|
|
|
"{}",
|
|
|
|
dust_renderer
|
2020-04-11 18:40:36 -04:00
|
|
|
.render(main_template_name, &context)
|
2020-04-11 18:25:48 -04:00
|
|
|
.expect("Failed to render")
|
|
|
|
);
|
2020-04-10 20:27:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn template_from_file<'a>(file_path: &str, file_contents: &'a str) -> CompiledTemplate<'a> {
|
|
|
|
let path: &Path = Path::new(file_path);
|
|
|
|
let name = path.file_stem().unwrap();
|
|
|
|
compile_template(file_contents, name.to_string_lossy().to_string())
|
2020-04-11 18:25:48 -04:00
|
|
|
.expect("Failed to compile template")
|
2020-04-10 19:07:02 -04:00
|
|
|
}
|
|
|
|
|
2020-04-11 22:52:20 -04:00
|
|
|
fn read_context_from_stdin() -> serde_json::Value {
|
2020-04-10 19:07:02 -04:00
|
|
|
let mut buffer = String::new();
|
|
|
|
io::stdin()
|
|
|
|
.read_to_string(&mut buffer)
|
|
|
|
.expect("Failed to read stdin");
|
|
|
|
|
|
|
|
let parsed: serde_json::Value = serde_json::from_str(&buffer).expect("Failed to parse json");
|
|
|
|
match parsed {
|
2020-04-11 22:52:20 -04:00
|
|
|
serde_json::Value::Object(obj) => serde_json::value::Value::Object(obj),
|
2020-04-10 19:07:02 -04:00
|
|
|
_ => panic!("Expected context to be an object"),
|
|
|
|
}
|
2020-04-05 19:12:48 -04:00
|
|
|
}
|
2020-04-11 19:11:14 -04:00
|
|
|
|
2020-04-11 22:47:31 -04:00
|
|
|
impl ContextElement for serde_json::Value {}
|
|
|
|
|
2020-04-11 19:11:14 -04:00
|
|
|
impl Renderable for serde_json::Value {
|
2020-04-12 21:57:42 -04:00
|
|
|
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
2020-04-11 19:19:40 -04:00
|
|
|
match self {
|
2020-04-12 21:03:55 -04:00
|
|
|
serde_json::Value::Null => Ok("".to_owned()),
|
|
|
|
serde_json::Value::Bool(boolean) => Ok(boolean.to_string()),
|
|
|
|
serde_json::Value::Number(num) => Ok(num.to_string()),
|
|
|
|
serde_json::Value::String(string) => Ok(string.to_string()),
|
2020-04-12 21:40:34 -04:00
|
|
|
serde_json::Value::Array(arr) => {
|
2020-04-12 21:54:15 -04:00
|
|
|
// TODO: Handle the filters instead of passing a Vec::new()
|
2020-04-12 21:40:34 -04:00
|
|
|
let rendered: Result<Vec<String>, RenderError> =
|
2020-04-12 21:54:15 -04:00
|
|
|
arr.iter().map(|val| val.render(&Vec::new())).collect();
|
2020-04-12 21:40:34 -04:00
|
|
|
let rendered_slice: &[String] = &rendered?;
|
|
|
|
Ok(rendered_slice.join(","))
|
|
|
|
}
|
|
|
|
serde_json::Value::Object(_obj) => Ok("[object Object]".to_owned()),
|
2020-04-11 19:19:40 -04:00
|
|
|
}
|
2020-04-11 19:11:14 -04:00
|
|
|
}
|
|
|
|
}
|
2020-04-11 22:47:31 -04:00
|
|
|
|
|
|
|
impl Walkable for serde_json::Value {
|
2020-04-12 18:29:40 -04:00
|
|
|
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, RenderError> {
|
2020-04-11 22:47:31 -04:00
|
|
|
match self {
|
2020-04-12 20:52:30 -04:00
|
|
|
serde_json::Value::Null => Err(RenderError::CantWalk {
|
|
|
|
segment: segment.to_string(),
|
|
|
|
elem: self,
|
|
|
|
}),
|
|
|
|
serde_json::Value::Bool(_boolean) => Err(RenderError::CantWalk {
|
|
|
|
segment: segment.to_string(),
|
|
|
|
elem: self,
|
|
|
|
}),
|
|
|
|
serde_json::Value::Number(_num) => Err(RenderError::CantWalk {
|
|
|
|
segment: segment.to_string(),
|
|
|
|
elem: self,
|
|
|
|
}),
|
|
|
|
serde_json::Value::String(_string) => Err(RenderError::CantWalk {
|
|
|
|
segment: segment.to_string(),
|
|
|
|
elem: self,
|
|
|
|
}),
|
2020-04-11 22:47:31 -04:00
|
|
|
serde_json::Value::Array(_arr) => todo!("Arrays not supported yet"),
|
2020-04-12 20:52:30 -04:00
|
|
|
serde_json::Value::Object(obj) => {
|
|
|
|
obj.get(segment)
|
|
|
|
.map(|val| val as _)
|
|
|
|
.ok_or(RenderError::WontWalk {
|
|
|
|
segment: segment.to_string(),
|
|
|
|
elem: self,
|
|
|
|
})
|
|
|
|
}
|
2020-04-11 22:47:31 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-28 19:34:52 -04:00
|
|
|
|
|
|
|
impl Loopable for serde_json::Value {
|
|
|
|
fn get_loop_elements(&self) -> Result<Vec<&dyn ContextElement>, RenderError> {
|
|
|
|
match self {
|
|
|
|
serde_json::Value::Null => Ok(Vec::new()),
|
|
|
|
serde_json::Value::Bool(boolean) => {
|
|
|
|
if *boolean {
|
|
|
|
Ok(vec![self])
|
|
|
|
} else {
|
|
|
|
Ok(Vec::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_json::Value::Number(_num) => Ok(vec![self]),
|
|
|
|
serde_json::Value::String(string_value) => {
|
|
|
|
if string_value.is_empty() {
|
|
|
|
Ok(Vec::new())
|
|
|
|
} else {
|
|
|
|
Ok(vec![self])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_json::Value::Array(array_value) => {
|
|
|
|
if array_value.is_empty() {
|
|
|
|
Ok(Vec::new())
|
|
|
|
} else {
|
|
|
|
Ok(array_value.iter().map(|x| x as _).collect())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_json::Value::Object(_obj) => Ok(vec![self]),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|