Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions cli/lsp/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use indexmap::IndexSet;
use lsp_types::ClientCapabilities;
use lsp_types::Uri;
use node_resolver::NodeResolverOptions;
use sys_traits::SystemTimeNow;
use tower_lsp::lsp_types as lsp;

use super::logging::lsp_log;
Expand Down Expand Up @@ -1775,6 +1776,35 @@ impl ConfigData {
self.member_dir.member_or_root_pkg_json()
}

/// Workspace `minimumDependencyAge`, with the same `.npmrc` and default
/// fallbacks the CLI uses when the config does not set an age.
pub fn minimum_dependency_age_config(
&self,
) -> deno_config::deno_json::MinimumDependencyAgeConfig {
let parsed = match self
.member_dir
.workspace
.minimum_dependency_age(&CliSys::default())
{
Ok(config) => config,
Err(err) => {
lsp_warn!(
"Failed to parse \"minimumDependencyAge\" for \"{}\": {err}",
self.scope
);
Default::default()
}
};
deno_resolver::factory::resolve_minimum_dependency_age_config(
parsed,
self
.npmrc
.as_ref()
.and_then(|npmrc| npmrc.min_release_age_days),
chrono::DateTime::<chrono::Utc>::from(CliSys::default().sys_time_now()),
)
}

