@statelyai/graph 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -15
- package/dist/{adjacency-list-CXpOCibq.mjs → adjacency-list-ITO40kmn.mjs} +34 -1
- package/dist/{algorithms-R35X6ro4.mjs → algorithms-NWSB2RWj.mjs} +753 -19
- package/dist/algorithms.d.mts +488 -11
- package/dist/algorithms.mjs +2 -2
- package/dist/converter-CchokMDg.mjs +67 -0
- package/dist/edge-list-CgX6bBIF.mjs +71 -0
- package/dist/formats/adjacency-list/index.d.mts +44 -0
- package/dist/formats/adjacency-list/index.mjs +3 -0
- package/dist/formats/converter/index.d.mts +61 -0
- package/dist/formats/converter/index.mjs +3 -0
- package/dist/formats/cytoscape/index.d.mts +83 -0
- package/dist/formats/cytoscape/index.mjs +135 -0
- package/dist/formats/d3/index.d.mts +68 -0
- package/dist/formats/d3/index.mjs +111 -0
- package/dist/formats/dot/index.d.mts +63 -0
- package/dist/formats/dot/index.mjs +288 -0
- package/dist/formats/edge-list/index.d.mts +43 -0
- package/dist/formats/edge-list/index.mjs +3 -0
- package/dist/formats/gexf/index.d.mts +9 -0
- package/dist/formats/gexf/index.mjs +249 -0
- package/dist/formats/gml/index.d.mts +65 -0
- package/dist/formats/gml/index.mjs +291 -0
- package/dist/formats/graphml/index.d.mts +9 -0
- package/dist/{graphml-CUTNRXqd.mjs → formats/graphml/index.mjs} +18 -4
- package/dist/formats/jgf/index.d.mts +79 -0
- package/dist/formats/jgf/index.mjs +134 -0
- package/dist/formats/mermaid/index.d.mts +381 -0
- package/dist/formats/mermaid/index.mjs +2237 -0
- package/dist/formats/tgf/index.d.mts +54 -0
- package/dist/formats/tgf/index.mjs +111 -0
- package/dist/index.d.mts +332 -21
- package/dist/index.mjs +117 -13
- package/dist/{indexing-BHg1VhqN.mjs → indexing-eNDrXdDA.mjs} +31 -2
- package/dist/queries.d.mts +430 -9
- package/dist/queries.mjs +472 -9
- package/dist/{types-XV3S5Jnh.d.mts → types-BDXC1O5b.d.mts} +37 -2
- package/package.json +43 -17
- package/dist/adjacency-list-DW-lAUe8.d.mts +0 -10
- package/dist/dot-BRtq3e3c.mjs +0 -59
- package/dist/dot-HmJeUMsj.d.mts +0 -6
- package/dist/edge-list-BRujEnnU.mjs +0 -39
- package/dist/edge-list-CJmfoNu2.d.mts +0 -10
- package/dist/formats/adjacency-list.d.mts +0 -2
- package/dist/formats/adjacency-list.mjs +0 -3
- package/dist/formats/dot.d.mts +0 -2
- package/dist/formats/dot.mjs +0 -3
- package/dist/formats/edge-list.d.mts +0 -2
- package/dist/formats/edge-list.mjs +0 -3
- package/dist/formats/graphml.d.mts +0 -2
- package/dist/formats/graphml.mjs +0 -3
- package/dist/graphml-CMjPzSfY.d.mts +0 -7
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { o as invalidateIndex, t as getIndex } from "./indexing-
|
|
2
|
-
import { A as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as toGraphML, t as fromGraphML } from "./graphml-CUTNRXqd.mjs";
|
|
6
|
-
import { t as toDOT } from "./dot-BRtq3e3c.mjs";
|
|
7
|
-
import { n as toAdjacencyList, t as fromAdjacencyList } from "./adjacency-list-CXpOCibq.mjs";
|
|
8
|
-
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-BRujEnnU.mjs";
|
|
1
|
+
import { o as invalidateIndex, t as getIndex } from "./indexing-eNDrXdDA.mjs";
|
|
2
|
+
import { A as addNode, B as hasNode, C as isAcyclic, D as GraphInstance, E as joinPaths, F as deleteEntities, H as updateEntities, I as deleteNode, L as getEdge, M as createGraphFromTransition, N as createVisualGraph, O as addEdge, P as deleteEdge, R as getNode, S as hasPath, T as isTree, U as updateNode, V as updateEdge, _ as getShortestPaths, a as genPreorders, b as getStronglyConnectedComponents, c as getAllPairsShortestPaths, d as getMinimumSpanningTree, f as getPostorder, g as getShortestPath, h as getPreorders, i as genPostorders, j as createGraph, k as addEntities, l as getConnectedComponents, m as getPreorder, n as dfs, o as genShortestPaths, p as getPostorders, r as genCycles, s as genSimplePaths, t as bfs, u as getCycles, v as getSimplePath, w as isConnected, x as getTopologicalSort, y as getSimplePaths, z as hasEdge } from "./algorithms-NWSB2RWj.mjs";
|
|
3
|
+
import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
|
|
4
|
+
import { n as createFormatConverter } from "./converter-CchokMDg.mjs";
|
|
9
5
|
|
|
10
6
|
//#region src/diff.ts
|
|
11
7
|
function nodeToConfig(node) {
|
|
@@ -71,7 +67,21 @@ const EDGE_COMPARE_KEYS = [
|
|
|
71
67
|
"color",
|
|
72
68
|
"style"
|
|
73
69
|
];
|
|
74
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Compute a structured diff from graph `a` to graph `b` by matching IDs.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { createGraph, getDiff } from '@statelyai/graph';
|
|
76
|
+
*
|
|
77
|
+
* const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
78
|
+
* const b = createGraph({ nodes: [{ id: 'n1', label: 'hello' }, { id: 'n2' }], edges: [] });
|
|
79
|
+
*
|
|
80
|
+
* const diff = getDiff(a, b);
|
|
81
|
+
* // diff.nodes.added → [{ id: 'n2' }]
|
|
82
|
+
* // diff.nodes.updated → [{ id: 'n1', old: { label: '' }, new: { label: 'hello' } }]
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
75
85
|
function getDiff(a, b) {
|
|
76
86
|
const aNodeMap = new Map(a.nodes.map((n) => [n.id, n]));
|
|
77
87
|
const bNodeMap = new Map(b.nodes.map((n) => [n.id, n]));
|
|
@@ -127,11 +137,37 @@ function getDiff(a, b) {
|
|
|
127
137
|
for (const [id, edgeA] of aEdgeMap) if (!bEdgeMap.has(id)) diff.edges.removed.push(edgeToConfig(edgeA));
|
|
128
138
|
return diff;
|
|
129
139
|
}
|
|
130
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Check if a diff has zero changes.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* import { createGraph, getDiff, isEmptyDiff } from '@statelyai/graph';
|
|
146
|
+
*
|
|
147
|
+
* const g = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
148
|
+
* const diff = getDiff(g, g);
|
|
149
|
+
* isEmptyDiff(diff); // true
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
131
152
|
function isEmptyDiff(diff) {
|
|
132
153
|
return diff.nodes.added.length === 0 && diff.nodes.removed.length === 0 && diff.nodes.updated.length === 0 && diff.edges.added.length === 0 && diff.edges.removed.length === 0 && diff.edges.updated.length === 0;
|
|
133
154
|
}
|
|
134
|
-
/**
|
|
155
|
+
/**
|
|
156
|
+
* Invert a diff: swap added/removed, swap old/new in updates.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* import { createGraph, getDiff, invertDiff } from '@statelyai/graph';
|
|
161
|
+
*
|
|
162
|
+
* const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
163
|
+
* const b = createGraph({ nodes: [{ id: 'n2' }], edges: [] });
|
|
164
|
+
*
|
|
165
|
+
* const diff = getDiff(a, b);
|
|
166
|
+
* const inv = invertDiff(diff);
|
|
167
|
+
* // inv.nodes.added contains n1 (was removed)
|
|
168
|
+
* // inv.nodes.removed contains n2 (was added)
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
135
171
|
function invertDiff(diff) {
|
|
136
172
|
return {
|
|
137
173
|
nodes: {
|
|
@@ -157,6 +193,17 @@ function invertDiff(diff) {
|
|
|
157
193
|
/**
|
|
158
194
|
* Compute an ordered patch list from graph `a` to graph `b`.
|
|
159
195
|
* Order: delete edges → delete nodes → add nodes → add edges → update nodes → update edges.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* import { createGraph, getPatches } from '@statelyai/graph';
|
|
200
|
+
*
|
|
201
|
+
* const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
202
|
+
* const b = createGraph({ nodes: [{ id: 'n1' }, { id: 'n2' }], edges: [] });
|
|
203
|
+
*
|
|
204
|
+
* const patches = getPatches(a, b);
|
|
205
|
+
* // patches → [{ op: 'addNode', node: { id: 'n2' } }]
|
|
206
|
+
* ```
|
|
160
207
|
*/
|
|
161
208
|
function getPatches(a, b) {
|
|
162
209
|
return toPatches(getDiff(a, b));
|
|
@@ -164,6 +211,18 @@ function getPatches(a, b) {
|
|
|
164
211
|
/**
|
|
165
212
|
* **Mutable.** Apply patches to a graph in order.
|
|
166
213
|
* Delegates to addNode/deleteNode/updateNode/addEdge/deleteEdge/updateEdge.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* import { createGraph, getPatches, applyPatches } from '@statelyai/graph';
|
|
218
|
+
*
|
|
219
|
+
* const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
220
|
+
* const b = createGraph({ nodes: [{ id: 'n1' }, { id: 'n2' }], edges: [] });
|
|
221
|
+
*
|
|
222
|
+
* const patches = getPatches(a, b);
|
|
223
|
+
* applyPatches(a, patches);
|
|
224
|
+
* // a now contains both n1 and n2
|
|
225
|
+
* ```
|
|
167
226
|
*/
|
|
168
227
|
function applyPatches(graph, patches) {
|
|
169
228
|
for (const patch of patches) switch (patch.op) {
|
|
@@ -192,6 +251,18 @@ function applyPatches(graph, patches) {
|
|
|
192
251
|
* Order: add nodes → update edges → delete edges → delete nodes → add edges → update nodes.
|
|
193
252
|
* This avoids cascading deletes removing edges that are being updated,
|
|
194
253
|
* and ensures new nodes exist before edges reference them.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```ts
|
|
257
|
+
* import { createGraph, getDiff, toPatches } from '@statelyai/graph';
|
|
258
|
+
*
|
|
259
|
+
* const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
260
|
+
* const b = createGraph({ nodes: [{ id: 'n2' }], edges: [] });
|
|
261
|
+
*
|
|
262
|
+
* const diff = getDiff(a, b);
|
|
263
|
+
* const patches = toPatches(diff);
|
|
264
|
+
* // patches → [{ op: 'addNode', ... }, { op: 'deleteNode', ... }]
|
|
265
|
+
* ```
|
|
195
266
|
*/
|
|
196
267
|
function toPatches(diff) {
|
|
197
268
|
const patches = [];
|
|
@@ -231,7 +302,21 @@ function toPatches(diff) {
|
|
|
231
302
|
}
|
|
232
303
|
return patches;
|
|
233
304
|
}
|
|
234
|
-
/**
|
|
305
|
+
/**
|
|
306
|
+
* Group a patch list into a structured diff.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```ts
|
|
310
|
+
* import { createGraph, getPatches, toDiff } from '@statelyai/graph';
|
|
311
|
+
*
|
|
312
|
+
* const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
|
|
313
|
+
* const b = createGraph({ nodes: [{ id: 'n1' }, { id: 'n2' }], edges: [] });
|
|
314
|
+
*
|
|
315
|
+
* const patches = getPatches(a, b);
|
|
316
|
+
* const diff = toDiff(patches);
|
|
317
|
+
* // diff.nodes.added → [{ id: 'n2' }]
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
235
320
|
function toDiff(patches) {
|
|
236
321
|
const diff = {
|
|
237
322
|
nodes: {
|
|
@@ -291,6 +376,25 @@ function toDiff(patches) {
|
|
|
291
376
|
* - Edges originating from a compound node expand to all leaf descendants.
|
|
292
377
|
* - Only leaf nodes (nodes with no children) appear in the result.
|
|
293
378
|
* - Duplicate edges (same source + target) are deduplicated.
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```ts
|
|
382
|
+
* import { createGraph, flatten } from '@statelyai/graph';
|
|
383
|
+
*
|
|
384
|
+
* const graph = createGraph({
|
|
385
|
+
* nodes: [
|
|
386
|
+
* { id: 'parent', initialNodeId: 'child1' },
|
|
387
|
+
* { id: 'child1', parentId: 'parent' },
|
|
388
|
+
* { id: 'child2', parentId: 'parent' },
|
|
389
|
+
* { id: 'other' },
|
|
390
|
+
* ],
|
|
391
|
+
* edges: [{ id: 'e1', sourceId: 'other', targetId: 'parent' }],
|
|
392
|
+
* });
|
|
393
|
+
*
|
|
394
|
+
* const flat = flatten(graph);
|
|
395
|
+
* // flat.nodes → [child1, child2, other] (leaf nodes only)
|
|
396
|
+
* // flat.edges → edge from 'other' → 'child1' (resolved via initialNodeId)
|
|
397
|
+
* ```
|
|
294
398
|
*/
|
|
295
399
|
function flatten(graph) {
|
|
296
400
|
const idx = getIndex(graph);
|
|
@@ -353,4 +457,4 @@ function flatten(graph) {
|
|
|
353
457
|
}
|
|
354
458
|
|
|
355
459
|
//#endregion
|
|
356
|
-
export {
|
|
460
|
+
export { GraphInstance, addEdge, addEntities, addNode, applyPatches, bfs, createFormatConverter, createGraph, createGraphFromTransition, createVisualGraph, deleteEdge, deleteEntities, deleteNode, dfs, flatten, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getAncestors, getChildren, getConnectedComponents, getCycles, getDegree, getDepth, getDescendants, getDiff, getEdge, getEdgeBetween, getEdgesOf, getInDegree, getInEdges, getLCA, getMinimumSpanningTree, getNeighbors, getNode, getOutDegree, getOutEdges, getParent, getPatches, getPostorder, getPostorders, getPredecessors, getPreorder, getPreorders, getRelativeDistance, getRelativeDistanceMap, getRoots, getShortestPath, getShortestPaths, getSiblings, getSimplePath, getSimplePaths, getSinks, getSources, getStronglyConnectedComponents, getSuccessors, getTopologicalSort, hasEdge, hasNode, hasPath, invalidateIndex, invertDiff, isAcyclic, isCompound, isConnected, isEmptyDiff, isLeaf, isTree, joinPaths, toDiff, toPatches, updateEdge, updateEntities, updateNode };
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
//#region src/indexing.ts
|
|
2
2
|
const indexes = /* @__PURE__ */ new WeakMap();
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Get or lazily build the index for a graph.
|
|
5
|
+
* Auto-rebuilds when node/edge count changes.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createGraph, getIndex } from '@statelyai/graph';
|
|
10
|
+
*
|
|
11
|
+
* const graph = createGraph({
|
|
12
|
+
* nodes: [{ id: 'a' }, { id: 'b' }],
|
|
13
|
+
* edges: [{ id: 'e1', sourceId: 'a', targetId: 'b' }],
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* const idx = getIndex(graph);
|
|
17
|
+
* idx.nodeById.get('a'); // 0
|
|
18
|
+
* idx.outEdges.get('a'); // ['e1']
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
4
21
|
function getIndex(graph) {
|
|
5
22
|
let idx = indexes.get(graph);
|
|
6
23
|
if (!idx || idx.nodeCount !== graph.nodes.length || idx.edgeCount !== graph.edges.length) {
|
|
@@ -9,7 +26,19 @@ function getIndex(graph) {
|
|
|
9
26
|
}
|
|
10
27
|
return idx;
|
|
11
28
|
}
|
|
12
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Clear the cached index. Call this if you mutate graph.nodes/edges directly.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { createGraph, invalidateIndex, getIndex } from '@statelyai/graph';
|
|
35
|
+
*
|
|
36
|
+
* const graph = createGraph({ nodes: [{ id: 'a' }], edges: [] });
|
|
37
|
+
* // manually mutate nodes array
|
|
38
|
+
* graph.nodes.push({ type: 'node', id: 'b', parentId: null, initialNodeId: null, label: '', data: undefined });
|
|
39
|
+
* invalidateIndex(graph); // forces rebuild on next getIndex()
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
13
42
|
function invalidateIndex(graph) {
|
|
14
43
|
indexes.delete(graph);
|
|
15
44
|
}
|