mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
fix(npm): support loose node semver ranges like >= ^x.x.x
(#17037)
This commit is contained in:
parent
12626b11f7
commit
878590b773
1 changed files with 89 additions and 5 deletions
|
@ -394,15 +394,13 @@ fn skip_whitespace_or_v(input: &str) -> ParseResult<()> {
|
||||||
|
|
||||||
// simple ::= primitive | partial | tilde | caret
|
// simple ::= primitive | partial | tilde | caret
|
||||||
fn simple(input: &str) -> ParseResult<VersionRange> {
|
fn simple(input: &str) -> ParseResult<VersionRange> {
|
||||||
let tilde = pair(or(tag("~>"), tag("~")), skip_whitespace_or_v);
|
|
||||||
or4(
|
or4(
|
||||||
map(preceded(tilde, partial), |partial| {
|
map(preceded(tilde, partial), |partial| {
|
||||||
partial.as_tilde_version_range()
|
partial.as_tilde_version_range()
|
||||||
}),
|
}),
|
||||||
map(
|
map(preceded(caret, partial), |partial| {
|
||||||
preceded(pair(ch('^'), skip_whitespace_or_v), partial),
|
partial.as_caret_version_range()
|
||||||
|partial| partial.as_caret_version_range(),
|
}),
|
||||||
),
|
|
||||||
map(primitive, |primitive| {
|
map(primitive, |primitive| {
|
||||||
let partial = primitive.partial;
|
let partial = primitive.partial;
|
||||||
match primitive.kind {
|
match primitive.kind {
|
||||||
|
@ -425,6 +423,28 @@ fn simple(input: &str) -> ParseResult<VersionRange> {
|
||||||
)(input)
|
)(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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum PrimitiveKind {
|
enum PrimitiveKind {
|
||||||
GreaterThan,
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue