1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Source trait and chunk types: the abstraction for pluggable input backends.
use Serialize;
use Error;
/// A scannable chunk of text with metadata about where it came from.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::{Chunk, ChunkMetadata};
///
/// let chunk = Chunk {
/// data: "API_KEY=sk_live_example".into(),
/// metadata: ChunkMetadata {
/// source_type: "filesystem".into(),
/// path: Some("app.env".into()),
/// commit: None,
/// author: None,
/// date: None,
/// },
/// };
///
/// assert_eq!(chunk.metadata.path.as_deref(), Some("app.env"));
/// ```
/// Metadata that tracks the source location for a scanned chunk.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::ChunkMetadata;
///
/// let metadata = ChunkMetadata {
/// source_type: "git-diff".into(),
/// path: Some("src/lib.rs".into()),
/// commit: Some("abc123".into()),
/// author: Some("Dev".into()),
/// date: Some("2026-03-26T00:00:00Z".into()),
/// };
///
/// assert_eq!(metadata.source_type, "git-diff");
/// ```
/// Produces chunks of text for the scanner to process.
/// Each implementation handles a different input source.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::{Chunk, ChunkMetadata, Source, SourceError};
///
/// struct StaticSource;
///
/// impl Source for StaticSource {
/// fn name(&self) -> &str {
/// "static"
/// }
///
/// fn chunks(&self) -> Box<dyn Iterator<Item = Result<Chunk, SourceError>> + '_> {
/// Box::new(std::iter::once(Ok(Chunk {
/// data: "TOKEN=value".into(),
/// metadata: ChunkMetadata {
/// source_type: "static".into(),
/// path: None,
/// commit: None,
/// author: None,
/// date: None,
/// },
/// })))
/// }
/// }
///
/// let source = StaticSource;
/// assert_eq!(source.name(), "static");
/// ```
/// Errors returned by input sources while enumerating or reading content.
///
/// # Examples
///
/// ```rust
/// use keyhog_core::SourceError;
///
/// let error = SourceError::Other("pass a readable file or directory".into());
/// assert!(error.to_string().contains("Fix"));
/// ```