sklears_core/
api_generator_config.rs

1//! API Generator Configuration Module
2//!
3//! This module provides configuration structures and settings for the API reference generator,
4//! including output formats, validation options, and generation parameters.
5
6use serde::{Deserialize, Serialize};
7
8/// Configuration for the API reference generator
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct GeneratorConfig {
11    /// Output format for the generated documentation
12    pub output_format: OutputFormat,
13    /// Whether to include code examples in the output
14    pub include_examples: bool,
15    /// Whether to validate examples by compilation
16    pub validate_examples: bool,
17    /// Whether to extract type information
18    pub include_type_info: bool,
19    /// Whether to generate cross-references
20    pub include_cross_refs: bool,
21    /// Maximum depth for trait hierarchy analysis
22    pub max_hierarchy_depth: usize,
23    /// Whether to include private items
24    pub include_private: bool,
25    /// Custom CSS/styling for HTML output
26    pub custom_styling: Option<String>,
27}
28
29impl GeneratorConfig {
30    /// Create a new generator configuration with default settings
31    pub fn new() -> Self {
32        Self {
33            output_format: OutputFormat::Json,
34            include_examples: true,
35            validate_examples: false, // Disabled by default for performance
36            include_type_info: true,
37            include_cross_refs: true,
38            max_hierarchy_depth: 5,
39            include_private: false,
40            custom_styling: None,
41        }
42    }
43
44    /// Set the output format
45    pub fn with_output_format(mut self, format: OutputFormat) -> Self {
46        self.output_format = format;
47        self
48    }
49
50    /// Enable or disable example validation
51    pub fn with_validation(mut self, validate: bool) -> Self {
52        self.validate_examples = validate;
53        self
54    }
55
56    /// Enable or disable example inclusion
57    pub fn with_examples(mut self, include: bool) -> Self {
58        self.include_examples = include;
59        self
60    }
61
62    /// Set maximum hierarchy depth
63    pub fn with_max_depth(mut self, depth: usize) -> Self {
64        self.max_hierarchy_depth = depth;
65        self
66    }
67
68    /// Include private items in documentation
69    pub fn with_private_items(mut self, include: bool) -> Self {
70        self.include_private = include;
71        self
72    }
73
74    /// Set custom CSS styling for HTML output
75    pub fn with_custom_styling(mut self, css: Option<String>) -> Self {
76        self.custom_styling = css;
77        self
78    }
79
80    /// Enable or disable type information extraction
81    pub fn with_type_info(mut self, include: bool) -> Self {
82        self.include_type_info = include;
83        self
84    }
85
86    /// Enable or disable cross-reference generation
87    pub fn with_cross_refs(mut self, include: bool) -> Self {
88        self.include_cross_refs = include;
89        self
90    }
91}
92
93impl Default for GeneratorConfig {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99/// Supported output formats for API documentation
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
101pub enum OutputFormat {
102    /// JSON format for programmatic consumption
103    #[default]
104    Json,
105    /// HTML format for web display
106    Html,
107    /// Markdown format for text display
108    Markdown,
109    /// Interactive WebAssembly playground
110    Interactive,
111    /// OpenAPI specification
112    OpenApi,
113}
114
115impl OutputFormat {
116    /// Get the file extension for this format
117    pub fn file_extension(&self) -> &'static str {
118        match self {
119            OutputFormat::Json => "json",
120            OutputFormat::Html => "html",
121            OutputFormat::Markdown => "md",
122            OutputFormat::Interactive => "html",
123            OutputFormat::OpenApi => "yaml",
124        }
125    }
126
127    /// Get the MIME type for this format
128    pub fn mime_type(&self) -> &'static str {
129        match self {
130            OutputFormat::Json => "application/json",
131            OutputFormat::Html => "text/html",
132            OutputFormat::Markdown => "text/markdown",
133            OutputFormat::Interactive => "text/html",
134            OutputFormat::OpenApi => "application/x-yaml",
135        }
136    }
137
138    /// Check if this format supports interactive features
139    pub fn supports_interactive(&self) -> bool {
140        matches!(self, OutputFormat::Html | OutputFormat::Interactive)
141    }
142
143    /// Check if this format supports syntax highlighting
144    pub fn supports_syntax_highlighting(&self) -> bool {
145        matches!(
146            self,
147            OutputFormat::Html | OutputFormat::Interactive | OutputFormat::Markdown
148        )
149    }
150}
151
152/// Configuration for playground generation
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct PlaygroundConfig {
155    /// Enable WebAssembly compilation
156    pub wasm_enabled: bool,
157    /// Enable real-time code execution
158    pub real_time_execution: bool,
159    /// Enable syntax highlighting
160    pub syntax_highlighting: bool,
161    /// Enable auto-completion
162    pub auto_completion: bool,
163    /// Enable error highlighting
164    pub error_highlighting: bool,
165    /// Available crates for import
166    pub available_crates: Vec<String>,
167    /// Number of examples available
168    pub example_count: usize,
169    /// Number of traits documented
170    pub trait_count: usize,
171    /// Number of types documented
172    pub type_count: usize,
173}
174
175impl PlaygroundConfig {
176    /// Create a new playground configuration with default settings
177    pub fn new() -> Self {
178        Self {
179            wasm_enabled: true,
180            real_time_execution: true,
181            syntax_highlighting: true,
182            auto_completion: true,
183            error_highlighting: true,
184            available_crates: vec!["sklears-core".to_string()],
185            example_count: 0,
186            trait_count: 0,
187            type_count: 0,
188        }
189    }
190
191    /// Enable or disable WebAssembly compilation
192    pub fn with_wasm(mut self, enabled: bool) -> Self {
193        self.wasm_enabled = enabled;
194        self
195    }
196
197    /// Enable or disable real-time execution
198    pub fn with_real_time_execution(mut self, enabled: bool) -> Self {
199        self.real_time_execution = enabled;
200        self
201    }
202
203    /// Enable or disable syntax highlighting
204    pub fn with_syntax_highlighting(mut self, enabled: bool) -> Self {
205        self.syntax_highlighting = enabled;
206        self
207    }
208
209    /// Enable or disable auto-completion
210    pub fn with_auto_completion(mut self, enabled: bool) -> Self {
211        self.auto_completion = enabled;
212        self
213    }
214
215    /// Enable or disable error highlighting
216    pub fn with_error_highlighting(mut self, enabled: bool) -> Self {
217        self.error_highlighting = enabled;
218        self
219    }
220
221    /// Set available crates for import
222    pub fn with_available_crates(mut self, crates: Vec<String>) -> Self {
223        self.available_crates = crates;
224        self
225    }
226
227    /// Update statistics
228    pub fn with_stats(
229        mut self,
230        example_count: usize,
231        trait_count: usize,
232        type_count: usize,
233    ) -> Self {
234        self.example_count = example_count;
235        self.trait_count = trait_count;
236        self.type_count = type_count;
237        self
238    }
239}
240
241impl Default for PlaygroundConfig {
242    fn default() -> Self {
243        Self::new()
244    }
245}
246
247/// Validation configuration for code examples
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct ValidationConfig {
250    /// Enable compilation validation
251    pub compile_check: bool,
252    /// Enable runtime validation
253    pub runtime_check: bool,
254    /// Timeout for validation (in milliseconds)
255    pub timeout_ms: u64,
256    /// Maximum memory usage for validation (in bytes)
257    pub max_memory: usize,
258    /// Enable linting during validation
259    pub lint_check: bool,
260    /// Additional validation flags
261    pub extra_flags: Vec<String>,
262}
263
264impl ValidationConfig {
265    /// Create a new validation configuration with default settings
266    pub fn new() -> Self {
267        Self {
268            compile_check: true,
269            runtime_check: false,
270            timeout_ms: 5000,
271            max_memory: 1024 * 1024 * 50, // 50MB
272            lint_check: true,
273            extra_flags: Vec::new(),
274        }
275    }
276
277    /// Enable or disable compilation checking
278    pub fn with_compile_check(mut self, enabled: bool) -> Self {
279        self.compile_check = enabled;
280        self
281    }
282
283    /// Enable or disable runtime checking
284    pub fn with_runtime_check(mut self, enabled: bool) -> Self {
285        self.runtime_check = enabled;
286        self
287    }
288
289    /// Set validation timeout
290    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
291        self.timeout_ms = timeout_ms;
292        self
293    }
294
295    /// Set maximum memory usage
296    pub fn with_max_memory(mut self, max_memory: usize) -> Self {
297        self.max_memory = max_memory;
298        self
299    }
300
301    /// Enable or disable linting
302    pub fn with_lint_check(mut self, enabled: bool) -> Self {
303        self.lint_check = enabled;
304        self
305    }
306
307    /// Add extra validation flags
308    pub fn with_extra_flags(mut self, flags: Vec<String>) -> Self {
309        self.extra_flags = flags;
310        self
311    }
312}
313
314impl Default for ValidationConfig {
315    fn default() -> Self {
316        Self::new()
317    }
318}
319
320/// Theme configuration for output styling
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct ThemeConfig {
323    /// Primary theme color
324    pub primary_color: String,
325    /// Secondary theme color
326    pub secondary_color: String,
327    /// Background color
328    pub background_color: String,
329    /// Text color
330    pub text_color: String,
331    /// Code block background color
332    pub code_background: String,
333    /// Code text color
334    pub code_text_color: String,
335    /// Font family for regular text
336    pub font_family: String,
337    /// Font family for code
338    pub code_font_family: String,
339    /// Enable dark mode
340    pub dark_mode: bool,
341}
342
343impl ThemeConfig {
344    /// Create a new theme configuration with default light theme
345    pub fn light_theme() -> Self {
346        Self {
347            primary_color: "#0066cc".to_string(),
348            secondary_color: "#ff6b35".to_string(),
349            background_color: "#ffffff".to_string(),
350            text_color: "#333333".to_string(),
351            code_background: "#f5f5f5".to_string(),
352            code_text_color: "#333333".to_string(),
353            font_family: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif".to_string(),
354            code_font_family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace".to_string(),
355            dark_mode: false,
356        }
357    }
358
359    /// Create a new theme configuration with default dark theme
360    pub fn dark_theme() -> Self {
361        Self {
362            primary_color: "#4da6ff".to_string(),
363            secondary_color: "#ff8c66".to_string(),
364            background_color: "#1e1e1e".to_string(),
365            text_color: "#d4d4d4".to_string(),
366            code_background: "#2d2d30".to_string(),
367            code_text_color: "#d4d4d4".to_string(),
368            font_family: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif".to_string(),
369            code_font_family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace".to_string(),
370            dark_mode: true,
371        }
372    }
373
374    /// Generate CSS variables for this theme
375    pub fn to_css_variables(&self) -> String {
376        format!(
377            r#":root {{
378    --primary-color: {};
379    --secondary-color: {};
380    --background-color: {};
381    --text-color: {};
382    --code-background: {};
383    --code-text-color: {};
384    --font-family: {};
385    --code-font-family: {};
386}}"#,
387            self.primary_color,
388            self.secondary_color,
389            self.background_color,
390            self.text_color,
391            self.code_background,
392            self.code_text_color,
393            self.font_family,
394            self.code_font_family
395        )
396    }
397}
398
399impl Default for ThemeConfig {
400    fn default() -> Self {
401        Self::light_theme()
402    }
403}
404
405// ================================================================================================
406// TESTS
407// ================================================================================================
408
409#[allow(non_snake_case)]
410#[cfg(test)]
411mod tests {
412    use super::*;
413
414    #[test]
415    fn test_generator_config_creation() {
416        let config = GeneratorConfig::new();
417        assert_eq!(config.output_format, OutputFormat::Json);
418        assert!(config.include_examples);
419        assert!(!config.validate_examples);
420        assert!(config.include_type_info);
421        assert!(config.include_cross_refs);
422        assert_eq!(config.max_hierarchy_depth, 5);
423        assert!(!config.include_private);
424        assert!(config.custom_styling.is_none());
425    }
426
427    #[test]
428    fn test_generator_config_builder() {
429        let config = GeneratorConfig::new()
430            .with_output_format(OutputFormat::Html)
431            .with_validation(true)
432            .with_examples(false)
433            .with_max_depth(10)
434            .with_private_items(true);
435
436        assert_eq!(config.output_format, OutputFormat::Html);
437        assert!(config.validate_examples);
438        assert!(!config.include_examples);
439        assert_eq!(config.max_hierarchy_depth, 10);
440        assert!(config.include_private);
441    }
442
443    #[test]
444    fn test_output_format_properties() {
445        assert_eq!(OutputFormat::Json.file_extension(), "json");
446        assert_eq!(OutputFormat::Html.file_extension(), "html");
447        assert_eq!(OutputFormat::Markdown.file_extension(), "md");
448        assert_eq!(OutputFormat::Interactive.file_extension(), "html");
449        assert_eq!(OutputFormat::OpenApi.file_extension(), "yaml");
450
451        assert_eq!(OutputFormat::Json.mime_type(), "application/json");
452        assert_eq!(OutputFormat::Html.mime_type(), "text/html");
453        assert_eq!(OutputFormat::Markdown.mime_type(), "text/markdown");
454
455        assert!(!OutputFormat::Json.supports_interactive());
456        assert!(OutputFormat::Html.supports_interactive());
457        assert!(OutputFormat::Interactive.supports_interactive());
458
459        assert!(!OutputFormat::Json.supports_syntax_highlighting());
460        assert!(OutputFormat::Html.supports_syntax_highlighting());
461        assert!(OutputFormat::Markdown.supports_syntax_highlighting());
462    }
463
464    #[test]
465    fn test_playground_config() {
466        let config = PlaygroundConfig::new()
467            .with_wasm(false)
468            .with_real_time_execution(false)
469            .with_available_crates(vec!["sklears-core".to_string(), "std".to_string()])
470            .with_stats(10, 5, 8);
471
472        assert!(!config.wasm_enabled);
473        assert!(!config.real_time_execution);
474        assert!(config.syntax_highlighting);
475        assert_eq!(config.available_crates.len(), 2);
476        assert_eq!(config.example_count, 10);
477        assert_eq!(config.trait_count, 5);
478        assert_eq!(config.type_count, 8);
479    }
480
481    #[test]
482    fn test_validation_config() {
483        let config = ValidationConfig::new()
484            .with_compile_check(false)
485            .with_runtime_check(true)
486            .with_timeout(10000)
487            .with_max_memory(1024 * 1024 * 100);
488
489        assert!(!config.compile_check);
490        assert!(config.runtime_check);
491        assert_eq!(config.timeout_ms, 10000);
492        assert_eq!(config.max_memory, 1024 * 1024 * 100);
493        assert!(config.lint_check);
494    }
495
496    #[test]
497    fn test_theme_config_light() {
498        let theme = ThemeConfig::light_theme();
499        assert_eq!(theme.primary_color, "#0066cc");
500        assert_eq!(theme.background_color, "#ffffff");
501        assert!(!theme.dark_mode);
502
503        let css = theme.to_css_variables();
504        assert!(css.contains("--primary-color: #0066cc"));
505        assert!(css.contains("--background-color: #ffffff"));
506    }
507
508    #[test]
509    fn test_theme_config_dark() {
510        let theme = ThemeConfig::dark_theme();
511        assert_eq!(theme.primary_color, "#4da6ff");
512        assert_eq!(theme.background_color, "#1e1e1e");
513        assert!(theme.dark_mode);
514
515        let css = theme.to_css_variables();
516        assert!(css.contains("--primary-color: #4da6ff"));
517        assert!(css.contains("--background-color: #1e1e1e"));
518    }
519
520    #[test]
521    fn test_config_serialization() {
522        let config = GeneratorConfig::new().with_output_format(OutputFormat::Html);
523        let serialized = serde_json::to_string(&config).unwrap();
524        let deserialized: GeneratorConfig = serde_json::from_str(&serialized).unwrap();
525
526        assert_eq!(config.output_format, deserialized.output_format);
527        assert_eq!(config.include_examples, deserialized.include_examples);
528    }
529
530    #[test]
531    fn test_default_implementations() {
532        let _: GeneratorConfig = Default::default();
533        let _: OutputFormat = Default::default();
534        let _: PlaygroundConfig = Default::default();
535        let _: ValidationConfig = Default::default();
536        let _: ThemeConfig = Default::default();
537    }
538}