use crate::ast::SchemaFile;
use crate::{ast::ASTNode, resolver::resolve_types};
use std::convert::TryFrom;
use std::ffi::OsStr;
use std::path::Path;
use std::path::PathBuf;
use walkdir::WalkDir;
#[derive(Debug, Eq, PartialEq, Default)]
pub struct ASTBuilder {
directories: Vec<PathBuf>,
}
#[allow(dead_code)]
impl ASTBuilder {
pub fn build(self) -> AST {
self.directories
.into_iter()
.map(|d| {
WalkDir::new(&d)
.follow_links(true)
.into_iter()
.filter_map(|e| e.ok())
.map(|e| {
e.path()
.to_str()
.map(|s| s.to_string())
.ok_or("Can't tranform into &str")
})
.filter_map(Result::ok)
.map(PathBuf::from)
.filter(|p| p.extension() == Some(OsStr::new("schema")))
.map(|p| (SchemaFile::try_from(p.clone()), p))
.map(|(schemas, buf)| match schemas {
Ok(data) => Ok(data),
Err(e) => {
eprintln!("{}: {:?}", e, buf);
Err(())
}
})
.filter_map(Result::ok)
.collect::<Vec<_>>()
})
.flatten()
.fold(AST::default(), |acc, val| {
acc.merge_schema(&val, &val.package_name)
})
}
pub fn with_directory<P: AsRef<Path>>(mut self, path: P) -> Self {
let path = path.as_ref().to_path_buf();
self.directories.push(path);
self
}
}
#[derive(Debug, Eq, PartialEq, Default)]
pub struct AST {
pub inner: Vec<ASTNode>,
}
impl AST {
pub fn generate<P: AsRef<Path> + Clone, S: AsRef<str>>(self, path: P, module: S) -> Result<(), std::io::Error> {
let new_ast = resolve_types(self, module);
let path_clone = path.clone();
if path_clone.as_ref().exists() {
std::fs::remove_dir_all(path)?;
}
for node in &new_ast.inner {
node.generate_node(path_clone.clone())?;
}
ASTNode::generate_mod_rs(&new_ast.inner, path_clone)
}
fn merge_schema<T: AsRef<str>>(self, schema: &SchemaFile, path: &[T]) -> Self {
if !path.is_empty() {
let is_path_present = self
.inner
.iter()
.map(|n| match n {
ASTNode::SchemaNode(_) => panic!("SchemaFile shouldn't be at the root of AST"),
ASTNode::PackageNode(pn) => pn.name == *path[0].as_ref(),
})
.fold(false, |acc, val| acc | val);
if is_path_present {
AST {
inner: self
.inner
.into_iter()
.map(|n| n.merge_schema(schema, path))
.collect::<Vec<ASTNode>>(),
}
} else {
let mut inner = self.inner;
inner.push(ASTNode::package_schema(schema, path));
AST { inner }
}
} else {
panic!("SchemaFile does not have a package name");
}
}
}