use chrono::{DateTime, Local}; use collections::{BTreeSet, HashMap}; use serde_json_lenient::Value; use std::{path::Path, sync::Arc}; #[derive(Clone, Debug)] pub struct PackageJson { pub mtime: DateTime, pub data: PackageJsonData, } #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct PackageJsonData { pub jest_package_path: Option>, pub mocha_package_path: Option>, pub vitest_package_path: Option>, pub jasmine_package_path: Option>, pub scripts: BTreeSet<(Arc, String)>, pub package_manager: Option<&'static str>, } impl PackageJsonData { pub fn new(path: Arc, package_json: HashMap) -> Self { let mut scripts = BTreeSet::new(); if let Some(Value::Object(package_json_scripts)) = package_json.get("scripts") { scripts.extend( package_json_scripts .keys() .cloned() .map(|name| (path.clone(), name)), ); } let mut jest_package_path = None; let mut mocha_package_path = None; let mut vitest_package_path = None; let mut jasmine_package_path = None; if let Some(Value::Object(dependencies)) = package_json.get("devDependencies") { if dependencies.contains_key("jest") { jest_package_path.get_or_insert_with(|| path.clone()); } if dependencies.contains_key("mocha") { mocha_package_path.get_or_insert_with(|| path.clone()); } if dependencies.contains_key("vitest") { vitest_package_path.get_or_insert_with(|| path.clone()); } if dependencies.contains_key("jasmine") { jasmine_package_path.get_or_insert_with(|| path.clone()); } } if let Some(Value::Object(dev_dependencies)) = package_json.get("dependencies") { if dev_dependencies.contains_key("jest") { jest_package_path.get_or_insert_with(|| path.clone()); } if dev_dependencies.contains_key("mocha") { mocha_package_path.get_or_insert_with(|| path.clone()); } if dev_dependencies.contains_key("vitest") { vitest_package_path.get_or_insert_with(|| path.clone()); } if dev_dependencies.contains_key("jasmine") { jasmine_package_path.get_or_insert_with(|| path.clone()); } } let package_manager = package_json .get("packageManager") .and_then(|value| value.as_str()) .and_then(|value| { if value.starts_with("pnpm") { Some("pnpm") } else if value.starts_with("yarn") { Some("yarn") } else if value.starts_with("npm") { Some("npm") } else { None } }); Self { jest_package_path, mocha_package_path, vitest_package_path, jasmine_package_path, scripts, package_manager, } } pub fn merge(&mut self, other: Self) { self.jest_package_path = self.jest_package_path.take().or(other.jest_package_path); self.mocha_package_path = self.mocha_package_path.take().or(other.mocha_package_path); self.vitest_package_path = self .vitest_package_path .take() .or(other.vitest_package_path); self.jasmine_package_path = self .jasmine_package_path .take() .or(other.jasmine_package_path); self.scripts.extend(other.scripts); self.package_manager = self.package_manager.or(other.package_manager); } }