@statelyai/graph 1.0.0 → 2.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 (77) hide show
  1. package/README.md +121 -44
  2. package/dist/{adjacency-list-VsUaH9SJ.mjs → adjacency-list-DQ32Mmhx.mjs} +3 -1
  3. package/dist/algorithms-D1cgly0g.d.mts +452 -0
  4. package/dist/algorithms-DBpH74hR.mjs +3309 -0
  5. package/dist/algorithms.d.mts +2 -2
  6. package/dist/algorithms.mjs +2 -2
  7. package/dist/config-Dt5u1gSf.mjs +793 -0
  8. package/dist/{converter-udLITX36.mjs → converter-DB6Rg6Vd.mjs} +2 -2
  9. package/dist/format-support.mjs +38 -11
  10. package/dist/formats/adjacency-list/index.d.mts +1 -1
  11. package/dist/formats/adjacency-list/index.mjs +1 -1
  12. package/dist/formats/converter/index.d.mts +1 -1
  13. package/dist/formats/converter/index.mjs +1 -1
  14. package/dist/formats/cytoscape/index.d.mts +4 -4
  15. package/dist/formats/cytoscape/index.mjs +10 -4
  16. package/dist/formats/d2/index.d.mts +1 -1
  17. package/dist/formats/d2/index.mjs +26 -12
  18. package/dist/formats/d3/index.d.mts +4 -4
  19. package/dist/formats/d3/index.mjs +10 -4
  20. package/dist/formats/dot/index.d.mts +1 -1
  21. package/dist/formats/dot/index.mjs +22 -6
  22. package/dist/formats/edge-list/index.d.mts +1 -1
  23. package/dist/formats/edge-list/index.mjs +1 -1
  24. package/dist/formats/elk/index.d.mts +1 -1
  25. package/dist/formats/elk/index.mjs +63 -24
  26. package/dist/formats/gexf/index.d.mts +1 -1
  27. package/dist/formats/gexf/index.mjs +43 -16
  28. package/dist/formats/gml/index.d.mts +4 -4
  29. package/dist/formats/gml/index.mjs +28 -15
  30. package/dist/formats/graphml/index.d.mts +1 -1
  31. package/dist/formats/graphml/index.mjs +96 -23
  32. package/dist/formats/jgf/index.d.mts +4 -4
  33. package/dist/formats/jgf/index.mjs +12 -5
  34. package/dist/formats/mermaid/index.d.mts +1 -1
  35. package/dist/formats/mermaid/index.mjs +49 -12
  36. package/dist/formats/tgf/index.d.mts +4 -4
  37. package/dist/formats/tgf/index.mjs +4 -4
  38. package/dist/formats/xyflow/index.d.mts +12 -6
  39. package/dist/formats/xyflow/index.mjs +42 -10
  40. package/dist/{index-D9Kj6Fe3.d.mts → index-BlbSWUvH.d.mts} +1 -1
  41. package/dist/{index-CHoriXZD.d.mts → index-CNvqxPLJ.d.mts} +157 -30
  42. package/dist/index.d.mts +6 -6
  43. package/dist/index.mjs +290 -307
  44. package/dist/layout/cytoscape.d.mts +66 -0
  45. package/dist/layout/cytoscape.mjs +114 -0
  46. package/dist/layout/d3-force.d.mts +52 -0
  47. package/dist/layout/d3-force.mjs +127 -0
  48. package/dist/layout/d3-hierarchy.d.mts +39 -0
  49. package/dist/layout/d3-hierarchy.mjs +135 -0
  50. package/dist/layout/dagre.d.mts +32 -0
  51. package/dist/layout/dagre.mjs +99 -0
  52. package/dist/layout/elk.d.mts +47 -0
  53. package/dist/layout/elk.mjs +73 -0
  54. package/dist/layout/forceatlas2.d.mts +48 -0
  55. package/dist/layout/forceatlas2.mjs +100 -0
  56. package/dist/layout/graphviz.d.mts +50 -0
  57. package/dist/layout/graphviz.mjs +179 -0
  58. package/dist/layout/index.d.mts +185 -0
  59. package/dist/layout/index.mjs +181 -0
  60. package/dist/layout/webcola.d.mts +40 -0
  61. package/dist/layout/webcola.mjs +104 -0
  62. package/dist/{queries-BlkA1HAN.d.mts → queries-B6quF529.d.mts} +43 -12
  63. package/dist/queries-BMM0XAv_.mjs +986 -0
  64. package/dist/queries.d.mts +1 -1
  65. package/dist/queries.mjs +1 -768
  66. package/dist/schemas.d.mts +19 -1
  67. package/dist/schemas.mjs +32 -84
  68. package/dist/{types-3-FS9NV2.d.mts → types-BAEQTwK_.d.mts} +99 -7
  69. package/dist/validate-BsfSOv0S.mjs +190 -0
  70. package/package.json +59 -7
  71. package/schemas/edge.schema.json +27 -0
  72. package/schemas/graph.schema.json +27 -0
  73. package/dist/algorithms-Ba7o7niK.mjs +0 -2394
  74. package/dist/algorithms-fTqmvhzP.d.mts +0 -178
  75. package/dist/indexing-DR8M1vBy.mjs +0 -137
  76. /package/dist/{edge-list-DP4otyPU.mjs → edge-list-CA9UTvn2.mjs} +0 -0
  77. /package/dist/{mode-D8OnHFBk.mjs → mode-gu_mhKKs.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -1,9 +1,98 @@
1
- import { o as invalidateIndex, t as getIndex } from "./indexing-DR8M1vBy.mjs";
2
- import { $ as createGraphPort, A as isAcyclic, B as getShortestPaths, C as getPreorder, D as getConnectedComponents, E as dfs, F as genSimplePaths, G as GraphInstance, H as getSimplePaths, I as getAStarPath, J as addNode, K as addEdge, L as getAllPairsShortestPaths, M as isTree, N as genCycles, O as getTopologicalSort, P as genShortestPaths, Q as createGraphNode, R as getCycles, S as getPostorders, T as bfs, U as getStronglyConnectedComponents, V as getSimplePath, W as joinPaths, X as createGraphEdge, Y as createGraph, Z as createGraphFromTransition, _ as getPageRank, a as genGirvanNewmanCommunities, at as getNode, b as genPreorders, c as getLabelPropagationCommunities, ct as updateEdge, d as getClosenessCentrality, et as createVisualGraph, f as getDegreeCentrality, g as getOutDegreeCentrality, h as getInDegreeCentrality, i as getBridges, it as getEdge, j as isConnected, k as hasPath, l as getModularity, lt as updateEntities, m as getHITS, n as getArticulationPoints, nt as deleteEntities, o as getGirvanNewmanCommunities, ot as hasEdge, p as getEigenvectorCentrality, q as addEntities, r as getBiconnectedComponents, rt as deleteNode, s as getGreedyModularityCommunities, st as hasNode, t as isIsomorphic, tt as deleteEdge, u as getBetweennessCentrality, ut as updateNode, v as getMinimumSpanningTree, w as getPreorders, x as getPostorder, y as genPostorders, z as getShortestPath } from "./algorithms-Ba7o7niK.mjs";
3
- import { n as isEdgeDirected, t as getEdgeMode } from "./mode-D8OnHFBk.mjs";
4
- import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgesBetween, getEdgesByPort, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPort, getPorts, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
5
- import { n as createFormatConverter } from "./converter-udLITX36.mjs";
1
+ import { C as getSinks, D as isLeaf, E as isCompound, N as invalidateIndex, S as getSiblings, T as getSuccessors, _ as getPorts, a as getDescendants, b as getRelativeDistanceMap, c as getEdgesOf, d as getLCA, f as getNeighbors, g as getPort, h as getParent, i as getDepth, l as getInDegree, m as getOutEdges, n as getChildren, o as getEdgesBetween, p as getOutDegree, r as getDegree, s as getEdgesByPort, t as getAncestors, u as getInEdges, v as getPredecessors, w as getSources, x as getRoots, y as getRelativeDistance } from "./queries-BMM0XAv_.mjs";
2
+ import { S as updateNode, _ as getNode, a as addEntities, b as updateEdge, c as createGraphEdge, d as createGraphPort, f as createVisualGraph, g as getEdge, h as deleteNode, i as addEdge, l as createGraphFromTransition, m as deleteEntities, n as toNodeConfig, o as addNode, p as deleteEdge, r as GraphInstance, s as createGraph, t as toEdgeConfig, u as createGraphNode, v as hasEdge, x as updateEntities, y as hasNode } from "./config-Dt5u1gSf.mjs";
3
+ import { n as isEdgeDirected, t as getEdgeMode } from "./mode-gu_mhKKs.mjs";
4
+ import { t as getGraphIssues } from "./validate-BsfSOv0S.mjs";
5
+ import { $ as getAStarPath, A as genPreorders, B as getTopologicalSort, C as getHITS, D as getPageRank, E as getOutDegreeCentrality, F as bfs, G as flatten, H as isAcyclic, I as dfs, J as getSubgraph, K as getFlattenedGraph, L as genBFS, M as getPostorders, N as getPreorder, O as getMinimumSpanningTree, P as getPreorders, Q as genSimplePaths, R as genDFS, S as getEigenvectorCentrality, T as getKatzCentrality, U as isConnected, V as hasPath, W as isTree, X as genCycles, Y as reverseGraph, Z as genShortestPaths, _ as getCoreNumbers, a as getLouvainCommunities, at as getSimplePath, b as getClosenessCentrality, c as getBiconnectedComponents, ct as joinPaths, d as getGirvanNewmanCommunities, et as getAllPairsShortestPaths, f as getGreedyModularityCommunities, g as isBipartite, h as getMaximumBipartiteMatching, i as getMinCut, it as getShortestPaths, j as getPostorder, k as genPostorders, l as getBridges, lt as mulberry32$1, m as getModularity, n as getDominatorTree, nt as getJoinedPath, o as isIsomorphic, ot as getSimplePaths, p as getLabelPropagationCommunities, q as getReversedGraph, r as getMaxFlow, rt as getShortestPath, s as getArticulationPoints, st as getStronglyConnectedComponents, t as getTransitiveReduction, tt as getCycles, u as genGirvanNewmanCommunities, v as getKCore, w as getInDegreeCentrality, x as getDegreeCentrality, y as getBetweennessCentrality, z as getConnectedComponents } from "./algorithms-DBpH74hR.mjs";
6
+ import { n as createFormatConverter } from "./converter-DB6Rg6Vd.mjs";
6
7
 
8
+ //#region src/generators.ts
9
+ function assertNonNegativeInteger(caller, name, value) {
10
+ if (!Number.isInteger(value) || value < 0) throw new Error(`${caller}: ${name} ${value} is invalid — pass a non-negative integer`);
11
+ }
12
+ /**
13
+ * Create the complete graph K_n: every pair of distinct nodes connected by
14
+ * one undirected edge. Nodes are `n0..n{n-1}` (`options.idPrefix` overrides
15
+ * the `n` prefix); edges are `e0..`.
16
+ */
17
+ function createCompleteGraph(n, options) {
18
+ assertNonNegativeInteger("createCompleteGraph", "node count", n);
19
+ const prefix = options?.idPrefix ?? "n";
20
+ const nodes = [];
21
+ for (let i = 0; i < n; i++) nodes.push({ id: `${prefix}${i}` });
22
+ const edges = [];
23
+ let edgeId = 0;
24
+ for (let i = 0; i < n; i++) for (let j = i + 1; j < n; j++) edges.push({
25
+ id: `e${edgeId++}`,
26
+ sourceId: `${prefix}${i}`,
27
+ targetId: `${prefix}${j}`
28
+ });
29
+ return createGraph({
30
+ mode: "undirected",
31
+ nodes,
32
+ edges
33
+ });
34
+ }
35
+ /**
36
+ * Create a `rows × cols` grid graph: node `(r, c)` is connected to its right
37
+ * and down neighbors by undirected edges. Nodes are `n{r}_{c}`
38
+ * (`options.idPrefix` overrides the `n` prefix); edges are `e0..`.
39
+ */
40
+ function createGridGraph(rows, cols, options) {
41
+ assertNonNegativeInteger("createGridGraph", "row count", rows);
42
+ assertNonNegativeInteger("createGridGraph", "column count", cols);
43
+ const prefix = options?.idPrefix ?? "n";
44
+ const nodeId = (r, c) => `${prefix}${r}_${c}`;
45
+ const nodes = [];
46
+ const edges = [];
47
+ let edgeId = 0;
48
+ for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
49
+ nodes.push({ id: nodeId(r, c) });
50
+ if (c + 1 < cols) edges.push({
51
+ id: `e${edgeId++}`,
52
+ sourceId: nodeId(r, c),
53
+ targetId: nodeId(r, c + 1)
54
+ });
55
+ if (r + 1 < rows) edges.push({
56
+ id: `e${edgeId++}`,
57
+ sourceId: nodeId(r, c),
58
+ targetId: nodeId(r + 1, c)
59
+ });
60
+ }
61
+ return createGraph({
62
+ mode: "undirected",
63
+ nodes,
64
+ edges
65
+ });
66
+ }
67
+ /**
68
+ * Create an Erdős–Rényi G(n, p) random graph: each of the n·(n-1)/2 node
69
+ * pairs gets an undirected edge with probability `probability`. With
70
+ * `options.seed` the result is deterministic per seed (mulberry32);
71
+ * otherwise `Math.random` is used. Nodes are `n0..n{n-1}`
72
+ * (`options.idPrefix` overrides the `n` prefix); edges are `e0..`.
73
+ */
74
+ function createRandomGraph(n, probability, options) {
75
+ assertNonNegativeInteger("createRandomGraph", "node count", n);
76
+ if (!(probability >= 0 && probability <= 1)) throw new Error(`createRandomGraph: probability ${probability} is invalid — pass a number between 0 and 1`);
77
+ const prefix = options?.idPrefix ?? "n";
78
+ const rng = options?.seed !== void 0 ? mulberry32$1(options.seed) : Math.random;
79
+ const nodes = [];
80
+ for (let i = 0; i < n; i++) nodes.push({ id: `${prefix}${i}` });
81
+ const edges = [];
82
+ let edgeId = 0;
83
+ for (let i = 0; i < n; i++) for (let j = i + 1; j < n; j++) if (rng() < probability) edges.push({
84
+ id: `e${edgeId++}`,
85
+ sourceId: `${prefix}${i}`,
86
+ targetId: `${prefix}${j}`
87
+ });
88
+ return createGraph({
89
+ mode: "undirected",
90
+ nodes,
91
+ edges
92
+ });
93
+ }
94
+
95
+ //#endregion
7
96
  //#region src/equivalence.ts
