@statelyai/graph 0.1.0 → 0.3.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 +65 -15
- package/dist/{adjacency-list-CXpOCibq.mjs → adjacency-list-A4_Eiwj3.mjs} +1 -1
- package/dist/{algorithms-R35X6ro4.mjs → algorithms-DBU7nmIV.mjs} +83 -2
- package/dist/algorithms.d.mts +10 -2
- package/dist/algorithms.mjs +2 -2
- package/dist/converter-DnbeyE_p.mjs +33 -0
- package/dist/{edge-list-BRujEnnU.mjs → edge-list-DuHMz8hf.mjs} +1 -1
- package/dist/{adjacency-list-DW-lAUe8.d.mts → formats/adjacency-list/index.d.mts} +3 -3
- package/dist/formats/adjacency-list/index.mjs +3 -0
- package/dist/formats/converter/index.d.mts +27 -0
- package/dist/formats/converter/index.mjs +3 -0
- package/dist/formats/cytoscape/index.d.mts +35 -0
- package/dist/formats/cytoscape/index.mjs +87 -0
- package/dist/formats/d3/index.d.mts +22 -0
- package/dist/formats/d3/index.mjs +65 -0
- package/dist/formats/dot/index.d.mts +9 -0
- package/dist/formats/dot/index.mjs +235 -0
- package/dist/{edge-list-CJmfoNu2.d.mts → formats/edge-list/index.d.mts} +3 -3
- 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 +9 -0
- package/dist/formats/gml/index.mjs +236 -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 +30 -0
- package/dist/formats/jgf/index.mjs +85 -0
- package/dist/formats/mermaid/index.d.mts +188 -0
- package/dist/formats/mermaid/index.mjs +1898 -0
- package/dist/formats/tgf/index.d.mts +9 -0
- package/dist/formats/tgf/index.mjs +67 -0
- package/dist/index.d.mts +14 -9
- package/dist/index.mjs +5 -9
- package/dist/queries.d.mts +78 -2
- package/dist/queries.mjs +121 -2
- package/dist/{types-XV3S5Jnh.d.mts → types-B6Tpeerk.d.mts} +36 -1
- package/package.json +43 -17
- package/dist/dot-BRtq3e3c.mjs +0 -59
- package/dist/dot-HmJeUMsj.d.mts +0 -6
- 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/{indexing-BHg1VhqN.mjs → indexing-BFFVMnjF.mjs} +0 -0
package/README.md
CHANGED
|
@@ -4,6 +4,18 @@ A TypeScript graph library built on plain JSON objects. Supports directed/undire
|
|
|
4
4
|
|
|
5
5
|
Made from our experience at [stately.ai](https://stately.ai), where we build visual tools for complex systems.
|
|
6
6
|
|
|
7
|
+
## Why this library?
|
|
8
|
+
|
|
9
|
+
Graph file formats (GEXF, GraphML) define how to _store_ graphs. Visualization libraries (Cytoscape.js, D3) define how to _render_ them. Neither gives you a good way to _work with_ them in between.
|
|
10
|
+
|
|
11
|
+
This library is the computational layer: plain JSON objects in, algorithms and mutations, plain JSON objects out. No classes, no DOM, no rendering engine — just data and functions.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
GEXF file → fromGEXF() → Graph → run algorithms, mutate → toCytoscapeJSON() → render
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Your `Graph` is a plain object that survives `JSON.stringify`, `structuredClone`, `postMessage`, and `localStorage` without adapters. Format converters are the I/O ports — read from any supported format, do your work, export to whatever your renderer or database expects.
|
|
18
|
+
|
|
7
19
|
## Install
|
|
8
20
|
|
|
9
21
|
```bash
|
|
@@ -77,22 +89,41 @@ const diagram = createVisualGraph({
|
|
|
77
89
|
});
|
|
78
90
|
```
|
|
79
91
|
|
|
80
|
-
###
|
|
92
|
+
### Format Conversion
|
|
81
93
|
|
|
82
94
|
```ts
|
|
83
|
-
import {
|
|
95
|
+
import { toCytoscapeJSON } from '@statelyai/graph/cytoscape';
|
|
96
|
+
import { fromJGF } from '@statelyai/graph/jgf';
|
|
97
|
+
import { toD3Graph } from '@statelyai/graph/d3';
|
|
98
|
+
import { toDOT } from '@statelyai/graph/dot';
|
|
99
|
+
import { toGraphML } from '@statelyai/graph/graphml';
|
|
100
|
+
import { fromGEXF } from '@statelyai/graph/gexf';
|
|
101
|
+
|
|
102
|
+
// Export to web visualization libraries
|
|
103
|
+
const cytoData = toCytoscapeJSON(graph); // Cytoscape.js JSON (compound graphs preserved)
|
|
104
|
+
const d3Data = toD3Graph(graph); // D3.js { nodes, links }
|
|
105
|
+
|
|
106
|
+
// Export to text formats
|
|
107
|
+
const dot = toDOT(graph); // Graphviz DOT
|
|
108
|
+
const xml = toGraphML(graph); // GraphML XML
|
|
109
|
+
|
|
110
|
+
// Import from any format
|
|
111
|
+
const g1 = fromJGF(jsonGraphData); // JSON Graph Format
|
|
112
|
+
const g2 = fromGEXF(gexfXmlString); // GEXF (Gephi)
|
|
113
|
+
```
|
|
84
114
|
|
|
85
|
-
|
|
86
|
-
// Logs a Graphviz DOT string
|
|
115
|
+
Each bidirectional format also has a converter object for a unified interface:
|
|
87
116
|
|
|
88
|
-
|
|
89
|
-
|
|
117
|
+
```ts
|
|
118
|
+
import { createFormatConverter } from '@statelyai/graph';
|
|
119
|
+
import { cytoscapeConverter } from '@statelyai/graph/cytoscape';
|
|
90
120
|
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
// Use a built-in converter
|
|
122
|
+
const cyto = cytoscapeConverter.to(graph);
|
|
123
|
+
const back = cytoscapeConverter.from(cyto);
|
|
93
124
|
|
|
94
|
-
|
|
95
|
-
|
|
125
|
+
// Create your own
|
|
126
|
+
const myConverter = createFormatConverter(myToFn, myFromFn);
|
|
96
127
|
```
|
|
97
128
|
|
|
98
129
|
## API
|
|
@@ -176,15 +207,34 @@ console.log(toEdgeList(graph));
|
|
|
176
207
|
|
|
177
208
|
Generator variants: `genShortestPaths`, `genSimplePaths`, `genCycles`, `genPreorders`, `genPostorders`.
|
|
178
209
|
|
|
179
|
-
### Transforms
|
|
210
|
+
### Transforms
|
|
180
211
|
|
|
181
212
|
| Function | Description |
|
|
182
213
|
|----------|-------------|
|
|
183
214
|
| `flatten(graph)` | Decompose hierarchy into flat leaf-node graph |
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
215
|
+
|
|
216
|
+
### Formats
|
|
217
|
+
|
|
218
|
+
Import format converters from subpaths (for example, `@statelyai/graph/dot` or `@statelyai/graph/mermaid`).
|
|
219
|
+
|
|
220
|
+
| Format | Export | Import | Compound? | Notes |
|
|
221
|
+
|--------|--------|--------|-----------|-------|
|
|
222
|
+
| **Cytoscape.js JSON** | `toCytoscapeJSON` | `fromCytoscapeJSON` | Yes | `parent` maps to `parentId` |
|
|
223
|
+
| **D3.js JSON** | `toD3Graph` | `fromD3Graph` | No | `{ nodes, links }` for force layouts |
|
|
224
|
+
| **JSON Graph Format** | `toJGF` | `fromJGF` | Yes | Formal spec, metadata-extensible |
|
|
225
|
+
| **GEXF** | `toGEXF` | `fromGEXF` | Yes | Gephi native, `pid` hierarchy, viz module |
|
|
226
|
+
| **GraphML** | `toGraphML` | `fromGraphML` | Yes | XML standard, requires `fast-xml-parser` |
|
|
227
|
+
| **GML** | `toGML` | `fromGML` | Yes | Nested node blocks for hierarchy |
|
|
228
|
+
| **TGF** | `toTGF` | `fromTGF` | No | Minimal (id + label only) |
|
|
229
|
+
| **DOT** | `toDOT` | `fromDOT` | Yes (subgraphs) | Graphviz DOT (`dotparser` peer dep) |
|
|
230
|
+
| **Mermaid** | `toMermaid*` | `fromMermaid*` | Varies by diagram | Sequence, flowchart, state, class, ER, mindmap, block |
|
|
231
|
+
| **Adjacency list** | `toAdjacencyList` | `fromAdjacencyList` | No | `Record<string, string[]>` |
|
|
232
|
+
| **Edge list** | `toEdgeList` | `fromEdgeList` | No | `[source, target][]` |
|
|
233
|
+
|
|
234
|
+
Optional peer deps by format:
|
|
235
|
+
- `@statelyai/graph/gexf` and `@statelyai/graph/graphml` use `fast-xml-parser`
|
|
236
|
+
- `@statelyai/graph/dot` uses `dotparser`
|
|
237
|
+
- Other formats are dependency-free
|
|
188
238
|
|
|
189
239
|
## License
|
|
190
240
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as indexUpdateEdgeEndpoints, i as indexReparentNode, n as indexAddEdge, o as invalidateIndex, r as indexAddNode, t as getIndex } from "./indexing-
|
|
1
|
+
import { a as indexUpdateEdgeEndpoints, i as indexReparentNode, n as indexAddEdge, o as invalidateIndex, r as indexAddNode, t as getIndex } from "./indexing-BFFVMnjF.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/graph.ts
|
|
4
4
|
function resolveNode(config) {
|
|
@@ -73,6 +73,72 @@ function createVisualGraph(config) {
|
|
|
73
73
|
}))
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a graph by BFS exploration of a transition function.
|
|
78
|
+
* Each unique state becomes a node; each (state, event) → nextState becomes an edge.
|
|
79
|
+
*
|
|
80
|
+
* - Node IDs are determined by `serializeState` (default: `JSON.stringify`).
|
|
81
|
+
* - Edge IDs use the format `sourceId|serializedEvent|targetId` for uniqueness
|
|
82
|
+
* and debuggability. Edge labels are just the serialized event string.
|
|
83
|
+
*/
|
|
84
|
+
function createGraphFromTransition(transition, options) {
|
|
85
|
+
const serializeState = options.serializeState ?? JSON.stringify;
|
|
86
|
+
const serializeEvent = options.serializeEvent ?? JSON.stringify;
|
|
87
|
+
const limit = options.limit ?? Infinity;
|
|
88
|
+
const getEvents = typeof options.events === "function" ? options.events : () => options.events;
|
|
89
|
+
const nodes = [];
|
|
90
|
+
const edges = [];
|
|
91
|
+
const visited = /* @__PURE__ */ new Set();
|
|
92
|
+
const edgeSet = /* @__PURE__ */ new Set();
|
|
93
|
+
const queue = [options.initialState];
|
|
94
|
+
const initialStateId = serializeState(options.initialState);
|
|
95
|
+
visited.add(initialStateId);
|
|
96
|
+
nodes.push({
|
|
97
|
+
id: initialStateId,
|
|
98
|
+
label: initialStateId,
|
|
99
|
+
data: options.initialState
|
|
100
|
+
});
|
|
101
|
+
let iterations = 0;
|
|
102
|
+
while (queue.length > 0) {
|
|
103
|
+
const state = queue.shift();
|
|
104
|
+
const stateId = serializeState(state);
|
|
105
|
+
if (++iterations > limit) throw new Error("Traversal limit exceeded");
|
|
106
|
+
if (options.stopWhen?.(state)) continue;
|
|
107
|
+
const events = getEvents(state);
|
|
108
|
+
for (const event of events) {
|
|
109
|
+
const nextState = transition(state, event);
|
|
110
|
+
const nextStateId = serializeState(nextState);
|
|
111
|
+
const eventStr = serializeEvent(event);
|
|
112
|
+
if (!visited.has(nextStateId)) {
|
|
113
|
+
visited.add(nextStateId);
|
|
114
|
+
nodes.push({
|
|
115
|
+
id: nextStateId,
|
|
116
|
+
label: nextStateId,
|
|
117
|
+
data: nextState
|
|
118
|
+
});
|
|
119
|
+
queue.push(nextState);
|
|
120
|
+
}
|
|
121
|
+
const edgeKey = `${stateId}|${eventStr}|${nextStateId}`;
|
|
122
|
+
if (!edgeSet.has(edgeKey)) {
|
|
123
|
+
edgeSet.add(edgeKey);
|
|
124
|
+
edges.push({
|
|
125
|
+
id: edgeKey,
|
|
126
|
+
sourceId: stateId,
|
|
127
|
+
targetId: nextStateId,
|
|
128
|
+
label: eventStr,
|
|
129
|
+
data: event
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return createGraph({
|
|
135
|
+
id: options.id ?? "",
|
|
136
|
+
type: "directed",
|
|
137
|
+
initialNodeId: initialStateId,
|
|
138
|
+
nodes,
|
|
139
|
+
edges
|
|
140
|
+
});
|
|
141
|
+
}
|
|
76
142
|
/** Get a node by id, or `undefined` if not found. */
|
|
77
143
|
function getNode(graph, id) {
|
|
78
144
|
const arrayIdx = getIndex(graph).nodeById.get(id);
|
|
@@ -1192,6 +1258,21 @@ function fwReconstruct(graph, prev, idxOf, nodeIds, sourceNode, sourceIdx, targe
|
|
|
1192
1258
|
}
|
|
1193
1259
|
return results;
|
|
1194
1260
|
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Joins two paths end-to-end. The last node of the head path must equal
|
|
1263
|
+
* the source of the tail path (the overlap node).
|
|
1264
|
+
*
|
|
1265
|
+
* Steps are concatenated: head.steps ++ tail.steps (tail already starts
|
|
1266
|
+
* from the overlap node, so no slicing is needed).
|
|
1267
|
+
*/
|
|
1268
|
+
function joinPaths(headPath, tailPath) {
|
|
1269
|
+
const headEnd = headPath.steps.length > 0 ? headPath.steps[headPath.steps.length - 1].node : headPath.source;
|
|
1270
|
+
if (headEnd.id !== tailPath.source.id) throw new Error(`Paths cannot be joined: head path ends at "${headEnd.id}" but tail path starts at "${tailPath.source.id}"`);
|
|
1271
|
+
return {
|
|
1272
|
+
source: headPath.source,
|
|
1273
|
+
steps: [...headPath.steps, ...tailPath.steps]
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1195
1276
|
|
|
1196
1277
|
//#endregion
|
|
1197
|
-
export {
|
|
1278
|
+
export { addNode as A, hasNode as B, isAcyclic as C, GraphInstance as D, joinPaths as E, deleteEntities as F, updateEntities as H, deleteNode as I, getEdge as L, createGraphFromTransition as M, createVisualGraph as N, addEdge as O, deleteEdge as P, getNode as R, hasPath as S, isTree as T, updateNode as U, updateEdge as V, getShortestPaths as _, genPreorders as a, getStronglyConnectedComponents as b, getAllPairsShortestPaths as c, getMinimumSpanningTree as d, getPostorder as f, getShortestPath as g, getPreorders as h, genPostorders as i, createGraph as j, addEntities as k, getConnectedComponents as l, getPreorder as m, dfs as n, genShortestPaths as o, getPostorders as p, genCycles as r, genSimplePaths as s, bfs as t, getCycles as u, getSimplePath as v, isConnected as w, getTopologicalSort as x, getSimplePaths as y, hasEdge as z };
|
package/dist/algorithms.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as TraversalOptions, _ as MSTOptions, b as PathOptions, c as Graph, h as GraphPath, p as GraphNode, t as AllPairsShortestPathsOptions, x as SinglePathOptions } from "./types-B6Tpeerk.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/algorithms.d.ts
|
|
4
4
|
declare function bfs<N>(graph: Graph<N>, startId: string): Generator<GraphNode<N>>;
|
|
@@ -78,5 +78,13 @@ declare function getMinimumSpanningTree<N, E>(graph: Graph<N, E>, opts?: MSTOpti
|
|
|
78
78
|
* Algorithm 'floyd-warshall': classic O(V³) dynamic programming.
|
|
79
79
|
*/
|
|
80
80
|
declare function getAllPairsShortestPaths<N, E>(graph: Graph<N, E>, opts?: AllPairsShortestPathsOptions<E>): GraphPath<N, E>[];
|
|
81
|
+
/**
|
|
82
|
+
* Joins two paths end-to-end. The last node of the head path must equal
|
|
83
|
+
* the source of the tail path (the overlap node).
|
|
84
|
+
*
|
|
85
|
+
* Steps are concatenated: head.steps ++ tail.steps (tail already starts
|
|
86
|
+
* from the overlap node, so no slicing is needed).
|
|
87
|
+
*/
|
|
88
|
+
declare function joinPaths<N, E>(headPath: GraphPath<N, E>, tailPath: GraphPath<N, E>): GraphPath<N, E>;
|
|
81
89
|
//#endregion
|
|
82
|
-
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 };
|
|
90
|
+
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 };
|
package/dist/algorithms.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as isAcyclic, S as hasPath, T as isTree, _ 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, 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 } from "./algorithms-
|
|
1
|
+
import { C as isAcyclic, E as joinPaths, S as hasPath, T as isTree, _ 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, 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 } from "./algorithms-DBU7nmIV.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 };
|
|
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 };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { n as toAdjacencyList, t as fromAdjacencyList } from "./adjacency-list-A4_Eiwj3.mjs";
|
|
2
|
+
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-DuHMz8hf.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/formats/converter/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a `GraphFormatConverter` from a pair of `to`/`from` functions.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createFormatConverter } from '@statelyai/graph';
|
|
11
|
+
*
|
|
12
|
+
* const yamlConverter = createFormatConverter(
|
|
13
|
+
* (graph) => toYAML(graph),
|
|
14
|
+
* (yaml) => fromYAML(yaml),
|
|
15
|
+
* );
|
|
16
|
+
*
|
|
17
|
+
* const yaml = yamlConverter.to(graph);
|
|
18
|
+
* const graph = yamlConverter.from(yaml);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
function createFormatConverter(to, from) {
|
|
22
|
+
return {
|
|
23
|
+
to,
|
|
24
|
+
from
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Bidirectional converter for adjacency-list format (`Record<string, string[]>`). */
|
|
28
|
+
const adjacencyListConverter = createFormatConverter(toAdjacencyList, fromAdjacencyList);
|
|
29
|
+
/** Bidirectional converter for edge-list format (`[source, target][]`). */
|
|
30
|
+
const edgeListConverter = createFormatConverter(toEdgeList, fromEdgeList);
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { createFormatConverter as n, edgeListConverter as r, adjacencyListConverter as t };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { c as Graph } from "
|
|
1
|
+
import { c as Graph } from "../../types-B6Tpeerk.mjs";
|
|
2
2
|
|
|
3
|
-
//#region src/formats/adjacency-list.d.ts
|
|
3
|
+
//#region src/formats/adjacency-list/index.d.ts
|
|
4
4
|
declare function toAdjacencyList(graph: Graph): Record<string, string[]>;
|
|
5
5
|
declare function fromAdjacencyList(adj: Record<string, string[]>, options?: {
|
|
6
6
|
directed?: boolean;
|
|
7
7
|
id?: string;
|
|
8
8
|
}): Graph;
|
|
9
9
|
//#endregion
|
|
10
|
-
export {
|
|
10
|
+
export { fromAdjacencyList, toAdjacencyList };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { c as Graph, f as GraphFormatConverter } from "../../types-B6Tpeerk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/converter/index.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create a `GraphFormatConverter` from a pair of `to`/`from` functions.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createFormatConverter } from '@statelyai/graph';
|
|
11
|
+
*
|
|
12
|
+
* const yamlConverter = createFormatConverter(
|
|
13
|
+
* (graph) => toYAML(graph),
|
|
14
|
+
* (yaml) => fromYAML(yaml),
|
|
15
|
+
* );
|
|
16
|
+
*
|
|
17
|
+
* const yaml = yamlConverter.to(graph);
|
|
18
|
+
* const graph = yamlConverter.from(yaml);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
declare function createFormatConverter<TSerial>(to: (graph: Graph) => TSerial, from: (input: TSerial) => Graph): GraphFormatConverter<TSerial>;
|
|
22
|
+
/** Bidirectional converter for adjacency-list format (`Record<string, string[]>`). */
|
|
23
|
+
declare const adjacencyListConverter: GraphFormatConverter<Record<string, string[]>>;
|
|
24
|
+
/** Bidirectional converter for edge-list format (`[source, target][]`). */
|
|
25
|
+
declare const edgeListConverter: GraphFormatConverter<[string, string][]>;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { adjacencyListConverter, createFormatConverter, edgeListConverter };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { c as Graph, f as GraphFormatConverter } from "../../types-B6Tpeerk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/cytoscape/index.d.ts
|
|
4
|
+
interface CytoscapeNode {
|
|
5
|
+
data: {
|
|
6
|
+
id: string;
|
|
7
|
+
parent?: string;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
};
|
|
10
|
+
position?: {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
interface CytoscapeEdge {
|
|
16
|
+
data: {
|
|
17
|
+
id: string;
|
|
18
|
+
source: string;
|
|
19
|
+
target: string;
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
interface CytoscapeJSON {
|
|
24
|
+
data?: Record<string, any>;
|
|
25
|
+
elements: {
|
|
26
|
+
nodes: CytoscapeNode[];
|
|
27
|
+
edges: CytoscapeEdge[];
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
declare function toCytoscapeJSON(graph: Graph): CytoscapeJSON;
|
|
31
|
+
declare function fromCytoscapeJSON(cyto: CytoscapeJSON): Graph;
|
|
32
|
+
/** Bidirectional converter for Cytoscape.js JSON format. */
|
|
33
|
+
declare const cytoscapeConverter: GraphFormatConverter<CytoscapeJSON>;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { CytoscapeEdge, CytoscapeJSON, CytoscapeNode, cytoscapeConverter, fromCytoscapeJSON, toCytoscapeJSON };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DnbeyE_p.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/cytoscape/index.ts
|
|
4
|
+
function toCytoscapeJSON(graph) {
|
|
5
|
+
const graphData = {};
|
|
6
|
+
if (graph.id) graphData.id = graph.id;
|
|
7
|
+
graphData.type = graph.type;
|
|
8
|
+
if (graph.initialNodeId !== null) graphData.initialNodeId = graph.initialNodeId;
|
|
9
|
+
if (graph.data !== void 0) graphData.graphData = graph.data;
|
|
10
|
+
if (graph.direction) graphData.direction = graph.direction;
|
|
11
|
+
return {
|
|
12
|
+
...Object.keys(graphData).length > 0 && { data: graphData },
|
|
13
|
+
elements: {
|
|
14
|
+
nodes: graph.nodes.map((n) => {
|
|
15
|
+
const data = { id: n.id };
|
|
16
|
+
if (n.parentId !== null) data.parent = n.parentId;
|
|
17
|
+
if (n.label) data.label = n.label;
|
|
18
|
+
if (n.initialNodeId !== null) data.initialNodeId = n.initialNodeId;
|
|
19
|
+
if (n.data !== void 0) data.nodeData = n.data;
|
|
20
|
+
if (n.width !== void 0) data.width = n.width;
|
|
21
|
+
if (n.height !== void 0) data.height = n.height;
|
|
22
|
+
if (n.shape) data.shape = n.shape;
|
|
23
|
+
if (n.color) data.color = n.color;
|
|
24
|
+
const node = { data };
|
|
25
|
+
if (n.x !== void 0 && n.y !== void 0) node.position = {
|
|
26
|
+
x: n.x,
|
|
27
|
+
y: n.y
|
|
28
|
+
};
|
|
29
|
+
return node;
|
|
30
|
+
}),
|
|
31
|
+
edges: graph.edges.map((e) => {
|
|
32
|
+
const data = {
|
|
33
|
+
id: e.id,
|
|
34
|
+
source: e.sourceId,
|
|
35
|
+
target: e.targetId
|
|
36
|
+
};
|
|
37
|
+
if (e.label) data.label = e.label;
|
|
38
|
+
if (e.data !== void 0) data.edgeData = e.data;
|
|
39
|
+
if (e.color) data.color = e.color;
|
|
40
|
+
return { data };
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function fromCytoscapeJSON(cyto) {
|
|
46
|
+
if (!cyto || typeof cyto !== "object") throw new Error("Cytoscape: expected an object");
|
|
47
|
+
if (!cyto.elements || typeof cyto.elements !== "object") throw new Error("Cytoscape: missing \"elements\" property");
|
|
48
|
+
if (!Array.isArray(cyto.elements.nodes)) throw new Error("Cytoscape: \"elements.nodes\" must be an array");
|
|
49
|
+
if (!Array.isArray(cyto.elements.edges)) throw new Error("Cytoscape: \"elements.edges\" must be an array");
|
|
50
|
+
return {
|
|
51
|
+
id: cyto.data?.id ?? "",
|
|
52
|
+
type: cyto.data?.type === "undirected" ? "undirected" : "directed",
|
|
53
|
+
initialNodeId: cyto.data?.initialNodeId ?? null,
|
|
54
|
+
data: cyto.data?.graphData,
|
|
55
|
+
...cyto.data?.direction && { direction: cyto.data.direction },
|
|
56
|
+
nodes: cyto.elements.nodes.map((n) => ({
|
|
57
|
+
type: "node",
|
|
58
|
+
id: n.data.id,
|
|
59
|
+
parentId: n.data.parent ?? null,
|
|
60
|
+
initialNodeId: n.data.initialNodeId ?? null,
|
|
61
|
+
label: n.data.label ?? "",
|
|
62
|
+
data: n.data.nodeData,
|
|
63
|
+
...n.position && {
|
|
64
|
+
x: n.position.x,
|
|
65
|
+
y: n.position.y
|
|
66
|
+
},
|
|
67
|
+
...n.data.width !== void 0 && { width: n.data.width },
|
|
68
|
+
...n.data.height !== void 0 && { height: n.data.height },
|
|
69
|
+
...n.data.shape && { shape: n.data.shape },
|
|
70
|
+
...n.data.color && { color: n.data.color }
|
|
71
|
+
})),
|
|
72
|
+
edges: cyto.elements.edges.map((e, i) => ({
|
|
73
|
+
type: "edge",
|
|
74
|
+
id: e.data.id ?? `e${i}`,
|
|
75
|
+
sourceId: e.data.source,
|
|
76
|
+
targetId: e.data.target,
|
|
77
|
+
label: e.data.label ?? "",
|
|
78
|
+
data: e.data.edgeData,
|
|
79
|
+
...e.data.color && { color: e.data.color }
|
|
80
|
+
}))
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Bidirectional converter for Cytoscape.js JSON format. */
|
|
84
|
+
const cytoscapeConverter = createFormatConverter(toCytoscapeJSON, fromCytoscapeJSON);
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
export { cytoscapeConverter, fromCytoscapeJSON, toCytoscapeJSON };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { c as Graph, f as GraphFormatConverter } from "../../types-B6Tpeerk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/d3/index.d.ts
|
|
4
|
+
interface D3Node {
|
|
5
|
+
id: string;
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
interface D3Link {
|
|
9
|
+
source: string;
|
|
10
|
+
target: string;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
interface D3Graph {
|
|
14
|
+
nodes: D3Node[];
|
|
15
|
+
links: D3Link[];
|
|
16
|
+
}
|
|
17
|
+
declare function toD3Graph(graph: Graph): D3Graph;
|
|
18
|
+
declare function fromD3Graph(d3: D3Graph): Graph;
|
|
19
|
+
/** Bidirectional converter for D3.js force-directed JSON format. */
|
|
20
|
+
declare const d3Converter: GraphFormatConverter<D3Graph>;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { D3Graph, D3Link, D3Node, d3Converter, fromD3Graph, toD3Graph };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DnbeyE_p.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/d3/index.ts
|
|
4
|
+
function toD3Graph(graph) {
|
|
5
|
+
return {
|
|
6
|
+
nodes: graph.nodes.map((n) => {
|
|
7
|
+
const node = { id: n.id };
|
|
8
|
+
if (n.label) node.label = n.label;
|
|
9
|
+
if (n.data !== void 0) node.data = n.data;
|
|
10
|
+
if (n.x !== void 0) node.x = n.x;
|
|
11
|
+
if (n.y !== void 0) node.y = n.y;
|
|
12
|
+
if (n.color) node.color = n.color;
|
|
13
|
+
if (n.shape) node.shape = n.shape;
|
|
14
|
+
return node;
|
|
15
|
+
}),
|
|
16
|
+
links: graph.edges.map((e) => {
|
|
17
|
+
const link = {
|
|
18
|
+
source: e.sourceId,
|
|
19
|
+
target: e.targetId
|
|
20
|
+
};
|
|
21
|
+
if (e.id) link.id = e.id;
|
|
22
|
+
if (e.label) link.label = e.label;
|
|
23
|
+
if (e.data !== void 0) link.data = e.data;
|
|
24
|
+
if (e.color) link.color = e.color;
|
|
25
|
+
return link;
|
|
26
|
+
})
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function fromD3Graph(d3) {
|
|
30
|
+
if (!d3 || typeof d3 !== "object") throw new Error("D3: expected an object");
|
|
31
|
+
if (!Array.isArray(d3.nodes)) throw new Error("D3: \"nodes\" must be an array");
|
|
32
|
+
if (!Array.isArray(d3.links)) throw new Error("D3: \"links\" must be an array");
|
|
33
|
+
return {
|
|
34
|
+
id: "",
|
|
35
|
+
type: "directed",
|
|
36
|
+
initialNodeId: null,
|
|
37
|
+
data: void 0,
|
|
38
|
+
nodes: d3.nodes.map((n) => ({
|
|
39
|
+
type: "node",
|
|
40
|
+
id: n.id,
|
|
41
|
+
parentId: null,
|
|
42
|
+
initialNodeId: null,
|
|
43
|
+
label: n.label ?? "",
|
|
44
|
+
data: n.data,
|
|
45
|
+
...n.x !== void 0 && { x: n.x },
|
|
46
|
+
...n.y !== void 0 && { y: n.y },
|
|
47
|
+
...n.color && { color: n.color },
|
|
48
|
+
...n.shape && { shape: n.shape }
|
|
49
|
+
})),
|
|
50
|
+
edges: d3.links.map((l, i) => ({
|
|
51
|
+
type: "edge",
|
|
52
|
+
id: l.id ?? `e${i}`,
|
|
53
|
+
sourceId: typeof l.source === "string" ? l.source : l.source.id,
|
|
54
|
+
targetId: typeof l.target === "string" ? l.target : l.target.id,
|
|
55
|
+
label: l.label ?? "",
|
|
56
|
+
data: l.data,
|
|
57
|
+
...l.color && { color: l.color }
|
|
58
|
+
}))
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Bidirectional converter for D3.js force-directed JSON format. */
|
|
62
|
+
const d3Converter = createFormatConverter(toD3Graph, fromD3Graph);
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { d3Converter, fromD3Graph, toD3Graph };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { c as Graph, f as GraphFormatConverter } from "../../types-B6Tpeerk.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/formats/dot/index.d.ts
|
|
4
|
+
declare function toDOT(graph: Graph): string;
|
|
5
|
+
declare function fromDOT(dot: string): Graph;
|
|
6
|
+
/** Bidirectional converter for DOT (Graphviz) format. */
|
|
7
|
+
declare const dotConverter: GraphFormatConverter<string>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { dotConverter, fromDOT, toDOT };
|