Skip to main content

blz_cli/config/
resolved.rs

1//! Resolved execution configuration for CLI commands.
2//!
3//! This module provides [`ExecutionConfig`], a struct that bundles common
4//! execution parameters that are shared across most commands.
5
6use blz_core::PerformanceMetrics;
7
8use crate::args::{OutputFormat, Verbosity};
9
10/// Common execution configuration shared across CLI commands.
11///
12/// This struct bundles the runtime configuration that most commands need,
13/// reducing parameter explosion in execute functions.
14///
15/// # Components
16///
17/// - **verbosity**: Controls output level (quiet/normal/verbose/debug)
18/// - **format**: Resolved output format (text/json/jsonl/raw)
19/// - **metrics**: Performance tracking for timing and resource usage
20///
21/// # Usage
22///
23/// Create from CLI args and pass to command execute functions:
24///
25/// ```ignore
26/// let config = ExecutionConfig::new(
27///     Verbosity::from_flags(cli.quiet, cli.verbose, cli.debug),
28///     format.resolve(),
29///     PerformanceMetrics::default(),
30/// );
31///
32/// commands::find::execute(&find_args, &config).await?;
33/// ```
34///
35/// # Design Notes
36///
37/// This struct intentionally excludes:
38/// - Command-specific parameters (query, limit, etc.)
39/// - Mutable state (`CliPreferences`, `ResourceMonitor`)
40///
41/// Mutable state should be passed separately as needed, as bundling
42/// mutable references in a config struct creates lifetime complications.
43#[derive(Clone, Debug)]
44pub struct ExecutionConfig {
45    /// Output verbosity level.
46    pub verbosity: Verbosity,
47
48    /// Resolved output format.
49    pub format: OutputFormat,
50
51    /// Performance metrics tracker.
52    pub metrics: PerformanceMetrics,
53}
54
55impl ExecutionConfig {
56    /// Create a new execution configuration.
57    #[must_use]
58    pub const fn new(
59        verbosity: Verbosity,
60        format: OutputFormat,
61        metrics: PerformanceMetrics,
62    ) -> Self {
63        Self {
64            verbosity,
65            format,
66            metrics,
67        }
68    }
69
70    /// Check if output should be suppressed (quiet mode).
71    #[must_use]
72    pub const fn is_quiet(&self) -> bool {
73        matches!(self.verbosity, Verbosity::Quiet)
74    }
75
76    /// Check if verbose output is enabled.
77    #[must_use]
78    pub const fn is_verbose(&self) -> bool {
79        matches!(self.verbosity, Verbosity::Verbose | Verbosity::Debug)
80    }
81
82    /// Check if debug output is enabled.
83    #[must_use]
84    pub const fn is_debug(&self) -> bool {
85        matches!(self.verbosity, Verbosity::Debug)
86    }
87
88    /// Check if output format is machine-readable (JSON/JSONL).
89    #[must_use]
90    pub const fn is_machine_readable(&self) -> bool {
91        self.format.is_machine_readable()
92    }
93
94    /// Create a builder for more complex configuration.
95    #[must_use]
96    pub fn builder() -> ExecutionConfigBuilder {
97        ExecutionConfigBuilder::default()
98    }
99
100    /// Create a minimal configuration for testing or simple commands.
101    #[must_use]
102    pub fn minimal(format: OutputFormat) -> Self {
103        Self {
104            verbosity: Verbosity::Normal,
105            format,
106            metrics: PerformanceMetrics::default(),
107        }
108    }
109}
110
111impl Default for ExecutionConfig {
112    fn default() -> Self {
113        Self {
114            verbosity: Verbosity::Normal,
115            format: OutputFormat::Text,
116            metrics: PerformanceMetrics::default(),
117        }
118    }
119}
120
121/// Builder for [`ExecutionConfig`].
122///
123/// Provides a fluent interface for creating configuration with optional
124/// parameters and sensible defaults.
125///
126/// # Examples
127///
128/// ```ignore
129/// let config = ExecutionConfig::builder()
130///     .verbosity(Verbosity::Verbose)
131///     .format(OutputFormat::Json)
132///     .build();
133/// ```
134#[derive(Default)]
135pub struct ExecutionConfigBuilder {
136    verbosity: Option<Verbosity>,
137    format: Option<OutputFormat>,
138    metrics: Option<PerformanceMetrics>,
139}
140
141impl ExecutionConfigBuilder {
142    /// Set the verbosity level.
143    #[must_use]
144    pub const fn verbosity(mut self, verbosity: Verbosity) -> Self {
145        self.verbosity = Some(verbosity);
146        self
147    }
148
149    /// Set the output format.
150    #[must_use]
151    pub const fn format(mut self, format: OutputFormat) -> Self {
152        self.format = Some(format);
153        self
154    }
155
156    /// Set the performance metrics.
157    #[must_use]
158    pub fn metrics(mut self, metrics: PerformanceMetrics) -> Self {
159        self.metrics = Some(metrics);
160        self
161    }
162
163    /// Build the configuration.
164    #[must_use]
165    pub fn build(self) -> ExecutionConfig {
166        ExecutionConfig {
167            verbosity: self.verbosity.unwrap_or(Verbosity::Normal),
168            format: self.format.unwrap_or(OutputFormat::Text),
169            metrics: self.metrics.unwrap_or_default(),
170        }
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_new() {
180        let config = ExecutionConfig::new(
181            Verbosity::Verbose,
182            OutputFormat::Json,
183            PerformanceMetrics::default(),
184        );
185
186        assert_eq!(config.verbosity, Verbosity::Verbose);
187        assert_eq!(config.format, OutputFormat::Json);
188    }
189
190    #[test]
191    fn test_minimal() {
192        let config = ExecutionConfig::minimal(OutputFormat::Json);
193
194        assert_eq!(config.verbosity, Verbosity::Normal);
195        assert_eq!(config.format, OutputFormat::Json);
196    }
197
198    #[test]
199    fn test_default() {
200        let config = ExecutionConfig::default();
201
202        assert_eq!(config.verbosity, Verbosity::Normal);
203        assert_eq!(config.format, OutputFormat::Text);
204    }
205
206    #[test]
207    fn test_is_quiet() {
208        let quiet = ExecutionConfig::new(
209            Verbosity::Quiet,
210            OutputFormat::Text,
211            PerformanceMetrics::default(),
212        );
213        let normal = ExecutionConfig::default();
214
215        assert!(quiet.is_quiet());
216        assert!(!normal.is_quiet());
217    }
218
219    #[test]
220    fn test_is_verbose() {
221        let verbose = ExecutionConfig::new(
222            Verbosity::Verbose,
223            OutputFormat::Text,
224            PerformanceMetrics::default(),
225        );
226        let debug = ExecutionConfig::new(
227            Verbosity::Debug,
228            OutputFormat::Text,
229            PerformanceMetrics::default(),
230        );
231        let normal = ExecutionConfig::default();
232
233        assert!(verbose.is_verbose());
234        assert!(debug.is_verbose());
235        assert!(!normal.is_verbose());
236    }
237
238    #[test]
239    fn test_is_debug() {
240        let debug = ExecutionConfig::new(
241            Verbosity::Debug,
242            OutputFormat::Text,
243            PerformanceMetrics::default(),
244        );
245        let verbose = ExecutionConfig::new(
246            Verbosity::Verbose,
247            OutputFormat::Text,
248            PerformanceMetrics::default(),
249        );
250
251        assert!(debug.is_debug());
252        assert!(!verbose.is_debug());
253    }
254
255    #[test]
256    fn test_is_machine_readable() {
257        let json = ExecutionConfig::minimal(OutputFormat::Json);
258        let jsonl = ExecutionConfig::minimal(OutputFormat::Jsonl);
259        let text = ExecutionConfig::minimal(OutputFormat::Text);
260
261        assert!(json.is_machine_readable());
262        assert!(jsonl.is_machine_readable());
263        assert!(!text.is_machine_readable());
264    }
265
266    #[test]
267    fn test_builder() {
268        let config = ExecutionConfig::builder()
269            .verbosity(Verbosity::Verbose)
270            .format(OutputFormat::Json)
271            .build();
272
273        assert_eq!(config.verbosity, Verbosity::Verbose);
274        assert_eq!(config.format, OutputFormat::Json);
275    }
276
277    #[test]
278    fn test_builder_defaults() {
279        let config = ExecutionConfig::builder().build();
280
281        assert_eq!(config.verbosity, Verbosity::Normal);
282        assert_eq!(config.format, OutputFormat::Text);
283    }
284}