summaryrefslogtreecommitdiff
path: root/cli/npm/semver/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/npm/semver/mod.rs')
-rw-r--r--cli/npm/semver/mod.rs94
1 files changed, 89 insertions, 5 deletions
diff --git a/cli/npm/semver/mod.rs b/cli/npm/semver/mod.rs
index c8c8e64fd..cf049c0dd 100644
--- a/cli/npm/semver/mod.rs
+++ b/cli/npm/semver/mod.rs
@@ -394,15 +394,13 @@ fn skip_whitespace_or_v(input: &str) -> ParseResult<()> {
// simple ::= primitive | partial | tilde | caret
fn simple(input: &str) -> ParseResult<VersionRange> {
- let tilde = pair(or(tag("~>"), tag("~")), skip_whitespace_or_v);
or4(
map(preceded(tilde, partial), |partial| {
partial.as_tilde_version_range()
}),
- map(
- preceded(pair(ch('^'), skip_whitespace_or_v), partial),
- |partial| partial.as_caret_version_range(),
- ),
+ map(preceded(caret, partial), |partial| {
+ partial.as_caret_version_range()
+ }),
map(primitive, |primitive| {
let partial = primitive.partial;
match primitive.kind {
@@ -425,6 +423,28 @@ fn simple(input: &str) -> ParseResult<VersionRange> {
)(input)
}
+fn tilde(input: &str) -> ParseResult<()> {
+ fn raw_tilde(input: &str) -> ParseResult<()> {
+ map(pair(or(tag("~>"), tag("~")), skip_whitespace_or_v), |_| ())(input)
+ }
+
+ or(
+ preceded(terminated(primitive_kind, whitespace), raw_tilde),
+ raw_tilde,
+ )(input)
+}
+
+fn caret(input: &str) -> ParseResult<()> {
+ fn raw_caret(input: &str) -> ParseResult<()> {
+ map(pair(ch('^'), skip_whitespace_or_v), |_| ())(input)
+ }
+
+ or(
+ preceded(terminated(primitive_kind, whitespace), raw_caret),
+ raw_caret,
+ )(input)
+}
+
#[derive(Debug, Clone, Copy)]
enum PrimitiveKind {
GreaterThan,
@@ -1069,4 +1089,68 @@ mod tests {
);
}
}
+
+ #[test]
+ fn range_primitive_kind_beside_caret_or_tilde_with_whitespace() {
+ // node semver should have enforced strictness, but it didn't
+ // and so we end up with a system that acts this way
+ let fixtures = &[
+ (">= ^1.2.3", "1.2.3", true),
+ (">= ^1.2.3", "1.2.4", true),
+ (">= ^1.2.3", "1.9.3", true),
+ (">= ^1.2.3", "2.0.0", false),
+ (">= ^1.2.3", "1.2.2", false),
+ // this is considered the same as the above by node semver
+ ("> ^1.2.3", "1.2.3", true),
+ ("> ^1.2.3", "1.2.4", true),
+ ("> ^1.2.3", "1.9.3", true),
+ ("> ^1.2.3", "2.0.0", false),
+ ("> ^1.2.3", "1.2.2", false),
+ // this is also considered the same
+ ("< ^1.2.3", "1.2.3", true),
+ ("< ^1.2.3", "1.2.4", true),
+ ("< ^1.2.3", "1.9.3", true),
+ ("< ^1.2.3", "2.0.0", false),
+ ("< ^1.2.3", "1.2.2", false),
+ // same with this
+ ("<= ^1.2.3", "1.2.3", true),
+ ("<= ^1.2.3", "1.2.4", true),
+ ("<= ^1.2.3", "1.9.3", true),
+ ("<= ^1.2.3", "2.0.0", false),
+ ("<= ^1.2.3", "1.2.2", false),
+ // now try a ~, which should work the same as above, but for ~
+ ("<= ~1.2.3", "1.2.3", true),
+ ("<= ~1.2.3", "1.2.4", true),
+ ("<= ~1.2.3", "1.9.3", false),
+ ("<= ~1.2.3", "2.0.0", false),
+ ("<= ~1.2.3", "1.2.2", false),
+ ];
+
+ for (req_text, version_text, satisfies) in fixtures {
+ let req = NpmVersionReq::parse(req_text).unwrap();
+ let version = NpmVersion::parse(version_text).unwrap();
+ assert_eq!(
+ req.matches(&version),
+ *satisfies,
+ "Checking {} {} satisfies {}",
+ req_text,
+ if *satisfies { "true" } else { "false" },
+ version_text
+ );
+ }
+ }
+
+ #[test]
+ fn range_primitive_kind_beside_caret_or_tilde_no_whitespace() {
+ let fixtures = &[
+ ">=^1.2.3", ">^1.2.3", "<^1.2.3", "<=^1.2.3", ">=~1.2.3", ">~1.2.3",
+ "<~1.2.3", "<=~1.2.3",
+ ];
+
+ for req_text in fixtures {
+ // when it has no space, this is considered invalid
+ // by node semver so we should error
+ assert!(NpmVersionReq::parse(req_text).is_err());
+ }
+ }
}