fsvalidator/
lib.rs

1//! # FSValidator
2//!
3//! A library for validating filesystem structures against a declarative schema.
4//!
5//! This crate allows you to define expected file and directory structures and validate
6//! that real filesystem paths match those expectations. It's useful for ensuring project layouts,
7//! validating data directories, or enforcing configuration structures.
8//!
9//! ## Features
10//!
11//! - Validate files and directories using literal names or regex patterns
12//! - Support for complex nested directory structures
13//! - Template system for reusing common structures
14//! - Control validation strictness with required flags and restricted directories
15//! - Load definitions from TOML or JSON files
16//! - Comprehensive validation with categorized errors for programmatic usage
17//! - Colorful, symbolic display for human-readable output
18//! - Fluent builder API for programmatically constructing validation models
19//!
20//! # Examples
21//!
22//! ## Using TOML Config File
23//!
24//! ```rust,no_run
25//! # #[cfg(feature = "toml")]
26//! # fn main() -> anyhow::Result<()> {
27//! use anyhow::Result;
28//! use fsvalidator::from_toml;
29//! use fsvalidator::display::format_validation_result;
30//!
31//!     // Load structure definition from TOML
32//!     let root = from_toml("path/to/fsvalidator.toml")?;
33//!     
34//!     // Validate a directory against the defined structure
35//!     // Note: The path should be the direct path to the item being validated
36//!     let path = "./path/to/validate";
37//!     
38//!     // Validate and get comprehensive results (with categorized errors)
39//!     let validation_result = root.validate(path);
40//!     
41//!     // Display results with colorful, symbolic output
42//!     println!("{}", format_validation_result(&validation_result, path));
43//!     
44//!     // Check success/failure and handle accordingly
45//!     if validation_result.is_err() {
46//!         eprintln!("Validation failed!");
47//!     }
48//!     
49//!     Ok(())
50//! # }
51//! # #[cfg(not(feature = "toml"))]
52//! # fn main() {}
53//! ```
54//!
55//! ## Using Builder API
56//!
57//! ```rust,no_run
58//! use anyhow::Result;
59//! use fsvalidator::ModelBuilder;
60//! use fsvalidator::display::format_validation_result;
61//!
62//! fn main() -> Result<()> {
63//!     // Create a project structure using the builder API
64//!     let project = ModelBuilder::new_dir("project")
65//!         .required(true)
66//!         .allow_defined_only(true)
67//!         .add_file("README.md", true)
68//!         .add_dir("src", true)
69//!             .add_file_pattern(".*\\.rs", true)
70//!             .up()
71//!         .add_dir("tests", false)
72//!             .add_file_pattern("test_.*\\.rs", false)
73//!             .build();
74//!     
75//!     // Validate a directory against the defined structure
76//!     let path = "./path/to/validate";
77//!     let validation_result = project.validate(path);
78//!     
79//!     // Display results with colorful, symbolic output
80//!     println!("{}", format_validation_result(&validation_result, path));
81//!     
82//!     Ok(())
83//! }
84//! ```
85//!
86//! ## Schema Definition
87//!
88//! The schema can be defined in TOML or JSON, with a structure like this:
89//!
90//! ```toml
91//! [root]
92//! type = "dir"
93//! name = "project"
94//! required = true
95//!
96//! [[root.children]]
97//! type = "file"
98//! name = "README.md"
99//! required = true
100//!
101//! [[root.children]]
102//! type = "dir"
103//! name = "src"
104//! required = true
105//!
106//! [[root.children.children]]
107//! type = "file"
108//! pattern = ".*\.rs"
109//! required = true
110//! ```
111
112pub mod display;
113pub mod loader;
114pub mod model;
115pub mod raw;
116pub mod validate;
117
118// Re-export validation error types
119pub use validate::{ValidationError, ValidationResult, ErrorCategory};
120// Re-export model builder for easier access
121pub use model::ModelBuilder;
122
123#[cfg(feature = "toml")]
124/// Load a filesystem structure definition from a TOML file and convert it to a validation model.
125///
126/// # Arguments
127///
128/// * `structure_def_path` - Path to the TOML file containing the structure definition
129///
130/// # Returns
131///
132/// * `Result<model::Node>` - The root node of the validation model
133///
134/// # Example
135///
136/// ```rust,no_run
137/// use anyhow::Result;
138/// use fsvalidator::from_toml;
139/// use fsvalidator::display::format_validation_result;
140///
141/// fn main() -> Result<()> {
142///     let root = from_toml("path/to/structure.toml")?;
143///     
144///     // Validate and get comprehensive results
145///     let path = "./path/to/validate";
146///     let result = root.validate(path);
147///     println!("{}", format_validation_result(&result, path));
148///     
149///     // Check if validation passed
150///     if result.is_ok() {
151///         println!("Validation passed!");
152///     }
153///     Ok(())
154/// }
155/// ```
156pub fn from_toml(structure_def_path: impl AsRef<std::path::Path>) -> anyhow::Result<model::Node> {
157    let def = std::fs::read_to_string(structure_def_path).expect("Invalid path");
158    let raw = toml::from_str::<raw::RawRoot>(&def).expect("Invalid TOML");
159    loader::load_root(&raw)
160}
161
162#[cfg(feature = "json")]
163/// Load a filesystem structure definition from a JSON file and convert it to a validation model.
164///
165/// # Arguments
166///
167/// * `structure_def_path` - Path to the JSON file containing the structure definition
168///
169/// # Returns
170///
171/// * `Result<model::Node>` - The root node of the validation model
172///
173/// # Example
174///
175/// ```rust,no_run
176/// use anyhow::Result;
177/// use fsvalidator::from_json;
178/// use fsvalidator::display::format_validation_result;
179///
180/// fn main() -> Result<()> {
181///     let root = from_json("path/to/structure.json")?;
182///     
183///     // Validate and get comprehensive results
184///     let path = "./path/to/validate";
185///     let result = root.validate(path);
186///     println!("{}", format_validation_result(&result, path));
187///     
188///     // Check if validation passed
189///     if result.is_ok() {
190///         println!("Validation passed!");
191///     }
192///     Ok(())
193/// }
194/// ```
195pub fn from_json(structure_def_path: impl AsRef<std::path::Path>) -> anyhow::Result<model::Node> {
196    let def = std::fs::read_to_string(structure_def_path).expect("Invalid path");
197    let raw = serde_json::from_str::<raw::RawRoot>(&def).expect("Invalid JSON");
198    loader::load_root(&raw)
199}