mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 02:48:24 +00:00
feat: binary npm commands (#15542)
This commit is contained in:
parent
362af63c6f
commit
e7367044d9
21 changed files with 2389 additions and 196 deletions
|
@ -8,12 +8,14 @@ use deno_ast::ModuleSpecifier;
|
|||
use deno_core::anyhow::bail;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures;
|
||||
use deno_core::parking_lot::RwLock;
|
||||
|
||||
use super::registry::NpmPackageInfo;
|
||||
use super::registry::NpmPackageVersionDistInfo;
|
||||
use super::registry::NpmPackageVersionInfo;
|
||||
use super::registry::NpmRegistryApi;
|
||||
use super::version_req::SpecifierVersionReq;
|
||||
|
||||
/// The version matcher used for npm schemed urls is more strict than
|
||||
/// the one used by npm packages.
|
||||
|
@ -28,10 +30,55 @@ pub struct NpmPackageReference {
|
|||
pub sub_path: Option<String>,
|
||||
}
|
||||
|
||||
impl NpmPackageReference {
|
||||
pub fn from_specifier(
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<NpmPackageReference, AnyError> {
|
||||
Self::from_str(specifier.as_str())
|
||||
}
|
||||
|
||||
pub fn from_str(specifier: &str) -> Result<NpmPackageReference, AnyError> {
|
||||
let specifier = match specifier.strip_prefix("npm:") {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
bail!("Not an npm specifier: '{}'", specifier);
|
||||
}
|
||||
};
|
||||
let (name, version_req) = match specifier.rsplit_once('@') {
|
||||
Some((name, version_req)) => (
|
||||
name,
|
||||
match SpecifierVersionReq::parse(version_req) {
|
||||
Ok(v) => Some(v),
|
||||
Err(_) => None, // not a version requirement
|
||||
},
|
||||
),
|
||||
None => (specifier, None),
|
||||
};
|
||||
Ok(NpmPackageReference {
|
||||
req: NpmPackageReq {
|
||||
name: name.to_string(),
|
||||
version_req,
|
||||
},
|
||||
// todo: implement and support this
|
||||
sub_path: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NpmPackageReference {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(sub_path) = &self.sub_path {
|
||||
write!(f, "{}/{}", self.req, sub_path)
|
||||
} else {
|
||||
write!(f, "{}", self.req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct NpmPackageReq {
|
||||
pub name: String,
|
||||
pub version_req: Option<semver::VersionReq>,
|
||||
pub version_req: Option<SpecifierVersionReq>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NpmPackageReq {
|
||||
|
@ -60,51 +107,6 @@ impl NpmVersionMatcher for NpmPackageReq {
|
|||
}
|
||||
}
|
||||
|
||||
impl NpmPackageReference {
|
||||
pub fn from_specifier(
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Result<NpmPackageReference, AnyError> {
|
||||
Self::from_str(specifier.as_str())
|
||||
}
|
||||
|
||||
pub fn from_str(specifier: &str) -> Result<NpmPackageReference, AnyError> {
|
||||
let specifier = match specifier.strip_prefix("npm:") {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
bail!("Not an npm specifier: '{}'", specifier);
|
||||
}
|
||||
};
|
||||
let (name, version_req) = match specifier.rsplit_once('@') {
|
||||
Some((name, version_req)) => (
|
||||
name,
|
||||
match semver::VersionReq::parse(version_req) {
|
||||
Ok(v) => Some(v),
|
||||
Err(_) => None, // not a version requirement
|
||||
},
|
||||
),
|
||||
None => (specifier, None),
|
||||
};
|
||||
Ok(NpmPackageReference {
|
||||
req: NpmPackageReq {
|
||||
name: name.to_string(),
|
||||
version_req,
|
||||
},
|
||||
// todo: implement and support this
|
||||
sub_path: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NpmPackageReference {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(sub_path) = &self.sub_path {
|
||||
write!(f, "{}/{}", self.req, sub_path)
|
||||
} else {
|
||||
write!(f, "{}", self.req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
pub struct NpmPackageId {
|
||||
pub name: String,
|
||||
|
@ -314,6 +316,27 @@ impl NpmResolution {
|
|||
ordering => ordering,
|
||||
});
|
||||
|
||||
// cache all the dependencies' registry infos in parallel when this env var isn't set
|
||||
if std::env::var("DENO_UNSTABLE_NPM_SYNC_DOWNLOAD") != Ok("1".to_string())
|
||||
{
|
||||
let handles = deps
|
||||
.iter()
|
||||
.map(|dep| {
|
||||
let name = dep.name.clone();
|
||||
let api = self.api.clone();
|
||||
tokio::task::spawn(async move {
|
||||
// it's ok to call this without storing the result, because
|
||||
// NpmRegistryApi will cache the package info in memory
|
||||
api.package_info(&name).await
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let results = futures::future::join_all(handles).await;
|
||||
for result in results {
|
||||
result??; // surface the first error
|
||||
}
|
||||
}
|
||||
|
||||
// now resolve them
|
||||
for dep in deps {
|
||||
// check if an existing dependency matches this
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue