diff --git a/docs/config/README.md b/docs/config/README.md index d75c805d..5050631c 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -2859,11 +2859,12 @@ By default the module will be shown if any of the following conditions are met: ### Variables -| Variable | Example | Description | -| -------- | ---------- | ------------------------------------ | -| version | `v13.12.0` | The version of `node` | -| symbol | | Mirrors the value of option `symbol` | -| style\* | | Mirrors the value of option `style` | +| Variable | Example | Description | +| --------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| version | `v13.12.0` | The version of `node` | +| engines_version | `>=12.0.0` | `node` version requirement as set in the engines property of `package.json`. Will only show if the version requirement does not match the `node` version. | +| symbol | | Mirrors the value of option `symbol` | +| style\* | | Mirrors the value of option `style` | *: This variable can only be used as a part of a style string diff --git a/src/modules/nodejs.rs b/src/modules/nodejs.rs index 295dc71e..bf319fcf 100644 --- a/src/modules/nodejs.rs +++ b/src/modules/nodejs.rs @@ -35,6 +35,8 @@ pub fn module<'a>(context: &'a Context) -> Option> { .exec_cmd("node", &["--version"]) .map(|cmd| cmd.stdout) }); + let engines_version = Lazy::new(|| get_engines_version(context)); + let parsed = StringFormatter::new(config.format).and_then(|formatter| { formatter .map_meta(|var, _| match var { @@ -43,9 +45,11 @@ pub fn module<'a>(context: &'a Context) -> Option> { }) .map_style(|variable| match variable { "style" => { - let engines_version = get_engines_version(context); - let in_engines_range = - check_engines_version(nodejs_version.as_deref(), engines_version); + let in_engines_range = check_engines_version( + nodejs_version.as_deref(), + engines_version.as_deref(), + ); + if in_engines_range { Some(Ok(config.style)) } else { @@ -56,7 +60,7 @@ pub fn module<'a>(context: &'a Context) -> Option> { }) .map(|variable| match variable { "version" => { - let version = nodejs_version + let node_ver = nodejs_version .deref() .as_ref()? .trim_start_matches('v') @@ -64,11 +68,20 @@ pub fn module<'a>(context: &'a Context) -> Option> { VersionFormatter::format_module_version( module.get_name(), - version, + node_ver, config.version_format, ) .map(Ok) } + "engines_version" => { + let in_engines_range = check_engines_version( + nodejs_version.as_deref(), + engines_version.as_deref(), + ); + let eng_ver = engines_version.as_deref()?.to_string(); + + (!in_engines_range).then_some(Ok(eng_ver)) + } _ => None, }) .parse(None, Some(context)) @@ -89,16 +102,19 @@ fn get_engines_version(context: &Context) -> Option { let json_str = context.read_file_from_pwd("package.json")?; let package_json: json::Value = json::from_str(&json_str).ok()?; let raw_version = package_json.get("engines")?.get("node")?.as_str()?; + Some(raw_version.to_string()) } -fn check_engines_version(nodejs_version: Option<&str>, engines_version: Option) -> bool { +fn check_engines_version(nodejs_version: Option<&str>, engines_version: Option<&str>) -> bool { let (Some(nodejs_version), Some(engines_version)) = (nodejs_version, engines_version) else { return true; }; - let Ok(r) = VersionReq::parse(&engines_version) else { + + let Ok(r) = VersionReq::parse(engines_version) else { return true; }; + let re = Regex::new(r"\d+\.\d+\.\d+").unwrap(); let version = re .captures(nodejs_version) @@ -106,6 +122,7 @@ fn check_engines_version(nodejs_version: Option<&str>, engines_version: Option v, Err(_e) => return true, @@ -269,6 +286,80 @@ mod tests { assert_eq!(expected, actual); dir.close() } + + #[test] + fn show_expected_version_when_engines_does_not_match() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let mut file = File::create(dir.path().join("package.json"))?; + file.write_all( + b"{ + \"engines\":{ + \"node\":\"<=11.0.0\" + } + }", + )?; + file.sync_all()?; + + let actual = ModuleRenderer::new("nodejs") + .path(dir.path()) + .config(toml::toml! { + [nodejs] + format = "via [$symbol($version )($engines_version )]($style)" + }) + .collect(); + let expected = Some(format!( + "via {}", + Color::Red.bold().paint(" v12.0.0 <=11.0.0 ") + )); + + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn do_not_show_expected_version_if_engines_match() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let mut file = File::create(dir.path().join("package.json"))?; + file.write_all( + b"{ + \"engines\":{ + \"node\":\">=12.0.0\" + } + }", + )?; + file.sync_all()?; + + let actual = ModuleRenderer::new("nodejs") + .path(dir.path()) + .config(toml::toml! [ + [nodejs] + format = "via [$symbol($version )($engines_version )]($style)" + ]) + .collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint(" v12.0.0 "))); + + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn do_not_show_expected_version_if_no_set_engines_version() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("package.json"))?.sync_all()?; + + let actual = ModuleRenderer::new("nodejs") + .path(dir.path()) + .config(toml::toml! { + [nodejs] + format = "via [$symbol($version )($engines_version )]($style)" + }) + .collect(); + let expected = Some(format!("via {}", Color::Green.bold().paint(" v12.0.0 "))); + + assert_eq!(expected, actual); + dir.close() + } + #[test] fn no_node_installed() -> io::Result<()> { let dir = tempfile::tempdir()?;