vx_tool_bun/
lib.rs

1//! Bun package manager support for vx
2//!
3//! This provides Bun package manager integration for the vx tool.
4
5use anyhow::Result;
6use std::path::Path;
7use vx_plugin::{Ecosystem, PackageSpec, VxPackageManager, VxPlugin, VxTool};
8
9/// Bun package manager implementation
10#[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    /// Detect if this is a bun project by looking for bun.lockb
28    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/// Bun plugin
76#[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
106/// Factory function to create the plugin
107pub 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}