mirror of
https://github.com/denoland/deno.git
synced 2025-08-03 18:38:33 +00:00
feat(unstable/pm): support npm packages in 'deno add' (#22715)
This commit is contained in:
parent
8b1f160bb5
commit
01bc2f530e
9 changed files with 135 additions and 67 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue