scribe_core/
lib.rs

1//! Core crate for Scribe
2
3//! # Scribe Core
4//!
5//! Core types, utilities, and foundational components for the Scribe code analysis library.
6//! This crate provides the fundamental data structures and traits used across all other
7//! Scribe crates.
8//!
9//! ## Features
10//!
11//! - **Comprehensive Error Handling**: Rich error types with proper context and error chaining
12//! - **File Analysis**: File metadata, language detection, and classification
13//! - **Scoring System**: Heuristic scoring components and configurable weights
14//! - **Configuration**: Flexible configuration with validation and serialization
15//! - **Extensibility**: Traits for custom analyzers, scorers, and formatters
16//! - **Utilities**: Common functions for path manipulation, string processing, and more
17//!
18//! ## Basic Usage
19//!
20//! ```rust
21//! use scribe_core::{Config, FileInfo, ScoreComponents, Result};
22//! use std::path::Path;
23//!
24//! # fn main() -> Result<()> {
25//! // Load configuration
26//! let config = Config::default();
27//!
28//! // Analyze a file (this would typically be done by other crates)
29//! // let file_info = analyze_file(Path::new("src/lib.rs"), &config)?;
30//! # Ok(())
31//! # }
32//! ```
33
34// Core modules
35pub mod config;
36pub mod error;
37pub mod file;
38pub mod tokenization;
39pub mod traits;
40pub mod types;
41pub mod utils;
42
43// Scaling optimizations (optional)
44#[cfg(feature = "scaling")]
45pub mod scaling;
46
47// Re-export commonly used types for convenience
48pub use error::{Result, ScribeError};
49
50pub use file::{
51    bytes_to_human, ConfigurationFormat, DocumentationFormat, FileInfo, FileType, GitFileStatus,
52    GitStatus, Language, RenderDecision, RenderDecisionCategory, BINARY_EXTENSIONS,
53    MARKDOWN_EXTENSIONS,
54};
55
56pub use types::{
57    AnalysisMetadata,
58    // Analysis results
59    AnalysisResult,
60    // Graph analysis
61    CentralityScores,
62    ChurnInfo,
63
64    FileTypeStats,
65    GitStatistics,
66    GraphStats,
67
68    HeuristicWeights,
69
70    LanguageStats,
71    // Core positioning and ranges
72    Position,
73    Range,
74
75    // Repository information
76    RepositoryInfo,
77    // Scoring system
78    ScoreComponents,
79    SizeStatistics,
80};
81
82pub use config::{
83    AnalysisConfig, Config, CustomScoringRule, FeatureFlags, FilteringConfig, GeneralConfig,
84    GitConfig, OutputConfig, OutputFormat, PerformanceConfig, ScoreModifier, ScoringConfig,
85};
86
87pub use traits::{
88    CacheStats,
89    CacheStorage,
90    CentralityComputer,
91    // Data structures
92    DependencyGraph,
93    DependencyNodeMetadata,
94    DocumentationBlock,
95    DocumentationType,
96    // Core analysis traits
97    FileAnalyzer,
98    GitIntegration,
99    GitRepositoryInfo,
100    HeuristicScorer,
101    LanguageExtension,
102
103    OutputFormatter,
104    // Infrastructure traits
105    PatternMatcher,
106    PluginRegistry,
107
108    ProgressReporter,
109    RepositoryAnalyzer,
110};
111
112// Utility re-exports for common functionality
113pub use utils::{
114    hash::{generate_hash, hash_file_content},
115    math::{clamp, mean, median, normalize, std_deviation},
116    path::{
117        find_repo_root, is_hidden, is_under_directory, normalize_path, path_depth, relative_path,
118    },
119    string::{count_lines, dedent, extract_identifier, is_likely_binary, truncate},
120    time::{current_timestamp, duration_to_human},
121    validation::{validate_directory, validate_file, validate_readable_path},
122};
123
124pub use tokenization::{
125    ContentType, TokenBudget, TokenCounter, TokenizationComparison, TokenizerConfig,
126};
127
128/// Current version of the Scribe library
129pub const VERSION: &str = env!("CARGO_PKG_VERSION");
130
131/// Library metadata and build information
132pub mod meta {
133    /// Library name
134    pub const NAME: &str = env!("CARGO_PKG_NAME");
135
136    /// Library version
137    pub const VERSION: &str = env!("CARGO_PKG_VERSION");
138
139    /// Library description
140    pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
141
142    /// Authors
143    pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
144
145    /// Repository URL
146    pub const REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
147
148    /// License
149    pub const LICENSE: &str = env!("CARGO_PKG_LICENSE");
150
151    /// Target triple (if available)
152    pub const TARGET: Option<&str> = option_env!("TARGET");
153
154    /// Build timestamp (if available)
155    pub const BUILD_TIMESTAMP: Option<&str> = option_env!("BUILD_TIMESTAMP");
156
157    /// Git commit hash (if available)
158    pub const GIT_HASH: Option<&str> = option_env!("GIT_HASH");
159
160    /// Get library information as a formatted string
161    pub fn info() -> String {
162        format!("{} v{} - {}", NAME, VERSION, DESCRIPTION)
163    }
164
165    /// Get detailed build information
166    pub fn build_info() -> String {
167        let mut info = format!("{} v{}", NAME, VERSION);
168
169        if let Some(target) = TARGET {
170            info.push_str(&format!(" ({})", target));
171        }
172
173        if let Some(git_hash) = GIT_HASH {
174            info.push_str(&format!(" [{}]", &git_hash[..8]));
175        }
176
177        if let Some(timestamp) = BUILD_TIMESTAMP {
178            info.push_str(&format!(" built on {}", timestamp));
179        }
180
181        info
182    }
183}
184
185/// Prelude module for convenient imports
186pub mod prelude {
187    //! Commonly used imports for Scribe applications
188
189    pub use crate::{
190        duration_to_human,
191        generate_hash,
192        // Common utilities
193        normalize_path,
194        Config,
195        FeatureFlags,
196
197        // Essential traits
198        FileAnalyzer,
199        FileInfo,
200        FileType,
201        HeuristicScorer,
202        HeuristicWeights,
203        Language,
204        OutputFormatter,
205        ProgressReporter,
206
207        RenderDecision,
208        RepositoryAnalyzer,
209        // Core types
210        Result,
211        ScoreComponents,
212        ScribeError,
213    };
214}
215
216#[cfg(test)]
217mod tests {
218    use super::*;
219
220    #[test]
221    fn test_version() {
222        assert!(!VERSION.is_empty());
223        assert!(VERSION.parse::<semver::Version>().is_ok());
224    }
225
226    #[test]
227    fn test_meta_info() {
228        let info = meta::info();
229        assert!(info.contains("scribe-core"));
230        assert!(info.contains(VERSION));
231    }
232
233    #[test]
234    fn test_build_info() {
235        let build_info = meta::build_info();
236        assert!(build_info.contains("scribe-core"));
237        assert!(build_info.contains(VERSION));
238    }
239
240    #[test]
241    fn test_prelude_imports() {
242        // Test that prelude imports work
243        use crate::prelude::*;
244
245        let config = Config::default();
246        assert!(config.general.verbosity <= 4);
247
248        let decision = RenderDecision::include("test");
249        assert!(decision.should_include());
250
251        let hash = generate_hash(&"test");
252        assert!(!hash.is_empty());
253    }
254
255    #[test]
256    fn test_core_functionality() {
257        // Test error creation
258        let err = ScribeError::config("test error");
259        assert!(err.to_string().contains("test error"));
260
261        // Test language detection
262        let lang = Language::from_extension("rs");
263        assert_eq!(lang, Language::Rust);
264
265        // Test path utilities
266        let depth = path_depth("src/lib/mod.rs");
267        assert_eq!(depth, 3);
268
269        // Test string utilities
270        let truncated = truncate("hello world", 5);
271        assert_eq!(truncated, "he...");
272    }
273
274    #[test]
275    fn test_score_components() {
276        let mut scores = ScoreComponents::zero();
277        scores.doc_score = 0.8;
278        scores.import_score = 0.6;
279
280        let weights = HeuristicWeights::default();
281        scores.compute_final_score(&weights);
282
283        assert!(scores.final_score > 0.0);
284        assert!(scores.final_score <= 1.0);
285    }
286
287    #[test]
288    fn test_configuration() {
289        let config = Config::default();
290        assert!(config.validate().is_ok());
291
292        let hash1 = config.compute_hash();
293        let hash2 = config.compute_hash();
294        assert_eq!(hash1, hash2);
295    }
296}