pub fn scope_contains_specifier(&self, specifier: &ModuleSpecifier) -> bool {
specifier.as_str().starts_with(self.scope.as_str())
|| self
Expand Down
49 changes: 45 additions & 4 deletions cli/lsp/jsr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use serde::Deserialize;
use sys_traits::SystemTimeNow;

use super::config::ConfigData;
use super::search::PackageSearchApi;
Expand Down Expand Up @@ -48,6 +49,8 @@ pub struct JsrCacheResolver {
info_by_name: DashMap<StackString, Option<Arc<JsrPackageInfo>>>,
workspace_packages_by_name: HashMap<StackString, WorkspacePackage>,
cache: Arc<dyn HttpCache>,
newest_dependency_date_options:
deno_graph::packages::NewestDependencyDateOptions,
}

impl JsrCacheResolver {
Expand All @@ -56,6 +59,22 @@ impl JsrCacheResolver {
config_data: Option<&ConfigData>,
workspace_resolver: &WorkspaceResolver<CliSys>,
) -> Self {
let newest_dependency_date_options = match config_data {
Some(config_data) => {
deno_resolver::factory::jsr_newest_dependency_date_options(
&config_data.minimum_dependency_age_config(),
)
}
None => deno_resolver::factory::jsr_newest_dependency_date_options(
&deno_resolver::factory::resolve_minimum_dependency_age_config(
Default::default(),
None,
chrono::DateTime::<chrono::Utc>::from(
CliSys::default().sys_time_now(),
),
),
),
};
let nv_by_req = DashMap::new();
let info_by_nv = DashMap::new();
let info_by_name = DashMap::new();
Expand Down Expand Up @@ -127,6 +146,7 @@ impl JsrCacheResolver {
info_by_name,
workspace_packages_by_name,
cache: cache.clone(),
newest_dependency_date_options,
}
}

Expand All @@ -147,6 +167,8 @@ impl JsrCacheResolver {
&req.version_req,
&package_info,
);
let newest_dependency_date =
self.newest_dependency_date_options.get_for_package(name);
let version = versions
.into_iter()
.rev()
Expand All @@ -160,6 +182,12 @@ impl JsrCacheResolver {
{
return false;
}
if let Some(cutoff) = newest_dependency_date
&& let Some(version_info) = package_info.versions.get(*v)
&& !version_info.matches_newest_dependency_date(cutoff)
{
return false;
}
let nv = PackageNv {
name: name.clone(),
version: (*v).clone(),
Expand Down Expand Up @@ -372,12 +400,14 @@ pub struct CliJsrSearchApi {
}

impl CliJsrSearchApi {
pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
pub fn new(
file_fetcher: Arc<CliFileFetcher>,
newest_dependency_date_options: deno_graph::packages::NewestDependencyDateOptions,
) -> Self {
let resolver = JsrFetchResolver::new(
file_fetcher.clone(),
Arc::new(JsrVersionResolver {
// not currently supported in the lsp
newest_dependency_date_options: Default::default(),
newest_dependency_date_options,
}),
);
Self {
Expand Down Expand Up @@ -428,7 +458,18 @@ impl PackageSearchApi for CliJsrSearchApi {
.package_info(name)
.await
.ok_or_else(|| anyhow!("JSR package info not found: {}", name))?;
let mut versions = info.versions.keys().cloned().collect::<Vec<_>>();
let package_name = deno_semver::package::PackageName::from(name);
let version_resolver = self
.resolver
.version_resolver_for_package(&package_name, &info);
let mut versions = info
.versions
.iter()
.filter(|(_, version_info)| {
version_resolver.matches_newest_dependency_date(version_info)
})
.map(|(version, _)| version.clone())
.collect::<Vec<_>>();
versions.sort();
versions.reverse();
let versions = Arc::new(versions);
Expand Down
84 changes: 61 additions & 23 deletions cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use indexmap::IndexSet;
use log::error;
use serde::Deserialize;
use serde_json::from_value;
use sys_traits::SystemTimeNow;
use tokio::sync::OnceCell;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::mpsc::UnboundedSender;
Expand Down Expand Up @@ -622,6 +623,47 @@ impl LanguageServer {
}
}

/// `minimumDependencyAge` for import completions. The search APIs are
/// process-global, so this follows the root workspace folder (then any other
/// loaded scope). Resolution itself is per-scope.
fn minimum_dependency_age_config(
config: &Config,
) -> deno_config::deno_json::MinimumDependencyAgeConfig {
let data = config
.root_url()
.and_then(|root| config.tree.data_for_specifier(root))
.or_else(|| config.tree.data_by_scope().values().next());
match data {
Some(data) => data.minimum_dependency_age_config(),
None => deno_resolver::factory::resolve_minimum_dependency_age_config(
Default::default(),
None,
chrono::DateTime::<chrono::Utc>::from(CliSys::default().sys_time_now()),
),
}
}

fn package_search_apis(
file_fetcher: Arc<crate::file_fetcher::CliFileFetcher>,
config: &deno_config::deno_json::MinimumDependencyAgeConfig,
) -> (CliJsrSearchApi, CliNpmSearchApi) {
let jsr_search_api = CliJsrSearchApi::new(
file_fetcher.clone(),
deno_resolver::factory::jsr_newest_dependency_date_options(config),
);
let npm_search_api = CliNpmSearchApi::new(
file_fetcher,
Arc::new(NpmVersionResolver {
link_packages: Default::default(),
newest_dependency_date_options:
deno_resolver::factory::npm_newest_dependency_date_options(config),
overrides: Default::default(),
trust_policy: Default::default(),
}),
);
(jsr_search_api, npm_search_api)
}

impl Inner {
fn new(client: Client, performance: Arc<Performance>) -> Self {
let cache = LspCache::default();
Expand All @@ -630,18 +672,11 @@ impl Inner {
cache.deno_dir().registries_folder_path(),
http_client_provider.clone(),
);
let jsr_search_api =
CliJsrSearchApi::new(module_registry.file_fetcher.clone());
let npm_search_api = CliNpmSearchApi::new(
let config = Config::default();
let (jsr_search_api, npm_search_api) = package_search_apis(
module_registry.file_fetcher.clone(),
Arc::new(NpmVersionResolver {
link_packages: Default::default(),
newest_dependency_date_options: Default::default(),
overrides: Default::default(),
trust_policy: Default::default(),
}),
&minimum_dependency_age_config(&config),
);
let config = Config::default();
let ts_server = Arc::new(TsServer::new(performance.clone()));
let initial_cwd = resolve_cwd(None).unwrap().into_owned();

Expand Down Expand Up @@ -855,21 +890,20 @@ impl Inner {
self.module_registry.disable(registry);
}
}
self.jsr_search_api =
CliJsrSearchApi::new(self.module_registry.file_fetcher.clone());
self.npm_search_api = CliNpmSearchApi::new(
// todo(dsherret): the npm_search_api should probably be specific
// to each workspace so that the link packages can be properly
// hooked up. minimumDependencyAge follows the root workspace.
self.rebuild_package_search_apis();
self.performance.measure(mark);
}

fn rebuild_package_search_apis(&mut self) {
let (jsr_search_api, npm_search_api) = package_search_apis(
self.module_registry.file_fetcher.clone(),
Arc::new(NpmVersionResolver {
// todo(dsherret): the npm_search_api should probably be specific
// to each workspace so that the link packages can be properly
// hooked up
link_packages: Default::default(),
newest_dependency_date_options: Default::default(),
overrides: Default::default(),
trust_policy: Default::default(),
}),
&minimum_dependency_age_config(&self.config),
);
self.performance.measure(mark);
self.jsr_search_api = jsr_search_api;
self.npm_search_api = npm_search_api;
}

#[cfg_attr(feature = "lsp-tracing", tracing::instrument(skip_all))]
Expand Down Expand Up @@ -1249,6 +1283,10 @@ impl Inner {
reason,
)
.await;
// Import-specifier completions read versions through the search APIs,
// which are process-global. Rebuild them so a deno.json change (including
// `minimumDependencyAge` and its `exclude` list) takes effect.
self.rebuild_package_search_apis();
self
.client
.send_did_refresh_deno_configuration_tree_notification(
Expand Down
21 changes: 19 additions & 2 deletions cli/lsp/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ use node_resolver::ResolutionMode;
use node_resolver::cache::NodeResolutionSys;
use node_resolver::cache::NodeResolutionThreadLocalCache;
use once_cell::sync::Lazy;
use sys_traits::SystemTimeNow;

use super::cache::LspCache;
use super::documents::DocumentModule;
Expand Down Expand Up @@ -1068,11 +1069,24 @@ impl<'a> ResolverFactory<'a> {
http_client_provider.clone(),
pb.clone(),
));
let minimum_dependency_age = match self.config_data {
Some(data) => data.minimum_dependency_age_config(),
None => deno_resolver::factory::resolve_minimum_dependency_age_config(
Default::default(),
npmrc.min_release_age_days,
chrono::DateTime::<chrono::Utc>::from(sys.sys_time_now()),
),
};
let registry_info_provider = Arc::new(CliNpmRegistryInfoProvider::new(
npm_cache.clone(),
npm_client.clone(),
npmrc.clone(),
NpmPackumentFormat::Abbreviated,
NpmPackumentFormat::new(
&npmrc,
minimum_dependency_age
.age
.and_then(|date| date.into_option()),
),
));
let link_packages: WorkspaceNpmLinkPackagesRc = self
.config_data
Expand Down Expand Up @@ -1115,7 +1129,10 @@ impl<'a> ResolverFactory<'a> {
.unwrap_or_default();
let npm_version_resolver = Arc::new(NpmVersionResolver {
link_packages: link_packages.0.clone(),
newest_dependency_date_options: Default::default(),
newest_dependency_date_options:
deno_resolver::factory::npm_newest_dependency_date_options(
&minimum_dependency_age,
),
overrides: Arc::new(overrides),
trust_policy: Default::default(),
});
Expand Down
Loading
Loading