diff options
Diffstat (limited to 'cli/npm')
-rw-r--r-- | cli/npm/registry.rs | 21 | ||||
-rw-r--r-- | cli/npm/resolution.rs | 75 | ||||
-rw-r--r-- | cli/npm/semver/mod.rs | 4 |
3 files changed, 96 insertions, 4 deletions
diff --git a/cli/npm/registry.rs b/cli/npm/registry.rs index c70741b01..1fb4b2e0a 100644 --- a/cli/npm/registry.rs +++ b/cli/npm/registry.rs @@ -31,6 +31,8 @@ use super::semver::NpmVersionReq; pub struct NpmPackageInfo { pub name: String, pub versions: HashMap<String, NpmPackageVersionInfo>, + #[serde(rename = "dist-tags")] + pub dist_tags: HashMap<String, String>, } pub struct NpmDependencyEntry { @@ -39,7 +41,7 @@ pub struct NpmDependencyEntry { pub version_req: NpmVersionReq, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone)] pub struct NpmPackageVersionInfo { pub version: String, pub dist: NpmPackageVersionDistInfo, @@ -89,7 +91,7 @@ impl NpmPackageVersionInfo { } } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone)] pub struct NpmPackageVersionDistInfo { /// URL to the tarball. pub tarball: String, @@ -231,7 +233,20 @@ impl NpmRegistryApi { Err(err) if err.kind() == ErrorKind::NotFound => return Ok(None), Err(err) => return Err(err.into()), }; - Ok(serde_json::from_str(&file_text)?) + match serde_json::from_str(&file_text) { + Ok(package_info) => Ok(Some(package_info)), + Err(err) => { + // This scenario might mean we need to load more data from the + // npm registry than before. So, just debug log while in debug + // rather than panic. + log::debug!( + "error deserializing registry.json for '{}'. Reloading. {:?}", + name, + err + ); + Ok(None) + } + } } fn save_package_info_to_file_cache( diff --git a/cli/npm/resolution.rs b/cli/npm/resolution.rs index 4f46bbed4..8fac92716 100644 --- a/cli/npm/resolution.rs +++ b/cli/npm/resolution.rs @@ -19,9 +19,10 @@ use super::semver::NpmVersion; use super::semver::SpecifierVersionReq; /// The version matcher used for npm schemed urls is more strict than -/// the one used by npm packages. +/// the one used by npm packages and so we represent either via a trait. pub trait NpmVersionMatcher { fn matches(&self, version: &NpmVersion) -> bool; + fn is_latest(&self) -> bool; fn version_text(&self) -> String; } @@ -112,6 +113,10 @@ impl NpmVersionMatcher for NpmPackageReq { } } + fn is_latest(&self) -> bool { + self.version_req.is_none() + } + fn version_text(&self) -> String { self .version_req @@ -484,6 +489,25 @@ fn get_resolved_package_version_and_info( parent: Option<&NpmPackageId>, ) -> Result<VersionAndInfo, AnyError> { let mut maybe_best_version: Option<VersionAndInfo> = None; + if version_matcher.is_latest() { + if let Some(version) = info.dist_tags.get("latest") { + match info.versions.get(version) { + Some(info) => { + return Ok(VersionAndInfo { + version: NpmVersion::parse(version)?, + info: info.clone(), + }); + } + None => { + bail!( + "Could not find version '{}' referenced in dist-tag 'latest'.", + version, + ) + } + } + } + } + for (_, version_info) in info.versions.into_iter() { let version = NpmVersion::parse(&version_info.version)?; if version_matcher.matches(&version) { @@ -651,4 +675,53 @@ mod tests { assert_eq!(name_without_path("@foo/bar/baz"), "@foo/bar"); assert_eq!(name_without_path("@hello"), "@hello"); } + + #[test] + fn test_get_resolved_package_version_and_info() { + // dist tag where version doesn't exist + let package_ref = NpmPackageReference::from_str("npm:test").unwrap(); + let result = get_resolved_package_version_and_info( + "test", + &package_ref.req, + NpmPackageInfo { + name: "test".to_string(), + versions: HashMap::new(), + dist_tags: HashMap::from([( + "latest".to_string(), + "1.0.0-alpha".to_string(), + )]), + }, + None, + ); + assert_eq!( + result.err().unwrap().to_string(), + "Could not find version '1.0.0-alpha' referenced in dist-tag 'latest'." + ); + + // dist tag where version is a pre-release + let package_ref = NpmPackageReference::from_str("npm:test").unwrap(); + let result = get_resolved_package_version_and_info( + "test", + &package_ref.req, + NpmPackageInfo { + name: "test".to_string(), + versions: HashMap::from([ + ("0.1.0".to_string(), NpmPackageVersionInfo::default()), + ( + "1.0.0-alpha".to_string(), + NpmPackageVersionInfo { + version: "0.1.0-alpha".to_string(), + ..Default::default() + }, + ), + ]), + dist_tags: HashMap::from([( + "latest".to_string(), + "1.0.0-alpha".to_string(), + )]), + }, + None, + ); + assert_eq!(result.unwrap().version.to_string(), "1.0.0-alpha"); + } } diff --git a/cli/npm/semver/mod.rs b/cli/npm/semver/mod.rs index 10a87a13f..53f0f199f 100644 --- a/cli/npm/semver/mod.rs +++ b/cli/npm/semver/mod.rs @@ -174,6 +174,10 @@ impl NpmVersionMatcher for NpmVersionReq { self.satisfies(version) } + fn is_latest(&self) -> bool { + false + } + fn version_text(&self) -> String { self.raw_text.clone() } |