diff --git a/docs/commands.md b/docs/commands.md index 6209dfa9a..3ab51a44a 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -571,6 +571,10 @@ OPTIONS: [default: info] [possible values: quiet, info, all, error] + --lts [] + List lts version. use --lts to list all lts version. use --lts=hydrogen to filter lts + version + --node-dist-mirror https://nodejs.org/dist/ mirror diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 015b3ac5f..335e5734f 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -1,17 +1,62 @@ use crate::config::FnmConfig; -use crate::remote_node_index; +use crate::remote_node_index::{self, IndexedNodeVersion}; use thiserror::Error; -#[derive(clap::Parser, Debug)] -pub struct LsRemote {} +#[derive(Debug)] +enum LtsOption { + Bool(bool), + String(String), +} -impl super::command::Command for LsRemote { - type Error = Error; +impl std::str::FromStr for LtsOption { + type Err = String; - fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> { + fn from_str(s: &str) -> Result { + Ok(LtsOption::String(s.to_owned())) + } +} + +#[derive(clap::Parser, Debug)] +pub struct LsRemote { + /// List lts version. + /// use --lts to list all lts version. + /// use --lts=hydrogen to filter lts version. + #[clap(long)] + lts: Option>, +} + +impl LsRemote { + fn run(self, config: &FnmConfig) -> Result, Error> { let all_versions = remote_node_index::list(&config.node_dist_mirror)?; - for version in all_versions { + let (lts, lts_name) = match self + .lts + .unwrap_or(Some(LtsOption::Bool(false))) + .unwrap_or(LtsOption::Bool(true)) + { + LtsOption::Bool(lts) => (lts, String::from("")), + LtsOption::String(lts_name) => (true, lts_name.trim().to_owned()), + }; + + let avaliable_versions = if lts { + all_versions + .into_iter() + .filter(|version| version.lts.is_some()) + .filter(|version| { + lts_name.is_empty() + || version + .lts + .as_deref() + .unwrap_or_default() + .to_lowercase() + .contains(<s_name.to_lowercase()) + }) + .collect() + } else { + all_versions + }; + + for version in &avaliable_versions { print!("{}", version.version); if let Some(lts) = &version.lts { print!(" ({lts})"); @@ -19,6 +64,16 @@ impl super::command::Command for LsRemote { println!(); } + Ok(avaliable_versions) + } +} + +impl super::command::Command for LsRemote { + type Error = Error; + + fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> { + self.run(&config)?; + Ok(()) } } @@ -31,3 +86,43 @@ pub enum Error { source: crate::http::Error, }, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ls_remote() { + let config = FnmConfig::default(); + + let all_versions = remote_node_index::list(&config.node_dist_mirror).unwrap(); + let versions = LsRemote { lts: None }.run(&config).unwrap(); + + assert!(all_versions.len() == versions.len()); + } + + #[test] + fn test_ls_remote_with_lts() { + let config = FnmConfig::default(); + + let versions = LsRemote { lts: Some(None) }.run(&config).unwrap(); + + assert!(versions.iter().all(|version| version.lts.is_some())); + } + + #[test] + fn test_ls_remote_with_lts_and_filter() { + let config = FnmConfig::default(); + let filter_name = "drogen"; + + let versions = LsRemote { + lts: Some(Some(LtsOption::String(filter_name.to_owned()))), + } + .run(&config) + .unwrap(); + + assert!(versions.iter().all(|version| { + version.lts.is_some() && version.lts.as_deref().unwrap().contains(filter_name) + })); + } +}