1use anyhow::Result;
6use std::path::Path;
7use vx_plugin::{Ecosystem, PackageSpec, VxPackageManager, VxPlugin, VxTool};
8
9#[derive(Default)]
11pub struct BunPackageManager;
12
13#[async_trait::async_trait]
14impl VxPackageManager for BunPackageManager {
15 fn name(&self) -> &str {
16 "bun"
17 }
18
19 fn ecosystem(&self) -> Ecosystem {
20 Ecosystem::Node
21 }
22
23 fn description(&self) -> &str {
24 "Incredibly fast JavaScript runtime, bundler, test runner, and package manager"
25 }
26
27 fn is_preferred_for_project(&self, project_path: &Path) -> bool {
29 project_path.join("bun.lockb").exists()
30 }
31
32 fn get_config_files(&self) -> Vec<&str> {
33 vec!["package.json", "bun.lockb", "bunfig.toml"]
34 }
35
36 async fn install_packages(&self, packages: &[PackageSpec], project_path: &Path) -> Result<()> {
37 if packages.is_empty() {
38 self.run_command(&["install"], &[], project_path).await
39 } else {
40 let package_names: Vec<String> = packages
41 .iter()
42 .map(|pkg| {
43 if let Some(version) = &pkg.version {
44 format!("{}@{}", pkg.name, version)
45 } else {
46 pkg.name.clone()
47 }
48 })
49 .collect();
50
51 let command = if packages.iter().any(|pkg| pkg.dev_dependency) {
52 vec!["add", "--dev"]
53 } else {
54 vec!["add"]
55 };
56
57 self.run_command(&command, &package_names, project_path)
58 .await
59 }
60 }
61
62 async fn remove_packages(&self, packages: &[String], project_path: &Path) -> Result<()> {
63 self.run_command(&["remove"], packages, project_path).await
64 }
65
66 async fn update_packages(&self, packages: &[String], project_path: &Path) -> Result<()> {
67 if packages.is_empty() {
68 self.run_command(&["update"], &[], project_path).await
69 } else {
70 self.run_command(&["update"], packages, project_path).await
71 }
72 }
73}
74
75#[derive(Default)]
77pub struct BunPlugin;
78
79#[async_trait::async_trait]
80impl VxPlugin for BunPlugin {
81 fn name(&self) -> &str {
82 "bun"
83 }
84
85 fn description(&self) -> &str {
86 "Bun package manager support for vx"
87 }
88
89 fn version(&self) -> &str {
90 "1.0.0"
91 }
92
93 fn tools(&self) -> Vec<Box<dyn VxTool>> {
94 vec![]
95 }
96
97 fn package_managers(&self) -> Vec<Box<dyn VxPackageManager>> {
98 vec![Box::new(BunPackageManager)]
99 }
100
101 fn supports_tool(&self, _tool_name: &str) -> bool {
102 false
103 }
104}
105
106pub fn create_bun_plugin() -> Box<dyn VxPlugin> {
108 Box::new(BunPlugin)
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_bun_package_manager() {
117 let pm = BunPackageManager;
118 assert_eq!(pm.name(), "bun");
119 assert_eq!(pm.ecosystem(), Ecosystem::Node);
120 assert_eq!(
121 pm.description(),
122 "Incredibly fast JavaScript runtime, bundler, test runner, and package manager"
123 );
124 }
125
126 #[test]
127 fn test_bun_plugin() {
128 let plugin = BunPlugin;
129 assert_eq!(plugin.name(), "bun");
130 assert_eq!(plugin.version(), "1.0.0");
131 }
132}