| Index: mojo/public/dart/third_party/pub_semver/lib/src/version_range.dart
|
| diff --git a/mojo/public/dart/third_party/pub_semver/lib/src/version_range.dart b/mojo/public/dart/third_party/pub_semver/lib/src/version_range.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5c53834c67267206a1184baf7853e489d72aaa94
|
| --- /dev/null
|
| +++ b/mojo/public/dart/third_party/pub_semver/lib/src/version_range.dart
|
| @@ -0,0 +1,337 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library pub_semver.src.version_range;
|
| +
|
| +import 'version.dart';
|
| +import 'version_constraint.dart';
|
| +import 'version_union.dart';
|
| +
|
| +/// Constrains versions to a fall within a given range.
|
| +///
|
| +/// If there is a minimum, then this only allows versions that are at that
|
| +/// minimum or greater. If there is a maximum, then only versions less than
|
| +/// that are allowed. In other words, this allows `>= min, < max`.
|
| +class VersionRange implements VersionConstraint {
|
| + /// The minimum end of the range.
|
| + ///
|
| + /// If [includeMin] is `true`, this will be the minimum allowed version.
|
| + /// Otherwise, it will be the highest version below the range that is not
|
| + /// allowed.
|
| + ///
|
| + /// This may be `null` in which case the range has no minimum end and allows
|
| + /// any version less than the maximum.
|
| + final Version min;
|
| +
|
| + /// The maximum end of the range.
|
| + ///
|
| + /// If [includeMax] is `true`, this will be the maximum allowed version.
|
| + /// Otherwise, it will be the lowest version above the range that is not
|
| + /// allowed.
|
| + ///
|
| + /// This may be `null` in which case the range has no maximum end and allows
|
| + /// any version greater than the minimum.
|
| + final Version max;
|
| +
|
| + /// If `true` then [min] is allowed by the range.
|
| + final bool includeMin;
|
| +
|
| + /// If `true`, then [max] is allowed by the range.
|
| + final bool includeMax;
|
| +
|
| + /// Creates a new version range from [min] to [max], either inclusive or
|
| + /// exclusive.
|
| + ///
|
| + /// If it is an error if [min] is greater than [max].
|
| + ///
|
| + /// Either [max] or [min] may be omitted to not clamp the range at that end.
|
| + /// If both are omitted, the range allows all versions.
|
| + ///
|
| + /// If [includeMin] is `true`, then the minimum end of the range is inclusive.
|
| + /// Likewise, passing [includeMax] as `true` makes the upper end inclusive.
|
| + VersionRange({this.min, this.max,
|
| + this.includeMin: false, this.includeMax: false}) {
|
| + if (min != null && max != null && min > max) {
|
| + throw new ArgumentError(
|
| + 'Minimum version ("$min") must be less than maximum ("$max").');
|
| + }
|
| + }
|
| +
|
| + bool operator ==(other) {
|
| + if (other is! VersionRange) return false;
|
| +
|
| + return min == other.min &&
|
| + max == other.max &&
|
| + includeMin == other.includeMin &&
|
| + includeMax == other.includeMax;
|
| + }
|
| +
|
| + int get hashCode => min.hashCode ^ (max.hashCode * 3) ^
|
| + (includeMin.hashCode * 5) ^ (includeMax.hashCode * 7);
|
| +
|
| + bool get isEmpty => false;
|
| +
|
| + bool get isAny => min == null && max == null;
|
| +
|
| + /// Tests if [other] falls within this version range.
|
| + bool allows(Version other) {
|
| + if (min != null) {
|
| + if (other < min) return false;
|
| + if (!includeMin && other == min) return false;
|
| + }
|
| +
|
| + if (max != null) {
|
| + if (other > max) return false;
|
| + if (!includeMax && other == max) return false;
|
| +
|
| +
|
| + // 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".
|
| + //
|
| + // 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 &&
|
| + _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);
|
| +
|
| + if (other is VersionUnion) {
|
| + return other.constraints.every((constraint) => allowsAll(constraint));
|
| + }
|
| +
|
| + if (other is VersionRange) {
|
| + if (min != null) {
|
| + if (other.min == null) return false;
|
| + if (min > other.min) return false;
|
| + if (min == other.min && !includeMin && other.includeMin) return false;
|
| + }
|
| +
|
| + if (max != null) {
|
| + if (other.max == null) return false;
|
| + if (max < other.max) return false;
|
| + if (max == other.max && !includeMax && other.includeMax) return false;
|
| + }
|
| +
|
| + return true;
|
| + }
|
| +
|
| + throw new ArgumentError('Unknown VersionConstraint type $other.');
|
| + }
|
| +
|
| + bool allowsAny(VersionConstraint other) {
|
| + if (other.isEmpty) return false;
|
| + if (other is Version) return allows(other);
|
| +
|
| + if (other is VersionUnion) {
|
| + return other.constraints.any((constraint) => allowsAny(constraint));
|
| + }
|
| +
|
| + if (other is VersionRange) {
|
| + // If neither range has a minimum, they'll overlap at some point.
|
| + //
|
| + // ... this ]
|
| + // ... other ]
|
| + if (min == null && other.min == null) return true;
|
| +
|
| + // If this range has a lower minimum than the other range, it overlaps as
|
| + // long as its maximum is higher than or the same as the other range's
|
| + // minimum.
|
| + //
|
| + // [ this ] [ this ]
|
| + // [ other ] [ other ]
|
| + if (min == null || (other.min != null && min < other.min)) {
|
| + if (max == null) return true;
|
| + if (max > other.min) return true;
|
| + if (max < other.min) return false;
|
| + assert(max == other.min);
|
| + return includeMax && other.includeMin;
|
| + }
|
| +
|
| + // If this range has a higher minimum than the other range, it overlaps as
|
| + // long as its minimum is lower than or the same as the other range's
|
| + // maximum.
|
| + //
|
| + // [ this ] [ this ]
|
| + // [ other ] [ other ]
|
| + if (other.max == null) return true;
|
| + if (min < other.max) return true;
|
| + if (min > other.max) return false;
|
| + assert(min == other.max);
|
| + return includeMin && other.includeMax;
|
| + }
|
| +
|
| + throw new ArgumentError('Unknown VersionConstraint type $other.');
|
| + }
|
| +
|
| + VersionConstraint intersect(VersionConstraint other) {
|
| + if (other.isEmpty) return other;
|
| + if (other is VersionUnion) return other.intersect(this);
|
| +
|
| + // A range and a Version just yields the version if it's in the range.
|
| + if (other is Version) {
|
| + return allows(other) ? other : VersionConstraint.empty;
|
| + }
|
| +
|
| + if (other is VersionRange) {
|
| + // Intersect the two ranges.
|
| + var intersectMin = min;
|
| + var intersectIncludeMin = includeMin;
|
| + var intersectMax = max;
|
| + var intersectIncludeMax = includeMax;
|
| +
|
| + if (other.min == null) {
|
| + // Do nothing.
|
| + } else if (intersectMin == null || intersectMin < other.min) {
|
| + intersectMin = other.min;
|
| + intersectIncludeMin = other.includeMin;
|
| + } else if (intersectMin == other.min && !other.includeMin) {
|
| + // The edges are the same, but one is exclusive, make it exclusive.
|
| + intersectIncludeMin = false;
|
| + }
|
| +
|
| + if (other.max == null) {
|
| + // Do nothing.
|
| + } else if (intersectMax == null || intersectMax > other.max) {
|
| + intersectMax = other.max;
|
| + intersectIncludeMax = other.includeMax;
|
| + } else if (intersectMax == other.max && !other.includeMax) {
|
| + // The edges are the same, but one is exclusive, make it exclusive.
|
| + intersectIncludeMax = false;
|
| + }
|
| +
|
| + if (intersectMin == null && intersectMax == null) {
|
| + // Open range.
|
| + return new VersionRange();
|
| + }
|
| +
|
| + // If the range is just a single version.
|
| + if (intersectMin == intersectMax) {
|
| + // If both ends are inclusive, allow that version.
|
| + if (intersectIncludeMin && intersectIncludeMax) return intersectMin;
|
| +
|
| + // Otherwise, no versions.
|
| + return VersionConstraint.empty;
|
| + }
|
| +
|
| + if (intersectMin != null && intersectMax != null &&
|
| + intersectMin > intersectMax) {
|
| + // Non-overlapping ranges, so empty.
|
| + return VersionConstraint.empty;
|
| + }
|
| +
|
| + // If we got here, there is an actual range.
|
| + return new VersionRange(min: intersectMin, max: intersectMax,
|
| + includeMin: intersectIncludeMin, includeMax: intersectIncludeMax);
|
| + }
|
| +
|
| + throw new ArgumentError('Unknown VersionConstraint type $other.');
|
| + }
|
| +
|
| + VersionConstraint union(VersionConstraint other) {
|
| + if (other is Version) {
|
| + if (allows(other)) return this;
|
| +
|
| + if (other == min) {
|
| + return new VersionRange(
|
| + min: this.min, max: this.max,
|
| + includeMin: true, includeMax: this.includeMax);
|
| + }
|
| +
|
| + if (other == max) {
|
| + return new VersionRange(
|
| + min: this.min, max: this.max,
|
| + includeMin: this.includeMin, includeMax: true);
|
| + }
|
| +
|
| + return new VersionConstraint.unionOf([this, other]);
|
| + }
|
| +
|
| + if (other is VersionRange) {
|
| + // If the two ranges don't overlap, we won't be able to create a single
|
| + // VersionRange for both of them.
|
| + var edgesTouch = (max == other.min && (includeMax || other.includeMin)) ||
|
| + (min == other.max && (includeMin || other.includeMax));
|
| + if (!edgesTouch && !allowsAny(other)) {
|
| + return new VersionConstraint.unionOf([this, other]);
|
| + }
|
| +
|
| + var unionMin = min;
|
| + var unionIncludeMin = includeMin;
|
| + var unionMax = max;
|
| + var unionIncludeMax = includeMax;
|
| +
|
| + if (unionMin == null) {
|
| + // Do nothing.
|
| + } else if (other.min == null || other.min < min) {
|
| + unionMin = other.min;
|
| + unionIncludeMin = other.includeMin;
|
| + } else if (min == other.min && other.includeMin) {
|
| + // If the edges are the same but one is inclusive, make it inclusive.
|
| + unionIncludeMin = true;
|
| + }
|
| +
|
| + if (unionMax == null) {
|
| + // Do nothing.
|
| + } else if (other.max == null || other.max > max) {
|
| + unionMax = other.max;
|
| + unionIncludeMax = other.includeMax;
|
| + } else if (max == other.max && other.includeMax) {
|
| + // If the edges are the same but one is inclusive, make it inclusive.
|
| + unionIncludeMax = true;
|
| + }
|
| +
|
| + return new VersionRange(min: unionMin, max: unionMax,
|
| + includeMin: unionIncludeMin, includeMax: unionIncludeMax);
|
| + }
|
| +
|
| + return new VersionConstraint.unionOf([this, other]);
|
| + }
|
| +
|
| + String toString() {
|
| + var buffer = new StringBuffer();
|
| +
|
| + if (min != null) {
|
| + buffer.write(includeMin ? '>=' : '>');
|
| + buffer.write(min);
|
| + }
|
| +
|
| + if (max != null) {
|
| + if (min != null) buffer.write(' ');
|
| + buffer.write(includeMax ? '<=' : '<');
|
| + buffer.write(max);
|
| + }
|
| +
|
| + if (min == null && max == null) buffer.write('any');
|
| + return buffer.toString();
|
| + }
|
| +}
|
|
|