use anyhow::{Context, Result};
use std::collections::HashSet;
static HOST_NAME: &str = "npmjs.com";
fn get_parsed_version(
version: &Option<&str>,
) -> thirdpass_core::extension::common::VersionParseResult {
if let Some(version) = version.and_then(|v| Some(v.to_string())) {
if version != "" {
return Ok(version);
}
}
Err(thirdpass_core::extension::common::VersionError::from_missing_version())
}
type JsonObject = serde_json::Map<String, serde_json::Value>;
fn parse_dependencies(
package_entry: &serde_json::Value,
include_dev_dependencies: bool,
) -> Result<Vec<thirdpass_core::extension::Dependency>> {
let mut unprocessed_dependencies_sections: std::collections::VecDeque<&JsonObject> =
std::collections::VecDeque::new();
if let Some(dependencies) = package_entry["dependencies"].as_object() {
unprocessed_dependencies_sections.push_back(dependencies);
}
let mut all_dependencies = HashSet::new();
while let Some(dependencies) = unprocessed_dependencies_sections.pop_front() {
for (package_name, entry) in dependencies {
if !include_dev_dependencies && entry["dev"].as_bool().unwrap_or_default() {
continue;
}
let version_parse_result = get_parsed_version(&entry["version"].as_str());
all_dependencies.insert(thirdpass_core::extension::Dependency {
name: package_name.clone(),
version: version_parse_result,
});
if let Some(sub_dependencies) = entry["dependencies"].as_object() {
unprocessed_dependencies_sections.push_back(sub_dependencies);
}
}
}
let mut all_dependencies: Vec<_> = all_dependencies.into_iter().collect();
all_dependencies.sort();
Ok(all_dependencies)
}
pub fn get_dependencies(
file_path: &std::path::PathBuf,
include_dev_dependencies: bool,
) -> Result<Vec<thirdpass_core::extension::Dependency>> {
let file = std::fs::File::open(file_path)?;
let reader = std::io::BufReader::new(file);
let package_entry: serde_json::Value = serde_json::from_reader(reader).context(format!(
"Failed to parse package-lock.json: {}",
file_path.display()
))?;
let all_dependencies = parse_dependencies(&package_entry, include_dev_dependencies)?;
Ok(all_dependencies)
}
pub fn get_registry_host_name() -> String {
HOST_NAME.to_string()
}