OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library pub_semver.src.version_constraint; | |
6 | |
7 import 'patterns.dart'; | |
8 import 'version.dart'; | |
9 import 'version_range.dart'; | |
10 | |
11 /// A [VersionConstraint] is a predicate that can determine whether a given | |
12 /// version is valid or not. | |
13 /// | |
14 /// For example, a ">= 2.0.0" constraint allows any version that is "2.0.0" or | |
15 /// greater. Version objects themselves implement this to match a specific | |
16 /// version. | |
17 abstract class VersionConstraint { | |
18 /// A [VersionConstraint] that allows all versions. | |
19 static VersionConstraint any = new VersionRange(); | |
20 | |
21 /// A [VersionConstraint] that allows no versions: i.e. the empty set. | |
nweiz
2014/09/25 22:52:02
I think we're supposed to avoid "i.e." in docs.
Bob Nystrom
2014/09/26 19:41:07
Done.
| |
22 static VersionConstraint empty = const _EmptyVersion(); | |
23 | |
24 /// Parses a version constraint. | |
25 /// | |
26 /// This string is either "any" or a series of version parts. Each part can | |
27 /// be one of: | |
28 /// | |
29 /// * A version string like `1.2.3`. In other words, anything that can be | |
30 /// parsed by [Version.parse()]. | |
31 /// * A comparison operator (`<`, `>`, `<=`, or `>=`) followed by a version | |
32 /// string. | |
33 /// | |
34 /// Whitespace is ignored. | |
35 /// | |
36 /// Examples: | |
37 /// | |
38 /// any | |
39 /// 1.2.3-alpha | |
40 /// <=5.1.4 | |
41 /// >2.0.4 <= 2.4.6 | |
42 factory VersionConstraint.parse(String text) { | |
43 // Handle the "any" constraint. | |
44 if (text.trim() == "any") return new VersionRange(); | |
45 | |
46 var originalText = text; | |
47 var constraints = <VersionConstraint>[]; | |
nweiz
2014/09/25 22:52:02
Nit: no type annotations here or for the functions
Bob Nystrom
2014/09/26 19:41:07
Done.
nweiz
2014/09/26 19:44:23
This array still has an annotation.
Bob Nystrom
2014/11/10 22:14:06
Done.
| |
48 | |
49 void skipWhitespace() { | |
50 text = text.trim(); | |
51 } | |
52 | |
53 // Try to parse and consume a version number. | |
54 Version matchVersion() { | |
55 var version = START_VERSION.firstMatch(text); | |
56 if (version == null) return null; | |
57 | |
58 text = text.substring(version.end); | |
59 return new Version.parse(version[0]); | |
60 } | |
61 | |
62 // Try to parse and consume a comparison operator followed by a version. | |
63 VersionConstraint matchComparison() { | |
64 var comparison = START_COMPARISON.firstMatch(text); | |
65 if (comparison == null) return null; | |
66 | |
67 var op = comparison[0]; | |
68 text = text.substring(comparison.end); | |
69 skipWhitespace(); | |
70 | |
71 var version = matchVersion(); | |
72 if (version == null) { | |
73 throw new FormatException('Expected version number after "$op" in ' | |
74 '"$originalText", got "$text".'); | |
75 } | |
76 | |
77 switch (op) { | |
78 case '<=': return new VersionRange(max: version, includeMax: true); | |
79 case '<': return new VersionRange(max: version, includeMax: false); | |
80 case '>=': return new VersionRange(min: version, includeMin: true); | |
81 case '>': return new VersionRange(min: version, includeMin: false); | |
82 } | |
83 throw "Unreachable."; | |
84 } | |
85 | |
86 while (true) { | |
87 skipWhitespace(); | |
88 if (text.isEmpty) break; | |
89 | |
90 var version = matchVersion(); | |
91 if (version != null) { | |
92 constraints.add(version); | |
93 continue; | |
94 } | |
95 | |
96 var comparison = matchComparison(); | |
97 if (comparison != null) { | |
98 constraints.add(comparison); | |
99 continue; | |
100 } | |
101 | |
102 // If we got here, we couldn't parse the remaining string. | |
103 throw new FormatException('Could not parse version "$originalText". ' | |
104 'Unknown text at "$text".'); | |
105 } | |
106 | |
107 if (constraints.isEmpty) { | |
108 throw new FormatException('Cannot parse an empty string.'); | |
109 } | |
110 | |
111 return new VersionConstraint.intersection(constraints); | |
112 } | |
113 | |
114 /// Creates a new version constraint that is the intersection of | |
115 /// [constraints]. | |
116 /// | |
117 /// It only allows versions that all of those constraints allow. If | |
118 /// constraints is empty, then it returns a VersionConstraint that allows | |
119 /// all versions. | |
120 factory VersionConstraint.intersection( | |
121 Iterable<VersionConstraint> constraints) { | |
122 var constraint = new VersionRange(); | |
123 for (var other in constraints) { | |
124 constraint = constraint.intersect(other); | |
125 } | |
126 return constraint; | |
127 } | |
128 | |
129 /// Returns `true` if this constraint allows no versions. | |
130 bool get isEmpty; | |
131 | |
132 /// Returns `true` if this constraint allows all versions. | |
133 bool get isAny; | |
134 | |
135 /// Returns `true` if this constraint allows [version]. | |
136 bool allows(Version version); | |
137 | |
138 /// Creates a new [VersionConstraint] that only allows [Version]s allowed by | |
139 /// both this and [other]. | |
140 VersionConstraint intersect(VersionConstraint other); | |
141 } | |
142 | |
143 class _EmptyVersion implements VersionConstraint { | |
144 const _EmptyVersion(); | |
145 | |
146 bool get isEmpty => true; | |
147 bool get isAny => false; | |
148 bool allows(Version other) => false; | |
149 VersionConstraint intersect(VersionConstraint other) => this; | |
150 String toString() => '<empty>'; | |
151 } | |
OLD | NEW |