Skip to content

Commit 08b6de8

Browse files
committed
feat: add utility functions to retrieve node references
findNodes, getNode, getFirstNode
1 parent bae0211 commit 08b6de8

6 files changed

Lines changed: 174 additions & 0 deletions

File tree

src/utils/findNodes.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { Graph } from '../Graph.js';
3+
import { findNodes } from './findNodes.js';
4+
import { getFirstNode } from './getFirstNode.js';
5+
import { getNode } from './getNode.js';
6+
7+
describe('findNodes', () => {
8+
type Node = { id: string; type: string };
9+
10+
it('should retrieve a node successfully when it exists in the graph', ({ expect }) => {
11+
const graph = new Graph<Node>();
12+
const node1 = { id: '1', type: 'foo' };
13+
const node2 = { id: '2', type: 'foo' };
14+
15+
graph.addNode(node1);
16+
graph.addNode(node2);
17+
18+
expect(findNodes(graph, (n) => n.id === '1')).toEqual([node1]);
19+
expect(findNodes(graph, (n) => n.id === '2')).toEqual([node2]);
20+
});
21+
22+
it('should return an empty array when no matching node is found', ({ expect }) => {
23+
const graph = new Graph<Node>();
24+
expect(findNodes(graph, (n) => n.id === 'nope')).toEqual([]);
25+
});
26+
27+
it('should return all the nodes matching', ({ expect }) => {
28+
const graph = new Graph<Node>();
29+
const node1 = { id: '1', type: 'foo' };
30+
const node2 = { id: '2', type: 'foo' };
31+
32+
graph.addNode(node1);
33+
graph.addNode(node2);
34+
35+
expect(findNodes(graph, (n) => n.type === 'foo')).toEqual([node1, node2]);
36+
});
37+
});

src/utils/findNodes.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Graph } from '../Graph.js';
2+
import { NoInfer } from '../types.js';
3+
4+
/**
5+
* Returns all the nodes matching your function.
6+
*/
7+
export function findNodes<Node>(
8+
graph: Graph<Node>,
9+
fn: (node: NoInfer<Node>) => boolean,
10+
): Node[] {
11+
const nodes: Node[] = [];
12+
13+
graph.nodes.forEach((node) => {
14+
if (fn(node)) {
15+
nodes.push(node);
16+
}
17+
});
18+
19+
return nodes;
20+
}

src/utils/getFirstNode.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { Graph } from '../Graph.js';
3+
import { getFirstNode } from './getFirstNode.js';
4+
import { getNode } from './getNode.js';
5+
6+
describe('getFirstNode', () => {
7+
type Node = { id: string; type: string };
8+
9+
it('should retrieve a node successfully when it exists in the graph', ({ expect }) => {
10+
const graph = new Graph<Node>();
11+
const node1 = { id: '1', type: 'foo' };
12+
const node2 = { id: '2', type: 'foo' };
13+
14+
graph.addNode(node1);
15+
graph.addNode(node2);
16+
17+
expect(getFirstNode(graph, (n) => n.id === '1')).toEqual(node1);
18+
expect(getFirstNode(graph, (n) => n.id === '2')).toEqual(node2);
19+
});
20+
21+
it('should throw when the node is not found', ({ expect }) => {
22+
const graph = new Graph<Node>();
23+
expect(() => getFirstNode(graph, (n) => n.id === 'nope')).toThrowError();
24+
});
25+
26+
it('should not throw when more than one node is found', ({ expect }) => {
27+
const graph = new Graph<Node>();
28+
const node1 = { id: '1', type: 'foo' };
29+
const node2 = { id: '2', type: 'foo' };
30+
31+
graph.addNode(node1);
32+
graph.addNode(node2);
33+
34+
expect(getFirstNode(graph, (n) => n.type === 'foo')).toEqual(node1);
35+
});
36+
});

src/utils/getFirstNode.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Graph } from '../Graph.js';
2+
import { NoInfer } from '../types.js';
3+
4+
/**
5+
* Return the first node matching your function and throws if none is found.
6+
*/
7+
export function getFirstNode<Node>(
8+
graph: Graph<Node>,
9+
fn: (node: NoInfer<Node>) => boolean,
10+
): Node {
11+
for (const node of graph.nodes) {
12+
if (fn(node)) {
13+
return node;
14+
}
15+
}
16+
17+
throw new Error('Node not found.');
18+
}

src/utils/getNode.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { Graph } from '../Graph.js';
3+
import { getNode } from './getNode.js';
4+
5+
describe('getNode', () => {
6+
type Node = { id: string; type: string };
7+
8+
it('should retrieve a node successfully when it exists in the graph', ({ expect }) => {
9+
const graph = new Graph<Node>();
10+
const node1 = { id: '1', type: 'foo' };
11+
const node2 = { id: '2', type: 'foo' };
12+
13+
graph.addNode(node1);
14+
graph.addNode(node2);
15+
16+
expect(getNode(graph, (n) => n.id === '1')).toEqual(node1);
17+
expect(getNode(graph, (n) => n.id === '2')).toEqual(node2);
18+
});
19+
20+
it('should throw when the node is not found', ({ expect }) => {
21+
const graph = new Graph<Node>();
22+
expect(() => getNode(graph, (n) => n.id === 'nope')).toThrowError();
23+
});
24+
25+
it('should throw when more than one node is found', ({ expect }) => {
26+
const graph = new Graph<Node>();
27+
const node1 = { id: '1', type: 'foo' };
28+
const node2 = { id: '2', type: 'foo' };
29+
30+
graph.addNode(node1);
31+
graph.addNode(node2);
32+
33+
expect(() => getNode(graph, (n) => n.type === 'foo')).toThrowError();
34+
});
35+
});

src/utils/getNode.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Graph } from '../Graph.js';
2+
import { NoInfer } from '../types.js';
3+
4+
/**
5+
* Return the node matching your function. Throws if none is found or if more than one node if found.
6+
*/
7+
export function getNode<Node>(
8+
graph: Graph<Node>,
9+
fn: (node: NoInfer<Node>) => boolean,
10+
): Node {
11+
const foundNodes: Node[] = [];
12+
13+
for (const node of graph.nodes) {
14+
if (fn(node)) {
15+
foundNodes.push(node);
16+
}
17+
}
18+
19+
if (foundNodes.length === 0) {
20+
throw new Error('Node not found.');
21+
}
22+
23+
if (foundNodes.length > 1) {
24+
throw new Error('More than one node found.');
25+
}
26+
27+
return foundNodes[0];
28+
}

0 commit comments

Comments
 (0)