package_json.rs

  1use chrono::{DateTime, Local};
  2use collections::{BTreeSet, HashMap};
  3use serde_json_lenient::Value;
  4use std::{path::Path, sync::Arc};
  5
  6#[derive(Clone, Debug)]
  7pub struct PackageJson {
  8    pub mtime: DateTime<Local>,
  9    pub data: PackageJsonData,
 10}
 11
 12#[derive(Clone, Debug, Default, PartialEq, Eq)]
 13pub struct PackageJsonData {
 14    pub jest_package_path: Option<Arc<Path>>,
 15    pub mocha_package_path: Option<Arc<Path>>,
 16    pub vitest_package_path: Option<Arc<Path>>,
 17    pub jasmine_package_path: Option<Arc<Path>>,
 18    pub scripts: BTreeSet<(Arc<Path>, String)>,
 19    pub package_manager: Option<&'static str>,
 20}
 21
 22impl PackageJsonData {
 23    pub fn new(path: Arc<Path>, package_json: HashMap<String, Value>) -> Self {
 24        let mut scripts = BTreeSet::new();
 25        if let Some(Value::Object(package_json_scripts)) = package_json.get("scripts") {
 26            scripts.extend(
 27                package_json_scripts
 28                    .keys()
 29                    .cloned()
 30                    .map(|name| (path.clone(), name)),
 31            );
 32        }
 33
 34        let mut jest_package_path = None;
 35        let mut mocha_package_path = None;
 36        let mut vitest_package_path = None;
 37        let mut jasmine_package_path = None;
 38        if let Some(Value::Object(dependencies)) = package_json.get("devDependencies") {
 39            if dependencies.contains_key("jest") {
 40                jest_package_path.get_or_insert_with(|| path.clone());
 41            }
 42            if dependencies.contains_key("mocha") {
 43                mocha_package_path.get_or_insert_with(|| path.clone());
 44            }
 45            if dependencies.contains_key("vitest") {
 46                vitest_package_path.get_or_insert_with(|| path.clone());
 47            }
 48            if dependencies.contains_key("jasmine") {
 49                jasmine_package_path.get_or_insert_with(|| path.clone());
 50            }
 51        }
 52        if let Some(Value::Object(dev_dependencies)) = package_json.get("dependencies") {
 53            if dev_dependencies.contains_key("jest") {
 54                jest_package_path.get_or_insert_with(|| path.clone());
 55            }
 56            if dev_dependencies.contains_key("mocha") {
 57                mocha_package_path.get_or_insert_with(|| path.clone());
 58            }
 59            if dev_dependencies.contains_key("vitest") {
 60                vitest_package_path.get_or_insert_with(|| path.clone());
 61            }
 62            if dev_dependencies.contains_key("jasmine") {
 63                jasmine_package_path.get_or_insert_with(|| path.clone());
 64            }
 65        }
 66
 67        let package_manager = package_json
 68            .get("packageManager")
 69            .and_then(|value| value.as_str())
 70            .and_then(|value| {
 71                if value.starts_with("pnpm") {
 72                    Some("pnpm")
 73                } else if value.starts_with("yarn") {
 74                    Some("yarn")
 75                } else if value.starts_with("npm") {
 76                    Some("npm")
 77                } else {
 78                    None
 79                }
 80            });
 81
 82        Self {
 83            jest_package_path,
 84            mocha_package_path,
 85            vitest_package_path,
 86            jasmine_package_path,
 87            scripts,
 88            package_manager,
 89        }
 90    }
 91
 92    pub fn merge(&mut self, other: Self) {
 93        self.jest_package_path = self.jest_package_path.take().or(other.jest_package_path);
 94        self.mocha_package_path = self.mocha_package_path.take().or(other.mocha_package_path);
 95        self.vitest_package_path = self
 96            .vitest_package_path
 97            .take()
 98            .or(other.vitest_package_path);
 99        self.jasmine_package_path = self
100            .jasmine_package_path
101            .take()
102            .or(other.jasmine_package_path);
103        self.scripts.extend(other.scripts);
104        self.package_manager = self.package_manager.or(other.package_manager);
105    }
106}