| use crate::*; | |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
| pub struct Range { | |
| pub comparator_set: Vec<Comparator>, | |
| pub compat: range_set::Compat, | |
| } | |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
| pub struct Comparator { | |
| pub op: Op, | |
| pub major: u64, | |
| pub minor: u64, | |
| pub patch: u64, | |
| pub pre: Vec<Identifier>, | |
| } | |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
| pub enum Op { | |
| Lt, | |
| Lte, | |
| Gt, | |
| Gte, | |
| Eq, | |
| } | |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
| pub enum Identifier { | |
| Numeric(u64), | |
| AlphaNumeric(String), | |
| } | |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
| pub struct Partial { | |
| major: Option<u64>, | |
| minor: Option<u64>, | |
| patch: Option<u64>, | |
| pre: Vec<Identifier>, | |
| kind: PartialKind, | |
| } | |
| #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
| pub enum PartialKind { | |
| XRangeOnly, | |
| MajorOnly, | |
| MajorMinor, | |
| MajorMinorPatch, | |
| } | |
| impl Partial { | |
| pub fn new() -> Self { | |
| Self { | |
| major: None, | |
| minor: None, | |
| patch: None, | |
| pre: Vec::new(), | |
| kind: PartialKind::XRangeOnly, | |
| } | |
| } | |
| pub fn as_comparator(&self, op: Op) -> Comparator { | |
| Comparator { | |
| op, | |
| major: self.major.unwrap_or(0), | |
| minor: self.minor.unwrap_or(0), | |
| patch: self.patch.unwrap_or(0), | |
| pre: self.pre.clone(), | |
| } | |
| } | |
| pub fn inc_major(&mut self) -> &mut Self { | |
| self.major = Some(self.major.unwrap_or(0) + 1); | |
| self | |
| } | |
| pub fn inc_minor(&mut self) -> &mut Self { | |
| self.minor = Some(self.minor.unwrap_or(0) + 1); | |
| self | |
| } | |
| pub fn inc_patch(&mut self) -> &mut Self { | |
| self.patch = Some(self.patch.unwrap_or(0) + 1); | |
| self | |
| } | |
| pub fn zero_missing(&mut self) -> &mut Self { | |
| self.major = Some(self.major.unwrap_or(0)); | |
| self.minor = Some(self.minor.unwrap_or(0)); | |
| self.patch = Some(self.patch.unwrap_or(0)); | |
| self | |
| } | |
| pub fn zero_minor(&mut self) -> &mut Self { | |
| self.minor = Some(0); | |
| self | |
| } | |
| pub fn zero_patch(&mut self) -> &mut Self { | |
| self.patch = Some(0); | |
| self | |
| } | |
| pub fn no_pre(&mut self) -> &mut Self { | |
| self.pre = Vec::new(); | |
| self | |
| } | |
| } | |
| pub fn from_pair_iterator( | |
| parsed_range: pest::iterators::Pair<'_, Rule>, | |
| compat: range_set::Compat, | |
| ) -> Result<Range, String> { | |
| // First of all, do we have the correct iterator? | |
| if parsed_range.as_rule() != Rule::range { | |
| return Err(String::from("Error parsing range")); | |
| } | |
| let mut comparator_set = Vec::new(); | |
| // Now we need to parse each comparator set out of the range | |
| for record in parsed_range.into_inner() { | |
| match record.as_rule() { | |
| Rule::hyphen => { | |
| let mut hyphen_set = simple::from_hyphen_range(record)?; | |
| comparator_set.append(&mut hyphen_set); | |
| } | |
| Rule::simple => { | |
| let mut comparators = simple::from_pair_iterator(record, compat)?; | |
| comparator_set.append(&mut comparators); | |
| } | |
| Rule::empty => { | |
| comparator_set.push(Partial::new().zero_missing().as_comparator(Op::Gte)); | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| Ok(Range { | |
| comparator_set, | |
| compat, | |
| }) | |
| } | |
| pub mod simple { | |
| use super::*; | |
| pub fn from_pair_iterator( | |
| parsed_simple: pest::iterators::Pair<'_, Rule>, | |
| compat: range_set::Compat, | |
| ) -> Result<Vec<Comparator>, String> { | |
| // First of all, do we have the correct iterator? | |
| if parsed_simple.as_rule() != Rule::simple { | |
| return Err(String::from("Error parsing comparator set")); | |
| } | |
| let mut comparators = Vec::new(); | |
| // Now we need to parse each comparator set out of the range | |
| for record in parsed_simple.into_inner() { | |
| match record.as_rule() { | |
| Rule::partial => { | |
| let components: Vec<_> = record.into_inner().collect(); | |
| let mut partial = parse_partial(components); | |
| match partial.kind { | |
| PartialKind::XRangeOnly => { | |
| // '*', 'x', 'X' --> ">=0.0.0" | |
| comparators.push(partial.zero_missing().as_comparator(Op::Gte)); | |
| } | |
| PartialKind::MajorOnly => { | |
| // "1", "1.*", or "1.*.*" --> ">=1.0.0 <2.0.0" | |
| // "1.*.3" == "1.*" | |
| comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); | |
| comparators | |
| .push(partial.inc_major().zero_missing().as_comparator(Op::Lt)); | |
| } | |
| PartialKind::MajorMinor => { | |
| // "1.2" or "1.2.*" --> ">=1.2.0 <1.3.0" | |
| comparators.push(partial.clone().zero_patch().as_comparator(Op::Gte)); | |
| comparators | |
| .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt)); | |
| } | |
| PartialKind::MajorMinorPatch => { | |
| match compat { | |
| range_set::Compat::Npm => { | |
| // for node, "1.2.3" is "=1.2.3" | |
| comparators.push(partial.as_comparator(Op::Eq)); | |
| } | |
| range_set::Compat::Cargo => { | |
| // for cargo, "1.2.3" is parsed as "^1.2.3" | |
| handle_caret_range(partial, &mut comparators); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| Rule::primitive => { | |
| let mut components: Vec<_> = record.into_inner().collect(); | |
| let op_component = components.remove(0); | |
| let op = match op_component.as_str() { | |
| "=" => Op::Eq, | |
| "<" => Op::Lt, | |
| "<=" => Op::Lte, | |
| ">" => Op::Gt, | |
| ">=" => Op::Gte, | |
| _ => unreachable!(), | |
| }; | |
| let partial_component = components.remove(0); | |
| let components: Vec<_> = partial_component.into_inner().collect(); | |
| let mut partial = parse_partial(components); | |
| // equal is different because it can be a range with 2 comparators | |
| if op == Op::Eq { | |
| match partial.kind { | |
| PartialKind::XRangeOnly => { | |
| // '=*' --> ">=0.0.0" | |
| comparators.push(partial.zero_missing().as_comparator(Op::Gte)); | |
| } | |
| PartialKind::MajorOnly => { | |
| // "=1", "=1.*", or "=1.*.*" --> ">=1.0.0 <2.0.0" | |
| comparators | |
| .push(partial.clone().zero_missing().as_comparator(Op::Gte)); | |
| comparators | |
| .push(partial.inc_major().zero_missing().as_comparator(Op::Lt)); | |
| } | |
| PartialKind::MajorMinor => { | |
| // "=1.2" or "=1.2.*" --> ">=1.2.0 <1.3.0" | |
| comparators | |
| .push(partial.clone().zero_patch().as_comparator(Op::Gte)); | |
| comparators | |
| .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt)); | |
| } | |
| PartialKind::MajorMinorPatch => { | |
| comparators.push(partial.as_comparator(Op::Eq)); | |
| } | |
| } | |
| } else { | |
| match partial.kind { | |
| PartialKind::XRangeOnly => { | |
| match op { | |
| Op::Eq => comparators | |
| .push(partial.zero_missing().as_comparator(Op::Gte)), | |
| Op::Lt => comparators | |
| .push(partial.zero_missing().as_comparator(Op::Lt)), | |
| Op::Lte => comparators | |
| .push(partial.zero_missing().as_comparator(Op::Gte)), | |
| Op::Gt => comparators | |
| .push(partial.zero_missing().as_comparator(Op::Lt)), | |
| Op::Gte => comparators | |
| .push(partial.zero_missing().as_comparator(Op::Gte)), | |
| } | |
| } | |
| PartialKind::MajorOnly => { | |
| // ">1", "=1", etc. | |
| // ">1.*.3" == ">1.*" | |
| match op { | |
| Op::Lte => comparators.push( | |
| partial | |
| .inc_major() | |
| .zero_minor() | |
| .zero_patch() | |
| .as_comparator(Op::Lt), | |
| ), | |
| _ => comparators.push(partial.zero_missing().as_comparator(op)), | |
| } | |
| } | |
| PartialKind::MajorMinor => { | |
| // ">1.2", "<1.2.*", etc. | |
| match op { | |
| Op::Lte => comparators.push( | |
| partial.inc_minor().zero_patch().as_comparator(Op::Lt), | |
| ), | |
| _ => comparators.push(partial.zero_patch().as_comparator(op)), | |
| } | |
| } | |
| PartialKind::MajorMinorPatch => { | |
| comparators.push(partial.as_comparator(op)); | |
| } | |
| } | |
| } | |
| } | |
| Rule::caret => { | |
| let mut components: Vec<_> = record.into_inner().collect(); | |
| let partial_component = components.remove(0); | |
| let components: Vec<_> = partial_component.into_inner().collect(); | |
| let partial = parse_partial(components); | |
| handle_caret_range(partial, &mut comparators); | |
| } | |
| Rule::tilde => { | |
| let mut components: Vec<_> = record.into_inner().collect(); | |
| let partial_component = components.remove(0); | |
| let components: Vec<_> = partial_component.into_inner().collect(); | |
| let mut partial = parse_partial(components); | |
| comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); | |
| match partial.kind { | |
| PartialKind::XRangeOnly => { | |
| // "~*" --> ">=0.0.0" | |
| // which has already been added, so nothing to do here | |
| } | |
| PartialKind::MajorOnly => { | |
| // "~0" --> ">=0.0.0 <1.0.0" | |
| comparators.push( | |
| partial | |
| .inc_major() | |
| .zero_missing() | |
| .no_pre() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| PartialKind::MajorMinor | PartialKind::MajorMinorPatch => { | |
| // "~1.2" --> ">=1.2.0 <1.3.0" | |
| // "~1.2.3" --> ">=1.2.3 <1.3.0" | |
| comparators.push( | |
| partial | |
| .inc_minor() | |
| .zero_patch() | |
| .no_pre() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| } | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| Ok(comparators) | |
| } | |
| fn handle_caret_range(mut partial: Partial, comparators: &mut Vec<Comparator>) { | |
| // major version 0 is a special case for caret | |
| if partial.major == Some(0) { | |
| match partial.kind { | |
| PartialKind::XRangeOnly => unreachable!(), | |
| PartialKind::MajorOnly => { | |
| // "^0", "^0.*" --> ">=0.0.0 <1.0.0" | |
| comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); | |
| comparators.push( | |
| partial | |
| .inc_major() | |
| .zero_missing() | |
| .no_pre() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| PartialKind::MajorMinor => { | |
| // "^0.2", "^0.2.*" --> ">=0.2.0 <0.3.0" | |
| comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); | |
| comparators.push( | |
| partial | |
| .inc_minor() | |
| .zero_patch() | |
| .no_pre() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| PartialKind::MajorMinorPatch => { | |
| if partial.minor == Some(0) { | |
| // "^0.0.1" --> ">=0.0.1 <0.0.2" | |
| comparators.push(partial.as_comparator(Op::Gte)); | |
| comparators.push(partial.inc_patch().no_pre().as_comparator(Op::Lt)); | |
| } else { | |
| // "^0.2.3" --> ">=0.2.3 <0.3.0" | |
| comparators.push(partial.as_comparator(Op::Gte)); | |
| comparators.push( | |
| partial | |
| .inc_minor() | |
| .zero_patch() | |
| .no_pre() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| } | |
| } | |
| } else { | |
| match partial.kind { | |
| PartialKind::XRangeOnly => { | |
| // "^*" --> ">=0.0.0" | |
| comparators.push(partial.zero_missing().as_comparator(Op::Gte)); | |
| } | |
| _ => { | |
| // "^1", "^1.*" --> ">=1.0.0 <2.0.0" | |
| // "^1.2", "^1.2.*" --> ">=1.2.0 <2.0.0" | |
| // "^1.2.3" --> ">=1.2.3 <2.0.0" | |
| comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte)); | |
| comparators.push( | |
| partial | |
| .inc_major() | |
| .zero_minor() | |
| .zero_patch() | |
| .no_pre() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| pub fn from_hyphen_range( | |
| parsed_simple: pest::iterators::Pair<'_, Rule>, | |
| ) -> Result<Vec<Comparator>, String> { | |
| // First of all, do we have the correct iterator? | |
| if parsed_simple.as_rule() != Rule::hyphen { | |
| return Err(String::from("Error parsing comparator set")); | |
| } | |
| let mut comparators = Vec::new(); | |
| // At this point, we have 2 partial records | |
| let mut records = parsed_simple.into_inner(); | |
| let components1: Vec<_> = records.next().unwrap().into_inner().collect(); | |
| let mut partial1 = parse_partial(components1); | |
| match partial1.kind { | |
| PartialKind::XRangeOnly => { | |
| // don't need to include this - the range will be limited by the 2nd part of hyphen | |
| // range | |
| } | |
| _ => comparators.push(partial1.zero_missing().as_comparator(Op::Gte)), | |
| } | |
| let components2: Vec<_> = records.next().unwrap().into_inner().collect(); | |
| let mut partial2 = parse_partial(components2); | |
| match partial2.kind { | |
| PartialKind::XRangeOnly => { | |
| // only include this if the first part of the hyphen range was also '*' | |
| if partial1.kind == PartialKind::XRangeOnly { | |
| comparators.push(partial2.zero_missing().as_comparator(Op::Gte)); | |
| } | |
| } | |
| PartialKind::MajorOnly => { | |
| // "1.2.3 - 2" --> ">=1.2.3 <3.0.0" | |
| comparators.push( | |
| partial2 | |
| .inc_major() | |
| .zero_minor() | |
| .zero_patch() | |
| .as_comparator(Op::Lt), | |
| ); | |
| } | |
| PartialKind::MajorMinor => { | |
| // "1.2.3 - 2.3.x" --> ">=1.2.3 <2.4.0" | |
| comparators.push(partial2.inc_minor().zero_patch().as_comparator(Op::Lt)); | |
| } | |
| PartialKind::MajorMinorPatch => { | |
| // "1.2.3 - 2.3.4" --> ">=1.2.3 <=2.3.4" | |
| comparators.push(partial2.as_comparator(Op::Lte)); | |
| } | |
| } | |
| Ok(comparators) | |
| } | |
| fn parse_partial(mut components: Vec<pest::iterators::Pair<'_, Rule>>) -> Partial { | |
| let mut partial = Partial::new(); | |
| // there will be at least one component | |
| let one = components.remove(0); | |
| match one.as_rule() { | |
| Rule::xr => { | |
| let inner = one.into_inner().next().unwrap(); | |
| match inner.as_rule() { | |
| Rule::xr_op => { | |
| // for "*", ">=*", etc. | |
| partial.major = None; | |
| partial.kind = PartialKind::XRangeOnly; | |
| // end the pattern here | |
| return partial; | |
| } | |
| Rule::nr => { | |
| partial.major = Some(inner.as_str().parse::<u64>().unwrap()); | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| _ => unreachable!(), | |
| } | |
| if components.is_empty() { | |
| // only the major has been given | |
| partial.kind = PartialKind::MajorOnly; | |
| return partial; | |
| } else { | |
| let two = components.remove(0); | |
| match two.as_rule() { | |
| Rule::xr => { | |
| let inner = two.into_inner().next().unwrap(); | |
| match inner.as_rule() { | |
| Rule::xr_op => { | |
| partial.minor = None; | |
| // only the major has been given, minor is xrange (ignore anything after) | |
| partial.kind = PartialKind::MajorOnly; | |
| return partial; | |
| } | |
| Rule::nr => { | |
| partial.minor = Some(inner.as_str().parse::<u64>().unwrap()); | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| if components.is_empty() { | |
| // only major and minor have been given | |
| partial.kind = PartialKind::MajorMinor; | |
| return partial; | |
| } else { | |
| let three = components.remove(0); | |
| match three.as_rule() { | |
| Rule::xr => { | |
| let inner = three.into_inner().next().unwrap(); | |
| match inner.as_rule() { | |
| Rule::xr_op => { | |
| partial.patch = None; | |
| // only major and minor have been given, patch is xrange | |
| partial.kind = PartialKind::MajorMinor; | |
| return partial; | |
| } | |
| Rule::nr => { | |
| partial.patch = Some(inner.as_str().parse::<u64>().unwrap()); | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| _ => unreachable!(), | |
| } | |
| } | |
| // at this point we at least have all three fields | |
| partial.kind = PartialKind::MajorMinorPatch; | |
| if !components.is_empty() { | |
| // there's only going to be one, let's move it out | |
| let pre = components.remove(0); | |
| // now we want to look at the inner bit, so that we don't have the leading - | |
| let mut pre: Vec<_> = pre.into_inner().collect(); | |
| let pre = pre.remove(0); | |
| let pre = pre.as_str(); | |
| // now we have all of the stuff in pre, so we split by . to get each bit | |
| for bit in pre.split('.') { | |
| let identifier = match bit.parse::<u64>() { | |
| Ok(num) => Identifier::Numeric(num), | |
| Err(_) => Identifier::AlphaNumeric(bit.to_string()), | |
| }; | |
| partial.pre.push(identifier); | |
| } | |
| } | |
| partial | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use pest::Parser; | |
| fn parse_range(input: &str) -> pest::iterators::Pair<'_, Rule> { | |
| match SemverParser::parse(Rule::range, input) { | |
| Ok(mut parsed) => match parsed.next() { | |
| Some(parsed) => parsed, | |
| None => panic!("Could not parse {}", input), | |
| }, | |
| Err(e) => panic!("Parse error:\n{}", e), | |
| } | |
| } | |
| // macros to handle the test boilerplate | |
| macro_rules! range_tests { | |
| ( $( $name:ident: $value:expr, )* ) => { | |
| $( | |
| #[test] | |
| fn $name() { | |
| let (input, expected_range) = $value; | |
| let parsed_range = parse_range(input); | |
| let range = from_pair_iterator(parsed_range, range_set::Compat::Cargo).expect("parsing failed"); | |
| // get the expected length from the input range | |
| let num_comparators = range.comparator_set.len(); | |
| let expected_comparators = expected_range.comparator_set.len(); | |
| assert_eq!(expected_comparators, num_comparators, "expected number of comparators: {}, got: {}", expected_comparators, num_comparators); | |
| assert_eq!(range, expected_range); | |
| } | |
| )* | |
| }; | |
| } | |
| macro_rules! range_tests_nodecompat { | |
| ( $( $name:ident: $value:expr, )* ) => { | |
| $( | |
| #[test] | |
| fn $name() { | |
| let (input, expected_range) = $value; | |
| let parsed_range = parse_range(input); | |
| let range = from_pair_iterator(parsed_range, range_set::Compat::Npm).expect("parsing failed"); | |
| // get the expected length from the input range | |
| let num_comparators = range.comparator_set.len(); | |
| let expected_comparators = expected_range.comparator_set.len(); | |
| assert_eq!(expected_comparators, num_comparators, "expected number of comparators: {}, got: {}", expected_comparators, num_comparators); | |
| assert_eq!(range, expected_range); | |
| } | |
| )* | |
| }; | |
| } | |
| macro_rules! comp_sets { | |
| ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr] ),* ) => { | |
| Range { | |
| comparator_set: vec![ | |
| $( | |
| Comparator { | |
| op: $op, | |
| major: $major, | |
| minor: $minor, | |
| patch: $patch, | |
| pre: pre!(None), | |
| }, | |
| )* | |
| ], | |
| compat: range_set::Compat::Cargo | |
| } | |
| }; | |
| // if you specify pre for one item, you have to do it for all of them | |
| ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr, $pre:expr] ),* ) => { | |
| Range { | |
| comparator_set: vec![ | |
| $( | |
| Comparator { | |
| op: $op, | |
| major: $major, | |
| minor: $minor, | |
| patch: $patch, | |
| pre: $pre, | |
| }, | |
| )* | |
| ], | |
| compat: range_set::Compat::Cargo | |
| } | |
| }; | |
| } | |
| // for node compatibility | |
| macro_rules! comp_sets_node { | |
| ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr] ),* ) => { | |
| Range { | |
| comparator_set: vec![ | |
| $( | |
| Comparator { | |
| op: $op, | |
| major: $major, | |
| minor: $minor, | |
| patch: $patch, | |
| pre: pre!(None), | |
| }, | |
| )* | |
| ], | |
| compat: range_set::Compat::Npm | |
| } | |
| }; | |
| } | |
| macro_rules! id_num { | |
| ( $num:expr ) => { | |
| Identifier::Numeric($num) | |
| }; | |
| } | |
| macro_rules! id_alpha { | |
| ( $alpha:expr ) => { | |
| Identifier::AlphaNumeric(String::from($alpha)) | |
| }; | |
| } | |
| macro_rules! pre { | |
| ( None ) => { | |
| Vec::new() | |
| }; | |
| ( $( $e:expr ),* ) => { | |
| vec![ | |
| $( | |
| $e, | |
| )* | |
| ] | |
| }; | |
| } | |
| macro_rules! op { | |
| ( "=" ) => { | |
| Op::Eq | |
| }; | |
| ( "<" ) => { | |
| Op::Lt | |
| }; | |
| ( "<=" ) => { | |
| Op::Lte | |
| }; | |
| ( ">" ) => { | |
| Op::Gt | |
| }; | |
| ( ">=" ) => { | |
| Op::Gte | |
| }; | |
| } | |
| // tests | |
| range_tests! { | |
| major: ("1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| major_minor: ("1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| major_minor_patch: ("1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )), | |
| major_0_minor_patch: ("0.2.3", comp_sets!( [op!(">="), 0, 2, 3], [op!("<"), 0, 3, 0] )), | |
| major_0_minor_0_patch: ("0.0.1", comp_sets!( [op!(">="), 0, 0, 1], [op!("<"), 0, 0, 2] )), | |
| eq_major: ("=1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| eq_major_minor: ("=1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| eq_major_minor_patch: ("=1.2.3", comp_sets!( [op!("="), 1, 2, 3] )), | |
| eq_all: ("=*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| eq_major_star: ("=1.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| eq_major_minor_star: ("=1.2.*", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| lt_major: ("<1", comp_sets!( [op!("<"), 1, 0, 0] )), | |
| lt_major_minor: ("<1.2", comp_sets!( [op!("<"), 1, 2, 0] )), | |
| lt_major_minor_patch: ("<1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )), | |
| lt_all: ("<*", comp_sets!( [op!("<"), 0, 0, 0] )), | |
| lt_major_star: ("<1.*", comp_sets!( [op!("<"), 1, 0, 0] )), | |
| lt_major_minor_star: ("<1.2.*", comp_sets!( [op!("<"), 1, 2, 0] )), | |
| lte_major: ("<=1", comp_sets!( [op!("<"), 2, 0, 0] )), | |
| lte_major_minor: ("<=1.2", comp_sets!( [op!("<"), 1, 3, 0] )), | |
| lte_major_minor_patch: ("<=1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )), | |
| lte_all: ("<=*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| lte_major_star: ("<=1.*", comp_sets!( [op!("<"), 2, 0, 0] )), | |
| lte_major_minor_star: ("<=1.2.*", comp_sets!( [op!("<"), 1, 3, 0] )), | |
| gt_major: (">1", comp_sets!( [op!(">"), 1, 0, 0] )), | |
| gt_major_minor: (">1.2", comp_sets!( [op!(">"), 1, 2, 0] )), | |
| gt_major_minor_patch: (">1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )), | |
| gt_all: (">*", comp_sets!( [op!("<"), 0, 0, 0] )), | |
| gt_major_star: (">1.*", comp_sets!( [op!(">"), 1, 0, 0] )), | |
| gt_major_minor_star: (">1.2.*", comp_sets!( [op!(">"), 1, 2, 0] )), | |
| gte_major: (">=1", comp_sets!( [op!(">="), 1, 0, 0] )), | |
| gte_major_minor: (">=1.2", comp_sets!( [op!(">="), 1, 2, 0] )), | |
| gte_major_minor_patch: (">=1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), | |
| gte_all: (">=*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| gte_major_star: (">=1.*", comp_sets!( [op!(">="), 1, 0, 0] )), | |
| gte_major_minor_star: (">=1.2.*", comp_sets!( [op!(">="), 1, 2, 0] )), | |
| tilde_major: ("~1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| tilde_major_0: ("~0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )), | |
| tilde_major_xrange: ("~1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| tilde_major_2: ("~>1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| tilde_major_minor: ("~1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| tilde_major_minor_xrange: ("~1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| tilde_major_minor_2: ("~>1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| tilde_major_minor_patch: ("~1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )), | |
| tilde_major_minor_patch_pre: ("~1.2.3-beta", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("beta"))], [op!("<"), 1, 3, 0, pre!()] )), | |
| tilde_major_minor_patch_2: ("~>1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )), | |
| tilde_major_0_minor_patch: ("~0.2.3", comp_sets!( [op!(">="), 0, 2, 3], [op!("<"), 0, 3, 0] )), | |
| tilde_all: ("~*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| caret_major: ("^1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| caret_major_xrange: ("^1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| caret_major_minor: ("^1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0] )), | |
| caret_major_minor_xrange: ("^1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0] )), | |
| caret_major_minor_patch: ("^1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )), | |
| 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!()] )), | |
| caret_major_0: ("^0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )), | |
| caret_major_0_xrange: ("^0.x", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )), | |
| caret_major_0_minor_0: ("^0.0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 0, 1, 0] )), | |
| caret_major_0_minor_0_xrange: ("^0.0.x", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 0, 1, 0] )), | |
| caret_major_0_minor: ("^0.1", comp_sets!( [op!(">="), 0, 1, 0], [op!("<"), 0, 2, 0] )), | |
| caret_major_0_minor_xrange: ("^0.1.x", comp_sets!( [op!(">="), 0, 1, 0], [op!("<"), 0, 2, 0] )), | |
| caret_major_0_minor_patch: ("^0.1.2", comp_sets!( [op!(">="), 0, 1, 2], [op!("<"), 0, 2, 0] )), | |
| caret_major_0_minor_0_patch: ("^0.0.1", comp_sets!( [op!(">="), 0, 0, 1], [op!("<"), 0, 0, 2] )), | |
| 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!()] )), | |
| caret_all: ("^*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| two_comparators_1: (">1.2.3 <4.5.6", comp_sets!( [op!(">"), 1, 2, 3], [op!("<"), 4, 5, 6] )), | |
| two_comparators_2: ("^1.2 ^1", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0], [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| comparator_with_pre: ("=1.2.3-rc.1", comp_sets!( [op!("="), 1, 2, 3, pre!(id_alpha!("rc"), id_num!(1))] )), | |
| hyphen_major: ("1 - 4", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 5, 0, 0] )), | |
| hyphen_major_x: ("1.* - 4.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 5, 0, 0] )), | |
| hyphen_major_minor_x: ("1.2.x - 4.5.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 4, 6, 0] )), | |
| hyphen_major_minor_patch: ("1.2.3 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3], [op!("<="), 4, 5, 6] )), | |
| 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!()] )), | |
| hyphen_xrange_minor_only1: ("1.*.3 - 3.4.5", comp_sets!( [op!(">="), 1, 0, 0], [op!("<="), 3, 4, 5] )), | |
| hyphen_xrange_minor_only2: ("1.2.3 - 3.*.5", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 4, 0, 0] )), | |
| hyphen_all_to_something: ("* - 3.4.5", comp_sets!( [op!("<="), 3, 4, 5] )), | |
| hyphen_to_all: ("1.2.3 - *", comp_sets!( [op!(">="), 1, 2, 3] )), | |
| hyphen_all_to_all: ("* - *", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| gte_space: (">= 1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), | |
| gte_tab: (">=\t1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), | |
| gte_two_spaces: (">= 1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )), | |
| gt_space: ("> 1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )), | |
| gt_two_spaces: ("> 1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )), | |
| lte_space: ("<= 1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )), | |
| lte_two_spaces: ("<= 1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )), | |
| lt_space: ("< 1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )), | |
| lt_two_spaces: ("< 1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )), | |
| eq_space: ("= 1.2.3", comp_sets!( [op!("="), 1, 2, 3] )), | |
| eq_two_spaces: ("= 1.2.3", comp_sets!( [op!("="), 1, 2, 3] )), | |
| caret_space: ("^ 1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )), | |
| tilde_space: ("~ 1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )), | |
| hyphen_spacing: ("1.2.3 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3], [op!("<="), 4, 5, 6] )), | |
| // digit options | |
| digits: ("=0.2.3", comp_sets!( [op!("="), 0, 2, 3] )), | |
| digits_2: ("=11.2.3", comp_sets!( [op!("="), 11, 2, 3] )), | |
| digits_3: ("=1.12.3", comp_sets!( [op!("="), 1, 12, 3] )), | |
| digits_4: ("=1.2.13", comp_sets!( [op!("="), 1, 2, 13] )), | |
| digits_5: ("=1.2.5678", comp_sets!( [op!("="), 1, 2, 5678] )), | |
| xrange_major_x: ("1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| xrange_major_x_x: ("1.x.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| xrange_major_minor_x: ("1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| xrange_major_xx: ("1.X", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| xrange_major_xx_xx: ("1.X.X", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| xrange_major_minor_xx: ("1.2.X", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| xrange_star: ("*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| xrange_x: ("x", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| xrange_xx: ("X", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| xrange_major_star: ("1.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| xrange_major_star_star: ("1.*.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| xrange_major_minor_star: ("1.2.*", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )), | |
| xrange_with_pre: ("1.*.*-beta", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| // this is handled as "1.*": | |
| xrange_minor_only: ("1.*.3", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )), | |
| // special cases | |
| gte_star: (">=*", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| empty: ("", comp_sets!( [op!(">="), 0, 0, 0] )), | |
| } | |
| range_tests_nodecompat! { | |
| node_major_minor_patch: ("1.2.3", comp_sets_node!( [op!("="), 1, 2, 3] )), | |
| } | |
| } |