diff --git a/Cargo.lock b/Cargo.lock index aa13ae0ccd..95633e3ce9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2242,6 +2242,7 @@ dependencies = [ "deno_node", "deno_path_util", "deno_permissions", + "deno_resolver", "deno_telemetry", "deno_terminal 0.2.0", "deno_tls", diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs index ff9f07fc4e..0d7808cba6 100644 --- a/cli/cache/mod.rs +++ b/cli/cache/mod.rs @@ -15,6 +15,7 @@ use deno_graph::source::CacheInfo; use deno_graph::source::LoadFuture; use deno_graph::source::LoadResponse; use deno_graph::source::Loader; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_runtime::deno_permissions::PermissionsContainer; use node_resolver::InNpmPackageChecker; @@ -76,7 +77,7 @@ pub struct FetchCacher { pub file_header_overrides: HashMap>, file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, module_info_cache: Arc, permissions: PermissionsContainer, sys: CliSys, @@ -88,7 +89,7 @@ impl FetchCacher { pub fn new( file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, module_info_cache: Arc, sys: CliSys, options: FetchCacherOptions, diff --git a/cli/emit.rs b/cli/emit.rs index e9b5a4e250..69ac8323bb 100644 --- a/cli/emit.rs +++ b/cli/emit.rs @@ -24,11 +24,11 @@ use deno_graph::ModuleGraph; use crate::cache::EmitCache; use crate::cache::FastInsecureHasher; use crate::cache::ParsedSourceCache; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; #[derive(Debug)] pub struct Emitter { - cjs_tracker: Arc, + cjs_tracker: Arc, emit_cache: Arc, parsed_source_cache: Arc, transpile_and_emit_options: @@ -39,7 +39,7 @@ pub struct Emitter { impl Emitter { pub fn new( - cjs_tracker: Arc, + cjs_tracker: Arc, emit_cache: Arc, parsed_source_cache: Arc, transpile_options: deno_ast::TranspileOptions, diff --git a/cli/factory.rs b/cli/factory.rs index e3873b5164..3280fd379b 100644 --- a/cli/factory.rs +++ b/cli/factory.rs @@ -16,6 +16,7 @@ use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions; use deno_resolver::npm::managed::NpmResolutionCell; use deno_resolver::npm::CreateInNpmPkgCheckerOptions; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_resolver::DenoResolverOptions; @@ -32,7 +33,6 @@ use deno_runtime::inspector_server::InspectorServer; use deno_runtime::permissions::RuntimePermissionDescriptorParser; use log::warn; use node_resolver::analyze::NodeCodeTranslator; -use node_resolver::InNpmPackageChecker; use once_cell::sync::OnceCell; use crate::args::check_warn_tsconfig; @@ -68,7 +68,6 @@ use crate::node::CliCjsCodeAnalyzer; use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; use crate::node::CliPackageJsonResolver; -use crate::npm::create_cli_npm_resolver; use crate::npm::installer::NpmInstaller; use crate::npm::installer::NpmResolutionInstaller; use crate::npm::CliByonmNpmResolverCreateOptions; @@ -83,7 +82,7 @@ use crate::npm::CliNpmTarballCache; use crate::npm::NpmRegistryReadPermissionChecker; use crate::npm::NpmRegistryReadPermissionCheckerMode; use crate::npm::NpmResolutionInitializer; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::resolver::CliDenoResolver; use crate::resolver::CliNpmGraphResolver; use crate::resolver::CliNpmReqResolver; @@ -190,7 +189,7 @@ impl Deferred { struct CliFactoryServices { blob_store: Deferred>, caches: Deferred>, - cjs_tracker: Deferred>, + cjs_tracker: Deferred>, cli_options: Deferred>, code_cache: Deferred>, deno_resolver: Deferred>, @@ -203,7 +202,7 @@ struct CliFactoryServices { global_http_cache: Deferred>, http_cache: Deferred>, http_client_provider: Deferred>, - in_npm_pkg_checker: Deferred>, + in_npm_pkg_checker: Deferred, main_graph_container: Deferred>, maybe_file_watcher_reporter: Deferred>, maybe_inspector_server: Deferred>>, @@ -223,7 +222,7 @@ struct CliFactoryServices { npm_resolution: Arc, npm_resolution_initializer: Deferred>, npm_resolution_installer: Deferred>, - npm_resolver: Deferred>, + npm_resolver: Deferred, npm_tarball_cache: Deferred>, parsed_source_cache: Deferred>, permission_desc_parser: @@ -399,7 +398,7 @@ impl CliFactory { pub fn in_npm_pkg_checker( &self, - ) -> Result<&Arc, AnyError> { + ) -> Result<&DenoInNpmPackageChecker, AnyError> { self.services.in_npm_pkg_checker.get_or_try_init(|| { let cli_options = self.cli_options()?; let options = if cli_options.use_byonm() { @@ -414,7 +413,7 @@ impl CliFactory { }, ) }; - Ok(deno_resolver::npm::create_in_npm_pkg_checker(options)) + Ok(DenoInNpmPackageChecker::new(options)) }) } @@ -559,16 +558,14 @@ impl CliFactory { }) } - pub async fn npm_resolver( - &self, - ) -> Result<&Arc, AnyError> { + pub async fn npm_resolver(&self) -> Result<&CliNpmResolver, AnyError> { self .services .npm_resolver .get_or_try_init_async( async { let cli_options = self.cli_options()?; - Ok(create_cli_npm_resolver(if cli_options.use_byonm() { + Ok(CliNpmResolver::new(if cli_options.use_byonm() { CliNpmResolverCreateOptions::Byonm( CliByonmNpmResolverCreateOptions { sys: self.sys(), @@ -796,11 +793,7 @@ impl CliFactory { Ok(Arc::new(CliNodeResolver::new( self.in_npm_pkg_checker()?.clone(), RealIsBuiltInNodeModuleChecker, - self - .npm_resolver() - .await? - .clone() - .into_npm_pkg_folder_resolver(), + self.npm_resolver().await?.clone(), self.pkg_json_resolver().clone(), self.sys(), node_resolver::ConditionsFromResolutionMode::default(), @@ -833,11 +826,7 @@ impl CliFactory { cjs_esm_analyzer, self.in_npm_pkg_checker()?.clone(), node_resolver, - self - .npm_resolver() - .await? - .clone() - .into_npm_pkg_folder_resolver(), + self.npm_resolver().await?.clone(), self.pkg_json_resolver().clone(), self.sys(), ))) @@ -857,7 +846,7 @@ impl CliFactory { sys: self.sys(), in_npm_pkg_checker: self.in_npm_pkg_checker()?.clone(), node_resolver: self.node_resolver().await?.clone(), - npm_resolver: npm_resolver.clone().into_byonm_or_managed(), + npm_resolver: npm_resolver.clone(), }))) }) .await @@ -988,10 +977,10 @@ impl CliFactory { .await } - pub fn cjs_tracker(&self) -> Result<&Arc, AnyError> { + pub fn cjs_tracker(&self) -> Result<&Arc, AnyError> { self.services.cjs_tracker.get_or_try_init(|| { let options = self.cli_options()?; - Ok(Arc::new(CjsTracker::new( + Ok(Arc::new(CliCjsTracker::new( self.in_npm_pkg_checker()?.clone(), self.pkg_json_resolver().clone(), if options.is_node_main() || options.unstable_detect_cjs() { @@ -1040,7 +1029,7 @@ impl CliFactory { self.emitter()?, self.file_fetcher()?, self.http_client_provider(), - self.npm_resolver().await?.as_ref(), + self.npm_resolver().await?, self.workspace_resolver().await?.as_ref(), cli_options.npm_system_info(), )) diff --git a/cli/graph_util.rs b/cli/graph_util.rs index 17d4fef553..e57fcf8a94 100644 --- a/cli/graph_util.rs +++ b/cli/graph_util.rs @@ -30,6 +30,7 @@ use deno_graph::ResolutionError; use deno_graph::SpecifierError; use deno_graph::WorkspaceFastCheckOption; use deno_path_util::url_to_file_path; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_resolver::sloppy_imports::SloppyImportsResolutionKind; use deno_runtime::deno_node; @@ -37,7 +38,6 @@ use deno_runtime::deno_permissions::PermissionsContainer; use deno_semver::jsr::JsrDepPackageReq; use deno_semver::package::PackageNv; use deno_semver::SmallStackString; -use node_resolver::InNpmPackageChecker; use crate::args::config_to_deno_graph_workspace_member; use crate::args::jsr_url; @@ -55,7 +55,7 @@ use crate::file_fetcher::CliFileFetcher; use crate::npm::installer::NpmInstaller; use crate::npm::installer::PackageCaching; use crate::npm::CliNpmResolver; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::resolver::CliNpmGraphResolver; use crate::resolver::CliResolver; use crate::resolver::CliSloppyImportsResolver; @@ -493,17 +493,17 @@ pub enum BuildGraphWithNpmResolutionError { pub struct ModuleGraphBuilder { caches: Arc, - cjs_tracker: Arc, + cjs_tracker: Arc, cli_options: Arc, file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, lockfile: Option>, maybe_file_watcher_reporter: Option, module_info_cache: Arc, npm_graph_resolver: Arc, npm_installer: Option>, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, root_permissions_container: PermissionsContainer, @@ -514,17 +514,17 @@ impl ModuleGraphBuilder { #[allow(clippy::too_many_arguments)] pub fn new( caches: Arc, - cjs_tracker: Arc, + cjs_tracker: Arc, cli_options: Arc, file_fetcher: Arc, global_http_cache: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, lockfile: Option>, maybe_file_watcher_reporter: Option, module_info_cache: Arc, npm_graph_resolver: Arc, npm_installer: Option>, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, root_permissions_container: PermissionsContainer, @@ -712,8 +712,7 @@ impl ModuleGraphBuilder { let initial_package_deps_len = graph.packages.package_deps_sum(); let initial_package_mappings_len = graph.packages.mappings().len(); - if roots.iter().any(|r| r.scheme() == "npm") - && self.npm_resolver.as_byonm().is_some() + if roots.iter().any(|r| r.scheme() == "npm") && self.npm_resolver.is_byonm() { return Err(BuildGraphWithNpmResolutionError::UnsupportedNpmSpecifierEntrypointResolutionWay); } @@ -1226,7 +1225,7 @@ fn format_deno_graph_error(err: &dyn Error) -> String { #[derive(Debug)] struct CliGraphResolver<'a> { - cjs_tracker: &'a CjsTracker, + cjs_tracker: &'a CliCjsTracker, resolver: &'a CliResolver, jsx_import_source_config: Option, } diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index f7b487f055..f8f382f594 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -19,6 +19,7 @@ use deno_core::ModuleSpecifier; use deno_error::JsErrorBox; use deno_lint::diagnostic::LintDiagnosticRange; use deno_path_util::url_to_file_path; +use deno_resolver::npm::managed::NpmResolutionCell; use deno_runtime::deno_node::PathClean; use deno_semver::jsr::JsrPackageNvReference; use deno_semver::jsr::JsrPackageReqReference; @@ -31,6 +32,7 @@ use deno_semver::SmallStackString; use deno_semver::StackString; use deno_semver::Version; use import_map::ImportMap; +use node_resolver::InNpmPackageChecker; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; use once_cell::sync::Lazy; @@ -365,7 +367,9 @@ impl<'a> TsResponseImportMapper<'a> { if let Ok(Some(pkg_id)) = npm_resolver.resolve_pkg_id_from_specifier(specifier) { - let pkg_reqs = npm_resolver.resolve_pkg_reqs_from_pkg_id(&pkg_id); + let pkg_reqs = npm_resolver + .resolution() + .resolve_pkg_reqs_from_pkg_id(&pkg_id); // check if any pkg reqs match what is found in an import map if !pkg_reqs.is_empty() { let sub_path = npm_resolver @@ -1295,6 +1299,19 @@ impl CodeActionCollection { range: &lsp::Range, language_server: &language_server::Inner, ) -> Option { + fn top_package_req_for_name( + resolution: &NpmResolutionCell, + name: &str, + ) -> Option { + let package_reqs = resolution.package_reqs(); + let mut entries = package_reqs + .into_iter() + .filter(|(_, nv)| nv.name == name) + .collect::>(); + entries.sort_by(|a, b| a.1.version.cmp(&b.1.version)); + Some(entries.pop()?.0) + } + let (dep_key, dependency, _) = document.get_maybe_dependency(&range.end)?; if dependency.maybe_deno_types_specifier.is_some() { @@ -1382,9 +1399,10 @@ impl CodeActionCollection { .and_then(|versions| versions.first().cloned())?; let types_specifier_text = if let Some(npm_resolver) = managed_npm_resolver { - let mut specifier_text = if let Some(req) = - npm_resolver.top_package_req_for_name(&types_package_name) - { + let mut specifier_text = if let Some(req) = top_package_req_for_name( + npm_resolver.resolution(), + &types_package_name, + ) { format!("npm:{req}") } else { format!("npm:{}@^{}", &types_package_name, types_package_version) diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs index af4ab6571f..1b393ad22b 100644 --- a/cli/lsp/resolver.rs +++ b/cli/lsp/resolver.rs @@ -26,6 +26,7 @@ use deno_resolver::cjs::IsCjsResolutionMode; use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions; use deno_resolver::npm::managed::NpmResolutionCell; use deno_resolver::npm::CreateInNpmPkgCheckerOptions; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::NpmReqResolverOptions; use deno_resolver::DenoResolverOptions; use deno_resolver::NodeAndNpmReqResolver; @@ -35,7 +36,6 @@ use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; use indexmap::IndexMap; -use node_resolver::InNpmPackageChecker; use node_resolver::NodeResolutionKind; use node_resolver::ResolutionMode; @@ -56,10 +56,10 @@ use crate::lsp::config::ConfigData; use crate::lsp::logging::lsp_warn; use crate::node::CliNodeResolver; use crate::node::CliPackageJsonResolver; -use crate::npm::create_cli_npm_resolver; use crate::npm::installer::NpmInstaller; use crate::npm::installer::NpmResolutionInstaller; use crate::npm::CliByonmNpmResolverCreateOptions; +use crate::npm::CliManagedNpmResolver; use crate::npm::CliManagedNpmResolverCreateOptions; use crate::npm::CliNpmCache; use crate::npm::CliNpmCacheHttpClient; @@ -67,14 +67,13 @@ use crate::npm::CliNpmRegistryInfoProvider; use crate::npm::CliNpmResolver; use crate::npm::CliNpmResolverCreateOptions; use crate::npm::CliNpmResolverManagedSnapshotOption; -use crate::npm::ManagedCliNpmResolver; use crate::npm::NpmResolutionInitializer; use crate::resolver::CliDenoResolver; +use crate::resolver::CliIsCjsResolver; use crate::resolver::CliNpmGraphResolver; use crate::resolver::CliNpmReqResolver; use crate::resolver::CliResolver; use crate::resolver::FoundPackageJsonDepFlag; -use crate::resolver::IsCjsResolver; use crate::sys::CliSys; use crate::tsc::into_specifier_and_media_type; use crate::util::progress_bar::ProgressBar; @@ -83,12 +82,13 @@ use crate::util::progress_bar::ProgressBarStyle; #[derive(Debug, Clone)] struct LspScopeResolver { resolver: Arc, - in_npm_pkg_checker: Arc, - is_cjs_resolver: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, + is_cjs_resolver: Arc, jsr_resolver: Option>, npm_graph_resolver: Arc, npm_installer: Option>, - npm_resolver: Option>, + npm_resolution: Arc, + npm_resolver: Option, node_resolver: Option>, npm_pkg_req_resolver: Option>, pkg_json_resolver: Arc, @@ -111,6 +111,7 @@ impl Default for LspScopeResolver { npm_installer: None, npm_resolver: None, node_resolver: None, + npm_resolution: factory.services.npm_resolution.clone(), npm_pkg_req_resolver: None, pkg_json_resolver: factory.pkg_json_resolver().clone(), redirect_resolver: None, @@ -224,6 +225,7 @@ impl LspScopeResolver { npm_pkg_req_resolver, npm_resolver, npm_installer, + npm_resolution: factory.services.npm_resolution.clone(), node_resolver, pkg_json_resolver, redirect_resolver, @@ -235,12 +237,58 @@ impl LspScopeResolver { } fn snapshot(&self) -> Arc { + // create a copy of the resolution and then re-initialize the npm resolver from that + // todo(dsherret): this is pretty terrible... we should improve this. It should + // be possible to just change the npm_resolution on the new factory then access + // another method to create a new npm resolver let mut factory = ResolverFactory::new(self.config_data.as_ref()); - let npm_resolver = - self.npm_resolver.as_ref().map(|r| r.clone_snapshotted()); + factory + .services + .npm_resolution + .set_snapshot(self.npm_resolution.snapshot()); + let npm_resolver = self.npm_resolver.as_ref(); if let Some(npm_resolver) = &npm_resolver { - factory.set_npm_resolver(npm_resolver.clone()); + factory.set_npm_resolver(CliNpmResolver::new::( + match npm_resolver { + CliNpmResolver::Byonm(byonm_npm_resolver) => { + CliNpmResolverCreateOptions::Byonm( + CliByonmNpmResolverCreateOptions { + root_node_modules_dir: byonm_npm_resolver + .root_node_modules_path() + .map(|p| p.to_path_buf()), + sys: CliSys::default(), + pkg_json_resolver: self.pkg_json_resolver.clone(), + }, + ) + } + CliNpmResolver::Managed(managed_npm_resolver) => { + CliNpmResolverCreateOptions::Managed({ + let npmrc = self + .config_data + .as_ref() + .and_then(|d| d.npmrc.clone()) + .unwrap_or_else(create_default_npmrc); + let npm_cache_dir = Arc::new(NpmCacheDir::new( + &CliSys::default(), + managed_npm_resolver.global_cache_root_path().to_path_buf(), + npmrc.get_all_known_registries_urls(), + )); + CliManagedNpmResolverCreateOptions { + sys: CliSys::default(), + npm_cache_dir, + maybe_node_modules_path: managed_npm_resolver + .root_node_modules_path() + .map(|p| p.to_path_buf()), + npmrc, + npm_resolution: factory.services.npm_resolution.clone(), + npm_system_info: NpmSystemInfo::default(), + } + }) + } + }, + )); } + Arc::new(Self { resolver: factory.cli_resolver().clone(), in_npm_pkg_checker: factory.in_npm_pkg_checker().clone(), @@ -250,6 +298,7 @@ impl LspScopeResolver { // npm installer isn't necessary for a snapshot npm_installer: None, npm_pkg_req_resolver: factory.npm_pkg_req_resolver().cloned(), + npm_resolution: factory.services.npm_resolution.clone(), npm_resolver: factory.npm_resolver().cloned(), node_resolver: factory.node_resolver().cloned(), redirect_resolver: self.redirect_resolver.clone(), @@ -366,7 +415,7 @@ impl LspResolver { pub fn as_is_cjs_resolver( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> &IsCjsResolver { + ) -> &CliIsCjsResolver { let resolver = self.get_scope_resolver(file_referrer); resolver.is_cjs_resolver.as_ref() } @@ -382,7 +431,7 @@ impl LspResolver { pub fn in_npm_pkg_checker( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> &Arc { + ) -> &DenoInNpmPackageChecker { let resolver = self.get_scope_resolver(file_referrer); &resolver.in_npm_pkg_checker } @@ -390,7 +439,7 @@ impl LspResolver { pub fn maybe_managed_npm_resolver( &self, file_referrer: Option<&ModuleSpecifier>, - ) -> Option<&ManagedCliNpmResolver> { + ) -> Option<&CliManagedNpmResolver> { let resolver = self.get_scope_resolver(file_referrer); resolver.npm_resolver.as_ref().and_then(|r| r.as_managed()) } @@ -605,13 +654,14 @@ pub struct ScopeDepInfo { struct ResolverFactoryServices { cli_resolver: Deferred>, found_pkg_json_dep_flag: Arc, - in_npm_pkg_checker: Deferred>, - is_cjs_resolver: Deferred>, + in_npm_pkg_checker: Deferred, + is_cjs_resolver: Deferred>, node_resolver: Deferred>>, npm_graph_resolver: Deferred>, npm_installer: Option>, npm_pkg_req_resolver: Deferred>>, - npm_resolver: Option>, + npm_resolver: Option, + npm_resolution: Arc, } struct ResolverFactory<'a> { @@ -686,10 +736,9 @@ impl<'a> ResolverFactory<'a> { npm_client.clone(), npmrc.clone(), )); - let npm_resolution = Arc::new(NpmResolutionCell::default()); let npm_resolution_initializer = Arc::new(NpmResolutionInitializer::new( registry_info_provider.clone(), - npm_resolution.clone(), + self.services.npm_resolution.clone(), match self.config_data.and_then(|d| d.lockfile.as_ref()) { Some(lockfile) => { CliNpmResolverManagedSnapshotOption::ResolveFromLockfile( @@ -712,13 +761,13 @@ impl<'a> ResolverFactory<'a> { )); let npm_resolution_installer = Arc::new(NpmResolutionInstaller::new( registry_info_provider, - npm_resolution.clone(), + self.services.npm_resolution.clone(), maybe_lockfile.clone(), )); let npm_installer = Arc::new(NpmInstaller::new( npm_cache.clone(), Arc::new(NpmInstallDepsProvider::empty()), - npm_resolution.clone(), + self.services.npm_resolution.clone(), npm_resolution_initializer.clone(), npm_resolution_installer, &pb, @@ -745,22 +794,22 @@ impl<'a> ResolverFactory<'a> { npm_cache_dir, maybe_node_modules_path, npmrc, - npm_resolution, + npm_resolution: self.services.npm_resolution.clone(), npm_system_info: NpmSystemInfo::default(), }) }; - self.set_npm_resolver(create_cli_npm_resolver(options)); + self.set_npm_resolver(CliNpmResolver::new(options)); } pub fn set_npm_installer(&mut self, npm_installer: Arc) { self.services.npm_installer = Some(npm_installer); } - pub fn set_npm_resolver(&mut self, npm_resolver: Arc) { + pub fn set_npm_resolver(&mut self, npm_resolver: CliNpmResolver) { self.services.npm_resolver = Some(npm_resolver); } - pub fn npm_resolver(&self) -> Option<&Arc> { + pub fn npm_resolver(&self) -> Option<&CliNpmResolver> { self.services.npm_resolver.as_ref() } @@ -825,29 +874,27 @@ impl<'a> ResolverFactory<'a> { &self.pkg_json_resolver } - pub fn in_npm_pkg_checker(&self) -> &Arc { + pub fn in_npm_pkg_checker(&self) -> &DenoInNpmPackageChecker { self.services.in_npm_pkg_checker.get_or_init(|| { - deno_resolver::npm::create_in_npm_pkg_checker( - match self.services.npm_resolver.as_ref().map(|r| r.as_inner()) { - Some(crate::npm::InnerCliNpmResolverRef::Byonm(_)) | None => { - CreateInNpmPkgCheckerOptions::Byonm - } - Some(crate::npm::InnerCliNpmResolverRef::Managed(m)) => { - CreateInNpmPkgCheckerOptions::Managed( - ManagedInNpmPkgCheckerCreateOptions { - root_cache_dir_url: m.global_cache_root_url(), - maybe_node_modules_path: m.maybe_node_modules_path(), - }, - ) - } - }, - ) + DenoInNpmPackageChecker::new(match &self.services.npm_resolver { + Some(CliNpmResolver::Byonm(_)) | None => { + CreateInNpmPkgCheckerOptions::Byonm + } + Some(CliNpmResolver::Managed(m)) => { + CreateInNpmPkgCheckerOptions::Managed( + ManagedInNpmPkgCheckerCreateOptions { + root_cache_dir_url: m.global_cache_root_url(), + maybe_node_modules_path: m.root_node_modules_path(), + }, + ) + } + }) }) } - pub fn is_cjs_resolver(&self) -> &Arc { + pub fn is_cjs_resolver(&self) -> &Arc { self.services.is_cjs_resolver.get_or_init(|| { - Arc::new(IsCjsResolver::new( + Arc::new(CliIsCjsResolver::new( self.in_npm_pkg_checker().clone(), self.pkg_json_resolver().clone(), if self @@ -871,7 +918,7 @@ impl<'a> ResolverFactory<'a> { Some(Arc::new(CliNodeResolver::new( self.in_npm_pkg_checker().clone(), RealIsBuiltInNodeModuleChecker, - npm_resolver.clone().into_npm_pkg_folder_resolver(), + npm_resolver.clone(), self.pkg_json_resolver.clone(), self.sys.clone(), node_resolver::ConditionsFromResolutionMode::default(), @@ -890,7 +937,7 @@ impl<'a> ResolverFactory<'a> { Some(Arc::new(CliNpmReqResolver::new(NpmReqResolverOptions { in_npm_pkg_checker: self.in_npm_pkg_checker().clone(), node_resolver: node_resolver.clone(), - npm_resolver: npm_resolver.clone().into_byonm_or_managed(), + npm_resolver: npm_resolver.clone(), sys: self.sys.clone(), }))) }) diff --git a/cli/module_loader.rs b/cli/module_loader.rs index ba53077a3c..daeb4dda37 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -39,6 +39,7 @@ use deno_graph::ModuleGraph; use deno_graph::ModuleGraphError; use deno_graph::Resolution; use deno_graph::WasmModule; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_runtime::code_cache; use deno_runtime::deno_node::create_host_defined_options; use deno_runtime::deno_node::NodeRequireLoader; @@ -70,7 +71,7 @@ use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; use crate::npm::NpmRegistryReadPermissionChecker; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::resolver::CliNpmReqResolver; use crate::resolver::CliResolver; use crate::resolver::ModuleCodeStringSource; @@ -233,10 +234,10 @@ struct SharedCliModuleLoaderState { initial_cwd: PathBuf, is_inspecting: bool, is_repl: bool, - cjs_tracker: Arc, + cjs_tracker: Arc, code_cache: Option>, emitter: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, main_module_graph_container: Arc, module_load_preparer: Arc, node_code_translator: Arc, @@ -244,7 +245,7 @@ struct SharedCliModuleLoaderState { npm_module_loader: NpmModuleLoader, npm_registry_permission_checker: Arc, npm_req_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, sys: CliSys, @@ -294,10 +295,10 @@ impl CliModuleLoaderFactory { #[allow(clippy::too_many_arguments)] pub fn new( options: &CliOptions, - cjs_tracker: Arc, + cjs_tracker: Arc, code_cache: Option>, emitter: Arc, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, main_module_graph_container: Arc, module_load_preparer: Arc, node_code_translator: Arc, @@ -305,7 +306,7 @@ impl CliModuleLoaderFactory { npm_module_loader: NpmModuleLoader, npm_registry_permission_checker: Arc, npm_req_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, parsed_source_cache: Arc, resolver: Arc, sys: CliSys, @@ -1139,11 +1140,11 @@ impl ModuleGraphUpdatePermit for WorkerModuleGraphUpdatePermit { #[derive(Debug)] struct CliNodeRequireLoader { - cjs_tracker: Arc, + cjs_tracker: Arc, emitter: Arc, sys: CliSys, graph_container: TGraphContainer, - in_npm_pkg_checker: Arc, + in_npm_pkg_checker: DenoInNpmPackageChecker, npm_registry_permission_checker: Arc, } diff --git a/cli/node.rs b/cli/node.rs index aa44dcab18..892e25914a 100644 --- a/cli/node.rs +++ b/cli/node.rs @@ -7,6 +7,7 @@ use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; use deno_graph::ParsedSourceStore; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_runtime::deno_fs; use deno_runtime::deno_node::RealIsBuiltInNodeModuleChecker; use node_resolver::analyze::CjsAnalysis as ExtNodeCjsAnalysis; @@ -19,15 +20,22 @@ use serde::Serialize; use crate::cache::CacheDBHash; use crate::cache::NodeAnalysisCache; use crate::cache::ParsedSourceCache; -use crate::resolver::CjsTracker; +use crate::npm::CliNpmResolver; +use crate::resolver::CliCjsTracker; use crate::sys::CliSys; pub type CliNodeCodeTranslator = NodeCodeTranslator< CliCjsCodeAnalyzer, + DenoInNpmPackageChecker, RealIsBuiltInNodeModuleChecker, + CliNpmResolver, + CliSys, +>; +pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver< + DenoInNpmPackageChecker, + CliNpmResolver, CliSys, >; -pub type CliNodeResolver = deno_runtime::deno_node::NodeResolver; pub type CliPackageJsonResolver = node_resolver::PackageJsonResolver; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -43,7 +51,7 @@ pub enum CliCjsAnalysis { pub struct CliCjsCodeAnalyzer { cache: NodeAnalysisCache, - cjs_tracker: Arc, + cjs_tracker: Arc, fs: deno_fs::FileSystemRc, parsed_source_cache: Option>, } @@ -51,7 +59,7 @@ pub struct CliCjsCodeAnalyzer { impl CliCjsCodeAnalyzer { pub fn new( cache: NodeAnalysisCache, - cjs_tracker: Arc, + cjs_tracker: Arc, fs: deno_fs::FileSystemRc, parsed_source_cache: Option>, ) -> Self { diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index bd29a6ec72..8dc498bb04 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -1,21 +1,12 @@ // Copyright 2018-2025 the Deno authors. MIT license. -use std::path::Path; -use std::path::PathBuf; use std::sync::Arc; use deno_core::serde_json; -use deno_core::url::Url; use deno_resolver::npm::ByonmNpmResolver; use deno_resolver::npm::ByonmNpmResolverCreateOptions; -use deno_resolver::npm::ByonmOrManagedNpmResolver; -use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; use deno_runtime::ops::process::NpmProcessStateProvider; -use deno_semver::package::PackageReq; -use node_resolver::NpmPackageFolderResolver; -use super::CliNpmResolver; -use super::InnerCliNpmResolverRef; use crate::args::NpmProcessState; use crate::args::NpmProcessStateKind; use crate::sys::CliSys; @@ -24,67 +15,18 @@ pub type CliByonmNpmResolverCreateOptions = ByonmNpmResolverCreateOptions; pub type CliByonmNpmResolver = ByonmNpmResolver; -// todo(dsherret): the services hanging off `CliNpmResolver` doesn't seem ideal. We should probably decouple. #[derive(Debug)] -struct CliByonmWrapper(Arc); +pub struct CliByonmNpmProcessStateProvider(pub Arc); -impl NpmProcessStateProvider for CliByonmWrapper { +impl NpmProcessStateProvider for CliByonmNpmProcessStateProvider { fn get_npm_process_state(&self) -> String { serde_json::to_string(&NpmProcessState { kind: NpmProcessStateKind::Byonm, local_node_modules_path: self .0 - .root_node_modules_dir() + .root_node_modules_path() .map(|p| p.to_string_lossy().to_string()), }) .unwrap() } } - -impl CliNpmResolver for CliByonmNpmResolver { - fn into_npm_pkg_folder_resolver( - self: Arc, - ) -> Arc { - self - } - - fn into_process_state_provider( - self: Arc, - ) -> Arc { - Arc::new(CliByonmWrapper(self)) - } - - fn into_byonm_or_managed( - self: Arc, - ) -> ByonmOrManagedNpmResolver { - ByonmOrManagedNpmResolver::Byonm(self) - } - - fn clone_snapshotted(&self) -> Arc { - Arc::new(self.clone()) - } - - fn as_inner(&self) -> InnerCliNpmResolverRef { - InnerCliNpmResolverRef::Byonm(self) - } - - fn root_node_modules_path(&self) -> Option<&Path> { - self.root_node_modules_dir() - } - - fn check_state_hash(&self) -> Option { - // it is very difficult to determine the check state hash for byonm - // so we just return None to signify check caching is not supported - None - } - - fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - referrer: &Url, - ) -> Result { - self - .resolve_pkg_folder_from_deno_module_req(req, referrer) - .map_err(ResolvePkgFolderFromDenoReqError::Byonm) - } -} diff --git a/cli/npm/managed.rs b/cli/npm/managed.rs index 0d4c209acc..4122c881f1 100644 --- a/cli/npm/managed.rs +++ b/cli/npm/managed.rs @@ -4,44 +4,28 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; -use deno_ast::ModuleSpecifier; -use deno_cache_dir::npm::NpmCacheDir; use deno_core::parking_lot::Mutex; use deno_core::serde_json; -use deno_core::url::Url; use deno_error::JsError; use deno_error::JsErrorBox; -use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmRegistryApi; use deno_npm::resolution::NpmResolutionSnapshot; -use deno_npm::resolution::PackageReqNotFoundError; use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; -use deno_npm::NpmPackageId; -use deno_npm::NpmResolutionPackage; -use deno_npm::NpmSystemInfo; +use deno_resolver::npm::managed::ManagedNpmResolverCreateOptions; use deno_resolver::npm::managed::NpmResolutionCell; -use deno_resolver::npm::managed::ResolvePkgFolderFromDenoModuleError; -use deno_resolver::npm::managed::ResolvePkgFolderFromPkgIdError; -use deno_resolver::npm::managed::ResolvePkgIdFromSpecifierError; -use deno_resolver::npm::ByonmOrManagedNpmResolver; -use deno_resolver::npm::ManagedNpmResolver; -use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; +use deno_resolver::npm::ManagedNpmResolverRc; use deno_runtime::ops::process::NpmProcessStateProvider; -use deno_semver::package::PackageNv; -use deno_semver::package::PackageReq; -use node_resolver::NpmPackageFolderResolver; -use sys_traits::FsMetadata; use thiserror::Error; use super::CliNpmRegistryInfoProvider; -use super::CliNpmResolver; -use super::InnerCliNpmResolverRef; use crate::args::CliLockfile; use crate::args::NpmProcessState; use crate::args::NpmProcessStateKind; -use crate::cache::FastInsecureHasher; use crate::sys::CliSys; +pub type CliManagedNpmResolverCreateOptions = + ManagedNpmResolverCreateOptions; + #[derive(Debug, Clone)] pub enum CliNpmResolverManagedSnapshotOption { ResolveFromLockfile(Arc), @@ -139,36 +123,6 @@ impl NpmResolutionInitializer { } } -pub struct CliManagedNpmResolverCreateOptions { - pub npm_cache_dir: Arc, - pub sys: CliSys, - pub maybe_node_modules_path: Option, - pub npm_system_info: NpmSystemInfo, - pub npmrc: Arc, - pub npm_resolution: Arc, -} - -pub fn create_managed_npm_resolver( - options: CliManagedNpmResolverCreateOptions, -) -> Arc { - let managed_npm_resolver = - Arc::new(ManagedNpmResolver::::new::( - &options.npm_cache_dir, - &options.npmrc, - options.npm_resolution.clone(), - options.sys.clone(), - options.maybe_node_modules_path, - )); - Arc::new(ManagedCliNpmResolver::new( - managed_npm_resolver, - options.npm_cache_dir, - options.npmrc, - options.npm_resolution, - options.sys, - options.npm_system_info, - )) -} - #[derive(Debug, Error, Clone, JsError)] #[error("failed reading lockfile '{}'", lockfile_path.display())] #[class(inherit)] @@ -254,145 +208,6 @@ async fn snapshot_from_lockfile( Ok(snapshot) } -/// An npm resolver where the resolution is managed by Deno rather than -/// the user bringing their own node_modules (BYONM) on the file system. -pub struct ManagedCliNpmResolver { - managed_npm_resolver: Arc>, - npm_cache_dir: Arc, - npm_rc: Arc, - sys: CliSys, - resolution: Arc, - system_info: NpmSystemInfo, -} - -impl std::fmt::Debug for ManagedCliNpmResolver { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ManagedCliNpmResolver") - .field("", &"") - .finish() - } -} - -impl ManagedCliNpmResolver { - #[allow(clippy::too_many_arguments)] - pub fn new( - managed_npm_resolver: Arc>, - npm_cache_dir: Arc, - npm_rc: Arc, - resolution: Arc, - sys: CliSys, - system_info: NpmSystemInfo, - ) -> Self { - Self { - managed_npm_resolver, - npm_cache_dir, - npm_rc, - resolution, - sys, - system_info, - } - } - - pub fn resolve_pkg_folder_from_pkg_id( - &self, - pkg_id: &NpmPackageId, - ) -> Result { - self - .managed_npm_resolver - .resolve_pkg_folder_from_pkg_id(pkg_id) - } - - /// Resolves the package id from the provided specifier. - pub fn resolve_pkg_id_from_specifier( - &self, - specifier: &ModuleSpecifier, - ) -> Result, ResolvePkgIdFromSpecifierError> { - self - .managed_npm_resolver - .resolve_pkg_id_from_specifier(specifier) - } - - pub fn resolve_pkg_reqs_from_pkg_id( - &self, - id: &NpmPackageId, - ) -> Vec { - self.resolution.resolve_pkg_reqs_from_pkg_id(id) - } - - pub fn all_system_packages( - &self, - system_info: &NpmSystemInfo, - ) -> Vec { - self.resolution.all_system_packages(system_info) - } - - /// Checks if the provided package req's folder is cached. - pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool { - self - .resolve_pkg_id_from_pkg_req(req) - .ok() - .and_then(|id| { - self - .managed_npm_resolver - .resolve_pkg_folder_from_pkg_id(&id) - .ok() - }) - .map(|folder| self.sys.fs_exists_no_err(folder)) - .unwrap_or(false) - } - - pub fn snapshot(&self) -> NpmResolutionSnapshot { - self.resolution.snapshot() - } - - pub fn top_package_req_for_name(&self, name: &str) -> Option { - let package_reqs = self.resolution.package_reqs(); - let mut entries = package_reqs - .iter() - .filter(|(_, nv)| nv.name == name) - .collect::>(); - entries.sort_by_key(|(_, nv)| &nv.version); - Some(entries.last()?.0.clone()) - } - - pub fn serialized_valid_snapshot_for_system( - &self, - system_info: &NpmSystemInfo, - ) -> ValidSerializedNpmResolutionSnapshot { - self - .resolution - .serialized_valid_snapshot_for_system(system_info) - } - - pub fn resolve_pkg_folder_from_deno_module( - &self, - nv: &PackageNv, - ) -> Result { - self - .managed_npm_resolver - .resolve_pkg_folder_from_deno_module(nv) - } - - pub fn resolve_pkg_id_from_pkg_req( - &self, - req: &PackageReq, - ) -> Result { - self.resolution.resolve_pkg_id_from_pkg_req(req) - } - - pub fn maybe_node_modules_path(&self) -> Option<&Path> { - self.managed_npm_resolver.node_modules_path() - } - - pub fn global_cache_root_path(&self) -> &Path { - self.npm_cache_dir.root_dir() - } - - pub fn global_cache_root_url(&self) -> &Url { - self.npm_cache_dir.root_dir_url() - } -} - pub fn npm_process_state( snapshot: ValidSerializedNpmResolutionSnapshot, node_modules_path: Option<&Path>, @@ -405,92 +220,14 @@ pub fn npm_process_state( .unwrap() } -impl NpmProcessStateProvider for ManagedCliNpmResolver { +#[derive(Debug)] +pub struct CliManagedNpmProcessStateProvider(pub ManagedNpmResolverRc); + +impl NpmProcessStateProvider for CliManagedNpmProcessStateProvider { fn get_npm_process_state(&self) -> String { npm_process_state( - self.resolution.serialized_valid_snapshot(), - self.managed_npm_resolver.node_modules_path(), + self.0.resolution().serialized_valid_snapshot(), + self.0.root_node_modules_path(), ) } } - -impl CliNpmResolver for ManagedCliNpmResolver { - fn into_npm_pkg_folder_resolver( - self: Arc, - ) -> Arc { - self.managed_npm_resolver.clone() - } - - fn into_process_state_provider( - self: Arc, - ) -> Arc { - self - } - - fn into_byonm_or_managed( - self: Arc, - ) -> ByonmOrManagedNpmResolver { - ByonmOrManagedNpmResolver::Managed(self.managed_npm_resolver.clone()) - } - - fn clone_snapshotted(&self) -> Arc { - // create a new snapshotted npm resolution and resolver - let npm_resolution = - Arc::new(NpmResolutionCell::new(self.resolution.snapshot())); - - Arc::new(ManagedCliNpmResolver::new( - Arc::new(ManagedNpmResolver::::new::( - &self.npm_cache_dir, - &self.npm_rc, - npm_resolution.clone(), - self.sys.clone(), - self.root_node_modules_path().map(ToOwned::to_owned), - )), - self.npm_cache_dir.clone(), - self.npm_rc.clone(), - npm_resolution, - self.sys.clone(), - self.system_info.clone(), - )) - } - - fn as_inner(&self) -> InnerCliNpmResolverRef { - InnerCliNpmResolverRef::Managed(self) - } - - fn root_node_modules_path(&self) -> Option<&Path> { - self.managed_npm_resolver.node_modules_path() - } - - fn check_state_hash(&self) -> Option { - // We could go further and check all the individual - // npm packages, but that's probably overkill. - let mut package_reqs = self - .resolution - .package_reqs() - .into_iter() - .collect::>(); - package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism - let mut hasher = FastInsecureHasher::new_without_deno_version(); - // ensure the cache gets busted when turning nodeModulesDir on or off - // as this could cause changes in resolution - hasher - .write_hashable(self.managed_npm_resolver.node_modules_path().is_some()); - for (pkg_req, pkg_nv) in package_reqs { - hasher.write_hashable(&pkg_req); - hasher.write_hashable(&pkg_nv); - } - Some(hasher.finish()) - } - - fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - referrer: &Url, - ) -> Result { - self - .managed_npm_resolver - .resolve_pkg_folder_from_deno_module_req(req, referrer) - .map_err(ResolvePkgFolderFromDenoReqError::Managed) - } -} diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 6ad7ad610e..1c12ce6c59 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -5,8 +5,6 @@ pub mod installer; mod managed; mod permission_checker; -use std::path::Path; -use std::path::PathBuf; use std::sync::Arc; use dashmap::DashMap; @@ -15,21 +13,15 @@ use deno_core::url::Url; use deno_error::JsErrorBox; use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::registry::NpmPackageInfo; -use deno_resolver::npm::ByonmNpmResolver; -use deno_resolver::npm::ByonmOrManagedNpmResolver; -use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; -use deno_runtime::ops::process::NpmProcessStateProvider; +use deno_runtime::ops::process::NpmProcessStateProviderRc; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; use http::HeaderName; use http::HeaderValue; -use node_resolver::NpmPackageFolderResolver; -pub use self::byonm::CliByonmNpmResolver; pub use self::byonm::CliByonmNpmResolverCreateOptions; pub use self::managed::CliManagedNpmResolverCreateOptions; pub use self::managed::CliNpmResolverManagedSnapshotOption; -pub use self::managed::ManagedCliNpmResolver; pub use self::managed::NpmResolutionInitializer; pub use self::managed::ResolveSnapshotError; pub use self::permission_checker::NpmRegistryReadPermissionChecker; @@ -44,6 +36,10 @@ pub type CliNpmTarballCache = pub type CliNpmCache = deno_npm_cache::NpmCache; pub type CliNpmRegistryInfoProvider = deno_npm_cache::RegistryInfoProvider; +pub type CliNpmResolver = deno_resolver::npm::NpmResolver; +pub type CliManagedNpmResolver = deno_resolver::npm::ManagedNpmResolver; +pub type CliNpmResolverCreateOptions = + deno_resolver::npm::NpmResolverCreateOptions; #[derive(Debug)] pub struct CliNpmCacheHttpClient { @@ -63,6 +59,19 @@ impl CliNpmCacheHttpClient { } } +pub fn create_npm_process_state_provider( + npm_resolver: &CliNpmResolver, +) -> NpmProcessStateProviderRc { + match npm_resolver { + CliNpmResolver::Byonm(byonm_npm_resolver) => Arc::new( + byonm::CliByonmNpmProcessStateProvider(byonm_npm_resolver.clone()), + ), + CliNpmResolver::Managed(managed_npm_resolver) => Arc::new( + managed::CliManagedNpmProcessStateProvider(managed_npm_resolver.clone()), + ), + } +} + #[async_trait::async_trait(?Send)] impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient { async fn download_with_retries_on_any_tokio_runtime( @@ -104,70 +113,6 @@ impl deno_npm_cache::NpmCacheHttpClient for CliNpmCacheHttpClient { } } -pub enum CliNpmResolverCreateOptions { - Managed(CliManagedNpmResolverCreateOptions), - Byonm(CliByonmNpmResolverCreateOptions), -} - -pub fn create_cli_npm_resolver( - options: CliNpmResolverCreateOptions, -) -> Arc { - use CliNpmResolverCreateOptions::*; - match options { - Managed(options) => managed::create_managed_npm_resolver(options), - Byonm(options) => Arc::new(ByonmNpmResolver::new(options)), - } -} - -pub enum InnerCliNpmResolverRef<'a> { - Managed(&'a ManagedCliNpmResolver), - #[allow(dead_code)] - Byonm(&'a CliByonmNpmResolver), -} - -// todo(dsherret): replace with an enum -pub trait CliNpmResolver: Send + Sync + std::fmt::Debug { - fn into_npm_pkg_folder_resolver( - self: Arc, - ) -> Arc; - fn into_process_state_provider( - self: Arc, - ) -> Arc; - fn into_byonm_or_managed( - self: Arc, - ) -> ByonmOrManagedNpmResolver; - - fn clone_snapshotted(&self) -> Arc; - - fn as_inner(&self) -> InnerCliNpmResolverRef; - - fn as_managed(&self) -> Option<&ManagedCliNpmResolver> { - match self.as_inner() { - InnerCliNpmResolverRef::Managed(inner) => Some(inner), - InnerCliNpmResolverRef::Byonm(_) => None, - } - } - - fn as_byonm(&self) -> Option<&CliByonmNpmResolver> { - match self.as_inner() { - InnerCliNpmResolverRef::Managed(_) => None, - InnerCliNpmResolverRef::Byonm(inner) => Some(inner), - } - } - - fn resolve_pkg_folder_from_deno_module_req( - &self, - req: &PackageReq, - referrer: &Url, - ) -> Result; - - fn root_node_modules_path(&self) -> Option<&Path>; - - /// Returns a hash returning the state of the npm resolver - /// or `None` if the state currently can't be determined. - fn check_state_hash(&self) -> Option; -} - #[derive(Debug)] pub struct NpmFetchResolver { nv_by_req: DashMap>, diff --git a/cli/resolver.rs b/cli/resolver.rs index 2f3d42e9e1..5677767fdd 100644 --- a/cli/resolver.rs +++ b/cli/resolver.rs @@ -19,6 +19,7 @@ use deno_graph::source::UnknownBuiltInNodeModuleError; use deno_graph::NpmLoadError; use deno_graph::NpmResolvePkgReqsResult; use deno_npm::resolution::NpmResolutionError; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::sloppy_imports::SloppyImportsCachedFs; use deno_resolver::sloppy_imports::SloppyImportsResolver; use deno_runtime::colors; @@ -35,22 +36,31 @@ use crate::args::DENO_DISABLE_PEDANTIC_NODE_WARNINGS; use crate::node::CliNodeCodeTranslator; use crate::npm::installer::NpmInstaller; use crate::npm::installer::PackageCaching; +use crate::npm::CliNpmResolver; use crate::sys::CliSys; use crate::util::sync::AtomicFlag; use crate::util::text_encoding::from_utf8_lossy_cow; -pub type CjsTracker = deno_resolver::cjs::CjsTracker; -pub type IsCjsResolver = deno_resolver::cjs::IsCjsResolver; +pub type CliCjsTracker = + deno_resolver::cjs::CjsTracker; +pub type CliIsCjsResolver = + deno_resolver::cjs::IsCjsResolver; pub type CliSloppyImportsCachedFs = SloppyImportsCachedFs; pub type CliSloppyImportsResolver = SloppyImportsResolver; pub type CliDenoResolver = deno_resolver::DenoResolver< + DenoInNpmPackageChecker, RealIsBuiltInNodeModuleChecker, + CliNpmResolver, CliSloppyImportsCachedFs, CliSys, >; -pub type CliNpmReqResolver = - deno_resolver::npm::NpmReqResolver; +pub type CliNpmReqResolver = deno_resolver::npm::NpmReqResolver< + DenoInNpmPackageChecker, + RealIsBuiltInNodeModuleChecker, + CliNpmResolver, + CliSys, +>; pub struct ModuleCodeStringSource { pub code: ModuleSourceCode, @@ -69,14 +79,14 @@ pub struct NotSupportedKindInNpmError { // todo(dsherret): move to module_loader.rs (it seems to be here due to use in standalone) #[derive(Clone)] pub struct NpmModuleLoader { - cjs_tracker: Arc, + cjs_tracker: Arc, fs: Arc, node_code_translator: Arc, } impl NpmModuleLoader { pub fn new( - cjs_tracker: Arc, + cjs_tracker: Arc, fs: Arc, node_code_translator: Arc, ) -> Self { diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs index ff0343e27f..c9b57f3d6b 100644 --- a/cli/standalone/binary.rs +++ b/cli/standalone/binary.rs @@ -92,8 +92,7 @@ use crate::emit::Emitter; use crate::file_fetcher::CliFileFetcher; use crate::http_util::HttpClientProvider; use crate::npm::CliNpmResolver; -use crate::npm::InnerCliNpmResolverRef; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::shared::ReleaseChannel; use crate::standalone::virtual_fs::VfsEntry; use crate::util::archive; @@ -410,13 +409,13 @@ pub struct WriteBinOptions<'a> { } pub struct DenoCompileBinaryWriter<'a> { - cjs_tracker: &'a CjsTracker, + cjs_tracker: &'a CliCjsTracker, cli_options: &'a CliOptions, deno_dir: &'a DenoDir, emitter: &'a Emitter, file_fetcher: &'a CliFileFetcher, http_client_provider: &'a HttpClientProvider, - npm_resolver: &'a dyn CliNpmResolver, + npm_resolver: &'a CliNpmResolver, workspace_resolver: &'a WorkspaceResolver, npm_system_info: NpmSystemInfo, } @@ -424,13 +423,13 @@ pub struct DenoCompileBinaryWriter<'a> { impl<'a> DenoCompileBinaryWriter<'a> { #[allow(clippy::too_many_arguments)] pub fn new( - cjs_tracker: &'a CjsTracker, + cjs_tracker: &'a CliCjsTracker, cli_options: &'a CliOptions, deno_dir: &'a DenoDir, emitter: &'a Emitter, file_fetcher: &'a CliFileFetcher, http_client_provider: &'a HttpClientProvider, - npm_resolver: &'a dyn CliNpmResolver, + npm_resolver: &'a CliNpmResolver, workspace_resolver: &'a WorkspaceResolver, npm_system_info: NpmSystemInfo, ) -> Self { @@ -599,10 +598,11 @@ impl<'a> DenoCompileBinaryWriter<'a> { None => None, }; let mut vfs = VfsBuilder::new(); - let npm_snapshot = match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(managed) => { - let snapshot = - managed.serialized_valid_snapshot_for_system(&self.npm_system_info); + let npm_snapshot = match &self.npm_resolver { + CliNpmResolver::Managed(managed) => { + let snapshot = managed + .resolution() + .serialized_valid_snapshot_for_system(&self.npm_system_info); if !snapshot.as_serialized().packages.is_empty() { self.fill_npm_vfs(&mut vfs).context("Building npm vfs.")?; Some(snapshot) @@ -610,7 +610,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { None } } - InnerCliNpmResolverRef::Byonm(_) => { + CliNpmResolver::Byonm(_) => { self.fill_npm_vfs(&mut vfs)?; None } @@ -751,8 +751,8 @@ impl<'a> DenoCompileBinaryWriter<'a> { ); } - let node_modules = match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(_) => { + let node_modules = match &self.npm_resolver { + CliNpmResolver::Managed(_) => { npm_snapshot.as_ref().map(|_| NodeModules::Managed { node_modules_dir: self.npm_resolver.root_node_modules_path().map( |path| { @@ -765,7 +765,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { ), }) } - InnerCliNpmResolverRef::Byonm(resolver) => Some(NodeModules::Byonm { + CliNpmResolver::Byonm(resolver) => Some(NodeModules::Byonm { root_node_modules_dir: resolver.root_node_modules_path().map( |node_modules_dir| { root_dir_url @@ -880,16 +880,17 @@ impl<'a> DenoCompileBinaryWriter<'a> { } } - match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(npm_resolver) => { + match &self.npm_resolver { + CliNpmResolver::Managed(npm_resolver) => { if let Some(node_modules_path) = npm_resolver.root_node_modules_path() { maybe_warn_different_system(&self.npm_system_info); builder.add_dir_recursive(node_modules_path)?; Ok(()) } else { // we'll flatten to remove any custom registries later - let mut packages = - npm_resolver.all_system_packages(&self.npm_system_info); + let mut packages = npm_resolver + .resolution() + .all_system_packages(&self.npm_system_info); packages.sort_by(|a, b| a.id.cmp(&b.id)); // determinism for package in packages { let folder = @@ -899,7 +900,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { Ok(()) } } - InnerCliNpmResolverRef::Byonm(_) => { + CliNpmResolver::Byonm(_) => { maybe_warn_different_system(&self.npm_system_info); for pkg_json in self.cli_options.workspace().package_jsons() { builder.add_file_at_path(&pkg_json.path)?; @@ -942,8 +943,8 @@ impl<'a> DenoCompileBinaryWriter<'a> { &self, mut vfs: VfsBuilder, ) -> BuiltVfs { - match self.npm_resolver.as_inner() { - InnerCliNpmResolverRef::Managed(npm_resolver) => { + match &self.npm_resolver { + CliNpmResolver::Managed(npm_resolver) => { if npm_resolver.root_node_modules_path().is_some() { return vfs.build(); } @@ -1035,7 +1036,7 @@ impl<'a> DenoCompileBinaryWriter<'a> { .insert(npm_global_cache_dir_entry, case_sensitivity); built_vfs } - InnerCliNpmResolverRef::Byonm(_) => vfs.build(), + CliNpmResolver::Byonm(_) => vfs.build(), } } } diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 4ca82f6b7d..876c194ed1 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -40,10 +40,11 @@ use deno_npm::npm_rc::ResolvedNpmRc; use deno_npm::resolution::NpmResolutionSnapshot; use deno_package_json::PackageJsonDepValue; use deno_resolver::cjs::IsCjsResolutionMode; -use deno_resolver::npm::create_in_npm_pkg_checker; use deno_resolver::npm::managed::ManagedInNpmPkgCheckerCreateOptions; use deno_resolver::npm::managed::NpmResolutionCell; +use deno_resolver::npm::ByonmNpmResolverCreateOptions; use deno_resolver::npm::CreateInNpmPkgCheckerOptions; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_resolver::npm::NpmReqResolverOptions; use deno_runtime::deno_fs; use deno_runtime::deno_fs::FileSystem; @@ -85,7 +86,6 @@ use crate::node::CliCjsCodeAnalyzer; use crate::node::CliNodeCodeTranslator; use crate::node::CliNodeResolver; use crate::node::CliPackageJsonResolver; -use crate::npm::create_cli_npm_resolver; use crate::npm::CliByonmNpmResolverCreateOptions; use crate::npm::CliManagedNpmResolverCreateOptions; use crate::npm::CliNpmResolver; @@ -94,7 +94,7 @@ use crate::npm::CliNpmResolverManagedSnapshotOption; use crate::npm::NpmRegistryReadPermissionChecker; use crate::npm::NpmRegistryReadPermissionCheckerMode; use crate::npm::NpmResolutionInitializer; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::resolver::CliNpmReqResolver; use crate::resolver::NpmModuleLoader; use crate::sys::CliSys; @@ -122,7 +122,7 @@ use self::binary::Metadata; pub use self::file_system::DenoCompileFileSystem; struct SharedModuleLoaderState { - cjs_tracker: Arc, + cjs_tracker: Arc, code_cache: Option>, fs: Arc, modules: StandaloneModules, @@ -131,7 +131,7 @@ struct SharedModuleLoaderState { npm_module_loader: Arc, npm_registry_permission_checker: NpmRegistryReadPermissionChecker, npm_req_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, source_maps: SourceMapStore, vfs: Arc, workspace_resolver: WorkspaceResolver, @@ -734,7 +734,7 @@ pub async fn run( let maybe_node_modules_path = node_modules_dir .map(|node_modules_dir| root_path.join(node_modules_dir)); let in_npm_pkg_checker = - create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Managed( + DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed( ManagedInNpmPkgCheckerCreateOptions { root_cache_dir_url: npm_cache_dir.root_dir_url(), maybe_node_modules_path: maybe_node_modules_path.as_deref(), @@ -743,7 +743,7 @@ pub async fn run( let npm_resolution = Arc::new(NpmResolutionCell::new(NpmResolutionSnapshot::new(snapshot))); let npm_resolver = - create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed( + CliNpmResolver::new(CliNpmResolverCreateOptions::Managed( CliManagedNpmResolverCreateOptions { npm_resolution, npm_cache_dir, @@ -761,8 +761,8 @@ pub async fn run( let root_node_modules_dir = root_node_modules_dir.map(|p| vfs.root().join(p)); let in_npm_pkg_checker = - create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Byonm); - let npm_resolver = create_cli_npm_resolver( + DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Byonm); + let npm_resolver = CliNpmResolver::new( CliNpmResolverCreateOptions::Byonm(CliByonmNpmResolverCreateOptions { sys: sys.clone(), pkg_json_resolver: pkg_json_resolver.clone(), @@ -781,7 +781,7 @@ pub async fn run( npmrc.get_all_known_registries_urls(), )); let in_npm_pkg_checker = - create_in_npm_pkg_checker(CreateInNpmPkgCheckerOptions::Managed( + DenoInNpmPackageChecker::new(CreateInNpmPkgCheckerOptions::Managed( ManagedInNpmPkgCheckerCreateOptions { root_cache_dir_url: npm_cache_dir.root_dir_url(), maybe_node_modules_path: None, @@ -789,7 +789,7 @@ pub async fn run( )); let npm_resolution = Arc::new(NpmResolutionCell::default()); let npm_resolver = - create_cli_npm_resolver(CliNpmResolverCreateOptions::Managed( + CliNpmResolver::new(CliNpmResolverCreateOptions::Managed( CliManagedNpmResolverCreateOptions { npm_resolution, sys: sys.clone(), @@ -807,12 +807,12 @@ pub async fn run( let node_resolver = Arc::new(NodeResolver::new( in_npm_pkg_checker.clone(), RealIsBuiltInNodeModuleChecker, - npm_resolver.clone().into_npm_pkg_folder_resolver(), + npm_resolver.clone(), pkg_json_resolver.clone(), sys.clone(), node_resolver::ConditionsFromResolutionMode::default(), )); - let cjs_tracker = Arc::new(CjsTracker::new( + let cjs_tracker = Arc::new(CliCjsTracker::new( in_npm_pkg_checker.clone(), pkg_json_resolver.clone(), if metadata.unstable_config.detect_cjs { @@ -830,7 +830,7 @@ pub async fn run( sys: sys.clone(), in_npm_pkg_checker: in_npm_pkg_checker.clone(), node_resolver: node_resolver.clone(), - npm_resolver: npm_resolver.clone().into_byonm_or_managed(), + npm_resolver: npm_resolver.clone(), })); let cjs_esm_code_analyzer = CliCjsCodeAnalyzer::new( node_analysis_cache, @@ -842,7 +842,7 @@ pub async fn run( cjs_esm_code_analyzer, in_npm_pkg_checker, node_resolver.clone(), - npm_resolver.clone().into_npm_pkg_folder_resolver(), + npm_resolver.clone(), pkg_json_resolver.clone(), sys.clone(), )); diff --git a/cli/task_runner.rs b/cli/task_runner.rs index 8510a650e7..50dcd64dc7 100644 --- a/cli/task_runner.rs +++ b/cli/task_runner.rs @@ -25,9 +25,8 @@ use tokio::task::LocalSet; use tokio_util::sync::CancellationToken; use crate::node::CliNodeResolver; +use crate::npm::CliManagedNpmResolver; use crate::npm::CliNpmResolver; -use crate::npm::InnerCliNpmResolverRef; -use crate::npm::ManagedCliNpmResolver; pub fn get_script_with_args(script: &str, argv: &[String]) -> String { let additional_args = argv @@ -414,15 +413,15 @@ impl ShellCommand for NodeModulesFileRunCommand { } pub fn resolve_custom_commands( - npm_resolver: &dyn CliNpmResolver, + npm_resolver: &CliNpmResolver, node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { - let mut commands = match npm_resolver.as_inner() { - InnerCliNpmResolverRef::Byonm(npm_resolver) => { + let mut commands = match npm_resolver { + CliNpmResolver::Byonm(npm_resolver) => { let node_modules_dir = npm_resolver.root_node_modules_path().unwrap(); resolve_npm_commands_from_bin_dir(node_modules_dir) } - InnerCliNpmResolverRef::Managed(npm_resolver) => { + CliNpmResolver::Managed(npm_resolver) => { resolve_managed_npm_commands(npm_resolver, node_resolver)? } }; @@ -521,13 +520,12 @@ fn resolve_execution_path_from_npx_shim( } fn resolve_managed_npm_commands( - npm_resolver: &ManagedCliNpmResolver, + npm_resolver: &CliManagedNpmResolver, node_resolver: &CliNodeResolver, ) -> Result>, AnyError> { let mut result = HashMap::new(); - let snapshot = npm_resolver.snapshot(); - for id in snapshot.top_level_packages() { - let package_folder = npm_resolver.resolve_pkg_folder_from_pkg_id(id)?; + for id in npm_resolver.resolution().top_level_packages() { + let package_folder = npm_resolver.resolve_pkg_folder_from_pkg_id(&id)?; let bin_commands = node_resolver.resolve_binary_commands(&package_folder)?; for bin_command in bin_commands { diff --git a/cli/tools/check.rs b/cli/tools/check.rs index c3a285a9b2..8c584113cb 100644 --- a/cli/tools/check.rs +++ b/cli/tools/check.rs @@ -112,7 +112,7 @@ pub struct TypeChecker { module_graph_builder: Arc, npm_installer: Option>, node_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, sys: CliSys, } @@ -146,7 +146,7 @@ impl TypeChecker { module_graph_builder: Arc, node_resolver: Arc, npm_installer: Option>, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, sys: CliSys, ) -> Self { Self { @@ -189,6 +189,29 @@ impl TypeChecker { mut graph: ModuleGraph, options: CheckOptions, ) -> Result<(Arc, Diagnostics), CheckError> { + fn check_state_hash(resolver: &CliNpmResolver) -> Option { + match resolver { + CliNpmResolver::Byonm(_) => { + // not feasible and probably slower to compute + None + } + CliNpmResolver::Managed(resolver) => { + // we should probably go further and check all the individual npm packages + let mut package_reqs = resolver.resolution().package_reqs(); + package_reqs.sort_by(|a, b| a.0.cmp(&b.0)); // determinism + let mut hasher = FastInsecureHasher::new_without_deno_version(); + // ensure the cache gets busted when turning nodeModulesDir on or off + // as this could cause changes in resolution + hasher.write_hashable(resolver.root_node_modules_path().is_some()); + for (pkg_req, pkg_nv) in package_reqs { + hasher.write_hashable(&pkg_req); + hasher.write_hashable(&pkg_nv); + } + Some(hasher.finish()) + } + } + } + if !options.type_check_mode.is_true() || graph.roots.is_empty() { return Ok((graph.into(), Default::default())); } @@ -240,7 +263,7 @@ impl TypeChecker { &self.sys, &graph, check_js, - self.npm_resolver.check_state_hash(), + check_state_hash(&self.npm_resolver), type_check_mode, &ts_config, ); diff --git a/cli/tools/coverage/mod.rs b/cli/tools/coverage/mod.rs index 06afa5fac2..9b6ef81ea3 100644 --- a/cli/tools/coverage/mod.rs +++ b/cli/tools/coverage/mod.rs @@ -22,6 +22,7 @@ use deno_core::serde_json; use deno_core::sourcemap::SourceMap; use deno_core::url::Url; use deno_core::LocalInspectorSession; +use deno_resolver::npm::DenoInNpmPackageChecker; use node_resolver::InNpmPackageChecker; use regex::Regex; use text_lines::TextLines; @@ -464,7 +465,7 @@ fn filter_coverages( coverages: Vec, include: Vec, exclude: Vec, - in_npm_pkg_checker: &dyn InNpmPackageChecker, + in_npm_pkg_checker: &DenoInNpmPackageChecker, ) -> Vec { let include: Vec = include.iter().map(|e| Regex::new(e).unwrap()).collect(); @@ -532,7 +533,7 @@ pub fn cover_files( script_coverages, coverage_flags.include, coverage_flags.exclude, - in_npm_pkg_checker.as_ref(), + in_npm_pkg_checker, ); if script_coverages.is_empty() { return Err(anyhow!("No covered files included in the report")); diff --git a/cli/tools/info.rs b/cli/tools/info.rs index 50faeda7d3..8c3b2665c5 100644 --- a/cli/tools/info.rs +++ b/cli/tools/info.rs @@ -32,8 +32,7 @@ use crate::args::InfoFlags; use crate::display; use crate::factory::CliFactory; use crate::graph_util::graph_exit_integrity_errors; -use crate::npm::CliNpmResolver; -use crate::npm::ManagedCliNpmResolver; +use crate::npm::CliManagedNpmResolver; use crate::util::checksum; use crate::util::display::DisplayTreeNode; @@ -138,6 +137,10 @@ pub async fn info( lockfile.write_if_changed()?; } + let maybe_npm_info = npm_resolver + .as_managed() + .map(|r| (r, r.resolution().snapshot())); + if info_flags.json { let mut json_graph = serde_json::json!(graph); if let Some(output) = json_graph.as_object_mut() { @@ -148,11 +151,19 @@ pub async fn info( ); } - add_npm_packages_to_json(&mut json_graph, npm_resolver.as_ref(), npmrc); + add_npm_packages_to_json( + &mut json_graph, + maybe_npm_info.as_ref().map(|(_, s)| s), + npmrc, + ); display::write_json_to_stdout(&json_graph)?; } else { let mut output = String::new(); - GraphDisplayContext::write(&graph, npm_resolver.as_ref(), &mut output)?; + GraphDisplayContext::write( + &graph, + maybe_npm_info.as_ref().map(|(r, s)| (*r, s)), + &mut output, + )?; display::write_to_stdout_ignore_sigpipe(output.as_bytes())?; } } else { @@ -251,15 +262,14 @@ fn print_cache_info( fn add_npm_packages_to_json( json: &mut serde_json::Value, - npm_resolver: &dyn CliNpmResolver, + npm_snapshot: Option<&NpmResolutionSnapshot>, npmrc: &ResolvedNpmRc, ) { - let Some(npm_resolver) = npm_resolver.as_managed() else { + let Some(npm_snapshot) = npm_snapshot else { return; // does not include byonm to deno info's output }; // ideally deno_graph could handle this, but for now we just modify the json here - let snapshot = npm_resolver.snapshot(); let json = json.as_object_mut().unwrap(); let modules = json.get_mut("modules").and_then(|m| m.as_array_mut()); if let Some(modules) = modules { @@ -273,7 +283,7 @@ fn add_npm_packages_to_json( .and_then(|k| k.as_str()) .and_then(|specifier| NpmPackageNvReference::from_str(specifier).ok()) .and_then(|package_ref| { - snapshot + npm_snapshot .resolve_package_from_deno_module(package_ref.nv()) .ok() }); @@ -295,7 +305,8 @@ fn add_npm_packages_to_json( if let Some(specifier) = dep.get("specifier").and_then(|s| s.as_str()) { if let Ok(npm_ref) = NpmPackageReqReference::from_str(specifier) { - if let Ok(pkg) = snapshot.resolve_pkg_from_pkg_req(npm_ref.req()) + if let Ok(pkg) = + npm_snapshot.resolve_pkg_from_pkg_req(npm_ref.req()) { dep.insert( "npmPackage".to_string(), @@ -321,8 +332,9 @@ fn add_npm_packages_to_json( } } - let mut sorted_packages = - snapshot.all_packages_for_every_system().collect::>(); + let mut sorted_packages = npm_snapshot + .all_packages_for_every_system() + .collect::>(); sorted_packages.sort_by(|a, b| a.id.cmp(&b.id)); let mut json_packages = serde_json::Map::with_capacity(sorted_packages.len()); for pkg in sorted_packages { @@ -356,7 +368,7 @@ struct NpmInfo { impl NpmInfo { pub fn build<'a>( graph: &'a ModuleGraph, - npm_resolver: &'a ManagedCliNpmResolver, + npm_resolver: &'a CliManagedNpmResolver, npm_snapshot: &'a NpmResolutionSnapshot, ) -> Self { let mut info = NpmInfo::default(); @@ -382,7 +394,7 @@ impl NpmInfo { fn fill_package_info<'a>( &mut self, package: &NpmResolutionPackage, - npm_resolver: &'a ManagedCliNpmResolver, + npm_resolver: &'a CliManagedNpmResolver, npm_snapshot: &'a NpmResolutionSnapshot, ) { self.packages.insert(package.id.clone(), package.clone()); @@ -419,13 +431,15 @@ struct GraphDisplayContext<'a> { impl<'a> GraphDisplayContext<'a> { pub fn write( graph: &'a ModuleGraph, - npm_resolver: &'a dyn CliNpmResolver, + managed_npm_info: Option<( + &'a CliManagedNpmResolver, + &'a NpmResolutionSnapshot, + )>, writer: &mut TWrite, ) -> Result<(), AnyError> { - let npm_info = match npm_resolver.as_managed() { - Some(npm_resolver) => { - let npm_snapshot = npm_resolver.snapshot(); - NpmInfo::build(graph, npm_resolver, &npm_snapshot) + let npm_info = match managed_npm_info { + Some((npm_resolver, npm_snapshot)) => { + NpmInfo::build(graph, npm_resolver, npm_snapshot) } None => NpmInfo::default(), }; diff --git a/cli/tools/registry/pm/deps.rs b/cli/tools/registry/pm/deps.rs index 1dbb464dbe..3d152490e8 100644 --- a/cli/tools/registry/pm/deps.rs +++ b/cli/tools/registry/pm/deps.rs @@ -451,7 +451,7 @@ pub struct DepManager { // TODO(nathanwhit): probably shouldn't be pub pub(crate) jsr_fetch_resolver: Arc, pub(crate) npm_fetch_resolver: Arc, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, npm_installer: Arc, permissions_container: PermissionsContainer, main_module_graph_container: Arc, @@ -463,7 +463,7 @@ pub struct DepManagerArgs { pub jsr_fetch_resolver: Arc, pub npm_fetch_resolver: Arc, pub npm_installer: Arc, - pub npm_resolver: Arc, + pub npm_resolver: CliNpmResolver, pub permissions_container: PermissionsContainer, pub main_module_graph_container: Arc, pub lockfile: Option>, @@ -551,9 +551,10 @@ impl DepManager { let npm_resolver = self.npm_resolver.as_managed().unwrap(); if self.deps.iter().all(|dep| match dep.kind { - DepKind::Npm => { - npm_resolver.resolve_pkg_id_from_pkg_req(&dep.req).is_ok() - } + DepKind::Npm => npm_resolver + .resolution() + .resolve_pkg_id_from_pkg_req(&dep.req) + .is_ok(), DepKind::Jsr => graph.packages.mappings().contains_key(&dep.req), }) { self.dependencies_resolved.raise(); @@ -630,7 +631,12 @@ impl DepManager { let graph = self.main_module_graph_container.graph(); let mut resolved = Vec::with_capacity(self.deps.len()); - let snapshot = self.npm_resolver.as_managed().unwrap().snapshot(); + let snapshot = self + .npm_resolver + .as_managed() + .unwrap() + .resolution() + .snapshot(); let resolved_npm = snapshot.package_reqs(); let resolved_jsr = graph.packages.mappings(); for dep in &self.deps { diff --git a/cli/tools/task.rs b/cli/tools/task.rs index d6d87dd45e..329195ab46 100644 --- a/cli/tools/task.rs +++ b/cli/tools/task.rs @@ -220,7 +220,7 @@ pub async fn execute_script( let task_runner = TaskRunner { task_flags: &task_flags, npm_installer: npm_installer.map(|n| n.as_ref()), - npm_resolver: npm_resolver.as_ref(), + npm_resolver, node_resolver: node_resolver.as_ref(), env_vars, cli_options, @@ -271,7 +271,7 @@ struct RunSingleOptions<'a> { struct TaskRunner<'a> { task_flags: &'a TaskFlags, npm_installer: Option<&'a NpmInstaller>, - npm_resolver: &'a dyn CliNpmResolver, + npm_resolver: &'a CliNpmResolver, node_resolver: &'a CliNodeResolver, env_vars: HashMap, cli_options: &'a CliOptions, diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index b6cf691c38..37d52c6cf2 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -46,7 +46,7 @@ use crate::cache::FastInsecureHasher; use crate::cache::ModuleInfoCache; use crate::node::CliNodeResolver; use crate::npm::CliNpmResolver; -use crate::resolver::CjsTracker; +use crate::resolver::CliCjsTracker; use crate::sys::CliSys; use crate::util::checksum; use crate::util::path::mapped_specifier_for_tsc; @@ -300,13 +300,13 @@ pub fn into_specifier_and_media_type( #[derive(Debug)] pub struct TypeCheckingCjsTracker { - cjs_tracker: Arc, + cjs_tracker: Arc, module_info_cache: Arc, } impl TypeCheckingCjsTracker { pub fn new( - cjs_tracker: Arc, + cjs_tracker: Arc, module_info_cache: Arc, ) -> Self { Self { @@ -358,7 +358,7 @@ impl TypeCheckingCjsTracker { pub struct RequestNpmState { pub cjs_tracker: Arc, pub node_resolver: Arc, - pub npm_resolver: Arc, + pub npm_resolver: CliNpmResolver, } /// A structure representing a request to be sent to the tsc runtime. diff --git a/cli/worker.rs b/cli/worker.rs index d93c6c5f40..45d4b0af70 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -19,6 +19,7 @@ use deno_core::ModuleLoader; use deno_core::PollEventLoopOptions; use deno_core::SharedArrayBufferStore; use deno_error::JsErrorBox; +use deno_resolver::npm::DenoInNpmPackageChecker; use deno_runtime::code_cache; use deno_runtime::deno_broadcast_channel::InMemoryBroadcastChannel; use deno_runtime::deno_fs; @@ -151,7 +152,7 @@ struct SharedWorkerState { module_loader_factory: Box, node_resolver: Arc, npm_installer: Option>, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, pkg_json_resolver: Arc, root_cert_store_provider: Arc, root_permissions: PermissionsContainer, @@ -168,18 +169,17 @@ impl SharedWorkerState { pub fn create_node_init_services( &self, node_require_loader: NodeRequireLoaderRc, - ) -> NodeExtInitServices { + ) -> NodeExtInitServices { NodeExtInitServices { node_require_loader, node_resolver: self.node_resolver.clone(), - npm_resolver: self.npm_resolver.clone().into_npm_pkg_folder_resolver(), pkg_json_resolver: self.pkg_json_resolver.clone(), sys: self.sys.clone(), } } pub fn npm_process_state_provider(&self) -> NpmProcessStateProviderRc { - self.npm_resolver.clone().into_process_state_provider() + crate::npm::create_npm_process_state_provider(&self.npm_resolver) } } @@ -427,7 +427,7 @@ impl CliMainWorkerFactory { module_loader_factory: Box, node_resolver: Arc, npm_installer: Option>, - npm_resolver: Arc, + npm_resolver: CliNpmResolver, pkg_json_resolver: Arc, root_cert_store_provider: Arc, root_permissions: PermissionsContainer, @@ -886,7 +886,11 @@ mod tests { ..Default::default() }; - MainWorker::bootstrap_from_options::( + MainWorker::bootstrap_from_options::< + DenoInNpmPackageChecker, + CliNpmResolver, + CliSys, + >( main_module, WorkerServiceOptions { module_loader: Rc::new(FsModuleLoader), diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 731cd3a9c7..325cec6f5b 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -15,8 +15,9 @@ use deno_core::v8; use deno_core::v8::ExternalReference; use deno_error::JsErrorBox; use node_resolver::errors::ClosestPkgJsonError; +use node_resolver::InNpmPackageChecker; use node_resolver::IsBuiltInNodeModuleChecker; -use node_resolver::NpmPackageFolderResolverRc; +use node_resolver::NpmPackageFolderResolver; use node_resolver::PackageJsonResolverRc; use once_cell::sync::Lazy; @@ -185,17 +186,21 @@ fn op_node_build_os() -> String { } #[derive(Clone)] -pub struct NodeExtInitServices { +pub struct NodeExtInitServices< + TInNpmPackageChecker: InNpmPackageChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, + TSys: ExtNodeSys, +> { pub node_require_loader: NodeRequireLoaderRc, - pub node_resolver: NodeResolverRc, - pub npm_resolver: NpmPackageFolderResolverRc, + pub node_resolver: + NodeResolverRc, pub pkg_json_resolver: PackageJsonResolverRc, pub sys: TSys, } deno_core::extension!(deno_node, deps = [ deno_io, deno_fs ], - parameters = [P: NodePermissions, TSys: ExtNodeSys], + parameters = [P: NodePermissions, TInNpmPackageChecker: InNpmPackageChecker, TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: ExtNodeSys], ops = [ ops::blocklist::op_socket_address_parse, ops::blocklist::op_socket_address_get_serialization, @@ -395,13 +400,13 @@ deno_core::extension!(deno_node, ops::require::op_require_init_paths, ops::require::op_require_node_module_paths, ops::require::op_require_proxy_path, - ops::require::op_require_is_deno_dir_package, - ops::require::op_require_resolve_deno_dir, + ops::require::op_require_is_deno_dir_package, + ops::require::op_require_resolve_deno_dir, ops::require::op_require_is_maybe_cjs, ops::require::op_require_is_request_relative, ops::require::op_require_resolve_lookup_paths, ops::require::op_require_try_self_parent_path, - ops::require::op_require_try_self, + ops::require::op_require_try_self, ops::require::op_require_real_path, ops::require::op_require_path_is_absolute, ops::require::op_require_path_dirname, @@ -410,9 +415,9 @@ deno_core::extension!(deno_node, ops::require::op_require_path_basename, ops::require::op_require_read_file

, ops::require::op_require_as_file_path, - ops::require::op_require_resolve_exports, + ops::require::op_require_resolve_exports, ops::require::op_require_read_package_scope, - ops::require::op_require_package_imports_resolve, + ops::require::op_require_package_imports_resolve, ops::require::op_require_break_on_next_statement, ops::util::op_node_guess_handle_type, ops::worker_threads::op_worker_threads_filename, @@ -681,7 +686,7 @@ deno_core::extension!(deno_node, "node:zlib" = "zlib.ts", ], options = { - maybe_init: Option>, + maybe_init: Option>, fs: deno_fs::FileSystemRc, }, state = |state, options| { @@ -691,7 +696,6 @@ deno_core::extension!(deno_node, state.put(init.sys.clone()); state.put(init.node_require_loader.clone()); state.put(init.node_resolver.clone()); - state.put(init.npm_resolver.clone()); state.put(init.pkg_json_resolver.clone()); } }, @@ -833,10 +837,18 @@ pub trait ExtNodeSys: impl ExtNodeSys for sys_traits::impls::RealSys {} -pub type NodeResolver = - node_resolver::NodeResolver; +pub type NodeResolver = + node_resolver::NodeResolver< + TInNpmPackageChecker, + RealIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >; #[allow(clippy::disallowed_types)] -pub type NodeResolverRc = deno_fs::sync::MaybeArc>; +pub type NodeResolverRc = + deno_fs::sync::MaybeArc< + NodeResolver, + >; #[allow(clippy::disallowed_types)] pub fn create_host_defined_options<'s>( diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs index 3135ba1e86..bff0cd79ed 100644 --- a/ext/node/ops/require.rs +++ b/ext/node/ops/require.rs @@ -19,7 +19,9 @@ use deno_path_util::normalize_path; use deno_path_util::url_from_file_path; use deno_path_util::url_to_file_path; use node_resolver::errors::ClosestPkgJsonError; +use node_resolver::InNpmPackageChecker; use node_resolver::NodeResolutionKind; +use node_resolver::NpmPackageFolderResolver; use node_resolver::ResolutionMode; use node_resolver::REQUIRE_CONDITIONS; use sys_traits::FsCanonicalize; @@ -30,7 +32,6 @@ use crate::ExtNodeSys; use crate::NodePermissions; use crate::NodeRequireLoaderRc; use crate::NodeResolverRc; -use crate::NpmPackageFolderResolverRc; use crate::PackageJsonResolverRc; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] @@ -256,12 +257,20 @@ pub fn op_require_is_request_relative(#[string] request: String) -> bool { #[op2] #[string] -pub fn op_require_resolve_deno_dir( +pub fn op_require_resolve_deno_dir< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] request: String, #[string] parent_filename: String, ) -> Result, deno_path_util::PathToUrlError> { - let resolver = state.borrow::(); + let resolver = state.borrow::>(); Ok( resolver @@ -275,11 +284,19 @@ pub fn op_require_resolve_deno_dir( } #[op2(fast)] -pub fn op_require_is_deno_dir_package( +pub fn op_require_is_deno_dir_package< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TSys: ExtNodeSys + 'static, +>( state: &mut OpState, #[string] path: String, ) -> bool { - let resolver = state.borrow::>(); + let resolver = state.borrow::>(); match deno_path_util::url_from_file_path(&PathBuf::from(path)) { Ok(specifier) => resolver.in_npm_package(&specifier), Err(_) => false, @@ -451,6 +468,8 @@ pub fn op_require_try_self_parent_path< #[string] pub fn op_require_try_self< P: NodePermissions + 'static, + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, TSys: ExtNodeSys + 'static, >( state: &mut OpState, @@ -493,7 +512,11 @@ pub fn op_require_try_self< let referrer = deno_core::url::Url::from_file_path(&pkg.path).unwrap(); if let Some(exports) = &pkg.exports { - let node_resolver = state.borrow::>(); + let node_resolver = state.borrow::>(); let r = node_resolver.package_exports_resolve( &pkg.path, &expansion, @@ -552,6 +575,8 @@ pub fn op_require_as_file_path(#[string] file_or_url: String) -> String { #[string] pub fn op_require_resolve_exports< P: NodePermissions + 'static, + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, TSys: ExtNodeSys + 'static, >( state: &mut OpState, @@ -563,7 +588,11 @@ pub fn op_require_resolve_exports< #[string] parent_path: String, ) -> Result, RequireError> { let sys = state.borrow::(); - let node_resolver = state.borrow::>(); + let node_resolver = state.borrow::>(); let pkg_json_resolver = state.borrow::>(); let modules_path = PathBuf::from(&modules_path_str); @@ -655,6 +684,8 @@ pub fn op_require_read_package_scope< #[string] pub fn op_require_package_imports_resolve< P: NodePermissions + 'static, + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, TSys: ExtNodeSys + 'static, >( state: &mut OpState, @@ -672,7 +703,11 @@ pub fn op_require_package_imports_resolve< }; if pkg.imports.is_some() { - let node_resolver = state.borrow::>(); + let node_resolver = state.borrow::>(); let referrer_url = Url::from_file_path(&referrer_filename).unwrap(); let url = node_resolver.package_imports_resolve( &request, diff --git a/resolvers/deno/cjs.rs b/resolvers/deno/cjs.rs index bae645b481..4358b0ced2 100644 --- a/resolvers/deno/cjs.rs +++ b/resolvers/deno/cjs.rs @@ -2,7 +2,7 @@ use deno_media_type::MediaType; use node_resolver::errors::ClosestPkgJsonError; -use node_resolver::InNpmPackageCheckerRc; +use node_resolver::InNpmPackageChecker; use node_resolver::PackageJsonResolverRc; use node_resolver::ResolutionMode; use sys_traits::FsRead; @@ -16,14 +16,16 @@ use crate::sync::MaybeDashMap; /// be CJS or ESM after they're loaded based on their contents. So these /// files will be "maybe CJS" until they're loaded. #[derive(Debug)] -pub struct CjsTracker { - is_cjs_resolver: IsCjsResolver, +pub struct CjsTracker { + is_cjs_resolver: IsCjsResolver, known: MaybeDashMap, } -impl CjsTracker { +impl + CjsTracker +{ pub fn new( - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, pkg_json_resolver: PackageJsonResolverRc, mode: IsCjsResolutionMode, ) -> Self { @@ -125,15 +127,20 @@ pub enum IsCjsResolutionMode { /// Resolves whether a module is CJS or ESM. #[derive(Debug)] -pub struct IsCjsResolver { - in_npm_pkg_checker: InNpmPackageCheckerRc, +pub struct IsCjsResolver< + TInNpmPackageChecker: InNpmPackageChecker, + TSys: FsRead, +> { + in_npm_pkg_checker: TInNpmPackageChecker, pkg_json_resolver: PackageJsonResolverRc, mode: IsCjsResolutionMode, } -impl IsCjsResolver { +impl + IsCjsResolver +{ pub fn new( - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, pkg_json_resolver: PackageJsonResolverRc, mode: IsCjsResolutionMode, ) -> Self { diff --git a/resolvers/deno/lib.rs b/resolvers/deno/lib.rs index 12d8effc46..454c7f12e2 100644 --- a/resolvers/deno/lib.rs +++ b/resolvers/deno/lib.rs @@ -19,11 +19,12 @@ use deno_package_json::PackageJsonDepValueParseError; use deno_semver::npm::NpmPackageReqReference; use node_resolver::errors::NodeResolveError; use node_resolver::errors::PackageSubpathResolveError; -use node_resolver::InNpmPackageCheckerRc; +use node_resolver::InNpmPackageChecker; use node_resolver::IsBuiltInNodeModuleChecker; use node_resolver::NodeResolution; use node_resolver::NodeResolutionKind; use node_resolver::NodeResolverRc; +use node_resolver::NpmPackageFolderResolver; use node_resolver::ResolutionMode; use npm::MissingPackageNodeModulesFolderError; use npm::NodeModulesOutOfDateError; @@ -101,22 +102,42 @@ pub enum DenoResolveErrorKind { #[derive(Debug)] pub struct NodeAndNpmReqResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - pub node_resolver: NodeResolverRc, - pub npm_req_resolver: NpmReqResolverRc, + pub node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + pub npm_req_resolver: NpmReqResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, } pub struct DenoResolverOptions< 'a, + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSloppyImportResolverFs: SloppyImportResolverFs, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - pub in_npm_pkg_checker: InNpmPackageCheckerRc, - pub node_and_req_resolver: - Option>, + pub in_npm_pkg_checker: TInNpmPackageChecker, + pub node_and_req_resolver: Option< + NodeAndNpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + >, pub sloppy_imports_resolver: Option>, pub workspace_resolver: WorkspaceResolverRc, @@ -131,13 +152,21 @@ pub struct DenoResolverOptions< /// import map, JSX settings. #[derive(Debug)] pub struct DenoResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSloppyImportResolverFs: SloppyImportResolverFs, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_and_npm_resolver: - Option>, + in_npm_pkg_checker: TInNpmPackageChecker, + node_and_npm_resolver: Option< + NodeAndNpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + >, sloppy_imports_resolver: Option>, workspace_resolver: WorkspaceResolverRc, @@ -146,14 +175,25 @@ pub struct DenoResolver< } impl< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSloppyImportResolverFs: SloppyImportResolverFs, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, - > DenoResolver + > + DenoResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSloppyImportResolverFs, + TSys, + > { pub fn new( options: DenoResolverOptions< + TInNpmPackageChecker, TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, TSloppyImportResolverFs, TSys, >, diff --git a/resolvers/deno/npm/byonm.rs b/resolvers/deno/npm/byonm.rs index bf25ba5646..4f72692f8b 100644 --- a/resolvers/deno/npm/byonm.rs +++ b/resolvers/deno/npm/byonm.rs @@ -27,8 +27,6 @@ use thiserror::Error; use url::Url; use super::local::normalize_pkg_name_for_node_modules_deno_folder; -use crate::sync::MaybeSend; -use crate::sync::MaybeSync; #[derive(Debug, Error, deno_error::JsError)] pub enum ByonmResolvePkgFolderFromDenoReqError { @@ -89,7 +87,7 @@ impl } } - pub fn root_node_modules_dir(&self) -> Option<&Path> { + pub fn root_node_modules_path(&self) -> Option<&Path> { self.root_node_modules_dir.as_deref() } @@ -377,15 +375,8 @@ impl } } -impl< - TSys: FsCanonicalize - + FsMetadata - + FsRead - + FsReadDir - + MaybeSend - + MaybeSync - + std::fmt::Debug, - > NpmPackageFolderResolver for ByonmNpmResolver +impl + NpmPackageFolderResolver for ByonmNpmResolver { fn resolve_package_folder_from_package( &self, @@ -438,7 +429,7 @@ impl< } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ByonmInNpmPackageChecker; impl InNpmPackageChecker for ByonmInNpmPackageChecker { diff --git a/resolvers/deno/npm/managed/common.rs b/resolvers/deno/npm/managed/common.rs index 6569a4594f..a92fe226dd 100644 --- a/resolvers/deno/npm/managed/common.rs +++ b/resolvers/deno/npm/managed/common.rs @@ -6,26 +6,69 @@ use std::path::PathBuf; use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageId; use node_resolver::NpmPackageFolderResolver; +use sys_traits::FsCanonicalize; +use sys_traits::FsMetadata; use url::Url; -use crate::sync::MaybeSend; -use crate::sync::MaybeSync; +#[derive(Debug)] +pub enum NpmPackageFsResolver { + Local(super::local::LocalNpmPackageResolver), + Global(super::global::GlobalNpmPackageResolver), +} -#[allow(clippy::disallowed_types)] -pub type NpmPackageFsResolverRc = - crate::sync::MaybeArc; +impl NpmPackageFsResolver { + /// The local node_modules folder (only for the local resolver). + pub fn node_modules_path(&self) -> Option<&Path> { + match self { + NpmPackageFsResolver::Local(resolver) => resolver.node_modules_path(), + NpmPackageFsResolver::Global(_) => None, + } + } -/// Part of the resolution that interacts with the file system. -pub trait NpmPackageFsResolver: - NpmPackageFolderResolver + MaybeSend + MaybeSync -{ - /// The local node_modules folder if it is applicable to the implementation. - fn node_modules_path(&self) -> Option<&Path>; + pub fn maybe_package_folder( + &self, + package_id: &NpmPackageId, + ) -> Option { + match self { + NpmPackageFsResolver::Local(resolver) => { + resolver.maybe_package_folder(package_id) + } + NpmPackageFsResolver::Global(resolver) => { + resolver.maybe_package_folder(package_id) + } + } + } - fn maybe_package_folder(&self, package_id: &NpmPackageId) -> Option; - - fn resolve_package_cache_folder_id_from_specifier( + pub fn resolve_package_cache_folder_id_from_specifier( &self, specifier: &Url, - ) -> Result, std::io::Error>; + ) -> Result, std::io::Error> { + match self { + NpmPackageFsResolver::Local(resolver) => { + resolver.resolve_package_cache_folder_id_from_specifier(specifier) + } + NpmPackageFsResolver::Global(resolver) => { + resolver.resolve_package_cache_folder_id_from_specifier(specifier) + } + } + } +} + +impl NpmPackageFolderResolver + for NpmPackageFsResolver +{ + fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + match self { + NpmPackageFsResolver::Local(r) => { + r.resolve_package_folder_from_package(specifier, referrer) + } + NpmPackageFsResolver::Global(r) => { + r.resolve_package_folder_from_package(specifier, referrer) + } + } + } } diff --git a/resolvers/deno/npm/managed/global.rs b/resolvers/deno/npm/managed/global.rs index d16234d8f4..271851c79c 100644 --- a/resolvers/deno/npm/managed/global.rs +++ b/resolvers/deno/npm/managed/global.rs @@ -2,7 +2,6 @@ //! Code for global npm cache resolution. -use std::path::Path; use std::path::PathBuf; use deno_npm::NpmPackageCacheFolderId; @@ -18,7 +17,6 @@ use url::Url; use super::resolution::NpmResolutionCellRc; use super::NpmCacheDirRc; -use super::NpmPackageFsResolver; use crate::ResolvedNpmRcRc; /// Resolves packages from the global npm cache. @@ -42,6 +40,26 @@ impl GlobalNpmPackageResolver { } } + pub fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { + let folder_copy_index = self + .resolution + .resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?; + let registry_url = self.npm_rc.get_registry_url(&id.nv.name); + Some(self.cache.package_folder_for_id( + &id.nv.name, + &id.nv.version.to_string(), + folder_copy_index, + registry_url, + )) + } + + pub fn resolve_package_cache_folder_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + Ok(self.resolve_package_cache_folder_id_from_specifier_inner(specifier)) + } + fn resolve_package_cache_folder_id_from_specifier_inner( &self, specifier: &Url, @@ -121,29 +139,3 @@ impl NpmPackageFolderResolver for GlobalNpmPackageResolver { } } } - -impl NpmPackageFsResolver for GlobalNpmPackageResolver { - fn node_modules_path(&self) -> Option<&Path> { - None - } - - fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { - let folder_copy_index = self - .resolution - .resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?; - let registry_url = self.npm_rc.get_registry_url(&id.nv.name); - Some(self.cache.package_folder_for_id( - &id.nv.name, - &id.nv.version.to_string(), - folder_copy_index, - registry_url, - )) - } - - fn resolve_package_cache_folder_id_from_specifier( - &self, - specifier: &Url, - ) -> Result, std::io::Error> { - Ok(self.resolve_package_cache_folder_id_from_specifier_inner(specifier)) - } -} diff --git a/resolvers/deno/npm/managed/local.rs b/resolvers/deno/npm/managed/local.rs index 72b0b0d451..e453101df4 100644 --- a/resolvers/deno/npm/managed/local.rs +++ b/resolvers/deno/npm/managed/local.rs @@ -20,27 +20,20 @@ use sys_traits::FsMetadata; use url::Url; use super::resolution::NpmResolutionCellRc; -use super::NpmPackageFsResolver; use crate::npm::local::get_package_folder_id_folder_name_from_parts; use crate::npm::local::get_package_folder_id_from_folder_name; -use crate::sync::MaybeSend; -use crate::sync::MaybeSync; /// Resolver that creates a local node_modules directory /// and resolves packages from it. #[derive(Debug)] -pub struct LocalNpmPackageResolver< - TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync, -> { +pub struct LocalNpmPackageResolver { resolution: NpmResolutionCellRc, sys: TSys, root_node_modules_path: PathBuf, root_node_modules_url: Url, } -impl - LocalNpmPackageResolver -{ +impl LocalNpmPackageResolver { #[allow(clippy::too_many_arguments)] pub fn new( resolution: NpmResolutionCellRc, @@ -56,6 +49,55 @@ impl } } + pub fn node_modules_path(&self) -> Option<&Path> { + Some(self.root_node_modules_path.as_ref()) + } + + pub fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { + let folder_copy_index = self + .resolution + .resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?; + // package is stored at: + // node_modules/.deno//node_modules/ + Some( + self + .root_node_modules_path + .join(".deno") + .join(get_package_folder_id_folder_name_from_parts( + &id.nv, + folder_copy_index, + )) + .join("node_modules") + .join(&id.nv.name), + ) + } + + pub fn resolve_package_cache_folder_id_from_specifier( + &self, + specifier: &Url, + ) -> Result, std::io::Error> { + let Some(folder_path) = + self.resolve_package_folder_from_specifier(specifier)? + else { + return Ok(None); + }; + // ex. project/node_modules/.deno/preact@10.24.3/node_modules/preact/ + let Some(node_modules_ancestor) = folder_path + .ancestors() + .find(|ancestor| ancestor.ends_with("node_modules")) + else { + return Ok(None); + }; + let Some(folder_name) = + node_modules_ancestor.parent().and_then(|p| p.file_name()) + else { + return Ok(None); + }; + Ok(get_package_folder_id_from_folder_name( + &folder_name.to_string_lossy(), + )) + } + fn resolve_package_root(&self, path: &Path) -> PathBuf { let mut last_found = path; loop { @@ -101,9 +143,8 @@ impl } } -impl< - TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync + std::fmt::Debug, - > NpmPackageFolderResolver for LocalNpmPackageResolver +impl NpmPackageFolderResolver + for LocalNpmPackageResolver { fn resolve_package_folder_from_package( &self, @@ -163,60 +204,6 @@ impl< } } -impl< - TSys: FsCanonicalize + FsMetadata + MaybeSend + MaybeSync + std::fmt::Debug, - > NpmPackageFsResolver for LocalNpmPackageResolver -{ - fn node_modules_path(&self) -> Option<&Path> { - Some(self.root_node_modules_path.as_ref()) - } - - fn maybe_package_folder(&self, id: &NpmPackageId) -> Option { - let folder_copy_index = self - .resolution - .resolve_pkg_cache_folder_copy_index_from_pkg_id(id)?; - // package is stored at: - // node_modules/.deno//node_modules/ - Some( - self - .root_node_modules_path - .join(".deno") - .join(get_package_folder_id_folder_name_from_parts( - &id.nv, - folder_copy_index, - )) - .join("node_modules") - .join(&id.nv.name), - ) - } - - fn resolve_package_cache_folder_id_from_specifier( - &self, - specifier: &Url, - ) -> Result, std::io::Error> { - let Some(folder_path) = - self.resolve_package_folder_from_specifier(specifier)? - else { - return Ok(None); - }; - // ex. project/node_modules/.deno/preact@10.24.3/node_modules/preact/ - let Some(node_modules_ancestor) = folder_path - .ancestors() - .find(|ancestor| ancestor.ends_with("node_modules")) - else { - return Ok(None); - }; - let Some(folder_name) = - node_modules_ancestor.parent().and_then(|p| p.file_name()) - else { - return Ok(None); - }; - Ok(get_package_folder_id_from_folder_name( - &folder_name.to_string_lossy(), - )) - } -} - fn join_package_name(path: &Path, package_name: &str) -> PathBuf { let mut path = path.to_path_buf(); // ensure backslashes are used on windows diff --git a/resolvers/deno/npm/managed/mod.rs b/resolvers/deno/npm/managed/mod.rs index 62147b2ac3..291e299bc8 100644 --- a/resolvers/deno/npm/managed/mod.rs +++ b/resolvers/deno/npm/managed/mod.rs @@ -13,6 +13,7 @@ use deno_npm::resolution::PackageNvNotFoundError; use deno_npm::resolution::PackageReqNotFoundError; use deno_npm::NpmPackageCacheFolderId; use deno_npm::NpmPackageId; +use deno_npm::NpmSystemInfo; use deno_path_util::fs::canonicalize_path_maybe_not_exists; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; @@ -23,14 +24,10 @@ use sys_traits::FsMetadata; use url::Url; use self::common::NpmPackageFsResolver; -use self::common::NpmPackageFsResolverRc; use self::global::GlobalNpmPackageResolver; use self::local::LocalNpmPackageResolver; pub use self::resolution::NpmResolutionCell; pub use self::resolution::NpmResolutionCellRc; -use crate::sync::new_rc; -use crate::sync::MaybeSend; -use crate::sync::MaybeSync; use crate::NpmCacheDirRc; use crate::ResolvedNpmRcRc; @@ -89,58 +86,84 @@ pub enum ResolvePkgIdFromSpecifierError { NotFound(#[from] PackageCacheFolderIdNotFoundError), } +pub struct ManagedNpmResolverCreateOptions< + TSys: FsCanonicalize + FsMetadata + Clone, +> { + pub npm_cache_dir: NpmCacheDirRc, + pub sys: TSys, + pub maybe_node_modules_path: Option, + pub npm_system_info: NpmSystemInfo, + pub npmrc: ResolvedNpmRcRc, + pub npm_resolution: NpmResolutionCellRc, +} + #[allow(clippy::disallowed_types)] pub type ManagedNpmResolverRc = crate::sync::MaybeArc>; #[derive(Debug)] -pub struct ManagedNpmResolver { - fs_resolver: NpmPackageFsResolverRc, +pub struct ManagedNpmResolver { + fs_resolver: NpmPackageFsResolver, + npm_cache_dir: NpmCacheDirRc, resolution: NpmResolutionCellRc, sys: TSys, } -impl ManagedNpmResolver { - pub fn new< - TCreateSys: FsCanonicalize - + FsMetadata - + std::fmt::Debug - + MaybeSend - + MaybeSync - + Clone - + 'static, - >( - npm_cache_dir: &NpmCacheDirRc, - npm_rc: &ResolvedNpmRcRc, - resolution: NpmResolutionCellRc, - sys: TCreateSys, - maybe_node_modules_path: Option, +impl ManagedNpmResolver { + pub fn new( + options: ManagedNpmResolverCreateOptions, ) -> ManagedNpmResolver { - let fs_resolver: NpmPackageFsResolverRc = match maybe_node_modules_path { - Some(node_modules_folder) => new_rc(LocalNpmPackageResolver::new( - resolution.clone(), - sys.clone(), - node_modules_folder, - )), - None => new_rc(GlobalNpmPackageResolver::new( - npm_cache_dir.clone(), - npm_rc.clone(), - resolution.clone(), + let fs_resolver = match options.maybe_node_modules_path { + Some(node_modules_folder) => { + NpmPackageFsResolver::Local(LocalNpmPackageResolver::new( + options.npm_resolution.clone(), + options.sys.clone(), + node_modules_folder, + )) + } + None => NpmPackageFsResolver::Global(GlobalNpmPackageResolver::new( + options.npm_cache_dir.clone(), + options.npmrc.clone(), + options.npm_resolution.clone(), )), }; ManagedNpmResolver { fs_resolver, - sys, - resolution, + npm_cache_dir: options.npm_cache_dir, + sys: options.sys, + resolution: options.npm_resolution, } } #[inline] - pub fn node_modules_path(&self) -> Option<&Path> { + pub fn root_node_modules_path(&self) -> Option<&Path> { self.fs_resolver.node_modules_path() } + pub fn global_cache_root_path(&self) -> &Path { + self.npm_cache_dir.root_dir() + } + + pub fn global_cache_root_url(&self) -> &Url { + self.npm_cache_dir.root_dir_url() + } + + pub fn resolution(&self) -> &NpmResolutionCell { + self.resolution.as_ref() + } + + /// Checks if the provided package req's folder is cached. + pub fn is_pkg_req_folder_cached(&self, req: &PackageReq) -> bool { + self + .resolution + .resolve_pkg_id_from_pkg_req(req) + .ok() + .and_then(|id| self.resolve_pkg_folder_from_pkg_id(&id).ok()) + .map(|folder| self.sys.fs_exists_no_err(folder)) + .unwrap_or(false) + } + pub fn resolve_pkg_folder_from_pkg_id( &self, package_id: &NpmPackageId, @@ -213,8 +236,8 @@ impl ManagedNpmResolver { } } -impl - NpmPackageFolderResolver for ManagedNpmResolver +impl NpmPackageFolderResolver + for ManagedNpmResolver { fn resolve_package_folder_from_package( &self, @@ -234,7 +257,7 @@ impl } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ManagedInNpmPackageChecker { root_dir: Url, } diff --git a/resolvers/deno/npm/managed/resolution.rs b/resolvers/deno/npm/managed/resolution.rs index 08dabf5a76..faa0d43664 100644 --- a/resolvers/deno/npm/managed/resolution.rs +++ b/resolvers/deno/npm/managed/resolution.rs @@ -1,7 +1,5 @@ // Copyright 2018-2025 the Deno authors. MIT license. -use std::collections::HashMap; - use deno_npm::resolution::NpmPackagesPartitioned; use deno_npm::resolution::NpmResolutionSnapshot; use deno_npm::resolution::PackageCacheFolderIdNotFoundError; @@ -124,8 +122,23 @@ impl NpmResolutionCell { .map(|pkg| pkg.id.clone()) } - pub fn package_reqs(&self) -> HashMap { - self.snapshot.read().package_reqs().clone() + pub fn package_reqs(&self) -> Vec<(PackageReq, PackageNv)> { + self + .snapshot + .read() + .package_reqs() + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect() + } + + pub fn top_level_packages(&self) -> Vec { + self + .snapshot + .read() + .top_level_packages() + .cloned() + .collect::>() } pub fn all_system_packages( diff --git a/resolvers/deno/npm/mod.rs b/resolvers/deno/npm/mod.rs index 26b156d29d..fed3d388bf 100644 --- a/resolvers/deno/npm/mod.rs +++ b/resolvers/deno/npm/mod.rs @@ -1,6 +1,7 @@ // Copyright 2018-2025 the Deno authors. MIT license. use std::fmt::Debug; +use std::path::Path; use std::path::PathBuf; use boxed_error::Boxed; @@ -14,11 +15,12 @@ use node_resolver::errors::PackageFolderResolveIoError; use node_resolver::errors::PackageNotFoundError; use node_resolver::errors::PackageResolveErrorKind; use node_resolver::errors::PackageSubpathResolveError; -use node_resolver::InNpmPackageCheckerRc; +use node_resolver::InNpmPackageChecker; use node_resolver::IsBuiltInNodeModuleChecker; use node_resolver::NodeResolution; use node_resolver::NodeResolutionKind; use node_resolver::NodeResolverRc; +use node_resolver::NpmPackageFolderResolver; use node_resolver::ResolutionMode; use sys_traits::FsCanonicalize; use sys_traits::FsMetadata; @@ -35,10 +37,14 @@ pub use self::byonm::ByonmResolvePkgFolderFromDenoReqError; pub use self::local::get_package_folder_id_folder_name; pub use self::local::normalize_pkg_name_for_node_modules_deno_folder; use self::managed::create_managed_in_npm_pkg_checker; +use self::managed::ManagedInNpmPackageChecker; use self::managed::ManagedInNpmPkgCheckerCreateOptions; pub use self::managed::ManagedNpmResolver; +use self::managed::ManagedNpmResolverCreateOptions; pub use self::managed::ManagedNpmResolverRc; use crate::sync::new_rc; +use crate::sync::MaybeSend; +use crate::sync::MaybeSync; mod byonm; mod local; @@ -49,14 +55,33 @@ pub enum CreateInNpmPkgCheckerOptions<'a> { Byonm, } -pub fn create_in_npm_pkg_checker( - options: CreateInNpmPkgCheckerOptions, -) -> InNpmPackageCheckerRc { - match options { - CreateInNpmPkgCheckerOptions::Managed(options) => { - new_rc(create_managed_in_npm_pkg_checker(options)) +#[derive(Debug, Clone)] +pub enum DenoInNpmPackageChecker { + Managed(ManagedInNpmPackageChecker), + Byonm(ByonmInNpmPackageChecker), +} + +impl DenoInNpmPackageChecker { + pub fn new(options: CreateInNpmPkgCheckerOptions) -> Self { + match options { + CreateInNpmPkgCheckerOptions::Managed(options) => { + DenoInNpmPackageChecker::Managed(create_managed_in_npm_pkg_checker( + options, + )) + } + CreateInNpmPkgCheckerOptions::Byonm => { + DenoInNpmPackageChecker::Byonm(ByonmInNpmPackageChecker) + } + } + } +} + +impl InNpmPackageChecker for DenoInNpmPackageChecker { + fn in_npm_package(&self, specifier: &Url) -> bool { + match self { + DenoInNpmPackageChecker::Managed(c) => c.in_npm_package(specifier), + DenoInNpmPackageChecker::Byonm(c) => c.in_npm_package(specifier), } - CreateInNpmPkgCheckerOptions::Byonm => new_rc(ByonmInNpmPackageChecker), } } @@ -115,10 +140,22 @@ pub enum ResolvePkgFolderFromDenoReqError { Byonm(byonm::ByonmResolvePkgFolderFromDenoReqError), } -#[derive(Debug, Clone)] -pub enum ByonmOrManagedNpmResolver< - TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, +pub enum NpmResolverCreateOptions< + TSys: FsRead + + FsCanonicalize + + FsMetadata + + std::fmt::Debug + + MaybeSend + + MaybeSync + + Clone + + 'static, > { + Managed(ManagedNpmResolverCreateOptions), + Byonm(ByonmNpmResolverCreateOptions), +} + +#[derive(Debug, Clone)] +pub enum NpmResolver { /// The resolver when "bring your own node_modules" is enabled where Deno /// does not setup the node_modules directories automatically, but instead /// uses what already exists on the file system. @@ -126,57 +163,158 @@ pub enum ByonmOrManagedNpmResolver< Managed(ManagedNpmResolverRc), } -impl - ByonmOrManagedNpmResolver -{ +impl NpmResolver { + pub fn new< + TCreateSys: FsCanonicalize + + FsMetadata + + FsRead + + FsReadDir + + std::fmt::Debug + + MaybeSend + + MaybeSync + + Clone + + 'static, + >( + options: NpmResolverCreateOptions, + ) -> NpmResolver { + match options { + NpmResolverCreateOptions::Managed(options) => { + NpmResolver::Managed(new_rc(ManagedNpmResolver::::new::< + TCreateSys, + >(options))) + } + NpmResolverCreateOptions::Byonm(options) => { + NpmResolver::Byonm(new_rc(ByonmNpmResolver::new(options))) + } + } + } + + pub fn is_byonm(&self) -> bool { + matches!(self, NpmResolver::Byonm(_)) + } + + pub fn is_managed(&self) -> bool { + matches!(self, NpmResolver::Managed(_)) + } + + pub fn as_managed(&self) -> Option<&ManagedNpmResolver> { + match self { + NpmResolver::Managed(resolver) => Some(resolver), + NpmResolver::Byonm(_) => None, + } + } + + pub fn root_node_modules_path(&self) -> Option<&Path> { + match self { + NpmResolver::Byonm(resolver) => resolver.root_node_modules_path(), + NpmResolver::Managed(resolver) => resolver.root_node_modules_path(), + } + } + pub fn resolve_pkg_folder_from_deno_module_req( &self, req: &PackageReq, referrer: &Url, ) -> Result { match self { - ByonmOrManagedNpmResolver::Byonm(byonm_resolver) => byonm_resolver + NpmResolver::Byonm(byonm_resolver) => byonm_resolver .resolve_pkg_folder_from_deno_module_req(req, referrer) .map_err(ResolvePkgFolderFromDenoReqError::Byonm), - ByonmOrManagedNpmResolver::Managed(managed_resolver) => managed_resolver + NpmResolver::Managed(managed_resolver) => managed_resolver .resolve_pkg_folder_from_deno_module_req(req, referrer) .map_err(ResolvePkgFolderFromDenoReqError::Managed), } } } +impl + NpmPackageFolderResolver for NpmResolver +{ + fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + match self { + NpmResolver::Byonm(byonm_resolver) => { + byonm_resolver.resolve_package_folder_from_package(specifier, referrer) + } + NpmResolver::Managed(managed_resolver) => managed_resolver + .resolve_package_folder_from_package(specifier, referrer), + } + } +} + pub struct NpmReqResolverOptions< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { - pub in_npm_pkg_checker: InNpmPackageCheckerRc, - pub node_resolver: NodeResolverRc, - pub npm_resolver: ByonmOrManagedNpmResolver, + pub in_npm_pkg_checker: TInNpmPackageChecker, + pub node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + pub npm_resolver: NpmResolver, pub sys: TSys, } #[allow(clippy::disallowed_types)] -pub type NpmReqResolverRc = - crate::sync::MaybeArc>; +pub type NpmReqResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, +> = crate::sync::MaybeArc< + NpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, +>; #[derive(Debug)] pub struct NpmReqResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, > { sys: TSys, - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_resolver: NodeResolverRc, - npm_resolver: ByonmOrManagedNpmResolver, + in_npm_pkg_checker: TInNpmPackageChecker, + node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + npm_resolver: NpmResolver, } impl< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead + FsReadDir, - > NpmReqResolver + > + NpmReqResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + > { pub fn new( - options: NpmReqResolverOptions, + options: NpmReqResolverOptions< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, ) -> Self { Self { sys: options.sys, @@ -224,7 +362,7 @@ impl< match resolution_result { Ok(url) => Ok(url), Err(err) => { - if matches!(self.npm_resolver, ByonmOrManagedNpmResolver::Byonm(_)) { + if matches!(self.npm_resolver, NpmResolver::Byonm(_)) { let package_json_path = package_folder.join("package.json"); if !self.sys.fs_exists_no_err(&package_json_path) { return Err( @@ -292,9 +430,8 @@ impl< .into_box(), ); } - if let ByonmOrManagedNpmResolver::Byonm( - byonm_npm_resolver, - ) = &self.npm_resolver + if let NpmResolver::Byonm(byonm_npm_resolver) = + &self.npm_resolver { if byonm_npm_resolver .find_ancestor_package_json_with_dep( diff --git a/resolvers/node/analyze.rs b/resolvers/node/analyze.rs index a6ba3927aa..e144e2b8fb 100644 --- a/resolvers/node/analyze.rs +++ b/resolvers/node/analyze.rs @@ -20,11 +20,11 @@ use sys_traits::FsMetadata; use sys_traits::FsRead; use url::Url; -use crate::npm::InNpmPackageCheckerRc; use crate::resolution::NodeResolverRc; +use crate::InNpmPackageChecker; use crate::IsBuiltInNodeModuleChecker; use crate::NodeResolutionKind; -use crate::NpmPackageFolderResolverRc; +use crate::NpmPackageFolderResolver; use crate::PackageJsonResolverRc; use crate::PathClean; use crate::ResolutionMode; @@ -62,28 +62,49 @@ pub trait CjsCodeAnalyzer { pub struct NodeCodeTranslator< TCjsCodeAnalyzer: CjsCodeAnalyzer, + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, > { cjs_code_analyzer: TCjsCodeAnalyzer, - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_resolver: NodeResolverRc, - npm_resolver: NpmPackageFolderResolverRc, + in_npm_pkg_checker: TInNpmPackageChecker, + node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + npm_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, } impl< TCjsCodeAnalyzer: CjsCodeAnalyzer, + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, - > NodeCodeTranslator + > + NodeCodeTranslator< + TCjsCodeAnalyzer, + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + > { pub fn new( cjs_code_analyzer: TCjsCodeAnalyzer, - in_npm_pkg_checker: InNpmPackageCheckerRc, - node_resolver: NodeResolverRc, - npm_resolver: NpmPackageFolderResolverRc, + in_npm_pkg_checker: TInNpmPackageChecker, + node_resolver: NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, + npm_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, ) -> Self { diff --git a/resolvers/node/lib.rs b/resolvers/node/lib.rs index faee4f1645..c0e6383237 100644 --- a/resolvers/node/lib.rs +++ b/resolvers/node/lib.rs @@ -14,9 +14,7 @@ mod sync; pub use deno_package_json::PackageJson; pub use npm::InNpmPackageChecker; -pub use npm::InNpmPackageCheckerRc; pub use npm::NpmPackageFolderResolver; -pub use npm::NpmPackageFolderResolverRc; pub use package_json::PackageJsonResolver; pub use package_json::PackageJsonResolverRc; pub use package_json::PackageJsonThreadLocalCache; diff --git a/resolvers/node/npm.rs b/resolvers/node/npm.rs index f799d6ddee..bb3de2a7f5 100644 --- a/resolvers/node/npm.rs +++ b/resolvers/node/npm.rs @@ -9,16 +9,8 @@ use url::Url; use crate::errors; use crate::path::PathClean; -use crate::sync::MaybeSend; -use crate::sync::MaybeSync; -#[allow(clippy::disallowed_types)] -pub type NpmPackageFolderResolverRc = - crate::sync::MaybeArc; - -pub trait NpmPackageFolderResolver: - std::fmt::Debug + MaybeSend + MaybeSync -{ +pub trait NpmPackageFolderResolver { /// Resolves an npm package folder path from the specified referrer. fn resolve_package_folder_from_package( &self, @@ -27,11 +19,8 @@ pub trait NpmPackageFolderResolver: ) -> Result; } -#[allow(clippy::disallowed_types)] -pub type InNpmPackageCheckerRc = crate::sync::MaybeArc; - /// Checks if a provided specifier is in an npm package. -pub trait InNpmPackageChecker: std::fmt::Debug + MaybeSend + MaybeSync { +pub trait InNpmPackageChecker { fn in_npm_package(&self, specifier: &Url) -> bool; fn in_npm_package_at_dir_path(&self, path: &Path) -> bool { diff --git a/resolvers/node/resolution.rs b/resolvers/node/resolution.rs index a60a6bec9e..9ea5e17e41 100644 --- a/resolvers/node/resolution.rs +++ b/resolvers/node/resolution.rs @@ -46,8 +46,8 @@ use crate::errors::TypesNotFoundError; use crate::errors::TypesNotFoundErrorData; use crate::errors::UnsupportedDirImportError; use crate::errors::UnsupportedEsmUrlSchemeError; -use crate::npm::InNpmPackageCheckerRc; -use crate::NpmPackageFolderResolverRc; +use crate::InNpmPackageChecker; +use crate::NpmPackageFolderResolver; use crate::PackageJsonResolverRc; use crate::PathClean; @@ -137,31 +137,52 @@ pub trait IsBuiltInNodeModuleChecker: std::fmt::Debug { } #[allow(clippy::disallowed_types)] -pub type NodeResolverRc = - crate::sync::MaybeArc>; +pub type NodeResolverRc< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, +> = crate::sync::MaybeArc< + NodeResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + >, +>; #[derive(Debug)] pub struct NodeResolver< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, > { - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker, - npm_pkg_folder_resolver: NpmPackageFolderResolverRc, + npm_pkg_folder_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, conditions_from_resolution_mode: ConditionsFromResolutionMode, } impl< + TInNpmPackageChecker: InNpmPackageChecker, TIsBuiltInNodeModuleChecker: IsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, TSys: FsCanonicalize + FsMetadata + FsRead, - > NodeResolver + > + NodeResolver< + TInNpmPackageChecker, + TIsBuiltInNodeModuleChecker, + TNpmPackageFolderResolver, + TSys, + > { pub fn new( - in_npm_pkg_checker: InNpmPackageCheckerRc, + in_npm_pkg_checker: TInNpmPackageChecker, is_built_in_node_module_checker: TIsBuiltInNodeModuleChecker, - npm_pkg_folder_resolver: NpmPackageFolderResolverRc, + npm_pkg_folder_resolver: TNpmPackageFolderResolver, pkg_json_resolver: PackageJsonResolverRc, sys: TSys, conditions_from_resolution_mode: ConditionsFromResolutionMode, @@ -444,6 +465,17 @@ impl< Ok(url) } + /// Resolves an npm package folder path from the specified referrer. + pub fn resolve_package_folder_from_package( + &self, + specifier: &str, + referrer: &Url, + ) -> Result { + self + .npm_pkg_folder_resolver + .resolve_package_folder_from_package(specifier, referrer) + } + /// Checks if the resolved file has a corresponding declaration file. fn path_to_declaration_url( &self, diff --git a/resolvers/node/sync.rs b/resolvers/node/sync.rs index 8cf06932ac..218253b453 100644 --- a/resolvers/node/sync.rs +++ b/resolvers/node/sync.rs @@ -6,17 +6,10 @@ pub use inner::*; mod inner { #![allow(clippy::disallowed_types)] - pub use core::marker::Send as MaybeSend; - pub use core::marker::Sync as MaybeSync; pub use std::sync::Arc as MaybeArc; } #[cfg(not(feature = "sync"))] mod inner { pub use std::rc::Rc as MaybeArc; - - pub trait MaybeSync {} - impl MaybeSync for T where T: ?Sized {} - pub trait MaybeSend {} - impl MaybeSend for T where T: ?Sized {} } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 5ecd911e8a..f59325962f 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -91,6 +91,7 @@ deno_net.workspace = true deno_node.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true +deno_resolver.workspace = true deno_telemetry.workspace = true deno_terminal.workspace = true deno_tls.workspace = true diff --git a/runtime/examples/extension/main.rs b/runtime/examples/extension/main.rs index 9f0eb63b01..e1538b8b75 100644 --- a/runtime/examples/extension/main.rs +++ b/runtime/examples/extension/main.rs @@ -12,6 +12,8 @@ use deno_core::op2; use deno_core::FsModuleLoader; use deno_core::ModuleSpecifier; use deno_fs::RealFs; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::npm::NpmResolver; use deno_runtime::deno_permissions::PermissionsContainer; use deno_runtime::permissions::RuntimePermissionDescriptorParser; use deno_runtime::worker::MainWorker; @@ -42,7 +44,11 @@ async fn main() -> Result<(), AnyError> { ); let mut worker = MainWorker::bootstrap_from_options( main_module.clone(), - WorkerServiceOptions:: { + WorkerServiceOptions::< + DenoInNpmPackageChecker, + NpmResolver, + sys_traits::impls::RealSys, + > { module_loader: Rc::new(FsModuleLoader), permissions: PermissionsContainer::allow_all(permission_desc_parser), blob_store: Default::default(), diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index 8d008eeab0..331369551c 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -14,6 +14,8 @@ use deno_core::Extension; use deno_http::DefaultHttpPropertyExtractor; use deno_io::fs::FsError; use deno_permissions::PermissionCheckError; +use deno_resolver::npm::DenoInNpmPackageChecker; +use deno_resolver::npm::NpmResolver; use crate::ops; use crate::ops::bootstrap::SnapshotOptions; @@ -310,6 +312,8 @@ pub fn create_runtime_snapshot( deno_fs::deno_fs::init_ops_and_esm::(fs.clone()), deno_node::deno_node::init_ops_and_esm::< Permissions, + DenoInNpmPackageChecker, + NpmResolver, sys_traits::impls::RealSys, >(None, fs.clone()), runtime::init_ops_and_esm(), diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 64393bb64c..4389c7752c 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -54,6 +54,8 @@ use deno_web::JsMessageData; use deno_web::MessagePort; use deno_web::Transferable; use log::debug; +use node_resolver::InNpmPackageChecker; +use node_resolver::NpmPackageFolderResolver; use crate::inspector_server::InspectorServer; use crate::ops; @@ -334,7 +336,11 @@ fn create_handles( (internal_handle, external_handle) } -pub struct WebWorkerServiceOptions { +pub struct WebWorkerServiceOptions< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, +> { pub blob_store: Arc, pub broadcast_channel: InMemoryBroadcastChannel, pub compiled_wasm_module_store: Option, @@ -342,7 +348,13 @@ pub struct WebWorkerServiceOptions { pub fs: Arc, pub maybe_inspector_server: Option>, pub module_loader: Rc, - pub node_services: Option>, + pub node_services: Option< + NodeExtInitServices< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, + >, pub npm_process_state_provider: Option, pub permissions: PermissionsContainer, pub root_cert_store_provider: Option>, @@ -398,8 +410,16 @@ impl Drop for WebWorker { } impl WebWorker { - pub fn bootstrap_from_options( - services: WebWorkerServiceOptions, + pub fn bootstrap_from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( + services: WebWorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, options: WebWorkerOptions, ) -> (Self, SendableWebWorkerHandle) { let (mut worker, handle, bootstrap_options) = @@ -408,8 +428,16 @@ impl WebWorker { (worker, handle) } - fn from_options( - services: WebWorkerServiceOptions, + fn from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( + services: WebWorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, mut options: WebWorkerOptions, ) -> (Self, SendableWebWorkerHandle, BootstrapOptions) { deno_core::extension!(deno_permissions_web_worker, @@ -500,10 +528,12 @@ impl WebWorker { deno_fs::deno_fs::init_ops_and_esm::( services.fs.clone(), ), - deno_node::deno_node::init_ops_and_esm::( - services.node_services, - services.fs, - ), + deno_node::deno_node::init_ops_and_esm::< + PermissionsContainer, + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >(services.node_services, services.fs), // Runtime ops that are always initialized for WebWorkers ops::runtime::deno_runtime::init_ops_and_esm(options.main_module.clone()), ops::worker_host::deno_worker_host::init_ops_and_esm( diff --git a/runtime/worker.rs b/runtime/worker.rs index a649c83d47..7cd6468fc5 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -45,6 +45,8 @@ use deno_tls::RootCertStoreProvider; use deno_tls::TlsKeys; use deno_web::BlobStore; use log::debug; +use node_resolver::InNpmPackageChecker; +use node_resolver::NpmPackageFolderResolver; use crate::code_cache::CodeCache; use crate::code_cache::CodeCacheType; @@ -128,7 +130,11 @@ pub struct MainWorker { dispatch_process_exit_event_fn_global: v8::Global, } -pub struct WorkerServiceOptions { +pub struct WorkerServiceOptions< + TInNpmPackageChecker: InNpmPackageChecker, + TNpmPackageFolderResolver: NpmPackageFolderResolver, + TExtNodeSys: ExtNodeSys, +> { pub blob_store: Arc, pub broadcast_channel: InMemoryBroadcastChannel, pub feature_checker: Arc, @@ -139,7 +145,13 @@ pub struct WorkerServiceOptions { /// If not provided runtime will error if code being /// executed tries to load modules. pub module_loader: Rc, - pub node_services: Option>, + pub node_services: Option< + NodeExtInitServices< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, + >, pub npm_process_state_provider: Option, pub permissions: PermissionsContainer, pub root_cert_store_provider: Option>, @@ -300,9 +312,17 @@ pub fn create_op_metrics( } impl MainWorker { - pub fn bootstrap_from_options( + pub fn bootstrap_from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( main_module: ModuleSpecifier, - services: WorkerServiceOptions, + services: WorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, options: WorkerOptions, ) -> Self { let (mut worker, bootstrap_options) = @@ -311,9 +331,17 @@ impl MainWorker { worker } - fn from_options( + fn from_options< + TInNpmPackageChecker: InNpmPackageChecker + 'static, + TNpmPackageFolderResolver: NpmPackageFolderResolver + 'static, + TExtNodeSys: ExtNodeSys + 'static, + >( main_module: ModuleSpecifier, - services: WorkerServiceOptions, + services: WorkerServiceOptions< + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >, mut options: WorkerOptions, ) -> (Self, BootstrapOptions) { deno_core::extension!(deno_permissions_worker, @@ -413,10 +441,12 @@ impl MainWorker { deno_fs::deno_fs::init_ops_and_esm::( services.fs.clone(), ), - deno_node::deno_node::init_ops_and_esm::( - services.node_services, - services.fs, - ), + deno_node::deno_node::init_ops_and_esm::< + PermissionsContainer, + TInNpmPackageChecker, + TNpmPackageFolderResolver, + TExtNodeSys, + >(services.node_services, services.fs), // Ops from this crate ops::runtime::deno_runtime::init_ops_and_esm(main_module.clone()), ops::worker_host::deno_worker_host::init_ops_and_esm(