refactor: updates in preparation for supporting a minimum dependency age (#30849)
Some checks are pending
ci / pre-build (push) Waiting to run
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions

This commit is contained in:
David Sherret 2025-09-25 18:31:49 -04:00 committed by GitHub
parent ebcda43eb6
commit 3b037dd00f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 551 additions and 279 deletions

55
Cargo.lock generated
View file

@ -883,9 +883,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.37"
version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [
"num-traits",
"serde",
@ -1631,7 +1631,7 @@ dependencies = [
"deno_lint",
"deno_lockfile",
"deno_media_type",
"deno_npm",
"deno_npm 0.39.0",
"deno_npm_cache",
"deno_npm_installer",
"deno_package_json",
@ -2034,9 +2034,9 @@ dependencies = [
[[package]]
name = "deno_doc"
version = "0.183.0"
version = "0.184.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02837b4ab5233d1ef04f2c6e328006999a368f2d0398c8ecad4f2a39c0cff918"
checksum = "797807db545563a88096326f0a380dee181b21b7b8184eaac3aed5096cabcc37"
dependencies = [
"anyhow",
"cfg-if",
@ -2187,13 +2187,14 @@ dependencies = [
[[package]]
name = "deno_graph"
version = "0.100.1"
version = "0.101.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0acfb48cc2e5a63b1c3501f2243e6898fb1b4518e1d0674b3344b11631c9d0ba"
checksum = "f0419813ac1469cfbb2b987dac6870de13cdff4bea6609f70fd99b3c2bc48403"
dependencies = [
"async-trait",
"boxed_error",
"capacity_builder",
"chrono",
"data-url",
"deno_ast",
"deno_error",
@ -2334,7 +2335,7 @@ dependencies = [
"deno_fs",
"deno_media_type",
"deno_node",
"deno_npm",
"deno_npm 0.39.0",
"deno_npm_installer",
"deno_path_util",
"deno_resolver",
@ -2577,6 +2578,28 @@ dependencies = [
"url",
]
[[package]]
name = "deno_npm"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bebc7c3013545f47d93564f9de54c74d12c387a0fdc50a0113a9d2aa676d7cb"
dependencies = [
"async-trait",
"capacity_builder",
"chrono",
"deno_error",
"deno_lockfile",
"deno_semver",
"futures",
"indexmap 2.9.0",
"log",
"monch",
"serde",
"serde_json",
"thiserror 2.0.12",
"url",
]
[[package]]
name = "deno_npm_cache"
version = "0.36.0"
@ -2586,7 +2609,7 @@ dependencies = [
"boxed_error",
"deno_cache_dir",
"deno_error",
"deno_npm",
"deno_npm 0.39.0",
"deno_path_util",
"deno_semver",
"deno_unsync",
@ -2617,11 +2640,12 @@ dependencies = [
"bincode",
"boxed_error",
"capacity_builder",
"chrono",
"deno_config",
"deno_error",
"deno_graph",
"deno_lockfile",
"deno_npm",
"deno_npm 0.39.0",
"deno_npm_cache",
"deno_package_json",
"deno_path_util",
@ -2790,6 +2814,7 @@ dependencies = [
"base32",
"boxed_error",
"capacity_builder",
"chrono",
"dashmap",
"deno_ast",
"deno_cache_dir",
@ -2799,7 +2824,7 @@ dependencies = [
"deno_lockfile",
"deno_maybe_sync",
"deno_media_type",
"deno_npm",
"deno_npm 0.39.0",
"deno_package_json",
"deno_path_util",
"deno_permissions",
@ -3262,7 +3287,7 @@ dependencies = [
"deno_error",
"deno_lib",
"deno_media_type",
"deno_npm",
"deno_npm 0.39.0",
"deno_package_json",
"deno_path_util",
"deno_resolver",
@ -3947,9 +3972,9 @@ dependencies = [
[[package]]
name = "eszip"
version = "0.99.0"
version = "0.100.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0805eb66d4e61a9c815ebcae3332c3cce47ad45e3797dd71695f724f02797d74"
checksum = "9c16339a0280af1d85d4e14bdf411d4160b2c03e0418719183cc469d1feaad7f"
dependencies = [
"anyhow",
"async-trait",
@ -3957,7 +3982,7 @@ dependencies = [
"deno_ast",
"deno_error",
"deno_graph",
"deno_npm",
"deno_npm 0.38.1",
"deno_semver",
"futures",
"hashlink 0.8.4",

View file

@ -65,21 +65,21 @@ deno_ast = { version = "=0.50.0", features = ["transpiling"] }
deno_core = { version = "0.362.0" }
deno_cache_dir = "=0.25.0"
deno_doc = "=0.183.0"
deno_doc = "=0.184.0"
deno_error = "=0.7.0"
deno_graph = { version = "=0.100.1", default-features = false }
deno_graph = { version = "=0.101.0", default-features = false }
deno_lint = "=0.80.0"
deno_lockfile = "=0.31.2"
deno_media_type = { version = "=0.2.9", features = ["module_specifier"] }
deno_native_certs = "0.3.0"
deno_npm = "=0.38.1"
deno_npm = "=0.39.0"
deno_path_util = "=0.6.1"
deno_semver = "=0.9.0"
deno_task_shell = "=0.26.0"
deno_terminal = "=0.2.2"
deno_unsync = { version = "0.4.4", default-features = false }
deno_whoami = "0.1.0"
eszip = "=0.99.0"
eszip = "=0.100.0"
denokv_proto = "0.12.0"
denokv_remote = "0.12.0"

View file

@ -739,6 +739,8 @@ pub struct Flags {
pub location: Option<Url>,
pub lock: Option<String>,
pub log_level: Option<Level>,
// TODO(#30752): hook this up so users can specify it
pub minimum_dependency_age: Option<chrono::DateTime<chrono::Utc>>,
pub no_remote: bool,
pub no_lock: bool,
pub no_npm: bool,

View file

@ -1352,6 +1352,12 @@ impl CliOptions {
}
}
pub fn newest_dependency_date(
&self,
) -> Option<chrono::DateTime<chrono::Utc>> {
self.flags.minimum_dependency_age
}
pub fn unstable_npm_lazy_caching(&self) -> bool {
self.flags.unstable_config.npm_lazy_caching
|| self.workspace().has_unstable("npm-lazy-caching")

View file

@ -16,6 +16,7 @@ use deno_core::futures::FutureExt;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_error::JsErrorBox;
use deno_graph::packages::JsrVersionResolver;
use deno_lib::args::CaData;
use deno_lib::args::get_root_cert_store;
use deno_lib::args::npm_process_state;
@ -26,6 +27,7 @@ use deno_lib::worker::LibMainWorkerFactory;
use deno_lib::worker::LibMainWorkerOptions;
use deno_lib::worker::LibWorkerFactoryRoots;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::resolution::NpmVersionResolver;
use deno_npm_cache::NpmCacheSetting;
use deno_npm_installer::NpmInstallerFactoryOptions;
use deno_npm_installer::lifecycle_scripts::LifecycleScriptsExecutor;
@ -428,7 +430,11 @@ impl CliFactory {
pub fn bin_name_resolver(&self) -> Result<BinNameResolver<'_>, AnyError> {
let http_client = self.http_client_provider();
let npm_api = self.npm_installer_factory()?.registry_info_provider()?;
Ok(BinNameResolver::new(http_client, npm_api.as_ref()))
Ok(BinNameResolver::new(
http_client,
npm_api.as_ref(),
self.npm_version_resolver()?,
))
}
pub fn root_cert_store_provider(&self) -> &Arc<dyn RootCertStoreProvider> {
@ -518,6 +524,12 @@ impl CliFactory {
self.resolver_factory()?.in_npm_package_checker()
}
pub fn jsr_version_resolver(
&self,
) -> Result<&Arc<JsrVersionResolver>, AnyError> {
self.resolver_factory()?.jsr_version_resolver()
}
pub fn npm_cache(&self) -> Result<&Arc<CliNpmCache>, AnyError> {
self.npm_installer_factory()?.npm_cache()
}
@ -588,6 +600,12 @@ impl CliFactory {
})
}
pub fn npm_version_resolver(
&self,
) -> Result<&Arc<NpmVersionResolver>, AnyError> {
self.resolver_factory()?.npm_version_resolver()
}
pub fn install_reporter(
&self,
) -> Result<Option<&Arc<crate::tools::installer::InstallReporter>>, AnyError>
@ -769,6 +787,7 @@ impl CliFactory {
self.file_fetcher()?.clone(),
self.global_http_cache()?.clone(),
self.in_npm_pkg_checker()?.clone(),
self.jsr_version_resolver()?.clone(),
self.maybe_lockfile().await?.cloned(),
self.graph_reporter()?.clone(),
self.module_info_cache()?.clone(),
@ -1146,6 +1165,7 @@ impl CliFactory {
} else {
IsCjsResolutionMode::Disabled
},
newest_dependency_date: options.newest_dependency_date(),
node_analysis_cache: Some(node_analysis_cache),
node_resolver_options: NodeResolverOptions {
conditions: NodeConditionOptions {
@ -1194,6 +1214,7 @@ impl CliFactory {
.clone(),
})),
bare_node_builtins: options.unstable_bare_node_builtins(),
types_node_version_req: Some(crate::npm::get_types_node_version_req()),
unstable_sloppy_imports: options.unstable_sloppy_imports(),
on_mapped_resolution_diagnostic: Some(Arc::new(
on_resolve_diagnostic,

View file

@ -1,5 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::borrow::Cow;
use std::collections::HashSet;
use std::path::PathBuf;
use std::sync::Arc;
@ -25,6 +26,7 @@ use deno_graph::ModuleLoadError;
use deno_graph::ResolutionError;
use deno_graph::SpecifierError;
use deno_graph::WorkspaceFastCheckOption;
use deno_graph::packages::JsrVersionResolver;
use deno_graph::source::Loader;
use deno_graph::source::ResolveError;
use deno_lib::util::result::downcast_ref_deno_resolve_error;
@ -655,6 +657,7 @@ pub struct ModuleGraphBuilder {
file_fetcher: Arc<CliFileFetcher>,
global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
jsr_version_resolver: Arc<JsrVersionResolver>,
lockfile: Option<Arc<CliLockfile>>,
maybe_reporter: Option<Arc<dyn deno_graph::source::Reporter>>,
module_info_cache: Arc<ModuleInfoCache>,
@ -679,6 +682,7 @@ impl ModuleGraphBuilder {
file_fetcher: Arc<CliFileFetcher>,
global_http_cache: Arc<GlobalHttpCache>,
in_npm_pkg_checker: DenoInNpmPackageChecker,
jsr_version_resolver: Arc<JsrVersionResolver>,
lockfile: Option<Arc<CliLockfile>>,
maybe_reporter: Option<Arc<dyn deno_graph::source::Reporter>>,
module_info_cache: Arc<ModuleInfoCache>,
@ -700,6 +704,7 @@ impl ModuleGraphBuilder {
file_fetcher,
global_http_cache,
in_npm_pkg_checker,
jsr_version_resolver,
lockfile,
maybe_reporter,
module_info_cache,
@ -765,7 +770,11 @@ impl ModuleGraphBuilder {
passthrough_jsr_specifiers: false,
executor: Default::default(),
file_system: &self.sys,
jsr_metadata_store: None,
jsr_url_provider: &CliJsrUrlProvider,
jsr_version_resolver: Cow::Borrowed(
self.jsr_version_resolver.as_ref(),
),
npm_resolver: Some(self.npm_graph_resolver.as_ref()),
module_analyzer: &analyzer,
module_info_cacher: self.module_info_cache.as_ref(),
@ -774,7 +783,6 @@ impl ModuleGraphBuilder {
locker: locker.as_mut().map(|l| l as _),
unstable_bytes_imports: self.cli_options.unstable_raw_imports(),
unstable_text_imports: self.cli_options.unstable_raw_imports(),
jsr_metadata_store: None,
},
options.npm_caching,
)

View file

@ -4,10 +4,10 @@ use std::sync::Arc;
use dashmap::DashMap;
use deno_core::serde_json;
use deno_graph::JsrPackageReqNotFoundError;
use deno_graph::packages::JsrPackageInfo;
use deno_graph::packages::JsrPackageInfoVersion;
use deno_graph::packages::JsrPackageVersionInfo;
use deno_semver::Version;
use deno_graph::packages::JsrVersionResolver;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
@ -24,68 +24,63 @@ pub struct JsrFetchResolver {
info_by_nv: DashMap<PackageNv, Option<Arc<JsrPackageVersionInfo>>>,
info_by_name: DashMap<String, Option<Arc<JsrPackageInfo>>>,
file_fetcher: Arc<CliFileFetcher>,
}
fn select_version<'a, I>(versions: I, req: &PackageReq) -> Option<Version>
where
I: IntoIterator<Item = (&'a Version, &'a JsrPackageInfoVersion)>,
{
let mut versions = versions.into_iter().collect::<Vec<_>>();
versions.sort_by_key(|(v, _)| *v);
versions
.into_iter()
.rev()
.find(|(v, i)| {
!i.yanked && req.version_req.tag().is_none() && req.version_req.matches(v)
})
.map(|(v, _)| v.clone())
jsr_version_resolver: Arc<JsrVersionResolver>,
}
impl JsrFetchResolver {
pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
pub fn new(
file_fetcher: Arc<CliFileFetcher>,
jsr_version_resolver: Arc<JsrVersionResolver>,
) -> Self {
Self {
nv_by_req: Default::default(),
info_by_nv: Default::default(),
info_by_name: Default::default(),
file_fetcher,
jsr_version_resolver,
}
}
pub async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> {
pub async fn req_to_nv(
&self,
req: &PackageReq,
) -> Result<Option<PackageNv>, JsrPackageReqNotFoundError> {
if let Some(nv) = self.nv_by_req.get(req) {
return nv.value().clone();
return Ok(nv.value().clone());
}
let maybe_get_nv = || async {
let name = req.name.clone();
let package_info = self.package_info(&name).await;
if package_info.is_none() {
let Some(package_info) = package_info else {
log::debug!("no package info found for jsr:{name}");
return None;
}
let package_info = package_info?;
// Find the first matching version of the package.
let version = select_version(&package_info.versions, req);
let version = if let Some(version) = version {
version
} else {
let info = self.force_refresh_package_info(&name).await;
let Some(info) = info else {
log::debug!("no package info found for jsr:{name}");
return None;
};
let version = select_version(&info.versions, req);
let Some(version) = version else {
log::debug!("no matching version found for jsr:{req}");
return None;
};
version
return Ok(None);
};
Some(PackageNv { name, version })
// Find the first matching version of the package.
let version = self.jsr_version_resolver.resolve_version(
req,
&package_info,
Vec::new().into_iter(),
);
let version = if let Ok(version) = version {
version.version.clone()
} else {
let package_info = self.force_refresh_package_info(&name).await;
let Some(package_info) = package_info else {
log::debug!("no package info found for jsr:{name}");
return Ok(None);
};
self
.jsr_version_resolver
.resolve_version(req, &package_info, Vec::new().into_iter())?
.version
.clone()
};
Ok(Some(PackageNv { name, version }))
};
let nv = maybe_get_nv().await;
let nv = maybe_get_nv().await?;
self.nv_by_req.insert(req.clone(), nv.clone());
nv
Ok(nv)
}
pub async fn force_refresh_package_info(
@ -119,6 +114,8 @@ impl JsrFetchResolver {
jsr_url().join(&format!("{}/meta.json", name)).ok()
}
// todo(dsherret): this should return error messages and only `None` when the package
// doesn't exist
pub async fn package_info(&self, name: &str) -> Option<Arc<JsrPackageInfo>> {
if let Some(info) = self.info_by_name.get(name) {
return info.value().clone();

View file

@ -532,7 +532,7 @@ async fn get_jsr_completions(
let export_prefix = sub_path.unwrap_or("");
let req = req_ref.req();
let nv = match jsr_resolver {
Some(jsr_resolver) => jsr_resolver.req_to_nv(req).await,
Some(jsr_resolver) => jsr_resolver.req_to_nv(req).await.ok().flatten(),
None => None,
};
let nv = nv.or_else(|| PackageNv::from_str(&req.to_string()).ok())?;

View file

@ -1452,8 +1452,13 @@ impl ConfigData {
ResolverFactoryOptions {
// these default options are fine because we don't use this for
// anything other than resolving the lockfile at the moment
allow_json_imports:
deno_resolver::loader::AllowJsonImports::WithAttribute,
bare_node_builtins: false,
compiler_options_overrides: Default::default(),
is_cjs_resolution_mode: Default::default(),
on_mapped_resolution_diagnostic: None,
newest_dependency_date: None,
npm_system_info: Default::default(),
node_code_translator_mode: Default::default(),
node_resolver_options: NodeResolverOptions::default(),
@ -1462,11 +1467,8 @@ impl ConfigData {
package_json_cache: None,
package_json_dep_resolution: None,
specified_import_map: None,
bare_node_builtins: false,
types_node_version_req: Some(crate::npm::get_types_node_version_req()),
unstable_sloppy_imports: false,
on_mapped_resolution_diagnostic: None,
allow_json_imports:
deno_resolver::loader::AllowJsonImports::WithAttribute,
},
);
let pb = ProgressBar::new(ProgressBarStyle::TextOnly);

View file

@ -13,6 +13,7 @@ use deno_graph::ModuleSpecifier;
use deno_graph::packages::JsrPackageInfo;
use deno_graph::packages::JsrPackageInfoVersion;
use deno_graph::packages::JsrPackageVersionInfo;
use deno_graph::packages::JsrVersionResolver;
use deno_resolver::workspace::WorkspaceResolver;
use deno_semver::StackString;
use deno_semver::Version;
@ -88,7 +89,10 @@ impl JsrCacheResolver {
Some(Arc::new(JsrPackageInfo {
versions: [(
nv.version.clone(),
JsrPackageInfoVersion { yanked: false },
JsrPackageInfoVersion {
yanked: false,
created_at: None,
},
)]
.into_iter()
.collect(),
@ -323,7 +327,13 @@ pub struct CliJsrSearchApi {
impl CliJsrSearchApi {
pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
let resolver = JsrFetchResolver::new(file_fetcher.clone());
let resolver = JsrFetchResolver::new(
file_fetcher.clone(),
Arc::new(JsrVersionResolver {
// not currently supported in the lsp
newest_dependency_date: None,
}),
);
Self {
file_fetcher,
resolver,

View file

@ -34,6 +34,7 @@ use deno_graph::Resolution;
use deno_lib::args::CaData;
use deno_lib::args::get_root_cert_store;
use deno_lib::version::DENO_VERSION_INFO;
use deno_npm::resolution::NpmVersionResolver;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_path_util::url_to_file_path;
use deno_resolver::deno_json::CompilerOptionsKey;
@ -115,6 +116,7 @@ use crate::lsp::diagnostics::generate_module_diagnostics;
use crate::lsp::lint::LspLinterResolver;
use crate::lsp::logging::init_log_file;
use crate::lsp::tsc::file_text_changes_to_workspace_edit;
use crate::npm::get_types_node_version_req;
use crate::sys::CliSys;
use crate::tools::fmt::format_file;
use crate::tools::fmt::format_parsed_source;
@ -589,8 +591,14 @@ impl Inner {
);
let jsr_search_api =
CliJsrSearchApi::new(module_registry.file_fetcher.clone());
let npm_search_api =
CliNpmSearchApi::new(module_registry.file_fetcher.clone());
let npm_search_api = CliNpmSearchApi::new(
module_registry.file_fetcher.clone(),
Arc::new(NpmVersionResolver {
types_node_version_req: Some(get_types_node_version_req()),
link_packages: Default::default(),
newest_dependency_date: None,
}),
);
let config = Config::default();
let ts_server = Arc::new(TsServer::new(performance.clone()));
let initial_cwd = std::env::current_dir().unwrap_or_else(|_| {
@ -839,8 +847,17 @@ impl Inner {
}
self.jsr_search_api =
CliJsrSearchApi::new(self.module_registry.file_fetcher.clone());
self.npm_search_api =
CliNpmSearchApi::new(self.module_registry.file_fetcher.clone());
self.npm_search_api = CliNpmSearchApi::new(
self.module_registry.file_fetcher.clone(),
Arc::new(NpmVersionResolver {
types_node_version_req: Some(get_types_node_version_req()),
// 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: None,
}),
);
self.performance.measure(mark);
}

View file

@ -8,6 +8,7 @@ use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_core::url::Url;
use deno_npm::npm_rc::NpmRc;
use deno_npm::resolution::NpmVersionResolver;
use deno_semver::Version;
use deno_semver::package::PackageNv;
use once_cell::sync::Lazy;
@ -28,10 +29,14 @@ pub struct CliNpmSearchApi {
}
impl CliNpmSearchApi {
pub fn new(file_fetcher: Arc<CliFileFetcher>) -> Self {
pub fn new(
file_fetcher: Arc<CliFileFetcher>,
npm_version_resolver: Arc<NpmVersionResolver>,
) -> Self {
let resolver = NpmFetchResolver::new(
file_fetcher.clone(),
Arc::new(NpmRc::default().as_resolved(npm_registry_url()).unwrap()),
npm_version_resolver,
);
Self {
file_fetcher,
@ -78,7 +83,12 @@ impl PackageSearchApi for CliNpmSearchApi {
.package_info(name)
.await
.ok_or_else(|| anyhow!("npm package info not found: {}", name))?;
let mut versions = info.versions.keys().cloned().collect::<Vec<_>>();
let mut versions = self
.resolver
.applicable_version_infos(&info)
.map(|vi| &vi.version)
.cloned()
.collect::<Vec<_>>();
versions.sort();
versions.reverse();
let versions = Arc::new(versions);

View file

@ -17,6 +17,7 @@ use deno_error::JsErrorBox;
use deno_graph::ModuleSpecifier;
use deno_graph::Range;
use deno_npm::NpmSystemInfo;
use deno_npm::resolution::NpmVersionResolver;
use deno_npm_cache::TarballCache;
use deno_npm_installer::LifecycleScriptsConfig;
use deno_npm_installer::initializer::NpmResolutionInitializer;
@ -42,7 +43,7 @@ use deno_resolver::workspace::CreateResolverOptions;
use deno_resolver::workspace::FsCacheOptions;
use deno_resolver::workspace::PackageJsonDepResolution;
use deno_resolver::workspace::SloppyImportsOptions;
use deno_resolver::workspace::WorkspaceNpmLinkPackages;
use deno_resolver::workspace::WorkspaceNpmLinkPackagesRc;
use deno_resolver::workspace::WorkspaceResolver;
use deno_runtime::tokio_util::create_basic_runtime;
use deno_semver::jsr::JsrPackageReqReference;
@ -79,6 +80,7 @@ use crate::npm::CliNpmInstaller;
use crate::npm::CliNpmRegistryInfoProvider;
use crate::npm::CliNpmResolver;
use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::get_types_node_version_req;
use crate::resolver::CliIsCjsResolver;
use crate::resolver::CliNpmReqResolver;
use crate::resolver::CliResolver;
@ -918,14 +920,12 @@ impl<'a> ResolverFactory<'a> {
npm_client.clone(),
npmrc.clone(),
));
let link_packages: Arc<WorkspaceNpmLinkPackages> = self
let link_packages: WorkspaceNpmLinkPackagesRc = self
.config_data
.as_ref()
.filter(|c| c.node_modules_dir.is_some()) // requires a node_modules dir
.map(|d| {
Arc::new(WorkspaceNpmLinkPackages::from_workspace(
&d.member_dir.workspace,
))
WorkspaceNpmLinkPackagesRc::from_workspace(&d.member_dir.workspace)
})
.unwrap_or_default();
let npm_resolution_initializer = Arc::new(NpmResolutionInitializer::new(
@ -952,12 +952,17 @@ impl<'a> ResolverFactory<'a> {
npmrc.clone(),
None,
));
let npm_version_resolver = Arc::new(NpmVersionResolver {
types_node_version_req: Some(get_types_node_version_req()),
link_packages: link_packages.0.clone(),
newest_dependency_date: None,
});
let npm_resolution_installer = Arc::new(NpmResolutionInstaller::new(
npm_version_resolver,
registry_info_provider.clone(),
None,
self.services.npm_resolution.clone(),
maybe_lockfile.clone(),
link_packages.clone(),
None,
));
let npm_installer = Arc::new(CliNpmInstaller::new(
Arc::new(NullLifecycleScriptsExecutor),

View file

@ -15,7 +15,9 @@ use deno_lib::version::DENO_VERSION_INFO;
use deno_npm::NpmResolutionPackage;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmPackageInfo;
use deno_npm::registry::NpmPackageVersionInfosIterator;
use deno_npm::resolution::NpmResolutionSnapshot;
use deno_npm::resolution::NpmVersionResolver;
use deno_npm_cache::NpmCacheHttpClientBytesResponse;
use deno_npm_cache::NpmCacheHttpClientResponse;
use deno_npm_installer::BinEntries;
@ -29,7 +31,6 @@ use deno_npm_installer::lifecycle_scripts::is_broken_default_install_script;
use deno_resolver::npm::ByonmNpmResolverCreateOptions;
use deno_resolver::npm::ManagedNpmResolverRc;
use deno_runtime::deno_io::FromRawIoHandle;
use deno_semver::Version;
use deno_semver::VersionReq;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
@ -159,35 +160,50 @@ pub struct NpmFetchResolver {
info_by_name: DashMap<String, Option<Arc<NpmPackageInfo>>>,
file_fetcher: Arc<CliFileFetcher>,
npmrc: Arc<ResolvedNpmRc>,
version_resolver: Arc<NpmVersionResolver>,
}
impl NpmFetchResolver {
pub fn new(
file_fetcher: Arc<CliFileFetcher>,
npmrc: Arc<ResolvedNpmRc>,
version_resolver: Arc<NpmVersionResolver>,
) -> Self {
Self {
nv_by_req: Default::default(),
info_by_name: Default::default(),
file_fetcher,
npmrc,
version_resolver,
}
}
pub async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> {
pub async fn req_to_nv(
&self,
req: &PackageReq,
) -> Result<Option<PackageNv>, AnyError> {
if let Some(nv) = self.nv_by_req.get(req) {
return nv.value().clone();
return Ok(nv.value().clone());
}
let maybe_get_nv = || async {
let name = req.name.clone();
let package_info = self.package_info(&name).await?;
let version =
version_from_package_info(&package_info, &req.version_req)?.clone();
Some(PackageNv { name, version })
let name = &req.name;
let Some(package_info) = self.package_info(name).await else {
return Result::<Option<PackageNv>, AnyError>::Ok(None);
};
let version_info =
self.version_resolver.resolve_best_package_version_info(
&req.version_req,
&package_info,
Vec::new().into_iter(),
)?;
Ok(Some(PackageNv {
name: name.clone(),
version: version_info.version.clone(),
}))
};
let nv = maybe_get_nv().await;
let nv = maybe_get_nv().await?;
self.nv_by_req.insert(req.clone(), nv.clone());
nv
Ok(nv)
}
pub async fn package_info(&self, name: &str) -> Option<Arc<NpmPackageInfo>> {
@ -223,22 +239,13 @@ impl NpmFetchResolver {
self.info_by_name.insert(name.to_string(), info.clone());
info
}
}
pub fn version_from_package_info<'a>(
package_info: &'a NpmPackageInfo,
version_req: &VersionReq,
) -> Option<&'a Version> {
if let Some(dist_tag) = version_req.tag() {
return package_info.dist_tags.get(dist_tag);
pub fn applicable_version_infos<'a>(
&'a self,
package_info: &'a NpmPackageInfo,
) -> NpmPackageVersionInfosIterator<'a> {
self.version_resolver.applicable_version_infos(package_info)
}
// Find the first matching version of the package.
let mut versions = package_info.versions.keys().collect::<Vec<_>>();
versions.sort();
versions
.into_iter()
.rev()
.find(|v| version_req.tag().is_none() && version_req.matches(v))
}
pub static NPM_CONFIG_USER_AGENT_ENV_VAR: &str = "npm_config_user_agent";
@ -573,3 +580,9 @@ impl DenoTaskLifeCycleScriptsExecutor {
.await
}
}
pub fn get_types_node_version_req() -> VersionReq {
// WARNING: When bumping this version, check if anything needs to be
// updated in the `setNodeOnlyGlobalNames` call in 99_main_compiler.js
VersionReq::parse_from_npm("24.0.4 - 24.2.0").unwrap()
}

View file

@ -9,7 +9,7 @@ use deno_core::error::AnyError;
use deno_npm::npm_rc::ResolvedNpmRc;
use deno_npm::registry::NpmRegistryApi;
use deno_npm_cache::TarballCache;
use deno_resolver::workspace::WorkspaceNpmLinkPackages;
use deno_resolver::workspace::WorkspaceNpmLinkPackagesRc;
use deno_semver::package::PackageNv;
use crate::cache::DenoDir;
@ -40,7 +40,7 @@ pub async fn ensure_esbuild(
deno_dir: &DenoDir,
npmrc: &ResolvedNpmRc,
api: &Arc<CliNpmRegistryInfoProvider>,
workspace_link_packages: &Arc<WorkspaceNpmLinkPackages>,
workspace_link_packages: &WorkspaceNpmLinkPackagesRc,
tarball_cache: &Arc<TarballCache<CliNpmCacheHttpClient, CliSys>>,
npm_cache: &CliNpmCache,
) -> Result<PathBuf, AnyError> {

View file

@ -483,6 +483,7 @@ fn get_os_specific_filepath(
#[cfg(test)]
mod test {
use deno_npm::registry::TestNpmRegistryApi;
use deno_npm::resolution::NpmVersionResolver;
pub use super::*;
use crate::http_util::HttpClientProvider;
@ -491,7 +492,9 @@ mod test {
async fn resolve_compile_executable_output_path_target_linux() {
let http_client = HttpClientProvider::new(None, None);
let npm_api = TestNpmRegistryApi::default();
let bin_name_resolver = BinNameResolver::new(&http_client, &npm_api);
let npm_version_resolver = NpmVersionResolver::default();
let bin_name_resolver =
BinNameResolver::new(&http_client, &npm_api, &npm_version_resolver);
let path = resolve_compile_executable_output_path(
&bin_name_resolver,
&CompileFlags {
@ -520,7 +523,9 @@ mod test {
async fn resolve_compile_executable_output_path_target_windows() {
let http_client = HttpClientProvider::new(None, None);
let npm_api = TestNpmRegistryApi::default();
let bin_name_resolver = BinNameResolver::new(&http_client, &npm_api);
let npm_version_resolver = NpmVersionResolver::default();
let bin_name_resolver =
BinNameResolver::new(&http_client, &npm_api, &npm_version_resolver);
let path = resolve_compile_executable_output_path(
&bin_name_resolver,
&CompileFlags {

View file

@ -79,7 +79,9 @@ async fn generate_doc_nodes_for_builtin_types(
passthrough_jsr_specifiers: false,
executor: Default::default(),
file_system: &NullFileSystem,
jsr_metadata_store: None,
jsr_url_provider: Default::default(),
jsr_version_resolver: Default::default(),
locker: None,
module_analyzer: analyzer,
module_info_cacher: Default::default(),
@ -88,7 +90,6 @@ async fn generate_doc_nodes_for_builtin_types(
resolver: None,
unstable_bytes_imports: false,
unstable_text_imports: false,
jsr_metadata_store: None,
},
)
.await;

View file

@ -6,6 +6,7 @@ use deno_core::error::AnyError;
use deno_core::url::Url;
use deno_npm::registry::NpmPackageInfo;
use deno_npm::registry::NpmRegistryApi;
use deno_npm::resolution::NpmVersionResolver;
use deno_semver::npm::NpmPackageReqReference;
use crate::http_util::HttpClientProvider;
@ -13,16 +14,19 @@ use crate::http_util::HttpClientProvider;
pub struct BinNameResolver<'a> {
http_client_provider: &'a HttpClientProvider,
npm_registry_api: &'a dyn NpmRegistryApi,
npm_version_resolver: &'a NpmVersionResolver,
}
impl<'a> BinNameResolver<'a> {
pub fn new(
http_client_provider: &'a HttpClientProvider,
npm_registry_api: &'a dyn NpmRegistryApi,
npm_version_resolver: &'a NpmVersionResolver,
) -> Self {
Self {
http_client_provider,
npm_registry_api,
npm_version_resolver,
}
}
@ -121,11 +125,14 @@ impl<'a> BinNameResolver<'a> {
package_info: &NpmPackageInfo,
npm_ref: &NpmPackageReqReference,
) -> Option<String> {
let version = crate::npm::version_from_package_info(
package_info,
&npm_ref.req().version_req,
)?;
let version_info = package_info.versions.get(version)?;
let version_info = self
.npm_version_resolver
.resolve_best_package_version_info(
&npm_ref.req().version_req,
package_info,
Vec::new().into_iter(),
)
.ok()?;
let bin_entries = version_info.bin.as_ref()?;
match bin_entries {
deno_npm::registry::NpmPackageVersionBinEntry::String(_) => {}
@ -145,6 +152,7 @@ mod test {
use deno_core::url::Url;
use deno_npm::registry::TestNpmRegistryApi;
use deno_npm::resolution::NpmVersionResolver;
use super::BinNameResolver;
use crate::http_util::HttpClientProvider;
@ -158,7 +166,9 @@ mod test {
HashMap::from([("gemini".to_string(), "./bin.js".to_string())]),
))
});
let resolver = BinNameResolver::new(&http_client, &registry_api);
let npm_version_resolver = NpmVersionResolver::default();
let resolver =
BinNameResolver::new(&http_client, &registry_api, &npm_version_resolver);
resolver.infer_name_from_url(url).await
}

View file

@ -787,10 +787,14 @@ async fn install_global(
let npmrc = factory.npmrc()?;
let deps_file_fetcher = Arc::new(deps_file_fetcher);
let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone()));
let jsr_resolver = Arc::new(JsrFetchResolver::new(
deps_file_fetcher.clone(),
factory.jsr_version_resolver()?.clone(),
));
let npm_resolver = Arc::new(NpmFetchResolver::new(
deps_file_fetcher.clone(),
npmrc.clone(),
factory.npm_version_resolver()?.clone(),
));
let entry_text = install_flags_global.module_url.as_str();
@ -799,12 +803,24 @@ async fn install_global(
if let Ok(Err(package_req)) =
super::pm::AddRmPackageReq::parse(entry_text, None)
{
if jsr_resolver.req_to_nv(&package_req).await.is_some() {
if jsr_resolver
.req_to_nv(&package_req)
.await
.ok()
.flatten()
.is_some()
{
bail!(
"{entry_text} is missing a prefix. Did you mean `{}`?",
crate::colors::yellow(format!("deno install -g jsr:{package_req}"))
);
} else if npm_resolver.req_to_nv(&package_req).await.is_some() {
} else if npm_resolver
.req_to_nv(&package_req)
.await
.ok()
.flatten()
.is_some()
{
bail!(
"{entry_text} is missing a prefix. Did you mean `{}`?",
crate::colors::yellow(format!("deno install -g npm:{package_req}"))
@ -1116,6 +1132,7 @@ mod tests {
use std::process::Command;
use deno_lib::args::UnstableConfig;
use deno_npm::resolution::NpmVersionResolver;
use test_util::TempDir;
use test_util::testdata_path;
@ -1133,7 +1150,9 @@ mod tests {
let cwd = std::env::current_dir().unwrap();
let http_client = HttpClientProvider::new(None, None);
let registry_api = deno_npm::registry::TestNpmRegistryApi::default();
let resolver = BinNameResolver::new(&http_client, &registry_api);
let npm_version_resolver = NpmVersionResolver::default();
let resolver =
BinNameResolver::new(&http_client, &registry_api, &npm_version_resolver);
super::create_install_shim(&resolver, &cwd, flags, install_flags_global)
.await
}
@ -1145,7 +1164,9 @@ mod tests {
let cwd = std::env::current_dir().unwrap();
let http_client = HttpClientProvider::new(None, None);
let registry_api = deno_npm::registry::TestNpmRegistryApi::default();
let resolver = BinNameResolver::new(&http_client, &registry_api);
let npm_version_resolver = NpmVersionResolver::default();
let resolver =
BinNameResolver::new(&http_client, &registry_api, &npm_version_resolver);
super::resolve_shim_data(&resolver, &cwd, flags, install_flags_global).await
}

View file

@ -8,6 +8,9 @@ use std::sync::Arc;
use deno_core::error::AnyError;
use deno_core::futures::StreamExt;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::url::Url;
use deno_graph::JsrPackageReqNotFoundError;
use deno_graph::packages::JsrPackageVersionInfo;
use deno_npm_installer::PackageCaching;
use deno_npm_installer::graph::NpmCachingStrategy;
use deno_semver::Version;
@ -45,6 +48,7 @@ pub async fn cache_top_level_deps(
} else {
Arc::new(crate::jsr::JsrFetchResolver::new(
factory.file_fetcher()?.clone(),
factory.jsr_version_resolver()?.clone(),
))
};
let mut graph_permit = factory
@ -128,15 +132,22 @@ pub async fn cache_top_level_deps(
let jsr_resolver = jsr_resolver.clone();
info_futures.push(async move {
let nv = if let Some(req) = resolved_req {
Cow::Borrowed(req)
let nv = if let Some(nv) = resolved_req {
Cow::Borrowed(nv)
} else if let Some(nv) =
jsr_resolver.req_to_nv(req_ref.req()).await?
{
Cow::Owned(nv)
} else {
Cow::Owned(jsr_resolver.req_to_nv(req_ref.req()).await?)
return Result::<
Option<(Url, Arc<JsrPackageVersionInfo>)>,
JsrPackageReqNotFoundError,
>::Ok(None);
};
if let Some(info) = jsr_resolver.package_version_info(&nv).await {
return Some((specifier.clone(), info));
return Ok(Some((specifier.clone(), info)));
}
None
Ok(None)
});
}
"npm" => {
@ -176,7 +187,7 @@ pub async fn cache_top_level_deps(
}
while let Some(info_future) = info_futures.next().await {
if let Some((specifier, info)) = info_future {
if let Some((specifier, info)) = info_future? {
let exports = info.exports();
for (k, _) in exports {
if let Ok(spec) = specifier.join(k) {

View file

@ -19,7 +19,10 @@ use deno_core::futures::future::try_join;
use deno_core::futures::stream::FuturesOrdered;
use deno_core::futures::stream::FuturesUnordered;
use deno_core::serde_json;
use deno_npm::registry::NpmPackageInfo;
use deno_core::url::Url;
use deno_graph::JsrPackageReqNotFoundError;
use deno_graph::packages::JsrPackageVersionInfo;
use deno_npm::resolution::NpmVersionResolver;
use deno_package_json::PackageJsonDepsMap;
use deno_package_json::PackageJsonRc;
use deno_runtime::deno_permissions::PermissionsContainer;
@ -464,6 +467,7 @@ pub struct DepManager {
pub(crate) jsr_fetch_resolver: Arc<JsrFetchResolver>,
pub(crate) npm_fetch_resolver: Arc<NpmFetchResolver>,
npm_resolver: CliNpmResolver,
npm_version_resolver: Arc<NpmVersionResolver>,
npm_installer: Arc<CliNpmInstaller>,
permissions_container: PermissionsContainer,
progress_bar: ProgressBar,
@ -477,6 +481,7 @@ pub struct DepManagerArgs {
pub npm_fetch_resolver: Arc<NpmFetchResolver>,
pub npm_installer: Arc<CliNpmInstaller>,
pub npm_resolver: CliNpmResolver,
pub npm_version_resolver: Arc<NpmVersionResolver>,
pub permissions_container: PermissionsContainer,
pub progress_bar: ProgressBar,
pub main_module_graph_container: Arc<MainModuleGraphContainer>,
@ -497,6 +502,7 @@ impl DepManager {
npm_fetch_resolver,
npm_installer,
npm_resolver,
npm_version_resolver,
progress_bar,
permissions_container,
main_module_graph_container,
@ -512,6 +518,7 @@ impl DepManager {
npm_fetch_resolver,
npm_installer,
npm_resolver,
npm_version_resolver,
progress_bar,
permissions_container,
main_module_graph_container,
@ -610,8 +617,15 @@ impl DepManager {
info_futures.push(async {
let nv = if let Some(nv) = resolved_nv {
nv
} else {
} else if let Some(nv) =
self.jsr_fetch_resolver.req_to_nv(&dep.req).await?
{
nv
} else {
return Result::<
Option<(Url, Arc<JsrPackageVersionInfo>)>,
JsrPackageReqNotFoundError,
>::Ok(None);
};
if let Some(info) =
self.jsr_fetch_resolver.package_version_info(&nv).await
@ -619,9 +633,9 @@ impl DepManager {
let specifier =
ModuleSpecifier::parse(&format!("jsr:/{}/", &dep.req))
.unwrap();
return Some((specifier, info));
return Ok(Some((specifier, info)));
}
None
Ok(None)
});
}
}
@ -629,7 +643,7 @@ impl DepManager {
}
while let Some(info_future) = info_futures.next().await {
if let Some((specifier, info)) = info_future {
if let Some((specifier, info)) = info_future? {
let exports = info.exports();
for (k, _) in exports {
if let Ok(spec) = specifier.join(k) {
@ -715,20 +729,26 @@ impl DepManager {
async {
let semver_req = &dep.req;
let _permit = npm_sema.acquire().await;
let mut semver_compatible =
self.npm_fetch_resolver.req_to_nv(semver_req).await;
let mut semver_compatible = self
.npm_fetch_resolver
.req_to_nv(semver_req)
.await
.ok()
.flatten();
let info =
self.npm_fetch_resolver.package_info(&semver_req.name).await;
let latest = info
.and_then(|info| {
let latest_tag = info.dist_tags.get("latest")?;
// see https://github.com/denoland/deno_npm/blob/722fbecb5bdbd93241e5fc774cc1deaebd40365b/src/resolution/common.rs#L117-L125
let can_use_latest = npm_version_satisfies(
latest_tag,
&semver_req.version_req,
&info,
);
let can_use_latest = self
.npm_version_resolver
.version_req_satisfies_and_matches_newest_dependency_date(
&semver_req.version_req,
latest_tag,
&info,
)
.ok()?;
if can_use_latest {
semver_compatible = Some(PackageNv {
@ -744,15 +764,16 @@ impl DepManager {
} else {
latest_version(
Some(latest_tag),
info.versions.iter().filter_map(
|(version, version_info)| {
self
.npm_version_resolver
.applicable_version_infos(&info)
.filter_map(|version_info| {
if version_info.deprecated.is_none() {
Some(version)
Some(&version_info.version)
} else {
None
}
},
),
}),
)
}
})
@ -771,8 +792,12 @@ impl DepManager {
async {
let semver_req = &dep.req;
let _permit = jsr_sema.acquire().await;
let semver_compatible =
self.jsr_fetch_resolver.req_to_nv(semver_req).await;
let semver_compatible = self
.jsr_fetch_resolver
.req_to_nv(semver_req)
.await
.ok()
.flatten();
let info =
self.jsr_fetch_resolver.package_info(&semver_req.name).await;
let latest = info
@ -947,17 +972,6 @@ impl DepManager {
}
}
fn npm_version_satisfies(
version: &Version,
version_req: &VersionReq,
npm_info: &NpmPackageInfo,
) -> bool {
if let Some(tag) = version_req.tag() {
return npm_info.dist_tags.get(tag) == Some(version);
}
version_req.matches(version)
}
fn get_or_create_updater<'a>(
config_updaters: &'a mut HashMap<std::path::PathBuf, ConfigUpdater>,
location: &DepLocation,

View file

@ -14,9 +14,9 @@ use deno_core::futures::StreamExt;
use deno_path_util::url_to_file_path;
use deno_semver::StackString;
use deno_semver::Version;
use deno_semver::VersionReq;
use deno_semver::jsr::JsrPackageReqReference;
use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageName;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
use deps::KeyPath;
@ -438,9 +438,15 @@ pub async fn add(
let npmrc = cli_factory.npmrc()?;
let deps_file_fetcher = Arc::new(deps_file_fetcher);
let jsr_resolver = Arc::new(JsrFetchResolver::new(deps_file_fetcher.clone()));
let npm_resolver =
Arc::new(NpmFetchResolver::new(deps_file_fetcher, npmrc.clone()));
let jsr_resolver = Arc::new(JsrFetchResolver::new(
deps_file_fetcher.clone(),
cli_factory.jsr_version_resolver()?.clone(),
));
let npm_resolver = Arc::new(NpmFetchResolver::new(
deps_file_fetcher,
npmrc.clone(),
cli_factory.npm_version_resolver()?.clone(),
));
let mut selected_packages = Vec::with_capacity(add_flags.packages.len());
let mut package_reqs = Vec::with_capacity(add_flags.packages.len());
@ -455,12 +461,24 @@ pub async fn add(
match req {
Ok(add_req) => package_reqs.push(add_req),
Err(package_req) => {
if jsr_resolver.req_to_nv(&package_req).await.is_some() {
if jsr_resolver
.req_to_nv(&package_req)
.await
.ok()
.flatten()
.is_some()
{
bail!(
"{entry_text} is missing a prefix. Did you mean `{}`?",
crate::colors::yellow(format!("deno {cmd_name} jsr:{package_req}"))
)
} else if npm_resolver.req_to_nv(&package_req).await.is_some() {
} else if npm_resolver
.req_to_nv(&package_req)
.await
.ok()
.flatten()
.is_some()
{
bail!(
"{entry_text} is missing a prefix. Did you mean `{}`?",
crate::colors::yellow(format!("deno {cmd_name} npm:{package_req}"))
@ -609,19 +627,25 @@ trait PackageInfoProvider {
const SPECIFIER_PREFIX: &str;
/// The help to return if a package is found by this provider
const HELP: NotFoundHelp;
async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv>;
async fn latest_version(&self, req: &PackageReq) -> Option<Version>;
async fn req_to_nv(
&self,
req: &PackageReq,
) -> Result<Option<PackageNv>, AnyError>;
async fn latest_version(&self, name: &PackageName) -> Option<Version>;
}
impl PackageInfoProvider for Arc<JsrFetchResolver> {
const HELP: NotFoundHelp = NotFoundHelp::JsrPackage;
const SPECIFIER_PREFIX: &str = "jsr";
async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> {
(**self).req_to_nv(req).await
async fn req_to_nv(
&self,
req: &PackageReq,
) -> Result<Option<PackageNv>, AnyError> {
Ok((**self).req_to_nv(req).await?)
}
async fn latest_version(&self, req: &PackageReq) -> Option<Version> {
let info = self.package_info(&req.name).await?;
async fn latest_version(&self, name: &PackageName) -> Option<Version> {
let info = self.package_info(name).await?;
best_version(
info
.versions
@ -636,13 +660,17 @@ impl PackageInfoProvider for Arc<JsrFetchResolver> {
impl PackageInfoProvider for Arc<NpmFetchResolver> {
const HELP: NotFoundHelp = NotFoundHelp::NpmPackage;
const SPECIFIER_PREFIX: &str = "npm";
async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> {
async fn req_to_nv(
&self,
req: &PackageReq,
) -> Result<Option<PackageNv>, AnyError> {
(**self).req_to_nv(req).await
}
async fn latest_version(&self, req: &PackageReq) -> Option<Version> {
let info = self.package_info(&req.name).await?;
best_version(info.versions.keys()).cloned()
async fn latest_version(&self, name: &PackageName) -> Option<Version> {
let info = self.package_info(name).await?;
best_version(self.applicable_version_infos(&info).map(|vi| &vi.version))
.cloned()
}
}
@ -662,33 +690,45 @@ async fn find_package_and_select_version_for_req(
};
let prefixed_name = format!("{}:{}", T::SPECIFIER_PREFIX, req.name);
let help_if_found_in_fallback = S::HELP;
let Some(nv) = main_resolver.req_to_nv(req).await else {
if fallback_resolver.req_to_nv(req).await.is_some() {
// it's in the other registry
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
help: Some(help_if_found_in_fallback),
package_req: req.clone(),
});
}
if req.version_req.version_text() == "*"
&& let Some(pre_release_version) =
main_resolver.latest_version(req).await
{
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
package_req: req.clone(),
help: Some(NotFoundHelp::PreReleaseVersion(
pre_release_version.clone(),
)),
});
}
let nv = match main_resolver.req_to_nv(req).await {
Ok(Some(nv)) => nv,
Ok(None) => {
if fallback_resolver
.req_to_nv(req)
.await
.ok()
.flatten()
.is_some()
{
// it's in the other registry
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
help: Some(help_if_found_in_fallback),
package_req: req.clone(),
});
}
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
help: None,
package_req: req.clone(),
});
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
help: None,
package_req: req.clone(),
});
}
Err(err) => {
if req.version_req.version_text() == "*"
&& let Some(pre_release_version) =
main_resolver.latest_version(&req.name).await
{
return Ok(PackageAndVersion::NotFound {
package: prefixed_name,
package_req: req.clone(),
help: Some(NotFoundHelp::PreReleaseVersion(
pre_release_version.clone(),
)),
});
}
return Err(err);
}
};
let range_symbol = if req.version_req.version_text().starts_with('~') {
"~"
@ -808,18 +848,7 @@ impl AddRmPackageReq {
Prefix::Npm => {
let req_ref =
NpmPackageReqReference::from_str(&format!("npm:{}", entry_text))?;
let mut package_req = req_ref.into_inner().req;
// deno_semver defaults to a version req of `*` if none is specified
// we want to default to `latest` instead
if package_req.version_req == *deno_semver::WILDCARD_VERSION_REQ
&& package_req.version_req.version_text() == "*"
&& !entry_text.contains("@*")
{
package_req.version_req = VersionReq::from_raw_text_and_inner(
"latest".into(),
deno_semver::RangeSetOrTag::Tag("latest".into()),
);
}
let package_req = req_ref.into_inner().req;
Ok(Ok(AddRmPackageReq {
alias: maybe_alias.unwrap_or_else(|| package_req.name.clone()),
value: AddRmPackageReqValue::Npm(package_req),
@ -941,7 +970,7 @@ mod test {
(("alias@jsr:foo", None), jsr_pkg_req("alias", "foo")),
(
("@alias/pkg@npm:foo", None),
npm_pkg_req("@alias/pkg", "foo@latest"),
npm_pkg_req("@alias/pkg", "foo@*"),
),
(
("@alias/pkg@jsr:foo", None),
@ -951,17 +980,11 @@ mod test {
("alias@jsr:foo@^1.5.0", None),
jsr_pkg_req("alias", "foo@^1.5.0"),
),
(("foo", Some(Prefix::Npm)), npm_pkg_req("foo", "foo@latest")),
(("foo", Some(Prefix::Npm)), npm_pkg_req("foo", "foo@*")),
(("foo", Some(Prefix::Jsr)), jsr_pkg_req("foo", "foo")),
(
("npm:foo", Some(Prefix::Npm)),
npm_pkg_req("foo", "foo@latest"),
),
(("npm:foo", Some(Prefix::Npm)), npm_pkg_req("foo", "foo@*")),
(("jsr:foo", Some(Prefix::Jsr)), jsr_pkg_req("foo", "foo")),
(
("npm:foo", Some(Prefix::Jsr)),
npm_pkg_req("foo", "foo@latest"),
),
(("npm:foo", Some(Prefix::Jsr)), npm_pkg_req("foo", "foo@*")),
(("jsr:foo", Some(Prefix::Npm)), jsr_pkg_req("foo", "foo")),
];

View file

@ -202,9 +202,12 @@ pub async fn outdated(
let npm_fetch_resolver = Arc::new(NpmFetchResolver::new(
file_fetcher.clone(),
factory.npmrc()?.clone(),
factory.npm_version_resolver()?.clone(),
));
let jsr_fetch_resolver = Arc::new(JsrFetchResolver::new(
file_fetcher.clone(),
factory.jsr_version_resolver()?.clone(),
));
let jsr_fetch_resolver =
Arc::new(JsrFetchResolver::new(file_fetcher.clone()));
if !cli_options.start_dir.has_deno_json()
&& !cli_options.start_dir.has_pkg_json()
@ -515,6 +518,7 @@ async fn dep_manager_args(
npm_fetch_resolver,
npm_resolver: factory.npm_resolver().await?.clone(),
npm_installer: factory.npm_installer().await?.clone(),
npm_version_resolver: factory.npm_version_resolver()?.clone(),
progress_bar: factory.text_only_progress_bar().clone(),
permissions_container: factory.root_permissions_container()?.clone(),
main_module_graph_container: factory

View file

@ -104,3 +104,9 @@ mod inner {
pub fn new_rc<T>(value: T) -> MaybeArc<T> {
MaybeArc::new(value)
}
#[allow(clippy::disallowed_types)]
#[inline]
pub fn new_arc<T>(value: T) -> std::sync::Arc<T> {
std::sync::Arc::new(value)
}

View file

@ -20,6 +20,7 @@ async-trait.workspace = true
bincode.workspace = true
boxed_error.workspace = true
capacity_builder.workspace = true
chrono.workspace = true
deno_config.workspace = true
deno_error.workspace = true
deno_graph.workspace = true

View file

@ -7,7 +7,7 @@ use deno_error::JsErrorBox;
use deno_npm::NpmPackageExtraInfo;
use deno_npm::NpmResolutionPackage;
use deno_npm::registry::NpmRegistryApi;
use deno_resolver::workspace::WorkspaceNpmLinkPackages;
use deno_resolver::workspace::WorkspaceNpmLinkPackagesRc;
use deno_semver::package::PackageNv;
use parking_lot::RwLock;
@ -72,7 +72,7 @@ pub trait NpmPackageExtraInfoProviderSys:
pub struct NpmPackageExtraInfoProvider {
npm_registry_info_provider: Arc<dyn NpmRegistryApi + Send + Sync>,
sys: Arc<dyn NpmPackageExtraInfoProviderSys>,
workspace_link_packages: Arc<WorkspaceNpmLinkPackages>,
workspace_link_packages: WorkspaceNpmLinkPackagesRc,
}
impl std::fmt::Debug for NpmPackageExtraInfoProvider {
@ -85,7 +85,7 @@ impl NpmPackageExtraInfoProvider {
pub fn new(
npm_registry_info_provider: Arc<dyn NpmRegistryApi + Send + Sync>,
sys: Arc<dyn NpmPackageExtraInfoProviderSys>,
workspace_link_packages: Arc<WorkspaceNpmLinkPackages>,
workspace_link_packages: WorkspaceNpmLinkPackagesRc,
) -> Self {
Self {
npm_registry_info_provider,

View file

@ -245,17 +245,14 @@ impl<
.npm_resolution_installer
.get_or_try_init(async move {
Ok(Arc::new(NpmResolutionInstaller::new(
self.resolver_factory.npm_version_resolver()?.clone(),
self.registry_info_provider()?.clone(),
self.resolver_factory.npm_resolution().clone(),
self.maybe_lockfile().await?.cloned(),
self
.workspace_factory()
.workspace_npm_link_packages()?
.clone(),
self
.install_reporter
.as_ref()
.map(|r| r.clone() as Arc<dyn deno_npm::resolution::Reporter>),
self.resolver_factory.npm_resolution().clone(),
self.maybe_lockfile().await?.cloned(),
)))
})
.await

View file

@ -10,12 +10,11 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot;
use deno_resolver::lockfile::LockfileLock;
use deno_resolver::lockfile::LockfileSys;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::workspace::WorkspaceNpmLinkPackagesRc;
use deno_unsync::sync::TaskQueue;
use parking_lot::Mutex;
use thiserror::Error;
use super::WorkspaceNpmLinkPackages;
#[derive(Debug, Clone)]
pub enum NpmResolverManagedSnapshotOption<TSys: LockfileSys> {
ResolveFromLockfile(Arc<LockfileLock<TSys>>),
@ -32,7 +31,7 @@ enum SyncState<TSys: LockfileSys> {
#[derive(Debug)]
pub struct NpmResolutionInitializer<TSys: LockfileSys> {
npm_resolution: Arc<NpmResolutionCell>,
link_packages: Arc<WorkspaceNpmLinkPackages>,
link_packages: WorkspaceNpmLinkPackagesRc,
queue: TaskQueue,
sync_state: Mutex<SyncState<TSys>>,
}
@ -40,7 +39,7 @@ pub struct NpmResolutionInitializer<TSys: LockfileSys> {
impl<TSys: LockfileSys> NpmResolutionInitializer<TSys> {
pub fn new(
npm_resolution: Arc<NpmResolutionCell>,
link_packages: Arc<WorkspaceNpmLinkPackages>,
link_packages: WorkspaceNpmLinkPackagesRc,
snapshot_option: NpmResolverManagedSnapshotOption<TSys>,
) -> Self {
Self {
@ -126,7 +125,7 @@ pub struct ResolveSnapshotError {
#[allow(clippy::result_large_err)]
fn resolve_snapshot<TSys: LockfileSys>(
snapshot: NpmResolverManagedSnapshotOption<TSys>,
link_packages: &WorkspaceNpmLinkPackages,
link_packages: &WorkspaceNpmLinkPackagesRc,
) -> Result<Option<ValidSerializedNpmResolutionSnapshot>, ResolveSnapshotError>
{
match snapshot {
@ -155,7 +154,7 @@ pub enum SnapshotFromLockfileError {
fn snapshot_from_lockfile<TSys: LockfileSys>(
lockfile: Arc<LockfileLock<TSys>>,
link_packages: &WorkspaceNpmLinkPackages,
link_packages: &WorkspaceNpmLinkPackagesRc,
) -> Result<ValidSerializedNpmResolutionSnapshot, SnapshotFromLockfileError> {
let snapshot = deno_npm::resolution::snapshot_from_lockfile(
deno_npm::resolution::SnapshotFromLockfileParams {

View file

@ -12,7 +12,7 @@ use deno_npm_cache::NpmCache;
use deno_npm_cache::NpmCacheHttpClient;
use deno_resolver::lockfile::LockfileLock;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::workspace::WorkspaceNpmLinkPackages;
use deno_resolver::workspace::WorkspaceNpmLinkPackagesRc;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
@ -184,7 +184,7 @@ impl<TNpmCacheHttpClient: NpmCacheHttpClient, TSys: NpmInstallerSys>
maybe_node_modules_path: Option<PathBuf>,
lifecycle_scripts: LifecycleScriptsConfig,
system_info: NpmSystemInfo,
workspace_link_packages: Arc<WorkspaceNpmLinkPackages>,
workspace_link_packages: WorkspaceNpmLinkPackagesRc,
install_reporter: Option<Arc<dyn InstallReporter>>,
) -> Self {
let fs_installer: Arc<dyn NpmPackageFsInstaller> =

View file

@ -22,13 +22,12 @@ use deno_npm_cache::NpmCacheHttpClient;
use deno_npm_cache::NpmCacheSys;
use deno_npm_cache::RegistryInfoProvider;
use deno_resolver::display::DisplayTreeNode;
use deno_resolver::factory::NpmVersionResolverRc;
use deno_resolver::lockfile::LockfileLock;
use deno_resolver::lockfile::LockfileSys;
use deno_resolver::npm::managed::NpmResolutionCell;
use deno_resolver::workspace::WorkspaceNpmLinkPackages;
use deno_semver::SmallStackString;
use deno_semver::StackString;
use deno_semver::VersionReq;
use deno_semver::jsr::JsrDepPackageReq;
use deno_semver::package::PackageNv;
use deno_semver::package::PackageReq;
@ -54,33 +53,33 @@ pub struct NpmResolutionInstaller<
TNpmCacheHttpClient: NpmCacheHttpClient,
TSys: NpmResolutionInstallerSys,
> {
npm_version_resolver: NpmVersionResolverRc,
registry_info_provider: Arc<RegistryInfoProvider<TNpmCacheHttpClient, TSys>>,
reporter: Option<Arc<dyn deno_npm::resolution::Reporter>>,
resolution: Arc<NpmResolutionCell>,
maybe_lockfile: Option<Arc<LockfileLock<TSys>>>,
link_packages: Arc<WorkspaceNpmLinkPackages>,
update_queue: TaskQueue,
reporter: Option<Arc<dyn deno_npm::resolution::Reporter>>,
}
impl<TNpmCacheHttpClient: NpmCacheHttpClient, TSys: NpmResolutionInstallerSys>
NpmResolutionInstaller<TNpmCacheHttpClient, TSys>
{
pub fn new(
npm_version_resolver: NpmVersionResolverRc,
registry_info_provider: Arc<
RegistryInfoProvider<TNpmCacheHttpClient, TSys>,
>,
reporter: Option<Arc<dyn deno_npm::resolution::Reporter>>,
resolution: Arc<NpmResolutionCell>,
maybe_lockfile: Option<Arc<LockfileLock<TSys>>>,
link_packages: Arc<WorkspaceNpmLinkPackages>,
reporter: Option<Arc<dyn deno_npm::resolution::Reporter>>,
) -> Self {
Self {
npm_version_resolver,
registry_info_provider,
reporter,
resolution,
maybe_lockfile,
link_packages,
update_queue: Default::default(),
reporter,
}
}
@ -116,12 +115,6 @@ impl<TNpmCacheHttpClient: NpmCacheHttpClient, TSys: NpmResolutionInstallerSys>
&self,
package_reqs: &[PackageReq],
) -> deno_npm::resolution::AddPkgReqsResult {
fn get_types_node_version() -> VersionReq {
// WARNING: When bumping this version, check if anything needs to be
// updated in the `setNodeOnlyGlobalNames` call in 99_main_compiler.js
VersionReq::parse_from_npm("24.0.4 - 24.2.0").unwrap()
}
let snapshot = self.resolution.snapshot();
if package_reqs
.iter()
@ -146,8 +139,7 @@ impl<TNpmCacheHttpClient: NpmCacheHttpClient, TSys: NpmResolutionInstallerSys>
self.registry_info_provider.as_ref(),
AddPkgReqsOptions {
package_reqs,
types_node_version_req: Some(get_types_node_version()),
link_packages: &self.link_packages.0,
version_resolver: &self.npm_version_resolver,
},
self.reporter.as_deref(),
)
@ -166,8 +158,7 @@ impl<TNpmCacheHttpClient: NpmCacheHttpClient, TSys: NpmResolutionInstallerSys>
self.registry_info_provider.as_ref(),
AddPkgReqsOptions {
package_reqs,
types_node_version_req: Some(get_types_node_version()),
link_packages: &self.link_packages.0,
version_resolver: &self.npm_version_resolver,
},
self.reporter.as_deref(),
)

View file

@ -233,6 +233,7 @@ pub struct PackageJson {
pub peer_dependencies: Option<IndexMap<String, String>>,
pub peer_dependencies_meta: Option<Value>,
pub optional_dependencies: Option<IndexMap<String, String>>,
pub directories: Option<Map<String, Value>>,
pub scripts: Option<IndexMap<String, String>>,
pub workspaces: Option<Vec<String>>,
pub os: Option<Vec<String>>,
@ -303,6 +304,7 @@ impl PackageJson {
peer_dependencies: None,
peer_dependencies_meta: None,
optional_dependencies: None,
directories: None,
scripts: None,
workspaces: None,
os: None,
@ -390,10 +392,10 @@ impl PackageJson {
.map(|exports| {
if is_conditional_exports_main_sugar(&exports)? {
let mut map = Map::new();
map.insert(".".to_string(), exports.to_owned());
map.insert(".".to_string(), exports);
Ok::<_, PackageJsonLoadError>(Some(map))
} else {
Ok(exports.as_object().map(|o| o.to_owned()))
Ok(map_object(exports))
}
})
.transpose()?
@ -426,6 +428,8 @@ impl PackageJson {
let scripts: Option<IndexMap<String, String>> =
package_json.remove("scripts").and_then(parse_string_map);
let directories: Option<Map<String, Value>> =
package_json.remove("directories").and_then(map_object);
// Ignore unknown types for forwards compatibility
let typ = if let Some(t) = type_val {
@ -447,9 +451,8 @@ impl PackageJson {
.remove("typings")
.or_else(|| package_json.remove("types"))
.and_then(map_string);
let types_versions = package_json
.remove("typesVersions")
.and_then(|exports| exports.as_object().map(|o| o.to_owned()));
let types_versions =
package_json.remove("typesVersions").and_then(map_object);
let workspaces = package_json
.remove("workspaces")
.and_then(parse_string_array);
@ -475,6 +478,7 @@ impl PackageJson {
peer_dependencies,
peer_dependencies_meta,
optional_dependencies,
directories,
scripts,
workspaces,
os,
@ -811,6 +815,9 @@ mod test {
"dependencies": {
"name": "1.2",
},
"directories": {
"bin": "./bin",
},
"devDependencies": {
"name": "1.2",
},

View file

@ -32,6 +32,7 @@ async-trait.workspace = true
base32.workspace = true
boxed_error.workspace = true
capacity_builder.workspace = true
chrono.workspace = true
dashmap = { workspace = true, optional = true }
deno_ast = { workspace = true, features = ["cjs"], optional = true }
deno_cache_dir.workspace = true

View file

@ -24,7 +24,9 @@ use deno_maybe_sync::MaybeSend;
use deno_maybe_sync::MaybeSync;
use deno_maybe_sync::new_rc;
pub use deno_npm::NpmSystemInfo;
use deno_npm::resolution::NpmVersionResolver;
use deno_path_util::fs::canonicalize_path_maybe_not_exists;
use deno_semver::VersionReq;
use futures::future::FutureExt;
use node_resolver::DenoIsBuiltInNodeModuleChecker;
use node_resolver::NodeResolver;
@ -85,7 +87,6 @@ use crate::npmrc::discover_npmrc_from_workspace;
use crate::workspace::FsCacheOptions;
use crate::workspace::PackageJsonDepResolution;
use crate::workspace::SloppyImportsOptions;
use crate::workspace::WorkspaceNpmLinkPackages;
use crate::workspace::WorkspaceNpmLinkPackagesRc;
use crate::workspace::WorkspaceResolver;
@ -109,6 +110,12 @@ pub type DenoNodeCodeTranslatorRc<TSys> = NodeCodeTranslatorRc<
NpmResolver<TSys>,
TSys,
>;
#[allow(clippy::disallowed_types)]
pub type NpmVersionResolverRc = deno_maybe_sync::MaybeArc<NpmVersionResolver>;
#[cfg(feature = "graph")]
#[allow(clippy::disallowed_types)]
pub type JsrVersionResolverRc =
deno_maybe_sync::MaybeArc<deno_graph::packages::JsrVersionResolver>;
#[derive(Debug, Boxed)]
pub struct HttpCacheCreateError(pub Box<HttpCacheCreateErrorKind>);
@ -628,9 +635,9 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
.workspace_npm_link_packages
.get_or_try_init(|| {
let workspace_dir = self.workspace_directory()?;
let npm_packages = new_rc(WorkspaceNpmLinkPackages::from_workspace(
let npm_packages = WorkspaceNpmLinkPackagesRc::from_workspace(
workspace_dir.workspace.as_ref(),
));
);
if !npm_packages.0.is_empty() && !matches!(self.node_modules_dir_mode()?, NodeModulesDirMode::Auto | NodeModulesDirMode::Manual) {
bail!("Linking npm packages requires using a node_modules directory. Ensure you have a package.json or set the \"nodeModulesDir\" option to \"auto\" or \"manual\" in your workspace root deno.json.")
} else {
@ -652,6 +659,8 @@ impl<TSys: WorkspaceFactorySys> WorkspaceFactory<TSys> {
pub struct ResolverFactoryOptions {
pub compiler_options_overrides: CompilerOptionsOverrides,
pub is_cjs_resolution_mode: IsCjsResolutionMode,
/// Prevents installing packages newer than the specified date.
pub newest_dependency_date: Option<chrono::DateTime<chrono::Utc>>,
pub node_analysis_cache: Option<NodeAnalysisCacheRc>,
pub node_code_translator_mode: node_resolver::analyze::NodeCodeTranslatorMode,
pub node_resolver_options: NodeResolverOptions,
@ -667,6 +676,9 @@ pub struct ResolverFactoryOptions {
pub on_mapped_resolution_diagnostic:
Option<crate::graph::OnMappedResolutionDiagnosticFn>,
pub allow_json_imports: AllowJsonImports,
/// Known good version requirement to use for the `@types/node` package
/// when the version is unspecified or "latest".
pub types_node_version_req: Option<VersionReq>,
}
pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
@ -683,8 +695,9 @@ pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
#[cfg(feature = "graph")]
found_package_json_dep_flag: crate::graph::FoundPackageJsonDepFlagRc,
in_npm_package_checker: Deferred<DenoInNpmPackageChecker>,
#[cfg(feature = "graph")]
jsr_version_resolver: Deferred<JsrVersionResolverRc>,
node_code_translator: Deferred<DenoNodeCodeTranslatorRc<TSys>>,
npm_module_loader: Deferred<DenoNpmModuleLoaderRc<TSys>>,
node_resolver: Deferred<
NodeResolverRc<
DenoInNpmPackageChecker,
@ -693,6 +706,7 @@ pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
TSys,
>,
>,
npm_module_loader: Deferred<DenoNpmModuleLoaderRc<TSys>>,
npm_req_resolver: Deferred<
NpmReqResolverRc<
DenoInNpmPackageChecker,
@ -703,6 +717,7 @@ pub struct ResolverFactory<TSys: WorkspaceFactorySys> {
>,
npm_resolver: Deferred<NpmResolver<TSys>>,
npm_resolution: NpmResolutionCellRc,
npm_version_resolver: Deferred<NpmVersionResolverRc>,
#[cfg(feature = "deno_ast")]
parsed_source_cache: crate::cache::ParsedSourceCacheRc,
pkg_json_resolver: Deferred<PackageJsonResolverRc<TSys>>,
@ -718,6 +733,9 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
workspace_factory: WorkspaceFactoryRc<TSys>,
options: ResolverFactoryOptions,
) -> Self {
if let Some(newest_dependency_date) = options.newest_dependency_date {
log::debug!("Newest dependency date: {}", newest_dependency_date);
}
Self {
sys: NodeResolutionSys::new(
workspace_factory.sys.clone(),
@ -734,12 +752,15 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
#[cfg(feature = "graph")]
found_package_json_dep_flag: Default::default(),
in_npm_package_checker: Default::default(),
#[cfg(feature = "graph")]
jsr_version_resolver: Default::default(),
node_code_translator: Default::default(),
node_resolver: Default::default(),
npm_module_loader: Default::default(),
npm_req_resolver: Default::default(),
npm_resolution: Default::default(),
npm_resolver: Default::default(),
npm_version_resolver: Default::default(),
#[cfg(feature = "deno_ast")]
parsed_source_cache: Default::default(),
pkg_json_resolver: Default::default(),
@ -906,6 +927,17 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
})
}
#[cfg(feature = "graph")]
pub fn jsr_version_resolver(
&self,
) -> Result<&JsrVersionResolverRc, anyhow::Error> {
self.jsr_version_resolver.get_or_try_init(|| {
Ok(new_rc(deno_graph::packages::JsrVersionResolver {
newest_dependency_date: self.options.newest_dependency_date,
}))
})
}
pub fn node_code_translator(
&self,
) -> Result<&DenoNodeCodeTranslatorRc<TSys>, anyhow::Error> {
@ -1012,6 +1044,22 @@ impl<TSys: WorkspaceFactorySys> ResolverFactory<TSys> {
})
}
pub fn npm_version_resolver(
&self,
) -> Result<&NpmVersionResolverRc, anyhow::Error> {
self.npm_version_resolver.get_or_try_init(|| {
Ok(new_rc(NpmVersionResolver {
types_node_version_req: self.options.types_node_version_req.clone(),
newest_dependency_date: self.options.newest_dependency_date,
link_packages: self
.workspace_factory
.workspace_npm_link_packages()?
.0
.clone(),
}))
})
}
#[cfg(feature = "deno_ast")]
pub fn parsed_source_cache(&self) -> &crate::cache::ParsedSourceCacheRc {
&self.parsed_source_cache

View file

@ -1615,15 +1615,12 @@ impl BaseUrl<'_> {
}
#[allow(clippy::disallowed_types)] // ok, because definition
pub type WorkspaceNpmLinkPackagesRc =
deno_maybe_sync::MaybeArc<WorkspaceNpmLinkPackages>;
#[derive(Debug, Default)]
pub struct WorkspaceNpmLinkPackages(
pub HashMap<PackageName, Vec<NpmPackageVersionInfo>>,
#[derive(Debug, Default, Clone)]
pub struct WorkspaceNpmLinkPackagesRc(
pub std::sync::Arc<HashMap<PackageName, Vec<NpmPackageVersionInfo>>>,
);
impl WorkspaceNpmLinkPackages {
impl WorkspaceNpmLinkPackagesRc {
pub fn from_workspace(workspace: &Workspace) -> Self {
let mut entries: HashMap<PackageName, Vec<NpmPackageVersionInfo>> =
HashMap::new();
@ -1651,7 +1648,7 @@ impl WorkspaceNpmLinkPackages {
}
}
}
Self(entries)
Self(deno_maybe_sync::new_arc(entries))
}
}
@ -1739,6 +1736,19 @@ fn pkg_json_to_version_info(
.collect()
})
.unwrap_or_default(),
directories: pkg_json
.directories
.as_ref()
.map(|directories| {
directories
.iter()
.filter_map(|(k, v)| {
let v = v.as_str()?;
Some((SmallStackString::from_str(k), v.to_string()))
})
.collect()
})
.unwrap_or_default(),
// not worth increasing memory for showing a deprecated
// message for linked packages
deprecated: None,
@ -3205,6 +3215,9 @@ mod test {
"bundleDependencies": [
"my-dep"
],
"directories": {
"bin": "./bin"
},
"peerDependenciesMeta": {
"my-peer-dep": {
"optional": true
@ -3245,6 +3258,10 @@ mod test {
)]),
os: vec![SmallStackString::from_static("win32")],
cpu: vec![SmallStackString::from_static("x86_64")],
directories: HashMap::from([(
SmallStackString::from_static("bin"),
"./bin".to_string(),
),]),
scripts: HashMap::from([
(
SmallStackString::from_static("script"),