Skip to content

Conversation

csasarak
Copy link
Contributor

@csasarak csasarak commented Jul 8, 2025

Overview

This PR attempts to add some support for version 9 of PNPM's lockfile.

Acceptance criteria

  • We can scan both pnpm version 9 lockfiles as well as workspaces.
  • PNPM's new pnpm-workspace.yaml file is now suppported.
  • Dev dependencies are correctly filtered.

Testing plan

I used both pnpm itself's repo and the vuejs core's repo to verify. I made sure that dev dependencies were not included in the output and verified that dependencies from multiple sub-modules were included properly.

Additionally, there are integration tests testing both the workspace case and the non-workspace case.

Risks

There isn't really a very detailed spec for the lockfile, so some of this I had to develop empirically rather than to spec. I would expect we'll get some bug reports for the functionality in this PR.

Additionally, the PNPM strategy probably should be refactored into several sub-parsers which each support some lockfile range. As it is now, a lot of the code for different versions is intermingled and just works by conditional branching and/or combining fields from different versions which is a smell IMO. I did not have time to do this refactor myself though so it's left for a future time, or Ficus. Overall, I think this PR is a bit gross but an improvement on the status quo.

References

ANE-2235

Checklist

  • I added tests for this PR's change (or explained in the PR description why tests don't make sense).
  • If this PR introduced a user-visible change, I added documentation into docs/.
  • If this PR added docs, I added links as appropriate to the user manual's ToC in docs/README.ms and gave consideration to how discoverable or not my documentation is.
  • If this change is externally visible, I updated Changelog.md. If this PR did not mark a release, I added my changes into an ## Unreleased section at the top.
  • If I made changes to .fossa.yml or fossa-deps.{json.yml}, I updated docs/references/files/*.schema.json AND I have updated example files used by fossa init command. You may also need to update these if you have added/removed new dependency type (e.g. pip) or analysis target type (e.g. poetry).
  • If I made changes to a subcommand's options, I updated docs/references/subcommands/<subcommand>.md.

csasarak and others added 20 commits January 3, 2025 23:08
1. Handle package keys without leading slash in v9 format
2. Add support for catalog versions (workspace:*) in v9 format
3. Improve version normalization and handling
4. Add more test cases and documentation
- Add catalogs field to PnpmLockfile type
- Create CatalogMap and CatalogEntry types for parsing catalog data
- Add getPackageVersion helper to resolve catalog versions
- Update version parsing to properly handle v7-v9 lockfiles
- Track dev dependencies from importers section
- Consider both importers and packages sections when determining dev status
- Pass dev dependency status through dependency resolution chain
- Update toDependency to combine isDev flags from both sources
- Rename version field in CatalogEntry to catalogVersion to avoid collision with ProjectMapDepMetadata
- Use parseJSON instead of undefined parseCatalogEntry
- Use fully qualified Yaml.parseJSON to fix compilation error
- Add KeyMap import
- Convert Object to Map Text using KeyMap.toMap
Reverting commits from Jan 31 - Feb 3 to restore the branch to how
csasarak left it on Jan 3rd (d78d81b)
@csasarak csasarak requested a review from a team as a code owner July 8, 2025 15:48
@csasarak csasarak requested a review from pete-fossa July 8, 2025 15:48
@csasarak csasarak requested review from spatten and zlav July 8, 2025 15:57
Copy link
Contributor

@spatten spatten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I had a few comments and questions, but nothing blocking.


type SnapShotDepRev = Text

-- | Lockfile versions > 9 use snapshots to represent the dependency graph.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an example of what this looks like? Just a snippet of the lockfile so that we can see the structure

@@ -156,7 +189,7 @@ instance FromJSON PnpmLockfile where
then Map.insert "." virtualRootWs importers
else importers

pure $ PnpmLockfile refinedImporters packages rawLockFileVersion
pure $ PnpmLockfile{importers = refinedImporters, packages = packages, lockFileVersion = rawLockFileVersion, lockFileSnapshots = snapshots}
where
getVersion (TextLike ver) = case (listToMaybe . toString $ ver) of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused about how TextLike deals with a version like '9.0', like we see here. Does that get parsed as an int and then turned into a string of '9'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call out, this was tricky and took me a bit of time to figure out. It turns out listToMaybe either returns Nothing for an empty list or the first element of the list in Just for a non-empty one.

csasarak and others added 2 commits July 8, 2025 16:13
Co-authored-by: Scott Patten <scott@fossa.com>
@csasarak csasarak merged commit 78010ff into master Jul 9, 2025
19 checks passed
@csasarak csasarak deleted the pnpm-9 branch July 9, 2025 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants