@statelyai/graph 0.13.0 → 2.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.
- package/README.md +57 -26
- package/dist/{adjacency-list-Ca0VjKIf.mjs → adjacency-list-GeL1Cu-L.mjs} +5 -3
- package/dist/{algorithms-BlM-qoJb.d.mts → algorithms-CsGNehct.d.mts} +137 -2
- package/dist/{algorithms-BNDQcHU3.mjs → algorithms-DF1pSQGv.mjs} +1494 -357
- package/dist/algorithms.d.mts +2 -2
- package/dist/algorithms.mjs +2 -2
- package/dist/{converter-Dspillnn.mjs → converter-DyCJJfTe.mjs} +2 -2
- package/dist/{edge-list-gKe8-iRa.mjs → edge-list-BcZ0h6zz.mjs} +1 -1
- package/dist/format-support.mjs +67 -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 -60
- package/dist/formats/converter/index.mjs +1 -1
- package/dist/formats/cytoscape/index.d.mts +1 -1
- package/dist/formats/cytoscape/index.mjs +5 -3
- package/dist/formats/d2/index.d.mts +109 -0
- package/dist/formats/d2/index.mjs +1100 -0
- package/dist/formats/d3/index.d.mts +2 -2
- package/dist/formats/d3/index.mjs +5 -3
- package/dist/formats/dot/index.d.mts +1 -1
- package/dist/formats/dot/index.mjs +24 -8
- 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 +23 -16
- package/dist/formats/gexf/index.d.mts +1 -1
- package/dist/formats/gexf/index.mjs +30 -17
- package/dist/formats/gml/index.d.mts +1 -1
- package/dist/formats/gml/index.mjs +22 -13
- package/dist/formats/graphml/index.d.mts +1 -1
- package/dist/formats/graphml/index.mjs +83 -25
- package/dist/formats/jgf/index.d.mts +1 -1
- package/dist/formats/jgf/index.mjs +6 -3
- package/dist/formats/mermaid/index.d.mts +1 -1
- package/dist/formats/mermaid/index.mjs +57 -20
- package/dist/formats/tgf/index.d.mts +1 -1
- package/dist/formats/tgf/index.mjs +2 -2
- package/dist/formats/xyflow/index.d.mts +1 -1
- package/dist/formats/xyflow/index.mjs +33 -6
- package/dist/index-D51lJnt2.d.mts +61 -0
- package/dist/index-DWmo1mIp.d.mts +697 -0
- package/dist/index.d.mts +6 -631
- package/dist/index.mjs +144 -295
- package/dist/mode-D8OnHFBk.mjs +15 -0
- package/dist/queries-BfXeTXRf.d.mts +547 -0
- package/dist/queries-KirMDR7e.mjs +980 -0
- package/dist/queries.d.mts +1 -514
- package/dist/queries.mjs +1 -766
- package/dist/schemas.d.mts +21 -10
- package/dist/schemas.mjs +35 -86
- package/dist/{types-CnZ01raw.d.mts → types-DNYdIU21.d.mts} +83 -11
- package/dist/validate-TtH-x3JV.mjs +190 -0
- package/package.json +14 -3
- package/schemas/edge.schema.json +11 -0
- package/schemas/graph.schema.json +24 -3
- package/schemas/node.schema.json +6 -0
- package/dist/indexing-DUl3kTqm.mjs +0 -137
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as Graph, g as GraphFormatConverter } from "../../types-DNYdIU21.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/d3/index.d.ts
|
|
4
4
|
interface D3Node {
|
|
@@ -12,7 +12,7 @@ interface D3Link {
|
|
|
12
12
|
}
|
|
13
13
|
interface D3Graph {
|
|
14
14
|
id?: string;
|
|
15
|
-
|
|
15
|
+
mode?: Graph['mode'];
|
|
16
16
|
initialNodeId?: string | null;
|
|
17
17
|
data?: any;
|
|
18
18
|
direction?: Graph['direction'];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DyCJJfTe.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/d3/index.ts
|
|
4
4
|
/**
|
|
@@ -21,7 +21,7 @@ import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
|
|
|
21
21
|
function toD3Graph(graph) {
|
|
22
22
|
return {
|
|
23
23
|
...graph.id && { id: graph.id },
|
|
24
|
-
|
|
24
|
+
mode: graph.mode,
|
|
25
25
|
initialNodeId: graph.initialNodeId,
|
|
26
26
|
...graph.data !== void 0 && { data: graph.data },
|
|
27
27
|
...graph.direction && { direction: graph.direction },
|
|
@@ -49,6 +49,7 @@ function toD3Graph(graph) {
|
|
|
49
49
|
};
|
|
50
50
|
if (e.id) link.id = e.id;
|
|
51
51
|
if (e.label) link.label = e.label;
|
|
52
|
+
if (e.mode) link.mode = e.mode;
|
|
52
53
|
if (e.data !== void 0) link.data = e.data;
|
|
53
54
|
if (e.weight !== void 0) link.weight = e.weight;
|
|
54
55
|
if (e.x !== void 0) link.x = e.x;
|
|
@@ -82,7 +83,7 @@ function fromD3Graph(d3) {
|
|
|
82
83
|
if (!Array.isArray(d3.links)) throw new Error("D3: \"links\" must be an array");
|
|
83
84
|
return {
|
|
84
85
|
id: d3.id ?? "",
|
|
85
|
-
|
|
86
|
+
mode: d3.mode ?? "directed",
|
|
86
87
|
initialNodeId: d3.initialNodeId ?? null,
|
|
87
88
|
data: d3.data,
|
|
88
89
|
...d3.direction && { direction: d3.direction },
|
|
@@ -109,6 +110,7 @@ function fromD3Graph(d3) {
|
|
|
109
110
|
sourceId: typeof l.source === "string" ? l.source : l.source.id,
|
|
110
111
|
targetId: typeof l.target === "string" ? l.target : l.target.id,
|
|
111
112
|
label: l.label ?? "",
|
|
113
|
+
...l.mode && { mode: l.mode },
|
|
112
114
|
data: l.data,
|
|
113
115
|
...l.weight !== void 0 && { weight: l.weight },
|
|
114
116
|
...l.x !== void 0 && { x: l.x },
|
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DyCJJfTe.mjs";
|
|
2
2
|
import parse from "dotparser";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/dot/index.ts
|
|
5
|
+
/** DOT reserved keywords — must be quoted when used as identifiers. */
|
|
6
|
+
const DOT_KEYWORDS = new Set([
|
|
7
|
+
"node",
|
|
8
|
+
"edge",
|
|
9
|
+
"graph",
|
|
10
|
+
"digraph",
|
|
11
|
+
"subgraph",
|
|
12
|
+
"strict"
|
|
13
|
+
]);
|
|
5
14
|
/** Escape a DOT identifier */
|
|
6
15
|
function escapeId(id) {
|
|
7
|
-
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(id)) return id;
|
|
16
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(id) && !DOT_KEYWORDS.has(id.toLowerCase())) return id;
|
|
8
17
|
return `"${id.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
9
18
|
}
|
|
10
19
|
/** Escape a DOT label string */
|
|
11
20
|
function escapeLabel(label) {
|
|
12
|
-
return label.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
21
|
+
return label.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Invert {@link escapeLabel}. dotparser unescapes `\"` itself but passes
|
|
25
|
+
* `\\` and `\n` through verbatim.
|
|
26
|
+
*/
|
|
27
|
+
function unescapeLabel(label) {
|
|
28
|
+
return label.replace(/\\(\\|n)/g, (_, ch) => ch === "n" ? "\n" : "\\");
|
|
13
29
|
}
|
|
14
30
|
function formatEndpoint(id, port) {
|
|
15
31
|
return `${escapeId(id)}${port ? `:${escapeId(port)}` : ""}`;
|
|
@@ -50,7 +66,7 @@ const SHAPE_TO_DOT = {
|
|
|
50
66
|
* ```
|
|
51
67
|
*/
|
|
52
68
|
function toDOT(graph) {
|
|
53
|
-
const isDirected = graph.
|
|
69
|
+
const isDirected = graph.mode !== "undirected";
|
|
54
70
|
const keyword = isDirected ? "digraph" : "graph";
|
|
55
71
|
const edgeOp = isDirected ? "->" : "--";
|
|
56
72
|
const lines = [];
|
|
@@ -112,7 +128,7 @@ function nodeFromAttrs(id, attrs, defaults, parentId) {
|
|
|
112
128
|
...defaults,
|
|
113
129
|
...attrs
|
|
114
130
|
};
|
|
115
|
-
const label = merged["label"] ?? "";
|
|
131
|
+
const label = unescapeLabel(merged["label"] ?? "");
|
|
116
132
|
const rawShape = merged["shape"];
|
|
117
133
|
const shape = rawShape ? DOT_TO_SHAPE[rawShape] ?? rawShape : void 0;
|
|
118
134
|
const color = merged["fillcolor"] ?? merged["color"] ?? void 0;
|
|
@@ -235,7 +251,7 @@ function fromDOT(dot) {
|
|
|
235
251
|
id: `e${edgeIdx++}`,
|
|
236
252
|
sourceId: source.id,
|
|
237
253
|
targetId: target.id,
|
|
238
|
-
label: mergedEdgeAttrs["label"] ?? "",
|
|
254
|
+
label: unescapeLabel(mergedEdgeAttrs["label"] ?? ""),
|
|
239
255
|
data: void 0,
|
|
240
256
|
...source.port && { sourcePort: source.port },
|
|
241
257
|
...target.port && { targetPort: target.port },
|
|
@@ -251,7 +267,7 @@ function fromDOT(dot) {
|
|
|
251
267
|
let subLabel = "";
|
|
252
268
|
for (const child of stmt.children) if (child.type === "attr_stmt" && child.target === "graph") {
|
|
253
269
|
const ga = attrsToMap(child.attr_list);
|
|
254
|
-
if (ga["label"]) subLabel = ga["label"];
|
|
270
|
+
if (ga["label"]) subLabel = unescapeLabel(ga["label"]);
|
|
255
271
|
}
|
|
256
272
|
const subNode = {
|
|
257
273
|
type: "node",
|
|
@@ -270,7 +286,7 @@ function fromDOT(dot) {
|
|
|
270
286
|
walkChildren(root.children, null, {}, {});
|
|
271
287
|
return {
|
|
272
288
|
id: root.id ?? "",
|
|
273
|
-
|
|
289
|
+
mode: isDirected ? "directed" : "undirected",
|
|
274
290
|
initialNodeId: null,
|
|
275
291
|
nodes: [...nodeMap.values()],
|
|
276
292
|
edges,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { L as VisualGraphFormatConverter, P as VisualGraph } from "../../types-DNYdIU21.mjs";
|
|
2
2
|
import { ElkEdge, ElkEdgeSection, ElkExtendedEdge, ElkGraphElement, ElkLabel, ElkNode, ElkNode as ElkNode$1, ElkPoint, ElkPort, ElkPrimitiveEdge, ElkShape, LayoutOptions } from "elkjs/lib/elk-api";
|
|
3
3
|
|
|
4
4
|
//#region src/formats/elk/index.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getChildren } from "../../queries.mjs";
|
|
1
|
+
import { n as getChildren } from "../../queries-KirMDR7e.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/elk/index.ts
|
|
4
4
|
const STATELYAI_METADATA_KEY = "statelyai.metadata";
|
|
@@ -33,8 +33,8 @@ 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
39
|
if (edge.label) elkEdge.labels = [{ text: edge.label }];
|
|
40
40
|
return addMetadata(elkEdge, { edge: {
|
|
@@ -43,6 +43,7 @@ function convertEdge(edge) {
|
|
|
43
43
|
sourcePort: edge.sourcePort,
|
|
44
44
|
targetPort: edge.targetPort,
|
|
45
45
|
label: edge.label,
|
|
46
|
+
mode: edge.mode,
|
|
46
47
|
data: edge.data,
|
|
47
48
|
weight: edge.weight,
|
|
48
49
|
color: edge.color,
|
|
@@ -53,9 +54,9 @@ function convertEdge(edge) {
|
|
|
53
54
|
height: edge.height
|
|
54
55
|
} });
|
|
55
56
|
}
|
|
56
|
-
function convertPort(port) {
|
|
57
|
+
function convertPort(nodeId, port) {
|
|
57
58
|
const elkPort = {
|
|
58
|
-
id: port.name
|
|
59
|
+
id: `${nodeId}__${port.name}`,
|
|
59
60
|
x: port.x,
|
|
60
61
|
y: port.y,
|
|
61
62
|
width: port.width,
|
|
@@ -64,6 +65,7 @@ function convertPort(port) {
|
|
|
64
65
|
if (port.label) elkPort.labels = [{ text: port.label }];
|
|
65
66
|
if (port.direction !== "inout") elkPort.layoutOptions = { "org.eclipse.elk.port.side": port.direction === "in" ? "WEST" : "EAST" };
|
|
66
67
|
return addMetadata(elkPort, { port: {
|
|
68
|
+
name: port.name,
|
|
67
69
|
data: port.data,
|
|
68
70
|
style: port.style
|
|
69
71
|
} });
|
|
@@ -77,7 +79,7 @@ function convertNode(graph, node) {
|
|
|
77
79
|
height: node.height
|
|
78
80
|
};
|
|
79
81
|
if (node.label) elkNode.labels = [{ text: node.label }];
|
|
80
|
-
if (node.ports && node.ports.length > 0) elkNode.ports = node.ports.map(convertPort);
|
|
82
|
+
if (node.ports && node.ports.length > 0) elkNode.ports = node.ports.map((port) => convertPort(node.id, port));
|
|
81
83
|
addMetadata(elkNode, { node: {
|
|
82
84
|
initialNodeId: node.initialNodeId,
|
|
83
85
|
data: node.data,
|
|
@@ -128,7 +130,7 @@ function toELK(graph) {
|
|
|
128
130
|
if (elkDir) root.layoutOptions = { "elk.direction": elkDir };
|
|
129
131
|
addMetadata(root, { graph: {
|
|
130
132
|
id: graph.id,
|
|
131
|
-
|
|
133
|
+
mode: graph.mode,
|
|
132
134
|
initialNodeId: graph.initialNodeId,
|
|
133
135
|
data: graph.data,
|
|
134
136
|
direction: graph.direction,
|
|
@@ -166,14 +168,18 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
|
166
168
|
...metadata?.style !== void 0 && { style: metadata.style }
|
|
167
169
|
};
|
|
168
170
|
if (child.ports && child.ports.length > 0) node.ports = child.ports.map((elkPort) => {
|
|
169
|
-
portOwner.set(elkPort.id, child.id);
|
|
170
171
|
const metadata$1 = readMetadata(elkPort)?.port;
|
|
172
|
+
const portName = metadata$1?.name ?? elkPort.id;
|
|
173
|
+
portOwner.set(elkPort.id, {
|
|
174
|
+
nodeId: child.id,
|
|
175
|
+
portName
|
|
176
|
+
});
|
|
171
177
|
const sideOpt = elkPort.layoutOptions?.["org.eclipse.elk.port.side"];
|
|
172
178
|
let direction = "inout";
|
|
173
179
|
if (sideOpt === "WEST") direction = "in";
|
|
174
180
|
else if (sideOpt === "EAST") direction = "out";
|
|
175
181
|
return {
|
|
176
|
-
name:
|
|
182
|
+
name: portName,
|
|
177
183
|
direction,
|
|
178
184
|
label: elkPort.labels?.[0]?.text,
|
|
179
185
|
data: metadata$1 && "data" in metadata$1 ? metadata$1.data : void 0,
|
|
@@ -189,27 +195,28 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
|
189
195
|
}
|
|
190
196
|
if (elkNode.edges) for (const elkEdge of elkNode.edges) for (const source of elkEdge.sources) for (const target of elkEdge.targets) {
|
|
191
197
|
const metadata = readMetadata(elkEdge)?.edge;
|
|
192
|
-
const
|
|
193
|
-
const
|
|
198
|
+
const sourceOwner = portOwner.get(source);
|
|
199
|
+
const targetOwner = portOwner.get(target);
|
|
194
200
|
const edge = {
|
|
195
201
|
type: "edge",
|
|
196
202
|
id: elkEdge.id ?? `e${edgeIdx.value++}`,
|
|
197
|
-
sourceId: metadata?.sourceId ??
|
|
198
|
-
targetId: metadata?.targetId ??
|
|
203
|
+
sourceId: metadata?.sourceId ?? sourceOwner?.nodeId ?? source,
|
|
204
|
+
targetId: metadata?.targetId ?? targetOwner?.nodeId ?? target,
|
|
199
205
|
label: metadata && "label" in metadata ? metadata.label : elkEdge.labels?.[0]?.text ?? "",
|
|
200
206
|
data: metadata && "data" in metadata ? metadata.data : void 0,
|
|
201
207
|
x: metadata?.x ?? 0,
|
|
202
208
|
y: metadata?.y ?? 0,
|
|
203
209
|
width: metadata?.width ?? 0,
|
|
204
210
|
height: metadata?.height ?? 0,
|
|
211
|
+
...metadata?.mode !== void 0 && { mode: metadata.mode },
|
|
205
212
|
...metadata?.weight !== void 0 && { weight: metadata.weight },
|
|
206
213
|
...metadata?.color !== void 0 && { color: metadata.color },
|
|
207
214
|
...metadata?.style !== void 0 && { style: metadata.style }
|
|
208
215
|
};
|
|
209
216
|
if (metadata && "sourcePort" in metadata) edge.sourcePort = metadata.sourcePort;
|
|
210
|
-
else if (
|
|
217
|
+
else if (sourceOwner) edge.sourcePort = sourceOwner.portName;
|
|
211
218
|
if (metadata && "targetPort" in metadata) edge.targetPort = metadata.targetPort;
|
|
212
|
-
else if (
|
|
219
|
+
else if (targetOwner) edge.targetPort = targetOwner.portName;
|
|
213
220
|
edges.push(edge);
|
|
214
221
|
}
|
|
215
222
|
}
|
|
@@ -244,7 +251,7 @@ function fromELK(elkRoot) {
|
|
|
244
251
|
const direction = graphMetadata?.direction ?? (elkDir ? ELK_TO_DIRECTION[elkDir] : void 0) ?? "down";
|
|
245
252
|
return {
|
|
246
253
|
id: graphMetadata?.id ?? elkRoot.id,
|
|
247
|
-
|
|
254
|
+
mode: graphMetadata?.mode ?? "directed",
|
|
248
255
|
initialNodeId: graphMetadata && "initialNodeId" in graphMetadata ? graphMetadata.initialNodeId : null,
|
|
249
256
|
nodes,
|
|
250
257
|
edges: [...seenEdges.values()],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as getEdgeMode } from "../../mode-D8OnHFBk.mjs";
|
|
2
|
+
import { n as createFormatConverter } from "../../converter-DyCJJfTe.mjs";
|
|
2
3
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
3
4
|
|
|
4
5
|
//#region src/formats/gexf/index.ts
|
|
@@ -128,7 +129,7 @@ function toGEXF(graph) {
|
|
|
128
129
|
});
|
|
129
130
|
const node = {
|
|
130
131
|
"@_id": n.id,
|
|
131
|
-
"@_label": n.label
|
|
132
|
+
"@_label": n.label ?? ""
|
|
132
133
|
};
|
|
133
134
|
if (n.parentId) node["@_pid"] = n.parentId;
|
|
134
135
|
if (attvalues.length > 0) node.attvalues = { attvalue: attvalues };
|
|
@@ -147,12 +148,15 @@ function toGEXF(graph) {
|
|
|
147
148
|
if (n.width !== void 0 || n.height !== void 0) node["viz:size"] = { "@_value": n.width ?? n.height ?? 0 };
|
|
148
149
|
return node;
|
|
149
150
|
});
|
|
151
|
+
const graphDirected = graph.mode !== "undirected";
|
|
150
152
|
const edges = graph.edges.map((e) => {
|
|
151
153
|
const edge = {
|
|
152
154
|
"@_id": e.id,
|
|
153
155
|
"@_source": e.sourceId,
|
|
154
156
|
"@_target": e.targetId
|
|
155
157
|
};
|
|
158
|
+
const edgeDirected = getEdgeMode(graph, e) !== "undirected";
|
|
159
|
+
if (edgeDirected !== graphDirected) edge["@_type"] = edgeDirected ? "directed" : "undirected";
|
|
156
160
|
if (e.label) edge["@_label"] = e.label;
|
|
157
161
|
if (e.data !== void 0) edge.attvalues = { attvalue: [{
|
|
158
162
|
"@_for": "a_edgeData",
|
|
@@ -212,7 +216,7 @@ function toGEXF(graph) {
|
|
|
212
216
|
"@_xmlns:viz": "http://gexf.net/1.3/viz",
|
|
213
217
|
"@_version": "1.3",
|
|
214
218
|
graph: {
|
|
215
|
-
"@_defaultedgetype": graph.
|
|
219
|
+
"@_defaultedgetype": graph.mode === "undirected" ? "undirected" : "directed",
|
|
216
220
|
...graph.id && { "@_id": graph.id },
|
|
217
221
|
...graph.initialNodeId && { "@_initialNodeId": graph.initialNodeId },
|
|
218
222
|
...graph.direction && { "@_direction": graph.direction },
|
|
@@ -246,7 +250,8 @@ function fromGEXF(xml) {
|
|
|
246
250
|
"attribute",
|
|
247
251
|
"attvalue",
|
|
248
252
|
"attributes"
|
|
249
|
-
].includes(name)
|
|
253
|
+
].includes(name),
|
|
254
|
+
trimValues: false
|
|
250
255
|
});
|
|
251
256
|
let parsed;
|
|
252
257
|
try {
|
|
@@ -279,16 +284,16 @@ function fromGEXF(xml) {
|
|
|
279
284
|
if (attvals["ports"] !== void 0) node.ports = tryParseJSON(attvals["ports"]);
|
|
280
285
|
const pos = n["viz:position"];
|
|
281
286
|
if (pos) {
|
|
282
|
-
node.x =
|
|
283
|
-
node.y =
|
|
287
|
+
node.x = parseNumber(pos["@_x"] ?? 0, "<viz:position> x", "node", id);
|
|
288
|
+
node.y = parseNumber(pos["@_y"] ?? 0, "<viz:position> y", "node", id);
|
|
284
289
|
}
|
|
285
290
|
const size = n["viz:size"];
|
|
286
291
|
if (size) {
|
|
287
|
-
node.width =
|
|
288
|
-
node.height =
|
|
292
|
+
node.width = parseNumber(size["@_value"] ?? 0, "<viz:size>", "node", id);
|
|
293
|
+
node.height = node.width;
|
|
289
294
|
}
|
|
290
|
-
if (attvals["width"] !== void 0) node.width =
|
|
291
|
-
if (attvals["height"] !== void 0) node.height =
|
|
295
|
+
if (attvals["width"] !== void 0) node.width = parseNumber(attvals["width"], "width attribute", "node", id);
|
|
296
|
+
if (attvals["height"] !== void 0) node.height = parseNumber(attvals["height"], "height attribute", "node", id);
|
|
292
297
|
const color = n["viz:color"];
|
|
293
298
|
if (color) {
|
|
294
299
|
const r = Number(color["@_r"] ?? 0);
|
|
@@ -304,18 +309,19 @@ function fromGEXF(xml) {
|
|
|
304
309
|
parseNodes(graphEl.nodes?.node ?? graphEl.node, null);
|
|
305
310
|
const edges = asArray(graphEl.edges?.edge ?? graphEl.edge).map((e, i) => {
|
|
306
311
|
const attvals = getAttValues(e, attrMap);
|
|
312
|
+
const id = String(e["@_id"] ?? `e${i}`);
|
|
307
313
|
const edge = {
|
|
308
314
|
type: "edge",
|
|
309
|
-
id
|
|
315
|
+
id,
|
|
310
316
|
sourceId: String(e["@_source"]),
|
|
311
317
|
targetId: String(e["@_target"]),
|
|
312
318
|
label: e["@_label"] ?? "",
|
|
313
319
|
data: attvals["data"] !== void 0 ? tryParseJSON(attvals["data"]) : void 0,
|
|
314
|
-
...attvals["weight"] !== void 0 && { weight:
|
|
315
|
-
...attvals["x"] !== void 0 && { x:
|
|
316
|
-
...attvals["y"] !== void 0 && { y:
|
|
317
|
-
...attvals["width"] !== void 0 && { width:
|
|
318
|
-
...attvals["height"] !== void 0 && { height:
|
|
320
|
+
...attvals["weight"] !== void 0 && { weight: parseNumber(attvals["weight"], "weight attribute", "edge", id) },
|
|
321
|
+
...attvals["x"] !== void 0 && { x: parseNumber(attvals["x"], "x attribute", "edge", id) },
|
|
322
|
+
...attvals["y"] !== void 0 && { y: parseNumber(attvals["y"], "y attribute", "edge", id) },
|
|
323
|
+
...attvals["width"] !== void 0 && { width: parseNumber(attvals["width"], "width attribute", "edge", id) },
|
|
324
|
+
...attvals["height"] !== void 0 && { height: parseNumber(attvals["height"], "height attribute", "edge", id) },
|
|
319
325
|
...attvals["style"] !== void 0 && { style: tryParseJSON(attvals["style"]) },
|
|
320
326
|
...attvals["sourcePort"] !== void 0 && { sourcePort: attvals["sourcePort"] },
|
|
321
327
|
...attvals["targetPort"] !== void 0 && { targetPort: attvals["targetPort"] }
|
|
@@ -327,11 +333,13 @@ function fromGEXF(xml) {
|
|
|
327
333
|
const b = Number(color["@_b"] ?? 0);
|
|
328
334
|
edge.color = `#${hex(r)}${hex(g)}${hex(b)}`;
|
|
329
335
|
}
|
|
336
|
+
const typeAttr = e["@_type"];
|
|
337
|
+
if (typeAttr !== void 0) edge.mode = String(typeAttr) === "undirected" ? "undirected" : "directed";
|
|
330
338
|
return edge;
|
|
331
339
|
});
|
|
332
340
|
return {
|
|
333
341
|
id: String(graphEl["@_id"] ?? ""),
|
|
334
|
-
|
|
342
|
+
mode: graphType,
|
|
335
343
|
initialNodeId: graphEl["@_initialNodeId"] ?? null,
|
|
336
344
|
nodes,
|
|
337
345
|
edges,
|
|
@@ -360,6 +368,11 @@ function tryParseJSON(str) {
|
|
|
360
368
|
return str;
|
|
361
369
|
}
|
|
362
370
|
}
|
|
371
|
+
function parseNumber(value, field, kind, ownerId) {
|
|
372
|
+
const parsed = Number(value);
|
|
373
|
+
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.`);
|
|
374
|
+
return parsed;
|
|
375
|
+
}
|
|
363
376
|
function hex(n) {
|
|
364
377
|
return n.toString(16).padStart(2, "0");
|
|
365
378
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createFormatConverter } from "../../converter-
|
|
1
|
+
import { n as createFormatConverter } from "../../converter-DyCJJfTe.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/gml/index.ts
|
|
4
4
|
/**
|
|
@@ -26,7 +26,8 @@ import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
|
|
|
26
26
|
function toGML(graph) {
|
|
27
27
|
const lines = [];
|
|
28
28
|
lines.push("graph [");
|
|
29
|
-
lines.push(` directed ${graph.
|
|
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,6 +68,7 @@ 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}`);
|
|
@@ -134,10 +136,10 @@ function fromGML(gml) {
|
|
|
134
136
|
...n["shape"] && { shape: n["shape"] },
|
|
135
137
|
...n["color"] && { color: n["color"] },
|
|
136
138
|
...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 }
|
|
139
|
+
...gfx?.x !== void 0 && { x: parseNumber(gfx.x, "graphics x", "node", id) },
|
|
140
|
+
...gfx?.y !== void 0 && { y: parseNumber(gfx.y, "graphics y", "node", id) },
|
|
141
|
+
...gfx?.w !== void 0 && { width: parseNumber(gfx.w, "graphics w", "node", id) },
|
|
142
|
+
...gfx?.h !== void 0 && { height: parseNumber(gfx.h, "graphics h", "node", id) }
|
|
141
143
|
});
|
|
142
144
|
if (n["node"] !== void 0) parseNodes(n, id);
|
|
143
145
|
}
|
|
@@ -146,27 +148,29 @@ function fromGML(gml) {
|
|
|
146
148
|
const edgeEntries = asArray(graphBlock["edge"]);
|
|
147
149
|
for (const e of edgeEntries) {
|
|
148
150
|
const gfx = e["graphics"];
|
|
151
|
+
const id = String(e["id"] ?? `e${edges.length}`);
|
|
149
152
|
edges.push({
|
|
150
153
|
type: "edge",
|
|
151
|
-
id
|
|
154
|
+
id,
|
|
152
155
|
sourceId: String(e["source"] ?? ""),
|
|
153
156
|
targetId: String(e["target"] ?? ""),
|
|
154
157
|
label: e["label"] ?? "",
|
|
158
|
+
...e["mode"] && { mode: String(e["mode"]) },
|
|
155
159
|
data: e["data"] !== void 0 ? tryParseJSON(e["data"]) : void 0,
|
|
156
|
-
...e["weight"] !== void 0 && { weight:
|
|
160
|
+
...e["weight"] !== void 0 && { weight: parseNumber(e["weight"], "weight", "edge", id) },
|
|
157
161
|
...e["sourcePort"] !== void 0 && { sourcePort: String(e["sourcePort"]) },
|
|
158
162
|
...e["targetPort"] !== void 0 && { targetPort: String(e["targetPort"]) },
|
|
159
163
|
...e["color"] && { color: e["color"] },
|
|
160
164
|
...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 }
|
|
165
|
+
...gfx?.x !== void 0 && { x: parseNumber(gfx.x, "graphics x", "edge", id) },
|
|
166
|
+
...gfx?.y !== void 0 && { y: parseNumber(gfx.y, "graphics y", "edge", id) },
|
|
167
|
+
...gfx?.w !== void 0 && { width: parseNumber(gfx.w, "graphics w", "edge", id) },
|
|
168
|
+
...gfx?.h !== void 0 && { height: parseNumber(gfx.h, "graphics h", "edge", id) }
|
|
165
169
|
});
|
|
166
170
|
}
|
|
167
171
|
return {
|
|
168
172
|
id: graphId,
|
|
169
|
-
|
|
173
|
+
mode: graphBlock["mode"] ? String(graphBlock["mode"]) : directed ? "directed" : "undirected",
|
|
170
174
|
initialNodeId: graphBlock["initialNodeId"] ?? null,
|
|
171
175
|
nodes,
|
|
172
176
|
edges,
|
|
@@ -301,6 +305,11 @@ function tryParseJSON(str) {
|
|
|
301
305
|
return str;
|
|
302
306
|
}
|
|
303
307
|
}
|
|
308
|
+
function parseNumber(value, field, kind, ownerId) {
|
|
309
|
+
const parsed = Number(value);
|
|
310
|
+
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.`);
|
|
311
|
+
return parsed;
|
|
312
|
+
}
|
|
304
313
|
/**
|
|
305
314
|
* Bidirectional converter for GML (Graph Modelling Language) format.
|
|
306
315
|
*
|