/src/semver-parser/src/range.rs
Line | Count | Source |
1 | | use crate::*; |
2 | | |
3 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
4 | | pub struct Range { |
5 | | pub comparator_set: Vec<Comparator>, |
6 | | pub compat: range_set::Compat, |
7 | | } |
8 | | |
9 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
10 | | pub struct Comparator { |
11 | | pub op: Op, |
12 | | pub major: u64, |
13 | | pub minor: u64, |
14 | | pub patch: u64, |
15 | | pub pre: Vec<Identifier>, |
16 | | } |
17 | | |
18 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
19 | | pub enum Op { |
20 | | Lt, |
21 | | Lte, |
22 | | Gt, |
23 | | Gte, |
24 | | Eq, |
25 | | } |
26 | | |
27 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
28 | | pub enum Identifier { |
29 | | Numeric(u64), |
30 | | AlphaNumeric(String), |
31 | | } |
32 | | |
33 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
34 | | pub struct Partial { |
35 | | major: Option<u64>, |
36 | | minor: Option<u64>, |
37 | | patch: Option<u64>, |
38 | | pre: Vec<Identifier>, |
39 | | kind: PartialKind, |
40 | | } |
41 | | |
42 | | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
43 | | pub enum PartialKind { |
44 | | XRangeOnly, |
45 | | MajorOnly, |
46 | | MajorMinor, |
47 | | MajorMinorPatch, |
48 | | } |
49 | | |
50 | | impl Partial { |
51 | 0 | pub fn new() -> Self { |
52 | 0 | Self { |
53 | 0 | major: None, |
54 | 0 | minor: None, |
55 | 0 | patch: None, |
56 | 0 | pre: Vec::new(), |
57 | 0 | kind: PartialKind::XRangeOnly, |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | 0 | pub fn as_comparator(&self, op: Op) -> Comparator { |
62 | 0 | Comparator { |
63 | 0 | op, |
64 | 0 | major: self.major.unwrap_or(0), |
65 | 0 | minor: self.minor.unwrap_or(0), |
66 | 0 | patch: self.patch.unwrap_or(0), |
67 | 0 | pre: self.pre.clone(), |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 0 | pub fn inc_major(&mut self) -> &mut Self { |
72 | 0 | self.major = Some(self.major.unwrap_or(0) + 1); |
73 | 0 | self |
74 | 0 | } |
75 | | |
76 | 0 | pub fn inc_minor(&mut self) -> &mut Self { |
77 | 0 | self.minor = Some(self.minor.unwrap_or(0) + 1); |
78 | 0 | self |
79 | 0 | } |
80 | | |
81 | 0 | pub fn inc_patch(&mut self) -> &mut Self { |
82 | 0 | self.patch = Some(self.patch.unwrap_or(0) + 1); |
83 | 0 | self |
84 | 0 | } |
85 | | |
86 | 0 | pub fn zero_missing(&mut self) -> &mut Self { |
87 | 0 | self.major = Some(self.major.unwrap_or(0)); |
88 | 0 | self.minor = Some(self.minor.unwrap_or(0)); |
89 | 0 | self.patch = Some(self.patch.unwrap_or(0)); |
90 | 0 | self |
91 | 0 | } |
92 | | |
93 | 0 | pub fn zero_minor(&mut self) -> &mut Self { |
94 | 0 | self.minor = Some(0); |
95 | 0 | self |
96 | 0 | } |
97 | | |
98 | 0 | pub fn zero_patch(&mut self) -> &mut Self { |
99 | 0 | self.patch = Some(0); |
100 | 0 | self |
101 | 0 | } |
102 | | |
103 | 0 | pub fn no_pre(&mut self) -> &mut Self { |
104 | 0 | self.pre = Vec::new(); |
105 | 0 | self |
106 | 0 | } |
107 | | } |
108 | | |
109 | 0 | pub fn from_pair_iterator( |
110 | 0 | parsed_range: pest::iterators::Pair<'_, Rule>, |
111 | 0 | compat: range_set::Compat, |
112 | 0 | ) -> Result<Range, String> { |
113 | | // First of all, do we have the correct iterator? |
114 | 0 | if parsed_range.as_rule() != Rule::range { |
115 | 0 | return Err(String::from("Error parsing range")); |
116 | 0 | } |
117 | | |
118 | 0 | let mut comparator_set = Vec::new(); |
119 | | |
120 | | // Now we need to parse each comparator set out of the range |
121 | 0 | for record in parsed_range.into_inner() { |
122 | 0 | match record.as_rule() { |
123 | | Rule::hyphen => { |
124 | 0 | let mut hyphen_set = simple::from_hyphen_range(record)?; |
125 | 0 | comparator_set.append(&mut hyphen_set); |
126 | | } |
127 | | Rule::simple => { |
128 | 0 | let mut comparators = simple::from_pair_iterator(record, compat)?; |
129 | 0 | comparator_set.append(&mut comparators); |
130 | | } |
131 | 0 | Rule::empty => { |
132 | 0 | comparator_set.push(Partial::new().zero_missing().as_comparator(Op::Gte)); |
133 | 0 | } |
134 | 0 | _ => unreachable!(), |
135 | | } |
136 | | } |
137 | | |
138 | 0 | Ok(Range { |
139 | 0 | comparator_set, |
140 | 0 | compat, |
141 | 0 | }) |
142 | 0 | } |
143 | | |
144 | | pub mod simple { |
145 | | use super::*; |
146 | | |
147 | 0 | pub fn from_pair_iterator( |
148 | 0 | parsed_simple: pest::iterators::Pair<'_, Rule>, |
149 | 0 | compat: range_set::Compat, |
150 | 0 | ) -> Result<Vec<Comparator>, String> { |
151 | | // First of all, do we have the correct iterator? |
152 | 0 | if parsed_simple.as_rule() != Rule::simple { |
153 | 0 | return Err(String::from("Error parsing comparator set")); |
154 | 0 | } |
155 | | |
156 | 0 | let mut comparators = Vec::new(); |
157 | | |
158 | | // Now we need to parse each comparator set out of the range |
159 | 0 | for record in parsed_simple.into_inner() { |
160 | 0 | match record.as_rule() { |
161 | | Rule::partial => { |
162 | 0 | let components: Vec<_> = record.into_inner().collect(); |
163 | | |
164 | 0 | let mut partial = parse_partial(components); |
165 | | |
166 | 0 | match partial.kind { |
167 | 0 | PartialKind::XRangeOnly => { |
168 | 0 | // '*', 'x', 'X' --> ">=0.0.0" |
169 | 0 | comparators.push(partial.zero_missing().as_comparator(Op::Gte)); |
170 | 0 | } |
171 | 0 | PartialKind::MajorOnly => { |
172 | 0 | // "1", "1.*", or "1.*.*" --> ">=1.0.0 <2.0.0" |
173 | 0 | // "1.*.3" == "1.*" |
174 | 0 | comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); |
175 | 0 | comparators |
176 | 0 | .push(partial.inc_major().zero_missing().as_comparator(Op::Lt)); |
177 | 0 | } |
178 | 0 | PartialKind::MajorMinor => { |
179 | 0 | // "1.2" or "1.2.*" --> ">=1.2.0 <1.3.0" |
180 | 0 | comparators.push(partial.clone().zero_patch().as_comparator(Op::Gte)); |
181 | 0 | comparators |
182 | 0 | .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt)); |
183 | 0 | } |
184 | | PartialKind::MajorMinorPatch => { |
185 | 0 | match compat { |
186 | 0 | range_set::Compat::Npm => { |
187 | 0 | // for node, "1.2.3" is "=1.2.3" |
188 | 0 | comparators.push(partial.as_comparator(Op::Eq)); |
189 | 0 | } |
190 | 0 | range_set::Compat::Cargo => { |
191 | 0 | // for cargo, "1.2.3" is parsed as "^1.2.3" |
192 | 0 | handle_caret_range(partial, &mut comparators); |
193 | 0 | } |
194 | | } |
195 | | } |
196 | | } |
197 | | } |
198 | | Rule::primitive => { |
199 | 0 | let mut components: Vec<_> = record.into_inner().collect(); |
200 | 0 | let op_component = components.remove(0); |
201 | | |
202 | 0 | let op = match op_component.as_str() { |
203 | 0 | "=" => Op::Eq, |
204 | 0 | "<" => Op::Lt, |
205 | 0 | "<=" => Op::Lte, |
206 | 0 | ">" => Op::Gt, |
207 | 0 | ">=" => Op::Gte, |
208 | 0 | _ => unreachable!(), |
209 | | }; |
210 | | |
211 | 0 | let partial_component = components.remove(0); |
212 | 0 | let components: Vec<_> = partial_component.into_inner().collect(); |
213 | 0 | let mut partial = parse_partial(components); |
214 | | |
215 | | // equal is different because it can be a range with 2 comparators |
216 | 0 | if op == Op::Eq { |
217 | 0 | match partial.kind { |
218 | 0 | PartialKind::XRangeOnly => { |
219 | 0 | // '=*' --> ">=0.0.0" |
220 | 0 | comparators.push(partial.zero_missing().as_comparator(Op::Gte)); |
221 | 0 | } |
222 | 0 | PartialKind::MajorOnly => { |
223 | 0 | // "=1", "=1.*", or "=1.*.*" --> ">=1.0.0 <2.0.0" |
224 | 0 | comparators |
225 | 0 | .push(partial.clone().zero_missing().as_comparator(Op::Gte)); |
226 | 0 | comparators |
227 | 0 | .push(partial.inc_major().zero_missing().as_comparator(Op::Lt)); |
228 | 0 | } |
229 | 0 | PartialKind::MajorMinor => { |
230 | 0 | // "=1.2" or "=1.2.*" --> ">=1.2.0 <1.3.0" |
231 | 0 | comparators |
232 | 0 | .push(partial.clone().zero_patch().as_comparator(Op::Gte)); |
233 | 0 | comparators |
234 | 0 | .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt)); |
235 | 0 | } |
236 | 0 | PartialKind::MajorMinorPatch => { |
237 | 0 | comparators.push(partial.as_comparator(Op::Eq)); |
238 | 0 | } |
239 | | } |
240 | | } else { |
241 | 0 | match partial.kind { |
242 | | PartialKind::XRangeOnly => { |
243 | 0 | match op { |
244 | 0 | Op::Eq => comparators |
245 | 0 | .push(partial.zero_missing().as_comparator(Op::Gte)), |
246 | 0 | Op::Lt => comparators |
247 | 0 | .push(partial.zero_missing().as_comparator(Op::Lt)), |
248 | 0 | Op::Lte => comparators |
249 | 0 | .push(partial.zero_missing().as_comparator(Op::Gte)), |
250 | 0 | Op::Gt => comparators |
251 | 0 | .push(partial.zero_missing().as_comparator(Op::Lt)), |
252 | 0 | Op::Gte => comparators |
253 | 0 | .push(partial.zero_missing().as_comparator(Op::Gte)), |
254 | | } |
255 | | } |
256 | | PartialKind::MajorOnly => { |
257 | | // ">1", "=1", etc. |
258 | | // ">1.*.3" == ">1.*" |
259 | 0 | match op { |
260 | 0 | Op::Lte => comparators.push( |
261 | 0 | partial |
262 | 0 | .inc_major() |
263 | 0 | .zero_minor() |
264 | 0 | .zero_patch() |
265 | 0 | .as_comparator(Op::Lt), |
266 | | ), |
267 | 0 | _ => comparators.push(partial.zero_missing().as_comparator(op)), |
268 | | } |
269 | | } |
270 | | PartialKind::MajorMinor => { |
271 | | // ">1.2", "<1.2.*", etc. |
272 | 0 | match op { |
273 | 0 | Op::Lte => comparators.push( |
274 | 0 | partial.inc_minor().zero_patch().as_comparator(Op::Lt), |
275 | | ), |
276 | 0 | _ => comparators.push(partial.zero_patch().as_comparator(op)), |
277 | | } |
278 | | } |
279 | 0 | PartialKind::MajorMinorPatch => { |
280 | 0 | comparators.push(partial.as_comparator(op)); |
281 | 0 | } |
282 | | } |
283 | | } |
284 | | } |
285 | 0 | Rule::caret => { |
286 | 0 | let mut components: Vec<_> = record.into_inner().collect(); |
287 | 0 |
|
288 | 0 | let partial_component = components.remove(0); |
289 | 0 | let components: Vec<_> = partial_component.into_inner().collect(); |
290 | 0 | let partial = parse_partial(components); |
291 | 0 |
|
292 | 0 | handle_caret_range(partial, &mut comparators); |
293 | 0 | } |
294 | | Rule::tilde => { |
295 | 0 | let mut components: Vec<_> = record.into_inner().collect(); |
296 | | |
297 | 0 | let partial_component = components.remove(0); |
298 | 0 | let components: Vec<_> = partial_component.into_inner().collect(); |
299 | 0 | let mut partial = parse_partial(components); |
300 | | |
301 | 0 | comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); |
302 | | |
303 | 0 | match partial.kind { |
304 | 0 | PartialKind::XRangeOnly => { |
305 | 0 | // "~*" --> ">=0.0.0" |
306 | 0 | // which has already been added, so nothing to do here |
307 | 0 | } |
308 | 0 | PartialKind::MajorOnly => { |
309 | 0 | // "~0" --> ">=0.0.0 <1.0.0" |
310 | 0 | comparators.push( |
311 | 0 | partial |
312 | 0 | .inc_major() |
313 | 0 | .zero_missing() |
314 | 0 | .no_pre() |
315 | 0 | .as_comparator(Op::Lt), |
316 | 0 | ); |
317 | 0 | } |
318 | 0 | PartialKind::MajorMinor | PartialKind::MajorMinorPatch => { |
319 | 0 | // "~1.2" --> ">=1.2.0 <1.3.0" |
320 | 0 | // "~1.2.3" --> ">=1.2.3 <1.3.0" |
321 | 0 | comparators.push( |
322 | 0 | partial |
323 | 0 | .inc_minor() |
324 | 0 | .zero_patch() |
325 | 0 | .no_pre() |
326 | 0 | .as_comparator(Op::Lt), |
327 | 0 | ); |
328 | 0 | } |
329 | | } |
330 | | } |
331 | 0 | _ => unreachable!(), |
332 | | } |
333 | | } |
334 | | |
335 | 0 | Ok(comparators) |
336 | 0 | } |
337 | | |
338 | 0 | fn handle_caret_range(mut partial: Partial, comparators: &mut Vec<Comparator>) { |
339 | | // major version 0 is a special case for caret |
340 | 0 | if partial.major == Some(0) { |
341 | 0 | match partial.kind { |
342 | 0 | PartialKind::XRangeOnly => unreachable!(), |
343 | 0 | PartialKind::MajorOnly => { |
344 | 0 | // "^0", "^0.*" --> ">=0.0.0 <1.0.0" |
345 | 0 | comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); |
346 | 0 | comparators.push( |
347 | 0 | partial |
348 | 0 | .inc_major() |
349 | 0 | .zero_missing() |
350 | 0 | .no_pre() |
351 | 0 | .as_comparator(Op::Lt), |
352 | 0 | ); |
353 | 0 | } |
354 | 0 | PartialKind::MajorMinor => { |
355 | 0 | // "^0.2", "^0.2.*" --> ">=0.2.0 <0.3.0" |
356 | 0 | comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); |
357 | 0 | comparators.push( |
358 | 0 | partial |
359 | 0 | .inc_minor() |
360 | 0 | .zero_patch() |
361 | 0 | .no_pre() |
362 | 0 | .as_comparator(Op::Lt), |
363 | 0 | ); |
364 | 0 | } |
365 | | PartialKind::MajorMinorPatch => { |
366 | 0 | if partial.minor == Some(0) { |
367 | 0 | // "^0.0.1" --> ">=0.0.1 <0.0.2" |
368 | 0 | comparators.push(partial.as_comparator(Op::Gte)); |
369 | 0 | comparators.push(partial.inc_patch().no_pre().as_comparator(Op::Lt)); |
370 | 0 | } else { |
371 | 0 | // "^0.2.3" --> ">=0.2.3 <0.3.0" |
372 | 0 | comparators.push(partial.as_comparator(Op::Gte)); |
373 | 0 | comparators.push( |
374 | 0 | partial |
375 | 0 | .inc_minor() |
376 | 0 | .zero_patch() |
377 | 0 | .no_pre() |
378 | 0 | .as_comparator(Op::Lt), |
379 | 0 | ); |
380 | 0 | } |
381 | | } |
382 | | } |
383 | | } else { |
384 | 0 | match partial.kind { |
385 | 0 | PartialKind::XRangeOnly => { |
386 | 0 | // "^*" --> ">=0.0.0" |
387 | 0 | comparators.push(partial.zero_missing().as_comparator(Op::Gte)); |
388 | 0 | } |
389 | 0 | _ => { |
390 | 0 | // "^1", "^1.*" --> ">=1.0.0 <2.0.0" |
391 | 0 | // "^1.2", "^1.2.*" --> ">=1.2.0 <2.0.0" |
392 | 0 | // "^1.2.3" --> ">=1.2.3 <2.0.0" |
393 | 0 | comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); |
394 | 0 | comparators.push( |
395 | 0 | partial |
396 | 0 | .inc_major() |
397 | 0 | .zero_minor() |
398 | 0 | .zero_patch() |
399 | 0 | .no_pre() |
400 | 0 | .as_comparator(Op::Lt), |
401 | 0 | ); |
402 | 0 | } |
403 | | } |
404 | | } |
405 | 0 | } |
406 | | |
407 | 0 | pub fn from_hyphen_range( |
408 | 0 | parsed_simple: pest::iterators::Pair<'_, Rule>, |
409 | 0 | ) -> Result<Vec<Comparator>, String> { |
410 | | // First of all, do we have the correct iterator? |
411 | 0 | if parsed_simple.as_rule() != Rule::hyphen { |
412 | 0 | return Err(String::from("Error parsing comparator set")); |
413 | 0 | } |
414 | | |
415 | 0 | let mut comparators = Vec::new(); |
416 | | |
417 | | // At this point, we have 2 partial records |
418 | 0 | let mut records = parsed_simple.into_inner(); |
419 | | |
420 | 0 | let components1: Vec<_> = records.next().unwrap().into_inner().collect(); |
421 | 0 | let mut partial1 = parse_partial(components1); |
422 | 0 | match partial1.kind { |
423 | 0 | PartialKind::XRangeOnly => { |
424 | 0 | // don't need to include this - the range will be limited by the 2nd part of hyphen |
425 | 0 | // range |
426 | 0 | } |
427 | 0 | _ => comparators.push(partial1.zero_missing().as_comparator(Op::Gte)), |
428 | | } |
429 | | |
430 | 0 | let components2: Vec<_> = records.next().unwrap().into_inner().collect(); |
431 | 0 | let mut partial2 = parse_partial(components2); |
432 | | |
433 | 0 | match partial2.kind { |
434 | | PartialKind::XRangeOnly => { |
435 | | // only include this if the first part of the hyphen range was also '*' |
436 | 0 | if partial1.kind == PartialKind::XRangeOnly { |
437 | 0 | comparators.push(partial2.zero_missing().as_comparator(Op::Gte)); |
438 | 0 | } |
439 | | } |
440 | 0 | PartialKind::MajorOnly => { |
441 | 0 | // "1.2.3 - 2" --> ">=1.2.3 <3.0.0" |
442 | 0 | comparators.push( |
443 | 0 | partial2 |
444 | 0 | .inc_major() |
445 | 0 | .zero_minor() |
446 | 0 | .zero_patch() |
447 | 0 | .as_comparator(Op::Lt), |
448 | 0 | ); |
449 | 0 | } |
450 | 0 | PartialKind::MajorMinor => { |
451 | 0 | // "1.2.3 - 2.3.x" --> ">=1.2.3 <2.4.0" |
452 | 0 | comparators.push(partial2.inc_minor().zero_patch().as_comparator(Op::Lt)); |
453 | 0 | } |
454 | 0 | PartialKind::MajorMinorPatch => { |
455 | 0 | // "1.2.3 - 2.3.4" --> ">=1.2.3 <=2.3.4" |
456 | 0 | comparators.push(partial2.as_comparator(Op::Lte)); |
457 | 0 | } |
458 | | } |
459 | | |
460 | 0 | Ok(comparators) |
461 | 0 | } |
462 | | |
463 | 0 | fn parse_partial(mut components: Vec<pest::iterators::Pair<'_, Rule>>) -> Partial { |
464 | 0 | let mut partial = Partial::new(); |
465 | | |
466 | | // there will be at least one component |
467 | 0 | let one = components.remove(0); |
468 | | |
469 | 0 | match one.as_rule() { |
470 | | Rule::xr => { |
471 | 0 | let inner = one.into_inner().next().unwrap(); |
472 | 0 | match inner.as_rule() { |
473 | | Rule::xr_op => { |
474 | | // for "*", ">=*", etc. |
475 | 0 | partial.major = None; |
476 | 0 | partial.kind = PartialKind::XRangeOnly; |
477 | | // end the pattern here |
478 | 0 | return partial; |
479 | | } |
480 | 0 | Rule::nr => { |
481 | 0 | partial.major = Some(inner.as_str().parse::<u64>().unwrap()); |
482 | 0 | } |
483 | 0 | _ => unreachable!(), |
484 | | } |
485 | | } |
486 | 0 | _ => unreachable!(), |
487 | | } |
488 | | |
489 | 0 | if components.is_empty() { |
490 | | // only the major has been given |
491 | 0 | partial.kind = PartialKind::MajorOnly; |
492 | 0 | return partial; |
493 | | } else { |
494 | 0 | let two = components.remove(0); |
495 | | |
496 | 0 | match two.as_rule() { |
497 | | Rule::xr => { |
498 | 0 | let inner = two.into_inner().next().unwrap(); |
499 | 0 | match inner.as_rule() { |
500 | | Rule::xr_op => { |
501 | 0 | partial.minor = None; |
502 | | // only the major has been given, minor is xrange (ignore anything after) |
503 | 0 | partial.kind = PartialKind::MajorOnly; |
504 | 0 | return partial; |
505 | | } |
506 | 0 | Rule::nr => { |
507 | 0 | partial.minor = Some(inner.as_str().parse::<u64>().unwrap()); |
508 | 0 | } |
509 | 0 | _ => unreachable!(), |
510 | | } |
511 | | } |
512 | 0 | _ => unreachable!(), |
513 | | } |
514 | | } |
515 | | |
516 | 0 | if components.is_empty() { |
517 | | // only major and minor have been given |
518 | 0 | partial.kind = PartialKind::MajorMinor; |
519 | 0 | return partial; |
520 | | } else { |
521 | 0 | let three = components.remove(0); |
522 | | |
523 | 0 | match three.as_rule() { |
524 | | Rule::xr => { |
525 | 0 | let inner = three.into_inner().next().unwrap(); |
526 | 0 | match inner.as_rule() { |
527 | | Rule::xr_op => { |
528 | 0 | partial.patch = None; |
529 | | // only major and minor have been given, patch is xrange |
530 | 0 | partial.kind = PartialKind::MajorMinor; |
531 | 0 | return partial; |
532 | | } |
533 | 0 | Rule::nr => { |
534 | 0 | partial.patch = Some(inner.as_str().parse::<u64>().unwrap()); |
535 | 0 | } |
536 | 0 | _ => unreachable!(), |
537 | | } |
538 | | } |
539 | 0 | _ => unreachable!(), |
540 | | } |
541 | | } |
542 | | |
543 | | // at this point we at least have all three fields |
544 | 0 | partial.kind = PartialKind::MajorMinorPatch; |
545 | | |
546 | 0 | if !components.is_empty() { |
547 | | // there's only going to be one, let's move it out |
548 | 0 | let pre = components.remove(0); |
549 | | // now we want to look at the inner bit, so that we don't have the leading - |
550 | 0 | let mut pre: Vec<_> = pre.into_inner().collect(); |
551 | 0 | let pre = pre.remove(0); |
552 | 0 | let pre = pre.as_str(); |
553 | | |
554 | | // now we have all of the stuff in pre, so we split by . to get each bit |
555 | 0 | for bit in pre.split('.') { |
556 | 0 | let identifier = match bit.parse::<u64>() { |
557 | 0 | Ok(num) => Identifier::Numeric(num), |
558 | 0 | Err(_) => Identifier::AlphaNumeric(bit.to_string()), |
559 | | }; |
560 | | |
561 | 0 | partial.pre.push(identifier); |
562 | | } |
563 | 0 | } |
564 | | |
565 | 0 | partial |
566 | 0 | } |
567 | | } |
568 | | |
569 | | #[cfg(test)] |
570 | | mod tests { |
571 | | use super::*; |
572 | | use pest::Parser; |
573 | | |
574 | | fn parse_range(input: &str) -> pest::iterators::Pair<'_, Rule> { |
575 | | match SemverParser::parse(Rule::range, input) { |
576 | | Ok(mut parsed) => match parsed.next() { |
577 | | Some(parsed) => parsed, |
578 | | None => panic!("Could not parse {}", input), |
579 | | }, |
580 | | Err(e) => panic!("Parse error:\n{}", e), |
581 | | } |
582 | | } |
583 | | |
584 | | // macros to handle the test boilerplate |
585 | | |
586 | | macro_rules! range_tests { |
587 | | ( $( $name:ident: $value:expr, )* ) => { |
588 | | $( |
589 | | #[test] |
590 | | fn $name() { |
591 | | let (input, expected_range) = $value; |
592 | | |
593 | | let parsed_range = parse_range(input); |
594 | | let range = from_pair_iterator(parsed_range, range_set::Compat::Cargo).expect("parsing failed"); |
595 | | |
596 | | // get the expected length from the input range |
597 | | let num_comparators = range.comparator_set.len(); |
598 | | let expected_comparators = expected_range.comparator_set.len(); |
599 | | assert_eq!(expected_comparators, num_comparators, "expected number of comparators: {}, got: {}", expected_comparators, num_comparators); |
600 | | |
601 | | assert_eq!(range, expected_range); |
602 | | } |
603 | | )* |
604 | | }; |
605 | | } |
606 | | |
607 | | macro_rules! range_tests_nodecompat { |
608 | | ( $( $name:ident: $value:expr, )* ) => { |
609 | | $( |
610 | | #[test] |
611 | | fn $name() { |
612 | | let (input, expected_range) = $value; |
613 | | |
614 | | let parsed_range = parse_range(input); |
615 | | let range = from_pair_iterator(parsed_range, range_set::Compat::Npm).expect("parsing failed"); |
616 | | |
617 | | // get the expected length from the input range |
618 | | let num_comparators = range.comparator_set.len(); |
619 | | let expected_comparators = expected_range.comparator_set.len(); |
620 | | assert_eq!(expected_comparators, num_comparators, "expected number of comparators: {}, got: {}", expected_comparators, num_comparators); |
621 | | |
622 | | assert_eq!(range, expected_range); |
623 | | } |
624 | | )* |
625 | | }; |
626 | | } |
627 | | |
628 | | macro_rules! comp_sets { |
629 | | ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr] ),* ) => { |
630 | | Range { |
631 | | comparator_set: vec![ |
632 | | $( |
633 | | Comparator { |
634 | | op: $op, |
635 | | major: $major, |
636 | | minor: $minor, |
637 | | patch: $patch, |
638 | | pre: pre!(None), |
639 | | }, |
640 | | )* |
641 | | ], |
642 | | compat: range_set::Compat::Cargo |
643 | | } |
644 | | }; |
645 | | // if you specify pre for one item, you have to do it for all of them |
646 | | ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr, $pre:expr] ),* ) => { |
647 | | Range { |
648 | | comparator_set: vec![ |
649 | | $( |
650 | | Comparator { |
651 | | op: $op, |
652 | | major: $major, |
653 | | minor: $minor, |
654 | | patch: $patch, |
655 | | pre: $pre, |
656 | | }, |
657 | | )* |
658 | | ], |
659 | | compat: range_set::Compat::Cargo |
660 | | } |
661 | | }; |
662 | | } |
663 | | |
664 | | // for node compatibility |
665 | | macro_rules! comp_sets_node { |
666 | | ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr] ),* ) => { |
667 | | Range { |
668 | | comparator_set: vec![ |
669 | | $( |
670 | | Comparator { |
671 | | op: $op, |
672 | | major: $major, |
673 | | minor: $minor, |
674 | | patch: $patch, |
675 | | pre: pre!(None), |
676 | | }, |
677 | | )* |
678 | | ], |
679 | | compat: range_set::Compat::Npm |
680 | | } |
681 | | }; |
682 | | } |
683 | | |
684 | | macro_rules! id_num { |
685 | | ( $num:expr ) => { |
686 | | Identifier::Numeric($num) |
687 | | }; |
688 | | } |
689 | | |
690 | | macro_rules! id_alpha { |
691 | | ( $alpha:expr ) => { |
692 | | Identifier::AlphaNumeric(String::from($alpha)) |
693 | | }; |
694 | | } |
695 | | |
696 | | macro_rules! pre { |
697 | | ( None ) => { |
698 | | Vec::new() |
699 | | }; |
700 | | ( $( $e:expr ),* ) => { |
701 | | vec![ |
702 | | $( |
703 | | $e, |
704 | | )* |
705 | | ] |
706 | | }; |
707 | | } |
708 | | |
709 | | macro_rules! op { |
710 | | ( "=" ) => { |
711 | | Op::Eq |
712 | | }; |
713 | | ( "<" ) => { |
714 | | Op::Lt |
715 | | }; |
716 | | ( "<=" ) => { |
717 | | Op::Lte |
718 | | }; |
719 | | ( ">" ) => { |
720 | | Op::Gt |
721 | | }; |
722 | | ( ">=" ) => { |
723 | | Op::Gte |
724 | | }; |
725 | | } |
726 | | |
727 | | // tests |
728 | | |
729 | | range_tests! { |
730 | | major: ("1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
731 | | major_minor: ("1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
732 | | major_minor_patch: ("1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )), |
733 | | major_0_minor_patch: ("0.2.3", comp_sets!( [op!(">="), 0, 2, 3], [op!("<"), 0, 3, 0] )), |
734 | | major_0_minor_0_patch: ("0.0.1", comp_sets!( [op!(">="), 0, 0, 1], [op!("<"), 0, 0, 2] )), |
735 | | |
736 | | eq_major: ("=1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
737 | | eq_major_minor: ("=1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
738 | | eq_major_minor_patch: ("=1.2.3", comp_sets!( [op!("="), 1, 2, 3] )), |
739 | | eq_all: ("=*", comp_sets!( [op!(">="), 0, 0, 0] )), |
740 | | eq_major_star: ("=1.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
741 | | eq_major_minor_star: ("=1.2.*", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
742 | | |
743 | | lt_major: ("<1", comp_sets!( [op!("<"), 1, 0, 0] )), |
744 | | lt_major_minor: ("<1.2", comp_sets!( [op!("<"), 1, 2, 0] )), |
745 | | lt_major_minor_patch: ("<1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )), |
746 | | lt_all: ("<*", comp_sets!( [op!("<"), 0, 0, 0] )), |
747 | | lt_major_star: ("<1.*", comp_sets!( [op!("<"), 1, 0, 0] )), |
748 | | lt_major_minor_star: ("<1.2.*", comp_sets!( [op!("<"), 1, 2, 0] )), |
749 | | |
750 | | lte_major: ("<=1", comp_sets!( [op!("<"), 2, 0, 0] )), |
751 | | lte_major_minor: ("<=1.2", comp_sets!( [op!("<"), 1, 3, 0] )), |
752 | | lte_major_minor_patch: ("<=1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )), |
753 | | lte_all: ("<=*", comp_sets!( [op!(">="), 0, 0, 0] )), |
754 | | lte_major_star: ("<=1.*", comp_sets!( [op!("<"), 2, 0, 0] )), |
755 | | lte_major_minor_star: ("<=1.2.*", comp_sets!( [op!("<"), 1, 3, 0] )), |
756 | | |
757 | | gt_major: (">1", comp_sets!( [op!(">"), 1, 0, 0] )), |
758 | | gt_major_minor: (">1.2", comp_sets!( [op!(">"), 1, 2, 0] )), |
759 | | gt_major_minor_patch: (">1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )), |
760 | | gt_all: (">*", comp_sets!( [op!("<"), 0, 0, 0] )), |
761 | | gt_major_star: (">1.*", comp_sets!( [op!(">"), 1, 0, 0] )), |
762 | | gt_major_minor_star: (">1.2.*", comp_sets!( [op!(">"), 1, 2, 0] )), |
763 | | |
764 | | gte_major: (">=1", comp_sets!( [op!(">="), 1, 0, 0] )), |
765 | | gte_major_minor: (">=1.2", comp_sets!( [op!(">="), 1, 2, 0] )), |
766 | | gte_major_minor_patch: (">=1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), |
767 | | gte_all: (">=*", comp_sets!( [op!(">="), 0, 0, 0] )), |
768 | | gte_major_star: (">=1.*", comp_sets!( [op!(">="), 1, 0, 0] )), |
769 | | gte_major_minor_star: (">=1.2.*", comp_sets!( [op!(">="), 1, 2, 0] )), |
770 | | |
771 | | tilde_major: ("~1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
772 | | tilde_major_0: ("~0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )), |
773 | | tilde_major_xrange: ("~1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
774 | | tilde_major_2: ("~>1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
775 | | tilde_major_minor: ("~1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
776 | | tilde_major_minor_xrange: ("~1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
777 | | tilde_major_minor_2: ("~>1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
778 | | tilde_major_minor_patch: ("~1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )), |
779 | | tilde_major_minor_patch_pre: ("~1.2.3-beta", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("beta"))], [op!("<"), 1, 3, 0, pre!()] )), |
780 | | tilde_major_minor_patch_2: ("~>1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )), |
781 | | tilde_major_0_minor_patch: ("~0.2.3", comp_sets!( [op!(">="), 0, 2, 3], [op!("<"), 0, 3, 0] )), |
782 | | tilde_all: ("~*", comp_sets!( [op!(">="), 0, 0, 0] )), |
783 | | |
784 | | caret_major: ("^1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
785 | | caret_major_xrange: ("^1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
786 | | caret_major_minor: ("^1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0] )), |
787 | | caret_major_minor_xrange: ("^1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0] )), |
788 | | caret_major_minor_patch: ("^1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )), |
789 | | caret_major_minor_patch_pre: ("^1.2.3-beta.4", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("beta"), id_num!(4))], [op!("<"), 2, 0, 0, pre!()] )), |
790 | | |
791 | | caret_major_0: ("^0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )), |
792 | | caret_major_0_xrange: ("^0.x", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )), |
793 | | caret_major_0_minor_0: ("^0.0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 0, 1, 0] )), |
794 | | caret_major_0_minor_0_xrange: ("^0.0.x", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 0, 1, 0] )), |
795 | | caret_major_0_minor: ("^0.1", comp_sets!( [op!(">="), 0, 1, 0], [op!("<"), 0, 2, 0] )), |
796 | | caret_major_0_minor_xrange: ("^0.1.x", comp_sets!( [op!(">="), 0, 1, 0], [op!("<"), 0, 2, 0] )), |
797 | | caret_major_0_minor_patch: ("^0.1.2", comp_sets!( [op!(">="), 0, 1, 2], [op!("<"), 0, 2, 0] )), |
798 | | caret_major_0_minor_0_patch: ("^0.0.1", comp_sets!( [op!(">="), 0, 0, 1], [op!("<"), 0, 0, 2] )), |
799 | | caret_major_0_minor_0_pre: ("^0.0.1-beta", comp_sets!( [op!(">="), 0, 0, 1, pre!(id_alpha!("beta"))], [op!("<"), 0, 0, 2, pre!()] )), |
800 | | caret_all: ("^*", comp_sets!( [op!(">="), 0, 0, 0] )), |
801 | | |
802 | | two_comparators_1: (">1.2.3 <4.5.6", comp_sets!( [op!(">"), 1, 2, 3], [op!("<"), 4, 5, 6] )), |
803 | | two_comparators_2: ("^1.2 ^1", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0], [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
804 | | |
805 | | comparator_with_pre: ("=1.2.3-rc.1", comp_sets!( [op!("="), 1, 2, 3, pre!(id_alpha!("rc"), id_num!(1))] )), |
806 | | |
807 | | hyphen_major: ("1 - 4", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 5, 0, 0] )), |
808 | | hyphen_major_x: ("1.* - 4.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 5, 0, 0] )), |
809 | | hyphen_major_minor_x: ("1.2.x - 4.5.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 4, 6, 0] )), |
810 | | hyphen_major_minor_patch: ("1.2.3 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3], [op!("<="), 4, 5, 6] )), |
811 | | hyphen_with_pre: ("1.2.3-rc1 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("rc1"))], [op!("<="), 4, 5, 6, pre!()] )), |
812 | | hyphen_xrange_minor_only1: ("1.*.3 - 3.4.5", comp_sets!( [op!(">="), 1, 0, 0], [op!("<="), 3, 4, 5] )), |
813 | | hyphen_xrange_minor_only2: ("1.2.3 - 3.*.5", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 4, 0, 0] )), |
814 | | |
815 | | hyphen_all_to_something: ("* - 3.4.5", comp_sets!( [op!("<="), 3, 4, 5] )), |
816 | | hyphen_to_all: ("1.2.3 - *", comp_sets!( [op!(">="), 1, 2, 3] )), |
817 | | hyphen_all_to_all: ("* - *", comp_sets!( [op!(">="), 0, 0, 0] )), |
818 | | |
819 | | gte_space: (">= 1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), |
820 | | gte_tab: (">=\t1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), |
821 | | gte_two_spaces: (">= 1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), |
822 | | gt_space: ("> 1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )), |
823 | | gt_two_spaces: ("> 1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )), |
824 | | lte_space: ("<= 1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )), |
825 | | lte_two_spaces: ("<= 1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )), |
826 | | lt_space: ("< 1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )), |
827 | | lt_two_spaces: ("< 1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )), |
828 | | eq_space: ("= 1.2.3", comp_sets!( [op!("="), 1, 2, 3] )), |
829 | | eq_two_spaces: ("= 1.2.3", comp_sets!( [op!("="), 1, 2, 3] )), |
830 | | caret_space: ("^ 1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )), |
831 | | tilde_space: ("~ 1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )), |
832 | | hyphen_spacing: ("1.2.3 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3], [op!("<="), 4, 5, 6] )), |
833 | | |
834 | | // digit options |
835 | | digits: ("=0.2.3", comp_sets!( [op!("="), 0, 2, 3] )), |
836 | | digits_2: ("=11.2.3", comp_sets!( [op!("="), 11, 2, 3] )), |
837 | | digits_3: ("=1.12.3", comp_sets!( [op!("="), 1, 12, 3] )), |
838 | | digits_4: ("=1.2.13", comp_sets!( [op!("="), 1, 2, 13] )), |
839 | | digits_5: ("=1.2.5678", comp_sets!( [op!("="), 1, 2, 5678] )), |
840 | | |
841 | | xrange_major_x: ("1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
842 | | xrange_major_x_x: ("1.x.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
843 | | xrange_major_minor_x: ("1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
844 | | xrange_major_xx: ("1.X", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
845 | | xrange_major_xx_xx: ("1.X.X", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
846 | | xrange_major_minor_xx: ("1.2.X", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
847 | | xrange_star: ("*", comp_sets!( [op!(">="), 0, 0, 0] )), |
848 | | xrange_x: ("x", comp_sets!( [op!(">="), 0, 0, 0] )), |
849 | | xrange_xx: ("X", comp_sets!( [op!(">="), 0, 0, 0] )), |
850 | | xrange_major_star: ("1.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
851 | | xrange_major_star_star: ("1.*.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
852 | | xrange_major_minor_star: ("1.2.*", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), |
853 | | xrange_with_pre: ("1.*.*-beta", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
854 | | // this is handled as "1.*": |
855 | | xrange_minor_only: ("1.*.3", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), |
856 | | |
857 | | // special cases |
858 | | gte_star: (">=*", comp_sets!( [op!(">="), 0, 0, 0] )), |
859 | | empty: ("", comp_sets!( [op!(">="), 0, 0, 0] )), |
860 | | } |
861 | | |
862 | | range_tests_nodecompat! { |
863 | | node_major_minor_patch: ("1.2.3", comp_sets_node!( [op!("="), 1, 2, 3] )), |
864 | | } |
865 | | } |