Make the VersionUnion class public.
This is the first of several pub_semver changes to support my solver
work.
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//2029263003 .
diff --git a/pkgs/pub_semver/CHANGELOG.md b/pkgs/pub_semver/CHANGELOG.md
index 78c85e7..dc169fb 100644
--- a/pkgs/pub_semver/CHANGELOG.md
+++ b/pkgs/pub_semver/CHANGELOG.md
@@ -1,3 +1,9 @@
+# 1.3.0
+
+* Make the `VersionUnion` class public. This was previously used internally to
+ implement `new VersionConstraint.unionOf()` and `VersionConstraint.union()`.
+ Now it's public so you can use it too.
+
# 1.2.4
* Fix all remaining strong mode warnings.
diff --git a/pkgs/pub_semver/lib/pub_semver.dart b/pkgs/pub_semver/lib/pub_semver.dart
index fd2320e..bfb7d8b 100644
--- a/pkgs/pub_semver/lib/pub_semver.dart
+++ b/pkgs/pub_semver/lib/pub_semver.dart
@@ -5,3 +5,4 @@
export 'src/version.dart';
export 'src/version_constraint.dart';
export 'src/version_range.dart';
+export 'src/version_union.dart';
diff --git a/pkgs/pub_semver/lib/src/version_constraint.dart b/pkgs/pub_semver/lib/src/version_constraint.dart
index f222b51..9f55da0 100644
--- a/pkgs/pub_semver/lib/src/version_constraint.dart
+++ b/pkgs/pub_semver/lib/src/version_constraint.dart
@@ -6,6 +6,7 @@
import 'version.dart';
import 'version_range.dart';
import 'version_union.dart';
+import 'utils.dart';
/// A [VersionConstraint] is a predicate that can determine whether a given
/// version is valid or not.
@@ -172,8 +173,44 @@
/// It allows any versions that any of those constraints allows. If
/// [constraints] is empty, this returns a constraint that allows no versions.
factory VersionConstraint.unionOf(
- Iterable<VersionConstraint> constraints) =>
- VersionUnion.create(constraints);
+ Iterable<VersionConstraint> constraints) {
+ var flattened = constraints.expand((constraint) {
+ if (constraint.isEmpty) return [];
+ if (constraint is VersionUnion) return constraint.ranges;
+ return [constraint];
+ }).toList();
+
+ if (flattened.isEmpty) return VersionConstraint.empty;
+
+ if (flattened.any((constraint) => constraint.isAny)) {
+ return VersionConstraint.any;
+ }
+
+ // Only allow Versions and VersionRanges here so we can more easily reason
+ // about everything in [flattened]. _EmptyVersions and VersionUnions are
+ // filtered out above.
+ for (var constraint in flattened) {
+ if (constraint is VersionRange) continue;
+ throw new ArgumentError('Unknown VersionConstraint type $constraint.');
+ }
+
+ flattened.sort(compareMax);
+
+ var merged = <VersionRange>[];
+ for (var constraint in flattened) {
+ // Merge this constraint with the previous one, but only if they touch.
+ if (merged.isEmpty ||
+ (!merged.last.allowsAny(constraint) &&
+ !areAdjacent(merged.last, constraint))) {
+ merged.add(constraint);
+ } else {
+ merged[merged.length - 1] = merged.last.union(constraint);
+ }
+ }
+
+ if (merged.length == 1) return merged.single;
+ return new VersionUnion.fromRanges(merged);
+ }
/// Returns `true` if this constraint allows no versions.
bool get isEmpty;
diff --git a/pkgs/pub_semver/lib/src/version_range.dart b/pkgs/pub_semver/lib/src/version_range.dart
index 668b9b2..145151f 100644
--- a/pkgs/pub_semver/lib/src/version_range.dart
+++ b/pkgs/pub_semver/lib/src/version_range.dart
@@ -124,7 +124,7 @@
if (other is Version) return allows(other);
if (other is VersionUnion) {
- return other.constraints.every((constraint) => allowsAll(constraint));
+ return other.ranges.every((constraint) => allowsAll(constraint));
}
if (other is VersionRange) {
@@ -151,7 +151,7 @@
if (other is Version) return allows(other);
if (other is VersionUnion) {
- return other.constraints.any((constraint) => allowsAny(constraint));
+ return other.ranges.any((constraint) => allowsAny(constraint));
}
if (other is VersionRange) {
diff --git a/pkgs/pub_semver/lib/src/version_union.dart b/pkgs/pub_semver/lib/src/version_union.dart
index 5d52564..dbdadcf 100644
--- a/pkgs/pub_semver/lib/src/version_union.dart
+++ b/pkgs/pub_semver/lib/src/version_union.dart
@@ -9,8 +9,8 @@
import 'version_constraint.dart';
import 'version_range.dart';
-/// A (package-private) version constraint representing a union of multiple
-/// disjoint version constraints.
+/// A version constraint representing a union of multiple disjoint version
+/// ranges.
///
/// An instance of this will only be created if the version can't be represented
/// as a non-compound value.
@@ -23,101 +23,63 @@
/// * Its contents are disjoint and non-adjacent. In other words, for any two
/// constraints next to each other in the list, there's some version between
/// those constraints that they don't match.
- final List<VersionRange> constraints;
+ final List<VersionRange> ranges;
bool get isEmpty => false;
bool get isAny => false;
- /// Returns the union of [constraints].
+ /// Creates a union from a list of ranges with no pre-processing.
///
- /// This ensures that an actual [VersionUnion] is only returned if necessary.
- /// It also takes care of sorting and merging the constraints to ensure that
- /// they're disjoint.
- static VersionConstraint create(Iterable<VersionConstraint> constraints) {
- var flattened = constraints.expand((constraint) {
- if (constraint.isEmpty) return [];
- if (constraint is VersionUnion) return constraint.constraints;
- return [constraint];
- }).toList();
-
- if (flattened.isEmpty) return VersionConstraint.empty;
-
- if (flattened.any((constraint) => constraint.isAny)) {
- return VersionConstraint.any;
- }
-
- // Only allow Versions and VersionRanges here so we can more easily reason
- // about everything in [flattened]. _EmptyVersions and VersionUnions are
- // filtered out above.
- for (var constraint in flattened) {
- if (constraint is VersionRange) continue;
- throw new ArgumentError('Unknown VersionConstraint type $constraint.');
- }
-
- flattened.sort(compareMax);
-
- var merged = <VersionRange>[];
- for (var constraint in flattened) {
- // Merge this constraint with the previous one, but only if they touch.
- if (merged.isEmpty ||
- (!merged.last.allowsAny(constraint) &&
- !areAdjacent(merged.last, constraint))) {
- merged.add(constraint);
- } else {
- merged[merged.length - 1] = merged.last.union(constraint);
- }
- }
-
- if (merged.length == 1) return merged.single;
- return new VersionUnion._(merged);
- }
-
- VersionUnion._(this.constraints);
+ /// It's up to the caller to ensure that the invariants described in [ranges]
+ /// are maintained. They are not verified by this constructor. To
+ /// automatically ensure that they're maintained, use [new
+ /// VersionConstraint.unionOf] instead.
+ VersionUnion.fromRanges(this.ranges);
bool allows(Version version) =>
- constraints.any((constraint) => constraint.allows(version));
+ ranges.any((constraint) => constraint.allows(version));
bool allowsAll(VersionConstraint other) {
- var ourConstraints = constraints.iterator;
- var theirConstraints = _constraintsFor(other).iterator;
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
- // Because both lists of constraints are ordered by minimum version, we can
+ // Because both lists of ranges are ordered by minimum version, we can
// safely move through them linearly here.
- ourConstraints.moveNext();
- theirConstraints.moveNext();
- while (ourConstraints.current != null && theirConstraints.current != null) {
- if (ourConstraints.current.allowsAll(theirConstraints.current)) {
- theirConstraints.moveNext();
+ ourRanges.moveNext();
+ theirRanges.moveNext();
+ while (ourRanges.current != null && theirRanges.current != null) {
+ if (ourRanges.current.allowsAll(theirRanges.current)) {
+ theirRanges.moveNext();
} else {
- ourConstraints.moveNext();
+ ourRanges.moveNext();
}
}
- // If our constraints have allowed all of their constraints, we'll have
- // consumed all of them.
- return theirConstraints.current == null;
+ // If our ranges have allowed all of their ranges, we'll have consumed all
+ // of them.
+ return theirRanges.current == null;
}
bool allowsAny(VersionConstraint other) {
- var ourConstraints = constraints.iterator;
- var theirConstraints = _constraintsFor(other).iterator;
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
- // Because both lists of constraints are ordered by minimum version, we can
+ // Because both lists of ranges are ordered by minimum version, we can
// safely move through them linearly here.
- ourConstraints.moveNext();
- theirConstraints.moveNext();
- while (ourConstraints.current != null && theirConstraints.current != null) {
- if (ourConstraints.current.allowsAny(theirConstraints.current)) {
+ ourRanges.moveNext();
+ theirRanges.moveNext();
+ while (ourRanges.current != null && theirRanges.current != null) {
+ if (ourRanges.current.allowsAny(theirRanges.current)) {
return true;
}
// Move the constraint with the higher max value forward. This ensures
// that we keep both lists in sync as much as possible.
- if (compareMax(ourConstraints.current, theirConstraints.current) < 0) {
- ourConstraints.moveNext();
+ if (compareMax(ourRanges.current, theirRanges.current) < 0) {
+ ourRanges.moveNext();
} else {
- theirConstraints.moveNext();
+ theirRanges.moveNext();
}
}
@@ -125,43 +87,42 @@
}
VersionConstraint intersect(VersionConstraint other) {
- var ourConstraints = constraints.iterator;
- var theirConstraints = _constraintsFor(other).iterator;
+ var ourRanges = ranges.iterator;
+ var theirRanges = _rangesFor(other).iterator;
- // Because both lists of constraints are ordered by minimum version, we can
+ // Because both lists of ranges are ordered by minimum version, we can
// safely move through them linearly here.
- var newConstraints = <VersionRange>[];
- ourConstraints.moveNext();
- theirConstraints.moveNext();
- while (ourConstraints.current != null && theirConstraints.current != null) {
- var intersection = ourConstraints.current
- .intersect(theirConstraints.current);
+ var newRanges = <VersionRange>[];
+ ourRanges.moveNext();
+ theirRanges.moveNext();
+ while (ourRanges.current != null && theirRanges.current != null) {
+ var intersection = ourRanges.current
+ .intersect(theirRanges.current);
- if (!intersection.isEmpty) newConstraints.add(intersection);
+ if (!intersection.isEmpty) newRanges.add(intersection);
// Move the constraint with the higher max value forward. This ensures
// that we keep both lists in sync as much as possible, and that large
- // constraints have a chance to match multiple small constraints that they
- // contain.
- if (compareMax(ourConstraints.current, theirConstraints.current) < 0) {
- ourConstraints.moveNext();
+ // ranges have a chance to match multiple small ranges that they contain.
+ if (compareMax(ourRanges.current, theirRanges.current) < 0) {
+ ourRanges.moveNext();
} else {
- theirConstraints.moveNext();
+ theirRanges.moveNext();
}
}
- if (newConstraints.isEmpty) return VersionConstraint.empty;
- if (newConstraints.length == 1) return newConstraints.single;
+ if (newRanges.isEmpty) return VersionConstraint.empty;
+ if (newRanges.length == 1) return newRanges.single;
- return new VersionUnion._(newConstraints);
+ return new VersionUnion.fromRanges(newRanges);
}
- /// Returns [constraint] as a list of constraints.
+ /// Returns [constraint] as a list of ranges.
///
- /// This is used to normalize constraints of various types.
- List<VersionRange> _constraintsFor(VersionConstraint constraint) {
+ /// This is used to normalize ranges of various types.
+ List<VersionRange> _rangesFor(VersionConstraint constraint) {
if (constraint.isEmpty) return [];
- if (constraint is VersionUnion) return constraint.constraints;
+ if (constraint is VersionUnion) return constraint.ranges;
if (constraint is VersionRange) return [constraint];
throw new ArgumentError('Unknown VersionConstraint type $constraint.');
}
@@ -171,10 +132,10 @@
bool operator ==(other) {
if (other is! VersionUnion) return false;
- return const ListEquality().equals(constraints, other.constraints);
+ return const ListEquality().equals(ranges, other.ranges);
}
- int get hashCode => const ListEquality().hash(constraints);
+ int get hashCode => const ListEquality().hash(ranges);
- String toString() => constraints.join(" or ");
+ String toString() => ranges.join(" or ");
}
diff --git a/pkgs/pub_semver/pubspec.yaml b/pkgs/pub_semver/pubspec.yaml
index a026e25..53ef4d3 100644
--- a/pkgs/pub_semver/pubspec.yaml
+++ b/pkgs/pub_semver/pubspec.yaml
@@ -1,5 +1,5 @@
name: pub_semver
-version: 1.2.4
+version: 1.3.0-dev
author: Dart Team <misc@dartlang.org>
description: >
Versions and version constraints implementing pub's versioning policy. This