tree-type 0.4.5

Rust macros for creating type-safe filesystem tree structures
Documentation
#![allow(deprecated)]

// Migration guide: Old API vs New API
use std::process::Command;
use tree_type::GenericDir;
use tree_type::GenericFile;
use tree_type::tree_type;

tree_type! {
    ProjectManagementRoot {
        #[required]
        projects/ as ProjectsDir {
            [project: String]/ as ProjectDir {
                #[required]
                tasks/ as TasksDir {
                    #[required]
                    counter(".task-counter") as TaskCounter,
                    #[required]
                    active/ as ActiveTasksDir,
                },
                implementation/ as ImplementationDir,
            }
        }
    }
}

#[test]
fn test_migration_as_generic_dir_to_as_generic() {
    let management_root = ProjectManagementRoot::new("/tmp/test").unwrap();
    let project_dir = management_root.projects().project("test-project");
    let impl_dir = project_dir.implementation();
    let active_dir = project_dir.tasks().active();

    // OLD API (no longer available):
    // let generic_root = management_root.as_generic_dir();
    // let generic_project = project_dir.as_generic_dir();
    // let generic_impl = impl_dir.as_generic_dir();
    // let generic_active = active_dir.as_generic_dir();

    // NEW API:
    let _generic_root = management_root.as_generic();
    let _generic_project = project_dir.as_generic();
    let _generic_impl = impl_dir.as_generic();
    let _generic_active = active_dir.as_generic();
}

#[test]
fn test_migration_as_generic_file_to_as_generic() {
    let counter = ProjectManagementRoot::new("/tmp/test")
        .unwrap()
        .projects()
        .project("test-project")
        .tasks()
        .counter();

    // OLD API (no longer available):
    // let generic_counter = counter.as_generic_file();

    // NEW API:
    let _generic_counter = counter.as_generic();
}

#[test]
fn test_migration_display_trait_now_available() {
    let project_dir = ProjectManagementRoot::new("/tmp/test")
        .unwrap()
        .projects()
        .project("test-project");
    let counter = project_dir.tasks().counter();

    // OLD: Had to use .as_path().display() or format!("{:?}", obj)
    // let error = format!("Missing {:?}", counter);
    // let error = format!("Missing {}", counter.as_path().display());

    // NEW: Can use Display trait directly
    let error = format!("Missing {}", counter);
    assert_eq!(
        error,
        "Missing /tmp/test/projects/test-project/tasks/.task-counter"
    );

    let project_error = format!("Project directory: {}", project_dir);
    assert_eq!(
        project_error,
        "Project directory: /tmp/test/projects/test-project"
    );
}

#[test]
fn test_migration_asref_path_now_available() {
    let management_root = ProjectManagementRoot::new("/tmp/test").unwrap();
    let project_dir = management_root.projects().project("test-project");
    let generic_dir = GenericDir::new("/tmp/test/repo").unwrap();

    // OLD: Had to use .as_path() explicitly
    // let mut cmd = Command::new("echo");
    // cmd.current_dir(project_dir.as_path());

    // NEW: Can use AsRef<Path> trait directly
    let mut _cmd1 = Command::new("echo");
    _cmd1.current_dir(&management_root);

    let mut _cmd2 = Command::new("echo");
    _cmd2.current_dir(&project_dir);

    let mut _cmd3 = Command::new("echo");
    _cmd3.current_dir(&generic_dir);

    // Path operations also work directly
    let some_path = std::path::Path::new("/tmp/test/projects/test-project/implementation/src");
    assert!(some_path.starts_with(&project_dir));
}

#[test]
fn test_migration_generic_types_have_same_methods() {
    let generic_dir = GenericDir::new("/tmp/test").unwrap();
    let generic_file = GenericFile::new("/tmp/test/file.txt").unwrap();

    // NEW: Generic types now have as_generic() method (returns self)
    let _same_dir = generic_dir.as_generic();
    let _same_file = generic_file.as_generic();

    // NEW: Generic types now have AsRef<Path> and Display traits
    let _dir_path: &std::path::Path = generic_dir.as_ref();
    let _file_path: &std::path::Path = generic_file.as_ref();

    let dir_display = format!("{}", generic_dir);
    let file_display = format!("{}", generic_file);

    assert_eq!(dir_display, "/tmp/test");
    assert_eq!(file_display, "/tmp/test/file.txt");
}

#[test]
#[cfg(feature = "serde")]
fn test_migration_serde_support_added() {
    use serde_json;

    let generic_dir = GenericDir::new("/tmp/test").unwrap();
    let generic_file = GenericFile::new("/tmp/test/file.txt").unwrap();

    // NEW: Serde support is now available on generic types
    let _dir_json = serde_json::to_string(&generic_dir).unwrap();
    let _file_json = serde_json::to_string(&generic_file).unwrap();

    // Generated types also have serde support
    let root = ProjectManagementRoot::new("/tmp/test").unwrap();
    let _root_json = serde_json::to_string(&root).unwrap();
}