checkmate-cli 0.4.1

Checkmate - API Testing Framework CLI
//! Clove subcommand - JSON query language operations

use clap::Subcommand;
use clove_lang::cli::{self, CheckOptions, CheckResult};
use std::io::{self, Read};

#[derive(Subcommand)]
pub enum CloveCommands {
    /// Execute a Clove query
    Check {
        /// The query to execute
        query: String,
        /// JSON input (reads from stdin if not provided)
        #[arg(short, long)]
        input: Option<String>,
        /// Pretty-print output
        #[arg(short, long)]
        pretty: bool,
        /// Only validate syntax
        #[arg(long)]
        syntax_only: bool,
    },
    /// List documentation categories
    Docs,
    /// Show documentation for a category
    Doc {
        /// Category name
        category: String,
    },
    /// Interactive onboarding
    Onboard,
}

pub fn run(command: CloveCommands) -> Result<(), Box<dyn std::error::Error>> {
    match command {
        CloveCommands::Check {
            query,
            input,
            pretty,
            syntax_only,
        } => {
            let input = resolve_input(input)?;
            let options = CheckOptions {
                query,
                input,
                pretty,
                syntax_only,
            };

            match cli::execute_check(&options)? {
                CheckResult::SyntaxValid => println!("Syntax is valid"),
                CheckResult::Success(output) => {
                    let json = if pretty {
                        serde_json::to_string_pretty(&output)?
                    } else {
                        serde_json::to_string(&output)?
                    };
                    println!("{}", json);
                }
            }
        }
        CloveCommands::Docs => print!("{}", cli::get_docs_overview()),
        CloveCommands::Doc { category } => print!("{}", cli::get_doc_category(&category)?),
        CloveCommands::Onboard => print!("{}", cli::get_onboarding_content()),
    }
    Ok(())
}

fn resolve_input(input: Option<String>) -> Result<Option<String>, io::Error> {
    match input {
        Some(s) => Ok(Some(s)),
        None if !atty::is(atty::Stream::Stdin) => {
            let mut buffer = String::new();
            io::stdin().read_to_string(&mut buffer)?;
            Ok(Some(buffer))
        }
        None => Ok(None),
    }
}