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/CHANGELOG.md b/CHANGELOG.md
index 06f7caa..58190a8 100644
--- a/CHANGELOG.md
+++ b/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/README.md b/README.md
index 3f9558f..b359754 100644
--- a/README.md
+++ b/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/lib/src/version_range.dart b/lib/src/version_range.dart
index 7a18edf..5c53834 100644
--- a/lib/src/version_range.dart
+++ b/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/test/version_range_test.dart b/test/version_range_test.dart
index ef35d80..6df6b31 100644
--- a/test/version_range_test.dart
+++ b/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'));