@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
package/dist/neo4j.js
CHANGED
|
@@ -1,22 +1,37 @@
|
|
|
1
|
-
import { R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1,
|
|
2
|
-
import { c as checkRecordSyntax, R as RecordReader, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-
|
|
1
|
+
import { i as DANGLING_REFERENCE_CODE$1, R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, n as DUPLICATE_NODE_CODE$1, s as MISSING_ENDPOINT_CODE$1, t as MISSING_ID_CODE$1, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, am as throwIfAborted, ar as IdCoercer, aq as DirectionResolver, b as plural, $ as agree, aT as ImportError, bI as declareAttribute, bY as declareOn, a0 as uniqueColumnName, ay as RENAMED_CODE, aL as parseWeightText, bK as parseDeclaredTemporal, bL as parseDeclaredValue, bM as losesPrecision, bs as declareCompanion, P as PRECISION_CODE, bO as splitListText, bz as isImportInput, bX as takenIn, bx as inputLength, bZ as parseTemporal, b_ as withArticle, c as capabilities, b9 as ID_TEXT_COLLISION_CODE, J as ID_TEXT_TYPE_CODE, r as resolveExportOptions, a as checkCapabilities, p as pairFolding, L as LOSS, bS as mapDeclaredType, e as explicitWeights, by as isCanonicalIntegerText, bU as formatTemporal, ab as formatF64, aa as formatF32, aG as formatInteger, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, C as COLUMN_RENAMED_CODE, U as UNKNOWN_ATTR_TYPE_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, A as COLUMN_TYPE_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE, bq as WEIGHT_KEY_CLASH_CODE, K as ROLE_DROPPED_CODE, bd as MUTUAL_EXPANDED_CODE } from "./chunks/export-CHd4tQE2.js";
|
|
2
|
+
import { c as checkRecordSyntax, R as RecordReader, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-CdlvL4RO.js";
|
|
3
3
|
import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { p as parseWeightText, e as explicitWeights, a as formatF64, f as formatF32, d as formatInteger } from "./chunks/weights-Dzba96G3.js";
|
|
7
|
-
import { j as joinText, e as encodeChunks } from "./chunks/writer-C7flM-Ih.js";
|
|
4
|
+
import { o as quoteCsvCell } from "./chunks/escape-D1HPTUrP.js";
|
|
5
|
+
import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
|
|
8
6
|
const STRUCTURAL = /* @__PURE__ */ new Set(["ID", "LABEL", "START_ID", "END_ID", "TYPE", "IGNORE"]);
|
|
9
7
|
const SPACE_KINDS = /* @__PURE__ */ new Set(["ID", "START_ID", "END_ID"]);
|
|
10
8
|
const HEADER_MARKER = /^[^:{}()]*:\s*(ID|START_ID|END_ID)\s*(\(|\{|$)/i;
|
|
11
9
|
const CELL = /^([^:(){}]*)(?::([^:(){}]*))?(?:\(([^)]*)\))?(?:\{([^}]*)\})?$/;
|
|
12
|
-
function isHeaderRecord(cells, count) {
|
|
10
|
+
function isHeaderRecord(cells, count, quoted) {
|
|
11
|
+
let quotedMarker = false;
|
|
13
12
|
for (let i = 0; i < count; i++) {
|
|
14
13
|
const cell = cells[i];
|
|
15
14
|
if (cell.indexOf(":") >= 0 && HEADER_MARKER.test(cell.trim())) {
|
|
16
|
-
|
|
15
|
+
if (quoted?.[i] !== true) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
quotedMarker = true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return quotedMarker && quoted !== void 0 && isQuotedHeader(cells, count, quoted);
|
|
22
|
+
}
|
|
23
|
+
function isQuotedHeader(cells, count, quoted) {
|
|
24
|
+
for (let i = 0; i < count; i++) {
|
|
25
|
+
if (!quoted[i]) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
parseHeaderField(cells[i]);
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
17
32
|
}
|
|
18
33
|
}
|
|
19
|
-
return
|
|
34
|
+
return true;
|
|
20
35
|
}
|
|
21
36
|
function parseHeaderField(text) {
|
|
22
37
|
const trimmed = text.trim();
|
|
@@ -103,6 +118,9 @@ const ENDPOINT_SPACE_CODE = "E_NEO4J_ENDPOINT_SPACE";
|
|
|
103
118
|
const ID_MERGED_CODE = ID_MERGED_CODE$1;
|
|
104
119
|
const HEADER_OPTION_CODE = "W_NEO4J_HEADER_OPTION_IGNORED";
|
|
105
120
|
const ROLE_TAKEN_CODE = ROLE_TAKEN_CODE$1;
|
|
121
|
+
const MISSING_TYPE_CODE = "W_NEO4J_MISSING_TYPE";
|
|
122
|
+
const SECTION_KIND_CODE = "W_NEO4J_SECTION_KIND";
|
|
123
|
+
const DANGLING_REFERENCE_CODE = DANGLING_REFERENCE_CODE$1;
|
|
106
124
|
const IGNORED_COLUMNS_LOSS = "W_NEO4J_IGNORED_COLUMNS";
|
|
107
125
|
const USED_OPTIONS = /* @__PURE__ */ new Set([
|
|
108
126
|
"ids",
|
|
@@ -161,16 +179,27 @@ function resolveNeo4jOptions(options) {
|
|
|
161
179
|
{ option: "arrayDelimiter", found: arrayDelimiter }
|
|
162
180
|
);
|
|
163
181
|
}
|
|
182
|
+
if (arrayDelimiter === "," && o.delimiter === void 0) {
|
|
183
|
+
throw new GraphFormatError(
|
|
184
|
+
"E_UNSUPPORTED",
|
|
185
|
+
'option arrayDelimiter "," needs the delimiter option: the field delimiter is a comma unless another is given',
|
|
186
|
+
{ option: "arrayDelimiter", found: arrayDelimiter }
|
|
187
|
+
);
|
|
188
|
+
}
|
|
164
189
|
const syntax = checkRecordSyntax({
|
|
165
190
|
delimiter: o.delimiter ?? null,
|
|
166
191
|
quote: o.quote ?? '"',
|
|
167
192
|
candidates: NEO4J_DELIMITER_CANDIDATES.filter((d) => d !== arrayDelimiter)
|
|
168
193
|
});
|
|
169
194
|
if (syntax.delimiter === arrayDelimiter) {
|
|
170
|
-
throw new GraphFormatError(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
195
|
+
throw new GraphFormatError(
|
|
196
|
+
"E_UNSUPPORTED",
|
|
197
|
+
`options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`,
|
|
198
|
+
{
|
|
199
|
+
option: "arrayDelimiter",
|
|
200
|
+
found: arrayDelimiter
|
|
201
|
+
}
|
|
202
|
+
);
|
|
174
203
|
}
|
|
175
204
|
return {
|
|
176
205
|
nodes: inputList("nodes", o.nodes),
|
|
@@ -299,6 +328,7 @@ class Neo4jImportSession {
|
|
|
299
328
|
*/
|
|
300
329
|
constructor(sink, report, common, options) {
|
|
301
330
|
this.registry = new NodeRegistry();
|
|
331
|
+
this.weightProperty = null;
|
|
302
332
|
this.labelsHandle = INVALID_INDEX;
|
|
303
333
|
this.typeHandle = INVALID_INDEX;
|
|
304
334
|
this.idSpaceHandle = INVALID_INDEX;
|
|
@@ -308,6 +338,10 @@ class Neo4jImportSession {
|
|
|
308
338
|
this.values = [];
|
|
309
339
|
this.texts = [];
|
|
310
340
|
this.precisionSlots = [];
|
|
341
|
+
this.overflows = [];
|
|
342
|
+
this.expectedKind = null;
|
|
343
|
+
this.nodeRows = false;
|
|
344
|
+
this.placeholders = [];
|
|
311
345
|
this.sink = sink;
|
|
312
346
|
this.report = report;
|
|
313
347
|
this.common = common;
|
|
@@ -316,38 +350,69 @@ class Neo4jImportSession {
|
|
|
316
350
|
this.direction = new DirectionResolver(sink, report, common.onMixedDirection);
|
|
317
351
|
}
|
|
318
352
|
/**
|
|
319
|
-
* Read every input.
|
|
320
|
-
*
|
|
353
|
+
* Read every input. A header-only input lends its header to the headerless input after it (the
|
|
354
|
+
* neo4j-admin convention `--nodes=header.csv,part1.csv`); an empty input is an error only when
|
|
355
|
+
* it is the only one.
|
|
356
|
+
* @param inputs - the inputs in reading order, each with the kind of section its option names (null for the primary input)
|
|
321
357
|
*/
|
|
322
358
|
async run(inputs) {
|
|
323
|
-
const progress = new ProgressTracker(
|
|
324
|
-
|
|
325
|
-
|
|
359
|
+
const progress = new ProgressTracker(
|
|
360
|
+
this.common.onProgress,
|
|
361
|
+
inputs.map((i) => i.input)
|
|
362
|
+
);
|
|
363
|
+
let carried = null;
|
|
364
|
+
for (const { input, kind } of inputs) {
|
|
365
|
+
this.expectedKind = kind;
|
|
366
|
+
if (carried !== null && kind !== null && carried.kind !== kind) {
|
|
367
|
+
carried = null;
|
|
368
|
+
}
|
|
369
|
+
carried = await this.readInput(
|
|
370
|
+
input,
|
|
371
|
+
{ ...progress.optionsFor(this.common.signal), encoding: this.common.encoding },
|
|
372
|
+
carried,
|
|
373
|
+
inputs.length > 1
|
|
374
|
+
);
|
|
326
375
|
progress.finishInput();
|
|
327
376
|
}
|
|
328
377
|
if (this.ignoredColumns > 0) {
|
|
329
378
|
this.report.loss(
|
|
330
379
|
IGNORED_COLUMNS_LOSS,
|
|
331
|
-
`${this.ignoredColumns} :IGNORE column(
|
|
380
|
+
`${this.ignoredColumns} :IGNORE column${plural(this.ignoredColumns)} ${agree(this.ignoredColumns, "was", "were")} skipped as the header instructs`,
|
|
332
381
|
null,
|
|
333
382
|
this.ignoredColumns
|
|
334
383
|
);
|
|
335
384
|
}
|
|
385
|
+
this.reportDangling();
|
|
336
386
|
}
|
|
337
387
|
/**
|
|
338
388
|
* Read one input: a header row, then data rows until the next header row.
|
|
339
389
|
* @param input - the input
|
|
340
390
|
* @param readOptions - cancellation and progress
|
|
391
|
+
* @param carried - the section of a header-only input just before this one, or null
|
|
392
|
+
* @param mayBeEmpty - whether an input without any record is allowed (other inputs exist)
|
|
393
|
+
* @returns this input's section when it held a header and no data row (lent to the next input), else null
|
|
341
394
|
*/
|
|
342
|
-
async readInput(input, readOptions) {
|
|
343
|
-
const reader = new RecordReader(input, this.report, this.options.syntax,
|
|
344
|
-
|
|
395
|
+
async readInput(input, readOptions, carried, mayBeEmpty) {
|
|
396
|
+
const reader = new RecordReader(input, this.report, this.options.syntax, {
|
|
397
|
+
...readOptions,
|
|
398
|
+
allowEmpty: mayBeEmpty
|
|
399
|
+
});
|
|
400
|
+
let section = carried;
|
|
401
|
+
let records = 0;
|
|
402
|
+
let rows = 0;
|
|
345
403
|
let sinceCheck = 0;
|
|
346
404
|
for await (const count of reader) {
|
|
347
|
-
|
|
405
|
+
const { cells, quoted } = reader;
|
|
406
|
+
if (records === 0 && count === 1 && !quoted[0] && cells[0].trim().length === 0) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
records++;
|
|
410
|
+
if (section === null || isHeaderRecord(cells, count, quoted)) {
|
|
348
411
|
section = this.declareSection(reader, count);
|
|
412
|
+
rows = 0;
|
|
349
413
|
continue;
|
|
350
414
|
}
|
|
415
|
+
rows++;
|
|
351
416
|
if (section.kind === "node") {
|
|
352
417
|
this.nodeRow(section, reader, count);
|
|
353
418
|
} else {
|
|
@@ -358,9 +423,13 @@ class Neo4jImportSession {
|
|
|
358
423
|
throwIfAborted(readOptions.signal);
|
|
359
424
|
}
|
|
360
425
|
}
|
|
361
|
-
if (
|
|
426
|
+
if (records === 0 && carried === null && !mayBeEmpty) {
|
|
362
427
|
this.report.fail(HEADER_CODE, "the input has no header row", { line: 1 });
|
|
363
428
|
}
|
|
429
|
+
if (section === carried) {
|
|
430
|
+
return carried;
|
|
431
|
+
}
|
|
432
|
+
return rows === 0 ? section : null;
|
|
364
433
|
}
|
|
365
434
|
/**
|
|
366
435
|
* Interpret a header row: parse every cell, check the section shape, declare its columns.
|
|
@@ -393,8 +462,17 @@ class Neo4jImportSession {
|
|
|
393
462
|
throw headerError("a header mixes :ID with :START_ID / :END_ID");
|
|
394
463
|
}
|
|
395
464
|
if (!isNode && !isRelationship) {
|
|
465
|
+
const apoc = fields.some((f) => f.name === "_id" || f.name === "_start");
|
|
396
466
|
throw headerError(
|
|
397
|
-
"a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)"
|
|
467
|
+
apoc ? "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" : "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)"
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
if (this.expectedKind !== null && this.expectedKind !== (isNode ? "node" : "relationship")) {
|
|
471
|
+
this.report.warning(
|
|
472
|
+
"validation-error",
|
|
473
|
+
SECTION_KIND_CODE,
|
|
474
|
+
`a ${isNode ? "node" : "relationship"} header in a file given as ${this.expectedKind === "node" ? "nodes" : "relationships"}; read by its header`,
|
|
475
|
+
{ line }
|
|
398
476
|
);
|
|
399
477
|
}
|
|
400
478
|
checkPropertyNames(fields);
|
|
@@ -427,7 +505,11 @@ class Neo4jImportSession {
|
|
|
427
505
|
);
|
|
428
506
|
} catch (err) {
|
|
429
507
|
if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
|
|
430
|
-
|
|
508
|
+
const other = [";", "|", " ", ","].find(
|
|
509
|
+
(d) => d !== reader.delimiter && reader.cells.slice(0, count).some((c) => c.includes(d))
|
|
510
|
+
);
|
|
511
|
+
const hint = other === void 0 ? "" : `; if the file is delimited by ${JSON.stringify(other)}, pass the delimiter option`;
|
|
512
|
+
this.report.fail(HEADER_CODE, `${err.message}${hint}`, { line }, { cause: err.code });
|
|
431
513
|
}
|
|
432
514
|
throw err;
|
|
433
515
|
}
|
|
@@ -513,6 +595,9 @@ class Neo4jImportSession {
|
|
|
513
595
|
let weightCell = -1;
|
|
514
596
|
if (weightFrom !== null) {
|
|
515
597
|
weightCell = fields.findIndex((field) => field.kind === "PROPERTY" && field.name === weightFrom);
|
|
598
|
+
if (weightCell >= 0 && weightFrom !== "weight") {
|
|
599
|
+
this.weightProperty = weightFrom;
|
|
600
|
+
}
|
|
516
601
|
}
|
|
517
602
|
const properties = this.declareProperties("edge", fields, line, weightCell);
|
|
518
603
|
const { space: startSpace } = fields[startCell];
|
|
@@ -675,7 +760,7 @@ class Neo4jImportSession {
|
|
|
675
760
|
report.error(
|
|
676
761
|
"validation-error",
|
|
677
762
|
COLUMN_COUNT_CODE,
|
|
678
|
-
`row has ${count} cell(
|
|
763
|
+
`row has ${count} cell${plural(count)} but the header has ${section.width}`,
|
|
679
764
|
{ line }
|
|
680
765
|
);
|
|
681
766
|
report.counts.skippedNodes++;
|
|
@@ -697,7 +782,16 @@ class Neo4jImportSession {
|
|
|
697
782
|
if (section.labelCells.length > 0 || section.extraLabels.length > 0) {
|
|
698
783
|
labels = this.labelsOf(section, cells, quoted);
|
|
699
784
|
}
|
|
700
|
-
|
|
785
|
+
this.nodeRows = true;
|
|
786
|
+
const existed = sink.indexOf(id) !== INVALID_INDEX;
|
|
787
|
+
let index;
|
|
788
|
+
try {
|
|
789
|
+
index = sink.addNode(id);
|
|
790
|
+
} catch (err) {
|
|
791
|
+
report.recordError(err, { line, element: idText2 });
|
|
792
|
+
report.counts.skippedNodes++;
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
701
795
|
const status = this.registry.declare(index, section.spaceCode);
|
|
702
796
|
if (status === "collision") {
|
|
703
797
|
report.error(
|
|
@@ -720,19 +814,61 @@ class Neo4jImportSession {
|
|
|
720
814
|
}
|
|
721
815
|
);
|
|
722
816
|
}
|
|
817
|
+
const set = (column, value) => {
|
|
818
|
+
this.guarded(line, idText2, () => {
|
|
819
|
+
sink.setNodeValue(column, index, value);
|
|
820
|
+
});
|
|
821
|
+
};
|
|
723
822
|
if (section.idHandle !== INVALID_INDEX) {
|
|
724
|
-
|
|
823
|
+
set(section.idHandle, idText2);
|
|
725
824
|
}
|
|
726
825
|
if (section.space !== null) {
|
|
727
|
-
|
|
728
|
-
|
|
826
|
+
set(this.idSpaceHandle, section.space);
|
|
827
|
+
set(this.originalIdHandle, idText2);
|
|
729
828
|
}
|
|
730
829
|
if (labels !== void 0) {
|
|
731
|
-
|
|
830
|
+
set(this.labelsHandle, labels);
|
|
732
831
|
}
|
|
733
|
-
this.writeProperties("node", section.properties, index);
|
|
832
|
+
this.writeProperties("node", section.properties, index, line, idText2);
|
|
734
833
|
this.reportPrecision(line, idText2);
|
|
735
|
-
|
|
834
|
+
if (!existed) {
|
|
835
|
+
report.counts.nodes++;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Run one sink write, recording a refusal (a GraphFormatError) on the row's line instead of
|
|
840
|
+
* letting it escape the import.
|
|
841
|
+
* @param line - the row's line
|
|
842
|
+
* @param element - the row's element name
|
|
843
|
+
* @param write - the write
|
|
844
|
+
*/
|
|
845
|
+
guarded(line, element, write) {
|
|
846
|
+
try {
|
|
847
|
+
write();
|
|
848
|
+
} catch (err) {
|
|
849
|
+
if (!(err instanceof GraphFormatError) || err instanceof ImportError) {
|
|
850
|
+
throw err;
|
|
851
|
+
}
|
|
852
|
+
this.report.recordError(err, { line, element });
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Report the relationship endpoints no node row declared (the shared W_DANGLING_REFERENCE,
|
|
857
|
+
* once) when the input has node rows: each became a node, where neo4j-admin refuses the
|
|
858
|
+
* relationship.
|
|
859
|
+
*/
|
|
860
|
+
reportDangling() {
|
|
861
|
+
const dangling = this.placeholders.filter((p) => this.registry.codeAt(p.index) === 0);
|
|
862
|
+
if (dangling.length === 0 || !this.nodeRows) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const shown = dangling.slice(0, 5).map((p) => String(p.id)).join(", ");
|
|
866
|
+
this.report.warning(
|
|
867
|
+
"validation-error",
|
|
868
|
+
DANGLING_REFERENCE_CODE,
|
|
869
|
+
`${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)`,
|
|
870
|
+
{ element: String(dangling[0].id) }
|
|
871
|
+
);
|
|
736
872
|
}
|
|
737
873
|
/**
|
|
738
874
|
* Push one relationship row.
|
|
@@ -751,7 +887,7 @@ class Neo4jImportSession {
|
|
|
751
887
|
report.error(
|
|
752
888
|
"validation-error",
|
|
753
889
|
COLUMN_COUNT_CODE,
|
|
754
|
-
`row has ${count} cell(
|
|
890
|
+
`row has ${count} cell${plural(count)} but the header has ${section.width}`,
|
|
755
891
|
{ line }
|
|
756
892
|
);
|
|
757
893
|
report.counts.skippedEdges++;
|
|
@@ -800,7 +936,7 @@ class Neo4jImportSession {
|
|
|
800
936
|
let weight;
|
|
801
937
|
if (section.weightCell >= 0) {
|
|
802
938
|
try {
|
|
803
|
-
weight = parseWeightText(cells[section.weightCell]);
|
|
939
|
+
weight = parseWeightText(cells[section.weightCell], this.report);
|
|
804
940
|
} catch (err) {
|
|
805
941
|
report.recordError(err, { line, element });
|
|
806
942
|
report.counts.skippedEdges++;
|
|
@@ -811,6 +947,9 @@ class Neo4jImportSession {
|
|
|
811
947
|
report.counts.skippedEdges++;
|
|
812
948
|
return;
|
|
813
949
|
}
|
|
950
|
+
const created = [source, target].filter(
|
|
951
|
+
(id, k) => (k === 0 || id !== source) && sink.indexOf(id) === INVALID_INDEX
|
|
952
|
+
);
|
|
814
953
|
let edge;
|
|
815
954
|
try {
|
|
816
955
|
edge = this.direction.addEdge(source, target, "directed", weight, { line, element });
|
|
@@ -819,13 +958,26 @@ class Neo4jImportSession {
|
|
|
819
958
|
report.counts.skippedEdges++;
|
|
820
959
|
return;
|
|
821
960
|
}
|
|
961
|
+
for (const id of created) {
|
|
962
|
+
report.counts.nodes++;
|
|
963
|
+
this.placeholders.push({ id, index: sink.indexOf(id) });
|
|
964
|
+
}
|
|
822
965
|
if (section.typeCell >= 0) {
|
|
823
966
|
const type = cells[section.typeCell];
|
|
824
967
|
if (type.length > 0) {
|
|
825
|
-
|
|
968
|
+
this.guarded(line, element, () => {
|
|
969
|
+
sink.setEdgeValue(this.typeHandle, edge, type);
|
|
970
|
+
});
|
|
971
|
+
} else {
|
|
972
|
+
report.warning(
|
|
973
|
+
"missing-value",
|
|
974
|
+
MISSING_TYPE_CODE,
|
|
975
|
+
"empty :TYPE cell; neo4j-admin requires a relationship type, the relationship is kept without one",
|
|
976
|
+
{ line, element }
|
|
977
|
+
);
|
|
826
978
|
}
|
|
827
979
|
}
|
|
828
|
-
this.writeProperties("edge", section.properties, edge);
|
|
980
|
+
this.writeProperties("edge", section.properties, edge, line, element);
|
|
829
981
|
this.reportPrecision(line, element);
|
|
830
982
|
report.counts.edges++;
|
|
831
983
|
}
|
|
@@ -886,6 +1038,7 @@ class Neo4jImportSession {
|
|
|
886
1038
|
parseProperties(slots, cells, quoted, line, element) {
|
|
887
1039
|
const { values, texts, precisionSlots } = this;
|
|
888
1040
|
precisionSlots.length = 0;
|
|
1041
|
+
this.overflows.length = 0;
|
|
889
1042
|
for (const slot of slots) {
|
|
890
1043
|
const text = cells[slot.cell];
|
|
891
1044
|
texts[slot.cell] = null;
|
|
@@ -896,16 +1049,21 @@ class Neo4jImportSession {
|
|
|
896
1049
|
const { spec } = slot;
|
|
897
1050
|
try {
|
|
898
1051
|
if (spec.temporal !== null && !spec.list) {
|
|
899
|
-
const
|
|
1052
|
+
const zoned = withZoneOffset(text, spec);
|
|
1053
|
+
const parsed = parseDeclaredTemporal(zoned, spec);
|
|
900
1054
|
values[slot.cell] = parsed.value;
|
|
901
|
-
texts[slot.cell] = parsed.text;
|
|
1055
|
+
texts[slot.cell] = zoned === text ? parsed.text : text;
|
|
902
1056
|
} else {
|
|
903
1057
|
values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
|
|
1058
|
+
checkNeo4jRange(spec, values[slot.cell], text);
|
|
904
1059
|
}
|
|
905
1060
|
} catch (err) {
|
|
906
1061
|
this.report.recordError(err, { line, element: `${element} ${slot.name}` });
|
|
907
1062
|
return false;
|
|
908
1063
|
}
|
|
1064
|
+
if (overflows(spec, values[slot.cell], text)) {
|
|
1065
|
+
this.overflows.push(slot.name);
|
|
1066
|
+
}
|
|
909
1067
|
if (spec.precision && losesPrecision(spec, text)) {
|
|
910
1068
|
precisionSlots.push(slot);
|
|
911
1069
|
}
|
|
@@ -917,8 +1075,10 @@ class Neo4jImportSession {
|
|
|
917
1075
|
* @param domain - node or edge
|
|
918
1076
|
* @param slots - the section's property slots
|
|
919
1077
|
* @param row - the node or edge index
|
|
1078
|
+
* @param line - the row's line
|
|
1079
|
+
* @param element - the row's element name for issues
|
|
920
1080
|
*/
|
|
921
|
-
writeProperties(domain, slots, row) {
|
|
1081
|
+
writeProperties(domain, slots, row, line, element) {
|
|
922
1082
|
const { sink, values, texts } = this;
|
|
923
1083
|
for (const slot of slots) {
|
|
924
1084
|
const value = values[slot.cell];
|
|
@@ -926,20 +1086,22 @@ class Neo4jImportSession {
|
|
|
926
1086
|
continue;
|
|
927
1087
|
}
|
|
928
1088
|
const text = texts[slot.cell];
|
|
929
|
-
|
|
930
|
-
slot.companion
|
|
931
|
-
|
|
932
|
-
if (domain === "node") {
|
|
933
|
-
sink.setNodeValue(slot.handle, row, value);
|
|
934
|
-
if (text !== null) {
|
|
935
|
-
sink.setNodeValue(slot.companion, row, text);
|
|
1089
|
+
this.guarded(line, `${element} ${slot.name}`, () => {
|
|
1090
|
+
if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
|
|
1091
|
+
slot.companion = declareCompanion(sink, domain, slot.companionDecl);
|
|
936
1092
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1093
|
+
if (domain === "node") {
|
|
1094
|
+
sink.setNodeValue(slot.handle, row, value);
|
|
1095
|
+
if (text !== null) {
|
|
1096
|
+
sink.setNodeValue(slot.companion, row, text);
|
|
1097
|
+
}
|
|
1098
|
+
} else {
|
|
1099
|
+
sink.setEdgeValue(slot.handle, row, value);
|
|
1100
|
+
if (text !== null) {
|
|
1101
|
+
sink.setEdgeValue(slot.companion, row, text);
|
|
1102
|
+
}
|
|
941
1103
|
}
|
|
942
|
-
}
|
|
1104
|
+
});
|
|
943
1105
|
}
|
|
944
1106
|
}
|
|
945
1107
|
/**
|
|
@@ -957,6 +1119,15 @@ class Neo4jImportSession {
|
|
|
957
1119
|
);
|
|
958
1120
|
}
|
|
959
1121
|
this.precisionSlots.length = 0;
|
|
1122
|
+
for (const name of this.overflows) {
|
|
1123
|
+
this.report.warning(
|
|
1124
|
+
"precision",
|
|
1125
|
+
PRECISION_CODE,
|
|
1126
|
+
`the value of "${name}" is beyond the range of its float / double type and was stored as the nearest representable value`,
|
|
1127
|
+
{ line, element }
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
this.overflows.length = 0;
|
|
960
1131
|
}
|
|
961
1132
|
/**
|
|
962
1133
|
* The labels of a node row: every `:LABEL` cell split by the array delimiter (empty items
|
|
@@ -994,6 +1165,101 @@ class Neo4jImportSession {
|
|
|
994
1165
|
function qualify(id, space) {
|
|
995
1166
|
return space === null ? id : `${space}:${String(id)}`;
|
|
996
1167
|
}
|
|
1168
|
+
const INTEGER_RANGES = {
|
|
1169
|
+
byte: [-128, 127],
|
|
1170
|
+
short: [-32768, 32767]
|
|
1171
|
+
};
|
|
1172
|
+
function isDuration(text) {
|
|
1173
|
+
if (DURATION_DATE_TIME.test(text)) {
|
|
1174
|
+
return true;
|
|
1175
|
+
}
|
|
1176
|
+
const m = /^[+-]?P([^T]*)(?:T(.*))?$/i.exec(text);
|
|
1177
|
+
if (m === null || m[2] === "" || m[1] === "" && m[2] === void 0) {
|
|
1178
|
+
return false;
|
|
1179
|
+
}
|
|
1180
|
+
return unitsInOrder(m[1], "YMWD") && unitsInOrder(m[2] ?? "", "HMS");
|
|
1181
|
+
}
|
|
1182
|
+
const DURATION_DATE_TIME = /^[+-]?P\d{4}-?\d{2}-?\d{2}T\d{2}:?\d{2}:?\d{2}(?:\.\d+)?$/i;
|
|
1183
|
+
function unitsInOrder(text, units) {
|
|
1184
|
+
let rest = text.toUpperCase();
|
|
1185
|
+
let from = 0;
|
|
1186
|
+
while (rest !== "") {
|
|
1187
|
+
const m = /^[-+]?\d+(?:\.\d+)?([A-Z])/.exec(rest);
|
|
1188
|
+
const at = m === null ? -1 : units.indexOf(m[1], from);
|
|
1189
|
+
if (m === null || at < 0) {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
from = at + 1;
|
|
1193
|
+
rest = rest.slice(m[0].length);
|
|
1194
|
+
}
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
function checkNeo4jRange(spec, value, text) {
|
|
1198
|
+
const base = spec.declared.trim().toLowerCase().replace(/\[\]$/, "");
|
|
1199
|
+
const items = spec.list && Array.isArray(value) ? value : [value];
|
|
1200
|
+
const range = INTEGER_RANGES[base];
|
|
1201
|
+
for (const item of items) {
|
|
1202
|
+
let bad = false;
|
|
1203
|
+
if (range !== void 0) {
|
|
1204
|
+
bad = typeof item === "number" && (item < range[0] || item > range[1]);
|
|
1205
|
+
} else if (base === "char") {
|
|
1206
|
+
bad = typeof item === "string" && item.length !== 1;
|
|
1207
|
+
} else if (base === "duration") {
|
|
1208
|
+
bad = typeof item === "string" && !isDuration(item.trim());
|
|
1209
|
+
}
|
|
1210
|
+
if (bad) {
|
|
1211
|
+
const span = range === void 0 ? "" : ` (${range[0]} to ${range[1]})`;
|
|
1212
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not ${withArticle(base)}${span}`, {
|
|
1213
|
+
value: text,
|
|
1214
|
+
kind: base
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
const F32_MAX = 34028234663852886e22;
|
|
1220
|
+
function overflows(spec, value, text) {
|
|
1221
|
+
if (spec.kind !== "float" && spec.kind !== "double" || /inf|nan/i.test(text)) {
|
|
1222
|
+
return false;
|
|
1223
|
+
}
|
|
1224
|
+
const items = spec.list && Array.isArray(value) ? value : [value];
|
|
1225
|
+
return items.some(
|
|
1226
|
+
(v) => typeof v === "number" && (!Number.isFinite(v) || spec.kind === "float" && Math.abs(v) > F32_MAX)
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
function withZoneOffset(text, spec) {
|
|
1230
|
+
const trimmed = text.trim();
|
|
1231
|
+
const open = trimmed.lastIndexOf("[");
|
|
1232
|
+
if (spec.temporal !== "dateTime" || open < 0 || !trimmed.endsWith("]")) {
|
|
1233
|
+
return text;
|
|
1234
|
+
}
|
|
1235
|
+
const local = trimmed.slice(0, open);
|
|
1236
|
+
const zone = trimmed.slice(open + 1, -1);
|
|
1237
|
+
if (zone === "" || zone.includes("]") || /[\n\r\u2028\u2029]/.test(local)) {
|
|
1238
|
+
return text;
|
|
1239
|
+
}
|
|
1240
|
+
let format;
|
|
1241
|
+
try {
|
|
1242
|
+
format = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" });
|
|
1243
|
+
} catch {
|
|
1244
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" names an unknown time zone ${zone}`, { value: text });
|
|
1245
|
+
}
|
|
1246
|
+
if (/(Z|z|[+-]\d{2}(:?\d{2})?)$/.test(local)) {
|
|
1247
|
+
return local;
|
|
1248
|
+
}
|
|
1249
|
+
const wall = parseTemporal(local, "localDateTime").value;
|
|
1250
|
+
const offsetAt = (ms) => {
|
|
1251
|
+
const name = format.formatToParts(new Date(ms)).find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
1252
|
+
const o = /GMT([+-])(\d{2}):(\d{2})/.exec(name);
|
|
1253
|
+
if (o === null) {
|
|
1254
|
+
return 0;
|
|
1255
|
+
}
|
|
1256
|
+
return (o[1] === "-" ? -1 : 1) * (Number(o[2]) * 60 + Number(o[3]));
|
|
1257
|
+
};
|
|
1258
|
+
const minutes = offsetAt(wall - offsetAt(wall) * 6e4);
|
|
1259
|
+
const sign = minutes < 0 ? "-" : "+";
|
|
1260
|
+
const abs = Math.abs(minutes);
|
|
1261
|
+
return `${local}${sign}${String(Math.floor(abs / 60)).padStart(2, "0")}:${String(abs % 60).padStart(2, "0")}`;
|
|
1262
|
+
}
|
|
997
1263
|
function emptyValue(spec) {
|
|
998
1264
|
if (spec.list) {
|
|
999
1265
|
return [];
|
|
@@ -1027,6 +1293,7 @@ function sniffNeo4j(head) {
|
|
|
1027
1293
|
}
|
|
1028
1294
|
const neo4jImporter = Object.freeze({
|
|
1029
1295
|
format: NEO4J$1,
|
|
1296
|
+
options: Object.freeze(["arrayDelimiter", "delimiter", "nodes", "quote", "relationships"]),
|
|
1030
1297
|
extensions: Object.freeze([".csv", ".tsv"]),
|
|
1031
1298
|
mimeTypes: Object.freeze(["text/csv", "text/tab-separated-values"]),
|
|
1032
1299
|
sniff: sniffNeo4j,
|
|
@@ -1044,7 +1311,14 @@ const neo4jImporter = Object.freeze({
|
|
|
1044
1311
|
reportSinkOptions(sink, options, report);
|
|
1045
1312
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
1046
1313
|
const session = new Neo4jImportSession(sink, report, common, format);
|
|
1047
|
-
await session.run([
|
|
1314
|
+
await session.run([
|
|
1315
|
+
{ input, kind: null },
|
|
1316
|
+
...format.nodes.map((file) => ({ input: file, kind: "node" })),
|
|
1317
|
+
...format.relationships.map((file) => ({ input: file, kind: "relationship" }))
|
|
1318
|
+
]);
|
|
1319
|
+
if (session.weightProperty !== null) {
|
|
1320
|
+
sink.setMeta({ extra: { neo4j: { weightProperty: session.weightProperty } } });
|
|
1321
|
+
}
|
|
1048
1322
|
throwIfAborted(common.signal);
|
|
1049
1323
|
return report.finish();
|
|
1050
1324
|
}
|
|
@@ -1121,7 +1395,7 @@ const NODE_NOTE_CODES = /* @__PURE__ */ new Set([
|
|
|
1121
1395
|
]);
|
|
1122
1396
|
const ARRAY_SYNTAXES = /* @__PURE__ */ new Set([";", ",", "|"]);
|
|
1123
1397
|
const PARTS = /* @__PURE__ */ new Set(["all", "nodes", "relationships"]);
|
|
1124
|
-
function resolveNeo4jExportOptions(options) {
|
|
1398
|
+
function resolveNeo4jExportOptions(options, readFrom) {
|
|
1125
1399
|
const o = options ?? {};
|
|
1126
1400
|
const part = o.part ?? "all";
|
|
1127
1401
|
if (!PARTS.has(part)) {
|
|
@@ -1145,12 +1419,16 @@ function resolveNeo4jExportOptions(options) {
|
|
|
1145
1419
|
const delimiter = o.delimiter ?? ",";
|
|
1146
1420
|
const syntax = { ...checkRecordSyntax({ delimiter, quote: o.quote ?? '"' }), delimiter };
|
|
1147
1421
|
if (syntax.delimiter === arrayDelimiter) {
|
|
1148
|
-
throw new GraphFormatError(
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1422
|
+
throw new GraphFormatError(
|
|
1423
|
+
"E_UNSUPPORTED",
|
|
1424
|
+
`options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`,
|
|
1425
|
+
{
|
|
1426
|
+
option: "arrayDelimiter",
|
|
1427
|
+
found: arrayDelimiter
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1152
1430
|
}
|
|
1153
|
-
const weightColumn = o.weightColumn === void 0 ? "weight" : o.weightColumn;
|
|
1431
|
+
const weightColumn = o.weightColumn === void 0 ? readFrom ?? "weight" : o.weightColumn;
|
|
1154
1432
|
if (weightColumn !== null && (typeof weightColumn !== "string" || weightColumn.length === 0)) {
|
|
1155
1433
|
throw new GraphFormatError("E_UNSUPPORTED", "option weightColumn: expected a non-empty name or null", {
|
|
1156
1434
|
option: "weightColumn",
|
|
@@ -1197,7 +1475,8 @@ class ExportPlan {
|
|
|
1197
1475
|
const generic = checkCapabilities(snapshot, NEO4J_CAPABILITIES, common, {
|
|
1198
1476
|
roles: SLOT_ROLES,
|
|
1199
1477
|
roleNames: ROLE_NAMES,
|
|
1200
|
-
temporalText: true
|
|
1478
|
+
temporalText: true,
|
|
1479
|
+
weights: options.weightColumn !== null
|
|
1201
1480
|
});
|
|
1202
1481
|
this.planColumns("node", snapshot.nodes, this.nodeColumns);
|
|
1203
1482
|
this.planColumns("edge", snapshot.edges, this.edgeColumns);
|
|
@@ -1246,7 +1525,7 @@ class ExportPlan {
|
|
|
1246
1525
|
if (!snapshot.directed) {
|
|
1247
1526
|
this.note(
|
|
1248
1527
|
UNDIRECTED_LOSS,
|
|
1249
|
-
`the snapshot is undirected; every edge is written as a directed relationship (${snapshot.edgeCount} edge(
|
|
1528
|
+
`the snapshot is undirected; every edge is written as a directed relationship (${snapshot.edgeCount} edge${plural(snapshot.edgeCount)})`,
|
|
1250
1529
|
null,
|
|
1251
1530
|
snapshot.edgeCount
|
|
1252
1531
|
);
|
|
@@ -1260,7 +1539,7 @@ class ExportPlan {
|
|
|
1260
1539
|
if (undirected > 0) {
|
|
1261
1540
|
this.note(
|
|
1262
1541
|
UNDIRECTED_LOSS,
|
|
1263
|
-
`${undirected} undirected edge(
|
|
1542
|
+
`${undirected} undirected edge${plural(undirected)} ${agree(undirected, "is", "are")} written as one directed relationship each (source to target, a pair folded to its primary); Neo4j has no undirected relationship`,
|
|
1264
1543
|
null,
|
|
1265
1544
|
undirected
|
|
1266
1545
|
);
|
|
@@ -1269,7 +1548,7 @@ class ExportPlan {
|
|
|
1269
1548
|
if (folding.mutualCount > 0) {
|
|
1270
1549
|
this.note(
|
|
1271
1550
|
LOSS.MUTUAL_EXPANDED,
|
|
1272
|
-
`${folding.mutualCount} mutual pair(
|
|
1551
|
+
`${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two directed relationships; the mutual mark is lost`,
|
|
1273
1552
|
null,
|
|
1274
1553
|
folding.mutualCount
|
|
1275
1554
|
);
|
|
@@ -1461,7 +1740,7 @@ class ExportPlan {
|
|
|
1461
1740
|
if (rows > 0) {
|
|
1462
1741
|
this.note(
|
|
1463
1742
|
ARRAY_DELIMITER_LOSS,
|
|
1464
|
-
`${label}: ${rows} row(
|
|
1743
|
+
`${label}: ${rows} row${plural(rows)} ${agree(rows, "holds", "hold")} an item containing the array delimiter "${arrayDelimiter}", which Neo4j cannot escape`,
|
|
1465
1744
|
column.meta.name,
|
|
1466
1745
|
rows
|
|
1467
1746
|
);
|
|
@@ -1496,7 +1775,7 @@ class ExportPlan {
|
|
|
1496
1775
|
} else if (taken !== void 0 && name === DEFAULT_WEIGHT_COLUMN) {
|
|
1497
1776
|
this.note(
|
|
1498
1777
|
LOSS.WEIGHT_KEY_CLASH,
|
|
1499
|
-
`edge column "${name}" is written under the property the importer reads
|
|
1778
|
+
`edge column "${name}" is written under the property the importer reads edge weights from (weightFrom "${name}"); it reads back as the weight, not as a column`,
|
|
1500
1779
|
name,
|
|
1501
1780
|
taken.column.length - taken.column.nullCount
|
|
1502
1781
|
);
|
|
@@ -1550,7 +1829,7 @@ class ExportPlan {
|
|
|
1550
1829
|
if (typeChanges > 0) {
|
|
1551
1830
|
this.note(
|
|
1552
1831
|
ID_TEXT_TYPE_LOSS,
|
|
1553
|
-
`${typeChanges} node id(
|
|
1832
|
+
`${typeChanges} node id${plural(typeChanges)} re-import as another type under the canonical id rule (a string of canonical integer text, or a non-integer number)`,
|
|
1554
1833
|
null,
|
|
1555
1834
|
typeChanges
|
|
1556
1835
|
);
|
|
@@ -1558,13 +1837,13 @@ class ExportPlan {
|
|
|
1558
1837
|
if (collisions > 0) {
|
|
1559
1838
|
this.note(
|
|
1560
1839
|
ID_TEXT_COLLISION_LOSS,
|
|
1561
|
-
`${collisions} node id(
|
|
1840
|
+
`${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id (a number and a string); the save fails`,
|
|
1562
1841
|
null,
|
|
1563
1842
|
collisions
|
|
1564
1843
|
);
|
|
1565
1844
|
this.fatalAll = new GraphFormatError(
|
|
1566
1845
|
"E_INVALID_ID",
|
|
1567
|
-
`${collisions} node id(
|
|
1846
|
+
`${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id; Neo4j ids are text`,
|
|
1568
1847
|
{ reason: "text collision", count: collisions }
|
|
1569
1848
|
);
|
|
1570
1849
|
}
|
|
@@ -1613,7 +1892,7 @@ class ExportPlan {
|
|
|
1613
1892
|
if (count > 0) {
|
|
1614
1893
|
this.note(
|
|
1615
1894
|
MULTIPLE_ID_PROPERTIES_LOSS,
|
|
1616
|
-
`${count} node(
|
|
1895
|
+
`${count} node${plural(count)} ${agree(count, "has", "have")} more than one stored-id column set; only the first in declaration order is written`,
|
|
1617
1896
|
null,
|
|
1618
1897
|
count
|
|
1619
1898
|
);
|
|
@@ -1713,6 +1992,16 @@ class ExportPlan {
|
|
|
1713
1992
|
* @returns nothing
|
|
1714
1993
|
*/
|
|
1715
1994
|
*lines() {
|
|
1995
|
+
for (const row of this.rows()) {
|
|
1996
|
+
yield row.line;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
/**
|
|
2000
|
+
* The lines of the requested part, each header line tagged with the file it starts.
|
|
2001
|
+
* @yields one line at a time, with the file name on a header line
|
|
2002
|
+
* @returns nothing
|
|
2003
|
+
*/
|
|
2004
|
+
*rows() {
|
|
1716
2005
|
if (this.fatal !== null) {
|
|
1717
2006
|
throw this.fatal;
|
|
1718
2007
|
}
|
|
@@ -1724,19 +2013,50 @@ class ExportPlan {
|
|
|
1724
2013
|
yield* this.relationshipLines();
|
|
1725
2014
|
}
|
|
1726
2015
|
}
|
|
2016
|
+
/**
|
|
2017
|
+
* The requested part as one file per section kind: a node file per id space (and stored-id
|
|
2018
|
+
* property), a relationship file per pair of endpoint id spaces, rows of one kind gathered
|
|
2019
|
+
* under one header.
|
|
2020
|
+
* @returns the files, node files first
|
|
2021
|
+
*/
|
|
2022
|
+
files() {
|
|
2023
|
+
const files = /* @__PURE__ */ new Map();
|
|
2024
|
+
const names = /* @__PURE__ */ new Set();
|
|
2025
|
+
let current = null;
|
|
2026
|
+
for (const row of this.rows()) {
|
|
2027
|
+
if (row.file !== null) {
|
|
2028
|
+
let file = files.get(row.line);
|
|
2029
|
+
if (file === void 0) {
|
|
2030
|
+
let name = `${row.file.name}.csv`;
|
|
2031
|
+
let k = 2;
|
|
2032
|
+
while (names.has(name)) {
|
|
2033
|
+
name = `${row.file.name}-${k}.csv`;
|
|
2034
|
+
k++;
|
|
2035
|
+
}
|
|
2036
|
+
names.add(name);
|
|
2037
|
+
file = { name, kind: row.file.kind, rows: [] };
|
|
2038
|
+
files.set(row.line, file);
|
|
2039
|
+
}
|
|
2040
|
+
current = file;
|
|
2041
|
+
} else if (current !== null) {
|
|
2042
|
+
current.rows.push(row.line);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
const written = [...files].filter(([, f], i) => f.rows.length > 0 || i === 0 && files.size === 1);
|
|
2046
|
+
return written.map(
|
|
2047
|
+
([header, f]) => Object.freeze({ name: f.name, kind: f.kind, text: header + f.rows.join("") })
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
1727
2050
|
/**
|
|
1728
2051
|
* The node sections.
|
|
1729
2052
|
* @yields one line at a time
|
|
1730
2053
|
* @returns nothing
|
|
1731
2054
|
*/
|
|
1732
2055
|
*nodeLines() {
|
|
1733
|
-
const { snapshot
|
|
1734
|
-
const { delimiter } = this.options.syntax;
|
|
1735
|
-
const propertyHeaders = nodeColumns.map((plan2) => plan2.header).join(delimiter);
|
|
2056
|
+
const { snapshot } = this;
|
|
1736
2057
|
let sections = 0;
|
|
1737
2058
|
let sectionSpace = null;
|
|
1738
2059
|
let sectionIdName = null;
|
|
1739
|
-
const cells = [];
|
|
1740
2060
|
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
1741
2061
|
const space = this.spaceOf(i);
|
|
1742
2062
|
const stored = this.storedIdOf(i);
|
|
@@ -1745,38 +2065,49 @@ class ExportPlan {
|
|
|
1745
2065
|
sections++;
|
|
1746
2066
|
sectionSpace = space;
|
|
1747
2067
|
sectionIdName = idName;
|
|
1748
|
-
|
|
1749
|
-
if (labels !== null) {
|
|
1750
|
-
header.push(":LABEL");
|
|
1751
|
-
}
|
|
1752
|
-
if (propertyHeaders.length > 0) {
|
|
1753
|
-
header.push(propertyHeaders);
|
|
1754
|
-
}
|
|
1755
|
-
yield `${header.join(delimiter)}
|
|
1756
|
-
`;
|
|
1757
|
-
}
|
|
1758
|
-
cells.length = 0;
|
|
1759
|
-
cells.push(this.cell(this.idTextOf(i)));
|
|
1760
|
-
if (labels !== null) {
|
|
1761
|
-
cells.push(this.cell(this.labelsText(i)));
|
|
1762
|
-
}
|
|
1763
|
-
for (const plan2 of nodeColumns) {
|
|
1764
|
-
cells.push(this.cell(this.valueText(plan2, i)));
|
|
2068
|
+
yield this.nodeHeader(idName, space, space ?? idName);
|
|
1765
2069
|
}
|
|
1766
|
-
yield
|
|
1767
|
-
`;
|
|
2070
|
+
yield { line: this.nodeRow(i), file: null };
|
|
1768
2071
|
}
|
|
1769
2072
|
if (sections === 0) {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
2073
|
+
yield this.nodeHeader(this.options.idColumn ?? "", null, null);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
/**
|
|
2077
|
+
* The header line of a node section, which starts its file.
|
|
2078
|
+
* @param idName - the id column's name
|
|
2079
|
+
* @param space - the id space, or null
|
|
2080
|
+
* @param fileKey - what names the file, or null for the default name
|
|
2081
|
+
* @returns the line
|
|
2082
|
+
*/
|
|
2083
|
+
nodeHeader(idName, space, fileKey) {
|
|
2084
|
+
const { delimiter } = this.options.syntax;
|
|
2085
|
+
const header = [formatHeaderField(idName, ID_TYPE, space)];
|
|
2086
|
+
if (this.labels !== null) {
|
|
2087
|
+
header.push(":LABEL");
|
|
2088
|
+
}
|
|
2089
|
+
const properties = this.nodeColumns.map((plan2) => plan2.header).join(delimiter);
|
|
2090
|
+
if (properties.length > 0) {
|
|
2091
|
+
header.push(properties);
|
|
2092
|
+
}
|
|
2093
|
+
return { line: `${header.join(delimiter)}
|
|
2094
|
+
`, file: { kind: "nodes", name: fileName("nodes", fileKey, null) } };
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* One node's line: the id, the labels, the properties.
|
|
2098
|
+
* @param i - the node
|
|
2099
|
+
* @returns the line
|
|
2100
|
+
*/
|
|
2101
|
+
nodeRow(i) {
|
|
2102
|
+
const cells = [this.cell(this.idTextOf(i))];
|
|
2103
|
+
if (this.labels !== null) {
|
|
2104
|
+
cells.push(this.cell(this.labelsText(i)));
|
|
2105
|
+
}
|
|
2106
|
+
for (const plan2 of this.nodeColumns) {
|
|
2107
|
+
cells.push(this.cell(this.valueText(plan2, i)));
|
|
1779
2108
|
}
|
|
2109
|
+
return `${cells.join(this.options.syntax.delimiter)}
|
|
2110
|
+
`;
|
|
1780
2111
|
}
|
|
1781
2112
|
/**
|
|
1782
2113
|
* The relationship sections.
|
|
@@ -1784,29 +2115,11 @@ class ExportPlan {
|
|
|
1784
2115
|
* @returns nothing
|
|
1785
2116
|
*/
|
|
1786
2117
|
*relationshipLines() {
|
|
1787
|
-
const { snapshot,
|
|
1788
|
-
const { delimiter } = this.options.syntax;
|
|
2118
|
+
const { snapshot, folding } = this;
|
|
1789
2119
|
const list = snapshot.edgeList();
|
|
1790
|
-
const propertyHeaders = edgeColumns.map((plan2) => plan2.header).join(delimiter);
|
|
1791
|
-
const weightHeader = weights === null ? null : formatHeaderField(this.options.weightColumn ?? "weight", "double", null);
|
|
1792
2120
|
let sections = 0;
|
|
1793
2121
|
let sectionStart = null;
|
|
1794
2122
|
let sectionEnd = null;
|
|
1795
|
-
const cells = [];
|
|
1796
|
-
const headerOf = (startSpace, endSpace) => {
|
|
1797
|
-
const header = [formatHeaderField("", "START_ID", startSpace), formatHeaderField("", "END_ID", endSpace)];
|
|
1798
|
-
if (kind !== null) {
|
|
1799
|
-
header.push(":TYPE");
|
|
1800
|
-
}
|
|
1801
|
-
if (weightHeader !== null) {
|
|
1802
|
-
header.push(weightHeader);
|
|
1803
|
-
}
|
|
1804
|
-
if (propertyHeaders.length > 0) {
|
|
1805
|
-
header.push(propertyHeaders);
|
|
1806
|
-
}
|
|
1807
|
-
return `${header.join(delimiter)}
|
|
1808
|
-
`;
|
|
1809
|
-
};
|
|
1810
2123
|
for (let e = 0; e < snapshot.edgeCount; e++) {
|
|
1811
2124
|
if (folding.folded(e)) {
|
|
1812
2125
|
continue;
|
|
@@ -1819,25 +2132,60 @@ class ExportPlan {
|
|
|
1819
2132
|
sections++;
|
|
1820
2133
|
sectionStart = startSpace;
|
|
1821
2134
|
sectionEnd = endSpace;
|
|
1822
|
-
yield
|
|
1823
|
-
}
|
|
1824
|
-
cells.length = 0;
|
|
1825
|
-
cells.push(this.cell(this.idTextOf(u)), this.cell(this.idTextOf(v)));
|
|
1826
|
-
if (kind !== null) {
|
|
1827
|
-
cells.push(this.cell(kind.isSet(e) ? textOf(kind, e) : null));
|
|
2135
|
+
yield this.relationshipHeader(startSpace, endSpace);
|
|
1828
2136
|
}
|
|
1829
|
-
|
|
1830
|
-
cells.push(this.cell(weights.text(e)));
|
|
1831
|
-
}
|
|
1832
|
-
for (const plan2 of edgeColumns) {
|
|
1833
|
-
cells.push(this.cell(this.valueText(plan2, e)));
|
|
1834
|
-
}
|
|
1835
|
-
yield `${cells.join(delimiter)}
|
|
1836
|
-
`;
|
|
2137
|
+
yield { line: this.relationshipRow(e, u, v), file: null };
|
|
1837
2138
|
}
|
|
1838
2139
|
if (sections === 0) {
|
|
1839
|
-
yield
|
|
2140
|
+
yield this.relationshipHeader(null, null);
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* The header line of a relationship section, which starts its file.
|
|
2145
|
+
* @param startSpace - the id space of the start nodes, or null
|
|
2146
|
+
* @param endSpace - the id space of the end nodes, or null
|
|
2147
|
+
* @returns the line
|
|
2148
|
+
*/
|
|
2149
|
+
relationshipHeader(startSpace, endSpace) {
|
|
2150
|
+
const { delimiter } = this.options.syntax;
|
|
2151
|
+
const header = [formatHeaderField("", "START_ID", startSpace), formatHeaderField("", "END_ID", endSpace)];
|
|
2152
|
+
if (this.kind !== null) {
|
|
2153
|
+
header.push(":TYPE");
|
|
2154
|
+
}
|
|
2155
|
+
if (this.weights !== null) {
|
|
2156
|
+
header.push(formatHeaderField(this.options.weightColumn ?? "weight", "double", null));
|
|
1840
2157
|
}
|
|
2158
|
+
const properties = this.edgeColumns.map((plan2) => plan2.header).join(delimiter);
|
|
2159
|
+
if (properties.length > 0) {
|
|
2160
|
+
header.push(properties);
|
|
2161
|
+
}
|
|
2162
|
+
return {
|
|
2163
|
+
line: `${header.join(delimiter)}
|
|
2164
|
+
`,
|
|
2165
|
+
file: { kind: "relationships", name: fileName("relationships", startSpace, endSpace) }
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
/**
|
|
2169
|
+
* One relationship's line: the ends, the type, the weight, the properties.
|
|
2170
|
+
* @param e - the edge
|
|
2171
|
+
* @param u - its source
|
|
2172
|
+
* @param v - its target
|
|
2173
|
+
* @returns the line
|
|
2174
|
+
*/
|
|
2175
|
+
relationshipRow(e, u, v) {
|
|
2176
|
+
const { kind, weights } = this;
|
|
2177
|
+
const cells = [this.cell(this.idTextOf(u)), this.cell(this.idTextOf(v))];
|
|
2178
|
+
if (kind !== null) {
|
|
2179
|
+
cells.push(this.cell(kind.isSet(e) ? textOf(kind, e) : null));
|
|
2180
|
+
}
|
|
2181
|
+
if (weights !== null) {
|
|
2182
|
+
cells.push(this.cell(weights.text(e)));
|
|
2183
|
+
}
|
|
2184
|
+
for (const plan2 of this.edgeColumns) {
|
|
2185
|
+
cells.push(this.cell(this.valueText(plan2, e)));
|
|
2186
|
+
}
|
|
2187
|
+
return `${cells.join(this.options.syntax.delimiter)}
|
|
2188
|
+
`;
|
|
1841
2189
|
}
|
|
1842
2190
|
/**
|
|
1843
2191
|
* A CSV cell: empty for an unset value, a quoted empty string for a set empty string, the
|
|
@@ -1853,7 +2201,7 @@ class ExportPlan {
|
|
|
1853
2201
|
if (text.length === 0) {
|
|
1854
2202
|
return quote + quote;
|
|
1855
2203
|
}
|
|
1856
|
-
return quoteCsvCell(text, this.options.syntax.delimiter);
|
|
2204
|
+
return quoteCsvCell(text, this.options.syntax.delimiter, quote);
|
|
1857
2205
|
}
|
|
1858
2206
|
/**
|
|
1859
2207
|
* The `:LABEL` cell of a node.
|
|
@@ -2000,7 +2348,7 @@ function formatPoint(value) {
|
|
|
2000
2348
|
if (typeof item === "number") {
|
|
2001
2349
|
parts.push(`${key}:${formatF64(item)}`);
|
|
2002
2350
|
} else if (typeof item === "string") {
|
|
2003
|
-
parts.push(`${key}:'${item.
|
|
2351
|
+
parts.push(`${key}:'${item.replaceAll("'", "")}'`);
|
|
2004
2352
|
} else {
|
|
2005
2353
|
return JSON.stringify(value) ?? "";
|
|
2006
2354
|
}
|
|
@@ -2033,6 +2381,7 @@ function textOf(column, row) {
|
|
|
2033
2381
|
}
|
|
2034
2382
|
const neo4jExporter = Object.freeze({
|
|
2035
2383
|
format: NEO4J,
|
|
2384
|
+
options: Object.freeze(["arrayDelimiter", "delimiter", "idColumn", "part", "quote", "weightColumn"]),
|
|
2036
2385
|
capabilities: NEO4J_CAPABILITIES,
|
|
2037
2386
|
/**
|
|
2038
2387
|
* Pre-flight: what export() would lose.
|
|
@@ -2062,23 +2411,56 @@ const neo4jExporter = Object.freeze({
|
|
|
2062
2411
|
return joinText(plan(snapshot, options).lines());
|
|
2063
2412
|
}
|
|
2064
2413
|
});
|
|
2414
|
+
function fileName(kind, first, second) {
|
|
2415
|
+
const parts = [kind, first ?? "", second ?? ""].filter((p) => p !== "");
|
|
2416
|
+
return parts.join("-").replaceAll(/[^\w.-]/g, "_");
|
|
2417
|
+
}
|
|
2418
|
+
function exportNeo4jFiles(snapshot, options) {
|
|
2419
|
+
try {
|
|
2420
|
+
return Promise.resolve(plan(snapshot, options).files());
|
|
2421
|
+
} catch (err) {
|
|
2422
|
+
return Promise.reject(err);
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2065
2425
|
function plan(snapshot, options) {
|
|
2066
|
-
return new ExportPlan(
|
|
2426
|
+
return new ExportPlan(
|
|
2427
|
+
snapshot,
|
|
2428
|
+
resolveNeo4jExportOptions(options, weightPropertyOf(snapshot)),
|
|
2429
|
+
resolveExportOptions(options)
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
function weightPropertyOf(snapshot) {
|
|
2433
|
+
const neo4j = snapshot.meta.extra?.neo4j;
|
|
2434
|
+
const name = neo4j?.weightProperty;
|
|
2435
|
+
return typeof name === "string" && name !== "" ? name : null;
|
|
2067
2436
|
}
|
|
2068
2437
|
const NEO4J_ISSUE = Object.freeze({
|
|
2069
|
-
|
|
2438
|
+
...INPUT_ISSUE,
|
|
2439
|
+
...ELEMENT_ISSUE,
|
|
2440
|
+
/**
|
|
2441
|
+
* A cell that does not parse as its column's declared type ("x" in an `:int` column, a `:byte` beyond 127). The
|
|
2442
|
+
* row is skipped.
|
|
2443
|
+
*/
|
|
2444
|
+
COLUMN_TYPE: COLUMN_TYPE_CODE,
|
|
2445
|
+
/** The input is not valid UTF-8. The import stops. */
|
|
2070
2446
|
INVALID_UTF8: INVALID_UTF8_CODE,
|
|
2071
|
-
/**
|
|
2447
|
+
/**
|
|
2448
|
+
* Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
|
|
2449
|
+
* `encoding` option). The import stops.
|
|
2450
|
+
*/
|
|
2072
2451
|
INVALID_ENCODING: INVALID_ENCODING_CODE,
|
|
2073
2452
|
/** Bytes that are not UTF-8 and declare no encoding were read as windows-1252. */
|
|
2074
2453
|
ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
|
|
2075
2454
|
/** A declared encoding the platform cannot decode was ignored. */
|
|
2076
2455
|
UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
|
|
2077
|
-
/**
|
|
2456
|
+
/** A quoted field is never closed. The import stops. */
|
|
2078
2457
|
CSV_UNCLOSED_QUOTE: UNCLOSED_QUOTE_CODE,
|
|
2079
|
-
/**
|
|
2458
|
+
/**
|
|
2459
|
+
* There is text after a closing quote, such as `"a"b`. Inside a quoted field, write a quote as two quotes. The
|
|
2460
|
+
* import stops.
|
|
2461
|
+
*/
|
|
2080
2462
|
CSV_QUOTE: BAD_QUOTE_CODE,
|
|
2081
|
-
/**
|
|
2463
|
+
/** The file has no header, or a header neo4j-admin would refuse. The import stops. */
|
|
2082
2464
|
HEADER: HEADER_CODE,
|
|
2083
2465
|
/** A row with a different field count than the header. */
|
|
2084
2466
|
COLUMN_COUNT: COLUMN_COUNT_CODE,
|
|
@@ -2092,41 +2474,65 @@ const NEO4J_ISSUE = Object.freeze({
|
|
|
2092
2474
|
ID_SPACE_COLLISION: ID_SPACE_COLLISION_CODE,
|
|
2093
2475
|
/** A spaced relationship endpoint `Space:id` that names a node declared without a space; the row is skipped. */
|
|
2094
2476
|
ENDPOINT_SPACE: ENDPOINT_SPACE_CODE,
|
|
2095
|
-
/** Two id texts
|
|
2477
|
+
/** Two different id texts became the same number because `ids` is "number", so their nodes were merged. */
|
|
2096
2478
|
ID_MERGED: ID_MERGED_CODE,
|
|
2097
2479
|
/** A header brace option the importer does not apply. */
|
|
2098
2480
|
HEADER_OPTION_IGNORED: HEADER_OPTION_CODE,
|
|
2099
2481
|
/** A declared type the format does not define (kept as string). */
|
|
2100
2482
|
UNKNOWN_ATTR_TYPE: UNKNOWN_ATTR_TYPE_CODE,
|
|
2101
|
-
/**
|
|
2483
|
+
/** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
|
|
2102
2484
|
PRECISION: PRECISION_CODE,
|
|
2103
|
-
/**
|
|
2485
|
+
/**
|
|
2486
|
+
* An attribute was renamed `<name>#<suffix>` because another attribute already has its name, for example a
|
|
2487
|
+
* repeated column header.
|
|
2488
|
+
*/
|
|
2104
2489
|
COLUMN_RENAMED: COLUMN_RENAMED_CODE,
|
|
2105
|
-
/**
|
|
2490
|
+
/**
|
|
2491
|
+
* You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
|
|
2492
|
+
* a plain attribute.
|
|
2493
|
+
*/
|
|
2106
2494
|
ROLE_TAKEN: ROLE_TAKEN_CODE,
|
|
2107
|
-
/**
|
|
2495
|
+
/** You set an option this format does not use; it had no effect. The message names the option. */
|
|
2108
2496
|
OPTION_IGNORED: OPTION_IGNORED_CODE,
|
|
2109
|
-
/**
|
|
2110
|
-
|
|
2497
|
+
/**
|
|
2498
|
+
* You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
|
|
2499
|
+
* `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
|
|
2500
|
+
*/
|
|
2501
|
+
SINK_OPTION: SINK_OPTION_CODE,
|
|
2502
|
+
/** A relationship with an empty :TYPE cell (neo4j-admin requires one); kept without a type. */
|
|
2503
|
+
MISSING_TYPE: MISSING_TYPE_CODE,
|
|
2504
|
+
/** A file under the nodes option holds a relationship header, or the reverse; read by its header. */
|
|
2505
|
+
SECTION_KIND: SECTION_KIND_CODE,
|
|
2506
|
+
/** Relationship endpoints no node row declares became nodes (neo4j-admin refuses them). */
|
|
2507
|
+
DANGLING_REFERENCE: DANGLING_REFERENCE_CODE
|
|
2111
2508
|
});
|
|
2112
2509
|
const NEO4J_LOSS = Object.freeze({
|
|
2113
2510
|
/** `:IGNORE` columns skipped on import. */
|
|
2114
2511
|
IGNORED_COLUMNS: IGNORED_COLUMNS_LOSS,
|
|
2115
|
-
/**
|
|
2512
|
+
/**
|
|
2513
|
+
* Neo4j relationships are always directed, so the edges of an undirected graph, and the undirected edges of a
|
|
2514
|
+
* mixed graph, read back as directed.
|
|
2515
|
+
*/
|
|
2116
2516
|
UNDIRECTED_AS_DIRECTED: UNDIRECTED_LOSS,
|
|
2117
2517
|
/** A mutual pair written as two directed relationships without its mark. */
|
|
2118
2518
|
MUTUAL_EXPANDED: MUTUAL_EXPANDED_CODE,
|
|
2119
|
-
/**
|
|
2519
|
+
/** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */
|
|
2120
2520
|
ROLE_DROPPED: ROLE_DROPPED_CODE,
|
|
2121
|
-
/**
|
|
2521
|
+
/**
|
|
2522
|
+
* An edge attribute named `weight` that is not the graph's weight reads back as the edge weight, because the
|
|
2523
|
+
* Neo4j importer reads weights from the `weight` property by default.
|
|
2524
|
+
*/
|
|
2122
2525
|
WEIGHT_KEY_CLASH: WEIGHT_KEY_CLASH_CODE,
|
|
2123
|
-
/**
|
|
2526
|
+
/**
|
|
2527
|
+
* A node id that reads back as a different type, such as the text "7" as the number 7. Read the file with `ids:
|
|
2528
|
+
* "string"` or `ids: "keep"` to keep the type.
|
|
2529
|
+
*/
|
|
2124
2530
|
ID_TEXT_TYPE: ID_TEXT_TYPE_LOSS,
|
|
2125
|
-
/**
|
|
2531
|
+
/** Two node ids would be written as the same text (the number 5 and the text "5"); the save fails with E_INVALID_ID. */
|
|
2126
2532
|
ID_TEXT_COLLISION: ID_TEXT_COLLISION_LOSS,
|
|
2127
|
-
/** The
|
|
2533
|
+
/** The `weightColumn` name is already an edge attribute; the save fails. */
|
|
2128
2534
|
WEIGHT_COLUMN_TAKEN: WEIGHT_COLUMN_TAKEN_LOSS,
|
|
2129
|
-
/** The
|
|
2535
|
+
/** The `idColumn` name is already a node attribute; the save fails. */
|
|
2130
2536
|
ID_COLUMN_TAKEN: ID_COLUMN_TAKEN_LOSS,
|
|
2131
2537
|
/** Several stored-id properties; one becomes the `:ID` column. */
|
|
2132
2538
|
MULTIPLE_ID_PROPERTIES: MULTIPLE_ID_PROPERTIES_LOSS,
|
|
@@ -2143,6 +2549,7 @@ export {
|
|
|
2143
2549
|
NEO4J_LOSS,
|
|
2144
2550
|
ORIGINAL_ID_COLUMN,
|
|
2145
2551
|
TYPE_COLUMN,
|
|
2552
|
+
exportNeo4jFiles,
|
|
2146
2553
|
neo4jExporter,
|
|
2147
2554
|
neo4jImporter
|
|
2148
2555
|
};
|