workspace_node_tools/
manager.rs1#![allow(clippy::all)]
5use std::{
6 collections::HashMap, fmt::Display, fmt::Formatter, fmt::Result as FmtResult, path::Path,
7};
8
9#[cfg(feature = "napi")]
10#[napi(string_enum)]
11#[derive(Debug, PartialEq)]
12pub enum PackageManager {
13 Npm,
14 Yarn,
15 Pnpm,
16 Bun,
17}
18
19#[cfg(not(feature = "napi"))]
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub enum PackageManager {
23 Npm,
24 Yarn,
25 Pnpm,
26 Bun,
27}
28
29impl Display for PackageManager {
30 fn fmt(&self, f: &mut Formatter) -> FmtResult {
31 let package_manager = match self {
32 PackageManager::Npm => "npm".to_string(),
33 PackageManager::Yarn => "yarn".to_string(),
34 PackageManager::Pnpm => "pnpm".to_string(),
35 PackageManager::Bun => "bun".to_string(),
36 };
37
38 write!(f, "{}", package_manager)
39 }
40}
41
42pub fn detect_package_manager(path: &Path) -> Option<PackageManager> {
44 let package_manager_files = HashMap::from([
45 ("package-lock.json", PackageManager::Npm),
46 ("npm-shrinkwrap.json", PackageManager::Npm),
47 ("yarn.lock", PackageManager::Yarn),
48 ("pnpm-lock.yaml", PackageManager::Pnpm),
49 ("bun.lockb", PackageManager::Bun),
50 ]);
51
52 for (file, package_manager) in package_manager_files.iter() {
53 let lock_file = path.join(file);
54
55 if lock_file.exists() {
56 return Some(*package_manager);
57 }
58 }
59
60 if let Some(parent) = path.parent() {
61 return detect_package_manager(&parent);
62 }
63
64 None
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::{paths::get_project_root_path, utils::create_test_monorepo};
71 use std::{fs::remove_dir_all, path::PathBuf};
72
73 #[test]
74 fn package_manager_for_npm_lock() -> Result<(), std::io::Error> {
75 let ref monorepo_dir = create_test_monorepo(&PackageManager::Npm)?;
76 let project_root = get_project_root_path(Some(monorepo_dir.to_path_buf()));
77
78 let package_manager =
79 detect_package_manager(&PathBuf::from(project_root.unwrap()).as_path());
80
81 assert_eq!(package_manager, Some(PackageManager::Npm));
82 remove_dir_all(&monorepo_dir)?;
83 Ok(())
84 }
85
86 #[test]
87 fn package_manager_for_yarn_lock() -> Result<(), std::io::Error> {
88 let ref monorepo_dir = create_test_monorepo(&PackageManager::Yarn)?;
89 let project_root = get_project_root_path(Some(monorepo_dir.to_path_buf()));
90
91 let package_manager =
92 detect_package_manager(&PathBuf::from(project_root.unwrap()).as_path());
93
94 assert_eq!(package_manager, Some(PackageManager::Yarn));
95 remove_dir_all(&monorepo_dir)?;
96 Ok(())
97 }
98
99 #[test]
100 fn package_manager_for_pnpm_lock() -> Result<(), std::io::Error> {
101 let ref monorepo_dir = create_test_monorepo(&PackageManager::Pnpm)?;
102 let project_root = get_project_root_path(Some(monorepo_dir.to_path_buf()));
103
104 let package_manager =
105 detect_package_manager(&PathBuf::from(project_root.unwrap()).as_path());
106
107 assert_eq!(package_manager, Some(PackageManager::Pnpm));
108 remove_dir_all(&monorepo_dir)?;
109 Ok(())
110 }
111
112 #[test]
113 fn package_manager_for_bun_lock() -> Result<(), std::io::Error> {
114 let ref monorepo_dir = create_test_monorepo(&PackageManager::Bun)?;
115 let project_root = get_project_root_path(Some(monorepo_dir.to_path_buf()));
116
117 let package_manager =
118 detect_package_manager(&PathBuf::from(project_root.unwrap()).as_path());
119
120 assert_eq!(package_manager, Some(PackageManager::Bun));
121 remove_dir_all(&monorepo_dir)?;
122 Ok(())
123 }
124
125 #[test]
126 fn package_manager_not_present() {
127 let path = std::env::current_dir().expect("Current user home directory");
128 let package_manager = detect_package_manager(&path);
129
130 assert_eq!(package_manager, None);
131 }
132
133 #[test]
134 #[should_panic]
135 fn package_manager_empty_display_should_panic() {
136 let path = std::env::current_dir().expect("Current user home directory");
137 let package_manager = detect_package_manager(&path);
138
139 assert_eq!(package_manager.unwrap().to_string(), String::from(""));
140 }
141}