Skip to content

Commit

Permalink
Add method for parsing namespaced names (#22)
Browse files Browse the repository at this point in the history
This adds the new `Purl::builder_with_combined_name` function that
allows parsing package names that include the namespace in their name.

The parsing is done according to its package type, which is why this
function is only implemented for `Purl` rather than `GenericPurl<T>`.
  • Loading branch information
cd-work authored Dec 17, 2024
1 parent d4a0282 commit b4abaee
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 9 deletions.
53 changes: 52 additions & 1 deletion purl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl PurlShape for String {
/// Without type-specific functionality, it's possible to create PURLs that have
/// incorrect capitalization or are missing a required namespace or required
/// qualifiers.
impl<'a> PurlShape for Cow<'a, str> {
impl PurlShape for Cow<'_, str> {
type Error = ParseError;

fn package_type(&self) -> Cow<str> {
Expand Down Expand Up @@ -321,6 +321,42 @@ impl<T> GenericPurl<T> {
}
}

#[cfg(feature = "package-type")]
impl Purl {
/// Create a new [`PurlBuilder`] with a combined name and namespace.
pub fn builder_with_combined_name<S>(
package_type: PackageType,
namespaced_name: S,
) -> PurlBuilder
where
S: AsRef<str>,
{
// Split apart namespace and name based on ecosystem.
let namespaced_name = namespaced_name.as_ref();
let (namespace, name) = match package_type {
PackageType::Cargo | PackageType::Gem | PackageType::NuGet | PackageType::PyPI => {
(None, namespaced_name)
},
PackageType::Golang | PackageType::Npm => match namespaced_name.rsplit_once('/') {
Some((namespace, name)) => (Some(namespace), name),
None => (None, namespaced_name),
},
PackageType::Maven => match namespaced_name.split_once(':') {
Some((namespace, name)) => (Some(namespace), name),
None => (None, namespaced_name),
},
};

// Create the PURL builder.
let mut builder = GenericPurlBuilder::new(package_type, name);
if let Some(namespace) = namespace {
builder = builder.with_namespace(namespace);
}

builder
}
}

/// Check whether a package type string is valid according to the rules of the
/// PURL spec.
#[must_use]
Expand Down Expand Up @@ -554,4 +590,19 @@ mod tests {
let purl = GenericPurl::new(Cow::Borrowed("type"), "name").unwrap();
assert_eq!(None, purl.subpath());
}

#[cfg(feature = "package-type")]
#[test]
fn namespaced_name() {
let purl =
Purl::builder_with_combined_name(PackageType::Npm, "@angular/cli").build().unwrap();
assert_eq!(purl.namespace(), Some("@angular"));
assert_eq!(purl.name(), "cli");

let purl = Purl::builder_with_combined_name(PackageType::Maven, "org.maven.plugins:pom")
.build()
.unwrap();
assert_eq!(purl.namespace(), Some("org.maven.plugins"));
assert_eq!(purl.name(), "pom");
}
}
2 changes: 1 addition & 1 deletion purl/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ mod de {

struct PurlVisitor<T>(PhantomData<T>);

impl<'de, T> Visitor<'de> for PurlVisitor<T>
impl<T> Visitor<'_> for PurlVisitor<T>
where
T: FromStr + PurlShape,
<T as PurlShape>::Error: fmt::Display + From<<T as FromStr>::Err>,
Expand Down
8 changes: 4 additions & 4 deletions purl/src/qualifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,9 @@ impl<'a> Iterator for Iter<'a> {
}
}

impl<'a> ExactSizeIterator for Iter<'a> {}
impl ExactSizeIterator for Iter<'_> {}

impl<'a> DoubleEndedIterator for Iter<'a> {
impl DoubleEndedIterator for Iter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let (k, v) = self.0.next_back()?;
Some((k, v.as_str()))
Expand Down Expand Up @@ -534,9 +534,9 @@ impl<'a> Iterator for IterMut<'a> {
}
}

impl<'a> ExactSizeIterator for IterMut<'a> {}
impl ExactSizeIterator for IterMut<'_> {}

impl<'a> DoubleEndedIterator for IterMut<'a> {
impl DoubleEndedIterator for IterMut<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let (k, v) = self.0.next_back()?;
Some((k, v))
Expand Down
6 changes: 3 additions & 3 deletions purl/src/qualifiers/well_known.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub struct Checksum<'a> {
algorithms: HashMap<SmallString, Cow<'a, str>>,
}

impl<'a> KnownQualifierKey for Checksum<'a> {
impl KnownQualifierKey for Checksum<'_> {
const KEY: &'static str = "checksum";
}

Expand Down Expand Up @@ -154,7 +154,7 @@ impl<'a> TryFrom<Checksum<'a>> for SmallString {
}
}

impl<'a> Checksum<'a> {
impl Checksum<'_> {
/// Get a reference to the hex bytes of a hash.
///
/// The hash may not be valid hex bytes.
Expand Down Expand Up @@ -258,7 +258,7 @@ impl<'a> ChecksumValue<'a> {
}
}

impl<'a> Deref for ChecksumValue<'a> {
impl Deref for ChecksumValue<'_> {
type Target = str;

fn deref(&self) -> &Self::Target {
Expand Down

0 comments on commit b4abaee

Please sign in to comment.