@statelyai/graph 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +12 -11
  2. package/dist/{algorithms-NWSB2RWj.mjs → algorithms-DldwenLt.mjs} +11 -6
  3. package/dist/algorithms.d.mts +1 -1
  4. package/dist/algorithms.mjs +1 -1
  5. package/dist/{converter-CchokMDg.mjs → converter-B5CUD0r9.mjs} +2 -2
  6. package/dist/formats/adjacency-list/index.d.mts +1 -1
  7. package/dist/formats/adjacency-list/index.mjs +1 -1
  8. package/dist/formats/converter/index.d.mts +2 -2
  9. package/dist/formats/converter/index.mjs +1 -1
  10. package/dist/formats/cytoscape/index.d.mts +1 -1
  11. package/dist/formats/cytoscape/index.mjs +4 -4
  12. package/dist/formats/d3/index.d.mts +1 -1
  13. package/dist/formats/d3/index.mjs +1 -1
  14. package/dist/formats/dot/index.d.mts +1 -1
  15. package/dist/formats/dot/index.mjs +1 -1
  16. package/dist/formats/edge-list/index.d.mts +1 -1
  17. package/dist/formats/edge-list/index.mjs +1 -1
  18. package/dist/formats/elk/index.d.mts +61 -0
  19. package/dist/formats/elk/index.mjs +176 -0
  20. package/dist/formats/gexf/index.d.mts +1 -1
  21. package/dist/formats/gexf/index.mjs +5 -5
  22. package/dist/formats/gml/index.d.mts +1 -1
  23. package/dist/formats/gml/index.mjs +3 -3
  24. package/dist/formats/graphml/index.d.mts +1 -1
  25. package/dist/formats/graphml/index.mjs +2 -2
  26. package/dist/formats/jgf/index.d.mts +1 -1
  27. package/dist/formats/jgf/index.mjs +4 -4
  28. package/dist/formats/mermaid/index.d.mts +46 -33
  29. package/dist/formats/mermaid/index.mjs +319 -35
  30. package/dist/formats/tgf/index.d.mts +1 -1
  31. package/dist/formats/tgf/index.mjs +1 -1
  32. package/dist/formats/xyflow/index.d.mts +73 -0
  33. package/dist/formats/xyflow/index.mjs +133 -0
  34. package/dist/index.d.mts +1 -1
  35. package/dist/index.mjs +5 -5
  36. package/dist/{indexing-eNDrXdDA.mjs → indexing-DyfgLuzw.mjs} +6 -5
  37. package/dist/queries.d.mts +2 -2
  38. package/dist/queries.mjs +9 -9
  39. package/dist/schemas.d.mts +37 -4
  40. package/dist/schemas.mjs +26 -5
  41. package/dist/{types-BDXC1O5b.d.mts → types-FBZCrmnG.d.mts} +17 -6
  42. package/package.json +9 -1
  43. package/schemas/edge.schema.json +32 -1
  44. package/schemas/graph.schema.json +114 -4
  45. package/schemas/node.schema.json +45 -2
  46. /package/dist/{adjacency-list-ITO40kmn.mjs → adjacency-list-fldj-QAL.mjs} +0 -0
  47. /package/dist/{edge-list-CgX6bBIF.mjs → edge-list-Br05wXMg.mjs} +0 -0
