Skip to content

Commit 087cac9

Browse files
committed
Restrict the maximum depth of the tree to 4 since the TreeView cannot handle more
1 parent cd3d53e commit 087cac9

File tree

3 files changed

+44
-18
lines changed

3 files changed

+44
-18
lines changed

src/lib/components/ComponentsTreeView.svelte

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
</ButtonSet>
3030
</div>
3131

32+
<p>
33+
<em
34+
>Nodes with … at the end indicate that the maximum level of nesting is reached for this view.</em
35+
>
36+
</p>
37+
3238
<TreeView bind:this={treeview} {nodes} />
3339

3440
<style lang="scss">
@@ -38,6 +44,10 @@
3844
margin-bottom: layout.$spacing-05;
3945
}
4046
47+
p {
48+
margin-bottom: layout.$spacing-02;
49+
}
50+
4151
.buttons {
4252
margin-bottom: layout.$spacing-04;
4353
}

src/lib/tree.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ describe('createTreeDataFromBom', () => {
104104

105105
const expected: TreeItem[] = [
106106
new TreeItemImpl('a-name', 'a-ref', [
107-
new TreeItemImpl('b-name', 'b-ref', [new TreeItemImpl('a-name', 'a-ref')])
107+
new TreeItemImpl('b-name', 'b-ref', [
108+
new TreeItemImpl('a-name', 'a-ref', [new TreeItemImpl('[cycle]', 'cycle')])
109+
])
108110
])
109111
];
110112

src/lib/tree.ts

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type { Bom } from '$lib/cyclonedx/models';
22
import { type TreeItem, TreeItemImpl } from '$lib/models/tree';
33

4-
export function createTreeDataFromBom(bom: Bom): TreeItem[] {
4+
const PlaceholderTreeItemForCycle: TreeItem = new TreeItemImpl('[cycle]', 'cycle');
5+
6+
export function createTreeDataFromBom(bom: Bom, maxDepth: number = 4): TreeItem[] {
57
const componentRefToName = new Map<string, string>();
68
const dependencyMap = new Map<string, string[]>();
79

@@ -21,40 +23,52 @@ export function createTreeDataFromBom(bom: Bom): TreeItem[] {
2123

2224
const childrenCache = new Map<string, TreeItem[] | undefined>();
2325

24-
function getChildTreeItems(componentRef: string, visited: Set<string>): TreeItem[] {
25-
// If we've already visited this component, return an empty array to prevent cycles
26-
if (visited.has(componentRef)) {
27-
console.warn(`Cycle detected for ${componentRef}`);
28-
return [];
29-
}
26+
let nodeCount = 1;
3027

28+
function getChildTreeItems(
29+
componentRef: string,
30+
visited: Set<string>,
31+
maxDepth: number
32+
): TreeItem[] {
3133
// Mark the current component as visited
3234
visited.add(componentRef);
3335

34-
const parentChildren: TreeItemImpl[] = [];
36+
const parentChildren: TreeItem[] = [];
3537

36-
for (const child of dependencyMap.get(componentRef) ?? []) {
37-
if (componentRefToName.has(child)) {
38+
for (const childRef of dependencyMap.get(componentRef) ?? []) {
39+
let childName = componentRefToName.get(childRef);
40+
if (childName) {
3841
let childChildren;
39-
if (childrenCache.has(child)) {
40-
childChildren = childrenCache.get(child);
42+
if (maxDepth <= 0) {
43+
console.warn('Maximum depth reached');
44+
childName += '…';
45+
childChildren = [];
46+
} else if (visited.has(childRef)) {
47+
// If we've already visited this component, return placeholder to prevent cycles
48+
console.warn(`Cycle detected for ${componentRef}`);
49+
childChildren = [PlaceholderTreeItemForCycle];
50+
} else if (childrenCache.has(childRef)) {
51+
childChildren = childrenCache.get(childRef);
4152
} else {
42-
childChildren = getChildTreeItems(child, new Set(visited));
43-
childrenCache.set(child, childChildren);
53+
childChildren = getChildTreeItems(childRef, new Set(visited), maxDepth - 1);
54+
childrenCache.set(childRef, childChildren);
4455
}
45-
parentChildren.push(new TreeItemImpl(componentRefToName.get(child)!, child, childChildren));
56+
nodeCount++;
57+
parentChildren.push(new TreeItemImpl(childName, childRef, childChildren));
4658
}
4759
}
4860

4961
return parentChildren;
5062
}
5163

5264
if (subject && subject['bom-ref']) {
53-
data.push(...getChildTreeItems(subject['bom-ref'], new Set<string>()));
65+
data.push(...getChildTreeItems(subject['bom-ref'], new Set<string>(), maxDepth));
5466
} else {
5567
console.error(`No subject found in ${bom.metadata}`);
5668
}
5769

58-
console.log('Successfully created tree');
70+
console.log(
71+
`Successfully created a tree with ${nodeCount} nodes`
72+
);
5973
return data;
6074
}

0 commit comments

Comments
 (0)