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//!
21//! // 1. Define the execution context
22//! #[derive(Default)]
23//! struct MyContext;
24//!
25//! impl ExecutionContext for MyContext {
26//! fn as_any(&self) -> &dyn std::any::Any { self }
27//! fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self }
28//! }
29//!
30//! // 2. Implement a command handler
31//! struct HelloCommand;
32//!
33//! impl CommandHandler for HelloCommand {
34//! fn execute(
35//! &self,
36//! _context: &mut dyn ExecutionContext,
37//! args: &ParsedArgs,
38//! ) -> dynamic_cli::Result<()> {
39//! let name = args.get_scalar("name").unwrap_or("World");
40//! println!("Hello, {}!", name);
41//! Ok(())
42//! }
43//! }
44//!
45//! // 3. Load configuration and register commands
46//! # fn main() -> dynamic_cli::Result<()> {
47//! use dynamic_cli::config::loader::load_config;
48//!
49//! let config = load_config("commands.yaml")?;
50//! let mut registry = CommandRegistry::new();
51//! registry.register_sync(config.commands[0].clone(), Box::new(HelloCommand))?;
52//!
53//! // 4. Parse and execute
54//! let parser = ReplParser::new(®istry);
55//! let parsed = parser.parse_line("hello World")?;
56//!
57//! let mut context = MyContext::default();
58//! let handler = registry.get_handler_sync(&parsed.command_name).unwrap();
59//! let args = ParsedArgs::from_scalars(parsed.arguments);
60//! handler.execute(&mut context, &args)?;
61//! # Ok(())
62//! # }
63//! ```
64//!
65//! ## Architecture
66//!
67//! The framework is organized into modules:
68//!
69//! - [`error`]: Error types and handling
70//! - [`config`]: Configuration file loading and validation
71//! - [`context`]: Execution context trait
72//! - [`executor`]: Command execution
73//! - [`registry`]: Command and handler registry
74//! - [`parser`]: CLI and REPL argument parsing
75//! - [`validator`]: Argument validation
76//!
77//! ## Module Status
78//!
79//! - ✅ Complete: error, config, context, executor, registry, parser, validator, interface, builder
80//! - 📋 Planned: utils, examples
81//!
82//! ## Examples
83//!
84//! See the documentation for each module for detailed examples.
85
86// ============================================================================
87// PUBLIC MODULES (Complete and ready to use)
88// ============================================================================
89
90pub mod builder;
91pub mod config;
92pub mod context;
93pub mod error;
94pub mod executor;
95pub mod help;
96pub mod interface;
97pub mod parser;
98pub mod plugin;
99pub mod registry;
100pub mod utils;
101pub mod validator;
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, ParsedArgs, 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// Helper system
135pub use help::{DefaultHelpFormatter, HelpFormatter};
136
137// Plugin system
138#[cfg(feature = "wasm-plugins")]
139pub use plugin::wasm::{WasmPlugin, WasmSerializationFormat};
140pub use plugin::{Plugin, SystemPlugin};
141
142// Utility functions
143pub use utils::{
144 detect_type, format_bytes, format_duration, get_extension, has_extension, is_blank, normalize,
145 normalize_path, parse_bool, parse_float, parse_int, truncate,
146};
147
148// ============================================================================
149// PRELUDE MODULE (Quick imports)
150// ============================================================================
151
152/// Prelude module for quickly importing essential types
153///
154/// This module re-exports the most commonly used types and traits,
155/// allowing you to import everything with a single `use` statement.
156///
157/// # Example
158///
159/// ```
160/// use dynamic_cli::prelude::*;
161///
162/// // Now you have access to:
163/// // - ExecutionContext, downcast_ref, downcast_mut
164/// // - CommandHandler
165/// // - DynamicCliError, Result
166/// // - CommandRegistry
167/// // - ParsedCommand, CliParser, ReplParser
168/// // - validate_file_exists, validate_file_extension, validate_range
169/// // - Common config types (ArgumentType, CommandsConfig)
170/// // - CliBuilder, CliApp
171/// // - Utility functions (parse_int, parse_bool, is_blank, etc.)
172/// ```
173pub mod prelude {
174 // Context management
175 pub use crate::context::{downcast_mut, downcast_ref, ExecutionContext};
176
177 // Command handling
178 pub use crate::executor::CommandHandler;
179
180 // Error handling
181 pub use crate::error::{DynamicCliError, Result};
182
183 // Configuration
184 pub use crate::config::schema::{ArgumentType, CommandsConfig};
185
186 // Registry
187 pub use crate::registry::CommandRegistry;
188
189 // Parsing
190 pub use crate::parser::{CliParser, ParsedArgs, ParsedCommand, ReplParser};
191
192 // Validation
193 pub use crate::validator::{validate_file_exists, validate_file_extension, validate_range};
194
195 // Interface
196 pub use crate::interface::{CliInterface, ReplInterface};
197
198 // Builder
199 pub use crate::builder::{CliApp, CliBuilder};
200
201 // Help system — re-exported so framework users need only `use dynamic_cli::prelude::*`
202 pub use crate::help::{DefaultHelpFormatter, HelpFormatter};
203
204 // Plugin system
205 #[cfg(feature = "wasm-plugins")]
206 pub use crate::plugin::wasm::{WasmPlugin, WasmSerializationFormat};
207 pub use crate::plugin::{Plugin, SystemPlugin};
208
209 // Utilities (most commonly used)
210 pub use crate::utils::{detect_type, is_blank, normalize, parse_bool, parse_float, parse_int};
211}
212
213// ============================================================================
214// INTEGRATION TESTS
215// ============================================================================
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 /// Verify that prelude imports work correctly
222 #[test]
223 fn test_prelude_imports() {
224 use crate::prelude::*;
225
226 // If this compiles, prelude imports are working
227 let _: Option<&dyn ExecutionContext> = None;
228 let _: Option<&dyn CommandHandler> = None;
229 }
230
231 /// Verify that individual module imports work
232 #[test]
233 fn test_module_imports() {
234 use crate::config::schema::CommandsConfig;
235 use crate::parser::ParsedCommand;
236 use crate::registry::CommandRegistry;
237
238 // If this compiles, module structure is correct
239 let _config = CommandsConfig::minimal();
240 let _registry = CommandRegistry::new();
241 let _parsed = ParsedCommand {
242 command_name: "test".to_string(),
243 arguments: std::collections::HashMap::new(),
244 };
245 }
246
247 /// Verify that re-exports work
248 #[test]
249 fn test_reexports() {
250 // These should be accessible from the crate root
251 let _: Option<&dyn ExecutionContext> = None;
252 let _: Option<&dyn CommandHandler> = None;
253 let _registry = CommandRegistry::new();
254
255 // If this compiles, re-exports are working
256 }
257
258 /// Verify that help types are accessible from the prelude
259 #[test]
260 fn test_help_prelude_imports() {
261 use crate::config::schema::{CommandsConfig, Metadata};
262 use crate::prelude::*;
263
264 let config = CommandsConfig {
265 metadata: Metadata {
266 version: "1.0.0".to_string(),
267 prompt: "test".to_string(),
268 prompt_suffix: " > ".to_string(),
269 },
270 commands: vec![],
271 global_options: vec![],
272 };
273
274 // DefaultHelpFormatter accessible from prelude
275 let f = DefaultHelpFormatter::new();
276 let _ = f.format_app(&config);
277
278 // Trait object usable (object-safe by design)
279 let _: Box<dyn HelpFormatter> = Box::new(DefaultHelpFormatter::new());
280 }
281}