1use std::path::PathBuf;
4
5#[derive(Debug, Clone)]
22pub struct DiscoveredFile {
23 pub id: FileId,
25 pub path: PathBuf,
27 pub size_bytes: u64,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49pub struct FileId(pub u32);
50
51const _: () = assert!(std::mem::size_of::<FileId>() == 4);
55#[cfg(all(target_pointer_width = "64", unix))]
56const _: () = assert!(std::mem::size_of::<DiscoveredFile>() == 40);
57
58#[derive(Debug, Clone)]
60pub struct EntryPoint {
61 pub path: PathBuf,
63 pub source: EntryPointSource,
65}
66
67impl std::fmt::Display for EntryPointSource {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 match self {
70 Self::PackageJsonMain => f.write_str("package.json main"),
71 Self::PackageJsonModule => f.write_str("package.json module"),
72 Self::PackageJsonExports => f.write_str("package.json exports"),
73 Self::PackageJsonBin => f.write_str("package.json bin"),
74 Self::PackageJsonScript => f.write_str("package.json script"),
75 Self::Plugin { name } => write!(f, "{name}"),
76 Self::TestFile => f.write_str("test file"),
77 Self::DefaultIndex => f.write_str("default index"),
78 Self::ManualEntry => f.write_str("manual entry"),
79 Self::InfrastructureConfig => f.write_str("infrastructure config"),
80 }
81 }
82}
83
84#[derive(Debug, Clone)]
86pub enum EntryPointSource {
87 PackageJsonMain,
89 PackageJsonModule,
91 PackageJsonExports,
93 PackageJsonBin,
95 PackageJsonScript,
97 Plugin {
99 name: String,
101 },
102 TestFile,
104 DefaultIndex,
106 ManualEntry,
108 InfrastructureConfig,
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use std::collections::hash_map::DefaultHasher;
116 use std::hash::{Hash, Hasher};
117
118 #[test]
121 fn file_id_equality() {
122 assert_eq!(FileId(0), FileId(0));
123 assert_eq!(FileId(42), FileId(42));
124 assert_ne!(FileId(0), FileId(1));
125 }
126
127 #[test]
128 fn file_id_copy_semantics() {
129 let a = FileId(5);
130 let b = a; assert_eq!(a, b);
132 }
133
134 #[test]
135 fn file_id_hash_consistent() {
136 let id = FileId(99);
137 let hash1 = {
138 let mut h = DefaultHasher::new();
139 id.hash(&mut h);
140 h.finish()
141 };
142 let hash2 = {
143 let mut h = DefaultHasher::new();
144 id.hash(&mut h);
145 h.finish()
146 };
147 assert_eq!(hash1, hash2);
148 }
149
150 #[test]
151 fn file_id_equal_values_same_hash() {
152 let a = FileId(7);
153 let b = FileId(7);
154 let hash_a = {
155 let mut h = DefaultHasher::new();
156 a.hash(&mut h);
157 h.finish()
158 };
159 let hash_b = {
160 let mut h = DefaultHasher::new();
161 b.hash(&mut h);
162 h.finish()
163 };
164 assert_eq!(hash_a, hash_b);
165 }
166
167 #[test]
168 fn file_id_inner_value_accessible() {
169 let id = FileId(123);
170 assert_eq!(id.0, 123);
171 }
172
173 #[test]
174 fn file_id_debug_format() {
175 let id = FileId(42);
176 let debug = format!("{id:?}");
177 assert!(
178 debug.contains("42"),
179 "Debug should show inner value: {debug}"
180 );
181 }
182
183 #[test]
186 fn discovered_file_clone() {
187 let original = DiscoveredFile {
188 id: FileId(0),
189 path: PathBuf::from("/project/src/index.ts"),
190 size_bytes: 1024,
191 };
192 let cloned = original.clone();
193 assert_eq!(cloned.id, original.id);
194 assert_eq!(cloned.path, original.path);
195 assert_eq!(cloned.size_bytes, original.size_bytes);
196 }
197
198 #[test]
199 fn discovered_file_zero_size() {
200 let file = DiscoveredFile {
201 id: FileId(0),
202 path: PathBuf::from("/empty.ts"),
203 size_bytes: 0,
204 };
205 assert_eq!(file.size_bytes, 0);
206 }
207
208 #[test]
209 fn discovered_file_large_size() {
210 let file = DiscoveredFile {
211 id: FileId(0),
212 path: PathBuf::from("/large.ts"),
213 size_bytes: u64::MAX,
214 };
215 assert_eq!(file.size_bytes, u64::MAX);
216 }
217
218 #[test]
221 fn entry_point_clone() {
222 let ep = EntryPoint {
223 path: PathBuf::from("/project/src/main.ts"),
224 source: EntryPointSource::PackageJsonMain,
225 };
226 let cloned = ep.clone();
227 assert_eq!(cloned.path, ep.path);
228 assert!(matches!(cloned.source, EntryPointSource::PackageJsonMain));
229 }
230
231 #[test]
234 fn entry_point_source_all_variants_constructible() {
235 let _ = EntryPointSource::PackageJsonMain;
237 let _ = EntryPointSource::PackageJsonModule;
238 let _ = EntryPointSource::PackageJsonExports;
239 let _ = EntryPointSource::PackageJsonBin;
240 let _ = EntryPointSource::PackageJsonScript;
241 let _ = EntryPointSource::Plugin {
242 name: "next".to_string(),
243 };
244 let _ = EntryPointSource::TestFile;
245 let _ = EntryPointSource::DefaultIndex;
246 let _ = EntryPointSource::ManualEntry;
247 let _ = EntryPointSource::InfrastructureConfig;
248 }
249
250 #[test]
251 fn entry_point_source_plugin_preserves_name() {
252 let source = EntryPointSource::Plugin {
253 name: "vitest".to_string(),
254 };
255 match source {
256 EntryPointSource::Plugin { name } => assert_eq!(name, "vitest"),
257 _ => panic!("expected Plugin variant"),
258 }
259 }
260
261 #[test]
262 fn entry_point_source_plugin_clone_preserves_name() {
263 let source = EntryPointSource::Plugin {
264 name: "storybook".to_string(),
265 };
266 let cloned = source.clone();
268 assert!(matches!(&source, EntryPointSource::Plugin { name } if name == "storybook"));
270 match cloned {
272 EntryPointSource::Plugin { name } => assert_eq!(name, "storybook"),
273 _ => panic!("expected Plugin variant after clone"),
274 }
275 }
276
277 #[test]
278 fn entry_point_source_debug_format() {
279 let source = EntryPointSource::PackageJsonMain;
280 let debug = format!("{source:?}");
281 assert!(
282 debug.contains("PackageJsonMain"),
283 "Debug should name the variant: {debug}"
284 );
285
286 let plugin = EntryPointSource::Plugin {
287 name: "remix".to_string(),
288 };
289 let debug = format!("{plugin:?}");
290 assert!(
291 debug.contains("remix"),
292 "Debug should show plugin name: {debug}"
293 );
294 }
295
296 #[test]
297 fn entry_point_source_display_all_variants() {
298 assert_eq!(
299 EntryPointSource::PackageJsonMain.to_string(),
300 "package.json main"
301 );
302 assert_eq!(
303 EntryPointSource::PackageJsonModule.to_string(),
304 "package.json module"
305 );
306 assert_eq!(
307 EntryPointSource::PackageJsonExports.to_string(),
308 "package.json exports"
309 );
310 assert_eq!(
311 EntryPointSource::PackageJsonBin.to_string(),
312 "package.json bin"
313 );
314 assert_eq!(
315 EntryPointSource::PackageJsonScript.to_string(),
316 "package.json script"
317 );
318 assert_eq!(
319 EntryPointSource::Plugin {
320 name: "vitest".to_string()
321 }
322 .to_string(),
323 "vitest"
324 );
325 assert_eq!(EntryPointSource::TestFile.to_string(), "test file");
326 assert_eq!(EntryPointSource::DefaultIndex.to_string(), "default index");
327 assert_eq!(EntryPointSource::ManualEntry.to_string(), "manual entry");
328 assert_eq!(
329 EntryPointSource::InfrastructureConfig.to_string(),
330 "infrastructure config"
331 );
332 }
333}