#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct AIContext {
pub architecture: String,
pub version: String,
pub components: Vec<ComponentInfo>,
pub relationships: Vec<RelationshipInfo>,
pub constraints: ConstraintSet,
pub suggestions: Vec<Suggestion>,
pub metadata: ContextMetadata,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct ComponentInfo {
pub type_name: String,
pub layer: String,
pub role: String,
pub module_path: String,
pub purpose: Option<String>,
pub dependencies: Vec<String>,
pub methods: Vec<MethodInfo>,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct MethodInfo {
pub name: String,
pub signature: String,
pub documentation: Option<String>,
pub parameters: Vec<ParameterInfo>,
pub return_type: Option<String>,
pub is_public: bool,
pub is_async: bool,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct ParameterInfo {
pub name: String,
pub param_type: String,
pub description: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct RelationshipInfo {
pub from: String,
pub to: String,
pub relationship_type: String,
pub is_valid: bool,
pub validation_message: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct ConstraintSet {
pub dependency_rules: Vec<DependencyRule>,
pub layer_boundaries: Vec<LayerBoundary>,
pub naming_conventions: Vec<NamingConvention>,
pub required_patterns: Vec<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct DependencyRule {
pub from_layer: String,
pub to_layer: String,
pub allowed: bool,
pub reason: String,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct LayerBoundary {
pub layer: String,
pub can_depend_on: Vec<String>,
pub dependents_allowed: Vec<String>,
pub purpose: String,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct NamingConvention {
pub applies_to: String,
pub pattern: String,
pub example: String,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct Suggestion {
pub suggestion_type: SuggestionType,
pub component: Option<String>,
pub description: String,
pub priority: Priority,
pub code_example: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum SuggestionType {
MissingImplementation,
ArchitecturalViolation,
Improvement,
BestPractice,
PotentialIssue,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(rename_all = "lowercase")]
pub enum Priority {
Low,
Medium,
High,
Critical,
}
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct ContextMetadata {
pub generated_at: String,
pub hex_version: String,
pub total_components: usize,
pub total_relationships: usize,
pub schema_version: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ai_context_serialization() {
let context = AIContext {
architecture: String::from("hexagonal"),
version: String::from("0.3.0"),
components: vec![],
relationships: vec![],
constraints: ConstraintSet {
dependency_rules: vec![],
layer_boundaries: vec![],
naming_conventions: vec![],
required_patterns: vec![],
},
suggestions: vec![],
metadata: ContextMetadata {
generated_at: String::from("2025-10-02T18:00:00Z"),
hex_version: String::from("0.3.0"),
total_components: 0,
total_relationships: 0,
schema_version: String::from("1.0.0"),
},
};
let json = serde_json::to_string(&context).unwrap();
assert!(json.contains("hexagonal"));
assert!(json.contains("schema_version"));
}
#[test]
fn test_component_info_serialization() {
let component = ComponentInfo {
type_name: String::from("User"),
layer: String::from("Domain"),
role: String::from("Entity"),
module_path: String::from("domain::user"),
purpose: Some(String::from("Represents a user")),
methods: vec![],
dependencies: vec![],
};
let json = serde_json::to_string(&component).unwrap();
assert!(json.contains("User"));
assert!(json.contains("Domain"));
}
#[test]
fn test_suggestion_serialization() {
let suggestion = Suggestion {
suggestion_type: SuggestionType::MissingImplementation,
component: Some(String::from("UserRepository")),
description: String::from("Port missing adapter implementation"),
priority: Priority::High,
code_example: Some(String::from("impl UserRepository for PostgresUserRepo")),
};
let json = serde_json::to_string(&suggestion).unwrap();
assert!(json.contains("missing_implementation"));
assert!(json.contains("high"));
}
#[test]
fn test_method_info_serialization() {
let method = MethodInfo {
name: String::from("save"),
signature: String::from("fn save(&mut self, entity: T) -> HexResult<()>"),
documentation: Some(String::from("Saves an entity to the repository")),
parameters: vec![
ParameterInfo {
name: String::from("self"),
param_type: String::from("&mut self"),
description: None,
},
ParameterInfo {
name: String::from("entity"),
param_type: String::from("T"),
description: Some(String::from("The entity to save")),
},
],
return_type: Some(String::from("HexResult<()>")),
is_public: true,
is_async: false,
};
let json = serde_json::to_string(&method).unwrap();
assert!(json.contains("save"));
assert!(json.contains("HexResult"));
assert!(json.contains("\"is_public\":true"));
}
#[test]
fn test_component_with_methods() {
let component = ComponentInfo {
type_name: String::from("UserRepository"),
layer: String::from("Port"),
role: String::from("Repository"),
module_path: String::from("ports::user_repository"),
purpose: Some(String::from("Manages user persistence")),
methods: vec![MethodInfo {
name: String::from("find_by_id"),
signature: String::from("fn find_by_id(&self, id: &str) -> HexResult<Option<User>>"),
documentation: Some(String::from("Finds a user by their ID")),
parameters: vec![ParameterInfo {
name: String::from("id"),
param_type: String::from("&str"),
description: Some(String::from("User identifier")),
}],
return_type: Some(String::from("HexResult<Option<User>>")),
is_public: true,
is_async: false,
}],
dependencies: vec![],
};
let json = serde_json::to_string(&component).unwrap();
assert!(json.contains("UserRepository"));
assert!(json.contains("find_by_id"));
assert!(json.contains("Finds a user"));
}
}
impl AIContext {
pub fn to_json(&self) -> Result<String, String> {
match serde_json::to_string(self) {
Ok(s) => Ok(s),
Err(e) => Err(format!("Serialization error: {}", e)),
}
}
}
#[cfg(test)]
mod tests_to_json {
#[test]
fn test_ai_context_to_json_method() {
let ctx = super::AIContext {
architecture: String::from("hexagonal"),
version: String::from("0.3.0"),
components: Vec::new(),
relationships: Vec::new(),
constraints: super::ConstraintSet {
dependency_rules: Vec::new(),
layer_boundaries: Vec::new(),
naming_conventions: Vec::new(),
required_patterns: Vec::new(),
},
suggestions: Vec::new(),
metadata: super::ContextMetadata {
generated_at: String::from("2025-10-06T17:59:00Z"),
hex_version: String::from("0.3.0"),
total_components: 0,
total_relationships: 0,
schema_version: String::from("1.0.0"),
},
};
let json = ctx.to_json().unwrap();
assert!(json.contains("\"schema_version\""));
assert!(json.contains("\"hexagonal\""));
}
}