Skip to content

Commit 74a26d8

Browse files
committed
feat: topologicalSort now accepts option shouldFollow to restrict graph traversal
1 parent 28e6e37 commit 74a26d8

6 files changed

Lines changed: 35 additions & 16 deletions

File tree

src/Graph.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, expect, it } from 'vitest';
22

3-
import { depthFirstSearch, Graph } from './index.js';
3+
import { Graph } from './index.js';
44
import { indegree } from './utils/indegree.js';
55
import { outdegree } from './utils/outdegree.js';
66

src/algorithms/topologicalSort/topologicalSort.spec.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,23 @@ describe('topologicalSort', () => {
7272
});
7373

7474
it('Should exclude source nodes with a cycle.', function () {
75-
const graph = new Graph().addEdge('a', 'b').addEdge('b', 'c').addEdge('c', 'a');
75+
const graph = new Graph<string, { type: string }>();
76+
graph
77+
.addEdge('a', 'b', undefined, { type: 'foo' })
78+
.addEdge('b', 'c', undefined, { type: 'foo' })
79+
.addEdge('c', 'a', undefined, { type: 'bar' });
80+
7681
const sorted = topologicalSort(graph, {
7782
sourceNodes: ['a'],
78-
includeSourceNodes: false,
83+
includeSourceNodes: true,
84+
shouldFollow: (source, target) =>
85+
graph.getEdgeProperties(source, target).type === 'foo',
7986
});
80-
expect(sorted.length).toEqual(2);
81-
expect(sorted[0]).toEqual('b');
82-
expect(sorted[1]).toEqual('c');
87+
88+
expect(sorted.length).toEqual(3);
89+
expect(sorted[0]).toEqual('a');
90+
expect(sorted[1]).toEqual('b');
91+
expect(sorted[2]).toEqual('c');
8392
});
8493

8594
it('Should exclude source nodes with multiple cycles.', function () {

src/algorithms/topologicalSort/topologicalSort.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Graph } from '../../Graph.js';
88
import { NoInfer } from '../../types.js';
99
import { depthFirstSearch } from '../depthFirstSearch/index.js';
1010

11-
export type TopologicalSortOptions<Node> = {
11+
export type TopologicalSortOptions<Node, LinkProps> = {
1212
/**
1313
* Run the first on those nodes.
1414
* @default all the nodes of the graph.
@@ -20,11 +20,24 @@ export type TopologicalSortOptions<Node> = {
2020
* @default true
2121
*/
2222
includeSourceNodes?: boolean;
23+
24+
/**
25+
* A function that is executed to determine if the branch should be visited or not.
26+
* @param source the current node
27+
* @param target the next node to explore
28+
* @param graph the graph instance being explored
29+
* @returns boolean
30+
*/
31+
shouldFollow?: (
32+
source: NoInfer<Node>,
33+
target: NoInfer<Node>,
34+
graph: Graph<Node, LinkProps>,
35+
) => boolean;
2336
};
2437

25-
export function topologicalSort<Node>(
26-
graph: Graph<Node>,
27-
opts: TopologicalSortOptions<NoInfer<Node>> = {},
38+
export function topologicalSort<Node, LinkProps>(
39+
graph: Graph<Node, LinkProps>,
40+
opts: TopologicalSortOptions<NoInfer<Node>, NoInfer<LinkProps>> = {},
2841
) {
2942
return depthFirstSearch(graph, {
3043
...opts,

src/utils/findNodes.spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, it } from 'vitest';
22
import { Graph } from '../Graph.js';
33
import { findNodes } from './findNodes.js';
4-
import { getFirstNode } from './getFirstNode.js';
5-
import { getNode } from './getNode.js';
64

75
describe('findNodes', () => {
86
type Node = { id: string; type: string };

src/utils/getFirstNode.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, it } from 'vitest';
22
import { Graph } from '../Graph.js';
33
import { getFirstNode } from './getFirstNode.js';
4-
import { getNode } from './getNode.js';
54

65
describe('getFirstNode', () => {
76
type Node = { id: string; type: string };

src/utils/getNode.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, it } from 'vitest';
22
import { Graph } from '../Graph.js';
33
import { getNode } from './getNode.js';
44

0 commit comments

Comments
 (0)