fix(reviewing): fix memory error in pnpm why (#7122)

* fix(reviewing): fix memory error in `pnpm why`

* fix: update comments

* fix: add support for `--depth`

* fix: move implementation to `@pnpm/list`

* fix: revert changes in Dependencies Hierarchy

* fix: add pnpm to patch list

* refactor: rename functions to descriptive names

* refactor: rename `findEndLeafs` to `findEndLeaves`
This commit is contained in:
Nacho Aldama
2023-09-27 14:35:48 +02:00
committed by GitHub
parent a30334f2f4
commit 40798fb1cd
4 changed files with 94 additions and 2 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/list": patch
"pnpm": patch
---
Fix memory error in `pnpm why` when the dependencies tree is too big, the command will now prune the tree to just 10 end leafs and now supports `--depth` argument.

View File

@@ -6,6 +6,7 @@ import { renderJson } from './renderJson'
import { renderParseable } from './renderParseable'
import { renderTree } from './renderTree'
import { type PackageDependencyHierarchy } from './types'
import { pruneDependenciesTrees } from './pruneTree'
export type { PackageNode } from '@pnpm/reviewing.dependencies-hierarchy'
export { renderJson, renderParseable, renderTree }
@@ -105,8 +106,10 @@ export async function listForPackages (
const pkgs = await searchForPackages(packages, projectPaths, opts)
const prunedPkgs = pruneDependenciesTrees(pkgs ?? null, 10)
const print = getPrinter(opts.reportAs)
return print(pkgs, {
return print(prunedPkgs, {
alwaysPrintRootPackage: opts.alwaysPrintRootPackage,
depth: opts.depth,
long: opts.long,

View File

@@ -0,0 +1,78 @@
import { type DependenciesHierarchy, type PackageNode } from '@pnpm/reviewing.dependencies-hierarchy'
import { type PackageDependencyHierarchy } from './types'
import { createHash } from 'crypto'
export function pruneDependenciesTrees (trees: PackageDependencyHierarchy[] | null, limit: number): PackageDependencyHierarchy[] {
if (trees === null) {
return []
}
return trees.map((tree) => {
const endLeafPaths: PackageNode[][] = []
const visitedNodes = new Set<string>()
function findEndLeaves (node: PackageNode, path: PackageNode[]): void {
if (node.circular) {
return
}
const nodeId = `${node.name}@${node.version}`
if (visitedNodes.has(nodeId)) {
return
}
visitedNodes.add(nodeId)
const newPath = [...path, node]
if (!node.dependencies || node.dependencies.length === 0) {
endLeafPaths.push(newPath)
if (endLeafPaths.length >= limit) {
return
}
}
for (const child of node.dependencies ?? []) {
findEndLeaves(child, newPath)
if (endLeafPaths.length >= limit) {
return
}
}
visitedNodes.delete(nodeId)
}
if (tree.dependencies) {
for (const node of tree.dependencies) {
findEndLeaves(node, [])
}
}
const firstNPaths = endLeafPaths.slice(0, limit)
const map = new Map<string, PackageNode>()
const newTree: DependenciesHierarchy = { dependencies: [] }
for (const path of firstNPaths) {
let currentDependencies: PackageNode[] = newTree.dependencies!
let pathSoFar = ''
for (const node of path) {
pathSoFar += `${node.name}@${node.version},`
const id = createHash('sha256').update(pathSoFar).digest('hex')
let existingNode = map.get(id)
if (!existingNode) {
existingNode = { ...node, dependencies: [] }
currentDependencies.push(existingNode)
map.set(id, existingNode)
}
currentDependencies = existingNode.dependencies!
}
}
return {
...tree,
dependencies: newTree.dependencies,
}
})
}

View File

@@ -8,6 +8,7 @@ import { handler as list, type ListCommandOptions } from './list'
export function rcOptionsTypes () {
return pick([
'depth',
'dev',
'global-dir',
'global',
@@ -79,6 +80,10 @@ For options that may be used with `-r`, see "pnpm help recursive"',
description: "Don't display packages from `optionalDependencies`",
name: '--no-optional',
},
{
name: '--depth <number>',
description: 'Max display depth of the dependency graph',
},
OPTIONS.globalDir,
...UNIVERSAL_OPTIONS,
],
@@ -103,7 +108,7 @@ export async function handler (
...opts,
cliOptions: {
...(opts.cliOptions ?? {}),
depth: Infinity,
depth: opts.depth ?? Infinity,
},
}, params)
}