@statelyai/graph 1.0.0 → 2.1.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 +121 -44
- package/dist/{adjacency-list-VsUaH9SJ.mjs → adjacency-list-DQ32Mmhx.mjs} +3 -1
- package/dist/algorithms-D1cgly0g.d.mts +452 -0
- package/dist/algorithms-DBpH74hR.mjs +3309 -0
- package/dist/algorithms.d.mts +2 -2
- package/dist/algorithms.mjs +2 -2
- package/dist/config-Dt5u1gSf.mjs +793 -0
- package/dist/{converter-udLITX36.mjs → converter-DB6Rg6Vd.mjs} +2 -2
- package/dist/format-support.mjs +38 -11
- 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 +4 -4
- package/dist/formats/cytoscape/index.mjs +10 -4
- package/dist/formats/d2/index.d.mts +1 -1
- package/dist/formats/d2/index.mjs +26 -12
- package/dist/formats/d3/index.d.mts +4 -4
- package/dist/formats/d3/index.mjs +10 -4
- package/dist/formats/dot/index.d.mts +1 -1
- package/dist/formats/dot/index.mjs +22 -6
- package/dist/formats/edge-list/index.d.mts +1 -1
- package/dist/formats/edge-list/index.mjs +1 -1
- package/dist/formats/elk/index.d.mts +1 -1
- package/dist/formats/elk/index.mjs +63 -24
- package/dist/formats/gexf/index.d.mts +1 -1
- package/dist/formats/gexf/index.mjs +43 -16
- package/dist/formats/gml/index.d.mts +4 -4
- package/dist/formats/gml/index.mjs +28 -15
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/graphml/index.mjs +96 -23
- package/dist/formats/jgf/index.d.mts +4 -4
- package/dist/formats/jgf/index.mjs +12 -5
- package/dist/formats/mermaid/index.d.mts +1 -1
- package/dist/formats/mermaid/index.mjs +49 -12
- package/dist/formats/tgf/index.d.mts +4 -4
- package/dist/formats/tgf/index.mjs +4 -4
- package/dist/formats/xyflow/index.d.mts +12 -6
- package/dist/formats/xyflow/index.mjs +42 -10
- package/dist/{index-D9Kj6Fe3.d.mts → index-BlbSWUvH.d.mts} +1 -1
- package/dist/{index-CHoriXZD.d.mts → index-CNvqxPLJ.d.mts} +157 -30
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +290 -307
- package/dist/layout/cytoscape.d.mts +66 -0
- package/dist/layout/cytoscape.mjs +114 -0
- package/dist/layout/d3-force.d.mts +52 -0
- package/dist/layout/d3-force.mjs +127 -0
- package/dist/layout/d3-hierarchy.d.mts +39 -0
- package/dist/layout/d3-hierarchy.mjs +135 -0
- package/dist/layout/dagre.d.mts +32 -0
- package/dist/layout/dagre.mjs +99 -0
- package/dist/layout/elk.d.mts +47 -0
- package/dist/layout/elk.mjs +73 -0
- package/dist/layout/forceatlas2.d.mts +48 -0
- package/dist/layout/forceatlas2.mjs +100 -0
- package/dist/layout/graphviz.d.mts +50 -0
- package/dist/layout/graphviz.mjs +179 -0
- package/dist/layout/index.d.mts +185 -0
- package/dist/layout/index.mjs +181 -0
- package/dist/layout/webcola.d.mts +40 -0
- package/dist/layout/webcola.mjs +104 -0
- package/dist/{queries-BlkA1HAN.d.mts → queries-B6quF529.d.mts} +43 -12
- package/dist/queries-BMM0XAv_.mjs +986 -0
- package/dist/queries.d.mts +1 -1
- package/dist/queries.mjs +1 -768
- package/dist/schemas.d.mts +19 -1
- package/dist/schemas.mjs +32 -84
- package/dist/{types-3-FS9NV2.d.mts → types-BAEQTwK_.d.mts} +99 -7
- package/dist/validate-BsfSOv0S.mjs +190 -0
- package/package.json +59 -7
- package/schemas/edge.schema.json +27 -0
- package/schemas/graph.schema.json +27 -0
- package/dist/algorithms-Ba7o7niK.mjs +0 -2394
- package/dist/algorithms-fTqmvhzP.d.mts +0 -178
- package/dist/indexing-DR8M1vBy.mjs +0 -137
- /package/dist/{edge-list-DP4otyPU.mjs → edge-list-CA9UTvn2.mjs} +0 -0
- /package/dist/{mode-D8OnHFBk.mjs → mode-gu_mhKKs.mjs} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getChildren } from "../../queries.mjs";
|
|
1
|
+
import { n as getChildren } from "../../queries-BMM0XAv_.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/elk/index.ts
|
|
4
4
|
const STATELYAI_METADATA_KEY = "statelyai.metadata";
|
|
@@ -33,16 +33,21 @@ const ELK_TO_DIRECTION = {
|
|
|
33
33
|
function convertEdge(edge) {
|
|
34
34
|
const elkEdge = {
|
|
35
35
|
id: edge.id,
|
|
36
|
-
sources: [edge.sourcePort
|
|
37
|
-
targets: [edge.targetPort
|
|
36
|
+
sources: [edge.sourcePort != null ? `${edge.sourceId}__${edge.sourcePort}` : edge.sourceId],
|
|
37
|
+
targets: [edge.targetPort != null ? `${edge.targetId}__${edge.targetPort}` : edge.targetId]
|
|
38
38
|
};
|
|
39
|
-
if (edge.label) elkEdge.labels = [{
|
|
39
|
+
if (edge.label) elkEdge.labels = [{
|
|
40
|
+
text: edge.label,
|
|
41
|
+
...edge.width > 0 && { width: edge.width },
|
|
42
|
+
...edge.height > 0 && { height: edge.height }
|
|
43
|
+
}];
|
|
40
44
|
return addMetadata(elkEdge, { edge: {
|
|
41
45
|
sourceId: edge.sourceId,
|
|
42
46
|
targetId: edge.targetId,
|
|
43
47
|
sourcePort: edge.sourcePort,
|
|
44
48
|
targetPort: edge.targetPort,
|
|
45
49
|
label: edge.label,
|
|
50
|
+
mode: edge.mode,
|
|
46
51
|
data: edge.data,
|
|
47
52
|
weight: edge.weight,
|
|
48
53
|
color: edge.color,
|
|
@@ -50,12 +55,14 @@ function convertEdge(edge) {
|
|
|
50
55
|
x: edge.x,
|
|
51
56
|
y: edge.y,
|
|
52
57
|
width: edge.width,
|
|
53
|
-
height: edge.height
|
|
58
|
+
height: edge.height,
|
|
59
|
+
points: edge.points,
|
|
60
|
+
routing: edge.routing
|
|
54
61
|
} });
|
|
55
62
|
}
|
|
56
|
-
function convertPort(port) {
|
|
63
|
+
function convertPort(nodeId, port) {
|
|
57
64
|
const elkPort = {
|
|
58
|
-
id: port.name
|
|
65
|
+
id: `${nodeId}__${port.name}`,
|
|
59
66
|
x: port.x,
|
|
60
67
|
y: port.y,
|
|
61
68
|
width: port.width,
|
|
@@ -64,6 +71,7 @@ function convertPort(port) {
|
|
|
64
71
|
if (port.label) elkPort.labels = [{ text: port.label }];
|
|
65
72
|
if (port.direction !== "inout") elkPort.layoutOptions = { "org.eclipse.elk.port.side": port.direction === "in" ? "WEST" : "EAST" };
|
|
66
73
|
return addMetadata(elkPort, { port: {
|
|
74
|
+
name: port.name,
|
|
67
75
|
data: port.data,
|
|
68
76
|
style: port.style
|
|
69
77
|
} });
|
|
@@ -77,7 +85,7 @@ function convertNode(graph, node) {
|
|
|
77
85
|
height: node.height
|
|
78
86
|
};
|
|
79
87
|
if (node.label) elkNode.labels = [{ text: node.label }];
|
|
80
|
-
if (node.ports && node.ports.length > 0) elkNode.ports = node.ports.map(convertPort);
|
|
88
|
+
if (node.ports && node.ports.length > 0) elkNode.ports = node.ports.map((port) => convertPort(node.id, port));
|
|
81
89
|
addMetadata(elkNode, { node: {
|
|
82
90
|
initialNodeId: node.initialNodeId,
|
|
83
91
|
data: node.data,
|
|
@@ -146,7 +154,7 @@ function toELK(graph) {
|
|
|
146
154
|
if (rootEdges.length > 0) root.edges = rootEdges.map(convertEdge);
|
|
147
155
|
return root;
|
|
148
156
|
}
|
|
149
|
-
function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
157
|
+
function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner, edgeRouting) {
|
|
150
158
|
if (elkNode.children) for (const child of elkNode.children) {
|
|
151
159
|
const label = child.labels?.[0]?.text ?? "";
|
|
152
160
|
const metadata = readMetadata(child)?.node;
|
|
@@ -166,14 +174,18 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
|
166
174
|
...metadata?.style !== void 0 && { style: metadata.style }
|
|
167
175
|
};
|
|
168
176
|
if (child.ports && child.ports.length > 0) node.ports = child.ports.map((elkPort) => {
|
|
169
|
-
portOwner.set(elkPort.id, child.id);
|
|
170
177
|
const metadata$1 = readMetadata(elkPort)?.port;
|
|
178
|
+
const portName = metadata$1?.name ?? elkPort.id;
|
|
179
|
+
portOwner.set(elkPort.id, {
|
|
180
|
+
nodeId: child.id,
|
|
181
|
+
portName
|
|
182
|
+
});
|
|
171
183
|
const sideOpt = elkPort.layoutOptions?.["org.eclipse.elk.port.side"];
|
|
172
184
|
let direction = "inout";
|
|
173
185
|
if (sideOpt === "WEST") direction = "in";
|
|
174
186
|
else if (sideOpt === "EAST") direction = "out";
|
|
175
187
|
return {
|
|
176
|
-
name:
|
|
188
|
+
name: portName,
|
|
177
189
|
direction,
|
|
178
190
|
label: elkPort.labels?.[0]?.text,
|
|
179
191
|
data: metadata$1 && "data" in metadata$1 ? metadata$1.data : void 0,
|
|
@@ -185,31 +197,55 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
|
185
197
|
};
|
|
186
198
|
});
|
|
187
199
|
nodes.push(node);
|
|
188
|
-
flattenElkNodes(child, child.id, nodes, edges, edgeIdx, portOwner);
|
|
200
|
+
flattenElkNodes(child, child.id, nodes, edges, edgeIdx, portOwner, edgeRouting);
|
|
189
201
|
}
|
|
190
202
|
if (elkNode.edges) for (const elkEdge of elkNode.edges) for (const source of elkEdge.sources) for (const target of elkEdge.targets) {
|
|
191
203
|
const metadata = readMetadata(elkEdge)?.edge;
|
|
192
|
-
const
|
|
193
|
-
const
|
|
204
|
+
const sourceOwner = portOwner.get(source);
|
|
205
|
+
const targetOwner = portOwner.get(target);
|
|
206
|
+
const elkLabel = elkEdge.labels?.[0];
|
|
207
|
+
const hasComputedLabel = elkLabel?.x !== void 0 && elkLabel?.y !== void 0;
|
|
208
|
+
const section = elkEdge.sections?.[0];
|
|
194
209
|
const edge = {
|
|
195
210
|
type: "edge",
|
|
196
211
|
id: elkEdge.id ?? `e${edgeIdx.value++}`,
|
|
197
|
-
sourceId: metadata?.sourceId ??
|
|
198
|
-
targetId: metadata?.targetId ??
|
|
199
|
-
label: metadata && "label" in metadata ? metadata.label :
|
|
212
|
+
sourceId: metadata?.sourceId ?? sourceOwner?.nodeId ?? source,
|
|
213
|
+
targetId: metadata?.targetId ?? targetOwner?.nodeId ?? target,
|
|
214
|
+
label: metadata && "label" in metadata ? metadata.label : elkLabel?.text ?? "",
|
|
200
215
|
data: metadata && "data" in metadata ? metadata.data : void 0,
|
|
201
|
-
x: metadata?.x ?? 0,
|
|
202
|
-
y: metadata?.y ?? 0,
|
|
203
|
-
width: metadata?.width ?? 0,
|
|
204
|
-
height: metadata?.height ?? 0,
|
|
216
|
+
x: hasComputedLabel ? elkLabel.x : metadata?.x ?? 0,
|
|
217
|
+
y: hasComputedLabel ? elkLabel.y : metadata?.y ?? 0,
|
|
218
|
+
width: hasComputedLabel ? elkLabel.width ?? metadata?.width ?? 0 : metadata?.width ?? 0,
|
|
219
|
+
height: hasComputedLabel ? elkLabel.height ?? metadata?.height ?? 0 : metadata?.height ?? 0,
|
|
220
|
+
...metadata?.mode !== void 0 && { mode: metadata.mode },
|
|
205
221
|
...metadata?.weight !== void 0 && { weight: metadata.weight },
|
|
206
222
|
...metadata?.color !== void 0 && { color: metadata.color },
|
|
207
223
|
...metadata?.style !== void 0 && { style: metadata.style }
|
|
208
224
|
};
|
|
225
|
+
if (section?.startPoint && section.endPoint) {
|
|
226
|
+
edge.points = [
|
|
227
|
+
{
|
|
228
|
+
x: section.startPoint.x,
|
|
229
|
+
y: section.startPoint.y
|
|
230
|
+
},
|
|
231
|
+
...(section.bendPoints ?? []).map((p) => ({
|
|
232
|
+
x: p.x,
|
|
233
|
+
y: p.y
|
|
234
|
+
})),
|
|
235
|
+
{
|
|
236
|
+
x: section.endPoint.x,
|
|
237
|
+
y: section.endPoint.y
|
|
238
|
+
}
|
|
239
|
+
];
|
|
240
|
+
edge.routing = edgeRouting;
|
|
241
|
+
} else if (metadata?.points !== void 0) {
|
|
242
|
+
edge.points = metadata.points;
|
|
243
|
+
if (metadata.routing !== void 0) edge.routing = metadata.routing;
|
|
244
|
+
}
|
|
209
245
|
if (metadata && "sourcePort" in metadata) edge.sourcePort = metadata.sourcePort;
|
|
210
|
-
else if (
|
|
246
|
+
else if (sourceOwner) edge.sourcePort = sourceOwner.portName;
|
|
211
247
|
if (metadata && "targetPort" in metadata) edge.targetPort = metadata.targetPort;
|
|
212
|
-
else if (
|
|
248
|
+
else if (targetOwner) edge.targetPort = targetOwner.portName;
|
|
213
249
|
edges.push(edge);
|
|
214
250
|
}
|
|
215
251
|
}
|
|
@@ -236,7 +272,10 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
|
236
272
|
function fromELK(elkRoot) {
|
|
237
273
|
const nodes = [];
|
|
238
274
|
const edges = [];
|
|
239
|
-
|
|
275
|
+
const edgeIdx = { value: 0 };
|
|
276
|
+
const portOwner = /* @__PURE__ */ new Map();
|
|
277
|
+
const elkEdgeRouting = String(elkRoot.layoutOptions?.["elk.edgeRouting"] ?? elkRoot.layoutOptions?.["org.eclipse.elk.edgeRouting"] ?? "").toUpperCase();
|
|
278
|
+
flattenElkNodes(elkRoot, null, nodes, edges, edgeIdx, portOwner, elkEdgeRouting === "SPLINES" ? "splines" : elkEdgeRouting === "POLYLINE" ? "polyline" : "orthogonal");
|
|
240
279
|
const seenEdges = /* @__PURE__ */ new Map();
|
|
241
280
|
for (const edge of edges) if (!seenEdges.has(edge.id)) seenEdges.set(edge.id, edge);
|
|
242
281
|
const elkDir = elkRoot.layoutOptions?.["elk.direction"];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getEdgeMode } from "../../mode-
|
|
2
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { t as getEdgeMode } from "../../mode-gu_mhKKs.mjs";
|
|
2
|
+
import { n as createFormatConverter } from "../../converter-DB6Rg6Vd.mjs";
|
|
3
3
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
4
4
|
|
|
5
5
|
//#region src/formats/gexf/index.ts
|
|
@@ -82,6 +82,16 @@ function toGEXF(graph) {
|
|
|
82
82
|
"@_title": "style",
|
|
83
83
|
"@_type": "string"
|
|
84
84
|
},
|
|
85
|
+
{
|
|
86
|
+
"@_id": "a_edgePoints",
|
|
87
|
+
"@_title": "points",
|
|
88
|
+
"@_type": "string"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"@_id": "a_edgeRouting",
|
|
92
|
+
"@_title": "routing",
|
|
93
|
+
"@_type": "string"
|
|
94
|
+
},
|
|
85
95
|
{
|
|
86
96
|
"@_id": "a_sourcePort",
|
|
87
97
|
"@_title": "sourcePort",
|
|
@@ -129,7 +139,7 @@ function toGEXF(graph) {
|
|
|
129
139
|
});
|
|
130
140
|
const node = {
|
|
131
141
|
"@_id": n.id,
|
|
132
|
-
"@_label": n.label
|
|
142
|
+
"@_label": n.label ?? ""
|
|
133
143
|
};
|
|
134
144
|
if (n.parentId) node["@_pid"] = n.parentId;
|
|
135
145
|
if (attvalues.length > 0) node.attvalues = { attvalue: attvalues };
|
|
@@ -167,6 +177,14 @@ function toGEXF(graph) {
|
|
|
167
177
|
"@_for": "a_edgeWeight",
|
|
168
178
|
"@_value": e.weight
|
|
169
179
|
});
|
|
180
|
+
if (e.points !== void 0) edgeAttvalues.push({
|
|
181
|
+
"@_for": "a_edgePoints",
|
|
182
|
+
"@_value": JSON.stringify(e.points)
|
|
183
|
+
});
|
|
184
|
+
if (e.routing !== void 0) edgeAttvalues.push({
|
|
185
|
+
"@_for": "a_edgeRouting",
|
|
186
|
+
"@_value": e.routing
|
|
187
|
+
});
|
|
170
188
|
if (e.x !== void 0) edgeAttvalues.push({
|
|
171
189
|
"@_for": "a_edgeX",
|
|
172
190
|
"@_value": e.x
|
|
@@ -250,7 +268,8 @@ function fromGEXF(xml) {
|
|
|
250
268
|
"attribute",
|
|
251
269
|
"attvalue",
|
|
252
270
|
"attributes"
|
|
253
|
-
].includes(name)
|
|
271
|
+
].includes(name),
|
|
272
|
+
trimValues: false
|
|
254
273
|
});
|
|
255
274
|
let parsed;
|
|
256
275
|
try {
|
|
@@ -283,16 +302,16 @@ function fromGEXF(xml) {
|
|
|
283
302
|
if (attvals["ports"] !== void 0) node.ports = tryParseJSON(attvals["ports"]);
|
|
284
303
|
const pos = n["viz:position"];
|
|
285
304
|
if (pos) {
|
|
286
|
-
node.x =
|
|
287
|
-
node.y =
|
|
305
|
+
node.x = parseNumber(pos["@_x"] ?? 0, "<viz:position> x", "node", id);
|
|
306
|
+
node.y = parseNumber(pos["@_y"] ?? 0, "<viz:position> y", "node", id);
|
|
288
307
|
}
|
|
289
308
|
const size = n["viz:size"];
|
|
290
309
|
if (size) {
|
|
291
|
-
node.width =
|
|
292
|
-
node.height =
|
|
310
|
+
node.width = parseNumber(size["@_value"] ?? 0, "<viz:size>", "node", id);
|
|
311
|
+
node.height = node.width;
|
|
293
312
|
}
|
|
294
|
-
if (attvals["width"] !== void 0) node.width =
|
|
295
|
-
if (attvals["height"] !== void 0) node.height =
|
|
313
|
+
if (attvals["width"] !== void 0) node.width = parseNumber(attvals["width"], "width attribute", "node", id);
|
|
314
|
+
if (attvals["height"] !== void 0) node.height = parseNumber(attvals["height"], "height attribute", "node", id);
|
|
296
315
|
const color = n["viz:color"];
|
|
297
316
|
if (color) {
|
|
298
317
|
const r = Number(color["@_r"] ?? 0);
|
|
@@ -308,18 +327,21 @@ function fromGEXF(xml) {
|
|
|
308
327
|
parseNodes(graphEl.nodes?.node ?? graphEl.node, null);
|
|
309
328
|
const edges = asArray(graphEl.edges?.edge ?? graphEl.edge).map((e, i) => {
|
|
310
329
|
const attvals = getAttValues(e, attrMap);
|
|
330
|
+
const id = String(e["@_id"] ?? `e${i}`);
|
|
311
331
|
const edge = {
|
|
312
332
|
type: "edge",
|
|
313
|
-
id
|
|
333
|
+
id,
|
|
314
334
|
sourceId: String(e["@_source"]),
|
|
315
335
|
targetId: String(e["@_target"]),
|
|
316
336
|
label: e["@_label"] ?? "",
|
|
317
337
|
data: attvals["data"] !== void 0 ? tryParseJSON(attvals["data"]) : void 0,
|
|
318
|
-
...attvals["weight"] !== void 0 && { weight:
|
|
319
|
-
...attvals["
|
|
320
|
-
...attvals["
|
|
321
|
-
...attvals["
|
|
322
|
-
...attvals["
|
|
338
|
+
...attvals["weight"] !== void 0 && { weight: parseNumber(attvals["weight"], "weight attribute", "edge", id) },
|
|
339
|
+
...attvals["points"] !== void 0 && { points: tryParseJSON(attvals["points"]) },
|
|
340
|
+
...attvals["routing"] !== void 0 && { routing: attvals["routing"] },
|
|
341
|
+
...attvals["x"] !== void 0 && { x: parseNumber(attvals["x"], "x attribute", "edge", id) },
|
|
342
|
+
...attvals["y"] !== void 0 && { y: parseNumber(attvals["y"], "y attribute", "edge", id) },
|
|
343
|
+
...attvals["width"] !== void 0 && { width: parseNumber(attvals["width"], "width attribute", "edge", id) },
|
|
344
|
+
...attvals["height"] !== void 0 && { height: parseNumber(attvals["height"], "height attribute", "edge", id) },
|
|
323
345
|
...attvals["style"] !== void 0 && { style: tryParseJSON(attvals["style"]) },
|
|
324
346
|
...attvals["sourcePort"] !== void 0 && { sourcePort: attvals["sourcePort"] },
|
|
325
347
|
...attvals["targetPort"] !== void 0 && { targetPort: attvals["targetPort"] }
|
|
@@ -366,6 +388,11 @@ function tryParseJSON(str) {
|
|
|
366
388
|
return str;
|
|
367
389
|
}
|
|
368
390
|
}
|
|
391
|
+
function parseNumber(value, field, kind, ownerId) {
|
|
392
|
+
const parsed = Number(value);
|
|
393
|
+
if (Number.isNaN(parsed)) throw new Error(`GEXF: ${field} value "${value}" on ${kind} "${ownerId}" is not a number. Fix the value or remove the attribute.`);
|
|
394
|
+
return parsed;
|
|
395
|
+
}
|
|
369
396
|
function hex(n) {
|
|
370
397
|
return n.toString(16).padStart(2, "0");
|
|
371
398
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as GraphFormatConverter, f as Graph } from "../../types-BAEQTwK_.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/gml/index.d.ts
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ import { h as GraphFormatConverter, u as Graph } from "../../types-3-FS9NV2.mjs"
|
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
10
|
* import { createGraph } from '@statelyai/graph';
|
|
11
|
-
* import { toGML } from '@statelyai/graph/
|
|
11
|
+
* import { toGML } from '@statelyai/graph/gml';
|
|
12
12
|
*
|
|
13
13
|
* const graph = createGraph({
|
|
14
14
|
* nodes: [{ id: 'a' }, { id: 'b' }],
|
|
@@ -30,7 +30,7 @@ declare function toGML(graph: Graph): string;
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```ts
|
|
33
|
-
* import { fromGML } from '@statelyai/graph/
|
|
33
|
+
* import { fromGML } from '@statelyai/graph/gml';
|
|
34
34
|
*
|
|
35
35
|
* const graph = fromGML(`
|
|
36
36
|
* graph [
|
|
@@ -49,7 +49,7 @@ declare function fromGML(gml: string): Graph;
|
|
|
49
49
|
* @example
|
|
50
50
|
* ```ts
|
|
51
51
|
* import { createGraph } from '@statelyai/graph';
|
|
52
|
-
* import { gmlConverter } from '@statelyai/graph/
|
|
52
|
+
* import { gmlConverter } from '@statelyai/graph/gml';
|
|
53
53
|
*
|
|
54
54
|
* const graph = createGraph({
|
|
55
55
|
* nodes: [{ id: 'a' }, { id: 'b' }],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DB6Rg6Vd.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/gml/index.ts
|
|
4
4
|
/**
|
|
@@ -7,7 +7,7 @@ import { n as createFormatConverter } from "../../converter-udLITX36.mjs";
|
|
|
7
7
|
* @example
|
|
8
8
|
* ```ts
|
|
9
9
|
* import { createGraph } from '@statelyai/graph';
|
|
10
|
-
* import { toGML } from '@statelyai/graph/
|
|
10
|
+
* import { toGML } from '@statelyai/graph/gml';
|
|
11
11
|
*
|
|
12
12
|
* const graph = createGraph({
|
|
13
13
|
* nodes: [{ id: 'a' }, { id: 'b' }],
|
|
@@ -27,6 +27,7 @@ function toGML(graph) {
|
|
|
27
27
|
const lines = [];
|
|
28
28
|
lines.push("graph [");
|
|
29
29
|
lines.push(` directed ${graph.mode === "undirected" ? 0 : 1}`);
|
|
30
|
+
if (graph.mode === "bidirectional") lines.push(` mode ${gmlString(graph.mode)}`);
|
|
30
31
|
if (graph.id) lines.push(` id ${gmlString(graph.id)}`);
|
|
31
32
|
if (graph.initialNodeId) lines.push(` initialNodeId ${gmlString(graph.initialNodeId)}`);
|
|
32
33
|
if (graph.data !== void 0) lines.push(` data ${gmlString(JSON.stringify(graph.data))}`);
|
|
@@ -67,9 +68,12 @@ function toGML(graph) {
|
|
|
67
68
|
lines.push(` id ${gmlString(edge.id)}`);
|
|
68
69
|
lines.push(` source ${gmlString(edge.sourceId)}`);
|
|
69
70
|
lines.push(` target ${gmlString(edge.targetId)}`);
|
|
71
|
+
if (edge.mode) lines.push(` mode ${gmlString(edge.mode)}`);
|
|
70
72
|
if (edge.label) lines.push(` label ${gmlString(edge.label)}`);
|
|
71
73
|
if (edge.data !== void 0) lines.push(` data ${gmlString(JSON.stringify(edge.data))}`);
|
|
72
74
|
if (edge.weight !== void 0) lines.push(` weight ${edge.weight}`);
|
|
75
|
+
if (edge.points !== void 0) lines.push(` points ${gmlString(JSON.stringify(edge.points))}`);
|
|
76
|
+
if (edge.routing !== void 0) lines.push(` routing ${gmlString(edge.routing)}`);
|
|
73
77
|
if (edge.sourcePort !== void 0) lines.push(` sourcePort ${gmlString(edge.sourcePort)}`);
|
|
74
78
|
if (edge.targetPort !== void 0) lines.push(` targetPort ${gmlString(edge.targetPort)}`);
|
|
75
79
|
if (edge.color) lines.push(` color ${gmlString(edge.color)}`);
|
|
@@ -95,7 +99,7 @@ function gmlString(s) {
|
|
|
95
99
|
*
|
|
96
100
|
* @example
|
|
97
101
|
* ```ts
|
|
98
|
-
* import { fromGML } from '@statelyai/graph/
|
|
102
|
+
* import { fromGML } from '@statelyai/graph/gml';
|
|
99
103
|
*
|
|
100
104
|
* const graph = fromGML(`
|
|
101
105
|
* graph [
|
|
@@ -134,10 +138,10 @@ function fromGML(gml) {
|
|
|
134
138
|
...n["shape"] && { shape: n["shape"] },
|
|
135
139
|
...n["color"] && { color: n["color"] },
|
|
136
140
|
...n["style"] !== void 0 && { style: tryParseJSON(n["style"]) },
|
|
137
|
-
...gfx?.x !== void 0 && { x: gfx.x },
|
|
138
|
-
...gfx?.y !== void 0 && { y: gfx.y },
|
|
139
|
-
...gfx?.w !== void 0 && { width: gfx.w },
|
|
140
|
-
...gfx?.h !== void 0 && { height: gfx.h }
|
|
141
|
+
...gfx?.x !== void 0 && { x: parseNumber(gfx.x, "graphics x", "node", id) },
|
|
142
|
+
...gfx?.y !== void 0 && { y: parseNumber(gfx.y, "graphics y", "node", id) },
|
|
143
|
+
...gfx?.w !== void 0 && { width: parseNumber(gfx.w, "graphics w", "node", id) },
|
|
144
|
+
...gfx?.h !== void 0 && { height: parseNumber(gfx.h, "graphics h", "node", id) }
|
|
141
145
|
});
|
|
142
146
|
if (n["node"] !== void 0) parseNodes(n, id);
|
|
143
147
|
}
|
|
@@ -146,27 +150,31 @@ function fromGML(gml) {
|
|
|
146
150
|
const edgeEntries = asArray(graphBlock["edge"]);
|
|
147
151
|
for (const e of edgeEntries) {
|
|
148
152
|
const gfx = e["graphics"];
|
|
153
|
+
const id = String(e["id"] ?? `e${edges.length}`);
|
|
149
154
|
edges.push({
|
|
150
155
|
type: "edge",
|
|
151
|
-
id
|
|
156
|
+
id,
|
|
152
157
|
sourceId: String(e["source"] ?? ""),
|
|
153
158
|
targetId: String(e["target"] ?? ""),
|
|
154
159
|
label: e["label"] ?? "",
|
|
160
|
+
...e["mode"] && { mode: String(e["mode"]) },
|
|
155
161
|
data: e["data"] !== void 0 ? tryParseJSON(e["data"]) : void 0,
|
|
156
|
-
...e["weight"] !== void 0 && { weight:
|
|
162
|
+
...e["weight"] !== void 0 && { weight: parseNumber(e["weight"], "weight", "edge", id) },
|
|
163
|
+
...e["points"] !== void 0 && { points: tryParseJSON(e["points"]) },
|
|
164
|
+
...e["routing"] !== void 0 && { routing: String(e["routing"]) },
|
|
157
165
|
...e["sourcePort"] !== void 0 && { sourcePort: String(e["sourcePort"]) },
|
|
158
166
|
...e["targetPort"] !== void 0 && { targetPort: String(e["targetPort"]) },
|
|
159
167
|
...e["color"] && { color: e["color"] },
|
|
160
168
|
...e["style"] !== void 0 && { style: tryParseJSON(e["style"]) },
|
|
161
|
-
...gfx?.x !== void 0 && { x: gfx.x },
|
|
162
|
-
...gfx?.y !== void 0 && { y: gfx.y },
|
|
163
|
-
...gfx?.w !== void 0 && { width: gfx.w },
|
|
164
|
-
...gfx?.h !== void 0 && { height: gfx.h }
|
|
169
|
+
...gfx?.x !== void 0 && { x: parseNumber(gfx.x, "graphics x", "edge", id) },
|
|
170
|
+
...gfx?.y !== void 0 && { y: parseNumber(gfx.y, "graphics y", "edge", id) },
|
|
171
|
+
...gfx?.w !== void 0 && { width: parseNumber(gfx.w, "graphics w", "edge", id) },
|
|
172
|
+
...gfx?.h !== void 0 && { height: parseNumber(gfx.h, "graphics h", "edge", id) }
|
|
165
173
|
});
|
|
166
174
|
}
|
|
167
175
|
return {
|
|
168
176
|
id: graphId,
|
|
169
|
-
mode: directed ? "directed" : "undirected",
|
|
177
|
+
mode: graphBlock["mode"] ? String(graphBlock["mode"]) : directed ? "directed" : "undirected",
|
|
170
178
|
initialNodeId: graphBlock["initialNodeId"] ?? null,
|
|
171
179
|
nodes,
|
|
172
180
|
edges,
|
|
@@ -301,13 +309,18 @@ function tryParseJSON(str) {
|
|
|
301
309
|
return str;
|
|
302
310
|
}
|
|
303
311
|
}
|
|
312
|
+
function parseNumber(value, field, kind, ownerId) {
|
|
313
|
+
const parsed = Number(value);
|
|
314
|
+
if (Number.isNaN(parsed)) throw new Error(`GML: ${field} value "${value}" on ${kind} "${ownerId}" is not a number. Fix the value or remove the attribute.`);
|
|
315
|
+
return parsed;
|
|
316
|
+
}
|
|
304
317
|
/**
|
|
305
318
|
* Bidirectional converter for GML (Graph Modelling Language) format.
|
|
306
319
|
*
|
|
307
320
|
* @example
|
|
308
321
|
* ```ts
|
|
309
322
|
* import { createGraph } from '@statelyai/graph';
|
|
310
|
-
* import { gmlConverter } from '@statelyai/graph/
|
|
323
|
+
* import { gmlConverter } from '@statelyai/graph/gml';
|
|
311
324
|
*
|
|
312
325
|
* const graph = createGraph({
|
|
313
326
|
* nodes: [{ id: 'a' }, { id: 'b' }],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getEdgeMode } from "../../mode-
|
|
2
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { t as getEdgeMode } from "../../mode-gu_mhKKs.mjs";
|
|
2
|
+
import { n as createFormatConverter } from "../../converter-DB6Rg6Vd.mjs";
|
|
3
3
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
4
4
|
|
|
5
5
|
//#region src/formats/graphml/index.ts
|
|
@@ -102,6 +102,18 @@ function toGraphML(graph) {
|
|
|
102
102
|
"@_attr.name": "weight",
|
|
103
103
|
"@_attr.type": "double"
|
|
104
104
|
},
|
|
105
|
+
{
|
|
106
|
+
"@_id": "points",
|
|
107
|
+
"@_for": "edge",
|
|
108
|
+
"@_attr.name": "points",
|
|
109
|
+
"@_attr.type": "string"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"@_id": "routing",
|
|
113
|
+
"@_for": "edge",
|
|
114
|
+
"@_attr.name": "routing",
|
|
115
|
+
"@_attr.type": "string"
|
|
116
|
+
},
|
|
105
117
|
{
|
|
106
118
|
"@_id": "ports",
|
|
107
119
|
"@_for": "node",
|
|
@@ -216,6 +228,14 @@ function toGraphML(graph) {
|
|
|
216
228
|
"@_key": "weight",
|
|
217
229
|
"#text": edge.weight
|
|
218
230
|
});
|
|
231
|
+
if (edge.points !== void 0) data.push({
|
|
232
|
+
"@_key": "points",
|
|
233
|
+
"#text": JSON.stringify(edge.points)
|
|
234
|
+
});
|
|
235
|
+
if (edge.routing !== void 0) data.push({
|
|
236
|
+
"@_key": "routing",
|
|
237
|
+
"#text": edge.routing
|
|
238
|
+
});
|
|
219
239
|
if (edge.sourcePort !== void 0) data.push({
|
|
220
240
|
"@_key": "sourcePort",
|
|
221
241
|
"#text": edge.sourcePort
|
|
@@ -281,8 +301,12 @@ function fromGraphML(xml) {
|
|
|
281
301
|
"node",
|
|
282
302
|
"edge",
|
|
283
303
|
"data",
|
|
284
|
-
"key"
|
|
285
|
-
|
|
304
|
+
"key",
|
|
305
|
+
"graph",
|
|
306
|
+
"port"
|
|
307
|
+
].includes(name),
|
|
308
|
+
parseTagValue: false,
|
|
309
|
+
trimValues: false
|
|
286
310
|
});
|
|
287
311
|
let parsed;
|
|
288
312
|
try {
|
|
@@ -292,50 +316,79 @@ function fromGraphML(xml) {
|
|
|
292
316
|
}
|
|
293
317
|
const graphml = parsed?.graphml;
|
|
294
318
|
if (!graphml) throw new Error("GraphML: missing <graphml> root element");
|
|
295
|
-
const graphEl = graphml.graph;
|
|
319
|
+
const graphEl = asArray(graphml.graph)[0];
|
|
296
320
|
if (!graphEl) throw new Error("GraphML: missing <graph> element");
|
|
297
321
|
const graphType = graphEl["@_edgedefault"] === "undirected" ? "undirected" : "directed";
|
|
298
322
|
const graphDataMap = parseDataElements(graphEl.data);
|
|
299
323
|
const graphData = graphDataMap.graphData !== void 0 ? tryParseJSON(graphDataMap.graphData) : void 0;
|
|
300
|
-
const
|
|
324
|
+
const nodeEntries = [];
|
|
325
|
+
const edgeEls = [];
|
|
326
|
+
function collectGraphContents(gEl, parentId) {
|
|
327
|
+
for (const nodeEl of asArray(gEl.node)) {
|
|
328
|
+
nodeEntries.push({
|
|
329
|
+
el: nodeEl,
|
|
330
|
+
structuralParentId: parentId
|
|
331
|
+
});
|
|
332
|
+
for (const subgraphEl of asArray(nodeEl.graph)) collectGraphContents(subgraphEl, String(nodeEl["@_id"]));
|
|
333
|
+
}
|
|
334
|
+
edgeEls.push(...asArray(gEl.edge));
|
|
335
|
+
}
|
|
336
|
+
collectGraphContents(graphEl, null);
|
|
337
|
+
const nodes = nodeEntries.map(({ el: nodeEl, structuralParentId }) => {
|
|
301
338
|
const dataMap = parseDataElements(nodeEl.data);
|
|
339
|
+
const id = String(nodeEl["@_id"]);
|
|
302
340
|
const node = {
|
|
303
341
|
type: "node",
|
|
304
|
-
id
|
|
305
|
-
parentId: dataMap.parentId ??
|
|
342
|
+
id,
|
|
343
|
+
parentId: dataMap.parentId ?? structuralParentId,
|
|
306
344
|
initialNodeId: dataMap.initialNodeId ?? null,
|
|
307
345
|
label: dataMap.label ?? "",
|
|
308
346
|
data: dataMap.data !== void 0 ? tryParseJSON(dataMap.data) : void 0
|
|
309
347
|
};
|
|
310
|
-
if (dataMap.x !== void 0) node.x = parseNumber(dataMap.x);
|
|
311
|
-
if (dataMap.y !== void 0) node.y = parseNumber(dataMap.y);
|
|
312
|
-
if (dataMap.width !== void 0) node.width = parseNumber(dataMap.width);
|
|
313
|
-
if (dataMap.height !== void 0) node.height = parseNumber(dataMap.height);
|
|
348
|
+
if (dataMap.x !== void 0) node.x = parseNumber(dataMap.x, "x", "node", id);
|
|
349
|
+
if (dataMap.y !== void 0) node.y = parseNumber(dataMap.y, "y", "node", id);
|
|
350
|
+
if (dataMap.width !== void 0) node.width = parseNumber(dataMap.width, "width", "node", id);
|
|
351
|
+
if (dataMap.height !== void 0) node.height = parseNumber(dataMap.height, "height", "node", id);
|
|
314
352
|
if (dataMap.shape !== void 0) node.shape = dataMap.shape;
|
|
315
353
|
if (dataMap.color !== void 0) node.color = dataMap.color;
|
|
316
354
|
if (dataMap.style !== void 0) node.style = tryParseJSON(dataMap.style);
|
|
317
355
|
if (dataMap.ports !== void 0) node.ports = tryParseJSON(dataMap.ports);
|
|
356
|
+
else if (nodeEl.port !== void 0) node.ports = collectPorts(nodeEl.port);
|
|
318
357
|
return node;
|
|
319
358
|
});
|
|
320
|
-
const
|
|
359
|
+
const usedEdgeIds = new Set(edgeEls.filter((edgeEl) => edgeEl["@_id"] != null).map((edgeEl) => String(edgeEl["@_id"])));
|
|
360
|
+
const edges = edgeEls.map((edgeEl, i) => {
|
|
321
361
|
const dataMap = parseDataElements(edgeEl.data);
|
|
362
|
+
const source = String(edgeEl["@_source"]);
|
|
363
|
+
const target = String(edgeEl["@_target"]);
|
|
364
|
+
let id;
|
|
365
|
+
if (edgeEl["@_id"] != null) id = String(edgeEl["@_id"]);
|
|
366
|
+
else {
|
|
367
|
+
id = `${source}-${target}-${i}`;
|
|
368
|
+
for (let suffix = 0; usedEdgeIds.has(id); suffix++) id = `${source}-${target}-${i}#e${suffix}`;
|
|
369
|
+
usedEdgeIds.add(id);
|
|
370
|
+
}
|
|
322
371
|
const edge = {
|
|
323
372
|
type: "edge",
|
|
324
|
-
id
|
|
325
|
-
sourceId:
|
|
326
|
-
targetId:
|
|
373
|
+
id,
|
|
374
|
+
sourceId: source,
|
|
375
|
+
targetId: target,
|
|
327
376
|
label: dataMap.label ?? "",
|
|
328
377
|
data: dataMap.data !== void 0 ? tryParseJSON(dataMap.data) : void 0
|
|
329
378
|
};
|
|
330
|
-
if (dataMap.weight !== void 0) edge.weight = parseNumber(dataMap.weight);
|
|
331
|
-
if (dataMap.
|
|
332
|
-
if (dataMap.
|
|
333
|
-
if (dataMap.
|
|
334
|
-
if (dataMap.
|
|
379
|
+
if (dataMap.weight !== void 0) edge.weight = parseNumber(dataMap.weight, "weight", "edge", id);
|
|
380
|
+
if (dataMap.points !== void 0) edge.points = tryParseJSON(dataMap.points);
|
|
381
|
+
if (dataMap.routing !== void 0) edge.routing = dataMap.routing;
|
|
382
|
+
if (dataMap.x !== void 0) edge.x = parseNumber(dataMap.x, "x", "edge", id);
|
|
383
|
+
if (dataMap.y !== void 0) edge.y = parseNumber(dataMap.y, "y", "edge", id);
|
|
384
|
+
if (dataMap.width !== void 0) edge.width = parseNumber(dataMap.width, "width", "edge", id);
|
|
385
|
+
if (dataMap.height !== void 0) edge.height = parseNumber(dataMap.height, "height", "edge", id);
|
|
335
386
|
if (dataMap.color !== void 0) edge.color = dataMap.color;
|
|
336
387
|
if (dataMap.style !== void 0) edge.style = tryParseJSON(dataMap.style);
|
|
337
388
|
if (dataMap.sourcePort !== void 0) edge.sourcePort = dataMap.sourcePort;
|
|
389
|
+
else if (edgeEl["@_sourceport"] != null) edge.sourcePort = String(edgeEl["@_sourceport"]);
|
|
338
390
|
if (dataMap.targetPort !== void 0) edge.targetPort = dataMap.targetPort;
|
|
391
|
+
else if (edgeEl["@_targetport"] != null) edge.targetPort = String(edgeEl["@_targetport"]);
|
|
339
392
|
const directedAttr = edgeEl["@_directed"];
|
|
340
393
|
if (directedAttr !== void 0) edge.mode = String(directedAttr) === "false" ? "undirected" : "directed";
|
|
341
394
|
return edge;
|
|
@@ -368,8 +421,28 @@ function tryParseJSON(str) {
|
|
|
368
421
|
return str;
|
|
369
422
|
}
|
|
370
423
|
}
|
|
371
|
-
|
|
372
|
-
|
|
424
|
+
/**
|
|
425
|
+
* Flattens native GraphML <port> elements (which may nest) into our port
|
|
426
|
+
* shape. Standard GraphML ports carry only a name; direction is unknowable,
|
|
427
|
+
* so they import as advisory 'inout' with null data.
|
|
428
|
+
*/
|
|
429
|
+
function collectPorts(portEls) {
|
|
430
|
+
const ports = [];
|
|
431
|
+
for (const portEl of asArray(portEls)) {
|
|
432
|
+
if (portEl?.["@_name"] == null) continue;
|
|
433
|
+
ports.push({
|
|
434
|
+
name: String(portEl["@_name"]),
|
|
435
|
+
direction: "inout",
|
|
436
|
+
data: null
|
|
437
|
+
});
|
|
438
|
+
if (portEl.port !== void 0) ports.push(...collectPorts(portEl.port) ?? []);
|
|
439
|
+
}
|
|
440
|
+
return ports;
|
|
441
|
+
}
|
|
442
|
+
function parseNumber(value, key, kind, ownerId) {
|
|
443
|
+
const parsed = Number(value);
|
|
444
|
+
if (Number.isNaN(parsed)) throw new Error(`GraphML: <data key="${key}"> value "${value}" on ${kind} "${ownerId}" is not a number. Fix the value or remove the attribute.`);
|
|
445
|
+
return parsed;
|
|
373
446
|
}
|
|
374
447
|
function parseDirection(value) {
|
|
375
448
|
return [
|