1use std::path::PathBuf;
7use vx_installer::{ArchiveFormat, InstallConfig, InstallMethod};
8use vx_tool_standard::{StandardToolConfig, StandardUrlBuilder, ToolDependency};
9
10pub struct Config;
12
13pub struct NodeUrlBuilder;
15
16impl StandardUrlBuilder for NodeUrlBuilder {
17 fn download_url(version: &str) -> Option<String> {
19 let _platform = Self::get_platform_string();
20 let filename = Self::get_filename(version);
21
22 Some(format!("https://nodejs.org/dist/v{}/{}", version, filename))
23 }
24
25 fn get_filename(version: &str) -> String {
27 let platform = Self::get_platform_string();
28 if cfg!(windows) {
29 format!("node-v{}-{}.zip", version, platform)
30 } else {
31 format!("node-v{}-{}.tar.gz", version, platform)
32 }
33 }
34
35 fn get_platform_string() -> String {
37 match (std::env::consts::OS, std::env::consts::ARCH) {
38 ("windows", "x86_64") => "win-x64".to_string(),
39 ("windows", "x86") => "win-x86".to_string(),
40 ("windows", "aarch64") => "win-arm64".to_string(),
41 ("macos", "x86_64") => "darwin-x64".to_string(),
42 ("macos", "aarch64") => "darwin-arm64".to_string(),
43 ("linux", "x86_64") => "linux-x64".to_string(),
44 ("linux", "x86") => "linux-x86".to_string(),
45 ("linux", "aarch64") => "linux-arm64".to_string(),
46 ("linux", "arm") => "linux-armv7l".to_string(),
47 _ => "linux-x64".to_string(), }
49 }
50}
51
52impl StandardToolConfig for Config {
54 fn tool_name() -> &'static str {
55 "node"
56 }
57
58 fn create_install_config(version: &str, install_dir: PathBuf) -> InstallConfig {
59 create_install_config(version, install_dir)
60 }
61
62 fn get_install_methods() -> Vec<String> {
63 get_install_methods()
64 }
65
66 fn supports_auto_install() -> bool {
67 true
68 }
69
70 fn get_manual_instructions() -> String {
71 get_manual_instructions()
72 }
73
74 fn get_dependencies() -> Vec<ToolDependency> {
75 vec![]
77 }
78
79 fn get_default_version() -> &'static str {
80 "20.11.0" }
82}
83
84pub fn create_install_config(version: &str, install_dir: PathBuf) -> InstallConfig {
86 let actual_version = if version == "latest" {
87 "20.11.0" } else {
89 version
90 };
91
92 let download_url = NodeUrlBuilder::download_url(actual_version);
93 let install_method = InstallMethod::Archive {
94 format: if cfg!(windows) {
95 ArchiveFormat::Zip
96 } else {
97 ArchiveFormat::TarGz
98 },
99 };
100
101 InstallConfig::builder()
102 .tool_name("node")
103 .version(version.to_string())
104 .install_method(install_method)
105 .download_url(download_url.unwrap_or_default())
106 .install_dir(install_dir)
107 .build()
108}
109
110pub fn get_install_methods() -> Vec<String> {
112 vec![
113 "Official releases".to_string(),
114 if cfg!(target_os = "macos") {
115 "Homebrew".to_string()
116 } else {
117 "Package manager".to_string()
118 },
119 "Node Version Manager (nvm)".to_string(),
120 ]
121}
122
123pub fn supports_auto_install() -> bool {
125 true
126}
127
128pub fn get_manual_instructions() -> String {
130 "To install Node.js manually:\n\
131 • Visit: https://nodejs.org/\n\
132 • Or use a version manager like nvm"
133 .to_string()
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_node_url_builder() {
142 let url = NodeUrlBuilder::download_url("18.17.0");
143 assert!(url.is_some());
144 assert!(url.unwrap().contains("nodejs.org"));
145 }
146
147 #[test]
148 fn test_platform_string() {
149 let platform = NodeUrlBuilder::get_platform_string();
150 assert!(!platform.is_empty());
151 }
152
153 #[test]
154 fn test_create_install_config() {
155 let config = create_install_config("18.17.0", PathBuf::from("/tmp/node"));
156 assert_eq!(config.tool_name, "node");
157 assert_eq!(config.version, "18.17.0");
158 assert!(config.download_url.is_some());
159 }
160
161 #[test]
162 fn test_latest_version_handling() {
163 let config = create_install_config("latest", PathBuf::from("/tmp/node"));
164 assert_eq!(config.version, "latest");
165 assert!(config.download_url.unwrap().contains("20.11.0"));
167 }
168}