tftio-asana-cli 3.1.0

An interface to the Asana API
Documentation
//! Typed error surface for the Asana CLI library.
//!
//! Per `REPO_INVARIANTS.md` (Error handling) the library exposes a `thiserror`
//! enum with one variant per distinct failure mode and `#[from]` seams onto the
//! domain error types that already live deeper in the crate ([`ApiError`],
//! [`RichTextError`]). The binary edge (`main.rs`, `cli/`, `output/`) erases
//! this type at the top of the call stack; library code never depends on the
//! edge error crate.

use std::path::PathBuf;

use crate::api::error::ApiError;
use crate::rich_text::RichTextError;

/// All errors raised by the Asana CLI library layer.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// A filesystem operation failed.
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    /// A configuration or template TOML document failed to parse.
    #[error("failed to parse TOML: {0}")]
    TomlDeserialize(#[from] toml::de::Error),

    /// Configuration could not be encoded to TOML for persistence.
    #[error("failed to encode TOML: {0}")]
    TomlSerialize(#[from] toml::ser::Error),

    /// A user-supplied regular expression in a filter expression was invalid.
    #[error("invalid filter regex: {0}")]
    Regex(#[from] regex::Error),

    /// An Asana API interaction failed.
    #[error(transparent)]
    Api(#[from] ApiError),

    /// Rich-text preparation or validation failed.
    #[error(transparent)]
    RichText(#[from] RichTextError),

    /// The platform's standard project directories could not be resolved.
    #[error("{0}")]
    ProjectDirs(String),

    /// A filter expression was empty.
    #[error("filter expression cannot be empty")]
    EmptyFilter,

    /// A filter expression did not match any supported operator syntax.
    #[error(
        "unable to parse filter expression '{0}'; \
         expected syntax field=value | field!=value | field~regex | field:substring"
    )]
    UnparseableFilter(String),

    /// A named saved-filter set could not be located on disk.
    #[error("saved filter '{name}' not found in {path}")]
    SavedFilterNotFound {
        /// The requested filter set name.
        name: String,
        /// The directory searched.
        path: PathBuf,
    },

    /// A named saved-filter set existed but contained no usable expressions.
    #[error("saved filter '{0}' does not contain any expressions")]
    EmptySavedFilter(String),

    /// A filter set was asked to be saved without any expressions.
    #[error("cannot save filter '{0}' without at least one filter expression")]
    NoFilterExpressions(String),

    /// A sort field name was not one of the supported values.
    #[error("unsupported sort field '{0}'; supported values: name, created_at, modified_at")]
    UnsupportedSortField(String),

    /// A named project template could not be located.
    #[error("template '{name}' not found; place templates in {search_dir}")]
    TemplateNotFound {
        /// The requested template identifier.
        name: String,
        /// The templates directory searched.
        search_dir: PathBuf,
    },

    /// The global tracing subscriber could not be installed.
    #[error("failed to initialise tracing: {0}")]
    TracingInit(String),
}

/// Result type alias for the Asana CLI library, carrying the typed [`Error`].
///
/// The binary edge does not use this alias; it imports its own edge-level
/// `Result` directly and collapses [`Error`] via `?` (the edge error crate
/// converts any `std::error::Error`).
pub type Result<T> = std::result::Result<T, Error>;