@monstermann/graph 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1383 -0
- package/dist/Graph/batch.d.mts +47 -0
- package/dist/Graph/batch.mjs +57 -0
- package/dist/Graph/create.d.mts +36 -0
- package/dist/Graph/create.mjs +37 -0
- package/dist/Graph/findEdge.d.mts +60 -0
- package/dist/Graph/findEdge.mjs +10 -0
- package/dist/Graph/findEdges.d.mts +65 -0
- package/dist/Graph/findEdges.mjs +12 -0
- package/dist/Graph/findNeighbor.d.mts +54 -0
- package/dist/Graph/findNeighbor.mjs +16 -0
- package/dist/Graph/findNeighbors.d.mts +59 -0
- package/dist/Graph/findNeighbors.mjs +18 -0
- package/dist/Graph/findNode.d.mts +67 -0
- package/dist/Graph/findNode.mjs +7 -0
- package/dist/Graph/findNodes.d.mts +63 -0
- package/dist/Graph/findNodes.mjs +9 -0
- package/dist/Graph/forEachEdge.d.mts +52 -0
- package/dist/Graph/forEachEdge.mjs +56 -0
- package/dist/Graph/forEachNeighbor.d.mts +52 -0
- package/dist/Graph/forEachNeighbor.mjs +59 -0
- package/dist/Graph/forEachNode.d.mts +49 -0
- package/dist/Graph/forEachNode.mjs +51 -0
- package/dist/Graph/fromJS.d.mts +55 -0
- package/dist/Graph/fromJS.mjs +62 -0
- package/dist/Graph/getEdge.d.mts +50 -0
- package/dist/Graph/getEdge.mjs +54 -0
- package/dist/Graph/getEdges.d.mts +47 -0
- package/dist/Graph/getEdges.mjs +51 -0
- package/dist/Graph/getNeighbor.d.mts +50 -0
- package/dist/Graph/getNeighbor.mjs +56 -0
- package/dist/Graph/getNeighbors.d.mts +47 -0
- package/dist/Graph/getNeighbors.mjs +58 -0
- package/dist/Graph/getNode.d.mts +48 -0
- package/dist/Graph/getNode.mjs +52 -0
- package/dist/Graph/getNodes.d.mts +46 -0
- package/dist/Graph/getNodes.mjs +48 -0
- package/dist/Graph/hasEdge.d.mts +46 -0
- package/dist/Graph/hasEdge.mjs +50 -0
- package/dist/Graph/hasNode.d.mts +42 -0
- package/dist/Graph/hasNode.mjs +46 -0
- package/dist/Graph/index.d.mts +68 -0
- package/dist/Graph/index.mjs +65 -0
- package/dist/Graph/internals/core.mjs +51 -0
- package/dist/Graph/internals/parseNodeIdentifier.mjs +7 -0
- package/dist/Graph/internals/types.d.mts +16 -0
- package/dist/Graph/mapEdge.d.mts +52 -0
- package/dist/Graph/mapEdge.mjs +60 -0
- package/dist/Graph/mapNode.d.mts +65 -0
- package/dist/Graph/mapNode.mjs +83 -0
- package/dist/Graph/mergeEdge.d.mts +52 -0
- package/dist/Graph/mergeEdge.mjs +63 -0
- package/dist/Graph/mergeNode.d.mts +50 -0
- package/dist/Graph/mergeNode.mjs +60 -0
- package/dist/Graph/removeEdge.d.mts +49 -0
- package/dist/Graph/removeEdge.mjs +71 -0
- package/dist/Graph/removeNode.d.mts +46 -0
- package/dist/Graph/removeNode.mjs +71 -0
- package/dist/Graph/setEdge.d.mts +52 -0
- package/dist/Graph/setEdge.mjs +78 -0
- package/dist/Graph/setNode.d.mts +43 -0
- package/dist/Graph/setNode.mjs +50 -0
- package/dist/Graph/toJS.d.mts +59 -0
- package/dist/Graph/toJS.mjs +82 -0
- package/dist/Graph/types.d.mts +29 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Bimap } from "./internals/types.mjs";
|
|
2
|
+
import { Edges, Graph, Node, NodeIdentifier, NodeType } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Graph/forEachEdge.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* # forEachEdge
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* function Graph.forEachEdge(
|
|
10
|
+
* graph: Graph,
|
|
11
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
12
|
+
* type: NodeType,
|
|
13
|
+
* fn: (edge: EdgeData) => void,
|
|
14
|
+
* ): Graph
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Iterates over all edges of a specific type from a source node, executing a function for each edge. Returns the graph unchanged (for chaining).
|
|
18
|
+
*
|
|
19
|
+
* ## Example
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { Graph } from "@monstermann/graph";
|
|
23
|
+
*
|
|
24
|
+
* type Nodes =
|
|
25
|
+
* | { type: "Task"; id: string }
|
|
26
|
+
* | { type: "Section"; id: string }
|
|
27
|
+
* | { type: "Project"; id: string };
|
|
28
|
+
*
|
|
29
|
+
* type Edges = {
|
|
30
|
+
* Project: { Task: { priority: number } };
|
|
31
|
+
* Section: { Task: void };
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
35
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
36
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
37
|
+
* g = Graph.setNode(g, { type: "Task", id: "2" });
|
|
38
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], { priority: 1 });
|
|
39
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "2"], { priority: 2 });
|
|
40
|
+
*
|
|
41
|
+
* Graph.forEachEdge(g, ["Project", "1"], "Task", (edge) => {
|
|
42
|
+
* console.log(edge.priority);
|
|
43
|
+
* });
|
|
44
|
+
* // Logs:
|
|
45
|
+
* // 1
|
|
46
|
+
* // 2
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
declare function forEachEdge<N extends Node, E extends Edges<N>, N1 extends keyof Bimap<E> & NodeType<N>, N2 extends keyof Bimap<E>[N1] & NodeType<N>>(graph: Graph<N, E>, source: NodeIdentifier<N, N1>, type: N2, fn: (edge: NoInfer<Bimap<E>[N1][N2]>) => void): Graph<N, E>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { forEachEdge };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { parseNodeIdentifier } from "./internals/parseNodeIdentifier.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/forEachEdge.ts
|
|
4
|
+
/**
|
|
5
|
+
* # forEachEdge
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.forEachEdge(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
11
|
+
* type: NodeType,
|
|
12
|
+
* fn: (edge: EdgeData) => void,
|
|
13
|
+
* ): Graph
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Iterates over all edges of a specific type from a source node, executing a function for each edge. Returns the graph unchanged (for chaining).
|
|
17
|
+
*
|
|
18
|
+
* ## Example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { Graph } from "@monstermann/graph";
|
|
22
|
+
*
|
|
23
|
+
* type Nodes =
|
|
24
|
+
* | { type: "Task"; id: string }
|
|
25
|
+
* | { type: "Section"; id: string }
|
|
26
|
+
* | { type: "Project"; id: string };
|
|
27
|
+
*
|
|
28
|
+
* type Edges = {
|
|
29
|
+
* Project: { Task: { priority: number } };
|
|
30
|
+
* Section: { Task: void };
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
34
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
35
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
36
|
+
* g = Graph.setNode(g, { type: "Task", id: "2" });
|
|
37
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], { priority: 1 });
|
|
38
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "2"], { priority: 2 });
|
|
39
|
+
*
|
|
40
|
+
* Graph.forEachEdge(g, ["Project", "1"], "Task", (edge) => {
|
|
41
|
+
* console.log(edge.priority);
|
|
42
|
+
* });
|
|
43
|
+
* // Logs:
|
|
44
|
+
* // 1
|
|
45
|
+
* // 2
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
function forEachEdge(graph, source, type, fn) {
|
|
50
|
+
const [sourceType, sourceId] = parseNodeIdentifier(source);
|
|
51
|
+
for (const edge of graph.get("edges")?.get(sourceType)?.get(sourceId)?.get(type)?.values() ?? []) fn(edge);
|
|
52
|
+
return graph;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { forEachEdge };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Bimap } from "./internals/types.mjs";
|
|
2
|
+
import { Edges, Graph, Node, NodeIdentifier, NodeOfType, NodeType } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Graph/forEachNeighbor.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* # forEachNeighbor
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* function Graph.forEachNeighbor(
|
|
10
|
+
* graph: Graph,
|
|
11
|
+
* node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
12
|
+
* type: NodeType,
|
|
13
|
+
* fn: (target: Node, edge: EdgeData, source: Node) => void,
|
|
14
|
+
* ): Graph
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Iterates over all neighbor nodes of a specific type, executing a function for each neighbor. The function receives the target node, edge data, and source node. Returns the graph unchanged (for chaining).
|
|
18
|
+
*
|
|
19
|
+
* ## Example
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { Graph } from "@monstermann/graph";
|
|
23
|
+
*
|
|
24
|
+
* type Nodes =
|
|
25
|
+
* | { type: "Task"; id: string; title: string }
|
|
26
|
+
* | { type: "Section"; id: string }
|
|
27
|
+
* | { type: "Project"; id: string; name: string };
|
|
28
|
+
*
|
|
29
|
+
* type Edges = {
|
|
30
|
+
* Project: { Task: { priority: number } };
|
|
31
|
+
* Section: { Task: void };
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
35
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1", name: "My Project" });
|
|
36
|
+
* g = Graph.setNode(g, { type: "Task", id: "1", title: "First Task" });
|
|
37
|
+
* g = Graph.setNode(g, { type: "Task", id: "2", title: "Second Task" });
|
|
38
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], { priority: 1 });
|
|
39
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "2"], { priority: 2 });
|
|
40
|
+
*
|
|
41
|
+
* Graph.forEachNeighbor(g, ["Project", "1"], "Task", (task, edge, project) => {
|
|
42
|
+
* console.log(`${project.name}: ${task.title} (priority: ${edge.priority})`);
|
|
43
|
+
* });
|
|
44
|
+
* // Logs:
|
|
45
|
+
* // "My Project: First Task (priority: 1)"
|
|
46
|
+
* // "My Project: Second Task (priority: 2)"
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
declare function forEachNeighbor<N extends Node, E extends Edges<N>, N1 extends NodeType<N>, N2 extends keyof Bimap<E>[N1] & NodeType<N>>(graph: Graph<N, E>, node: NodeIdentifier<N, N1>, type: N2, fn: (target: NoInfer<NodeOfType<N, N2>>, edge: NoInfer<Bimap<E>[N1][N2]>, source: NoInfer<NodeOfType<N, N1>>) => void): Graph<N, E>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { forEachNeighbor };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { getNode } from "./getNode.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/forEachNeighbor.ts
|
|
4
|
+
/**
|
|
5
|
+
* # forEachNeighbor
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.forEachNeighbor(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
11
|
+
* type: NodeType,
|
|
12
|
+
* fn: (target: Node, edge: EdgeData, source: Node) => void,
|
|
13
|
+
* ): Graph
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Iterates over all neighbor nodes of a specific type, executing a function for each neighbor. The function receives the target node, edge data, and source node. Returns the graph unchanged (for chaining).
|
|
17
|
+
*
|
|
18
|
+
* ## Example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { Graph } from "@monstermann/graph";
|
|
22
|
+
*
|
|
23
|
+
* type Nodes =
|
|
24
|
+
* | { type: "Task"; id: string; title: string }
|
|
25
|
+
* | { type: "Section"; id: string }
|
|
26
|
+
* | { type: "Project"; id: string; name: string };
|
|
27
|
+
*
|
|
28
|
+
* type Edges = {
|
|
29
|
+
* Project: { Task: { priority: number } };
|
|
30
|
+
* Section: { Task: void };
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
34
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1", name: "My Project" });
|
|
35
|
+
* g = Graph.setNode(g, { type: "Task", id: "1", title: "First Task" });
|
|
36
|
+
* g = Graph.setNode(g, { type: "Task", id: "2", title: "Second Task" });
|
|
37
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], { priority: 1 });
|
|
38
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "2"], { priority: 2 });
|
|
39
|
+
*
|
|
40
|
+
* Graph.forEachNeighbor(g, ["Project", "1"], "Task", (task, edge, project) => {
|
|
41
|
+
* console.log(`${project.name}: ${task.title} (priority: ${edge.priority})`);
|
|
42
|
+
* });
|
|
43
|
+
* // Logs:
|
|
44
|
+
* // "My Project: First Task (priority: 1)"
|
|
45
|
+
* // "My Project: Second Task (priority: 2)"
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
function forEachNeighbor(graph, node, type, fn) {
|
|
50
|
+
const sourceNode = getNode(graph, node);
|
|
51
|
+
if (!sourceNode) return graph;
|
|
52
|
+
const nodeMap = graph.get("nodes")?.get(type);
|
|
53
|
+
if (!nodeMap) return graph;
|
|
54
|
+
for (const [targetId, edge] of graph.get("edges")?.get(sourceNode.type)?.get(sourceNode.id)?.get(type) ?? []) fn(nodeMap.get(targetId), edge, sourceNode);
|
|
55
|
+
return graph;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { forEachNeighbor };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Edges, Graph, Node, NodeOfType, NodeType } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/forEachNode.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* # forEachNode
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.forEachNode(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* type: NodeType,
|
|
11
|
+
* fn: (node: Node) => void,
|
|
12
|
+
* ): Graph
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* Iterates over all nodes of a specific type, executing a function for each node. Returns the graph unchanged (for chaining).
|
|
16
|
+
*
|
|
17
|
+
* ## Example
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { Graph } from "@monstermann/graph";
|
|
21
|
+
*
|
|
22
|
+
* type Nodes =
|
|
23
|
+
* | { type: "Task"; id: string; title: string }
|
|
24
|
+
* | { type: "Section"; id: string }
|
|
25
|
+
* | { type: "Project"; id: string };
|
|
26
|
+
*
|
|
27
|
+
* type Edges = {
|
|
28
|
+
* Project: { Task: void };
|
|
29
|
+
* Section: { Task: void };
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
33
|
+
* let g = Graph.setNode(graph, { type: "Task", id: "1", title: "First Task" });
|
|
34
|
+
* g = Graph.setNode(g, { type: "Task", id: "2", title: "Second Task" });
|
|
35
|
+
* g = Graph.setNode(g, { type: "Task", id: "3", title: "Third Task" });
|
|
36
|
+
*
|
|
37
|
+
* Graph.forEachNode(g, "Task", (task) => {
|
|
38
|
+
* console.log(task.title);
|
|
39
|
+
* });
|
|
40
|
+
* // Logs:
|
|
41
|
+
* // "First Task"
|
|
42
|
+
* // "Second Task"
|
|
43
|
+
* // "Third Task"
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
declare function forEachNode<N extends Node, E extends Edges<N>, U extends NodeType<N>>(graph: Graph<N, E>, type: U, fn: (node: NoInfer<NodeOfType<N, U>>) => void): Graph<N, E>;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { forEachNode };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/Graph/forEachNode.ts
|
|
2
|
+
/**
|
|
3
|
+
* # forEachNode
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* function Graph.forEachNode(
|
|
7
|
+
* graph: Graph,
|
|
8
|
+
* type: NodeType,
|
|
9
|
+
* fn: (node: Node) => void,
|
|
10
|
+
* ): Graph
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Iterates over all nodes of a specific type, executing a function for each node. Returns the graph unchanged (for chaining).
|
|
14
|
+
*
|
|
15
|
+
* ## Example
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Graph } from "@monstermann/graph";
|
|
19
|
+
*
|
|
20
|
+
* type Nodes =
|
|
21
|
+
* | { type: "Task"; id: string; title: string }
|
|
22
|
+
* | { type: "Section"; id: string }
|
|
23
|
+
* | { type: "Project"; id: string };
|
|
24
|
+
*
|
|
25
|
+
* type Edges = {
|
|
26
|
+
* Project: { Task: void };
|
|
27
|
+
* Section: { Task: void };
|
|
28
|
+
* };
|
|
29
|
+
*
|
|
30
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
31
|
+
* let g = Graph.setNode(graph, { type: "Task", id: "1", title: "First Task" });
|
|
32
|
+
* g = Graph.setNode(g, { type: "Task", id: "2", title: "Second Task" });
|
|
33
|
+
* g = Graph.setNode(g, { type: "Task", id: "3", title: "Third Task" });
|
|
34
|
+
*
|
|
35
|
+
* Graph.forEachNode(g, "Task", (task) => {
|
|
36
|
+
* console.log(task.title);
|
|
37
|
+
* });
|
|
38
|
+
* // Logs:
|
|
39
|
+
* // "First Task"
|
|
40
|
+
* // "Second Task"
|
|
41
|
+
* // "Third Task"
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
function forEachNode(graph, type, fn) {
|
|
46
|
+
for (const node of graph.get("nodes")?.get(type)?.values() ?? []) fn(node);
|
|
47
|
+
return graph;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { forEachNode };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Edge, Edges, Graph, Node, NodeId } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/fromJS.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* # fromJS
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.fromJS(data: {
|
|
9
|
+
* nodes: Node[];
|
|
10
|
+
* edges: [NodeType, NodeId, NodeType, NodeId, EdgeData][];
|
|
11
|
+
* }): Graph
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Creates a graph from a plain JavaScript object representation. Useful for deserializing graphs from JSON or other storage formats.
|
|
15
|
+
*
|
|
16
|
+
* ## Example
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Graph } from "@monstermann/graph";
|
|
20
|
+
*
|
|
21
|
+
* type Nodes =
|
|
22
|
+
* | { type: "Task"; id: string; title: string }
|
|
23
|
+
* | { type: "Section"; id: string }
|
|
24
|
+
* | { type: "Project"; id: string };
|
|
25
|
+
*
|
|
26
|
+
* type Edges = {
|
|
27
|
+
* Project: { Task: void };
|
|
28
|
+
* Section: { Task: void };
|
|
29
|
+
* };
|
|
30
|
+
*
|
|
31
|
+
* const data = {
|
|
32
|
+
* nodes: [
|
|
33
|
+
* { type: "Project", id: "1" },
|
|
34
|
+
* { type: "Task", id: "1", title: "My Task" },
|
|
35
|
+
* { type: "Task", id: "2", title: "Another Task" },
|
|
36
|
+
* ],
|
|
37
|
+
* edges: [
|
|
38
|
+
* ["Project", "1", "Task", "1", undefined],
|
|
39
|
+
* ["Project", "1", "Task", "2", undefined],
|
|
40
|
+
* ],
|
|
41
|
+
* };
|
|
42
|
+
*
|
|
43
|
+
* const graph = Graph.fromJS<Nodes, Edges>(data);
|
|
44
|
+
*
|
|
45
|
+
* Graph.hasNode(graph, ["Project", "1"]); // true
|
|
46
|
+
* Graph.hasEdge(graph, ["Project", "1"], ["Task", "1"]); // true
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
declare function fromJS<N extends Node, E extends Edges<N>>(data: {
|
|
51
|
+
edges: [string, NodeId, string, NodeId, Edge][];
|
|
52
|
+
nodes: Node[];
|
|
53
|
+
}): Graph<N, E>;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { fromJS };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { batch } from "./batch.mjs";
|
|
2
|
+
import { create } from "./create.mjs";
|
|
3
|
+
import { setEdge } from "./setEdge.mjs";
|
|
4
|
+
import { setNode } from "./setNode.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/Graph/fromJS.ts
|
|
7
|
+
/**
|
|
8
|
+
* # fromJS
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* function Graph.fromJS(data: {
|
|
12
|
+
* nodes: Node[];
|
|
13
|
+
* edges: [NodeType, NodeId, NodeType, NodeId, EdgeData][];
|
|
14
|
+
* }): Graph
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Creates a graph from a plain JavaScript object representation. Useful for deserializing graphs from JSON or other storage formats.
|
|
18
|
+
*
|
|
19
|
+
* ## Example
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { Graph } from "@monstermann/graph";
|
|
23
|
+
*
|
|
24
|
+
* type Nodes =
|
|
25
|
+
* | { type: "Task"; id: string; title: string }
|
|
26
|
+
* | { type: "Section"; id: string }
|
|
27
|
+
* | { type: "Project"; id: string };
|
|
28
|
+
*
|
|
29
|
+
* type Edges = {
|
|
30
|
+
* Project: { Task: void };
|
|
31
|
+
* Section: { Task: void };
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* const data = {
|
|
35
|
+
* nodes: [
|
|
36
|
+
* { type: "Project", id: "1" },
|
|
37
|
+
* { type: "Task", id: "1", title: "My Task" },
|
|
38
|
+
* { type: "Task", id: "2", title: "Another Task" },
|
|
39
|
+
* ],
|
|
40
|
+
* edges: [
|
|
41
|
+
* ["Project", "1", "Task", "1", undefined],
|
|
42
|
+
* ["Project", "1", "Task", "2", undefined],
|
|
43
|
+
* ],
|
|
44
|
+
* };
|
|
45
|
+
*
|
|
46
|
+
* const graph = Graph.fromJS<Nodes, Edges>(data);
|
|
47
|
+
*
|
|
48
|
+
* Graph.hasNode(graph, ["Project", "1"]); // true
|
|
49
|
+
* Graph.hasEdge(graph, ["Project", "1"], ["Task", "1"]); // true
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
*/
|
|
53
|
+
function fromJS(data) {
|
|
54
|
+
return batch(create(), (graph) => {
|
|
55
|
+
for (const node of data.nodes) graph = setNode(graph, node);
|
|
56
|
+
for (const [sourceType, sourceId, targetType, targetId, edge] of data.edges) graph = setEdge(graph, [sourceType, sourceId], [targetType, targetId], edge);
|
|
57
|
+
return graph;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { fromJS };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Bimap } from "./internals/types.mjs";
|
|
2
|
+
import { Edges, Graph, Node, NodeIdentifier, NodeType } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Graph/getEdge.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* # getEdge
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* function Graph.getEdge(
|
|
10
|
+
* graph: Graph,
|
|
11
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
12
|
+
* target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
13
|
+
* ): EdgeData | undefined
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Retrieves the edge data between two nodes. Returns `undefined` if the edge doesn't exist.
|
|
17
|
+
*
|
|
18
|
+
* ## Example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { Graph } from "@monstermann/graph";
|
|
22
|
+
*
|
|
23
|
+
* type Nodes =
|
|
24
|
+
* | { type: "Task"; id: string }
|
|
25
|
+
* | { type: "Section"; id: string }
|
|
26
|
+
* | { type: "Project"; id: string };
|
|
27
|
+
*
|
|
28
|
+
* type Edges = {
|
|
29
|
+
* Project: { Task: { assignedAt: Date } };
|
|
30
|
+
* Section: { Task: void };
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
34
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
35
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
36
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
|
|
37
|
+
* assignedAt: new Date(),
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* const edge = Graph.getEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
41
|
+
* // edge: { assignedAt: Date }
|
|
42
|
+
*
|
|
43
|
+
* const missing = Graph.getEdge(g, ["Project", "1"], ["Task", "2"]);
|
|
44
|
+
* // missing: undefined
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
declare function getEdge<N extends Node, E extends Edges<N>, N1 extends keyof Bimap<E> & NodeType<N>, N2 extends keyof Bimap<E>[N1] & NodeType<N>>(graph: Graph<N, E>, source: NodeIdentifier<N, N1>, target: NodeIdentifier<N, N2>): Bimap<E>[N1][N2] | undefined;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { getEdge };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { parseNodeIdentifier } from "./internals/parseNodeIdentifier.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/getEdge.ts
|
|
4
|
+
/**
|
|
5
|
+
* # getEdge
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.getEdge(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
11
|
+
* target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
12
|
+
* ): EdgeData | undefined
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* Retrieves the edge data between two nodes. Returns `undefined` if the edge doesn't exist.
|
|
16
|
+
*
|
|
17
|
+
* ## Example
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { Graph } from "@monstermann/graph";
|
|
21
|
+
*
|
|
22
|
+
* type Nodes =
|
|
23
|
+
* | { type: "Task"; id: string }
|
|
24
|
+
* | { type: "Section"; id: string }
|
|
25
|
+
* | { type: "Project"; id: string };
|
|
26
|
+
*
|
|
27
|
+
* type Edges = {
|
|
28
|
+
* Project: { Task: { assignedAt: Date } };
|
|
29
|
+
* Section: { Task: void };
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
33
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
34
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
35
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
|
|
36
|
+
* assignedAt: new Date(),
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* const edge = Graph.getEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
40
|
+
* // edge: { assignedAt: Date }
|
|
41
|
+
*
|
|
42
|
+
* const missing = Graph.getEdge(g, ["Project", "1"], ["Task", "2"]);
|
|
43
|
+
* // missing: undefined
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
function getEdge(graph, source, target) {
|
|
48
|
+
const [sourceType, sourceId] = parseNodeIdentifier(source);
|
|
49
|
+
const [targetType, targetId] = parseNodeIdentifier(target);
|
|
50
|
+
return graph.get("edges")?.get(sourceType)?.get(sourceId)?.get(targetType)?.get(targetId);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
export { getEdge };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Bimap } from "./internals/types.mjs";
|
|
2
|
+
import { Edges, Graph, Node, NodeIdentifier, NodeType } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/Graph/getEdges.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* # getEdges
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* function Graph.getEdges(
|
|
10
|
+
* graph: Graph,
|
|
11
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
12
|
+
* type: NodeType,
|
|
13
|
+
* ): EdgeData[]
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Retrieves all edges of a specific type from a source node.
|
|
17
|
+
*
|
|
18
|
+
* ## Example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { Graph } from "@monstermann/graph";
|
|
22
|
+
*
|
|
23
|
+
* type Nodes =
|
|
24
|
+
* | { type: "Task"; id: string }
|
|
25
|
+
* | { type: "Section"; id: string }
|
|
26
|
+
* | { type: "Project"; id: string };
|
|
27
|
+
*
|
|
28
|
+
* type Edges = {
|
|
29
|
+
* Project: { Task: { priority: number } };
|
|
30
|
+
* Section: { Task: void };
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
34
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
35
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
36
|
+
* g = Graph.setNode(g, { type: "Task", id: "2" });
|
|
37
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], { priority: 1 });
|
|
38
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "2"], { priority: 2 });
|
|
39
|
+
*
|
|
40
|
+
* const edges = Graph.getEdges(g, ["Project", "1"], "Task");
|
|
41
|
+
* // edges: [{ priority: 1 }, { priority: 2 }]
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
declare function getEdges<N extends Node, E extends Edges<N>, N1 extends keyof Bimap<E> & NodeType<N>, N2 extends keyof Bimap<E>[N1] & NodeType<N>>(graph: Graph<N, E>, source: NodeIdentifier<N, N1>, type: N2): Bimap<E>[N1][N2][];
|
|
46
|
+
//#endregion
|
|
47
|
+
export { getEdges };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { parseNodeIdentifier } from "./internals/parseNodeIdentifier.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/getEdges.ts
|
|
4
|
+
/**
|
|
5
|
+
* # getEdges
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.getEdges(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
11
|
+
* type: NodeType,
|
|
12
|
+
* ): EdgeData[]
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* Retrieves all edges of a specific type from a source node.
|
|
16
|
+
*
|
|
17
|
+
* ## Example
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { Graph } from "@monstermann/graph";
|
|
21
|
+
*
|
|
22
|
+
* type Nodes =
|
|
23
|
+
* | { type: "Task"; id: string }
|
|
24
|
+
* | { type: "Section"; id: string }
|
|
25
|
+
* | { type: "Project"; id: string };
|
|
26
|
+
*
|
|
27
|
+
* type Edges = {
|
|
28
|
+
* Project: { Task: { priority: number } };
|
|
29
|
+
* Section: { Task: void };
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
33
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
34
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
35
|
+
* g = Graph.setNode(g, { type: "Task", id: "2" });
|
|
36
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], { priority: 1 });
|
|
37
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "2"], { priority: 2 });
|
|
38
|
+
*
|
|
39
|
+
* const edges = Graph.getEdges(g, ["Project", "1"], "Task");
|
|
40
|
+
* // edges: [{ priority: 1 }, { priority: 2 }]
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
function getEdges(graph, source, type) {
|
|
45
|
+
const [sourceType, sourceId] = parseNodeIdentifier(source);
|
|
46
|
+
const edgeMap = graph.get("edges")?.get(sourceType)?.get(sourceId)?.get(type);
|
|
47
|
+
return edgeMap ? [...edgeMap.values()] : [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { getEdges };
|