@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.
- package/README.md +120 -46
- package/dist/{algorithms-BHHg7lGq.mjs → algorithms-BNDQcHU3.mjs} +7 -7
- package/dist/algorithms.mjs +1 -1
- package/dist/format-support.d.mts +6 -0
- package/dist/format-support.mjs +51 -45
- package/dist/formats/cytoscape/index.mjs +24 -2
- package/dist/formats/d3/index.d.mts +7 -0
- package/dist/formats/d3/index.mjs +42 -8
- package/dist/formats/dot/index.mjs +18 -6
- package/dist/formats/elk/index.mjs +86 -23
- package/dist/formats/gexf/index.mjs +138 -17
- package/dist/formats/gml/index.mjs +44 -11
- package/dist/formats/jgf/index.mjs +24 -2
- package/dist/formats/mermaid/index.d.mts +1 -0
- package/dist/formats/mermaid/index.mjs +39 -9
- package/dist/formats/xyflow/index.d.mts +1 -0
- package/dist/formats/xyflow/index.mjs +97 -40
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{indexing-CJc-ul8e.mjs → indexing-DUl3kTqm.mjs} +18 -4
- package/dist/queries.mjs +1 -1
- package/dist/schemas.d.mts +22 -7
- package/dist/schemas.mjs +158 -2
- package/package.json +1 -1
- package/schemas/graph.schema.json +1 -0
- package/schemas/node.schema.json +1 -0
|
@@ -20,14 +20,26 @@ import { n as createFormatConverter } from "../../converter-Dspillnn.mjs";
|
|
|
20
20
|
*/
|
|
21
21
|
function toD3Graph(graph) {
|
|
22
22
|
return {
|
|
23
|
+
...graph.id && { id: graph.id },
|
|
24
|
+
type: graph.type,
|
|
25
|
+
initialNodeId: graph.initialNodeId,
|
|
26
|
+
...graph.data !== void 0 && { data: graph.data },
|
|
27
|
+
...graph.direction && { direction: graph.direction },
|
|
28
|
+
...graph.style !== void 0 && { style: graph.style },
|
|
23
29
|
nodes: graph.nodes.map((n) => {
|
|
24
30
|
const node = { id: n.id };
|
|
31
|
+
if (n.parentId) node.parentId = n.parentId;
|
|
32
|
+
if (n.initialNodeId) node.initialNodeId = n.initialNodeId;
|
|
25
33
|
if (n.label) node.label = n.label;
|
|
26
34
|
if (n.data !== void 0) node.data = n.data;
|
|
27
35
|
if (n.x !== void 0) node.x = n.x;
|
|
28
36
|
if (n.y !== void 0) node.y = n.y;
|
|
37
|
+
if (n.width !== void 0) node.width = n.width;
|
|
38
|
+
if (n.height !== void 0) node.height = n.height;
|
|
29
39
|
if (n.color) node.color = n.color;
|
|
30
40
|
if (n.shape) node.shape = n.shape;
|
|
41
|
+
if (n.style !== void 0) node.style = n.style;
|
|
42
|
+
if (n.ports !== void 0) node.ports = n.ports;
|
|
31
43
|
return node;
|
|
32
44
|
}),
|
|
33
45
|
links: graph.edges.map((e) => {
|
|
@@ -38,7 +50,15 @@ function toD3Graph(graph) {
|
|
|
38
50
|
if (e.id) link.id = e.id;
|
|
39
51
|
if (e.label) link.label = e.label;
|
|
40
52
|
if (e.data !== void 0) link.data = e.data;
|
|
53
|
+
if (e.weight !== void 0) link.weight = e.weight;
|
|
54
|
+
if (e.x !== void 0) link.x = e.x;
|
|
55
|
+
if (e.y !== void 0) link.y = e.y;
|
|
56
|
+
if (e.width !== void 0) link.width = e.width;
|
|
57
|
+
if (e.height !== void 0) link.height = e.height;
|
|
41
58
|
if (e.color) link.color = e.color;
|
|
59
|
+
if (e.style !== void 0) link.style = e.style;
|
|
60
|
+
if (e.sourcePort !== void 0) link.sourcePort = e.sourcePort;
|
|
61
|
+
if (e.targetPort !== void 0) link.targetPort = e.targetPort;
|
|
42
62
|
return link;
|
|
43
63
|
})
|
|
44
64
|
};
|
|
@@ -61,21 +81,27 @@ function fromD3Graph(d3) {
|
|
|
61
81
|
if (!Array.isArray(d3.nodes)) throw new Error("D3: \"nodes\" must be an array");
|
|
62
82
|
if (!Array.isArray(d3.links)) throw new Error("D3: \"links\" must be an array");
|
|
63
83
|
return {
|
|
64
|
-
id: "",
|
|
65
|
-
type: "directed",
|
|
66
|
-
initialNodeId: null,
|
|
67
|
-
data:
|
|
84
|
+
id: d3.id ?? "",
|
|
85
|
+
type: d3.type === "undirected" ? "undirected" : "directed",
|
|
86
|
+
initialNodeId: d3.initialNodeId ?? null,
|
|
87
|
+
data: d3.data,
|
|
88
|
+
...d3.direction && { direction: d3.direction },
|
|
89
|
+
...d3.style !== void 0 && { style: d3.style },
|
|
68
90
|
nodes: d3.nodes.map((n) => ({
|
|
69
91
|
type: "node",
|
|
70
92
|
id: n.id,
|
|
71
|
-
parentId: null,
|
|
72
|
-
initialNodeId: null,
|
|
93
|
+
parentId: n.parentId ?? null,
|
|
94
|
+
initialNodeId: n.initialNodeId ?? null,
|
|
73
95
|
label: n.label ?? "",
|
|
74
96
|
data: n.data,
|
|
75
97
|
...n.x !== void 0 && { x: n.x },
|
|
76
98
|
...n.y !== void 0 && { y: n.y },
|
|
99
|
+
...n.width !== void 0 && { width: n.width },
|
|
100
|
+
...n.height !== void 0 && { height: n.height },
|
|
77
101
|
...n.color && { color: n.color },
|
|
78
|
-
...n.shape && { shape: n.shape }
|
|
102
|
+
...n.shape && { shape: n.shape },
|
|
103
|
+
...n.style !== void 0 && { style: n.style },
|
|
104
|
+
...n.ports !== void 0 && { ports: n.ports }
|
|
79
105
|
})),
|
|
80
106
|
edges: d3.links.map((l, i) => ({
|
|
81
107
|
type: "edge",
|
|
@@ -84,7 +110,15 @@ function fromD3Graph(d3) {
|
|
|
84
110
|
targetId: typeof l.target === "string" ? l.target : l.target.id,
|
|
85
111
|
label: l.label ?? "",
|
|
86
112
|
data: l.data,
|
|
87
|
-
...l.
|
|
113
|
+
...l.weight !== void 0 && { weight: l.weight },
|
|
114
|
+
...l.x !== void 0 && { x: l.x },
|
|
115
|
+
...l.y !== void 0 && { y: l.y },
|
|
116
|
+
...l.width !== void 0 && { width: l.width },
|
|
117
|
+
...l.height !== void 0 && { height: l.height },
|
|
118
|
+
...l.color && { color: l.color },
|
|
119
|
+
...l.style !== void 0 && { style: l.style },
|
|
120
|
+
...l.sourcePort !== void 0 && { sourcePort: l.sourcePort },
|
|
121
|
+
...l.targetPort !== void 0 && { targetPort: l.targetPort }
|
|
88
122
|
}))
|
|
89
123
|
};
|
|
90
124
|
}
|
|
@@ -11,6 +11,9 @@ function escapeId(id) {
|
|
|
11
11
|
function escapeLabel(label) {
|
|
12
12
|
return label.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
13
13
|
}
|
|
14
|
+
function formatEndpoint(id, port) {
|
|
15
|
+
return `${escapeId(id)}${port ? `:${escapeId(port)}` : ""}`;
|
|
16
|
+
}
|
|
14
17
|
const DIRECTION_TO_RANKDIR = {
|
|
15
18
|
down: "TB",
|
|
16
19
|
up: "BT",
|
|
@@ -72,7 +75,7 @@ function toDOT(graph) {
|
|
|
72
75
|
if (edge.label) attrs.push(`label="${escapeLabel(edge.label)}"`);
|
|
73
76
|
if (edge.color) attrs.push(`color="${escapeLabel(edge.color)}"`);
|
|
74
77
|
const attrStr = attrs.length > 0 ? ` [${attrs.join(", ")}]` : "";
|
|
75
|
-
lines.push(` ${
|
|
78
|
+
lines.push(` ${formatEndpoint(edge.sourceId, edge.sourcePort)} ${edgeOp} ${formatEndpoint(edge.targetId, edge.targetPort)}${attrStr};`);
|
|
76
79
|
}
|
|
77
80
|
lines.push("}");
|
|
78
81
|
return lines.join("\n");
|
|
@@ -95,6 +98,10 @@ const DOT_TO_SHAPE = {
|
|
|
95
98
|
cylinder: "cylinder",
|
|
96
99
|
parallelogram: "parallelogram"
|
|
97
100
|
};
|
|
101
|
+
function getPortId(nodeId) {
|
|
102
|
+
const port = nodeId.port;
|
|
103
|
+
return typeof port?.id === "string" ? port.id : void 0;
|
|
104
|
+
}
|
|
98
105
|
function attrsToMap(attrList) {
|
|
99
106
|
const map = {};
|
|
100
107
|
for (const a of attrList) map[a.id] = String(a.eq);
|
|
@@ -209,24 +216,29 @@ function fromDOT(dot) {
|
|
|
209
216
|
const endpointGroups = [];
|
|
210
217
|
for (const item of stmt.edge_list) if (item.type === "node_id") {
|
|
211
218
|
ensureNode(item.id, parentId, nd);
|
|
212
|
-
endpointGroups.push([
|
|
219
|
+
endpointGroups.push([{
|
|
220
|
+
id: item.id,
|
|
221
|
+
...getPortId(item) && { port: getPortId(item) }
|
|
222
|
+
}]);
|
|
213
223
|
} else if (item.type === "subgraph") {
|
|
214
224
|
walkChildren(item.children, parentId, nd, ed);
|
|
215
225
|
const subNodeIds = getNodeIdsFromSubgraph(item.children);
|
|
216
226
|
for (const subNodeId of subNodeIds) ensureNode(subNodeId, parentId, nd);
|
|
217
|
-
if (subNodeIds.length > 0) endpointGroups.push(subNodeIds);
|
|
227
|
+
if (subNodeIds.length > 0) endpointGroups.push(subNodeIds.map((id) => ({ id })));
|
|
218
228
|
}
|
|
219
229
|
for (let i = 0; i < endpointGroups.length - 1; i++) {
|
|
220
230
|
const left = endpointGroups[i];
|
|
221
231
|
const right = endpointGroups[i + 1];
|
|
222
|
-
for (const
|
|
232
|
+
for (const source of left) for (const target of right) {
|
|
223
233
|
const edge = {
|
|
224
234
|
type: "edge",
|
|
225
235
|
id: `e${edgeIdx++}`,
|
|
226
|
-
sourceId,
|
|
227
|
-
targetId,
|
|
236
|
+
sourceId: source.id,
|
|
237
|
+
targetId: target.id,
|
|
228
238
|
label: mergedEdgeAttrs["label"] ?? "",
|
|
229
239
|
data: void 0,
|
|
240
|
+
...source.port && { sourcePort: source.port },
|
|
241
|
+
...target.port && { targetPort: target.port },
|
|
230
242
|
...mergedEdgeAttrs["color"] && { color: mergedEdgeAttrs["color"] }
|
|
231
243
|
};
|
|
232
244
|
edges.push(edge);
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import { getChildren } from "../../queries.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/formats/elk/index.ts
|
|
4
|
+
const STATELYAI_METADATA_KEY = "statelyai.metadata";
|
|
5
|
+
function addMetadata(target, metadata) {
|
|
6
|
+
target.layoutOptions = {
|
|
7
|
+
...target.layoutOptions ?? {},
|
|
8
|
+
[STATELYAI_METADATA_KEY]: JSON.stringify(metadata)
|
|
9
|
+
};
|
|
10
|
+
return target;
|
|
11
|
+
}
|
|
12
|
+
function readMetadata(value) {
|
|
13
|
+
const raw = value.layoutOptions?.[STATELYAI_METADATA_KEY];
|
|
14
|
+
if (typeof raw !== "string") return void 0;
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
} catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
4
21
|
const DIRECTION_TO_ELK = {
|
|
5
22
|
down: "DOWN",
|
|
6
23
|
up: "UP",
|
|
@@ -20,7 +37,21 @@ function convertEdge(edge) {
|
|
|
20
37
|
targets: [edge.targetPort ?? edge.targetId]
|
|
21
38
|
};
|
|
22
39
|
if (edge.label) elkEdge.labels = [{ text: edge.label }];
|
|
23
|
-
return elkEdge
|
|
40
|
+
return addMetadata(elkEdge, { edge: {
|
|
41
|
+
sourceId: edge.sourceId,
|
|
42
|
+
targetId: edge.targetId,
|
|
43
|
+
sourcePort: edge.sourcePort,
|
|
44
|
+
targetPort: edge.targetPort,
|
|
45
|
+
label: edge.label,
|
|
46
|
+
data: edge.data,
|
|
47
|
+
weight: edge.weight,
|
|
48
|
+
color: edge.color,
|
|
49
|
+
style: edge.style,
|
|
50
|
+
x: edge.x,
|
|
51
|
+
y: edge.y,
|
|
52
|
+
width: edge.width,
|
|
53
|
+
height: edge.height
|
|
54
|
+
} });
|
|
24
55
|
}
|
|
25
56
|
function convertPort(port) {
|
|
26
57
|
const elkPort = {
|
|
@@ -32,7 +63,10 @@ function convertPort(port) {
|
|
|
32
63
|
};
|
|
33
64
|
if (port.label) elkPort.labels = [{ text: port.label }];
|
|
34
65
|
if (port.direction !== "inout") elkPort.layoutOptions = { "org.eclipse.elk.port.side": port.direction === "in" ? "WEST" : "EAST" };
|
|
35
|
-
return elkPort
|
|
66
|
+
return addMetadata(elkPort, { port: {
|
|
67
|
+
data: port.data,
|
|
68
|
+
style: port.style
|
|
69
|
+
} });
|
|
36
70
|
}
|
|
37
71
|
function convertNode(graph, node) {
|
|
38
72
|
const elkNode = {
|
|
@@ -44,6 +78,13 @@ function convertNode(graph, node) {
|
|
|
44
78
|
};
|
|
45
79
|
if (node.label) elkNode.labels = [{ text: node.label }];
|
|
46
80
|
if (node.ports && node.ports.length > 0) elkNode.ports = node.ports.map(convertPort);
|
|
81
|
+
addMetadata(elkNode, { node: {
|
|
82
|
+
initialNodeId: node.initialNodeId,
|
|
83
|
+
data: node.data,
|
|
84
|
+
shape: node.shape,
|
|
85
|
+
color: node.color,
|
|
86
|
+
style: node.style
|
|
87
|
+
} });
|
|
47
88
|
const children = getChildren(graph, node.id);
|
|
48
89
|
if (children.length > 0) {
|
|
49
90
|
elkNode.children = children.map((child) => convertNode(graph, child));
|
|
@@ -85,6 +126,14 @@ function toELK(graph) {
|
|
|
85
126
|
const root = { id: graph.id };
|
|
86
127
|
const elkDir = DIRECTION_TO_ELK[graph.direction];
|
|
87
128
|
if (elkDir) root.layoutOptions = { "elk.direction": elkDir };
|
|
129
|
+
addMetadata(root, { graph: {
|
|
130
|
+
id: graph.id,
|
|
131
|
+
type: graph.type,
|
|
132
|
+
initialNodeId: graph.initialNodeId,
|
|
133
|
+
data: graph.data,
|
|
134
|
+
direction: graph.direction,
|
|
135
|
+
style: graph.style
|
|
136
|
+
} });
|
|
88
137
|
const roots = getChildren(graph, null);
|
|
89
138
|
if (roots.length > 0) root.children = roots.map((node) => convertNode(graph, node));
|
|
90
139
|
const allInnerEdgeIds = /* @__PURE__ */ new Set();
|
|
@@ -100,20 +149,25 @@ function toELK(graph) {
|
|
|
100
149
|
function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
101
150
|
if (elkNode.children) for (const child of elkNode.children) {
|
|
102
151
|
const label = child.labels?.[0]?.text ?? "";
|
|
152
|
+
const metadata = readMetadata(child)?.node;
|
|
103
153
|
const node = {
|
|
104
154
|
type: "node",
|
|
105
155
|
id: child.id,
|
|
106
156
|
parentId,
|
|
107
|
-
initialNodeId: null,
|
|
157
|
+
initialNodeId: metadata && "initialNodeId" in metadata ? metadata.initialNodeId : null,
|
|
108
158
|
label,
|
|
109
|
-
data: void 0,
|
|
159
|
+
data: metadata && "data" in metadata ? metadata.data : void 0,
|
|
110
160
|
x: child.x ?? 0,
|
|
111
161
|
y: child.y ?? 0,
|
|
112
162
|
width: child.width ?? 0,
|
|
113
|
-
height: child.height ?? 0
|
|
163
|
+
height: child.height ?? 0,
|
|
164
|
+
...metadata?.shape !== void 0 && { shape: metadata.shape },
|
|
165
|
+
...metadata?.color !== void 0 && { color: metadata.color },
|
|
166
|
+
...metadata?.style !== void 0 && { style: metadata.style }
|
|
114
167
|
};
|
|
115
168
|
if (child.ports && child.ports.length > 0) node.ports = child.ports.map((elkPort) => {
|
|
116
169
|
portOwner.set(elkPort.id, child.id);
|
|
170
|
+
const metadata$1 = readMetadata(elkPort)?.port;
|
|
117
171
|
const sideOpt = elkPort.layoutOptions?.["org.eclipse.elk.port.side"];
|
|
118
172
|
let direction = "inout";
|
|
119
173
|
if (sideOpt === "WEST") direction = "in";
|
|
@@ -122,33 +176,40 @@ function flattenElkNodes(elkNode, parentId, nodes, edges, edgeIdx, portOwner) {
|
|
|
122
176
|
name: elkPort.id,
|
|
123
177
|
direction,
|
|
124
178
|
label: elkPort.labels?.[0]?.text,
|
|
125
|
-
data: void 0,
|
|
179
|
+
data: metadata$1 && "data" in metadata$1 ? metadata$1.data : void 0,
|
|
126
180
|
x: elkPort.x ?? 0,
|
|
127
181
|
y: elkPort.y ?? 0,
|
|
128
182
|
width: elkPort.width ?? 0,
|
|
129
|
-
height: elkPort.height ?? 0
|
|
183
|
+
height: elkPort.height ?? 0,
|
|
184
|
+
...metadata$1?.style !== void 0 && { style: metadata$1.style }
|
|
130
185
|
};
|
|
131
186
|
});
|
|
132
187
|
nodes.push(node);
|
|
133
188
|
flattenElkNodes(child, child.id, nodes, edges, edgeIdx, portOwner);
|
|
134
189
|
}
|
|
135
190
|
if (elkNode.edges) for (const elkEdge of elkNode.edges) for (const source of elkEdge.sources) for (const target of elkEdge.targets) {
|
|
191
|
+
const metadata = readMetadata(elkEdge)?.edge;
|
|
136
192
|
const sourceNodeId = portOwner.get(source);
|
|
137
193
|
const targetNodeId = portOwner.get(target);
|
|
138
194
|
const edge = {
|
|
139
195
|
type: "edge",
|
|
140
196
|
id: elkEdge.id ?? `e${edgeIdx.value++}`,
|
|
141
|
-
sourceId: sourceNodeId ?? source,
|
|
142
|
-
targetId: targetNodeId ?? target,
|
|
143
|
-
label: elkEdge.labels?.[0]?.text ?? "",
|
|
144
|
-
data: void 0,
|
|
145
|
-
x: 0,
|
|
146
|
-
y: 0,
|
|
147
|
-
width: 0,
|
|
148
|
-
height: 0
|
|
197
|
+
sourceId: metadata?.sourceId ?? sourceNodeId ?? source,
|
|
198
|
+
targetId: metadata?.targetId ?? targetNodeId ?? target,
|
|
199
|
+
label: metadata && "label" in metadata ? metadata.label : elkEdge.labels?.[0]?.text ?? "",
|
|
200
|
+
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,
|
|
205
|
+
...metadata?.weight !== void 0 && { weight: metadata.weight },
|
|
206
|
+
...metadata?.color !== void 0 && { color: metadata.color },
|
|
207
|
+
...metadata?.style !== void 0 && { style: metadata.style }
|
|
149
208
|
};
|
|
150
|
-
if (
|
|
151
|
-
if (
|
|
209
|
+
if (metadata && "sourcePort" in metadata) edge.sourcePort = metadata.sourcePort;
|
|
210
|
+
else if (sourceNodeId) edge.sourcePort = source;
|
|
211
|
+
if (metadata && "targetPort" in metadata) edge.targetPort = metadata.targetPort;
|
|
212
|
+
else if (targetNodeId) edge.targetPort = target;
|
|
152
213
|
edges.push(edge);
|
|
153
214
|
}
|
|
154
215
|
}
|
|
@@ -179,15 +240,17 @@ function fromELK(elkRoot) {
|
|
|
179
240
|
const seenEdges = /* @__PURE__ */ new Map();
|
|
180
241
|
for (const edge of edges) if (!seenEdges.has(edge.id)) seenEdges.set(edge.id, edge);
|
|
181
242
|
const elkDir = elkRoot.layoutOptions?.["elk.direction"];
|
|
182
|
-
const
|
|
243
|
+
const graphMetadata = readMetadata(elkRoot)?.graph;
|
|
244
|
+
const direction = graphMetadata?.direction ?? (elkDir ? ELK_TO_DIRECTION[elkDir] : void 0) ?? "down";
|
|
183
245
|
return {
|
|
184
|
-
id: elkRoot.id,
|
|
185
|
-
type: "directed",
|
|
186
|
-
initialNodeId: null,
|
|
246
|
+
id: graphMetadata?.id ?? elkRoot.id,
|
|
247
|
+
type: graphMetadata?.type === "undirected" ? "undirected" : "directed",
|
|
248
|
+
initialNodeId: graphMetadata && "initialNodeId" in graphMetadata ? graphMetadata.initialNodeId : null,
|
|
187
249
|
nodes,
|
|
188
250
|
edges: [...seenEdges.values()],
|
|
189
|
-
data: void 0,
|
|
190
|
-
direction
|
|
251
|
+
data: graphMetadata && "data" in graphMetadata ? graphMetadata.data : void 0,
|
|
252
|
+
direction,
|
|
253
|
+
...graphMetadata?.style !== void 0 && { style: graphMetadata.style }
|
|
191
254
|
};
|
|
192
255
|
}
|
|
193
256
|
/**
|
|
@@ -23,13 +23,75 @@ function toGEXF(graph) {
|
|
|
23
23
|
"@_id": "a_shape",
|
|
24
24
|
"@_title": "shape",
|
|
25
25
|
"@_type": "string"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"@_id": "a_width",
|
|
29
|
+
"@_title": "width",
|
|
30
|
+
"@_type": "double"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"@_id": "a_height",
|
|
34
|
+
"@_title": "height",
|
|
35
|
+
"@_type": "double"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"@_id": "a_style",
|
|
39
|
+
"@_title": "style",
|
|
40
|
+
"@_type": "string"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"@_id": "a_ports",
|
|
44
|
+
"@_title": "ports",
|
|
45
|
+
"@_type": "string"
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
const edgeAttrs = [
|
|
49
|
+
{
|
|
50
|
+
"@_id": "a_edgeData",
|
|
51
|
+
"@_title": "data",
|
|
52
|
+
"@_type": "string"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"@_id": "a_edgeWeight",
|
|
56
|
+
"@_title": "weight",
|
|
57
|
+
"@_type": "double"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"@_id": "a_edgeX",
|
|
61
|
+
"@_title": "x",
|
|
62
|
+
"@_type": "double"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"@_id": "a_edgeY",
|
|
66
|
+
"@_title": "y",
|
|
67
|
+
"@_type": "double"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"@_id": "a_edgeWidth",
|
|
71
|
+
"@_title": "width",
|
|
72
|
+
"@_type": "double"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"@_id": "a_edgeHeight",
|
|
76
|
+
"@_title": "height",
|
|
77
|
+
"@_type": "double"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"@_id": "a_edgeStyle",
|
|
81
|
+
"@_title": "style",
|
|
82
|
+
"@_type": "string"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"@_id": "a_sourcePort",
|
|
86
|
+
"@_title": "sourcePort",
|
|
87
|
+
"@_type": "string"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"@_id": "a_targetPort",
|
|
91
|
+
"@_title": "targetPort",
|
|
92
|
+
"@_type": "string"
|
|
26
93
|
}
|
|
27
94
|
];
|
|
28
|
-
const edgeAttrs = [{
|
|
29
|
-
"@_id": "a_edgeData",
|
|
30
|
-
"@_title": "data",
|
|
31
|
-
"@_type": "string"
|
|
32
|
-
}];
|
|
33
95
|
const nodes = graph.nodes.map((n) => {
|
|
34
96
|
const attvalues = [];
|
|
35
97
|
if (n.parentId) attvalues.push({
|
|
@@ -48,6 +110,22 @@ function toGEXF(graph) {
|
|
|
48
110
|
"@_for": "a_shape",
|
|
49
111
|
"@_value": n.shape
|
|
50
112
|
});
|
|
113
|
+
if (n.width !== void 0) attvalues.push({
|
|
114
|
+
"@_for": "a_width",
|
|
115
|
+
"@_value": n.width
|
|
116
|
+
});
|
|
117
|
+
if (n.height !== void 0) attvalues.push({
|
|
118
|
+
"@_for": "a_height",
|
|
119
|
+
"@_value": n.height
|
|
120
|
+
});
|
|
121
|
+
if (n.style !== void 0) attvalues.push({
|
|
122
|
+
"@_for": "a_style",
|
|
123
|
+
"@_value": JSON.stringify(n.style)
|
|
124
|
+
});
|
|
125
|
+
if (n.ports !== void 0) attvalues.push({
|
|
126
|
+
"@_for": "a_ports",
|
|
127
|
+
"@_value": JSON.stringify(n.ports)
|
|
128
|
+
});
|
|
51
129
|
const node = {
|
|
52
130
|
"@_id": n.id,
|
|
53
131
|
"@_label": n.label || n.id
|
|
@@ -80,6 +158,40 @@ function toGEXF(graph) {
|
|
|
80
158
|
"@_for": "a_edgeData",
|
|
81
159
|
"@_value": JSON.stringify(e.data)
|
|
82
160
|
}] };
|
|
161
|
+
const edgeAttvalues = edge.attvalues?.attvalue ?? [];
|
|
162
|
+
if (e.weight !== void 0) edgeAttvalues.push({
|
|
163
|
+
"@_for": "a_edgeWeight",
|
|
164
|
+
"@_value": e.weight
|
|
165
|
+
});
|
|
166
|
+
if (e.x !== void 0) edgeAttvalues.push({
|
|
167
|
+
"@_for": "a_edgeX",
|
|
168
|
+
"@_value": e.x
|
|
169
|
+
});
|
|
170
|
+
if (e.y !== void 0) edgeAttvalues.push({
|
|
171
|
+
"@_for": "a_edgeY",
|
|
172
|
+
"@_value": e.y
|
|
173
|
+
});
|
|
174
|
+
if (e.width !== void 0) edgeAttvalues.push({
|
|
175
|
+
"@_for": "a_edgeWidth",
|
|
176
|
+
"@_value": e.width
|
|
177
|
+
});
|
|
178
|
+
if (e.height !== void 0) edgeAttvalues.push({
|
|
179
|
+
"@_for": "a_edgeHeight",
|
|
180
|
+
"@_value": e.height
|
|
181
|
+
});
|
|
182
|
+
if (e.style !== void 0) edgeAttvalues.push({
|
|
183
|
+
"@_for": "a_edgeStyle",
|
|
184
|
+
"@_value": JSON.stringify(e.style)
|
|
185
|
+
});
|
|
186
|
+
if (e.sourcePort !== void 0) edgeAttvalues.push({
|
|
187
|
+
"@_for": "a_sourcePort",
|
|
188
|
+
"@_value": e.sourcePort
|
|
189
|
+
});
|
|
190
|
+
if (e.targetPort !== void 0) edgeAttvalues.push({
|
|
191
|
+
"@_for": "a_targetPort",
|
|
192
|
+
"@_value": e.targetPort
|
|
193
|
+
});
|
|
194
|
+
if (edgeAttvalues.length > 0) edge.attvalues = { attvalue: edgeAttvalues };
|
|
83
195
|
if (e.color) {
|
|
84
196
|
const hex$1 = e.color.replace("#", "");
|
|
85
197
|
if (hex$1.length === 6) edge["viz:color"] = {
|
|
@@ -90,15 +202,6 @@ function toGEXF(graph) {
|
|
|
90
202
|
}
|
|
91
203
|
return edge;
|
|
92
204
|
});
|
|
93
|
-
const graphData = [];
|
|
94
|
-
if (graph.initialNodeId) graphData.push({
|
|
95
|
-
"@_for": "a_initialNodeId",
|
|
96
|
-
"@_value": graph.initialNodeId
|
|
97
|
-
});
|
|
98
|
-
if (graph.data !== void 0) graphData.push({
|
|
99
|
-
"@_for": "a_data",
|
|
100
|
-
"@_value": JSON.stringify(graph.data)
|
|
101
|
-
});
|
|
102
205
|
const obj = {
|
|
103
206
|
"?xml": {
|
|
104
207
|
"@_version": "1.0",
|
|
@@ -111,6 +214,10 @@ function toGEXF(graph) {
|
|
|
111
214
|
graph: {
|
|
112
215
|
"@_defaultedgetype": graph.type === "directed" ? "directed" : "undirected",
|
|
113
216
|
...graph.id && { "@_id": graph.id },
|
|
217
|
+
...graph.initialNodeId && { "@_initialNodeId": graph.initialNodeId },
|
|
218
|
+
...graph.direction && { "@_direction": graph.direction },
|
|
219
|
+
...graph.data !== void 0 && { "@_data": JSON.stringify(graph.data) },
|
|
220
|
+
...graph.style !== void 0 && { "@_style": JSON.stringify(graph.style) },
|
|
114
221
|
attributes: [{
|
|
115
222
|
"@_class": "node",
|
|
116
223
|
attribute: nodeAttrs
|
|
@@ -168,6 +275,8 @@ function fromGEXF(xml) {
|
|
|
168
275
|
data: attvals["data"] !== void 0 ? tryParseJSON(attvals["data"]) : void 0
|
|
169
276
|
};
|
|
170
277
|
if (attvals["shape"]) node.shape = attvals["shape"];
|
|
278
|
+
if (attvals["style"] !== void 0) node.style = tryParseJSON(attvals["style"]);
|
|
279
|
+
if (attvals["ports"] !== void 0) node.ports = tryParseJSON(attvals["ports"]);
|
|
171
280
|
const pos = n["viz:position"];
|
|
172
281
|
if (pos) {
|
|
173
282
|
node.x = Number(pos["@_x"] ?? 0);
|
|
@@ -178,6 +287,8 @@ function fromGEXF(xml) {
|
|
|
178
287
|
node.width = Number(size["@_value"] ?? 0);
|
|
179
288
|
node.height = Number(size["@_value"] ?? 0);
|
|
180
289
|
}
|
|
290
|
+
if (attvals["width"] !== void 0) node.width = Number(attvals["width"]);
|
|
291
|
+
if (attvals["height"] !== void 0) node.height = Number(attvals["height"]);
|
|
181
292
|
const color = n["viz:color"];
|
|
182
293
|
if (color) {
|
|
183
294
|
const r = Number(color["@_r"] ?? 0);
|
|
@@ -199,7 +310,15 @@ function fromGEXF(xml) {
|
|
|
199
310
|
sourceId: String(e["@_source"]),
|
|
200
311
|
targetId: String(e["@_target"]),
|
|
201
312
|
label: e["@_label"] ?? "",
|
|
202
|
-
data: attvals["data"] !== void 0 ? tryParseJSON(attvals["data"]) : void 0
|
|
313
|
+
data: attvals["data"] !== void 0 ? tryParseJSON(attvals["data"]) : void 0,
|
|
314
|
+
...attvals["weight"] !== void 0 && { weight: Number(attvals["weight"]) },
|
|
315
|
+
...attvals["x"] !== void 0 && { x: Number(attvals["x"]) },
|
|
316
|
+
...attvals["y"] !== void 0 && { y: Number(attvals["y"]) },
|
|
317
|
+
...attvals["width"] !== void 0 && { width: Number(attvals["width"]) },
|
|
318
|
+
...attvals["height"] !== void 0 && { height: Number(attvals["height"]) },
|
|
319
|
+
...attvals["style"] !== void 0 && { style: tryParseJSON(attvals["style"]) },
|
|
320
|
+
...attvals["sourcePort"] !== void 0 && { sourcePort: attvals["sourcePort"] },
|
|
321
|
+
...attvals["targetPort"] !== void 0 && { targetPort: attvals["targetPort"] }
|
|
203
322
|
};
|
|
204
323
|
const color = e["viz:color"];
|
|
205
324
|
if (color) {
|
|
@@ -213,10 +332,12 @@ function fromGEXF(xml) {
|
|
|
213
332
|
return {
|
|
214
333
|
id: String(graphEl["@_id"] ?? ""),
|
|
215
334
|
type: graphType,
|
|
216
|
-
initialNodeId: null,
|
|
335
|
+
initialNodeId: graphEl["@_initialNodeId"] ?? null,
|
|
217
336
|
nodes,
|
|
218
337
|
edges,
|
|
219
|
-
data: void 0
|
|
338
|
+
data: graphEl["@_data"] !== void 0 ? tryParseJSON(String(graphEl["@_data"])) : void 0,
|
|
339
|
+
...graphEl["@_direction"] && { direction: graphEl["@_direction"] },
|
|
340
|
+
...graphEl["@_style"] !== void 0 && { style: tryParseJSON(String(graphEl["@_style"])) }
|
|
220
341
|
};
|
|
221
342
|
}
|
|
222
343
|
function asArray(val) {
|
|
@@ -28,6 +28,10 @@ function toGML(graph) {
|
|
|
28
28
|
lines.push("graph [");
|
|
29
29
|
lines.push(` directed ${graph.type === "directed" ? 1 : 0}`);
|
|
30
30
|
if (graph.id) lines.push(` id ${gmlString(graph.id)}`);
|
|
31
|
+
if (graph.initialNodeId) lines.push(` initialNodeId ${gmlString(graph.initialNodeId)}`);
|
|
32
|
+
if (graph.data !== void 0) lines.push(` data ${gmlString(JSON.stringify(graph.data))}`);
|
|
33
|
+
if (graph.direction) lines.push(` direction ${gmlString(graph.direction)}`);
|
|
34
|
+
if (graph.style !== void 0) lines.push(` style ${gmlString(JSON.stringify(graph.style))}`);
|
|
31
35
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
32
36
|
for (const node of graph.nodes) {
|
|
33
37
|
const pid = node.parentId ?? null;
|
|
@@ -40,8 +44,10 @@ function toGML(graph) {
|
|
|
40
44
|
if (node.label) lines.push(`${indent} label ${gmlString(node.label)}`);
|
|
41
45
|
if (node.initialNodeId) lines.push(`${indent} initialNodeId ${gmlString(node.initialNodeId)}`);
|
|
42
46
|
if (node.data !== void 0) lines.push(`${indent} data ${gmlString(JSON.stringify(node.data))}`);
|
|
47
|
+
if (node.ports !== void 0) lines.push(`${indent} ports ${gmlString(JSON.stringify(node.ports))}`);
|
|
43
48
|
if (node.shape) lines.push(`${indent} shape ${gmlString(node.shape)}`);
|
|
44
49
|
if (node.color) lines.push(`${indent} color ${gmlString(node.color)}`);
|
|
50
|
+
if (node.style !== void 0) lines.push(`${indent} style ${gmlString(JSON.stringify(node.style))}`);
|
|
45
51
|
if (node.x !== void 0 || node.y !== void 0 || node.width !== void 0 || node.height !== void 0) {
|
|
46
52
|
lines.push(`${indent} graphics [`);
|
|
47
53
|
if (node.x !== void 0) lines.push(`${indent} x ${node.x}`);
|
|
@@ -63,7 +69,19 @@ function toGML(graph) {
|
|
|
63
69
|
lines.push(` target ${gmlString(edge.targetId)}`);
|
|
64
70
|
if (edge.label) lines.push(` label ${gmlString(edge.label)}`);
|
|
65
71
|
if (edge.data !== void 0) lines.push(` data ${gmlString(JSON.stringify(edge.data))}`);
|
|
72
|
+
if (edge.weight !== void 0) lines.push(` weight ${edge.weight}`);
|
|
73
|
+
if (edge.sourcePort !== void 0) lines.push(` sourcePort ${gmlString(edge.sourcePort)}`);
|
|
74
|
+
if (edge.targetPort !== void 0) lines.push(` targetPort ${gmlString(edge.targetPort)}`);
|
|
66
75
|
if (edge.color) lines.push(` color ${gmlString(edge.color)}`);
|
|
76
|
+
if (edge.style !== void 0) lines.push(` style ${gmlString(JSON.stringify(edge.style))}`);
|
|
77
|
+
if (edge.x !== void 0 || edge.y !== void 0 || edge.width !== void 0 || edge.height !== void 0) {
|
|
78
|
+
lines.push(" graphics [");
|
|
79
|
+
if (edge.x !== void 0) lines.push(` x ${edge.x}`);
|
|
80
|
+
if (edge.y !== void 0) lines.push(` y ${edge.y}`);
|
|
81
|
+
if (edge.width !== void 0) lines.push(` w ${edge.width}`);
|
|
82
|
+
if (edge.height !== void 0) lines.push(` h ${edge.height}`);
|
|
83
|
+
lines.push(" ]");
|
|
84
|
+
}
|
|
67
85
|
lines.push(" ]");
|
|
68
86
|
}
|
|
69
87
|
lines.push("]");
|
|
@@ -112,8 +130,10 @@ function fromGML(gml) {
|
|
|
112
130
|
initialNodeId: n["initialNodeId"] ?? null,
|
|
113
131
|
label: n["label"] ?? "",
|
|
114
132
|
data: n["data"] !== void 0 ? tryParseJSON(n["data"]) : void 0,
|
|
133
|
+
...n["ports"] !== void 0 && { ports: tryParseJSON(n["ports"]) },
|
|
115
134
|
...n["shape"] && { shape: n["shape"] },
|
|
116
135
|
...n["color"] && { color: n["color"] },
|
|
136
|
+
...n["style"] !== void 0 && { style: tryParseJSON(n["style"]) },
|
|
117
137
|
...gfx?.x !== void 0 && { x: gfx.x },
|
|
118
138
|
...gfx?.y !== void 0 && { y: gfx.y },
|
|
119
139
|
...gfx?.w !== void 0 && { width: gfx.w },
|
|
@@ -124,22 +144,35 @@ function fromGML(gml) {
|
|
|
124
144
|
}
|
|
125
145
|
parseNodes(graphBlock, null);
|
|
126
146
|
const edgeEntries = asArray(graphBlock["edge"]);
|
|
127
|
-
for (const e of edgeEntries)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
147
|
+
for (const e of edgeEntries) {
|
|
148
|
+
const gfx = e["graphics"];
|
|
149
|
+
edges.push({
|
|
150
|
+
type: "edge",
|
|
151
|
+
id: String(e["id"] ?? `e${edges.length}`),
|
|
152
|
+
sourceId: String(e["source"] ?? ""),
|
|
153
|
+
targetId: String(e["target"] ?? ""),
|
|
154
|
+
label: e["label"] ?? "",
|
|
155
|
+
data: e["data"] !== void 0 ? tryParseJSON(e["data"]) : void 0,
|
|
156
|
+
...e["weight"] !== void 0 && { weight: Number(e["weight"]) },
|
|
157
|
+
...e["sourcePort"] !== void 0 && { sourcePort: String(e["sourcePort"]) },
|
|
158
|
+
...e["targetPort"] !== void 0 && { targetPort: String(e["targetPort"]) },
|
|
159
|
+
...e["color"] && { color: e["color"] },
|
|
160
|
+
...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
|
+
});
|
|
166
|
+
}
|
|
136
167
|
return {
|
|
137
168
|
id: graphId,
|
|
138
169
|
type: directed ? "directed" : "undirected",
|
|
139
|
-
initialNodeId: null,
|
|
170
|
+
initialNodeId: graphBlock["initialNodeId"] ?? null,
|
|
140
171
|
nodes,
|
|
141
172
|
edges,
|
|
142
|
-
data: void 0
|
|
173
|
+
data: graphBlock["data"] !== void 0 ? tryParseJSON(graphBlock["data"]) : void 0,
|
|
174
|
+
...graphBlock["direction"] && { direction: String(graphBlock["direction"]) },
|
|
175
|
+
...graphBlock["style"] !== void 0 && { style: tryParseJSON(graphBlock["style"]) }
|
|
143
176
|
};
|
|
144
177
|
}
|
|
145
178
|
function tokenize(input) {
|