diff --git a/.changeset/famous-cloths-press.md b/.changeset/famous-cloths-press.md new file mode 100644 index 0000000000..4ee116265c --- /dev/null +++ b/.changeset/famous-cloths-press.md @@ -0,0 +1,6 @@ +--- +"@pnpm/reviewing.dependencies-hierarchy": patch +"pnpm": patch +--- + +Handle undefined pkgSnapshot in `pnpm why -r` [#10700](https://github.com/pnpm/pnpm/issues/10700). diff --git a/reviewing/dependencies-hierarchy/src/getPkgInfo.ts b/reviewing/dependencies-hierarchy/src/getPkgInfo.ts index 16b062b06f..f2f999a310 100644 --- a/reviewing/dependencies-hierarchy/src/getPkgInfo.ts +++ b/reviewing/dependencies-hierarchy/src/getPkgInfo.ts @@ -68,7 +68,7 @@ export function getPkgInfo (opts: GetPkgInfoOpts): { pkgInfo: PackageInfo, readM let integrity: string | undefined const depPath = refToRelative(opts.ref, opts.alias) if (depPath) { - let pkgSnapshot!: PackageSnapshot + let pkgSnapshot: PackageSnapshot | undefined if (opts.currentPackages[depPath]) { pkgSnapshot = opts.currentPackages[depPath] const parsed = nameVerFromPkgSnapshot(depPath, pkgSnapshot) @@ -87,12 +87,14 @@ export function getPkgInfo (opts: GetPkgInfoOpts): { pkgInfo: PackageInfo, readM isMissing = true isSkipped = opts.skipped.has(depPath) } - resolved = (pkgSnapshotToResolution(depPath, pkgSnapshot, opts.registries) as TarballResolution).tarball - depType = opts.depTypes[depPath] - optional = pkgSnapshot.optional - if ('integrity' in pkgSnapshot.resolution) { - integrity = pkgSnapshot.resolution.integrity as string + if (pkgSnapshot) { + resolved = (pkgSnapshotToResolution(depPath, pkgSnapshot, opts.registries) as TarballResolution).tarball + optional = pkgSnapshot.optional + if ('integrity' in pkgSnapshot.resolution) { + integrity = pkgSnapshot.resolution.integrity as string + } } + depType = opts.depTypes[depPath] } else { name = opts.alias version = opts.ref diff --git a/reviewing/dependencies-hierarchy/test/getPkgInfo.test.ts b/reviewing/dependencies-hierarchy/test/getPkgInfo.test.ts new file mode 100644 index 0000000000..cf79a4e087 --- /dev/null +++ b/reviewing/dependencies-hierarchy/test/getPkgInfo.test.ts @@ -0,0 +1,33 @@ +import { getPkgInfo, type GetPkgInfoOpts } from '../src/getPkgInfo.js' +import path from 'path' + +test('getPkgInfo handles missing pkgSnapshot without crashing', () => { + const opts: GetPkgInfoOpts = { + alias: 'missing-pkg', + ref: 'missing-pkg@1.0.0', + currentPackages: {}, + wantedPackages: {}, + depTypes: {}, + skipped: new Set(), + registries: { + default: 'https://registry.npmjs.org/', + }, + virtualStoreDirMaxLength: 120, + modulesDir: '', + linkedPathBaseDir: '', + } + + const result = getPkgInfo(opts) + + expect(result.pkgInfo).toEqual({ + alias: 'missing-pkg', + name: 'missing-pkg', + version: 'missing-pkg@1.0.0', + isMissing: true, + isPeer: false, + isSkipped: false, + path: path.join('.pnpm/missing-pkg@1.0.0/node_modules/missing-pkg'), + }) + expect(result.pkgInfo.resolved).toBeUndefined() + expect(result.pkgInfo.optional).toBeUndefined() +})