v2 / vlib / semver / range.v
228 lines · 205 sloc · 4.98 KB · 8e35f4d9848f7ad35d857a187dddbfd2eca5e19d
Raw
1module semver
2
3// * Private functions.
4const comparator_sep = ' '
5const comparator_set_sep = ' || '
6const hyphen_range_sep = ' - '
7const x_range_symbols = 'Xx*'
8
9enum Operator {
10 gt
11 lt
12 ge
13 le
14 eq
15}
16
17struct Comparator {
18 ver Version
19 op Operator
20}
21
22struct ComparatorSet {
23 comparators []Comparator
24}
25
26struct Range {
27 comparator_sets []ComparatorSet
28}
29
30struct InvalidComparatorFormatError {
31 MessageError
32}
33
34fn (r Range) satisfies(ver Version) bool {
35 return r.comparator_sets.any(it.satisfies(ver))
36}
37
38fn (set ComparatorSet) satisfies(ver Version) bool {
39 for comp in set.comparators {
40 if !comp.satisfies(ver) {
41 return false
42 }
43 }
44 return true
45}
46
47fn (c Comparator) satisfies(ver Version) bool {
48 return match c.op {
49 .gt { ver > c.ver }
50 .lt { ver < c.ver }
51 .ge { ver >= c.ver }
52 .le { ver <= c.ver }
53 .eq { ver == c.ver }
54 }
55}
56
57fn parse_range(input string) !Range {
58 raw_comparator_sets := input.split(comparator_set_sep)
59 mut comparator_sets := []ComparatorSet{}
60 for raw_comp_set in raw_comparator_sets {
61 if can_expand(raw_comp_set) {
62 s := expand_comparator_set(raw_comp_set) or { return err }
63 comparator_sets << s
64 } else {
65 s := parse_comparator_set(raw_comp_set) or { return err }
66 comparator_sets << s
67 }
68 }
69 return Range{comparator_sets}
70}
71
72fn parse_comparator_set(input string) !ComparatorSet {
73 raw_comparators := input.split(comparator_sep)
74 if raw_comparators.len > 2 {
75 return &InvalidComparatorFormatError{
76 msg: 'Invalid format of comparator set for input "${input}"'
77 }
78 }
79 mut comparators := []Comparator{}
80 for raw_comp in raw_comparators {
81 c := parse_comparator(raw_comp) or {
82 return &InvalidComparatorFormatError{
83 msg: 'Invalid comparator "${raw_comp}" in input "${input}"'
84 }
85 }
86 comparators << c
87 }
88 return ComparatorSet{comparators}
89}
90
91fn parse_comparator(input string) ?Comparator {
92 mut op := Operator.eq
93 raw_version := match true {
94 input.starts_with('>=') {
95 op = .ge
96 input[2..]
97 }
98 input.starts_with('<=') {
99 op = .le
100 input[2..]
101 }
102 input.starts_with('>') {
103 op = .gt
104 input[1..]
105 }
106 input.starts_with('<') {
107 op = .lt
108 input[1..]
109 }
110 input.starts_with('=') {
111 input[1..]
112 }
113 else {
114 input
115 }
116 }
117
118 version := coerce_version(raw_version) or { return none }
119 return Comparator{version, op}
120}
121
122fn parse_xrange(input string) ?Version {
123 mut raw_ver := parse(input).complete()
124 for typ in versions {
125 if raw_ver.raw_ints[typ].index_any(x_range_symbols) == -1 {
126 continue
127 }
128 match typ {
129 ver_major {
130 raw_ver.raw_ints[ver_major] = '0'
131 raw_ver.raw_ints[ver_minor] = '0'
132 raw_ver.raw_ints[ver_patch] = '0'
133 }
134 ver_minor {
135 raw_ver.raw_ints[ver_minor] = '0'
136 raw_ver.raw_ints[ver_patch] = '0'
137 }
138 ver_patch {
139 raw_ver.raw_ints[ver_patch] = '0'
140 }
141 else {}
142 }
143 }
144 return raw_ver.validate()
145}
146
147fn can_expand(input string) bool {
148 return input[0] == `~` || input[0] == `^` || input.contains(hyphen_range_sep)
149 || input.index_any(x_range_symbols) > -1
150}
151
152fn expand_comparator_set(input string) ?ComparatorSet {
153 match input[0] {
154 `~` { return expand_tilda(input[1..]) }
155 `^` { return expand_caret(input[1..]) }
156 else {}
157 }
158
159 if input.contains(hyphen_range_sep) {
160 return expand_hyphen(input)
161 }
162 return expand_xrange(input)
163}
164
165fn expand_tilda(raw_version string) ?ComparatorSet {
166 min_ver := coerce_version(raw_version) or { return none }
167 max_ver := if min_ver.minor == 0 && min_ver.patch == 0 {
168 min_ver.increment(.major)
169 } else {
170 min_ver.increment(.minor)
171 }
172 return make_comparator_set_ge_lt(min_ver, max_ver)
173}
174
175fn expand_caret(raw_version string) ?ComparatorSet {
176 min_ver := coerce_version(raw_version) or { return none }
177 max_ver := if min_ver.major == 0 {
178 min_ver.increment(.minor)
179 } else {
180 min_ver.increment(.major)
181 }
182 return make_comparator_set_ge_lt(min_ver, max_ver)
183}
184
185fn expand_hyphen(raw_range string) ?ComparatorSet {
186 raw_versions := raw_range.split(hyphen_range_sep)
187 if raw_versions.len != 2 {
188 return none
189 }
190 min_ver := coerce_version(raw_versions[0]) or { return none }
191 raw_max_ver := parse(raw_versions[1])
192 if raw_max_ver.is_missing(ver_major) {
193 return none
194 }
195 if raw_max_ver.is_missing(ver_minor) {
196 max_ver := raw_max_ver.coerce() or { return none }.increment(.minor)
197 return make_comparator_set_ge_lt(min_ver, max_ver)
198 }
199 max_ver := raw_max_ver.coerce() or { return none }
200 return make_comparator_set_ge_le(min_ver, max_ver)
201}
202
203fn expand_xrange(raw_range string) ?ComparatorSet {
204 min_ver := parse_xrange(raw_range) or { return none }
205 if min_ver.major == 0 {
206 return ComparatorSet{[Comparator{min_ver, Operator.ge}]}
207 }
208 max_ver := if min_ver.minor == 0 {
209 min_ver.increment(.major)
210 } else {
211 min_ver.increment(.minor)
212 }
213 return make_comparator_set_ge_lt(min_ver, max_ver)
214}
215
216fn make_comparator_set_ge_lt(min Version, max Version) ComparatorSet {
217 return ComparatorSet{[
218 Comparator{min, Operator.ge},
219 Comparator{max, Operator.lt},
220 ]}
221}
222
223fn make_comparator_set_ge_le(min Version, max Version) ComparatorSet {
224 return ComparatorSet{[
225 Comparator{min, Operator.ge},
226 Comparator{max, Operator.le},
227 ]}
228}
229