Skip to content

Commit ab6d91b

Browse files
committed
feat: add filter ability to graph
today we don't have the ability to filter graphs as we could easily do with dep-tree this adds the ability to filter out nodes by node id, package name or package name and version the way it works is by creating a new graph (using the builder), iterate over the existing graph and adding the nodes.
1 parent 30970c8 commit ab6d91b

File tree

3 files changed

+36736
-0
lines changed

3 files changed

+36736
-0
lines changed

src/core/filter-from-graph.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { DepGraph, DepGraphInternal, NodeInfo, PkgInfo } from './types';
2+
import { DepGraphBuilder } from './builder';
3+
4+
type NodeId = string;
5+
type PkgName = string;
6+
7+
export async function filterPackagesFromGraph(
8+
originalDepGraph: DepGraph,
9+
packagesToFilterOut: (PkgName | PkgInfo)[],
10+
): Promise<DepGraph> {
11+
if (!packagesToFilterOut?.length) return originalDepGraph;
12+
13+
const depGraph = originalDepGraph as DepGraphInternal;
14+
15+
const packages = depGraph
16+
.getDepPkgs()
17+
.filter((existingPkg) =>
18+
packagesToFilterOut.some((pkgToFilter) =>
19+
isString(pkgToFilter)
20+
? existingPkg.name === pkgToFilter
21+
: existingPkg.name === pkgToFilter.name &&
22+
existingPkg.version === pkgToFilter.version,
23+
),
24+
);
25+
26+
const nodeIdsToFilterOut: NodeId[] = [];
27+
for (const pkg of packages) {
28+
const nodeIds = depGraph.getPkgNodeIds(pkg);
29+
for (const nodeId of nodeIds) {
30+
nodeIdsToFilterOut.push(nodeId);
31+
}
32+
}
33+
34+
return filterNodesFromGraph(originalDepGraph, nodeIdsToFilterOut);
35+
}
36+
37+
export async function filterNodesFromGraph(
38+
originalDepGraph: DepGraph,
39+
nodeIdsToFilterOut: NodeId[],
40+
): Promise<DepGraph> {
41+
if (!nodeIdsToFilterOut?.length) return originalDepGraph;
42+
43+
const depGraph = originalDepGraph as DepGraphInternal;
44+
const existingNodeIds: Set<NodeId> = new Set(depGraph['_graph'].nodes());
45+
nodeIdsToFilterOut = nodeIdsToFilterOut.filter((nodeId) =>
46+
existingNodeIds.has(nodeId),
47+
);
48+
if (nodeIdsToFilterOut.length === 0) return originalDepGraph;
49+
50+
const depGraphBuilder = new DepGraphBuilder(
51+
depGraph.pkgManager,
52+
depGraph.rootPkg,
53+
);
54+
55+
const nodeIdsToFilterOutSet = new Set(nodeIdsToFilterOut);
56+
57+
const queue: [NodeId, NodeId?][] = [[depGraph.rootNodeId, undefined]];
58+
59+
while (queue.length > 0) {
60+
const [nodeId, parentNodeId] = queue.pop()!;
61+
62+
if (nodeIdsToFilterOutSet.has(nodeId)) continue;
63+
64+
if (parentNodeId) {
65+
const pkgInfo = depGraph.getNodePkg(nodeId);
66+
let nodeInfo: NodeInfo | undefined = depGraph.getNode(nodeId);
67+
if (isEmpty(nodeInfo)) nodeInfo = undefined;
68+
69+
depGraphBuilder.addPkgNode(pkgInfo, nodeId, nodeInfo);
70+
depGraphBuilder.connectDep(parentNodeId, nodeId);
71+
}
72+
73+
const dependencies = depGraph.getNodeDepsNodeIds(nodeId).slice().reverse();
74+
75+
for (const depNodeId of dependencies) {
76+
queue.push([depNodeId, nodeId]);
77+
}
78+
}
79+
80+
return depGraphBuilder.build();
81+
}
82+
83+
function isString(pkgToFilter: string | PkgInfo): pkgToFilter is string {
84+
return typeof pkgToFilter === 'string';
85+
}
86+
87+
function isEmpty(obj) {
88+
return !obj || Object.keys(obj).length === 0;
89+
}

0 commit comments

Comments
 (0)