1pub mod config;
36pub mod error;
37pub mod file;
38pub mod tokenization;
39pub mod traits;
40pub mod types;
41pub mod utils;
42
43pub use error::{Result, ScribeError};
45
46pub use file::{
47 bytes_to_human, ConfigurationFormat, DocumentationFormat, FileInfo, FileType, GitFileStatus,
48 GitStatus, Language, RenderDecision, RenderDecisionCategory, BINARY_EXTENSIONS,
49 MARKDOWN_EXTENSIONS,
50};
51
52pub use types::{
53 AnalysisMetadata,
54 AnalysisResult,
56 CentralityScores,
58 ChurnInfo,
59
60 FileTypeStats,
61 GitStatistics,
62 GraphStats,
63
64 HeuristicWeights,
65
66 LanguageStats,
67 Position,
69 Range,
70
71 RepositoryInfo,
73 ScoreComponents,
75 SizeStatistics,
76};
77
78pub use config::{
79 AnalysisConfig, Config, CustomScoringRule, FeatureFlags, FilteringConfig, GeneralConfig,
80 GitConfig, OutputConfig, OutputFormat, PerformanceConfig, ScoreModifier, ScoringConfig,
81};
82
83pub use traits::{
84 CacheStats,
85 CacheStorage,
86 CentralityComputer,
87 DependencyGraph,
89 DependencyNodeMetadata,
90 DocumentationBlock,
91 DocumentationType,
92 FileAnalyzer,
94 GitIntegration,
95 GitRepositoryInfo,
96 HeuristicScorer,
97 LanguageExtension,
98
99 OutputFormatter,
100 PatternMatcher,
102 PluginRegistry,
103
104 ProgressReporter,
105 RepositoryAnalyzer,
106};
107
108pub use utils::{
110 hash::{generate_hash, hash_file_content},
111 math::{clamp, mean, median, normalize, std_deviation},
112 path::{
113 find_repo_root, is_hidden, is_under_directory, normalize_path, path_depth, relative_path,
114 },
115 string::{count_lines, dedent, extract_identifier, is_likely_binary, truncate},
116 time::{current_timestamp, duration_to_human},
117 validation::{validate_directory, validate_file, validate_readable_path},
118};
119
120pub use tokenization::{
121 ContentType, TokenBudget, TokenCounter, TokenizationComparison, TokenizerConfig,
122};
123
124pub const VERSION: &str = env!("CARGO_PKG_VERSION");
126
127pub mod meta {
129 pub const NAME: &str = env!("CARGO_PKG_NAME");
131
132 pub const VERSION: &str = env!("CARGO_PKG_VERSION");
134
135 pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
137
138 pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
140
141 pub const REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
143
144 pub const LICENSE: &str = env!("CARGO_PKG_LICENSE");
146
147 pub const TARGET: Option<&str> = option_env!("TARGET");
149
150 pub const BUILD_TIMESTAMP: Option<&str> = option_env!("BUILD_TIMESTAMP");
152
153 pub const GIT_HASH: Option<&str> = option_env!("GIT_HASH");
155
156 pub fn info() -> String {
158 format!("{} v{} - {}", NAME, VERSION, DESCRIPTION)
159 }
160
161 pub fn build_info() -> String {
163 let mut info = format!("{} v{}", NAME, VERSION);
164
165 if let Some(target) = TARGET {
166 info.push_str(&format!(" ({})", target));
167 }
168
169 if let Some(git_hash) = GIT_HASH {
170 info.push_str(&format!(" [{}]", &git_hash[..8]));
171 }
172
173 if let Some(timestamp) = BUILD_TIMESTAMP {
174 info.push_str(&format!(" built on {}", timestamp));
175 }
176
177 info
178 }
179}
180
181pub mod prelude {
183 pub use crate::{
186 duration_to_human,
187 generate_hash,
188 normalize_path,
190 Config,
191 FeatureFlags,
192
193 FileAnalyzer,
195 FileInfo,
196 FileType,
197 HeuristicScorer,
198 HeuristicWeights,
199 Language,
200 OutputFormatter,
201 ProgressReporter,
202
203 RenderDecision,
204 RepositoryAnalyzer,
205 Result,
207 ScoreComponents,
208 ScribeError,
209 };
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_version() {
218 assert!(!VERSION.is_empty());
219 assert!(VERSION.parse::<semver::Version>().is_ok());
220 }
221
222 #[test]
223 fn test_meta_info() {
224 let info = meta::info();
225 assert!(info.contains("scribe-core"));
226 assert!(info.contains(VERSION));
227 }
228
229 #[test]
230 fn test_build_info() {
231 let build_info = meta::build_info();
232 assert!(build_info.contains("scribe-core"));
233 assert!(build_info.contains(VERSION));
234 }
235
236 #[test]
237 fn test_prelude_imports() {
238 use crate::prelude::*;
240
241 let config = Config::default();
242 assert!(config.general.verbosity <= 4);
243
244 let decision = RenderDecision::include("test");
245 assert!(decision.should_include());
246
247 let hash = generate_hash(&"test");
248 assert!(!hash.is_empty());
249 }
250
251 #[test]
252 fn test_core_functionality() {
253 let err = ScribeError::config("test error");
255 assert!(err.to_string().contains("test error"));
256
257 let lang = Language::from_extension("rs");
259 assert_eq!(lang, Language::Rust);
260
261 let depth = path_depth("src/lib/mod.rs");
263 assert_eq!(depth, 3);
264
265 let truncated = truncate("hello world", 5);
267 assert_eq!(truncated, "he...");
268 }
269
270 #[test]
271 fn test_score_components() {
272 let mut scores = ScoreComponents::zero();
273 scores.doc_score = 0.8;
274 scores.import_score = 0.6;
275
276 let weights = HeuristicWeights::default();
277 scores.compute_final_score(&weights);
278
279 assert!(scores.final_score > 0.0);
280 assert!(scores.final_score <= 1.0);
281 }
282
283 #[test]
284 fn test_configuration() {
285 let config = Config::default();
286 assert!(config.validate().is_ok());
287
288 let hash1 = config.compute_hash();
289 let hash2 = config.compute_hash();
290 assert_eq!(hash1, hash2);
291 }
292}