Skip to content

Commit

Permalink
fix: semver intersection with prereleases
Browse files Browse the repository at this point in the history
  • Loading branch information
elbywan committed Feb 7, 2024
1 parent c633c12 commit 68e4412
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/utils/semver/comparator.cr
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ struct Zap::Utils::Semver::Comparator
end

def limits : {Limit, Limit}
max_limit = version.prerelease? ? Limit.exclusive(version.increment(:patch).copy_with(prerelease: Prerelease.new(""))) : Limit::MAX
min_limit = version.prerelease? ? Limit.inclusive(version.copy_with(prerelease: Prerelease.new(""))) : Limit::MIN
max_limit = Limit::MAX
min_limit = Limit::MIN

case @operator
in .greater_than?
Expand Down
9 changes: 1 addition & 8 deletions src/utils/semver/comparator_set.cr
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct Zap::Utils::Semver::ComparatorSet
# if at least one comparator with the same [major, minor, patch] tuple also has a prerelease tag.
# See: https://github.com/npm/node-semver?tab=readme-ov-file#prerelease-tags
allow_prerelease = version.prerelease && @comparators.any? { |c|
!!c.prerelease && version.major == c.major && version.minor == c.minor && version.patch == c.patch
!!c.prerelease && c.version.same_version_numbers?(version)
}
@comparators.all? do |comparator|
comparator.satisfies?(version, allow_prerelease)
Expand Down Expand Up @@ -87,13 +87,6 @@ struct Zap::Utils::Semver::ComparatorSet
# Return nil if one of the comparator sets is not a proper interval (lower limit > higher limit)
return nil if self_low.version > self_high.version || other_low.version > other_high.version

# If one version has a prerelease tag, then ranges only intersect if the other version has a prerelease tag
return nil if self_low.prerelease? != other_low.prerelease?
if self_low.prerelease
# If both versions have a prerelease tag, then ranges only intersect if the version numbers are the same
return nil if self_low.major != other_low.major || self_low.minor != other_low.minor || self_low.patch != other_low.patch
end

if self_low.version <= other_high.version && self_high.version >= other_low.version
# No overlap when the boundaries are exclusive
return nil if self_low.version == other_high.version && (self_low.boundary.exclusive? || other_high.boundary.exclusive?)
Expand Down
13 changes: 10 additions & 3 deletions src/utils/semver/fixtures/comparator_intersection.cr
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ COMPARATOR_INTERSECTION_FIXTURES = {
{">1.2.0-alpha.0", ">1.2.0-beta", ">1.2.0-beta"},
{">=1.2.0-alpha.0", "<1.2.0-beta", ">=1.2.0-alpha.0 <1.2.0-beta"},
{"<1.2.0-alpha", "<1.2.0-beta", "<1.2.0-alpha"},
{"<1.2.1-alpha", "<1.2.0-beta", ""},
{"<1.2.1-alpha", "<1.2.1", ""},
{"<1.2.1", "<1.2.1-beta", ""},
{"<1.2.1-alpha", "<1.2.0-beta", "<1.2.0-beta"},
{">1.2.1-alpha", ">1.2.0-beta", ">1.2.1-alpha"},
{"<1.2.1-alpha", "<1.2.1", "<1.2.1"},
{"<1.2.1", "<1.2.1-beta", "<1.2.1"},
{"<=1.2.1-alpha", "<=1.2.1", "<=1.2.1"},
{"<=1.2.1", "<=1.2.1-beta", "<=1.2.1"},
{">8.0.0-0", ">8.0.0", ">8.0.0"},
{">8.0.0", ">8.0.0-0", ">8.0.0"},
{">=8.0.0-0", ">=8.0.0", ">=8.0.0"},
{">=8.0.0", ">=8.0.0-0", ">=8.0.0"},
}
3 changes: 2 additions & 1 deletion src/utils/semver/fixtures/range_exclusion.cr
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,6 @@ RANGE_EXCLUSION_FIXTURES = [

{">=1.0.0 <1.1.0", "1.1.0"},
{">=1.0.0 <1.1.0", "1.1.0-pre"},
{">=1.0.0 <1.1.0-pre", "1.1.0-pre"},
{">=1.0.0 <1.1.0", "1.1.0-pre"},
{"^1.0.0-0", "1.0.1-pre"},
]
8 changes: 8 additions & 0 deletions src/utils/semver/limit.cr
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,28 @@ struct Zap::Utils::Semver::Limit
end

def max(other : self, *, side : Symbol = :left)
same_numbers = version.same_version_numbers?(other.version)
if version == other.version
return self if boundary == other.boundary || (side == :left ? boundary.inclusive? : boundary.exclusive?)
return other
else
if same_numbers && self.version.prerelease? != other.version.prerelease?
return self.version.prerelease? ? other : self
end
return self if version >= other.version
return other
end
end

def min(other : self, *, side : Symbol = :left)
same_numbers = version.same_version_numbers?(other.version)
if version == other.version
return self if boundary == other.boundary || (side == :left ? boundary.exclusive? : boundary.inclusive?)
return other
else
if same_numbers && self.version.prerelease? != other.version.prerelease?
return self.version.prerelease? ? other : self
end
return self if version <= other.version
return other
end
Expand Down
4 changes: 4 additions & 0 deletions src/utils/semver/version.cr
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ record(Zap::Utils::Semver::Version,
end
end

def same_version_numbers?(other : self)
major == other.major && minor == other.minor && patch == other.patch
end

def <=>(other : self) : Int32
return -1 if major < other.major
return 1 if major > other.major
Expand Down

0 comments on commit 68e4412

Please sign in to comment.