difference method

VersionConstraint difference (VersionConstraint other)
override

Returns a VersionConstraint that allows Versions allowed by this but not other.

Implementation

VersionConstraint difference(VersionConstraint other) {
  if (other.isEmpty) return this;

  if (other is Version) {
    if (!allows(other)) return this;

    if (other == min) {
      if (!includeMin) return this;
      return new VersionRange(
          min: min,
          max: max,
          includeMin: false,
          includeMax: includeMax,
          alwaysIncludeMaxPreRelease: true);
    }

    if (other == max) {
      if (!includeMax) return this;
      return new VersionRange(
          min: min,
          max: max,
          includeMin: includeMin,
          includeMax: false,
          alwaysIncludeMaxPreRelease: true);
    }

    return new VersionUnion.fromRanges([
      new VersionRange(
          min: min,
          max: other,
          includeMin: includeMin,
          includeMax: false,
          alwaysIncludeMaxPreRelease: true),
      new VersionRange(
          min: other,
          max: max,
          includeMin: false,
          includeMax: includeMax,
          alwaysIncludeMaxPreRelease: true)
    ]);
  } else if (other is VersionRange) {
    if (!allowsAny(other)) return this;

    VersionRange before;
    if (!allowsLower(this, other)) {
      before = null;
    } else if (min == other.min) {
      assert(includeMin && !other.includeMin);
      assert(min != null);
      before = min;
    } else {
      before = new VersionRange(
          min: min,
          max: other.min,
          includeMin: includeMin,
          includeMax: !other.includeMin,
          alwaysIncludeMaxPreRelease: true);
    }

    VersionRange after;
    if (!allowsHigher(this, other)) {
      after = null;
    } else if (max == other.max) {
      assert(includeMax && !other.includeMax);
      assert(max != null);
      after = max;
    } else {
      after = new VersionRange(
          min: other.max,
          max: max,
          includeMin: !other.includeMax,
          includeMax: includeMax,
          alwaysIncludeMaxPreRelease: true);
    }

    if (before == null && after == null) return VersionConstraint.empty;
    if (before == null) return after;
    if (after == null) return before;
    return new VersionUnion.fromRanges([before, after]);
  } else if (other is VersionUnion) {
    var ranges = <VersionRange>[];
    var current = this;

    for (var range in other.ranges) {
      // Skip any ranges that are strictly lower than [current].
      if (strictlyLower(range, current)) continue;

      // If we reach a range strictly higher than [current], no more ranges
      // will be relevant so we can bail early.
      if (strictlyHigher(range, current)) break;

      var difference = current.difference(range);
      if (difference.isEmpty) {
        return VersionConstraint.empty;
      } else if (difference is VersionUnion) {
        // If [range] split [current] in half, we only need to continue
        // checking future ranges against the latter half.
        assert(difference.ranges.length == 2);
        ranges.add(difference.ranges.first);
        current = difference.ranges.last;
      } else {
        current = difference as VersionRange;
      }
    }

    if (ranges.isEmpty) return current;
    return new VersionUnion.fromRanges(ranges..add(current));
  }

  throw new ArgumentError('Unknown VersionConstraint type $other.');
}