semver_parser/
range.rs

1use crate::*;
2
3#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
4pub 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)]
10pub 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)]
19pub enum Op {
20    Lt,
21    Lte,
22    Gt,
23    Gte,
24    Eq,
25}
26
27#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
28pub enum Identifier {
29    Numeric(u64),
30    AlphaNumeric(String),
31}
32
33#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
34pub 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)]
43pub enum PartialKind {
44    XRangeOnly,
45    MajorOnly,
46    MajorMinor,
47    MajorMinorPatch,
48}
49
50impl Partial {
51    pub fn new() -> Self {
52        Self {
53            major: None,
54            minor: None,
55            patch: None,
56            pre: Vec::new(),
57            kind: PartialKind::XRangeOnly,
58        }
59    }
60
61    pub fn as_comparator(&self, op: Op) -> Comparator {
62        Comparator {
63            op,
64            major: self.major.unwrap_or(0),
65            minor: self.minor.unwrap_or(0),
66            patch: self.patch.unwrap_or(0),
67            pre: self.pre.clone(),
68        }
69    }
70
71    pub fn inc_major(&mut self) -> &mut Self {
72        self.major = Some(self.major.unwrap_or(0) + 1);
73        self
74    }
75
76    pub fn inc_minor(&mut self) -> &mut Self {
77        self.minor = Some(self.minor.unwrap_or(0) + 1);
78        self
79    }
80
81    pub fn inc_patch(&mut self) -> &mut Self {
82        self.patch = Some(self.patch.unwrap_or(0) + 1);
83        self
84    }
85
86    pub fn zero_missing(&mut self) -> &mut Self {
87        self.major = Some(self.major.unwrap_or(0));
88        self.minor = Some(self.minor.unwrap_or(0));
89        self.patch = Some(self.patch.unwrap_or(0));
90        self
91    }
92
93    pub fn zero_minor(&mut self) -> &mut Self {
94        self.minor = Some(0);
95        self
96    }
97
98    pub fn zero_patch(&mut self) -> &mut Self {
99        self.patch = Some(0);
100        self
101    }
102
103    pub fn no_pre(&mut self) -> &mut Self {
104        self.pre = Vec::new();
105        self
106    }
107}
108
109pub fn from_pair_iterator(
110    parsed_range: pest::iterators::Pair<'_, Rule>,
111    compat: range_set::Compat,
112) -> Result<Range, String> {
113    // First of all, do we have the correct iterator?
114    if parsed_range.as_rule() != Rule::range {
115        return Err(String::from("Error parsing range"));
116    }
117
118    let mut comparator_set = Vec::new();
119
120    // Now we need to parse each comparator set out of the range
121    for record in parsed_range.into_inner() {
122        match record.as_rule() {
123            Rule::hyphen => {
124                let mut hyphen_set = simple::from_hyphen_range(record)?;
125                comparator_set.append(&mut hyphen_set);
126            }
127            Rule::simple => {
128                let mut comparators = simple::from_pair_iterator(record, compat)?;
129                comparator_set.append(&mut comparators);
130            }
131            Rule::empty => {
132                comparator_set.push(Partial::new().zero_missing().as_comparator(Op::Gte));
133            }
134            _ => unreachable!(),
135        }
136    }
137
138    Ok(Range {
139        comparator_set,
140        compat,
141    })
142}
143
144pub mod simple {
145    use super::*;
146
147    pub fn from_pair_iterator(
148        parsed_simple: pest::iterators::Pair<'_, Rule>,
149        compat: range_set::Compat,
150    ) -> Result<Vec<Comparator>, String> {
151        // First of all, do we have the correct iterator?
152        if parsed_simple.as_rule() != Rule::simple {
153            return Err(String::from("Error parsing comparator set"));
154        }
155
156        let mut comparators = Vec::new();
157
158        // Now we need to parse each comparator set out of the range
159        for record in parsed_simple.into_inner() {
160            match record.as_rule() {
161                Rule::partial => {
162                    let components: Vec<_> = record.into_inner().collect();
163
164                    let mut partial = parse_partial(components);
165
166                    match partial.kind {
167                        PartialKind::XRangeOnly => {
168                            // '*', 'x', 'X' --> ">=0.0.0"
169                            comparators.push(partial.zero_missing().as_comparator(Op::Gte));
170                        }
171                        PartialKind::MajorOnly => {
172                            // "1", "1.*", or "1.*.*" --> ">=1.0.0 <2.0.0"
173                            // "1.*.3" == "1.*"
174                            comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
175                            comparators
176                                .push(partial.inc_major().zero_missing().as_comparator(Op::Lt));
177                        }
178                        PartialKind::MajorMinor => {
179                            // "1.2" or "1.2.*" --> ">=1.2.0 <1.3.0"
180                            comparators.push(partial.clone().zero_patch().as_comparator(Op::Gte));
181                            comparators
182                                .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt));
183                        }
184                        PartialKind::MajorMinorPatch => {
185                            match compat {
186                                range_set::Compat::Npm => {
187                                    // for node, "1.2.3" is "=1.2.3"
188                                    comparators.push(partial.as_comparator(Op::Eq));
189                                }
190                                range_set::Compat::Cargo => {
191                                    // for cargo, "1.2.3" is parsed as "^1.2.3"
192                                    handle_caret_range(partial, &mut comparators);
193                                }
194                            }
195                        }
196                    }
197                }
198                Rule::primitive => {
199                    let mut components: Vec<_> = record.into_inner().collect();
200                    let op_component = components.remove(0);
201
202                    let op = match op_component.as_str() {
203                        "=" => Op::Eq,
204                        "<" => Op::Lt,
205                        "<=" => Op::Lte,
206                        ">" => Op::Gt,
207                        ">=" => Op::Gte,
208                        _ => unreachable!(),
209                    };
210
211                    let partial_component = components.remove(0);
212                    let components: Vec<_> = partial_component.into_inner().collect();
213                    let mut partial = parse_partial(components);
214
215                    // equal is different because it can be a range with 2 comparators
216                    if op == Op::Eq {
217                        match partial.kind {
218                            PartialKind::XRangeOnly => {
219                                // '=*' --> ">=0.0.0"
220                                comparators.push(partial.zero_missing().as_comparator(Op::Gte));
221                            }
222                            PartialKind::MajorOnly => {
223                                // "=1", "=1.*", or "=1.*.*" --> ">=1.0.0 <2.0.0"
224                                comparators
225                                    .push(partial.clone().zero_missing().as_comparator(Op::Gte));
226                                comparators
227                                    .push(partial.inc_major().zero_missing().as_comparator(Op::Lt));
228                            }
229                            PartialKind::MajorMinor => {
230                                // "=1.2" or "=1.2.*" --> ">=1.2.0 <1.3.0"
231                                comparators
232                                    .push(partial.clone().zero_patch().as_comparator(Op::Gte));
233                                comparators
234                                    .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt));
235                            }
236                            PartialKind::MajorMinorPatch => {
237                                comparators.push(partial.as_comparator(Op::Eq));
238                            }
239                        }
240                    } else {
241                        match partial.kind {
242                            PartialKind::XRangeOnly => {
243                                match op {
244                                    Op::Eq => comparators
245                                        .push(partial.zero_missing().as_comparator(Op::Gte)),
246                                    Op::Lt => comparators
247                                        .push(partial.zero_missing().as_comparator(Op::Lt)),
248                                    Op::Lte => comparators
249                                        .push(partial.zero_missing().as_comparator(Op::Gte)),
250                                    Op::Gt => comparators
251                                        .push(partial.zero_missing().as_comparator(Op::Lt)),
252                                    Op::Gte => comparators
253                                        .push(partial.zero_missing().as_comparator(Op::Gte)),
254                                }
255                            }
256                            PartialKind::MajorOnly => {
257                                // ">1", "=1", etc.
258                                // ">1.*.3" == ">1.*"
259                                match op {
260                                    Op::Lte => comparators.push(
261                                        partial
262                                            .inc_major()
263                                            .zero_minor()
264                                            .zero_patch()
265                                            .as_comparator(Op::Lt),
266                                    ),
267                                    _ => comparators.push(partial.zero_missing().as_comparator(op)),
268                                }
269                            }
270                            PartialKind::MajorMinor => {
271                                // ">1.2", "<1.2.*", etc.
272                                match op {
273                                    Op::Lte => comparators.push(
274                                        partial.inc_minor().zero_patch().as_comparator(Op::Lt),
275                                    ),
276                                    _ => comparators.push(partial.zero_patch().as_comparator(op)),
277                                }
278                            }
279                            PartialKind::MajorMinorPatch => {
280                                comparators.push(partial.as_comparator(op));
281                            }
282                        }
283                    }
284                }
285                Rule::caret => {
286                    let mut components: Vec<_> = record.into_inner().collect();
287
288                    let partial_component = components.remove(0);
289                    let components: Vec<_> = partial_component.into_inner().collect();
290                    let partial = parse_partial(components);
291
292                    handle_caret_range(partial, &mut comparators);
293                }
294                Rule::tilde => {
295                    let mut components: Vec<_> = record.into_inner().collect();
296
297                    let partial_component = components.remove(0);
298                    let components: Vec<_> = partial_component.into_inner().collect();
299                    let mut partial = parse_partial(components);
300
301                    comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
302
303                    match partial.kind {
304                        PartialKind::XRangeOnly => {
305                            // "~*" --> ">=0.0.0"
306                            // which has already been added, so nothing to do here
307                        }
308                        PartialKind::MajorOnly => {
309                            // "~0" --> ">=0.0.0 <1.0.0"
310                            comparators.push(
311                                partial
312                                    .inc_major()
313                                    .zero_missing()
314                                    .no_pre()
315                                    .as_comparator(Op::Lt),
316                            );
317                        }
318                        PartialKind::MajorMinor | PartialKind::MajorMinorPatch => {
319                            // "~1.2" --> ">=1.2.0 <1.3.0"
320                            // "~1.2.3" --> ">=1.2.3 <1.3.0"
321                            comparators.push(
322                                partial
323                                    .inc_minor()
324                                    .zero_patch()
325                                    .no_pre()
326                                    .as_comparator(Op::Lt),
327                            );
328                        }
329                    }
330                }
331                _ => unreachable!(),
332            }
333        }
334
335        Ok(comparators)
336    }
337
338    fn handle_caret_range(mut partial: Partial, comparators: &mut Vec<Comparator>) {
339        // major version 0 is a special case for caret
340        if partial.major == Some(0) {
341            match partial.kind {
342                PartialKind::XRangeOnly => unreachable!(),
343                PartialKind::MajorOnly => {
344                    // "^0", "^0.*" --> ">=0.0.0 <1.0.0"
345                    comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
346                    comparators.push(
347                        partial
348                            .inc_major()
349                            .zero_missing()
350                            .no_pre()
351                            .as_comparator(Op::Lt),
352                    );
353                }
354                PartialKind::MajorMinor => {
355                    // "^0.2", "^0.2.*" --> ">=0.2.0 <0.3.0"
356                    comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
357                    comparators.push(
358                        partial
359                            .inc_minor()
360                            .zero_patch()
361                            .no_pre()
362                            .as_comparator(Op::Lt),
363                    );
364                }
365                PartialKind::MajorMinorPatch => {
366                    if partial.minor == Some(0) {
367                        // "^0.0.1" --> ">=0.0.1 <0.0.2"
368                        comparators.push(partial.as_comparator(Op::Gte));
369                        comparators.push(partial.inc_patch().no_pre().as_comparator(Op::Lt));
370                    } else {
371                        // "^0.2.3" --> ">=0.2.3 <0.3.0"
372                        comparators.push(partial.as_comparator(Op::Gte));
373                        comparators.push(
374                            partial
375                                .inc_minor()
376                                .zero_patch()
377                                .no_pre()
378                                .as_comparator(Op::Lt),
379                        );
380                    }
381                }
382            }
383        } else {
384            match partial.kind {
385                PartialKind::XRangeOnly => {
386                    // "^*" --> ">=0.0.0"
387                    comparators.push(partial.zero_missing().as_comparator(Op::Gte));
388                }
389                _ => {
390                    // "^1", "^1.*" --> ">=1.0.0 <2.0.0"
391                    // "^1.2", "^1.2.*" --> ">=1.2.0 <2.0.0"
392                    // "^1.2.3" --> ">=1.2.3 <2.0.0"
393                    comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
394                    comparators.push(
395                        partial
396                            .inc_major()
397                            .zero_minor()
398                            .zero_patch()
399                            .no_pre()
400                            .as_comparator(Op::Lt),
401                    );
402                }
403            }
404        }
405    }
406
407    pub fn from_hyphen_range(
408        parsed_simple: pest::iterators::Pair<'_, Rule>,
409    ) -> Result<Vec<Comparator>, String> {
410        // First of all, do we have the correct iterator?
411        if parsed_simple.as_rule() != Rule::hyphen {
412            return Err(String::from("Error parsing comparator set"));
413        }
414
415        let mut comparators = Vec::new();
416
417        // At this point, we have 2 partial records
418        let mut records = parsed_simple.into_inner();
419
420        let components1: Vec<_> = records.next().unwrap().into_inner().collect();
421        let mut partial1 = parse_partial(components1);
422        match partial1.kind {
423            PartialKind::XRangeOnly => {
424                // don't need to include this - the range will be limited by the 2nd part of hyphen
425                // range
426            }
427            _ => comparators.push(partial1.zero_missing().as_comparator(Op::Gte)),
428        }
429
430        let components2: Vec<_> = records.next().unwrap().into_inner().collect();
431        let mut partial2 = parse_partial(components2);
432
433        match partial2.kind {
434            PartialKind::XRangeOnly => {
435                // only include this if the first part of the hyphen range was also '*'
436                if partial1.kind == PartialKind::XRangeOnly {
437                    comparators.push(partial2.zero_missing().as_comparator(Op::Gte));
438                }
439            }
440            PartialKind::MajorOnly => {
441                // "1.2.3 - 2" --> ">=1.2.3 <3.0.0"
442                comparators.push(
443                    partial2
444                        .inc_major()
445                        .zero_minor()
446                        .zero_patch()
447                        .as_comparator(Op::Lt),
448                );
449            }
450            PartialKind::MajorMinor => {
451                // "1.2.3 - 2.3.x" --> ">=1.2.3 <2.4.0"
452                comparators.push(partial2.inc_minor().zero_patch().as_comparator(Op::Lt));
453            }
454            PartialKind::MajorMinorPatch => {
455                // "1.2.3 - 2.3.4" --> ">=1.2.3 <=2.3.4"
456                comparators.push(partial2.as_comparator(Op::Lte));
457            }
458        }
459
460        Ok(comparators)
461    }
462
463    fn parse_partial(mut components: Vec<pest::iterators::Pair<'_, Rule>>) -> Partial {
464        let mut partial = Partial::new();
465
466        // there will be at least one component
467        let one = components.remove(0);
468
469        match one.as_rule() {
470            Rule::xr => {
471                let inner = one.into_inner().next().unwrap();
472                match inner.as_rule() {
473                    Rule::xr_op => {
474                        // for "*", ">=*", etc.
475                        partial.major = None;
476                        partial.kind = PartialKind::XRangeOnly;
477                        // end the pattern here
478                        return partial;
479                    }
480                    Rule::nr => {
481                        partial.major = Some(inner.as_str().parse::<u64>().unwrap());
482                    }
483                    _ => unreachable!(),
484                }
485            }
486            _ => unreachable!(),
487        }
488
489        if components.is_empty() {
490            // only the major has been given
491            partial.kind = PartialKind::MajorOnly;
492            return partial;
493        } else {
494            let two = components.remove(0);
495
496            match two.as_rule() {
497                Rule::xr => {
498                    let inner = two.into_inner().next().unwrap();
499                    match inner.as_rule() {
500                        Rule::xr_op => {
501                            partial.minor = None;
502                            // only the major has been given, minor is xrange (ignore anything after)
503                            partial.kind = PartialKind::MajorOnly;
504                            return partial;
505                        }
506                        Rule::nr => {
507                            partial.minor = Some(inner.as_str().parse::<u64>().unwrap());
508                        }
509                        _ => unreachable!(),
510                    }
511                }
512                _ => unreachable!(),
513            }
514        }
515
516        if components.is_empty() {
517            // only major and minor have been given
518            partial.kind = PartialKind::MajorMinor;
519            return partial;
520        } else {
521            let three = components.remove(0);
522
523            match three.as_rule() {
524                Rule::xr => {
525                    let inner = three.into_inner().next().unwrap();
526                    match inner.as_rule() {
527                        Rule::xr_op => {
528                            partial.patch = None;
529                            // only major and minor have been given, patch is xrange
530                            partial.kind = PartialKind::MajorMinor;
531                            return partial;
532                        }
533                        Rule::nr => {
534                            partial.patch = Some(inner.as_str().parse::<u64>().unwrap());
535                        }
536                        _ => unreachable!(),
537                    }
538                }
539                _ => unreachable!(),
540            }
541        }
542
543        // at this point we at least have all three fields
544        partial.kind = PartialKind::MajorMinorPatch;
545
546        if !components.is_empty() {
547            // there's only going to be one, let's move it out
548            let pre = components.remove(0);
549            // now we want to look at the inner bit, so that we don't have the leading -
550            let mut pre: Vec<_> = pre.into_inner().collect();
551            let pre = pre.remove(0);
552            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            for bit in pre.split('.') {
556                let identifier = match bit.parse::<u64>() {
557                    Ok(num) => Identifier::Numeric(num),
558                    Err(_) => Identifier::AlphaNumeric(bit.to_string()),
559                };
560
561                partial.pre.push(identifier);
562            }
563        }
564
565        partial
566    }
567}
568
569#[cfg(test)]
570mod 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}