socket_patch_core/utils/
enumerate.rs1use std::path::Path;
2
3use crate::crawlers::types::{CrawledPackage, CrawlerOptions};
4use crate::crawlers::NpmCrawler;
5
6pub type EnumeratedPackage = CrawledPackage;
8
9pub async fn enumerate_node_modules(cwd: &Path) -> Vec<CrawledPackage> {
14 let crawler = NpmCrawler::new();
15 let options = CrawlerOptions {
16 cwd: cwd.to_path_buf(),
17 global: false,
18 global_prefix: None,
19 batch_size: 100,
20 };
21 crawler.crawl_all(&options).await
22}
23
24#[cfg(test)]
25mod tests {
26 use super::*;
27
28 #[tokio::test]
29 async fn test_enumerate_empty_dir() {
30 let dir = tempfile::tempdir().unwrap();
31 let packages = enumerate_node_modules(dir.path()).await;
32 assert!(packages.is_empty());
33 }
34
35 #[tokio::test]
36 async fn test_enumerate_with_packages() {
37 let dir = tempfile::tempdir().unwrap();
38 let nm = dir.path().join("node_modules");
39
40 let pkg_dir = nm.join("test-pkg");
42 tokio::fs::create_dir_all(&pkg_dir).await.unwrap();
43 tokio::fs::write(
44 pkg_dir.join("package.json"),
45 r#"{"name": "test-pkg", "version": "1.0.0"}"#,
46 )
47 .await
48 .unwrap();
49
50 let scoped_dir = nm.join("@scope").join("my-lib");
52 tokio::fs::create_dir_all(&scoped_dir).await.unwrap();
53 tokio::fs::write(
54 scoped_dir.join("package.json"),
55 r#"{"name": "@scope/my-lib", "version": "2.0.0"}"#,
56 )
57 .await
58 .unwrap();
59
60 let packages = enumerate_node_modules(dir.path()).await;
61 assert_eq!(packages.len(), 2);
62
63 let purls: Vec<&str> = packages.iter().map(|p| p.purl.as_str()).collect();
64 assert!(purls.contains(&"pkg:npm/test-pkg@1.0.0"));
65 assert!(purls.contains(&"pkg:npm/@scope/my-lib@2.0.0"));
66 }
67
68 #[tokio::test]
69 async fn test_enumerate_deduplicates() {
70 let dir = tempfile::tempdir().unwrap();
71 let nm = dir.path().join("node_modules");
72
73 let pkg1 = nm.join("foo");
75 tokio::fs::create_dir_all(&pkg1).await.unwrap();
76 tokio::fs::write(
77 pkg1.join("package.json"),
78 r#"{"name": "foo", "version": "1.0.0"}"#,
79 )
80 .await
81 .unwrap();
82
83 let pkg2 = nm.join("bar");
85 tokio::fs::create_dir_all(&pkg2).await.unwrap();
86 tokio::fs::write(
87 pkg2.join("package.json"),
88 r#"{"name": "bar", "version": "2.0.0"}"#,
89 )
90 .await
91 .unwrap();
92 let nested_foo = pkg2.join("node_modules").join("foo");
93 tokio::fs::create_dir_all(&nested_foo).await.unwrap();
94 tokio::fs::write(
95 nested_foo.join("package.json"),
96 r#"{"name": "foo", "version": "1.0.0"}"#,
97 )
98 .await
99 .unwrap();
100
101 let packages = enumerate_node_modules(dir.path()).await;
102 let foo_count = packages
104 .iter()
105 .filter(|p| p.purl == "pkg:npm/foo@1.0.0")
106 .count();
107 assert_eq!(foo_count, 1);
108 }
109}