@graphty/graph-io 0.3.25 → 0.3.27
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 +49 -414
- package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
- package/dist/chunks/choose-DrXtu_96.js +56 -0
- package/dist/chunks/choose-DrXtu_96.js.map +1 -0
- package/dist/chunks/constants-ikG85dT8.js +231 -0
- package/dist/chunks/constants-ikG85dT8.js.map +1 -0
- package/dist/chunks/{escape-B-tkk_Cl.js → escape-D1HPTUrP.js} +390 -99
- package/dist/chunks/escape-D1HPTUrP.js.map +1 -0
- package/dist/chunks/export-CHd4tQE2.js +4333 -0
- package/dist/chunks/export-CHd4tQE2.js.map +1 -0
- package/dist/chunks/{importer-eUREhBGj.js → exporter-D23CKNqF.js} +4969 -3201
- package/dist/chunks/exporter-D23CKNqF.js.map +1 -0
- package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-DfWTgrti.js} +23 -21
- package/dist/chunks/exporter-DfWTgrti.js.map +1 -0
- package/dist/chunks/exporter-DhtW6FxK.js +3465 -0
- package/dist/chunks/exporter-DhtW6FxK.js.map +1 -0
- package/dist/chunks/{exporter-BGrsWamJ.js → exporter-IHv4nkCm.js} +38 -229
- package/dist/chunks/exporter-IHv4nkCm.js.map +1 -0
- package/dist/chunks/{importer-BWY2FFc5.js → importer-B1wmPQjr.js} +255 -77
- package/dist/chunks/importer-B1wmPQjr.js.map +1 -0
- package/dist/chunks/{importer-D_e7e7LX.js → importer-B2W_58pz.js} +399 -146
- package/dist/chunks/importer-B2W_58pz.js.map +1 -0
- package/dist/chunks/importer-BSALvkui.js +2811 -0
- package/dist/chunks/importer-BSALvkui.js.map +1 -0
- package/dist/chunks/{importer-vi3bSdtw.js → importer-BVRE--Un.js} +510 -77
- package/dist/chunks/importer-BVRE--Un.js.map +1 -0
- package/dist/chunks/{importer-DET1tg6s.js → importer-CIAzt-wo.js} +1689 -312
- package/dist/chunks/importer-CIAzt-wo.js.map +1 -0
- package/dist/chunks/{importer-DIrbbnAf.js → importer-DpEW5zeG.js} +585 -226
- package/dist/chunks/importer-DpEW5zeG.js.map +1 -0
- package/dist/chunks/{importer-zGLo8Dg_.js → importer-z_FL4VMb.js} +488 -161
- package/dist/chunks/importer-z_FL4VMb.js.map +1 -0
- package/dist/chunks/json-elements-BAmNBZok.js +1225 -0
- package/dist/chunks/json-elements-BAmNBZok.js.map +1 -0
- package/dist/chunks/ontology-export-Bab4eUA8.js +357 -0
- package/dist/chunks/ontology-export-Bab4eUA8.js.map +1 -0
- package/dist/chunks/{records-dbRkxwaq.js → records-CdlvL4RO.js} +298 -114
- package/dist/chunks/records-CdlvL4RO.js.map +1 -0
- package/dist/chunks/{text-Dr0Ifpag.js → text-DzXjAiTl.js} +29 -11
- package/dist/chunks/text-DzXjAiTl.js.map +1 -0
- package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
- package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
- package/dist/csv.js +952 -262
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +6 -3
- package/dist/cx2.js +2 -2
- package/dist/cys.js +6 -3
- package/dist/dot.js +1 -1
- package/dist/gexf.js +554 -122
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +344 -87
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +1105 -213
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -2
- package/dist/graphml.js.map +1 -1
- package/dist/json.js +3 -2
- package/dist/neo4j.js +565 -158
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +6 -3
- package/dist/pajek.js +1 -1
- package/dist/src/children.d.ts +18 -6
- package/dist/src/children.d.ts.map +1 -1
- package/dist/src/children.js +6 -3
- package/dist/src/children.js.map +1 -1
- package/dist/src/common/attributes.d.ts +29 -11
- package/dist/src/common/attributes.d.ts.map +1 -1
- package/dist/src/common/attributes.js +25 -7
- package/dist/src/common/attributes.js.map +1 -1
- package/dist/src/common/cell-budget.d.ts +9 -2
- package/dist/src/common/cell-budget.d.ts.map +1 -1
- package/dist/src/common/cell-budget.js +11 -3
- package/dist/src/common/cell-budget.js.map +1 -1
- package/dist/src/common/choose.d.ts +19 -0
- package/dist/src/common/choose.d.ts.map +1 -0
- package/dist/src/common/choose.js +72 -0
- package/dist/src/common/choose.js.map +1 -0
- package/dist/src/common/codes.d.ts +456 -66
- package/dist/src/common/codes.d.ts.map +1 -1
- package/dist/src/common/codes.js +458 -66
- package/dist/src/common/codes.js.map +1 -1
- package/dist/src/common/compare.d.ts +81 -0
- package/dist/src/common/compare.d.ts.map +1 -0
- package/dist/src/common/compare.js +394 -0
- package/dist/src/common/compare.js.map +1 -0
- package/dist/src/common/cx-export.d.ts +123 -0
- package/dist/src/common/cx-export.d.ts.map +1 -0
- package/dist/src/common/cx-export.js +334 -0
- package/dist/src/common/cx-export.js.map +1 -0
- package/dist/src/common/declared-types.d.ts +22 -2
- package/dist/src/common/declared-types.d.ts.map +1 -1
- package/dist/src/common/declared-types.js +21 -3
- package/dist/src/common/declared-types.js.map +1 -1
- package/dist/src/common/direction.d.ts +74 -50
- package/dist/src/common/direction.d.ts.map +1 -1
- package/dist/src/common/direction.js +47 -27
- package/dist/src/common/direction.js.map +1 -1
- package/dist/src/common/escape.d.ts +21 -9
- package/dist/src/common/escape.d.ts.map +1 -1
- package/dist/src/common/escape.js +39 -22
- package/dist/src/common/escape.js.map +1 -1
- package/dist/src/common/export.d.ts +144 -32
- package/dist/src/common/export.d.ts.map +1 -1
- package/dist/src/common/export.js +216 -42
- package/dist/src/common/export.js.map +1 -1
- package/dist/src/common/format.d.ts +23 -1
- package/dist/src/common/format.d.ts.map +1 -1
- package/dist/src/common/format.js +26 -1
- package/dist/src/common/format.js.map +1 -1
- package/dist/src/common/ids.d.ts +9 -2
- package/dist/src/common/ids.d.ts.map +1 -1
- package/dist/src/common/ids.js +6 -2
- package/dist/src/common/ids.js.map +1 -1
- package/dist/src/common/input.d.ts +122 -28
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +890 -124
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/json-elements.d.ts +144 -20
- package/dist/src/common/json-elements.d.ts.map +1 -1
- package/dist/src/common/json-elements.js +869 -189
- package/dist/src/common/json-elements.js.map +1 -1
- package/dist/src/common/line-format.d.ts +90 -0
- package/dist/src/common/line-format.d.ts.map +1 -0
- package/dist/src/common/line-format.js +185 -0
- package/dist/src/common/line-format.js.map +1 -0
- package/dist/src/common/lists.d.ts +6 -1
- package/dist/src/common/lists.d.ts.map +1 -1
- package/dist/src/common/lists.js +3 -1
- package/dist/src/common/lists.js.map +1 -1
- package/dist/src/common/ontology-export.d.ts +167 -0
- package/dist/src/common/ontology-export.d.ts.map +1 -0
- package/dist/src/common/ontology-export.js +359 -0
- package/dist/src/common/ontology-export.js.map +1 -0
- package/dist/src/common/ontology.d.ts +25 -3
- package/dist/src/common/ontology.d.ts.map +1 -1
- package/dist/src/common/ontology.js +30 -9
- package/dist/src/common/ontology.js.map +1 -1
- package/dist/src/common/options.d.ts +62 -12
- package/dist/src/common/options.d.ts.map +1 -1
- package/dist/src/common/options.js +89 -11
- package/dist/src/common/options.js.map +1 -1
- package/dist/src/common/plural.d.ts +31 -0
- package/dist/src/common/plural.d.ts.map +1 -0
- package/dist/src/common/plural.js +46 -0
- package/dist/src/common/plural.js.map +1 -0
- package/dist/src/common/report.d.ts +72 -14
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +146 -22
- package/dist/src/common/report.js.map +1 -1
- package/dist/src/common/temporal.d.ts +22 -5
- package/dist/src/common/temporal.d.ts.map +1 -1
- package/dist/src/common/temporal.js +13 -2
- package/dist/src/common/temporal.js.map +1 -1
- package/dist/src/common/text.d.ts +39 -23
- package/dist/src/common/text.d.ts.map +1 -1
- package/dist/src/common/text.js +51 -21
- package/dist/src/common/text.js.map +1 -1
- package/dist/src/common/weights.d.ts +37 -4
- package/dist/src/common/weights.d.ts.map +1 -1
- package/dist/src/common/weights.js +61 -2
- package/dist/src/common/weights.js.map +1 -1
- package/dist/src/common/writer.d.ts +19 -3
- package/dist/src/common/writer.d.ts.map +1 -1
- package/dist/src/common/writer.js +30 -2
- package/dist/src/common/writer.js.map +1 -1
- package/dist/src/common/xml.d.ts +125 -9
- package/dist/src/common/xml.d.ts.map +1 -1
- package/dist/src/common/xml.js +402 -85
- package/dist/src/common/xml.js.map +1 -1
- package/dist/src/common/zip.d.ts +44 -4
- package/dist/src/common/zip.d.ts.map +1 -1
- package/dist/src/common/zip.js +134 -5
- package/dist/src/common/zip.js.map +1 -1
- package/dist/src/formats/csv/exporter.d.ts +80 -24
- package/dist/src/formats/csv/exporter.d.ts.map +1 -1
- package/dist/src/formats/csv/exporter.js +146 -33
- package/dist/src/formats/csv/exporter.js.map +1 -1
- package/dist/src/formats/csv/header.d.ts +38 -9
- package/dist/src/formats/csv/header.d.ts.map +1 -1
- package/dist/src/formats/csv/header.js +46 -10
- package/dist/src/formats/csv/header.js.map +1 -1
- package/dist/src/formats/csv/importer.d.ts +187 -37
- package/dist/src/formats/csv/importer.d.ts.map +1 -1
- package/dist/src/formats/csv/importer.js +835 -204
- package/dist/src/formats/csv/importer.js.map +1 -1
- package/dist/src/formats/csv/index.d.ts +100 -19
- package/dist/src/formats/csv/index.d.ts.map +1 -1
- package/dist/src/formats/csv/index.js +94 -21
- package/dist/src/formats/csv/index.js.map +1 -1
- package/dist/src/formats/csv/records.d.ts +95 -10
- package/dist/src/formats/csv/records.d.ts.map +1 -1
- package/dist/src/formats/csv/records.js +333 -122
- package/dist/src/formats/csv/records.js.map +1 -1
- package/dist/src/formats/csv/values.d.ts +1 -0
- package/dist/src/formats/csv/values.d.ts.map +1 -1
- package/dist/src/formats/csv/values.js +1 -0
- package/dist/src/formats/csv/values.js.map +1 -1
- package/dist/src/formats/cx/exporter.d.ts +102 -0
- package/dist/src/formats/cx/exporter.d.ts.map +1 -0
- package/dist/src/formats/cx/exporter.js +1217 -0
- package/dist/src/formats/cx/exporter.js.map +1 -0
- package/dist/src/formats/cx/importer.d.ts +79 -32
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +682 -287
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/index.d.ts +4 -3
- package/dist/src/formats/cx/index.d.ts.map +1 -1
- package/dist/src/formats/cx/index.js +4 -3
- package/dist/src/formats/cx/index.js.map +1 -1
- package/dist/src/formats/cx2/exporter.d.ts +29 -11
- package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
- package/dist/src/formats/cx2/exporter.js +39 -268
- package/dist/src/formats/cx2/exporter.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts +78 -28
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +227 -80
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/index.d.ts +2 -1
- package/dist/src/formats/cx2/index.d.ts.map +1 -1
- package/dist/src/formats/cx2/index.js +2 -1
- package/dist/src/formats/cx2/index.js.map +1 -1
- package/dist/src/formats/cys/constants.d.ts +66 -17
- package/dist/src/formats/cys/constants.d.ts.map +1 -1
- package/dist/src/formats/cys/constants.js +59 -18
- package/dist/src/formats/cys/constants.js.map +1 -1
- package/dist/src/formats/cys/exporter.d.ts +118 -0
- package/dist/src/formats/cys/exporter.d.ts.map +1 -0
- package/dist/src/formats/cys/exporter.js +1072 -0
- package/dist/src/formats/cys/exporter.js.map +1 -0
- package/dist/src/formats/cys/importer.d.ts +22 -8
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +510 -149
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/index.d.ts +4 -2
- package/dist/src/formats/cys/index.d.ts.map +1 -1
- package/dist/src/formats/cys/index.js +4 -2
- package/dist/src/formats/cys/index.js.map +1 -1
- package/dist/src/formats/cys/session.d.ts +46 -7
- package/dist/src/formats/cys/session.d.ts.map +1 -1
- package/dist/src/formats/cys/session.js +101 -27
- package/dist/src/formats/cys/session.js.map +1 -1
- package/dist/src/formats/cys/tables.d.ts +9 -2
- package/dist/src/formats/cys/tables.d.ts.map +1 -1
- package/dist/src/formats/cys/tables.js +29 -7
- package/dist/src/formats/cys/tables.js.map +1 -1
- package/dist/src/formats/dot/exporter.d.ts +42 -14
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +56 -29
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts +91 -29
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +190 -39
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +2 -1
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +2 -1
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/names.d.ts +44 -11
- package/dist/src/formats/dot/names.d.ts.map +1 -1
- package/dist/src/formats/dot/names.js +44 -11
- package/dist/src/formats/dot/names.js.map +1 -1
- package/dist/src/formats/dot/tokenizer.d.ts +9 -2
- package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
- package/dist/src/formats/dot/tokenizer.js +20 -5
- package/dist/src/formats/dot/tokenizer.js.map +1 -1
- package/dist/src/formats/gexf/exporter.d.ts +46 -15
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
- package/dist/src/formats/gexf/exporter.js +45 -15
- package/dist/src/formats/gexf/exporter.js.map +1 -1
- package/dist/src/formats/gexf/importer.d.ts +87 -23
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +471 -90
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/index.d.ts +84 -21
- package/dist/src/formats/gexf/index.d.ts.map +1 -1
- package/dist/src/formats/gexf/index.js +80 -23
- package/dist/src/formats/gexf/index.js.map +1 -1
- package/dist/src/formats/gexf/schema.d.ts +67 -15
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +59 -13
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gml/exporter.d.ts +69 -21
- package/dist/src/formats/gml/exporter.d.ts.map +1 -1
- package/dist/src/formats/gml/exporter.js +74 -29
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts +116 -25
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +290 -61
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +87 -24
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +79 -26
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/syntax.d.ts +67 -18
- package/dist/src/formats/gml/syntax.d.ts.map +1 -1
- package/dist/src/formats/gml/syntax.js +110 -28
- package/dist/src/formats/gml/syntax.js.map +1 -1
- package/dist/src/formats/graphml/constants.d.ts +174 -44
- package/dist/src/formats/graphml/constants.d.ts.map +1 -1
- package/dist/src/formats/graphml/constants.js +165 -44
- package/dist/src/formats/graphml/constants.js.map +1 -1
- package/dist/src/formats/graphml/exporter.d.ts +17 -9
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
- package/dist/src/formats/graphml/exporter.js +33 -12
- package/dist/src/formats/graphml/exporter.js.map +1 -1
- package/dist/src/formats/graphml/importer.d.ts +19 -7
- package/dist/src/formats/graphml/importer.d.ts.map +1 -1
- package/dist/src/formats/graphml/importer.js +466 -39
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/graphml/index.d.ts +2 -1
- package/dist/src/formats/graphml/index.d.ts.map +1 -1
- package/dist/src/formats/graphml/index.js +2 -1
- package/dist/src/formats/graphml/index.js.map +1 -1
- package/dist/src/formats/graphml/tree.d.ts +6 -2
- package/dist/src/formats/graphml/tree.d.ts.map +1 -1
- package/dist/src/formats/graphml/tree.js +6 -2
- package/dist/src/formats/graphml/tree.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +8 -3
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +36 -15
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/dialect.d.ts +88 -24
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +109 -19
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/exporter.d.ts +134 -22
- package/dist/src/formats/json/exporter.d.ts.map +1 -1
- package/dist/src/formats/json/exporter.js +135 -54
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +173 -52
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +899 -220
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/index.d.ts +3 -2
- package/dist/src/formats/json/index.d.ts.map +1 -1
- package/dist/src/formats/json/index.js +3 -2
- package/dist/src/formats/json/index.js.map +1 -1
- package/dist/src/formats/json/obographs-export.d.ts +68 -0
- package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
- package/dist/src/formats/json/obographs-export.js +941 -0
- package/dist/src/formats/json/obographs-export.js.map +1 -0
- package/dist/src/formats/json/obographs.d.ts +26 -0
- package/dist/src/formats/json/obographs.d.ts.map +1 -1
- package/dist/src/formats/json/obographs.js +297 -80
- package/dist/src/formats/json/obographs.js.map +1 -1
- package/dist/src/formats/neo4j/exporter.d.ts +109 -21
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
- package/dist/src/formats/neo4j/exporter.js +239 -86
- package/dist/src/formats/neo4j/exporter.js.map +1 -1
- package/dist/src/formats/neo4j/header.d.ts +17 -4
- package/dist/src/formats/neo4j/header.d.ts.map +1 -1
- package/dist/src/formats/neo4j/header.js +36 -4
- package/dist/src/formats/neo4j/header.js.map +1 -1
- package/dist/src/formats/neo4j/importer.d.ts +107 -27
- package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
- package/dist/src/formats/neo4j/importer.js +415 -63
- package/dist/src/formats/neo4j/importer.js.map +1 -1
- package/dist/src/formats/neo4j/index.d.ts +73 -23
- package/dist/src/formats/neo4j/index.d.ts.map +1 -1
- package/dist/src/formats/neo4j/index.js +65 -25
- package/dist/src/formats/neo4j/index.js.map +1 -1
- package/dist/src/formats/obo/exporter.d.ts +150 -0
- package/dist/src/formats/obo/exporter.d.ts.map +1 -0
- package/dist/src/formats/obo/exporter.js +1736 -0
- package/dist/src/formats/obo/exporter.js.map +1 -0
- package/dist/src/formats/obo/importer.d.ts +95 -19
- package/dist/src/formats/obo/importer.d.ts.map +1 -1
- package/dist/src/formats/obo/importer.js +475 -104
- package/dist/src/formats/obo/importer.js.map +1 -1
- package/dist/src/formats/obo/index.d.ts +6 -3
- package/dist/src/formats/obo/index.d.ts.map +1 -1
- package/dist/src/formats/obo/index.js +6 -3
- package/dist/src/formats/obo/index.js.map +1 -1
- package/dist/src/formats/obo/syntax.d.ts +108 -4
- package/dist/src/formats/obo/syntax.d.ts.map +1 -1
- package/dist/src/formats/obo/syntax.js +211 -34
- package/dist/src/formats/obo/syntax.js.map +1 -1
- package/dist/src/formats/pajek/exporter.d.ts +54 -16
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +67 -35
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +84 -22
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +303 -83
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +2 -1
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js +2 -1
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts +77 -14
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +186 -54
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/columns.d.ts +1 -0
- package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
- package/dist/src/formats/xgmml/columns.js +4 -0
- package/dist/src/formats/xgmml/columns.js.map +1 -1
- package/dist/src/formats/xgmml/constants.d.ts +186 -56
- package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
- package/dist/src/formats/xgmml/constants.js +181 -57
- package/dist/src/formats/xgmml/constants.js.map +1 -1
- package/dist/src/formats/xgmml/document.d.ts +65 -11
- package/dist/src/formats/xgmml/document.d.ts.map +1 -1
- package/dist/src/formats/xgmml/document.js +157 -28
- package/dist/src/formats/xgmml/document.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts +61 -3
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +129 -26
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/exporter.d.ts +13 -6
- package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
- package/dist/src/formats/xgmml/exporter.js +21 -22
- package/dist/src/formats/xgmml/exporter.js.map +1 -1
- package/dist/src/formats/xgmml/importer.d.ts +33 -12
- package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
- package/dist/src/formats/xgmml/importer.js +35 -72
- package/dist/src/formats/xgmml/importer.js.map +1 -1
- package/dist/src/formats/xgmml/index.d.ts +1 -0
- package/dist/src/formats/xgmml/index.d.ts.map +1 -1
- package/dist/src/formats/xgmml/index.js +1 -0
- package/dist/src/formats/xgmml/index.js.map +1 -1
- package/dist/src/formats/xgmml/values.d.ts +8 -1
- package/dist/src/formats/xgmml/values.d.ts.map +1 -1
- package/dist/src/formats/xgmml/values.js +8 -3
- package/dist/src/formats/xgmml/values.js.map +1 -1
- package/dist/src/index.d.ts +23 -18
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +28 -16
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts +478 -92
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +807 -88
- package/dist/src/registry.js.map +1 -1
- package/dist/src/sniff.d.ts +61 -19
- package/dist/src/sniff.d.ts.map +1 -1
- package/dist/src/sniff.js +121 -29
- package/dist/src/sniff.js.map +1 -1
- package/dist/src/types.d.ts +362 -112
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +28 -7
- package/dist/src/types.js.map +1 -1
- package/dist/xgmml.js +2 -2
- package/docs/samples/README.md +25 -0
- package/docs/samples/got-edges.csv +353 -0
- package/docs/samples/got-network.graphml +1384 -0
- package/docs/samples/got-nodes.csv +108 -0
- package/docs/samples/got.cx +930 -0
- package/docs/samples/got.cx2 +465 -0
- package/docs/samples/got.gexf +471 -0
- package/docs/samples/got.gml +2650 -0
- package/docs/samples/got.json +2546 -0
- package/docs/samples/got.net +461 -0
- package/docs/samples/movies-nodes.csv +9 -0
- package/docs/samples/movies-rels.csv +8 -0
- package/docs/samples/networks.cys +0 -0
- package/docs/samples/proteins.xgmml +9 -0
- package/docs/samples/teams.gv +24 -0
- package/docs/samples/vehicles.obo +25 -0
- package/package.json +9 -4
- package/src/children.ts +18 -6
- package/src/common/attributes.ts +29 -11
- package/src/common/cell-budget.ts +11 -3
- package/src/common/choose.ts +89 -0
- package/src/common/codes.ts +490 -66
- package/src/common/compare.ts +472 -0
- package/src/common/cx-export.ts +432 -0
- package/src/common/declared-types.ts +40 -6
- package/src/common/direction.ts +78 -51
- package/src/common/escape.ts +39 -22
- package/src/common/export.ts +284 -47
- package/src/common/format.ts +30 -1
- package/src/common/ids.ts +14 -3
- package/src/common/input.ts +1057 -134
- package/src/common/json-elements.ts +1035 -199
- package/src/common/line-format.ts +249 -0
- package/src/common/lists.ts +7 -2
- package/src/common/ontology-export.ts +461 -0
- package/src/common/ontology.ts +31 -9
- package/src/common/options.ts +110 -15
- package/src/common/plural.ts +49 -0
- package/src/common/report.ts +168 -25
- package/src/common/temporal.ts +22 -5
- package/src/common/text.ts +62 -23
- package/src/common/weights.ts +74 -4
- package/src/common/writer.ts +37 -3
- package/src/common/xml.ts +479 -90
- package/src/common/zip.ts +169 -7
- package/src/formats/csv/exporter.ts +202 -47
- package/src/formats/csv/header.ts +50 -11
- package/src/formats/csv/importer.ts +1133 -245
- package/src/formats/csv/index.ts +106 -19
- package/src/formats/csv/records.ts +396 -122
- package/src/formats/csv/values.ts +1 -0
- package/src/formats/cx/exporter.ts +1483 -0
- package/src/formats/cx/importer.ts +890 -302
- package/src/formats/cx/index.ts +4 -3
- package/src/formats/cx2/exporter.ts +62 -339
- package/src/formats/cx2/importer.ts +318 -87
- package/src/formats/cx2/index.ts +2 -1
- package/src/formats/cys/constants.ts +62 -17
- package/src/formats/cys/exporter.ts +1368 -0
- package/src/formats/cys/importer.ts +659 -157
- package/src/formats/cys/index.ts +4 -2
- package/src/formats/cys/session.ts +142 -34
- package/src/formats/cys/tables.ts +47 -9
- package/src/formats/dot/exporter.ts +83 -37
- package/src/formats/dot/importer.ts +248 -54
- package/src/formats/dot/index.ts +2 -1
- package/src/formats/dot/names.ts +44 -11
- package/src/formats/dot/tokenizer.ts +25 -6
- package/src/formats/gexf/exporter.ts +57 -18
- package/src/formats/gexf/importer.ts +636 -105
- package/src/formats/gexf/index.ts +90 -21
- package/src/formats/gexf/schema.ts +67 -15
- package/src/formats/gml/exporter.ts +90 -36
- package/src/formats/gml/importer.ts +388 -67
- package/src/formats/gml/index.ts +85 -24
- package/src/formats/gml/syntax.ts +113 -28
- package/src/formats/graphml/constants.ts +178 -44
- package/src/formats/graphml/exporter.ts +52 -18
- package/src/formats/graphml/importer.ts +640 -60
- package/src/formats/graphml/index.ts +2 -1
- package/src/formats/graphml/tree.ts +6 -2
- package/src/formats/graphml/yfiles.ts +37 -15
- package/src/formats/json/dialect.ts +128 -29
- package/src/formats/json/exporter.ts +205 -68
- package/src/formats/json/importer.ts +1163 -253
- package/src/formats/json/index.ts +3 -1
- package/src/formats/json/obographs-export.ts +1197 -0
- package/src/formats/json/obographs.ts +353 -92
- package/src/formats/neo4j/exporter.ts +321 -102
- package/src/formats/neo4j/header.ts +44 -6
- package/src/formats/neo4j/importer.ts +512 -73
- package/src/formats/neo4j/index.ts +75 -23
- package/src/formats/obo/exporter.ts +2210 -0
- package/src/formats/obo/importer.ts +622 -109
- package/src/formats/obo/index.ts +6 -3
- package/src/formats/obo/syntax.ts +232 -37
- package/src/formats/pajek/exporter.ts +90 -42
- package/src/formats/pajek/importer.ts +407 -93
- package/src/formats/pajek/index.ts +2 -1
- package/src/formats/pajek/syntax.ts +216 -55
- package/src/formats/xgmml/columns.ts +10 -0
- package/src/formats/xgmml/constants.ts +183 -56
- package/src/formats/xgmml/document.ts +212 -34
- package/src/formats/xgmml/emit.ts +175 -34
- package/src/formats/xgmml/exporter.ts +36 -28
- package/src/formats/xgmml/importer.ts +64 -86
- package/src/formats/xgmml/index.ts +1 -0
- package/src/formats/xgmml/values.ts +12 -4
- package/src/index.ts +81 -11
- package/src/registry.ts +1121 -135
- package/src/sniff.ts +163 -32
- package/src/types.ts +385 -114
- package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
- package/dist/chunks/export-Bh60Dv-n.js +0 -582
- package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
- package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
- package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
- package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
- package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
- package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
- package/dist/chunks/importer-DET1tg6s.js.map +0 -1
- package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
- package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
- package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
- package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
- package/dist/chunks/importer-eUREhBGj.js.map +0 -1
- package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
- package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
- package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
- package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
- package/dist/chunks/ontology-BnrJ4I98.js +0 -113
- package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
- package/dist/chunks/records-dbRkxwaq.js.map +0 -1
- package/dist/chunks/report-B1z4WT9e.js +0 -2372
- package/dist/chunks/report-B1z4WT9e.js.map +0 -1
- package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
- package/dist/chunks/weights-Dzba96G3.js +0 -176
- package/dist/chunks/weights-Dzba96G3.js.map +0 -1
- package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
uniqueColumnName,
|
|
59
59
|
} from "../../common/attributes.js";
|
|
60
60
|
import {
|
|
61
|
+
DANGLING_REFERENCE_CODE as SHARED_DANGLING_REFERENCE_CODE,
|
|
61
62
|
DUPLICATE_NODE_CODE as SHARED_DUPLICATE_NODE_CODE,
|
|
62
63
|
MISSING_ENDPOINT_CODE as SHARED_MISSING_ENDPOINT_CODE,
|
|
63
64
|
MISSING_ID_CODE as SHARED_MISSING_ID_CODE,
|
|
@@ -74,7 +75,9 @@ import {
|
|
|
74
75
|
type ResolvedImportOptions,
|
|
75
76
|
resolveImportOptions,
|
|
76
77
|
} from "../../common/options.js";
|
|
78
|
+
import { agree, plural, withArticle } from "../../common/plural.js";
|
|
77
79
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
80
|
+
import { parseTemporal } from "../../common/temporal.js";
|
|
78
81
|
import { parseWeightText } from "../../common/weights.js";
|
|
79
82
|
import {
|
|
80
83
|
type CommonImportOptions,
|
|
@@ -86,72 +89,152 @@ import {
|
|
|
86
89
|
import { checkRecordSyntax, RecordReader, type RecordSyntax } from "../csv/records.js";
|
|
87
90
|
import { type FieldKind, type HeaderField, isHeaderRecord, parseHeaderField } from "./header.js";
|
|
88
91
|
|
|
89
|
-
/**
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
/**
|
|
93
|
+
* The format-specific options of the Neo4j importer.
|
|
94
|
+
* @category Built-in formats
|
|
95
|
+
*/
|
|
96
|
+
export interface Neo4jImportOptions extends CommonImportOptions {
|
|
97
|
+
/**
|
|
98
|
+
* More node files, each a string, bytes or a stream with its own header row; read after the
|
|
99
|
+
* main input.
|
|
100
|
+
*/
|
|
92
101
|
nodes?: ImportInput | readonly ImportInput[] | undefined;
|
|
93
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Relationship files, each a string, bytes or a stream with its own header row; read after the
|
|
104
|
+
* node files.
|
|
105
|
+
*/
|
|
94
106
|
relationships?: ImportInput | readonly ImportInput[] | undefined;
|
|
95
107
|
/**
|
|
96
|
-
* The field delimiter (neo4j-admin `--delimiter`)
|
|
97
|
-
*
|
|
108
|
+
* The field delimiter, one character (neo4j-admin's `--delimiter`). The default is to detect
|
|
109
|
+
* "," or a tab from the first rows, so a `.tsv` file needs no option. It must differ from
|
|
110
|
+
* `arrayDelimiter`: with `delimiter: ";"`, also pass `arrayDelimiter: ","` or `"|"`.
|
|
111
|
+
* @defaultValue detected
|
|
98
112
|
*/
|
|
99
113
|
delimiter?: string | undefined;
|
|
100
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* The delimiter inside list values and `:LABEL` cells (neo4j-admin's `--array-delimiter`). It
|
|
116
|
+
* must differ from `delimiter`.
|
|
117
|
+
* @defaultValue ";"
|
|
118
|
+
*/
|
|
101
119
|
arrayDelimiter?: ";" | "," | "|" | undefined;
|
|
102
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* The quote character, one character (neo4j-admin's `--quote`).
|
|
122
|
+
* @defaultValue '"'
|
|
123
|
+
*/
|
|
103
124
|
quote?: string | undefined;
|
|
104
125
|
}
|
|
105
126
|
|
|
106
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* The name of the node list column holding `:LABEL` values.
|
|
129
|
+
* @category Built-in formats
|
|
130
|
+
*/
|
|
107
131
|
export const LABELS_COLUMN = "labels";
|
|
108
132
|
|
|
109
|
-
/**
|
|
133
|
+
/**
|
|
134
|
+
* The name of the edge dict column holding `:TYPE` values.
|
|
135
|
+
* @category Built-in formats
|
|
136
|
+
*/
|
|
110
137
|
export const TYPE_COLUMN = "type";
|
|
111
138
|
|
|
112
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* The name of the node dict column holding the id space of `:ID(Space)`.
|
|
141
|
+
* @category Built-in formats
|
|
142
|
+
*/
|
|
113
143
|
export const ID_SPACE_COLUMN = "idSpace";
|
|
114
144
|
|
|
115
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Neo4j CSV: the name of the node column that holds a node's id as the file wrote it, for a node of an id
|
|
147
|
+
* space (`:ID(Person)`), whose node id is `Person:<id>`. It has nothing to do with the `originalId` role that
|
|
148
|
+
* `sanitizeIds: "mangle"` uses.
|
|
149
|
+
* @category Built-in formats
|
|
150
|
+
*/
|
|
116
151
|
export const ORIGINAL_ID_COLUMN = "originalId";
|
|
117
152
|
|
|
118
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* A header row (or a whole section) is malformed; the import aborts.
|
|
155
|
+
* @category Issue and loss codes
|
|
156
|
+
*/
|
|
119
157
|
export const HEADER_CODE = "E_NEO4J_HEADER";
|
|
120
158
|
|
|
121
|
-
/**
|
|
159
|
+
/**
|
|
160
|
+
* A row has a different number of cells than its header.
|
|
161
|
+
* @category Issue and loss codes
|
|
162
|
+
*/
|
|
122
163
|
export const COLUMN_COUNT_CODE = "E_NEO4J_COLUMN_COUNT";
|
|
123
164
|
|
|
124
|
-
/**
|
|
165
|
+
/**
|
|
166
|
+
* A node row has an unquoted empty `:ID` cell (a quoted empty cell is the id "").
|
|
167
|
+
* @category Issue and loss codes
|
|
168
|
+
*/
|
|
125
169
|
export const MISSING_ID_CODE = SHARED_MISSING_ID_CODE;
|
|
126
170
|
|
|
127
|
-
/**
|
|
171
|
+
/**
|
|
172
|
+
* A relationship row has an unquoted empty `:START_ID` or `:END_ID` cell.
|
|
173
|
+
* @category Issue and loss codes
|
|
174
|
+
*/
|
|
128
175
|
export const MISSING_ENDPOINT_CODE = SHARED_MISSING_ENDPOINT_CODE;
|
|
129
176
|
|
|
130
|
-
/**
|
|
177
|
+
/**
|
|
178
|
+
* A node id was declared twice (same id space); the later row's properties win.
|
|
179
|
+
* @category Issue and loss codes
|
|
180
|
+
*/
|
|
131
181
|
export const DUPLICATE_NODE_CODE = SHARED_DUPLICATE_NODE_CODE;
|
|
132
182
|
|
|
133
183
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
184
|
+
* A node id was declared in two id spaces -- a spaced id `Space:id` equals the text of an id declared without a space;
|
|
185
|
+
* the later row is skipped.
|
|
186
|
+
* @category Issue and loss codes
|
|
136
187
|
*/
|
|
137
188
|
export const ID_SPACE_COLLISION_CODE = "E_NEO4J_ID_SPACE_COLLISION";
|
|
138
189
|
|
|
139
190
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
191
|
+
* A `:START_ID(Space)` / `:END_ID(Space)` endpoint's qualified id `Space:id` names a node a node row declared in
|
|
192
|
+
* another id space (without a space); the row is skipped.
|
|
193
|
+
* @category Issue and loss codes
|
|
142
194
|
*/
|
|
143
195
|
export const ENDPOINT_SPACE_CODE = "E_NEO4J_ENDPOINT_SPACE";
|
|
144
196
|
|
|
145
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Two different id cells became one id under `ids: "number"`.
|
|
199
|
+
* @category Issue and loss codes
|
|
200
|
+
*/
|
|
146
201
|
export const ID_MERGED_CODE = SHARED_ID_MERGED_CODE;
|
|
147
202
|
|
|
148
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* A header brace option the importer does not act on.
|
|
205
|
+
* @category Issue and loss codes
|
|
206
|
+
*/
|
|
149
207
|
export const HEADER_OPTION_CODE = "W_NEO4J_HEADER_OPTION_IGNORED";
|
|
150
208
|
|
|
151
|
-
/**
|
|
209
|
+
/**
|
|
210
|
+
* You read into a graph builder that already has the labels, type or id space attribute, so this file's one is kept
|
|
211
|
+
* without its role.
|
|
212
|
+
* @category Issue and loss codes
|
|
213
|
+
*/
|
|
152
214
|
export const ROLE_TAKEN_CODE = SHARED_ROLE_TAKEN_CODE;
|
|
153
215
|
|
|
154
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* A relationship row with an empty `:TYPE` cell (neo4j-admin requires a type); the relationship is kept.
|
|
218
|
+
* @category Issue and loss codes
|
|
219
|
+
*/
|
|
220
|
+
export const MISSING_TYPE_CODE = "W_NEO4J_MISSING_TYPE";
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* A file given under the `nodes` option holds a relationship header, or the reverse.
|
|
224
|
+
* @category Issue and loss codes
|
|
225
|
+
*/
|
|
226
|
+
export const SECTION_KIND_CODE = "W_NEO4J_SECTION_KIND";
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Relationship endpoints that no node row declares became nodes (the shared W_DANGLING_REFERENCE).
|
|
230
|
+
* @category Issue and loss codes
|
|
231
|
+
*/
|
|
232
|
+
export const DANGLING_REFERENCE_CODE = SHARED_DANGLING_REFERENCE_CODE;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* `:IGNORE` columns were skipped.
|
|
236
|
+
* @category Built-in formats
|
|
237
|
+
*/
|
|
155
238
|
export const IGNORED_COLUMNS_LOSS = "W_NEO4J_IGNORED_COLUMNS";
|
|
156
239
|
|
|
157
240
|
/** The common options the Neo4j importer reads (the rest is reported by reportUnusedOptions). */
|
|
@@ -287,16 +370,27 @@ function resolveNeo4jOptions(options: Neo4jImportOptions | undefined): ResolvedN
|
|
|
287
370
|
{ option: "arrayDelimiter", found: arrayDelimiter },
|
|
288
371
|
);
|
|
289
372
|
}
|
|
373
|
+
if (arrayDelimiter === "," && o.delimiter === undefined) {
|
|
374
|
+
throw new GraphFormatError(
|
|
375
|
+
"E_UNSUPPORTED",
|
|
376
|
+
'option arrayDelimiter "," needs the delimiter option: the field delimiter is a comma unless another is given',
|
|
377
|
+
{ option: "arrayDelimiter", found: arrayDelimiter },
|
|
378
|
+
);
|
|
379
|
+
}
|
|
290
380
|
const syntax = checkRecordSyntax({
|
|
291
381
|
delimiter: o.delimiter ?? null,
|
|
292
382
|
quote: o.quote ?? '"',
|
|
293
383
|
candidates: NEO4J_DELIMITER_CANDIDATES.filter((d) => d !== arrayDelimiter),
|
|
294
384
|
});
|
|
295
385
|
if (syntax.delimiter === arrayDelimiter) {
|
|
296
|
-
throw new GraphFormatError(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
386
|
+
throw new GraphFormatError(
|
|
387
|
+
"E_UNSUPPORTED",
|
|
388
|
+
`options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`,
|
|
389
|
+
{
|
|
390
|
+
option: "arrayDelimiter",
|
|
391
|
+
found: arrayDelimiter,
|
|
392
|
+
},
|
|
393
|
+
);
|
|
300
394
|
}
|
|
301
395
|
return {
|
|
302
396
|
nodes: inputList("nodes", o.nodes),
|
|
@@ -307,7 +401,7 @@ function resolveNeo4jOptions(options: Neo4jImportOptions | undefined): ResolvedN
|
|
|
307
401
|
}
|
|
308
402
|
|
|
309
403
|
/**
|
|
310
|
-
*
|
|
404
|
+
* Normalize an input-list option.
|
|
311
405
|
* @param name - the option name
|
|
312
406
|
* @param value - one input, a list of inputs, or undefined
|
|
313
407
|
* @returns the inputs; E_UNSUPPORTED for anything else
|
|
@@ -462,6 +556,9 @@ class Neo4jImportSession {
|
|
|
462
556
|
|
|
463
557
|
private readonly registry = new NodeRegistry();
|
|
464
558
|
|
|
559
|
+
/** The relationship property the weights were read from, when it is not "weight"; the exporter writes it back under that name. */
|
|
560
|
+
weightProperty: string | null = null;
|
|
561
|
+
|
|
465
562
|
private labelsHandle: ColumnHandle = INVALID_INDEX as ColumnHandle;
|
|
466
563
|
|
|
467
564
|
private typeHandle: ColumnHandle = INVALID_INDEX as ColumnHandle;
|
|
@@ -484,6 +581,18 @@ class Neo4jImportSession {
|
|
|
484
581
|
/** Scratch: the property slots of the current row that lost precision. */
|
|
485
582
|
private readonly precisionSlots: PropertySlot[] = [];
|
|
486
583
|
|
|
584
|
+
/** Scratch: the values of the current row that overflowed their float / double type. */
|
|
585
|
+
private readonly overflows: string[] = [];
|
|
586
|
+
|
|
587
|
+
/** The section kind the option of the input being read names, or null for the primary input. */
|
|
588
|
+
private expectedKind: Section["kind"] | null = null;
|
|
589
|
+
|
|
590
|
+
/** Whether any node row was read. */
|
|
591
|
+
private nodeRows = false;
|
|
592
|
+
|
|
593
|
+
/** Nodes relationship endpoints created (no node row declared them yet), the first few by id. */
|
|
594
|
+
private readonly placeholders: { readonly id: NodeId; readonly index: number }[] = [];
|
|
595
|
+
|
|
487
596
|
/**
|
|
488
597
|
* Create a session.
|
|
489
598
|
* @param sink - the sink
|
|
@@ -506,39 +615,80 @@ class Neo4jImportSession {
|
|
|
506
615
|
}
|
|
507
616
|
|
|
508
617
|
/**
|
|
509
|
-
* Read every input.
|
|
510
|
-
*
|
|
618
|
+
* Read every input. A header-only input lends its header to the headerless input after it (the
|
|
619
|
+
* neo4j-admin convention `--nodes=header.csv,part1.csv`); an empty input is an error only when
|
|
620
|
+
* it is the only one.
|
|
621
|
+
* @param inputs - the inputs in reading order, each with the kind of section its option names (null for the primary input)
|
|
511
622
|
*/
|
|
512
|
-
async run(
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
623
|
+
async run(
|
|
624
|
+
inputs: readonly { readonly input: ImportInput; readonly kind: Section["kind"] | null }[],
|
|
625
|
+
): Promise<void> {
|
|
626
|
+
const progress = new ProgressTracker(
|
|
627
|
+
this.common.onProgress,
|
|
628
|
+
inputs.map((i) => i.input),
|
|
629
|
+
);
|
|
630
|
+
let carried: Section | null = null;
|
|
631
|
+
for (const { input, kind } of inputs) {
|
|
632
|
+
this.expectedKind = kind;
|
|
633
|
+
if (carried !== null && kind !== null && carried.kind !== kind) {
|
|
634
|
+
// a nodes header never lends itself to a relationships file, nor the reverse
|
|
635
|
+
carried = null;
|
|
636
|
+
}
|
|
637
|
+
carried = await this.readInput(
|
|
638
|
+
input,
|
|
639
|
+
{ ...progress.optionsFor(this.common.signal), encoding: this.common.encoding },
|
|
640
|
+
carried,
|
|
641
|
+
inputs.length > 1,
|
|
642
|
+
);
|
|
516
643
|
progress.finishInput();
|
|
517
644
|
}
|
|
518
645
|
if (this.ignoredColumns > 0) {
|
|
519
646
|
this.report.loss(
|
|
520
647
|
IGNORED_COLUMNS_LOSS,
|
|
521
|
-
`${this.ignoredColumns} :IGNORE column(
|
|
648
|
+
`${this.ignoredColumns} :IGNORE column${plural(this.ignoredColumns)} ${agree(this.ignoredColumns, "was", "were")} skipped as the header instructs`,
|
|
522
649
|
null,
|
|
523
650
|
this.ignoredColumns,
|
|
524
651
|
);
|
|
525
652
|
}
|
|
653
|
+
this.reportDangling();
|
|
526
654
|
}
|
|
527
655
|
|
|
528
656
|
/**
|
|
529
657
|
* Read one input: a header row, then data rows until the next header row.
|
|
530
658
|
* @param input - the input
|
|
531
659
|
* @param readOptions - cancellation and progress
|
|
660
|
+
* @param carried - the section of a header-only input just before this one, or null
|
|
661
|
+
* @param mayBeEmpty - whether an input without any record is allowed (other inputs exist)
|
|
662
|
+
* @returns this input's section when it held a header and no data row (lent to the next input), else null
|
|
532
663
|
*/
|
|
533
|
-
private async readInput(
|
|
534
|
-
|
|
535
|
-
|
|
664
|
+
private async readInput(
|
|
665
|
+
input: ImportInput,
|
|
666
|
+
readOptions: ReadOptions,
|
|
667
|
+
carried: Section | null,
|
|
668
|
+
mayBeEmpty: boolean,
|
|
669
|
+
): Promise<Section | null> {
|
|
670
|
+
const reader = new RecordReader(input, this.report, this.options.syntax, {
|
|
671
|
+
...readOptions,
|
|
672
|
+
allowEmpty: mayBeEmpty,
|
|
673
|
+
});
|
|
674
|
+
let section: Section | null = carried;
|
|
675
|
+
let records = 0;
|
|
676
|
+
let rows = 0;
|
|
536
677
|
let sinceCheck = 0;
|
|
537
678
|
for await (const count of reader) {
|
|
538
|
-
|
|
679
|
+
const { cells, quoted } = reader;
|
|
680
|
+
if (records === 0 && count === 1 && !quoted[0] && cells[0].trim().length === 0) {
|
|
681
|
+
// a whitespace-only line before anything else is a blank line, not an empty header
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
records++;
|
|
685
|
+
// a quoted marker cell is data ("ref:id") unless the whole record is a quoted header
|
|
686
|
+
if (section === null || isHeaderRecord(cells, count, quoted)) {
|
|
539
687
|
section = this.declareSection(reader, count);
|
|
688
|
+
rows = 0;
|
|
540
689
|
continue;
|
|
541
690
|
}
|
|
691
|
+
rows++;
|
|
542
692
|
if (section.kind === "node") {
|
|
543
693
|
this.nodeRow(section, reader, count);
|
|
544
694
|
} else {
|
|
@@ -549,9 +699,14 @@ class Neo4jImportSession {
|
|
|
549
699
|
throwIfAborted(readOptions.signal);
|
|
550
700
|
}
|
|
551
701
|
}
|
|
552
|
-
if (
|
|
702
|
+
if (records === 0 && carried === null && !mayBeEmpty) {
|
|
553
703
|
this.report.fail(HEADER_CODE, "the input has no header row", { line: 1 });
|
|
554
704
|
}
|
|
705
|
+
// the header lent on: a header-only input's, or the one lent to this input when it had none
|
|
706
|
+
if (section === carried) {
|
|
707
|
+
return carried;
|
|
708
|
+
}
|
|
709
|
+
return rows === 0 ? section : null;
|
|
555
710
|
}
|
|
556
711
|
|
|
557
712
|
/**
|
|
@@ -585,8 +740,19 @@ class Neo4jImportSession {
|
|
|
585
740
|
throw headerError("a header mixes :ID with :START_ID / :END_ID");
|
|
586
741
|
}
|
|
587
742
|
if (!isNode && !isRelationship) {
|
|
743
|
+
const apoc = fields.some((f) => f.name === "_id" || f.name === "_start");
|
|
588
744
|
throw headerError(
|
|
589
|
-
|
|
745
|
+
apoc
|
|
746
|
+
? "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships); this is the apoc.export.csv layout (_id, _labels, _start, _end, _type), which is not the neo4j-admin import format"
|
|
747
|
+
: "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)",
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
if (this.expectedKind !== null && this.expectedKind !== (isNode ? "node" : "relationship")) {
|
|
751
|
+
this.report.warning(
|
|
752
|
+
"validation-error",
|
|
753
|
+
SECTION_KIND_CODE,
|
|
754
|
+
`a ${isNode ? "node" : "relationship"} header in a file given as ${this.expectedKind === "node" ? "nodes" : "relationships"}; read by its header`,
|
|
755
|
+
{ line },
|
|
590
756
|
);
|
|
591
757
|
}
|
|
592
758
|
checkPropertyNames(fields);
|
|
@@ -619,7 +785,15 @@ class Neo4jImportSession {
|
|
|
619
785
|
);
|
|
620
786
|
} catch (err) {
|
|
621
787
|
if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
|
|
622
|
-
|
|
788
|
+
// a header written with another delimiter reads as one cell holding it
|
|
789
|
+
const other = [";", "|", "\t", ","].find(
|
|
790
|
+
(d) => d !== reader.delimiter && reader.cells.slice(0, count).some((c) => c.includes(d)),
|
|
791
|
+
);
|
|
792
|
+
const hint =
|
|
793
|
+
other === undefined
|
|
794
|
+
? ""
|
|
795
|
+
: `; if the file is delimited by ${JSON.stringify(other)}, pass the delimiter option`;
|
|
796
|
+
this.report.fail(HEADER_CODE, `${err.message}${hint}`, { line }, { cause: err.code });
|
|
623
797
|
}
|
|
624
798
|
throw err;
|
|
625
799
|
}
|
|
@@ -718,6 +892,9 @@ class Neo4jImportSession {
|
|
|
718
892
|
let weightCell = -1;
|
|
719
893
|
if (weightFrom !== null) {
|
|
720
894
|
weightCell = fields.findIndex((field) => field.kind === "PROPERTY" && field.name === weightFrom);
|
|
895
|
+
if (weightCell >= 0 && weightFrom !== "weight") {
|
|
896
|
+
this.weightProperty = weightFrom;
|
|
897
|
+
}
|
|
721
898
|
}
|
|
722
899
|
const properties = this.declareProperties("edge", fields, line, weightCell);
|
|
723
900
|
const { space: startSpace } = fields[startCell];
|
|
@@ -898,7 +1075,7 @@ class Neo4jImportSession {
|
|
|
898
1075
|
report.error(
|
|
899
1076
|
"validation-error",
|
|
900
1077
|
COLUMN_COUNT_CODE,
|
|
901
|
-
`row has ${count} cell(
|
|
1078
|
+
`row has ${count} cell${plural(count)} but the header has ${section.width}`,
|
|
902
1079
|
{ line },
|
|
903
1080
|
);
|
|
904
1081
|
report.counts.skippedNodes++;
|
|
@@ -921,7 +1098,16 @@ class Neo4jImportSession {
|
|
|
921
1098
|
if (section.labelCells.length > 0 || section.extraLabels.length > 0) {
|
|
922
1099
|
labels = this.labelsOf(section, cells, quoted);
|
|
923
1100
|
}
|
|
924
|
-
|
|
1101
|
+
this.nodeRows = true;
|
|
1102
|
+
const existed = sink.indexOf(id) !== INVALID_INDEX;
|
|
1103
|
+
let index: number;
|
|
1104
|
+
try {
|
|
1105
|
+
index = sink.addNode(id);
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
report.recordError(err, { line, element: idText });
|
|
1108
|
+
report.counts.skippedNodes++;
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
925
1111
|
const status = this.registry.declare(index, section.spaceCode);
|
|
926
1112
|
if (status === "collision") {
|
|
927
1113
|
report.error(
|
|
@@ -944,19 +1130,69 @@ class Neo4jImportSession {
|
|
|
944
1130
|
},
|
|
945
1131
|
);
|
|
946
1132
|
}
|
|
1133
|
+
// a write the sink refuses is recorded and the rest of the row is still written
|
|
1134
|
+
const set = (column: ColumnHandle, value: unknown): void => {
|
|
1135
|
+
this.guarded(line, idText, () => {
|
|
1136
|
+
sink.setNodeValue(column, index, value);
|
|
1137
|
+
});
|
|
1138
|
+
};
|
|
947
1139
|
if (section.idHandle !== INVALID_INDEX) {
|
|
948
|
-
|
|
1140
|
+
set(section.idHandle, idText);
|
|
949
1141
|
}
|
|
950
1142
|
if (section.space !== null) {
|
|
951
|
-
|
|
952
|
-
|
|
1143
|
+
set(this.idSpaceHandle, section.space);
|
|
1144
|
+
set(this.originalIdHandle, idText);
|
|
953
1145
|
}
|
|
954
1146
|
if (labels !== undefined) {
|
|
955
|
-
|
|
1147
|
+
set(this.labelsHandle, labels);
|
|
956
1148
|
}
|
|
957
|
-
this.writeProperties("node", section.properties, index);
|
|
1149
|
+
this.writeProperties("node", section.properties, index, line, idText);
|
|
958
1150
|
this.reportPrecision(line, idText);
|
|
959
|
-
|
|
1151
|
+
// a node a relationship created before its row (or an earlier row) is counted once
|
|
1152
|
+
if (!existed) {
|
|
1153
|
+
report.counts.nodes++;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* Run one sink write, recording a refusal (a GraphFormatError) on the row's line instead of
|
|
1159
|
+
* letting it escape the import.
|
|
1160
|
+
* @param line - the row's line
|
|
1161
|
+
* @param element - the row's element name
|
|
1162
|
+
* @param write - the write
|
|
1163
|
+
*/
|
|
1164
|
+
private guarded(line: number, element: string, write: () => void): void {
|
|
1165
|
+
try {
|
|
1166
|
+
write();
|
|
1167
|
+
} catch (err) {
|
|
1168
|
+
if (!(err instanceof GraphFormatError) || err instanceof ImportError) {
|
|
1169
|
+
throw err;
|
|
1170
|
+
}
|
|
1171
|
+
this.report.recordError(err, { line, element });
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/**
|
|
1176
|
+
* Report the relationship endpoints no node row declared (the shared W_DANGLING_REFERENCE,
|
|
1177
|
+
* once) when the input has node rows: each became a node, where neo4j-admin refuses the
|
|
1178
|
+
* relationship.
|
|
1179
|
+
*/
|
|
1180
|
+
private reportDangling(): void {
|
|
1181
|
+
const dangling = this.placeholders.filter((p) => this.registry.codeAt(p.index) === 0);
|
|
1182
|
+
// without any node row, every node comes from the relationships (a relationships-only file)
|
|
1183
|
+
if (dangling.length === 0 || !this.nodeRows) {
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
const shown = dangling
|
|
1187
|
+
.slice(0, 5)
|
|
1188
|
+
.map((p) => String(p.id))
|
|
1189
|
+
.join(", ");
|
|
1190
|
+
this.report.warning(
|
|
1191
|
+
"validation-error",
|
|
1192
|
+
DANGLING_REFERENCE_CODE,
|
|
1193
|
+
`${dangling.length} relationship endpoint${plural(dangling.length)} ${agree(dangling.length, "names", "name")} no node row and became nodes: ${shown}${dangling.length > 5 ? ", ..." : ""} (neo4j-admin refuses such relationships)`,
|
|
1194
|
+
{ element: String(dangling[0].id) },
|
|
1195
|
+
);
|
|
960
1196
|
}
|
|
961
1197
|
|
|
962
1198
|
/**
|
|
@@ -978,7 +1214,7 @@ class Neo4jImportSession {
|
|
|
978
1214
|
report.error(
|
|
979
1215
|
"validation-error",
|
|
980
1216
|
COLUMN_COUNT_CODE,
|
|
981
|
-
`row has ${count} cell(
|
|
1217
|
+
`row has ${count} cell${plural(count)} but the header has ${section.width}`,
|
|
982
1218
|
{ line },
|
|
983
1219
|
);
|
|
984
1220
|
report.counts.skippedEdges++;
|
|
@@ -1027,7 +1263,7 @@ class Neo4jImportSession {
|
|
|
1027
1263
|
let weight: number | undefined;
|
|
1028
1264
|
if (section.weightCell >= 0) {
|
|
1029
1265
|
try {
|
|
1030
|
-
weight = parseWeightText(cells[section.weightCell]);
|
|
1266
|
+
weight = parseWeightText(cells[section.weightCell], this.report);
|
|
1031
1267
|
} catch (err) {
|
|
1032
1268
|
report.recordError(err, { line, element });
|
|
1033
1269
|
report.counts.skippedEdges++;
|
|
@@ -1038,6 +1274,9 @@ class Neo4jImportSession {
|
|
|
1038
1274
|
report.counts.skippedEdges++;
|
|
1039
1275
|
return;
|
|
1040
1276
|
}
|
|
1277
|
+
const created = [source, target].filter(
|
|
1278
|
+
(id, k) => (k === 0 || id !== source) && sink.indexOf(id) === INVALID_INDEX,
|
|
1279
|
+
);
|
|
1041
1280
|
let edge: number;
|
|
1042
1281
|
try {
|
|
1043
1282
|
edge = this.direction.addEdge(source, target, "directed", weight, { line, element });
|
|
@@ -1046,13 +1285,27 @@ class Neo4jImportSession {
|
|
|
1046
1285
|
report.counts.skippedEdges++;
|
|
1047
1286
|
return;
|
|
1048
1287
|
}
|
|
1288
|
+
for (const id of created) {
|
|
1289
|
+
// a node no row declared yet: counted now; reported at the end unless a node row follows
|
|
1290
|
+
report.counts.nodes++;
|
|
1291
|
+
this.placeholders.push({ id, index: sink.indexOf(id) });
|
|
1292
|
+
}
|
|
1049
1293
|
if (section.typeCell >= 0) {
|
|
1050
1294
|
const type = cells[section.typeCell];
|
|
1051
1295
|
if (type.length > 0) {
|
|
1052
|
-
|
|
1296
|
+
this.guarded(line, element, () => {
|
|
1297
|
+
sink.setEdgeValue(this.typeHandle, edge, type);
|
|
1298
|
+
});
|
|
1299
|
+
} else {
|
|
1300
|
+
report.warning(
|
|
1301
|
+
"missing-value",
|
|
1302
|
+
MISSING_TYPE_CODE,
|
|
1303
|
+
"empty :TYPE cell; neo4j-admin requires a relationship type, the relationship is kept without one",
|
|
1304
|
+
{ line, element },
|
|
1305
|
+
);
|
|
1053
1306
|
}
|
|
1054
1307
|
}
|
|
1055
|
-
this.writeProperties("edge", section.properties, edge);
|
|
1308
|
+
this.writeProperties("edge", section.properties, edge, line, element);
|
|
1056
1309
|
this.reportPrecision(line, element);
|
|
1057
1310
|
report.counts.edges++;
|
|
1058
1311
|
}
|
|
@@ -1122,6 +1375,7 @@ class Neo4jImportSession {
|
|
|
1122
1375
|
): boolean {
|
|
1123
1376
|
const { values, texts, precisionSlots } = this;
|
|
1124
1377
|
precisionSlots.length = 0;
|
|
1378
|
+
this.overflows.length = 0;
|
|
1125
1379
|
for (const slot of slots) {
|
|
1126
1380
|
const text = cells[slot.cell];
|
|
1127
1381
|
texts[slot.cell] = null;
|
|
@@ -1132,16 +1386,22 @@ class Neo4jImportSession {
|
|
|
1132
1386
|
const { spec } = slot;
|
|
1133
1387
|
try {
|
|
1134
1388
|
if (spec.temporal !== null && !spec.list) {
|
|
1135
|
-
const
|
|
1389
|
+
const zoned = withZoneOffset(text, spec);
|
|
1390
|
+
const parsed = parseDeclaredTemporal(zoned, spec);
|
|
1136
1391
|
values[slot.cell] = parsed.value;
|
|
1137
|
-
|
|
1392
|
+
// a zone name is kept in the companion text, the value is its instant
|
|
1393
|
+
texts[slot.cell] = zoned === text ? parsed.text : text;
|
|
1138
1394
|
} else {
|
|
1139
1395
|
values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
|
|
1396
|
+
checkNeo4jRange(spec, values[slot.cell], text);
|
|
1140
1397
|
}
|
|
1141
1398
|
} catch (err) {
|
|
1142
1399
|
this.report.recordError(err, { line, element: `${element} ${slot.name}` });
|
|
1143
1400
|
return false;
|
|
1144
1401
|
}
|
|
1402
|
+
if (overflows(spec, values[slot.cell], text)) {
|
|
1403
|
+
this.overflows.push(slot.name);
|
|
1404
|
+
}
|
|
1145
1405
|
if (spec.precision && losesPrecision(spec, text)) {
|
|
1146
1406
|
precisionSlots.push(slot);
|
|
1147
1407
|
}
|
|
@@ -1154,8 +1414,16 @@ class Neo4jImportSession {
|
|
|
1154
1414
|
* @param domain - node or edge
|
|
1155
1415
|
* @param slots - the section's property slots
|
|
1156
1416
|
* @param row - the node or edge index
|
|
1417
|
+
* @param line - the row's line
|
|
1418
|
+
* @param element - the row's element name for issues
|
|
1157
1419
|
*/
|
|
1158
|
-
private writeProperties(
|
|
1420
|
+
private writeProperties(
|
|
1421
|
+
domain: "node" | "edge",
|
|
1422
|
+
slots: readonly PropertySlot[],
|
|
1423
|
+
row: number,
|
|
1424
|
+
line: number,
|
|
1425
|
+
element: string,
|
|
1426
|
+
): void {
|
|
1159
1427
|
const { sink, values, texts } = this;
|
|
1160
1428
|
for (const slot of slots) {
|
|
1161
1429
|
const value = values[slot.cell];
|
|
@@ -1163,20 +1431,23 @@ class Neo4jImportSession {
|
|
|
1163
1431
|
continue;
|
|
1164
1432
|
}
|
|
1165
1433
|
const text = texts[slot.cell];
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
sink.setNodeValue(slot.handle, row, value);
|
|
1171
|
-
if (text !== null) {
|
|
1172
|
-
sink.setNodeValue(slot.companion, row, text);
|
|
1434
|
+
// a value the sink refuses is recorded on the row's line; the other properties are written
|
|
1435
|
+
this.guarded(line, `${element} ${slot.name}`, () => {
|
|
1436
|
+
if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
|
|
1437
|
+
slot.companion = declareCompanion(sink, domain, slot.companionDecl);
|
|
1173
1438
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1439
|
+
if (domain === "node") {
|
|
1440
|
+
sink.setNodeValue(slot.handle, row, value);
|
|
1441
|
+
if (text !== null) {
|
|
1442
|
+
sink.setNodeValue(slot.companion, row, text);
|
|
1443
|
+
}
|
|
1444
|
+
} else {
|
|
1445
|
+
sink.setEdgeValue(slot.handle, row, value);
|
|
1446
|
+
if (text !== null) {
|
|
1447
|
+
sink.setEdgeValue(slot.companion, row, text);
|
|
1448
|
+
}
|
|
1178
1449
|
}
|
|
1179
|
-
}
|
|
1450
|
+
});
|
|
1180
1451
|
}
|
|
1181
1452
|
}
|
|
1182
1453
|
|
|
@@ -1195,6 +1466,15 @@ class Neo4jImportSession {
|
|
|
1195
1466
|
);
|
|
1196
1467
|
}
|
|
1197
1468
|
this.precisionSlots.length = 0;
|
|
1469
|
+
for (const name of this.overflows) {
|
|
1470
|
+
this.report.warning(
|
|
1471
|
+
"precision",
|
|
1472
|
+
PRECISION_CODE,
|
|
1473
|
+
`the value of "${name}" is beyond the range of its float / double type and was stored as the nearest representable value`,
|
|
1474
|
+
{ line, element },
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
this.overflows.length = 0;
|
|
1198
1478
|
}
|
|
1199
1479
|
|
|
1200
1480
|
/**
|
|
@@ -1242,6 +1522,154 @@ function qualify(id: NodeId, space: string | null): NodeId {
|
|
|
1242
1522
|
return space === null ? id : `${space}:${String(id)}`;
|
|
1243
1523
|
}
|
|
1244
1524
|
|
|
1525
|
+
/** The integer range of the narrow neo4j-admin types (Java byte and short). */
|
|
1526
|
+
const INTEGER_RANGES: Readonly<Record<string, readonly [number, number]>> = {
|
|
1527
|
+
byte: [-128, 127],
|
|
1528
|
+
short: [-32768, 32767],
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
/**
|
|
1532
|
+
* A Cypher duration (ISO 8601): unit form `P14DT16H12M` / `PT0.75M` / `P2.5W` (components may be
|
|
1533
|
+
* signed or fractional) or the date-time form `P2012-02-02T14:37:21.545`.
|
|
1534
|
+
*/
|
|
1535
|
+
/**
|
|
1536
|
+
* Whether a text is a Cypher duration (ISO 8601): unit form `P14DT16H12M` / `PT0.75M` / `P2.5W`
|
|
1537
|
+
* (components may be signed or fractional) or the date-time form `P2012-02-02T14:37:21.545`.
|
|
1538
|
+
* @param text - the text, trimmed
|
|
1539
|
+
* @returns true when it is
|
|
1540
|
+
*/
|
|
1541
|
+
function isDuration(text: string): boolean {
|
|
1542
|
+
if (DURATION_DATE_TIME.test(text)) {
|
|
1543
|
+
return true;
|
|
1544
|
+
}
|
|
1545
|
+
const m = /^[+-]?P([^T]*)(?:T(.*))?$/i.exec(text);
|
|
1546
|
+
if (m === null || m[2] === "" || (m[1] === "" && m[2] === undefined)) {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
return unitsInOrder(m[1], "YMWD") && unitsInOrder(m[2] ?? "", "HMS");
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
/** The date-time form of a Cypher duration, `P2012-02-02T14:37:21.545`. */
|
|
1553
|
+
const DURATION_DATE_TIME = /^[+-]?P\d{4}-?\d{2}-?\d{2}T\d{2}:?\d{2}:?\d{2}(?:\.\d+)?$/i;
|
|
1554
|
+
|
|
1555
|
+
/**
|
|
1556
|
+
* Whether a run of duration components (`14D`, `-1.5H30M`) names its units in the order given,
|
|
1557
|
+
* each at most once.
|
|
1558
|
+
* @param text - the components
|
|
1559
|
+
* @param units - the unit letters in their order
|
|
1560
|
+
* @returns true when it does
|
|
1561
|
+
*/
|
|
1562
|
+
function unitsInOrder(text: string, units: string): boolean {
|
|
1563
|
+
let rest = text.toUpperCase();
|
|
1564
|
+
let from = 0;
|
|
1565
|
+
while (rest !== "") {
|
|
1566
|
+
const m = /^[-+]?\d+(?:\.\d+)?([A-Z])/.exec(rest);
|
|
1567
|
+
const at = m === null ? -1 : units.indexOf(m[1], from);
|
|
1568
|
+
if (m === null || at < 0) {
|
|
1569
|
+
return false;
|
|
1570
|
+
}
|
|
1571
|
+
from = at + 1;
|
|
1572
|
+
rest = rest.slice(m[0].length);
|
|
1573
|
+
}
|
|
1574
|
+
return true;
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
/**
|
|
1578
|
+
* Check the neo4j-admin types the shared parser maps to a wider dtype: byte and short values within
|
|
1579
|
+
* their Java range, a char of one character, a duration in Cypher's syntax.
|
|
1580
|
+
* @param spec - the declared type
|
|
1581
|
+
* @param value - the parsed value (a list of items for an array type)
|
|
1582
|
+
* @param text - the cell text, for the error
|
|
1583
|
+
*/
|
|
1584
|
+
function checkNeo4jRange(spec: DeclaredTypeSpec, value: unknown, text: string): void {
|
|
1585
|
+
const base = spec.declared.trim().toLowerCase().replace(/\[\]$/, "");
|
|
1586
|
+
const items: unknown[] = spec.list && Array.isArray(value) ? value : [value];
|
|
1587
|
+
const range = INTEGER_RANGES[base];
|
|
1588
|
+
for (const item of items) {
|
|
1589
|
+
let bad = false;
|
|
1590
|
+
if (range !== undefined) {
|
|
1591
|
+
bad = typeof item === "number" && (item < range[0] || item > range[1]);
|
|
1592
|
+
} else if (base === "char") {
|
|
1593
|
+
// a Java char: one UTF-16 code unit
|
|
1594
|
+
bad = typeof item === "string" && item.length !== 1;
|
|
1595
|
+
} else if (base === "duration") {
|
|
1596
|
+
bad = typeof item === "string" && !isDuration(item.trim());
|
|
1597
|
+
}
|
|
1598
|
+
if (bad) {
|
|
1599
|
+
const span = range === undefined ? "" : ` (${range[0]} to ${range[1]})`;
|
|
1600
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not ${withArticle(base)}${span}`, {
|
|
1601
|
+
value: text,
|
|
1602
|
+
kind: base,
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
/** The largest finite f32. */
|
|
1609
|
+
const F32_MAX = 3.4028234663852886e38;
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* Whether a float / double cell overflowed: a finite literal read as an infinity, or a float beyond
|
|
1613
|
+
* the f32 range (Java's Double.parseDouble accepts both silently; the value changes).
|
|
1614
|
+
* @param spec - the declared type
|
|
1615
|
+
* @param value - the parsed value
|
|
1616
|
+
* @param text - the cell text
|
|
1617
|
+
* @returns true when the stored value is not the one written
|
|
1618
|
+
*/
|
|
1619
|
+
function overflows(spec: DeclaredTypeSpec, value: unknown, text: string): boolean {
|
|
1620
|
+
if ((spec.kind !== "float" && spec.kind !== "double") || /inf|nan/i.test(text)) {
|
|
1621
|
+
return false;
|
|
1622
|
+
}
|
|
1623
|
+
const items: unknown[] = spec.list && Array.isArray(value) ? value : [value];
|
|
1624
|
+
return items.some(
|
|
1625
|
+
(v) => typeof v === "number" && (!Number.isFinite(v) || (spec.kind === "float" && Math.abs(v) > F32_MAX)),
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/**
|
|
1630
|
+
* A Cypher date-time with a zone name (`2020-01-01T00:00:00[Europe/Berlin]`) as one with a UTC
|
|
1631
|
+
* offset the temporal parser reads: the offset the text gives, else the zone's offset at that wall
|
|
1632
|
+
* time. Any other text is returned unchanged.
|
|
1633
|
+
* @param text - the cell text
|
|
1634
|
+
* @param spec - the declared type
|
|
1635
|
+
* @returns the text to parse
|
|
1636
|
+
*/
|
|
1637
|
+
function withZoneOffset(text: string, spec: DeclaredTypeSpec): string {
|
|
1638
|
+
const trimmed = text.trim();
|
|
1639
|
+
const open = trimmed.lastIndexOf("[");
|
|
1640
|
+
if (spec.temporal !== "dateTime" || open < 0 || !trimmed.endsWith("]")) {
|
|
1641
|
+
return text;
|
|
1642
|
+
}
|
|
1643
|
+
const local = trimmed.slice(0, open);
|
|
1644
|
+
const zone = trimmed.slice(open + 1, -1);
|
|
1645
|
+
if (zone === "" || zone.includes("]") || /[\n\r\u2028\u2029]/.test(local)) {
|
|
1646
|
+
return text;
|
|
1647
|
+
}
|
|
1648
|
+
let format: Intl.DateTimeFormat;
|
|
1649
|
+
try {
|
|
1650
|
+
format = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" });
|
|
1651
|
+
} catch {
|
|
1652
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" names an unknown time zone ${zone}`, { value: text });
|
|
1653
|
+
}
|
|
1654
|
+
if (/(Z|z|[+-]\d{2}(:?\d{2})?)$/.test(local)) {
|
|
1655
|
+
return local;
|
|
1656
|
+
}
|
|
1657
|
+
const wall = parseTemporal(local, "localDateTime").value;
|
|
1658
|
+
const offsetAt = (ms: number): number => {
|
|
1659
|
+
const name = format.formatToParts(new Date(ms)).find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
1660
|
+
const o = /GMT([+-])(\d{2}):(\d{2})/.exec(name);
|
|
1661
|
+
if (o === null) {
|
|
1662
|
+
return 0;
|
|
1663
|
+
}
|
|
1664
|
+
return (o[1] === "-" ? -1 : 1) * (Number(o[2]) * 60 + Number(o[3]));
|
|
1665
|
+
};
|
|
1666
|
+
// the offset at the instant the wall time names (twice, so a wall time near a transition settles)
|
|
1667
|
+
const minutes = offsetAt(wall - offsetAt(wall) * 60_000);
|
|
1668
|
+
const sign = minutes < 0 ? "-" : "+";
|
|
1669
|
+
const abs = Math.abs(minutes);
|
|
1670
|
+
return `${local}${sign}${String(Math.floor(abs / 60)).padStart(2, "0")}:${String(abs % 60).padStart(2, "0")}`;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1245
1673
|
/**
|
|
1246
1674
|
* The value of a quoted empty cell: an empty string for a string-kind property, an empty list for
|
|
1247
1675
|
* a list property, unset for anything else (neo4j-admin's default `--ignore-empty-strings=false`).
|
|
@@ -1298,9 +1726,13 @@ function sniffNeo4j(head: Uint8Array): number {
|
|
|
1298
1726
|
return isHeaderRecord(cells, cells.length) ? 0.95 : 0;
|
|
1299
1727
|
}
|
|
1300
1728
|
|
|
1301
|
-
/**
|
|
1729
|
+
/**
|
|
1730
|
+
* The Neo4j importer.
|
|
1731
|
+
* @category Built-in formats
|
|
1732
|
+
*/
|
|
1302
1733
|
export const neo4jImporter: GraphImporter<Neo4jImportOptions> = Object.freeze({
|
|
1303
1734
|
format: NEO4J,
|
|
1735
|
+
options: Object.freeze(["arrayDelimiter", "delimiter", "nodes", "quote", "relationships"]),
|
|
1304
1736
|
extensions: Object.freeze([".csv", ".tsv"]),
|
|
1305
1737
|
mimeTypes: Object.freeze(["text/csv", "text/tab-separated-values"]),
|
|
1306
1738
|
sniff: sniffNeo4j,
|
|
@@ -1324,7 +1756,14 @@ export const neo4jImporter: GraphImporter<Neo4jImportOptions> = Object.freeze({
|
|
|
1324
1756
|
// column and every relationship is directed
|
|
1325
1757
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
1326
1758
|
const session = new Neo4jImportSession(sink, report, common, format);
|
|
1327
|
-
await session.run([
|
|
1759
|
+
await session.run([
|
|
1760
|
+
{ input, kind: null },
|
|
1761
|
+
...format.nodes.map((file) => ({ input: file, kind: "node" as const })),
|
|
1762
|
+
...format.relationships.map((file) => ({ input: file, kind: "relationship" as const })),
|
|
1763
|
+
]);
|
|
1764
|
+
if (session.weightProperty !== null) {
|
|
1765
|
+
sink.setMeta({ extra: { neo4j: { weightProperty: session.weightProperty } } });
|
|
1766
|
+
}
|
|
1328
1767
|
throwIfAborted(common.signal);
|
|
1329
1768
|
return report.finish();
|
|
1330
1769
|
},
|