Skip to main content

vulnera_advisor/
ecosystem.rs

1//! Shared ecosystem and package-name normalization helpers.
2
3/// Normalize ecosystem aliases to canonical names used internally.
4///
5/// Canonical values:
6/// - npm
7/// - pypi
8/// - maven
9/// - cargo
10/// - go
11/// - packagist
12/// - rubygems
13/// - nuget
14pub fn canonicalize_ecosystem(ecosystem: &str) -> Option<&'static str> {
15    match ecosystem.trim().to_ascii_lowercase().as_str() {
16        "npm" => Some("npm"),
17        "pypi" | "python" | "pip" => Some("pypi"),
18        "maven" | "java" => Some("maven"),
19        "cargo" | "rust" | "crates.io" => Some("cargo"),
20        "go" | "golang" => Some("go"),
21        "packagist" | "composer" | "php" => Some("packagist"),
22        "rubygems" | "ruby" | "gem" | "bundler" => Some("rubygems"),
23        "nuget" | "dotnet" | ".net" => Some("nuget"),
24        _ => None,
25    }
26}
27
28/// Normalize a package name for stable matching/indexing.
29pub fn normalize_package_name(ecosystem: &str, package_name: &str) -> String {
30    let package_name = package_name.trim();
31    if package_name.is_empty() {
32        return String::new();
33    }
34
35    match canonicalize_ecosystem(ecosystem) {
36        Some("go") => package_name.to_string(),
37        Some(_) => package_name.to_ascii_lowercase(),
38        None => package_name.to_string(),
39    }
40}
41
42/// Normalize ecosystem + package pair used in cache/index keys.
43pub fn normalize_package_key(ecosystem: &str, package_name: &str) -> (String, String) {
44    let eco = canonicalize_ecosystem(ecosystem)
45        .unwrap_or(ecosystem)
46        .to_ascii_lowercase();
47    let pkg = normalize_package_name(&eco, package_name);
48    (eco, pkg)
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn test_canonicalize_ecosystem_aliases() {
57        assert_eq!(canonicalize_ecosystem("PyPI"), Some("pypi"));
58        assert_eq!(canonicalize_ecosystem("crates.io"), Some("cargo"));
59        assert_eq!(canonicalize_ecosystem("composer"), Some("packagist"));
60        assert_eq!(canonicalize_ecosystem("gem"), Some("rubygems"));
61        assert_eq!(canonicalize_ecosystem("unknown"), None);
62    }
63
64    #[test]
65    fn test_normalize_package_name() {
66        assert_eq!(normalize_package_name("npm", " Lodash "), "lodash");
67        assert_eq!(normalize_package_name("pypi", "Requests"), "requests");
68        assert_eq!(
69            normalize_package_name("go", "golang.org/x/Mod"),
70            "golang.org/x/Mod"
71        );
72    }
73}