onefetch_manifest/
lib.rs

1use anyhow::{Context, Result};
2use std::fs;
3use std::path::Path;
4use strum::{Display, EnumIter};
5
6#[derive(Clone, PartialEq, Eq, Debug)]
7pub struct Manifest {
8    pub manifest_type: ManifestType,
9    pub number_of_dependencies: usize,
10    pub name: String,
11    pub description: Option<String>,
12    pub version: String,
13    pub license: Option<String>,
14}
15
16#[derive(Display, Clone, Copy, PartialEq, Eq, Debug, EnumIter)]
17pub enum ManifestType {
18    Npm,
19    Cargo,
20}
21
22pub fn get_manifests<P: AsRef<Path>>(path: P) -> Result<Vec<Manifest>> {
23    let manifest_paths = fs::read_dir(path)?
24        .filter_map(std::result::Result::ok)
25        .map(|entry| entry.path())
26        .filter(|entry| entry.is_file())
27        .filter_map(|file_path| {
28            let file_name = file_path
29                .file_name()
30                .and_then(|name| name.to_str())
31                .unwrap_or_default();
32            file_name_to_manifest_type(file_name).map(|manifest_type| (file_path, manifest_type))
33        })
34        .map(|(file_path, manifest_type)| match manifest_type {
35            ManifestType::Cargo => parse_cargo_manifest(&file_path),
36            ManifestType::Npm => parse_npm_manifest(&file_path),
37        })
38        .filter_map(std::result::Result::ok)
39        .collect::<Vec<_>>();
40
41    Ok(manifest_paths)
42}
43
44fn parse_cargo_manifest(path: &Path) -> Result<Manifest> {
45    let m = cargo_toml::Manifest::from_path(path)?;
46    let package = m.package.context("Not a package (only a workspace)")?;
47    let description = package.description().map(|v| v.into());
48
49    Ok(Manifest {
50        manifest_type: ManifestType::Cargo,
51        number_of_dependencies: m.dependencies.len(),
52        name: package.name.clone(),
53        description,
54        version: package.version().into(),
55        license: package.license().map(|x| x.into()),
56    })
57}
58
59fn parse_npm_manifest(path: &Path) -> Result<Manifest> {
60    let package = npm_package_json::Package::from_path(path)?;
61    Ok(Manifest {
62        manifest_type: ManifestType::Npm,
63        number_of_dependencies: package.dependencies.len(),
64        name: package.name,
65        description: package.description,
66        version: package.version,
67        license: package.license,
68    })
69}
70
71fn file_name_to_manifest_type(filename: &str) -> Option<ManifestType> {
72    match filename {
73        "Cargo.toml" => Some(ManifestType::Cargo),
74        "package.json" => Some(ManifestType::Npm),
75        _ => None,
76    }
77}