use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Maintainer {
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub email: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dist {
#[serde(default)]
pub tarball: Option<String>,
#[serde(default)]
pub shasum: Option<String>,
#[serde(default)]
pub integrity: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersionInfo {
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub version: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub dist: Option<Dist>,
#[serde(default)]
pub scripts: Option<HashMap<String, String>>,
#[serde(default)]
pub dependencies: Option<HashMap<String, String>>,
#[serde(default, rename = "devDependencies")]
pub dev_dependencies: Option<HashMap<String, String>>,
#[serde(default)]
pub maintainers: Option<Vec<Maintainer>>,
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PackageMetadata {
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub versions: HashMap<String, VersionInfo>,
#[serde(default)]
pub time: HashMap<String, String>,
#[serde(default)]
pub maintainers: Option<Vec<Maintainer>>,
#[serde(default, rename = "dist-tags")]
pub dist_tags: Option<HashMap<String, String>>,
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
const INSTALL_SCRIPT_KEYS: &[&str] = &[
"preinstall",
"install",
"postinstall",
"preuninstall",
"postuninstall",
"prepare",
];
impl VersionInfo {
pub fn install_scripts(&self) -> HashMap<String, String> {
let Some(scripts) = &self.scripts else {
return HashMap::new();
};
scripts
.iter()
.filter(|(key, _)| INSTALL_SCRIPT_KEYS.contains(&key.as_str()))
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
}
}
impl PackageMetadata {
pub fn latest_version(&self) -> Option<&str> {
self.dist_tags
.as_ref()
.and_then(|tags| tags.get("latest"))
.map(|s| s.as_str())
}
pub fn latest_version_info(&self) -> Option<&VersionInfo> {
let v = self.latest_version()?;
self.versions.get(v)
}
}