@@ -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, D as VisualNode, E as VisualGraphConfig, 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-BDXC1O5b.mjs";
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-FBZCrmnG.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-eNDrXdDA.mjs";
2
- import { A as addNode, B as hasNode, C as isAcyclic, D as GraphInstance, E as joinPaths, F as deleteEntities, H as updateEntities, I as deleteNode, L as getEdge, M as createGraphFromTransition, N as createVisualGraph, O as addEdge, P as deleteEdge, R as getNode, S as hasPath, T as isTree, U as updateNode, V as updateEdge, _ as getShortestPaths, a as genPreorders, b as getStronglyConnectedComponents, c as getAllPairsShortestPaths, d as getMinimumSpanningTree, f as getPostorder, g as getShortestPath, h as getPreorders, i as genPostorders, j as createGraph, k as addEntities, l as getConnectedComponents, m as getPreorder, n as dfs, o as genShortestPaths, p as getPostorders, r as genCycles, s as genSimplePaths, t as bfs, u as getCycles, v as getSimplePath, w as isConnected, x as getTopologicalSort, y as getSimplePaths, z as hasEdge } from "./algorithms-NWSB2RWj.mjs";
1
+ import { o as invalidateIndex, t as getIndex } from "./indexing-DyfgLuzw.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-DldwenLt.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-CchokMDg.mjs";
4
+ import { n as createFormatConverter } from "./converter-B5CUD0r9.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 !== null) config.parentId = node.parentId;
10
- if (node.initialNodeId !== null) config.initialNodeId = 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
- if (!idx.childNodes.has(newParentId)) idx.childNodes.set(newParentId, []);
99
- idx.childNodes.get(newParentId).push(nodeId);
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) {
@@ -1,4 +1,4 @@
1
- import { c as Graph, d as GraphEdge, p as GraphNode } from "./types-BDXC1O5b.mjs";
1
+ import { c as Graph, d as GraphEdge, p as GraphNode } from "./types-FBZCrmnG.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, i.e. `parentId === null`).
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-eNDrXdDA.mjs";
1
+ import { t as getIndex } from "./indexing-DyfgLuzw.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 === null) return void 0;
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 !== null) {
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, i.e. `parentId === null`).
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 !== null) {
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 !== null) {
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).
@@ -4,10 +4,17 @@ import * as z from "zod";
4
4
  declare const NodeSchema: z.ZodObject<{
5
5
  type: z.ZodLiteral<"node">;
6
6
  id: z.ZodString;
7
- parentId: z.ZodNullable<z.ZodString>;
8
- initialNodeId: z.ZodNullable<z.ZodString>;
7
+ parentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
8
+ initialNodeId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
9
9
  label: z.ZodString;
10
10
  data: z.ZodAny;
11
+ x: z.ZodOptional<z.ZodNumber>;
12
+ y: z.ZodOptional<z.ZodNumber>;
13
+ width: z.ZodOptional<z.ZodNumber>;
14
+ height: z.ZodOptional<z.ZodNumber>;
15
+ shape: z.ZodOptional<z.ZodString>;
16
+ color: z.ZodOptional<z.ZodString>;
17
+ style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
11
18
  }, z.core.$strip>;
