#![allow(dead_code)]
use std::path::{Path, PathBuf};
use super::schemas::{PluginManifest, PluginMarketplaceEntry};
use super::types::PluginMarketplace;
pub struct ValidationResult {
pub success: bool,
pub errors: Vec<ValidationError>,
pub warnings: Vec<ValidationWarning>,
pub file_path: String,
pub file_type: String,
}
#[derive(Debug)]
pub struct ValidationError {
pub path: String,
pub message: String,
}
#[derive(Debug)]
pub struct ValidationWarning {
pub path: String,
pub message: String,
}
pub async fn validate_plugin_manifest(file_path: &str) -> ValidationResult {
let absolute_path = match std::fs::canonicalize(file_path) {
Ok(p) => p,
Err(e) => {
return ValidationResult {
success: false,
errors: vec![ValidationError {
path: "file".to_string(),
message: format!("File not found: {}", e),
}],
warnings: Vec::new(),
file_path: file_path.to_string(),
file_type: "plugin".to_string(),
};
}
};
let content = match tokio::fs::read_to_string(&absolute_path).await {
Ok(c) => c,
Err(e) => {
return ValidationResult {
success: false,
errors: vec![ValidationError {
path: "file".to_string(),
message: format!("Failed to read file: {}", e),
}],
warnings: Vec::new(),
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "plugin".to_string(),
};
}
};
let parsed: serde_json::Value = match serde_json::from_str(&content) {
Ok(v) => v,
Err(e) => {
return ValidationResult {
success: false,
errors: vec![ValidationError {
path: "json".to_string(),
message: format!("Invalid JSON syntax: {}", e),
}],
warnings: Vec::new(),
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "plugin".to_string(),
};
}
};
let manifest: PluginManifest = match serde_json::from_value(parsed) {
Ok(m) => m,
Err(e) => {
return ValidationResult {
success: false,
errors: e
.to_string()
.lines()
.map(|line| ValidationError {
path: "manifest".to_string(),
message: line.to_string(),
})
.collect(),
warnings: Vec::new(),
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "plugin".to_string(),
};
}
};
let mut warnings = Vec::new();
if !regex::Regex::new(r"^[a-z0-9]+(-[a-z0-9]+)*$")
.unwrap()
.is_match(&manifest.name)
{
warnings.push(ValidationWarning {
path: "name".to_string(),
message: format!("Plugin name \"{}\" is not kebab-case.", manifest.name),
});
}
if manifest.version.is_none() {
warnings.push(ValidationWarning {
path: "version".to_string(),
message: "No version specified.".to_string(),
});
}
if manifest.description.is_none() {
warnings.push(ValidationWarning {
path: "description".to_string(),
message: "No description provided.".to_string(),
});
}
ValidationResult {
success: true,
errors: Vec::new(),
warnings,
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "plugin".to_string(),
}
}
pub async fn validate_marketplace_manifest(file_path: &str) -> ValidationResult {
let absolute_path = match std::fs::canonicalize(file_path) {
Ok(p) => p,
Err(e) => {
return ValidationResult {
success: false,
errors: vec![ValidationError {
path: "file".to_string(),
message: format!("File not found: {}", e),
}],
warnings: Vec::new(),
file_path: file_path.to_string(),
file_type: "marketplace".to_string(),
};
}
};
let content = match tokio::fs::read_to_string(&absolute_path).await {
Ok(c) => c,
Err(e) => {
return ValidationResult {
success: false,
errors: vec![ValidationError {
path: "file".to_string(),
message: format!("Failed to read file: {}", e),
}],
warnings: Vec::new(),
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "marketplace".to_string(),
};
}
};
let marketplace: PluginMarketplace = match serde_json::from_str(&content) {
Ok(m) => m,
Err(e) => {
return ValidationResult {
success: false,
errors: vec![ValidationError {
path: "json".to_string(),
message: format!("Invalid JSON syntax: {}", e),
}],
warnings: Vec::new(),
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "marketplace".to_string(),
};
}
};
let mut warnings = Vec::new();
if marketplace.plugins.is_empty() {
warnings.push(ValidationWarning {
path: "plugins".to_string(),
message: "Marketplace has no plugins defined".to_string(),
});
}
ValidationResult {
success: true,
errors: Vec::new(),
warnings,
file_path: absolute_path.to_string_lossy().to_string(),
file_type: "marketplace".to_string(),
}
}