Skip to content

Commit

Permalink
Fix PNPM v5 version parsing
Browse files Browse the repository at this point in the history
This fixes an issue with the lockfile parser of PNPM v5 lockfiles which
would incorrectly include metadata in the package version.

Closes #1538.
  • Loading branch information
cd-work committed Nov 22, 2024
1 parent 69413fc commit 6ae64a8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 11 deletions.
52 changes: 41 additions & 11 deletions lockfile/src/javascript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,9 @@ impl PnpmLock {
///
/// This parses the combined name and version used as an index for the
/// `packages` map.
fn parse_key(mut key: &str, version: PnpmVersion) -> anyhow::Result<(String, String)> {
fn parse_key(mut key: &str, pnpm_version: PnpmVersion) -> anyhow::Result<(String, String)> {
// Strip prefix from `version < 9` lockfiles.
if version < PnpmVersion::V9 {
if pnpm_version < PnpmVersion::V9 {
key = key
.strip_prefix('/')
.ok_or_else(|| anyhow!("Dependency '{key}' is missing '/' prefix"))?;
Expand All @@ -356,16 +356,23 @@ impl PnpmLock {
let name = key.split_once('(').map(|(name, _)| name).unwrap_or(key);

// Get version separator based on PNPM version.
let version_separator = match version {
let version_separator = match pnpm_version {
PnpmVersion::V6 | PnpmVersion::V9 => '@',
PnpmVersion::V5 => '/',
};

// Separate name and version.
match name.rsplit_once(version_separator) {
Some((name, version)) => Ok((name.into(), version.into())),
let (name, mut version) = match name.rsplit_once(version_separator) {
Some((name, version)) => Ok((name, version)),
None => Err(anyhow!("Dependency '{name}' is missing a version")),
}?;

// Remove dependency information from V5 versions.
if pnpm_version == PnpmVersion::V5 {
version = version.split_once('_').map_or(version, |(version, _)| version);
}

Ok((name.into(), version.into()))
}

/// Parse a first-party registry package.
Expand Down Expand Up @@ -682,7 +689,7 @@ mod tests {
fn pnpm() {
let pkgs = Pnpm.parse(include_str!("../../tests/fixtures/pnpm-lock.yaml")).unwrap();

assert_eq!(pkgs.len(), 65);
assert_eq!(pkgs.len(), 66);

let expected_pkgs = [
Package {
Expand Down Expand Up @@ -725,6 +732,11 @@ mod tests {
version: PackageVersion::Path(Some("projects/workspace_member".into())),
package_type: PackageType::Npm,
},
Package {
name: "@emotion/use-insertion-effect-with-fallbacks".into(),
version: PackageVersion::FirstParty("1.1.0".into()),
package_type: PackageType::Npm,
},
];

for expected_pkg in expected_pkgs {
Expand Down Expand Up @@ -774,10 +786,28 @@ mod tests {
fn pnpm_v5() {
let pkgs = Pnpm.parse(include_str!("../../tests/fixtures/pnpm-lock-v5.yaml")).unwrap();

assert_eq!(pkgs, vec![Package {
name: "lodash".into(),
version: PackageVersion::FirstParty("4.17.21".into()),
package_type: PackageType::Npm,
}]);
assert_eq!(pkgs.len(), 3);

let expected_pkgs = [
Package {
name: "use-sync-external-store".into(),
version: PackageVersion::FirstParty("1.2.2".into()),
package_type: PackageType::Npm,
},
Package {
name: "@types/eslint__js".into(),
version: PackageVersion::FirstParty("8.42.3".into()),
package_type: PackageType::Npm,
},
Package {
name: "lodash".into(),
version: PackageVersion::FirstParty("4.17.21".into()),
package_type: PackageType::Npm,
},
];

for expected_pkg in expected_pkgs {
assert!(pkgs.contains(&expected_pkg), "missing package {expected_pkg:?}");
}
}
}
13 changes: 13 additions & 0 deletions tests/fixtures/pnpm-lock-v5.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,18 @@ packages:
dev: false
resolution:
integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==

/use-sync-external-store/1.2.2_react@18.3.1:
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.3.1

/@types/eslint__js/8.42.3:
resolution: {integrity: sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==}
dependencies:
'@types/eslint': 9.6.1
dev: true
specifiers:
lodash: ^4.17.21
8 changes: 8 additions & 0 deletions tests/fixtures/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6ae64a8

Please sign in to comment.