@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
|
@@ -1,2372 +0,0 @@
|
|
|
1
|
-
import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
|
|
2
|
-
const MISSING_ID_CODE = "E_MISSING_ID";
|
|
3
|
-
const MISSING_ENDPOINT_CODE = "E_MISSING_ENDPOINT";
|
|
4
|
-
const DUPLICATE_NODE_CODE = "W_DUPLICATE_NODE";
|
|
5
|
-
const NO_GRAPH_CODE = "E_NO_GRAPH";
|
|
6
|
-
const MULTIPLE_GRAPHS_CODE = "W_MULTIPLE_GRAPHS";
|
|
7
|
-
const EMPTY_INPUT_CODE = "E_EMPTY_INPUT";
|
|
8
|
-
const SYNTAX_CODE = "E_SYNTAX";
|
|
9
|
-
const XML_SYNTAX_CODE = "E_XML_SYNTAX";
|
|
10
|
-
const UNKNOWN_ELEMENT_CODE = "W_UNKNOWN_ELEMENT";
|
|
11
|
-
const STRAY_TEXT_CODE = "W_STRAY_TEXT";
|
|
12
|
-
const UNKNOWN_PARENT_CODE = "E_UNKNOWN_PARENT";
|
|
13
|
-
const HYPEREDGE_CODE = "E_HYPEREDGE";
|
|
14
|
-
const DUPLICATE_KEY_CODE = "E_DUPLICATE_KEY";
|
|
15
|
-
const COLUMN_RENAMED_CODE = "W_COLUMN_RENAMED";
|
|
16
|
-
const ROLE_TAKEN_CODE = "W_ROLE_TAKEN";
|
|
17
|
-
const PRECISION_CODE = "W_PRECISION";
|
|
18
|
-
const ID_MERGED_CODE = "W_ID_MERGED";
|
|
19
|
-
const SINK_OPTION_CODE = "W_SINK_OPTION";
|
|
20
|
-
const OPTION_IGNORED_CODE = "W_OPTION_IGNORED";
|
|
21
|
-
const INVALID_UTF8_CODE = "E_INVALID_UTF8";
|
|
22
|
-
const INVALID_ENCODING_CODE = "E_INVALID_ENCODING";
|
|
23
|
-
const ENCODING_FALLBACK_CODE = "W_ENCODING_FALLBACK";
|
|
24
|
-
const UNKNOWN_ENCODING_CODE = "W_UNKNOWN_ENCODING";
|
|
25
|
-
const DIRECTION_REFUSED_CODE = "W_DIRECTION_REFUSED";
|
|
26
|
-
const DIRECTION_FORCED_CODE = "W_DIRECTION_FORCED";
|
|
27
|
-
const MIXED_DIRECTION_CODE = "E_MIXED_DIRECTION";
|
|
28
|
-
const COUNT_HINT_CODE = "W_COUNT_HINT";
|
|
29
|
-
const UNKNOWN_ATTR_TYPE_CODE = "W_UNKNOWN_ATTR_TYPE";
|
|
30
|
-
const BAD_DEFAULT_CODE = "W_BAD_DEFAULT";
|
|
31
|
-
const BAD_OPTIONS_CODE = "W_BAD_OPTIONS";
|
|
32
|
-
const DUPLICATE_EDGE_ID_CODE = "E_DUPLICATE_EDGE_ID";
|
|
33
|
-
const BAD_VALUE_CODE = "E_BAD_VALUE";
|
|
34
|
-
const WIDENED_CODE = "W_WIDENED";
|
|
35
|
-
const DANGLING_REFERENCE_CODE = "W_DANGLING_REFERENCE";
|
|
36
|
-
const DUPLICATE_ATTRIBUTE_CODE = "W_DUPLICATE_ATTRIBUTE";
|
|
37
|
-
const PARENT_CYCLE_CODE = "E_PARENT_CYCLE";
|
|
38
|
-
const EQUATION_AS_TEXT_CODE = "W_EQUATION_AS_TEXT";
|
|
39
|
-
const STYLES_NOT_IMPORTED_CODE = "W_STYLES_NOT_IMPORTED";
|
|
40
|
-
const BAD_ASPECT_BLOCK_CODE = "E_BAD_ASPECT_BLOCK";
|
|
41
|
-
const ASPECT_ORDER_CODE = "W_ASPECT_ORDER";
|
|
42
|
-
const COUNT_MISMATCH_CODE = "W_COUNT_MISMATCH";
|
|
43
|
-
const STATUS_FAILED_CODE = "E_STATUS_FAILED";
|
|
44
|
-
const STATUS_WARNING_CODE = "W_STATUS_WARNING";
|
|
45
|
-
const TOO_LARGE_CODE = "E_TOO_LARGE";
|
|
46
|
-
const GRAPH_NOT_FOUND_CODE = "E_GRAPH_NOT_FOUND";
|
|
47
|
-
const AMBIGUOUS_GRAPH_NAME_CODE = "E_AMBIGUOUS_GRAPH_NAME";
|
|
48
|
-
const ROLE_DROPPED_CODE = "W_ROLE_DROPPED";
|
|
49
|
-
const PARENTS_DROPPED_CODE = "W_PARENTS_DROPPED";
|
|
50
|
-
const TEMPORAL_DROPPED_CODE = "W_TEMPORAL_DROPPED";
|
|
51
|
-
const MUTUAL_EXPANDED_CODE = "W_MUTUAL_EXPANDED";
|
|
52
|
-
const MUTUAL_AS_UNDIRECTED_CODE = "W_MUTUAL_AS_UNDIRECTED";
|
|
53
|
-
const ID_TEXT_TYPE_CODE = "W_ID_TEXT_TYPE";
|
|
54
|
-
const ID_TEXT_COLLISION_CODE = "E_ID_TEXT_COLLISION";
|
|
55
|
-
const TEMPORAL_TEXT_DROPPED_CODE = "W_TEMPORAL_TEXT_DROPPED";
|
|
56
|
-
const WEIGHT_KEY_CLASH_CODE = "W_WEIGHT_KEY_CLASH";
|
|
57
|
-
const ROLE_ASSUMED_CODE = "W_ROLE_ASSUMED";
|
|
58
|
-
const COLUMN_RENAMED_LOSS_CODE = "W_COLUMN_NAME_CHANGED";
|
|
59
|
-
const EMPTY_COLUMN_DROPPED_CODE = "W_EMPTY_COLUMN_DROPPED";
|
|
60
|
-
const STORAGE_CLASS_CODE = "W_STORAGE_CLASS_CHANGED";
|
|
61
|
-
const INTEGRAL_F64_CODE = "W_INTEGRAL_F64_AS_I32";
|
|
62
|
-
const TEXT_INFERRED_CODE = "W_TEXT_INFERRED";
|
|
63
|
-
const XML_ILLEGAL_CHAR_CODE = "E_XML_ILLEGAL_CHAR";
|
|
64
|
-
const OPTIONS_GAINED_CODE = "W_OPTIONS_GAINED";
|
|
65
|
-
const TIME_TEXT_ROLE = "timeText";
|
|
66
|
-
const TIME_TEXT_SUFFIX = ".text";
|
|
67
|
-
const DATE_TIME$1 = /^(-?[0-9]{4,})-([0-9]{2})-([0-9]{2})(?:[T ]([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\.([0-9]{1,9}))?)?)?(Z|z|[+-][0-9]{2}(?::?[0-9]{2})?)?$/;
|
|
68
|
-
const TIME$1 = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\.([0-9]{1,9}))?)?(Z|z|[+-][0-9]{2}(?::?[0-9]{2})?)?$/;
|
|
69
|
-
const NUMERIC = /^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
|
|
70
|
-
const MS_PER_MINUTE = 6e4;
|
|
71
|
-
const MS_PER_DAY = 864e5;
|
|
72
|
-
function parseTemporal(text, kind) {
|
|
73
|
-
let value;
|
|
74
|
-
switch (kind) {
|
|
75
|
-
case "date":
|
|
76
|
-
case "dateTime":
|
|
77
|
-
case "localDateTime":
|
|
78
|
-
value = parseDateTime(text, kind);
|
|
79
|
-
break;
|
|
80
|
-
case "time":
|
|
81
|
-
case "localTime":
|
|
82
|
-
value = parseTime(text, kind);
|
|
83
|
-
break;
|
|
84
|
-
default: {
|
|
85
|
-
const name = kind;
|
|
86
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `unknown temporal kind ${name}`, { kind: name });
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const canonical = formatTemporal(value, kind);
|
|
90
|
-
return { value, text: canonical === text ? null : text };
|
|
91
|
-
}
|
|
92
|
-
function parseTimeText(text, timeFormat) {
|
|
93
|
-
const trimmed = text.trim();
|
|
94
|
-
switch (timeFormat) {
|
|
95
|
-
case "integer":
|
|
96
|
-
case "double":
|
|
97
|
-
return parseNumericTime(trimmed);
|
|
98
|
-
case "date":
|
|
99
|
-
return parseTemporal(trimmed, "date");
|
|
100
|
-
case "dateTime":
|
|
101
|
-
return parseTemporal(trimmed, "dateTime");
|
|
102
|
-
case null:
|
|
103
|
-
return NUMERIC.test(trimmed) ? parseNumericTime(trimmed) : parseTemporal(trimmed, "dateTime");
|
|
104
|
-
default: {
|
|
105
|
-
const name = timeFormat;
|
|
106
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `unknown timeformat ${name}`, { timeFormat: name });
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function formatTemporal(value, kind) {
|
|
111
|
-
switch (kind) {
|
|
112
|
-
case "date": {
|
|
113
|
-
const d = new Date(value);
|
|
114
|
-
return `${year(d)}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
|
|
115
|
-
}
|
|
116
|
-
case "dateTime":
|
|
117
|
-
case "localDateTime": {
|
|
118
|
-
const d = new Date(value);
|
|
119
|
-
const date = `${year(d)}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
|
|
120
|
-
const time = clock(d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
|
|
121
|
-
return kind === "dateTime" ? `${date}T${time}Z` : `${date}T${time}`;
|
|
122
|
-
}
|
|
123
|
-
case "time":
|
|
124
|
-
case "localTime": {
|
|
125
|
-
const ms = (value % MS_PER_DAY + MS_PER_DAY) % MS_PER_DAY;
|
|
126
|
-
const h = Math.floor(ms / 36e5);
|
|
127
|
-
const m = Math.floor(ms % 36e5 / MS_PER_MINUTE);
|
|
128
|
-
const s = Math.floor(ms % MS_PER_MINUTE / 1e3);
|
|
129
|
-
const text = clock(h, m, s, ms % 1e3);
|
|
130
|
-
return kind === "time" ? `${text}Z` : text;
|
|
131
|
-
}
|
|
132
|
-
default: {
|
|
133
|
-
const name = kind;
|
|
134
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `unknown temporal kind ${name}`, { kind: name });
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function formatTimeValue(value, timeFormat) {
|
|
139
|
-
switch (timeFormat) {
|
|
140
|
-
case "date":
|
|
141
|
-
return formatTemporal(value, "date");
|
|
142
|
-
case "dateTime":
|
|
143
|
-
return formatTemporal(value, "dateTime");
|
|
144
|
-
case "integer":
|
|
145
|
-
case "double":
|
|
146
|
-
case null:
|
|
147
|
-
return String(value);
|
|
148
|
-
default: {
|
|
149
|
-
const name = timeFormat;
|
|
150
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `unknown timeformat ${name}`, { timeFormat: name });
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
function timeTextCompanion(column) {
|
|
155
|
-
return {
|
|
156
|
-
name: column + TIME_TEXT_SUFFIX,
|
|
157
|
-
dtype: "string",
|
|
158
|
-
role: TIME_TEXT_ROLE,
|
|
159
|
-
nullable: true,
|
|
160
|
-
extra: { for: column }
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
function parseNumericTime(text) {
|
|
164
|
-
if (!NUMERIC.test(text)) {
|
|
165
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not a numeric time`, { value: text });
|
|
166
|
-
}
|
|
167
|
-
const value = Number(text);
|
|
168
|
-
return { value, text: String(value) === text ? null : text };
|
|
169
|
-
}
|
|
170
|
-
function parseDateTime(text, kind) {
|
|
171
|
-
const m = DATE_TIME$1.exec(text);
|
|
172
|
-
if (m === null) {
|
|
173
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not an ISO-8601 ${kind}`, { value: text, kind });
|
|
174
|
-
}
|
|
175
|
-
const y = Number(m[1]);
|
|
176
|
-
const month = Number(m[2]);
|
|
177
|
-
const day = Number(m[3]);
|
|
178
|
-
const hour = m[4] === void 0 ? 0 : Number(m[4]);
|
|
179
|
-
const minute = m[5] === void 0 ? 0 : Number(m[5]);
|
|
180
|
-
const second = m[6] === void 0 ? 0 : Number(m[6]);
|
|
181
|
-
const ms = m[7] === void 0 ? 0 : fractionMs(m[7]);
|
|
182
|
-
if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 24 || minute > 59 || second > 60) {
|
|
183
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is out of range for a ${kind}`, { value: text, kind });
|
|
184
|
-
}
|
|
185
|
-
const d = /* @__PURE__ */ new Date(0);
|
|
186
|
-
d.setUTCFullYear(y, month - 1, day);
|
|
187
|
-
d.setUTCHours(hour, minute, second, ms);
|
|
188
|
-
if (d.getUTCDate() !== day && hour !== 24) {
|
|
189
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not a calendar date`, { value: text, kind });
|
|
190
|
-
}
|
|
191
|
-
const offset = m[8] === void 0 ? 0 : offsetMinutes(m[8]);
|
|
192
|
-
return d.getTime() - offset * MS_PER_MINUTE;
|
|
193
|
-
}
|
|
194
|
-
function parseTime(text, kind) {
|
|
195
|
-
const m = TIME$1.exec(text);
|
|
196
|
-
if (m === null) {
|
|
197
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not an ISO-8601 ${kind}`, { value: text, kind });
|
|
198
|
-
}
|
|
199
|
-
const hour = Number(m[1]);
|
|
200
|
-
const minute = Number(m[2]);
|
|
201
|
-
const second = m[3] === void 0 ? 0 : Number(m[3]);
|
|
202
|
-
const ms = m[4] === void 0 ? 0 : fractionMs(m[4]);
|
|
203
|
-
if (hour > 24 || minute > 59 || second > 60) {
|
|
204
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is out of range for a ${kind}`, { value: text, kind });
|
|
205
|
-
}
|
|
206
|
-
const local = ((hour * 60 + minute) * 60 + second) * 1e3 + ms;
|
|
207
|
-
const offset = m[5] === void 0 ? 0 : offsetMinutes(m[5]);
|
|
208
|
-
const utc = local - offset * MS_PER_MINUTE;
|
|
209
|
-
return (utc % MS_PER_DAY + MS_PER_DAY) % MS_PER_DAY;
|
|
210
|
-
}
|
|
211
|
-
function fractionMs(digits) {
|
|
212
|
-
return Math.floor(Number(`0.${digits}`) * 1e3);
|
|
213
|
-
}
|
|
214
|
-
function offsetMinutes(zone) {
|
|
215
|
-
if (zone === "Z" || zone === "z") {
|
|
216
|
-
return 0;
|
|
217
|
-
}
|
|
218
|
-
const sign = zone.startsWith("-") ? -1 : 1;
|
|
219
|
-
const digits = zone.slice(1).replace(":", "");
|
|
220
|
-
const hours = Number(digits.slice(0, 2));
|
|
221
|
-
const minutes = digits.length > 2 ? Number(digits.slice(2, 4)) : 0;
|
|
222
|
-
return sign * (hours * 60 + minutes);
|
|
223
|
-
}
|
|
224
|
-
function pad2(n) {
|
|
225
|
-
return n < 10 ? `0${n}` : String(n);
|
|
226
|
-
}
|
|
227
|
-
function year(d) {
|
|
228
|
-
const y = d.getUTCFullYear();
|
|
229
|
-
const abs = String(Math.abs(y)).padStart(4, "0");
|
|
230
|
-
return y < 0 ? `-${abs}` : abs;
|
|
231
|
-
}
|
|
232
|
-
function clock(h, m, s, ms) {
|
|
233
|
-
const base = `${pad2(h)}:${pad2(m)}:${pad2(s)}`;
|
|
234
|
-
return ms === 0 ? base : `${base}.${String(ms).padStart(3, "0")}`;
|
|
235
|
-
}
|
|
236
|
-
const BOOLEAN = { dtype: "bool", kind: "boolean" };
|
|
237
|
-
const INTEGER = { dtype: "i32", kind: "integer" };
|
|
238
|
-
const LONG = { dtype: "f64", kind: "long", precision: true };
|
|
239
|
-
const FLOAT = { dtype: "f32", kind: "float" };
|
|
240
|
-
const DOUBLE = { dtype: "f64", kind: "double" };
|
|
241
|
-
const STRING = { dtype: "string", kind: "string" };
|
|
242
|
-
const DATE = { dtype: "f64", kind: "temporal", temporal: "date" };
|
|
243
|
-
const DATE_TIME = { dtype: "f64", kind: "temporal", temporal: "dateTime" };
|
|
244
|
-
const LOCAL_DATE_TIME = { dtype: "f64", kind: "temporal", temporal: "localDateTime" };
|
|
245
|
-
const TIME = { dtype: "f64", kind: "temporal", temporal: "time" };
|
|
246
|
-
const LOCAL_TIME = { dtype: "f64", kind: "temporal", temporal: "localTime" };
|
|
247
|
-
const DURATION = { dtype: "string", kind: "duration" };
|
|
248
|
-
const POINT = { dtype: "json", kind: "point" };
|
|
249
|
-
const RECORD = { dtype: "json", kind: "json" };
|
|
250
|
-
const GEXF_SCALARS = {
|
|
251
|
-
integer: INTEGER,
|
|
252
|
-
long: LONG,
|
|
253
|
-
double: DOUBLE,
|
|
254
|
-
float: FLOAT,
|
|
255
|
-
boolean: BOOLEAN,
|
|
256
|
-
string: STRING,
|
|
257
|
-
anyuri: STRING,
|
|
258
|
-
char: STRING,
|
|
259
|
-
byte: INTEGER,
|
|
260
|
-
short: INTEGER,
|
|
261
|
-
bigdecimal: STRING,
|
|
262
|
-
biginteger: STRING,
|
|
263
|
-
date: DATE,
|
|
264
|
-
datetime: DATE_TIME
|
|
265
|
-
};
|
|
266
|
-
const GRAPHML_SCALARS = {
|
|
267
|
-
boolean: BOOLEAN,
|
|
268
|
-
int: INTEGER,
|
|
269
|
-
long: LONG,
|
|
270
|
-
float: FLOAT,
|
|
271
|
-
double: DOUBLE,
|
|
272
|
-
string: STRING
|
|
273
|
-
};
|
|
274
|
-
const GML_SCALARS = {
|
|
275
|
-
int: INTEGER,
|
|
276
|
-
real: DOUBLE,
|
|
277
|
-
string: STRING,
|
|
278
|
-
record: RECORD
|
|
279
|
-
};
|
|
280
|
-
const NEO4J_SCALARS = {
|
|
281
|
-
int: INTEGER,
|
|
282
|
-
integer: LONG,
|
|
283
|
-
long: LONG,
|
|
284
|
-
float: FLOAT,
|
|
285
|
-
double: DOUBLE,
|
|
286
|
-
boolean: BOOLEAN,
|
|
287
|
-
byte: INTEGER,
|
|
288
|
-
short: INTEGER,
|
|
289
|
-
char: STRING,
|
|
290
|
-
string: STRING,
|
|
291
|
-
point: POINT,
|
|
292
|
-
date: DATE,
|
|
293
|
-
localtime: LOCAL_TIME,
|
|
294
|
-
time: TIME,
|
|
295
|
-
localdatetime: LOCAL_DATE_TIME,
|
|
296
|
-
datetime: DATE_TIME,
|
|
297
|
-
duration: DURATION
|
|
298
|
-
};
|
|
299
|
-
const TABLES = {
|
|
300
|
-
gexf: GEXF_SCALARS,
|
|
301
|
-
graphml: GRAPHML_SCALARS,
|
|
302
|
-
gml: GML_SCALARS,
|
|
303
|
-
neo4j: NEO4J_SCALARS
|
|
304
|
-
};
|
|
305
|
-
const INTEGER_TEXT$1 = /^[+-]?[0-9]+$/;
|
|
306
|
-
const DECIMAL_TEXT = /^[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
|
|
307
|
-
const I32_MIN = -2147483648;
|
|
308
|
-
const I32_MAX = 2147483647;
|
|
309
|
-
function mapDeclaredType(format, type, long) {
|
|
310
|
-
const table = TABLES[format];
|
|
311
|
-
let key = type.trim().toLowerCase();
|
|
312
|
-
let list2 = false;
|
|
313
|
-
if (format === "gexf" && key.startsWith("list") && key.length > 4) {
|
|
314
|
-
list2 = true;
|
|
315
|
-
key = key.slice(4);
|
|
316
|
-
} else if (format === "neo4j" && key.endsWith("[]")) {
|
|
317
|
-
list2 = true;
|
|
318
|
-
key = key.slice(0, -2);
|
|
319
|
-
} else if (format === "gml" && key === "list") {
|
|
320
|
-
return {
|
|
321
|
-
declared: type,
|
|
322
|
-
dtype: "list",
|
|
323
|
-
itemDtype: "json",
|
|
324
|
-
kind: "json",
|
|
325
|
-
list: true,
|
|
326
|
-
temporal: null,
|
|
327
|
-
precision: false
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
let entry = table[key];
|
|
331
|
-
if (entry === void 0) {
|
|
332
|
-
return null;
|
|
333
|
-
}
|
|
334
|
-
if (entry.kind === "long" && long === "string") {
|
|
335
|
-
entry = STRING;
|
|
336
|
-
}
|
|
337
|
-
return {
|
|
338
|
-
declared: type,
|
|
339
|
-
dtype: list2 ? "list" : entry.dtype,
|
|
340
|
-
itemDtype: list2 ? entry.dtype : null,
|
|
341
|
-
kind: entry.kind,
|
|
342
|
-
list: list2,
|
|
343
|
-
temporal: entry.temporal ?? null,
|
|
344
|
-
precision: entry.precision ?? false
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
function stringSpec(declared) {
|
|
348
|
-
return {
|
|
349
|
-
declared: declared ?? "",
|
|
350
|
-
dtype: "string",
|
|
351
|
-
itemDtype: null,
|
|
352
|
-
kind: "string",
|
|
353
|
-
list: false,
|
|
354
|
-
temporal: null,
|
|
355
|
-
precision: false
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
function parseScalarText(text, kind, temporal = null) {
|
|
359
|
-
switch (kind) {
|
|
360
|
-
case "boolean": {
|
|
361
|
-
const value = parseBooleanText(text);
|
|
362
|
-
if (value === null) {
|
|
363
|
-
throw typeError(text, kind);
|
|
364
|
-
}
|
|
365
|
-
return value;
|
|
366
|
-
}
|
|
367
|
-
case "integer": {
|
|
368
|
-
const trimmed = text.trim();
|
|
369
|
-
if (!INTEGER_TEXT$1.test(trimmed)) {
|
|
370
|
-
throw typeError(text, kind);
|
|
371
|
-
}
|
|
372
|
-
const value = Number(trimmed);
|
|
373
|
-
if (value < I32_MIN || value > I32_MAX) {
|
|
374
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${trimmed}" is outside the 32-bit integer range`, {
|
|
375
|
-
value: trimmed,
|
|
376
|
-
kind
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
return value;
|
|
380
|
-
}
|
|
381
|
-
case "long": {
|
|
382
|
-
const trimmed = text.trim();
|
|
383
|
-
if (!INTEGER_TEXT$1.test(trimmed)) {
|
|
384
|
-
throw typeError(text, kind);
|
|
385
|
-
}
|
|
386
|
-
return Number(trimmed);
|
|
387
|
-
}
|
|
388
|
-
case "float":
|
|
389
|
-
case "double":
|
|
390
|
-
return parseDecimalText(text, kind);
|
|
391
|
-
case "string":
|
|
392
|
-
case "duration":
|
|
393
|
-
return text;
|
|
394
|
-
case "temporal": {
|
|
395
|
-
if (temporal === null) {
|
|
396
|
-
throw new GraphFormatError("E_COLUMN_TYPE", "a temporal value needs its temporal kind", { kind });
|
|
397
|
-
}
|
|
398
|
-
return parseTemporal(text.trim(), temporal).value;
|
|
399
|
-
}
|
|
400
|
-
case "point":
|
|
401
|
-
return parsePointText(text);
|
|
402
|
-
case "json":
|
|
403
|
-
return parseJsonText(text);
|
|
404
|
-
default: {
|
|
405
|
-
const name = kind;
|
|
406
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `unknown value kind ${name}`, { kind: name });
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
function parseBooleanText(text) {
|
|
411
|
-
switch (text.trim().toLowerCase()) {
|
|
412
|
-
case "true":
|
|
413
|
-
case "1":
|
|
414
|
-
return true;
|
|
415
|
-
case "false":
|
|
416
|
-
case "0":
|
|
417
|
-
return false;
|
|
418
|
-
default:
|
|
419
|
-
return null;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
function parseDecimalText(text, kind = "double") {
|
|
423
|
-
const trimmed = text.trim();
|
|
424
|
-
if (DECIMAL_TEXT.test(trimmed)) {
|
|
425
|
-
return Number(trimmed);
|
|
426
|
-
}
|
|
427
|
-
switch (trimmed) {
|
|
428
|
-
case "INF":
|
|
429
|
-
case "+INF":
|
|
430
|
-
case "Infinity":
|
|
431
|
-
case "+Infinity":
|
|
432
|
-
return Infinity;
|
|
433
|
-
case "-INF":
|
|
434
|
-
case "-Infinity":
|
|
435
|
-
return -Infinity;
|
|
436
|
-
case "NaN":
|
|
437
|
-
return NaN;
|
|
438
|
-
default:
|
|
439
|
-
throw typeError(text, kind);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
function parsePointText(text) {
|
|
443
|
-
const trimmed = text.trim();
|
|
444
|
-
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
445
|
-
throw typeError(text, "point");
|
|
446
|
-
}
|
|
447
|
-
const out = {};
|
|
448
|
-
const inner = trimmed.slice(1, -1).trim();
|
|
449
|
-
if (inner.length === 0) {
|
|
450
|
-
return out;
|
|
451
|
-
}
|
|
452
|
-
for (const part of inner.split(",")) {
|
|
453
|
-
const colon = part.indexOf(":");
|
|
454
|
-
if (colon < 0) {
|
|
455
|
-
throw typeError(text, "point");
|
|
456
|
-
}
|
|
457
|
-
const key = part.slice(0, colon).trim().replace(/^["']|["']$/g, "");
|
|
458
|
-
const raw = part.slice(colon + 1).trim();
|
|
459
|
-
if (key.length === 0) {
|
|
460
|
-
throw typeError(text, "point");
|
|
461
|
-
}
|
|
462
|
-
if (DECIMAL_TEXT.test(raw)) {
|
|
463
|
-
out[key] = Number(raw);
|
|
464
|
-
} else if (raw.startsWith("'") && raw.endsWith("'") || raw.startsWith('"') && raw.endsWith('"')) {
|
|
465
|
-
out[key] = raw.slice(1, -1);
|
|
466
|
-
} else {
|
|
467
|
-
throw typeError(text, "point");
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return out;
|
|
471
|
-
}
|
|
472
|
-
function parseJsonText(text) {
|
|
473
|
-
try {
|
|
474
|
-
return JSON.parse(text);
|
|
475
|
-
} catch {
|
|
476
|
-
throw typeError(text, "json");
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
function typeError(text, kind) {
|
|
480
|
-
const shown = text.length > 40 ? `${text.slice(0, 40)}...` : text;
|
|
481
|
-
return new GraphFormatError("E_COLUMN_TYPE", `"${shown}" is not a ${kind}`, { value: text, kind });
|
|
482
|
-
}
|
|
483
|
-
function splitListText(text, syntax) {
|
|
484
|
-
const trimmed = text.trim();
|
|
485
|
-
if (trimmed.length === 0) {
|
|
486
|
-
return [];
|
|
487
|
-
}
|
|
488
|
-
switch (syntax) {
|
|
489
|
-
case "gexf": {
|
|
490
|
-
if (isBracketed(trimmed)) {
|
|
491
|
-
return splitBracketed(trimmed);
|
|
492
|
-
}
|
|
493
|
-
const separator = firstSeparator(trimmed, ["|", ",", ";"]);
|
|
494
|
-
return separator === null ? [trimmed] : splitOn(trimmed, separator);
|
|
495
|
-
}
|
|
496
|
-
case "brackets":
|
|
497
|
-
return isBracketed(trimmed) ? splitBracketed(trimmed) : [trimmed];
|
|
498
|
-
case "pipe":
|
|
499
|
-
return splitOn(trimmed, "|");
|
|
500
|
-
case "comma":
|
|
501
|
-
return splitOn(trimmed, ",");
|
|
502
|
-
case "semicolon":
|
|
503
|
-
return splitOn(trimmed, ";");
|
|
504
|
-
default: {
|
|
505
|
-
const name = syntax;
|
|
506
|
-
throw new GraphFormatError("E_UNSUPPORTED", `unknown list syntax ${name}`, {
|
|
507
|
-
option: "listSyntax",
|
|
508
|
-
found: name
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
function joinListText(items, syntax) {
|
|
514
|
-
switch (syntax) {
|
|
515
|
-
case "gexf":
|
|
516
|
-
case "brackets":
|
|
517
|
-
return `[${items.map(quoteBracketItem).join(", ")}]`;
|
|
518
|
-
case "pipe":
|
|
519
|
-
return items.join("|");
|
|
520
|
-
case "comma":
|
|
521
|
-
return items.join(",");
|
|
522
|
-
case "semicolon":
|
|
523
|
-
return items.join(";");
|
|
524
|
-
default: {
|
|
525
|
-
const name = syntax;
|
|
526
|
-
throw new GraphFormatError("E_UNSUPPORTED", `unknown list syntax ${name}`, {
|
|
527
|
-
option: "listSyntax",
|
|
528
|
-
found: name
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
function isBracketed(text) {
|
|
534
|
-
return text.length >= 2 && text.startsWith("[") && text.endsWith("]");
|
|
535
|
-
}
|
|
536
|
-
function firstSeparator(text, candidates) {
|
|
537
|
-
for (const candidate of candidates) {
|
|
538
|
-
if (text.includes(candidate)) {
|
|
539
|
-
return candidate;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
function splitOn(text, separator) {
|
|
545
|
-
return text.split(separator).map((item) => item.trim());
|
|
546
|
-
}
|
|
547
|
-
function splitBracketed(text) {
|
|
548
|
-
const inner = text.slice(1, -1);
|
|
549
|
-
const items = [];
|
|
550
|
-
const n = inner.length;
|
|
551
|
-
if (inner.trim().length === 0) {
|
|
552
|
-
return items;
|
|
553
|
-
}
|
|
554
|
-
let i = 0;
|
|
555
|
-
for (; ; ) {
|
|
556
|
-
while (i < n && isSpace(inner.charCodeAt(i))) {
|
|
557
|
-
i++;
|
|
558
|
-
}
|
|
559
|
-
let item = "";
|
|
560
|
-
if (i < n && (inner[i] === '"' || inner[i] === "'")) {
|
|
561
|
-
const quote = inner[i];
|
|
562
|
-
i++;
|
|
563
|
-
while (i < n) {
|
|
564
|
-
if (inner[i] === quote) {
|
|
565
|
-
if (inner[i + 1] === quote) {
|
|
566
|
-
item += quote;
|
|
567
|
-
i += 2;
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
i++;
|
|
571
|
-
break;
|
|
572
|
-
}
|
|
573
|
-
item += inner[i];
|
|
574
|
-
i++;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
let end = inner.indexOf(",", i);
|
|
578
|
-
if (end < 0) {
|
|
579
|
-
end = n;
|
|
580
|
-
}
|
|
581
|
-
item += inner.slice(i, end).trim();
|
|
582
|
-
items.push(item);
|
|
583
|
-
i = end;
|
|
584
|
-
if (i >= n) {
|
|
585
|
-
return items;
|
|
586
|
-
}
|
|
587
|
-
i++;
|
|
588
|
-
if (inner.slice(i).trim().length === 0) {
|
|
589
|
-
items.push("");
|
|
590
|
-
return items;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
function isSpace(c) {
|
|
595
|
-
return c === 32 || c === 9 || c === 13 || c === 10;
|
|
596
|
-
}
|
|
597
|
-
function quoteBracketItem(item) {
|
|
598
|
-
if (item.length === 0 || /[,[\]"']/.test(item) || item !== item.trim()) {
|
|
599
|
-
return `"${item.replace(/"/g, '""')}"`;
|
|
600
|
-
}
|
|
601
|
-
return item;
|
|
602
|
-
}
|
|
603
|
-
const UNKNOWN_TYPE_CODE = UNKNOWN_ATTR_TYPE_CODE;
|
|
604
|
-
const RENAMED_CODE = COLUMN_RENAMED_CODE;
|
|
605
|
-
const DICT_SAMPLE_ROWS = 1024;
|
|
606
|
-
function declareAttribute(input) {
|
|
607
|
-
const issues = [];
|
|
608
|
-
const listSyntax = input.listSyntax ?? "gexf";
|
|
609
|
-
let spec;
|
|
610
|
-
if (input.type === null) {
|
|
611
|
-
spec = stringSpec(null);
|
|
612
|
-
} else {
|
|
613
|
-
const mapped = mapDeclaredType(input.format, input.type, input.long);
|
|
614
|
-
if (mapped === null) {
|
|
615
|
-
spec = stringSpec(input.type);
|
|
616
|
-
issues.push({
|
|
617
|
-
category: "unsupported",
|
|
618
|
-
code: UNKNOWN_TYPE_CODE,
|
|
619
|
-
message: `${input.format} type "${input.type}" is not supported; values kept as text`
|
|
620
|
-
});
|
|
621
|
-
} else {
|
|
622
|
-
spec = mapped;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
const { name, renamed } = resolveName(input);
|
|
626
|
-
if (renamed) {
|
|
627
|
-
issues.push({
|
|
628
|
-
category: "coercion",
|
|
629
|
-
code: RENAMED_CODE,
|
|
630
|
-
message: `attribute "${input.title ?? input.id ?? ""}" renamed to "${name}": the name was taken`
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
const decl = {
|
|
634
|
-
name,
|
|
635
|
-
dtype: spec.dtype,
|
|
636
|
-
nullable: true,
|
|
637
|
-
origin: {
|
|
638
|
-
format: input.format,
|
|
639
|
-
id: input.id,
|
|
640
|
-
title: input.title !== null && input.title !== name ? input.title : null,
|
|
641
|
-
type: input.type,
|
|
642
|
-
namespace: input.namespace ?? null
|
|
643
|
-
}
|
|
644
|
-
};
|
|
645
|
-
if (spec.list) {
|
|
646
|
-
decl.itemDtype = spec.itemDtype ?? "string";
|
|
647
|
-
}
|
|
648
|
-
if (input.role !== void 0 && input.role !== null) {
|
|
649
|
-
decl.role = input.role;
|
|
650
|
-
}
|
|
651
|
-
if (input.dynamic === true) {
|
|
652
|
-
decl.dynamic = true;
|
|
653
|
-
}
|
|
654
|
-
const optionsText = input.optionsText ?? null;
|
|
655
|
-
if (optionsText !== null) {
|
|
656
|
-
try {
|
|
657
|
-
const options = splitListText(optionsText, listSyntax).map((item) => parseItem(item, spec));
|
|
658
|
-
decl.options = options;
|
|
659
|
-
if (spec.dtype === "string" && !spec.list && options.every((o) => typeof o === "string")) {
|
|
660
|
-
decl.dtype = "dict";
|
|
661
|
-
spec = { ...spec, dtype: "dict" };
|
|
662
|
-
}
|
|
663
|
-
} catch (err) {
|
|
664
|
-
issues.push({
|
|
665
|
-
category: "validation-error",
|
|
666
|
-
code: BAD_OPTIONS_CODE,
|
|
667
|
-
message: `options "${optionsText}" of attribute "${name}" do not parse as ${spec.declared}: ${messageOf(err)}`
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
const defaultText = input.defaultText ?? null;
|
|
672
|
-
if (defaultText !== null) {
|
|
673
|
-
try {
|
|
674
|
-
decl.default = parseDeclaredValue(defaultText, spec, listSyntax);
|
|
675
|
-
} catch (err) {
|
|
676
|
-
issues.push({
|
|
677
|
-
category: "validation-error",
|
|
678
|
-
code: BAD_DEFAULT_CODE,
|
|
679
|
-
message: `default "${defaultText}" of attribute "${name}" does not parse as ${spec.declared}: ${messageOf(err)}`
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
const companion = spec.temporal !== null && !spec.list ? timeTextCompanion(name) : null;
|
|
684
|
-
return { decl, spec, listSyntax, companion, renamed, issues };
|
|
685
|
-
}
|
|
686
|
-
function parseDeclaredValue(text, spec, listSyntax) {
|
|
687
|
-
if (spec.list) {
|
|
688
|
-
return splitListText(text, listSyntax).map((item) => parseItem(item, spec));
|
|
689
|
-
}
|
|
690
|
-
return parseItem(text, spec);
|
|
691
|
-
}
|
|
692
|
-
function parseDeclaredTemporal(text, spec) {
|
|
693
|
-
if (spec.temporal === null || spec.list) {
|
|
694
|
-
throw new GraphFormatError("E_COLUMN_TYPE", `"${spec.declared}" is not a scalar temporal type`, {
|
|
695
|
-
declared: spec.declared
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
return parseTemporal(text.trim(), spec.temporal);
|
|
699
|
-
}
|
|
700
|
-
const INTEGER_TEXT = /^[+-]?[0-9]+$/;
|
|
701
|
-
function losesPrecision(spec, text) {
|
|
702
|
-
if (!spec.precision) {
|
|
703
|
-
return false;
|
|
704
|
-
}
|
|
705
|
-
const trimmed = text.trim();
|
|
706
|
-
if (!INTEGER_TEXT.test(trimmed)) {
|
|
707
|
-
return false;
|
|
708
|
-
}
|
|
709
|
-
const n = Number(trimmed);
|
|
710
|
-
return !Number.isFinite(n) || BigInt(trimmed) !== BigInt(n);
|
|
711
|
-
}
|
|
712
|
-
function declareOn(sink, domain, decl) {
|
|
713
|
-
return domain === "node" ? sink.declareNodeColumn(decl) : sink.declareEdgeColumn(decl);
|
|
714
|
-
}
|
|
715
|
-
function declareResolved(sink, domain, decl, report, where) {
|
|
716
|
-
let current = decl;
|
|
717
|
-
let renamed = false;
|
|
718
|
-
let roleDropped = false;
|
|
719
|
-
for (; ; ) {
|
|
720
|
-
try {
|
|
721
|
-
return { handle: declareOn(sink, domain, current), decl: current, renamed, roleDropped };
|
|
722
|
-
} catch (err) {
|
|
723
|
-
if (!(err instanceof GraphFormatError)) {
|
|
724
|
-
throw err;
|
|
725
|
-
}
|
|
726
|
-
if (err.code === "E_COLUMN_EXISTS" && !renamed) {
|
|
727
|
-
const taken = takenIn(sink, domain);
|
|
728
|
-
const id = current.origin?.id ?? null;
|
|
729
|
-
const name = uniqueColumnName(current.name, id, taken);
|
|
730
|
-
report.warning(
|
|
731
|
-
"coercion",
|
|
732
|
-
COLUMN_RENAMED_CODE,
|
|
733
|
-
`${domain} column "${current.name}" renamed to "${name}": the sink already holds that name with another shape`,
|
|
734
|
-
{ ...where, element: where?.element ?? current.name }
|
|
735
|
-
);
|
|
736
|
-
current = { ...current, name };
|
|
737
|
-
renamed = true;
|
|
738
|
-
continue;
|
|
739
|
-
}
|
|
740
|
-
if (err.code === "E_DUPLICATE_ROLE" && current.role !== void 0 && !roleDropped) {
|
|
741
|
-
const holder = typeof err.details.holder === "string" ? err.details.holder : "another column";
|
|
742
|
-
report.warning(
|
|
743
|
-
"coercion",
|
|
744
|
-
ROLE_TAKEN_CODE,
|
|
745
|
-
`${domain} column "${current.name}" loses the ${current.role} role: "${holder}" already holds it`,
|
|
746
|
-
{ ...where, element: where?.element ?? current.name }
|
|
747
|
-
);
|
|
748
|
-
const { role: _role, ...withoutRole } = current;
|
|
749
|
-
current = withoutRole;
|
|
750
|
-
roleDropped = true;
|
|
751
|
-
continue;
|
|
752
|
-
}
|
|
753
|
-
throw err;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
function declareCompanion(sink, domain, companion, report) {
|
|
758
|
-
try {
|
|
759
|
-
return declareOn(sink, domain, companion);
|
|
760
|
-
} catch (err) {
|
|
761
|
-
if (err instanceof GraphFormatError && err.code === "E_DUPLICATE_ROLE") {
|
|
762
|
-
report?.warnOnce(
|
|
763
|
-
"coercion",
|
|
764
|
-
ROLE_TAKEN_CODE,
|
|
765
|
-
`${domain} column "${companion.name}" is declared without the timeText role: another companion holds it (exporters use extra.for)`,
|
|
766
|
-
{ element: companion.name }
|
|
767
|
-
);
|
|
768
|
-
const { role: _role, ...withoutRole } = companion;
|
|
769
|
-
return declareOn(sink, domain, withoutRole);
|
|
770
|
-
}
|
|
771
|
-
throw err;
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
function takenIn(sink, domain) {
|
|
775
|
-
return (name) => (domain === "node" ? sink.nodeColumn(name) : sink.edgeColumn(name)) !== INVALID_INDEX;
|
|
776
|
-
}
|
|
777
|
-
function uniqueColumnName(name, id, taken) {
|
|
778
|
-
if (!taken(name)) {
|
|
779
|
-
return name;
|
|
780
|
-
}
|
|
781
|
-
const base = id === null ? name : `${name}#${id}`;
|
|
782
|
-
if (id !== null && !taken(base)) {
|
|
783
|
-
return base;
|
|
784
|
-
}
|
|
785
|
-
for (let n = 2; ; n++) {
|
|
786
|
-
const candidate = `${base}#${n}`;
|
|
787
|
-
if (!taken(candidate)) {
|
|
788
|
-
return candidate;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
class DictHeuristic {
|
|
793
|
-
/**
|
|
794
|
-
* Create a heuristic.
|
|
795
|
-
* @param sampleRows - rows observed before deciding; DICT_SAMPLE_ROWS by default
|
|
796
|
-
*/
|
|
797
|
-
constructor(sampleRows = DICT_SAMPLE_ROWS) {
|
|
798
|
-
this.distinct = /* @__PURE__ */ new Set();
|
|
799
|
-
this.rowsSeen = 0;
|
|
800
|
-
this.sampleRows = sampleRows;
|
|
801
|
-
}
|
|
802
|
-
/**
|
|
803
|
-
* Rows observed so far.
|
|
804
|
-
* @returns the count
|
|
805
|
-
*/
|
|
806
|
-
get rows() {
|
|
807
|
-
return this.rowsSeen;
|
|
808
|
-
}
|
|
809
|
-
/**
|
|
810
|
-
* Distinct values observed so far.
|
|
811
|
-
* @returns the count
|
|
812
|
-
*/
|
|
813
|
-
get distinctCount() {
|
|
814
|
-
return this.distinct.size;
|
|
815
|
-
}
|
|
816
|
-
/**
|
|
817
|
-
* Whether the sample is full.
|
|
818
|
-
* @returns true once sampleRows values were observed
|
|
819
|
-
*/
|
|
820
|
-
get decided() {
|
|
821
|
-
return this.rowsSeen >= this.sampleRows;
|
|
822
|
-
}
|
|
823
|
-
/**
|
|
824
|
-
* Observe one value.
|
|
825
|
-
* @param value - the value text
|
|
826
|
-
* @returns true when this observation completed the sample
|
|
827
|
-
*/
|
|
828
|
-
observe(value) {
|
|
829
|
-
this.rowsSeen++;
|
|
830
|
-
if (this.distinct.size < this.rowsSeen) {
|
|
831
|
-
this.distinct.add(value);
|
|
832
|
-
}
|
|
833
|
-
return this.rowsSeen === this.sampleRows;
|
|
834
|
-
}
|
|
835
|
-
/**
|
|
836
|
-
* The dtype the sample suggests: dict when the distinct count is below rows / 2 (and at least
|
|
837
|
-
* one row was seen), string otherwise. Valid before the sample is full (end of input).
|
|
838
|
-
* @returns "dict" or "string"
|
|
839
|
-
*/
|
|
840
|
-
decide() {
|
|
841
|
-
return this.rowsSeen > 0 && this.distinct.size * 2 < this.rowsSeen ? "dict" : "string";
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
function resolveName(input) {
|
|
845
|
-
const preferred = input.title !== null && input.title.length > 0 ? input.title : input.id;
|
|
846
|
-
if (preferred === null || preferred.length === 0) {
|
|
847
|
-
throw new GraphFormatError("E_COLUMN_TYPE", "an attribute declaration needs a title or an id", {
|
|
848
|
-
field: "name",
|
|
849
|
-
format: input.format
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
if (input.taken === void 0) {
|
|
853
|
-
return { name: preferred, renamed: false };
|
|
854
|
-
}
|
|
855
|
-
const name = uniqueColumnName(preferred, input.id, input.taken);
|
|
856
|
-
return { name, renamed: name !== preferred };
|
|
857
|
-
}
|
|
858
|
-
function parseItem(text, spec) {
|
|
859
|
-
return parseScalarText(text, spec.kind, spec.temporal);
|
|
860
|
-
}
|
|
861
|
-
function messageOf(err) {
|
|
862
|
-
return err instanceof Error ? err.message : String(err);
|
|
863
|
-
}
|
|
864
|
-
const DIRECTED_COLUMN = "graphty.directed";
|
|
865
|
-
const PAIR_COLUMN = "graphty.pair";
|
|
866
|
-
const MUTUAL_COLUMN = "graphty.mutual";
|
|
867
|
-
const DIRECTED_DECL = { name: DIRECTED_COLUMN, dtype: "bool", role: "directed" };
|
|
868
|
-
const PAIR_DECL = { name: PAIR_COLUMN, dtype: "u32", role: "pair", refersTo: "edge" };
|
|
869
|
-
const MUTUAL_DECL = { name: MUTUAL_COLUMN, dtype: "bool", role: "mutual" };
|
|
870
|
-
class DirectionResolver {
|
|
871
|
-
/**
|
|
872
|
-
* Create a resolver.
|
|
873
|
-
* @param sink - the sink edges are pushed into
|
|
874
|
-
* @param report - the report issues are recorded in
|
|
875
|
-
* @param policy - the resolved onMixedDirection option
|
|
876
|
-
*/
|
|
877
|
-
constructor(sink, report, policy) {
|
|
878
|
-
this.directedHandle = INVALID_INDEX;
|
|
879
|
-
this.pairHandle = INVALID_INDEX;
|
|
880
|
-
this.mutualHandle = INVALID_INDEX;
|
|
881
|
-
this.firstEdge = -1;
|
|
882
|
-
this.nextEdge = -1;
|
|
883
|
-
this.forcedCount = 0;
|
|
884
|
-
this.headerSet = false;
|
|
885
|
-
this.mirrorOfLast = INVALID_INDEX;
|
|
886
|
-
this.sink = sink;
|
|
887
|
-
this.report = report;
|
|
888
|
-
this.policy = policy;
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* The sink's current direction.
|
|
892
|
-
* @returns true when directed
|
|
893
|
-
*/
|
|
894
|
-
get directed() {
|
|
895
|
-
return this.sink.directed;
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Whether the reserved direction columns exist (the sink holds expanded edges).
|
|
899
|
-
* @returns true once graphty.pair was declared or adopted
|
|
900
|
-
*/
|
|
901
|
-
get expanded() {
|
|
902
|
-
return this.pairHandle !== INVALID_INDEX;
|
|
903
|
-
}
|
|
904
|
-
/**
|
|
905
|
-
* Rule 1 of design section 8.4: set the sink's direction from the file's header (or the
|
|
906
|
-
* `defaultDirected` option for a file that declares none) before the first edge. Under the
|
|
907
|
-
* "directed" / "undirected" policies the policy's direction is used instead and the difference
|
|
908
|
-
* is reported. A refusal (E_DIRECTED: locked, or a non-empty directed sink for an undirected
|
|
909
|
-
* header) is recorded as a coercion issue and the sink's direction stands; a non-empty unlocked
|
|
910
|
-
* undirected sink with a directed header is expanded in place.
|
|
911
|
-
* @param headerDirected - the direction the file declares (or the default)
|
|
912
|
-
* @param where - the line of the header, when known
|
|
913
|
-
*/
|
|
914
|
-
setHeader(headerDirected, where) {
|
|
915
|
-
this.headerSet = true;
|
|
916
|
-
let wanted = headerDirected;
|
|
917
|
-
if (this.policy === "directed" || this.policy === "undirected") {
|
|
918
|
-
wanted = this.policy === "directed";
|
|
919
|
-
if (wanted !== headerDirected) {
|
|
920
|
-
this.report.warning(
|
|
921
|
-
"coercion",
|
|
922
|
-
DIRECTION_FORCED_CODE,
|
|
923
|
-
`the file declares ${direction(headerDirected)} edges; read as ${direction(wanted)} per onMixedDirection`,
|
|
924
|
-
{ line: where?.line ?? null }
|
|
925
|
-
);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
const { sink } = this;
|
|
929
|
-
if (sink.directed === wanted) {
|
|
930
|
-
this.adoptExisting();
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
try {
|
|
934
|
-
if (wanted && sink.edgeCount > 0 && !sink.directedLocked) {
|
|
935
|
-
const before = sink.edgeCount;
|
|
936
|
-
sink.setDirected(true, { expand: true });
|
|
937
|
-
this.adoptExpansionColumns();
|
|
938
|
-
this.report.counts.expandedMixed += before;
|
|
939
|
-
} else {
|
|
940
|
-
sink.setDirected(wanted);
|
|
941
|
-
}
|
|
942
|
-
} catch (err) {
|
|
943
|
-
if (!(err instanceof GraphFormatError) || err.code !== "E_DIRECTED") {
|
|
944
|
-
throw err;
|
|
945
|
-
}
|
|
946
|
-
this.report.warning(
|
|
947
|
-
"coercion",
|
|
948
|
-
DIRECTION_REFUSED_CODE,
|
|
949
|
-
`the file is ${direction(wanted)} but the sink is ${direction(sink.directed)} (${reasonOf(err)}); read as ${direction(sink.directed)}`,
|
|
950
|
-
{ line: where?.line ?? null }
|
|
951
|
-
);
|
|
952
|
-
}
|
|
953
|
-
this.adoptExisting();
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* Pick up reserved columns a caller's sink already holds (an earlier expansion), so every edge
|
|
957
|
-
* pushed from now on gets its graphty.directed value.
|
|
958
|
-
*/
|
|
959
|
-
adoptExisting() {
|
|
960
|
-
if (this.pairHandle === INVALID_INDEX && this.sink.edgeColumn(PAIR_COLUMN) !== INVALID_INDEX) {
|
|
961
|
-
this.adoptExpansionColumns();
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
/**
|
|
965
|
-
* The mirror half of the edge most recently pushed by addEdge(), when it was expanded into a
|
|
966
|
-
* pair; INVALID_INDEX otherwise. An importer that learns an edge's weight after pushing it
|
|
967
|
-
* (a GEXF attvalue) sets it on both halves.
|
|
968
|
-
* @returns the mirror's logical index, or INVALID_INDEX
|
|
969
|
-
*/
|
|
970
|
-
get lastMirror() {
|
|
971
|
-
return this.mirrorOfLast;
|
|
972
|
-
}
|
|
973
|
-
/**
|
|
974
|
-
* Rule 2 of design section 8.4: push one source edge. An edge whose direction equals the
|
|
975
|
-
* sink's is one addEdge; one that differs is expanded, forced or refused per the policy.
|
|
976
|
-
* @param source - the source id
|
|
977
|
-
* @param target - the target id
|
|
978
|
-
* @param kind - the edge's direction in the file
|
|
979
|
-
* @param weight - the weight, or undefined when the file gives none
|
|
980
|
-
* @param where - the line and element, for issues
|
|
981
|
-
* @returns the logical index of the (primary) edge
|
|
982
|
-
*/
|
|
983
|
-
addEdge(source, target, kind, weight, where) {
|
|
984
|
-
if (!this.headerSet) {
|
|
985
|
-
throw new GraphFormatError("E_DIRECTED", "DirectionResolver.setHeader() must run before the first edge", {
|
|
986
|
-
reason: "header not set"
|
|
987
|
-
});
|
|
988
|
-
}
|
|
989
|
-
const { sink } = this;
|
|
990
|
-
this.mirrorOfLast = INVALID_INDEX;
|
|
991
|
-
const edgeDirected = kind !== "undirected";
|
|
992
|
-
if (edgeDirected === sink.directed && kind !== "mutual") {
|
|
993
|
-
const e = sink.addEdge(source, target, weight);
|
|
994
|
-
this.track(e);
|
|
995
|
-
if (this.directedHandle !== INVALID_INDEX) {
|
|
996
|
-
sink.setEdgeValue(this.directedHandle, e, edgeDirected);
|
|
997
|
-
}
|
|
998
|
-
return e;
|
|
999
|
-
}
|
|
1000
|
-
switch (this.policy) {
|
|
1001
|
-
case "directed":
|
|
1002
|
-
case "undirected": {
|
|
1003
|
-
this.forcedCount++;
|
|
1004
|
-
this.report.warnOnce(
|
|
1005
|
-
"coercion",
|
|
1006
|
-
DIRECTION_FORCED_CODE,
|
|
1007
|
-
`${kind} edges read as ${direction(sink.directed)} per onMixedDirection`,
|
|
1008
|
-
where
|
|
1009
|
-
);
|
|
1010
|
-
const e = sink.addEdge(source, target, weight);
|
|
1011
|
-
this.track(e);
|
|
1012
|
-
if (this.directedHandle !== INVALID_INDEX) {
|
|
1013
|
-
sink.setEdgeValue(this.directedHandle, e, sink.directed);
|
|
1014
|
-
}
|
|
1015
|
-
return e;
|
|
1016
|
-
}
|
|
1017
|
-
case "error":
|
|
1018
|
-
this.report.error(
|
|
1019
|
-
"validation-error",
|
|
1020
|
-
MIXED_DIRECTION_CODE,
|
|
1021
|
-
`${kind} edge in a ${direction(sink.directed)} graph (onMixedDirection: "error")`,
|
|
1022
|
-
where
|
|
1023
|
-
);
|
|
1024
|
-
throw this.report.abort("mixed direction refused", { code: MIXED_DIRECTION_CODE });
|
|
1025
|
-
case "expand":
|
|
1026
|
-
return this.expand(source, target, kind, weight, where);
|
|
1027
|
-
default: {
|
|
1028
|
-
const name = this.policy;
|
|
1029
|
-
throw new GraphFormatError("E_UNSUPPORTED", `unknown onMixedDirection ${name}`, {
|
|
1030
|
-
option: "onMixedDirection",
|
|
1031
|
-
found: name
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
/**
|
|
1037
|
-
* How many edges were pushed with a direction other than their own under the forcing policies.
|
|
1038
|
-
* @returns the count
|
|
1039
|
-
*/
|
|
1040
|
-
get forced() {
|
|
1041
|
-
return this.forcedCount;
|
|
1042
|
-
}
|
|
1043
|
-
/**
|
|
1044
|
-
* Expand one edge that differs from the sink's direction.
|
|
1045
|
-
* @param source - the source id
|
|
1046
|
-
* @param target - the target id
|
|
1047
|
-
* @param kind - the edge's direction in the file
|
|
1048
|
-
* @param weight - the weight, or undefined
|
|
1049
|
-
* @param where - the line and element, for issues
|
|
1050
|
-
* @returns the primary edge index
|
|
1051
|
-
*/
|
|
1052
|
-
expand(source, target, kind, weight, where) {
|
|
1053
|
-
const { sink } = this;
|
|
1054
|
-
if (!sink.directed) {
|
|
1055
|
-
try {
|
|
1056
|
-
const before = sink.edgeCount;
|
|
1057
|
-
sink.setDirected(true, { expand: true });
|
|
1058
|
-
this.adoptExpansionColumns();
|
|
1059
|
-
this.report.counts.expandedMixed += before;
|
|
1060
|
-
} catch (err) {
|
|
1061
|
-
if (!(err instanceof GraphFormatError) || err.code !== "E_DIRECTED") {
|
|
1062
|
-
throw err;
|
|
1063
|
-
}
|
|
1064
|
-
this.report.error(
|
|
1065
|
-
"coercion",
|
|
1066
|
-
DIRECTION_REFUSED_CODE,
|
|
1067
|
-
`${direction(true)} edge in a locked ${direction(false)} sink cannot be expanded`,
|
|
1068
|
-
where
|
|
1069
|
-
);
|
|
1070
|
-
throw this.report.abort("the sink refused the expansion to directed", {
|
|
1071
|
-
code: DIRECTION_REFUSED_CODE,
|
|
1072
|
-
reason: err.details.reason
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
if (kind === "directed") {
|
|
1076
|
-
const e = sink.addEdge(source, target, weight);
|
|
1077
|
-
this.track(e);
|
|
1078
|
-
sink.setEdgeValue(this.directedHandle, e, true);
|
|
1079
|
-
return e;
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
this.ensureExpansionColumns();
|
|
1083
|
-
const first = sink.addEdge(source, target, weight);
|
|
1084
|
-
this.track(first);
|
|
1085
|
-
const mutual = kind === "mutual";
|
|
1086
|
-
sink.setEdgeValue(this.directedHandle, first, mutual);
|
|
1087
|
-
this.report.counts.expandedMixed++;
|
|
1088
|
-
if (mutual) {
|
|
1089
|
-
this.ensureMutualColumn();
|
|
1090
|
-
sink.setEdgeValue(this.mutualHandle, first, true);
|
|
1091
|
-
}
|
|
1092
|
-
const u = sink.indexOf(source);
|
|
1093
|
-
const v = sink.indexOf(target);
|
|
1094
|
-
if (u === v) {
|
|
1095
|
-
return first;
|
|
1096
|
-
}
|
|
1097
|
-
const mirror = sink.addEdge(target, source, weight);
|
|
1098
|
-
this.track(mirror);
|
|
1099
|
-
this.mirrorOfLast = mirror;
|
|
1100
|
-
sink.setEdgeValue(this.directedHandle, mirror, mutual);
|
|
1101
|
-
sink.setEdgeValue(this.pairHandle, first, mirror);
|
|
1102
|
-
sink.setEdgeValue(this.pairHandle, mirror, first);
|
|
1103
|
-
return first;
|
|
1104
|
-
}
|
|
1105
|
-
/**
|
|
1106
|
-
* Note an edge index this resolver pushed, for the backfill of graphty.directed.
|
|
1107
|
-
* @param e - the edge index
|
|
1108
|
-
*/
|
|
1109
|
-
track(e) {
|
|
1110
|
-
if (this.firstEdge < 0) {
|
|
1111
|
-
this.firstEdge = e;
|
|
1112
|
-
}
|
|
1113
|
-
this.nextEdge = e + 1;
|
|
1114
|
-
}
|
|
1115
|
-
/**
|
|
1116
|
-
* Pick up the reserved columns the builder wrote during its own expansion.
|
|
1117
|
-
*/
|
|
1118
|
-
adoptExpansionColumns() {
|
|
1119
|
-
this.directedHandle = this.sink.declareEdgeColumn(DIRECTED_DECL);
|
|
1120
|
-
this.pairHandle = this.sink.declareEdgeColumn(PAIR_DECL);
|
|
1121
|
-
}
|
|
1122
|
-
/**
|
|
1123
|
-
* Declare the reserved columns on first use in a directed sink and backfill graphty.directed
|
|
1124
|
-
* = true for every edge this resolver pushed so far (they were directed in the source).
|
|
1125
|
-
*/
|
|
1126
|
-
ensureExpansionColumns() {
|
|
1127
|
-
if (this.pairHandle !== INVALID_INDEX) {
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
this.directedHandle = this.sink.declareEdgeColumn(DIRECTED_DECL);
|
|
1131
|
-
this.pairHandle = this.sink.declareEdgeColumn(PAIR_DECL);
|
|
1132
|
-
if (this.firstEdge >= 0) {
|
|
1133
|
-
for (let e = this.firstEdge; e < this.nextEdge; e++) {
|
|
1134
|
-
this.sink.setEdgeValue(this.directedHandle, e, true);
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
/** Declare graphty.mutual on first use. */
|
|
1139
|
-
ensureMutualColumn() {
|
|
1140
|
-
if (this.mutualHandle === INVALID_INDEX) {
|
|
1141
|
-
this.mutualHandle = this.sink.declareEdgeColumn(MUTUAL_DECL);
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
function reasonOf(err) {
|
|
1146
|
-
const { reason } = err.details;
|
|
1147
|
-
return typeof reason === "string" ? reason : "refused";
|
|
1148
|
-
}
|
|
1149
|
-
function direction(directed) {
|
|
1150
|
-
return directed ? "directed" : "undirected";
|
|
1151
|
-
}
|
|
1152
|
-
function pairFolding(snapshot, options = {}) {
|
|
1153
|
-
const foldMutual = options.foldMutual ?? false;
|
|
1154
|
-
const directedColumn = roleColumn(snapshot.edges.byRole("directed"), "bool");
|
|
1155
|
-
const pairColumn = roleColumn(snapshot.edges.byRole("pair"), "u32");
|
|
1156
|
-
const mutualColumn = roleColumn(snapshot.edges.byRole("mutual"), "bool");
|
|
1157
|
-
const { edgeCount } = snapshot;
|
|
1158
|
-
const mateOf = (e) => {
|
|
1159
|
-
if (pairColumn === null || !pairColumn.isSet(e)) {
|
|
1160
|
-
return INVALID_INDEX;
|
|
1161
|
-
}
|
|
1162
|
-
const mate = pairColumn.value(e);
|
|
1163
|
-
return typeof mate === "number" && mate !== INVALID_INDEX ? mate : INVALID_INDEX;
|
|
1164
|
-
};
|
|
1165
|
-
const sourceDirected = (e) => directedColumn === null || !directedColumn.isSet(e) || directedColumn.value(e) === true;
|
|
1166
|
-
const isMutual = (e) => {
|
|
1167
|
-
if (mutualColumn === null) {
|
|
1168
|
-
return false;
|
|
1169
|
-
}
|
|
1170
|
-
if (mutualColumn.isSet(e) && mutualColumn.value(e) === true) {
|
|
1171
|
-
return true;
|
|
1172
|
-
}
|
|
1173
|
-
const mate = mateOf(e);
|
|
1174
|
-
return mate !== INVALID_INDEX && mutualColumn.isSet(mate) && mutualColumn.value(mate) === true;
|
|
1175
|
-
};
|
|
1176
|
-
const folded = (e) => {
|
|
1177
|
-
const mate = mateOf(e);
|
|
1178
|
-
if (mate === INVALID_INDEX || mate >= e) {
|
|
1179
|
-
return false;
|
|
1180
|
-
}
|
|
1181
|
-
return !sourceDirected(e) || foldMutual && isMutual(e);
|
|
1182
|
-
};
|
|
1183
|
-
let mutualCount = 0;
|
|
1184
|
-
if (mutualColumn !== null) {
|
|
1185
|
-
for (let e = 0; e < edgeCount; e++) {
|
|
1186
|
-
if (mutualColumn.isSet(e) && mutualColumn.value(e) === true && mateOf(e) > e) {
|
|
1187
|
-
mutualCount++;
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
return { expanded: pairColumn !== null, mutualCount, folded, mateOf, sourceDirected, isMutual };
|
|
1192
|
-
}
|
|
1193
|
-
function roleColumn(column, dtype) {
|
|
1194
|
-
return column !== null && column.dtype === dtype ? column : null;
|
|
1195
|
-
}
|
|
1196
|
-
const CANONICAL_INTEGER = /^-?(0|[1-9][0-9]*)$/;
|
|
1197
|
-
function canonicalId(text) {
|
|
1198
|
-
if (text !== "-0" && CANONICAL_INTEGER.test(text)) {
|
|
1199
|
-
const n = Number(text);
|
|
1200
|
-
if (Number.isSafeInteger(n)) {
|
|
1201
|
-
return n;
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
return text;
|
|
1205
|
-
}
|
|
1206
|
-
function isCanonicalIntegerText(text) {
|
|
1207
|
-
return typeof canonicalId(text) === "number";
|
|
1208
|
-
}
|
|
1209
|
-
function coerceIdText(text, mode) {
|
|
1210
|
-
switch (mode) {
|
|
1211
|
-
case "keep":
|
|
1212
|
-
case "string":
|
|
1213
|
-
return text;
|
|
1214
|
-
case "canonical":
|
|
1215
|
-
return canonicalId(text);
|
|
1216
|
-
case "number": {
|
|
1217
|
-
if (text.trim().length === 0) {
|
|
1218
|
-
throw invalidId(text, "empty text is not a number");
|
|
1219
|
-
}
|
|
1220
|
-
const n = Number(text);
|
|
1221
|
-
if (!Number.isFinite(n)) {
|
|
1222
|
-
throw invalidId(text, "not a finite number");
|
|
1223
|
-
}
|
|
1224
|
-
return n;
|
|
1225
|
-
}
|
|
1226
|
-
default: {
|
|
1227
|
-
const name = mode;
|
|
1228
|
-
throw new GraphFormatError("E_UNSUPPORTED", `unknown id coercion ${name}`, { option: "ids", found: name });
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
function coerceId(value, mode) {
|
|
1233
|
-
if (typeof value === "string") {
|
|
1234
|
-
return coerceIdText(value, mode);
|
|
1235
|
-
}
|
|
1236
|
-
if (typeof value === "number") {
|
|
1237
|
-
if (!Number.isFinite(value)) {
|
|
1238
|
-
throw invalidId(value, "not a finite number");
|
|
1239
|
-
}
|
|
1240
|
-
return mode === "string" ? String(value) : value;
|
|
1241
|
-
}
|
|
1242
|
-
if (mode === "string" && (typeof value === "boolean" || typeof value === "bigint" || value === null)) {
|
|
1243
|
-
return String(value);
|
|
1244
|
-
}
|
|
1245
|
-
throw invalidId(value, `a ${value === null ? "null" : typeof value} is not an id under ids: "${mode}"`);
|
|
1246
|
-
}
|
|
1247
|
-
function invalidId(value, reason) {
|
|
1248
|
-
const shown = typeof value === "string" || typeof value === "number" ? value : typeof value;
|
|
1249
|
-
return new GraphFormatError("E_INVALID_ID", `invalid node id ${JSON.stringify(shown)}: ${reason}`, {
|
|
1250
|
-
reason,
|
|
1251
|
-
value: typeof value === "bigint" ? value.toString() : value
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
class IdCoercer {
|
|
1255
|
-
/**
|
|
1256
|
-
* Create a coercer.
|
|
1257
|
-
* @param mode - the rule
|
|
1258
|
-
*/
|
|
1259
|
-
constructor(mode) {
|
|
1260
|
-
this.mergeCount = 0;
|
|
1261
|
-
this.lastMerge = null;
|
|
1262
|
-
this.mode = mode;
|
|
1263
|
-
this.firstText = mode === "number" ? /* @__PURE__ */ new Map() : null;
|
|
1264
|
-
}
|
|
1265
|
-
/**
|
|
1266
|
-
* Coerce a text cell, recording a merge under "number" when a different text already produced
|
|
1267
|
-
* the same number.
|
|
1268
|
-
* @param text - the cell text
|
|
1269
|
-
* @returns the id
|
|
1270
|
-
*/
|
|
1271
|
-
text(text) {
|
|
1272
|
-
const id = coerceIdText(text, this.mode);
|
|
1273
|
-
this.lastMerge = null;
|
|
1274
|
-
if (this.firstText !== null && typeof id === "number") {
|
|
1275
|
-
const previous = this.firstText.get(id);
|
|
1276
|
-
if (previous === void 0) {
|
|
1277
|
-
this.firstText.set(id, text);
|
|
1278
|
-
} else if (previous !== text) {
|
|
1279
|
-
this.mergeCount++;
|
|
1280
|
-
this.lastMerge = { id, text, previousText: previous };
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
return id;
|
|
1284
|
-
}
|
|
1285
|
-
/**
|
|
1286
|
-
* Coerce a typed value.
|
|
1287
|
-
* @param value - the value
|
|
1288
|
-
* @returns the id
|
|
1289
|
-
*/
|
|
1290
|
-
value(value) {
|
|
1291
|
-
if (typeof value === "string") {
|
|
1292
|
-
return this.text(value);
|
|
1293
|
-
}
|
|
1294
|
-
this.lastMerge = null;
|
|
1295
|
-
return coerceId(value, this.mode);
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
const HEAD_BYTES = 1024;
|
|
1299
|
-
const BOM_BYTES = 3;
|
|
1300
|
-
function canonicalEncoding(label) {
|
|
1301
|
-
try {
|
|
1302
|
-
return new TextDecoder(label.trim()).encoding;
|
|
1303
|
-
} catch {
|
|
1304
|
-
return null;
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
function bomEncoding(head) {
|
|
1308
|
-
if (head.byteLength >= 3 && head[0] === 239 && head[1] === 187 && head[2] === 191) {
|
|
1309
|
-
return "utf-8";
|
|
1310
|
-
}
|
|
1311
|
-
if (head.byteLength >= 2 && head[0] === 255 && head[1] === 254) {
|
|
1312
|
-
return "utf-16le";
|
|
1313
|
-
}
|
|
1314
|
-
if (head.byteLength >= 2 && head[0] === 254 && head[1] === 255) {
|
|
1315
|
-
return "utf-16be";
|
|
1316
|
-
}
|
|
1317
|
-
return null;
|
|
1318
|
-
}
|
|
1319
|
-
class ByteDecoder {
|
|
1320
|
-
/**
|
|
1321
|
-
* Create the decoder of one import.
|
|
1322
|
-
* @param report - where warnings and the fatal decode error go
|
|
1323
|
-
* @param options - the encoding option and the format's declaration reader
|
|
1324
|
-
*/
|
|
1325
|
-
constructor(report, options) {
|
|
1326
|
-
this.report = report;
|
|
1327
|
-
this.options = options;
|
|
1328
|
-
this.decoder = null;
|
|
1329
|
-
this.encoding = "utf-8";
|
|
1330
|
-
this.mayFallBack = false;
|
|
1331
|
-
this.asciiSoFar = true;
|
|
1332
|
-
this.carry = new Uint8Array(0);
|
|
1333
|
-
this.offset = 0;
|
|
1334
|
-
}
|
|
1335
|
-
/**
|
|
1336
|
-
* Whether start() ran.
|
|
1337
|
-
* @returns true once the encoding is chosen
|
|
1338
|
-
*/
|
|
1339
|
-
get started() {
|
|
1340
|
-
return this.decoder !== null;
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* Choose the encoding from the first bytes of the input.
|
|
1344
|
-
* @param head - the first bytes (up to HEAD_BYTES; fewer when the input is shorter)
|
|
1345
|
-
*/
|
|
1346
|
-
start(head) {
|
|
1347
|
-
const explicit = this.options.encoding ?? null;
|
|
1348
|
-
if (explicit !== null) {
|
|
1349
|
-
this.use(explicit, false);
|
|
1350
|
-
return;
|
|
1351
|
-
}
|
|
1352
|
-
const bom = bomEncoding(head);
|
|
1353
|
-
if (bom !== null) {
|
|
1354
|
-
this.use(bom, false);
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
const declared = this.options.declaredEncoding?.(new TextDecoder("windows-1252").decode(head)) ?? null;
|
|
1358
|
-
if (declared !== null) {
|
|
1359
|
-
const canonical = canonicalEncoding(declared);
|
|
1360
|
-
if (canonical === null) {
|
|
1361
|
-
this.report.warning(
|
|
1362
|
-
"unsupported",
|
|
1363
|
-
UNKNOWN_ENCODING_CODE,
|
|
1364
|
-
`the input declares the encoding ${JSON.stringify(declared)}, which this platform cannot decode; reading it as UTF-8`,
|
|
1365
|
-
{ element: declared }
|
|
1366
|
-
);
|
|
1367
|
-
} else if (canonical !== "utf-8" && !canonical.startsWith("utf-16")) {
|
|
1368
|
-
this.use(canonical, false);
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
this.use("utf-8", true);
|
|
1373
|
-
}
|
|
1374
|
-
/**
|
|
1375
|
-
* Decode the next bytes.
|
|
1376
|
-
* @param bytes - the bytes
|
|
1377
|
-
* @param stream - whether more bytes follow
|
|
1378
|
-
* @returns the text
|
|
1379
|
-
*/
|
|
1380
|
-
decode(bytes, stream) {
|
|
1381
|
-
const decoder = this.decoder;
|
|
1382
|
-
let text;
|
|
1383
|
-
try {
|
|
1384
|
-
text = decoder.decode(bytes, { stream });
|
|
1385
|
-
} catch (err) {
|
|
1386
|
-
if (!(err instanceof TypeError)) {
|
|
1387
|
-
throw err;
|
|
1388
|
-
}
|
|
1389
|
-
text = this.recover(bytes, stream);
|
|
1390
|
-
}
|
|
1391
|
-
if (this.asciiSoFar && this.mayFallBack) {
|
|
1392
|
-
if (/[\u0080-\uffff]/.test(text)) {
|
|
1393
|
-
this.asciiSoFar = false;
|
|
1394
|
-
this.carry = new Uint8Array(0);
|
|
1395
|
-
} else {
|
|
1396
|
-
const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);
|
|
1397
|
-
this.carry = all.slice(text.length);
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
this.offset += bytes.byteLength;
|
|
1401
|
-
return text;
|
|
1402
|
-
}
|
|
1403
|
-
/**
|
|
1404
|
-
* A decode failed: switch to windows-1252 when allowed, else fail the import.
|
|
1405
|
-
* @param bytes - the bytes that failed
|
|
1406
|
-
* @param stream - whether more bytes follow
|
|
1407
|
-
* @returns the bytes decoded as windows-1252
|
|
1408
|
-
*/
|
|
1409
|
-
recover(bytes, stream) {
|
|
1410
|
-
const where = { byteOffset: this.offset };
|
|
1411
|
-
const all = this.carry.byteLength === 0 ? bytes : concatBytes([this.carry, bytes]);
|
|
1412
|
-
if (this.mayFallBack && this.asciiSoFar && !all.includes(0) && !startsWithUtf8(all)) {
|
|
1413
|
-
this.report.warning(
|
|
1414
|
-
"coercion",
|
|
1415
|
-
ENCODING_FALLBACK_CODE,
|
|
1416
|
-
`the input is not valid UTF-8 (near byte ${this.offset}) and declares no encoding; read as windows-1252 (pass the encoding option to choose another)`
|
|
1417
|
-
);
|
|
1418
|
-
this.use("windows-1252", false);
|
|
1419
|
-
return this.decoder.decode(all, { stream });
|
|
1420
|
-
}
|
|
1421
|
-
if (this.encoding === "utf-8") {
|
|
1422
|
-
const after = this.mayFallBack ? " after valid non-ASCII UTF-8 text; pass the encoding option" : "";
|
|
1423
|
-
return this.report.fail(
|
|
1424
|
-
INVALID_UTF8_CODE,
|
|
1425
|
-
`invalid UTF-8 near byte ${this.offset}${after}`,
|
|
1426
|
-
void 0,
|
|
1427
|
-
where
|
|
1428
|
-
);
|
|
1429
|
-
}
|
|
1430
|
-
return this.report.fail(
|
|
1431
|
-
INVALID_ENCODING_CODE,
|
|
1432
|
-
`the bytes near byte ${this.offset} are not valid ${this.encoding}`,
|
|
1433
|
-
void 0,
|
|
1434
|
-
where
|
|
1435
|
-
);
|
|
1436
|
-
}
|
|
1437
|
-
/**
|
|
1438
|
-
* Switch to an encoding.
|
|
1439
|
-
* @param label - the encoding label
|
|
1440
|
-
* @param mayFallBack - whether a UTF-8 failure may switch to windows-1252
|
|
1441
|
-
*/
|
|
1442
|
-
use(label, mayFallBack) {
|
|
1443
|
-
this.decoder = new TextDecoder(label, { fatal: true, ignoreBOM: true });
|
|
1444
|
-
this.encoding = this.decoder.encoding;
|
|
1445
|
-
this.mayFallBack = mayFallBack;
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
function startsWithUtf8(bytes) {
|
|
1449
|
-
const i = bytes.findIndex((b) => b >= 128);
|
|
1450
|
-
const lead = bytes[i];
|
|
1451
|
-
let length = 0;
|
|
1452
|
-
if (lead >= 194 && lead <= 223) {
|
|
1453
|
-
length = 2;
|
|
1454
|
-
} else if (lead >= 224 && lead <= 239) {
|
|
1455
|
-
length = 3;
|
|
1456
|
-
} else if (lead >= 240 && lead <= 244) {
|
|
1457
|
-
length = 4;
|
|
1458
|
-
}
|
|
1459
|
-
if (i < 0 || length === 0 || i + length > bytes.byteLength) {
|
|
1460
|
-
return false;
|
|
1461
|
-
}
|
|
1462
|
-
try {
|
|
1463
|
-
new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(i, i + length));
|
|
1464
|
-
return true;
|
|
1465
|
-
} catch {
|
|
1466
|
-
return false;
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
function decodeEntryName(bytes) {
|
|
1470
|
-
try {
|
|
1471
|
-
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
1472
|
-
} catch {
|
|
1473
|
-
return new TextDecoder("windows-1252").decode(bytes);
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
function concatBytes(chunks) {
|
|
1477
|
-
if (chunks.length === 1) {
|
|
1478
|
-
return chunks[0];
|
|
1479
|
-
}
|
|
1480
|
-
const out = new Uint8Array(chunks.reduce((sum, c) => sum + c.byteLength, 0));
|
|
1481
|
-
let offset = 0;
|
|
1482
|
-
for (const chunk of chunks) {
|
|
1483
|
-
out.set(chunk, offset);
|
|
1484
|
-
offset += chunk.byteLength;
|
|
1485
|
-
}
|
|
1486
|
-
return out;
|
|
1487
|
-
}
|
|
1488
|
-
const DECODE_SLICE = 256 * 1024;
|
|
1489
|
-
const BOM = String.fromCharCode(65279);
|
|
1490
|
-
function isImportInput(input) {
|
|
1491
|
-
if (typeof input === "string" || input instanceof Uint8Array) {
|
|
1492
|
-
return true;
|
|
1493
|
-
}
|
|
1494
|
-
if (typeof input !== "object" || input === null) {
|
|
1495
|
-
return false;
|
|
1496
|
-
}
|
|
1497
|
-
return typeof input.getReader === "function" || Symbol.asyncIterator in input;
|
|
1498
|
-
}
|
|
1499
|
-
function inputLength(input) {
|
|
1500
|
-
if (typeof input === "string") {
|
|
1501
|
-
return input.length;
|
|
1502
|
-
}
|
|
1503
|
-
if (input instanceof Uint8Array) {
|
|
1504
|
-
return input.byteLength;
|
|
1505
|
-
}
|
|
1506
|
-
return null;
|
|
1507
|
-
}
|
|
1508
|
-
function throwIfAborted(signal) {
|
|
1509
|
-
if (signal === null || signal === void 0 || !signal.aborted) {
|
|
1510
|
-
return;
|
|
1511
|
-
}
|
|
1512
|
-
const { reason } = signal;
|
|
1513
|
-
if (reason === void 0) {
|
|
1514
|
-
throw abortError();
|
|
1515
|
-
}
|
|
1516
|
-
throw reason;
|
|
1517
|
-
}
|
|
1518
|
-
function abortError() {
|
|
1519
|
-
const message = "The import was aborted";
|
|
1520
|
-
if (typeof DOMException === "function") {
|
|
1521
|
-
return new DOMException(message, "AbortError");
|
|
1522
|
-
}
|
|
1523
|
-
const err = new Error(message);
|
|
1524
|
-
err.name = "AbortError";
|
|
1525
|
-
return err;
|
|
1526
|
-
}
|
|
1527
|
-
async function* textChunks(input, report, options = {}) {
|
|
1528
|
-
const signal = options.signal ?? null;
|
|
1529
|
-
const onProgress = options.onProgress ?? null;
|
|
1530
|
-
const total = inputLength(input);
|
|
1531
|
-
let done = 0;
|
|
1532
|
-
let first = true;
|
|
1533
|
-
const emit = (text) => {
|
|
1534
|
-
if (first && text.length > 0) {
|
|
1535
|
-
first = false;
|
|
1536
|
-
return text.startsWith(BOM) ? text.slice(1) : text;
|
|
1537
|
-
}
|
|
1538
|
-
return text;
|
|
1539
|
-
};
|
|
1540
|
-
throwIfAborted(signal);
|
|
1541
|
-
if (typeof input === "string") {
|
|
1542
|
-
const text = emit(input);
|
|
1543
|
-
done = input.length;
|
|
1544
|
-
if (text.length > 0) {
|
|
1545
|
-
yield text;
|
|
1546
|
-
}
|
|
1547
|
-
onProgress?.(done, total ?? void 0);
|
|
1548
|
-
return;
|
|
1549
|
-
}
|
|
1550
|
-
const decoder = new ByteDecoder(report, options);
|
|
1551
|
-
if (input instanceof Uint8Array) {
|
|
1552
|
-
decoder.start(input.subarray(0, HEAD_BYTES));
|
|
1553
|
-
for (let offset = 0; offset < input.byteLength; offset += DECODE_SLICE) {
|
|
1554
|
-
throwIfAborted(signal);
|
|
1555
|
-
const slice = input.subarray(offset, Math.min(offset + DECODE_SLICE, input.byteLength));
|
|
1556
|
-
const text = emit(decoder.decode(slice, offset + DECODE_SLICE < input.byteLength));
|
|
1557
|
-
done = Math.min(offset + DECODE_SLICE, input.byteLength);
|
|
1558
|
-
if (text.length > 0) {
|
|
1559
|
-
yield text;
|
|
1560
|
-
}
|
|
1561
|
-
onProgress?.(done, total ?? void 0);
|
|
1562
|
-
}
|
|
1563
|
-
if (input.byteLength === 0) {
|
|
1564
|
-
onProgress?.(0, 0);
|
|
1565
|
-
}
|
|
1566
|
-
return;
|
|
1567
|
-
}
|
|
1568
|
-
const needed = options.declaredEncoding === void 0 ? BOM_BYTES : HEAD_BYTES;
|
|
1569
|
-
let head = [];
|
|
1570
|
-
let headLength = 0;
|
|
1571
|
-
const flushHead = (stream) => {
|
|
1572
|
-
const bytes = concatBytes(head);
|
|
1573
|
-
head = [];
|
|
1574
|
-
headLength = 0;
|
|
1575
|
-
decoder.start(bytes.subarray(0, HEAD_BYTES));
|
|
1576
|
-
return decoder.decode(bytes, stream);
|
|
1577
|
-
};
|
|
1578
|
-
const chunks = isReadableStream(input) ? streamChunks(input, signal) : input;
|
|
1579
|
-
for await (const chunk of chunks) {
|
|
1580
|
-
throwIfAborted(signal);
|
|
1581
|
-
let text;
|
|
1582
|
-
if (typeof chunk === "string") {
|
|
1583
|
-
let pending = "";
|
|
1584
|
-
if (!decoder.started && headLength > 0) {
|
|
1585
|
-
pending = flushHead(false);
|
|
1586
|
-
} else if (decoder.started) {
|
|
1587
|
-
pending = decoder.decode(new Uint8Array(0), false);
|
|
1588
|
-
}
|
|
1589
|
-
text = emit(pending + chunk);
|
|
1590
|
-
done += chunk.length;
|
|
1591
|
-
} else if (chunk instanceof Uint8Array) {
|
|
1592
|
-
done += chunk.byteLength;
|
|
1593
|
-
if (decoder.started) {
|
|
1594
|
-
text = emit(decoder.decode(chunk, true));
|
|
1595
|
-
} else {
|
|
1596
|
-
head.push(chunk);
|
|
1597
|
-
headLength += chunk.byteLength;
|
|
1598
|
-
text = headLength >= needed ? emit(flushHead(true)) : "";
|
|
1599
|
-
}
|
|
1600
|
-
} else {
|
|
1601
|
-
throw new GraphFormatError("E_UNSUPPORTED", "an input chunk must be a string or a Uint8Array", {
|
|
1602
|
-
reason: "chunk type",
|
|
1603
|
-
found: typeof chunk
|
|
1604
|
-
});
|
|
1605
|
-
}
|
|
1606
|
-
if (text.length > 0) {
|
|
1607
|
-
yield text;
|
|
1608
|
-
}
|
|
1609
|
-
onProgress?.(done);
|
|
1610
|
-
}
|
|
1611
|
-
let tail = "";
|
|
1612
|
-
if (!decoder.started && headLength > 0) {
|
|
1613
|
-
tail = flushHead(false);
|
|
1614
|
-
} else if (decoder.started) {
|
|
1615
|
-
tail = decoder.decode(new Uint8Array(0), false);
|
|
1616
|
-
}
|
|
1617
|
-
tail = emit(tail);
|
|
1618
|
-
if (tail.length > 0) {
|
|
1619
|
-
yield tail;
|
|
1620
|
-
}
|
|
1621
|
-
onProgress?.(done, done);
|
|
1622
|
-
}
|
|
1623
|
-
function isReadableStream(input) {
|
|
1624
|
-
return typeof input.getReader === "function";
|
|
1625
|
-
}
|
|
1626
|
-
async function* streamChunks(stream, signal) {
|
|
1627
|
-
const reader = stream.getReader();
|
|
1628
|
-
let finished = false;
|
|
1629
|
-
try {
|
|
1630
|
-
for (; ; ) {
|
|
1631
|
-
throwIfAborted(signal);
|
|
1632
|
-
const { done, value } = await reader.read();
|
|
1633
|
-
if (done) {
|
|
1634
|
-
finished = true;
|
|
1635
|
-
return;
|
|
1636
|
-
}
|
|
1637
|
-
yield value;
|
|
1638
|
-
}
|
|
1639
|
-
} finally {
|
|
1640
|
-
if (!finished) {
|
|
1641
|
-
await reader.cancel(signal?.reason).catch(() => void 0);
|
|
1642
|
-
}
|
|
1643
|
-
reader.releaseLock();
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
async function readBytes(input, options = {}) {
|
|
1647
|
-
const signal = options.signal ?? null;
|
|
1648
|
-
throwIfAborted(signal);
|
|
1649
|
-
if (typeof input === "string") {
|
|
1650
|
-
return null;
|
|
1651
|
-
}
|
|
1652
|
-
if (input instanceof Uint8Array) {
|
|
1653
|
-
options.onProgress?.(input.byteLength, input.byteLength);
|
|
1654
|
-
return input;
|
|
1655
|
-
}
|
|
1656
|
-
const parts = [];
|
|
1657
|
-
let done = 0;
|
|
1658
|
-
for await (const chunk of isReadableStream(input) ? streamChunks(input, signal) : input) {
|
|
1659
|
-
throwIfAborted(signal);
|
|
1660
|
-
if (typeof chunk === "string") {
|
|
1661
|
-
return null;
|
|
1662
|
-
}
|
|
1663
|
-
if (!(chunk instanceof Uint8Array)) {
|
|
1664
|
-
throw new GraphFormatError("E_UNSUPPORTED", "an input chunk must be a string or a Uint8Array", {
|
|
1665
|
-
reason: "chunk type",
|
|
1666
|
-
found: typeof chunk
|
|
1667
|
-
});
|
|
1668
|
-
}
|
|
1669
|
-
parts.push(chunk);
|
|
1670
|
-
done += chunk.byteLength;
|
|
1671
|
-
options.onProgress?.(done);
|
|
1672
|
-
}
|
|
1673
|
-
options.onProgress?.(done, done);
|
|
1674
|
-
return parts.length === 0 ? new Uint8Array(0) : concatBytes(parts);
|
|
1675
|
-
}
|
|
1676
|
-
async function readText(input, report, options = {}) {
|
|
1677
|
-
if (typeof input === "string") {
|
|
1678
|
-
throwIfAborted(options.signal);
|
|
1679
|
-
options.onProgress?.(input.length, input.length);
|
|
1680
|
-
return input.startsWith(BOM) ? input.slice(1) : input;
|
|
1681
|
-
}
|
|
1682
|
-
const parts = [];
|
|
1683
|
-
for await (const chunk of textChunks(input, report, options)) {
|
|
1684
|
-
parts.push(chunk);
|
|
1685
|
-
}
|
|
1686
|
-
return parts.length === 1 ? parts[0] : parts.join("");
|
|
1687
|
-
}
|
|
1688
|
-
class LineReader {
|
|
1689
|
-
/**
|
|
1690
|
-
* Create a reader over an input; nothing is read until iteration starts.
|
|
1691
|
-
* @param input - the input
|
|
1692
|
-
* @param report - the report decode errors are recorded in
|
|
1693
|
-
* @param options - cancellation and progress
|
|
1694
|
-
*/
|
|
1695
|
-
constructor(input, report, options = {}) {
|
|
1696
|
-
this.lineNumber = 0;
|
|
1697
|
-
this.input = input;
|
|
1698
|
-
this.report = report;
|
|
1699
|
-
this.options = options;
|
|
1700
|
-
}
|
|
1701
|
-
/**
|
|
1702
|
-
* The 1-based number of the line most recently yielded.
|
|
1703
|
-
* @returns the line number; 0 before the first line
|
|
1704
|
-
*/
|
|
1705
|
-
get line() {
|
|
1706
|
-
return this.lineNumber;
|
|
1707
|
-
}
|
|
1708
|
-
/**
|
|
1709
|
-
* Iterate the lines.
|
|
1710
|
-
* @yields one line at a time, terminator removed
|
|
1711
|
-
* @returns nothing
|
|
1712
|
-
*/
|
|
1713
|
-
async *[Symbol.asyncIterator]() {
|
|
1714
|
-
const pending = [];
|
|
1715
|
-
let trailingCr = false;
|
|
1716
|
-
for await (const chunk of textChunks(this.input, this.report, this.options)) {
|
|
1717
|
-
let start = 0;
|
|
1718
|
-
const end = chunk.length;
|
|
1719
|
-
if (trailingCr) {
|
|
1720
|
-
trailingCr = false;
|
|
1721
|
-
this.lineNumber++;
|
|
1722
|
-
const joined = pending.join("");
|
|
1723
|
-
pending.length = 0;
|
|
1724
|
-
yield joined.slice(0, -1);
|
|
1725
|
-
if (chunk.charCodeAt(0) === 10) {
|
|
1726
|
-
start = 1;
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
let nl = chunk.indexOf("\n", start);
|
|
1730
|
-
let cr = chunk.indexOf("\r", start);
|
|
1731
|
-
while (nl >= 0 || cr >= 0) {
|
|
1732
|
-
let cut;
|
|
1733
|
-
let next;
|
|
1734
|
-
if (cr >= 0 && (nl < 0 || cr < nl)) {
|
|
1735
|
-
if (cr === end - 1) {
|
|
1736
|
-
break;
|
|
1737
|
-
}
|
|
1738
|
-
cut = cr;
|
|
1739
|
-
next = chunk.charCodeAt(cr + 1) === 10 ? cr + 2 : cr + 1;
|
|
1740
|
-
} else {
|
|
1741
|
-
cut = nl;
|
|
1742
|
-
next = nl + 1;
|
|
1743
|
-
}
|
|
1744
|
-
this.lineNumber++;
|
|
1745
|
-
const piece = chunk.slice(start, cut);
|
|
1746
|
-
if (pending.length === 0) {
|
|
1747
|
-
yield piece;
|
|
1748
|
-
} else {
|
|
1749
|
-
pending.push(piece);
|
|
1750
|
-
const joined = pending.join("");
|
|
1751
|
-
pending.length = 0;
|
|
1752
|
-
yield joined;
|
|
1753
|
-
}
|
|
1754
|
-
start = next;
|
|
1755
|
-
if (nl >= 0 && nl < next) {
|
|
1756
|
-
nl = chunk.indexOf("\n", next);
|
|
1757
|
-
}
|
|
1758
|
-
if (cr >= 0 && cr < next) {
|
|
1759
|
-
cr = chunk.indexOf("\r", next);
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
if (start < end) {
|
|
1763
|
-
pending.push(start === 0 ? chunk : chunk.slice(start));
|
|
1764
|
-
trailingCr = chunk.charCodeAt(end - 1) === 13;
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
if (pending.length > 0) {
|
|
1768
|
-
this.lineNumber++;
|
|
1769
|
-
const joined = pending.join("");
|
|
1770
|
-
yield joined.endsWith("\r") ? joined.slice(0, -1) : joined;
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
}
|
|
1774
|
-
const ID_COERCIONS = /* @__PURE__ */ new Set(["keep", "canonical", "string", "number"]);
|
|
1775
|
-
const NODE_ID_SOURCES = /* @__PURE__ */ new Set(["id", "label", "index"]);
|
|
1776
|
-
const DUPLICATE_POLICIES = /* @__PURE__ */ new Set(["keep", "error", "first", "last", "sum", "min", "max"]);
|
|
1777
|
-
const SELF_LOOP_POLICIES = /* @__PURE__ */ new Set(["keep", "drop", "error"]);
|
|
1778
|
-
const IMPORT_MIXED_POLICIES = /* @__PURE__ */ new Set(["expand", "directed", "undirected", "error"]);
|
|
1779
|
-
const EXPORT_MIXED_POLICIES = /* @__PURE__ */ new Set(["error", "directed", "undirected"]);
|
|
1780
|
-
const WEIGHT_DTYPES = /* @__PURE__ */ new Set(["f32", "f64"]);
|
|
1781
|
-
const LONG_MODES = /* @__PURE__ */ new Set(["f64", "string"]);
|
|
1782
|
-
const HYPEREDGE_POLICIES = /* @__PURE__ */ new Set(["error", "skip", "star", "clique"]);
|
|
1783
|
-
const SANITIZE_MODES = /* @__PURE__ */ new Set(["error", "mangle"]);
|
|
1784
|
-
const DEFAULT_ERROR_LIMIT = 100;
|
|
1785
|
-
const SINK_OPTION_NAMES = ["addMissingNodes", "duplicateEdges", "selfLoops", "weightDtype"];
|
|
1786
|
-
function reportSinkOptions(sink, options, report, enforcesMissingNodes = false) {
|
|
1787
|
-
if (options === void 0) {
|
|
1788
|
-
return 0;
|
|
1789
|
-
}
|
|
1790
|
-
let recorded = 0;
|
|
1791
|
-
for (const name of SINK_OPTION_NAMES) {
|
|
1792
|
-
const wanted = options[name];
|
|
1793
|
-
const actual = sink.options[name];
|
|
1794
|
-
if (wanted === void 0 || wanted === actual) {
|
|
1795
|
-
continue;
|
|
1796
|
-
}
|
|
1797
|
-
if (name === "addMissingNodes" && enforcesMissingNodes && wanted === false) {
|
|
1798
|
-
continue;
|
|
1799
|
-
}
|
|
1800
|
-
report.warning(
|
|
1801
|
-
"coercion",
|
|
1802
|
-
SINK_OPTION_CODE,
|
|
1803
|
-
`option ${name}: ${JSON.stringify(wanted)} requested but the sink uses ${JSON.stringify(actual)}; the sink's setting applies`,
|
|
1804
|
-
{ element: name }
|
|
1805
|
-
);
|
|
1806
|
-
recorded++;
|
|
1807
|
-
}
|
|
1808
|
-
return recorded;
|
|
1809
|
-
}
|
|
1810
|
-
const IGNORABLE_OPTION_NAMES = [
|
|
1811
|
-
"ids",
|
|
1812
|
-
"nodeIdFrom",
|
|
1813
|
-
"addMissingNodes",
|
|
1814
|
-
"duplicateEdges",
|
|
1815
|
-
"selfLoops",
|
|
1816
|
-
"onMixedDirection",
|
|
1817
|
-
"defaultDirected",
|
|
1818
|
-
"weightFrom",
|
|
1819
|
-
"weightDtype",
|
|
1820
|
-
"long",
|
|
1821
|
-
"restoreMangledIds",
|
|
1822
|
-
"hyperedges"
|
|
1823
|
-
];
|
|
1824
|
-
function reportUnusedOptions(options, report, used) {
|
|
1825
|
-
if (options === void 0) {
|
|
1826
|
-
return 0;
|
|
1827
|
-
}
|
|
1828
|
-
let recorded = 0;
|
|
1829
|
-
for (const name of IGNORABLE_OPTION_NAMES) {
|
|
1830
|
-
if (used.has(name) || SINK_OPTION_NAMES.includes(name)) {
|
|
1831
|
-
continue;
|
|
1832
|
-
}
|
|
1833
|
-
const value = options[name];
|
|
1834
|
-
if (value === void 0) {
|
|
1835
|
-
continue;
|
|
1836
|
-
}
|
|
1837
|
-
report.warning(
|
|
1838
|
-
"unsupported",
|
|
1839
|
-
OPTION_IGNORED_CODE,
|
|
1840
|
-
`option ${name}: ${JSON.stringify(value)} has no effect on the ${report.format} importer`,
|
|
1841
|
-
{ element: name }
|
|
1842
|
-
);
|
|
1843
|
-
recorded++;
|
|
1844
|
-
}
|
|
1845
|
-
return recorded;
|
|
1846
|
-
}
|
|
1847
|
-
function chooseGraph(names, options, report) {
|
|
1848
|
-
const { graphIndex, graphName } = options ?? {};
|
|
1849
|
-
if (graphIndex !== void 0 && (typeof graphIndex !== "number" || !Number.isInteger(graphIndex) || graphIndex < 0)) {
|
|
1850
|
-
throw new GraphFormatError(
|
|
1851
|
-
"E_UNSUPPORTED",
|
|
1852
|
-
`option graphIndex: ${describe(graphIndex)} is not a non-negative integer`,
|
|
1853
|
-
{
|
|
1854
|
-
option: "graphIndex",
|
|
1855
|
-
found: graphIndex
|
|
1856
|
-
}
|
|
1857
|
-
);
|
|
1858
|
-
}
|
|
1859
|
-
if (graphName !== void 0 && typeof graphName !== "string") {
|
|
1860
|
-
throw new GraphFormatError("E_UNSUPPORTED", `option graphName: ${describe(graphName)} is not a string`, {
|
|
1861
|
-
option: "graphName",
|
|
1862
|
-
found: graphName
|
|
1863
|
-
});
|
|
1864
|
-
}
|
|
1865
|
-
if (graphIndex !== void 0 && graphName !== void 0) {
|
|
1866
|
-
throw new GraphFormatError("E_UNSUPPORTED", "options graphIndex and graphName both choose a graph; pass one", {
|
|
1867
|
-
option: "graphName",
|
|
1868
|
-
found: graphName
|
|
1869
|
-
});
|
|
1870
|
-
}
|
|
1871
|
-
if (names.length === 0) {
|
|
1872
|
-
return report.fail(NO_GRAPH_CODE, "the input holds no graph");
|
|
1873
|
-
}
|
|
1874
|
-
if (graphName !== void 0) {
|
|
1875
|
-
const matches = names.flatMap((name, i) => name === graphName ? [i] : []);
|
|
1876
|
-
if (matches.length > 1) {
|
|
1877
|
-
return report.fail(
|
|
1878
|
-
AMBIGUOUS_GRAPH_NAME_CODE,
|
|
1879
|
-
`graphName ${JSON.stringify(graphName)} names the graphs at indexes ${matches.join(", ")}; pass graphIndex`,
|
|
1880
|
-
{ element: graphName }
|
|
1881
|
-
);
|
|
1882
|
-
}
|
|
1883
|
-
if (matches.length === 0) {
|
|
1884
|
-
return report.fail(
|
|
1885
|
-
GRAPH_NOT_FOUND_CODE,
|
|
1886
|
-
`graphName ${JSON.stringify(graphName)} names none of the ${names.length} graph(s)`,
|
|
1887
|
-
{ element: graphName },
|
|
1888
|
-
{ names: [...names] }
|
|
1889
|
-
);
|
|
1890
|
-
}
|
|
1891
|
-
return matches[0];
|
|
1892
|
-
}
|
|
1893
|
-
const index = graphIndex ?? 0;
|
|
1894
|
-
if (index >= names.length) {
|
|
1895
|
-
return report.fail(GRAPH_NOT_FOUND_CODE, `graphIndex ${index} is beyond the ${names.length} graph(s)`);
|
|
1896
|
-
}
|
|
1897
|
-
return index;
|
|
1898
|
-
}
|
|
1899
|
-
function resolveImportOptions(options, defaults) {
|
|
1900
|
-
const o = options ?? {};
|
|
1901
|
-
return Object.freeze({
|
|
1902
|
-
ids: enumOption("ids", o.ids, defaults.ids, ID_COERCIONS),
|
|
1903
|
-
nodeIdFrom: enumOption("nodeIdFrom", o.nodeIdFrom, "id", NODE_ID_SOURCES),
|
|
1904
|
-
addMissingNodes: booleanOption("addMissingNodes", o.addMissingNodes, defaults.addMissingNodes ?? true),
|
|
1905
|
-
duplicateEdges: enumOption("duplicateEdges", o.duplicateEdges, "keep", DUPLICATE_POLICIES),
|
|
1906
|
-
selfLoops: enumOption("selfLoops", o.selfLoops, "keep", SELF_LOOP_POLICIES),
|
|
1907
|
-
onMixedDirection: enumOption("onMixedDirection", o.onMixedDirection, "expand", IMPORT_MIXED_POLICIES),
|
|
1908
|
-
defaultDirected: booleanOption("defaultDirected", o.defaultDirected, defaults.defaultDirected),
|
|
1909
|
-
weightFrom: weightFromOption(o.weightFrom, defaults.weightFrom),
|
|
1910
|
-
weightDtype: enumOption("weightDtype", o.weightDtype, "f64", WEIGHT_DTYPES),
|
|
1911
|
-
long: enumOption("long", o.long, "f64", LONG_MODES),
|
|
1912
|
-
restoreMangledIds: booleanOption("restoreMangledIds", o.restoreMangledIds, true),
|
|
1913
|
-
hyperedges: enumOption("hyperedges", o.hyperedges, "skip", HYPEREDGE_POLICIES),
|
|
1914
|
-
errorLimit: errorLimitOption(o.errorLimit),
|
|
1915
|
-
signal: signalOption(o.signal),
|
|
1916
|
-
onProgress: progressOption(o.onProgress),
|
|
1917
|
-
encoding: encodingOption(o.encoding)
|
|
1918
|
-
});
|
|
1919
|
-
}
|
|
1920
|
-
function resolveExportOptions(options) {
|
|
1921
|
-
const o = options ?? {};
|
|
1922
|
-
return Object.freeze({
|
|
1923
|
-
sanitizeIds: enumOption("sanitizeIds", o.sanitizeIds, "error", SANITIZE_MODES),
|
|
1924
|
-
onMixedDirection: enumOption("onMixedDirection", o.onMixedDirection, "error", EXPORT_MIXED_POLICIES)
|
|
1925
|
-
});
|
|
1926
|
-
}
|
|
1927
|
-
function enumOption(name, value, fallback, allowed) {
|
|
1928
|
-
if (value === void 0) {
|
|
1929
|
-
return fallback;
|
|
1930
|
-
}
|
|
1931
|
-
if (typeof value !== "string" || !allowed.has(value)) {
|
|
1932
|
-
throw new GraphFormatError(
|
|
1933
|
-
"E_UNSUPPORTED",
|
|
1934
|
-
`option ${name}: ${describe(value)} is not one of ${list(allowed)}`,
|
|
1935
|
-
{
|
|
1936
|
-
option: name,
|
|
1937
|
-
found: value,
|
|
1938
|
-
supported: [...allowed]
|
|
1939
|
-
}
|
|
1940
|
-
);
|
|
1941
|
-
}
|
|
1942
|
-
return value;
|
|
1943
|
-
}
|
|
1944
|
-
function booleanOption(name, value, fallback) {
|
|
1945
|
-
if (value === void 0) {
|
|
1946
|
-
return fallback;
|
|
1947
|
-
}
|
|
1948
|
-
if (typeof value !== "boolean") {
|
|
1949
|
-
throw new GraphFormatError("E_UNSUPPORTED", `option ${name}: ${describe(value)} is not a boolean`, {
|
|
1950
|
-
option: name,
|
|
1951
|
-
found: value
|
|
1952
|
-
});
|
|
1953
|
-
}
|
|
1954
|
-
return value;
|
|
1955
|
-
}
|
|
1956
|
-
function weightFromOption(value, fallback) {
|
|
1957
|
-
if (value === void 0) {
|
|
1958
|
-
return fallback;
|
|
1959
|
-
}
|
|
1960
|
-
if (value === null || typeof value === "string" && value.length > 0) {
|
|
1961
|
-
return value;
|
|
1962
|
-
}
|
|
1963
|
-
throw new GraphFormatError(
|
|
1964
|
-
"E_UNSUPPORTED",
|
|
1965
|
-
`option weightFrom: ${describe(value)} is not an attribute name or null`,
|
|
1966
|
-
{ option: "weightFrom", found: value }
|
|
1967
|
-
);
|
|
1968
|
-
}
|
|
1969
|
-
function errorLimitOption(value) {
|
|
1970
|
-
if (value === void 0) {
|
|
1971
|
-
return DEFAULT_ERROR_LIMIT;
|
|
1972
|
-
}
|
|
1973
|
-
if (typeof value === "number" && value >= 0 && (Number.isInteger(value) || value === Infinity)) {
|
|
1974
|
-
return value;
|
|
1975
|
-
}
|
|
1976
|
-
throw new GraphFormatError(
|
|
1977
|
-
"E_UNSUPPORTED",
|
|
1978
|
-
`option errorLimit: ${describe(value)} is not a non-negative integer or Infinity`,
|
|
1979
|
-
{ option: "errorLimit", found: value }
|
|
1980
|
-
);
|
|
1981
|
-
}
|
|
1982
|
-
function signalOption(value) {
|
|
1983
|
-
if (value === void 0 || value === null) {
|
|
1984
|
-
return null;
|
|
1985
|
-
}
|
|
1986
|
-
if (typeof value === "object" && typeof value.aborted === "boolean") {
|
|
1987
|
-
return value;
|
|
1988
|
-
}
|
|
1989
|
-
throw new GraphFormatError("E_UNSUPPORTED", `option signal: ${describe(value)} is not an AbortSignal`, {
|
|
1990
|
-
option: "signal",
|
|
1991
|
-
found: typeof value
|
|
1992
|
-
});
|
|
1993
|
-
}
|
|
1994
|
-
function progressOption(value) {
|
|
1995
|
-
if (value === void 0 || value === null) {
|
|
1996
|
-
return null;
|
|
1997
|
-
}
|
|
1998
|
-
if (typeof value === "function") {
|
|
1999
|
-
return value;
|
|
2000
|
-
}
|
|
2001
|
-
throw new GraphFormatError("E_UNSUPPORTED", `option onProgress: ${describe(value)} is not a function`, {
|
|
2002
|
-
option: "onProgress",
|
|
2003
|
-
found: typeof value
|
|
2004
|
-
});
|
|
2005
|
-
}
|
|
2006
|
-
function encodingOption(value) {
|
|
2007
|
-
if (value === void 0 || value === null) {
|
|
2008
|
-
return null;
|
|
2009
|
-
}
|
|
2010
|
-
const canonical = typeof value === "string" ? canonicalEncoding(value) : null;
|
|
2011
|
-
if (canonical === null) {
|
|
2012
|
-
throw new GraphFormatError(
|
|
2013
|
-
"E_UNSUPPORTED",
|
|
2014
|
-
`option encoding: ${describe(value)} is not an encoding this platform's TextDecoder knows`,
|
|
2015
|
-
{ option: "encoding", found: value }
|
|
2016
|
-
);
|
|
2017
|
-
}
|
|
2018
|
-
return canonical;
|
|
2019
|
-
}
|
|
2020
|
-
function describe(value) {
|
|
2021
|
-
switch (typeof value) {
|
|
2022
|
-
case "string":
|
|
2023
|
-
return JSON.stringify(value);
|
|
2024
|
-
case "number":
|
|
2025
|
-
case "boolean":
|
|
2026
|
-
return String(value);
|
|
2027
|
-
default:
|
|
2028
|
-
return value === null ? "null" : typeof value;
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
function list(allowed) {
|
|
2032
|
-
return [...allowed].map((v) => JSON.stringify(v)).join(", ");
|
|
2033
|
-
}
|
|
2034
|
-
class ImportError extends GraphFormatError {
|
|
2035
|
-
/**
|
|
2036
|
-
* Create an ImportError.
|
|
2037
|
-
* @param message - a plain-ASCII human-readable message
|
|
2038
|
-
* @param report - the partial report
|
|
2039
|
-
* @param details - optional machine-readable context
|
|
2040
|
-
*/
|
|
2041
|
-
constructor(message, report, details) {
|
|
2042
|
-
super("E_IMPORT", message, details);
|
|
2043
|
-
this.name = "ImportError";
|
|
2044
|
-
this.report = report;
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
const CATEGORY_BY_CODE = {
|
|
2048
|
-
E_UNKNOWN_NODE: "missing-value",
|
|
2049
|
-
E_UNKNOWN_COLUMN: "missing-value",
|
|
2050
|
-
E_DIRECTED: "coercion",
|
|
2051
|
-
E_TOO_LARGE: "unsupported",
|
|
2052
|
-
E_UNSUPPORTED: "unsupported",
|
|
2053
|
-
E_GPU_INELIGIBLE: "unsupported"
|
|
2054
|
-
};
|
|
2055
|
-
const PARSE_ERROR_CODE = "E_PARSE";
|
|
2056
|
-
class ImportReportBuilder {
|
|
2057
|
-
/**
|
|
2058
|
-
* Create a builder for one import call.
|
|
2059
|
-
* @param format - the importer's format name
|
|
2060
|
-
* @param errorLimit - errors tolerated before the import aborts; Infinity for no limit
|
|
2061
|
-
*/
|
|
2062
|
-
constructor(format, errorLimit) {
|
|
2063
|
-
this.counts = { nodes: 0, edges: 0, skippedNodes: 0, skippedEdges: 0, expandedMixed: 0 };
|
|
2064
|
-
this.issueList = [];
|
|
2065
|
-
this.lossList = [];
|
|
2066
|
-
this.onceCodes = /* @__PURE__ */ new Set();
|
|
2067
|
-
this.errors = 0;
|
|
2068
|
-
this.warnings = 0;
|
|
2069
|
-
this.truncatedFlag = false;
|
|
2070
|
-
this.format = format;
|
|
2071
|
-
this.errorLimit = errorLimit;
|
|
2072
|
-
this.startedAt = now();
|
|
2073
|
-
}
|
|
2074
|
-
/**
|
|
2075
|
-
* Issues recorded so far, in order.
|
|
2076
|
-
* @returns the live list (not copied; finish() copies)
|
|
2077
|
-
*/
|
|
2078
|
-
get issues() {
|
|
2079
|
-
return this.issueList;
|
|
2080
|
-
}
|
|
2081
|
-
/**
|
|
2082
|
-
* Issues with severity "error".
|
|
2083
|
-
* @returns the count
|
|
2084
|
-
*/
|
|
2085
|
-
get errorCount() {
|
|
2086
|
-
return this.errors;
|
|
2087
|
-
}
|
|
2088
|
-
/**
|
|
2089
|
-
* Issues with severity "warning".
|
|
2090
|
-
* @returns the count
|
|
2091
|
-
*/
|
|
2092
|
-
get warningCount() {
|
|
2093
|
-
return this.warnings;
|
|
2094
|
-
}
|
|
2095
|
-
/**
|
|
2096
|
-
* Whether the error limit was exceeded.
|
|
2097
|
-
* @returns true once an error beyond the limit was recorded
|
|
2098
|
-
*/
|
|
2099
|
-
get truncated() {
|
|
2100
|
-
return this.truncatedFlag;
|
|
2101
|
-
}
|
|
2102
|
-
/**
|
|
2103
|
-
* Loss notes recorded so far.
|
|
2104
|
-
* @returns the live list
|
|
2105
|
-
*/
|
|
2106
|
-
get lossy() {
|
|
2107
|
-
return this.lossList;
|
|
2108
|
-
}
|
|
2109
|
-
/**
|
|
2110
|
-
* Record an error. When the count goes beyond the error limit the report is marked truncated
|
|
2111
|
-
* and an ImportError carrying it is thrown; the importer does not catch that.
|
|
2112
|
-
* @param category - the issue category
|
|
2113
|
-
* @param code - a stable code such as "E_UNKNOWN_NODE"
|
|
2114
|
-
* @param message - a plain-ASCII message
|
|
2115
|
-
* @param where - the line and element, when known
|
|
2116
|
-
* @returns the recorded issue
|
|
2117
|
-
*/
|
|
2118
|
-
error(category, code, message, where) {
|
|
2119
|
-
const issue = makeIssue(category, "error", code, message, where);
|
|
2120
|
-
this.issueList.push(issue);
|
|
2121
|
-
this.errors++;
|
|
2122
|
-
if (this.errors > this.errorLimit) {
|
|
2123
|
-
this.truncatedFlag = true;
|
|
2124
|
-
throw this.abort(`error limit of ${this.errorLimit} exceeded: ${message}`, {
|
|
2125
|
-
code,
|
|
2126
|
-
limit: this.errorLimit
|
|
2127
|
-
});
|
|
2128
|
-
}
|
|
2129
|
-
return issue;
|
|
2130
|
-
}
|
|
2131
|
-
/**
|
|
2132
|
-
* Record a warning; warnings never count toward the limit.
|
|
2133
|
-
* @param category - the issue category
|
|
2134
|
-
* @param code - a stable code such as "W_WIDENED"
|
|
2135
|
-
* @param message - a plain-ASCII message
|
|
2136
|
-
* @param where - the line and element, when known
|
|
2137
|
-
* @returns the recorded issue
|
|
2138
|
-
*/
|
|
2139
|
-
warning(category, code, message, where) {
|
|
2140
|
-
const issue = makeIssue(category, "warning", code, message, where);
|
|
2141
|
-
this.issueList.push(issue);
|
|
2142
|
-
this.warnings++;
|
|
2143
|
-
return issue;
|
|
2144
|
-
}
|
|
2145
|
-
/**
|
|
2146
|
-
* Record a warning the first time its key is seen and ignore later repeats, for conditions
|
|
2147
|
-
* that would otherwise produce one warning per row.
|
|
2148
|
-
* @param category - the issue category
|
|
2149
|
-
* @param code - the stable code
|
|
2150
|
-
* @param message - a plain-ASCII message
|
|
2151
|
-
* @param where - the line and element, when known
|
|
2152
|
-
* @param key - what repeats are deduplicated on; the code itself by default (pass `code:column`
|
|
2153
|
-
* to warn once per column)
|
|
2154
|
-
* @returns the recorded issue, or null when the key was already recorded
|
|
2155
|
-
*/
|
|
2156
|
-
warnOnce(category, code, message, where, key = code) {
|
|
2157
|
-
if (this.onceCodes.has(key)) {
|
|
2158
|
-
return null;
|
|
2159
|
-
}
|
|
2160
|
-
this.onceCodes.add(key);
|
|
2161
|
-
return this.warning(category, code, message, where);
|
|
2162
|
-
}
|
|
2163
|
-
/**
|
|
2164
|
-
* Record something the importer could not represent.
|
|
2165
|
-
* @param code - a stable code
|
|
2166
|
-
* @param message - a plain-ASCII message
|
|
2167
|
-
* @param column - the affected column, or null
|
|
2168
|
-
* @param count - the affected count, or null
|
|
2169
|
-
* @returns the recorded note
|
|
2170
|
-
*/
|
|
2171
|
-
loss(code, message, column = null, count = null) {
|
|
2172
|
-
const note = Object.freeze({ code, message, column, count });
|
|
2173
|
-
this.lossList.push(note);
|
|
2174
|
-
return note;
|
|
2175
|
-
}
|
|
2176
|
-
/**
|
|
2177
|
-
* The per-element catch of design section 8.6: record a thrown GraphFormatError as an error
|
|
2178
|
-
* issue with its code and the category the code implies. Anything else is re-thrown unchanged:
|
|
2179
|
-
* an ImportError (the import already aborted), an abort reason, and any other thrown value (a
|
|
2180
|
-
* TypeError or RangeError is a programming error in the importer or the sink, never a defect of
|
|
2181
|
-
* the input, so it must surface as an exception rather than as an issue blamed on the file).
|
|
2182
|
-
* @param err - the thrown value
|
|
2183
|
-
* @param where - the line and element, when known
|
|
2184
|
-
* @returns the recorded issue
|
|
2185
|
-
*/
|
|
2186
|
-
recordError(err, where) {
|
|
2187
|
-
if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
|
|
2188
|
-
const category = CATEGORY_BY_CODE[err.code] ?? "validation-error";
|
|
2189
|
-
return this.error(category, err.code, err.message, where);
|
|
2190
|
-
}
|
|
2191
|
-
throw err;
|
|
2192
|
-
}
|
|
2193
|
-
/**
|
|
2194
|
-
* Build the ImportError that aborts the import, carrying the report so far. The caller throws
|
|
2195
|
-
* it; this method only constructs it so it can be used in expression position.
|
|
2196
|
-
* @param message - a plain-ASCII message
|
|
2197
|
-
* @param details - optional machine-readable context
|
|
2198
|
-
* @returns the error to throw
|
|
2199
|
-
*/
|
|
2200
|
-
abort(message, details) {
|
|
2201
|
-
return new ImportError(message, this.finish(), details);
|
|
2202
|
-
}
|
|
2203
|
-
/**
|
|
2204
|
-
* Record a fatal parse error and abort: the issue is recorded (even beyond the error limit)
|
|
2205
|
-
* and an ImportError carrying the report is thrown.
|
|
2206
|
-
* @param code - a stable code such as "E_INVALID_UTF8"
|
|
2207
|
-
* @param message - a plain-ASCII message
|
|
2208
|
-
* @param where - the line and element, when known
|
|
2209
|
-
* @param details - optional machine-readable context for the ImportError
|
|
2210
|
-
*/
|
|
2211
|
-
fail(code, message, where, details) {
|
|
2212
|
-
const issue = makeIssue("parse-error", "error", code, message, where);
|
|
2213
|
-
this.issueList.push(issue);
|
|
2214
|
-
this.errors++;
|
|
2215
|
-
if (this.errors > this.errorLimit) {
|
|
2216
|
-
this.truncatedFlag = true;
|
|
2217
|
-
}
|
|
2218
|
-
throw this.abort(message, { code, ...details });
|
|
2219
|
-
}
|
|
2220
|
-
/**
|
|
2221
|
-
* The report as it stands: a frozen snapshot with the parse duration so far. Can be called more
|
|
2222
|
-
* than once; each call reflects everything recorded up to that point.
|
|
2223
|
-
* @returns the report
|
|
2224
|
-
*/
|
|
2225
|
-
finish() {
|
|
2226
|
-
const { nodes, edges, skippedNodes, skippedEdges, expandedMixed } = this.counts;
|
|
2227
|
-
return Object.freeze({
|
|
2228
|
-
format: this.format,
|
|
2229
|
-
counts: Object.freeze({ nodes, edges, skippedNodes, skippedEdges, expandedMixed }),
|
|
2230
|
-
issues: Object.freeze([...this.issueList]),
|
|
2231
|
-
errorCount: this.errors,
|
|
2232
|
-
warningCount: this.warnings,
|
|
2233
|
-
truncated: this.truncatedFlag,
|
|
2234
|
-
lossy: Object.freeze([...this.lossList]),
|
|
2235
|
-
durationMs: now() - this.startedAt
|
|
2236
|
-
});
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
function makeIssue(category, severity, code, message, where) {
|
|
2240
|
-
return Object.freeze({
|
|
2241
|
-
category,
|
|
2242
|
-
severity,
|
|
2243
|
-
code,
|
|
2244
|
-
message,
|
|
2245
|
-
line: where?.line ?? null,
|
|
2246
|
-
element: where?.element ?? null
|
|
2247
|
-
});
|
|
2248
|
-
}
|
|
2249
|
-
function isAbortError(err) {
|
|
2250
|
-
return typeof err === "object" && err !== null && err.name === "AbortError";
|
|
2251
|
-
}
|
|
2252
|
-
function now() {
|
|
2253
|
-
return typeof performance === "object" ? performance.now() : Date.now();
|
|
2254
|
-
}
|
|
2255
|
-
export {
|
|
2256
|
-
OPTIONS_GAINED_CODE as $,
|
|
2257
|
-
AMBIGUOUS_GRAPH_NAME_CODE as A,
|
|
2258
|
-
BAD_VALUE_CODE as B,
|
|
2259
|
-
COLUMN_RENAMED_CODE as C,
|
|
2260
|
-
DIRECTION_FORCED_CODE as D,
|
|
2261
|
-
ENCODING_FALLBACK_CODE as E,
|
|
2262
|
-
reportSinkOptions as F,
|
|
2263
|
-
GRAPH_NOT_FOUND_CODE as G,
|
|
2264
|
-
chooseGraph as H,
|
|
2265
|
-
ID_MERGED_CODE as I,
|
|
2266
|
-
DirectionResolver as J,
|
|
2267
|
-
IdCoercer as K,
|
|
2268
|
-
declareResolved as L,
|
|
2269
|
-
MULTIPLE_GRAPHS_CODE as M,
|
|
2270
|
-
NO_GRAPH_CODE as N,
|
|
2271
|
-
OPTION_IGNORED_CODE as O,
|
|
2272
|
-
PRECISION_CODE as P,
|
|
2273
|
-
uniqueColumnName as Q,
|
|
2274
|
-
ROLE_TAKEN_CODE as R,
|
|
2275
|
-
SINK_OPTION_CODE as S,
|
|
2276
|
-
TOO_LARGE_CODE as T,
|
|
2277
|
-
UNKNOWN_PARENT_CODE as U,
|
|
2278
|
-
resolveExportOptions as V,
|
|
2279
|
-
WIDENED_CODE as W,
|
|
2280
|
-
pairFolding as X,
|
|
2281
|
-
UNKNOWN_ELEMENT_CODE as Y,
|
|
2282
|
-
BAD_DEFAULT_CODE as Z,
|
|
2283
|
-
DictHeuristic as _,
|
|
2284
|
-
DIRECTION_REFUSED_CODE as a,
|
|
2285
|
-
XML_ILLEGAL_CHAR_CODE as a0,
|
|
2286
|
-
TEXT_INFERRED_CODE as a1,
|
|
2287
|
-
INTEGRAL_F64_CODE as a2,
|
|
2288
|
-
STORAGE_CLASS_CODE as a3,
|
|
2289
|
-
EMPTY_COLUMN_DROPPED_CODE as a4,
|
|
2290
|
-
COLUMN_RENAMED_LOSS_CODE as a5,
|
|
2291
|
-
ROLE_ASSUMED_CODE as a6,
|
|
2292
|
-
WEIGHT_KEY_CLASH_CODE as a7,
|
|
2293
|
-
ID_TEXT_COLLISION_CODE as a8,
|
|
2294
|
-
MUTUAL_AS_UNDIRECTED_CODE as a9,
|
|
2295
|
-
declareCompanion as aA,
|
|
2296
|
-
decodeEntryName as aB,
|
|
2297
|
-
inputLength as aC,
|
|
2298
|
-
isAbortError as aD,
|
|
2299
|
-
isCanonicalIntegerText as aE,
|
|
2300
|
-
isImportInput as aF,
|
|
2301
|
-
readText as aG,
|
|
2302
|
-
parseDecimalText as aH,
|
|
2303
|
-
TIME_TEXT_ROLE as aI,
|
|
2304
|
-
TIME_TEXT_SUFFIX as aJ,
|
|
2305
|
-
declareAttribute as aK,
|
|
2306
|
-
parseDeclaredTemporal as aL,
|
|
2307
|
-
parseDeclaredValue as aM,
|
|
2308
|
-
losesPrecision as aN,
|
|
2309
|
-
parseTimeText as aO,
|
|
2310
|
-
splitListText as aP,
|
|
2311
|
-
timeTextCompanion as aQ,
|
|
2312
|
-
formatTimeValue as aR,
|
|
2313
|
-
mapDeclaredType as aS,
|
|
2314
|
-
joinListText as aT,
|
|
2315
|
-
formatTemporal as aU,
|
|
2316
|
-
DICT_SAMPLE_ROWS as aV,
|
|
2317
|
-
declareOn as aW,
|
|
2318
|
-
takenIn as aX,
|
|
2319
|
-
readBytes as aY,
|
|
2320
|
-
MUTUAL_EXPANDED_CODE as aa,
|
|
2321
|
-
PARENTS_DROPPED_CODE as ab,
|
|
2322
|
-
ROLE_DROPPED_CODE as ac,
|
|
2323
|
-
TEMPORAL_TEXT_DROPPED_CODE as ad,
|
|
2324
|
-
TEMPORAL_DROPPED_CODE as ae,
|
|
2325
|
-
MIXED_DIRECTION_CODE as af,
|
|
2326
|
-
describe as ag,
|
|
2327
|
-
BAD_OPTIONS_CODE as ah,
|
|
2328
|
-
COUNT_HINT_CODE as ai,
|
|
2329
|
-
DEFAULT_ERROR_LIMIT as aj,
|
|
2330
|
-
DIRECTED_COLUMN as ak,
|
|
2331
|
-
DUPLICATE_KEY_CODE as al,
|
|
2332
|
-
EQUATION_AS_TEXT_CODE as am,
|
|
2333
|
-
HYPEREDGE_CODE as an,
|
|
2334
|
-
ImportError as ao,
|
|
2335
|
-
LineReader as ap,
|
|
2336
|
-
MUTUAL_COLUMN as aq,
|
|
2337
|
-
PAIR_COLUMN as ar,
|
|
2338
|
-
PARSE_ERROR_CODE as as,
|
|
2339
|
-
RENAMED_CODE as at,
|
|
2340
|
-
STRAY_TEXT_CODE as au,
|
|
2341
|
-
UNKNOWN_TYPE_CODE as av,
|
|
2342
|
-
XML_SYNTAX_CODE as aw,
|
|
2343
|
-
canonicalId as ax,
|
|
2344
|
-
coerceId as ay,
|
|
2345
|
-
coerceIdText as az,
|
|
2346
|
-
ID_TEXT_TYPE_CODE as b,
|
|
2347
|
-
DUPLICATE_EDGE_ID_CODE as c,
|
|
2348
|
-
DUPLICATE_NODE_CODE as d,
|
|
2349
|
-
MISSING_ENDPOINT_CODE as e,
|
|
2350
|
-
MISSING_ID_CODE as f,
|
|
2351
|
-
STYLES_NOT_IMPORTED_CODE as g,
|
|
2352
|
-
PARENT_CYCLE_CODE as h,
|
|
2353
|
-
DUPLICATE_ATTRIBUTE_CODE as i,
|
|
2354
|
-
DANGLING_REFERENCE_CODE as j,
|
|
2355
|
-
UNKNOWN_ATTR_TYPE_CODE as k,
|
|
2356
|
-
COUNT_MISMATCH_CODE as l,
|
|
2357
|
-
ASPECT_ORDER_CODE as m,
|
|
2358
|
-
BAD_ASPECT_BLOCK_CODE as n,
|
|
2359
|
-
STATUS_WARNING_CODE as o,
|
|
2360
|
-
STATUS_FAILED_CODE as p,
|
|
2361
|
-
UNKNOWN_ENCODING_CODE as q,
|
|
2362
|
-
INVALID_ENCODING_CODE as r,
|
|
2363
|
-
INVALID_UTF8_CODE as s,
|
|
2364
|
-
SYNTAX_CODE as t,
|
|
2365
|
-
EMPTY_INPUT_CODE as u,
|
|
2366
|
-
resolveImportOptions as v,
|
|
2367
|
-
ImportReportBuilder as w,
|
|
2368
|
-
textChunks as x,
|
|
2369
|
-
throwIfAborted as y,
|
|
2370
|
-
reportUnusedOptions as z
|
|
2371
|
-
};
|
|
2372
|
-
//# sourceMappingURL=report-B1z4WT9e.js.map
|