@statelyai/graph 0.12.0 → 1.0.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 (56) hide show
  1. package/README.md +26 -16
  2. package/dist/{adjacency-list-Ca0VjKIf.mjs → adjacency-list-VsUaH9SJ.mjs} +2 -2
  3. package/dist/{algorithms-BHHg7lGq.mjs → algorithms-Ba7o7niK.mjs} +35 -31
  4. package/dist/{algorithms-BlM-qoJb.d.mts → algorithms-fTqmvhzP.d.mts} +1 -1
  5. package/dist/algorithms.d.mts +1 -1
  6. package/dist/algorithms.mjs +1 -1
  7. package/dist/{converter-Dspillnn.mjs → converter-udLITX36.mjs} +2 -2
  8. package/dist/{edge-list-gKe8-iRa.mjs → edge-list-DP4otyPU.mjs} +1 -1
  9. package/dist/format-support.d.mts +6 -0
  10. package/dist/format-support.mjs +68 -33
  11. package/dist/formats/adjacency-list/index.d.mts +1 -1
  12. package/dist/formats/adjacency-list/index.mjs +1 -1
  13. package/dist/formats/converter/index.d.mts +1 -60
  14. package/dist/formats/converter/index.mjs +1 -1
  15. package/dist/formats/cytoscape/index.d.mts +1 -1
  16. package/dist/formats/cytoscape/index.mjs +19 -3
  17. package/dist/formats/d2/index.d.mts +109 -0
  18. package/dist/formats/d2/index.mjs +1086 -0
  19. package/dist/formats/d3/index.d.mts +8 -1
  20. package/dist/formats/d3/index.mjs +35 -7
  21. package/dist/formats/dot/index.d.mts +1 -1
  22. package/dist/formats/dot/index.mjs +3 -3
  23. package/dist/formats/edge-list/index.d.mts +1 -1
  24. package/dist/formats/edge-list/index.mjs +1 -1
  25. package/dist/formats/elk/index.d.mts +1 -1
  26. package/dist/formats/elk/index.mjs +86 -23
  27. package/dist/formats/gexf/index.d.mts +1 -1
  28. package/dist/formats/gexf/index.mjs +102 -4
  29. package/dist/formats/gml/index.d.mts +1 -1
  30. package/dist/formats/gml/index.mjs +43 -16
  31. package/dist/formats/graphml/index.d.mts +1 -1
  32. package/dist/formats/graphml/index.mjs +11 -4
  33. package/dist/formats/jgf/index.d.mts +1 -1
  34. package/dist/formats/jgf/index.mjs +19 -3
  35. package/dist/formats/mermaid/index.d.mts +2 -1
  36. package/dist/formats/mermaid/index.mjs +48 -18
  37. package/dist/formats/tgf/index.d.mts +1 -1
  38. package/dist/formats/tgf/index.mjs +2 -2
  39. package/dist/formats/xyflow/index.d.mts +2 -1
  40. package/dist/formats/xyflow/index.mjs +97 -40
  41. package/dist/index-CHoriXZD.d.mts +638 -0
  42. package/dist/index-D9Kj6Fe3.d.mts +61 -0
  43. package/dist/index.d.mts +6 -631
  44. package/dist/index.mjs +8 -7
  45. package/dist/{indexing-CJc-ul8e.mjs → indexing-DR8M1vBy.mjs} +18 -4
  46. package/dist/mode-D8OnHFBk.mjs +15 -0
  47. package/dist/queries-BlkA1HAN.d.mts +516 -0
  48. package/dist/queries.d.mts +1 -514
  49. package/dist/queries.mjs +17 -15
  50. package/dist/schemas.d.mts +29 -17
  51. package/dist/schemas.mjs +139 -6
  52. package/dist/{types-CnZ01raw.d.mts → types-3-FS9NV2.d.mts} +30 -7
  53. package/package.json +2 -1
  54. package/schemas/edge.schema.json +11 -0
  55. package/schemas/graph.schema.json +25 -3
  56. package/schemas/node.schema.json +7 -0
