@statelyai/graph 0.11.1 → 0.13.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.
@@ -23,6 +23,7 @@ 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
29
  directed: graph.type === "directed",
@@ -38,6 +39,8 @@ 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;
43
+ if (n.ports !== void 0) meta.ports = n.ports;
41
44
  return {
42
45
  id: n.id,
43
46
  ...n.label && { label: n.label },
@@ -47,7 +50,15 @@ function toJGF(graph) {
47
50
  edges: graph.edges.map((e) => {
48
51
  const meta = {};
49
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;
50
58
  if (e.color) meta.color = e.color;
59
+ if (e.style !== void 0) meta.style = e.style;
60
+ if (e.sourcePort !== void 0) meta.sourcePort = e.sourcePort;
61
+ if (e.targetPort !== void 0) meta.targetPort = e.targetPort;
51
62
  return {
52
63
  id: e.id,
53
64
  source: e.sourceId,
@@ -86,6 +97,7 @@ function fromJGF(jgf) {
86
97
  initialNodeId: g.metadata?.initialNodeId ?? null,
87
98
  data: g.metadata?.data,
88
99
  ...g.metadata?.direction && { direction: g.metadata.direction },
100
+ ...g.metadata?.style !== void 0 && { style: g.metadata.style },
89
101
  nodes: g.nodes.map((n) => ({
90
102
  type: "node",
91
103
  id: n.id,
@@ -98,7 +110,9 @@ function fromJGF(jgf) {
98
110
  ...n.metadata?.width !== void 0 && { width: n.metadata.width },
99
111
  ...n.metadata?.height !== void 0 && { height: n.metadata.height },
100
112
  ...n.metadata?.shape && { shape: n.metadata.shape },
101
- ...n.metadata?.color && { color: n.metadata.color }
113
+ ...n.metadata?.color && { color: n.metadata.color },
114
+ ...n.metadata?.style !== void 0 && { style: n.metadata.style },
115
+ ...n.metadata?.ports !== void 0 && { ports: n.metadata.ports }
102
116
  })),
103
117
  edges: g.edges.map((e, i) => ({
104
118
  type: "edge",
@@ -107,7 +121,15 @@ function fromJGF(jgf) {
107
121
  targetId: e.target,
108
122
  label: e.label ?? "",
109
123
  data: e.metadata?.data,
110
- ...e.metadata?.color && { color: e.metadata.color }
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 },
129
+ ...e.metadata?.color && { color: e.metadata.color },
130
+ ...e.metadata?.style !== void 0 && { style: e.metadata.style },
131
+ ...e.metadata?.sourcePort !== void 0 && { sourcePort: e.metadata.sourcePort },
132
+ ...e.metadata?.targetPort !== void 0 && { targetPort: e.metadata.targetPort }
111
133
  }))
112
134
  };
113
135
  }
@@ -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;
@@ -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
  }
@@ -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, " ");
@@ -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
+ type: graph.type,
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
+ type: graphMetadata?.type === "undirected" ? "undirected" : "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
  /**
package/dist/index.d.mts CHANGED
@@ -11,7 +11,7 @@ import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdge
11
11
  * @example
12
12
  * ```ts
13
13
  * const port = createGraphPort({ name: 'output', direction: 'out' });
14
- * // { name: 'output', direction: 'out', data: undefined }
14
+ * // { name: 'output', direction: 'out', data: null }
15
15
  * ```
16
16
  */
17
17
  declare function createGraphPort<P = any>(config: PortConfig<P>): GraphPort<P>;
@@ -31,7 +31,7 @@ declare function createGraphNode<N = any, P = any>(config: NodeConfig<N, P>): Gr
31
31
  * @example
32
32
  * ```ts
33
33
  * const edge = createGraphEdge({ id: 'e1', sourceId: 'a', targetId: 'b' });
34
- * // { type: 'edge', id: 'e1', sourceId: 'a', targetId: 'b', label: null, data: undefined }
34
+ * // { type: 'edge', id: 'e1', sourceId: 'a', targetId: 'b', label: null, data: null }
35
35
  * ```
36
36
  */
37
37
  declare function createGraphEdge<T = any>(config: EdgeConfig<T>): GraphEdge<T>;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { o as invalidateIndex, t as getIndex } from "./indexing-CJc-ul8e.mjs";
2
- import { $ as createGraphPort, A as isAcyclic, B as getShortestPaths, C as getPreorder, D as getConnectedComponents, E as dfs, F as genSimplePaths, G as GraphInstance, H as getSimplePaths, I as getAStarPath, J as addNode, K as addEdge, L as getAllPairsShortestPaths, M as isTree, N as genCycles, O as getTopologicalSort, P as genShortestPaths, Q as createGraphNode, R as getCycles, S as getPostorders, T as bfs, U as getStronglyConnectedComponents, V as getSimplePath, W as joinPaths, X as createGraphEdge, Y as createGraph, Z as createGraphFromTransition, _ as getPageRank, a as genGirvanNewmanCommunities, at as getNode, b as genPreorders, c as getLabelPropagationCommunities, ct as updateEdge, d as getClosenessCentrality, et as createVisualGraph, f as getDegreeCentrality, g as getOutDegreeCentrality, h as getInDegreeCentrality, i as getBridges, it as getEdge, j as isConnected, k as hasPath, l as getModularity, lt as updateEntities, m as getHITS, n as getArticulationPoints, nt as deleteEntities, o as getGirvanNewmanCommunities, ot as hasEdge, p as getEigenvectorCentrality, q as addEntities, r as getBiconnectedComponents, rt as deleteNode, s as getGreedyModularityCommunities, st as hasNode, t as isIsomorphic, tt as deleteEdge, u as getBetweennessCentrality, ut as updateNode, v as getMinimumSpanningTree, w as getPreorders, x as getPostorder, y as genPostorders, z as getShortestPath } from "./algorithms-BHHg7lGq.mjs";
1
+ import { o as invalidateIndex, t as getIndex } from "./indexing-DUl3kTqm.mjs";
2
+ import { $ as createGraphPort, A as isAcyclic, B as getShortestPaths, C as getPreorder, D as getConnectedComponents, E as dfs, F as genSimplePaths, G as GraphInstance, H as getSimplePaths, I as getAStarPath, J as addNode, K as addEdge, L as getAllPairsShortestPaths, M as isTree, N as genCycles, O as getTopologicalSort, P as genShortestPaths, Q as createGraphNode, R as getCycles, S as getPostorders, T as bfs, U as getStronglyConnectedComponents, V as getSimplePath, W as joinPaths, X as createGraphEdge, Y as createGraph, Z as createGraphFromTransition, _ as getPageRank, a as genGirvanNewmanCommunities, at as getNode, b as genPreorders, c as getLabelPropagationCommunities, ct as updateEdge, d as getClosenessCentrality, et as createVisualGraph, f as getDegreeCentrality, g as getOutDegreeCentrality, h as getInDegreeCentrality, i as getBridges, it as getEdge, j as isConnected, k as hasPath, l as getModularity, lt as updateEntities, m as getHITS, n as getArticulationPoints, nt as deleteEntities, o as getGirvanNewmanCommunities, ot as hasEdge, p as getEigenvectorCentrality, q as addEntities, r as getBiconnectedComponents, rt as deleteNode, s as getGreedyModularityCommunities, st as hasNode, t as isIsomorphic, tt as deleteEdge, u as getBetweennessCentrality, ut as updateNode, v as getMinimumSpanningTree, w as getPreorders, x as getPostorder, y as genPostorders, z as getShortestPath } from "./algorithms-BNDQcHU3.mjs";
3
3
  import { getAncestors, getChildren, getDegree, getDepth, getDescendants, getEdgesBetween, getEdgesByPort, getEdgesOf, getInDegree, getInEdges, getLCA, getNeighbors, getOutDegree, getOutEdges, getParent, getPort, getPorts, getPredecessors, getRelativeDistance, getRelativeDistanceMap, getRoots, getSiblings, getSinks, getSources, getSuccessors, isCompound, isLeaf } from "./queries.mjs";
4
4
  import { n as createFormatConverter } from "./converter-Dspillnn.mjs";
5
5
 
@@ -20,8 +20,10 @@ const indexes = /* @__PURE__ */ new WeakMap();
20
20
  */
21
21
  function getIndex(graph) {
22
22
  let idx = indexes.get(graph);
23
- if (!idx || idx.nodeCount !== graph.nodes.length || idx.edgeCount !== graph.edges.length) {
24
- idx = buildIndex(graph);
23
+ const sameStructure = idx && idx.nodeCount === graph.nodes.length && idx.edgeCount === graph.edges.length;
24
+ const signature = idx !== void 0 && sameStructure && idx.nodesRef === graph.nodes && idx.edgesRef === graph.edges ? getIndexSignature(graph) : void 0;
25
+ if (!idx || idx.nodeCount !== graph.nodes.length || idx.edgeCount !== graph.edges.length || signature !== void 0 && idx.signature !== signature) {
26
+ idx = buildIndex(graph, signature ?? getIndexSignature(graph));
25
27
  indexes.set(graph, idx);
26
28
  }
27
29
  return idx;
@@ -42,7 +44,12 @@ function getIndex(graph) {
42
44
  function invalidateIndex(graph) {
43
45
  indexes.delete(graph);
44
46
  }
45
- function buildIndex(graph) {
47
+ function getIndexSignature(graph) {
48
+ const nodeParts = graph.nodes.map((node) => `${node.id}\u0000${node.parentId ?? ""}`);
49
+ const edgeParts = graph.edges.map((edge) => `${edge.id}\u0000${edge.sourceId}\u0000${edge.targetId}`);
50
+ return `${nodeParts.join("")}\u0002${edgeParts.join("")}`;
51
+ }
52
+ function buildIndex(graph, signature) {
46
53
  const nodeById = /* @__PURE__ */ new Map();
47
54
  const edgeById = /* @__PURE__ */ new Map();
48
55
  const outEdges = /* @__PURE__ */ new Map();
@@ -70,7 +77,10 @@ function buildIndex(graph) {
70
77
  inEdges,
71
78
  childNodes,
72
79
  nodeCount: graph.nodes.length,
73
- edgeCount: graph.edges.length
80
+ edgeCount: graph.edges.length,
81
+ signature,
82
+ nodesRef: graph.nodes,
83
+ edgesRef: graph.edges
74
84
  };
75
85
  }
76
86
  function indexAddNode(idx, node, arrayIndex) {
@@ -81,12 +91,14 @@ function indexAddNode(idx, node, arrayIndex) {
81
91
  if (!idx.childNodes.has(parent)) idx.childNodes.set(parent, []);
82
92
  idx.childNodes.get(parent).push(node.id);
83
93
  idx.nodeCount++;
94
+ idx.signature = "";
84
95
  }
85
96
  function indexAddEdge(idx, edge, arrayIndex) {
86
97
  idx.edgeById.set(edge.id, arrayIndex);
87
98
  idx.outEdges.get(edge.sourceId)?.push(edge.id);
88
99
  idx.inEdges.get(edge.targetId)?.push(edge.id);
89
100
  idx.edgeCount++;
101
+ idx.signature = "";
90
102
  }
91
103
  /** Update childNodes index when a node's parentId changes. */
92
104
  function indexReparentNode(idx, nodeId, oldParentId, newParentId) {
@@ -98,6 +110,7 @@ function indexReparentNode(idx, nodeId, oldParentId, newParentId) {
98
110
  const np = newParentId ?? null;
99
111
  if (!idx.childNodes.has(np)) idx.childNodes.set(np, []);
100
112
  idx.childNodes.get(np).push(nodeId);
113
+ idx.signature = "";
101
114
  }
102
115
  /** Update adjacency lists when an edge's sourceId/targetId changes. */
103
116
  function indexUpdateEdgeEndpoints(idx, edgeId, oldSourceId, oldTargetId, newSourceId, newTargetId) {
@@ -117,6 +130,7 @@ function indexUpdateEdgeEndpoints(idx, edgeId, oldSourceId, oldTargetId, newSour
117
130
  }
118
131
  idx.inEdges.get(newTargetId)?.push(edgeId);
119
132
  }
133
+ idx.signature = "";
120
134
  }
121
135
 
122
136
  //#endregion
package/dist/queries.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as getIndex } from "./indexing-CJc-ul8e.mjs";
1
+ import { t as getIndex } from "./indexing-DUl3kTqm.mjs";
2
2
 
3
3
  //#region src/queries.ts
4
4
  /**
@@ -1,13 +1,14 @@
1
+ import { g as GraphNode, p as GraphEdge, u as Graph, y as GraphPort } from "./types-CnZ01raw.mjs";
1
2
  import * as z from "zod";
2
3
 
3
4
  //#region src/schemas.d.ts
4
5
  declare const PortSchema: z.ZodObject<{
5
6
  name: z.ZodString;
6
- direction: z.ZodOptional<z.ZodEnum<{
7
+ direction: z.ZodEnum<{
7
8
  in: "in";
8
9
  out: "out";
9
10
  inout: "inout";
10
- }>>;
11
+ }>;
11
12
  label: z.ZodOptional<z.ZodString>;
12
13
  data: z.ZodAny;
13
14
  x: z.ZodOptional<z.ZodNumber>;
@@ -32,11 +33,11 @@ declare const NodeSchema: z.ZodObject<{
32
33
  style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
33
34
  ports: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
35
  name: z.ZodString;
35
- direction: z.ZodOptional<z.ZodEnum<{
36
+ direction: z.ZodEnum<{
36
37
  in: "in";
37
38
  out: "out";
38
39
  inout: "inout";
39
- }>>;
40
+ }>;
40
41
  label: z.ZodOptional<z.ZodString>;
41
42
  data: z.ZodAny;
42
43
  x: z.ZodOptional<z.ZodNumber>;
@@ -86,11 +87,11 @@ declare const GraphSchema: z.ZodObject<{
86
87
  style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
87
88
  ports: z.ZodOptional<z.ZodArray<z.ZodObject<{
88
89
  name: z.ZodString;
89
- direction: z.ZodOptional<z.ZodEnum<{
90
+ direction: z.ZodEnum<{
90
91
  in: "in";
91
92
  out: "out";
92
93
  inout: "inout";
93
- }>>;
94
+ }>;
94
95
  label: z.ZodOptional<z.ZodString>;
95
96
  data: z.ZodAny;
96
97
  x: z.ZodOptional<z.ZodNumber>;
@@ -126,5 +127,19 @@ declare const GraphSchema: z.ZodObject<{
126
127
  }>>;
127
128
  style: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
128
129
  }, z.core.$strip>;
130
+ interface GraphValidationIssue {
131
+ code: string;
132
+ message: string;
133
+ path: Array<string | number>;
134
+ }
135
+ declare function isGraphPort(value: unknown): value is GraphPort;
136
+ declare function isGraphNode(value: unknown): value is GraphNode;
137
+ declare function isGraphEdge(value: unknown): value is GraphEdge;
138
+ declare function isGraph(value: unknown): value is Graph;
139
+ declare function getGraphPortIssues(value: unknown): GraphValidationIssue[];
140
+ declare function getGraphNodeIssues(value: unknown): GraphValidationIssue[];
141
+ declare function getGraphEdgeIssues(value: unknown): GraphValidationIssue[];
142
+ declare function getGraphIssues(value: unknown): GraphValidationIssue[];
143
+ declare function validateGraph(value: unknown): GraphValidationIssue[];
129
144
  //#endregion
130
- export { EdgeSchema, GraphSchema, NodeSchema, PortSchema };
145
+ export { EdgeSchema, GraphSchema, GraphValidationIssue, NodeSchema, PortSchema, getGraphEdgeIssues, getGraphIssues, getGraphNodeIssues, getGraphPortIssues, isGraph, isGraphEdge, isGraphNode, isGraphPort, validateGraph };