use indexmap::IndexMap;
use serde_yaml::Value;
use crate::tree::{Tree, TreeConfig};
use crate::lexers::*;
use crate::generators::*;
pub struct Blueprint {
pub config: BlueprintConfig,
}
pub struct BlueprintConfig {
pub generators: Vec<String>,
pub only: Vec<String>,
pub skip: Vec<String>,
}
impl Default for BlueprintConfig {
fn default() -> Self {
Self {
generators: vec![
"models".to_string(),
"migrations".to_string(),
"factories".to_string(),
"controllers".to_string(),
"routes".to_string(),
"form_requests".to_string(),
"tests".to_string(),
"seeders".to_string(),
],
only: vec![],
skip: vec![],
}
}
}
impl Blueprint {
pub fn new(config: BlueprintConfig) -> Self {
Self { config }
}
pub fn parse(&self, content: &str) -> Result<IndexMap<String, Value>, anyhow::Error> {
let value: Value = serde_yaml::from_str(content)?;
match value {
Value::Mapping(map) => {
let mut result = IndexMap::new();
for (k, v) in map {
if let Some(key_str) = k.as_str() {
result.insert(key_str.to_string(), v);
}
}
Ok(result)
}
_ => Err(anyhow::anyhow!("Expected a YAML mapping at the root")),
}
}
pub fn analyze(&self, tokens: &IndexMap<String, Value>) -> Tree {
let mut tree = Tree::new();
for (key, value) in tokens {
match key.as_str() {
"models" => {
if let Value::Mapping(models) = value {
let mut map = IndexMap::new();
for (k, v) in models {
if let Some(k_str) = k.as_str() {
map.insert(k_str.to_string(), v.clone());
}
}
tree.models = ModelLexer::analyze(&map);
}
}
"controllers" => {
if let Value::Mapping(controllers) = value {
let mut map = IndexMap::new();
for (k, v) in controllers {
if let Some(k_str) = k.as_str() {
map.insert(k_str.to_string(), v.clone());
}
}
tree.controllers = ControllerLexer::analyze(&map);
}
}
"seeders" => {
if let Value::Sequence(seeders) = value {
tree.seeders = SeederLexer::analyze(seeders);
}
}
"config" => {
if let Value::Mapping(config) = value {
Self::parse_config(&mut tree.config, config);
}
}
_ => {}
}
}
tree
}
pub fn generate(&self, tree: &Tree) -> IndexMap<String, String> {
let mut files = IndexMap::new();
if self.should_generate("models") {
files.extend(ModelGenerator::generate(tree));
}
if self.should_generate("migrations") {
files.extend(MigrationGenerator::generate(tree));
}
if self.should_generate("factories") {
files.extend(FactoryGenerator::generate(tree));
}
if self.should_generate("controllers") {
files.extend(ControllerGenerator::generate(tree));
}
if self.should_generate("routes") {
files.extend(RouteGenerator::generate(tree));
}
if self.should_generate("form_requests") {
files.extend(FormRequestGenerator::generate(tree));
}
if self.should_generate("tests") {
files.extend(TestGenerator::generate(tree));
}
if self.should_generate("seeders") {
files.extend(SeederGenerator::generate(tree));
}
files
}
pub fn build(&self, content: &str) -> Result<IndexMap<String, String>, anyhow::Error> {
let tokens = self.parse(content)?;
let tree = self.analyze(&tokens);
Ok(self.generate(&tree))
}
fn should_generate(&self, generator: &str) -> bool {
let in_generators = self.config.generators.contains(&generator.to_string());
if !self.config.only.is_empty() {
return in_generators && self.config.only.contains(&generator.to_string());
}
if !self.config.skip.is_empty() {
return in_generators && !self.config.skip.contains(&generator.to_string());
}
in_generators
}
fn parse_config(config: &mut TreeConfig, mapping: &serde_yaml::Mapping) {
for (key, value) in mapping {
let key_str = key.as_str().unwrap_or("");
match key_str {
"phpunit" => config.generate_phpunit = value.as_bool().unwrap_or(true),
"pest" => config.generate_pest = value.as_bool().unwrap_or(false),
"forms" => config.forms = value.as_bool().unwrap_or(true),
"pagination" => config.pagination = value.as_bool().unwrap_or(true),
_ => {}
}
}
}
}