use std::path::PathBuf;
use crate::graph::Graph;
use crate::utils::error::{Error, Result};
use crate::validation::{SparqlValidator, ValidationResult};
const SHAPES_FILE: &str = "membrane-boundary-crossing.ttl";
fn load_membrane_shapes() -> Result<String> {
let candidates: Vec<PathBuf> = {
let mut v = Vec::new();
if let Ok(dir) = std::env::var("GGEN_SHAPES_DIR") {
v.push(PathBuf::from(dir).join(SHAPES_FILE));
}
v.push(PathBuf::from(".specify/shapes").join(SHAPES_FILE));
if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
v.push(
PathBuf::from(manifest_dir)
.join("../../.specify/shapes")
.join(SHAPES_FILE),
);
}
v
};
for path in &candidates {
if path.exists() {
return std::fs::read_to_string(path).map_err(|e| {
Error::new(&format!(
"Failed to read membrane SHACL shapes from {}: {}",
path.display(),
e
))
});
}
}
Err(Error::new(&format!(
"membrane SHACL shapes file '{}' not found; searched: {}",
SHAPES_FILE,
candidates
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join(", ")
)))
}
pub struct MembraneShaclValidator;
impl MembraneShaclValidator {
pub fn validate(projected_graph: &Graph) -> Result<ValidationResult> {
let shapes_ttl = load_membrane_shapes()?;
let shapes_graph = Graph::new()?;
shapes_graph.insert_turtle(&shapes_ttl)?;
let validator = SparqlValidator::new();
let report = validator
.validate(projected_graph, &shapes_graph)
.map_err(|e| Error::new(&format!("SHACL validation failed: {}", e)))?;
Ok(report)
}
}