feat(unstable/pm): support npm packages in 'deno add' (#22715)

This commit is contained in:
Nayeem Rahman 2024-03-06 13:24:15 +00:00 committed by GitHub
parent 8b1f160bb5
commit 01bc2f530e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 135 additions and 67 deletions

View file

@ -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
}
}