@graphty/graph-io 0.3.40 → 0.3.41
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/dist/chunks/{choose-CS3fvGT1.js → choose-CwFQamH9.js} +2 -2
- package/dist/chunks/{choose-CS3fvGT1.js.map → choose-CwFQamH9.js.map} +1 -1
- package/dist/chunks/{constants-DqKZT6cH.js → constants-Cf4Nn6tw.js} +2 -2
- package/dist/chunks/{constants-DqKZT6cH.js.map → constants-Cf4Nn6tw.js.map} +1 -1
- package/dist/chunks/{escape-BJRLd3vJ.js → escape-DBb8zuNE.js} +2 -2
- package/dist/chunks/{escape-BJRLd3vJ.js.map → escape-DBb8zuNE.js.map} +1 -1
- package/dist/chunks/{export-B-aVCwyG.js → export-DD3Lvw-F.js} +173 -116
- package/dist/chunks/export-DD3Lvw-F.js.map +1 -0
- package/dist/chunks/{exporter-Bcp-l4Bo.js → exporter-BqtmlxNr.js} +545 -459
- package/dist/chunks/exporter-BqtmlxNr.js.map +1 -0
- package/dist/chunks/{exporter-6ocL_9x_.js → exporter-CS35R6Fg.js} +4 -4
- package/dist/chunks/{exporter-6ocL_9x_.js.map → exporter-CS35R6Fg.js.map} +1 -1
- package/dist/chunks/{exporter-BVXnV9-9.js → exporter-D8r1N2dU.js} +28 -16
- package/dist/chunks/exporter-D8r1N2dU.js.map +1 -0
- package/dist/chunks/{exporter-SFYkDzD0.js → exporter-NMplSnYn.js} +23 -20
- package/dist/chunks/{exporter-SFYkDzD0.js.map → exporter-NMplSnYn.js.map} +1 -1
- package/dist/chunks/{importer-CPqnIY8m.js → importer-BKC7AmCA.js} +42 -29
- package/dist/chunks/importer-BKC7AmCA.js.map +1 -0
- package/dist/chunks/{importer-D_srHyj6.js → importer-BdWHmlmG.js} +4 -4
- package/dist/chunks/{importer-D_srHyj6.js.map → importer-BdWHmlmG.js.map} +1 -1
- package/dist/chunks/{importer-AjwOJrn2.js → importer-BfbzWk6k.js} +202 -181
- package/dist/chunks/importer-BfbzWk6k.js.map +1 -0
- package/dist/chunks/{importer-BpuS3J8C.js → importer-BmaZcskq.js} +73 -60
- package/dist/chunks/importer-BmaZcskq.js.map +1 -0
- package/dist/chunks/{importer-DEp_fYjf.js → importer-DviEsHy4.js} +92 -64
- package/dist/chunks/importer-DviEsHy4.js.map +1 -0
- package/dist/chunks/{importer-DcKB97kW.js → importer-S-abxJHn.js} +5 -5
- package/dist/chunks/{importer-DcKB97kW.js.map → importer-S-abxJHn.js.map} +1 -1
- package/dist/chunks/{importer-BJlGAOht.js → importer-r29cWnEf.js} +3 -3
- package/dist/chunks/{importer-BJlGAOht.js.map → importer-r29cWnEf.js.map} +1 -1
- package/dist/chunks/{json-elements-DpO6AXIc.js → json-elements-DdF-etPT.js} +3 -3
- package/dist/chunks/{json-elements-DpO6AXIc.js.map → json-elements-DdF-etPT.js.map} +1 -1
- package/dist/chunks/{ontology-export-50L9DOV4.js → ontology-export-BC0zyPhj.js} +2 -2
- package/dist/chunks/{ontology-export-50L9DOV4.js.map → ontology-export-BC0zyPhj.js.map} +1 -1
- package/dist/chunks/{records-r3SFHz11.js → records-Uc3LkABx.js} +15 -12
- package/dist/chunks/records-Uc3LkABx.js.map +1 -0
- package/dist/chunks/{text-Bjfa1xYL.js → text-Bh9SaAob.js} +20 -11
- package/dist/chunks/text-Bh9SaAob.js.map +1 -0
- package/dist/csv.js +67 -49
- 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 +26 -26
- 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/common/attributes.d.ts.map +1 -1
- package/dist/src/common/attributes.js +34 -9
- 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 +180 -102
- package/dist/src/common/input.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 +77 -25
- 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 +16 -6
- 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 +18 -10
- 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/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/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/common/attributes.ts +59 -19
- package/src/common/input.ts +216 -102
- package/src/common/text.ts +24 -15
- package/src/common/zip.ts +47 -18
- package/src/formats/csv/exporter.ts +103 -39
- package/src/formats/csv/importer.ts +17 -6
- package/src/formats/csv/records.ts +19 -10
- package/src/formats/cys/tables.ts +11 -10
- 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/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/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/records-r3SFHz11.js.map +0 -1
- package/dist/chunks/text-Bjfa1xYL.js.map +0 -1
|
@@ -503,21 +503,7 @@ function writeMeta(
|
|
|
503
503
|
element: string,
|
|
504
504
|
): void {
|
|
505
505
|
const path = `${element}.meta`;
|
|
506
|
-
|
|
507
|
-
if (isJsonObject(definition)) {
|
|
508
|
-
const xrefs = strings(ctx, definition.xrefs, `${path}.definition.xrefs`);
|
|
509
|
-
if (typeof definition.val === "string") {
|
|
510
|
-
columns.node("def", row, definition.val);
|
|
511
|
-
columns.node("def.xrefs", row, xrefs);
|
|
512
|
-
} else {
|
|
513
|
-
badValue(ctx, `${path}.definition has no string val; it is dropped`, `${path}.definition.val`);
|
|
514
|
-
}
|
|
515
|
-
if (definition.meta !== undefined) {
|
|
516
|
-
unrecognized["meta.definition.meta"] = definition.meta;
|
|
517
|
-
}
|
|
518
|
-
} else if (definition !== undefined && definition !== null) {
|
|
519
|
-
badValue(ctx, `${path}.definition must be an object with a val; it is dropped`, `${path}.definition`);
|
|
520
|
-
}
|
|
506
|
+
writeDefinition(ctx, columns, meta.definition, row, unrecognized, path);
|
|
521
507
|
const comments = strings(ctx, meta.comments, `${path}.comments`);
|
|
522
508
|
if (comments.length > 0) {
|
|
523
509
|
columns.node("comment", row, comments.join("\n"));
|
|
@@ -547,6 +533,40 @@ function writeMeta(
|
|
|
547
533
|
}
|
|
548
534
|
}
|
|
549
535
|
|
|
536
|
+
/**
|
|
537
|
+
* Write a node's `meta.definition`: the text and its xrefs; a nested `meta` is kept in
|
|
538
|
+
* `obo.unrecognized`.
|
|
539
|
+
* @param ctx - the context
|
|
540
|
+
* @param columns - the column writer
|
|
541
|
+
* @param definition - the `definition` field
|
|
542
|
+
* @param row - the node index
|
|
543
|
+
* @param unrecognized - where keys without a column go
|
|
544
|
+
* @param path - the meta path in messages
|
|
545
|
+
*/
|
|
546
|
+
function writeDefinition(
|
|
547
|
+
ctx: ImportContext,
|
|
548
|
+
columns: ColumnWriter,
|
|
549
|
+
definition: unknown,
|
|
550
|
+
row: number,
|
|
551
|
+
unrecognized: JsonRecord,
|
|
552
|
+
path: string,
|
|
553
|
+
): void {
|
|
554
|
+
if (isJsonObject(definition)) {
|
|
555
|
+
const xrefs = strings(ctx, definition.xrefs, `${path}.definition.xrefs`);
|
|
556
|
+
if (typeof definition.val === "string") {
|
|
557
|
+
columns.node("def", row, definition.val);
|
|
558
|
+
columns.node("def.xrefs", row, xrefs);
|
|
559
|
+
} else {
|
|
560
|
+
badValue(ctx, `${path}.definition has no string val; it is dropped`, `${path}.definition.val`);
|
|
561
|
+
}
|
|
562
|
+
if (definition.meta !== undefined) {
|
|
563
|
+
unrecognized["meta.definition.meta"] = definition.meta;
|
|
564
|
+
}
|
|
565
|
+
} else if (definition !== undefined && definition !== null) {
|
|
566
|
+
badValue(ctx, `${path}.definition must be an object with a val; it is dropped`, `${path}.definition`);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
550
570
|
/**
|
|
551
571
|
* The synonyms of a node's meta as the OBO `synonym` items: each entry that is not an object or
|
|
552
572
|
* has no string val reported and dropped, a predicate that is not one of the four scopes kept with
|
|
@@ -400,6 +400,17 @@ class ExportPlan {
|
|
|
400
400
|
this.checkStoredIds();
|
|
401
401
|
this.directionNotes();
|
|
402
402
|
const slots = new Set([this.kind, this.labels, this.idSpace].flatMap((c) => (c === null ? [] : [c.meta.name])));
|
|
403
|
+
this.addGenericNotes(generic, slots);
|
|
404
|
+
this.notes.push(...this.ownNotes);
|
|
405
|
+
this.filterNotesByPart();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Add the generic capability notes, leaving out the ones this format reads back as they were.
|
|
410
|
+
* @param generic - the notes the capability check found
|
|
411
|
+
* @param slots - the names of the :TYPE, :LABEL and :ID(Space) columns
|
|
412
|
+
*/
|
|
413
|
+
private addGenericNotes(generic: ReturnType<typeof checkCapabilities>, slots: ReadonlySet<string>): void {
|
|
403
414
|
for (const gen of generic) {
|
|
404
415
|
if (gen.code === LOSS.JSON && gen.column !== null && this.writtenAsPoint(gen.column)) {
|
|
405
416
|
continue;
|
|
@@ -425,8 +436,6 @@ class ExportPlan {
|
|
|
425
436
|
}
|
|
426
437
|
this.notes.push(gen);
|
|
427
438
|
}
|
|
428
|
-
this.notes.push(...this.ownNotes);
|
|
429
|
-
this.filterNotesByPart();
|
|
430
439
|
}
|
|
431
440
|
|
|
432
441
|
/**
|
|
@@ -617,22 +626,7 @@ class ExportPlan {
|
|
|
617
626
|
* @returns the scalar plan
|
|
618
627
|
*/
|
|
619
628
|
private integralOrDouble(column: Column, declared: string, label: string): ScalarPlan {
|
|
620
|
-
|
|
621
|
-
if (column.dtype === "f64") {
|
|
622
|
-
for (let r = 0; r < column.length && integral; r++) {
|
|
623
|
-
if (column.isSet(r) && !Number.isInteger(column.data[r])) {
|
|
624
|
-
integral = false;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
} else if (column.dtype === "list" && column.child.dtype === "f64") {
|
|
628
|
-
const { data } = column.child;
|
|
629
|
-
for (let i = 0; i < data.length && integral; i++) {
|
|
630
|
-
if (!Number.isInteger(data[i])) {
|
|
631
|
-
integral = false;
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
if (integral) {
|
|
629
|
+
if (holdsOnlyIntegers(column)) {
|
|
636
630
|
return { type: declared, kind: "integer", temporal: null };
|
|
637
631
|
}
|
|
638
632
|
this.note(
|
|
@@ -1186,23 +1180,34 @@ class ExportPlan {
|
|
|
1186
1180
|
return null;
|
|
1187
1181
|
}
|
|
1188
1182
|
if (plan.list) {
|
|
1189
|
-
|
|
1190
|
-
const texts: string[] = [];
|
|
1191
|
-
for (const item of Array.from(items)) {
|
|
1192
|
-
// an item of several components (itemComponents > 1) is flattened into the array
|
|
1193
|
-
if (Array.isArray(item) || ArrayBuffer.isView(item)) {
|
|
1194
|
-
for (const component of Array.from(item as ArrayLike<unknown>)) {
|
|
1195
|
-
texts.push(formatScalar(component, scalar, null));
|
|
1196
|
-
}
|
|
1197
|
-
} else {
|
|
1198
|
-
texts.push(formatScalar(item, scalar, null));
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
return texts.join(this.options.arrayDelimiter);
|
|
1183
|
+
return this.listText(plan, row);
|
|
1202
1184
|
}
|
|
1203
1185
|
const text = companion?.isSet(row) ? textOf(companion, row) : null;
|
|
1204
1186
|
return formatScalar(column.dtype === "json" ? column.values[row] : column.value(row), scalar, text);
|
|
1205
1187
|
}
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* The text of one list cell: its items joined by the array delimiter.
|
|
1191
|
+
* @param plan - the column plan
|
|
1192
|
+
* @param row - the row, which is set
|
|
1193
|
+
* @returns the text
|
|
1194
|
+
*/
|
|
1195
|
+
private listText(plan: ColumnPlan, row: number): string {
|
|
1196
|
+
const { column, scalar } = plan;
|
|
1197
|
+
const items = column.dtype === "list" ? column.sliceOf(row) : (column.value(row) as ArrayLike<unknown>);
|
|
1198
|
+
const texts: string[] = [];
|
|
1199
|
+
for (const item of Array.from(items)) {
|
|
1200
|
+
// an item of several components (itemComponents > 1) is flattened into the array
|
|
1201
|
+
if (Array.isArray(item) || ArrayBuffer.isView(item)) {
|
|
1202
|
+
for (const component of Array.from(item as ArrayLike<unknown>)) {
|
|
1203
|
+
texts.push(formatScalar(component, scalar, null));
|
|
1204
|
+
}
|
|
1205
|
+
} else {
|
|
1206
|
+
texts.push(formatScalar(item, scalar, null));
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return texts.join(this.options.arrayDelimiter);
|
|
1210
|
+
}
|
|
1206
1211
|
}
|
|
1207
1212
|
|
|
1208
1213
|
/**
|
|
@@ -1319,6 +1324,16 @@ function defaultScalar(dtype: Dtype | ScalarDtype): ScalarPlan {
|
|
|
1319
1324
|
}
|
|
1320
1325
|
}
|
|
1321
1326
|
|
|
1327
|
+
/**
|
|
1328
|
+
* Format a number with a formatter; any other value is written as String(value).
|
|
1329
|
+
* @param value - the value
|
|
1330
|
+
* @param format - the number formatter
|
|
1331
|
+
* @returns the text
|
|
1332
|
+
*/
|
|
1333
|
+
function numberOrString(value: unknown, format: (n: number) => string): string {
|
|
1334
|
+
return typeof value === "number" ? format(value) : String(value);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1322
1337
|
/**
|
|
1323
1338
|
* Format one scalar value for a cell.
|
|
1324
1339
|
* @param value - the value
|
|
@@ -1329,22 +1344,22 @@ function defaultScalar(dtype: Dtype | ScalarDtype): ScalarPlan {
|
|
|
1329
1344
|
function formatScalar(value: unknown, scalar: ScalarPlan, text: string | null): string {
|
|
1330
1345
|
switch (scalar.kind) {
|
|
1331
1346
|
case "integer":
|
|
1332
|
-
return
|
|
1347
|
+
return numberOrString(value, formatInteger);
|
|
1333
1348
|
case "float":
|
|
1334
|
-
return
|
|
1349
|
+
return numberOrString(value, formatF32);
|
|
1335
1350
|
case "double":
|
|
1336
|
-
return
|
|
1351
|
+
return numberOrString(value, formatF64);
|
|
1337
1352
|
case "boolean":
|
|
1338
1353
|
return value === true ? "true" : "false";
|
|
1339
1354
|
case "string":
|
|
1340
|
-
return
|
|
1355
|
+
return String(value);
|
|
1341
1356
|
case "temporal":
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1357
|
+
return (
|
|
1358
|
+
text ??
|
|
1359
|
+
numberOrString(value, (n) =>
|
|
1360
|
+
scalar.temporal === null ? String(n) : formatTemporal(n, scalar.temporal),
|
|
1361
|
+
)
|
|
1362
|
+
);
|
|
1348
1363
|
case "point":
|
|
1349
1364
|
return formatPoint(value);
|
|
1350
1365
|
case "json":
|
|
@@ -1539,3 +1554,26 @@ function weightPropertyOf(snapshot: GraphSnapshot): string | null {
|
|
|
1539
1554
|
const name = neo4j?.weightProperty;
|
|
1540
1555
|
return typeof name === "string" && name !== "" ? name : null;
|
|
1541
1556
|
}
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* Whether every set value of an f64 column, or of an f64 list column's items, is integral.
|
|
1560
|
+
* @param column - the column
|
|
1561
|
+
* @returns false when a value is not an integer
|
|
1562
|
+
*/
|
|
1563
|
+
function holdsOnlyIntegers(column: Column): boolean {
|
|
1564
|
+
if (column.dtype === "f64") {
|
|
1565
|
+
for (let r = 0; r < column.length; r++) {
|
|
1566
|
+
if (column.isSet(r) && !Number.isInteger(column.data[r])) {
|
|
1567
|
+
return false;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
} else if (column.dtype === "list" && column.child.dtype === "f64") {
|
|
1571
|
+
const { data } = column.child;
|
|
1572
|
+
for (let i = 0; i < data.length; i++) {
|
|
1573
|
+
if (!Number.isInteger(data[i])) {
|
|
1574
|
+
return false;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
return true;
|
|
1579
|
+
}
|
|
@@ -108,28 +108,14 @@ export function parseHeaderField(text: string): HeaderField {
|
|
|
108
108
|
const space = m[3] === undefined ? null : m[3].trim();
|
|
109
109
|
const options = parseOptions(text, m[4]);
|
|
110
110
|
if (rawType === null) {
|
|
111
|
-
|
|
112
|
-
if (name.length === 0) {
|
|
113
|
-
throw headerError(text, "an empty header cell");
|
|
114
|
-
}
|
|
115
|
-
if (space !== null || options.size > 0) {
|
|
116
|
-
throw headerError(text, "an id space or options need a field type");
|
|
117
|
-
}
|
|
118
|
-
return { text, name, kind: "PROPERTY", type: null, space: null, options };
|
|
111
|
+
return untypedField(text, name, space, options);
|
|
119
112
|
}
|
|
120
113
|
if (rawType.length === 0) {
|
|
121
114
|
throw headerError(text, "an empty field type");
|
|
122
115
|
}
|
|
123
116
|
const upper = rawType.toUpperCase();
|
|
124
117
|
if (STRUCTURAL.has(upper)) {
|
|
125
|
-
|
|
126
|
-
if (space !== null && !SPACE_KINDS.has(kind)) {
|
|
127
|
-
throw headerError(text, `an id space is only allowed on ID, START_ID and END_ID, not ${kind}`);
|
|
128
|
-
}
|
|
129
|
-
if (name.length > 0 && kind !== "ID" && kind !== "IGNORE") {
|
|
130
|
-
throw headerError(text, `a ${kind} field cannot be stored as a property`);
|
|
131
|
-
}
|
|
132
|
-
return { text, name, kind, type: null, space: space === "" ? null : space, options };
|
|
118
|
+
return structuralField(text, name, upper as Exclude<FieldKind, "PROPERTY">, space, options);
|
|
133
119
|
}
|
|
134
120
|
if (name.length === 0) {
|
|
135
121
|
throw headerError(text, "a property column needs a name");
|
|
@@ -140,6 +126,54 @@ export function parseHeaderField(text: string): HeaderField {
|
|
|
140
126
|
return { text, name, kind: "PROPERTY", type: rawType, space: null, options };
|
|
141
127
|
}
|
|
142
128
|
|
|
129
|
+
/**
|
|
130
|
+
* The field of a cell with no type: `name` alone is a string property.
|
|
131
|
+
* @param text - the whole cell, for errors
|
|
132
|
+
* @param name - the property name
|
|
133
|
+
* @param space - the id space, or null
|
|
134
|
+
* @param options - the options
|
|
135
|
+
* @returns the field
|
|
136
|
+
*/
|
|
137
|
+
function untypedField(
|
|
138
|
+
text: string,
|
|
139
|
+
name: string,
|
|
140
|
+
space: string | null,
|
|
141
|
+
options: ReadonlyMap<string, string>,
|
|
142
|
+
): HeaderField {
|
|
143
|
+
if (name.length === 0) {
|
|
144
|
+
throw headerError(text, "an empty header cell");
|
|
145
|
+
}
|
|
146
|
+
if (space !== null || options.size > 0) {
|
|
147
|
+
throw headerError(text, "an id space or options need a field type");
|
|
148
|
+
}
|
|
149
|
+
return { text, name, kind: "PROPERTY", type: null, space: null, options };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The field of a cell with a structural type (ID, START_ID, END_ID, LABEL, TYPE, IGNORE).
|
|
154
|
+
* @param text - the whole cell, for errors
|
|
155
|
+
* @param name - the property name, or empty
|
|
156
|
+
* @param kind - the structural kind
|
|
157
|
+
* @param space - the id space, or null
|
|
158
|
+
* @param options - the options
|
|
159
|
+
* @returns the field
|
|
160
|
+
*/
|
|
161
|
+
function structuralField(
|
|
162
|
+
text: string,
|
|
163
|
+
name: string,
|
|
164
|
+
kind: Exclude<FieldKind, "PROPERTY">,
|
|
165
|
+
space: string | null,
|
|
166
|
+
options: ReadonlyMap<string, string>,
|
|
167
|
+
): HeaderField {
|
|
168
|
+
if (space !== null && !SPACE_KINDS.has(kind)) {
|
|
169
|
+
throw headerError(text, `an id space is only allowed on ID, START_ID and END_ID, not ${kind}`);
|
|
170
|
+
}
|
|
171
|
+
if (name.length > 0 && kind !== "ID" && kind !== "IGNORE") {
|
|
172
|
+
throw headerError(text, `a ${kind} field cannot be stored as a property`);
|
|
173
|
+
}
|
|
174
|
+
return { text, name, kind, type: null, space: space === "" ? null : space, options };
|
|
175
|
+
}
|
|
176
|
+
|
|
143
177
|
/**
|
|
144
178
|
* Parse the `{key:value, key:value}` options of a header cell.
|
|
145
179
|
* @param text - the whole cell, for errors
|
|
@@ -1385,16 +1385,7 @@ class Neo4jImportSession {
|
|
|
1385
1385
|
}
|
|
1386
1386
|
const { spec } = slot;
|
|
1387
1387
|
try {
|
|
1388
|
-
|
|
1389
|
-
const zoned = withZoneOffset(text, spec);
|
|
1390
|
-
const parsed = parseDeclaredTemporal(zoned, spec);
|
|
1391
|
-
values[slot.cell] = parsed.value;
|
|
1392
|
-
// a zone name is kept in the companion text, the value is its instant
|
|
1393
|
-
texts[slot.cell] = zoned === text ? parsed.text : text;
|
|
1394
|
-
} else {
|
|
1395
|
-
values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
|
|
1396
|
-
checkNeo4jRange(spec, values[slot.cell], text);
|
|
1397
|
-
}
|
|
1388
|
+
this.parseCell(slot, text);
|
|
1398
1389
|
} catch (err) {
|
|
1399
1390
|
this.report.recordError(err, { line, element: `${element} ${slot.name}` });
|
|
1400
1391
|
return false;
|
|
@@ -1409,6 +1400,26 @@ class Neo4jImportSession {
|
|
|
1409
1400
|
return true;
|
|
1410
1401
|
}
|
|
1411
1402
|
|
|
1403
|
+
/**
|
|
1404
|
+
* Parse one non-empty property cell into the scratch arrays; throws on a malformed value.
|
|
1405
|
+
* @param slot - the cell's property slot
|
|
1406
|
+
* @param text - the cell text
|
|
1407
|
+
*/
|
|
1408
|
+
private parseCell(slot: PropertySlot, text: string): void {
|
|
1409
|
+
const { values, texts } = this;
|
|
1410
|
+
const { spec } = slot;
|
|
1411
|
+
if (spec.temporal !== null && !spec.list) {
|
|
1412
|
+
const zoned = withZoneOffset(text, spec);
|
|
1413
|
+
const parsed = parseDeclaredTemporal(zoned, spec);
|
|
1414
|
+
values[slot.cell] = parsed.value;
|
|
1415
|
+
// a zone name is kept in the companion text, the value is its instant
|
|
1416
|
+
texts[slot.cell] = zoned === text ? parsed.text : text;
|
|
1417
|
+
} else {
|
|
1418
|
+
values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
|
|
1419
|
+
checkNeo4jRange(spec, values[slot.cell], text);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1412
1423
|
/**
|
|
1413
1424
|
* Write the parsed property values of a row.
|
|
1414
1425
|
* @param domain - node or edge
|
|
@@ -972,6 +972,39 @@ function keptObo(snapshot: GraphSnapshot): {
|
|
|
972
972
|
return { header: clauses(record.header), typedefs, unknownFrames };
|
|
973
973
|
}
|
|
974
974
|
|
|
975
|
+
/**
|
|
976
|
+
* Note the frame kinds the written nodes read back as: the type column gained, and the nodes
|
|
977
|
+
* written as [Typedef] frames.
|
|
978
|
+
* @param snapshot - the snapshot
|
|
979
|
+
* @param rows - the node indices written as frames
|
|
980
|
+
* @param kinds - the frame kind of each node
|
|
981
|
+
* @param note - receives the notes
|
|
982
|
+
*/
|
|
983
|
+
function noteFrameKinds(
|
|
984
|
+
snapshot: GraphSnapshot,
|
|
985
|
+
rows: readonly number[],
|
|
986
|
+
kinds: readonly string[],
|
|
987
|
+
note: NoteFn,
|
|
988
|
+
): void {
|
|
989
|
+
if (rows.length > 0 && !snapshot.nodes.has("type")) {
|
|
990
|
+
note(
|
|
991
|
+
OBO_LOSS.TYPE_GAINED,
|
|
992
|
+
`${rows.length} node${plural(rows.length)} ${agree(rows.length, "is", "are")} written as [Term] frames and ${agree(rows.length, "reads", "read")} back with the type Term in a new node column "type"`,
|
|
993
|
+
null,
|
|
994
|
+
rows.length,
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
const typedefNodes = rows.filter((i) => kinds[i] === "Typedef").length;
|
|
998
|
+
if (typedefNodes > 0) {
|
|
999
|
+
note(
|
|
1000
|
+
OBO_LOSS.TYPEDEF_NODES,
|
|
1001
|
+
`${typedefNodes} node${plural(typedefNodes)} ${agree(typedefNodes, "is", "are")} written as [Typedef] frames; they read back as nodes only when imported with typedefs: "nodes", and then after the other nodes, with the [Typedef] frames that declare the relations`,
|
|
1002
|
+
"type",
|
|
1003
|
+
typedefNodes,
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
975
1008
|
/**
|
|
976
1009
|
* Plan an export: the notes, the fatal condition and what is written.
|
|
977
1010
|
* @param snapshot - the snapshot
|
|
@@ -1014,23 +1047,7 @@ function plan(snapshot: GraphSnapshot, options: (OboExportOptions & CommonExport
|
|
|
1014
1047
|
}
|
|
1015
1048
|
}
|
|
1016
1049
|
const { kinds, type } = planKinds(snapshot, frameless);
|
|
1017
|
-
|
|
1018
|
-
note(
|
|
1019
|
-
OBO_LOSS.TYPE_GAINED,
|
|
1020
|
-
`${rows.length} node${plural(rows.length)} ${agree(rows.length, "is", "are")} written as [Term] frames and ${agree(rows.length, "reads", "read")} back with the type Term in a new node column "type"`,
|
|
1021
|
-
null,
|
|
1022
|
-
rows.length,
|
|
1023
|
-
);
|
|
1024
|
-
}
|
|
1025
|
-
const typedefNodes = rows.filter((i) => kinds[i] === "Typedef").length;
|
|
1026
|
-
if (typedefNodes > 0) {
|
|
1027
|
-
note(
|
|
1028
|
-
OBO_LOSS.TYPEDEF_NODES,
|
|
1029
|
-
`${typedefNodes} node${plural(typedefNodes)} ${agree(typedefNodes, "is", "are")} written as [Typedef] frames; they read back as nodes only when imported with typedefs: "nodes", and then after the other nodes, with the [Typedef] frames that declare the relations`,
|
|
1030
|
-
"type",
|
|
1031
|
-
typedefNodes,
|
|
1032
|
-
);
|
|
1033
|
-
}
|
|
1050
|
+
noteFrameKinds(snapshot, rows, kinds, note);
|
|
1034
1051
|
|
|
1035
1052
|
const kept = keptObo(snapshot);
|
|
1036
1053
|
const scopes = synonymTypeScopes(kept.header);
|