@graphty/graph-io 0.3.24 → 0.3.26
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-BbJI55dx.js +56 -0
- package/dist/chunks/choose-BbJI55dx.js.map +1 -0
- package/dist/chunks/constants-BCsFsMj4.js +231 -0
- package/dist/chunks/constants-BCsFsMj4.js.map +1 -0
- package/dist/chunks/{escape-B-tkk_Cl.js → escape-D0g6NNUy.js} +382 -92
- package/dist/chunks/escape-D0g6NNUy.js.map +1 -0
- package/dist/chunks/export-BTI4yQgy.js +4333 -0
- package/dist/chunks/export-BTI4yQgy.js.map +1 -0
- package/dist/chunks/exporter-BMqk5oxW.js +3465 -0
- package/dist/chunks/exporter-BMqk5oxW.js.map +1 -0
- package/dist/chunks/{importer-eUREhBGj.js → exporter-Cra2GYcN.js} +4969 -3201
- package/dist/chunks/exporter-Cra2GYcN.js.map +1 -0
- package/dist/chunks/{exporter-BGrsWamJ.js → exporter-Dxh231ZF.js} +38 -229
- package/dist/chunks/exporter-Dxh231ZF.js.map +1 -0
- package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-tne475KK.js} +22 -20
- package/dist/chunks/exporter-tne475KK.js.map +1 -0
- package/dist/chunks/importer-90YWhJoF.js +2811 -0
- package/dist/chunks/importer-90YWhJoF.js.map +1 -0
- package/dist/chunks/{importer-D_e7e7LX.js → importer-Bcl1d4xH.js} +398 -145
- package/dist/chunks/importer-Bcl1d4xH.js.map +1 -0
- package/dist/chunks/{importer-BWY2FFc5.js → importer-BfIsp1f9.js} +255 -77
- package/dist/chunks/importer-BfIsp1f9.js.map +1 -0
- package/dist/chunks/{importer-zGLo8Dg_.js → importer-C_TEA1zJ.js} +484 -157
- package/dist/chunks/importer-C_TEA1zJ.js.map +1 -0
- package/dist/chunks/{importer-DET1tg6s.js → importer-DCjOvO7U.js} +1687 -310
- package/dist/chunks/importer-DCjOvO7U.js.map +1 -0
- package/dist/chunks/{importer-vi3bSdtw.js → importer-DfVu6j59.js} +509 -76
- package/dist/chunks/importer-DfVu6j59.js.map +1 -0
- package/dist/chunks/{importer-DIrbbnAf.js → importer-Dku_VAIY.js} +585 -226
- package/dist/chunks/importer-Dku_VAIY.js.map +1 -0
- package/dist/chunks/json-elements-3tnyt5uZ.js +1225 -0
- package/dist/chunks/json-elements-3tnyt5uZ.js.map +1 -0
- package/dist/chunks/ontology-export-B9Tcf37D.js +357 -0
- package/dist/chunks/ontology-export-B9Tcf37D.js.map +1 -0
- package/dist/chunks/{records-dbRkxwaq.js → records-CQXT__mY.js} +298 -114
- package/dist/chunks/records-CQXT__mY.js.map +1 -0
- package/dist/chunks/{text-Dr0Ifpag.js → text-DmcUs5_Q.js} +29 -11
- package/dist/chunks/text-DmcUs5_Q.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 +951 -261
- 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 +342 -85
- 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 +564 -157
- 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 +19 -1
- 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 +33 -17
- 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 +868 -188
- 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 +2 -0
- 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 +400 -83
- 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 +145 -32
- 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 +680 -285
- 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 +226 -79
- 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 +98 -24
- 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 +108 -26
- 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 +238 -85
- 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 +66 -34
- 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 +183 -51
- 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 +20 -21
- 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 +7 -2
- 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 +38 -4
- package/src/common/direction.ts +78 -51
- package/src/common/escape.ts +33 -17
- 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 +1034 -198
- package/src/common/line-format.ts +249 -0
- package/src/common/lists.ts +6 -1
- 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 +477 -88
- package/src/common/zip.ts +169 -7
- package/src/formats/csv/exporter.ts +201 -46
- 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 +888 -300
- package/src/formats/cx/index.ts +4 -3
- package/src/formats/cx2/exporter.ts +61 -338
- package/src/formats/cx2/importer.ts +317 -86
- 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 +139 -31
- 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 +111 -26
- 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 +320 -101
- 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 +89 -41
- package/src/formats/pajek/importer.ts +407 -93
- package/src/formats/pajek/index.ts +2 -1
- package/src/formats/pajek/syntax.ts +213 -52
- 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 +35 -27
- package/src/formats/xgmml/importer.ts +64 -86
- package/src/formats/xgmml/index.ts +1 -0
- package/src/formats/xgmml/values.ts +11 -3
- 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
|
@@ -35,52 +35,113 @@
|
|
|
35
35
|
*/
|
|
36
36
|
import { GraphFormatError, INVALID_INDEX, } from "@graphty/graph-format";
|
|
37
37
|
import { declareAttribute, declareCompanion, declareOn, losesPrecision, parseDeclaredTemporal, parseDeclaredValue, PRECISION_CODE, RENAMED_CODE, takenIn, uniqueColumnName, } from "../../common/attributes.js";
|
|
38
|
-
import { DUPLICATE_NODE_CODE as SHARED_DUPLICATE_NODE_CODE, MISSING_ENDPOINT_CODE as SHARED_MISSING_ENDPOINT_CODE, MISSING_ID_CODE as SHARED_MISSING_ID_CODE, ROLE_TAKEN_CODE as SHARED_ROLE_TAKEN_CODE, } from "../../common/codes.js";
|
|
38
|
+
import { DANGLING_REFERENCE_CODE as SHARED_DANGLING_REFERENCE_CODE, DUPLICATE_NODE_CODE as SHARED_DUPLICATE_NODE_CODE, MISSING_ENDPOINT_CODE as SHARED_MISSING_ENDPOINT_CODE, MISSING_ID_CODE as SHARED_MISSING_ID_CODE, ROLE_TAKEN_CODE as SHARED_ROLE_TAKEN_CODE, } from "../../common/codes.js";
|
|
39
39
|
import { DirectionResolver } from "../../common/direction.js";
|
|
40
40
|
import { ID_MERGED_CODE as SHARED_ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
|
|
41
41
|
import { inputLength, isImportInput, throwIfAborted } from "../../common/input.js";
|
|
42
42
|
import { splitListText } from "../../common/lists.js";
|
|
43
43
|
import { reportSinkOptions, reportUnusedOptions, resolveImportOptions, } from "../../common/options.js";
|
|
44
|
+
import { agree, plural, withArticle } from "../../common/plural.js";
|
|
44
45
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
46
|
+
import { parseTemporal } from "../../common/temporal.js";
|
|
45
47
|
import { parseWeightText } from "../../common/weights.js";
|
|
46
48
|
import { ImportError, } from "../../types.js";
|
|
47
49
|
import { checkRecordSyntax, RecordReader } from "../csv/records.js";
|
|
48
50
|
import { isHeaderRecord, parseHeaderField } from "./header.js";
|
|
49
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* The name of the node list column holding `:LABEL` values.
|
|
53
|
+
* @category Built-in formats
|
|
54
|
+
*/
|
|
50
55
|
export const LABELS_COLUMN = "labels";
|
|
51
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* The name of the edge dict column holding `:TYPE` values.
|
|
58
|
+
* @category Built-in formats
|
|
59
|
+
*/
|
|
52
60
|
export const TYPE_COLUMN = "type";
|
|
53
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* The name of the node dict column holding the id space of `:ID(Space)`.
|
|
63
|
+
* @category Built-in formats
|
|
64
|
+
*/
|
|
54
65
|
export const ID_SPACE_COLUMN = "idSpace";
|
|
55
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* 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
|
|
68
|
+
* space (`:ID(Person)`), whose node id is `Person:<id>`. It has nothing to do with the `originalId` role that
|
|
69
|
+
* `sanitizeIds: "mangle"` uses.
|
|
70
|
+
* @category Built-in formats
|
|
71
|
+
*/
|
|
56
72
|
export const ORIGINAL_ID_COLUMN = "originalId";
|
|
57
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* A header row (or a whole section) is malformed; the import aborts.
|
|
75
|
+
* @category Issue and loss codes
|
|
76
|
+
*/
|
|
58
77
|
export const HEADER_CODE = "E_NEO4J_HEADER";
|
|
59
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* A row has a different number of cells than its header.
|
|
80
|
+
* @category Issue and loss codes
|
|
81
|
+
*/
|
|
60
82
|
export const COLUMN_COUNT_CODE = "E_NEO4J_COLUMN_COUNT";
|
|
61
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* A node row has an unquoted empty `:ID` cell (a quoted empty cell is the id "").
|
|
85
|
+
* @category Issue and loss codes
|
|
86
|
+
*/
|
|
62
87
|
export const MISSING_ID_CODE = SHARED_MISSING_ID_CODE;
|
|
63
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* A relationship row has an unquoted empty `:START_ID` or `:END_ID` cell.
|
|
90
|
+
* @category Issue and loss codes
|
|
91
|
+
*/
|
|
64
92
|
export const MISSING_ENDPOINT_CODE = SHARED_MISSING_ENDPOINT_CODE;
|
|
65
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* A node id was declared twice (same id space); the later row's properties win.
|
|
95
|
+
* @category Issue and loss codes
|
|
96
|
+
*/
|
|
66
97
|
export const DUPLICATE_NODE_CODE = SHARED_DUPLICATE_NODE_CODE;
|
|
67
98
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
99
|
+
* A node id was declared in two id spaces -- a spaced id `Space:id` equals the text of an id declared without a space;
|
|
100
|
+
* the later row is skipped.
|
|
101
|
+
* @category Issue and loss codes
|
|
70
102
|
*/
|
|
71
103
|
export const ID_SPACE_COLLISION_CODE = "E_NEO4J_ID_SPACE_COLLISION";
|
|
72
104
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
105
|
+
* A `:START_ID(Space)` / `:END_ID(Space)` endpoint's qualified id `Space:id` names a node a node row declared in
|
|
106
|
+
* another id space (without a space); the row is skipped.
|
|
107
|
+
* @category Issue and loss codes
|
|
75
108
|
*/
|
|
76
109
|
export const ENDPOINT_SPACE_CODE = "E_NEO4J_ENDPOINT_SPACE";
|
|
77
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Two different id cells became one id under `ids: "number"`.
|
|
112
|
+
* @category Issue and loss codes
|
|
113
|
+
*/
|
|
78
114
|
export const ID_MERGED_CODE = SHARED_ID_MERGED_CODE;
|
|
79
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* A header brace option the importer does not act on.
|
|
117
|
+
* @category Issue and loss codes
|
|
118
|
+
*/
|
|
80
119
|
export const HEADER_OPTION_CODE = "W_NEO4J_HEADER_OPTION_IGNORED";
|
|
81
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* You read into a graph builder that already has the labels, type or id space attribute, so this file's one is kept
|
|
122
|
+
* without its role.
|
|
123
|
+
* @category Issue and loss codes
|
|
124
|
+
*/
|
|
82
125
|
export const ROLE_TAKEN_CODE = SHARED_ROLE_TAKEN_CODE;
|
|
83
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* A relationship row with an empty `:TYPE` cell (neo4j-admin requires a type); the relationship is kept.
|
|
128
|
+
* @category Issue and loss codes
|
|
129
|
+
*/
|
|
130
|
+
export const MISSING_TYPE_CODE = "W_NEO4J_MISSING_TYPE";
|
|
131
|
+
/**
|
|
132
|
+
* A file given under the `nodes` option holds a relationship header, or the reverse.
|
|
133
|
+
* @category Issue and loss codes
|
|
134
|
+
*/
|
|
135
|
+
export const SECTION_KIND_CODE = "W_NEO4J_SECTION_KIND";
|
|
136
|
+
/**
|
|
137
|
+
* Relationship endpoints that no node row declares became nodes (the shared W_DANGLING_REFERENCE).
|
|
138
|
+
* @category Issue and loss codes
|
|
139
|
+
*/
|
|
140
|
+
export const DANGLING_REFERENCE_CODE = SHARED_DANGLING_REFERENCE_CODE;
|
|
141
|
+
/**
|
|
142
|
+
* `:IGNORE` columns were skipped.
|
|
143
|
+
* @category Built-in formats
|
|
144
|
+
*/
|
|
84
145
|
export const IGNORED_COLUMNS_LOSS = "W_NEO4J_IGNORED_COLUMNS";
|
|
85
146
|
/** The common options the Neo4j importer reads (the rest is reported by reportUnusedOptions). */
|
|
86
147
|
const USED_OPTIONS = new Set([
|
|
@@ -143,13 +204,16 @@ function resolveNeo4jOptions(options) {
|
|
|
143
204
|
if (typeof arrayDelimiter !== "string" || listSyntax === undefined) {
|
|
144
205
|
throw new GraphFormatError("E_UNSUPPORTED", `option arrayDelimiter: ${JSON.stringify(arrayDelimiter)} is not one of ";", ",", "|"`, { option: "arrayDelimiter", found: arrayDelimiter });
|
|
145
206
|
}
|
|
207
|
+
if (arrayDelimiter === "," && o.delimiter === undefined) {
|
|
208
|
+
throw new GraphFormatError("E_UNSUPPORTED", 'option arrayDelimiter "," needs the delimiter option: the field delimiter is a comma unless another is given', { option: "arrayDelimiter", found: arrayDelimiter });
|
|
209
|
+
}
|
|
146
210
|
const syntax = checkRecordSyntax({
|
|
147
211
|
delimiter: o.delimiter ?? null,
|
|
148
212
|
quote: o.quote ?? '"',
|
|
149
213
|
candidates: NEO4J_DELIMITER_CANDIDATES.filter((d) => d !== arrayDelimiter),
|
|
150
214
|
});
|
|
151
215
|
if (syntax.delimiter === arrayDelimiter) {
|
|
152
|
-
throw new GraphFormatError("E_UNSUPPORTED",
|
|
216
|
+
throw new GraphFormatError("E_UNSUPPORTED", `options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`, {
|
|
153
217
|
option: "arrayDelimiter",
|
|
154
218
|
found: arrayDelimiter,
|
|
155
219
|
});
|
|
@@ -162,7 +226,7 @@ function resolveNeo4jOptions(options) {
|
|
|
162
226
|
};
|
|
163
227
|
}
|
|
164
228
|
/**
|
|
165
|
-
*
|
|
229
|
+
* Normalize an input-list option.
|
|
166
230
|
* @param name - the option name
|
|
167
231
|
* @param value - one input, a list of inputs, or undefined
|
|
168
232
|
* @returns the inputs; E_UNSUPPORTED for anything else
|
|
@@ -299,6 +363,8 @@ class Neo4jImportSession {
|
|
|
299
363
|
*/
|
|
300
364
|
constructor(sink, report, common, options) {
|
|
301
365
|
this.registry = new NodeRegistry();
|
|
366
|
+
/** The relationship property the weights were read from, when it is not "weight"; the exporter writes it back under that name. */
|
|
367
|
+
this.weightProperty = null;
|
|
302
368
|
this.labelsHandle = INVALID_INDEX;
|
|
303
369
|
this.typeHandle = INVALID_INDEX;
|
|
304
370
|
this.idSpaceHandle = INVALID_INDEX;
|
|
@@ -312,6 +378,14 @@ class Neo4jImportSession {
|
|
|
312
378
|
this.texts = [];
|
|
313
379
|
/** Scratch: the property slots of the current row that lost precision. */
|
|
314
380
|
this.precisionSlots = [];
|
|
381
|
+
/** Scratch: the values of the current row that overflowed their float / double type. */
|
|
382
|
+
this.overflows = [];
|
|
383
|
+
/** The section kind the option of the input being read names, or null for the primary input. */
|
|
384
|
+
this.expectedKind = null;
|
|
385
|
+
/** Whether any node row was read. */
|
|
386
|
+
this.nodeRows = false;
|
|
387
|
+
/** Nodes relationship endpoints created (no node row declared them yet), the first few by id. */
|
|
388
|
+
this.placeholders = [];
|
|
315
389
|
this.sink = sink;
|
|
316
390
|
this.report = report;
|
|
317
391
|
this.common = common;
|
|
@@ -320,33 +394,59 @@ class Neo4jImportSession {
|
|
|
320
394
|
this.direction = new DirectionResolver(sink, report, common.onMixedDirection);
|
|
321
395
|
}
|
|
322
396
|
/**
|
|
323
|
-
* Read every input.
|
|
324
|
-
*
|
|
397
|
+
* Read every input. A header-only input lends its header to the headerless input after it (the
|
|
398
|
+
* neo4j-admin convention `--nodes=header.csv,part1.csv`); an empty input is an error only when
|
|
399
|
+
* it is the only one.
|
|
400
|
+
* @param inputs - the inputs in reading order, each with the kind of section its option names (null for the primary input)
|
|
325
401
|
*/
|
|
326
402
|
async run(inputs) {
|
|
327
|
-
const progress = new ProgressTracker(this.common.onProgress, inputs);
|
|
328
|
-
|
|
329
|
-
|
|
403
|
+
const progress = new ProgressTracker(this.common.onProgress, inputs.map((i) => i.input));
|
|
404
|
+
let carried = null;
|
|
405
|
+
for (const { input, kind } of inputs) {
|
|
406
|
+
this.expectedKind = kind;
|
|
407
|
+
if (carried !== null && kind !== null && carried.kind !== kind) {
|
|
408
|
+
// a nodes header never lends itself to a relationships file, nor the reverse
|
|
409
|
+
carried = null;
|
|
410
|
+
}
|
|
411
|
+
carried = await this.readInput(input, { ...progress.optionsFor(this.common.signal), encoding: this.common.encoding }, carried, inputs.length > 1);
|
|
330
412
|
progress.finishInput();
|
|
331
413
|
}
|
|
332
414
|
if (this.ignoredColumns > 0) {
|
|
333
|
-
this.report.loss(IGNORED_COLUMNS_LOSS, `${this.ignoredColumns} :IGNORE column(
|
|
415
|
+
this.report.loss(IGNORED_COLUMNS_LOSS, `${this.ignoredColumns} :IGNORE column${plural(this.ignoredColumns)} ${agree(this.ignoredColumns, "was", "were")} skipped as the header instructs`, null, this.ignoredColumns);
|
|
334
416
|
}
|
|
417
|
+
this.reportDangling();
|
|
335
418
|
}
|
|
336
419
|
/**
|
|
337
420
|
* Read one input: a header row, then data rows until the next header row.
|
|
338
421
|
* @param input - the input
|
|
339
422
|
* @param readOptions - cancellation and progress
|
|
423
|
+
* @param carried - the section of a header-only input just before this one, or null
|
|
424
|
+
* @param mayBeEmpty - whether an input without any record is allowed (other inputs exist)
|
|
425
|
+
* @returns this input's section when it held a header and no data row (lent to the next input), else null
|
|
340
426
|
*/
|
|
341
|
-
async readInput(input, readOptions) {
|
|
342
|
-
const reader = new RecordReader(input, this.report, this.options.syntax,
|
|
343
|
-
|
|
427
|
+
async readInput(input, readOptions, carried, mayBeEmpty) {
|
|
428
|
+
const reader = new RecordReader(input, this.report, this.options.syntax, {
|
|
429
|
+
...readOptions,
|
|
430
|
+
allowEmpty: mayBeEmpty,
|
|
431
|
+
});
|
|
432
|
+
let section = carried;
|
|
433
|
+
let records = 0;
|
|
434
|
+
let rows = 0;
|
|
344
435
|
let sinceCheck = 0;
|
|
345
436
|
for await (const count of reader) {
|
|
346
|
-
|
|
437
|
+
const { cells, quoted } = reader;
|
|
438
|
+
if (records === 0 && count === 1 && !quoted[0] && cells[0].trim().length === 0) {
|
|
439
|
+
// a whitespace-only line before anything else is a blank line, not an empty header
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
records++;
|
|
443
|
+
// a quoted marker cell is data ("ref:id") unless the whole record is a quoted header
|
|
444
|
+
if (section === null || isHeaderRecord(cells, count, quoted)) {
|
|
347
445
|
section = this.declareSection(reader, count);
|
|
446
|
+
rows = 0;
|
|
348
447
|
continue;
|
|
349
448
|
}
|
|
449
|
+
rows++;
|
|
350
450
|
if (section.kind === "node") {
|
|
351
451
|
this.nodeRow(section, reader, count);
|
|
352
452
|
}
|
|
@@ -358,9 +458,14 @@ class Neo4jImportSession {
|
|
|
358
458
|
throwIfAborted(readOptions.signal);
|
|
359
459
|
}
|
|
360
460
|
}
|
|
361
|
-
if (
|
|
461
|
+
if (records === 0 && carried === null && !mayBeEmpty) {
|
|
362
462
|
this.report.fail(HEADER_CODE, "the input has no header row", { line: 1 });
|
|
363
463
|
}
|
|
464
|
+
// the header lent on: a header-only input's, or the one lent to this input when it had none
|
|
465
|
+
if (section === carried) {
|
|
466
|
+
return carried;
|
|
467
|
+
}
|
|
468
|
+
return rows === 0 ? section : null;
|
|
364
469
|
}
|
|
365
470
|
/**
|
|
366
471
|
* Interpret a header row: parse every cell, check the section shape, declare its columns.
|
|
@@ -394,7 +499,13 @@ class Neo4jImportSession {
|
|
|
394
499
|
throw headerError("a header mixes :ID with :START_ID / :END_ID");
|
|
395
500
|
}
|
|
396
501
|
if (!isNode && !isRelationship) {
|
|
397
|
-
|
|
502
|
+
const apoc = fields.some((f) => f.name === "_id" || f.name === "_start");
|
|
503
|
+
throw headerError(apoc
|
|
504
|
+
? "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"
|
|
505
|
+
: "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)");
|
|
506
|
+
}
|
|
507
|
+
if (this.expectedKind !== null && this.expectedKind !== (isNode ? "node" : "relationship")) {
|
|
508
|
+
this.report.warning("validation-error", SECTION_KIND_CODE, `a ${isNode ? "node" : "relationship"} header in a file given as ${this.expectedKind === "node" ? "nodes" : "relationships"}; read by its header`, { line });
|
|
398
509
|
}
|
|
399
510
|
checkPropertyNames(fields);
|
|
400
511
|
this.ignoredColumns += (kinds.get("IGNORE") ?? []).length;
|
|
@@ -421,7 +532,12 @@ class Neo4jImportSession {
|
|
|
421
532
|
}
|
|
422
533
|
catch (err) {
|
|
423
534
|
if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
|
|
424
|
-
|
|
535
|
+
// a header written with another delimiter reads as one cell holding it
|
|
536
|
+
const other = [";", "|", "\t", ","].find((d) => d !== reader.delimiter && reader.cells.slice(0, count).some((c) => c.includes(d)));
|
|
537
|
+
const hint = other === undefined
|
|
538
|
+
? ""
|
|
539
|
+
: `; if the file is delimited by ${JSON.stringify(other)}, pass the delimiter option`;
|
|
540
|
+
this.report.fail(HEADER_CODE, `${err.message}${hint}`, { line }, { cause: err.code });
|
|
425
541
|
}
|
|
426
542
|
throw err;
|
|
427
543
|
}
|
|
@@ -492,6 +608,9 @@ class Neo4jImportSession {
|
|
|
492
608
|
let weightCell = -1;
|
|
493
609
|
if (weightFrom !== null) {
|
|
494
610
|
weightCell = fields.findIndex((field) => field.kind === "PROPERTY" && field.name === weightFrom);
|
|
611
|
+
if (weightCell >= 0 && weightFrom !== "weight") {
|
|
612
|
+
this.weightProperty = weightFrom;
|
|
613
|
+
}
|
|
495
614
|
}
|
|
496
615
|
const properties = this.declareProperties("edge", fields, line, weightCell);
|
|
497
616
|
const { space: startSpace } = fields[startCell];
|
|
@@ -645,7 +764,7 @@ class Neo4jImportSession {
|
|
|
645
764
|
const { sink, report } = this;
|
|
646
765
|
const { cells, quoted, line } = reader;
|
|
647
766
|
if (count !== section.width) {
|
|
648
|
-
report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell(
|
|
767
|
+
report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell${plural(count)} but the header has ${section.width}`, { line });
|
|
649
768
|
report.counts.skippedNodes++;
|
|
650
769
|
return;
|
|
651
770
|
}
|
|
@@ -666,7 +785,17 @@ class Neo4jImportSession {
|
|
|
666
785
|
if (section.labelCells.length > 0 || section.extraLabels.length > 0) {
|
|
667
786
|
labels = this.labelsOf(section, cells, quoted);
|
|
668
787
|
}
|
|
669
|
-
|
|
788
|
+
this.nodeRows = true;
|
|
789
|
+
const existed = sink.indexOf(id) !== INVALID_INDEX;
|
|
790
|
+
let index;
|
|
791
|
+
try {
|
|
792
|
+
index = sink.addNode(id);
|
|
793
|
+
}
|
|
794
|
+
catch (err) {
|
|
795
|
+
report.recordError(err, { line, element: idText });
|
|
796
|
+
report.counts.skippedNodes++;
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
670
799
|
const status = this.registry.declare(index, section.spaceCode);
|
|
671
800
|
if (status === "collision") {
|
|
672
801
|
report.error("validation-error", ID_SPACE_COLLISION_CODE, `node ${idText} is declared in id space ${section.space ?? "(none)"} and in another id space; the core has one id space and this row is skipped`, { line, element: idText });
|
|
@@ -679,19 +808,63 @@ class Neo4jImportSession {
|
|
|
679
808
|
element: idText,
|
|
680
809
|
});
|
|
681
810
|
}
|
|
811
|
+
// a write the sink refuses is recorded and the rest of the row is still written
|
|
812
|
+
const set = (column, value) => {
|
|
813
|
+
this.guarded(line, idText, () => {
|
|
814
|
+
sink.setNodeValue(column, index, value);
|
|
815
|
+
});
|
|
816
|
+
};
|
|
682
817
|
if (section.idHandle !== INVALID_INDEX) {
|
|
683
|
-
|
|
818
|
+
set(section.idHandle, idText);
|
|
684
819
|
}
|
|
685
820
|
if (section.space !== null) {
|
|
686
|
-
|
|
687
|
-
|
|
821
|
+
set(this.idSpaceHandle, section.space);
|
|
822
|
+
set(this.originalIdHandle, idText);
|
|
688
823
|
}
|
|
689
824
|
if (labels !== undefined) {
|
|
690
|
-
|
|
825
|
+
set(this.labelsHandle, labels);
|
|
691
826
|
}
|
|
692
|
-
this.writeProperties("node", section.properties, index);
|
|
827
|
+
this.writeProperties("node", section.properties, index, line, idText);
|
|
693
828
|
this.reportPrecision(line, idText);
|
|
694
|
-
|
|
829
|
+
// a node a relationship created before its row (or an earlier row) is counted once
|
|
830
|
+
if (!existed) {
|
|
831
|
+
report.counts.nodes++;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Run one sink write, recording a refusal (a GraphFormatError) on the row's line instead of
|
|
836
|
+
* letting it escape the import.
|
|
837
|
+
* @param line - the row's line
|
|
838
|
+
* @param element - the row's element name
|
|
839
|
+
* @param write - the write
|
|
840
|
+
*/
|
|
841
|
+
guarded(line, element, write) {
|
|
842
|
+
try {
|
|
843
|
+
write();
|
|
844
|
+
}
|
|
845
|
+
catch (err) {
|
|
846
|
+
if (!(err instanceof GraphFormatError) || err instanceof ImportError) {
|
|
847
|
+
throw err;
|
|
848
|
+
}
|
|
849
|
+
this.report.recordError(err, { line, element });
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Report the relationship endpoints no node row declared (the shared W_DANGLING_REFERENCE,
|
|
854
|
+
* once) when the input has node rows: each became a node, where neo4j-admin refuses the
|
|
855
|
+
* relationship.
|
|
856
|
+
*/
|
|
857
|
+
reportDangling() {
|
|
858
|
+
const dangling = this.placeholders.filter((p) => this.registry.codeAt(p.index) === 0);
|
|
859
|
+
// without any node row, every node comes from the relationships (a relationships-only file)
|
|
860
|
+
if (dangling.length === 0 || !this.nodeRows) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const shown = dangling
|
|
864
|
+
.slice(0, 5)
|
|
865
|
+
.map((p) => String(p.id))
|
|
866
|
+
.join(", ");
|
|
867
|
+
this.report.warning("validation-error", DANGLING_REFERENCE_CODE, `${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)`, { element: String(dangling[0].id) });
|
|
695
868
|
}
|
|
696
869
|
/**
|
|
697
870
|
* Push one relationship row.
|
|
@@ -709,7 +882,7 @@ class Neo4jImportSession {
|
|
|
709
882
|
this.direction.setHeader(true, { line });
|
|
710
883
|
}
|
|
711
884
|
if (count !== section.width) {
|
|
712
|
-
report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell(
|
|
885
|
+
report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell${plural(count)} but the header has ${section.width}`, { line });
|
|
713
886
|
report.counts.skippedEdges++;
|
|
714
887
|
return;
|
|
715
888
|
}
|
|
@@ -747,7 +920,7 @@ class Neo4jImportSession {
|
|
|
747
920
|
let weight;
|
|
748
921
|
if (section.weightCell >= 0) {
|
|
749
922
|
try {
|
|
750
|
-
weight = parseWeightText(cells[section.weightCell]);
|
|
923
|
+
weight = parseWeightText(cells[section.weightCell], this.report);
|
|
751
924
|
}
|
|
752
925
|
catch (err) {
|
|
753
926
|
report.recordError(err, { line, element });
|
|
@@ -759,6 +932,7 @@ class Neo4jImportSession {
|
|
|
759
932
|
report.counts.skippedEdges++;
|
|
760
933
|
return;
|
|
761
934
|
}
|
|
935
|
+
const created = [source, target].filter((id, k) => (k === 0 || id !== source) && sink.indexOf(id) === INVALID_INDEX);
|
|
762
936
|
let edge;
|
|
763
937
|
try {
|
|
764
938
|
edge = this.direction.addEdge(source, target, "directed", weight, { line, element });
|
|
@@ -768,13 +942,23 @@ class Neo4jImportSession {
|
|
|
768
942
|
report.counts.skippedEdges++;
|
|
769
943
|
return;
|
|
770
944
|
}
|
|
945
|
+
for (const id of created) {
|
|
946
|
+
// a node no row declared yet: counted now; reported at the end unless a node row follows
|
|
947
|
+
report.counts.nodes++;
|
|
948
|
+
this.placeholders.push({ id, index: sink.indexOf(id) });
|
|
949
|
+
}
|
|
771
950
|
if (section.typeCell >= 0) {
|
|
772
951
|
const type = cells[section.typeCell];
|
|
773
952
|
if (type.length > 0) {
|
|
774
|
-
|
|
953
|
+
this.guarded(line, element, () => {
|
|
954
|
+
sink.setEdgeValue(this.typeHandle, edge, type);
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
report.warning("missing-value", MISSING_TYPE_CODE, "empty :TYPE cell; neo4j-admin requires a relationship type, the relationship is kept without one", { line, element });
|
|
775
959
|
}
|
|
776
960
|
}
|
|
777
|
-
this.writeProperties("edge", section.properties, edge);
|
|
961
|
+
this.writeProperties("edge", section.properties, edge, line, element);
|
|
778
962
|
this.reportPrecision(line, element);
|
|
779
963
|
report.counts.edges++;
|
|
780
964
|
}
|
|
@@ -831,6 +1015,7 @@ class Neo4jImportSession {
|
|
|
831
1015
|
parseProperties(slots, cells, quoted, line, element) {
|
|
832
1016
|
const { values, texts, precisionSlots } = this;
|
|
833
1017
|
precisionSlots.length = 0;
|
|
1018
|
+
this.overflows.length = 0;
|
|
834
1019
|
for (const slot of slots) {
|
|
835
1020
|
const text = cells[slot.cell];
|
|
836
1021
|
texts[slot.cell] = null;
|
|
@@ -841,18 +1026,24 @@ class Neo4jImportSession {
|
|
|
841
1026
|
const { spec } = slot;
|
|
842
1027
|
try {
|
|
843
1028
|
if (spec.temporal !== null && !spec.list) {
|
|
844
|
-
const
|
|
1029
|
+
const zoned = withZoneOffset(text, spec);
|
|
1030
|
+
const parsed = parseDeclaredTemporal(zoned, spec);
|
|
845
1031
|
values[slot.cell] = parsed.value;
|
|
846
|
-
|
|
1032
|
+
// a zone name is kept in the companion text, the value is its instant
|
|
1033
|
+
texts[slot.cell] = zoned === text ? parsed.text : text;
|
|
847
1034
|
}
|
|
848
1035
|
else {
|
|
849
1036
|
values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
|
|
1037
|
+
checkNeo4jRange(spec, values[slot.cell], text);
|
|
850
1038
|
}
|
|
851
1039
|
}
|
|
852
1040
|
catch (err) {
|
|
853
1041
|
this.report.recordError(err, { line, element: `${element} ${slot.name}` });
|
|
854
1042
|
return false;
|
|
855
1043
|
}
|
|
1044
|
+
if (overflows(spec, values[slot.cell], text)) {
|
|
1045
|
+
this.overflows.push(slot.name);
|
|
1046
|
+
}
|
|
856
1047
|
if (spec.precision && losesPrecision(spec, text)) {
|
|
857
1048
|
precisionSlots.push(slot);
|
|
858
1049
|
}
|
|
@@ -864,8 +1055,10 @@ class Neo4jImportSession {
|
|
|
864
1055
|
* @param domain - node or edge
|
|
865
1056
|
* @param slots - the section's property slots
|
|
866
1057
|
* @param row - the node or edge index
|
|
1058
|
+
* @param line - the row's line
|
|
1059
|
+
* @param element - the row's element name for issues
|
|
867
1060
|
*/
|
|
868
|
-
writeProperties(domain, slots, row) {
|
|
1061
|
+
writeProperties(domain, slots, row, line, element) {
|
|
869
1062
|
const { sink, values, texts } = this;
|
|
870
1063
|
for (const slot of slots) {
|
|
871
1064
|
const value = values[slot.cell];
|
|
@@ -873,21 +1066,24 @@ class Neo4jImportSession {
|
|
|
873
1066
|
continue;
|
|
874
1067
|
}
|
|
875
1068
|
const text = texts[slot.cell];
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
sink.setNodeValue(slot.handle, row, value);
|
|
881
|
-
if (text !== null) {
|
|
882
|
-
sink.setNodeValue(slot.companion, row, text);
|
|
1069
|
+
// a value the sink refuses is recorded on the row's line; the other properties are written
|
|
1070
|
+
this.guarded(line, `${element} ${slot.name}`, () => {
|
|
1071
|
+
if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
|
|
1072
|
+
slot.companion = declareCompanion(sink, domain, slot.companionDecl);
|
|
883
1073
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1074
|
+
if (domain === "node") {
|
|
1075
|
+
sink.setNodeValue(slot.handle, row, value);
|
|
1076
|
+
if (text !== null) {
|
|
1077
|
+
sink.setNodeValue(slot.companion, row, text);
|
|
1078
|
+
}
|
|
889
1079
|
}
|
|
890
|
-
|
|
1080
|
+
else {
|
|
1081
|
+
sink.setEdgeValue(slot.handle, row, value);
|
|
1082
|
+
if (text !== null) {
|
|
1083
|
+
sink.setEdgeValue(slot.companion, row, text);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
891
1087
|
}
|
|
892
1088
|
}
|
|
893
1089
|
/**
|
|
@@ -900,6 +1096,10 @@ class Neo4jImportSession {
|
|
|
900
1096
|
this.report.warning("precision", PRECISION_CODE, `long value of "${slot.name}" is beyond 2^53 and was stored as the nearest f64`, { line, element });
|
|
901
1097
|
}
|
|
902
1098
|
this.precisionSlots.length = 0;
|
|
1099
|
+
for (const name of this.overflows) {
|
|
1100
|
+
this.report.warning("precision", PRECISION_CODE, `the value of "${name}" is beyond the range of its float / double type and was stored as the nearest representable value`, { line, element });
|
|
1101
|
+
}
|
|
1102
|
+
this.overflows.length = 0;
|
|
903
1103
|
}
|
|
904
1104
|
/**
|
|
905
1105
|
* The labels of a node row: every `:LABEL` cell split by the array delimiter (empty items
|
|
@@ -944,6 +1144,147 @@ class Neo4jImportSession {
|
|
|
944
1144
|
function qualify(id, space) {
|
|
945
1145
|
return space === null ? id : `${space}:${String(id)}`;
|
|
946
1146
|
}
|
|
1147
|
+
/** The integer range of the narrow neo4j-admin types (Java byte and short). */
|
|
1148
|
+
const INTEGER_RANGES = {
|
|
1149
|
+
byte: [-128, 127],
|
|
1150
|
+
short: [-32768, 32767],
|
|
1151
|
+
};
|
|
1152
|
+
/**
|
|
1153
|
+
* A Cypher duration (ISO 8601): unit form `P14DT16H12M` / `PT0.75M` / `P2.5W` (components may be
|
|
1154
|
+
* signed or fractional) or the date-time form `P2012-02-02T14:37:21.545`.
|
|
1155
|
+
*/
|
|
1156
|
+
/**
|
|
1157
|
+
* Whether a text is a Cypher duration (ISO 8601): unit form `P14DT16H12M` / `PT0.75M` / `P2.5W`
|
|
1158
|
+
* (components may be signed or fractional) or the date-time form `P2012-02-02T14:37:21.545`.
|
|
1159
|
+
* @param text - the text, trimmed
|
|
1160
|
+
* @returns true when it is
|
|
1161
|
+
*/
|
|
1162
|
+
function isDuration(text) {
|
|
1163
|
+
if (DURATION_DATE_TIME.test(text)) {
|
|
1164
|
+
return true;
|
|
1165
|
+
}
|
|
1166
|
+
const m = /^[+-]?P([^T]*)(?:T(.*))?$/i.exec(text);
|
|
1167
|
+
if (m === null || m[2] === "" || (m[1] === "" && m[2] === undefined)) {
|
|
1168
|
+
return false;
|
|
1169
|
+
}
|
|
1170
|
+
return unitsInOrder(m[1], "YMWD") && unitsInOrder(m[2] ?? "", "HMS");
|
|
1171
|
+
}
|
|
1172
|
+
/** The date-time form of a Cypher duration, `P2012-02-02T14:37:21.545`. */
|
|
1173
|
+
const DURATION_DATE_TIME = /^[+-]?P\d{4}-?\d{2}-?\d{2}T\d{2}:?\d{2}:?\d{2}(?:\.\d+)?$/i;
|
|
1174
|
+
/**
|
|
1175
|
+
* Whether a run of duration components (`14D`, `-1.5H30M`) names its units in the order given,
|
|
1176
|
+
* each at most once.
|
|
1177
|
+
* @param text - the components
|
|
1178
|
+
* @param units - the unit letters in their order
|
|
1179
|
+
* @returns true when it does
|
|
1180
|
+
*/
|
|
1181
|
+
function unitsInOrder(text, units) {
|
|
1182
|
+
let rest = text.toUpperCase();
|
|
1183
|
+
let from = 0;
|
|
1184
|
+
while (rest !== "") {
|
|
1185
|
+
const m = /^[-+]?\d+(?:\.\d+)?([A-Z])/.exec(rest);
|
|
1186
|
+
const at = m === null ? -1 : units.indexOf(m[1], from);
|
|
1187
|
+
if (m === null || at < 0) {
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1190
|
+
from = at + 1;
|
|
1191
|
+
rest = rest.slice(m[0].length);
|
|
1192
|
+
}
|
|
1193
|
+
return true;
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Check the neo4j-admin types the shared parser maps to a wider dtype: byte and short values within
|
|
1197
|
+
* their Java range, a char of one character, a duration in Cypher's syntax.
|
|
1198
|
+
* @param spec - the declared type
|
|
1199
|
+
* @param value - the parsed value (a list of items for an array type)
|
|
1200
|
+
* @param text - the cell text, for the error
|
|
1201
|
+
*/
|
|
1202
|
+
function checkNeo4jRange(spec, value, text) {
|
|
1203
|
+
const base = spec.declared.trim().toLowerCase().replace(/\[\]$/, "");
|
|
1204
|
+
const items = spec.list && Array.isArray(value) ? value : [value];
|
|
1205
|
+
const range = INTEGER_RANGES[base];
|
|
1206
|
+
for (const item of items) {
|
|
1207
|
+
let bad = false;
|
|
1208
|
+
if (range !== undefined) {
|
|
1209
|
+
bad = typeof item === "number" && (item < range[0] || item > range[1]);
|
|
1210
|
+
}
|
|
1211
|
+
else if (base === "char") {
|
|
1212
|
+
// a Java char: one UTF-16 code unit
|
|
1213
|
+
bad = typeof item === "string" && item.length !== 1;
|
|
1214
|
+
}
|
|
1215
|
+
else if (base === "duration") {
|
|
1216
|
+
bad = typeof item === "string" && !isDuration(item.trim());
|
|
1217
|
+
}
|
|
1218
|
+
if (bad) {
|
|
1219
|
+
const span = range === undefined ? "" : ` (${range[0]} to ${range[1]})`;
|
|
1220
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not ${withArticle(base)}${span}`, {
|
|
1221
|
+
value: text,
|
|
1222
|
+
kind: base,
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
/** The largest finite f32. */
|
|
1228
|
+
const F32_MAX = 3.4028234663852886e38;
|
|
1229
|
+
/**
|
|
1230
|
+
* Whether a float / double cell overflowed: a finite literal read as an infinity, or a float beyond
|
|
1231
|
+
* the f32 range (Java's Double.parseDouble accepts both silently; the value changes).
|
|
1232
|
+
* @param spec - the declared type
|
|
1233
|
+
* @param value - the parsed value
|
|
1234
|
+
* @param text - the cell text
|
|
1235
|
+
* @returns true when the stored value is not the one written
|
|
1236
|
+
*/
|
|
1237
|
+
function overflows(spec, value, text) {
|
|
1238
|
+
if ((spec.kind !== "float" && spec.kind !== "double") || /inf|nan/i.test(text)) {
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
const items = spec.list && Array.isArray(value) ? value : [value];
|
|
1242
|
+
return items.some((v) => typeof v === "number" && (!Number.isFinite(v) || (spec.kind === "float" && Math.abs(v) > F32_MAX)));
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* A Cypher date-time with a zone name (`2020-01-01T00:00:00[Europe/Berlin]`) as one with a UTC
|
|
1246
|
+
* offset the temporal parser reads: the offset the text gives, else the zone's offset at that wall
|
|
1247
|
+
* time. Any other text is returned unchanged.
|
|
1248
|
+
* @param text - the cell text
|
|
1249
|
+
* @param spec - the declared type
|
|
1250
|
+
* @returns the text to parse
|
|
1251
|
+
*/
|
|
1252
|
+
function withZoneOffset(text, spec) {
|
|
1253
|
+
const trimmed = text.trim();
|
|
1254
|
+
const open = trimmed.lastIndexOf("[");
|
|
1255
|
+
if (spec.temporal !== "dateTime" || open < 0 || !trimmed.endsWith("]")) {
|
|
1256
|
+
return text;
|
|
1257
|
+
}
|
|
1258
|
+
const local = trimmed.slice(0, open);
|
|
1259
|
+
const zone = trimmed.slice(open + 1, -1);
|
|
1260
|
+
if (zone === "" || zone.includes("]") || /[\n\r\u2028\u2029]/.test(local)) {
|
|
1261
|
+
return text;
|
|
1262
|
+
}
|
|
1263
|
+
let format;
|
|
1264
|
+
try {
|
|
1265
|
+
format = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" });
|
|
1266
|
+
}
|
|
1267
|
+
catch {
|
|
1268
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" names an unknown time zone ${zone}`, { value: text });
|
|
1269
|
+
}
|
|
1270
|
+
if (/(Z|z|[+-]\d{2}(:?\d{2})?)$/.test(local)) {
|
|
1271
|
+
return local;
|
|
1272
|
+
}
|
|
1273
|
+
const wall = parseTemporal(local, "localDateTime").value;
|
|
1274
|
+
const offsetAt = (ms) => {
|
|
1275
|
+
const name = format.formatToParts(new Date(ms)).find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
1276
|
+
const o = /GMT([+-])(\d{2}):(\d{2})/.exec(name);
|
|
1277
|
+
if (o === null) {
|
|
1278
|
+
return 0;
|
|
1279
|
+
}
|
|
1280
|
+
return (o[1] === "-" ? -1 : 1) * (Number(o[2]) * 60 + Number(o[3]));
|
|
1281
|
+
};
|
|
1282
|
+
// the offset at the instant the wall time names (twice, so a wall time near a transition settles)
|
|
1283
|
+
const minutes = offsetAt(wall - offsetAt(wall) * 60000);
|
|
1284
|
+
const sign = minutes < 0 ? "-" : "+";
|
|
1285
|
+
const abs = Math.abs(minutes);
|
|
1286
|
+
return `${local}${sign}${String(Math.floor(abs / 60)).padStart(2, "0")}:${String(abs % 60).padStart(2, "0")}`;
|
|
1287
|
+
}
|
|
947
1288
|
/**
|
|
948
1289
|
* The value of a quoted empty cell: an empty string for a string-kind property, an empty list for
|
|
949
1290
|
* a list property, unset for anything else (neo4j-admin's default `--ignore-empty-strings=false`).
|
|
@@ -996,9 +1337,13 @@ function sniffNeo4j(head) {
|
|
|
996
1337
|
const cells = first.split(/[,;|\t]/);
|
|
997
1338
|
return isHeaderRecord(cells, cells.length) ? 0.95 : 0;
|
|
998
1339
|
}
|
|
999
|
-
/**
|
|
1340
|
+
/**
|
|
1341
|
+
* The Neo4j importer.
|
|
1342
|
+
* @category Built-in formats
|
|
1343
|
+
*/
|
|
1000
1344
|
export const neo4jImporter = Object.freeze({
|
|
1001
1345
|
format: NEO4J,
|
|
1346
|
+
options: Object.freeze(["arrayDelimiter", "delimiter", "nodes", "quote", "relationships"]),
|
|
1002
1347
|
extensions: Object.freeze([".csv", ".tsv"]),
|
|
1003
1348
|
mimeTypes: Object.freeze(["text/csv", "text/tab-separated-values"]),
|
|
1004
1349
|
sniff: sniffNeo4j,
|
|
@@ -1018,7 +1363,14 @@ export const neo4jImporter = Object.freeze({
|
|
|
1018
1363
|
// column and every relationship is directed
|
|
1019
1364
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
1020
1365
|
const session = new Neo4jImportSession(sink, report, common, format);
|
|
1021
|
-
await session.run([
|
|
1366
|
+
await session.run([
|
|
1367
|
+
{ input, kind: null },
|
|
1368
|
+
...format.nodes.map((file) => ({ input: file, kind: "node" })),
|
|
1369
|
+
...format.relationships.map((file) => ({ input: file, kind: "relationship" })),
|
|
1370
|
+
]);
|
|
1371
|
+
if (session.weightProperty !== null) {
|
|
1372
|
+
sink.setMeta({ extra: { neo4j: { weightProperty: session.weightProperty } } });
|
|
1373
|
+
}
|
|
1022
1374
|
throwIfAborted(common.signal);
|
|
1023
1375
|
return report.finish();
|
|
1024
1376
|
},
|