@graphty/graph-io 0.3.40 → 0.3.42
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 +2 -0
- package/dist/chunks/{children-CL3Cy0ez.js → children-CA4coBi0.js} +36 -27
- package/dist/chunks/children-CA4coBi0.js.map +1 -0
- package/dist/chunks/{choose-CS3fvGT1.js → choose-DvpbdRuz.js} +2 -2
- package/dist/chunks/{choose-CS3fvGT1.js.map → choose-DvpbdRuz.js.map} +1 -1
- package/dist/chunks/{constants-DqKZT6cH.js → constants-fT3E8JYY.js} +2 -2
- package/dist/chunks/{constants-DqKZT6cH.js.map → constants-fT3E8JYY.js.map} +1 -1
- package/dist/chunks/{escape-BJRLd3vJ.js → escape-B62ZGM_a.js} +2 -2
- package/dist/chunks/{escape-BJRLd3vJ.js.map → escape-B62ZGM_a.js.map} +1 -1
- package/dist/chunks/{export-B-aVCwyG.js → export-rKLeGQMo.js} +404 -243
- package/dist/chunks/export-rKLeGQMo.js.map +1 -0
- package/dist/chunks/{exporter-6ocL_9x_.js → exporter-8hLNemFk.js} +4 -4
- package/dist/chunks/{exporter-6ocL_9x_.js.map → exporter-8hLNemFk.js.map} +1 -1
- package/dist/chunks/{exporter-BVXnV9-9.js → exporter-BWwEuOPT.js} +29 -17
- package/dist/chunks/exporter-BWwEuOPT.js.map +1 -0
- package/dist/chunks/{exporter-Bcp-l4Bo.js → exporter-CpRyHZ3H.js} +574 -475
- package/dist/chunks/exporter-CpRyHZ3H.js.map +1 -0
- package/dist/chunks/{exporter-SFYkDzD0.js → exporter-yLxKBvLE.js} +23 -20
- package/dist/chunks/{exporter-SFYkDzD0.js.map → exporter-yLxKBvLE.js.map} +1 -1
- package/dist/chunks/{importer-DcKB97kW.js → importer-BbNb7eNg.js} +111 -71
- package/dist/chunks/importer-BbNb7eNg.js.map +1 -0
- package/dist/chunks/{importer-D_srHyj6.js → importer-C98dpSH4.js} +5 -5
- package/dist/chunks/{importer-D_srHyj6.js.map → importer-C98dpSH4.js.map} +1 -1
- package/dist/chunks/{importer-BJlGAOht.js → importer-D794XUTe.js} +3 -3
- package/dist/chunks/{importer-BJlGAOht.js.map → importer-D794XUTe.js.map} +1 -1
- package/dist/chunks/{importer-AjwOJrn2.js → importer-Dz7tI8Sa.js} +202 -181
- package/dist/chunks/importer-Dz7tI8Sa.js.map +1 -0
- package/dist/chunks/{importer-DEp_fYjf.js → importer-Ht7LNg8L.js} +92 -64
- package/dist/chunks/importer-Ht7LNg8L.js.map +1 -0
- package/dist/chunks/{importer-CPqnIY8m.js → importer-WrGRZb0N.js} +42 -29
- package/dist/chunks/importer-WrGRZb0N.js.map +1 -0
- package/dist/chunks/{importer-BpuS3J8C.js → importer-xZ-3suY1.js} +74 -61
- package/dist/chunks/importer-xZ-3suY1.js.map +1 -0
- package/dist/chunks/{json-elements-DpO6AXIc.js → json-elements-DKSqpNW1.js} +3 -3
- package/dist/chunks/{json-elements-DpO6AXIc.js.map → json-elements-DKSqpNW1.js.map} +1 -1
- package/dist/chunks/{ontology-export-50L9DOV4.js → ontology-export-CtRXjg_i.js} +2 -2
- package/dist/chunks/{ontology-export-50L9DOV4.js.map → ontology-export-CtRXjg_i.js.map} +1 -1
- package/dist/chunks/{records-r3SFHz11.js → records-Cu4bxYOm.js} +69 -36
- package/dist/chunks/records-Cu4bxYOm.js.map +1 -0
- package/dist/chunks/{text-Bjfa1xYL.js → text-DHOJXnED.js} +20 -11
- package/dist/chunks/text-DHOJXnED.js.map +1 -0
- package/dist/csv.js +323 -241
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +1 -1
- package/dist/cx2.js +2 -2
- package/dist/cys.js +1 -1
- package/dist/dot.js +1 -1
- package/dist/gexf.js +195 -97
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +170 -149
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +27 -27
- package/dist/graphml.js +2 -2
- package/dist/json.js +1 -1
- package/dist/neo4j.js +103 -65
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +1 -1
- package/dist/pajek.js +1 -1
- package/dist/src/children.d.ts.map +1 -1
- package/dist/src/children.js +50 -27
- package/dist/src/children.js.map +1 -1
- package/dist/src/common/attributes.d.ts.map +1 -1
- package/dist/src/common/attributes.js +86 -42
- package/dist/src/common/attributes.js.map +1 -1
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +358 -184
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/lists.js +30 -15
- package/dist/src/common/lists.js.map +1 -1
- package/dist/src/common/text.d.ts +7 -0
- package/dist/src/common/text.d.ts.map +1 -1
- package/dist/src/common/text.js +15 -7
- package/dist/src/common/text.js.map +1 -1
- package/dist/src/common/zip.d.ts.map +1 -1
- package/dist/src/common/zip.js +36 -19
- package/dist/src/common/zip.js.map +1 -1
- package/dist/src/formats/csv/exporter.d.ts.map +1 -1
- package/dist/src/formats/csv/exporter.js +288 -146
- package/dist/src/formats/csv/exporter.js.map +1 -1
- package/dist/src/formats/csv/importer.d.ts.map +1 -1
- package/dist/src/formats/csv/importer.js +129 -80
- package/dist/src/formats/csv/importer.js.map +1 -1
- package/dist/src/formats/csv/records.d.ts.map +1 -1
- package/dist/src/formats/csv/records.js +78 -36
- package/dist/src/formats/csv/records.js.map +1 -1
- package/dist/src/formats/cys/tables.d.ts.map +1 -1
- package/dist/src/formats/cys/tables.js +11 -8
- package/dist/src/formats/cys/tables.js.map +1 -1
- package/dist/src/formats/dot/tokenizer.d.ts +39 -0
- package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
- package/dist/src/formats/dot/tokenizer.js +112 -66
- package/dist/src/formats/dot/tokenizer.js.map +1 -1
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
- package/dist/src/formats/gexf/exporter.js +65 -37
- package/dist/src/formats/gexf/exporter.js.map +1 -1
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +138 -50
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gml/exporter.d.ts.map +1 -1
- package/dist/src/formats/gml/exporter.js +51 -35
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +103 -58
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/syntax.d.ts.map +1 -1
- package/dist/src/formats/gml/syntax.js +17 -8
- package/dist/src/formats/gml/syntax.js.map +1 -1
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
- package/dist/src/formats/graphml/exporter.js +34 -24
- package/dist/src/formats/graphml/exporter.js.map +1 -1
- package/dist/src/formats/graphml/importer.d.ts.map +1 -1
- package/dist/src/formats/graphml/importer.js +17 -13
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/graphml/tree.js +23 -14
- package/dist/src/formats/graphml/tree.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +22 -10
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +54 -20
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/exporter.d.ts.map +1 -1
- package/dist/src/formats/json/exporter.js +38 -21
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +536 -343
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/obographs.js +29 -17
- package/dist/src/formats/json/obographs.js.map +1 -1
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
- package/dist/src/formats/neo4j/exporter.js +73 -43
- package/dist/src/formats/neo4j/exporter.js.map +1 -1
- package/dist/src/formats/neo4j/header.d.ts.map +1 -1
- package/dist/src/formats/neo4j/header.js +37 -16
- package/dist/src/formats/neo4j/header.js.map +1 -1
- package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
- package/dist/src/formats/neo4j/importer.js +21 -11
- package/dist/src/formats/neo4j/importer.js.map +1 -1
- package/dist/src/formats/obo/exporter.d.ts.map +1 -1
- package/dist/src/formats/obo/exporter.js +18 -7
- package/dist/src/formats/obo/exporter.js.map +1 -1
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +142 -73
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +26 -15
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +85 -58
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts +7 -0
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +79 -40
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
- package/dist/src/formats/xgmml/exporter.js +38 -12
- package/dist/src/formats/xgmml/exporter.js.map +1 -1
- package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
- package/dist/src/formats/xgmml/importer.js +38 -18
- package/dist/src/formats/xgmml/importer.js.map +1 -1
- package/dist/src/sniff.js +109 -57
- package/dist/src/sniff.js.map +1 -1
- package/dist/xgmml.js +2 -2
- package/package.json +2 -2
- package/src/children.ts +54 -27
- package/src/common/attributes.ts +118 -49
- package/src/common/input.ts +439 -197
- package/src/common/lists.ts +29 -15
- package/src/common/text.ts +24 -15
- package/src/common/zip.ts +47 -18
- package/src/formats/csv/exporter.ts +377 -175
- package/src/formats/csv/importer.ts +155 -84
- package/src/formats/csv/records.ts +90 -35
- package/src/formats/cys/tables.ts +11 -10
- package/src/formats/dot/tokenizer.ts +118 -68
- package/src/formats/gexf/exporter.ts +67 -36
- package/src/formats/gexf/importer.ts +173 -63
- package/src/formats/gml/exporter.ts +78 -82
- package/src/formats/gml/importer.ts +119 -68
- package/src/formats/gml/syntax.ts +18 -8
- package/src/formats/graphml/exporter.ts +44 -24
- package/src/formats/graphml/importer.ts +18 -11
- package/src/formats/graphml/tree.ts +22 -12
- package/src/formats/graphml/yfiles.ts +23 -10
- package/src/formats/json/dialect.ts +61 -22
- package/src/formats/json/exporter.ts +40 -21
- package/src/formats/json/importer.ts +701 -385
- package/src/formats/json/obographs.ts +35 -15
- package/src/formats/neo4j/exporter.ts +79 -41
- package/src/formats/neo4j/header.ts +50 -16
- package/src/formats/neo4j/importer.ts +21 -10
- package/src/formats/obo/exporter.ts +34 -17
- package/src/formats/pajek/exporter.ts +180 -117
- package/src/formats/pajek/importer.ts +27 -15
- package/src/formats/pajek/syntax.ts +99 -58
- package/src/formats/xgmml/emit.ts +88 -40
- package/src/formats/xgmml/exporter.ts +40 -12
- package/src/formats/xgmml/importer.ts +45 -23
- package/src/sniff.ts +115 -59
- package/dist/chunks/children-CL3Cy0ez.js.map +0 -1
- package/dist/chunks/export-B-aVCwyG.js.map +0 -1
- package/dist/chunks/exporter-BVXnV9-9.js.map +0 -1
- package/dist/chunks/exporter-Bcp-l4Bo.js.map +0 -1
- package/dist/chunks/importer-AjwOJrn2.js.map +0 -1
- package/dist/chunks/importer-BpuS3J8C.js.map +0 -1
- package/dist/chunks/importer-CPqnIY8m.js.map +0 -1
- package/dist/chunks/importer-DEp_fYjf.js.map +0 -1
- package/dist/chunks/importer-DcKB97kW.js.map +0 -1
- package/dist/chunks/records-r3SFHz11.js.map +0 -1
- package/dist/chunks/text-Bjfa1xYL.js.map +0 -1
|
@@ -270,18 +270,7 @@ function writeElements(name: string, value: unknown, indent: string, out: string
|
|
|
270
270
|
return;
|
|
271
271
|
}
|
|
272
272
|
const object = value as XmlTreeObject;
|
|
273
|
-
|
|
274
|
-
let text: string | null = null;
|
|
275
|
-
let hasChildren = false;
|
|
276
|
-
for (const [key, child] of Object.entries(object)) {
|
|
277
|
-
if (key === TEXT_KEY) {
|
|
278
|
-
text = scalarText(child);
|
|
279
|
-
} else if (key.startsWith(ATTRIBUTE_PREFIX)) {
|
|
280
|
-
attrs += ` ${key.slice(ATTRIBUTE_PREFIX.length)}="${escapeXmlAttribute(scalarText(child))}"`;
|
|
281
|
-
} else {
|
|
282
|
-
hasChildren = true;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
273
|
+
const { attrs, text, hasChildren } = scanElement(object);
|
|
285
274
|
if (!hasChildren) {
|
|
286
275
|
out.push(
|
|
287
276
|
text === null || text.length === 0
|
|
@@ -303,6 +292,27 @@ function writeElements(name: string, value: unknown, indent: string, out: string
|
|
|
303
292
|
out.push(`\n${indent}</${name}>`);
|
|
304
293
|
}
|
|
305
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Split an element object into its attribute text, its text content and whether it has children.
|
|
297
|
+
* @param object - the element object
|
|
298
|
+
* @returns the attribute text, the text content (null when absent) and the children flag
|
|
299
|
+
*/
|
|
300
|
+
function scanElement(object: XmlTreeObject): { attrs: string; text: string | null; hasChildren: boolean } {
|
|
301
|
+
let attrs = "";
|
|
302
|
+
let text: string | null = null;
|
|
303
|
+
let hasChildren = false;
|
|
304
|
+
for (const [key, child] of Object.entries(object)) {
|
|
305
|
+
if (key === TEXT_KEY) {
|
|
306
|
+
text = scalarText(child);
|
|
307
|
+
} else if (key.startsWith(ATTRIBUTE_PREFIX)) {
|
|
308
|
+
attrs += ` ${key.slice(ATTRIBUTE_PREFIX.length)}="${escapeXmlAttribute(scalarText(child))}"`;
|
|
309
|
+
} else {
|
|
310
|
+
hasChildren = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return { attrs, text, hasChildren };
|
|
314
|
+
}
|
|
315
|
+
|
|
306
316
|
/**
|
|
307
317
|
* The text of a scalar tree value.
|
|
308
318
|
* @param value - a string, number, boolean or null
|
|
@@ -109,16 +109,7 @@ export function staleGraphicsRows(column: Column, table: Iterable<Column>, domai
|
|
|
109
109
|
}
|
|
110
110
|
let stale = 0;
|
|
111
111
|
for (let r = 0; r < column.length; r++) {
|
|
112
|
-
const wants =
|
|
113
|
-
for (const tree of trees) {
|
|
114
|
-
const want = graphicsValues(domain, tree.values[r]).find(([f]) => f === field);
|
|
115
|
-
if (want !== undefined) {
|
|
116
|
-
wants.add(JSON.stringify(want[1]));
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (wants.size === 0) {
|
|
120
|
-
wants.add(JSON.stringify(undefined));
|
|
121
|
-
}
|
|
112
|
+
const wants = wantedGraphics(trees, domain, field, r);
|
|
122
113
|
const value = column.value(r);
|
|
123
114
|
const have = column.meta.components > 1 && value !== undefined ? Array.from(value as ArrayLike<number>) : value;
|
|
124
115
|
if (!wants.has(JSON.stringify(have))) {
|
|
@@ -128,6 +119,28 @@ export function staleGraphicsRows(column: Column, table: Iterable<Column>, domai
|
|
|
128
119
|
return stale;
|
|
129
120
|
}
|
|
130
121
|
|
|
122
|
+
/**
|
|
123
|
+
* The serialized values the trees want for one row of a mapped column.
|
|
124
|
+
* @param trees - the yFiles tree columns of the table
|
|
125
|
+
* @param domain - node or edge
|
|
126
|
+
* @param field - the mapped field name
|
|
127
|
+
* @param r - the row
|
|
128
|
+
* @returns the wanted values as JSON text; just `undefined`'s when no tree wants one
|
|
129
|
+
*/
|
|
130
|
+
function wantedGraphics(trees: JsonColumn[], domain: "node" | "edge", field: string, r: number): Set<string> {
|
|
131
|
+
const wants = new Set<string>();
|
|
132
|
+
for (const tree of trees) {
|
|
133
|
+
const want = graphicsValues(domain, tree.values[r]).find(([f]) => f === field);
|
|
134
|
+
if (want !== undefined) {
|
|
135
|
+
wants.add(JSON.stringify(want[1]));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (wants.size === 0) {
|
|
139
|
+
wants.add(JSON.stringify(undefined));
|
|
140
|
+
}
|
|
141
|
+
return wants;
|
|
142
|
+
}
|
|
143
|
+
|
|
131
144
|
/**
|
|
132
145
|
* The mapped values of one `<data>` tree of a yFiles key: a ShapeNode's for a node, a
|
|
133
146
|
* PolyLineEdge's for an edge; nothing for any other graphics (GenericNode, BezierEdge, ...).
|
|
@@ -170,6 +170,17 @@ export function sniffJsonDialect(root: unknown): JsonImportDialect | null {
|
|
|
170
170
|
if (!isJsonObject(root)) {
|
|
171
171
|
return null;
|
|
172
172
|
}
|
|
173
|
+
const decided = sniffWrapperDialect(root) ?? sniffEdgelessDialect(root);
|
|
174
|
+
return decided === undefined ? sniffEdgeListDialect(root) : decided;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* The dialects a top-level wrapper key settles: Cytoscape `elements`, JGF `graph.nodes` /
|
|
179
|
+
* `graph.edges`, and a `graphs[]` array (OBO Graphs when any graph looks like one, else JGF).
|
|
180
|
+
* @param root - the parsed document object
|
|
181
|
+
* @returns the dialect, or undefined when no wrapper key decides it
|
|
182
|
+
*/
|
|
183
|
+
function sniffWrapperDialect(root: Record<string, unknown>): JsonImportDialect | undefined {
|
|
173
184
|
if (hasKey(root, "elements")) {
|
|
174
185
|
return "cytoscape";
|
|
175
186
|
}
|
|
@@ -180,14 +191,31 @@ export function sniffJsonDialect(root: unknown): JsonImportDialect | null {
|
|
|
180
191
|
// any graph decides: an ontology's first graph may be an empty stub before its imports
|
|
181
192
|
return root.graphs.some((g: unknown) => isJsonObject(g) && isOboGraph(g)) ? "obographs" : "jgf";
|
|
182
193
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The dialect of a document with neither `edges` nor `links`: NetworkX adjacency_data (`nodes`
|
|
199
|
+
* and `adjacency`), tree_data (`children` without `nodes`), or no graph at all.
|
|
200
|
+
* @param root - the parsed document object
|
|
201
|
+
* @returns the dialect; null for no graph; undefined when the edge-list rules decide
|
|
202
|
+
*/
|
|
203
|
+
function sniffEdgelessDialect(root: Record<string, unknown>): JsonImportDialect | null | undefined {
|
|
204
|
+
if (hasKey(root, "edges") || hasKey(root, "links")) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
if (hasKey(root, "nodes")) {
|
|
208
|
+
return hasKey(root, "adjacency") ? "adjacency" : undefined;
|
|
190
209
|
}
|
|
210
|
+
return hasKey(root, "children") ? "tree" : null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The dialect of a node and edge list document: graphology, vis, d3 or NetworkX node-link.
|
|
215
|
+
* @param root - the parsed document object
|
|
216
|
+
* @returns the dialect
|
|
217
|
+
*/
|
|
218
|
+
function sniffEdgeListDialect(root: Record<string, unknown>): JsonImportDialect {
|
|
191
219
|
const firstNode = firstJsonObject(root.nodes);
|
|
192
220
|
const firstEdge = firstJsonObject(hasKey(root, "edges") ? root.edges : root.links);
|
|
193
221
|
if (isJsonObject(root.options) && (hasKey(root.options, "type") || hasKey(root.options, "multi"))) {
|
|
@@ -197,25 +225,36 @@ export function sniffJsonDialect(root: unknown): JsonImportDialect | null {
|
|
|
197
225
|
// like a graphology or vis field (`attributes`, `undirected`, `key`, `from`) must not re-route it
|
|
198
226
|
const networkx =
|
|
199
227
|
hasKey(root, "links") || hasKey(root, "directed") || hasKey(root, "multigraph") || hasKey(root, "graph");
|
|
200
|
-
|
|
228
|
+
const record = networkx ? undefined : sniffRecordDialect(firstNode, firstEdge);
|
|
229
|
+
if (record !== undefined) {
|
|
230
|
+
return record;
|
|
231
|
+
}
|
|
232
|
+
const bare = !hasKey(root, "directed") && !hasKey(root, "multigraph") && !hasKey(root, "graph");
|
|
233
|
+
return bare && hasKey(root, "links") ? "d3" : "node-link";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The graphology or vis dialect, read from the first node and edge records of a document without
|
|
238
|
+
* NetworkX's keys: graphology for a `key` node without `id`, or an edge without `from` that has
|
|
239
|
+
* `undirected` or an `attributes` record; vis for an edge with `from` and `to` but no `source`.
|
|
240
|
+
* @param firstNode - the first node record, or null
|
|
241
|
+
* @param firstEdge - the first edge record, or null
|
|
242
|
+
* @returns the dialect, or undefined when the records name neither
|
|
243
|
+
*/
|
|
244
|
+
function sniffRecordDialect(
|
|
245
|
+
firstNode: Record<string, unknown> | null,
|
|
246
|
+
firstEdge: Record<string, unknown> | null,
|
|
247
|
+
): JsonImportDialect | undefined {
|
|
248
|
+
if (firstNode !== null && hasKey(firstNode, "key") && !hasKey(firstNode, "id")) {
|
|
201
249
|
return "graphology";
|
|
202
250
|
}
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
return "graphology";
|
|
206
|
-
}
|
|
251
|
+
if (firstEdge === null) {
|
|
252
|
+
return undefined;
|
|
207
253
|
}
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
firstEdge !== null &&
|
|
211
|
-
hasKey(firstEdge, "from") &&
|
|
212
|
-
hasKey(firstEdge, "to") &&
|
|
213
|
-
!hasKey(firstEdge, "source")
|
|
214
|
-
) {
|
|
215
|
-
return "vis";
|
|
254
|
+
if (!hasKey(firstEdge, "from")) {
|
|
255
|
+
return hasKey(firstEdge, "undirected") || isJsonObject(firstEdge.attributes) ? "graphology" : undefined;
|
|
216
256
|
}
|
|
217
|
-
|
|
218
|
-
return bare && hasKey(root, "links") ? "d3" : "node-link";
|
|
257
|
+
return hasKey(firstEdge, "to") && !hasKey(firstEdge, "source") ? "vis" : undefined;
|
|
219
258
|
}
|
|
220
259
|
|
|
221
260
|
/** The node types of OBO Graphs (the OWL entity kinds). */
|
|
@@ -1609,7 +1609,6 @@ function* writeCytoscape(snapshot: GraphSnapshot, p: Plan): Generator<string, vo
|
|
|
1609
1609
|
const c: Cursor = { w: new JsonWriter(resolved.indent), ids: snapshot.ids, nonfinite: { count: 0 } };
|
|
1610
1610
|
const { w } = c;
|
|
1611
1611
|
const parentSlots: ReadonlySet<Slot> = new Set(["parent"]);
|
|
1612
|
-
const positionSlots: ReadonlySet<Slot> = new Set(["cytoscapePosition"]);
|
|
1613
1612
|
w.open("{");
|
|
1614
1613
|
w.key("elements");
|
|
1615
1614
|
w.open("{");
|
|
@@ -1625,18 +1624,7 @@ function* writeCytoscape(snapshot: GraphSnapshot, p: Plan): Generator<string, vo
|
|
|
1625
1624
|
writeSlots(c, p.nodes, i, parentSlots);
|
|
1626
1625
|
writeSlots(c, p.nodes, i, ATTRIBUTE_SLOTS);
|
|
1627
1626
|
w.close("}");
|
|
1628
|
-
|
|
1629
|
-
if (positionSlots.has(item.slot) && item.column.isSet(i)) {
|
|
1630
|
-
const value = item.column.value(i) as ArrayLike<number>;
|
|
1631
|
-
const f32 = item.column.dtype === "f32";
|
|
1632
|
-
w.key("position");
|
|
1633
|
-
w.open("{");
|
|
1634
|
-
w.member("x", numberText(value[0], f32, c.nonfinite));
|
|
1635
|
-
// stored y-up; Cytoscape's y grows downward
|
|
1636
|
-
w.member("y", numberText(flipY(value[1]), f32, c.nonfinite));
|
|
1637
|
-
w.close("}");
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1627
|
+
writeCytoscapePosition(c, p.nodes, i);
|
|
1640
1628
|
writeSlots(c, p.nodes, i, ELEMENT_SLOTS);
|
|
1641
1629
|
w.close("}");
|
|
1642
1630
|
yield w.take();
|
|
@@ -1673,18 +1661,49 @@ function* writeCytoscape(snapshot: GraphSnapshot, p: Plan): Generator<string, vo
|
|
|
1673
1661
|
w.key("data");
|
|
1674
1662
|
writeGraphObject(c, p);
|
|
1675
1663
|
}
|
|
1676
|
-
|
|
1677
|
-
if (extra !== undefined) {
|
|
1678
|
-
for (const key of Object.keys(extra)) {
|
|
1679
|
-
if (key !== "elements" && key !== "data") {
|
|
1680
|
-
w.member(key, valueText(extra[key], false, c.nonfinite));
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1664
|
+
writeCytoscapeExtra(c, resolved.shape.cytoscape);
|
|
1684
1665
|
w.close("}");
|
|
1685
1666
|
yield w.take();
|
|
1686
1667
|
}
|
|
1687
1668
|
|
|
1669
|
+
/**
|
|
1670
|
+
* Write a node's `position` member (Cytoscape.js), when its position is set.
|
|
1671
|
+
* @param c - the cursor
|
|
1672
|
+
* @param items - the node plan items
|
|
1673
|
+
* @param i - the node index
|
|
1674
|
+
*/
|
|
1675
|
+
function writeCytoscapePosition(c: Cursor, items: readonly ColumnPlan[], i: number): void {
|
|
1676
|
+
const { w } = c;
|
|
1677
|
+
for (const item of items) {
|
|
1678
|
+
if (item.slot === "cytoscapePosition" && item.column.isSet(i)) {
|
|
1679
|
+
const value = item.column.value(i) as ArrayLike<number>;
|
|
1680
|
+
const f32 = item.column.dtype === "f32";
|
|
1681
|
+
w.key("position");
|
|
1682
|
+
w.open("{");
|
|
1683
|
+
w.member("x", numberText(value[0], f32, c.nonfinite));
|
|
1684
|
+
// stored y-up; Cytoscape's y grows downward
|
|
1685
|
+
w.member("y", numberText(flipY(value[1]), f32, c.nonfinite));
|
|
1686
|
+
w.close("}");
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* Write the extra top-level members of a Cytoscape.js document, beyond `elements` and `data`.
|
|
1693
|
+
* @param c - the cursor
|
|
1694
|
+
* @param extra - the extra members, when any
|
|
1695
|
+
*/
|
|
1696
|
+
function writeCytoscapeExtra(c: Cursor, extra: Readonly<Record<string, unknown>> | undefined): void {
|
|
1697
|
+
if (extra === undefined) {
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
for (const key of Object.keys(extra)) {
|
|
1701
|
+
if (key !== "elements" && key !== "data") {
|
|
1702
|
+
c.w.member(key, valueText(extra[key], false, c.nonfinite));
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1688
1707
|
/**
|
|
1689
1708
|
* A generator of canonical `e<index>` edge ids for the edges without one (design section 4.6),
|
|
1690
1709
|
* skipping any text a node id or an explicit edge id already uses (Cytoscape ids share one
|