diff --git a/src/utils/graph.spec.ts b/src/utils/graph.spec.ts index 179cd0af..98f75eff 100644 --- a/src/utils/graph.spec.ts +++ b/src/utils/graph.spec.ts @@ -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([ @@ -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([ @@ -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"]]); }); }); diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 9855a49f..fb2e7fb7 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -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(); - const ret: string[][] = []; const nodeps: string[] = []; - const singledeps = new Map(); - 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(); + 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; }