dynamic_cli/
lib.rs

1//! # dynamic-cli
2//!
3//! A framework for creating configurable CLI and REPL applications via YAML/JSON.
4//!
5//! ## Overview
6//!
7//! **dynamic-cli** allows you to define your application's command-line interface
8//! in a configuration file rather than coding it manually. The framework
9//! automatically generates:
10//! - Argument parsing
11//! - Input validation
12//! - Contextual help
13//! - Interactive mode (REPL)
14//! - Error handling with suggestions
15//!
16//! ## Quick Start
17//!
18//! ```no_run
19//! use dynamic_cli::prelude::*;
20//! use std::collections::HashMap;
21//!
22//! // 1. Define the execution context
23//! #[derive(Default)]
24//! struct MyContext;
25//!
26//! impl ExecutionContext for MyContext {
27//!     fn as_any(&self) -> &dyn std::any::Any { self }
28//!     fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
29//! }
30//!
31//! // 2. Implement a command handler
32//! struct HelloCommand;
33//!
34//! impl CommandHandler for HelloCommand {
35//!     fn execute(
36//!         &self,
37//!         _context: &mut dyn ExecutionContext,
38//!         args: &HashMap<String, String>,
39//!     ) -> dynamic_cli::Result<()> {
40//!         let default_name = "World".to_string();
41//!         let name = args.get("name").unwrap_or(&default_name);
42//!         println!("Hello, {}!", name);
43//!         Ok(())
44//!     }
45//! }
46//!
47//! // 3. Load configuration and register commands
48//! # fn main() -> dynamic_cli::Result<()> {
49//! use dynamic_cli::config::loader::load_config;
50//!
51//! let config = load_config("commands.yaml")?;
52//! let mut registry = CommandRegistry::new();
53//! registry.register(config.commands[0].clone(), Box::new(HelloCommand))?;
54//!
55//! // 4. Parse and execute
56//! let parser = ReplParser::new(&registry);
57//! let parsed = parser.parse_line("hello World")?;
58//!
59//! let mut context = MyContext::default();
60//! let handler = registry.get_handler(&parsed.command_name).unwrap();
61//! handler.execute(&mut context, &parsed.arguments)?;
62//! # Ok(())
63//! # }
64//! ```
65//!
66//! ## Architecture
67//!
68//! The framework is organized into modules:
69//!
70//! - [`error`]: Error types and handling
71//! - [`config`]: Configuration file loading and validation
72//! - [`context`]: Execution context trait
73//! - [`executor`]: Command execution
74//! - [`registry`]: Command and handler registry
75//! - [`parser`]: CLI and REPL argument parsing
76//! - [`validator`]: Argument validation
77//!
78//! ## Module Status
79//!
80//! - ✅ Complete: error, config, context, executor, registry, parser, validator, interface, builder
81//! - 📋 Planned: utils, examples
82//!
83//! ## Examples
84//!
85//! See the documentation for each module for detailed examples.
86
87// ============================================================================
88// PUBLIC MODULES (Complete and ready to use)
89// ============================================================================
90
91pub mod builder;
92pub mod config;
93pub mod context;
94pub mod error;
95pub mod executor;
96pub mod interface;
97pub mod parser;
98pub mod registry;
99pub mod utils;
100pub mod validator;
101
102// ============================================================================
103// PUBLIC RE-EXPORTS (For convenience)
104// ============================================================================
105
106// Core traits
107pub use context::{downcast_mut, downcast_ref, ExecutionContext};
108pub use executor::CommandHandler;
109
110// Error handling
111pub use error::{DynamicCliError, Result};
112
113// Configuration types
114pub use config::schema::{
115    ArgumentDefinition, ArgumentType, CommandDefinition, CommandsConfig, Metadata,
116    OptionDefinition, ValidationRule,
117};
118
119// Registry
120pub use registry::CommandRegistry;
121
122// Parser types
123pub use parser::{CliParser, ParsedCommand, ReplParser};
124
125// Validator functions
126pub use validator::{validate_file_exists, validate_file_extension, validate_range};
127
128// Interface types
129pub use interface::{CliInterface, ReplInterface};
130
131// Builder types
132pub use builder::{CliApp, CliBuilder};
133
134// Utility functions
135pub use utils::{
136    detect_type, format_bytes, format_duration, get_extension, has_extension, is_blank, normalize,
137    normalize_path, parse_bool, parse_float, parse_int, truncate,
138};
139
140// ============================================================================
141// PRELUDE MODULE (Quick imports)
142// ============================================================================
143
144/// Prelude module for quickly importing essential types
145///
146/// This module re-exports the most commonly used types and traits,
147/// allowing you to import everything with a single `use` statement.
148///
149/// # Example
150///
151/// ```
152/// use dynamic_cli::prelude::*;
153///
154/// // Now you have access to:
155/// // - ExecutionContext, downcast_ref, downcast_mut
156/// // - CommandHandler
157/// // - DynamicCliError, Result
158/// // - CommandRegistry
159/// // - ParsedCommand, CliParser, ReplParser
160/// // - validate_file_exists, validate_file_extension, validate_range
161/// // - Common config types (ArgumentType, CommandsConfig)
162/// // - CliBuilder, CliApp
163/// // - Utility functions (parse_int, parse_bool, is_blank, etc.)
164/// ```
165pub mod prelude {
166    // Context management
167    pub use crate::context::{downcast_mut, downcast_ref, ExecutionContext};
168
169    // Command handling
170    pub use crate::executor::CommandHandler;
171
172    // Error handling
173    pub use crate::error::{DynamicCliError, Result};
174
175    // Configuration
176    pub use crate::config::schema::{ArgumentType, CommandsConfig};
177
178    // Registry
179    pub use crate::registry::CommandRegistry;
180
181    // Parsing
182    pub use crate::parser::{CliParser, ParsedCommand, ReplParser};
183
184    // Validation
185    pub use crate::validator::{validate_file_exists, validate_file_extension, validate_range};
186
187    // Interface
188    pub use crate::interface::{CliInterface, ReplInterface};
189
190    // Builder
191    pub use crate::builder::{CliApp, CliBuilder};
192
193    // Utilities (most commonly used)
194    pub use crate::utils::{detect_type, is_blank, normalize, parse_bool, parse_float, parse_int};
195}
196
197// ============================================================================
198// INTEGRATION TESTS
199// ============================================================================
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    /// Verify that prelude imports work correctly
206    #[test]
207    fn test_prelude_imports() {
208        use crate::prelude::*;
209
210        // If this compiles, prelude imports are working
211        let _: Option<&dyn ExecutionContext> = None;
212        let _: Option<&dyn CommandHandler> = None;
213    }
214
215    /// Verify that individual module imports work
216    #[test]
217    fn test_module_imports() {
218        use crate::config::schema::CommandsConfig;
219        use crate::parser::ParsedCommand;
220        use crate::registry::CommandRegistry;
221
222        // If this compiles, module structure is correct
223        let _config = CommandsConfig::minimal();
224        let _registry = CommandRegistry::new();
225        let _parsed = ParsedCommand {
226            command_name: "test".to_string(),
227            arguments: std::collections::HashMap::new(),
228        };
229    }
230
231    /// Verify that re-exports work
232    #[test]
233    fn test_reexports() {
234        // These should be accessible from the crate root
235        let _: Option<&dyn ExecutionContext> = None;
236        let _: Option<&dyn CommandHandler> = None;
237        let _registry = CommandRegistry::new();
238
239        // If this compiles, re-exports are working
240    }
241}