12
19
  declare const EdgeSchema: z.ZodObject<{
13
20
  type: z.ZodLiteral<"edge">;
@@ -16,6 +23,12 @@ declare const EdgeSchema: z.ZodObject<{
16
23
  targetId: z.ZodString;
17
24
  label: z.ZodString;
18
25
  data: z.ZodAny;
26
+ x: z.ZodOptional<z.ZodNumber>;
27
+ y: z.ZodOptional<z.ZodNumber>;
28
+ width: z.ZodOptional<z.ZodNumber>;
29
+ height: z.ZodOptional<z.ZodNumber>;
30
+ color: z.ZodOptional<z.ZodString>;
31
+ style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
19
32
  }, z.core.$strip>;
20
33
  declare const GraphSchema: z.ZodObject<{
21
34
  id: z.ZodString;
@@ -27,10 +40,17 @@ declare const GraphSchema: z.ZodObject<{
27
40
  nodes: z.ZodArray<z.ZodObject<{
28
41
  type: z.ZodLiteral<"node">;
29
42
  id: z.ZodString;
30
- parentId: z.ZodNullable<z.ZodString>;
31
- initialNodeId: z.ZodNullable<z.ZodString>;
43
+ parentId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
44
+ initialNodeId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
32
45
  label: z.ZodString;
33
46
  data: z.ZodAny;
47
+ x: z.ZodOptional<z.ZodNumber>;
48
+ y: z.ZodOptional<z.ZodNumber>;
49
+ width: z.ZodOptional<z.ZodNumber>;
50
+ height: z.ZodOptional<z.ZodNumber>;
51
+ shape: z.ZodOptional<z.ZodString>;
52
+ color: z.ZodOptional<z.ZodString>;
53
+ style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
34
54
  }, z.core.$strip>>;
35
55
  edges: z.ZodArray<z.ZodObject<{
36
56
  type: z.ZodLiteral<"edge">;
@@ -39,8 +59,21 @@ declare const GraphSchema: z.ZodObject<{
39
59
  targetId: z.ZodString;
40
60
  label: z.ZodString;
41
61
  data: z.ZodAny;
62
+ x: z.ZodOptional<z.ZodNumber>;
63
+ y: z.ZodOptional<z.ZodNumber>;
64
+ width: z.ZodOptional<z.ZodNumber>;
65
+ height: z.ZodOptional<z.ZodNumber>;
66
+ color: z.ZodOptional<z.ZodString>;
67
+ style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
42
68
  }, z.core.$strip>>;
43
69
  data: z.ZodAny;
70
+ direction: z.ZodOptional<z.ZodEnum<{
71
+ up: "up";
72
+ down: "down";
73
+ left: "left";
74
+ right: "right";
75
+ }>>;
76
+ style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
44
77
  }, z.core.$strip>;
45
78
  //#endregion
46
79
  export { EdgeSchema, GraphSchema, NodeSchema };
package/dist/schemas.mjs CHANGED
@@ -1,13 +1,21 @@
1
1
  import * as z from "zod";
2
2
 
3
3
  //#region src/schemas.ts
4
+ const StyleSchema = z.record(z.string(), z.union([z.string(), z.number()]));
4
5
  const NodeSchema = z.object({
5
6
  type: z.literal("node"),
6
7
  id: z.string(),
7
- parentId: z.string().nullable(),
8
- initialNodeId: z.string().nullable(),
8
+ parentId: z.string().nullable().optional(),
9
+ initialNodeId: z.string().nullable().optional(),
9
10
  label: z.string(),
10
- data: z.any()
11
+ data: z.any(),
12
+ x: z.number().optional(),
13
+ y: z.number().optional(),
14
+ width: z.number().optional(),
15
+ height: z.number().optional(),
16
+ shape: z.string().optional(),
17
+ color: z.string().optional(),
18
+ style: StyleSchema.optional()
11
19
  });
12
20
  const EdgeSchema = z.object({
13
21
  type: z.literal("edge"),
@@ -15,7 +23,13 @@ const EdgeSchema = z.object({
15
23
  sourceId: z.string(),
16
24
  targetId: z.string(),
17
25
  label: z.string(),
18
- data: z.any()
26
+ data: z.any(),
27
+ x: z.number().optional(),
28
+ y: z.number().optional(),
29
+ width: z.number().optional(),
30
+ height: z.number().optional(),
31
+ color: z.string().optional(),
32
+ style: StyleSchema.optional()
19
33
  });
20
34
  const GraphSchema = z.object({
21
35
  id: z.string(),
@@ -23,7 +37,14 @@ const GraphSchema = z.object({
23
37
  initialNodeId: z.string().nullable(),
24
38
  nodes: z.array(NodeSchema),
25
39
  edges: z.array(EdgeSchema),
26
- data: z.any()
40
+ data: z.any(),
41
+ direction: z.enum([
42
+ "up",
43
+ "down",
44
+ "left",
45
+ "right"
46
+ ]).optional(),
47
+ style: StyleSchema.optional()
27
48
  });
28
49
 
29
50
  //#endregion
@@ -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: string | null;
71
- initialNodeId: string | null;
70
+ parentId?: string | null;
71
+ initialNodeId?: string | null;
72
72
  label: string;
73
73
  data: TNodeData;
74
74
  x?: number;
@@ -228,11 +228,22 @@ type GraphPatch<TNodeData = any, TEdgeData = any> = {
228
228
  * };
229
229
  * ```
230
230
  */
231
- interface GraphFormatConverter<TSerial> {
231
+ interface GraphFormatConverter<TSerial, N = any, E = any, G = any> {
232
232
  /** Convert a Graph to the serialized format. */
233
- to(graph: Graph): TSerial;
233
+ to(graph: Graph<N, E, G>): TSerial;
234
234
  /** Convert from the serialized format to a Graph. */
235
- from(input: TSerial): Graph;
235
+ from(input: TSerial): Graph<N, E, G>;
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, N = any, E = any, G = any> {
243
+ /** Convert a VisualGraph to the serialized format. */
244
+ to(graph: VisualGraph<N, E, G>): TSerial;
245
+ /** Convert from the serialized format to a VisualGraph. */
246
+ from(input: TSerial): VisualGraph<N, E, G>;
236
247
  }
237
248
  interface TransitionOptions<TState, TEvent> {
238
249
  /** Initial state to begin BFS exploration from. */
@@ -251,4 +262,4 @@ interface TransitionOptions<TState, TEvent> {
251
262
  id?: string;
252
263
  }
253
264
  //#endregion
254
- export { TraversalOptions as C, VisualNode as D, VisualGraphConfig as E, 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 };
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.3.1",
4
+ "version": "0.5.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",
@@ -30,12 +30,14 @@
30
30
  "./d3": "./dist/formats/d3/index.mjs",
31
31
  "./dot": "./dist/formats/dot/index.mjs",
32
32
  "./edge-list": "./dist/formats/edge-list/index.mjs",
33
+ "./elk": "./dist/formats/elk/index.mjs",
33
34
  "./gexf": "./dist/formats/gexf/index.mjs",
34
35
  "./gml": "./dist/formats/gml/index.mjs",
35
36
  "./graphml": "./dist/formats/graphml/index.mjs",
36
37
  "./jgf": "./dist/formats/jgf/index.mjs",
37
38
  "./mermaid": "./dist/formats/mermaid/index.mjs",
38
39
  "./tgf": "./dist/formats/tgf/index.mjs",
40
+ "./xyflow": "./dist/formats/xyflow/index.mjs",
39
41
  "./queries": "./dist/queries.mjs",
40
42
  "./schemas": "./dist/schemas.mjs",
41
43
  "./package.json": "./package.json"
@@ -53,11 +55,13 @@
53
55
  "@types/d3-array": "^3.2.2",
54
56
  "@types/d3-force": "^3.0.10",
55
57
  "@types/node": "^25.0.3",
58
+ "@xyflow/system": "^0.0.75",
56
59
  "bumpp": "^10.3.2",
57
60
  "cytoscape": "^3.33.1",
58
61
  "d3-array": "^3.2.4",
59
62
  "d3-force": "^3.0.0",
60
63
  "dotparser": "^1.1.1",
64
+ "elkjs": "^0.11.1",
61
65
  "fast-xml-parser": "^5.3.4",
62
66
  "tsdown": "^0.18.1",
63
67
  "tsx": "^4.21.0",
@@ -70,6 +74,7 @@
70
74
  "cytoscape": "^3.0.0",
71
75
  "d3-force": "^3.0.0",
72
76
  "dotparser": "^1.0.0",
77
+ "elkjs": "^0.9.0 || ^0.10.0 || ^0.11.0",
73
78
  "fast-xml-parser": "^5.0.0",
74
79
  "zod": "^4.0.0"
75
80
  },
@@ -83,6 +88,9 @@
83
88
  "dotparser": {
84
89
  "optional": true
85
90
  },
91
+ "elkjs": {
92
+ "optional": true
93
+ },
86
94
  "fast-xml-parser": {
87
95
  "optional": true
88
96
  },
@@ -18,7 +18,38 @@
18
18
  "label": {
19
19
  "type": "string"
20
20
  },
21
- "data": {}
21
+ "data": {},
22
+ "x": {
23
+ "type": "number"
24
+ },
25
+ "y": {
26
+ "type": "number"
27
+ },
28
+ "width": {
29
+ "type": "number"
30
+ },
31
+ "height": {
32
+ "type": "number"
33
+ },
34
+ "color": {
35
+ "type": "string"
36
+ },
37
+ "style": {
38
+ "type": "object",
39
+ "propertyNames": {
40
+ "type": "string"
41
+ },
42
+ "additionalProperties": {
43
+ "anyOf": [
44
+ {
45
+ "type": "string"
46
+ },
47
+ {
48
+ "type": "number"
49
+ }
50
+ ]
51
+ }
52
+ }
22
53
  },
23
54
  "required": [
24
55
  "type",