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}