@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
|
@@ -17,38 +17,59 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { GraphFormatError, INVALID_INDEX, } from "@graphty/graph-format";
|
|
19
19
|
import { declareResolved, RENAMED_CODE, ROLE_TAKEN_CODE, uniqueColumnName } from "../../common/attributes.js";
|
|
20
|
-
import {
|
|
20
|
+
import { importChosenGraph } from "../../common/choose.js";
|
|
21
|
+
import { AMBIGUOUS_GRAPH_NAME_CODE, DUPLICATE_ATTRIBUTE_CODE, DUPLICATE_NODE_CODE, ELEMENT_ISSUE, ENCODING_FALLBACK_CODE, GRAPH_NOT_FOUND_CODE, INPUT_ISSUE, INVALID_ENCODING_CODE, INVALID_UTF8_CODE, MULTIPLE_GRAPHS_CODE, OPTION_IGNORED_CODE, PRECISION_CODE, SYNTAX_CODE, UNKNOWN_ENCODING_CODE, } from "../../common/codes.js";
|
|
21
22
|
import { DirectionResolver } from "../../common/direction.js";
|
|
23
|
+
import { survivesF32 } from "../../common/format.js";
|
|
22
24
|
import { coerceIdText, ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
|
|
23
25
|
import { LineReader, throwIfAborted } from "../../common/input.js";
|
|
24
|
-
import { reportSinkOptions, reportUnusedOptions, resolveImportOptions, SINK_OPTION_CODE, } from "../../common/options.js";
|
|
26
|
+
import { graphChosen, reportSinkOptions, reportUnusedOptions, resolveImportOptions, SINK_OPTION_CODE, } from "../../common/options.js";
|
|
27
|
+
import { agree, plural } from "../../common/plural.js";
|
|
25
28
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
26
29
|
import { isNumericText, TextCellWriter, WIDENING_UNSUPPORTED_CODE } from "../../common/text.js";
|
|
27
30
|
import { isWeightField, parseWeightText } from "../../common/weights.js";
|
|
28
|
-
import { decodeCharacterReferences, isCommentOrBlank, isIntervalToken, isSectionLine, isShapeKeyword, isVertexNumber, LABEL_COLUMN, ORIGINAL_ID_KEY, parseIntervals, parseSectionHeader, PARTITION_COLUMN, POSITION_COLUMN, RELATION_COLUMN, SHAPE_COLUMN, SPELLS_COLUMN, tokenize, VALUE_COLUMN, VALUE_FIELD, VECTOR_COLUMN, } from "./syntax.js";
|
|
29
|
-
/**
|
|
31
|
+
import { decodeCharacterReferences, isCommentOrBlank, isIntervalToken, isProjectObject, isSectionLine, isShapeKeyword, isVertexNumber, LABEL_COLUMN, ORIGINAL_ID_KEY, parseIntervals, parseSectionHeader, PARTITION_COLUMN, POSITION_COLUMN, RELATION_COLUMN, SHAPE_COLUMN, SPELLS_COLUMN, tokenize, VALUE_COLUMN, VALUE_FIELD, VECTOR_COLUMN, } from "./syntax.js";
|
|
32
|
+
/**
|
|
33
|
+
* Issue codes of the Pajek importer.
|
|
34
|
+
* @category Built-in formats
|
|
35
|
+
*/
|
|
30
36
|
export const PAJEK_ISSUE = Object.freeze({
|
|
31
|
-
|
|
37
|
+
...INPUT_ISSUE,
|
|
38
|
+
...ELEMENT_ISSUE,
|
|
39
|
+
/** The input is not valid UTF-8. The import stops. */
|
|
32
40
|
INVALID_UTF8: INVALID_UTF8_CODE,
|
|
33
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
|
|
43
|
+
* `encoding` option). The import stops.
|
|
44
|
+
*/
|
|
34
45
|
INVALID_ENCODING: INVALID_ENCODING_CODE,
|
|
35
46
|
/** Bytes that are not UTF-8 and declare no encoding were read as windows-1252. */
|
|
36
47
|
ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
|
|
37
48
|
/** A declared encoding the platform cannot decode was ignored. */
|
|
38
49
|
UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
|
|
39
|
-
/**
|
|
50
|
+
/** There is no `*Vertices` section: the file is empty or not a Pajek network. The import stops. */
|
|
40
51
|
NO_VERTICES: "E_PAJEK_NO_VERTICES",
|
|
41
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* `*Vertices` without a vertex count, with a count too large to hold, or with a first-mode count outside 0 to N;
|
|
54
|
+
* the import stops.
|
|
55
|
+
*/
|
|
42
56
|
VERTICES_COUNT: "E_PAJEK_VERTICES_COUNT",
|
|
43
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* The file holds several graphs and only the first was read. It is not added when `graphIndex` or `graphName` chose the graph.
|
|
59
|
+
* `importAllGraphs()` reads every one.
|
|
60
|
+
*/
|
|
44
61
|
MULTIPLE_GRAPHS: MULTIPLE_GRAPHS_CODE,
|
|
62
|
+
/** `graphIndex` or `graphName` names no graph of the file; the message lists the graphs it holds. The import stops. */
|
|
63
|
+
GRAPH_NOT_FOUND: GRAPH_NOT_FOUND_CODE,
|
|
64
|
+
/** `graphName` matches more than one graph; pass `graphIndex`. The import stops. */
|
|
65
|
+
AMBIGUOUS_GRAPH_NAME: AMBIGUOUS_GRAPH_NAME_CODE,
|
|
45
66
|
/** A data line before the first section header. */
|
|
46
67
|
OUTSIDE_SECTION: "E_PAJEK_OUTSIDE_SECTION",
|
|
47
68
|
/** A section header the importer cannot parse. */
|
|
48
69
|
SYNTAX: SYNTAX_CODE,
|
|
49
70
|
/** A double quote not closed before the end of the line. */
|
|
50
71
|
UNTERMINATED_QUOTE: "E_PAJEK_UNTERMINATED_QUOTE",
|
|
51
|
-
/** A vertex line the
|
|
72
|
+
/** A vertex line that is not in Pajek's vertex syntax; the vertex is skipped. */
|
|
52
73
|
VERTEX_LINE: "E_PAJEK_VERTEX_LINE",
|
|
53
74
|
/** A vertex number outside the declared range. */
|
|
54
75
|
VERTEX_RANGE: "E_PAJEK_VERTEX_RANGE",
|
|
@@ -56,9 +77,12 @@ export const PAJEK_ISSUE = Object.freeze({
|
|
|
56
77
|
VERTEX_COUNT: "W_PAJEK_VERTEX_COUNT",
|
|
57
78
|
/** A second line for the same vertex; the later values overwrite. */
|
|
58
79
|
DUPLICATE_NODE: DUPLICATE_NODE_CODE,
|
|
59
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* A line that is not in Pajek's syntax for its section (an arc, edge, list, matrix row, partition or vector
|
|
82
|
+
* value); it is skipped.
|
|
83
|
+
*/
|
|
60
84
|
LINE: "E_PAJEK_LINE",
|
|
61
|
-
/**
|
|
85
|
+
/** An edge names a vertex number outside the range `*Vertices` declared; the edge is skipped. */
|
|
62
86
|
UNKNOWN_NODE: "E_UNKNOWN_NODE",
|
|
63
87
|
/** A malformed time interval token. */
|
|
64
88
|
INTERVAL: "E_PAJEK_INTERVAL",
|
|
@@ -70,32 +94,57 @@ export const PAJEK_ISSUE = Object.freeze({
|
|
|
70
94
|
OBJECT_COUNT: "E_PAJEK_OBJECT_COUNT",
|
|
71
95
|
/** A project-file section (`*Events`, `*Permutation`, ...) the importer does not read; its lines are skipped. */
|
|
72
96
|
UNSUPPORTED_SECTION: "W_PAJEK_UNSUPPORTED_SECTION",
|
|
73
|
-
/**
|
|
97
|
+
/** A section header has extra words Pajek does not define; they are ignored. */
|
|
74
98
|
HEADER_EXTRA: "W_PAJEK_HEADER_EXTRA",
|
|
75
99
|
/** The file declares vertices but no line section. */
|
|
76
100
|
NO_LINES: "W_PAJEK_NO_LINES",
|
|
77
|
-
/** Vertex numbering starts at 0 rather than 1. */
|
|
101
|
+
/** Vertex numbering starts at 0 rather than 1, found by `firstVertex: "auto"` (passing `firstVertex: 0` says so and gives no warning). */
|
|
78
102
|
ZERO_BASED: "W_PAJEK_ZERO_BASED",
|
|
79
103
|
/** Vertex lines mix two and three coordinates. */
|
|
80
104
|
COORD_DIMS: "W_PAJEK_COORD_DIMS",
|
|
81
105
|
/** Two vertices share a label under nodeIdFrom "label" and became one node. */
|
|
82
106
|
LABEL_MERGED: "W_PAJEK_LABEL_MERGED",
|
|
83
|
-
/** Two
|
|
107
|
+
/** Two different labels became the same number because `ids` is "number", so their vertices were merged. */
|
|
84
108
|
ID_MERGED: ID_MERGED_CODE,
|
|
85
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* Your graph builder cannot change an attribute's type after its first value, so a text column keeps the type of
|
|
111
|
+
* its first values.
|
|
112
|
+
*/
|
|
86
113
|
WIDENING_UNSUPPORTED: WIDENING_UNSUPPORTED_CODE,
|
|
87
|
-
/** A structural column (label, position, shape, spells, relation) renamed `<name>#<id>` because the name was taken
|
|
114
|
+
/** A structural column (label, position, shape, spells, relation) renamed `<name>#<id>` because the name was taken. */
|
|
88
115
|
COLUMN_RENAMED: RENAMED_CODE,
|
|
89
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
|
|
118
|
+
* a plain attribute.
|
|
119
|
+
*/
|
|
90
120
|
ROLE_TAKEN: ROLE_TAKEN_CODE,
|
|
91
121
|
/** Two vertices carry the same `graphty_originalId` under restoreMangledIds and became one node. */
|
|
92
122
|
ORIGINAL_ID_MERGED: "W_PAJEK_ORIGINAL_ID_MERGED",
|
|
93
123
|
/** A vertex line's `graphty_originalId` came after a later vertex's line had created it under its number. */
|
|
94
124
|
ORIGINAL_ID_UNRESTORED: "W_PAJEK_ORIGINAL_ID_UNRESTORED",
|
|
95
|
-
/**
|
|
125
|
+
/** You set an option this format does not use; it had no effect. The message names the option. */
|
|
96
126
|
OPTION_IGNORED: OPTION_IGNORED_CODE,
|
|
97
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
|
|
129
|
+
* `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
|
|
130
|
+
*/
|
|
98
131
|
SINK_OPTION: SINK_OPTION_CODE,
|
|
132
|
+
/** A double quote inside a token (a CSV-style doubled quote, a quote mid-word): removed and the parts joined. */
|
|
133
|
+
QUOTE_IN_TOKEN: "W_PAJEK_QUOTE_IN_TOKEN",
|
|
134
|
+
/** The same parameter twice on one line; the later value stands. */
|
|
135
|
+
DUPLICATE_ATTRIBUTE: DUPLICATE_ATTRIBUTE_CODE,
|
|
136
|
+
/** A character reference beyond U+10FFFF in a label; kept as written. */
|
|
137
|
+
REFERENCE_RANGE: "W_PAJEK_REFERENCE_RANGE",
|
|
138
|
+
/** A line of a two-mode network whose endpoints are both in one mode. */
|
|
139
|
+
TWO_MODE_LINE: "W_PAJEK_TWO_MODE_LINE",
|
|
140
|
+
/** A bare non-integer number read as a vertex label before two coordinates (`1 0.1 0.2 0.3`); it may be an x y z line without a label. */
|
|
141
|
+
NUMERIC_LABEL: "W_PAJEK_NUMERIC_LABEL",
|
|
142
|
+
/** A relation number given a second name by a later `*Arcs :k "name"` header. */
|
|
143
|
+
RELATION_RENAMED: "W_PAJEK_RELATION_RENAMED",
|
|
144
|
+
/** A negative vertex number in an adjacency list, read as its absolute value. */
|
|
145
|
+
NEGATIVE_LIST_ENTRY: "W_PAJEK_NEGATIVE_LIST_ENTRY",
|
|
146
|
+
/** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
|
|
147
|
+
PRECISION: PRECISION_CODE,
|
|
99
148
|
});
|
|
100
149
|
/** The common options the Pajek importer reads (the rest is reported by reportUnusedOptions). */
|
|
101
150
|
const USED_OPTIONS = new Set([
|
|
@@ -117,6 +166,9 @@ const DEFAULTS = { ids: "canonical", defaultDirected: true, weightFrom: VALUE_FI
|
|
|
117
166
|
/** Lines between two checks of the cancellation signal (a whole string input is one chunk). */
|
|
118
167
|
const ABORT_CHECK_INTERVAL = 64;
|
|
119
168
|
const FIRST_VERTEX_VALUES = new Set([0, 1, "auto"]);
|
|
169
|
+
/** A numeral that is not a finite number (`1e999`, `NaN`, `Infinity`): never a parameter key. */
|
|
170
|
+
const NUMERAL = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
171
|
+
const NON_FINITE_WORD = /^[+-]?(?:nan|inf|infinity)$/i;
|
|
120
172
|
const LABEL_DECL = {
|
|
121
173
|
name: LABEL_COLUMN,
|
|
122
174
|
dtype: "string",
|
|
@@ -214,6 +266,8 @@ class PajekParser {
|
|
|
214
266
|
this.relation = null;
|
|
215
267
|
/** `*Vertices N`; -1 before the header. */
|
|
216
268
|
this.vertexCount = -1;
|
|
269
|
+
/** The line of the `*Vertices` header. */
|
|
270
|
+
this.verticesLine = 0;
|
|
217
271
|
/** The first-mode count of a two-mode network, or null. */
|
|
218
272
|
this.firstMode = null;
|
|
219
273
|
this.networkName = null;
|
|
@@ -232,6 +286,10 @@ class PajekParser {
|
|
|
232
286
|
this.objects = [];
|
|
233
287
|
/** Set when the previous line was a project-object header, whose `*Vertices N` line comes next. */
|
|
234
288
|
this.objectHeader = false;
|
|
289
|
+
/** The first unsupported section keyword, for the message of a file without `*Vertices`. */
|
|
290
|
+
this.firstUnsupported = null;
|
|
291
|
+
/** Vertex lines skipped because their number is outside the declared range (not lines of declared vertices). */
|
|
292
|
+
this.outOfRange = 0;
|
|
235
293
|
/** Node index per vertex position (vertex number minus base). */
|
|
236
294
|
this.indexOfPos = new Uint32Array(0);
|
|
237
295
|
/**
|
|
@@ -302,7 +360,7 @@ class PajekParser {
|
|
|
302
360
|
this.matrixLine(text, line);
|
|
303
361
|
return false;
|
|
304
362
|
case "object":
|
|
305
|
-
this.objectLine(text);
|
|
363
|
+
this.objectLine(text, line);
|
|
306
364
|
return false;
|
|
307
365
|
case "skip":
|
|
308
366
|
return false;
|
|
@@ -327,7 +385,10 @@ class PajekParser {
|
|
|
327
385
|
*/
|
|
328
386
|
finish() {
|
|
329
387
|
if (this.vertexCount < 0) {
|
|
330
|
-
|
|
388
|
+
const seen = this.firstUnsupported === null
|
|
389
|
+
? ""
|
|
390
|
+
: ` (the file has the unrecognised section *${this.firstUnsupported})`;
|
|
391
|
+
this.report.fail(PAJEK_ISSUE.NO_VERTICES, `not a Pajek network: no *Vertices section found${seen}`);
|
|
331
392
|
}
|
|
332
393
|
this.endSection();
|
|
333
394
|
this.finishVertices();
|
|
@@ -341,7 +402,7 @@ class PajekParser {
|
|
|
341
402
|
}
|
|
342
403
|
const objects = this.writeObjects();
|
|
343
404
|
if (this.coercer.mergeCount > 0) {
|
|
344
|
-
this.report.warning("coercion", PAJEK_ISSUE.ID_MERGED, `${this.coercer.mergeCount} label(
|
|
405
|
+
this.report.warning("coercion", PAJEK_ISSUE.ID_MERGED, `${this.coercer.mergeCount} label${plural(this.coercer.mergeCount)} merged into an id another label already produced under ids "number"`);
|
|
345
406
|
}
|
|
346
407
|
const pajek = {
|
|
347
408
|
...(this.firstMode === null ? {} : { firstMode: this.firstMode }),
|
|
@@ -383,7 +444,7 @@ class PajekParser {
|
|
|
383
444
|
}
|
|
384
445
|
const declared = object.count ?? object.values.length;
|
|
385
446
|
if (declared !== this.vertexCount || object.values.length !== declared) {
|
|
386
|
-
this.report.error("validation-error", PAJEK_ISSUE.OBJECT_COUNT, `*${partition ? "Partition" : "Vector"} "${object.name}" declares ${declared} vertices and holds ${object.values.length} value(
|
|
447
|
+
this.report.error("validation-error", PAJEK_ISSUE.OBJECT_COUNT, `*${partition ? "Partition" : "Vector"} "${object.name}" declares ${declared} vertices and holds ${object.values.length} value${plural(object.values.length)}; the network has ${this.vertexCount}`, where);
|
|
387
448
|
}
|
|
388
449
|
written.push({ kind: object.kind, name: object.name, column: decl.name });
|
|
389
450
|
}
|
|
@@ -405,7 +466,7 @@ class PajekParser {
|
|
|
405
466
|
throw new LineError("parse-error", PAJEK_ISSUE.SYNTAX, `cannot read the section header "${text}"`);
|
|
406
467
|
}
|
|
407
468
|
if (h.extra.length > 0) {
|
|
408
|
-
this.report.warning("validation-error", PAJEK_ISSUE.HEADER_EXTRA, `ignored ${h.extra.length} unexpected token(
|
|
469
|
+
this.report.warning("validation-error", PAJEK_ISSUE.HEADER_EXTRA, `ignored ${h.extra.length} unexpected token${plural(h.extra.length)} after *${h.keyword}: ${h.extra.join(" ")}`, { line });
|
|
409
470
|
}
|
|
410
471
|
switch (h.kind) {
|
|
411
472
|
case "network":
|
|
@@ -453,7 +514,9 @@ class PajekParser {
|
|
|
453
514
|
return;
|
|
454
515
|
case "unsupported":
|
|
455
516
|
this.section = "skip";
|
|
456
|
-
|
|
517
|
+
// only a project object's next line is its own `*Vertices N`
|
|
518
|
+
this.objectHeader = isProjectObject(h.keyword);
|
|
519
|
+
this.firstUnsupported ?? (this.firstUnsupported = h.keyword);
|
|
457
520
|
this.report.warning("unsupported", PAJEK_ISSUE.UNSUPPORTED_SECTION, `the *${h.keyword} section is not supported; its lines are skipped`, { line });
|
|
458
521
|
return;
|
|
459
522
|
default: {
|
|
@@ -478,8 +541,9 @@ class PajekParser {
|
|
|
478
541
|
this.report.fail(PAJEK_ISSUE.VERTICES_COUNT, `*Vertices ${h.count} ${h.secondCount}: the first-mode count is not within 0..${h.count}`, { line });
|
|
479
542
|
}
|
|
480
543
|
try {
|
|
481
|
-
// the declared count must be reservable (the sink is the authority on what it can hold
|
|
482
|
-
//
|
|
544
|
+
// the declared count must be reservable (the sink is the authority on what it can hold;
|
|
545
|
+
// the builder refuses more than its id map holds with E_TOO_LARGE) before any vertex
|
|
546
|
+
// or per-vertex table is allocated
|
|
483
547
|
this.sink.reserve(h.count);
|
|
484
548
|
}
|
|
485
549
|
catch (err) {
|
|
@@ -489,6 +553,7 @@ class PajekParser {
|
|
|
489
553
|
});
|
|
490
554
|
}
|
|
491
555
|
this.vertexCount = h.count;
|
|
556
|
+
this.verticesLine = line;
|
|
492
557
|
if (h.secondCount !== null) {
|
|
493
558
|
this.firstMode = h.secondCount;
|
|
494
559
|
}
|
|
@@ -525,7 +590,12 @@ class PajekParser {
|
|
|
525
590
|
this.kind = kind;
|
|
526
591
|
this.relation = h.relation === null ? null : (h.name ?? String(h.relation));
|
|
527
592
|
if (h.relation !== null) {
|
|
528
|
-
|
|
593
|
+
const name = this.relation ?? String(h.relation);
|
|
594
|
+
const before = this.relationNames.get(h.relation);
|
|
595
|
+
if (before !== undefined && before !== name) {
|
|
596
|
+
this.report.warning("validation-error", PAJEK_ISSUE.RELATION_RENAMED, `relation ${h.relation} was named ${JSON.stringify(before)} and is now named ${JSON.stringify(name)}; its lines carry the name of their own section`, { line, element: String(h.relation) });
|
|
597
|
+
}
|
|
598
|
+
this.relationNames.set(h.relation, name);
|
|
529
599
|
}
|
|
530
600
|
}
|
|
531
601
|
/**
|
|
@@ -534,7 +604,7 @@ class PajekParser {
|
|
|
534
604
|
endSection() {
|
|
535
605
|
const rows = this.firstMode ?? this.vertexCount;
|
|
536
606
|
if (this.section === "matrix" && this.matrixRows !== rows) {
|
|
537
|
-
this.report.error("validation-error", PAJEK_ISSUE.MATRIX_ROWS, `*Matrix has ${this.matrixRows} row(
|
|
607
|
+
this.report.error("validation-error", PAJEK_ISSUE.MATRIX_ROWS, `*Matrix has ${this.matrixRows} row${plural(this.matrixRows)}; *Vertices declares ${rows}`);
|
|
538
608
|
}
|
|
539
609
|
this.section = "none";
|
|
540
610
|
}
|
|
@@ -548,7 +618,8 @@ class PajekParser {
|
|
|
548
618
|
setBase(base, line) {
|
|
549
619
|
this.base = base;
|
|
550
620
|
this.baseKnown = true;
|
|
551
|
-
|
|
621
|
+
// the caller who passed firstVertex: 0 knows the numbering; the warning is for a guess
|
|
622
|
+
if (base === 0 && this.firstVertex === "auto") {
|
|
552
623
|
this.report.warning("coercion", PAJEK_ISSUE.ZERO_BASED, "vertex numbering starts at 0; Pajek numbers vertices from 1", { line });
|
|
553
624
|
}
|
|
554
625
|
}
|
|
@@ -563,12 +634,29 @@ class PajekParser {
|
|
|
563
634
|
}
|
|
564
635
|
this.nodesCreated = true;
|
|
565
636
|
const n = this.vertexCount;
|
|
566
|
-
const { sink } = this;
|
|
567
637
|
for (let pos = 0; pos < n; pos++) {
|
|
568
|
-
this.indexOfPos[pos] =
|
|
638
|
+
this.indexOfPos[pos] = this.addNode(this.idOfNumber(pos + this.base));
|
|
569
639
|
}
|
|
570
640
|
this.report.counts.nodes += n;
|
|
571
641
|
}
|
|
642
|
+
/**
|
|
643
|
+
* Add a vertex to the sink. A sink that cannot hold the declared vertex set (the builder's
|
|
644
|
+
* E_TOO_LARGE id map limit) makes the file unreadable, so its refusal is fatal; any other
|
|
645
|
+
* error passes to the caller.
|
|
646
|
+
* @param id - the vertex id
|
|
647
|
+
* @returns the node index
|
|
648
|
+
*/
|
|
649
|
+
addNode(id) {
|
|
650
|
+
try {
|
|
651
|
+
return this.sink.addNode(id);
|
|
652
|
+
}
|
|
653
|
+
catch (err) {
|
|
654
|
+
if (!(err instanceof GraphFormatError) || err.code !== "E_TOO_LARGE") {
|
|
655
|
+
throw err;
|
|
656
|
+
}
|
|
657
|
+
return this.report.fail(PAJEK_ISSUE.VERTICES_COUNT, `*Vertices ${this.vertexCount}: the sink cannot hold that many (${err.message})`, { line: this.verticesLine });
|
|
658
|
+
}
|
|
659
|
+
}
|
|
572
660
|
/**
|
|
573
661
|
* The id of a vertex number under nodeIdFrom "id" (the number coerced by the ids rule) or
|
|
574
662
|
* "index" (the position).
|
|
@@ -624,9 +712,9 @@ class PajekParser {
|
|
|
624
712
|
}
|
|
625
713
|
}
|
|
626
714
|
// a partial list: fewer lines than declared, counting the lines skipped after an error
|
|
627
|
-
const lines = this.seenCount + this.report.counts.skippedNodes;
|
|
715
|
+
const lines = this.seenCount + this.report.counts.skippedNodes - this.outOfRange;
|
|
628
716
|
if (this.seenCount > 0 && lines < n) {
|
|
629
|
-
this.report.warning("validation-error", PAJEK_ISSUE.VERTEX_COUNT, `*Vertices declares ${n} vertices but ${lines} vertex line(
|
|
717
|
+
this.report.warning("validation-error", PAJEK_ISSUE.VERTEX_COUNT, `*Vertices declares ${n} vertices but ${lines} vertex line${plural(lines)} ${agree(lines, "was", "were")} read; the others have no label`);
|
|
630
718
|
}
|
|
631
719
|
}
|
|
632
720
|
/**
|
|
@@ -635,7 +723,7 @@ class PajekParser {
|
|
|
635
723
|
* @param line - the line number
|
|
636
724
|
*/
|
|
637
725
|
vertexLine(text, line) {
|
|
638
|
-
const tokens = this.tokens(text, "node");
|
|
726
|
+
const tokens = this.tokens(text, "node", line);
|
|
639
727
|
if (!isVertexNumber(tokens[0])) {
|
|
640
728
|
this.report.counts.skippedNodes++;
|
|
641
729
|
throw new LineError("parse-error", PAJEK_ISSUE.VERTEX_LINE, `a vertex line starts with a vertex number, not "${tokens[0]}"`);
|
|
@@ -647,13 +735,14 @@ class PajekParser {
|
|
|
647
735
|
const pos = k - this.base;
|
|
648
736
|
if (pos < 0 || pos >= this.vertexCount) {
|
|
649
737
|
this.report.counts.skippedNodes++;
|
|
738
|
+
this.outOfRange++;
|
|
650
739
|
throw new LineError("validation-error", PAJEK_ISSUE.VERTEX_RANGE, `vertex ${k} is outside ${this.base}..${this.base + this.vertexCount - 1}`);
|
|
651
740
|
}
|
|
652
741
|
// parse everything before writing anything
|
|
653
742
|
let i = 1;
|
|
654
743
|
let label = null;
|
|
655
744
|
if (tokens.length > 1 && !startsWithCoordinates(text, tokens)) {
|
|
656
|
-
label =
|
|
745
|
+
label = this.labelOf(tokens[1], k, line);
|
|
657
746
|
i = 2;
|
|
658
747
|
}
|
|
659
748
|
let x = 0;
|
|
@@ -675,12 +764,13 @@ class PajekParser {
|
|
|
675
764
|
this.report.counts.skippedNodes++;
|
|
676
765
|
throw new LineError("parse-error", PAJEK_ISSUE.VERTEX_LINE, `vertex ${k}: a single coordinate "${tokens[i]}"; coordinates are x y [z]`);
|
|
677
766
|
}
|
|
767
|
+
this.checkCoordinates(text, tokens, i, dims === 2 && label !== null, k, line);
|
|
678
768
|
let shape = null;
|
|
679
769
|
if (i < tokens.length && isShapeKeyword(tokens[i])) {
|
|
680
770
|
shape = tokens[i].toLowerCase();
|
|
681
771
|
i++;
|
|
682
772
|
}
|
|
683
|
-
const extras = this.extras(tokens, i, "node");
|
|
773
|
+
const extras = this.extras(tokens, i, "node", line);
|
|
684
774
|
const restored = this.restoredId(extras);
|
|
685
775
|
this.createNodes();
|
|
686
776
|
// write
|
|
@@ -727,14 +817,7 @@ class PajekParser {
|
|
|
727
817
|
sink.setNodeValue(this.labelHandle, index, label);
|
|
728
818
|
}
|
|
729
819
|
if (dims > 0) {
|
|
730
|
-
|
|
731
|
-
this.coordDims = dims;
|
|
732
|
-
this.positionHandle = declareResolved(sink, "node", positionDecl(dims), this.report, { line }).handle;
|
|
733
|
-
}
|
|
734
|
-
else if (dims !== this.coordDims) {
|
|
735
|
-
this.report.warnOnce("validation-error", PAJEK_ISSUE.COORD_DIMS, `vertex lines mix ${this.coordDims} and ${dims} coordinates; the position column records sourceDims ${this.coordDims}`, { line, element: String(k) });
|
|
736
|
-
}
|
|
737
|
-
sink.setNodeValue(this.positionHandle, index, [x, y, z]);
|
|
820
|
+
this.writePosition(index, dims, [x, y, z], k, line);
|
|
738
821
|
}
|
|
739
822
|
if (shape !== null) {
|
|
740
823
|
if (this.shapeHandle === INVALID_INDEX && this.nodeParams.has(SHAPE_COLUMN)) {
|
|
@@ -758,6 +841,65 @@ class PajekParser {
|
|
|
758
841
|
sink.setNodeValue(this.nodeSpellsHandle, index, extras.spells);
|
|
759
842
|
}
|
|
760
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* A vertex label as written, its character references decoded.
|
|
846
|
+
* @param token - the label token
|
|
847
|
+
* @param k - the vertex number
|
|
848
|
+
* @param line - the line number
|
|
849
|
+
* @returns the label
|
|
850
|
+
*/
|
|
851
|
+
labelOf(token, k, line) {
|
|
852
|
+
return decodeCharacterReferences(token, (reference) => {
|
|
853
|
+
this.report.warnOnce("validation-error", PAJEK_ISSUE.REFERENCE_RANGE, `character reference ${reference} is beyond U+10FFFF; it is kept as written`, { line, element: String(k) }, `${PAJEK_ISSUE.REFERENCE_RANGE}:${reference}`);
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Check the token after a vertex line's coordinates (or where they would stand): a numeral the
|
|
858
|
+
* number range cannot hold is a broken coordinate, never a parameter named "1e999" or "NaN";
|
|
859
|
+
* and a bare non-integer label before two coordinates may be the x of an x y z line.
|
|
860
|
+
* @param text - the line
|
|
861
|
+
* @param tokens - its tokens
|
|
862
|
+
* @param i - the index after the coordinates
|
|
863
|
+
* @param labelAndXy - whether the line was read as a label and two coordinates
|
|
864
|
+
* @param k - the vertex number
|
|
865
|
+
* @param line - the line number
|
|
866
|
+
*/
|
|
867
|
+
checkCoordinates(text, tokens, i, labelAndXy, k, line) {
|
|
868
|
+
if (i < tokens.length &&
|
|
869
|
+
(NUMERAL.test(tokens[i]) || NON_FINITE_WORD.test(tokens[i])) &&
|
|
870
|
+
!isNumericText(tokens[i])) {
|
|
871
|
+
this.report.counts.skippedNodes++;
|
|
872
|
+
throw new LineError("parse-error", PAJEK_ISSUE.VERTEX_LINE, `vertex ${k}: coordinate "${tokens[i]}" is not a finite number`);
|
|
873
|
+
}
|
|
874
|
+
const label = tokens[1];
|
|
875
|
+
if (labelAndXy &&
|
|
876
|
+
isNumericText(label) &&
|
|
877
|
+
!Number.isInteger(Number(label)) &&
|
|
878
|
+
!quotedAfterNumber(text, tokens)) {
|
|
879
|
+
this.report.warnOnce("validation-error", PAJEK_ISSUE.NUMERIC_LABEL, `vertex ${k}: "${label} ${tokens[2]} ${tokens[3]}" is read as the label ${label} and x y; quote the label, or it may be meant as x y z`, { line, element: String(k) });
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Write a vertex's coordinates into the position column (f32 x 3), declared on first use.
|
|
884
|
+
* @param index - the node index
|
|
885
|
+
* @param dims - 2 or 3, the coordinates the line gave
|
|
886
|
+
* @param point - x, y, z (0 when absent)
|
|
887
|
+
* @param k - the vertex number
|
|
888
|
+
* @param line - the line number
|
|
889
|
+
*/
|
|
890
|
+
writePosition(index, dims, point, k, line) {
|
|
891
|
+
if (this.positionHandle === INVALID_INDEX) {
|
|
892
|
+
this.coordDims = dims;
|
|
893
|
+
this.positionHandle = declareResolved(this.sink, "node", positionDecl(dims), this.report, { line }).handle;
|
|
894
|
+
}
|
|
895
|
+
else if (dims !== this.coordDims) {
|
|
896
|
+
this.report.warnOnce("validation-error", PAJEK_ISSUE.COORD_DIMS, `vertex lines mix ${this.coordDims} and ${dims} coordinates; the position column records sourceDims ${this.coordDims}`, { line, element: String(k) });
|
|
897
|
+
}
|
|
898
|
+
if (!point.every(survivesF32)) {
|
|
899
|
+
this.report.warnOnce("precision", PAJEK_ISSUE.PRECISION, `vertex ${k} has a coordinate the f32 position column rounds (warned once)`, { line, element: String(k) }, `${PAJEK_ISSUE.PRECISION}:position`);
|
|
900
|
+
}
|
|
901
|
+
this.sink.setNodeValue(this.positionHandle, index, point);
|
|
902
|
+
}
|
|
761
903
|
/**
|
|
762
904
|
* Whether a `graphty_originalId` parameter is restored as the vertex id: restoreMangledIds
|
|
763
905
|
* under nodeIdFrom "id" (under "label" / "index" the parameter stays an ordinary column).
|
|
@@ -775,7 +917,7 @@ class PajekParser {
|
|
|
775
917
|
numberedNode(ids, pos) {
|
|
776
918
|
const id = this.idOfNumber(pos + this.base);
|
|
777
919
|
ids[pos] = id;
|
|
778
|
-
this.indexOfPos[pos] = this.
|
|
920
|
+
this.indexOfPos[pos] = this.addNode(id);
|
|
779
921
|
this.report.counts.nodes++;
|
|
780
922
|
}
|
|
781
923
|
/**
|
|
@@ -812,7 +954,7 @@ class PajekParser {
|
|
|
812
954
|
deferredNode(ids, pos, k, text, line, from) {
|
|
813
955
|
const id = text === null ? this.idOfNumber(k) : this.coercer.text(text);
|
|
814
956
|
const before = this.sink.indexOf(id);
|
|
815
|
-
const index = this.
|
|
957
|
+
const index = this.addNode(id);
|
|
816
958
|
ids[pos] = id;
|
|
817
959
|
this.indexOfPos[pos] = index;
|
|
818
960
|
this.report.counts.nodes++;
|
|
@@ -830,7 +972,7 @@ class PajekParser {
|
|
|
830
972
|
* @param line - the line number
|
|
831
973
|
*/
|
|
832
974
|
edgeLine(text, line) {
|
|
833
|
-
let tokens = this.tokens(text, "edge");
|
|
975
|
+
let tokens = this.tokens(text, "edge", line);
|
|
834
976
|
// a `k:` prefix puts this one line in relation k
|
|
835
977
|
let { relation } = this;
|
|
836
978
|
const prefix = RELATION_PREFIX.exec(tokens[0]);
|
|
@@ -851,7 +993,7 @@ class PajekParser {
|
|
|
851
993
|
valueText = tokens[i];
|
|
852
994
|
i++;
|
|
853
995
|
}
|
|
854
|
-
const extras = this.extras(tokens, i, "edge");
|
|
996
|
+
const extras = this.extras(tokens, i, "edge", line);
|
|
855
997
|
const { weightFrom } = this.options;
|
|
856
998
|
let weight;
|
|
857
999
|
let valueIsWeight = false;
|
|
@@ -883,13 +1025,16 @@ class PajekParser {
|
|
|
883
1025
|
* @param line - the line number
|
|
884
1026
|
*/
|
|
885
1027
|
listLine(text, line) {
|
|
886
|
-
const tokens = this.tokens(text, "edge");
|
|
1028
|
+
const tokens = this.tokens(text, "edge", line);
|
|
887
1029
|
for (const token of tokens) {
|
|
888
1030
|
if (!LIST_VERTEX.test(token)) {
|
|
889
1031
|
this.report.counts.skippedEdges++;
|
|
890
1032
|
throw new LineError("parse-error", PAJEK_ISSUE.LINE, `an adjacency list holds vertex numbers only, not "${token}"`);
|
|
891
1033
|
}
|
|
892
1034
|
}
|
|
1035
|
+
if (tokens.some((token) => token.startsWith("-"))) {
|
|
1036
|
+
this.report.warnOnce("coercion", PAJEK_ISSUE.NEGATIVE_LIST_ENTRY, "an adjacency list holds a negative vertex number; it is read as its absolute value and the sign is dropped", { line });
|
|
1037
|
+
}
|
|
893
1038
|
const u = this.endpoint(Math.abs(Number(tokens[0])));
|
|
894
1039
|
for (let i = 1; i < tokens.length; i++) {
|
|
895
1040
|
const v = this.endpoint(Math.abs(Number(tokens[i])));
|
|
@@ -905,17 +1050,17 @@ class PajekParser {
|
|
|
905
1050
|
* @param line - the line number
|
|
906
1051
|
*/
|
|
907
1052
|
matrixLine(text, line) {
|
|
908
|
-
const tokens = this.tokens(text, "edge");
|
|
1053
|
+
const tokens = this.tokens(text, "edge", line);
|
|
909
1054
|
const row = this.matrixRows;
|
|
910
1055
|
this.matrixRows++;
|
|
911
1056
|
const offset = this.firstMode ?? 0;
|
|
912
1057
|
const rows = this.firstMode ?? this.vertexCount;
|
|
913
1058
|
const columns = this.vertexCount - offset;
|
|
914
1059
|
if (row >= rows) {
|
|
915
|
-
throw new LineError("validation-error", PAJEK_ISSUE.MATRIX_ROWS, `*Matrix row ${row + 1} is beyond the ${rows} declared row(
|
|
1060
|
+
throw new LineError("validation-error", PAJEK_ISSUE.MATRIX_ROWS, `*Matrix row ${row + 1} is beyond the ${rows} declared row${plural(rows)}`);
|
|
916
1061
|
}
|
|
917
1062
|
if (tokens.length < columns) {
|
|
918
|
-
throw new LineError("parse-error", PAJEK_ISSUE.LINE, `*Matrix row ${row + 1} has ${tokens.length} value(
|
|
1063
|
+
throw new LineError("parse-error", PAJEK_ISSUE.LINE, `*Matrix row ${row + 1} has ${tokens.length} value${plural(tokens.length)}; the matrix has ${columns} column${plural(columns)}`);
|
|
919
1064
|
}
|
|
920
1065
|
for (let j = 0; j < columns; j++) {
|
|
921
1066
|
if (!isNumericText(tokens[j])) {
|
|
@@ -923,7 +1068,7 @@ class PajekParser {
|
|
|
923
1068
|
}
|
|
924
1069
|
}
|
|
925
1070
|
if (tokens.length > columns) {
|
|
926
|
-
this.report.warnOnce("validation-error", PAJEK_ISSUE.MATRIX_EXTRA, `*Matrix row ${row + 1} has ${tokens.length} value(
|
|
1071
|
+
this.report.warnOnce("validation-error", PAJEK_ISSUE.MATRIX_EXTRA, `*Matrix row ${row + 1} has ${tokens.length} value${plural(tokens.length)} for ${columns} column${plural(columns)}; the extra values are ignored`, { line });
|
|
927
1072
|
}
|
|
928
1073
|
for (let j = 0; j < columns; j++) {
|
|
929
1074
|
const value = Number(tokens[j]);
|
|
@@ -938,10 +1083,11 @@ class PajekParser {
|
|
|
938
1083
|
* A value line of a `*Partition` (integers) or `*Vector` (numbers): the values of the next
|
|
939
1084
|
* vertices, usually one per line.
|
|
940
1085
|
* @param text - the line
|
|
1086
|
+
* @param line - the line number
|
|
941
1087
|
*/
|
|
942
|
-
objectLine(text) {
|
|
1088
|
+
objectLine(text, line) {
|
|
943
1089
|
const object = this.objects[this.objects.length - 1];
|
|
944
|
-
const tokens = this.tokens(text, "node");
|
|
1090
|
+
const tokens = this.tokens(text, "node", line);
|
|
945
1091
|
for (const token of tokens) {
|
|
946
1092
|
if (!isNumericText(token) || (object.kind === "partition" && !isI32(Number(token)))) {
|
|
947
1093
|
// keep the later values on their vertices
|
|
@@ -967,6 +1113,9 @@ class PajekParser {
|
|
|
967
1113
|
this.directionSet = true;
|
|
968
1114
|
this.resolver.setHeader(this.kind === "directed", { line });
|
|
969
1115
|
}
|
|
1116
|
+
if (this.firstMode !== null && u < this.firstMode === v < this.firstMode) {
|
|
1117
|
+
this.report.warnOnce("validation-error", PAJEK_ISSUE.TWO_MODE_LINE, `a line of the two-mode network joins two vertices of the ${u < this.firstMode ? "first" : "second"} mode`, { line });
|
|
1118
|
+
}
|
|
970
1119
|
const before = sink.edgeCount;
|
|
971
1120
|
const e = this.resolver.addEdge(this.idAt(u), this.idAt(v), this.kind, weight, { line });
|
|
972
1121
|
this.report.counts.edges += sink.edgeCount - before;
|
|
@@ -1027,7 +1176,7 @@ class PajekParser {
|
|
|
1027
1176
|
*/
|
|
1028
1177
|
weightOf(text) {
|
|
1029
1178
|
try {
|
|
1030
|
-
return parseWeightText(text);
|
|
1179
|
+
return parseWeightText(text, this.report);
|
|
1031
1180
|
}
|
|
1032
1181
|
catch (err) {
|
|
1033
1182
|
this.report.counts.skippedEdges++;
|
|
@@ -1039,10 +1188,15 @@ class PajekParser {
|
|
|
1039
1188
|
* Tokenize a data line.
|
|
1040
1189
|
* @param text - the line
|
|
1041
1190
|
* @param domain - what is skipped on an unterminated quote
|
|
1191
|
+
* @param line - the line number
|
|
1042
1192
|
* @returns the tokens (at least one: blank lines never reach here)
|
|
1043
1193
|
*/
|
|
1044
|
-
tokens(text, domain) {
|
|
1045
|
-
const
|
|
1194
|
+
tokens(text, domain, line) {
|
|
1195
|
+
const notes = { oddQuote: false };
|
|
1196
|
+
const tokens = tokenize(text, notes);
|
|
1197
|
+
if (notes.oddQuote) {
|
|
1198
|
+
this.report.warnOnce("coercion", PAJEK_ISSUE.QUOTE_IN_TOKEN, "a double quote inside a token is removed and the parts joined (Pajek has no escape for a quote)", { line });
|
|
1199
|
+
}
|
|
1046
1200
|
if (tokens === null) {
|
|
1047
1201
|
if (domain === "node") {
|
|
1048
1202
|
this.report.counts.skippedNodes++;
|
|
@@ -1060,22 +1214,16 @@ class PajekParser {
|
|
|
1060
1214
|
* @param tokens - the row's tokens
|
|
1061
1215
|
* @param start - the first token to read
|
|
1062
1216
|
* @param domain - what is skipped when the row is malformed
|
|
1217
|
+
* @param line - the line number
|
|
1063
1218
|
* @returns the parsed extras
|
|
1064
1219
|
*/
|
|
1065
|
-
extras(tokens, start, domain) {
|
|
1220
|
+
extras(tokens, start, domain, line) {
|
|
1066
1221
|
const extras = { keys: [], values: [], spells: null };
|
|
1222
|
+
const seen = new Set();
|
|
1067
1223
|
for (let i = start; i < tokens.length;) {
|
|
1068
1224
|
const token = tokens[i];
|
|
1069
|
-
if (
|
|
1070
|
-
|
|
1071
|
-
const spells = parseIntervals(token);
|
|
1072
|
-
// an empty `[]` is no spell at all
|
|
1073
|
-
extras.spells = spells.length === 0 ? null : spells;
|
|
1074
|
-
}
|
|
1075
|
-
catch (err) {
|
|
1076
|
-
this.skip(domain);
|
|
1077
|
-
throw new LineError("validation-error", PAJEK_ISSUE.INTERVAL, err instanceof Error ? err.message : String(err));
|
|
1078
|
-
}
|
|
1225
|
+
if (token.startsWith("[")) {
|
|
1226
|
+
extras.spells = this.intervals(token, domain);
|
|
1079
1227
|
i++;
|
|
1080
1228
|
continue;
|
|
1081
1229
|
}
|
|
@@ -1083,12 +1231,36 @@ class PajekParser {
|
|
|
1083
1231
|
this.skip(domain);
|
|
1084
1232
|
throw new LineError("parse-error", domain === "node" ? PAJEK_ISSUE.VERTEX_LINE : PAJEK_ISSUE.LINE, `parameter "${token}" has no value`);
|
|
1085
1233
|
}
|
|
1234
|
+
if (seen.has(token)) {
|
|
1235
|
+
this.report.warning("merged", PAJEK_ISSUE.DUPLICATE_ATTRIBUTE, `parameter ${JSON.stringify(token)} is given twice on one line; the later value ${JSON.stringify(tokens[i + 1])} stands`, { line, element: token });
|
|
1236
|
+
}
|
|
1237
|
+
seen.add(token);
|
|
1086
1238
|
extras.keys.push(token);
|
|
1087
1239
|
extras.values.push(tokens[i + 1]);
|
|
1088
1240
|
i += 2;
|
|
1089
1241
|
}
|
|
1090
1242
|
return extras;
|
|
1091
1243
|
}
|
|
1244
|
+
/**
|
|
1245
|
+
* The spells of a row's interval token; a malformed one skips the row.
|
|
1246
|
+
* @param token - the token, starting with "["
|
|
1247
|
+
* @param domain - what is skipped when the token is malformed
|
|
1248
|
+
* @returns the spells, or null for an empty `[]`, which is no spell at all
|
|
1249
|
+
*/
|
|
1250
|
+
intervals(token, domain) {
|
|
1251
|
+
if (!isIntervalToken(token)) {
|
|
1252
|
+
this.skip(domain);
|
|
1253
|
+
throw new LineError("validation-error", PAJEK_ISSUE.INTERVAL, `time interval ${token} is not closed by "]"`);
|
|
1254
|
+
}
|
|
1255
|
+
try {
|
|
1256
|
+
const spells = parseIntervals(token);
|
|
1257
|
+
return spells.length === 0 ? null : spells;
|
|
1258
|
+
}
|
|
1259
|
+
catch (err) {
|
|
1260
|
+
this.skip(domain);
|
|
1261
|
+
throw new LineError("validation-error", PAJEK_ISSUE.INTERVAL, err instanceof Error ? err.message : String(err));
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1092
1264
|
/**
|
|
1093
1265
|
* Count a skipped element.
|
|
1094
1266
|
* @param domain - node or edge
|
|
@@ -1135,7 +1307,7 @@ class PajekParser {
|
|
|
1135
1307
|
* @returns true when tokens[1] is the first coordinate
|
|
1136
1308
|
*/
|
|
1137
1309
|
function startsWithCoordinates(text, tokens) {
|
|
1138
|
-
if (text
|
|
1310
|
+
if (quotedAfterNumber(text, tokens)) {
|
|
1139
1311
|
return false;
|
|
1140
1312
|
}
|
|
1141
1313
|
let run = 0;
|
|
@@ -1144,6 +1316,15 @@ function startsWithCoordinates(text, tokens) {
|
|
|
1144
1316
|
}
|
|
1145
1317
|
return run === 2;
|
|
1146
1318
|
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Whether the token after a row's vertex number is written in quotes.
|
|
1321
|
+
* @param text - the line
|
|
1322
|
+
* @param tokens - its tokens
|
|
1323
|
+
* @returns true when the second token was quoted
|
|
1324
|
+
*/
|
|
1325
|
+
function quotedAfterNumber(text, tokens) {
|
|
1326
|
+
return text.trimStart().slice(tokens[0].length).trimStart().startsWith('"');
|
|
1327
|
+
}
|
|
1147
1328
|
/**
|
|
1148
1329
|
* Resolve the firstVertex option.
|
|
1149
1330
|
* @param value - the caller's value
|
|
@@ -1161,24 +1342,41 @@ function firstVertexOption(value) {
|
|
|
1161
1342
|
found: value,
|
|
1162
1343
|
});
|
|
1163
1344
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1345
|
+
/**
|
|
1346
|
+
* The section a Pajek network starts with, after blank lines and `%` comment lines.
|
|
1347
|
+
* @param text - the head of the input
|
|
1348
|
+
* @returns "vertices" or "network" (lower case), or null when the text starts otherwise
|
|
1349
|
+
*/
|
|
1350
|
+
function headSection(text) {
|
|
1351
|
+
let rest = text.trimStart();
|
|
1352
|
+
while (rest.startsWith("%")) {
|
|
1353
|
+
const end = rest.search(/[\r\n]/);
|
|
1354
|
+
rest = end < 0 ? "" : rest.slice(end).trimStart();
|
|
1355
|
+
}
|
|
1356
|
+
return /^\*(vertices|network)\b/i.exec(rest)?.[1].toLowerCase() ?? null;
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* The Pajek NET importer.
|
|
1360
|
+
* @category Built-in formats
|
|
1361
|
+
*/
|
|
1166
1362
|
export const pajekImporter = Object.freeze({
|
|
1167
1363
|
format: "pajek",
|
|
1364
|
+
options: Object.freeze(["firstVertex"]),
|
|
1168
1365
|
extensions: Object.freeze([".net", ".paj"]),
|
|
1169
1366
|
mimeTypes: Object.freeze(["text/x-pajek", "text/plain"]),
|
|
1170
1367
|
/**
|
|
1171
|
-
* Confidence that the input is a Pajek network: it starts with `*Vertices` (or `*Network`)
|
|
1368
|
+
* Confidence that the input is a Pajek network: it starts with `*Vertices` (or `*Network`),
|
|
1369
|
+
* after any `%` comment lines.
|
|
1172
1370
|
* @param head - the first bytes
|
|
1173
1371
|
* @returns 0.9 for a `*Vertices` start, 0.8 for `*Network`, 0 otherwise
|
|
1174
1372
|
*/
|
|
1175
1373
|
sniff(head) {
|
|
1176
|
-
const text = new TextDecoder("utf-8").decode(head
|
|
1177
|
-
const
|
|
1178
|
-
if (
|
|
1374
|
+
const text = new TextDecoder("utf-8").decode(head);
|
|
1375
|
+
const section = headSection(text.startsWith("\ufeff") ? text.slice(1) : text);
|
|
1376
|
+
if (section === null) {
|
|
1179
1377
|
return 0;
|
|
1180
1378
|
}
|
|
1181
|
-
return
|
|
1379
|
+
return section === "vertices" ? 0.9 : 0.8;
|
|
1182
1380
|
},
|
|
1183
1381
|
/**
|
|
1184
1382
|
* Read a Pajek network into the sink.
|
|
@@ -1188,6 +1386,10 @@ export const pajekImporter = Object.freeze({
|
|
|
1188
1386
|
* @returns the report
|
|
1189
1387
|
*/
|
|
1190
1388
|
async import(input, sink, options) {
|
|
1389
|
+
if (graphChosen(options)) {
|
|
1390
|
+
// the choice is honored here too, not only by the registry
|
|
1391
|
+
return importChosenGraph(pajekImporter, input, sink, options);
|
|
1392
|
+
}
|
|
1191
1393
|
const resolved = resolveImportOptions(options, DEFAULTS);
|
|
1192
1394
|
const firstVertex = firstVertexOption(options?.firstVertex);
|
|
1193
1395
|
const report = new ImportReportBuilder("pajek", resolved.errorLimit);
|
|
@@ -1199,7 +1401,8 @@ export const pajekImporter = Object.freeze({
|
|
|
1199
1401
|
let rest = null;
|
|
1200
1402
|
let restLine = 0;
|
|
1201
1403
|
let sinceCheck = 0;
|
|
1202
|
-
for await (const
|
|
1404
|
+
for await (const raw of reader) {
|
|
1405
|
+
const text = withoutStrayBom(raw);
|
|
1203
1406
|
if (rest !== null) {
|
|
1204
1407
|
rest.line(text);
|
|
1205
1408
|
}
|
|
@@ -1215,7 +1418,8 @@ export const pajekImporter = Object.freeze({
|
|
|
1215
1418
|
}
|
|
1216
1419
|
parser.finish();
|
|
1217
1420
|
if (rest !== null) {
|
|
1218
|
-
|
|
1421
|
+
const objects = rest.objects > 0 ? `; ${rest.objects} *Partition / *Vector object(s) after them are not read` : "";
|
|
1422
|
+
report.warning("unsupported", PAJEK_ISSUE.MULTIPLE_GRAPHS, `the project file holds ${rest.count} more network${plural(rest.count)} after the first; the first is read (graphIndex or graphName chooses another; importAllGraphs() reads every one)${objects}`, { line: restLine });
|
|
1219
1423
|
}
|
|
1220
1424
|
throwIfAborted(resolved.signal);
|
|
1221
1425
|
return report.finish();
|
|
@@ -1244,7 +1448,8 @@ export const pajekImporter = Object.freeze({
|
|
|
1244
1448
|
// decoding issues belong to the file, so they go to the first network's report
|
|
1245
1449
|
const reader = new LineReader(input, reports[0], resolved);
|
|
1246
1450
|
let sinceCheck = 0;
|
|
1247
|
-
for await (const
|
|
1451
|
+
for await (const raw of reader) {
|
|
1452
|
+
const text = withoutStrayBom(raw);
|
|
1248
1453
|
if (parser.line(text, reader.line)) {
|
|
1249
1454
|
parser.finish();
|
|
1250
1455
|
reports.push(new ImportReportBuilder("pajek", resolved.errorLimit));
|
|
@@ -1261,6 +1466,15 @@ export const pajekImporter = Object.freeze({
|
|
|
1261
1466
|
return reports.map((r) => r.finish());
|
|
1262
1467
|
},
|
|
1263
1468
|
});
|
|
1469
|
+
/**
|
|
1470
|
+
* A line without the U+FEFF that starts it: a BOM left at the start of a later line by
|
|
1471
|
+
* concatenated files (the decoder removes only the first; the shared text check reports it).
|
|
1472
|
+
* @param text - the line
|
|
1473
|
+
* @returns the line without a leading U+FEFF
|
|
1474
|
+
*/
|
|
1475
|
+
function withoutStrayBom(text) {
|
|
1476
|
+
return text.codePointAt(0) === 0xfeff ? text.slice(1) : text;
|
|
1477
|
+
}
|
|
1264
1478
|
/**
|
|
1265
1479
|
* Counts the networks of the rest of a project file by their headers alone, with the parser's
|
|
1266
1480
|
* rule: a network starts at `*Network` after a named or populated one, or at a `*Vertices` after a
|
|
@@ -1271,6 +1485,8 @@ class NetworkCounter {
|
|
|
1271
1485
|
constructor() {
|
|
1272
1486
|
/** Networks started so far (the first header fed opens the first). */
|
|
1273
1487
|
this.count = 0;
|
|
1488
|
+
/** `*Partition` / `*Vector` objects seen; import() does not read them. */
|
|
1489
|
+
this.objects = 0;
|
|
1274
1490
|
this.named = false;
|
|
1275
1491
|
this.populated = false;
|
|
1276
1492
|
this.afterObjectHeader = false;
|
|
@@ -1293,8 +1509,12 @@ class NetworkCounter {
|
|
|
1293
1509
|
return;
|
|
1294
1510
|
}
|
|
1295
1511
|
const { kind } = h;
|
|
1296
|
-
if (kind === "partition" || kind === "vector"
|
|
1512
|
+
if (kind === "partition" || kind === "vector") {
|
|
1297
1513
|
this.afterObjectHeader = true;
|
|
1514
|
+
this.objects++;
|
|
1515
|
+
}
|
|
1516
|
+
else if (kind === "unsupported") {
|
|
1517
|
+
this.afterObjectHeader = isProjectObject(h.keyword);
|
|
1298
1518
|
}
|
|
1299
1519
|
else if (kind === "network") {
|
|
1300
1520
|
if (this.count === 0 || this.named || this.populated) {
|