Skip to content

Commit 08563b8

Browse files
committed
fix: 💫 add multiple version requirement parsing
1 parent 6259188 commit 08563b8

File tree

2 files changed

+128
-229
lines changed

2 files changed

+128
-229
lines changed

src/domain/semver/mod.rs

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -61,30 +61,7 @@ impl fmt::Display for Version {
6161

6262
impl PartialOrd for Version {
6363
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
64-
if Self::error_if_comparator_operator_not_supported(&self.req).is_err() {
65-
return None;
66-
}
67-
// Wildcard and multiple version requirements not yet implemented - `new()` should not yet
68-
// let them be created
69-
debug_assert!(self.req.comparators.len() == 1 && other.req.comparators.len() == 1);
70-
71-
let range = self.range();
72-
let other_range = other.range();
73-
if range == other_range {
74-
Some(Ordering::Equal)
75-
} else if range.end <= other_range.start
76-
|| (range.start < other_range.start && range.end == other_range.end)
77-
|| (range.start == other_range.start && range.end < other_range.end)
78-
{
79-
Some(Ordering::Less)
80-
} else if range.start >= other_range.end
81-
|| (range.start > other_range.start && range.end == other_range.end)
82-
|| (range.start == other_range.start && range.end > other_range.end)
83-
{
84-
Some(Ordering::Greater)
85-
} else {
86-
None
87-
}
64+
Version::range_compare(&self.comparator_ranges(), &other.comparator_ranges())
8865
}
8966
}
9067

@@ -100,11 +77,29 @@ impl Version {
10077
pub fn new(version_number: &str) -> Result<Self, String> {
10178
let req = VersionReq::parse(version_number).map_err(|error| format!("{error}"))?;
10279

103-
let () = Self::error_if_comparator_operator_not_supported(&req)?;
80+
// let () = Self::error_if_comparator_operator_not_supported(&req)?;
10481

10582
Ok(Self { req })
10683
}
10784

85+
fn range_compare(a: &Range<semver::Version>, b: &Range<semver::Version>) -> Option<Ordering> {
86+
if a == b {
87+
Some(Ordering::Equal)
88+
} else if a.end <= b.start
89+
|| (a.start < b.start && a.end == b.end)
90+
|| (a.start == b.start && a.end < b.end)
91+
{
92+
Some(Ordering::Less)
93+
} else if a.start >= b.end
94+
|| (a.start > b.start && a.end == b.end)
95+
|| (a.start == b.start && a.end > b.end)
96+
{
97+
Some(Ordering::Greater)
98+
} else {
99+
None
100+
}
101+
}
102+
108103
fn version_with_bumped_major(major: u64) -> semver::Version {
109104
semver::Version {
110105
major: major
@@ -311,7 +306,7 @@ impl Version {
311306
// <I.J.K
312307
Range {
313308
start,
314-
end: Self::version_with_bumped_patch(major, minor_version, patch_version),
309+
end: semver::Version::new(major, minor_version, patch_version),
315310
}
316311
} else {
317312
// <I.J
@@ -404,30 +399,60 @@ impl Version {
404399
}
405400
}
406401

407-
fn range(&self) -> Range<semver::Version> {
408-
let first_comparator = self.req.comparators.first().unwrap();
402+
/// Returns a vector containing the ranges for each comparator. Collapses all ranges into a
403+
/// single one if possible. If collapsing to a single range is not possible, no attempt is
404+
/// made to collapse any pairs of elements, which could feasibly be collapsed. Result is
405+
/// sorted by increasing range starts.
406+
fn comparator_ranges(&self) -> Range<semver::Version> {
407+
debug_assert!(!self.req.comparators.is_empty());
408+
409+
let mut start = semver::Version::new(0, 0, 0);
410+
let mut end = semver::Version::new(u64::MAX, u64::MAX, u64::MAX);
411+
for comparator in &self.req.comparators {
412+
let Comparator {
413+
op,
414+
major,
415+
minor,
416+
patch,
417+
..
418+
} = comparator;
419+
let range = match op {
420+
Op::Exact => Self::exact_range(*major, *minor, *patch),
421+
Op::Greater => Self::greater_range(*major, *minor, *patch),
422+
Op::GreaterEq => Self::greater_or_equal_range(*major, *minor, *patch),
423+
Op::Less => Self::less_range(*major, *minor, *patch),
424+
Op::LessEq => Self::less_or_equal_range(*major, *minor, *patch),
425+
Op::Tilde => Self::tilde_range(*major, *minor, *patch),
426+
Op::Caret => Self::caret_range(*major, *minor, *patch),
427+
Op::Wildcard => Self::wildcard_range(*major, *minor, *patch),
428+
_ => unimplemented!(),
429+
};
430+
431+
match op {
432+
Op::Exact | Op::Tilde | Op::Caret | Op::Wildcard | Op::Greater | Op::GreaterEq => {
433+
if range.start > start {
434+
start = range.start;
435+
}
436+
}
437+
_ => {}
438+
}
439+
match op {
440+
Op::Exact | Op::Tilde | Op::Caret | Op::Wildcard | Op::Less | Op::LessEq => {
441+
if range.end < end {
442+
end = range.end;
443+
}
444+
}
445+
_ => {}
446+
}
447+
}
409448

410-
let Comparator {
411-
op,
412-
major,
413-
minor,
414-
patch,
415-
..
416-
} = first_comparator;
417-
match op {
418-
Op::Caret => Self::caret_range(*major, *minor, *patch),
419-
Op::Exact => Self::exact_range(*major, *minor, *patch),
420-
Op::Greater => Self::greater_range(*major, *minor, *patch),
421-
Op::GreaterEq => Self::greater_or_equal_range(*major, *minor, *patch),
422-
Op::Less => Self::less_range(*major, *minor, *patch),
423-
Op::LessEq => Self::less_or_equal_range(*major, *minor, *patch),
424-
Op::Tilde => Self::tilde_range(*major, *minor, *patch),
425-
Op::Wildcard => Self::wildcard_range(*major, *minor, *patch),
426-
_ => unimplemented!(
427-
"Ranges only implemented for caret, exact, greater than, greater than or equal, \
428-
less than, less than or equal, tilde and wildcard requirements."
429-
),
449+
if end < start {
450+
log::error!(
451+
"Unexpected invalid range requirement: {:?}",
452+
self.req.comparators,
453+
);
430454
}
455+
Range { start, end }
431456
}
432457

433458
pub fn change_type(&self, other: &Self) -> Change {
@@ -476,28 +501,6 @@ impl Version {
476501
Change::Unknown
477502
}
478503

479-
fn error_if_comparator_operator_not_supported(req: &VersionReq) -> Result<(), String> {
480-
if req.comparators.len() != 1 {
481-
return Err(String::from(
482-
"Multiple version requirement comparison is not yet implemented",
483-
));
484-
}
485-
let Comparator { op, .. } = req.comparators.first().expect("Index should be valid");
486-
match op {
487-
Op::Caret
488-
| Op::Exact
489-
| Op::Greater
490-
| Op::GreaterEq
491-
| Op::Less
492-
| Op::LessEq
493-
| Op::Tilde
494-
| Op::Wildcard => Ok(()),
495-
_ => Err(String::from(
496-
"Unexpected version requirement. Requirement type is not yet implemented",
497-
)),
498-
}
499-
}
500-
501504
fn fmt_comparator_version(
502505
comparator: &Comparator,
503506
formatter: &mut fmt::Formatter,

0 commit comments

Comments
 (0)