@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,71 @@
|
|
|
1
|
+
import { batch } from "./batch.mjs";
|
|
2
|
+
import { parseNodeIdentifier } from "./internals/parseNodeIdentifier.mjs";
|
|
3
|
+
import { unsetInGraph } from "./internals/core.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/Graph/removeEdge.ts
|
|
6
|
+
/**
|
|
7
|
+
* # removeEdge
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Graph.removeEdge(
|
|
11
|
+
* graph: Graph,
|
|
12
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
13
|
+
* target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
14
|
+
* ): Graph
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Removes an edge between two nodes. The nodes remain in the graph. Returns a new graph instance without the edge.
|
|
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: void };
|
|
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.setEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
38
|
+
*
|
|
39
|
+
* // Remove the edge
|
|
40
|
+
* g = Graph.removeEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
41
|
+
*
|
|
42
|
+
* Graph.hasNode(g, ["Project", "1"]); // true
|
|
43
|
+
* Graph.hasNode(g, ["Task", "1"]); // true
|
|
44
|
+
* Graph.hasEdge(g, ["Project", "1"], ["Task", "1"]); // false
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
function removeEdge(graph, source, target) {
|
|
49
|
+
const [sourceType, sourceId] = parseNodeIdentifier(source);
|
|
50
|
+
const [targetType, targetId] = parseNodeIdentifier(target);
|
|
51
|
+
return batch(graph, (graph) => {
|
|
52
|
+
graph = unsetInGraph(graph, [
|
|
53
|
+
"edges",
|
|
54
|
+
sourceType,
|
|
55
|
+
sourceId,
|
|
56
|
+
targetType,
|
|
57
|
+
targetId
|
|
58
|
+
]);
|
|
59
|
+
graph = unsetInGraph(graph, [
|
|
60
|
+
"edges",
|
|
61
|
+
targetType,
|
|
62
|
+
targetId,
|
|
63
|
+
sourceType,
|
|
64
|
+
sourceId
|
|
65
|
+
]);
|
|
66
|
+
return graph;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { removeEdge };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Edges, Graph, Node, NodeIdentifier, NodeType } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/removeNode.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* # removeNode
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.removeNode(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
11
|
+
* ): Graph
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Removes a node and all its associated edges from the graph. Returns a new graph instance without the node.
|
|
15
|
+
*
|
|
16
|
+
* ## Example
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Graph } from "@monstermann/graph";
|
|
20
|
+
*
|
|
21
|
+
* type Nodes =
|
|
22
|
+
* | { type: "Task"; id: 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 graph = Graph.create<Nodes, Edges>();
|
|
32
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
33
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
34
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
35
|
+
*
|
|
36
|
+
* // Remove the task (also removes the edge)
|
|
37
|
+
* g = Graph.removeNode(g, ["Task", "1"]);
|
|
38
|
+
*
|
|
39
|
+
* Graph.hasNode(g, ["Task", "1"]); // false
|
|
40
|
+
* Graph.hasEdge(g, ["Project", "1"], ["Task", "1"]); // false
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
declare function removeNode<N extends Node, E extends Edges<N>, U extends NodeType<N>>(graph: Graph<N, E>, node: NodeIdentifier<N, U>): Graph<N, E>;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { removeNode };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { batch } from "./batch.mjs";
|
|
2
|
+
import { parseNodeIdentifier } from "./internals/parseNodeIdentifier.mjs";
|
|
3
|
+
import { unsetInGraph } from "./internals/core.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/Graph/removeNode.ts
|
|
6
|
+
/**
|
|
7
|
+
* # removeNode
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* function Graph.removeNode(
|
|
11
|
+
* graph: Graph,
|
|
12
|
+
* node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
13
|
+
* ): Graph
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Removes a node and all its associated edges from the graph. Returns a new graph instance without the 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: void };
|
|
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
|
+
*
|
|
38
|
+
* // Remove the task (also removes the edge)
|
|
39
|
+
* g = Graph.removeNode(g, ["Task", "1"]);
|
|
40
|
+
*
|
|
41
|
+
* Graph.hasNode(g, ["Task", "1"]); // false
|
|
42
|
+
* Graph.hasEdge(g, ["Project", "1"], ["Task", "1"]); // false
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
function removeNode(graph, node) {
|
|
47
|
+
const [sourceType, sourceId] = parseNodeIdentifier(node);
|
|
48
|
+
return batch(graph, (graph) => {
|
|
49
|
+
for (const [targetType, targets] of graph.get("edges")?.get(sourceType)?.get(sourceId) ?? []) for (const targetId of targets.keys()) graph = unsetInGraph(graph, [
|
|
50
|
+
"edges",
|
|
51
|
+
targetType,
|
|
52
|
+
targetId,
|
|
53
|
+
sourceType,
|
|
54
|
+
sourceId
|
|
55
|
+
]);
|
|
56
|
+
graph = unsetInGraph(graph, [
|
|
57
|
+
"edges",
|
|
58
|
+
sourceType,
|
|
59
|
+
sourceId
|
|
60
|
+
]);
|
|
61
|
+
graph = unsetInGraph(graph, [
|
|
62
|
+
"nodes",
|
|
63
|
+
sourceType,
|
|
64
|
+
sourceId
|
|
65
|
+
]);
|
|
66
|
+
return graph;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { removeNode };
|
|
@@ -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/setEdge.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* # setEdge
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* function Graph.setEdge(
|
|
10
|
+
* graph: Graph,
|
|
11
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
12
|
+
* target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
13
|
+
* data?: EdgeData,
|
|
14
|
+
* ): Graph
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Adds or updates an edge between two nodes. Both nodes must exist in the graph. Returns a new graph instance with the edge set. Edges are bidirectional.
|
|
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: { assignedAt: Date } };
|
|
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
|
+
*
|
|
38
|
+
* // Add edge with data
|
|
39
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
|
|
40
|
+
* assignedAt: new Date(),
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* // Add edge without data (void)
|
|
44
|
+
* let g2 = Graph.setNode(graph, { type: "Section", id: "1" });
|
|
45
|
+
* g2 = Graph.setNode(g2, { type: "Task", id: "1" });
|
|
46
|
+
* g2 = Graph.setEdge(g2, ["Section", "1"], ["Task", "1"]);
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
declare function setEdge<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>, ...args: Bimap<E>[N1][N2] extends void ? [] | [data: void] : [data: Bimap<E>[N1][N2]]): Graph<N, E>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { setEdge };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { batch } from "./batch.mjs";
|
|
2
|
+
import { parseNodeIdentifier } from "./internals/parseNodeIdentifier.mjs";
|
|
3
|
+
import { hasNode } from "./hasNode.mjs";
|
|
4
|
+
import { setInGraph } from "./internals/core.mjs";
|
|
5
|
+
|
|
6
|
+
//#region src/Graph/setEdge.ts
|
|
7
|
+
/**
|
|
8
|
+
* # setEdge
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* function Graph.setEdge(
|
|
12
|
+
* graph: Graph,
|
|
13
|
+
* source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
14
|
+
* target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
|
|
15
|
+
* data?: EdgeData,
|
|
16
|
+
* ): Graph
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Adds or updates an edge between two nodes. Both nodes must exist in the graph. Returns a new graph instance with the edge set. Edges are bidirectional.
|
|
20
|
+
*
|
|
21
|
+
* ## Example
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { Graph } from "@monstermann/graph";
|
|
25
|
+
*
|
|
26
|
+
* type Nodes =
|
|
27
|
+
* | { type: "Task"; id: string }
|
|
28
|
+
* | { type: "Section"; id: string }
|
|
29
|
+
* | { type: "Project"; id: string };
|
|
30
|
+
*
|
|
31
|
+
* type Edges = {
|
|
32
|
+
* Project: { Task: { assignedAt: Date } };
|
|
33
|
+
* Section: { Task: void };
|
|
34
|
+
* };
|
|
35
|
+
*
|
|
36
|
+
* const graph = Graph.create<Nodes, Edges>();
|
|
37
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
38
|
+
* g = Graph.setNode(g, { type: "Task", id: "1" });
|
|
39
|
+
*
|
|
40
|
+
* // Add edge with data
|
|
41
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
|
|
42
|
+
* assignedAt: new Date(),
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* // Add edge without data (void)
|
|
46
|
+
* let g2 = Graph.setNode(graph, { type: "Section", id: "1" });
|
|
47
|
+
* g2 = Graph.setNode(g2, { type: "Task", id: "1" });
|
|
48
|
+
* g2 = Graph.setEdge(g2, ["Section", "1"], ["Task", "1"]);
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
function setEdge(graph, source, target, ...args) {
|
|
53
|
+
const edge = args[0];
|
|
54
|
+
const [sourceType, sourceId] = parseNodeIdentifier(source);
|
|
55
|
+
const [targetType, targetId] = parseNodeIdentifier(target);
|
|
56
|
+
if (!hasNode(graph, source)) return graph;
|
|
57
|
+
if (!hasNode(graph, target)) return graph;
|
|
58
|
+
return batch(graph, (graph) => {
|
|
59
|
+
graph = setInGraph(graph, [
|
|
60
|
+
"edges",
|
|
61
|
+
sourceType,
|
|
62
|
+
sourceId,
|
|
63
|
+
targetType,
|
|
64
|
+
targetId
|
|
65
|
+
], edge);
|
|
66
|
+
graph = setInGraph(graph, [
|
|
67
|
+
"edges",
|
|
68
|
+
targetType,
|
|
69
|
+
targetId,
|
|
70
|
+
sourceType,
|
|
71
|
+
sourceId
|
|
72
|
+
], edge);
|
|
73
|
+
return graph;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
export { setEdge };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Edges, Graph, Node } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/setNode.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* # setNode
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.setNode(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* node: Node,
|
|
11
|
+
* ): Graph
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Adds or updates a node in the graph. Returns a new graph instance with the node set.
|
|
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 graph = Graph.create<Nodes, Edges>();
|
|
32
|
+
*
|
|
33
|
+
* // Add a new node
|
|
34
|
+
* const g1 = Graph.setNode(graph, { type: "Task", id: "1", title: "My Task" });
|
|
35
|
+
*
|
|
36
|
+
* // Update existing node
|
|
37
|
+
* const g2 = Graph.setNode(g1, { type: "Task", id: "1", title: "Updated Task" });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
declare function setNode<N extends Node, E extends Edges<N>>(graph: Graph<N, E>, node: NoInfer<N>): Graph<N, E>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { setNode };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { setInGraph } from "./internals/core.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/setNode.ts
|
|
4
|
+
/**
|
|
5
|
+
* # setNode
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.setNode(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* node: Node,
|
|
11
|
+
* ): Graph
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Adds or updates a node in the graph. Returns a new graph instance with the node set.
|
|
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 graph = Graph.create<Nodes, Edges>();
|
|
32
|
+
*
|
|
33
|
+
* // Add a new node
|
|
34
|
+
* const g1 = Graph.setNode(graph, { type: "Task", id: "1", title: "My Task" });
|
|
35
|
+
*
|
|
36
|
+
* // Update existing node
|
|
37
|
+
* const g2 = Graph.setNode(g1, { type: "Task", id: "1", title: "Updated Task" });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
function setNode(graph, node) {
|
|
42
|
+
return setInGraph(graph, [
|
|
43
|
+
"nodes",
|
|
44
|
+
node.type,
|
|
45
|
+
node.id
|
|
46
|
+
], node);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { setNode };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Edge, Edges, Graph, Node, NodeId } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/toJS.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* # toJS
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* function Graph.toJS(
|
|
9
|
+
* graph: Graph,
|
|
10
|
+
* ): {
|
|
11
|
+
* nodes: Node[];
|
|
12
|
+
* edges: [NodeType, NodeId, NodeType, NodeId, EdgeData][];
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Converts a graph to a plain JavaScript object representation. Useful for serializing graphs to JSON or other storage formats.
|
|
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 };
|
|
27
|
+
*
|
|
28
|
+
* type Edges = {
|
|
29
|
+
* Project: { Task: void };
|
|
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", title: "My Task" });
|
|
36
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
37
|
+
*
|
|
38
|
+
* const data = Graph.toJS(g);
|
|
39
|
+
* // data: {
|
|
40
|
+
* // nodes: [
|
|
41
|
+
* // { type: "Project", id: "1" },
|
|
42
|
+
* // { type: "Task", id: "1", title: "My Task" }
|
|
43
|
+
* // ],
|
|
44
|
+
* // edges: [
|
|
45
|
+
* // ["Project", "1", "Task", "1", undefined]
|
|
46
|
+
* // ]
|
|
47
|
+
* // }
|
|
48
|
+
*
|
|
49
|
+
* // Can be serialized to JSON
|
|
50
|
+
* const json = JSON.stringify(data);
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
*/
|
|
54
|
+
declare function toJS<N extends Node, E extends Edges<N>>(graph: Graph<N, E>): {
|
|
55
|
+
edges: [string, NodeId, string, NodeId, Edge][];
|
|
56
|
+
nodes: Node[];
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
export { toJS };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/Graph/toJS.ts
|
|
2
|
+
/**
|
|
3
|
+
* # toJS
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* function Graph.toJS(
|
|
7
|
+
* graph: Graph,
|
|
8
|
+
* ): {
|
|
9
|
+
* nodes: Node[];
|
|
10
|
+
* edges: [NodeType, NodeId, NodeType, NodeId, EdgeData][];
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Converts a graph to a plain JavaScript object representation. Useful for serializing graphs to 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 graph = Graph.create<Nodes, Edges>();
|
|
32
|
+
* let g = Graph.setNode(graph, { type: "Project", id: "1" });
|
|
33
|
+
* g = Graph.setNode(g, { type: "Task", id: "1", title: "My Task" });
|
|
34
|
+
* g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"]);
|
|
35
|
+
*
|
|
36
|
+
* const data = Graph.toJS(g);
|
|
37
|
+
* // data: {
|
|
38
|
+
* // nodes: [
|
|
39
|
+
* // { type: "Project", id: "1" },
|
|
40
|
+
* // { type: "Task", id: "1", title: "My Task" }
|
|
41
|
+
* // ],
|
|
42
|
+
* // edges: [
|
|
43
|
+
* // ["Project", "1", "Task", "1", undefined]
|
|
44
|
+
* // ]
|
|
45
|
+
* // }
|
|
46
|
+
*
|
|
47
|
+
* // Can be serialized to JSON
|
|
48
|
+
* const json = JSON.stringify(data);
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
function toJS(graph) {
|
|
53
|
+
const nodes = [];
|
|
54
|
+
const edges = [];
|
|
55
|
+
const seenEdges = /* @__PURE__ */ new Set();
|
|
56
|
+
for (const ids of graph.get("nodes")?.values() ?? []) for (const node of ids.values()) nodes.push(node);
|
|
57
|
+
for (const [sourceType, sourceIds] of graph.get("edges") ?? []) for (const [sourceId, targetTypes] of sourceIds) for (const [targetType, targetIds] of targetTypes) for (const [targetId, edge] of targetIds) {
|
|
58
|
+
const key = createEdgeKey(sourceType, String(sourceId), targetType, String(targetId));
|
|
59
|
+
if (seenEdges.has(key)) continue;
|
|
60
|
+
seenEdges.add(key);
|
|
61
|
+
edges.push([
|
|
62
|
+
sourceType,
|
|
63
|
+
sourceId,
|
|
64
|
+
targetType,
|
|
65
|
+
targetId,
|
|
66
|
+
edge
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
edges,
|
|
71
|
+
nodes
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function createEdgeKey(type1, id1, type2, id2) {
|
|
75
|
+
const cmp = type1.localeCompare(type2);
|
|
76
|
+
if (cmp < 0) return `${type1}\0${id1}\0${type2}\0${id2}`;
|
|
77
|
+
else if (cmp > 0) return `${type2}\0${id2}\0${type1}\0${id1}`;
|
|
78
|
+
else return id1 < id2 ? `${type1}\0${id1}\0${type2}\0${id2}` : `${type2}\0${id2}\0${type1}\0${id1}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
export { toJS };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { NodeTypesMap, SourceTypesMap } from "./internals/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/Graph/types.d.ts
|
|
4
|
+
type NodeId = PropertyKey;
|
|
5
|
+
type Node = {
|
|
6
|
+
id: NodeId;
|
|
7
|
+
type: string;
|
|
8
|
+
};
|
|
9
|
+
type NodeType<T extends Node> = T["type"];
|
|
10
|
+
type NodeOfType<T extends Node, U extends NodeType<T>> = Extract<T, {
|
|
11
|
+
type: U;
|
|
12
|
+
}>;
|
|
13
|
+
type NodeIdentifier<T extends Node, U extends NodeType<T>> = {
|
|
14
|
+
id: Extract<T, {
|
|
15
|
+
type: U;
|
|
16
|
+
}>["id"];
|
|
17
|
+
type: U;
|
|
18
|
+
} | [U, id: Extract<T, {
|
|
19
|
+
type: U;
|
|
20
|
+
}>["id"]];
|
|
21
|
+
type Edge = Record<string, unknown> | void;
|
|
22
|
+
type Edges<N extends Node> = Partial<Record<NodeType<N>, Partial<Record<NodeType<N>, Edge>>>>;
|
|
23
|
+
interface Graph<N extends Node, _E extends Edges<N>> extends Map<"nodes" | "edges" | "clones", NodeTypesMap<N> | SourceTypesMap | Set<any>> {
|
|
24
|
+
delete: (key: "clones") => boolean;
|
|
25
|
+
get: ((key: "nodes") => NodeTypesMap<N> | undefined) & ((key: "edges") => SourceTypesMap | undefined) & ((key: "clones") => Set<any> | undefined);
|
|
26
|
+
set: (key: "clones", value: Set<any>) => this;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Edge, Edges, Graph, Node, NodeId, NodeIdentifier, NodeOfType, NodeType };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Edge, Edges, Graph, Node, NodeId, NodeIdentifier, NodeIdsMap, NodeOfType, NodeType, NodeTypesMap, SourceIdsMap, SourceTypesMap, TargetIdsMap, TargetTypesMap } from "./Graph/index.mjs";
|
|
2
|
+
export { Edge, Edges, Graph, Node, NodeId, NodeIdentifier, NodeIdsMap, NodeOfType, NodeType, NodeTypesMap, SourceIdsMap, SourceTypesMap, TargetIdsMap, TargetTypesMap };
|
package/dist/index.mjs
ADDED