1pub mod config;
7pub mod exclusions;
8
9use std::collections::HashSet;
10use std::fs;
11use std::path::Path;
12
13pub struct FlattenConfig {
17 pub skip_folders: HashSet<String>,
19 pub skip_extensions: HashSet<String>,
21 pub show_skipped: bool,
23 pub max_file_size: u64,
25 pub include_hidden: bool,
27 pub max_depth: usize,
29}
30
31impl Default for FlattenConfig {
32 fn default() -> Self {
33 Self {
34 skip_folders: HashSet::new(),
35 skip_extensions: HashSet::new(),
36 show_skipped: false,
37 max_file_size: 104857600, include_hidden: false,
39 max_depth: usize::MAX,
40 }
41 }
42}
43
44impl FlattenConfig {
45 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn should_skip_path(&self, path: &Path) -> bool {
58 if let Some(name) = path.file_name()
59 && let Some(name_str) = name.to_str() {
60 if !self.include_hidden && name_str.starts_with('.') {
62 return true;
63 }
64 return self.skip_folders.contains(name_str);
65 }
66 false
67 }
68
69 pub fn should_skip_file(&self, path: &Path) -> bool {
70 if let Some(extension) = path.extension()
71 && let Some(ext_str) = extension.to_str() {
72 return self.skip_extensions.contains(ext_str);
73 }
74 false
75 }
76}
77
78pub fn create_test_structure() -> anyhow::Result<tempfile::TempDir> {
79 let temp_dir = tempfile::TempDir::new()?;
80
81 fs::create_dir_all(temp_dir.path().join("src"))?;
83 fs::create_dir_all(temp_dir.path().join("tests"))?;
84 fs::create_dir_all(temp_dir.path().join("node_modules"))?;
85
86 fs::write(
88 temp_dir.path().join("src/main.rs"),
89 "fn main() { println!(\"Hello\"); }",
90 )?;
91 fs::write(
92 temp_dir.path().join("src/lib.rs"),
93 "pub fn hello() { \"world\" }",
94 )?;
95 fs::write(
96 temp_dir.path().join("tests/integration.rs"),
97 "#[test] fn test_integration() {}",
98 )?;
99 fs::write(temp_dir.path().join("README.md"), "# Test Project")?;
100 fs::write(
101 temp_dir.path().join("Cargo.toml"),
102 "[package]\nname = \"test\"\nversion = \"0.1.0\"",
103 )?;
104
105 fs::write(temp_dir.path().join("test.bin"), b"\x00\x01\x02\x03\x04")?;
107
108 Ok(temp_dir)
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use std::fs;
115
116 #[test]
117 fn test_config_skip_folders() {
118 let mut config = FlattenConfig::new();
119 config.skip_folders.insert("node_modules".to_string());
120 config.skip_folders.insert(".git".to_string());
121
122 assert!(config.should_skip_path(Path::new("/project/node_modules")));
123 assert!(config.should_skip_path(Path::new("/project/.git")));
124 assert!(!config.should_skip_path(Path::new("/project/src")));
125 }
126
127 #[test]
128 fn test_config_skip_extensions() {
129 let mut config = FlattenConfig::new();
130 config.skip_extensions.insert("exe".to_string());
131 config.skip_extensions.insert("bin".to_string());
132
133 assert!(config.should_skip_file(Path::new("/project/test.exe")));
134 assert!(config.should_skip_file(Path::new("/project/test.bin")));
135 assert!(!config.should_skip_file(Path::new("/project/test.rs")));
136 }
137
138 #[test]
139 fn test_create_test_structure() {
140 let temp_dir = create_test_structure().unwrap();
141
142 assert!(temp_dir.path().join("src").exists());
143 assert!(temp_dir.path().join("tests").exists());
144 assert!(temp_dir.path().join("node_modules").exists());
145 assert!(temp_dir.path().join("src/main.rs").exists());
146 assert!(temp_dir.path().join("README.md").exists());
147 }
148
149 #[test]
150 fn test_file_content_reading() {
151 let temp_dir = create_test_structure().unwrap();
152 let main_rs_path = temp_dir.path().join("src/main.rs");
153
154 let content = fs::read_to_string(&main_rs_path).unwrap();
155 assert!(content.contains("fn main()"));
156 }
157}