Support wildcards to fix remaining tests
This commit is contained in:
parent
d610e9954f
commit
5d9ce0d93a
163
src/lib.rs
163
src/lib.rs
|
@ -4,21 +4,25 @@
|
||||||
Lenient parser or Semantic Version ranges.
|
Lenient parser or Semantic Version ranges.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use lenient_semver_parser::{parse_partial, VersionBuilder};
|
use lenient_semver_parser::{parse_partial, ErrorKind, VersionBuilder};
|
||||||
use lenient_version::Version;
|
use lenient_version::Version;
|
||||||
|
|
||||||
pub fn parse<'a>(input: &'a str) -> Result<RangeSet<'a>, Box<dyn std::error::Error + 'a>> {
|
pub fn parse<'a>(input: &'a str) -> Result<RangeSet<'a>, Box<dyn std::error::Error + 'a>> {
|
||||||
parse_compat(input, Compat::Npm)
|
parse_compat(input, Compat::Npm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_cargp<'a>(input: &'a str) -> Result<RangeSet<'a>, Box<dyn std::error::Error + 'a>> {
|
||||||
|
parse_compat(input, Compat::Cargo)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_npm<'a>(input: &'a str) -> Result<RangeSet<'a>, Box<dyn std::error::Error + 'a>> {
|
pub fn parse_npm<'a>(input: &'a str) -> Result<RangeSet<'a>, Box<dyn std::error::Error + 'a>> {
|
||||||
parse_compat(input, Compat::Npm)
|
parse_compat(input, Compat::Npm)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_compat<'a>(
|
pub fn parse_compat<'input>(
|
||||||
mut input: &'a str,
|
mut input: &'input str,
|
||||||
compat: Compat,
|
compat: Compat,
|
||||||
) -> Result<RangeSet<'a>, Box<dyn std::error::Error + 'a>> {
|
) -> Result<RangeSet<'input>, Box<dyn std::error::Error + 'input>> {
|
||||||
let mut ranges = vec![];
|
let mut ranges = vec![];
|
||||||
let mut operations: Vec<Operation> = vec![];
|
let mut operations: Vec<Operation> = vec![];
|
||||||
let mut allow_chain_operators = false;
|
let mut allow_chain_operators = false;
|
||||||
|
@ -57,7 +61,7 @@ pub fn parse_compat<'a>(
|
||||||
_ => (Op::Nothing, input),
|
_ => (Op::Nothing, input),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (version, remainder) = parse_partial::<VersionQualifier<'a>>(next_input)?;
|
let (version, remainder) = parse_next_version(next_input)?;
|
||||||
let op = match op {
|
let op = match op {
|
||||||
Op::Nothing => Operation::Default(version),
|
Op::Nothing => Operation::Default(version),
|
||||||
Op::Eq => Operation::Apply(Operator::Eq, version),
|
Op::Eq => Operation::Apply(Operator::Eq, version),
|
||||||
|
@ -111,6 +115,24 @@ pub fn parse_compat<'a>(
|
||||||
Ok(RangeSet { ranges })
|
Ok(RangeSet { ranges })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn parse_next_version<'input>(
|
||||||
|
input: &'input str,
|
||||||
|
) -> Result<(VersionQualifier<'input>, &'input str), lenient_semver_parser::Error<'input>> {
|
||||||
|
match parse_partial::<VersionQualifier<'input>>(input) {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(err) => {
|
||||||
|
if err.error_kind() == ErrorKind::UnexpectedInput {
|
||||||
|
if matches!(err.erroneous_input(), "x" | "X" | "*" | "?") {
|
||||||
|
let span = err.error_span();
|
||||||
|
return Ok((VersionQualifier::empty(), &input[span.end..]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct RangeSet<'input> {
|
pub struct RangeSet<'input> {
|
||||||
ranges: Vec<Range<'input>>,
|
ranges: Vec<Range<'input>>,
|
||||||
|
@ -165,6 +187,16 @@ enum Operator {
|
||||||
Lte,
|
Lte,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Operator {
|
||||||
|
fn or_if_eq(self, other: Self) -> Self {
|
||||||
|
if self == Self::Eq {
|
||||||
|
other
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
enum Op {
|
enum Op {
|
||||||
Nothing,
|
Nothing,
|
||||||
|
@ -237,6 +269,22 @@ impl<'input> VersionQualifier<'input> {
|
||||||
build: Vec::new(),
|
build: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_version<F>(self, mut f: F) -> Version<'input>
|
||||||
|
where
|
||||||
|
F: for<'a> FnMut(&'a mut Version<'input>),
|
||||||
|
{
|
||||||
|
let mut version = Version {
|
||||||
|
major: self.major.into(),
|
||||||
|
minor: self.minor.into(),
|
||||||
|
patch: self.patch.into(),
|
||||||
|
additional: self.additional.into_iter().map(u64::from).collect(),
|
||||||
|
pre: self.pre,
|
||||||
|
build: self.build,
|
||||||
|
};
|
||||||
|
f(&mut version);
|
||||||
|
version
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'input> VersionBuilder<'input> for VersionQualifier<'input> {
|
impl<'input> VersionBuilder<'input> for VersionQualifier<'input> {
|
||||||
|
@ -301,20 +349,50 @@ impl<'input> Operation<'input> {
|
||||||
Compat::Cargo => Operation::Caret(v).into_versions(compat),
|
Compat::Cargo => Operation::Caret(v).into_versions(compat),
|
||||||
Compat::Npm => Operation::Apply(Operator::Eq, v).into_versions(compat),
|
Compat::Npm => Operation::Apply(Operator::Eq, v).into_versions(compat),
|
||||||
},
|
},
|
||||||
Operation::Apply(op, v) => (
|
Operation::Apply(op, v) => match v.major {
|
||||||
Comparator {
|
VersionNumber::Wildcard | VersionNumber::Unspecified => (
|
||||||
op,
|
Comparator {
|
||||||
version: Version {
|
op: op.or_if_eq(Operator::Gte),
|
||||||
major: v.major.into(),
|
version: v.to_version(|v| v.set_major(0)),
|
||||||
minor: v.minor.into(),
|
},
|
||||||
patch: v.patch.into(),
|
None,
|
||||||
additional: v.additional.into_iter().map(u64::from).collect(),
|
),
|
||||||
pre: v.pre,
|
VersionNumber::Num(major) => match v.minor {
|
||||||
build: v.build,
|
VersionNumber::Unspecified | VersionNumber::Wildcard => {
|
||||||
|
let min = Comparator {
|
||||||
|
op: op.or_if_eq(Operator::Gte),
|
||||||
|
version: v.to_version(|v| v.set_minor(0)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let max = major
|
||||||
|
.checked_add(1)
|
||||||
|
.map(|m| Comparator::lt(Version::new(m, 0, 0)));
|
||||||
|
|
||||||
|
(min, max)
|
||||||
|
}
|
||||||
|
VersionNumber::Num(minor) => match v.patch {
|
||||||
|
VersionNumber::Unspecified | VersionNumber::Wildcard => {
|
||||||
|
let min = Comparator {
|
||||||
|
op: op.or_if_eq(Operator::Gte),
|
||||||
|
version: v.to_version(|v| v.set_patch(0)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let max = minor
|
||||||
|
.checked_add(1)
|
||||||
|
.map(|m| Comparator::lt(Version::new(major, m, 0)));
|
||||||
|
|
||||||
|
(min, max)
|
||||||
|
}
|
||||||
|
VersionNumber::Num(_) => (
|
||||||
|
Comparator {
|
||||||
|
op,
|
||||||
|
version: v.to_version(|_| ()),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
None,
|
},
|
||||||
),
|
|
||||||
Operation::Tilde(v) => match v.segment {
|
Operation::Tilde(v) => match v.segment {
|
||||||
Segment::Empty => (Comparator::gte(Version::new(0, 0, 0)), None),
|
Segment::Empty => (Comparator::gte(Version::new(0, 0, 0)), None),
|
||||||
Segment::Major => {
|
Segment::Major => {
|
||||||
|
@ -326,50 +404,17 @@ impl<'input> Operation<'input> {
|
||||||
.map(|m| Comparator::lt(Version::new(m, 0, 0))),
|
.map(|m| Comparator::lt(Version::new(m, 0, 0))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Segment::Minor => {
|
Segment::Minor | Segment::Patch | Segment::Additional => {
|
||||||
let major = u64::from(v.major);
|
let major = u64::from(v.major);
|
||||||
let minor = u64::from(v.minor);
|
let minor = u64::from(v.minor);
|
||||||
|
let version = v.to_version(|_| ());
|
||||||
(
|
(
|
||||||
Comparator::gte(Version::new(major, minor, 0)),
|
Comparator::gte(version),
|
||||||
minor
|
minor
|
||||||
.checked_add(1)
|
.checked_add(1)
|
||||||
.map(|m| Comparator::lt(Version::new(major, m, 0))),
|
.map(|m| Comparator::lt(Version::new(major, m, 0))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Segment::Patch => {
|
|
||||||
let major = u64::from(v.major);
|
|
||||||
let minor = u64::from(v.minor);
|
|
||||||
let patch = u64::from(v.patch);
|
|
||||||
(
|
|
||||||
Comparator::gte(Version::new(major, minor, patch)),
|
|
||||||
minor
|
|
||||||
.checked_add(1)
|
|
||||||
.map(|m| Comparator::lt(Version::new(major, minor, m))),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Segment::Additional => {
|
|
||||||
let major = u64::from(v.major);
|
|
||||||
let minor = u64::from(v.minor);
|
|
||||||
let patch = u64::from(v.patch);
|
|
||||||
|
|
||||||
let mut min = Version::new(major, minor, patch);
|
|
||||||
min.additional = v.additional.into_iter().map(u64::from).collect();
|
|
||||||
|
|
||||||
let max = min
|
|
||||||
.additional
|
|
||||||
.last()
|
|
||||||
.expect("empty additional")
|
|
||||||
.checked_add(1)
|
|
||||||
.map(|m| {
|
|
||||||
let mut add = min.additional.clone();
|
|
||||||
*add.last_mut().expect("empty additional") = m;
|
|
||||||
let mut max = Version::new(major, minor, patch);
|
|
||||||
max.additional = add;
|
|
||||||
Comparator::lt(max)
|
|
||||||
});
|
|
||||||
|
|
||||||
(Comparator::gte(min), max)
|
|
||||||
}
|
|
||||||
Segment::PreRelease => {
|
Segment::PreRelease => {
|
||||||
let min = Version {
|
let min = Version {
|
||||||
major: u64::from(v.major),
|
major: u64::from(v.major),
|
||||||
|
@ -611,17 +656,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_x_4() {
|
fn test_x_4() {
|
||||||
assert_eq!(
|
assert_eq!(parse("").unwrap(), RangeSet { ranges: vec![] });
|
||||||
parse("").unwrap(),
|
|
||||||
RangeSet {
|
|
||||||
ranges: vec![Range {
|
|
||||||
comparators: vec![Comparator {
|
|
||||||
op: Operator::Gte,
|
|
||||||
version: Version::new(0, 0, 0)
|
|
||||||
},]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue