Change the pre-release range semantics. This allows ">=1.2.3-dev <1.2.3" to work how it looks like it should work, as opposed to matching no versions at all. R=rnystrom@google.com Review URL: https://codereview.chromium.org//1149543002
diff --git a/pkgs/pub_semver/CHANGELOG.md b/pkgs/pub_semver/CHANGELOG.md index 06f7caa..58190a8 100644 --- a/pkgs/pub_semver/CHANGELOG.md +++ b/pkgs/pub_semver/CHANGELOG.md
@@ -1,3 +1,11 @@ +# 1.2.1 + +* Allow version ranges like `>=1.2.3-dev.1 <1.2.3` to match pre-release versions + of `1.2.3`. Previously, these didn't match, since the pre-release versions had + the same major, minor, and patch numbers as the max; now an exception has been + added if they also have the same major, minor, and patch numbers as the min + *and* the min is also a pre-release version. + # 1.2.0 * Add a `VersionConstraint.union()` method and a `new
diff --git a/pkgs/pub_semver/README.md b/pkgs/pub_semver/README.md index 3f9558f..b359754 100644 --- a/pkgs/pub_semver/README.md +++ b/pkgs/pub_semver/README.md
@@ -33,10 +33,12 @@ unstable versions of `2.0.0`'s API, which is what pre-release versions represent. - To handle that, `<` version ranges to not allow pre-release versions of the - maximum unless the max is itself a pre-release. In other words, a `<2.0.0` - constraint will prohibit not just `2.0.0` but any pre-release of `2.0.0`. - However, `<2.0.0-beta` will exclude `2.0.0-beta` but allow `2.0.0-alpha`. + To handle that, `<` version ranges don't allow pre-release versions of the + maximum unless the max is itself a pre-release, or the min is a pre-release + of the same version. In other words, a `<2.0.0` constraint will prohibit not + just `2.0.0` but any pre-release of `2.0.0`. However, `<2.0.0-beta` will + exclude `2.0.0-beta` but allow `2.0.0-alpha`. Likewise, `>2.0.0-alpha + <2.0.0` will exclude `2.0.0-alpha` but allow `2.0.0-beta`. * **Pre-release versions are avoided when possible.** The above case handles pre-release versions at the top of the range, but what about in
diff --git a/pkgs/pub_semver/lib/src/version_range.dart b/pkgs/pub_semver/lib/src/version_range.dart index 7a18edf..5c53834 100644 --- a/pkgs/pub_semver/lib/src/version_range.dart +++ b/pkgs/pub_semver/lib/src/version_range.dart
@@ -85,21 +85,42 @@ if (other > max) return false; if (!includeMax && other == max) return false; - // If the max isn't itself a pre-release, don't allow any pre-release - // versions of the max. + + // Disallow pre-release versions that have the same major, minor, and + // patch version as the max, but only if neither the max nor the min is a + // pre-release of that version. This ensures that "^1.2.3" doesn't include + // "2.0.0-pre", while also allowing both ">=2.0.0-pre.2 <2.0.0" and + // ">=1.2.3 <2.0.0-pre.7" to match "2.0.0-pre.5". // - // See: https://www.npmjs.org/doc/misc/semver.html - if (!includeMax && + // It's worth noting that this is different than [NPM's semantics][]. NPM + // disallows **all** pre-release versions unless their major, minor, and + // patch numbers match those of a prerelease min or max. This ensures that + // no prerelease versions will ever be selected if the user doesn't + // explicitly allow them. + // + // [NPM's semantics]: https://www.npmjs.org/doc/misc/semver.html#prerelease-tags + // + // Instead, we ensure that release versions will always be preferred over + // prerelease versions by ordering the release versions first in + // [Version.prioritize]. This means that constraints like "any" or + // ">1.2.3" can still match prerelease versions if they're the only things + // available. + var maxIsReleaseOfOther = !includeMax && !max.isPreRelease && other.isPreRelease && - other.major == max.major && other.minor == max.minor && - other.patch == max.patch) { - return false; - } + _equalsWithoutPreRelease(other, max); + var minIsPreReleaseOfOther = min != null && min.isPreRelease && + _equalsWithoutPreRelease(other, min); + if (maxIsReleaseOfOther && !minIsPreReleaseOfOther) return false; } return true; } + bool _equalsWithoutPreRelease(Version version1, Version version2) => + version1.major == version2.major && + version1.minor == version2.minor && + version1.patch == version2.patch; + bool allowsAll(VersionConstraint other) { if (other.isEmpty) return true; if (other is Version) return allows(other);
diff --git a/pkgs/pub_semver/test/version_range_test.dart b/pkgs/pub_semver/test/version_range_test.dart index ef35d80..6df6b31 100644 --- a/pkgs/pub_semver/test/version_range_test.dart +++ b/pkgs/pub_semver/test/version_range_test.dart
@@ -105,6 +105,18 @@ new Version.parse('2.3.4'))); }); + test('pre-release versions of non-pre-release max are included if min is a ' + 'pre-release of the same version', () { + var range = new VersionRange( + min: new Version.parse('2.3.4-dev.0'), max: v234); + + expect(range, allows(new Version.parse('2.3.4-dev.1'))); + expect(range, doesNotAllow( + new Version.parse('2.3.3'), + new Version.parse('2.3.4-dev'), + new Version.parse('2.3.4'))); + }); + test('pre-release versions of pre-release max are included', () { var range = new VersionRange(max: new Version.parse('2.3.4-dev.2'));