Support pnpm 2-part "env lockfile" pnpm-lock.yaml files in parseLockFile - #1197
Merged
Elizabeth Craig (ecraig12345) merged 2 commits intoAug 5, 2026
Merged
Conversation
pnpm v11+ writes `pnpm-lock.yaml` as two `---`-separated YAML documents (an "env" document holding `configDependencies`/`packageManagerDependencies`, followed by the regular lockfile document) whenever either of those fields is recorded (see pnpm/pnpm#10964). `readYaml()`'s use of js-yaml's `load()` throws on such files ("expected a single document in the stream, but found more"), so `parseLockFile` completely blew up for any repo whose pnpm-lock.yaml happened to have an env document. Add `readYamlDocuments()` (using js-yaml's `loadAll()`) and use it for the pnpm branch of parseLockFile, taking only the last document. This is a no-op for legacy single-document lockfiles, and for 2-document env lockfiles the env document (and its configDependencies/packageManagerDependencies) is intentionally discarded so it can never leak into the parsed dependency graph. Adds a basic-pnpm-9-env-lockfile fixture/test that also verifies a deliberately colliding package name in the env document does not affect the parsed output. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes a CI type-check failure: setupFixture()'s TestFixtureName union didn't include the new basic-pnpm-9-env-lockfile fixture added for the env-lockfile test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Andrew Stegmaier (astegmaier)
marked this pull request as ready for review
August 5, 2026 17:01
Elizabeth Craig (ecraig12345)
approved these changes
Aug 5, 2026
Elizabeth Craig (ecraig12345)
merged commit Aug 5, 2026
57c95cc
into
microsoft:main
14 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Follow-up to #1165 (which taught
parseLockFileto read pnpmlockfileVersion6.0/9.0 lockfiles). I missed a case: pnpm v11+ can writepnpm-lock.yamlas two----separated YAML documents rather than one, whenever either of two fields needs to be persisted:packageManagerDependencies— resolved integrity for pnpm's own binary (self-managed pnpm versions,packageManager/devEngines.packageManagerfield inpackage.json).configDependencies— resolved integrity for config dependencies declared inpnpm-workspace.yaml.Both are recorded in a separate "env" document (first document in the file) so pnpm's regular install/lockfile logic never needs to read/understand them. See pnpm#10964 ("refactor: merge env lockfile into pnpm-lock.yaml") for the pnpm-side implementation.
readYaml()'s use ofjs-yaml'sload()throws on such files:...which means
parseLockFile(and therefore lage's cache-key hasher, and any downstream consumer) completely blows up for any repo whose pnpm lockfile happens to have an env document — e.g. any repo that pinspackageManager: pnpm@12.x, usesdevEngines.packageManager, or declaresconfigDependencies.I verified this end-to-end against a real repo generated with an actual pnpm 12 beta binary (published at https://github.com/astegmaier/playground-pnpm-paquet-test, along with a detailed writeup of exactly what causes the 2-part format and when it was introduced).
What changed
readYamlDocuments()toreadYaml.ts— same as the existingreadYaml(), but usesjs-yaml'sloadAll()to return every document in the file instead of throwing when there's more than one.parseLockFile's pnpm branch now usesreadYamlDocuments()and takes only the last document.configDependencies/packageManagerDependencies(and their resolvedpackages/snapshotsentries) never leak into the parsed dependency graph. This also protects against a same-named package appearing in both the env document and the real dependency graph with different resolutions — only the real (main document) resolution is ever used.parsePnpmLockadded in Support pnpm lockfileVersion 6.0 and 9.0 in parseLockFile #1165) —readYaml()itself, and its use by yarn/berry parsing elsewhere in the same file, are untouched.Testing
basic-pnpm-9-env-lockfilefixture: the existingbasic-pnpm-9fixture with a real env document prepended (configDependencies+packageManagerDependencies, mirroring the playground repo above). The env document also deliberately declares awhich@2.0.2entry with a bogus dependency edge, to verify a name collision with the main document doesn't leak through.lockfile.test.tsasserts:which@2.0.2bogus edge — appears in the parsed output.workspace-toolssuite passes (347 tests, +1 vs. main), plus lint andyarn api(no public API surface changed —readYamlDocumentsis not exported).parseLockFileagainst the real playground repo; it now returns the correct parsed graph instead of throwing.Change type
Includes a beachball change file (
workspace-tools, patch).