@graphty/graph-io 0.3.25 → 0.3.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -414
- package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
- package/dist/chunks/choose-DrXtu_96.js +56 -0
- package/dist/chunks/choose-DrXtu_96.js.map +1 -0
- package/dist/chunks/constants-ikG85dT8.js +231 -0
- package/dist/chunks/constants-ikG85dT8.js.map +1 -0
- package/dist/chunks/{escape-B-tkk_Cl.js → escape-D1HPTUrP.js} +390 -99
- package/dist/chunks/escape-D1HPTUrP.js.map +1 -0
- package/dist/chunks/export-CHd4tQE2.js +4333 -0
- package/dist/chunks/export-CHd4tQE2.js.map +1 -0
- package/dist/chunks/{importer-eUREhBGj.js → exporter-D23CKNqF.js} +4969 -3201
- package/dist/chunks/exporter-D23CKNqF.js.map +1 -0
- package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-DfWTgrti.js} +23 -21
- package/dist/chunks/exporter-DfWTgrti.js.map +1 -0
- package/dist/chunks/exporter-DhtW6FxK.js +3465 -0
- package/dist/chunks/exporter-DhtW6FxK.js.map +1 -0
- package/dist/chunks/{exporter-BGrsWamJ.js → exporter-IHv4nkCm.js} +38 -229
- package/dist/chunks/exporter-IHv4nkCm.js.map +1 -0
- package/dist/chunks/{importer-BWY2FFc5.js → importer-B1wmPQjr.js} +255 -77
- package/dist/chunks/importer-B1wmPQjr.js.map +1 -0
- package/dist/chunks/{importer-D_e7e7LX.js → importer-B2W_58pz.js} +399 -146
- package/dist/chunks/importer-B2W_58pz.js.map +1 -0
- package/dist/chunks/importer-BSALvkui.js +2811 -0
- package/dist/chunks/importer-BSALvkui.js.map +1 -0
- package/dist/chunks/{importer-vi3bSdtw.js → importer-BVRE--Un.js} +510 -77
- package/dist/chunks/importer-BVRE--Un.js.map +1 -0
- package/dist/chunks/{importer-DET1tg6s.js → importer-CIAzt-wo.js} +1689 -312
- package/dist/chunks/importer-CIAzt-wo.js.map +1 -0
- package/dist/chunks/{importer-DIrbbnAf.js → importer-DpEW5zeG.js} +585 -226
- package/dist/chunks/importer-DpEW5zeG.js.map +1 -0
- package/dist/chunks/{importer-zGLo8Dg_.js → importer-z_FL4VMb.js} +488 -161
- package/dist/chunks/importer-z_FL4VMb.js.map +1 -0
- package/dist/chunks/json-elements-BAmNBZok.js +1225 -0
- package/dist/chunks/json-elements-BAmNBZok.js.map +1 -0
- package/dist/chunks/ontology-export-Bab4eUA8.js +357 -0
- package/dist/chunks/ontology-export-Bab4eUA8.js.map +1 -0
- package/dist/chunks/{records-dbRkxwaq.js → records-CdlvL4RO.js} +298 -114
- package/dist/chunks/records-CdlvL4RO.js.map +1 -0
- package/dist/chunks/{text-Dr0Ifpag.js → text-DzXjAiTl.js} +29 -11
- package/dist/chunks/text-DzXjAiTl.js.map +1 -0
- package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
- package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
- package/dist/csv.js +952 -262
- package/dist/csv.js.map +1 -1
- package/dist/cx.js +6 -3
- package/dist/cx2.js +2 -2
- package/dist/cys.js +6 -3
- package/dist/dot.js +1 -1
- package/dist/gexf.js +554 -122
- package/dist/gexf.js.map +1 -1
- package/dist/gml.js +344 -87
- package/dist/gml.js.map +1 -1
- package/dist/graph-io.js +1105 -213
- package/dist/graph-io.js.map +1 -1
- package/dist/graphml.js +3 -2
- package/dist/graphml.js.map +1 -1
- package/dist/json.js +3 -2
- package/dist/neo4j.js +565 -158
- package/dist/neo4j.js.map +1 -1
- package/dist/obo.js +6 -3
- package/dist/pajek.js +1 -1
- package/dist/src/children.d.ts +18 -6
- package/dist/src/children.d.ts.map +1 -1
- package/dist/src/children.js +6 -3
- package/dist/src/children.js.map +1 -1
- package/dist/src/common/attributes.d.ts +29 -11
- package/dist/src/common/attributes.d.ts.map +1 -1
- package/dist/src/common/attributes.js +25 -7
- package/dist/src/common/attributes.js.map +1 -1
- package/dist/src/common/cell-budget.d.ts +9 -2
- package/dist/src/common/cell-budget.d.ts.map +1 -1
- package/dist/src/common/cell-budget.js +11 -3
- package/dist/src/common/cell-budget.js.map +1 -1
- package/dist/src/common/choose.d.ts +19 -0
- package/dist/src/common/choose.d.ts.map +1 -0
- package/dist/src/common/choose.js +72 -0
- package/dist/src/common/choose.js.map +1 -0
- package/dist/src/common/codes.d.ts +456 -66
- package/dist/src/common/codes.d.ts.map +1 -1
- package/dist/src/common/codes.js +458 -66
- package/dist/src/common/codes.js.map +1 -1
- package/dist/src/common/compare.d.ts +81 -0
- package/dist/src/common/compare.d.ts.map +1 -0
- package/dist/src/common/compare.js +394 -0
- package/dist/src/common/compare.js.map +1 -0
- package/dist/src/common/cx-export.d.ts +123 -0
- package/dist/src/common/cx-export.d.ts.map +1 -0
- package/dist/src/common/cx-export.js +334 -0
- package/dist/src/common/cx-export.js.map +1 -0
- package/dist/src/common/declared-types.d.ts +22 -2
- package/dist/src/common/declared-types.d.ts.map +1 -1
- package/dist/src/common/declared-types.js +21 -3
- package/dist/src/common/declared-types.js.map +1 -1
- package/dist/src/common/direction.d.ts +74 -50
- package/dist/src/common/direction.d.ts.map +1 -1
- package/dist/src/common/direction.js +47 -27
- package/dist/src/common/direction.js.map +1 -1
- package/dist/src/common/escape.d.ts +21 -9
- package/dist/src/common/escape.d.ts.map +1 -1
- package/dist/src/common/escape.js +39 -22
- package/dist/src/common/escape.js.map +1 -1
- package/dist/src/common/export.d.ts +144 -32
- package/dist/src/common/export.d.ts.map +1 -1
- package/dist/src/common/export.js +216 -42
- package/dist/src/common/export.js.map +1 -1
- package/dist/src/common/format.d.ts +23 -1
- package/dist/src/common/format.d.ts.map +1 -1
- package/dist/src/common/format.js +26 -1
- package/dist/src/common/format.js.map +1 -1
- package/dist/src/common/ids.d.ts +9 -2
- package/dist/src/common/ids.d.ts.map +1 -1
- package/dist/src/common/ids.js +6 -2
- package/dist/src/common/ids.js.map +1 -1
- package/dist/src/common/input.d.ts +122 -28
- package/dist/src/common/input.d.ts.map +1 -1
- package/dist/src/common/input.js +890 -124
- package/dist/src/common/input.js.map +1 -1
- package/dist/src/common/json-elements.d.ts +144 -20
- package/dist/src/common/json-elements.d.ts.map +1 -1
- package/dist/src/common/json-elements.js +869 -189
- package/dist/src/common/json-elements.js.map +1 -1
- package/dist/src/common/line-format.d.ts +90 -0
- package/dist/src/common/line-format.d.ts.map +1 -0
- package/dist/src/common/line-format.js +185 -0
- package/dist/src/common/line-format.js.map +1 -0
- package/dist/src/common/lists.d.ts +6 -1
- package/dist/src/common/lists.d.ts.map +1 -1
- package/dist/src/common/lists.js +3 -1
- package/dist/src/common/lists.js.map +1 -1
- package/dist/src/common/ontology-export.d.ts +167 -0
- package/dist/src/common/ontology-export.d.ts.map +1 -0
- package/dist/src/common/ontology-export.js +359 -0
- package/dist/src/common/ontology-export.js.map +1 -0
- package/dist/src/common/ontology.d.ts +25 -3
- package/dist/src/common/ontology.d.ts.map +1 -1
- package/dist/src/common/ontology.js +30 -9
- package/dist/src/common/ontology.js.map +1 -1
- package/dist/src/common/options.d.ts +62 -12
- package/dist/src/common/options.d.ts.map +1 -1
- package/dist/src/common/options.js +89 -11
- package/dist/src/common/options.js.map +1 -1
- package/dist/src/common/plural.d.ts +31 -0
- package/dist/src/common/plural.d.ts.map +1 -0
- package/dist/src/common/plural.js +46 -0
- package/dist/src/common/plural.js.map +1 -0
- package/dist/src/common/report.d.ts +72 -14
- package/dist/src/common/report.d.ts.map +1 -1
- package/dist/src/common/report.js +146 -22
- package/dist/src/common/report.js.map +1 -1
- package/dist/src/common/temporal.d.ts +22 -5
- package/dist/src/common/temporal.d.ts.map +1 -1
- package/dist/src/common/temporal.js +13 -2
- package/dist/src/common/temporal.js.map +1 -1
- package/dist/src/common/text.d.ts +39 -23
- package/dist/src/common/text.d.ts.map +1 -1
- package/dist/src/common/text.js +51 -21
- package/dist/src/common/text.js.map +1 -1
- package/dist/src/common/weights.d.ts +37 -4
- package/dist/src/common/weights.d.ts.map +1 -1
- package/dist/src/common/weights.js +61 -2
- package/dist/src/common/weights.js.map +1 -1
- package/dist/src/common/writer.d.ts +19 -3
- package/dist/src/common/writer.d.ts.map +1 -1
- package/dist/src/common/writer.js +30 -2
- package/dist/src/common/writer.js.map +1 -1
- package/dist/src/common/xml.d.ts +125 -9
- package/dist/src/common/xml.d.ts.map +1 -1
- package/dist/src/common/xml.js +402 -85
- package/dist/src/common/xml.js.map +1 -1
- package/dist/src/common/zip.d.ts +44 -4
- package/dist/src/common/zip.d.ts.map +1 -1
- package/dist/src/common/zip.js +134 -5
- package/dist/src/common/zip.js.map +1 -1
- package/dist/src/formats/csv/exporter.d.ts +80 -24
- package/dist/src/formats/csv/exporter.d.ts.map +1 -1
- package/dist/src/formats/csv/exporter.js +146 -33
- package/dist/src/formats/csv/exporter.js.map +1 -1
- package/dist/src/formats/csv/header.d.ts +38 -9
- package/dist/src/formats/csv/header.d.ts.map +1 -1
- package/dist/src/formats/csv/header.js +46 -10
- package/dist/src/formats/csv/header.js.map +1 -1
- package/dist/src/formats/csv/importer.d.ts +187 -37
- package/dist/src/formats/csv/importer.d.ts.map +1 -1
- package/dist/src/formats/csv/importer.js +835 -204
- package/dist/src/formats/csv/importer.js.map +1 -1
- package/dist/src/formats/csv/index.d.ts +100 -19
- package/dist/src/formats/csv/index.d.ts.map +1 -1
- package/dist/src/formats/csv/index.js +94 -21
- package/dist/src/formats/csv/index.js.map +1 -1
- package/dist/src/formats/csv/records.d.ts +95 -10
- package/dist/src/formats/csv/records.d.ts.map +1 -1
- package/dist/src/formats/csv/records.js +333 -122
- package/dist/src/formats/csv/records.js.map +1 -1
- package/dist/src/formats/csv/values.d.ts +1 -0
- package/dist/src/formats/csv/values.d.ts.map +1 -1
- package/dist/src/formats/csv/values.js +1 -0
- package/dist/src/formats/csv/values.js.map +1 -1
- package/dist/src/formats/cx/exporter.d.ts +102 -0
- package/dist/src/formats/cx/exporter.d.ts.map +1 -0
- package/dist/src/formats/cx/exporter.js +1217 -0
- package/dist/src/formats/cx/exporter.js.map +1 -0
- package/dist/src/formats/cx/importer.d.ts +79 -32
- package/dist/src/formats/cx/importer.d.ts.map +1 -1
- package/dist/src/formats/cx/importer.js +682 -287
- package/dist/src/formats/cx/importer.js.map +1 -1
- package/dist/src/formats/cx/index.d.ts +4 -3
- package/dist/src/formats/cx/index.d.ts.map +1 -1
- package/dist/src/formats/cx/index.js +4 -3
- package/dist/src/formats/cx/index.js.map +1 -1
- package/dist/src/formats/cx2/exporter.d.ts +29 -11
- package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
- package/dist/src/formats/cx2/exporter.js +39 -268
- package/dist/src/formats/cx2/exporter.js.map +1 -1
- package/dist/src/formats/cx2/importer.d.ts +78 -28
- package/dist/src/formats/cx2/importer.d.ts.map +1 -1
- package/dist/src/formats/cx2/importer.js +227 -80
- package/dist/src/formats/cx2/importer.js.map +1 -1
- package/dist/src/formats/cx2/index.d.ts +2 -1
- package/dist/src/formats/cx2/index.d.ts.map +1 -1
- package/dist/src/formats/cx2/index.js +2 -1
- package/dist/src/formats/cx2/index.js.map +1 -1
- package/dist/src/formats/cys/constants.d.ts +66 -17
- package/dist/src/formats/cys/constants.d.ts.map +1 -1
- package/dist/src/formats/cys/constants.js +59 -18
- package/dist/src/formats/cys/constants.js.map +1 -1
- package/dist/src/formats/cys/exporter.d.ts +118 -0
- package/dist/src/formats/cys/exporter.d.ts.map +1 -0
- package/dist/src/formats/cys/exporter.js +1072 -0
- package/dist/src/formats/cys/exporter.js.map +1 -0
- package/dist/src/formats/cys/importer.d.ts +22 -8
- package/dist/src/formats/cys/importer.d.ts.map +1 -1
- package/dist/src/formats/cys/importer.js +510 -149
- package/dist/src/formats/cys/importer.js.map +1 -1
- package/dist/src/formats/cys/index.d.ts +4 -2
- package/dist/src/formats/cys/index.d.ts.map +1 -1
- package/dist/src/formats/cys/index.js +4 -2
- package/dist/src/formats/cys/index.js.map +1 -1
- package/dist/src/formats/cys/session.d.ts +46 -7
- package/dist/src/formats/cys/session.d.ts.map +1 -1
- package/dist/src/formats/cys/session.js +101 -27
- package/dist/src/formats/cys/session.js.map +1 -1
- package/dist/src/formats/cys/tables.d.ts +9 -2
- package/dist/src/formats/cys/tables.d.ts.map +1 -1
- package/dist/src/formats/cys/tables.js +29 -7
- package/dist/src/formats/cys/tables.js.map +1 -1
- package/dist/src/formats/dot/exporter.d.ts +42 -14
- package/dist/src/formats/dot/exporter.d.ts.map +1 -1
- package/dist/src/formats/dot/exporter.js +56 -29
- package/dist/src/formats/dot/exporter.js.map +1 -1
- package/dist/src/formats/dot/importer.d.ts +91 -29
- package/dist/src/formats/dot/importer.d.ts.map +1 -1
- package/dist/src/formats/dot/importer.js +190 -39
- package/dist/src/formats/dot/importer.js.map +1 -1
- package/dist/src/formats/dot/index.d.ts +2 -1
- package/dist/src/formats/dot/index.d.ts.map +1 -1
- package/dist/src/formats/dot/index.js +2 -1
- package/dist/src/formats/dot/index.js.map +1 -1
- package/dist/src/formats/dot/names.d.ts +44 -11
- package/dist/src/formats/dot/names.d.ts.map +1 -1
- package/dist/src/formats/dot/names.js +44 -11
- package/dist/src/formats/dot/names.js.map +1 -1
- package/dist/src/formats/dot/tokenizer.d.ts +9 -2
- package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
- package/dist/src/formats/dot/tokenizer.js +20 -5
- package/dist/src/formats/dot/tokenizer.js.map +1 -1
- package/dist/src/formats/gexf/exporter.d.ts +46 -15
- package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
- package/dist/src/formats/gexf/exporter.js +45 -15
- package/dist/src/formats/gexf/exporter.js.map +1 -1
- package/dist/src/formats/gexf/importer.d.ts +87 -23
- package/dist/src/formats/gexf/importer.d.ts.map +1 -1
- package/dist/src/formats/gexf/importer.js +471 -90
- package/dist/src/formats/gexf/importer.js.map +1 -1
- package/dist/src/formats/gexf/index.d.ts +84 -21
- package/dist/src/formats/gexf/index.d.ts.map +1 -1
- package/dist/src/formats/gexf/index.js +80 -23
- package/dist/src/formats/gexf/index.js.map +1 -1
- package/dist/src/formats/gexf/schema.d.ts +67 -15
- package/dist/src/formats/gexf/schema.d.ts.map +1 -1
- package/dist/src/formats/gexf/schema.js +59 -13
- package/dist/src/formats/gexf/schema.js.map +1 -1
- package/dist/src/formats/gml/exporter.d.ts +69 -21
- package/dist/src/formats/gml/exporter.d.ts.map +1 -1
- package/dist/src/formats/gml/exporter.js +74 -29
- package/dist/src/formats/gml/exporter.js.map +1 -1
- package/dist/src/formats/gml/importer.d.ts +116 -25
- package/dist/src/formats/gml/importer.d.ts.map +1 -1
- package/dist/src/formats/gml/importer.js +290 -61
- package/dist/src/formats/gml/importer.js.map +1 -1
- package/dist/src/formats/gml/index.d.ts +87 -24
- package/dist/src/formats/gml/index.d.ts.map +1 -1
- package/dist/src/formats/gml/index.js +79 -26
- package/dist/src/formats/gml/index.js.map +1 -1
- package/dist/src/formats/gml/syntax.d.ts +67 -18
- package/dist/src/formats/gml/syntax.d.ts.map +1 -1
- package/dist/src/formats/gml/syntax.js +110 -28
- package/dist/src/formats/gml/syntax.js.map +1 -1
- package/dist/src/formats/graphml/constants.d.ts +174 -44
- package/dist/src/formats/graphml/constants.d.ts.map +1 -1
- package/dist/src/formats/graphml/constants.js +165 -44
- package/dist/src/formats/graphml/constants.js.map +1 -1
- package/dist/src/formats/graphml/exporter.d.ts +17 -9
- package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
- package/dist/src/formats/graphml/exporter.js +33 -12
- package/dist/src/formats/graphml/exporter.js.map +1 -1
- package/dist/src/formats/graphml/importer.d.ts +19 -7
- package/dist/src/formats/graphml/importer.d.ts.map +1 -1
- package/dist/src/formats/graphml/importer.js +466 -39
- package/dist/src/formats/graphml/importer.js.map +1 -1
- package/dist/src/formats/graphml/index.d.ts +2 -1
- package/dist/src/formats/graphml/index.d.ts.map +1 -1
- package/dist/src/formats/graphml/index.js +2 -1
- package/dist/src/formats/graphml/index.js.map +1 -1
- package/dist/src/formats/graphml/tree.d.ts +6 -2
- package/dist/src/formats/graphml/tree.d.ts.map +1 -1
- package/dist/src/formats/graphml/tree.js +6 -2
- package/dist/src/formats/graphml/tree.js.map +1 -1
- package/dist/src/formats/graphml/yfiles.d.ts +8 -3
- package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
- package/dist/src/formats/graphml/yfiles.js +36 -15
- package/dist/src/formats/graphml/yfiles.js.map +1 -1
- package/dist/src/formats/json/dialect.d.ts +88 -24
- package/dist/src/formats/json/dialect.d.ts.map +1 -1
- package/dist/src/formats/json/dialect.js +109 -19
- package/dist/src/formats/json/dialect.js.map +1 -1
- package/dist/src/formats/json/exporter.d.ts +134 -22
- package/dist/src/formats/json/exporter.d.ts.map +1 -1
- package/dist/src/formats/json/exporter.js +135 -54
- package/dist/src/formats/json/exporter.js.map +1 -1
- package/dist/src/formats/json/importer.d.ts +173 -52
- package/dist/src/formats/json/importer.d.ts.map +1 -1
- package/dist/src/formats/json/importer.js +899 -220
- package/dist/src/formats/json/importer.js.map +1 -1
- package/dist/src/formats/json/index.d.ts +3 -2
- package/dist/src/formats/json/index.d.ts.map +1 -1
- package/dist/src/formats/json/index.js +3 -2
- package/dist/src/formats/json/index.js.map +1 -1
- package/dist/src/formats/json/obographs-export.d.ts +68 -0
- package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
- package/dist/src/formats/json/obographs-export.js +941 -0
- package/dist/src/formats/json/obographs-export.js.map +1 -0
- package/dist/src/formats/json/obographs.d.ts +26 -0
- package/dist/src/formats/json/obographs.d.ts.map +1 -1
- package/dist/src/formats/json/obographs.js +297 -80
- package/dist/src/formats/json/obographs.js.map +1 -1
- package/dist/src/formats/neo4j/exporter.d.ts +109 -21
- package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
- package/dist/src/formats/neo4j/exporter.js +239 -86
- package/dist/src/formats/neo4j/exporter.js.map +1 -1
- package/dist/src/formats/neo4j/header.d.ts +17 -4
- package/dist/src/formats/neo4j/header.d.ts.map +1 -1
- package/dist/src/formats/neo4j/header.js +36 -4
- package/dist/src/formats/neo4j/header.js.map +1 -1
- package/dist/src/formats/neo4j/importer.d.ts +107 -27
- package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
- package/dist/src/formats/neo4j/importer.js +415 -63
- package/dist/src/formats/neo4j/importer.js.map +1 -1
- package/dist/src/formats/neo4j/index.d.ts +73 -23
- package/dist/src/formats/neo4j/index.d.ts.map +1 -1
- package/dist/src/formats/neo4j/index.js +65 -25
- package/dist/src/formats/neo4j/index.js.map +1 -1
- package/dist/src/formats/obo/exporter.d.ts +150 -0
- package/dist/src/formats/obo/exporter.d.ts.map +1 -0
- package/dist/src/formats/obo/exporter.js +1736 -0
- package/dist/src/formats/obo/exporter.js.map +1 -0
- package/dist/src/formats/obo/importer.d.ts +95 -19
- package/dist/src/formats/obo/importer.d.ts.map +1 -1
- package/dist/src/formats/obo/importer.js +475 -104
- package/dist/src/formats/obo/importer.js.map +1 -1
- package/dist/src/formats/obo/index.d.ts +6 -3
- package/dist/src/formats/obo/index.d.ts.map +1 -1
- package/dist/src/formats/obo/index.js +6 -3
- package/dist/src/formats/obo/index.js.map +1 -1
- package/dist/src/formats/obo/syntax.d.ts +108 -4
- package/dist/src/formats/obo/syntax.d.ts.map +1 -1
- package/dist/src/formats/obo/syntax.js +211 -34
- package/dist/src/formats/obo/syntax.js.map +1 -1
- package/dist/src/formats/pajek/exporter.d.ts +54 -16
- package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
- package/dist/src/formats/pajek/exporter.js +67 -35
- package/dist/src/formats/pajek/exporter.js.map +1 -1
- package/dist/src/formats/pajek/importer.d.ts +84 -22
- package/dist/src/formats/pajek/importer.d.ts.map +1 -1
- package/dist/src/formats/pajek/importer.js +303 -83
- package/dist/src/formats/pajek/importer.js.map +1 -1
- package/dist/src/formats/pajek/index.d.ts +2 -1
- package/dist/src/formats/pajek/index.d.ts.map +1 -1
- package/dist/src/formats/pajek/index.js +2 -1
- package/dist/src/formats/pajek/index.js.map +1 -1
- package/dist/src/formats/pajek/syntax.d.ts +77 -14
- package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
- package/dist/src/formats/pajek/syntax.js +186 -54
- package/dist/src/formats/pajek/syntax.js.map +1 -1
- package/dist/src/formats/xgmml/columns.d.ts +1 -0
- package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
- package/dist/src/formats/xgmml/columns.js +4 -0
- package/dist/src/formats/xgmml/columns.js.map +1 -1
- package/dist/src/formats/xgmml/constants.d.ts +186 -56
- package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
- package/dist/src/formats/xgmml/constants.js +181 -57
- package/dist/src/formats/xgmml/constants.js.map +1 -1
- package/dist/src/formats/xgmml/document.d.ts +65 -11
- package/dist/src/formats/xgmml/document.d.ts.map +1 -1
- package/dist/src/formats/xgmml/document.js +157 -28
- package/dist/src/formats/xgmml/document.js.map +1 -1
- package/dist/src/formats/xgmml/emit.d.ts +61 -3
- package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
- package/dist/src/formats/xgmml/emit.js +129 -26
- package/dist/src/formats/xgmml/emit.js.map +1 -1
- package/dist/src/formats/xgmml/exporter.d.ts +13 -6
- package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
- package/dist/src/formats/xgmml/exporter.js +21 -22
- package/dist/src/formats/xgmml/exporter.js.map +1 -1
- package/dist/src/formats/xgmml/importer.d.ts +33 -12
- package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
- package/dist/src/formats/xgmml/importer.js +35 -72
- package/dist/src/formats/xgmml/importer.js.map +1 -1
- package/dist/src/formats/xgmml/index.d.ts +1 -0
- package/dist/src/formats/xgmml/index.d.ts.map +1 -1
- package/dist/src/formats/xgmml/index.js +1 -0
- package/dist/src/formats/xgmml/index.js.map +1 -1
- package/dist/src/formats/xgmml/values.d.ts +8 -1
- package/dist/src/formats/xgmml/values.d.ts.map +1 -1
- package/dist/src/formats/xgmml/values.js +8 -3
- package/dist/src/formats/xgmml/values.js.map +1 -1
- package/dist/src/index.d.ts +23 -18
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +28 -16
- package/dist/src/index.js.map +1 -1
- package/dist/src/registry.d.ts +478 -92
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +807 -88
- package/dist/src/registry.js.map +1 -1
- package/dist/src/sniff.d.ts +61 -19
- package/dist/src/sniff.d.ts.map +1 -1
- package/dist/src/sniff.js +121 -29
- package/dist/src/sniff.js.map +1 -1
- package/dist/src/types.d.ts +362 -112
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +28 -7
- package/dist/src/types.js.map +1 -1
- package/dist/xgmml.js +2 -2
- package/docs/samples/README.md +25 -0
- package/docs/samples/got-edges.csv +353 -0
- package/docs/samples/got-network.graphml +1384 -0
- package/docs/samples/got-nodes.csv +108 -0
- package/docs/samples/got.cx +930 -0
- package/docs/samples/got.cx2 +465 -0
- package/docs/samples/got.gexf +471 -0
- package/docs/samples/got.gml +2650 -0
- package/docs/samples/got.json +2546 -0
- package/docs/samples/got.net +461 -0
- package/docs/samples/movies-nodes.csv +9 -0
- package/docs/samples/movies-rels.csv +8 -0
- package/docs/samples/networks.cys +0 -0
- package/docs/samples/proteins.xgmml +9 -0
- package/docs/samples/teams.gv +24 -0
- package/docs/samples/vehicles.obo +25 -0
- package/package.json +9 -4
- package/src/children.ts +18 -6
- package/src/common/attributes.ts +29 -11
- package/src/common/cell-budget.ts +11 -3
- package/src/common/choose.ts +89 -0
- package/src/common/codes.ts +490 -66
- package/src/common/compare.ts +472 -0
- package/src/common/cx-export.ts +432 -0
- package/src/common/declared-types.ts +40 -6
- package/src/common/direction.ts +78 -51
- package/src/common/escape.ts +39 -22
- package/src/common/export.ts +284 -47
- package/src/common/format.ts +30 -1
- package/src/common/ids.ts +14 -3
- package/src/common/input.ts +1057 -134
- package/src/common/json-elements.ts +1035 -199
- package/src/common/line-format.ts +249 -0
- package/src/common/lists.ts +7 -2
- package/src/common/ontology-export.ts +461 -0
- package/src/common/ontology.ts +31 -9
- package/src/common/options.ts +110 -15
- package/src/common/plural.ts +49 -0
- package/src/common/report.ts +168 -25
- package/src/common/temporal.ts +22 -5
- package/src/common/text.ts +62 -23
- package/src/common/weights.ts +74 -4
- package/src/common/writer.ts +37 -3
- package/src/common/xml.ts +479 -90
- package/src/common/zip.ts +169 -7
- package/src/formats/csv/exporter.ts +202 -47
- package/src/formats/csv/header.ts +50 -11
- package/src/formats/csv/importer.ts +1133 -245
- package/src/formats/csv/index.ts +106 -19
- package/src/formats/csv/records.ts +396 -122
- package/src/formats/csv/values.ts +1 -0
- package/src/formats/cx/exporter.ts +1483 -0
- package/src/formats/cx/importer.ts +890 -302
- package/src/formats/cx/index.ts +4 -3
- package/src/formats/cx2/exporter.ts +62 -339
- package/src/formats/cx2/importer.ts +318 -87
- package/src/formats/cx2/index.ts +2 -1
- package/src/formats/cys/constants.ts +62 -17
- package/src/formats/cys/exporter.ts +1368 -0
- package/src/formats/cys/importer.ts +659 -157
- package/src/formats/cys/index.ts +4 -2
- package/src/formats/cys/session.ts +142 -34
- package/src/formats/cys/tables.ts +47 -9
- package/src/formats/dot/exporter.ts +83 -37
- package/src/formats/dot/importer.ts +248 -54
- package/src/formats/dot/index.ts +2 -1
- package/src/formats/dot/names.ts +44 -11
- package/src/formats/dot/tokenizer.ts +25 -6
- package/src/formats/gexf/exporter.ts +57 -18
- package/src/formats/gexf/importer.ts +636 -105
- package/src/formats/gexf/index.ts +90 -21
- package/src/formats/gexf/schema.ts +67 -15
- package/src/formats/gml/exporter.ts +90 -36
- package/src/formats/gml/importer.ts +388 -67
- package/src/formats/gml/index.ts +85 -24
- package/src/formats/gml/syntax.ts +113 -28
- package/src/formats/graphml/constants.ts +178 -44
- package/src/formats/graphml/exporter.ts +52 -18
- package/src/formats/graphml/importer.ts +640 -60
- package/src/formats/graphml/index.ts +2 -1
- package/src/formats/graphml/tree.ts +6 -2
- package/src/formats/graphml/yfiles.ts +37 -15
- package/src/formats/json/dialect.ts +128 -29
- package/src/formats/json/exporter.ts +205 -68
- package/src/formats/json/importer.ts +1163 -253
- package/src/formats/json/index.ts +3 -1
- package/src/formats/json/obographs-export.ts +1197 -0
- package/src/formats/json/obographs.ts +353 -92
- package/src/formats/neo4j/exporter.ts +321 -102
- package/src/formats/neo4j/header.ts +44 -6
- package/src/formats/neo4j/importer.ts +512 -73
- package/src/formats/neo4j/index.ts +75 -23
- package/src/formats/obo/exporter.ts +2210 -0
- package/src/formats/obo/importer.ts +622 -109
- package/src/formats/obo/index.ts +6 -3
- package/src/formats/obo/syntax.ts +232 -37
- package/src/formats/pajek/exporter.ts +90 -42
- package/src/formats/pajek/importer.ts +407 -93
- package/src/formats/pajek/index.ts +2 -1
- package/src/formats/pajek/syntax.ts +216 -55
- package/src/formats/xgmml/columns.ts +10 -0
- package/src/formats/xgmml/constants.ts +183 -56
- package/src/formats/xgmml/document.ts +212 -34
- package/src/formats/xgmml/emit.ts +175 -34
- package/src/formats/xgmml/exporter.ts +36 -28
- package/src/formats/xgmml/importer.ts +64 -86
- package/src/formats/xgmml/index.ts +1 -0
- package/src/formats/xgmml/values.ts +12 -4
- package/src/index.ts +81 -11
- package/src/registry.ts +1121 -135
- package/src/sniff.ts +163 -32
- package/src/types.ts +385 -114
- package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
- package/dist/chunks/export-Bh60Dv-n.js +0 -582
- package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
- package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
- package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
- package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
- package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
- package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
- package/dist/chunks/importer-DET1tg6s.js.map +0 -1
- package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
- package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
- package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
- package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
- package/dist/chunks/importer-eUREhBGj.js.map +0 -1
- package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
- package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
- package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
- package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
- package/dist/chunks/ontology-BnrJ4I98.js +0 -113
- package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
- package/dist/chunks/records-dbRkxwaq.js.map +0 -1
- package/dist/chunks/report-B1z4WT9e.js +0 -2372
- package/dist/chunks/report-B1z4WT9e.js.map +0 -1
- package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
- package/dist/chunks/weights-Dzba96G3.js +0 -176
- package/dist/chunks/weights-Dzba96G3.js.map +0 -1
- package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
|
@@ -28,20 +28,29 @@ import {
|
|
|
28
28
|
} from "@graphty/graph-format";
|
|
29
29
|
|
|
30
30
|
import { declareResolved, RENAMED_CODE, ROLE_TAKEN_CODE, uniqueColumnName } from "../../common/attributes.js";
|
|
31
|
+
import { importChosenGraph } from "../../common/choose.js";
|
|
31
32
|
import {
|
|
33
|
+
AMBIGUOUS_GRAPH_NAME_CODE,
|
|
34
|
+
DUPLICATE_ATTRIBUTE_CODE,
|
|
32
35
|
DUPLICATE_NODE_CODE,
|
|
36
|
+
ELEMENT_ISSUE,
|
|
33
37
|
ENCODING_FALLBACK_CODE,
|
|
38
|
+
GRAPH_NOT_FOUND_CODE,
|
|
39
|
+
INPUT_ISSUE,
|
|
34
40
|
INVALID_ENCODING_CODE,
|
|
35
41
|
INVALID_UTF8_CODE,
|
|
36
42
|
MULTIPLE_GRAPHS_CODE,
|
|
37
43
|
OPTION_IGNORED_CODE,
|
|
44
|
+
PRECISION_CODE,
|
|
38
45
|
SYNTAX_CODE,
|
|
39
46
|
UNKNOWN_ENCODING_CODE,
|
|
40
47
|
} from "../../common/codes.js";
|
|
41
48
|
import { DirectionResolver, type EdgeKind } from "../../common/direction.js";
|
|
49
|
+
import { survivesF32 } from "../../common/format.js";
|
|
42
50
|
import { coerceIdText, ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
|
|
43
51
|
import { LineReader, throwIfAborted } from "../../common/input.js";
|
|
44
52
|
import {
|
|
53
|
+
graphChosen,
|
|
45
54
|
type ImportFormatDefaults,
|
|
46
55
|
reportSinkOptions,
|
|
47
56
|
reportUnusedOptions,
|
|
@@ -49,14 +58,22 @@ import {
|
|
|
49
58
|
resolveImportOptions,
|
|
50
59
|
SINK_OPTION_CODE,
|
|
51
60
|
} from "../../common/options.js";
|
|
61
|
+
import { agree, plural } from "../../common/plural.js";
|
|
52
62
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
53
63
|
import { isNumericText, TextCellWriter, WIDENING_UNSUPPORTED_CODE } from "../../common/text.js";
|
|
54
64
|
import { isWeightField, parseWeightText } from "../../common/weights.js";
|
|
55
|
-
import {
|
|
65
|
+
import {
|
|
66
|
+
type CommonImportOptions,
|
|
67
|
+
type GraphChoiceOptions,
|
|
68
|
+
type GraphImporter,
|
|
69
|
+
type ImportInput,
|
|
70
|
+
type ImportReport,
|
|
71
|
+
} from "../../types.js";
|
|
56
72
|
import {
|
|
57
73
|
decodeCharacterReferences,
|
|
58
74
|
isCommentOrBlank,
|
|
59
75
|
isIntervalToken,
|
|
76
|
+
isProjectObject,
|
|
60
77
|
isSectionLine,
|
|
61
78
|
isShapeKeyword,
|
|
62
79
|
isVertexNumber,
|
|
@@ -71,43 +88,66 @@ import {
|
|
|
71
88
|
SHAPE_COLUMN,
|
|
72
89
|
SPELLS_COLUMN,
|
|
73
90
|
tokenize,
|
|
91
|
+
type TokenNotes,
|
|
74
92
|
VALUE_COLUMN,
|
|
75
93
|
VALUE_FIELD,
|
|
76
94
|
VECTOR_COLUMN,
|
|
77
95
|
} from "./syntax.js";
|
|
78
96
|
|
|
79
|
-
/**
|
|
80
|
-
|
|
97
|
+
/**
|
|
98
|
+
* The format-specific options of the Pajek importer.
|
|
99
|
+
* @category Built-in formats
|
|
100
|
+
*/
|
|
101
|
+
export interface PajekImportOptions extends GraphChoiceOptions, CommonImportOptions {
|
|
81
102
|
/**
|
|
82
103
|
* The number of the first vertex: 1 (Pajek's rule), 0 (files written by zero-based scripts), or
|
|
83
|
-
* "auto"
|
|
104
|
+
* "auto": 0 when the first vertex line is numbered 0, 1 otherwise.
|
|
105
|
+
* @defaultValue "auto"
|
|
84
106
|
*/
|
|
85
107
|
firstVertex?: 0 | 1 | "auto" | undefined;
|
|
86
108
|
}
|
|
87
109
|
|
|
88
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Issue codes of the Pajek importer.
|
|
112
|
+
* @category Built-in formats
|
|
113
|
+
*/
|
|
89
114
|
export const PAJEK_ISSUE = Object.freeze({
|
|
90
|
-
|
|
115
|
+
...INPUT_ISSUE,
|
|
116
|
+
...ELEMENT_ISSUE,
|
|
117
|
+
/** The input is not valid UTF-8. The import stops. */
|
|
91
118
|
INVALID_UTF8: INVALID_UTF8_CODE,
|
|
92
|
-
/**
|
|
119
|
+
/**
|
|
120
|
+
* Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
|
|
121
|
+
* `encoding` option). The import stops.
|
|
122
|
+
*/
|
|
93
123
|
INVALID_ENCODING: INVALID_ENCODING_CODE,
|
|
94
124
|
/** Bytes that are not UTF-8 and declare no encoding were read as windows-1252. */
|
|
95
125
|
ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
|
|
96
126
|
/** A declared encoding the platform cannot decode was ignored. */
|
|
97
127
|
UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
|
|
98
|
-
/**
|
|
128
|
+
/** There is no `*Vertices` section: the file is empty or not a Pajek network. The import stops. */
|
|
99
129
|
NO_VERTICES: "E_PAJEK_NO_VERTICES",
|
|
100
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* `*Vertices` without a vertex count, with a count too large to hold, or with a first-mode count outside 0 to N;
|
|
132
|
+
* the import stops.
|
|
133
|
+
*/
|
|
101
134
|
VERTICES_COUNT: "E_PAJEK_VERTICES_COUNT",
|
|
102
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* The file holds several graphs and only the first was read. It is not added when `graphIndex` or `graphName` chose the graph.
|
|
137
|
+
* `importAllGraphs()` reads every one.
|
|
138
|
+
*/
|
|
103
139
|
MULTIPLE_GRAPHS: MULTIPLE_GRAPHS_CODE,
|
|
140
|
+
/** `graphIndex` or `graphName` names no graph of the file; the message lists the graphs it holds. The import stops. */
|
|
141
|
+
GRAPH_NOT_FOUND: GRAPH_NOT_FOUND_CODE,
|
|
142
|
+
/** `graphName` matches more than one graph; pass `graphIndex`. The import stops. */
|
|
143
|
+
AMBIGUOUS_GRAPH_NAME: AMBIGUOUS_GRAPH_NAME_CODE,
|
|
104
144
|
/** A data line before the first section header. */
|
|
105
145
|
OUTSIDE_SECTION: "E_PAJEK_OUTSIDE_SECTION",
|
|
106
146
|
/** A section header the importer cannot parse. */
|
|
107
147
|
SYNTAX: SYNTAX_CODE,
|
|
108
148
|
/** A double quote not closed before the end of the line. */
|
|
109
149
|
UNTERMINATED_QUOTE: "E_PAJEK_UNTERMINATED_QUOTE",
|
|
110
|
-
/** A vertex line the
|
|
150
|
+
/** A vertex line that is not in Pajek's vertex syntax; the vertex is skipped. */
|
|
111
151
|
VERTEX_LINE: "E_PAJEK_VERTEX_LINE",
|
|
112
152
|
/** A vertex number outside the declared range. */
|
|
113
153
|
VERTEX_RANGE: "E_PAJEK_VERTEX_RANGE",
|
|
@@ -115,9 +155,12 @@ export const PAJEK_ISSUE = Object.freeze({
|
|
|
115
155
|
VERTEX_COUNT: "W_PAJEK_VERTEX_COUNT",
|
|
116
156
|
/** A second line for the same vertex; the later values overwrite. */
|
|
117
157
|
DUPLICATE_NODE: DUPLICATE_NODE_CODE,
|
|
118
|
-
/**
|
|
158
|
+
/**
|
|
159
|
+
* A line that is not in Pajek's syntax for its section (an arc, edge, list, matrix row, partition or vector
|
|
160
|
+
* value); it is skipped.
|
|
161
|
+
*/
|
|
119
162
|
LINE: "E_PAJEK_LINE",
|
|
120
|
-
/**
|
|
163
|
+
/** An edge names a vertex number outside the range `*Vertices` declared; the edge is skipped. */
|
|
121
164
|
UNKNOWN_NODE: "E_UNKNOWN_NODE",
|
|
122
165
|
/** A malformed time interval token. */
|
|
123
166
|
INTERVAL: "E_PAJEK_INTERVAL",
|
|
@@ -129,32 +172,57 @@ export const PAJEK_ISSUE = Object.freeze({
|
|
|
129
172
|
OBJECT_COUNT: "E_PAJEK_OBJECT_COUNT",
|
|
130
173
|
/** A project-file section (`*Events`, `*Permutation`, ...) the importer does not read; its lines are skipped. */
|
|
131
174
|
UNSUPPORTED_SECTION: "W_PAJEK_UNSUPPORTED_SECTION",
|
|
132
|
-
/**
|
|
175
|
+
/** A section header has extra words Pajek does not define; they are ignored. */
|
|
133
176
|
HEADER_EXTRA: "W_PAJEK_HEADER_EXTRA",
|
|
134
177
|
/** The file declares vertices but no line section. */
|
|
135
178
|
NO_LINES: "W_PAJEK_NO_LINES",
|
|
136
|
-
/** Vertex numbering starts at 0 rather than 1. */
|
|
179
|
+
/** Vertex numbering starts at 0 rather than 1, found by `firstVertex: "auto"` (passing `firstVertex: 0` says so and gives no warning). */
|
|
137
180
|
ZERO_BASED: "W_PAJEK_ZERO_BASED",
|
|
138
181
|
/** Vertex lines mix two and three coordinates. */
|
|
139
182
|
COORD_DIMS: "W_PAJEK_COORD_DIMS",
|
|
140
183
|
/** Two vertices share a label under nodeIdFrom "label" and became one node. */
|
|
141
184
|
LABEL_MERGED: "W_PAJEK_LABEL_MERGED",
|
|
142
|
-
/** Two
|
|
185
|
+
/** Two different labels became the same number because `ids` is "number", so their vertices were merged. */
|
|
143
186
|
ID_MERGED: ID_MERGED_CODE,
|
|
144
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* Your graph builder cannot change an attribute's type after its first value, so a text column keeps the type of
|
|
189
|
+
* its first values.
|
|
190
|
+
*/
|
|
145
191
|
WIDENING_UNSUPPORTED: WIDENING_UNSUPPORTED_CODE,
|
|
146
|
-
/** A structural column (label, position, shape, spells, relation) renamed `<name>#<id>` because the name was taken
|
|
192
|
+
/** A structural column (label, position, shape, spells, relation) renamed `<name>#<id>` because the name was taken. */
|
|
147
193
|
COLUMN_RENAMED: RENAMED_CODE,
|
|
148
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
|
|
196
|
+
* a plain attribute.
|
|
197
|
+
*/
|
|
149
198
|
ROLE_TAKEN: ROLE_TAKEN_CODE,
|
|
150
199
|
/** Two vertices carry the same `graphty_originalId` under restoreMangledIds and became one node. */
|
|
151
200
|
ORIGINAL_ID_MERGED: "W_PAJEK_ORIGINAL_ID_MERGED",
|
|
152
201
|
/** A vertex line's `graphty_originalId` came after a later vertex's line had created it under its number. */
|
|
153
202
|
ORIGINAL_ID_UNRESTORED: "W_PAJEK_ORIGINAL_ID_UNRESTORED",
|
|
154
|
-
/**
|
|
203
|
+
/** You set an option this format does not use; it had no effect. The message names the option. */
|
|
155
204
|
OPTION_IGNORED: OPTION_IGNORED_CODE,
|
|
156
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
|
|
207
|
+
* `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
|
|
208
|
+
*/
|
|
157
209
|
SINK_OPTION: SINK_OPTION_CODE,
|
|
210
|
+
/** A double quote inside a token (a CSV-style doubled quote, a quote mid-word): removed and the parts joined. */
|
|
211
|
+
QUOTE_IN_TOKEN: "W_PAJEK_QUOTE_IN_TOKEN",
|
|
212
|
+
/** The same parameter twice on one line; the later value stands. */
|
|
213
|
+
DUPLICATE_ATTRIBUTE: DUPLICATE_ATTRIBUTE_CODE,
|
|
214
|
+
/** A character reference beyond U+10FFFF in a label; kept as written. */
|
|
215
|
+
REFERENCE_RANGE: "W_PAJEK_REFERENCE_RANGE",
|
|
216
|
+
/** A line of a two-mode network whose endpoints are both in one mode. */
|
|
217
|
+
TWO_MODE_LINE: "W_PAJEK_TWO_MODE_LINE",
|
|
218
|
+
/** 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. */
|
|
219
|
+
NUMERIC_LABEL: "W_PAJEK_NUMERIC_LABEL",
|
|
220
|
+
/** A relation number given a second name by a later `*Arcs :k "name"` header. */
|
|
221
|
+
RELATION_RENAMED: "W_PAJEK_RELATION_RENAMED",
|
|
222
|
+
/** A negative vertex number in an adjacency list, read as its absolute value. */
|
|
223
|
+
NEGATIVE_LIST_ENTRY: "W_PAJEK_NEGATIVE_LIST_ENTRY",
|
|
224
|
+
/** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
|
|
225
|
+
PRECISION: PRECISION_CODE,
|
|
158
226
|
});
|
|
159
227
|
|
|
160
228
|
/** The common options the Pajek importer reads (the rest is reported by reportUnusedOptions). */
|
|
@@ -181,6 +249,10 @@ const ABORT_CHECK_INTERVAL = 64;
|
|
|
181
249
|
|
|
182
250
|
const FIRST_VERTEX_VALUES: ReadonlySet<unknown> = new Set([0, 1, "auto"]);
|
|
183
251
|
|
|
252
|
+
/** A numeral that is not a finite number (`1e999`, `NaN`, `Infinity`): never a parameter key. */
|
|
253
|
+
const NUMERAL = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
254
|
+
const NON_FINITE_WORD = /^[+-]?(?:nan|inf|infinity)$/i;
|
|
255
|
+
|
|
184
256
|
const LABEL_DECL: ColumnDecl = {
|
|
185
257
|
name: LABEL_COLUMN,
|
|
186
258
|
dtype: "string",
|
|
@@ -327,6 +399,8 @@ class PajekParser {
|
|
|
327
399
|
|
|
328
400
|
/** `*Vertices N`; -1 before the header. */
|
|
329
401
|
private vertexCount = -1;
|
|
402
|
+
/** The line of the `*Vertices` header. */
|
|
403
|
+
private verticesLine = 0;
|
|
330
404
|
|
|
331
405
|
/** The first-mode count of a two-mode network, or null. */
|
|
332
406
|
private firstMode: number | null = null;
|
|
@@ -358,6 +432,12 @@ class PajekParser {
|
|
|
358
432
|
/** Set when the previous line was a project-object header, whose `*Vertices N` line comes next. */
|
|
359
433
|
private objectHeader = false;
|
|
360
434
|
|
|
435
|
+
/** The first unsupported section keyword, for the message of a file without `*Vertices`. */
|
|
436
|
+
private firstUnsupported: string | null = null;
|
|
437
|
+
|
|
438
|
+
/** Vertex lines skipped because their number is outside the declared range (not lines of declared vertices). */
|
|
439
|
+
private outOfRange = 0;
|
|
440
|
+
|
|
361
441
|
/** Node index per vertex position (vertex number minus base). */
|
|
362
442
|
private indexOfPos: U32 = new Uint32Array(0);
|
|
363
443
|
|
|
@@ -462,7 +542,7 @@ class PajekParser {
|
|
|
462
542
|
this.matrixLine(text, line);
|
|
463
543
|
return false;
|
|
464
544
|
case "object":
|
|
465
|
-
this.objectLine(text);
|
|
545
|
+
this.objectLine(text, line);
|
|
466
546
|
return false;
|
|
467
547
|
case "skip":
|
|
468
548
|
return false;
|
|
@@ -487,7 +567,11 @@ class PajekParser {
|
|
|
487
567
|
*/
|
|
488
568
|
finish(): void {
|
|
489
569
|
if (this.vertexCount < 0) {
|
|
490
|
-
|
|
570
|
+
const seen =
|
|
571
|
+
this.firstUnsupported === null
|
|
572
|
+
? ""
|
|
573
|
+
: ` (the file has the unrecognised section *${this.firstUnsupported})`;
|
|
574
|
+
this.report.fail(PAJEK_ISSUE.NO_VERTICES, `not a Pajek network: no *Vertices section found${seen}`);
|
|
491
575
|
}
|
|
492
576
|
this.endSection();
|
|
493
577
|
this.finishVertices();
|
|
@@ -507,7 +591,7 @@ class PajekParser {
|
|
|
507
591
|
this.report.warning(
|
|
508
592
|
"coercion",
|
|
509
593
|
PAJEK_ISSUE.ID_MERGED,
|
|
510
|
-
`${this.coercer.mergeCount} label(
|
|
594
|
+
`${this.coercer.mergeCount} label${plural(this.coercer.mergeCount)} merged into an id another label already produced under ids "number"`,
|
|
511
595
|
);
|
|
512
596
|
}
|
|
513
597
|
const pajek = {
|
|
@@ -560,7 +644,7 @@ class PajekParser {
|
|
|
560
644
|
this.report.error(
|
|
561
645
|
"validation-error",
|
|
562
646
|
PAJEK_ISSUE.OBJECT_COUNT,
|
|
563
|
-
`*${partition ? "Partition" : "Vector"} "${object.name}" declares ${declared} vertices and holds ${object.values.length} value(
|
|
647
|
+
`*${partition ? "Partition" : "Vector"} "${object.name}" declares ${declared} vertices and holds ${object.values.length} value${plural(object.values.length)}; the network has ${this.vertexCount}`,
|
|
564
648
|
where,
|
|
565
649
|
);
|
|
566
650
|
}
|
|
@@ -589,7 +673,7 @@ class PajekParser {
|
|
|
589
673
|
this.report.warning(
|
|
590
674
|
"validation-error",
|
|
591
675
|
PAJEK_ISSUE.HEADER_EXTRA,
|
|
592
|
-
`ignored ${h.extra.length} unexpected token(
|
|
676
|
+
`ignored ${h.extra.length} unexpected token${plural(h.extra.length)} after *${h.keyword}: ${h.extra.join(" ")}`,
|
|
593
677
|
{ line },
|
|
594
678
|
);
|
|
595
679
|
}
|
|
@@ -639,7 +723,9 @@ class PajekParser {
|
|
|
639
723
|
return;
|
|
640
724
|
case "unsupported":
|
|
641
725
|
this.section = "skip";
|
|
642
|
-
|
|
726
|
+
// only a project object's next line is its own `*Vertices N`
|
|
727
|
+
this.objectHeader = isProjectObject(h.keyword);
|
|
728
|
+
this.firstUnsupported ??= h.keyword;
|
|
643
729
|
this.report.warning(
|
|
644
730
|
"unsupported",
|
|
645
731
|
PAJEK_ISSUE.UNSUPPORTED_SECTION,
|
|
@@ -674,8 +760,9 @@ class PajekParser {
|
|
|
674
760
|
);
|
|
675
761
|
}
|
|
676
762
|
try {
|
|
677
|
-
// the declared count must be reservable (the sink is the authority on what it can hold
|
|
678
|
-
//
|
|
763
|
+
// the declared count must be reservable (the sink is the authority on what it can hold;
|
|
764
|
+
// the builder refuses more than its id map holds with E_TOO_LARGE) before any vertex
|
|
765
|
+
// or per-vertex table is allocated
|
|
679
766
|
this.sink.reserve(h.count);
|
|
680
767
|
} catch (err) {
|
|
681
768
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -688,6 +775,7 @@ class PajekParser {
|
|
|
688
775
|
);
|
|
689
776
|
}
|
|
690
777
|
this.vertexCount = h.count;
|
|
778
|
+
this.verticesLine = line;
|
|
691
779
|
if (h.secondCount !== null) {
|
|
692
780
|
this.firstMode = h.secondCount;
|
|
693
781
|
}
|
|
@@ -729,7 +817,17 @@ class PajekParser {
|
|
|
729
817
|
this.kind = kind;
|
|
730
818
|
this.relation = h.relation === null ? null : (h.name ?? String(h.relation));
|
|
731
819
|
if (h.relation !== null) {
|
|
732
|
-
|
|
820
|
+
const name = this.relation ?? String(h.relation);
|
|
821
|
+
const before = this.relationNames.get(h.relation);
|
|
822
|
+
if (before !== undefined && before !== name) {
|
|
823
|
+
this.report.warning(
|
|
824
|
+
"validation-error",
|
|
825
|
+
PAJEK_ISSUE.RELATION_RENAMED,
|
|
826
|
+
`relation ${h.relation} was named ${JSON.stringify(before)} and is now named ${JSON.stringify(name)}; its lines carry the name of their own section`,
|
|
827
|
+
{ line, element: String(h.relation) },
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
this.relationNames.set(h.relation, name);
|
|
733
831
|
}
|
|
734
832
|
}
|
|
735
833
|
|
|
@@ -742,7 +840,7 @@ class PajekParser {
|
|
|
742
840
|
this.report.error(
|
|
743
841
|
"validation-error",
|
|
744
842
|
PAJEK_ISSUE.MATRIX_ROWS,
|
|
745
|
-
`*Matrix has ${this.matrixRows} row(
|
|
843
|
+
`*Matrix has ${this.matrixRows} row${plural(this.matrixRows)}; *Vertices declares ${rows}`,
|
|
746
844
|
);
|
|
747
845
|
}
|
|
748
846
|
this.section = "none";
|
|
@@ -759,7 +857,8 @@ class PajekParser {
|
|
|
759
857
|
private setBase(base: 0 | 1, line: number): void {
|
|
760
858
|
this.base = base;
|
|
761
859
|
this.baseKnown = true;
|
|
762
|
-
|
|
860
|
+
// the caller who passed firstVertex: 0 knows the numbering; the warning is for a guess
|
|
861
|
+
if (base === 0 && this.firstVertex === "auto") {
|
|
763
862
|
this.report.warning(
|
|
764
863
|
"coercion",
|
|
765
864
|
PAJEK_ISSUE.ZERO_BASED,
|
|
@@ -780,13 +879,34 @@ class PajekParser {
|
|
|
780
879
|
}
|
|
781
880
|
this.nodesCreated = true;
|
|
782
881
|
const n = this.vertexCount;
|
|
783
|
-
const { sink } = this;
|
|
784
882
|
for (let pos = 0; pos < n; pos++) {
|
|
785
|
-
this.indexOfPos[pos] =
|
|
883
|
+
this.indexOfPos[pos] = this.addNode(this.idOfNumber(pos + this.base));
|
|
786
884
|
}
|
|
787
885
|
this.report.counts.nodes += n;
|
|
788
886
|
}
|
|
789
887
|
|
|
888
|
+
/**
|
|
889
|
+
* Add a vertex to the sink. A sink that cannot hold the declared vertex set (the builder's
|
|
890
|
+
* E_TOO_LARGE id map limit) makes the file unreadable, so its refusal is fatal; any other
|
|
891
|
+
* error passes to the caller.
|
|
892
|
+
* @param id - the vertex id
|
|
893
|
+
* @returns the node index
|
|
894
|
+
*/
|
|
895
|
+
private addNode(id: NodeId): number {
|
|
896
|
+
try {
|
|
897
|
+
return this.sink.addNode(id);
|
|
898
|
+
} catch (err) {
|
|
899
|
+
if (!(err instanceof GraphFormatError) || err.code !== "E_TOO_LARGE") {
|
|
900
|
+
throw err;
|
|
901
|
+
}
|
|
902
|
+
return this.report.fail(
|
|
903
|
+
PAJEK_ISSUE.VERTICES_COUNT,
|
|
904
|
+
`*Vertices ${this.vertexCount}: the sink cannot hold that many (${err.message})`,
|
|
905
|
+
{ line: this.verticesLine },
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
790
910
|
/**
|
|
791
911
|
* The id of a vertex number under nodeIdFrom "id" (the number coerced by the ids rule) or
|
|
792
912
|
* "index" (the position).
|
|
@@ -844,12 +964,12 @@ class PajekParser {
|
|
|
844
964
|
}
|
|
845
965
|
}
|
|
846
966
|
// a partial list: fewer lines than declared, counting the lines skipped after an error
|
|
847
|
-
const lines = this.seenCount + this.report.counts.skippedNodes;
|
|
967
|
+
const lines = this.seenCount + this.report.counts.skippedNodes - this.outOfRange;
|
|
848
968
|
if (this.seenCount > 0 && lines < n) {
|
|
849
969
|
this.report.warning(
|
|
850
970
|
"validation-error",
|
|
851
971
|
PAJEK_ISSUE.VERTEX_COUNT,
|
|
852
|
-
`*Vertices declares ${n} vertices but ${lines} vertex line(
|
|
972
|
+
`*Vertices declares ${n} vertices but ${lines} vertex line${plural(lines)} ${agree(lines, "was", "were")} read; the others have no label`,
|
|
853
973
|
);
|
|
854
974
|
}
|
|
855
975
|
}
|
|
@@ -860,7 +980,7 @@ class PajekParser {
|
|
|
860
980
|
* @param line - the line number
|
|
861
981
|
*/
|
|
862
982
|
private vertexLine(text: string, line: number): void {
|
|
863
|
-
const tokens = this.tokens(text, "node");
|
|
983
|
+
const tokens = this.tokens(text, "node", line);
|
|
864
984
|
if (!isVertexNumber(tokens[0])) {
|
|
865
985
|
this.report.counts.skippedNodes++;
|
|
866
986
|
throw new LineError(
|
|
@@ -876,6 +996,7 @@ class PajekParser {
|
|
|
876
996
|
const pos = k - this.base;
|
|
877
997
|
if (pos < 0 || pos >= this.vertexCount) {
|
|
878
998
|
this.report.counts.skippedNodes++;
|
|
999
|
+
this.outOfRange++;
|
|
879
1000
|
throw new LineError(
|
|
880
1001
|
"validation-error",
|
|
881
1002
|
PAJEK_ISSUE.VERTEX_RANGE,
|
|
@@ -886,7 +1007,7 @@ class PajekParser {
|
|
|
886
1007
|
let i = 1;
|
|
887
1008
|
let label: string | null = null;
|
|
888
1009
|
if (tokens.length > 1 && !startsWithCoordinates(text, tokens)) {
|
|
889
|
-
label =
|
|
1010
|
+
label = this.labelOf(tokens[1], k, line);
|
|
890
1011
|
i = 2;
|
|
891
1012
|
}
|
|
892
1013
|
let x = 0;
|
|
@@ -911,12 +1032,13 @@ class PajekParser {
|
|
|
911
1032
|
`vertex ${k}: a single coordinate "${tokens[i]}"; coordinates are x y [z]`,
|
|
912
1033
|
);
|
|
913
1034
|
}
|
|
1035
|
+
this.checkCoordinates(text, tokens, i, dims === 2 && label !== null, k, line);
|
|
914
1036
|
let shape: string | null = null;
|
|
915
1037
|
if (i < tokens.length && isShapeKeyword(tokens[i])) {
|
|
916
1038
|
shape = tokens[i].toLowerCase();
|
|
917
1039
|
i++;
|
|
918
1040
|
}
|
|
919
|
-
const extras = this.extras(tokens, i, "node");
|
|
1041
|
+
const extras = this.extras(tokens, i, "node", line);
|
|
920
1042
|
const restored = this.restoredId(extras);
|
|
921
1043
|
this.createNodes();
|
|
922
1044
|
// write
|
|
@@ -970,18 +1092,7 @@ class PajekParser {
|
|
|
970
1092
|
sink.setNodeValue(this.labelHandle, index, label);
|
|
971
1093
|
}
|
|
972
1094
|
if (dims > 0) {
|
|
973
|
-
|
|
974
|
-
this.coordDims = dims;
|
|
975
|
-
this.positionHandle = declareResolved(sink, "node", positionDecl(dims), this.report, { line }).handle;
|
|
976
|
-
} else if (dims !== this.coordDims) {
|
|
977
|
-
this.report.warnOnce(
|
|
978
|
-
"validation-error",
|
|
979
|
-
PAJEK_ISSUE.COORD_DIMS,
|
|
980
|
-
`vertex lines mix ${this.coordDims} and ${dims} coordinates; the position column records sourceDims ${this.coordDims}`,
|
|
981
|
-
{ line, element: String(k) },
|
|
982
|
-
);
|
|
983
|
-
}
|
|
984
|
-
sink.setNodeValue(this.positionHandle, index, [x, y, z]);
|
|
1095
|
+
this.writePosition(index, dims, [x, y, z], k, line);
|
|
985
1096
|
}
|
|
986
1097
|
if (shape !== null) {
|
|
987
1098
|
if (this.shapeHandle === INVALID_INDEX && this.nodeParams.has(SHAPE_COLUMN)) {
|
|
@@ -1005,6 +1116,104 @@ class PajekParser {
|
|
|
1005
1116
|
}
|
|
1006
1117
|
}
|
|
1007
1118
|
|
|
1119
|
+
/**
|
|
1120
|
+
* A vertex label as written, its character references decoded.
|
|
1121
|
+
* @param token - the label token
|
|
1122
|
+
* @param k - the vertex number
|
|
1123
|
+
* @param line - the line number
|
|
1124
|
+
* @returns the label
|
|
1125
|
+
*/
|
|
1126
|
+
private labelOf(token: string, k: number, line: number): string {
|
|
1127
|
+
return decodeCharacterReferences(token, (reference) => {
|
|
1128
|
+
this.report.warnOnce(
|
|
1129
|
+
"validation-error",
|
|
1130
|
+
PAJEK_ISSUE.REFERENCE_RANGE,
|
|
1131
|
+
`character reference ${reference} is beyond U+10FFFF; it is kept as written`,
|
|
1132
|
+
{ line, element: String(k) },
|
|
1133
|
+
`${PAJEK_ISSUE.REFERENCE_RANGE}:${reference}`,
|
|
1134
|
+
);
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Check the token after a vertex line's coordinates (or where they would stand): a numeral the
|
|
1140
|
+
* number range cannot hold is a broken coordinate, never a parameter named "1e999" or "NaN";
|
|
1141
|
+
* and a bare non-integer label before two coordinates may be the x of an x y z line.
|
|
1142
|
+
* @param text - the line
|
|
1143
|
+
* @param tokens - its tokens
|
|
1144
|
+
* @param i - the index after the coordinates
|
|
1145
|
+
* @param labelAndXy - whether the line was read as a label and two coordinates
|
|
1146
|
+
* @param k - the vertex number
|
|
1147
|
+
* @param line - the line number
|
|
1148
|
+
*/
|
|
1149
|
+
private checkCoordinates(
|
|
1150
|
+
text: string,
|
|
1151
|
+
tokens: readonly string[],
|
|
1152
|
+
i: number,
|
|
1153
|
+
labelAndXy: boolean,
|
|
1154
|
+
k: number,
|
|
1155
|
+
line: number,
|
|
1156
|
+
): void {
|
|
1157
|
+
if (
|
|
1158
|
+
i < tokens.length &&
|
|
1159
|
+
(NUMERAL.test(tokens[i]) || NON_FINITE_WORD.test(tokens[i])) &&
|
|
1160
|
+
!isNumericText(tokens[i])
|
|
1161
|
+
) {
|
|
1162
|
+
this.report.counts.skippedNodes++;
|
|
1163
|
+
throw new LineError(
|
|
1164
|
+
"parse-error",
|
|
1165
|
+
PAJEK_ISSUE.VERTEX_LINE,
|
|
1166
|
+
`vertex ${k}: coordinate "${tokens[i]}" is not a finite number`,
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
const label = tokens[1];
|
|
1170
|
+
if (
|
|
1171
|
+
labelAndXy &&
|
|
1172
|
+
isNumericText(label) &&
|
|
1173
|
+
!Number.isInteger(Number(label)) &&
|
|
1174
|
+
!quotedAfterNumber(text, tokens)
|
|
1175
|
+
) {
|
|
1176
|
+
this.report.warnOnce(
|
|
1177
|
+
"validation-error",
|
|
1178
|
+
PAJEK_ISSUE.NUMERIC_LABEL,
|
|
1179
|
+
`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`,
|
|
1180
|
+
{ line, element: String(k) },
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
/**
|
|
1186
|
+
* Write a vertex's coordinates into the position column (f32 x 3), declared on first use.
|
|
1187
|
+
* @param index - the node index
|
|
1188
|
+
* @param dims - 2 or 3, the coordinates the line gave
|
|
1189
|
+
* @param point - x, y, z (0 when absent)
|
|
1190
|
+
* @param k - the vertex number
|
|
1191
|
+
* @param line - the line number
|
|
1192
|
+
*/
|
|
1193
|
+
private writePosition(index: number, dims: number, point: readonly number[], k: number, line: number): void {
|
|
1194
|
+
if (this.positionHandle === INVALID_INDEX) {
|
|
1195
|
+
this.coordDims = dims;
|
|
1196
|
+
this.positionHandle = declareResolved(this.sink, "node", positionDecl(dims), this.report, { line }).handle;
|
|
1197
|
+
} else if (dims !== this.coordDims) {
|
|
1198
|
+
this.report.warnOnce(
|
|
1199
|
+
"validation-error",
|
|
1200
|
+
PAJEK_ISSUE.COORD_DIMS,
|
|
1201
|
+
`vertex lines mix ${this.coordDims} and ${dims} coordinates; the position column records sourceDims ${this.coordDims}`,
|
|
1202
|
+
{ line, element: String(k) },
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
if (!point.every(survivesF32)) {
|
|
1206
|
+
this.report.warnOnce(
|
|
1207
|
+
"precision",
|
|
1208
|
+
PAJEK_ISSUE.PRECISION,
|
|
1209
|
+
`vertex ${k} has a coordinate the f32 position column rounds (warned once)`,
|
|
1210
|
+
{ line, element: String(k) },
|
|
1211
|
+
`${PAJEK_ISSUE.PRECISION}:position`,
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
this.sink.setNodeValue(this.positionHandle, index, point);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1008
1217
|
/**
|
|
1009
1218
|
* Whether a `graphty_originalId` parameter is restored as the vertex id: restoreMangledIds
|
|
1010
1219
|
* under nodeIdFrom "id" (under "label" / "index" the parameter stays an ordinary column).
|
|
@@ -1023,7 +1232,7 @@ class PajekParser {
|
|
|
1023
1232
|
private numberedNode(ids: NodeId[], pos: number): void {
|
|
1024
1233
|
const id = this.idOfNumber(pos + this.base);
|
|
1025
1234
|
ids[pos] = id;
|
|
1026
|
-
this.indexOfPos[pos] = this.
|
|
1235
|
+
this.indexOfPos[pos] = this.addNode(id);
|
|
1027
1236
|
this.report.counts.nodes++;
|
|
1028
1237
|
}
|
|
1029
1238
|
|
|
@@ -1069,7 +1278,7 @@ class PajekParser {
|
|
|
1069
1278
|
): number {
|
|
1070
1279
|
const id = text === null ? this.idOfNumber(k) : this.coercer.text(text);
|
|
1071
1280
|
const before = this.sink.indexOf(id);
|
|
1072
|
-
const index = this.
|
|
1281
|
+
const index = this.addNode(id);
|
|
1073
1282
|
ids[pos] = id;
|
|
1074
1283
|
this.indexOfPos[pos] = index;
|
|
1075
1284
|
this.report.counts.nodes++;
|
|
@@ -1094,7 +1303,7 @@ class PajekParser {
|
|
|
1094
1303
|
* @param line - the line number
|
|
1095
1304
|
*/
|
|
1096
1305
|
private edgeLine(text: string, line: number): void {
|
|
1097
|
-
let tokens = this.tokens(text, "edge");
|
|
1306
|
+
let tokens = this.tokens(text, "edge", line);
|
|
1098
1307
|
// a `k:` prefix puts this one line in relation k
|
|
1099
1308
|
let { relation } = this;
|
|
1100
1309
|
const prefix = RELATION_PREFIX.exec(tokens[0]);
|
|
@@ -1119,7 +1328,7 @@ class PajekParser {
|
|
|
1119
1328
|
valueText = tokens[i];
|
|
1120
1329
|
i++;
|
|
1121
1330
|
}
|
|
1122
|
-
const extras = this.extras(tokens, i, "edge");
|
|
1331
|
+
const extras = this.extras(tokens, i, "edge", line);
|
|
1123
1332
|
const { weightFrom } = this.options;
|
|
1124
1333
|
let weight: number | undefined;
|
|
1125
1334
|
let valueIsWeight = false;
|
|
@@ -1151,7 +1360,7 @@ class PajekParser {
|
|
|
1151
1360
|
* @param line - the line number
|
|
1152
1361
|
*/
|
|
1153
1362
|
private listLine(text: string, line: number): void {
|
|
1154
|
-
const tokens = this.tokens(text, "edge");
|
|
1363
|
+
const tokens = this.tokens(text, "edge", line);
|
|
1155
1364
|
for (const token of tokens) {
|
|
1156
1365
|
if (!LIST_VERTEX.test(token)) {
|
|
1157
1366
|
this.report.counts.skippedEdges++;
|
|
@@ -1162,6 +1371,14 @@ class PajekParser {
|
|
|
1162
1371
|
);
|
|
1163
1372
|
}
|
|
1164
1373
|
}
|
|
1374
|
+
if (tokens.some((token) => token.startsWith("-"))) {
|
|
1375
|
+
this.report.warnOnce(
|
|
1376
|
+
"coercion",
|
|
1377
|
+
PAJEK_ISSUE.NEGATIVE_LIST_ENTRY,
|
|
1378
|
+
"an adjacency list holds a negative vertex number; it is read as its absolute value and the sign is dropped",
|
|
1379
|
+
{ line },
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1165
1382
|
const u = this.endpoint(Math.abs(Number(tokens[0])));
|
|
1166
1383
|
for (let i = 1; i < tokens.length; i++) {
|
|
1167
1384
|
const v = this.endpoint(Math.abs(Number(tokens[i])));
|
|
@@ -1178,7 +1395,7 @@ class PajekParser {
|
|
|
1178
1395
|
* @param line - the line number
|
|
1179
1396
|
*/
|
|
1180
1397
|
private matrixLine(text: string, line: number): void {
|
|
1181
|
-
const tokens = this.tokens(text, "edge");
|
|
1398
|
+
const tokens = this.tokens(text, "edge", line);
|
|
1182
1399
|
const row = this.matrixRows;
|
|
1183
1400
|
this.matrixRows++;
|
|
1184
1401
|
const offset = this.firstMode ?? 0;
|
|
@@ -1188,14 +1405,14 @@ class PajekParser {
|
|
|
1188
1405
|
throw new LineError(
|
|
1189
1406
|
"validation-error",
|
|
1190
1407
|
PAJEK_ISSUE.MATRIX_ROWS,
|
|
1191
|
-
`*Matrix row ${row + 1} is beyond the ${rows} declared row(
|
|
1408
|
+
`*Matrix row ${row + 1} is beyond the ${rows} declared row${plural(rows)}`,
|
|
1192
1409
|
);
|
|
1193
1410
|
}
|
|
1194
1411
|
if (tokens.length < columns) {
|
|
1195
1412
|
throw new LineError(
|
|
1196
1413
|
"parse-error",
|
|
1197
1414
|
PAJEK_ISSUE.LINE,
|
|
1198
|
-
`*Matrix row ${row + 1} has ${tokens.length} value(
|
|
1415
|
+
`*Matrix row ${row + 1} has ${tokens.length} value${plural(tokens.length)}; the matrix has ${columns} column${plural(columns)}`,
|
|
1199
1416
|
);
|
|
1200
1417
|
}
|
|
1201
1418
|
for (let j = 0; j < columns; j++) {
|
|
@@ -1211,7 +1428,7 @@ class PajekParser {
|
|
|
1211
1428
|
this.report.warnOnce(
|
|
1212
1429
|
"validation-error",
|
|
1213
1430
|
PAJEK_ISSUE.MATRIX_EXTRA,
|
|
1214
|
-
`*Matrix row ${row + 1} has ${tokens.length} value(
|
|
1431
|
+
`*Matrix row ${row + 1} has ${tokens.length} value${plural(tokens.length)} for ${columns} column${plural(columns)}; the extra values are ignored`,
|
|
1215
1432
|
{ line },
|
|
1216
1433
|
);
|
|
1217
1434
|
}
|
|
@@ -1229,10 +1446,11 @@ class PajekParser {
|
|
|
1229
1446
|
* A value line of a `*Partition` (integers) or `*Vector` (numbers): the values of the next
|
|
1230
1447
|
* vertices, usually one per line.
|
|
1231
1448
|
* @param text - the line
|
|
1449
|
+
* @param line - the line number
|
|
1232
1450
|
*/
|
|
1233
|
-
private objectLine(text: string): void {
|
|
1451
|
+
private objectLine(text: string, line: number): void {
|
|
1234
1452
|
const object = this.objects[this.objects.length - 1];
|
|
1235
|
-
const tokens = this.tokens(text, "node");
|
|
1453
|
+
const tokens = this.tokens(text, "node", line);
|
|
1236
1454
|
for (const token of tokens) {
|
|
1237
1455
|
if (!isNumericText(token) || (object.kind === "partition" && !isI32(Number(token)))) {
|
|
1238
1456
|
// keep the later values on their vertices
|
|
@@ -1263,6 +1481,14 @@ class PajekParser {
|
|
|
1263
1481
|
this.directionSet = true;
|
|
1264
1482
|
this.resolver.setHeader(this.kind === "directed", { line });
|
|
1265
1483
|
}
|
|
1484
|
+
if (this.firstMode !== null && u < this.firstMode === v < this.firstMode) {
|
|
1485
|
+
this.report.warnOnce(
|
|
1486
|
+
"validation-error",
|
|
1487
|
+
PAJEK_ISSUE.TWO_MODE_LINE,
|
|
1488
|
+
`a line of the two-mode network joins two vertices of the ${u < this.firstMode ? "first" : "second"} mode`,
|
|
1489
|
+
{ line },
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1266
1492
|
const before = sink.edgeCount;
|
|
1267
1493
|
const e = this.resolver.addEdge(this.idAt(u), this.idAt(v), this.kind, weight, { line });
|
|
1268
1494
|
this.report.counts.edges += sink.edgeCount - before;
|
|
@@ -1331,7 +1557,7 @@ class PajekParser {
|
|
|
1331
1557
|
*/
|
|
1332
1558
|
private weightOf(text: string): number | undefined {
|
|
1333
1559
|
try {
|
|
1334
|
-
return parseWeightText(text);
|
|
1560
|
+
return parseWeightText(text, this.report);
|
|
1335
1561
|
} catch (err) {
|
|
1336
1562
|
this.report.counts.skippedEdges++;
|
|
1337
1563
|
throw err;
|
|
@@ -1344,10 +1570,20 @@ class PajekParser {
|
|
|
1344
1570
|
* Tokenize a data line.
|
|
1345
1571
|
* @param text - the line
|
|
1346
1572
|
* @param domain - what is skipped on an unterminated quote
|
|
1573
|
+
* @param line - the line number
|
|
1347
1574
|
* @returns the tokens (at least one: blank lines never reach here)
|
|
1348
1575
|
*/
|
|
1349
|
-
private tokens(text: string, domain: "node" | "edge"): string[] {
|
|
1350
|
-
const
|
|
1576
|
+
private tokens(text: string, domain: "node" | "edge", line: number): string[] {
|
|
1577
|
+
const notes: TokenNotes = { oddQuote: false };
|
|
1578
|
+
const tokens = tokenize(text, notes);
|
|
1579
|
+
if (notes.oddQuote) {
|
|
1580
|
+
this.report.warnOnce(
|
|
1581
|
+
"coercion",
|
|
1582
|
+
PAJEK_ISSUE.QUOTE_IN_TOKEN,
|
|
1583
|
+
"a double quote inside a token is removed and the parts joined (Pajek has no escape for a quote)",
|
|
1584
|
+
{ line },
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1351
1587
|
if (tokens === null) {
|
|
1352
1588
|
if (domain === "node") {
|
|
1353
1589
|
this.report.counts.skippedNodes++;
|
|
@@ -1365,25 +1601,16 @@ class PajekParser {
|
|
|
1365
1601
|
* @param tokens - the row's tokens
|
|
1366
1602
|
* @param start - the first token to read
|
|
1367
1603
|
* @param domain - what is skipped when the row is malformed
|
|
1604
|
+
* @param line - the line number
|
|
1368
1605
|
* @returns the parsed extras
|
|
1369
1606
|
*/
|
|
1370
|
-
private extras(tokens: readonly string[], start: number, domain: "node" | "edge"): RowExtras {
|
|
1607
|
+
private extras(tokens: readonly string[], start: number, domain: "node" | "edge", line: number): RowExtras {
|
|
1371
1608
|
const extras: RowExtras = { keys: [], values: [], spells: null };
|
|
1372
|
-
|
|
1609
|
+
const seen = new Set<string>();
|
|
1610
|
+
for (let i = start; i < tokens.length; ) {
|
|
1373
1611
|
const token = tokens[i];
|
|
1374
|
-
if (
|
|
1375
|
-
|
|
1376
|
-
const spells = parseIntervals(token);
|
|
1377
|
-
// an empty `[]` is no spell at all
|
|
1378
|
-
extras.spells = spells.length === 0 ? null : spells;
|
|
1379
|
-
} catch (err) {
|
|
1380
|
-
this.skip(domain);
|
|
1381
|
-
throw new LineError(
|
|
1382
|
-
"validation-error",
|
|
1383
|
-
PAJEK_ISSUE.INTERVAL,
|
|
1384
|
-
err instanceof Error ? err.message : String(err),
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1612
|
+
if (token.startsWith("[")) {
|
|
1613
|
+
extras.spells = this.intervals(token, domain);
|
|
1387
1614
|
i++;
|
|
1388
1615
|
continue;
|
|
1389
1616
|
}
|
|
@@ -1395,6 +1622,15 @@ class PajekParser {
|
|
|
1395
1622
|
`parameter "${token}" has no value`,
|
|
1396
1623
|
);
|
|
1397
1624
|
}
|
|
1625
|
+
if (seen.has(token)) {
|
|
1626
|
+
this.report.warning(
|
|
1627
|
+
"merged",
|
|
1628
|
+
PAJEK_ISSUE.DUPLICATE_ATTRIBUTE,
|
|
1629
|
+
`parameter ${JSON.stringify(token)} is given twice on one line; the later value ${JSON.stringify(tokens[i + 1])} stands`,
|
|
1630
|
+
{ line, element: token },
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
seen.add(token);
|
|
1398
1634
|
extras.keys.push(token);
|
|
1399
1635
|
extras.values.push(tokens[i + 1]);
|
|
1400
1636
|
i += 2;
|
|
@@ -1402,6 +1638,34 @@ class PajekParser {
|
|
|
1402
1638
|
return extras;
|
|
1403
1639
|
}
|
|
1404
1640
|
|
|
1641
|
+
/**
|
|
1642
|
+
* The spells of a row's interval token; a malformed one skips the row.
|
|
1643
|
+
* @param token - the token, starting with "["
|
|
1644
|
+
* @param domain - what is skipped when the token is malformed
|
|
1645
|
+
* @returns the spells, or null for an empty `[]`, which is no spell at all
|
|
1646
|
+
*/
|
|
1647
|
+
private intervals(token: string, domain: "node" | "edge"): [number, number][] | null {
|
|
1648
|
+
if (!isIntervalToken(token)) {
|
|
1649
|
+
this.skip(domain);
|
|
1650
|
+
throw new LineError(
|
|
1651
|
+
"validation-error",
|
|
1652
|
+
PAJEK_ISSUE.INTERVAL,
|
|
1653
|
+
`time interval ${token} is not closed by "]"`,
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
try {
|
|
1657
|
+
const spells = parseIntervals(token);
|
|
1658
|
+
return spells.length === 0 ? null : spells;
|
|
1659
|
+
} catch (err) {
|
|
1660
|
+
this.skip(domain);
|
|
1661
|
+
throw new LineError(
|
|
1662
|
+
"validation-error",
|
|
1663
|
+
PAJEK_ISSUE.INTERVAL,
|
|
1664
|
+
err instanceof Error ? err.message : String(err),
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1405
1669
|
/**
|
|
1406
1670
|
* Count a skipped element.
|
|
1407
1671
|
* @param domain - node or edge
|
|
@@ -1449,7 +1713,7 @@ class PajekParser {
|
|
|
1449
1713
|
* @returns true when tokens[1] is the first coordinate
|
|
1450
1714
|
*/
|
|
1451
1715
|
function startsWithCoordinates(text: string, tokens: readonly string[]): boolean {
|
|
1452
|
-
if (text
|
|
1716
|
+
if (quotedAfterNumber(text, tokens)) {
|
|
1453
1717
|
return false;
|
|
1454
1718
|
}
|
|
1455
1719
|
let run = 0;
|
|
@@ -1459,6 +1723,16 @@ function startsWithCoordinates(text: string, tokens: readonly string[]): boolean
|
|
|
1459
1723
|
return run === 2;
|
|
1460
1724
|
}
|
|
1461
1725
|
|
|
1726
|
+
/**
|
|
1727
|
+
* Whether the token after a row's vertex number is written in quotes.
|
|
1728
|
+
* @param text - the line
|
|
1729
|
+
* @param tokens - its tokens
|
|
1730
|
+
* @returns true when the second token was quoted
|
|
1731
|
+
*/
|
|
1732
|
+
function quotedAfterNumber(text: string, tokens: readonly string[]): boolean {
|
|
1733
|
+
return text.trimStart().slice(tokens[0].length).trimStart().startsWith('"');
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1462
1736
|
/**
|
|
1463
1737
|
* Resolve the firstVertex option.
|
|
1464
1738
|
* @param value - the caller's value
|
|
@@ -1481,26 +1755,43 @@ function firstVertexOption(value: unknown): 0 | 1 | "auto" {
|
|
|
1481
1755
|
);
|
|
1482
1756
|
}
|
|
1483
1757
|
|
|
1484
|
-
|
|
1758
|
+
/**
|
|
1759
|
+
* The section a Pajek network starts with, after blank lines and `%` comment lines.
|
|
1760
|
+
* @param text - the head of the input
|
|
1761
|
+
* @returns "vertices" or "network" (lower case), or null when the text starts otherwise
|
|
1762
|
+
*/
|
|
1763
|
+
function headSection(text: string): string | null {
|
|
1764
|
+
let rest = text.trimStart();
|
|
1765
|
+
while (rest.startsWith("%")) {
|
|
1766
|
+
const end = rest.search(/[\r\n]/);
|
|
1767
|
+
rest = end < 0 ? "" : rest.slice(end).trimStart();
|
|
1768
|
+
}
|
|
1769
|
+
return /^\*(vertices|network)\b/i.exec(rest)?.[1].toLowerCase() ?? null;
|
|
1770
|
+
}
|
|
1485
1771
|
|
|
1486
|
-
/**
|
|
1772
|
+
/**
|
|
1773
|
+
* The Pajek NET importer.
|
|
1774
|
+
* @category Built-in formats
|
|
1775
|
+
*/
|
|
1487
1776
|
export const pajekImporter: GraphImporter<PajekImportOptions> = Object.freeze({
|
|
1488
1777
|
format: "pajek",
|
|
1778
|
+
options: Object.freeze(["firstVertex"]),
|
|
1489
1779
|
extensions: Object.freeze([".net", ".paj"]),
|
|
1490
1780
|
mimeTypes: Object.freeze(["text/x-pajek", "text/plain"]),
|
|
1491
1781
|
|
|
1492
1782
|
/**
|
|
1493
|
-
* Confidence that the input is a Pajek network: it starts with `*Vertices` (or `*Network`)
|
|
1783
|
+
* Confidence that the input is a Pajek network: it starts with `*Vertices` (or `*Network`),
|
|
1784
|
+
* after any `%` comment lines.
|
|
1494
1785
|
* @param head - the first bytes
|
|
1495
1786
|
* @returns 0.9 for a `*Vertices` start, 0.8 for `*Network`, 0 otherwise
|
|
1496
1787
|
*/
|
|
1497
1788
|
sniff(head: Uint8Array): number {
|
|
1498
|
-
const text = new TextDecoder("utf-8").decode(head
|
|
1499
|
-
const
|
|
1500
|
-
if (
|
|
1789
|
+
const text = new TextDecoder("utf-8").decode(head);
|
|
1790
|
+
const section = headSection(text.startsWith("\ufeff") ? text.slice(1) : text);
|
|
1791
|
+
if (section === null) {
|
|
1501
1792
|
return 0;
|
|
1502
1793
|
}
|
|
1503
|
-
return
|
|
1794
|
+
return section === "vertices" ? 0.9 : 0.8;
|
|
1504
1795
|
},
|
|
1505
1796
|
|
|
1506
1797
|
/**
|
|
@@ -1515,6 +1806,10 @@ export const pajekImporter: GraphImporter<PajekImportOptions> = Object.freeze({
|
|
|
1515
1806
|
sink: GraphSink,
|
|
1516
1807
|
options?: PajekImportOptions & CommonImportOptions,
|
|
1517
1808
|
): Promise<ImportReport> {
|
|
1809
|
+
if (graphChosen(options)) {
|
|
1810
|
+
// the choice is honored here too, not only by the registry
|
|
1811
|
+
return importChosenGraph(pajekImporter, input, sink, options);
|
|
1812
|
+
}
|
|
1518
1813
|
const resolved = resolveImportOptions(options, DEFAULTS);
|
|
1519
1814
|
const firstVertex = firstVertexOption(options?.firstVertex);
|
|
1520
1815
|
const report = new ImportReportBuilder("pajek", resolved.errorLimit);
|
|
@@ -1526,7 +1821,8 @@ export const pajekImporter: GraphImporter<PajekImportOptions> = Object.freeze({
|
|
|
1526
1821
|
let rest: NetworkCounter | null = null;
|
|
1527
1822
|
let restLine = 0;
|
|
1528
1823
|
let sinceCheck = 0;
|
|
1529
|
-
for await (const
|
|
1824
|
+
for await (const raw of reader) {
|
|
1825
|
+
const text = withoutStrayBom(raw);
|
|
1530
1826
|
if (rest !== null) {
|
|
1531
1827
|
rest.line(text);
|
|
1532
1828
|
} else if (parser.line(text, reader.line)) {
|
|
@@ -1541,10 +1837,12 @@ export const pajekImporter: GraphImporter<PajekImportOptions> = Object.freeze({
|
|
|
1541
1837
|
}
|
|
1542
1838
|
parser.finish();
|
|
1543
1839
|
if (rest !== null) {
|
|
1840
|
+
const objects =
|
|
1841
|
+
rest.objects > 0 ? `; ${rest.objects} *Partition / *Vector object(s) after them are not read` : "";
|
|
1544
1842
|
report.warning(
|
|
1545
1843
|
"unsupported",
|
|
1546
1844
|
PAJEK_ISSUE.MULTIPLE_GRAPHS,
|
|
1547
|
-
`the project file holds ${rest.count} more network(
|
|
1845
|
+
`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}`,
|
|
1548
1846
|
{ line: restLine },
|
|
1549
1847
|
);
|
|
1550
1848
|
}
|
|
@@ -1580,7 +1878,8 @@ export const pajekImporter: GraphImporter<PajekImportOptions> = Object.freeze({
|
|
|
1580
1878
|
// decoding issues belong to the file, so they go to the first network's report
|
|
1581
1879
|
const reader = new LineReader(input, reports[0], resolved);
|
|
1582
1880
|
let sinceCheck = 0;
|
|
1583
|
-
for await (const
|
|
1881
|
+
for await (const raw of reader) {
|
|
1882
|
+
const text = withoutStrayBom(raw);
|
|
1584
1883
|
if (parser.line(text, reader.line)) {
|
|
1585
1884
|
parser.finish();
|
|
1586
1885
|
reports.push(new ImportReportBuilder("pajek", resolved.errorLimit));
|
|
@@ -1598,6 +1897,16 @@ export const pajekImporter: GraphImporter<PajekImportOptions> = Object.freeze({
|
|
|
1598
1897
|
},
|
|
1599
1898
|
});
|
|
1600
1899
|
|
|
1900
|
+
/**
|
|
1901
|
+
* A line without the U+FEFF that starts it: a BOM left at the start of a later line by
|
|
1902
|
+
* concatenated files (the decoder removes only the first; the shared text check reports it).
|
|
1903
|
+
* @param text - the line
|
|
1904
|
+
* @returns the line without a leading U+FEFF
|
|
1905
|
+
*/
|
|
1906
|
+
function withoutStrayBom(text: string): string {
|
|
1907
|
+
return text.codePointAt(0) === 0xfeff ? text.slice(1) : text;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1601
1910
|
/**
|
|
1602
1911
|
* Counts the networks of the rest of a project file by their headers alone, with the parser's
|
|
1603
1912
|
* rule: a network starts at `*Network` after a named or populated one, or at a `*Vertices` after a
|
|
@@ -1608,6 +1917,9 @@ class NetworkCounter {
|
|
|
1608
1917
|
/** Networks started so far (the first header fed opens the first). */
|
|
1609
1918
|
count = 0;
|
|
1610
1919
|
|
|
1920
|
+
/** `*Partition` / `*Vector` objects seen; import() does not read them. */
|
|
1921
|
+
objects = 0;
|
|
1922
|
+
|
|
1611
1923
|
private named = false;
|
|
1612
1924
|
|
|
1613
1925
|
private populated = false;
|
|
@@ -1632,8 +1944,11 @@ class NetworkCounter {
|
|
|
1632
1944
|
return;
|
|
1633
1945
|
}
|
|
1634
1946
|
const { kind } = h;
|
|
1635
|
-
if (kind === "partition" || kind === "vector"
|
|
1947
|
+
if (kind === "partition" || kind === "vector") {
|
|
1636
1948
|
this.afterObjectHeader = true;
|
|
1949
|
+
this.objects++;
|
|
1950
|
+
} else if (kind === "unsupported") {
|
|
1951
|
+
this.afterObjectHeader = isProjectObject(h.keyword);
|
|
1637
1952
|
} else if (kind === "network") {
|
|
1638
1953
|
if (this.count === 0 || this.named || this.populated) {
|
|
1639
1954
|
this.count++;
|
|
@@ -1649,4 +1964,3 @@ class NetworkCounter {
|
|
|
1649
1964
|
}
|
|
1650
1965
|
}
|
|
1651
1966
|
}
|
|
1652
|
-
|