fsvalidator 0.3.0

A file structure validator
Documentation
//! # FSValidator
//!
//! A library for validating filesystem structures against a declarative schema.
//!
//! This crate allows you to define expected file and directory structures and validate
//! that real filesystem paths match those expectations. It's useful for ensuring project layouts,
//! validating data directories, or enforcing configuration structures.
//!
//! ## Features
//!
//! - Validate files and directories using literal names or regex patterns
//! - Support for complex nested directory structures
//! - Template system for reusing common structures
//! - Control validation strictness with required flags and restricted directories
//! - Load definitions from TOML or JSON files
//! - Comprehensive validation with categorized errors for programmatic usage
//! - Colorful, symbolic display for human-readable output
//! - Fluent builder API for programmatically constructing validation models
//!
//! # Examples
//!
//! ## Using TOML Config File
//!
//! ```rust,no_run
//! # #[cfg(feature = "toml")]
//! # fn main() -> anyhow::Result<()> {
//! use anyhow::Result;
//! use fsvalidator::from_toml;
//! use fsvalidator::display::format_validation_result;
//!
//!     // Load structure definition from TOML
//!     let root = from_toml("path/to/fsvalidator.toml")?;
//!     
//!     // Validate a directory against the defined structure
//!     // Note: The path should be the direct path to the item being validated
//!     let path = "./path/to/validate";
//!     
//!     // Validate and get comprehensive results (with categorized errors)
//!     let validation_result = root.validate(path);
//!     
//!     // Display results with colorful, symbolic output
//!     println!("{}", format_validation_result(&validation_result, path));
//!     
//!     // Check success/failure and handle accordingly
//!     if validation_result.is_err() {
//!         eprintln!("Validation failed!");
//!     }
//!     
//!     Ok(())
//! # }
//! # #[cfg(not(feature = "toml"))]
//! # fn main() {}
//! ```
//!
//! ## Using Builder API
//!
//! ```rust,no_run
//! use anyhow::Result;
//! use fsvalidator::ModelBuilder;
//! use fsvalidator::display::format_validation_result;
//!
//! fn main() -> Result<()> {
//!     // Create a project structure using the builder API
//!     let project = ModelBuilder::new_dir("project")
//!         .required(true)
//!         .allow_defined_only(true)
//!         .add_file("README.md", true)
//!         .add_dir("src", true)
//!             .add_file_pattern(".*\\.rs", true)
//!             .up()
//!         .add_dir("tests", false)
//!             .add_file_pattern("test_.*\\.rs", false)
//!             .build();
//!     
//!     // Validate a directory against the defined structure
//!     let path = "./path/to/validate";
//!     let validation_result = project.validate(path);
//!     
//!     // Display results with colorful, symbolic output
//!     println!("{}", format_validation_result(&validation_result, path));
//!     
//!     Ok(())
//! }
//! ```
//!
//! ## Schema Definition
//!
//! The schema can be defined in TOML or JSON, with a structure like this:
//!
//! ```toml
//! [root]
//! type = "dir"
//! name = "project"
//! required = true
//!
//! [[root.children]]
//! type = "file"
//! name = "README.md"
//! required = true
//!
//! [[root.children]]
//! type = "dir"
//! name = "src"
//! required = true
//!
//! [[root.children.children]]
//! type = "file"
//! pattern = ".*\.rs"
//! required = true
//! ```

pub mod display;
pub mod loader;
pub mod model;
pub mod raw;
pub mod validate;

// Re-export validation error types
pub use validate::{ValidationError, ValidationResult, ErrorCategory};
// Re-export model builder for easier access
pub use model::ModelBuilder;

#[cfg(feature = "toml")]
/// Load a filesystem structure definition from a TOML file and convert it to a validation model.
///
/// # Arguments
///
/// * `structure_def_path` - Path to the TOML file containing the structure definition
///
/// # Returns
///
/// * `Result<model::Node>` - The root node of the validation model
///
/// # Example
///
/// ```rust,no_run
/// use anyhow::Result;
/// use fsvalidator::from_toml;
/// use fsvalidator::display::format_validation_result;
///
/// fn main() -> Result<()> {
///     let root = from_toml("path/to/structure.toml")?;
///     
///     // Validate and get comprehensive results
///     let path = "./path/to/validate";
///     let result = root.validate(path);
///     println!("{}", format_validation_result(&result, path));
///     
///     // Check if validation passed
///     if result.is_ok() {
///         println!("Validation passed!");
///     }
///     Ok(())
/// }
/// ```
pub fn from_toml(structure_def_path: impl AsRef<std::path::Path>) -> anyhow::Result<model::Node> {
    let def = std::fs::read_to_string(structure_def_path).expect("Invalid path");
    let raw = toml::from_str::<raw::RawRoot>(&def).expect("Invalid TOML");
    loader::load_root(&raw)
}

#[cfg(feature = "json")]
/// Load a filesystem structure definition from a JSON file and convert it to a validation model.
///
/// # Arguments
///
/// * `structure_def_path` - Path to the JSON file containing the structure definition
///
/// # Returns
///
/// * `Result<model::Node>` - The root node of the validation model
///
/// # Example
///
/// ```rust,no_run
/// use anyhow::Result;
/// use fsvalidator::from_json;
/// use fsvalidator::display::format_validation_result;
///
/// fn main() -> Result<()> {
///     let root = from_json("path/to/structure.json")?;
///     
///     // Validate and get comprehensive results
///     let path = "./path/to/validate";
///     let result = root.validate(path);
///     println!("{}", format_validation_result(&result, path));
///     
///     // Check if validation passed
///     if result.is_ok() {
///         println!("Validation passed!");
///     }
///     Ok(())
/// }
/// ```
pub fn from_json(structure_def_path: impl AsRef<std::path::Path>) -> anyhow::Result<model::Node> {
    let def = std::fs::read_to_string(structure_def_path).expect("Invalid path");
    let raw = serde_json::from_str::<raw::RawRoot>(&def).expect("Invalid JSON");
    loader::load_root(&raw)
}