Skip to content

Commit

Permalink
fix: Invalid hierarchy creation for dependency graph
Browse files Browse the repository at this point in the history
  • Loading branch information
miyanokomiya committed Nov 7, 2024
1 parent dba931f commit 40a1ddd
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 19 deletions.
18 changes: 16 additions & 2 deletions src/utils/graph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ describe("topSortHierarchy", () => {
]),
);
expect(result1).toEqual([["c"], ["b"], ["a"]]);
});

test("result isn't always optimal but correct", () => {
const result1 = topSortHierarchy(
new Map([
["a", new Set(["d"])],
["b", new Set(["f"])],
["c", new Set(["f"])],
["d", new Set(["b"])],
["e", new Set(["b"])],
["f", new Set()],
]),
);
expect(result1).toEqual([["f"], ["b"], ["d"], ["a", "c", "e"]]);

const result2 = topSortHierarchy(
new Map([
Expand All @@ -75,7 +89,7 @@ describe("topSortHierarchy", () => {
["d", new Set(["c"])],
]),
);
expect(result2).toEqual([["c"], ["b", "d"], ["a"]]);
expect(result2).toEqual([["c"], ["b"], ["a", "d"]]);

const result3 = topSortHierarchy(
new Map([
Expand All @@ -85,6 +99,6 @@ describe("topSortHierarchy", () => {
["d", new Set(["c"])],
]),
);
expect(result3, "multiple dependencies can't be regarded").toEqual([["c"], ["d"], ["a"], ["b"]]);
expect(result3, "multiple dependencies can't be regarded").toEqual([["c"], ["d"], ["b"], ["a"]]);
});
});
42 changes: 25 additions & 17 deletions src/utils/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,35 +46,43 @@ function topSortStep(

/**
* Items in the same hierarchy are independent from each other.
* This hierarchy only regards items having single dependency. This isn't perfect but much performant.
* This hierarchy isn't optimal but much performant.
*/
export function topSortHierarchy(depSrc: DependencyMap, strict = false): string[][] {
const sorted = topSort(depSrc, strict);
const finishedSet = new Set<string>();

const ret: string[][] = [];
const nodeps: string[] = [];
const singledeps = new Map<string, string[]>();
const others: string[] = [];

sorted.forEach((id) => {
const deps = depSrc.get(id);
if (!deps || deps.size === 0) {
nodeps.push(id);
} else if (deps.size === 1) {
const dep = deps.values().next().value!;
if (singledeps.has(dep)) {
singledeps.get(dep)!.push(id);
} else {
singledeps.set(dep, [id]);
}
} else {
others.push(id);
finishedSet.add(id);
return;
}
});

ret.push(nodeps);
singledeps.forEach((keys) => ret.push(keys));
others.forEach((key) => ret.push([key]));
const ret: string[][] = [nodeps];
let currentSet = new Set<string>();
sorted.forEach((id) => {
const deps = depSrc.get(id);
if (!deps || deps.size === 0) return;

for (const dep of deps) {
if (currentSet.has(dep)) {
if (currentSet.size > 0) {
ret.push(Array.from(currentSet));
}
currentSet = new Set([id]);
return;
}
}

currentSet.add(id);
});
if (currentSet.size > 0) {
ret.push(Array.from(currentSet));
}

return ret;
}

0 comments on commit 40a1ddd

Please sign in to comment.