OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library pub_semver.src.version; | 5 library pub_semver.src.version; |
6 | 6 |
7 import 'dart:math'; | 7 import 'dart:math' as math; |
8 | 8 |
9 import 'package:collection/equality.dart'; | 9 import 'package:collection/equality.dart'; |
10 | 10 |
11 import 'patterns.dart'; | 11 import 'patterns.dart'; |
12 import 'version_constraint.dart'; | 12 import 'version_constraint.dart'; |
13 import 'version_range.dart'; | 13 import 'version_range.dart'; |
14 | 14 |
15 /// The equality operator to use for comparing version components. | 15 /// The equality operator to use for comparing version components. |
16 final _equality = const IterableEquality(); | 16 final _equality = const IterableEquality(); |
17 | 17 |
18 /// A parsed semantic version number. | 18 /// A parsed semantic version number. |
19 class Version implements Comparable<Version>, VersionConstraint { | 19 class Version implements Comparable<Version>, VersionConstraint, VersionRange { |
20 /// No released version: i.e. "0.0.0". | 20 /// No released version: i.e. "0.0.0". |
21 static Version get none => new Version(0, 0, 0); | 21 static Version get none => new Version(0, 0, 0); |
22 | 22 |
23 /// Compares [a] and [b] to see which takes priority over the other. | 23 /// Compares [a] and [b] to see which takes priority over the other. |
24 /// | 24 /// |
25 /// Returns `1` if [a] takes priority over [b] and `-1` if vice versa. If | 25 /// Returns `1` if [a] takes priority over [b] and `-1` if vice versa. If |
26 /// [a] and [b] are equivalent, returns `0`. | 26 /// [a] and [b] are equivalent, returns `0`. |
27 /// | 27 /// |
28 /// Unlike [compareTo], which *orders* versions, this determines which | 28 /// Unlike [compareTo], which *orders* versions, this determines which |
29 /// version a user is likely to prefer. In particular, it prioritizes | 29 /// version a user is likely to prefer. In particular, it prioritizes |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 /// string or a non-negative integer. It may also be empty, indicating that | 78 /// string or a non-negative integer. It may also be empty, indicating that |
79 /// this version has no build identifier. | 79 /// this version has no build identifier. |
80 final List build; | 80 final List build; |
81 | 81 |
82 /// The original string representation of the version number. | 82 /// The original string representation of the version number. |
83 /// | 83 /// |
84 /// This preserves textual artifacts like leading zeros that may be left out | 84 /// This preserves textual artifacts like leading zeros that may be left out |
85 /// of the parsed version. | 85 /// of the parsed version. |
86 final String _text; | 86 final String _text; |
87 | 87 |
| 88 Version get min => this; |
| 89 Version get max => this; |
| 90 bool get includeMin => true; |
| 91 bool get includeMax => true; |
| 92 |
88 Version._(this.major, this.minor, this.patch, String preRelease, String build, | 93 Version._(this.major, this.minor, this.patch, String preRelease, String build, |
89 this._text) | 94 this._text) |
90 : preRelease = preRelease == null ? [] : _splitParts(preRelease), | 95 : preRelease = preRelease == null ? [] : _splitParts(preRelease), |
91 build = build == null ? [] : _splitParts(build) { | 96 build = build == null ? [] : _splitParts(build) { |
92 if (major < 0) throw new ArgumentError( | 97 if (major < 0) throw new ArgumentError( |
93 'Major version must be non-negative.'); | 98 'Major version must be non-negative.'); |
94 if (minor < 0) throw new ArgumentError( | 99 if (minor < 0) throw new ArgumentError( |
95 'Minor version must be non-negative.'); | 100 'Minor version must be non-negative.'); |
96 if (patch < 0) throw new ArgumentError( | 101 if (patch < 0) throw new ArgumentError( |
97 'Patch version must be non-negative.'); | 102 'Patch version must be non-negative.'); |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 return _incrementMajor(); | 235 return _incrementMajor(); |
231 } | 236 } |
232 | 237 |
233 Version _incrementMajor() => new Version(major + 1, 0, 0); | 238 Version _incrementMajor() => new Version(major + 1, 0, 0); |
234 Version _incrementMinor() => new Version(major, minor + 1, 0); | 239 Version _incrementMinor() => new Version(major, minor + 1, 0); |
235 Version _incrementPatch() => new Version(major, minor, patch + 1); | 240 Version _incrementPatch() => new Version(major, minor, patch + 1); |
236 | 241 |
237 /// Tests if [other] matches this version exactly. | 242 /// Tests if [other] matches this version exactly. |
238 bool allows(Version other) => this == other; | 243 bool allows(Version other) => this == other; |
239 | 244 |
240 VersionConstraint intersect(VersionConstraint other) { | 245 bool allowsAll(VersionConstraint other) => other.isEmpty || other == this; |
241 if (other.isEmpty) return other; | |
242 | 246 |
243 // Intersect a version and a range. | 247 bool allowsAny(VersionConstraint other) => other.allows(this); |
244 if (other is VersionRange) return other.intersect(this); | |
245 | 248 |
246 // Intersecting two versions only works if they are the same. | 249 VersionConstraint intersect(VersionConstraint other) => |
247 if (other is Version) { | 250 other.allows(this) ? this : VersionConstraint.empty; |
248 return this == other ? this : VersionConstraint.empty; | 251 |
| 252 VersionConstraint union(VersionConstraint other) { |
| 253 if (other.allows(this)) return other; |
| 254 |
| 255 if (other is VersionRange) { |
| 256 if (other.min == this) { |
| 257 return new VersionRange( |
| 258 min: other.min, max: other.max, |
| 259 includeMin: true, includeMax: other.includeMax); |
| 260 } |
| 261 |
| 262 if (other.max == this) { |
| 263 return new VersionRange( |
| 264 min: other.min, max: other.max, |
| 265 includeMin: other.includeMin, includeMax: true); |
| 266 } |
249 } | 267 } |
250 | 268 |
251 throw new ArgumentError( | 269 return new VersionConstraint.unionOf([this, other]); |
252 'Unknown VersionConstraint type $other.'); | |
253 } | 270 } |
254 | 271 |
255 int compareTo(Version other) { | 272 int compareTo(Version other) { |
256 if (major != other.major) return major.compareTo(other.major); | 273 if (major != other.major) return major.compareTo(other.major); |
257 if (minor != other.minor) return minor.compareTo(other.minor); | 274 if (minor != other.minor) return minor.compareTo(other.minor); |
258 if (patch != other.patch) return patch.compareTo(other.patch); | 275 if (patch != other.patch) return patch.compareTo(other.patch); |
259 | 276 |
260 // Pre-releases always come before no pre-release string. | 277 // Pre-releases always come before no pre-release string. |
261 if (!isPreRelease && other.isPreRelease) return 1; | 278 if (!isPreRelease && other.isPreRelease) return 1; |
262 if (!other.isPreRelease && isPreRelease) return -1; | 279 if (!other.isPreRelease && isPreRelease) return -1; |
263 | 280 |
264 var comparison = _compareLists(preRelease, other.preRelease); | 281 var comparison = _compareLists(preRelease, other.preRelease); |
265 if (comparison != 0) return comparison; | 282 if (comparison != 0) return comparison; |
266 | 283 |
267 // Builds always come after no build string. | 284 // Builds always come after no build string. |
268 if (build.isEmpty && other.build.isNotEmpty) return -1; | 285 if (build.isEmpty && other.build.isNotEmpty) return -1; |
269 if (other.build.isEmpty && build.isNotEmpty) return 1; | 286 if (other.build.isEmpty && build.isNotEmpty) return 1; |
270 return _compareLists(build, other.build); | 287 return _compareLists(build, other.build); |
271 } | 288 } |
272 | 289 |
273 String toString() => _text; | 290 String toString() => _text; |
274 | 291 |
275 /// Compares a dot-separated component of two versions. | 292 /// Compares a dot-separated component of two versions. |
276 /// | 293 /// |
277 /// This is used for the pre-release and build version parts. This follows | 294 /// This is used for the pre-release and build version parts. This follows |
278 /// Rule 12 of the Semantic Versioning spec (v2.0.0-rc.1). | 295 /// Rule 12 of the Semantic Versioning spec (v2.0.0-rc.1). |
279 int _compareLists(List a, List b) { | 296 int _compareLists(List a, List b) { |
280 for (var i = 0; i < max(a.length, b.length); i++) { | 297 for (var i = 0; i < math.max(a.length, b.length); i++) { |
281 var aPart = (i < a.length) ? a[i] : null; | 298 var aPart = (i < a.length) ? a[i] : null; |
282 var bPart = (i < b.length) ? b[i] : null; | 299 var bPart = (i < b.length) ? b[i] : null; |
283 | 300 |
284 if (aPart == bPart) continue; | 301 if (aPart == bPart) continue; |
285 | 302 |
286 // Missing parts come before present ones. | 303 // Missing parts come before present ones. |
287 if (aPart == null) return -1; | 304 if (aPart == null) return -1; |
288 if (bPart == null) return 1; | 305 if (bPart == null) return 1; |
289 | 306 |
290 if (aPart is num) { | 307 if (aPart is num) { |
(...skipping 12 matching lines...) Expand all Loading... |
303 // Compare two strings. | 320 // Compare two strings. |
304 return aPart.compareTo(bPart); | 321 return aPart.compareTo(bPart); |
305 } | 322 } |
306 } | 323 } |
307 } | 324 } |
308 | 325 |
309 // The lists are entirely equal. | 326 // The lists are entirely equal. |
310 return 0; | 327 return 0; |
311 } | 328 } |
312 } | 329 } |
OLD | NEW |