fsvalidator 0.1.3

A file structure validator
Documentation
# File Structure Validator (fsvalidator)

A Rust library for validating real filesystem directories against a declarative, strongly-typed schema. Useful for enforcing project structure, data ingestion layout, or configuration rules.

[![Crates.io](https://img.shields.io/crates/v/fsvalidator.svg)](https://crates.io/crates/fsvalidator)
[![Documentation](https://docs.rs/fsvalidator/badge.svg)](https://docs.rs/fsvalidator)

## Features

- **Flexible Matching**: Validate files and directories using both literal names and regex patterns
- **Nested Hierarchies**: Support for complex directory trees with arbitrary depth
- **Template System**: Reuse common structures via a template reference system
- **Strictness Controls**: Fine-grained control over validation strictness (required files, restricted directories)
- **Format Options**: Define validation rules in TOML or JSON formats
- **Descriptive Errors**: Clear, informative error messages for validation failures

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
fsvalidator = { version = "0.1.3", features = ["toml"] } # or "json" feature
```

## Quick Start

```rust
use anyhow::Result;
use fsvalidator::from_toml;

fn main() -> Result<()> {
    // Load structure definition from TOML
    let root = from_toml("path/to/fsvalidator.toml")?;

    // Display the parsed structure (optional)
    println!("{root}");

    // Validate a directory against the defined structure
    root.validate("./path/to/validate")?;

    Ok(())
}
```

## Definition Format

### TOML Example

```toml
# Root directory definition
[root]
type = "dir"
name = "project"
required = true
allow_defined_only = true

# Define children of the root directory
[[root.children]]
type = "file"
name = "README.md"
required = true

[[root.children]]
type = "dir"
name = "src"
required = true

# Define children of the src directory
[[root.children.children]]
type = "file"
pattern = ".*\.rs"
required = true

# Reference to a template
[[root.children]]
type = "ref"
name = "tests"
ref = "test_directory"

# Template definition
[template.test_directory]
type = "dir"
name = "tests"
required = false

[[template.test_directory.children]]
type = "file"
pattern = "test_.*\.rs"
required = false

# Global settings (applied to all nodes unless overridden)
[global]
required = false
allow_defined_only = false
```

### JSON Example

```json
{
  "root": {
    "type": "dir",
    "name": "project",
    "required": true,
    "allow_defined_only": true,
    "children": [
      {
        "type": "file",
        "name": "README.md",
        "required": true
      },
      {
        "type": "dir",
        "name": "src",
        "required": true,
        "children": [
          {
            "type": "file",
            "pattern": ".*\.rs",
            "required": true
          }
        ]
      },
      {
        "type": "ref",
        "name": "tests",
        "ref": "test_directory"
      }
    ]
  },
  "template": {
    "test_directory": {
      "type": "dir",
      "name": "tests",
      "required": false,
      "children": [
        {
          "type": "file",
          "pattern": "test_.*\.rs",
          "required": false
        }
      ]
    }
  },
  "global": {
    "required": false,
    "allow_defined_only": false
  }
}
```

## Definition Structure

### Node Types

- `dir`: A directory node
- `file`: A file node
- `ref`: A reference to a template

### Node Properties

- `name`: Literal name of the file or directory
- `pattern`: Regex pattern to match against file or directory name (use either `name` or `pattern`, not both)
- `required`: Whether the node must exist (default: false)
- `allow_defined_only`: For directories, whether only defined children are allowed (default: false)
- `children`: List of child nodes (only valid for `dir` type)
- `ref`: Template reference name (only valid for `ref` type)

### Special Sections

- `root`: The root node of the validation tree
- `template`: Dictionary of reusable node templates
- `global`: Global settings applied to all nodes unless overridden
- `config`: Configuration options for the validator

## Model Structure

```rust
// Main node types
enum Node {
    Dir(Rc<RefCell<DirNode>>),
    File(Rc<RefCell<FileNode>>),
}

// Directory node with children
struct DirNode {
    name: NodeName,
    children: Vec<Node>,
    required: bool,
    allow_defined_only: bool,
}

// File node
struct FileNode {
    name: NodeName,
    required: bool,
}

// Node name (literal or pattern)
enum NodeName {
    Literal(String),
    Pattern(String), // Regex pattern
}
```

## Use Cases

- Enforcing consistent project layouts
- Validating data pipeline inputs/outputs
- Ensuring configuration directories are correctly structured
- Verifying deployment artifacts
- Testing file-based APIs

## Advanced Usage

### Programmatic Structure Creation

You can create validation structures programmatically:

```rust
use fsvalidator::model::{DirNode, FileNode, Node, NodeName};

// Create a file node
let readme = FileNode::new(NodeName::Literal("README.md".to_string()), true);

// Create a directory with pattern-matched files
let src_files = FileNode::new(NodeName::Pattern(".*\.rs".to_string()), true);
let src_dir = DirNode::new(
    NodeName::Literal("src".to_string()),
    vec![src_files],
    true,
    false
);

// Create the project root
let project = DirNode::new(
    NodeName::Literal("project".to_string()),
    vec![readme, src_dir],
    true,
    true
);

// Validate a directory
project.validate("path/to/project").expect("Validation failed");
```

## License

MIT OR Apache-2.0