Skip to main content

provenant/parsers/maven/
mod.rs

1// SPDX-FileCopyrightText: Provenant contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Parser for Apache Maven pom.xml files.
5//!
6//! Extracts package metadata, dependencies, and license information from
7//! Maven Project Object Model (POM) files.
8//!
9//! # Supported Formats
10//! - pom.xml (Project Object Model)
11//! - pom.properties
12//! - MANIFEST.MF (JAR manifest)
13//!
14//! # Key Features
15//! - Property value substitution (`${project.version}`)
16//! - `is_pinned` analysis (exact version vs ranges like `[1.0,2.0)`)
17//! - Dependency scope handling (compile, test, provided, runtime, system)
18//! - Package URL (purl) generation
19//! - Multiple license support (combined with " OR ")
20
21mod coordinates;
22mod manifest;
23mod pom;
24mod properties;
25
26#[cfg(test)]
27mod manifest_test;
28#[cfg(test)]
29mod pom_test;
30#[cfg(test)]
31mod properties_test;
32#[cfg(test)]
33mod scan_test;
34
35use self::{manifest::parse_manifest_mf, pom::parse_pom_xml, properties::parse_pom_properties};
36use super::PackageParser;
37use crate::models::{DatasourceId, PackageData, PackageType};
38use std::path::Path;
39
40/// Maven package parser supporting pom.xml, pom.properties, and MANIFEST.MF files.
41pub struct MavenParser;
42
43impl PackageParser for MavenParser {
44    const PACKAGE_TYPE: PackageType = PackageType::Maven;
45
46    fn extract_packages(path: &Path) -> Vec<PackageData> {
47        if let Some(filename) = path.file_name().and_then(|name| name.to_str()) {
48            if filename == "pom.properties" {
49                return vec![parse_pom_properties(path)];
50            }
51            if filename == "MANIFEST.MF" {
52                return vec![parse_manifest_mf(path)];
53            }
54        }
55
56        parse_pom_xml(path)
57    }
58
59    fn is_match(path: &Path) -> bool {
60        if let Some(filename) = path.file_name().and_then(|name| name.to_str()) {
61            filename == "pom.xml"
62                || filename.ends_with(".pom.xml")
63                || filename.ends_with("-pom.xml")
64                || filename.ends_with("_pom.xml")
65                || filename == "pom.properties"
66                || filename == "MANIFEST.MF"
67                || filename.ends_with(".pom")
68        } else {
69            false
70        }
71    }
72}
73
74fn default_package_data(datasource_id: DatasourceId) -> PackageData {
75    PackageData {
76        package_type: Some(PackageType::Maven),
77        datasource_id: Some(datasource_id),
78        ..Default::default()
79    }
80}
81
82crate::register_parser!(
83    "Apache Maven POM",
84    &[
85        "**/*.pom",
86        "**/pom.xml",
87        "**/pom.properties",
88        "**/META-INF/MANIFEST.MF"
89    ],
90    "maven",
91    "Java",
92    Some("https://maven.apache.org/pom.html"),
93);