@monstermann/graph 0.0.0 → 0.1.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 +48 -0
  3. package/dist/Graph/batch.mjs +57 -0
  4. package/dist/Graph/create.d.mts +37 -0
  5. package/dist/Graph/create.mjs +37 -0
  6. package/dist/Graph/findEdge.d.mts +61 -0
  7. package/dist/Graph/findEdge.mjs +10 -0
  8. package/dist/Graph/findEdges.d.mts +66 -0
  9. package/dist/Graph/findEdges.mjs +12 -0
  10. package/dist/Graph/findNeighbor.d.mts +55 -0
  11. package/dist/Graph/findNeighbor.mjs +16 -0
  12. package/dist/Graph/findNeighbors.d.mts +60 -0
  13. package/dist/Graph/findNeighbors.mjs +18 -0
  14. package/dist/Graph/findNode.d.mts +68 -0
  15. package/dist/Graph/findNode.mjs +7 -0
  16. package/dist/Graph/findNodes.d.mts +64 -0
  17. package/dist/Graph/findNodes.mjs +9 -0
  18. package/dist/Graph/forEachEdge.d.mts +53 -0
  19. package/dist/Graph/forEachEdge.mjs +56 -0
  20. package/dist/Graph/forEachNeighbor.d.mts +53 -0
  21. package/dist/Graph/forEachNeighbor.mjs +59 -0
  22. package/dist/Graph/forEachNode.d.mts +50 -0
  23. package/dist/Graph/forEachNode.mjs +51 -0
  24. package/dist/Graph/fromJS.d.mts +56 -0
  25. package/dist/Graph/fromJS.mjs +62 -0
  26. package/dist/Graph/getEdge.d.mts +51 -0
  27. package/dist/Graph/getEdge.mjs +54 -0
  28. package/dist/Graph/getEdges.d.mts +48 -0
  29. package/dist/Graph/getEdges.mjs +51 -0
  30. package/dist/Graph/getNeighbor.d.mts +51 -0
  31. package/dist/Graph/getNeighbor.mjs +56 -0
  32. package/dist/Graph/getNeighbors.d.mts +48 -0
  33. package/dist/Graph/getNeighbors.mjs +58 -0
  34. package/dist/Graph/getNode.d.mts +49 -0
  35. package/dist/Graph/getNode.mjs +52 -0
  36. package/dist/Graph/getNodes.d.mts +47 -0
  37. package/dist/Graph/getNodes.mjs +48 -0
  38. package/dist/Graph/hasEdge.d.mts +47 -0
  39. package/dist/Graph/hasEdge.mjs +50 -0
  40. package/dist/Graph/hasNode.d.mts +43 -0
  41. package/dist/Graph/hasNode.mjs +46 -0
  42. package/dist/Graph/index.d.mts +69 -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 +53 -0
  48. package/dist/Graph/mapEdge.mjs +60 -0
  49. package/dist/Graph/mapNode.d.mts +66 -0
  50. package/dist/Graph/mapNode.mjs +83 -0
  51. package/dist/Graph/mergeEdge.d.mts +53 -0
  52. package/dist/Graph/mergeEdge.mjs +63 -0
  53. package/dist/Graph/mergeNode.d.mts +51 -0
  54. package/dist/Graph/mergeNode.mjs +60 -0
  55. package/dist/Graph/removeEdge.d.mts +50 -0
  56. package/dist/Graph/removeEdge.mjs +71 -0
  57. package/dist/Graph/removeNode.d.mts +47 -0
  58. package/dist/Graph/removeNode.mjs +71 -0
  59. package/dist/Graph/setEdge.d.mts +53 -0
  60. package/dist/Graph/setEdge.mjs +78 -0
  61. package/dist/Graph/setNode.d.mts +44 -0
  62. package/dist/Graph/setNode.mjs +50 -0
  63. package/dist/Graph/toJS.d.mts +60 -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,65 @@
