diff options
Diffstat (limited to 'cli/npm/mod.rs')
-rw-r--r-- | cli/npm/mod.rs | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index cc14bec0a..08c15941a 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -8,11 +8,19 @@ mod managed; use std::path::PathBuf; use std::sync::Arc; +use dashmap::DashMap; use deno_ast::ModuleSpecifier; use deno_core::error::AnyError; +use deno_core::serde_json; +use deno_npm::registry::NpmPackageInfo; use deno_runtime::deno_node::NpmResolver; +use deno_runtime::permissions::PermissionsContainer; +use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; +use crate::args::npm_registry_url; +use crate::file_fetcher::FileFetcher; + pub use self::byonm::ByonmCliNpmResolver; pub use self::byonm::CliNpmResolverByonmCreateOptions; pub use self::cache_dir::NpmCacheDir; @@ -87,3 +95,60 @@ pub trait CliNpmResolver: NpmResolver { /// or `None` if the state currently can't be determined. fn check_state_hash(&self) -> Option<u64>; } + +#[derive(Debug)] +pub struct NpmFetchResolver { + nv_by_req: DashMap<PackageReq, Option<PackageNv>>, + info_by_name: DashMap<String, Option<Arc<NpmPackageInfo>>>, + file_fetcher: FileFetcher, +} + +impl NpmFetchResolver { + pub fn new(file_fetcher: FileFetcher) -> Self { + Self { + nv_by_req: Default::default(), + info_by_name: Default::default(), + file_fetcher, + } + } + + pub async fn req_to_nv(&self, req: &PackageReq) -> Option<PackageNv> { + if let Some(nv) = self.nv_by_req.get(req) { + return nv.value().clone(); + } + let maybe_get_nv = || async { + let name = req.name.clone(); + let package_info = self.package_info(&name).await?; + // Find the first matching version of the package which is cached. + let mut versions = package_info.versions.keys().collect::<Vec<_>>(); + versions.sort(); + let version = versions + .into_iter() + .rev() + .find(|v| req.version_req.tag().is_none() && req.version_req.matches(v)) + .cloned()?; + Some(PackageNv { name, version }) + }; + let nv = maybe_get_nv().await; + self.nv_by_req.insert(req.clone(), nv.clone()); + nv + } + + pub async fn package_info(&self, name: &str) -> Option<Arc<NpmPackageInfo>> { + if let Some(info) = self.info_by_name.get(name) { + return info.value().clone(); + } + let fetch_package_info = || async { + let info_url = npm_registry_url().join(name).ok()?; + let file = self + .file_fetcher + .fetch(&info_url, PermissionsContainer::allow_all()) + .await + .ok()?; + serde_json::from_slice::<NpmPackageInfo>(&file.source).ok() + }; + let info = fetch_package_info().await.map(Arc::new); + self.info_by_name.insert(name.to_string(), info.clone()); + info + } +} |