1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-23 15:49:44 -05:00

fix(lsp): complete npm specifier versions correctly (#22332)

This commit is contained in:
Nayeem Rahman 2024-02-10 01:27:04 +00:00 committed by GitHub
parent f232c36c48
commit 34c8d17140
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -474,6 +474,29 @@ fn get_relative_specifiers(
.collect()
}
/// Find the index of the '@' delimiting the package name and version, if any.
fn parse_npm_specifier_version_index(specifier: &str) -> Option<usize> {
let bare_specifier = specifier.strip_prefix("npm:")?;
if bare_specifier.starts_with('@') {
bare_specifier
.find('/')
.filter(|idx| !bare_specifier[1..*idx].is_empty())
.and_then(|idx| {
bare_specifier[idx..]
.find('@')
.filter(|idx2| !bare_specifier[idx..][1..*idx2].is_empty())
.filter(|idx2| !bare_specifier[idx..][1..*idx2].contains('/'))
.map(|idx2| 4 + idx + idx2)
})
} else {
bare_specifier
.find('@')
.filter(|idx| !bare_specifier[1..*idx].is_empty())
.filter(|idx| !bare_specifier[1..*idx].contains('/'))
.map(|idx| 4 + idx)
}
}
/// Get completions for `npm:` specifiers.
async fn get_npm_completions(
referrer: &ModuleSpecifier,
@ -481,31 +504,10 @@ async fn get_npm_completions(
range: &lsp::Range,
npm_search_api: &impl NpmSearchApi,
) -> Option<Vec<lsp::CompletionItem>> {
debug_assert!(specifier.starts_with("npm:"));
let bare_specifier = &specifier[4..];
// Find the index of the '@' delimiting the package name and version, if any.
let v_index = if bare_specifier.starts_with('@') {
bare_specifier
.find('/')
.filter(|idx| !bare_specifier[1..*idx].is_empty())
.and_then(|idx| {
bare_specifier[idx..]
.find('@')
.filter(|idx2| !bare_specifier[(idx + 1)..*idx2].is_empty())
.filter(|idx2| !bare_specifier[(idx + 1)..*idx2].contains('/'))
})
} else {
bare_specifier
.find('@')
.filter(|idx| !bare_specifier[..*idx].is_empty())
.filter(|idx| !bare_specifier[..*idx].contains('/'))
};
// First try to match `npm:some-package@<version-to-complete>`.
if let Some(v_index) = v_index {
let package_name = &bare_specifier[..v_index];
let v_prefix = &bare_specifier[(v_index + 1)..];
if let Some(v_index) = parse_npm_specifier_version_index(specifier) {
let package_name = &specifier[..v_index].strip_prefix("npm:")?;
let v_prefix = &specifier[(v_index + 1)..];
let versions = &npm_search_api
.package_info(package_name)
.await
@ -550,7 +552,8 @@ async fn get_npm_completions(
}
// Otherwise match `npm:<package-to-complete>`.
let names = npm_search_api.search(bare_specifier).await.ok()?;
let package_name_prefix = specifier.strip_prefix("npm:")?;
let names = npm_search_api.search(package_name_prefix).await.ok()?;
let items = names
.iter()
.enumerate()
@ -842,6 +845,37 @@ mod tests {
);
}
#[test]
fn test_parse_npm_specifier_version_index() {
assert_eq!(parse_npm_specifier_version_index("npm:"), None);
assert_eq!(parse_npm_specifier_version_index("npm:/"), None);
assert_eq!(parse_npm_specifier_version_index("npm:/@"), None);
assert_eq!(parse_npm_specifier_version_index("npm:@"), None);
assert_eq!(parse_npm_specifier_version_index("npm:@/"), None);
assert_eq!(parse_npm_specifier_version_index("npm:@/@"), None);
assert_eq!(parse_npm_specifier_version_index("npm:foo"), None);
assert_eq!(parse_npm_specifier_version_index("npm:foo/bar"), None);
assert_eq!(parse_npm_specifier_version_index("npm:foo/bar@"), None);
assert_eq!(parse_npm_specifier_version_index("npm:@org/foo/bar"), None);
assert_eq!(parse_npm_specifier_version_index("npm:@org/foo/bar@"), None);
assert_eq!(parse_npm_specifier_version_index("npm:foo@"), Some(7));
assert_eq!(parse_npm_specifier_version_index("npm:foo@1."), Some(7));
assert_eq!(parse_npm_specifier_version_index("npm:@org/foo@"), Some(12));
assert_eq!(
parse_npm_specifier_version_index("npm:@org/foo@1."),
Some(12)
);
// Regression test for https://github.com/denoland/deno/issues/22325.
assert_eq!(
parse_npm_specifier_version_index(
"npm:@longer_than_right_one/arbitrary_string@"
),
Some(43)
);
}
#[tokio::test]
async fn test_get_npm_completions() {
let npm_search_api = TestNpmSearchApi(