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_sync(config.commands[0].clone(), Box::new(HelloCommand))?;
54//!
55//! // 4. Parse and execute
56//! let parser = ReplParser::new(®istry);
57//! let parsed = parser.parse_line("hello World")?;
58//!
59//! let mut context = MyContext::default();
60//! let handler = registry.get_handler_sync(&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 help;
97pub mod interface;
98pub mod parser;
99pub mod plugin;
100pub mod registry;
101pub mod utils;
102pub mod validator;
103// ============================================================================
104// PUBLIC RE-EXPORTS (For convenience)
105// ============================================================================
106
107// Core traits
108pub use context::{downcast_mut, downcast_ref, ExecutionContext};
109pub use executor::CommandHandler;
110
111// Error handling
112pub use error::{DynamicCliError, Result};
113
114// Configuration types
115pub use config::schema::{
116 ArgumentDefinition, ArgumentType, CommandDefinition, CommandsConfig, Metadata,
117 OptionDefinition, ValidationRule,
118};
119
120// Registry
121pub use registry::CommandRegistry;
122
123// Parser types
124pub use parser::{CliParser, ParsedCommand, ReplParser};
125
126// Validator functions
127pub use validator::{validate_file_exists, validate_file_extension, validate_range};
128
129// Interface types
130pub use interface::{CliInterface, ReplInterface};
131
132// Builder types
133pub use builder::{CliApp, CliBuilder};
134
135// Helper system
136pub use help::{DefaultHelpFormatter, HelpFormatter};
137
138// Plugin system
139#[cfg(feature = "wasm-plugins")]
140pub use plugin::wasm::{WasmPlugin, WasmSerializationFormat};
141pub use plugin::{Plugin, SystemPlugin};
142
143// Utility functions
144pub use utils::{
145 detect_type, format_bytes, format_duration, get_extension, has_extension, is_blank, normalize,
146 normalize_path, parse_bool, parse_float, parse_int, truncate,
147};
148
149// ============================================================================
150// PRELUDE MODULE (Quick imports)
151// ============================================================================
152
153/// Prelude module for quickly importing essential types
154///
155/// This module re-exports the most commonly used types and traits,
156/// allowing you to import everything with a single `use` statement.
157///
158/// # Example
159///
160/// ```
161/// use dynamic_cli::prelude::*;
162///
163/// // Now you have access to:
164/// // - ExecutionContext, downcast_ref, downcast_mut
165/// // - CommandHandler
166/// // - DynamicCliError, Result
167/// // - CommandRegistry
168/// // - ParsedCommand, CliParser, ReplParser
169/// // - validate_file_exists, validate_file_extension, validate_range
170/// // - Common config types (ArgumentType, CommandsConfig)
171/// // - CliBuilder, CliApp
172/// // - Utility functions (parse_int, parse_bool, is_blank, etc.)
173/// ```
174pub mod prelude {
175 // Context management
176 pub use crate::context::{downcast_mut, downcast_ref, ExecutionContext};
177
178 // Command handling
179 pub use crate::executor::CommandHandler;
180
181 // Error handling
182 pub use crate::error::{DynamicCliError, Result};
183
184 // Configuration
185 pub use crate::config::schema::{ArgumentType, CommandsConfig};
186
187 // Registry
188 pub use crate::registry::CommandRegistry;
189
190 // Parsing
191 pub use crate::parser::{CliParser, ParsedCommand, ReplParser};
192
193 // Validation
194 pub use crate::validator::{validate_file_exists, validate_file_extension, validate_range};
195
196 // Interface
197 pub use crate::interface::{CliInterface, ReplInterface};
198
199 // Builder
200 pub use crate::builder::{CliApp, CliBuilder};
201
202 // Help system — re-exported so framework users need only `use dynamic_cli::prelude::*`
203 pub use crate::help::{DefaultHelpFormatter, HelpFormatter};
204
205 // Plugin system
206 #[cfg(feature = "wasm-plugins")]
207 pub use crate::plugin::wasm::{WasmPlugin, WasmSerializationFormat};
208 pub use crate::plugin::{Plugin, SystemPlugin};
209
210 // Utilities (most commonly used)
211 pub use crate::utils::{detect_type, is_blank, normalize, parse_bool, parse_float, parse_int};
212}
213
214// ============================================================================
215// INTEGRATION TESTS
216// ============================================================================
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 /// Verify that prelude imports work correctly
223 #[test]
224 fn test_prelude_imports() {
225 use crate::prelude::*;
226
227 // If this compiles, prelude imports are working
228 let _: Option<&dyn ExecutionContext> = None;
229 let _: Option<&dyn CommandHandler> = None;
230 }
231
232 /// Verify that individual module imports work
233 #[test]
234 fn test_module_imports() {
235 use crate::config::schema::CommandsConfig;
236 use crate::parser::ParsedCommand;
237 use crate::registry::CommandRegistry;
238
239 // If this compiles, module structure is correct
240 let _config = CommandsConfig::minimal();
241 let _registry = CommandRegistry::new();
242 let _parsed = ParsedCommand {
243 command_name: "test".to_string(),
244 arguments: std::collections::HashMap::new(),
245 };
246 }
247
248 /// Verify that re-exports work
249 #[test]
250 fn test_reexports() {
251 // These should be accessible from the crate root
252 let _: Option<&dyn ExecutionContext> = None;
253 let _: Option<&dyn CommandHandler> = None;
254 let _registry = CommandRegistry::new();
255
256 // If this compiles, re-exports are working
257 }
258
259 /// Verify that help types are accessible from the prelude
260 #[test]
261 fn test_help_prelude_imports() {
262 use crate::config::schema::{CommandsConfig, Metadata};
263 use crate::prelude::*;
264
265 let config = CommandsConfig {
266 metadata: Metadata {
267 version: "1.0.0".to_string(),
268 prompt: "test".to_string(),
269 prompt_suffix: " > ".to_string(),
270 },
271 commands: vec![],
272 global_options: vec![],
273 };
274
275 // DefaultHelpFormatter accessible from prelude
276 let f = DefaultHelpFormatter::new();
277 let _ = f.format_app(&config);
278
279 // Trait object usable (object-safe by design)
280 let _: Box<dyn HelpFormatter> = Box::new(DefaultHelpFormatter::new());
281 }
282}