@@ -1,4 +1,4 @@
1
- import { h as GraphFormatConverter, u as Graph } from "../../types-CnZ01raw.mjs";
1
+ import { h as GraphFormatConverter, u as Graph } from "../../types-3-FS9NV2.mjs";
2
2
 
3
3
  //#region src/formats/graphml/index.d.ts
4
4
  declare function toGraphML(graph: Graph): string;
@@ -1,4 +1,5 @@
1
- import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
1
+ import { t as getEdgeMode } from "../../mode-D8OnHFBk.mjs";
2
+ import { n as createFormatConverter } from "../../converter-udLITX36.mjs";
2
3
  import { XMLBuilder, XMLParser } from "fast-xml-parser";
3
4
 
4
5
  //#region src/formats/graphml/index.ts
@@ -175,7 +176,9 @@ function toGraphML(graph) {
175
176
  ...data.length > 0 && { data }
176
177
  };
177
178
  });
179
+ const graphDirected = graph.mode !== "undirected";
178
180
  const edges = graph.edges.map((edge) => {
181
+ const edgeDirected = getEdgeMode(graph, edge) !== "undirected";
179
182
  const data = [];
180
183
  if (edge.label) data.push({
181
184
  "@_key": "label",
@@ -225,6 +228,7 @@ function toGraphML(graph) {
225
228
  "@_id": edge.id,
226
229
  "@_source": edge.sourceId,
227
230
  "@_target": edge.targetId,
231
+ ...edgeDirected !== graphDirected && { "@_directed": edgeDirected ? "true" : "false" },
228
232
  ...data.length > 0 && { data }
229
233
  };
230
234
  });
@@ -255,7 +259,7 @@ function toGraphML(graph) {
255
259
  key: keys,
256
260
  graph: {
257
261
  "@_id": graph.id,
258
- "@_edgedefault": graph.type === "directed" ? "directed" : "undirected",
262
+ "@_edgedefault": graph.mode === "undirected" ? "undirected" : "directed",
259
263
  ...graphData.length > 0 && { data: graphData },
260
264
  node: nodes,
261
265
  edge: edges
@@ -265,7 +269,8 @@ function toGraphML(graph) {
265
269
  return new XMLBuilder({
266
270
  ignoreAttributes: false,
267
271
  format: true,
268
- suppressEmptyNode: true
272
+ suppressEmptyNode: true,
273
+ suppressBooleanAttributes: false
269
274
  }).build(obj);
270
275
  }
271
276
  function fromGraphML(xml) {
@@ -331,11 +336,13 @@ function fromGraphML(xml) {
331
336
  if (dataMap.style !== void 0) edge.style = tryParseJSON(dataMap.style);
332
337
  if (dataMap.sourcePort !== void 0) edge.sourcePort = dataMap.sourcePort;
333
338
  if (dataMap.targetPort !== void 0) edge.targetPort = dataMap.targetPort;
339
+ const directedAttr = edgeEl["@_directed"];
340
+ if (directedAttr !== void 0) edge.mode = String(directedAttr) === "false" ? "undirected" : "directed";
334
341
  return edge;
335
342
  });
336
343
  const graph = {
337
344
  id: String(graphEl["@_id"] ?? ""),
338
- type: graphType,
345
+ mode: graphType,
339
346
  initialNodeId: graphDataMap.graphInitialNodeId ?? null,
340
347
  nodes,
341
348
  edges,
@@ -1,4 +1,4 @@
1
- import { h as GraphFormatConverter, u as Graph } from "../../types-CnZ01raw.mjs";
1
+ import { h as GraphFormatConverter, u as Graph } from "../../types-3-FS9NV2.mjs";
2
2
 
3
3
  //#region src/formats/jgf/index.d.ts
4
4
  interface JGFNode {
@@ -1,4 +1,4 @@
1
- import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
1
+ import { n as createFormatConverter } from "../../converter-udLITX36.mjs";
2
2
 
3
3
  //#region src/formats/jgf/index.ts
4
4
  /**
@@ -23,9 +23,10 @@ function toJGF(graph) {
23
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
+ if (graph.style !== void 0) metadata.style = graph.style;
26
27
  return { graph: {
27
28
  id: graph.id || void 0,
28
- directed: graph.type === "directed",
29
+ directed: graph.mode !== "undirected",
29
30
  ...Object.keys(metadata).length > 0 && { metadata },
30
31
  nodes: graph.nodes.map((n) => {
31
32
  const meta = {};
@@ -38,6 +39,7 @@ function toJGF(graph) {
38
39
  if (n.height !== void 0) meta.height = n.height;
39
40
  if (n.shape) meta.shape = n.shape;
40
41
  if (n.color) meta.color = n.color;
42
+ if (n.style !== void 0) meta.style = n.style;
41
43
  if (n.ports !== void 0) meta.ports = n.ports;
42
44
  return {
43
45
  id: n.id,
@@ -48,7 +50,13 @@ function toJGF(graph) {
48
50
  edges: graph.edges.map((e) => {
49
51
  const meta = {};
50
52
  if (e.data !== void 0) meta.data = e.data;
53
+ if (e.weight !== void 0) meta.weight = e.weight;
54
+ if (e.x !== void 0) meta.x = e.x;
55
+ if (e.y !== void 0) meta.y = e.y;
56
+ if (e.width !== void 0) meta.width = e.width;
57
+ if (e.height !== void 0) meta.height = e.height;
51
58
  if (e.color) meta.color = e.color;
59
+ if (e.style !== void 0) meta.style = e.style;
52
60
  if (e.sourcePort !== void 0) meta.sourcePort = e.sourcePort;
53
61
  if (e.targetPort !== void 0) meta.targetPort = e.targetPort;
54
62
  return {
@@ -85,10 +93,11 @@ function fromJGF(jgf) {
85
93
  if (!Array.isArray(g.edges)) throw new Error("JGF: \"graph.edges\" must be an array");
86
94
  return {
87
95
  id: g.id ?? "",
88
- type: g.directed === false ? "undirected" : "directed",
96
+ mode: g.directed === false ? "undirected" : "directed",
89
97
  initialNodeId: g.metadata?.initialNodeId ?? null,
90
98
  data: g.metadata?.data,
91
99
  ...g.metadata?.direction && { direction: g.metadata.direction },
100
+ ...g.metadata?.style !== void 0 && { style: g.metadata.style },
92
101
  nodes: g.nodes.map((n) => ({
93
102
  type: "node",
94
103
  id: n.id,
@@ -102,6 +111,7 @@ function fromJGF(jgf) {
102
111
  ...n.metadata?.height !== void 0 && { height: n.metadata.height },
103
112
  ...n.metadata?.shape && { shape: n.metadata.shape },
104
113
  ...n.metadata?.color && { color: n.metadata.color },
114
+ ...n.metadata?.style !== void 0 && { style: n.metadata.style },
105
115
  ...n.metadata?.ports !== void 0 && { ports: n.metadata.ports }
106
116
  })),
107
117
  edges: g.edges.map((e, i) => ({
@@ -111,7 +121,13 @@ function fromJGF(jgf) {
111
121
  targetId: e.target,
112
122
  label: e.label ?? "",
113
123
  data: e.metadata?.data,
124
+ ...e.metadata?.weight !== void 0 && { weight: e.metadata.weight },
125
+ ...e.metadata?.x !== void 0 && { x: e.metadata.x },
126
+ ...e.metadata?.y !== void 0 && { y: e.metadata.y },
127
+ ...e.metadata?.width !== void 0 && { width: e.metadata.width },
128
+ ...e.metadata?.height !== void 0 && { height: e.metadata.height },
114
129
  ...e.metadata?.color && { color: e.metadata.color },
130
+ ...e.metadata?.style !== void 0 && { style: e.metadata.style },
115
131
  ...e.metadata?.sourcePort !== void 0 && { sourcePort: e.metadata.sourcePort },
116
132
  ...e.metadata?.targetPort !== void 0 && { targetPort: e.metadata.targetPort }
117
133
  }))
@@ -1,4 +1,4 @@
1
- import { h as GraphFormatConverter, u as Graph } from "../../types-CnZ01raw.mjs";
1
+ import { h as GraphFormatConverter, u as Graph } from "../../types-3-FS9NV2.mjs";
2
2
 
3
3
  //#region src/formats/mermaid/sequence.d.ts
4
4
  interface SequenceNodeData {
@@ -165,6 +165,7 @@ interface StateNodeData {
165
165
  notes?: Array<{
166
166
  position: 'left' | 'right';
167
167
  text: string;
168
+ format?: 'inline' | 'block';
168
169
  }>;
169
170
  isStart?: boolean;
170
171
  isEnd?: boolean;
@@ -1,4 +1,4 @@
1
- import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
1
+ import { n as createFormatConverter } from "../../converter-udLITX36.mjs";
2
2
 
3
3
  //#region src/formats/mermaid/shared.ts
4
4
  const MERMAID_TO_DIRECTION = {
@@ -497,7 +497,7 @@ function fromMermaidSequence(input) {
497
497
  }
498
498
  return {
499
499
  id: "",
500
- type: "directed",
500
+ mode: "directed",
501
501
  initialNodeId: null,
502
502
  nodes: Array.from(nodeMap.values()),
503
503
  edges,
@@ -1292,7 +1292,7 @@ function fromMermaidFlowchart(input) {
1292
1292
  }
1293
1293
  return {
1294
1294
  id: "",
1295
- type: "directed",
1295
+ mode: "directed",
1296
1296
  initialNodeId: null,
1297
1297
  nodes: Array.from(nodeMap.values()),
1298
1298
  edges,
@@ -1415,10 +1415,16 @@ function fromMermaidState(input) {
1415
1415
  const parentStack = [null];
1416
1416
  const regionCounters = /* @__PURE__ */ new Map();
1417
1417
  function ensureNode(id) {
1418
- if (!nodeMap.has(id)) nodeMap.set(id, {
1418
+ const parentId = parentStack[parentStack.length - 1];
1419
+ const existing = nodeMap.get(id);
1420
+ if (existing) {
1421
+ if (parentId && existing.parentId === null && existing.id !== parentId) existing.parentId = parentId;
1422
+ return existing;
1423
+ }
1424
+ nodeMap.set(id, {
1419
1425
  type: "node",
1420
1426
  id,
1421
- parentId: parentStack[parentStack.length - 1],
1427
+ parentId,
1422
1428
  initialNodeId: null,
1423
1429
  label: id,
1424
1430
  data: {}
@@ -1462,6 +1468,15 @@ function fromMermaidState(input) {
1462
1468
  parentStack.push(stateId);
1463
1469
  continue;
1464
1470
  }
1471
+ const compositeStateAsMatch = line.match(/^state\s+"([^"]+)"\s+as\s+(\S+)\s*\{\s*$/);
1472
+ if (compositeStateAsMatch) {
1473
+ const description = compositeStateAsMatch[1];
1474
+ const stateId = compositeStateAsMatch[2];
1475
+ const node = ensureNode(stateId);
1476
+ node.data.description = description;
1477
+ parentStack.push(stateId);
1478
+ continue;
1479
+ }
1465
1480
  const stereotypeMatch = line.match(/^state\s+(\S+)\s+<<(choice|fork|join)>>\s*$/);
1466
1481
  if (stereotypeMatch) {
1467
1482
  const stateId = stereotypeMatch[1];
@@ -1542,16 +1557,27 @@ function fromMermaidState(input) {
1542
1557
  }
1543
1558
  continue;
1544
1559
  }
1545
- const noteMatch = line.match(/^note\s+(left|right)\s+of\s+(\S+)\s*:\s*(.+)$/i);
1560
+ const noteMatch = line.match(/^note\s+(left|right)\s+of\s+(\S+)\s*(?::\s*(.*))?$/i);
1546
1561
  if (noteMatch) {
1547
1562
  const position = noteMatch[1].toLowerCase();
1548
1563
  const stateId = noteMatch[2];
1549
- const text = noteMatch[3].trim();
1564
+ const inlineText = noteMatch[3]?.trim();
1565
+ const text = inlineText && inlineText.length > 0 ? inlineText : (() => {
1566
+ const content = [];
1567
+ while (i + 1 < lines.length) {
1568
+ i++;
1569
+ const noteLine = lines[i].trim();
1570
+ if (/^end\s+note$/i.test(noteLine)) break;
1571
+ content.push(noteLine);
1572
+ }
1573
+ return content.join("\n").trim();
1574
+ })();
1550
1575
  const node = ensureNode(stateId);
1551
1576
  if (!node.data.notes) node.data.notes = [];
1552
1577
  node.data.notes.push({
1553
1578
  position,
1554
- text
1579
+ text,
1580
+ format: inlineText && inlineText.length > 0 ? "inline" : "block"
1555
1581
  });
1556
1582
  continue;
1557
1583
  }
@@ -1649,7 +1675,7 @@ function fromMermaidState(input) {
1649
1675
  }
1650
1676
  return {
1651
1677
  id: "",
1652
- type: "directed",
1678
+ mode: "directed",
1653
1679
  initialNodeId: null,
1654
1680
  nodes: Array.from(nodeMap.values()),
1655
1681
  edges,
@@ -1687,9 +1713,9 @@ function toMermaidState(graph) {
1687
1713
  if (node.data?.isStart || node.data?.isEnd) continue;
1688
1714
  if (node.id.includes("_region_")) continue;
1689
1715
  if (node.data?.stateType && node.data.stateType !== "parallel") lines.push(`${indent}state ${node.id} <<${node.data.stateType}>>`);
1690
- if (node.data?.description) lines.push(`${indent}state "${escapeMermaidLabel(node.data.description)}" as ${node.id}`);
1691
1716
  if (isParent.has(node.id)) {
1692
- lines.push(`${indent}state ${node.id} {`);
1717
+ const stateDecl = node.data?.description ? `state "${escapeMermaidLabel(node.data.description)}" as ${node.id} {` : `state ${node.id} {`;
1718
+ lines.push(`${indent}${stateDecl}`);
1693
1719
  if (node.data?.direction) {
1694
1720
  const mDir = DIRECTION_TO_MERMAID[node.data.direction];
1695
1721
  if (mDir) lines.push(`${indent} direction ${mDir}`);
@@ -1702,8 +1728,12 @@ function toMermaidState(graph) {
1702
1728
  }
1703
1729
  } else writeNodes(node.id, indent + " ");
1704
1730
  lines.push(`${indent}}`);
1705
- }
1706
- if (node.data?.notes) for (const note of node.data.notes) lines.push(`${indent}note ${note.position} of ${node.id} : ${escapeMermaidLabel(note.text)}`);
1731
+ } else if (node.data?.description) lines.push(`${indent}state "${escapeMermaidLabel(node.data.description)}" as ${node.id}`);
1732
+ if (node.data?.notes) for (const note of node.data.notes) if (note.format === "block" || note.text.includes("\n")) {
1733
+ lines.push(`${indent}note ${note.position} of ${node.id}`);
1734
+ for (const noteLine of note.text.split("\n")) lines.push(`${indent} ${escapeMermaidLabel(noteLine)}`);
1735
+ lines.push(`${indent}end note`);
1736
+ } else lines.push(`${indent}note ${note.position} of ${node.id} : ${escapeMermaidLabel(note.text)}`);
1707
1737
  }
1708
1738
  }
1709
1739
  writeNodes(null, " ");
@@ -2023,7 +2053,7 @@ function fromMermaidClass(input) {
2023
2053
  }
2024
2054
  return {
2025
2055
  id: "",
2026
- type: "directed",
2056
+ mode: "directed",
2027
2057
  initialNodeId: null,
2028
2058
  nodes: Array.from(nodeMap.values()),
2029
2059
  edges,
@@ -2221,7 +2251,7 @@ function fromMermaidER(input) {
2221
2251
  }
2222
2252
  return {
2223
2253
  id: "",
2224
- type: "directed",
2254
+ mode: "directed",
2225
2255
  initialNodeId: null,
2226
2256
  nodes: Array.from(nodeMap.values()),
2227
2257
  edges,
@@ -2379,7 +2409,7 @@ function fromMermaidMindmap(input) {
2379
2409
  }
2380
2410
  return {
2381
2411
  id: "",
2382
- type: "directed",
2412
+ mode: "directed",
2383
2413
  initialNodeId: null,
2384
2414
  nodes: Array.from(nodeMap.values()),
2385
2415
  edges,
@@ -2578,7 +2608,7 @@ function fromMermaidBlock(input) {
2578
2608
  }
2579
2609
  return {
2580
2610
  id: "",
2581
- type: "directed",
2611
+ mode: "directed",
2582
2612
  initialNodeId: null,
2583
2613
  nodes: Array.from(nodeMap.values()),
2584
2614
  edges,
@@ -2690,7 +2720,7 @@ function fromMermaidIshikawa(input) {
2690
2720
  }
2691
2721
  return {
2692
2722
  id: "",
2693
- type: "directed",
2723
+ mode: "directed",
2694
2724
  initialNodeId: null,
2695
2725
  nodes,
2696
2726
  edges,
@@ -1,4 +1,4 @@
1
- import { h as GraphFormatConverter, u as Graph } from "../../types-CnZ01raw.mjs";
1
+ import { h as GraphFormatConverter, u as Graph } from "../../types-3-FS9NV2.mjs";
2
2
 
3
3
  //#region src/formats/tgf/index.d.ts
4
4
 
@@ -1,4 +1,4 @@
1
- import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
1
+ import { n as createFormatConverter } from "../../converter-udLITX36.mjs";
2
2
 
3
3
  //#region src/formats/tgf/index.ts
4
4
  /**
@@ -81,7 +81,7 @@ function fromTGF(tgf) {
81
81
  }
82
82
  return {
83
83
  id: "",
84
- type: "directed",
84
+ mode: "directed",
85
85
  initialNodeId: null,
86
86
  nodes,
87
87
  edges,
@@ -1,4 +1,4 @@
1
- import { P as VisualGraphFormatConverter, j as VisualGraph } from "../../types-CnZ01raw.mjs";
1
+ import { F as VisualGraphFormatConverter, M as VisualGraph } from "../../types-3-FS9NV2.mjs";
2
2
  import { EdgeBase, NodeBase } from "@xyflow/system";
3
3
 
4
4
  //#region src/formats/xyflow/index.d.ts
@@ -9,6 +9,7 @@ type XYFlowEdge<TEdgeData extends Record<string, unknown> = Record<string, unkno
9
9
  interface XYFlow<TNodeData extends Record<string, unknown> = Record<string, unknown>, TEdgeData extends Record<string, unknown> = Record<string, unknown>> {
10
10
  nodes: XYFlowNode<TNodeData>[];
11
11
  edges: XYFlowEdge<TEdgeData>[];
12
+ data?: Record<string, unknown>;
12
13
  }
13
14
  /**
14
15
  * Converts a visual graph to xyflow (React Flow / Svelte Flow) format.
@@ -1,4 +1,27 @@
1
1
  //#region src/formats/xyflow/index.ts
2
+ const STATELYAI_METADATA_KEY = "__statelyai";
3
+ function toDataObject(value) {
4
+ return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
5
+ }
6
+ function withMetadata(value, metadata) {
7
+ return {
8
+ ...toDataObject(value),
9
+ [STATELYAI_METADATA_KEY]: {
10
+ ...value !== void 0 && { data: value },
11
+ ...metadata
12
+ }
13
+ };
14
+ }
15
+ function readMetadata(value) {
16
+ if (!value || typeof value !== "object") return void 0;
17
+ const metadata = value[STATELYAI_METADATA_KEY];
18
+ return metadata && typeof metadata === "object" ? metadata : void 0;
19
+ }
20
+ function readUserData(value) {
21
+ const metadata = readMetadata(value);
22
+ if (metadata && "data" in metadata) return metadata.data;
23
+ return value;
24
+ }
2
25
  /**
3
26
  * Converts a visual graph to xyflow (React Flow / Svelte Flow) format.
4
27
  *
@@ -21,6 +44,14 @@
21
44
  */
22
45
  function toXYFlow(graph) {
23
46
  return {
47
+ data: { [STATELYAI_METADATA_KEY]: { graph: {
48
+ id: graph.id,
49
+ mode: graph.mode,
50
+ initialNodeId: graph.initialNodeId,
51
+ data: graph.data,
52
+ direction: graph.direction,
53
+ style: graph.style
54
+ } } },
24
55
  nodes: graph.nodes.map((n) => {
25
56
  const node = {
26
57
  id: n.id,
@@ -28,12 +59,18 @@ function toXYFlow(graph) {
28
59
  x: n.x,
29
60
  y: n.y
30
61
  },
31
- data: n.data ?? {}
62
+ data: withMetadata(n.data, { node: {
63
+ initialNodeId: n.initialNodeId,
64
+ label: n.label,
65
+ color: n.color,
66
+ style: n.style,
67
+ ports: n.ports
68
+ } })
32
69
  };
33
70
  if (n.parentId) node.parentId = n.parentId;
34
71
  if (n.shape) node.type = n.shape;
35
- if (n.width) node.width = n.width;
36
- if (n.height) node.height = n.height;
72
+ if (n.width !== void 0) node.width = n.width;
73
+ if (n.height !== void 0) node.height = n.height;
37
74
  return node;
38
75
  }),
39
76
  edges: graph.edges.map((e) => {
@@ -44,11 +81,17 @@ function toXYFlow(graph) {
44
81
  };
45
82
  if (e.sourcePort) edge.sourceHandle = e.sourcePort;
46
83
  if (e.targetPort) edge.targetHandle = e.targetPort;
47
- if (e.data !== void 0) edge.data = e.data;
48
- if (e.label) edge.data = {
49
- ...edge.data,
50
- label: e.label
51
- };
84
+ edge.data = withMetadata(e.data, { edge: {
85
+ label: e.label,
86
+ weight: e.weight,
87
+ color: e.color,
88
+ style: e.style,
89
+ x: e.x,
90
+ y: e.y,
91
+ width: e.width,
92
+ height: e.height
93
+ } });
94
+ if (e.label) edge.data.label = e.label;
52
95
  return edge;
53
96
  })
54
97
  };
@@ -73,39 +116,53 @@ function fromXYFlow(flow) {
73
116
  if (!flow || typeof flow !== "object") throw new Error("XYFlow: expected an object");
74
117
  if (!Array.isArray(flow.nodes)) throw new Error("XYFlow: \"nodes\" must be an array");
75
118
  if (!Array.isArray(flow.edges)) throw new Error("XYFlow: \"edges\" must be an array");
119
+ const graphMetadata = readMetadata(flow.data)?.graph;
76
120
  return {
77
- id: "",
78
- type: "directed",
79
- initialNodeId: null,
80
- data: void 0,
81
- direction: "down",
82
- nodes: flow.nodes.map((n) => ({
83
- type: "node",
84
- id: n.id,
85
- parentId: n.parentId ?? null,
86
- initialNodeId: null,
87
- label: "",
88
- data: n.data,
89
- x: n.position.x,
90
- y: n.position.y,
91
- width: n.measured?.width ?? n.width ?? n.initialWidth ?? 0,
92
- height: n.measured?.height ?? n.height ?? n.initialHeight ?? 0,
93
- ...n.type && { shape: n.type }
94
- })),
95
- edges: flow.edges.map((e, i) => ({
96
- type: "edge",
97
- id: e.id ?? `e${i}`,
98
- sourceId: e.source,
99
- targetId: e.target,
100
- label: e.data?.label?.toString() ?? "",
101
- ...e.sourceHandle && { sourcePort: e.sourceHandle },
102
- ...e.targetHandle && { targetPort: e.targetHandle },
103
- data: e.data,
104
- x: 0,
105
- y: 0,
106
- width: 0,
107
- height: 0
108
- }))
121
+ id: graphMetadata?.id?.toString() ?? "",
122
+ mode: graphMetadata?.mode ?? "directed",
123
+ initialNodeId: graphMetadata && "initialNodeId" in graphMetadata ? graphMetadata.initialNodeId : null,
124
+ data: graphMetadata && "data" in graphMetadata ? graphMetadata.data : void 0,
125
+ direction: graphMetadata?.direction ?? "down",
126
+ ...graphMetadata?.style !== void 0 && { style: graphMetadata.style },
127
+ nodes: flow.nodes.map((n) => {
128
+ const metadata = readMetadata(n.data)?.node;
129
+ return {
130
+ type: "node",
131
+ id: n.id,
132
+ parentId: n.parentId ?? null,
133
+ initialNodeId: metadata && "initialNodeId" in metadata ? metadata.initialNodeId : null,
134
+ label: metadata && "label" in metadata ? metadata.label : "",
135
+ data: readUserData(n.data),
136
+ x: n.position.x,
137
+ y: n.position.y,
138
+ width: n.measured?.width ?? n.width ?? n.initialWidth ?? 0,
139
+ height: n.measured?.height ?? n.height ?? n.initialHeight ?? 0,
140
+ ...n.type && { shape: n.type },
141
+ ...metadata?.color !== void 0 && { color: metadata.color },
142
+ ...metadata?.style !== void 0 && { style: metadata.style },
143
+ ...metadata?.ports !== void 0 && { ports: metadata.ports }
144
+ };
145
+ }),
146
+ edges: flow.edges.map((e, i) => {
147
+ const metadata = readMetadata(e.data)?.edge;
148
+ return {
149
+ type: "edge",
150
+ id: e.id ?? `e${i}`,
151
+ sourceId: e.source,
152
+ targetId: e.target,
153
+ label: metadata && "label" in metadata ? metadata.label : e.data?.label?.toString() ?? "",
154
+ ...e.sourceHandle && { sourcePort: e.sourceHandle },
155
+ ...e.targetHandle && { targetPort: e.targetHandle },
156
+ data: readUserData(e.data),
157
+ x: metadata?.x ?? 0,
158
+ y: metadata?.y ?? 0,
159
+ width: metadata?.width ?? 0,
160
+ height: metadata?.height ?? 0,
161
+ ...metadata?.weight !== void 0 && { weight: metadata.weight },
162
+ ...metadata?.color !== void 0 && { color: metadata.color },
163
+ ...metadata?.style !== void 0 && { style: metadata.style }
164
+ };
165
+ })
109
166
  };
110
167
  }
111
168
  /**