VersionConstraint.parse constructor
Parses a version constraint.
This string is one of:
- "any". any version.
- "^" followed by a version string. Versions compatible with (VersionConstraint.compatibleWith) the version.
- a series of version parts. Each part can be one of:
- A version string like
1.2.3
. In other words, anything that can be parsed by Version.parse(). - A comparison operator (
<
,>
,<=
, or>=
) followed by a version string.
- A version string like
Whitespace is ignored.
Examples:
any
^0.7.2
^1.0.0-alpha
1.2.3-alpha
<=5.1.4
>2.0.4 <= 2.4.6
Implementation
factory VersionConstraint.parse(String text) {
var originalText = text;
skipWhitespace() {
text = text.trim();
}
skipWhitespace();
// Handle the "any" constraint.
if (text == "any") return any;
// Try to parse and consume a version number.
Version matchVersion() {
var version = START_VERSION.firstMatch(text);
if (version == null) return null;
text = text.substring(version.end);
return new Version.parse(version[0]);
}
// Try to parse and consume a comparison operator followed by a version.
VersionRange matchComparison() {
var comparison = START_COMPARISON.firstMatch(text);
if (comparison == null) return null;
var op = comparison[0];
text = text.substring(comparison.end);
skipWhitespace();
var version = matchVersion();
if (version == null) {
throw new FormatException('Expected version number after "$op" in '
'"$originalText", got "$text".');
}
switch (op) {
case '<=':
return new VersionRange(max: version, includeMax: true);
case '<':
return new VersionRange(
max: version,
includeMax: false,
alwaysIncludeMaxPreRelease: true);
case '>=':
return new VersionRange(min: version, includeMin: true);
case '>':
return new VersionRange(min: version, includeMin: false);
}
throw "Unreachable.";
}
// Try to parse the "^" operator followed by a version.
matchCompatibleWith() {
if (!text.startsWith(COMPATIBLE_WITH)) return null;
text = text.substring(COMPATIBLE_WITH.length);
skipWhitespace();
var version = matchVersion();
if (version == null) {
throw new FormatException('Expected version number after '
'"$COMPATIBLE_WITH" in "$originalText", got "$text".');
}
if (text.isNotEmpty) {
throw new FormatException('Cannot include other constraints with '
'"$COMPATIBLE_WITH" constraint in "$originalText".');
}
return new VersionConstraint.compatibleWith(version);
}
var compatibleWith = matchCompatibleWith();
if (compatibleWith != null) return compatibleWith;
Version min;
var includeMin = false;
Version max;
var includeMax = false;
while (true) {
skipWhitespace();
if (text.isEmpty) break;
var newRange = matchVersion() ?? matchComparison();
if (newRange == null) {
throw new FormatException('Could not parse version "$originalText". '
'Unknown text at "$text".');
}
if (newRange.min != null) {
if (min == null || newRange.min > min) {
min = newRange.min;
includeMin = newRange.includeMin;
} else if (newRange.min == min && !newRange.includeMin) {
includeMin = false;
}
}
if (newRange.max != null) {
if (max == null || newRange.max < max) {
max = newRange.max;
includeMax = newRange.includeMax;
} else if (newRange.max == max && !newRange.includeMax) {
includeMax = false;
}
}
}
if (min == null && max == null) {
throw new FormatException('Cannot parse an empty string.');
}
if (min != null && max != null) {
if (min > max) return VersionConstraint.empty;
if (min == max) {
if (includeMin && includeMax) return min;
return VersionConstraint.empty;
}
}
return new VersionRange(
min: min, includeMin: includeMin, max: max, includeMax: includeMax);
}