Skip to content

Commit 95e5bf1

Browse files
committed
feat: change addEdge signature to accept an object as a 3rd argument.
1 parent dd161e4 commit 95e5bf1

6 files changed

Lines changed: 55 additions & 29 deletions

File tree

src/Graph.spec-d.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ describe('graph types', () => {
3838
it('should require edge properties if LinkProps is defined', () => {
3939
const g = new Graph<string, { type: string }>();
4040

41-
g.addEdge('a', 'b', undefined, { type: 'foo' });
42-
g.addEdge('a', 'b', 1, { type: 'foo' });
41+
g.addEdge('a', 'b', { props: { type: 'foo' } });
42+
g.addEdge('a', 'b', { weight: 1, props: { type: 'foo' } });
4343

4444
// @ts-expect-error
4545
g.addEdge('a', 'b', 1);
46+
47+
// @ts-expect-error
48+
g.addEdge('a', 'b', { weight: 1 });
4649
});
4750

4851
it('should not allow edge properties if LinkProps is never', () => {

src/Graph.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,25 @@ export class Graph<Node = string, LinkProps = never> {
116116
* Adds an edge from the `source` node to `target` node.
117117
* This method will create the nodes if they were not already added.
118118
*/
119-
addEdge(
120-
source: Node,
121-
target: Node,
122-
...opts: [LinkProps] extends [never]
123-
? [weight?: EdgeWeight]
124-
: [weight: EdgeWeight | undefined, linkProps: LinkProps]
125-
): this {
126-
const [weight, linkProps] = opts;
119+
addEdge(source: Node, target: Node, ...args: AddEdgeArgs<LinkProps>): this {
120+
let weight: number | undefined;
121+
let linkProps: LinkProps | undefined;
122+
123+
const firstArg = args[0];
124+
125+
if (typeof firstArg === 'number') {
126+
weight = firstArg;
127+
}
128+
129+
if (typeof firstArg === 'object') {
130+
weight = firstArg.weight;
131+
132+
if (firstArg)
133+
linkProps = Object.prototype.hasOwnProperty.call(firstArg, 'props')
134+
? (firstArg as { props: LinkProps }).props
135+
: undefined;
136+
}
137+
127138
this.addNode(source);
128139
this.addNode(target);
129140
const adjacentNodes = this.adjacent(source);
@@ -162,3 +173,7 @@ export class Graph<Node = string, LinkProps = never> {
162173
return this.edges.get(source)?.has(target) ?? false;
163174
}
164175
}
176+
177+
type AddEdgeArgs<LinkProps> = [LinkProps] extends [never]
178+
? [weight?: EdgeWeight] | [opts?: { weight?: EdgeWeight }]
179+
: [opts: { weight?: EdgeWeight; props: LinkProps }];

src/algorithms/depthFirstSearch/depthFirstSearch.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ describe('depthFirstSearch', () => {
66
it('Should return the nodes connected to the source node with the correct type of edge.', function () {
77
const graph = new Graph<string, { type: 'foo' | 'bar' }>();
88

9-
graph.addEdge('a', 'b', undefined, { type: 'foo' });
10-
graph.addEdge('b', 'c', undefined, { type: 'bar' });
11-
graph.addEdge('b', 'd', undefined, { type: 'bar' });
12-
graph.addEdge('b', 'e', undefined, { type: 'foo' });
9+
graph.addEdge('a', 'b', { props: { type: 'foo' } });
10+
graph.addEdge('b', 'c', { props: { type: 'bar' } });
11+
graph.addEdge('b', 'd', { props: { type: 'bar' } });
12+
graph.addEdge('b', 'e', { props: { type: 'foo' } });
1313

1414
const nodes = depthFirstSearch(graph, {
1515
shouldFollow: ({ source, target, graph }) =>

src/algorithms/topologicalSort/topologicalSort.spec.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,21 @@ describe('topologicalSort', () => {
4646
});
4747

4848
it('Should compute topological sort tricky case.', function () {
49-
const graph = new Graph(); // a
50-
// / \
51-
graph.addEdge('a', 'b'); // b |
52-
graph.addEdge('a', 'd'); // | d
53-
graph.addEdge('b', 'c'); // c |
54-
graph.addEdge('d', 'e'); // \ /
55-
graph.addEdge('c', 'e'); // e
49+
// a
50+
// / \
51+
// b |
52+
// | d
53+
// c |
54+
// \ /
55+
// e
56+
57+
const graph = new Graph();
58+
59+
graph.addEdge('a', 'b');
60+
graph.addEdge('a', 'd');
61+
graph.addEdge('b', 'c');
62+
graph.addEdge('d', 'e');
63+
graph.addEdge('c', 'e');
5664

5765
const sorted = topologicalSort(graph, {
5866
sourceNodes: ['a'],
@@ -74,9 +82,9 @@ describe('topologicalSort', () => {
7482
it('Should exclude source nodes with a cycle.', function () {
7583
const graph = new Graph<string, { type: string }>();
7684
graph
77-
.addEdge('a', 'b', undefined, { type: 'foo' })
78-
.addEdge('b', 'c', undefined, { type: 'foo' })
79-
.addEdge('c', 'a', undefined, { type: 'bar' });
85+
.addEdge('a', 'b', { props: { type: 'foo' } })
86+
.addEdge('b', 'c', { props: { type: 'foo' } })
87+
.addEdge('c', 'a', { props: { type: 'bar' } });
8088

8189
const sorted = topologicalSort(graph, {
8290
sourceNodes: ['a'],

src/utils/hasCycle.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ describe('hasCycle', () => {
4545

4646
it('should not detect the cycle when the traversing is stopped by the shouldFollow option.', function () {
4747
const graph = new Graph<string, string>();
48-
graph.addEdge('a', 'b', undefined, 'foo');
49-
graph.addEdge('b', 'c', undefined, 'foo');
50-
graph.addEdge('c', 'd', undefined, 'foo');
51-
graph.addEdge('d', 'a', undefined, 'bar');
48+
graph.addEdge('a', 'b', { props: 'foo' });
49+
graph.addEdge('b', 'c', { props: 'foo' });
50+
graph.addEdge('c', 'd', { props: 'foo' });
51+
graph.addEdge('d', 'a', { props: 'bar' });
5252

5353
expect(
5454
hasCycle(graph, {

src/utils/serializeGraph.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('serializeGraph', () => {
1818
const nodeB = { title: 'b' };
1919

2020
const graph = new Graph<{ title: string }, { type: string }>();
21-
graph.addEdge(nodeA, nodeB, undefined, { type: 'foo' });
21+
graph.addEdge(nodeA, nodeB, { props: { type: 'foo' } });
2222

2323
const serialized = serializeGraph(graph);
2424

0 commit comments

Comments
 (0)