use super::Implement;
use crate::codegen::filesystem::{output_code, OutputConfig};
use crate::codegen::string_format::{OWNER_FORM_KEY, VALUE_FORM_KEY};
use crate::codegen::{code, CodeConfig, CodegenConfig, StructConfig};
use heck::{CamelCase, SnakeCase};
use itertools::Itertools;
use std::collections::HashMap;
use zamm_yin::node_wrappers::CommonNodeTrait;
use zamm_yin::tao::archetype::{Archetype, ArchetypeFormTrait, ArchetypeTrait, AttributeArchetype};
use zamm_yin::tao::attribute::{Attribute, OwnerArchetype, ValueArchetype};
use zamm_yin::tao::{Form, FormTrait, Tao};
fn in_own_submodule(target: &Archetype) -> bool {
target.individuals().iter().any(|i| *i != target.as_form()) }
fn ancestor_names(target: &Archetype, separator: &str) -> String {
let ancestors = target.ancestry();
let mut path = ancestors
.iter()
.map(|a| {
let name = a.internal_name().unwrap();
name.as_str().to_snake_case()
})
.format(separator)
.to_string();
if in_own_submodule(target) {
if !ancestors.is_empty() {
path += separator;
}
path += &target.internal_name().unwrap().as_str().to_snake_case();
}
path.to_ascii_lowercase()
}
fn file_path(target: &Archetype) -> String {
let snake_name = target.internal_name().unwrap().as_str().to_snake_case();
format!("src/{}/{}_form.rs", ancestor_names(target, "/"), snake_name).to_ascii_lowercase()
}
fn import_path(target: &Archetype) -> String {
let struct_name = target.internal_name().unwrap().as_str().to_camel_case();
format!("{}::{}", ancestor_names(target, "::"), struct_name)
}
fn concept_to_struct(target: &Archetype) -> StructConfig {
StructConfig {
name: target.internal_name().unwrap().as_str().to_camel_case(),
import: import_path(target),
}
}
pub fn handle_implementation(request: Implement, codegen_cfg: &CodegenConfig) {
let target = request.target().unwrap();
let target_name = target.internal_name().unwrap();
let ancestors = target.ancestry();
let parent = ancestors.iter().last().unwrap();
let parent_struct = concept_to_struct(parent);
let all_attributes = target
.attribute_archetypes()
.iter()
.map(|a| concept_to_struct(&a.as_archetype()))
.collect();
let introduced_attributes = target
.introduced_attribute_archetypes()
.iter()
.map(|a| concept_to_struct(&a.as_archetype()))
.collect();
let mut attr_structs = HashMap::new();
if target == Attribute::archetype().as_archetype()
|| target.has_ancestor(Attribute::archetype().as_archetype())
{
let target_attr = AttributeArchetype::from(target.id());
let owner_type = target_attr.owner_archetype();
let value_type = target_attr.value_archetype();
attr_structs.insert(OwnerArchetype::TYPE_NAME, concept_to_struct(&owner_type));
attr_structs.insert(ValueArchetype::TYPE_NAME, concept_to_struct(&value_type));
let owner_form = if owner_type == Tao::archetype() {
Form::archetype()
} else {
owner_type
};
let value_form = if value_type == Tao::archetype() {
Form::archetype()
} else {
value_type
};
attr_structs.insert(OWNER_FORM_KEY, concept_to_struct(&owner_form));
attr_structs.insert(VALUE_FORM_KEY, concept_to_struct(&value_form));
}
let code = code(&CodeConfig {
name: target_name.as_str(),
parent: parent_struct,
all_attributes,
introduced_attributes,
attribute_structs: attr_structs,
impl_cfg: request.config().unwrap(),
codegen_cfg: *codegen_cfg,
});
let file_path = file_path(&target);
output_code(&OutputConfig {
code: &code,
file_path: &file_path,
git_ignore: !codegen_cfg.release,
cargo_track: codegen_cfg.track_autogen,
});
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codegen::string_format::{OWNER_FORM_KEY, VALUE_FORM_KEY};
use crate::tao::initialize_kb;
use zamm_yin::tao::attribute::{Attribute, Owner};
use zamm_yin::tao::Tao;
#[test]
fn own_submodule_tao() {
initialize_kb();
assert!(in_own_submodule(&Tao::archetype()));
}
#[test]
fn own_submodule_attributes() {
initialize_kb();
assert!(in_own_submodule(&Attribute::archetype().as_archetype()));
}
#[test]
fn own_submodule_nested() {
initialize_kb();
assert!(!in_own_submodule(&Owner::archetype().as_archetype()));
}
#[test]
fn folder_path_tao() {
initialize_kb();
assert_eq!(file_path(&Tao::archetype()), "src/tao/tao_form.rs");
}
#[test]
fn folder_path_attributes() {
initialize_kb();
assert_eq!(
file_path(&Attribute::archetype().as_archetype()),
"src/tao/attribute/attribute_form.rs"
);
}
#[test]
fn folder_path_nested() {
initialize_kb();
assert_eq!(
file_path(&Owner::archetype().as_archetype()),
"src/tao/attribute/owner_form.rs"
);
}
#[test]
fn import_path_tao() {
initialize_kb();
assert_eq!(import_path(&Tao::archetype()), "tao::Tao");
}
#[test]
fn import_path_attributes() {
initialize_kb();
assert_eq!(
import_path(&Attribute::archetype().as_archetype()),
"tao::attribute::Attribute"
);
}
#[test]
fn import_path_nested() {
initialize_kb();
assert_eq!(
import_path(&Owner::archetype().as_archetype()),
"tao::attribute::Owner"
);
}
#[test]
fn integration_test_attribute_generation() {
let mut attr_structs = HashMap::new();
attr_structs.insert(
OwnerArchetype::TYPE_NAME,
StructConfig {
name: "MyOwner".to_owned(),
import: "zamm_yin::tao::MyOwner".to_owned(),
},
);
attr_structs.insert(
ValueArchetype::TYPE_NAME,
StructConfig {
name: "MyValue".to_owned(),
import: "zamm_yin::tao::MyValue".to_owned(),
},
);
attr_structs.insert(
OWNER_FORM_KEY,
StructConfig {
name: "MyOwner".to_owned(),
import: "zamm_yin::tao::MyOwner".to_owned(),
},
);
attr_structs.insert(
VALUE_FORM_KEY,
StructConfig {
name: "MyValue".to_owned(),
import: "zamm_yin::tao::MyValue".to_owned(),
},
);
let code = code(&CodeConfig {
parent: StructConfig {
name: "Attribute".to_owned(),
..StructConfig::default()
},
attribute_structs: attr_structs,
..CodeConfig::default()
});
assert!(code.contains("type OwnerForm = MyOwner"));
assert!(code.contains("type ValueForm = MyValue"));
}
#[test]
fn integration_test_non_attribute_generation() {
assert!(!code(&CodeConfig {
parent: StructConfig {
name: "Tao".to_owned(),
..StructConfig::default()
},
..CodeConfig::default()
})
.contains("Attribute"));
}
}