1pub mod config;
36pub mod error;
37pub mod file;
38pub mod tokenization;
39pub mod traits;
40pub mod types;
41pub mod utils;
42
43#[cfg(feature = "scaling")]
45pub mod scaling;
46
47pub 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 AnalysisResult,
60 CentralityScores,
62 ChurnInfo,
63
64 FileTypeStats,
65 GitStatistics,
66 GraphStats,
67
68 HeuristicWeights,
69
70 LanguageStats,
71 Position,
73 Range,
74
75 RepositoryInfo,
77 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 DependencyGraph,
93 DependencyNodeMetadata,
94 DocumentationBlock,
95 DocumentationType,
96 FileAnalyzer,
98 GitIntegration,
99 GitRepositoryInfo,
100 HeuristicScorer,
101 LanguageExtension,
102
103 OutputFormatter,
104 PatternMatcher,
106 PluginRegistry,
107
108 ProgressReporter,
109 RepositoryAnalyzer,
110};
111
112pub 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
128pub const VERSION: &str = env!("CARGO_PKG_VERSION");
130
131pub mod meta {
133 pub const NAME: &str = env!("CARGO_PKG_NAME");
135
136 pub const VERSION: &str = env!("CARGO_PKG_VERSION");
138
139 pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
141
142 pub const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
144
145 pub const REPOSITORY: &str = env!("CARGO_PKG_REPOSITORY");
147
148 pub const LICENSE: &str = env!("CARGO_PKG_LICENSE");
150
151 pub const TARGET: Option<&str> = option_env!("TARGET");
153
154 pub const BUILD_TIMESTAMP: Option<&str> = option_env!("BUILD_TIMESTAMP");
156
157 pub const GIT_HASH: Option<&str> = option_env!("GIT_HASH");
159
160 pub fn info() -> String {
162 format!("{} v{} - {}", NAME, VERSION, DESCRIPTION)
163 }
164
165 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
185pub mod prelude {
187 pub use crate::{
190 duration_to_human,
191 generate_hash,
192 normalize_path,
194 Config,
195 FeatureFlags,
196
197 FileAnalyzer,
199 FileInfo,
200 FileType,
201 HeuristicScorer,
202 HeuristicWeights,
203 Language,
204 OutputFormatter,
205 ProgressReporter,
206
207 RenderDecision,
208 RepositoryAnalyzer,
209 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 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 let err = ScribeError::config("test error");
259 assert!(err.to_string().contains("test error"));
260
261 let lang = Language::from_extension("rs");
263 assert_eq!(lang, Language::Rust);
264
265 let depth = path_depth("src/lib/mod.rs");
267 assert_eq!(depth, 3);
268
269 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}