@statelyai/graph 0.3.1 → 0.4.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 +12 -11
- package/dist/{algorithms-NWSB2RWj.mjs → algorithms-CnTmuX9t.mjs} +11 -6
- package/dist/algorithms.d.mts +1 -1
- package/dist/algorithms.mjs +1 -1
- package/dist/{converter-CchokMDg.mjs → converter-C5DlzzHs.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 +1 -1
- package/dist/formats/converter/index.mjs +1 -1
- package/dist/formats/cytoscape/index.d.mts +1 -1
- package/dist/formats/cytoscape/index.mjs +4 -4
- 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/gexf/index.d.mts +1 -1
- package/dist/formats/gexf/index.mjs +5 -5
- package/dist/formats/gml/index.d.mts +1 -1
- package/dist/formats/gml/index.mjs +3 -3
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/graphml/index.mjs +2 -2
- package/dist/formats/jgf/index.d.mts +1 -1
- package/dist/formats/jgf/index.mjs +4 -4
- package/dist/formats/mermaid/index.d.mts +1 -1
- package/dist/formats/mermaid/index.mjs +5 -5
- package/dist/formats/tgf/index.d.mts +1 -1
- package/dist/formats/tgf/index.mjs +1 -1
- package/dist/formats/xyflow/index.d.mts +73 -0
- package/dist/formats/xyflow/index.mjs +133 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +5 -5
- package/dist/{indexing-eNDrXdDA.mjs → indexing-DitHphT7.mjs} +6 -5
- package/dist/queries.d.mts +2 -2
- package/dist/queries.mjs +9 -9
- package/dist/{types-BDXC1O5b.d.mts → types-Bq_fmLwW.d.mts} +14 -3
- package/package.json +3 -1
- /package/dist/{adjacency-list-ITO40kmn.mjs → adjacency-list-Bv4tfiM3.mjs} +0 -0
- /package/dist/{edge-list-CgX6bBIF.mjs → edge-list-R1SUbHwe.mjs} +0 -0
package/README.md
CHANGED
|
@@ -4,17 +4,6 @@ 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
8
|
## Install
|
|
20
9
|
|
|
@@ -126,6 +115,18 @@ const back = cytoscapeConverter.from(cyto);
|
|
|
126
115
|
const myConverter = createFormatConverter(myToFn, myFromFn);
|
|
127
116
|
```
|
|
128
117
|
|
|
118
|
+
## Why this library?
|
|
119
|
+
|
|
120
|
+
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.
|
|
121
|
+
|
|
122
|
+
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.
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
GEXF file → fromGEXF() → Graph → run algorithms, mutate → toCytoscapeJSON() → render
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
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.
|
|
129
|
+
|
|
129
130
|
## API
|
|
130
131
|
|
|
131
132
|
### Graph Creation
|
|
@@ -1,12 +1,14 @@
|
|
|
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-DitHphT7.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/graph.ts
|
|
4
4
|
function resolveNode(config) {
|
|
5
|
+
if (!config.id) throw new Error("Node id must be a non-empty string");
|
|
6
|
+
if (config.parentId === "") throw new Error("Node parentId must be a non-empty string");
|
|
5
7
|
const node = {
|
|
6
8
|
type: "node",
|
|
7
9
|
id: config.id,
|
|
8
|
-
parentId: config.parentId ?? null,
|
|
9
|
-
initialNodeId: config.initialNodeId ?? null,
|
|
10
|
+
...config.parentId !== void 0 && { parentId: config.parentId ?? null },
|
|
11
|
+
...config.initialNodeId !== void 0 && { initialNodeId: config.initialNodeId ?? null },
|
|
10
12
|
label: config.label ?? "",
|
|
11
13
|
data: config.data
|
|
12
14
|
};
|
|
@@ -20,6 +22,9 @@ function resolveNode(config) {
|
|
|
20
22
|
return node;
|
|
21
23
|
}
|
|
22
24
|
function resolveEdge(config) {
|
|
25
|
+
if (!config.id) throw new Error("Edge id must be a non-empty string");
|
|
26
|
+
if (!config.sourceId) throw new Error("Edge sourceId must be a non-empty string");
|
|
27
|
+
if (!config.targetId) throw new Error("Edge targetId must be a non-empty string");
|
|
23
28
|
const edge = {
|
|
24
29
|
type: "edge",
|
|
25
30
|
id: config.id,
|
|
@@ -251,10 +256,10 @@ function hasEdge(graph, id) {
|
|
|
251
256
|
* ```
|
|
252
257
|
*/
|
|
253
258
|
function addNode(graph, config) {
|
|
259
|
+
const node = resolveNode(config);
|
|
254
260
|
const idx = getIndex(graph);
|
|
255
261
|
if (idx.nodeById.has(config.id)) throw new Error(`Node "${config.id}" already exists`);
|
|
256
|
-
if (config.parentId
|
|
257
|
-
const node = resolveNode(config);
|
|
262
|
+
if (config.parentId && !idx.nodeById.has(config.parentId)) throw new Error(`Parent node "${config.parentId}" does not exist`);
|
|
258
263
|
indexAddNode(idx, node, graph.nodes.push(node) - 1);
|
|
259
264
|
return node;
|
|
260
265
|
}
|
|
@@ -270,11 +275,11 @@ function addNode(graph, config) {
|
|
|
270
275
|
* ```
|
|
271
276
|
*/
|
|
272
277
|
function addEdge(graph, config) {
|
|
278
|
+
const edge = resolveEdge(config);
|
|
273
279
|
const idx = getIndex(graph);
|
|
274
280
|
if (idx.edgeById.has(config.id)) throw new Error(`Edge "${config.id}" already exists`);
|
|
275
281
|
if (!idx.nodeById.has(config.sourceId)) throw new Error(`Source node "${config.sourceId}" does not exist`);
|
|
276
282
|
if (!idx.nodeById.has(config.targetId)) throw new Error(`Target node "${config.targetId}" does not exist`);
|
|
277
|
-
const edge = resolveEdge(config);
|
|
278
283
|
indexAddEdge(idx, edge, graph.edges.push(edge) - 1);
|
|
279
284
|
return edge;
|
|
280
285
|
}
|
package/dist/algorithms.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-
|
|
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-Bq_fmLwW.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/algorithms.d.ts
|
|
4
4
|
|
package/dist/algorithms.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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-
|
|
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-CnTmuX9t.mjs";
|
|
2
2
|
|
|
3
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 };
|
|
@@ -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-Bv4tfiM3.mjs";
|
|
2
|
+
import { n as toEdgeList, t as fromEdgeList } from "./edge-list-R1SUbHwe.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/converter/index.ts
|
|
5
5
|
/**
|
|
@@ -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-C5DlzzHs.mjs";
|
|
2
2
|
|
|
3
3
|
export { adjacencyListConverter, createFormatConverter, edgeListConverter };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-C5DlzzHs.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/cytoscape/index.ts
|
|
4
4
|
/**
|
|
@@ -22,7 +22,7 @@ function toCytoscapeJSON(graph) {
|
|
|
22
22
|
const graphData = {};
|
|
23
23
|
if (graph.id) graphData.id = graph.id;
|
|
24
24
|
graphData.type = graph.type;
|
|
25
|
-
if (graph.initialNodeId
|
|
25
|
+
if (graph.initialNodeId) graphData.initialNodeId = graph.initialNodeId;
|
|
26
26
|
if (graph.data !== void 0) graphData.graphData = graph.data;
|
|
27
27
|
if (graph.direction) graphData.direction = graph.direction;
|
|
28
28
|
return {
|
|
@@ -30,9 +30,9 @@ function toCytoscapeJSON(graph) {
|
|
|
30
30
|
elements: {
|
|
31
31
|
nodes: graph.nodes.map((n) => {
|
|
32
32
|
const data = { id: n.id };
|
|
33
|
-
if (n.parentId
|
|
33
|
+
if (n.parentId) data.parent = n.parentId;
|
|
34
34
|
if (n.label) data.label = n.label;
|
|
35
|
-
if (n.initialNodeId
|
|
35
|
+
if (n.initialNodeId) data.initialNodeId = n.initialNodeId;
|
|
36
36
|
if (n.data !== void 0) data.nodeData = n.data;
|
|
37
37
|
if (n.width !== void 0) data.width = n.width;
|
|
38
38
|
if (n.height !== void 0) data.height = n.height;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-C5DlzzHs.mjs";
|
|
2
2
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/gexf/index.ts
|
|
@@ -32,11 +32,11 @@ function toGEXF(graph) {
|
|
|
32
32
|
}];
|
|
33
33
|
const nodes = graph.nodes.map((n) => {
|
|
34
34
|
const attvalues = [];
|
|
35
|
-
if (n.parentId
|
|
35
|
+
if (n.parentId) attvalues.push({
|
|
36
36
|
"@_for": "a_parentId",
|
|
37
37
|
"@_value": n.parentId
|
|
38
38
|
});
|
|
39
|
-
if (n.initialNodeId
|
|
39
|
+
if (n.initialNodeId) attvalues.push({
|
|
40
40
|
"@_for": "a_initialNodeId",
|
|
41
41
|
"@_value": n.initialNodeId
|
|
42
42
|
});
|
|
@@ -52,7 +52,7 @@ function toGEXF(graph) {
|
|
|
52
52
|
"@_id": n.id,
|
|
53
53
|
"@_label": n.label || n.id
|
|
54
54
|
};
|
|
55
|
-
if (n.parentId
|
|
55
|
+
if (n.parentId) node["@_pid"] = n.parentId;
|
|
56
56
|
if (attvalues.length > 0) node.attvalues = { attvalue: attvalues };
|
|
57
57
|
if (n.color) {
|
|
58
58
|
const hex$1 = n.color.replace("#", "");
|
|
@@ -91,7 +91,7 @@ function toGEXF(graph) {
|
|
|
91
91
|
return edge;
|
|
92
92
|
});
|
|
93
93
|
const graphData = [];
|
|
94
|
-
if (graph.initialNodeId
|
|
94
|
+
if (graph.initialNodeId) graphData.push({
|
|
95
95
|
"@_for": "a_initialNodeId",
|
|
96
96
|
"@_value": graph.initialNodeId
|
|
97
97
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-C5DlzzHs.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/gml/index.ts
|
|
4
4
|
/**
|
|
@@ -30,7 +30,7 @@ function toGML(graph) {
|
|
|
30
30
|
if (graph.id) lines.push(` id ${gmlString(graph.id)}`);
|
|
31
31
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
32
32
|
for (const node of graph.nodes) {
|
|
33
|
-
const pid = node.parentId;
|
|
33
|
+
const pid = node.parentId ?? null;
|
|
34
34
|
if (!childrenMap.has(pid)) childrenMap.set(pid, []);
|
|
35
35
|
childrenMap.get(pid).push(node);
|
|
36
36
|
}
|
|
@@ -38,7 +38,7 @@ function toGML(graph) {
|
|
|
38
38
|
lines.push(`${indent}node [`);
|
|
39
39
|
lines.push(`${indent} id ${gmlString(node.id)}`);
|
|
40
40
|
if (node.label) lines.push(`${indent} label ${gmlString(node.label)}`);
|
|
41
|
-
if (node.initialNodeId
|
|
41
|
+
if (node.initialNodeId) lines.push(`${indent} initialNodeId ${gmlString(node.initialNodeId)}`);
|
|
42
42
|
if (node.data !== void 0) lines.push(`${indent} data ${gmlString(JSON.stringify(node.data))}`);
|
|
43
43
|
if (node.shape) lines.push(`${indent} shape ${gmlString(node.shape)}`);
|
|
44
44
|
if (node.color) lines.push(`${indent} color ${gmlString(node.color)}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-C5DlzzHs.mjs";
|
|
2
2
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/graphml/index.ts
|
|
@@ -72,7 +72,7 @@ function toGraphML(graph) {
|
|
|
72
72
|
"@_key": "label",
|
|
73
73
|
"#text": n.label
|
|
74
74
|
});
|
|
75
|
-
if (n.parentId
|
|
75
|
+
if (n.parentId) data.push({
|
|
76
76
|
"@_key": "parentId",
|
|
77
77
|
"#text": n.parentId
|
|
78
78
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-C5DlzzHs.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/jgf/index.ts
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ import { n as createFormatConverter } from "../../converter-CchokMDg.mjs";
|
|
|
20
20
|
*/
|
|
21
21
|
function toJGF(graph) {
|
|
22
22
|
const metadata = {};
|
|
23
|
-
if (graph.initialNodeId
|
|
23
|
+
if (graph.initialNodeId) metadata.initialNodeId = graph.initialNodeId;
|
|
24
24
|
if (graph.data !== void 0) metadata.data = graph.data;
|
|
25
25
|
if (graph.direction) metadata.direction = graph.direction;
|
|
26
26
|
return { graph: {
|
|
@@ -29,8 +29,8 @@ function toJGF(graph) {
|
|
|
29
29
|
...Object.keys(metadata).length > 0 && { metadata },
|
|
30
30
|
nodes: graph.nodes.map((n) => {
|
|
31
31
|
const meta = {};
|
|
32
|
-
if (n.parentId
|
|
33
|
-
if (n.initialNodeId
|
|
32
|
+
if (n.parentId) meta.parentId = n.parentId;
|
|
33
|
+
if (n.initialNodeId) meta.initialNodeId = n.initialNodeId;
|
|
34
34
|
if (n.data !== void 0) meta.data = n.data;
|
|
35
35
|
if (n.x !== void 0) meta.x = n.x;
|
|
36
36
|
if (n.y !== void 0) meta.y = n.y;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-C5DlzzHs.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/mermaid/shared.ts
|
|
4
4
|
const MERMAID_TO_DIRECTION = {
|
|
@@ -1097,7 +1097,7 @@ function toMermaidFlowchart(graph) {
|
|
|
1097
1097
|
}
|
|
1098
1098
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
1099
1099
|
for (const node of graph.nodes) {
|
|
1100
|
-
const pid = node.parentId;
|
|
1100
|
+
const pid = node.parentId ?? null;
|
|
1101
1101
|
if (!childrenMap.has(pid)) childrenMap.set(pid, []);
|
|
1102
1102
|
childrenMap.get(pid).push(node);
|
|
1103
1103
|
}
|
|
@@ -1304,7 +1304,7 @@ function toMermaidState(graph) {
|
|
|
1304
1304
|
const lines = ["stateDiagram-v2"];
|
|
1305
1305
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
1306
1306
|
for (const node of graph.nodes) {
|
|
1307
|
-
const pid = node.parentId;
|
|
1307
|
+
const pid = node.parentId ?? null;
|
|
1308
1308
|
if (!childrenMap.has(pid)) childrenMap.set(pid, []);
|
|
1309
1309
|
childrenMap.get(pid).push(node);
|
|
1310
1310
|
}
|
|
@@ -1995,7 +1995,7 @@ function toMermaidMindmap(graph) {
|
|
|
1995
1995
|
const lines = ["mindmap"];
|
|
1996
1996
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
1997
1997
|
for (const node of graph.nodes) {
|
|
1998
|
-
const pid = node.parentId;
|
|
1998
|
+
const pid = node.parentId ?? null;
|
|
1999
1999
|
if (!childrenMap.has(pid)) childrenMap.set(pid, []);
|
|
2000
2000
|
childrenMap.get(pid).push(node);
|
|
2001
2001
|
}
|
|
@@ -2198,7 +2198,7 @@ function toMermaidBlock(graph) {
|
|
|
2198
2198
|
if (graph.data?.columns) lines.push(` columns ${graph.data.columns}`);
|
|
2199
2199
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
2200
2200
|
for (const node of graph.nodes) {
|
|
2201
|
-
const pid = node.parentId;
|
|
2201
|
+
const pid = node.parentId ?? null;
|
|
2202
2202
|
if (!childrenMap.has(pid)) childrenMap.set(pid, []);
|
|
2203
2203
|
childrenMap.get(pid).push(node);
|
|
2204
2204
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { D as VisualGraphFormatConverter, T as VisualGraph } from "../../types-Bq_fmLwW.mjs";
|
|
2
|
+
import { EdgeBase, NodeBase } from "@xyflow/system";
|
|
3
|
+
|
|
4
|
+
//#region src/formats/xyflow/index.d.ts
|
|
5
|
+
/** xyflow Node — re-exported from `@xyflow/system`. */
|
|
6
|
+
type XYFlowNode<TNodeData extends Record<string, unknown> = Record<string, unknown>> = NodeBase<TNodeData>;
|
|
7
|
+
/** xyflow Edge — re-exported from `@xyflow/system`. */
|
|
8
|
+
type XYFlowEdge<TEdgeData extends Record<string, unknown> = Record<string, unknown>> = EdgeBase<TEdgeData>;
|
|
9
|
+
interface XYFlow<TNodeData extends Record<string, unknown> = Record<string, unknown>, TEdgeData extends Record<string, unknown> = Record<string, unknown>> {
|
|
10
|
+
nodes: XYFlowNode<TNodeData>[];
|
|
11
|
+
edges: XYFlowEdge<TEdgeData>[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Converts a visual graph to xyflow (React Flow / Svelte Flow) format.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { createVisualGraph } from '@statelyai/graph';
|
|
19
|
+
* import { toXYFlow } from '@statelyai/graph/formats/xyflow';
|
|
20
|
+
*
|
|
21
|
+
* const graph = createVisualGraph({
|
|
22
|
+
* nodes: [
|
|
23
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
24
|
+
* { id: 'b', x: 200, y: 100, width: 100, height: 50 },
|
|
25
|
+
* ],
|
|
26
|
+
* edges: [{ id: 'e0', sourceId: 'a', targetId: 'b' }],
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* const flow = toXYFlow(graph);
|
|
30
|
+
* // { nodes: [...], edges: [...] }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
declare function toXYFlow(graph: VisualGraph): XYFlow;
|
|
34
|
+
/**
|
|
35
|
+
* Parses an xyflow (React Flow / Svelte Flow) object into a visual graph.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { fromXYFlow } from '@statelyai/graph/formats/xyflow';
|
|
40
|
+
*
|
|
41
|
+
* const graph = fromXYFlow({
|
|
42
|
+
* nodes: [
|
|
43
|
+
* { id: 'a', position: { x: 0, y: 0 }, data: {} },
|
|
44
|
+
* { id: 'b', position: { x: 200, y: 100 }, data: {} },
|
|
45
|
+
* ],
|
|
46
|
+
* edges: [{ id: 'e0', source: 'a', target: 'b' }],
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function fromXYFlow(flow: XYFlow): VisualGraph;
|
|
51
|
+
/**
|
|
52
|
+
* Bidirectional converter for xyflow (React Flow / Svelte Flow) format.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { createVisualGraph } from '@statelyai/graph';
|
|
57
|
+
* import { xyflowConverter } from '@statelyai/graph/formats/xyflow';
|
|
58
|
+
*
|
|
59
|
+
* const graph = createVisualGraph({
|
|
60
|
+
* nodes: [
|
|
61
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
62
|
+
* { id: 'b', x: 200, y: 100, width: 100, height: 50 },
|
|
63
|
+
* ],
|
|
64
|
+
* edges: [{ id: 'e0', sourceId: 'a', targetId: 'b' }],
|
|
65
|
+
* });
|
|
66
|
+
*
|
|
67
|
+
* const flow = xyflowConverter.to(graph);
|
|
68
|
+
* const roundTripped = xyflowConverter.from(flow);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare const xyflowConverter: VisualGraphFormatConverter<XYFlow>;
|
|
72
|
+
//#endregion
|
|
73
|
+
export { XYFlow, XYFlowEdge, XYFlowNode, fromXYFlow, toXYFlow, xyflowConverter };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
//#region src/formats/xyflow/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Converts a visual graph to xyflow (React Flow / Svelte Flow) format.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { createVisualGraph } from '@statelyai/graph';
|
|
8
|
+
* import { toXYFlow } from '@statelyai/graph/formats/xyflow';
|
|
9
|
+
*
|
|
10
|
+
* const graph = createVisualGraph({
|
|
11
|
+
* nodes: [
|
|
12
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
13
|
+
* { id: 'b', x: 200, y: 100, width: 100, height: 50 },
|
|
14
|
+
* ],
|
|
15
|
+
* edges: [{ id: 'e0', sourceId: 'a', targetId: 'b' }],
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const flow = toXYFlow(graph);
|
|
19
|
+
* // { nodes: [...], edges: [...] }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function toXYFlow(graph) {
|
|
23
|
+
return {
|
|
24
|
+
nodes: graph.nodes.map((n) => {
|
|
25
|
+
const node = {
|
|
26
|
+
id: n.id,
|
|
27
|
+
position: {
|
|
28
|
+
x: n.x,
|
|
29
|
+
y: n.y
|
|
30
|
+
},
|
|
31
|
+
data: n.data ?? {}
|
|
32
|
+
};
|
|
33
|
+
if (n.parentId) node.parentId = n.parentId;
|
|
34
|
+
if (n.shape) node.type = n.shape;
|
|
35
|
+
if (n.width) node.width = n.width;
|
|
36
|
+
if (n.height) node.height = n.height;
|
|
37
|
+
return node;
|
|
38
|
+
}),
|
|
39
|
+
edges: graph.edges.map((e) => {
|
|
40
|
+
const edge = {
|
|
41
|
+
id: e.id,
|
|
42
|
+
source: e.sourceId,
|
|
43
|
+
target: e.targetId
|
|
44
|
+
};
|
|
45
|
+
if (e.data !== void 0) edge.data = e.data;
|
|
46
|
+
if (e.label) edge.data = {
|
|
47
|
+
...edge.data,
|
|
48
|
+
label: e.label
|
|
49
|
+
};
|
|
50
|
+
return edge;
|
|
51
|
+
})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parses an xyflow (React Flow / Svelte Flow) object into a visual graph.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* import { fromXYFlow } from '@statelyai/graph/formats/xyflow';
|
|
60
|
+
*
|
|
61
|
+
* const graph = fromXYFlow({
|
|
62
|
+
* nodes: [
|
|
63
|
+
* { id: 'a', position: { x: 0, y: 0 }, data: {} },
|
|
64
|
+
* { id: 'b', position: { x: 200, y: 100 }, data: {} },
|
|
65
|
+
* ],
|
|
66
|
+
* edges: [{ id: 'e0', source: 'a', target: 'b' }],
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
function fromXYFlow(flow) {
|
|
71
|
+
if (!flow || typeof flow !== "object") throw new Error("XYFlow: expected an object");
|
|
72
|
+
if (!Array.isArray(flow.nodes)) throw new Error("XYFlow: \"nodes\" must be an array");
|
|
73
|
+
if (!Array.isArray(flow.edges)) throw new Error("XYFlow: \"edges\" must be an array");
|
|
74
|
+
return {
|
|
75
|
+
id: "",
|
|
76
|
+
type: "directed",
|
|
77
|
+
initialNodeId: null,
|
|
78
|
+
data: void 0,
|
|
79
|
+
direction: "down",
|
|
80
|
+
nodes: flow.nodes.map((n) => ({
|
|
81
|
+
type: "node",
|
|
82
|
+
id: n.id,
|
|
83
|
+
parentId: n.parentId ?? null,
|
|
84
|
+
initialNodeId: null,
|
|
85
|
+
label: "",
|
|
86
|
+
data: n.data,
|
|
87
|
+
x: n.position.x,
|
|
88
|
+
y: n.position.y,
|
|
89
|
+
width: n.measured?.width ?? n.width ?? n.initialWidth ?? 0,
|
|
90
|
+
height: n.measured?.height ?? n.height ?? n.initialHeight ?? 0,
|
|
91
|
+
...n.type && { shape: n.type }
|
|
92
|
+
})),
|
|
93
|
+
edges: flow.edges.map((e, i) => ({
|
|
94
|
+
type: "edge",
|
|
95
|
+
id: e.id ?? `e${i}`,
|
|
96
|
+
sourceId: e.source,
|
|
97
|
+
targetId: e.target,
|
|
98
|
+
label: e.data?.label?.toString() ?? "",
|
|
99
|
+
data: e.data,
|
|
100
|
+
x: 0,
|
|
101
|
+
y: 0,
|
|
102
|
+
width: 0,
|
|
103
|
+
height: 0
|
|
104
|
+
}))
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Bidirectional converter for xyflow (React Flow / Svelte Flow) format.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* import { createVisualGraph } from '@statelyai/graph';
|
|
113
|
+
* import { xyflowConverter } from '@statelyai/graph/formats/xyflow';
|
|
114
|
+
*
|
|
115
|
+
* const graph = createVisualGraph({
|
|
116
|
+
* nodes: [
|
|
117
|
+
* { id: 'a', x: 0, y: 0, width: 100, height: 50 },
|
|
118
|
+
* { id: 'b', x: 200, y: 100, width: 100, height: 50 },
|
|
119
|
+
* ],
|
|
120
|
+
* edges: [{ id: 'e0', sourceId: 'a', targetId: 'b' }],
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* const flow = xyflowConverter.to(graph);
|
|
124
|
+
* const roundTripped = xyflowConverter.from(flow);
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
const xyflowConverter = {
|
|
128
|
+
to: toXYFlow,
|
|
129
|
+
from: fromXYFlow
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
export { fromXYFlow, toXYFlow, xyflowConverter };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as TraversalOptions,
|
|
1
|
+
import { C as TraversalOptions, E as VisualGraphConfig, O as VisualNode, S as TransitionOptions, T as VisualGraph, _ as MSTOptions, a as EntitiesConfig, b as PathOptions, c as Graph, d as GraphEdge, f as GraphFormatConverter, g as GraphStep, h as GraphPath, i as EdgeConfig, l as GraphConfig, m as GraphPatch, n as DeleteNodeOptions, o as EntitiesUpdate, p as GraphNode, r as EdgeChange, s as EntityRect, t as AllPairsShortestPathsOptions, u as GraphDiff, v as NodeChange, w as VisualEdge, x as SinglePathOptions, y as NodeConfig } from "./types-Bq_fmLwW.mjs";
|
|
2
2
|
import { 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 } from "./algorithms.mjs";
|
|
3
3
|
import { createFormatConverter } from "./formats/converter/index.mjs";
|
|
4
4
|
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";
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { o as invalidateIndex, t as getIndex } from "./indexing-
|
|
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-
|
|
1
|
+
import { o as invalidateIndex, t as getIndex } from "./indexing-DitHphT7.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-CnTmuX9t.mjs";
|
|
3
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-
|
|
4
|
+
import { n as createFormatConverter } from "./converter-C5DlzzHs.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/diff.ts
|
|
7
7
|
function nodeToConfig(node) {
|
|
8
8
|
const config = { id: node.id };
|
|
9
|
-
if (node.parentId
|
|
10
|
-
if (node.initialNodeId
|
|
9
|
+
if (node.parentId) config.parentId = node.parentId;
|
|
10
|
+
if (node.initialNodeId) config.initialNodeId = node.initialNodeId;
|
|
11
11
|
if (node.label !== "") config.label = node.label;
|
|
12
12
|
if (node.data !== void 0) config.data = node.data;
|
|
13
13
|
if (node.x !== void 0) config.x = node.x;
|
|
@@ -53,7 +53,7 @@ function buildIndex(graph) {
|
|
|
53
53
|
nodeById.set(n.id, i);
|
|
54
54
|
outEdges.set(n.id, []);
|
|
55
55
|
inEdges.set(n.id, []);
|
|
56
|
-
const parent = n.parentId;
|
|
56
|
+
const parent = n.parentId ?? null;
|
|
57
57
|
if (!childNodes.has(parent)) childNodes.set(parent, []);
|
|
58
58
|
childNodes.get(parent).push(n.id);
|
|
59
59
|
}
|
|
@@ -77,7 +77,7 @@ function indexAddNode(idx, node, arrayIndex) {
|
|
|
77
77
|
idx.nodeById.set(node.id, arrayIndex);
|
|
78
78
|
idx.outEdges.set(node.id, []);
|
|
79
79
|
idx.inEdges.set(node.id, []);
|
|
80
|
-
const parent = node.parentId;
|
|
80
|
+
const parent = node.parentId ?? null;
|
|
81
81
|
if (!idx.childNodes.has(parent)) idx.childNodes.set(parent, []);
|
|
82
82
|
idx.childNodes.get(parent).push(node.id);
|
|
83
83
|
idx.nodeCount++;
|
|
@@ -90,13 +90,14 @@ function indexAddEdge(idx, edge, arrayIndex) {
|
|
|
90
90
|
}
|
|
91
91
|
/** Update childNodes index when a node's parentId changes. */
|
|
92
92
|
function indexReparentNode(idx, nodeId, oldParentId, newParentId) {
|
|
93
|
-
const oldSiblings = idx.childNodes.get(oldParentId);
|
|
93
|
+
const oldSiblings = idx.childNodes.get(oldParentId ?? null);
|
|
94
94
|
if (oldSiblings) {
|
|
95
95
|
const pos = oldSiblings.indexOf(nodeId);
|
|
96
96
|
if (pos !== -1) oldSiblings.splice(pos, 1);
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
idx.childNodes.
|
|
98
|
+
const np = newParentId ?? null;
|
|
99
|
+
if (!idx.childNodes.has(np)) idx.childNodes.set(np, []);
|
|
100
|
+
idx.childNodes.get(np).push(nodeId);
|
|
100
101
|
}
|
|
101
102
|
/** Update adjacency lists when an edge's sourceId/targetId changes. */
|
|
102
103
|
function indexUpdateEdgeEndpoints(idx, edgeId, oldSourceId, oldTargetId, newSourceId, newTargetId) {
|
package/dist/queries.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as Graph, d as GraphEdge, p as GraphNode } from "./types-
|
|
1
|
+
import { c as Graph, d as GraphEdge, p as GraphNode } from "./types-Bq_fmLwW.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/queries.d.ts
|
|
4
4
|
|
|
@@ -238,7 +238,7 @@ declare function getAncestors<N>(graph: Graph<N>, nodeId: string): GraphNode<N>[
|
|
|
238
238
|
*/
|
|
239
239
|
declare function getDescendants<N>(graph: Graph<N>, nodeId: string): GraphNode<N>[];
|
|
240
240
|
/**
|
|
241
|
-
* Returns all root nodes (nodes with no parent
|
|
241
|
+
* Returns all root nodes (nodes with no parent).
|
|
242
242
|
*
|
|
243
243
|
* @example
|
|
244
244
|
* ```ts
|
package/dist/queries.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as getIndex } from "./indexing-
|
|
1
|
+
import { t as getIndex } from "./indexing-DitHphT7.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/queries.ts
|
|
4
4
|
/**
|
|
@@ -293,7 +293,7 @@ function getParent(graph, nodeId) {
|
|
|
293
293
|
const ni = idx.nodeById.get(nodeId);
|
|
294
294
|
if (ni === void 0) return void 0;
|
|
295
295
|
const node = graph.nodes[ni];
|
|
296
|
-
if (node.parentId
|
|
296
|
+
if (!node.parentId) return void 0;
|
|
297
297
|
const pi = idx.nodeById.get(node.parentId);
|
|
298
298
|
return pi !== void 0 ? graph.nodes[pi] : void 0;
|
|
299
299
|
}
|
|
@@ -319,7 +319,7 @@ function getAncestors(graph, nodeId) {
|
|
|
319
319
|
let ni = idx.nodeById.get(nodeId);
|
|
320
320
|
if (ni === void 0) return result;
|
|
321
321
|
let current = graph.nodes[ni];
|
|
322
|
-
while (current && current.parentId
|
|
322
|
+
while (current && current.parentId) {
|
|
323
323
|
const pi = idx.nodeById.get(current.parentId);
|
|
324
324
|
if (pi === void 0) break;
|
|
325
325
|
const p = graph.nodes[pi];
|
|
@@ -361,7 +361,7 @@ function getDescendants(graph, nodeId) {
|
|
|
361
361
|
return result;
|
|
362
362
|
}
|
|
363
363
|
/**
|
|
364
|
-
* Returns all root nodes (nodes with no parent
|
|
364
|
+
* Returns all root nodes (nodes with no parent).
|
|
365
365
|
*
|
|
366
366
|
* @example
|
|
367
367
|
* ```ts
|
|
@@ -440,7 +440,7 @@ function getDepth(graph, nodeId) {
|
|
|
440
440
|
let ni = idx.nodeById.get(nodeId);
|
|
441
441
|
if (ni === void 0) return -1;
|
|
442
442
|
let current = graph.nodes[ni];
|
|
443
|
-
while (current.parentId
|
|
443
|
+
while (current.parentId) {
|
|
444
444
|
d++;
|
|
445
445
|
const pi = idx.nodeById.get(current.parentId);
|
|
446
446
|
if (pi === void 0) break;
|
|
@@ -470,7 +470,7 @@ function getSiblings(graph, nodeId) {
|
|
|
470
470
|
const ni = idx.nodeById.get(nodeId);
|
|
471
471
|
if (ni === void 0) return [];
|
|
472
472
|
const node = graph.nodes[ni];
|
|
473
|
-
return (idx.childNodes.get(node.parentId) ?? []).filter((id) => id !== nodeId).map((id) => graph.nodes[idx.nodeById.get(id)]).filter(Boolean);
|
|
473
|
+
return (idx.childNodes.get(node.parentId ?? null) ?? []).filter((id) => id !== nodeId).map((id) => graph.nodes[idx.nodeById.get(id)]).filter(Boolean);
|
|
474
474
|
}
|
|
475
475
|
/**
|
|
476
476
|
* Least Common Ancestor -- deepest proper ancestor of all given nodes.
|
|
@@ -500,7 +500,7 @@ function getLCA(graph, ...nodeIds) {
|
|
|
500
500
|
let ni$1 = idx.nodeById.get(id);
|
|
501
501
|
if (ni$1 === void 0) return result;
|
|
502
502
|
let current = graph.nodes[ni$1];
|
|
503
|
-
while (current.parentId
|
|
503
|
+
while (current.parentId) {
|
|
504
504
|
result.push(current.parentId);
|
|
505
505
|
const pi = idx.nodeById.get(current.parentId);
|
|
506
506
|
if (pi === void 0) break;
|
|
@@ -564,7 +564,7 @@ function getRelativeDistanceMap(graph, parentId) {
|
|
|
564
564
|
let sourceId = null;
|
|
565
565
|
if (parentId !== null) {
|
|
566
566
|
const pi = idx.nodeById.get(parentId);
|
|
567
|
-
if (pi !== void 0) sourceId = graph.nodes[pi].initialNodeId;
|
|
567
|
+
if (pi !== void 0) sourceId = graph.nodes[pi].initialNodeId ?? null;
|
|
568
568
|
} else sourceId = graph.initialNodeId;
|
|
569
569
|
if (!sourceId) return {};
|
|
570
570
|
const siblingSet = new Set(idx.childNodes.get(parentId) ?? []);
|
|
@@ -637,7 +637,7 @@ function getRelativeDistance(graph, nodeId) {
|
|
|
637
637
|
const ni = getIndex(graph).nodeById.get(nodeId);
|
|
638
638
|
if (ni === void 0) return void 0;
|
|
639
639
|
const node = graph.nodes[ni];
|
|
640
|
-
return getRelativeDistanceMap(graph, node.parentId)[nodeId];
|
|
640
|
+
return getRelativeDistanceMap(graph, node.parentId ?? null)[nodeId];
|
|
641
641
|
}
|
|
642
642
|
/**
|
|
643
643
|
* Nodes with no incoming edges (inDegree 0).
|
|
@@ -67,8 +67,8 @@ interface Graph<TNodeData = any, TEdgeData = any, TGraphData = any> {
|
|
|
67
67
|
interface GraphNode<TNodeData = any> {
|
|
68
68
|
type: 'node';
|
|
69
69
|
id: string;
|
|
70
|
-
parentId
|
|
71
|
-
initialNodeId
|
|
70
|
+
parentId?: string | null;
|
|
71
|
+
initialNodeId?: string | null;
|
|
72
72
|
label: string;
|
|
73
73
|
data: TNodeData;
|
|
74
74
|
x?: number;
|
|
@@ -234,6 +234,17 @@ interface GraphFormatConverter<TSerial> {
|
|
|
234
234
|
/** Convert from the serialized format to a Graph. */
|
|
235
235
|
from(input: TSerial): Graph;
|
|
236
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* A bidirectional converter between `VisualGraph` and a serialized format.
|
|
239
|
+
*
|
|
240
|
+
* Use this for formats that carry position/size data (e.g. xyflow, cytoscape).
|
|
241
|
+
*/
|
|
242
|
+
interface VisualGraphFormatConverter<TSerial> {
|
|
243
|
+
/** Convert a VisualGraph to the serialized format. */
|
|
244
|
+
to(graph: VisualGraph): TSerial;
|
|
245
|
+
/** Convert from the serialized format to a VisualGraph. */
|
|
246
|
+
from(input: TSerial): VisualGraph;
|
|
247
|
+
}
|
|
237
248
|
interface TransitionOptions<TState, TEvent> {
|
|
238
249
|
/** Initial state to begin BFS exploration from. */
|
|
239
250
|
initialState: TState;
|
|
@@ -251,4 +262,4 @@ interface TransitionOptions<TState, TEvent> {
|
|
|
251
262
|
id?: string;
|
|
252
263
|
}
|
|
253
264
|
//#endregion
|
|
254
|
-
export { TraversalOptions as C,
|
|
265
|
+
export { TraversalOptions as C, VisualGraphFormatConverter as D, VisualGraphConfig as E, VisualNode as O, TransitionOptions as S, VisualGraph as T, MSTOptions as _, EntitiesConfig as a, PathOptions as b, Graph as c, GraphEdge as d, GraphFormatConverter as f, GraphStep as g, GraphPath as h, EdgeConfig as i, GraphConfig as l, GraphPatch as m, DeleteNodeOptions as n, EntitiesUpdate as o, GraphNode as p, EdgeChange as r, EntityRect as s, AllPairsShortestPathsOptions as t, GraphDiff as u, NodeChange as v, VisualEdge as w, SinglePathOptions as x, NodeConfig as y };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/graph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"description": "A TypeScript-first graph library with plain JSON-serializable objects",
|
|
6
6
|
"author": "David Khourshid <david@stately.ai>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"./jgf": "./dist/formats/jgf/index.mjs",
|
|
37
37
|
"./mermaid": "./dist/formats/mermaid/index.mjs",
|
|
38
38
|
"./tgf": "./dist/formats/tgf/index.mjs",
|
|
39
|
+
"./xyflow": "./dist/formats/xyflow/index.mjs",
|
|
39
40
|
"./queries": "./dist/queries.mjs",
|
|
40
41
|
"./schemas": "./dist/schemas.mjs",
|
|
41
42
|
"./package.json": "./package.json"
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"@types/d3-array": "^3.2.2",
|
|
54
55
|
"@types/d3-force": "^3.0.10",
|
|
55
56
|
"@types/node": "^25.0.3",
|
|
57
|
+
"@xyflow/system": "^0.0.75",
|
|
56
58
|
"bumpp": "^10.3.2",
|
|
57
59
|
"cytoscape": "^3.33.1",
|
|
58
60
|
"d3-array": "^3.2.4",
|
|
File without changes
|
|
File without changes
|