1
+ import { batch } from "./batch.mjs";
2
+ import { create } from "./create.mjs";
3
+ import { findEdge } from "./findEdge.mjs";
4
+ import { findEdges } from "./findEdges.mjs";
5
+ import { getNode } from "./getNode.mjs";
6
+ import { findNeighbor } from "./findNeighbor.mjs";
7
+ import { findNeighbors } from "./findNeighbors.mjs";
8
+ import { findNode } from "./findNode.mjs";
9
+ import { findNodes } from "./findNodes.mjs";
10
+ import { forEachEdge } from "./forEachEdge.mjs";
11
+ import { forEachNeighbor } from "./forEachNeighbor.mjs";
12
+ import { forEachNode } from "./forEachNode.mjs";
13
+ import { hasNode } from "./hasNode.mjs";
14
+ import { setEdge } from "./setEdge.mjs";
15
+ import { setNode } from "./setNode.mjs";
16
+ import { fromJS } from "./fromJS.mjs";
17
+ import { getEdge } from "./getEdge.mjs";
18
+ import { getEdges } from "./getEdges.mjs";
19
+ import { getNeighbor } from "./getNeighbor.mjs";
20
+ import { getNeighbors } from "./getNeighbors.mjs";
21
+ import { getNodes } from "./getNodes.mjs";
22
+ import { hasEdge } from "./hasEdge.mjs";
23
+ import { mapEdge } from "./mapEdge.mjs";
24
+ import { removeNode } from "./removeNode.mjs";
25
+ import { mapNode } from "./mapNode.mjs";
26
+ import { mergeEdge } from "./mergeEdge.mjs";
27
+ import { mergeNode } from "./mergeNode.mjs";
28
+ import { removeEdge } from "./removeEdge.mjs";
29
+ import { toJS } from "./toJS.mjs";
30
+
31
+ //#region src/Graph/index.js
32
+ const Graph = {
33
+ batch,
34
+ create,
35
+ findEdge,
36
+ findEdges,
37
+ findNeighbor,
38
+ findNeighbors,
39
+ findNode,
40
+ findNodes,
41
+ forEachEdge,
42
+ forEachNeighbor,
43
+ forEachNode,
44
+ fromJS,
45
+ getEdge,
46
+ getEdges,
47
+ getNeighbor,
48
+ getNeighbors,
49
+ getNode,
50
+ getNodes,
51
+ hasEdge,
52
+ hasNode,
53
+ mapEdge,
54
+ mapNode,
55
+ mergeEdge,
56
+ mergeNode,
57
+ removeEdge,
58
+ removeNode,
59
+ setEdge,
60
+ setNode,
61
+ toJS
62
+ };
63
+
64
+ //#endregion
65
+ export { Graph };
@@ -0,0 +1,51 @@
1
+ //#region src/Graph/internals/core.ts
2
+ function setInGraph(graph, path, value) {
3
+ return setInMap(graph.get("clones"), graph, path, value);
4
+ }
5
+ function unsetInGraph(graph, path) {
6
+ return unsetInMap(graph.get("clones"), graph, path);
7
+ }
8
+ const emptyMap = /* @__PURE__ */ new Map();
9
+ function setInMap(clones, map, path, value, offset = 0) {
10
+ if (path.length === 0) return map;
11
+ const key = path[offset];
12
+ if (offset === path.length - 1) return set(map, key, value, clones);
13
+ return set(map, key, setInMap(clones, map.get(key) ?? createMap(clones), path, value, offset + 1), clones);
14
+ }
15
+ function unsetInMap(clones, map, path, offset = 0) {
16
+ if (path.length === 0) return emptyMap;
17
+ const key = path[offset];
18
+ const isLast = offset === path.length - 1;
19
+ if (!map.has(key)) return map;
20
+ if (isLast) return unset(map, key, clones);
21
+ const child = unsetInMap(clones, map.get(key), path, offset + 1);
22
+ if (child.size === 0) return unset(map, key, clones);
23
+ return set(map, key, child, clones);
24
+ }
25
+ function createMap(clones) {
26
+ const map = /* @__PURE__ */ new Map();
27
+ clones?.add(map);
28
+ return map;
29
+ }
30
+ function set(map, key, value, clones) {
31
+ if (map.get(key) === value) return map;
32
+ const clone = cloneMap(map, clones);
33
+ clone.set(key, value);
34
+ return clone;
35
+ }
36
+ function unset(map, key, clones) {
37
+ if (map.size === 1) return emptyMap;
38
+ const clone = cloneMap(map, clones);
39
+ clone.delete(key);
40
+ return clone;
41
+ }
42
+ function cloneMap(target, clones) {
43
+ if (!clones) return new Map(target);
44
+ if (clones.has(target)) return target;
45
+ const clone = new Map(target);
46
+ clones.add(clone);
47
+ return clone;
48
+ }
49
+
50
+ //#endregion
51
+ export { setInGraph, unsetInGraph };
@@ -0,0 +1,7 @@
1
+ //#region src/Graph/internals/parseNodeIdentifier.ts
2
+ function parseNodeIdentifier(identifier) {
3
+ return Array.isArray(identifier) ? identifier : [identifier.type, identifier.id];
4
+ }
5
+
6
+ //#endregion
7
+ export { parseNodeIdentifier };
@@ -0,0 +1,16 @@
1
+ import { Edge, Node, NodeId, NodeOfType, NodeType } from "../types.mjs";
2
+
3
+ //#region src/Graph/internals/types.d.ts
4
+ type GetAllTargets<E> = E extends Record<string, infer V> ? V extends Record<string, any> ? keyof V : never : never;
5
+ type GetReverseMappings<E, Target> = { [K in keyof E as Target extends keyof E[K] ? K : never]: E[K][Target & keyof E[K]] };
6
+ type Bimap<E> = { [K in keyof E | GetAllTargets<E>]: (K extends keyof E ? E[K] : {}) & GetReverseMappings<E, K> };
7
+ type SourceTypesMap = ReadonlyMap<any, SourceIdsMap>;
8
+ type SourceIdsMap = ReadonlyMap<NodeId, TargetTypesMap>;
9
+ type TargetTypesMap = ReadonlyMap<any, TargetIdsMap>;
10
+ type TargetIdsMap = ReadonlyMap<NodeId, Edge>;
11
+ type NodeIdsMap<T extends Node, U extends NodeType<T> = NodeType<T>> = ReadonlyMap<NodeId, NodeOfType<T, U>>;
12
+ interface NodeTypesMap<T extends Node> extends ReadonlyMap<NodeType<T>, NodeIdsMap<T, NodeType<T>>> {
13
+ get: <V$1 extends NodeType<T>>(type: V$1) => NodeIdsMap<T, V$1> | undefined;
14
+ }
15
+ //#endregion
16
+ export { Bimap, NodeTypesMap, SourceTypesMap };
@@ -0,0 +1,53 @@
1
+ import { Bimap } from "./internals/types.mjs";
2
+ import { Edges, Graph, Node, NodeIdentifier, NodeType } from "./types.mjs";
3
+
4
+ //#region src/Graph/mapEdge.d.ts
5
+
6
+ /**
7
+ * # mapEdge
8
+ *
9
+ * ```ts
10
+ * function Graph.mapEdge(
11
+ * graph: Graph,
12
+ * source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
13
+ * target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
14
+ * update: (edge: EdgeData) => EdgeData,
15
+ * ): Graph
16
+ * ```
17
+ *
18
+ * Updates an edge by applying a transformation function. Returns a new graph instance with the updated edge.
19
+ *
20
+ * ## Example
21
+ *
22
+ * ```ts
23
+ * import { Graph } from "@monstermann/graph";
24
+ *
25
+ * type Nodes =
26
+ * | { type: "Task"; id: string }
27
+ * | { type: "Section"; id: string }
28
+ * | { type: "Project"; id: string };
29
+ *
30
+ * type Edges = {
31
+ * Project: { Task: { priority: number; assignedAt: Date } };
32
+ * Section: { Task: void };
33
+ * };
34
+ *
35
+ * const graph = Graph.create<Nodes, Edges>();
36
+ * let g = Graph.setNode(graph, { type: "Project", id: "1" });
37
+ * g = Graph.setNode(g, { type: "Task", id: "1" });
38
+ * g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
39
+ * priority: 1,
40
+ * assignedAt: new Date(),
41
+ * });
42
+ *
43
+ * // Update edge data
44
+ * g = Graph.mapEdge(g, ["Project", "1"], ["Task", "1"], (edge) => ({
45
+ * ...edge,
46
+ * priority: 2,
47
+ * }));
48
+ * ```
49
+ *
50
+ */
51
+ declare function mapEdge<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>, update: (edge: NoInfer<Bimap<E>[N1][N2]>) => NoInfer<Bimap<E>[N1][N2]>): Graph<N, E>;
52
+ //#endregion
53
+ export { mapEdge };
@@ -0,0 +1,60 @@
1
+ import { setEdge } from "./setEdge.mjs";
2
+ import { getEdge } from "./getEdge.mjs";
3
+ import { hasEdge } from "./hasEdge.mjs";
4
+
5
+ //#region src/Graph/mapEdge.ts
6
+ /**
7
+ * # mapEdge
8
+ *
9
+ * ```ts
10
+ * function Graph.mapEdge(
11
+ * graph: Graph,
12
+ * source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
13
+ * target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
14
+ * update: (edge: EdgeData) => EdgeData,
15
+ * ): Graph
16
+ * ```
17
+ *
18
+ * Updates an edge by applying a transformation function. Returns a new graph instance with the updated edge.
19
+ *
20
+ * ## Example
21
+ *
22
+ * ```ts
23
+ * import { Graph } from "@monstermann/graph";
24
+ *
25
+ * type Nodes =
26
+ * | { type: "Task"; id: string }
27
+ * | { type: "Section"; id: string }
28
+ * | { type: "Project"; id: string };
29
+ *
30
+ * type Edges = {
31
+ * Project: { Task: { priority: number; assignedAt: Date } };
32
+ * Section: { Task: void };
33
+ * };
34
+ *
35
+ * const graph = Graph.create<Nodes, Edges>();
36
+ * let g = Graph.setNode(graph, { type: "Project", id: "1" });
37
+ * g = Graph.setNode(g, { type: "Task", id: "1" });
38
+ * g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
39
+ * priority: 1,
40
+ * assignedAt: new Date(),
41
+ * });
42
+ *
43
+ * // Update edge data
44
+ * g = Graph.mapEdge(g, ["Project", "1"], ["Task", "1"], (edge) => ({
45
+ * ...edge,
46
+ * priority: 2,
47
+ * }));
48
+ * ```
49
+ *
50
+ */
51
+ function mapEdge(graph, source, target, update) {
52
+ if (!hasEdge(graph, source, target)) return graph;
53
+ const before = getEdge(graph, source, target);
54
+ const after = update(before);
55
+ if (before === after) return graph;
56
+ return setEdge(graph, source, target, after);
57
+ }
58
+
59
+ //#endregion
60
+ export { mapEdge };
@@ -0,0 +1,66 @@
1
+ import { Edges, Graph, Node, NodeIdentifier, NodeOfType, NodeType } from "./types.mjs";
2
+
3
+ //#region src/Graph/mapNode.d.ts
4
+
5
+ /**
6
+ * # mapNode
7
+ *
8
+ * ```ts
9
+ * function Graph.mapNode(
10
+ * graph: Graph,
11
+ * node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
12
+ * update: (node: Node) => Node,
13
+ * ): Graph
14
+ * ```
15
+ *
16
+ * Updates a node by applying a transformation function. If the node's type or id changes, all edges are preserved. Returns a new graph instance with the updated node.
17
+ *
18
+ * ## Example
19
+ *
20
+ * ```ts
21
+ * import { Graph } from "@monstermann/graph";
22
+ *
23
+ * type Nodes =
24
+ * | { type: "Task"; id: string; title: string; completed: boolean }
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, {
35
+ * type: "Task",
36
+ * id: "1",
37
+ * title: "My Task",
38
+ * completed: false,
39
+ * });
40
+ *
41
+ * // Update a property
42
+ * g = Graph.mapNode(g, ["Task", "1"], (task) => ({
43
+ * ...task,
44
+ * completed: true,
45
+ * }));
46
+ *
47
+ * // Change id (edges are preserved)
48
+ * let g2 = Graph.setNode(graph, {
49
+ * type: "Task",
50
+ * id: "1",
51
+ * title: "Task",
52
+ * completed: false,
53
+ * });
54
+ * g2 = Graph.setNode(g2, { type: "Project", id: "1" });
55
+ * g2 = Graph.setEdge(g2, ["Project", "1"], ["Task", "1"]);
56
+ * g2 = Graph.mapNode(g2, ["Task", "1"], (task) => ({
57
+ * ...task,
58
+ * id: "2",
59
+ * }));
60
+ * // Edge now connects ["Project", "1"] -> ["Task", "2"]
61
+ * ```
62
+ *
63
+ */
64
+ declare function mapNode<N extends Node, E extends Edges<N>, U extends NodeType<N>>(graph: Graph<N, E>, node: NodeIdentifier<N, U>, update: (node: NoInfer<NodeOfType<N, U>>) => NoInfer<NodeOfType<N, U>>): Graph<N, E>;
65
+ //#endregion
66
+ export { mapNode };
@@ -0,0 +1,83 @@
1
+ import { batch } from "./batch.mjs";
2
+ import { getNode } from "./getNode.mjs";
3
+ import { setEdge } from "./setEdge.mjs";
4
+ import { setNode } from "./setNode.mjs";
5
+ import { removeNode } from "./removeNode.mjs";
6
+
7
+ //#region src/Graph/mapNode.ts
8
+ /**
9
+ * # mapNode
10
+ *
11
+ * ```ts
12
+ * function Graph.mapNode(
13
+ * graph: Graph,
14
+ * node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
15
+ * update: (node: Node) => Node,
16
+ * ): Graph
17
+ * ```
18
+ *
19
+ * Updates a node by applying a transformation function. If the node's type or id changes, all edges are preserved. Returns a new graph instance with the updated node.
20
+ *
21
+ * ## Example
22
+ *
23
+ * ```ts
24
+ * import { Graph } from "@monstermann/graph";
25
+ *
26
+ * type Nodes =
27
+ * | { type: "Task"; id: string; title: string; completed: boolean }
28
+ * | { type: "Section"; id: string }
29
+ * | { type: "Project"; id: string };
30
+ *
31
+ * type Edges = {
32
+ * Project: { Task: void };
33
+ * Section: { Task: void };
34
+ * };
35
+ *
36
+ * const graph = Graph.create<Nodes, Edges>();
37
+ * let g = Graph.setNode(graph, {
38
+ * type: "Task",
39
+ * id: "1",
40
+ * title: "My Task",
41
+ * completed: false,
42
+ * });
43
+ *
44
+ * // Update a property
45
+ * g = Graph.mapNode(g, ["Task", "1"], (task) => ({
46
+ * ...task,
47
+ * completed: true,
48
+ * }));
49
+ *
50
+ * // Change id (edges are preserved)
51
+ * let g2 = Graph.setNode(graph, {
52
+ * type: "Task",
53
+ * id: "1",
54
+ * title: "Task",
55
+ * completed: false,
56
+ * });
57
+ * g2 = Graph.setNode(g2, { type: "Project", id: "1" });
58
+ * g2 = Graph.setEdge(g2, ["Project", "1"], ["Task", "1"]);
59
+ * g2 = Graph.mapNode(g2, ["Task", "1"], (task) => ({
60
+ * ...task,
61
+ * id: "2",
62
+ * }));
63
+ * // Edge now connects ["Project", "1"] -> ["Task", "2"]
64
+ * ```
65
+ *
66
+ */
67
+ function mapNode(graph, node, update) {
68
+ const prev = getNode(graph, node);
69
+ if (!prev) return graph;
70
+ const next = update(prev);
71
+ if (prev === next) return graph;
72
+ if (prev.id === next.id && prev.type === next.type) return setNode(graph, next);
73
+ return batch(graph, (graph$1) => {
74
+ graph$1 = setNode(graph$1, next);
75
+ const edges = graph$1.get("edges");
76
+ for (const [targetType, targetIds] of edges?.get(prev.type)?.get(prev.id) ?? []) for (const [targetId, targetData] of targetIds) graph$1 = setEdge(graph$1, [next.type, next.id], [targetType, targetId], targetData);
77
+ graph$1 = removeNode(graph$1, prev);
78
+ return graph$1;
79
+ });
80
+ }
81
+
82
+ //#endregion
83
+ export { mapNode };
@@ -0,0 +1,53 @@
1
+ import { Bimap } from "./internals/types.mjs";
2
+ import { Edges, Graph, Node, NodeIdentifier, NodeType } from "./types.mjs";
3
+
4
+ //#region src/Graph/mergeEdge.d.ts
5
+
6
+ /**
7
+ * # mergeEdge
8
+ *
9
+ * ```ts
10
+ * function Graph.mergeEdge(
11
+ * graph: Graph,
12
+ * source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
13
+ * target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
14
+ * update: Partial<EdgeData>,
15
+ * ): Graph
16
+ * ```
17
+ *
18
+ * Partially updates an edge by merging the provided properties. Returns a new graph instance with the updated edge.
19
+ *
20
+ * ## Example
21
+ *
22
+ * ```ts
23
+ * import { Graph } from "@monstermann/graph";
24
+ *
25
+ * type Nodes =
26
+ * | { type: "Task"; id: string }
27
+ * | { type: "Section"; id: string }
28
+ * | { type: "Project"; id: string };
29
+ *
30
+ * type Edges = {
31
+ * Project: { Task: { priority: number; assignedAt: Date } };
32
+ * Section: { Task: void };
33
+ * };
34
+ *
35
+ * const graph = Graph.create<Nodes, Edges>();
36
+ * let g = Graph.setNode(graph, { type: "Project", id: "1" });
37
+ * g = Graph.setNode(g, { type: "Task", id: "1" });
38
+ * g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
39
+ * priority: 1,
40
+ * assignedAt: new Date(),
41
+ * });
42
+ *
43
+ * // Merge partial update
44
+ * g = Graph.mergeEdge(g, ["Project", "1"], ["Task", "1"], { priority: 2 });
45
+ *
46
+ * const edge = Graph.getEdge(g, ["Project", "1"], ["Task", "1"]);
47
+ * // edge: { priority: 2, assignedAt: <original date> }
48
+ * ```
49
+ *
50
+ */
51
+ declare function mergeEdge<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>, update: Partial<Bimap<E>[N1][N2]>): Graph<N, E>;
52
+ //#endregion
53
+ export { mergeEdge };
@@ -0,0 +1,63 @@
1
+ import { setEdge } from "./setEdge.mjs";
2
+ import { getEdge } from "./getEdge.mjs";
3
+ import { hasEdge } from "./hasEdge.mjs";
4
+
5
+ //#region src/Graph/mergeEdge.ts
6
+ /**
7
+ * # mergeEdge
8
+ *
9
+ * ```ts
10
+ * function Graph.mergeEdge(
11
+ * graph: Graph,
12
+ * source: [NodeType, NodeId] | { type: NodeType, id: NodeId },
13
+ * target: [NodeType, NodeId] | { type: NodeType, id: NodeId },
14
+ * update: Partial<EdgeData>,
15
+ * ): Graph
16
+ * ```
17
+ *
18
+ * Partially updates an edge by merging the provided properties. Returns a new graph instance with the updated edge.
19
+ *
20
+ * ## Example
21
+ *
22
+ * ```ts
23
+ * import { Graph } from "@monstermann/graph";
24
+ *
25
+ * type Nodes =
26
+ * | { type: "Task"; id: string }
27
+ * | { type: "Section"; id: string }
28
+ * | { type: "Project"; id: string };
29
+ *
30
+ * type Edges = {
31
+ * Project: { Task: { priority: number; assignedAt: Date } };
32
+ * Section: { Task: void };
33
+ * };
34
+ *
35
+ * const graph = Graph.create<Nodes, Edges>();
36
+ * let g = Graph.setNode(graph, { type: "Project", id: "1" });
37
+ * g = Graph.setNode(g, { type: "Task", id: "1" });
38
+ * g = Graph.setEdge(g, ["Project", "1"], ["Task", "1"], {
39
+ * priority: 1,
40
+ * assignedAt: new Date(),
41
+ * });
42
+ *
43
+ * // Merge partial update
44
+ * g = Graph.mergeEdge(g, ["Project", "1"], ["Task", "1"], { priority: 2 });
45
+ *
46
+ * const edge = Graph.getEdge(g, ["Project", "1"], ["Task", "1"]);
47
+ * // edge: { priority: 2, assignedAt: <original date> }
48
+ * ```
49
+ *
50
+ */
51
+ function mergeEdge(graph, source, target, update) {
52
+ if (!hasEdge(graph, source, target)) return graph;
53
+ const edge = getEdge(graph, source, target);
54
+ const keys = Object.keys(update);
55
+ if (keys.length === 0) return graph;
56
+ return keys.some((k) => update[k] !== edge[k]) ? setEdge(graph, source, target, {
57
+ ...edge,
58
+ ...update
59
+ }) : graph;
60
+ }
61
+
62
+ //#endregion
63
+ export { mergeEdge };
@@ -0,0 +1,51 @@
1
+ import { Edges, Graph, Node, NodeIdentifier, NodeOfType, NodeType } from "./types.mjs";
2
+
3
+ //#region src/Graph/mergeNode.d.ts
4
+
5
+ /**
6
+ * # mergeNode
7
+ *
8
+ * ```ts
9
+ * function Graph.mergeNode(
10
+ * graph: Graph,
11
+ * node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
12
+ * update: Partial<Node>,
13
+ * ): Graph
14
+ * ```
15
+ *
16
+ * Partially updates a node by merging the provided properties. Returns a new graph instance with the updated node.
17
+ *
18
+ * ## Example
19
+ *
20
+ * ```ts
21
+ * import { Graph } from "@monstermann/graph";
22
+ *
23
+ * type Nodes =
24
+ * | { type: "Task"; id: string; title: string; completed: boolean }
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, {
35
+ * type: "Task",
36
+ * id: "1",
37
+ * title: "My Task",
38
+ * completed: false,
39
+ * });
40
+ *
41
+ * // Merge partial update
42
+ * g = Graph.mergeNode(g, ["Task", "1"], { completed: true });
43
+ *
44
+ * const task = Graph.getNode(g, ["Task", "1"]);
45
+ * // task: { type: "Task", id: "1", title: "My Task", completed: true }
46
+ * ```
47
+ *
48
+ */
49
+ declare function mergeNode<N extends Node, E extends Edges<N>, U extends NodeType<N>>(graph: Graph<N, E>, node: NodeIdentifier<N, U>, update: Partial<NodeOfType<N, U>>): Graph<N, E>;
50
+ //#endregion
51
+ export { mergeNode };
@@ -0,0 +1,60 @@
1
+ import { mapNode } from "./mapNode.mjs";
2
+
3
+ //#region src/Graph/mergeNode.ts
4
+ /**
5
+ * # mergeNode
6
+ *
7
+ * ```ts
8
+ * function Graph.mergeNode(
9
+ * graph: Graph,
10
+ * node: [NodeType, NodeId] | { type: NodeType, id: NodeId },
11
+ * update: Partial<Node>,
12
+ * ): Graph
13
+ * ```
14
+ *
15
+ * Partially updates a node by merging the provided properties. Returns a new graph instance with the updated node.
16
+ *
17
+ * ## Example
18
+ *
19
+ * ```ts
20
+ * import { Graph } from "@monstermann/graph";
21
+ *
22
+ * type Nodes =
23
+ * | { type: "Task"; id: string; title: string; completed: boolean }
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, {
34
+ * type: "Task",
35
+ * id: "1",
36
+ * title: "My Task",
37
+ * completed: false,
38
+ * });
39
+ *
40
+ * // Merge partial update
41
+ * g = Graph.mergeNode(g, ["Task", "1"], { completed: true });
42
+ *
43
+ * const task = Graph.getNode(g, ["Task", "1"]);
44
+ * // task: { type: "Task", id: "1", title: "My Task", completed: true }
45
+ * ```
46
+ *
47
+ */
48
+ function mergeNode(graph, node, update) {
49
+ return mapNode(graph, node, (node$1) => {
50
+ const keys = Object.keys(update);
51
+ if (keys.length === 0) return node$1;
52
+ return keys.some((k) => update[k] !== node$1[k]) ? {
53
+ ...node$1,
54
+ ...update
55
+ } : node$1;
56
+ });
57
+ }
58
+
59
+ //#endregion
60
+ export { mergeNode };
@@ -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/removeEdge.d.ts
5
+
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
+ declare function removeEdge<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>): Graph<N, E>;
49
+ //#endregion
50
+ export { removeEdge };