use crate::generator::{NamespaceNode, Node, TestTree};
use crate::util::Escaper;
use codegen::Scope;
use miette::IntoDiagnostic;
use std::fs::{DirBuilder, File};
use std::io::Write;
use std::path::{Path, PathBuf};
const FILE_HEADER: &str = "\
// ********************************************************************************************** //
// *NOTE*: This file is generated by partiql-conformance-test-generator. Do not edit directly.
// ********************************************************************************************** //
#[allow(unused_imports)]
use super::*;
";
#[derive(Debug)]
pub struct Writer {}
impl Writer {
pub fn new() -> Self {
Self {}
}
pub fn write(&self, path: impl AsRef<Path>, mut root: NamespaceNode) -> miette::Result<()> {
let path: PathBuf = path
.as_ref()
.components()
.map(|c| c.as_os_str().to_string_lossy().to_string().escape_path())
.collect();
std::fs::create_dir_all(&path).into_diagnostic()?;
write_module(&path, &mut root)?;
Ok(())
}
}
fn write_module(path: impl AsRef<Path>, module: &mut NamespaceNode) -> miette::Result<bool> {
DirBuilder::new()
.recursive(true)
.create(&path)
.into_diagnostic()?;
let mut sub_mods = vec![];
for (name, child) in &mut module.children {
let mut child_path: PathBuf = path.as_ref().into();
child_path.push(name);
let is_sub_mod = match child {
TestTree::Node(Node::Test(s)) => write_scope(child_path, s.module.scope())?,
TestTree::Node(Node::Value(e)) => write_file(child_path, &e.value)?,
TestTree::Namespace(m) => write_module(child_path, m)?,
};
if is_sub_mod {
sub_mods.push(name.clone());
}
}
if !sub_mods.is_empty() {
write_dir_mod(&path, sub_mods.iter())?;
}
Ok(!sub_mods.is_empty())
}
fn write_dir_mod<'a>(
path: impl AsRef<Path>,
sub_mods: impl Iterator<Item = &'a String>,
) -> miette::Result<bool> {
std::fs::create_dir_all(&path).into_diagnostic()?;
let mut contents = FILE_HEADER.to_string();
for sub_mod in sub_mods {
contents.push_str(&format!("mod {};\n", sub_mod.replace(".rs", "")))
}
let file_path = path.as_ref().join("mod.rs");
File::create(file_path)
.into_diagnostic()?
.write_all(contents.as_bytes())
.into_diagnostic()?;
Ok(true)
}
fn write_scope(path: impl AsRef<Path>, scope: &Scope) -> miette::Result<bool> {
let contents = format!("{}{}", FILE_HEADER, scope.to_string());
write_file(path, &contents)?;
Ok(true)
}
fn write_file(path: impl AsRef<Path>, contents: &str) -> miette::Result<bool> {
let mut file = File::create(path).into_diagnostic()?;
file.write_all(contents.as_bytes()).into_diagnostic()?;
file.sync_all().into_diagnostic()?;
Ok(false)
}