use crate::parser::FafFile;
#[derive(Debug, Clone)]
pub struct ValidationResult {
pub valid: bool,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub score: u8,
}
pub fn validate(faf: &FafFile) -> ValidationResult {
let mut errors = Vec::new();
let mut warnings = Vec::new();
if faf.data.faf_version.is_empty() {
errors.push("Missing faf_version".to_string());
}
if faf.data.project.name.is_empty() {
errors.push("Missing project.name".to_string());
}
if let Some(ic) = &faf.data.instant_context {
if ic.what_building.is_none() {
warnings.push("Missing instant_context.what_building".to_string());
}
if ic.tech_stack.is_none() {
warnings.push("Missing instant_context.tech_stack".to_string());
}
} else {
warnings.push("Missing instant_context section".to_string());
}
if faf.data.stack.is_none() {
warnings.push("Missing stack section".to_string());
}
if faf.data.human_context.is_none() {
warnings.push("Missing human_context section".to_string());
}
let score = calculate_score(faf);
ValidationResult {
valid: errors.is_empty(),
errors,
warnings,
score,
}
}
fn calculate_score(faf: &FafFile) -> u8 {
let mut score: u8 = 0;
if !faf.data.faf_version.is_empty() {
score += 10;
}
if !faf.data.project.name.is_empty() {
score += 10;
}
if faf.data.project.goal.is_some() {
score += 10;
}
if let Some(ic) = &faf.data.instant_context {
if ic.what_building.is_some() {
score += 10;
}
if ic.tech_stack.is_some() {
score += 10;
}
if !ic.key_files.is_empty() {
score += 10;
}
}
if faf.data.stack.is_some() {
score += 15;
}
if faf.data.human_context.is_some() {
score += 15;
}
if !faf.data.tags.is_empty() {
score += 5;
}
if faf.data.state.is_some() {
score += 5;
}
score.min(100)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse;
#[test]
fn test_validate_minimal() {
let content = r#"
faf_version: 2.5.0
project:
name: test
"#;
let faf = parse(content).unwrap();
let result = validate(&faf);
assert!(result.valid);
assert!(result.score >= 20);
}
#[test]
fn test_validate_full() {
let content = r#"
faf_version: 2.5.0
project:
name: test
goal: Testing
instant_context:
what_building: Test
tech_stack: Rust
key_files:
- main.rs
stack:
backend: Rust
human_context:
who: Developers
tags:
- rust
state:
phase: dev
"#;
let faf = parse(content).unwrap();
let result = validate(&faf);
assert!(result.valid);
assert!(result.score >= 90);
}
}