@statelyai/graph 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -144
- package/dist/{algorithms-CnTmuX9t.mjs → algorithms-oVD9PYil.mjs} +219 -31
- package/dist/algorithms.d.mts +91 -3
- package/dist/algorithms.mjs +2 -2
- package/dist/{converter-C5DlzzHs.mjs → converter-B5CUD0r9.mjs} +2 -2
- package/dist/formats/adjacency-list/index.d.mts +1 -1
- package/dist/formats/adjacency-list/index.mjs +1 -1
- package/dist/formats/converter/index.d.mts +2 -2
- package/dist/formats/converter/index.mjs +1 -1
- package/dist/formats/cytoscape/index.d.mts +1 -1
- package/dist/formats/cytoscape/index.mjs +1 -1
- package/dist/formats/d3/index.d.mts +1 -1
- package/dist/formats/d3/index.mjs +1 -1
- package/dist/formats/dot/index.d.mts +1 -1
- package/dist/formats/dot/index.mjs +1 -1
- package/dist/formats/edge-list/index.d.mts +1 -1
- package/dist/formats/edge-list/index.mjs +1 -1
- package/dist/formats/elk/index.d.mts +61 -0
- package/dist/formats/elk/index.mjs +176 -0
- package/dist/formats/gexf/index.d.mts +1 -1
- package/dist/formats/gexf/index.mjs +1 -1
- package/dist/formats/gml/index.d.mts +1 -1
- package/dist/formats/gml/index.mjs +1 -1
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/graphml/index.mjs +148 -56
- package/dist/formats/jgf/index.d.mts +1 -1
- package/dist/formats/jgf/index.mjs +1 -1
- package/dist/formats/mermaid/index.d.mts +51 -33
- package/dist/formats/mermaid/index.mjs +315 -31
- package/dist/formats/tgf/index.d.mts +1 -1
- package/dist/formats/tgf/index.mjs +1 -1
- package/dist/formats/xyflow/index.d.mts +1 -1
- package/dist/index.d.mts +100 -3
- package/dist/index.mjs +366 -10
- package/dist/queries.d.mts +1 -1
- package/dist/queries.mjs +1 -1
- package/dist/schemas.d.mts +39 -4
- package/dist/schemas.mjs +27 -5
- package/dist/{types-Bq_fmLwW.d.mts → types-DF-HNw50.d.mts} +65 -13
- package/package.json +7 -1
- package/schemas/edge.schema.json +32 -1
- package/schemas/graph.schema.json +114 -4
- package/schemas/node.schema.json +45 -2
- /package/dist/{adjacency-list-Bv4tfiM3.mjs → adjacency-list-fldj-QAL.mjs} +0 -0
- /package/dist/{edge-list-R1SUbHwe.mjs → edge-list-Br05wXMg.mjs} +0 -0
- /package/dist/{indexing-DitHphT7.mjs → indexing-DyfgLuzw.mjs} +0 -0
package/dist/algorithms.d.mts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as SinglePathOptions, S as PathOptions, T as TraversalOptions, _ as GraphPath, h as GraphNode, n as AllPairsShortestPathsOptions, t as AStarOptions, u as Graph, y as MSTOptions } from "./types-DF-HNw50.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/algorithms.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Breadth-first traversal generator yielding nodes level by level.
|
|
7
7
|
*
|
|
8
|
+
* **O(V + E)** time, **O(V)** space.
|
|
9
|
+
*
|
|
8
10
|
* @example
|
|
9
11
|
* ```ts
|
|
10
12
|
* import { createGraph, bfs } from '@statelyai/graph';
|
|
@@ -23,6 +25,8 @@ declare function bfs<N>(graph: Graph<N>, startId: string): Generator<GraphNode<N
|
|
|
23
25
|
/**
|
|
24
26
|
* Depth-first traversal generator yielding nodes as visited.
|
|
25
27
|
*
|
|
28
|
+
* **O(V + E)** time, **O(V)** space.
|
|
29
|
+
*
|
|
26
30
|
* @example
|
|
27
31
|
* ```ts
|
|
28
32
|
* import { createGraph, dfs } from '@statelyai/graph';
|
|
@@ -41,6 +45,8 @@ declare function dfs<N>(graph: Graph<N>, startId: string): Generator<GraphNode<N
|
|
|
41
45
|
/**
|
|
42
46
|
* Checks whether the graph contains no cycles.
|
|
43
47
|
*
|
|
48
|
+
* **O(V + E)** time.
|
|
49
|
+
*
|
|
44
50
|
* @example
|
|
45
51
|
* ```ts
|
|
46
52
|
* import { createGraph, isAcyclic } from '@statelyai/graph';
|
|
@@ -58,6 +64,8 @@ declare function isAcyclic(graph: Graph): boolean;
|
|
|
58
64
|
* Returns connected components as arrays of nodes.
|
|
59
65
|
* Treats all edges as undirected for connectivity.
|
|
60
66
|
*
|
|
67
|
+
* **O(V + E)** time.
|
|
68
|
+
*
|
|
61
69
|
* @example
|
|
62
70
|
* ```ts
|
|
63
71
|
* import { createGraph, getConnectedComponents } from '@statelyai/graph';
|
|
@@ -75,6 +83,8 @@ declare function getConnectedComponents<N>(graph: Graph<N>): GraphNode<N>[][];
|
|
|
75
83
|
/**
|
|
76
84
|
* Returns a topological ordering of nodes, or `null` if the graph is cyclic.
|
|
77
85
|
*
|
|
86
|
+
* **O(V + E)** time (Kahn's algorithm).
|
|
87
|
+
*
|
|
78
88
|
* @example
|
|
79
89
|
* ```ts
|
|
80
90
|
* import { createGraph, getTopologicalSort } from '@statelyai/graph';
|
|
@@ -95,6 +105,8 @@ declare function getTopologicalSort<N>(graph: Graph<N>): GraphNode<N>[] | null;
|
|
|
95
105
|
/**
|
|
96
106
|
* Checks whether a path exists between two nodes.
|
|
97
107
|
*
|
|
108
|
+
* **O(V + E)** time (BFS) or **O((V + E) log V)** (Dijkstra when weighted).
|
|
109
|
+
*
|
|
98
110
|
* @example
|
|
99
111
|
* ```ts
|
|
100
112
|
* import { createGraph, hasPath } from '@statelyai/graph';
|
|
@@ -112,6 +124,8 @@ declare function hasPath(graph: Graph, sourceId: string, targetId: string): bool
|
|
|
112
124
|
/**
|
|
113
125
|
* Checks whether the graph is connected (all nodes reachable from any node).
|
|
114
126
|
*
|
|
127
|
+
* **O(V + E)** time.
|
|
128
|
+
*
|
|
115
129
|
* @example
|
|
116
130
|
* ```ts
|
|
117
131
|
* import { createGraph, isConnected } from '@statelyai/graph';
|
|
@@ -128,6 +142,8 @@ declare function isConnected(graph: Graph): boolean;
|
|
|
128
142
|
/**
|
|
129
143
|
* Checks whether the graph is a tree (connected and acyclic).
|
|
130
144
|
*
|
|
145
|
+
* **O(V + E)** time.
|
|
146
|
+
*
|
|
131
147
|
* @example
|
|
132
148
|
* ```ts
|
|
133
149
|
* import { createGraph, isTree } from '@statelyai/graph';
|
|
@@ -148,6 +164,9 @@ declare function isTree(graph: Graph): boolean;
|
|
|
148
164
|
* Lazily yields all shortest paths from a source node.
|
|
149
165
|
* Use `getShortestPaths` for the full array.
|
|
150
166
|
*
|
|
167
|
+
* **O(V + E)** time (BFS) or **O((V + E) log V)** (Dijkstra when weighted),
|
|
168
|
+
* plus **O(P)** per path yielded where P is the path length.
|
|
169
|
+
*
|
|
151
170
|
* @example
|
|
152
171
|
* ```ts
|
|
153
172
|
* import { createGraph, genShortestPaths } from '@statelyai/graph';
|
|
@@ -171,6 +190,8 @@ declare function genShortestPaths<N, E>(graph: Graph<N, E>, opts?: PathOptions<E
|
|
|
171
190
|
* Returns all shortest paths from a source node as an array.
|
|
172
191
|
* Delegates to `genShortestPaths` internally.
|
|
173
192
|
*
|
|
193
|
+
* **O(V + E)** time (BFS) or **O((V + E) log V)** (Dijkstra when weighted).
|
|
194
|
+
*
|
|
174
195
|
* @example
|
|
175
196
|
* ```ts
|
|
176
197
|
* import { createGraph, getShortestPaths } from '@statelyai/graph';
|
|
@@ -192,6 +213,8 @@ declare function getShortestPaths<N, E>(graph: Graph<N, E>, opts?: PathOptions<E
|
|
|
192
213
|
/**
|
|
193
214
|
* Returns a single shortest path from source to target, or `undefined` if unreachable.
|
|
194
215
|
*
|
|
216
|
+
* **O(V + E)** time (BFS) or **O((V + E) log V)** (Dijkstra when weighted).
|
|
217
|
+
*
|
|
195
218
|
* @example
|
|
196
219
|
* ```ts
|
|
197
220
|
* import { createGraph, getShortestPath } from '@statelyai/graph';
|
|
@@ -214,6 +237,8 @@ declare function getShortestPath<N, E>(graph: Graph<N, E>, opts: SinglePathOptio
|
|
|
214
237
|
* Returns all simple (acyclic) paths from a source node as an array.
|
|
215
238
|
* Delegates to `genSimplePaths` internally.
|
|
216
239
|
*
|
|
240
|
+
* **O(V!)** worst-case (exponential in dense graphs).
|
|
241
|
+
*
|
|
217
242
|
* @example
|
|
218
243
|
* ```ts
|
|
219
244
|
* import { createGraph, getSimplePaths } from '@statelyai/graph';
|
|
@@ -237,6 +262,8 @@ declare function getSimplePaths<N, E>(graph: Graph<N, E>, opts?: PathOptions<E>)
|
|
|
237
262
|
* Lazily yields all simple (acyclic) paths from a source node via DFS backtracking.
|
|
238
263
|
* Use `getSimplePaths` for the full array.
|
|
239
264
|
*
|
|
265
|
+
* **O(V!)** worst-case (exponential in dense graphs).
|
|
266
|
+
*
|
|
240
267
|
* @example
|
|
241
268
|
* ```ts
|
|
242
269
|
* import { createGraph, genSimplePaths } from '@statelyai/graph';
|
|
@@ -261,6 +288,8 @@ declare function genSimplePaths<N, E>(graph: Graph<N, E>, opts?: PathOptions<E>)
|
|
|
261
288
|
/**
|
|
262
289
|
* Returns a single simple (acyclic) path from source to target, or `undefined` if unreachable.
|
|
263
290
|
*
|
|
291
|
+
* **O(V + E)** typical, **O(V!)** worst-case.
|
|
292
|
+
*
|
|
264
293
|
* @example
|
|
265
294
|
* ```ts
|
|
266
295
|
* import { createGraph, getSimplePath } from '@statelyai/graph';
|
|
@@ -283,6 +312,8 @@ declare function getSimplePath<N, E>(graph: Graph<N, E>, opts: SinglePathOptions
|
|
|
283
312
|
* Returns strongly connected components using Tarjan's algorithm.
|
|
284
313
|
* Only meaningful for directed graphs.
|
|
285
314
|
*
|
|
315
|
+
* **O(V + E)** time.
|
|
316
|
+
*
|
|
286
317
|
* @example
|
|
287
318
|
* ```ts
|
|
288
319
|
* import { createGraph, getStronglyConnectedComponents } from '@statelyai/graph';
|
|
@@ -305,6 +336,8 @@ declare function getStronglyConnectedComponents<N>(graph: Graph<N>): GraphNode<N
|
|
|
305
336
|
* Returns all elementary cycles as an array of paths.
|
|
306
337
|
* Delegates to `genCycles` internally.
|
|
307
338
|
*
|
|
339
|
+
* **O((V + E) · C)** where C is the number of elementary cycles (can be exponential).
|
|
340
|
+
*
|
|
308
341
|
* @example
|
|
309
342
|
* ```ts
|
|
310
343
|
* import { createGraph, getCycles } from '@statelyai/graph';
|
|
@@ -326,6 +359,8 @@ declare function getCycles<N, E>(graph: Graph<N, E>): GraphPath<N, E>[];
|
|
|
326
359
|
* Lazily yields elementary cycles one at a time.
|
|
327
360
|
* Use `getCycles` for the full array.
|
|
328
361
|
*
|
|
362
|
+
* **O((V + E) · C)** where C is the number of elementary cycles (can be exponential).
|
|
363
|
+
*
|
|
329
364
|
* @example
|
|
330
365
|
* ```ts
|
|
331
366
|
* import { createGraph, genCycles } from '@statelyai/graph';
|
|
@@ -348,6 +383,8 @@ declare function genCycles<N, E>(graph: Graph<N, E>): Generator<GraphPath<N, E>>
|
|
|
348
383
|
* Returns a single canonical preorder (DFS visit-order) sequence.
|
|
349
384
|
* Visits neighbors in the order they appear in the adjacency list.
|
|
350
385
|
*
|
|
386
|
+
* **O(V + E)** time.
|
|
387
|
+
*
|
|
351
388
|
* @example
|
|
352
389
|
* ```ts
|
|
353
390
|
* import { createGraph, getPreorder } from '@statelyai/graph';
|
|
@@ -370,6 +407,8 @@ declare function getPreorder<N>(graph: Graph<N>, opts?: TraversalOptions): Graph
|
|
|
370
407
|
* Returns a single canonical postorder (DFS finish-order) sequence.
|
|
371
408
|
* Visits neighbors in the order they appear in the adjacency list.
|
|
372
409
|
*
|
|
410
|
+
* **O(V + E)** time.
|
|
411
|
+
*
|
|
373
412
|
* @example
|
|
374
413
|
* ```ts
|
|
375
414
|
* import { createGraph, getPostorder } from '@statelyai/graph';
|
|
@@ -391,6 +430,8 @@ declare function getPostorder<N>(graph: Graph<N>, opts?: TraversalOptions): Grap
|
|
|
391
430
|
/**
|
|
392
431
|
* Returns all possible preorder sequences as an array. Can be exponential -- prefer `genPreorders`.
|
|
393
432
|
*
|
|
433
|
+
* **O(V! · V)** worst-case (exponential).
|
|
434
|
+
*
|
|
394
435
|
* @example
|
|
395
436
|
* ```ts
|
|
396
437
|
* import { createGraph, getPreorders } from '@statelyai/graph';
|
|
@@ -412,6 +453,8 @@ declare function getPreorders<N>(graph: Graph<N>, opts?: TraversalOptions): Grap
|
|
|
412
453
|
/**
|
|
413
454
|
* Returns all possible postorder sequences as an array. Can be exponential -- prefer `genPostorders`.
|
|
414
455
|
*
|
|
456
|
+
* **O(V! · V)** worst-case (exponential).
|
|
457
|
+
*
|
|
415
458
|
* @example
|
|
416
459
|
* ```ts
|
|
417
460
|
* import { createGraph, getPostorders } from '@statelyai/graph';
|
|
@@ -435,6 +478,8 @@ declare function getPostorders<N>(graph: Graph<N>, opts?: TraversalOptions): Gra
|
|
|
435
478
|
* Different neighbor exploration orders yield different sequences.
|
|
436
479
|
* Use `getPreorder()` for a single canonical ordering.
|
|
437
480
|
*
|
|
481
|
+
* **O(V! · V)** worst-case (exponential).
|
|
482
|
+
*
|
|
438
483
|
* @example
|
|
439
484
|
* ```ts
|
|
440
485
|
* import { createGraph, genPreorders } from '@statelyai/graph';
|
|
@@ -460,6 +505,8 @@ declare function genPreorders<N>(graph: Graph<N>, opts?: TraversalOptions): Gene
|
|
|
460
505
|
* Different neighbor exploration orders yield different sequences.
|
|
461
506
|
* Use `getPostorder()` for a single canonical ordering.
|
|
462
507
|
*
|
|
508
|
+
* **O(V! · V)** worst-case (exponential).
|
|
509
|
+
*
|
|
463
510
|
* @example
|
|
464
511
|
* ```ts
|
|
465
512
|
* import { createGraph, genPostorders } from '@statelyai/graph';
|
|
@@ -485,6 +532,8 @@ declare function genPostorders<N>(graph: Graph<N>, opts?: TraversalOptions): Gen
|
|
|
485
532
|
* Only meaningful for connected undirected graphs (or the component reachable
|
|
486
533
|
* from an arbitrary start node in directed graphs).
|
|
487
534
|
*
|
|
535
|
+
* **O(E log E)** using either edge sorting (Kruskal) or a min-heap (Prim).
|
|
536
|
+
*
|
|
488
537
|
* @example
|
|
489
538
|
* ```ts
|
|
490
539
|
* import { createGraph, getMinimumSpanningTree } from '@statelyai/graph';
|
|
@@ -509,7 +558,9 @@ declare function getMinimumSpanningTree<N, E>(graph: Graph<N, E>, opts?: MSTOpti
|
|
|
509
558
|
/**
|
|
510
559
|
* Returns shortest paths between all pairs of nodes.
|
|
511
560
|
* Algorithm 'dijkstra' (default): runs getShortestPaths per source node.
|
|
512
|
-
* Algorithm 'floyd-warshall': classic
|
|
561
|
+
* Algorithm 'floyd-warshall': classic dynamic programming.
|
|
562
|
+
*
|
|
563
|
+
* **O(V · (V + E) log V)** (Dijkstra) or **O(V³)** (Floyd-Warshall).
|
|
513
564
|
*
|
|
514
565
|
* @example
|
|
515
566
|
* ```ts
|
|
@@ -528,6 +579,43 @@ declare function getMinimumSpanningTree<N, E>(graph: Graph<N, E>, opts?: MSTOpti
|
|
|
528
579
|
* ```
|
|
529
580
|
*/
|
|
530
581
|
declare function getAllPairsShortestPaths<N, E>(graph: Graph<N, E>, opts?: AllPairsShortestPathsOptions<E>): GraphPath<N, E>[];
|
|
582
|
+
/**
|
|
583
|
+
* Returns a shortest path using A* search with an admissible heuristic.
|
|
584
|
+
* More efficient than Dijkstra when a good heuristic is available.
|
|
585
|
+
*
|
|
586
|
+
* **O((V + E) log V)** time with a good heuristic; degrades to Dijkstra
|
|
587
|
+
* with `heuristic: () => 0`.
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* ```ts
|
|
591
|
+
* import { createGraph, getAStarPath } from '@statelyai/graph';
|
|
592
|
+
*
|
|
593
|
+
* const graph = createGraph({
|
|
594
|
+
* nodes: [
|
|
595
|
+
* { id: 'a', x: 0, y: 0 },
|
|
596
|
+
* { id: 'b', x: 1, y: 0 },
|
|
597
|
+
* { id: 'c', x: 1, y: 1 },
|
|
598
|
+
* ],
|
|
599
|
+
* edges: [
|
|
600
|
+
* { id: 'ab', sourceId: 'a', targetId: 'b', weight: 1 },
|
|
601
|
+
* { id: 'bc', sourceId: 'b', targetId: 'c', weight: 1 },
|
|
602
|
+
* { id: 'ac', sourceId: 'a', targetId: 'c', weight: 3 },
|
|
603
|
+
* ],
|
|
604
|
+
* });
|
|
605
|
+
*
|
|
606
|
+
* const path = getAStarPath(graph, {
|
|
607
|
+
* from: 'a',
|
|
608
|
+
* to: 'c',
|
|
609
|
+
* heuristic: (nodeId) => {
|
|
610
|
+
* const node = graph.nodes.find(n => n.id === nodeId)!;
|
|
611
|
+
* const target = graph.nodes.find(n => n.id === 'c')!;
|
|
612
|
+
* return Math.abs(node.x! - target.x!) + Math.abs(node.y! - target.y!);
|
|
613
|
+
* },
|
|
614
|
+
* });
|
|
615
|
+
* // path: a -> b -> c (weight 2, cheaper than direct a -> c)
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
declare function getAStarPath<N, E>(graph: Graph<N, E>, opts: AStarOptions<E>): GraphPath<N, E> | undefined;
|
|
531
619
|
/**
|
|
532
620
|
* Joins two paths end-to-end. The last node of the head path must equal
|
|
533
621
|
* the source of the tail path (the overlap node).
|
|
@@ -556,4 +644,4 @@ declare function getAllPairsShortestPaths<N, E>(graph: Graph<N, E>, opts?: AllPa
|
|
|
556
644
|
*/
|
|
557
645
|
declare function joinPaths<N, E>(headPath: GraphPath<N, E>, tailPath: GraphPath<N, E>): GraphPath<N, E>;
|
|
558
646
|
//#endregion
|
|
559
|
-
export { bfs, dfs, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getConnectedComponents, getCycles, getMinimumSpanningTree, getPostorder, getPostorders, getPreorder, getPreorders, getShortestPath, getShortestPaths, getSimplePath, getSimplePaths, getStronglyConnectedComponents, getTopologicalSort, hasPath, isAcyclic, isConnected, isTree, joinPaths };
|
|
647
|
+
export { bfs, dfs, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAStarPath, getAllPairsShortestPaths, getConnectedComponents, getCycles, getMinimumSpanningTree, getPostorder, getPostorders, getPreorder, getPreorders, getShortestPath, getShortestPaths, getSimplePath, getSimplePaths, getStronglyConnectedComponents, getTopologicalSort, hasPath, isAcyclic, isConnected, isTree, joinPaths };
|
package/dist/algorithms.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as hasPath, D as joinPaths, E as isTree, S as getTopologicalSort, T as isConnected, _ as getShortestPath, a as genPreorders, b as getSimplePaths, c as getAStarPath, d as getCycles, f as getMinimumSpanningTree, g as getPreorders, h as getPreorder, i as genPostorders, l as getAllPairsShortestPaths, m as getPostorders, n as dfs, o as genShortestPaths, p as getPostorder, r as genCycles, s as genSimplePaths, t as bfs, u as getConnectedComponents, v as getShortestPaths, w as isAcyclic, x as getStronglyConnectedComponents, y as getSimplePath } from "./algorithms-oVD9PYil.mjs";
|
|
2
2
|
|
|
3
|
-
export { bfs, dfs, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAllPairsShortestPaths, getConnectedComponents, getCycles, getMinimumSpanningTree, getPostorder, getPostorders, getPreorder, getPreorders, getShortestPath, getShortestPaths, getSimplePath, getSimplePaths, getStronglyConnectedComponents, getTopologicalSort, hasPath, isAcyclic, isConnected, isTree, joinPaths };
|
|
3
|
+
export { bfs, dfs, genCycles, genPostorders, genPreorders, genShortestPaths, genSimplePaths, getAStarPath, getAllPairsShortestPaths, getConnectedComponents, getCycles, getMinimumSpanningTree, getPostorder, getPostorders, getPreorder, getPreorders, getShortestPath, getShortestPaths, getSimplePath, getSimplePaths, getStronglyConnectedComponents, getTopologicalSort, hasPath, isAcyclic, isConnected, isTree, joinPaths };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as toAdjacencyList, t as fromAdjacencyList } from "./adjacency-list-
|
|
2
|
-
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-
|
|
1
|
+
import { n as toAdjacencyList, t as fromAdjacencyList } from "./adjacency-list-fldj-QAL.mjs";
|
|
2
|
+
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-Br05wXMg.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/converter/index.ts
|
|
5
5
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as GraphFormatConverter, u as Graph } from "../../types-DF-HNw50.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/converter/index.d.ts
|
|
4
4
|
|
|
@@ -18,7 +18,7 @@ import { c as Graph, f as GraphFormatConverter } from "../../types-Bq_fmLwW.mjs"
|
|
|
18
18
|
* const graph = yamlConverter.from(yaml);
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
|
-
declare function createFormatConverter<TSerial>(to: (graph: Graph) => TSerial, from: (input: TSerial) => Graph): GraphFormatConverter<TSerial>;
|
|
21
|
+
declare function createFormatConverter<TSerial, N = any, E = any, G = any>(to: (graph: Graph<N, E, G>) => TSerial, from: (input: TSerial) => Graph<N, E, G>): GraphFormatConverter<TSerial, N, E, G>;
|
|
22
22
|
/**
|
|
23
23
|
* Bidirectional converter for adjacency-list format (`Record<string, string[]>`).
|
|
24
24
|
*
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as createFormatConverter, r as edgeListConverter, t as adjacencyListConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter, r as edgeListConverter, t as adjacencyListConverter } from "../../converter-B5CUD0r9.mjs";
|
|
2
2
|
|
|
3
3
|
export { adjacencyListConverter, createFormatConverter, edgeListConverter };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { D as VisualGraph, k as VisualGraphFormatConverter } from "../../types-DF-HNw50.mjs";
|
|
2
|
+
import { ElkEdge, ElkEdgeSection, ElkExtendedEdge, ElkGraphElement, ElkLabel, ElkNode, ElkNode as ElkNode$1, ElkPoint, ElkPort, ElkPrimitiveEdge, ElkShape, LayoutOptions } from "elkjs/lib/elk-api";
|
|
3
|
+
|
|
4
|
+
//#region src/formats/elk/index.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Converts a visual graph to ELK JSON format.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { createVisualGraph } from '@statelyai/graph';
|
|
12
|
+
* import { toELK } from '@statelyai/graph/elk';
|
|
13
|
+
*
|
|
14
|
+
* const graph = createVisualGraph({
|
|
15
|
+
* nodes: [
|
|
16
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
17
|
+
* { id: 'b', x: 200, y: 0, width: 100, height: 50 },
|
|
18
|
+
* ],
|
|
19
|
+
* edges: [{ id: 'e1', sourceId: 'a', targetId: 'b' }],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const elk = toELK(graph);
|
|
23
|
+
* // { id: '', children: [...], edges: [...] }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
declare function toELK(graph: VisualGraph): ElkNode$1;
|
|
27
|
+
/**
|
|
28
|
+
* Parses an ELK JSON node into a visual graph.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { fromELK } from '@statelyai/graph/elk';
|
|
33
|
+
*
|
|
34
|
+
* const graph = fromELK({
|
|
35
|
+
* id: 'root',
|
|
36
|
+
* children: [
|
|
37
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
38
|
+
* { id: 'b', x: 200, y: 0, width: 100, height: 50 },
|
|
39
|
+
* ],
|
|
40
|
+
* edges: [{ id: 'e1', sources: ['a'], targets: ['b'] }],
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* graph.nodes; // [{id: 'a', x: 0, y: 0, ...}, {id: 'b', x: 200, ...}]
|
|
44
|
+
* graph.edges; // [{sourceId: 'a', targetId: 'b', ...}]
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function fromELK(elkRoot: ElkNode$1): VisualGraph;
|
|
48
|
+
/**
|
|
49
|
+
* Bidirectional converter for ELK JSON format.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { elkConverter } from '@statelyai/graph/elk';
|
|
54
|
+
*
|
|
55
|
+
* const elk = elkConverter.to(graph);
|
|
56
|
+
* const roundTripped = elkConverter.from(elk);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare const elkConverter: VisualGraphFormatConverter<ElkNode$1>;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkLabel, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkShape, type LayoutOptions, elkConverter, fromELK, toELK };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { getChildren } from "../../queries.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/elk/index.ts
|
|
4
|
+
const DIRECTION_TO_ELK = {
|
|
5
|
+
down: "DOWN",
|
|
6
|
+
up: "UP",
|
|
7
|
+
right: "RIGHT",
|
|
8
|
+
left: "LEFT"
|
|
9
|
+
};
|
|
10
|
+
const ELK_TO_DIRECTION = {
|
|
11
|
+
DOWN: "down",
|
|
12
|
+
UP: "up",
|
|
13
|
+
RIGHT: "right",
|
|
14
|
+
LEFT: "left"
|
|
15
|
+
};
|
|
16
|
+
function convertEdge(edge) {
|
|
17
|
+
const elkEdge = {
|
|
18
|
+
id: edge.id,
|
|
19
|
+
sources: [edge.sourceId],
|
|
20
|
+
targets: [edge.targetId]
|
|
21
|
+
};
|
|
22
|
+
if (edge.label) elkEdge.labels = [{ text: edge.label }];
|
|
23
|
+
return elkEdge;
|
|
24
|
+
}
|
|
25
|
+
function convertNode(graph, node) {
|
|
26
|
+
const elkNode = {
|
|
27
|
+
id: node.id,
|
|
28
|
+
x: node.x,
|
|
29
|
+
y: node.y,
|
|
30
|
+
width: node.width,
|
|
31
|
+
height: node.height
|
|
32
|
+
};
|
|
33
|
+
if (node.label) elkNode.labels = [{ text: node.label }];
|
|
34
|
+
const children = getChildren(graph, node.id);
|
|
35
|
+
if (children.length > 0) {
|
|
36
|
+
elkNode.children = children.map((child) => convertNode(graph, child));
|
|
37
|
+
const descendantIds = /* @__PURE__ */ new Set();
|
|
38
|
+
collectDescendants(graph, node.id, descendantIds);
|
|
39
|
+
const innerEdges = graph.edges.filter((e) => descendantIds.has(e.sourceId) && descendantIds.has(e.targetId));
|
|
40
|
+
if (innerEdges.length > 0) elkNode.edges = innerEdges.map(convertEdge);
|
|
41
|
+
}
|
|
42
|
+
return elkNode;
|
|
43
|
+
}
|
|
44
|
+
function collectDescendants(graph, nodeId, set) {
|
|
45
|
+
const children = getChildren(graph, nodeId);
|
|
46
|
+
for (const child of children) {
|
|
47
|
+
set.add(child.id);
|
|
48
|
+
collectDescendants(graph, child.id, set);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Converts a visual graph to ELK JSON format.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { createVisualGraph } from '@statelyai/graph';
|
|
57
|
+
* import { toELK } from '@statelyai/graph/elk';
|
|
58
|
+
*
|
|
59
|
+
* const graph = createVisualGraph({
|
|
60
|
+
* nodes: [
|
|
61
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
62
|
+
* { id: 'b', x: 200, y: 0, width: 100, height: 50 },
|
|
63
|
+
* ],
|
|
64
|
+
* edges: [{ id: 'e1', sourceId: 'a', targetId: 'b' }],
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* const elk = toELK(graph);
|
|
68
|
+
* // { id: '', children: [...], edges: [...] }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
function toELK(graph) {
|
|
72
|
+
const root = { id: graph.id };
|
|
73
|
+
const elkDir = DIRECTION_TO_ELK[graph.direction];
|
|
74
|
+
if (elkDir) root.layoutOptions = { "elk.direction": elkDir };
|
|
75
|
+
const roots = getChildren(graph, null);
|
|
76
|
+
if (roots.length > 0) root.children = roots.map((node) => convertNode(graph, node));
|
|
77
|
+
const allInnerEdgeIds = /* @__PURE__ */ new Set();
|
|
78
|
+
for (const node of graph.nodes) if (getChildren(graph, node.id).length > 0) {
|
|
79
|
+
const descendantIds = /* @__PURE__ */ new Set();
|
|
80
|
+
collectDescendants(graph, node.id, descendantIds);
|
|
81
|
+
for (const edge of graph.edges) if (descendantIds.has(edge.sourceId) && descendantIds.has(edge.targetId)) allInnerEdgeIds.add(edge.id);
|
|
82
|
+
}
|
|
83
|
+
const rootEdges = graph.edges.filter((e) => !allInnerEdgeIds.has(e.id));
|
|
84
|
+
if (rootEdges.length > 0) root.edges = rootEdges.map(convertEdge);
|
|
85
|
+
return root;
|
|
86
|
+
}
|
|
87
|
+
function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx) {
|
|
88
|
+
if (elkNode.children) for (const child of elkNode.children) {
|
|
89
|
+
const label = child.labels?.[0]?.text ?? "";
|
|
90
|
+
const node = {
|
|
91
|
+
type: "node",
|
|
92
|
+
id: child.id,
|
|
93
|
+
parentId,
|
|
94
|
+
initialNodeId: null,
|
|
95
|
+
label,
|
|
96
|
+
data: void 0,
|
|
97
|
+
x: child.x ?? 0,
|
|
98
|
+
y: child.y ?? 0,
|
|
99
|
+
width: child.width ?? 0,
|
|
100
|
+
height: child.height ?? 0
|
|
101
|
+
};
|
|
102
|
+
nodes.push(node);
|
|
103
|
+
flattenElkNodes(child, child.id, nodes, edges, edgeIdx);
|
|
104
|
+
}
|
|
105
|
+
if (elkNode.edges) for (const elkEdge of elkNode.edges) for (const source of elkEdge.sources) for (const target of elkEdge.targets) {
|
|
106
|
+
const edge = {
|
|
107
|
+
type: "edge",
|
|
108
|
+
id: elkEdge.id ?? `e${edgeIdx.value++}`,
|
|
109
|
+
sourceId: source,
|
|
110
|
+
targetId: target,
|
|
111
|
+
label: elkEdge.labels?.[0]?.text ?? "",
|
|
112
|
+
data: void 0,
|
|
113
|
+
x: 0,
|
|
114
|
+
y: 0,
|
|
115
|
+
width: 0,
|
|
116
|
+
height: 0
|
|
117
|
+
};
|
|
118
|
+
edges.push(edge);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Parses an ELK JSON node into a visual graph.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* import { fromELK } from '@statelyai/graph/elk';
|
|
127
|
+
*
|
|
128
|
+
* const graph = fromELK({
|
|
129
|
+
* id: 'root',
|
|
130
|
+
* children: [
|
|
131
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
132
|
+
* { id: 'b', x: 200, y: 0, width: 100, height: 50 },
|
|
133
|
+
* ],
|
|
134
|
+
* edges: [{ id: 'e1', sources: ['a'], targets: ['b'] }],
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* graph.nodes; // [{id: 'a', x: 0, y: 0, ...}, {id: 'b', x: 200, ...}]
|
|
138
|
+
* graph.edges; // [{sourceId: 'a', targetId: 'b', ...}]
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
function fromELK(elkRoot) {
|
|
142
|
+
const nodes = [];
|
|
143
|
+
const edges = [];
|
|
144
|
+
flattenElkNodes(elkRoot, null, nodes, edges, { value: 0 });
|
|
145
|
+
const seenEdges = /* @__PURE__ */ new Map();
|
|
146
|
+
for (const edge of edges) if (!seenEdges.has(edge.id)) seenEdges.set(edge.id, edge);
|
|
147
|
+
const elkDir = elkRoot.layoutOptions?.["elk.direction"];
|
|
148
|
+
const direction = (elkDir ? ELK_TO_DIRECTION[elkDir] : void 0) ?? "down";
|
|
149
|
+
return {
|
|
150
|
+
id: elkRoot.id,
|
|
151
|
+
type: "directed",
|
|
152
|
+
initialNodeId: null,
|
|
153
|
+
nodes,
|
|
154
|
+
edges: [...seenEdges.values()],
|
|
155
|
+
data: void 0,
|
|
156
|
+
direction
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Bidirectional converter for ELK JSON format.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* import { elkConverter } from '@statelyai/graph/elk';
|
|
165
|
+
*
|
|
166
|
+
* const elk = elkConverter.to(graph);
|
|
167
|
+
* const roundTripped = elkConverter.from(elk);
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
const elkConverter = {
|
|
171
|
+
to: toELK,
|
|
172
|
+
from: fromELK
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
//#endregion
|
|
176
|
+
export { elkConverter, fromELK, toELK };
|