package_json_parser/def/
package_manager.rs

1use std::ops::Range;
2
3use derive_more::{Deref, DerefMut};
4use jsonc_parser::{ast::ObjectProp, common::Ranged};
5use miette::{LabeledSpan, MietteDiagnostic, Severity};
6use serde::{Deserialize, Serialize};
7
8use crate::ext::Validator;
9
10#[derive(Debug, PartialEq, Serialize, Deserialize, Eq, Clone, Deref, DerefMut)]
11pub struct PackageManager(String);
12
13impl PackageManager {
14  fn get_package_manager_range(&self, prop: Option<&ObjectProp>) -> Option<Range<usize>> {
15    prop
16      .and_then(|prop| prop.value.as_string_lit())
17      .map(|value| value.range())
18      .map(|range| range.start..range.end)
19  }
20}
21
22impl Validator for PackageManager {
23  fn validate(&self, prop: Option<&ObjectProp>) -> miette::Result<()> {
24    let regex = lazy_regex::regex_is_match!(r#"(npm|pnpm|yarn|bun)@\d+\.\d+\.\d+(-.+)?"#, &self);
25
26    if regex {
27      return Ok(());
28    }
29
30    let range = self.get_package_manager_range(prop);
31
32    let mut diagnostic = MietteDiagnostic::new("Invalid package manager".to_string())
33      .with_help("Please provide a valid package manager")
34      .with_severity(Severity::Error)
35      .with_code("invalid_package_manager");
36
37    if let Some(range) = range {
38      let label = LabeledSpan::at(range, "here".to_string());
39      diagnostic = diagnostic.with_labels(vec![label]);
40    }
41
42    return Err(miette::miette!(diagnostic));
43  }
44}
45
46#[cfg(test)]
47mod tests {
48  use crate::PackageJsonParser;
49
50  #[test]
51  fn should_pass_validate_package_manager() {
52    let jsones = [
53      r#"{"packageManager": "npm@1.0.0"}"#,
54      r#"{"packageManager": "pnpm@1.0.0"}"#,
55      r#"{"packageManager": "yarn@1.0.0"}"#,
56      r#"{"packageManager": "bun@1.0.0"}"#,
57    ];
58
59    for json in jsones {
60      let res = PackageJsonParser::parse_str(json).unwrap();
61      let res = res.validate();
62      assert!(res.is_ok());
63    }
64  }
65
66  #[test]
67  fn should_fail_validate_package_manager() {
68    let jsones = [r#"{"packageManager": "invalid"}"#];
69
70    for json in jsones {
71      let res = PackageJsonParser::parse_str(json).unwrap();
72      let res = res.validate();
73      assert!(res.is_err());
74    }
75  }
76}