@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.
Files changed (68) hide show
  1. package/README.md +1383 -0
  2. package/dist/Graph/batch.d.mts +47 -0
  3. package/dist/Graph/batch.mjs +57 -0
  4. package/dist/Graph/create.d.mts +36 -0
  5. package/dist/Graph/create.mjs +37 -0
  6. package/dist/Graph/findEdge.d.mts +60 -0
  7. package/dist/Graph/findEdge.mjs +10 -0
  8. package/dist/Graph/findEdges.d.mts +65 -0
  9. package/dist/Graph/findEdges.mjs +12 -0
  10. package/dist/Graph/findNeighbor.d.mts +54 -0
  11. package/dist/Graph/findNeighbor.mjs +16 -0
  12. package/dist/Graph/findNeighbors.d.mts +59 -0
  13. package/dist/Graph/findNeighbors.mjs +18 -0
  14. package/dist/Graph/findNode.d.mts +67 -0
  15. package/dist/Graph/findNode.mjs +7 -0
  16. package/dist/Graph/findNodes.d.mts +63 -0
  17. package/dist/Graph/findNodes.mjs +9 -0
  18. package/dist/Graph/forEachEdge.d.mts +52 -0
  19. package/dist/Graph/forEachEdge.mjs +56 -0
  20. package/dist/Graph/forEachNeighbor.d.mts +52 -0
  21. package/dist/Graph/forEachNeighbor.mjs +59 -0
  22. package/dist/Graph/forEachNode.d.mts +49 -0
  23. package/dist/Graph/forEachNode.mjs +51 -0
  24. package/dist/Graph/fromJS.d.mts +55 -0
  25. package/dist/Graph/fromJS.mjs +62 -0
  26. package/dist/Graph/getEdge.d.mts +50 -0
  27. package/dist/Graph/getEdge.mjs +54 -0
  28. package/dist/Graph/getEdges.d.mts +47 -0
  29. package/dist/Graph/getEdges.mjs +51 -0
  30. package/dist/Graph/getNeighbor.d.mts +50 -0
  31. package/dist/Graph/getNeighbor.mjs +56 -0
  32. package/dist/Graph/getNeighbors.d.mts +47 -0
  33. package/dist/Graph/getNeighbors.mjs +58 -0
  34. package/dist/Graph/getNode.d.mts +48 -0
  35. package/dist/Graph/getNode.mjs +52 -0
  36. package/dist/Graph/getNodes.d.mts +46 -0
  37. package/dist/Graph/getNodes.mjs +48 -0
  38. package/dist/Graph/hasEdge.d.mts +46 -0
  39. package/dist/Graph/hasEdge.mjs +50 -0
  40. package/dist/Graph/hasNode.d.mts +42 -0
  41. package/dist/Graph/hasNode.mjs +46 -0
  42. package/dist/Graph/index.d.mts +68 -0
  43. package/dist/Graph/index.mjs +65 -0
  44. package/dist/Graph/internals/core.mjs +51 -0
  45. package/dist/Graph/internals/parseNodeIdentifier.mjs +7 -0
  46. package/dist/Graph/internals/types.d.mts +16 -0
  47. package/dist/Graph/mapEdge.d.mts +52 -0
  48. package/dist/Graph/mapEdge.mjs +60 -0
  49. package/dist/Graph/mapNode.d.mts +65 -0
  50. package/dist/Graph/mapNode.mjs +83 -0
  51. package/dist/Graph/mergeEdge.d.mts +52 -0
  52. package/dist/Graph/mergeEdge.mjs +63 -0
  53. package/dist/Graph/mergeNode.d.mts +50 -0
  54. package/dist/Graph/mergeNode.mjs +60 -0
  55. package/dist/Graph/removeEdge.d.mts +49 -0
  56. package/dist/Graph/removeEdge.mjs +71 -0
  57. package/dist/Graph/removeNode.d.mts +46 -0
  58. package/dist/Graph/removeNode.mjs +71 -0
  59. package/dist/Graph/setEdge.d.mts +52 -0
  60. package/dist/Graph/setEdge.mjs +78 -0
  61. package/dist/Graph/setNode.d.mts +43 -0
  62. package/dist/Graph/setNode.mjs +50 -0
  63. package/dist/Graph/toJS.d.mts +59 -0
  64. package/dist/Graph/toJS.mjs +82 -0
  65. package/dist/Graph/types.d.mts +29 -0
  66. package/dist/index.d.mts +2 -0
  67. package/dist/index.mjs +3 -0
  68. 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 };
@@ -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
@@ -0,0 +1,3 @@
1
+ import { Graph } from "./Graph/index.mjs";
2
+
3
+ export { Graph };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@monstermann/graph",
3
3
  "type": "module",
4
- "version": "0.0.0",
4
+ "version": "0.2.0",
5
5
  "description": "Functional graph data-structure.",
6
6
  "author": "Michael Ostermann <michaelostermann@me.com>",
7
7
  "license": "MIT",