Coverage Report

Created: 2025-12-14 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}