8
97
  /** Shallow-compare two values, returning true if they differ. */
9
98
  function differs$1(a, b) {
@@ -27,6 +116,8 @@ const LAYOUT_KEYS = {
27
116
  "y",
28
117
  "width",
29
118
  "height",
119
+ "points",
120
+ "routing",
30
121
  "style",
31
122
  "color"
32
123
  ]
@@ -52,7 +143,7 @@ const LAYOUT_KEY_SET = {
52
143
  * ```
53
144
  */
54
145
  function areEntitiesEqual(a, b, keys) {
55
- const compareKeys = keys && keys.length > 0 ? keys : Object.keys(a);
146
+ const compareKeys = keys && keys.length > 0 ? keys : [...new Set([...Object.keys(a), ...Object.keys(b)])];
56
147
  for (const key of compareKeys) if (differs$1(a[key], b[key])) return false;
57
148
  return true;
58
149
  }
@@ -87,47 +178,16 @@ function isLayoutEqual(a, b) {
87
178
  */
88
179
  function isNonLayoutEqual(a, b) {
89
180
  const skip = LAYOUT_KEY_SET[a.type];
90
- const keys = Object.keys(a);
91
- for (let i = 0; i < keys.length; i++) {
92
- if (skip.has(keys[i])) continue;
93
- if (differs$1(a[keys[i]], b[keys[i]])) return false;
181
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
182
+ for (const key of keys) {
183
+ if (skip.has(key)) continue;
184
+ if (differs$1(a[key], b[key])) return false;
94
185
  }
95
186
  return true;
96
187
  }
97
188
 
98
189
  //#endregion
99
190
  //#region src/diff.ts
100
- function nodeToConfig$1(node) {
101
- const config = { id: node.id };
102
- if (node.parentId) config.parentId = node.parentId;
103
- if (node.initialNodeId) config.initialNodeId = node.initialNodeId;
104
- if (node.label !== "") config.label = node.label;
105
- if (node.data !== void 0) config.data = node.data;
106
- if (node.x !== void 0) config.x = node.x;
107
- if (node.y !== void 0) config.y = node.y;
108
- if (node.width !== void 0) config.width = node.width;
109
- if (node.height !== void 0) config.height = node.height;
110
- if (node.shape !== void 0) config.shape = node.shape;
111
- if (node.color !== void 0) config.color = node.color;
112
- if (node.style !== void 0) config.style = node.style;
113
- return config;
114
- }
115
- function edgeToConfig$1(edge) {
116
- const config = {
117
- id: edge.id,
118
- sourceId: edge.sourceId,
119
- targetId: edge.targetId
120
- };
121
- if (edge.label !== "") config.label = edge.label;
122
- if (edge.data !== void 0) config.data = edge.data;
123
- if (edge.x !== void 0) config.x = edge.x;
124
- if (edge.y !== void 0) config.y = edge.y;
125
- if (edge.width !== void 0) config.width = edge.width;
126
- if (edge.height !== void 0) config.height = edge.height;
127
- if (edge.color !== void 0) config.color = edge.color;
128
- if (edge.style !== void 0) config.style = edge.style;
129
- return config;
130
- }
131
191
  /** Shallow-compare two values, returning true if they differ. */
132
192
  function differs(a, b) {
133
193
  if (a === b) return false;
@@ -140,6 +200,7 @@ const NODE_COMPARE_KEYS = [
140
200
  "initialNodeId",
141
201
  "label",
142
202
  "data",
203
+ "ports",
143
204
  "x",
144
205
  "y",
145
206
  "width",
@@ -153,6 +214,12 @@ const EDGE_COMPARE_KEYS = [
153
214
  "targetId",
154
215
  "label",
155
216
  "data",
217
+ "weight",
218
+ "mode",
219
+ "sourcePort",
220
+ "targetPort",
221
+ "points",
222
+ "routing",
156
223
  "x",
157
224
  "y",
158
225
  "width",
@@ -194,13 +261,17 @@ function getDiff(a, b) {
194
261
  };
195
262
  for (const [id, nodeB] of bNodeMap) {
196
263
  const nodeA = aNodeMap.get(id);
197
- if (!nodeA) diff.nodes.added.push(nodeToConfig$1(nodeB));
264
+ if (!nodeA) diff.nodes.added.push(toNodeConfig(nodeB));
198
265
  else {
199
266
  const oldPartial = {};
200
267
  const newPartial = {};
201
- for (const key of NODE_COMPARE_KEYS) if (differs(nodeA[key], nodeB[key])) {
202
- oldPartial[key] = nodeA[key];
203
- newPartial[key] = nodeB[key];
268
+ for (const key of NODE_COMPARE_KEYS) {
269
+ const oldValue = nodeA[key] ?? null;
270
+ const newValue = nodeB[key] ?? null;
271
+ if (differs(oldValue, newValue)) {
272
+ oldPartial[key] = oldValue;
273
+ newPartial[key] = newValue;
274
+ }
204
275
  }
205
276
  if (Object.keys(oldPartial).length > 0) diff.nodes.updated.push({
206
277
  id,
@@ -209,16 +280,20 @@ function getDiff(a, b) {
209
280
  });
210
281
  }
211
282
  }
212
- for (const [id, nodeA] of aNodeMap) if (!bNodeMap.has(id)) diff.nodes.removed.push(nodeToConfig$1(nodeA));
283
+ for (const [id, nodeA] of aNodeMap) if (!bNodeMap.has(id)) diff.nodes.removed.push(toNodeConfig(nodeA));
213
284
  for (const [id, edgeB] of bEdgeMap) {
214
285
  const edgeA = aEdgeMap.get(id);
215
- if (!edgeA) diff.edges.added.push(edgeToConfig$1(edgeB));
286
+ if (!edgeA) diff.edges.added.push(toEdgeConfig(edgeB));
216
287
  else {
217
288
  const oldPartial = {};
218
289
  const newPartial = {};
219
- for (const key of EDGE_COMPARE_KEYS) if (differs(edgeA[key], edgeB[key])) {
220
- oldPartial[key] = edgeA[key];
221
- newPartial[key] = edgeB[key];
290
+ for (const key of EDGE_COMPARE_KEYS) {
291
+ const oldValue = edgeA[key] ?? null;
292
+ const newValue = edgeB[key] ?? null;
293
+ if (differs(oldValue, newValue)) {
294
+ oldPartial[key] = oldValue;
295
+ newPartial[key] = newValue;
296
+ }
222
297
  }
223
298
  if (Object.keys(oldPartial).length > 0) diff.edges.updated.push({
224
299
  id,
@@ -227,7 +302,7 @@ function getDiff(a, b) {
227
302
  });
228
303
  }
229
304
  }
230
- for (const [id, edgeA] of aEdgeMap) if (!bEdgeMap.has(id)) diff.edges.removed.push(edgeToConfig$1(edgeA));
305
+ for (const [id, edgeA] of aEdgeMap) if (!bEdgeMap.has(id)) diff.edges.removed.push(toEdgeConfig(edgeA));
231
306
  return diff;
232
307
  }
233
308
  /**
@@ -250,42 +325,49 @@ function isEmptyDiff(diff) {
250
325
  *
251
326
  * @example
252
327
  * ```ts
253
- * import { createGraph, getDiff, invertDiff } from '@statelyai/graph';
328
+ * import { createGraph, getDiff, getInvertedDiff } from '@statelyai/graph';
254
329
  *
255
330
  * const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
256
331
  * const b = createGraph({ nodes: [{ id: 'n2' }], edges: [] });
257
332
  *
258
333
  * const diff = getDiff(a, b);
259
- * const inv = invertDiff(diff);
334
+ * const inv = getInvertedDiff(diff);
260
335
  * // inv.nodes.added contains n1 (was removed)
261
336
  * // inv.nodes.removed contains n2 (was added)
262
337
  * ```
263
338
  */
264
- function invertDiff(diff) {
339
+ function getInvertedDiff(diff) {
265
340
  return {
266
341
  nodes: {
267
- added: diff.nodes.removed,
268
- removed: diff.nodes.added,
342
+ added: diff.nodes.removed.map((c) => structuredClone(c)),
343
+ removed: diff.nodes.added.map((c) => structuredClone(c)),
269
344
  updated: diff.nodes.updated.map((c) => ({
270
345
  id: c.id,
271
- old: c.new,
272
- new: c.old
346
+ old: structuredClone(c.new),
347
+ new: structuredClone(c.old)
273
348
  }))
274
349
  },
275
350
  edges: {
276
- added: diff.edges.removed,
277
- removed: diff.edges.added,
351
+ added: diff.edges.removed.map((c) => structuredClone(c)),
352
+ removed: diff.edges.added.map((c) => structuredClone(c)),
278
353
  updated: diff.edges.updated.map((c) => ({
279
354
  id: c.id,
280
- old: c.new,
281
- new: c.old
355
+ old: structuredClone(c.new),
356
+ new: structuredClone(c.old)
282
357
  }))
283
358
  }
284
359
  };
285
360
  }
286
361
  /**
362
+ * @deprecated Use {@link getInvertedDiff}.
363
+ */
364
+ function invertDiff(diff) {
365
+ return getInvertedDiff(diff);
366
+ }
367
+ /**
287
368
  * Compute an ordered patch list from graph `a` to graph `b`.
288
- * Order: delete edges delete nodes → add nodes → add edges → update nodes update edges.
369
+ * Order (see {@link toPatches}): add nodes → update edges → delete edges
370
+ * delete nodes → add edges → update nodes.
289
371
  *
290
372
  * @example
291
373
  * ```ts
@@ -307,17 +389,17 @@ function getPatches(a, b) {
307
389
  *
308
390
  * @example
309
391
  * ```ts
310
- * import { createGraph, getPatches, applyPatches } from '@statelyai/graph';
392
+ * import { createGraph, getPatches, updateGraphWithPatches } from '@statelyai/graph';
311
393
  *
312
394
  * const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
313
395
  * const b = createGraph({ nodes: [{ id: 'n1' }, { id: 'n2' }], edges: [] });
314
396
  *
315
397
  * const patches = getPatches(a, b);
316
- * applyPatches(a, patches);
398
+ * updateGraphWithPatches(a, patches);
317
399
  * // a now contains both n1 and n2
318
400
  * ```
319
401
  */
320
- function applyPatches(graph, patches) {
402
+ function updateGraphWithPatches(graph, patches) {
321
403
  for (const patch of patches) switch (patch.op) {
322
404
  case "addNode":
323
405
  addNode(graph, patch.node);
@@ -340,6 +422,12 @@ function applyPatches(graph, patches) {
340
422
  }
341
423
  }
342
424
  /**
425
+ * @deprecated Use {@link updateGraphWithPatches}.
426
+ */
427
+ function applyPatches(graph, patches) {
428
+ updateGraphWithPatches(graph, patches);
429
+ }
430
+ /**
343
431
  * Flatten a structured diff into an ordered patch list.
344
432
  * Order: add nodes → update edges → delete edges → delete nodes → add edges → update nodes.
345
433
  * This avoids cascading deletes removing edges that are being updated,
@@ -365,7 +453,7 @@ function toPatches(diff) {
365
453
  });
366
454
  for (const change of diff.edges.updated) {
367
455
  const data = {};
368
- for (const [key, value] of Object.entries(change.new)) data[key] = value;
456
+ for (const [key, value] of Object.entries(change.new)) data[key] = value ?? null;
369
457
  patches.push({
370
458
  op: "updateEdge",
371
459
  id: change.id,
@@ -386,7 +474,7 @@ function toPatches(diff) {
386
474
  });
387
475
  for (const change of diff.nodes.updated) {
388
476
  const data = {};
389
- for (const [key, value] of Object.entries(change.new)) data[key] = value;
477
+ for (const [key, value] of Object.entries(change.new)) data[key] = value ?? null;
390
478
  patches.push({
391
479
  op: "updateNode",
392
480
  id: change.id,
@@ -460,201 +548,6 @@ function toDiff(patches) {
460
548
  return diff;
461
549
  }
462
550
 
463
- //#endregion
464
- //#region src/transforms.ts
465
- /**
466
- * Flattens a hierarchical graph into a flat graph with only leaf nodes.
467
- *
468
- * - Edges targeting a compound node resolve to its initial child (recursively).
469
- * - Edges originating from a compound node expand to all leaf descendants.
470
- * - Only leaf nodes (nodes with no children) appear in the result.
471
- * - Duplicate edges (same source + target) are deduplicated.
472
- *
473
- * @example
474
- * ```ts
475
- * import { createGraph, flatten } from '@statelyai/graph';
476
- *
477
- * const graph = createGraph({
478
- * nodes: [
479
- * { id: 'parent', initialNodeId: 'child1' },
480
- * { id: 'child1', parentId: 'parent' },
481
- * { id: 'child2', parentId: 'parent' },
482
- * { id: 'other' },
483
- * ],
484
- * edges: [{ id: 'e1', sourceId: 'other', targetId: 'parent' }],
485
- * });
486
- *
487
- * const flat = flatten(graph);
488
- * // flat.nodes → [child1, child2, other] (leaf nodes only)
489
- * // flat.edges → edge from 'other' → 'child1' (resolved via initialNodeId)
490
- * ```
491
- */
492
- function flatten(graph) {
493
- const idx = getIndex(graph);
494
- const leaves = /* @__PURE__ */ new Set();
495
- for (const node of graph.nodes) if ((idx.childNodes.get(node.id) ?? []).length === 0) leaves.add(node.id);
496
- function resolveInitial(nodeId) {
497
- if (leaves.has(nodeId)) return nodeId;
498
- const ni = idx.nodeById.get(nodeId);
499
- if (ni === void 0) return null;
500
- const node = graph.nodes[ni];
501
- if (node.initialNodeId) return resolveInitial(node.initialNodeId);
502
- const childIds = idx.childNodes.get(nodeId) ?? [];
503
- if (childIds.length > 0) return resolveInitial(childIds[0]);
504
- return nodeId;
505
- }
506
- function getLeafDescendants(nodeId) {
507
- if (leaves.has(nodeId)) return [nodeId];
508
- const result = [];
509
- const collect = (id) => {
510
- const childIds = idx.childNodes.get(id) ?? [];
511
- for (const childId of childIds) if (leaves.has(childId)) result.push(childId);
512
- else collect(childId);
513
- };
514
- collect(nodeId);
515
- return result;
516
- }
517
- const edgeSeen = /* @__PURE__ */ new Set();
518
- const flatEdges = [];
519
- for (const edge of graph.edges) {
520
- const sources = leaves.has(edge.sourceId) ? [edge.sourceId] : getLeafDescendants(edge.sourceId);
521
- const target = leaves.has(edge.targetId) ? edge.targetId : resolveInitial(edge.targetId);
522
- if (target === null) continue;
523
- for (const source of sources) {
524
- if (source === target) continue;
525
- const key = `${source}->${target}`;
526
- if (edgeSeen.has(key)) continue;
527
- edgeSeen.add(key);
528
- flatEdges.push({
529
- type: "edge",
530
- id: `${edge.id}:${source}->${target}`,
531
- sourceId: source,
532
- targetId: target,
533
- label: edge.label,
534
- data: edge.data
535
- });
536
- }
537
- }
538
- const leafNodes = graph.nodes.filter((n) => leaves.has(n.id)).map((n) => ({
539
- id: n.id,
540
- label: n.label,
541
- data: n.data
542
- }));
543
- return createGraph({
544
- id: graph.id,
545
- mode: graph.mode,
546
- nodes: leafNodes,
547
- edges: flatEdges,
548
- data: graph.data
549
- });
550
- }
551
- function nodeToConfig(node, nodeIdSet) {
552
- const config = {
553
- id: node.id,
554
- label: node.label,
555
- data: node.data
556
- };
557
- if (node.parentId !== void 0 && node.parentId !== null) config.parentId = nodeIdSet && !nodeIdSet.has(node.parentId) ? void 0 : node.parentId;
558
- if (node.initialNodeId !== void 0) config.initialNodeId = node.initialNodeId ?? void 0;
559
- if (node.x !== void 0) config.x = node.x;
560
- if (node.y !== void 0) config.y = node.y;
561
- if (node.width !== void 0) config.width = node.width;
562
- if (node.height !== void 0) config.height = node.height;
563
- if (node.shape !== void 0) config.shape = node.shape;
564
- if (node.color !== void 0) config.color = node.color;
565
- if (node.style !== void 0) config.style = node.style;
566
- return config;
567
- }
568
- function edgeToConfig(edge) {
569
- const config = {
570
- id: edge.id,
571
- sourceId: edge.sourceId,
572
- targetId: edge.targetId,
573
- label: edge.label,
574
- data: edge.data
575
- };
576
- if (edge.weight !== void 0) config.weight = edge.weight;
577
- if (edge.x !== void 0) config.x = edge.x;
578
- if (edge.y !== void 0) config.y = edge.y;
579
- if (edge.width !== void 0) config.width = edge.width;
580
- if (edge.height !== void 0) config.height = edge.height;
581
- if (edge.color !== void 0) config.color = edge.color;
582
- if (edge.style !== void 0) config.style = edge.style;
583
- return config;
584
- }
585
- /**
586
- * Returns the induced subgraph containing only the given node IDs
587
- * and edges whose endpoints are both in the set.
588
- *
589
- * Parent references to nodes outside the set are removed.
590
- *
591
- * @example
592
- * ```ts
593
- * import { createGraph, getSubgraph } from '@statelyai/graph';
594
- *
595
- * const graph = createGraph({
596
- * nodes: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
597
- * edges: [
598
- * { id: 'ab', sourceId: 'a', targetId: 'b' },
599
- * { id: 'bc', sourceId: 'b', targetId: 'c' },
600
- * ],
601
- * });
602
- *
603
- * const sub = getSubgraph(graph, ['a', 'b']);
604
- * // sub.nodes: [a, b], sub.edges: [ab]
605
- * ```
606
- */
607
- function getSubgraph(graph, nodeIds) {
608
- const nodeIdSet = new Set(nodeIds);
609
- return createGraph({
610
- id: graph.id,
611
- mode: graph.mode,
612
- initialNodeId: graph.initialNodeId && nodeIdSet.has(graph.initialNodeId) ? graph.initialNodeId : void 0,
613
- nodes: graph.nodes.filter((n) => nodeIdSet.has(n.id)).map((n) => nodeToConfig(n, nodeIdSet)),
614
- edges: graph.edges.filter((e) => nodeIdSet.has(e.sourceId) && nodeIdSet.has(e.targetId)).map(edgeToConfig),
615
- data: graph.data
616
- });
617
- }
618
- /**
619
- * Returns a new graph with all edge directions flipped (source ↔ target).
620
- * Optionally filters which edges to include.
621
- *
622
- * @example
623
- * ```ts
624
- * import { createGraph, reverseGraph } from '@statelyai/graph';
625
- *
626
- * const graph = createGraph({
627
- * nodes: [{ id: 'a' }, { id: 'b' }, { id: 'c' }],
628
- * edges: [
629
- * { id: 'ab', sourceId: 'a', targetId: 'b' },
630
- * { id: 'bc', sourceId: 'b', targetId: 'c' },
631
- * ],
632
- * });
633
- *
634
- * const rev = reverseGraph(graph);
635
- * // rev edges: b→a, c→b
636
- *
637
- * const filtered = reverseGraph(graph, (e) => e.id !== 'bc');
638
- * // filtered edges: b→a (only ab reversed, bc excluded)
639
- * ```
640
- */
641
- function reverseGraph(graph, filterEdge) {
642
- const edges = filterEdge ? graph.edges.filter(filterEdge) : graph.edges;
643
- return createGraph({
644
- id: graph.id,
645
- mode: graph.mode,
646
- initialNodeId: graph.initialNodeId ?? void 0,
647
- nodes: graph.nodes.map((n) => nodeToConfig(n)),
648
- edges: edges.map((e) => {
649
- const config = edgeToConfig(e);
650
- config.sourceId = e.targetId;
651
- config.targetId = e.sourceId;
652
- return config;
653
- }),
654
- data: graph.data
655
- });
656
- }
657
-
658
551
  //#endregion
659
552
  //#region src/walks.ts
660
553
  function mulberry32(seed) {
@@ -680,7 +573,24 @@ function resolveFrom(graph, from) {
680
573
  throw new Error("Cannot determine start node: provide `from`, set graph.initialNodeId, or have exactly one source node.");
681
574
  }
682
575
  /**
683
- * Random walk. At each node, picks a uniformly random outgoing edge.
576
+ * Edges traversable from a node, with the node reached by taking each one.
577
+ * Out-edges always; in-edges too when their effective mode is not 'directed'.
578
+ */
579
+ function getTraversableEdges(graph, nodeId) {
580
+ const result = [];
581
+ for (const edge of getOutEdges(graph, nodeId)) result.push({
582
+ edge,
583
+ nextId: edge.targetId
584
+ });
585
+ for (const edge of getInEdges(graph, nodeId)) if (edge.sourceId !== edge.targetId && getEdgeMode(graph, edge) !== "directed") result.push({
586
+ edge,
587
+ nextId: edge.sourceId
588
+ });
589
+ return result;
590
+ }
591
+ /**
592
+ * Random walk. At each node, picks a uniformly random traversable edge
593
+ * (outgoing edges, plus non-directed edges both ways).
684
594
  * Yields steps indefinitely (may revisit nodes) until a sink node is reached.
685
595
  */
686
596
  function* genRandomWalk(graph, options) {
@@ -693,11 +603,11 @@ function* genRandomWalk(graph, options) {
693
603
  stepCount: 0
694
604
  };
695
605
  while (true) {
696
- let edges = getOutEdges(graph, currentId);
697
- if (options?.filter) edges = edges.filter((e) => options.filter(e, ctx));
698
- if (edges.length === 0) return;
699
- const edge = edges[Math.floor(rng() * edges.length)];
700
- const node = getNode(graph, edge.targetId);
606
+ let traversable = getTraversableEdges(graph, currentId);
607
+ if (options?.filter) traversable = traversable.filter(({ edge: edge$1 }) => options.filter(edge$1, ctx));
608
+ if (traversable.length === 0) return;
609
+ const { edge, nextId } = traversable[Math.floor(rng() * traversable.length)];
610
+ const node = getNode(graph, nextId);
701
611
  const step = {
702
612
  edge,
703
613
  node
@@ -725,30 +635,30 @@ function* genWeightedRandomWalk(graph, options) {
725
635
  stepCount: 0
726
636
  };
727
637
  while (true) {
728
- let edges = getOutEdges(graph, currentId);
729
- if (options?.filter) edges = edges.filter((e) => options.filter(e, ctx));
730
- if (edges.length === 0) return;
731
- const weights = edges.map((e) => Math.max(0, getWeight(e)));
638
+ let traversable = getTraversableEdges(graph, currentId);
639
+ if (options?.filter) traversable = traversable.filter(({ edge }) => options.filter(edge, ctx));
640
+ if (traversable.length === 0) return;
641
+ const weights = traversable.map(({ edge }) => Math.max(0, getWeight(edge)));
732
642
  const total = weights.reduce((a, b) => a + b, 0);
733
643
  if (total === 0) return;
734
644
  let r = rng() * total;
735
- let chosen = edges[0];
736
- for (let i = 0; i < edges.length; i++) {
645
+ let chosen = traversable[0];
646
+ for (let i = 0; i < traversable.length; i++) {
737
647
  r -= weights[i];
738
648
  if (r <= 0) {
739
- chosen = edges[i];
649
+ chosen = traversable[i];
740
650
  break;
741
651
  }
742
652
  }
743
- const node = getNode(graph, chosen.targetId);
653
+ const node = getNode(graph, chosen.nextId);
744
654
  const step = {
745
- edge: chosen,
655
+ edge: chosen.edge,
746
656
  node
747
657
  };
748
658
  currentId = node.id;
749
659
  ctx.currentNodeId = currentId;
750
660
  ctx.visitedNodes.add(currentId);
751
- ctx.visitedEdges.add(chosen.id);
661
+ ctx.visitedEdges.add(chosen.edge.id);
752
662
  ctx.stepCount++;
753
663
  options?.onStep?.(step, ctx);
754
664
  yield step;
@@ -756,8 +666,9 @@ function* genWeightedRandomWalk(graph, options) {
756
666
  }
757
667
  /**
758
668
  * Quick random walk targeting unvisited edges.
759
- * If unvisited outgoing edges exist, picks one randomly.
760
- * Otherwise, finds shortest path to a node with unvisited outgoing edges.
669
+ * If unvisited traversable edges exist at the current node, picks one randomly.
670
+ * Otherwise, walks the fewest-hop path (BFS, honoring `filter` and edge modes)
671
+ * to the nearest unvisited edge. Ends when no unvisited edge is reachable.
761
672
  */
762
673
  function* genQuickRandomWalk(graph, options) {
763
674
  const rng = makeRng(options?.seed);
@@ -770,13 +681,16 @@ function* genQuickRandomWalk(graph, options) {
770
681
  visitedEdges,
771
682
  stepCount: 0
772
683
  };
684
+ const allowedEdges = (nodeId) => {
685
+ let traversable = getTraversableEdges(graph, nodeId);
686
+ if (options?.filter) traversable = traversable.filter(({ edge }) => options.filter(edge, ctx));
687
+ return traversable;
688
+ };
773
689
  while (visitedEdges.size < allEdgeIds.size) {
774
- let edges = getOutEdges(graph, currentId);
775
- if (options?.filter) edges = edges.filter((e) => options.filter(e, ctx));
776
- const unvisited = edges.filter((e) => !visitedEdges.has(e.id));
690
+ const unvisited = allowedEdges(currentId).filter(({ edge }) => !visitedEdges.has(edge.id));
777
691
  if (unvisited.length > 0) {
778
- const edge = unvisited[Math.floor(rng() * unvisited.length)];
779
- const node = getNode(graph, edge.targetId);
692
+ const { edge, nextId } = unvisited[Math.floor(rng() * unvisited.length)];
693
+ const node = getNode(graph, nextId);
780
694
  const step = {
781
695
  edge,
782
696
  node
@@ -789,22 +703,54 @@ function* genQuickRandomWalk(graph, options) {
789
703
  options?.onStep?.(step, ctx);
790
704
  yield step;
791
705
  } else {
792
- let targetNodeId;
793
- for (const n of graph.nodes) if (getOutEdges(graph, n.id).some((e) => !visitedEdges.has(e.id))) {
794
- targetNodeId = n.id;
795
- break;
706
+ const prevStep = /* @__PURE__ */ new Map();
707
+ const seen = new Set([currentId]);
708
+ const queue = [currentId];
709
+ let found;
710
+ while (queue.length > 0 && !found) {
711
+ const id = queue.shift();
712
+ for (const t of allowedEdges(id)) {
713
+ if (!visitedEdges.has(t.edge.id)) {
714
+ found = {
715
+ atId: id,
716
+ edge: t.edge,
717
+ nextId: t.nextId
718
+ };
719
+ break;
720
+ }
721
+ if (!seen.has(t.nextId)) {
722
+ seen.add(t.nextId);
723
+ prevStep.set(t.nextId, {
724
+ edge: t.edge,
725
+ fromId: id
726
+ });
727
+ queue.push(t.nextId);
728
+ }
729
+ }
796
730
  }
797
- if (!targetNodeId) return;
798
- const path = getShortestPath(graph, {
799
- from: currentId,
800
- to: targetNodeId
801
- });
802
- if (!path || path.steps.length === 0) return;
803
- for (const step of path.steps) {
804
- currentId = step.node.id;
731
+ if (!found) return;
732
+ const pathSteps = [{
733
+ edge: found.edge,
734
+ nextId: found.nextId
735
+ }];
736
+ let cursor = found.atId;
737
+ while (cursor !== currentId) {
738
+ const p = prevStep.get(cursor);
739
+ pathSteps.unshift({
740
+ edge: p.edge,
741
+ nextId: cursor
742
+ });
743
+ cursor = p.fromId;
744
+ }
745
+ for (const { edge, nextId } of pathSteps) {
746
+ const step = {
747
+ edge,
748
+ node: getNode(graph, nextId)
749
+ };
750
+ currentId = nextId;
805
751
  ctx.currentNodeId = currentId;
806
752
  ctx.visitedNodes.add(currentId);
807
- visitedEdges.add(step.edge.id);
753
+ visitedEdges.add(edge.id);
808
754
  ctx.stepCount++;
809
755
  options?.onStep?.(step, ctx);
810
756
  yield step;
@@ -815,14 +761,19 @@ function* genQuickRandomWalk(graph, options) {
815
761
  /**
816
762
  * Walk a predefined sequence of edge IDs.
817
763
  * Validates each edge exists and connects from the current position.
764
+ * Edges whose effective mode is not `'directed'` may be traversed
765
+ * target → source as well.
818
766
  */
819
767
  function* genPredefinedWalk(graph, edgeIds, options) {
820
768
  let currentId = resolveFrom(graph, options?.from);
821
769
  for (const edgeId of edgeIds) {
822
770
  const edge = graph.edges.find((e) => e.id === edgeId);
823
771
  if (!edge) throw new Error(`Edge "${edgeId}" not found in graph.`);
824
- if (edge.sourceId !== currentId) throw new Error(`Edge "${edgeId}" starts at "${edge.sourceId}" but current position is "${currentId}".`);
825
- const node = getNode(graph, edge.targetId);
772
+ let nextId;
773
+ if (edge.sourceId === currentId) nextId = edge.targetId;
774
+ else if (edge.targetId === currentId && getEdgeMode(graph, edge) !== "directed") nextId = edge.sourceId;
775
+ else throw new Error(`Edge "${edgeId}" connects "${edge.sourceId}" → "${edge.targetId}" but current position is "${currentId}".`);
776
+ const node = getNode(graph, nextId);
826
777
  currentId = node.id;
827
778
  yield {
828
779
  edge,
@@ -833,7 +784,7 @@ function* genPredefinedWalk(graph, edgeIds, options) {
833
784
  /**
834
785
  * Yield at most `n` steps from the source generator.
835
786
  */
836
- function* takeSteps(gen, n) {
787
+ function* genWalkSteps(gen, n) {
837
788
  let count = 0;
838
789
  for (const step of gen) {
839
790
  yield step;
@@ -841,31 +792,50 @@ function* takeSteps(gen, n) {
841
792
  }
842
793
  }
843
794
  /**
795
+ * @deprecated Use {@link genWalkSteps}.
796
+ */
797
+ function* takeSteps(gen, n) {
798
+ yield* genWalkSteps(gen, n);
799
+ }
800
+ /**
844
801
  * Yield steps until a specific node is reached.
845
802
  */
846
- function* takeUntilNode(gen, nodeId) {
803
+ function* genWalkUntilNode(gen, nodeId) {
847
804
  for (const step of gen) {
848
805
  yield step;
849
806
  if (step.node.id === nodeId) return;
850
807
  }
851
808
  }
852
809
  /**
810
+ * @deprecated Use {@link genWalkUntilNode}.
811
+ */
812
+ function* takeUntilNode(gen, nodeId) {
813
+ yield* genWalkUntilNode(gen, nodeId);
814
+ }
815
+ /**
853
816
  * Yield steps until a specific edge is traversed.
854
817
  */
855
- function* takeUntilEdge(gen, edgeId) {
818
+ function* genWalkUntilEdge(gen, edgeId) {
856
819
  for (const step of gen) {
857
820
  yield step;
858
821
  if (step.edge.id === edgeId) return;
859
822
  }
860
823
  }
861
824
  /**
825
+ * @deprecated Use {@link genWalkUntilEdge}.
826
+ */
827
+ function* takeUntilEdge(gen, edgeId) {
828
+ yield* genWalkUntilEdge(gen, edgeId);
829
+ }
830
+ /**
862
831
  * Yield steps until node coverage reaches the target (0–1).
863
832
  */
864
- function* takeUntilNodeCoverage(gen, graph, coverage, options) {
833
+ function* genWalkUntilNodeCoverage(gen, graph, coverage, options) {
865
834
  const totalNodes = graph.nodes.length;
866
835
  const target = Math.ceil(coverage * totalNodes);
867
836
  const startId = options?.from ?? graph.initialNodeId ?? graph.nodes[0]?.id;
868
837
  const visited = new Set(startId ? [startId] : []);
838
+ if (visited.size >= target) return;
869
839
  for (const step of gen) {
870
840
  visited.add(step.node.id);
871
841
  yield step;
@@ -873,12 +843,19 @@ function* takeUntilNodeCoverage(gen, graph, coverage, options) {
873
843
  }
874
844
  }
875
845
  /**
846
+ * @deprecated Use {@link genWalkUntilNodeCoverage}.
847
+ */
848
+ function* takeUntilNodeCoverage(gen, graph, coverage, options) {
849
+ yield* genWalkUntilNodeCoverage(gen, graph, coverage, options);
850
+ }
851
+ /**
876
852
  * Yield steps until edge coverage reaches the target (0–1).
877
853
  */
878
- function* takeUntilEdgeCoverage(gen, graph, coverage) {
854
+ function* genWalkUntilEdgeCoverage(gen, graph, coverage) {
879
855
  const totalEdges = graph.edges.length;
880
856
  const target = Math.ceil(coverage * totalEdges);
881
857
  const visited = /* @__PURE__ */ new Set();
858
+ if (target <= 0) return;
882
859
  for (const step of gen) {
883
860
  visited.add(step.edge.id);
884
861
  yield step;
@@ -886,6 +863,12 @@ function* takeUntilEdgeCoverage(gen, graph, coverage) {
886
863
  }
887
864
  }
888
865
  /**
866
+ * @deprecated Use {@link genWalkUntilEdgeCoverage}.
867
+ */
868
+ function* takeUntilEdgeCoverage(gen, graph, coverage) {
869
+ yield* genWalkUntilEdgeCoverage(gen, graph, coverage);
870
+ }
871
+ /**
889
872
  * Compute coverage statistics for a completed walk.
890
873
  */
891
874
  function getCoverage(graph, steps, options) {
@@ -906,4 +889,4 @@ function getCoverage(graph, steps, options) {
906
889
  }
907
890
 
908
891
  //#endregion
909
- export { GraphInstance, LAYOUT_KEYS, addEdge, addEntities, addNode, applyPatches, areEntitiesEqual, bfs, createFormatConverter, createGraph, createGraphEdge, createGraphFromTransition, createGraphNode, createGraphPort, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genGirvanNewmanCommunities, genPostorders, genPredefinedWalk, genPreorders, genQuickRandomWalk, genRandomWalk, genShortestPaths, genSimplePaths, genWeightedRandomWalk, getAStarPath, getAllPairsShortestPaths, getAncestors, getArticulationPoints, getBetweennessCentrality, getBiconnectedComponents, getBridges, getChildren, getClosenessCentrality, getConnectedComponents, getCoverage, getCycles, getDegree, getDegreeCentrality, getDepth, getDescendants, getDiff, getEdge, getEdgeMode, getEdgesBetween, getEdgesByPort, getEdgesOf, getEigenvectorCentrality, getGirvanNewmanCommunities, getGreedyModularityCommunities, getHITS, getInDegree, getInDegreeCentrality, getInEdges, getLCA, getLabelPropagationCommunities, getMinimumSpanningTree, getModularity, getNeighbors, getNode, getOutDegree, getOutDegreeCentrality, getOutEdges, getPageRank, getParent, getPatches, getPort, getPorts, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSubgraph, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEdgeDirected, isEmptyDiff, isIsomorphic, isLayoutEqual, isLeaf, isNonLayoutEqual, isTree, joinPaths, reverseGraph, takeSteps, takeUntilEdge, takeUntilEdgeCoverage, takeUntilNode, takeUntilNodeCoverage, toDiff, toPatches, updateEdge, updateEntities, updateNode };
892
+ export { GraphInstance, LAYOUT_KEYS, addEdge, addEntities, addNode, applyPatches, areEntitiesEqual, bfs, createCompleteGraph, createFormatConverter, createGraph, createGraphEdge, createGraphFromTransition, createGraphNode, createGraphPort, createGridGraph, createRandomGraph, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genBFS, genCycles, genDFS, genGirvanNewmanCommunities, genPostorders, genPredefinedWalk, genPreorders, genQuickRandomWalk, genRandomWalk, genShortestPaths, genSimplePaths, genWalkSteps, genWalkUntilEdge, genWalkUntilEdgeCoverage, genWalkUntilNode, genWalkUntilNodeCoverage, genWeightedRandomWalk, getAStarPath, getAllPairsShortestPaths, getAncestors, getArticulationPoints, getBetweennessCentrality, getBiconnectedComponents, getBridges, getChildren, getClosenessCentrality, getConnectedComponents, getCoreNumbers, getCoverage, getCycles, getDegree, getDegreeCentrality, getDepth, getDescendants, getDiff, getDominatorTree, getEdge, getEdgeMode, getEdgesBetween, getEdgesByPort, getEdgesOf, getEigenvectorCentrality, getFlattenedGraph, getGirvanNewmanCommunities, getGraphIssues, getGreedyModularityCommunities, getHITS, getInDegree, getInDegreeCentrality, getInEdges, getInvertedDiff, getJoinedPath, getKCore, getKatzCentrality, getLCA, getLabelPropagationCommunities, getLouvainCommunities, getMaxFlow, getMaximumBipartiteMatching, getMinCut, getMinimumSpanningTree, getModularity, getNeighbors, getNode, getOutDegree, getOutDegreeCentrality, getOutEdges, getPageRank, getParent, getPatches, getPort, getPorts, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getReversedGraph, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSubgraph, getSuccessors, getTopologicalSort, getTransitiveReduction, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isBipartite, isCompound, isConnected, isEdgeDirected, isEmptyDiff, isIsomorphic, isLayoutEqual, isLeaf, isNonLayoutEqual, isTree, joinPaths, reverseGraph, takeSteps, takeUntilEdge, takeUntilEdgeCoverage, takeUntilNode, takeUntilNodeCoverage, toDiff, toPatches, updateEdge, updateEntities, updateGraphWithPatches, updateNode };