@graphty/graph-io 0.3.25 → 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
|
@@ -0,0 +1,941 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `obographs` dialect of the JSON exporter: writes a snapshot as an OBO Graphs document
|
|
3
|
+
* (`{ "graphs": [{ "id", "meta", "nodes", "edges", ... }] }`), the JSON form the Gene Ontology and
|
|
4
|
+
* the OBO Foundry publish, and the form the JSON importer's `obographs` dialect reads back.
|
|
5
|
+
*
|
|
6
|
+
* Nodes carry `lbl` from the label column, `type` from the `type` column (Term as CLASS, Instance
|
|
7
|
+
* as INDIVIDUAL, Typedef as PROPERTY) and a `meta` built from the OBO vocabulary columns
|
|
8
|
+
* (src/common/ontology.ts: definition, comments, subsets, xrefs, synonyms, deprecated, and the
|
|
9
|
+
* basicPropertyValues of namespace, alt_id, created_by, creation_date, replaced_by, consider and
|
|
10
|
+
* property_value); any other node column becomes basicPropertyValues named after the column. Edges
|
|
11
|
+
* are `{ sub, pred, obj }` with the edge's `meta` column and its other columns in `meta`. Ids are
|
|
12
|
+
* written as IRIs (`GO:0008150` as `http://purl.obolibrary.org/obo/GO_0008150`, a relation by the
|
|
13
|
+
* IRI of the property whose shorthand it is) whenever the importer compacts the IRI back to the
|
|
14
|
+
* same id. The graph metadata, the PROPERTY nodes, the property edges and the axioms an OBO Graphs
|
|
15
|
+
* import kept in `meta.extra.obographs` are written back.
|
|
16
|
+
*/
|
|
17
|
+
import { GraphFormatError } from "@graphty/graph-format";
|
|
18
|
+
import { COLUMN_AS_PROPERTY_VALUE_CODE, DIRECTION_DROPPED_CODE, GRAPH_COLUMN_AS_METADATA_CODE, NODE_ORDER_CODE, NONFINITE_AS_NULL_CODE, RELATION_ASSUMED_CODE, TYPEDEF_NODES_CODE, } from "../../common/codes.js";
|
|
19
|
+
import { pairFolding } from "../../common/direction.js";
|
|
20
|
+
import { LOSS } from "../../common/export.js";
|
|
21
|
+
import { compactOboIri, OBO_IN_OWL, OBO_NODE_COLUMNS, OBO_PURL, OBOGRAPHS_PREDICATE_TAGS, PLACEHOLDER_COLUMN, SYNONYM_SCOPES, } from "../../common/ontology.js";
|
|
22
|
+
import { capabilityNotes, cellOf, emptyColumnNotes, fitsVocabulary, framelessNodes, movedNodes, notePropertyColumn, slotColumn, textOf, UNWRITTEN_ROLES, valuesOf, } from "../../common/ontology-export.js";
|
|
23
|
+
import { agree, plural } from "../../common/plural.js";
|
|
24
|
+
import { explicitWeights } from "../../common/weights.js";
|
|
25
|
+
import { dialectCapabilities, exponentIfUnsafe, isJsonObject } from "./dialect.js";
|
|
26
|
+
import { BUILTIN_PREDICATES, FRAME_TYPES, META_KEYS, NODE_KEYS, PROPERTY_PREDICATES } from "./obographs.js";
|
|
27
|
+
/**
|
|
28
|
+
* The loss codes only the `obographs` dialect records.
|
|
29
|
+
* @category Built-in formats
|
|
30
|
+
*/
|
|
31
|
+
export const OBOGRAPHS_LOSS = Object.freeze({
|
|
32
|
+
/** An edge column (or the explicit weights) is written into the edge's `meta` and reads back inside the `meta` column. */
|
|
33
|
+
EDGE_COLUMN_AS_META: "W_OBOGRAPHS_EDGE_COLUMN_AS_META",
|
|
34
|
+
/** A node id or relation is written as an IRI the importer's default `oboIds: "curie"` reads back as a different id. */
|
|
35
|
+
ID_CHANGED: "W_OBOGRAPHS_ID_CHANGED",
|
|
36
|
+
/** A `property_value` with an xsd datatype: basicPropertyValues have no datatype, so it reads back without one. */
|
|
37
|
+
DATATYPE_DROPPED: "W_OBOGRAPHS_DATATYPE_DROPPED",
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* The codes the dialect shares with the other exporters, under the names JSON_LOSS gives them.
|
|
41
|
+
* @category Built-in formats
|
|
42
|
+
*/
|
|
43
|
+
export const OBOGRAPHS_SHARED_LOSS = Object.freeze({
|
|
44
|
+
/** A node column outside the OBO vocabulary reads back inside the `property_value` column. */
|
|
45
|
+
COLUMN_AS_PROPERTY_VALUE: COLUMN_AS_PROPERTY_VALUE_CODE,
|
|
46
|
+
/** An edge without a relation is written with the predicate `is_a`. */
|
|
47
|
+
RELATION_ASSUMED: RELATION_ASSUMED_CODE,
|
|
48
|
+
/** Typedef nodes are written as PROPERTY nodes, which read back as nodes only under `typedefs: "nodes"`. */
|
|
49
|
+
TYPEDEF_NODES: TYPEDEF_NODES_CODE,
|
|
50
|
+
/** A graph attribute is written into the graph's `meta` and reads back in `snapshot.meta.extra.obographs`. */
|
|
51
|
+
GRAPH_COLUMN_AS_METADATA: GRAPH_COLUMN_AS_METADATA_CODE,
|
|
52
|
+
});
|
|
53
|
+
/** The node type of each OBO frame type. */
|
|
54
|
+
const NODE_TYPES = Object.freeze({
|
|
55
|
+
Term: "CLASS",
|
|
56
|
+
Instance: "INDIVIDUAL",
|
|
57
|
+
Typedef: "PROPERTY",
|
|
58
|
+
});
|
|
59
|
+
/** The basicPropertyValues predicate of each OBO tag (the reverse of OBOGRAPHS_PREDICATE_TAGS). */
|
|
60
|
+
const TAG_PREDICATES = new Map([...OBOGRAPHS_PREDICATE_TAGS].map(([pred, tag]) => [tag, pred]));
|
|
61
|
+
/** The OBO Graphs pred of the relations the importer reads from a built-in pred. */
|
|
62
|
+
const REVERSE_PREDICATES = Object.freeze({ is_a: "is_a", instance_of: "type" });
|
|
63
|
+
/** The vocabulary columns the dialect has a place for; every other node column is property values. */
|
|
64
|
+
const PLACED = new Set([
|
|
65
|
+
"type",
|
|
66
|
+
"propertyType",
|
|
67
|
+
"def",
|
|
68
|
+
"def.xrefs",
|
|
69
|
+
"comment",
|
|
70
|
+
"subset",
|
|
71
|
+
"xref",
|
|
72
|
+
"synonym",
|
|
73
|
+
"is_obsolete",
|
|
74
|
+
"namespace",
|
|
75
|
+
"created_by",
|
|
76
|
+
"creation_date",
|
|
77
|
+
"alt_id",
|
|
78
|
+
"replaced_by",
|
|
79
|
+
"consider",
|
|
80
|
+
"property_value",
|
|
81
|
+
"obo.unrecognized",
|
|
82
|
+
]);
|
|
83
|
+
/** The basicPropertyValues columns, in the order they are written. */
|
|
84
|
+
const PROPERTY_TAGS = [
|
|
85
|
+
"namespace",
|
|
86
|
+
"alt_id",
|
|
87
|
+
"created_by",
|
|
88
|
+
"creation_date",
|
|
89
|
+
"replaced_by",
|
|
90
|
+
"consider",
|
|
91
|
+
];
|
|
92
|
+
/** An IRI with a scheme. */
|
|
93
|
+
const IRI = /^[A-Za-z][A-Za-z0-9+.-]*:\/\//;
|
|
94
|
+
/** A CURIE whose prefix the OBO PURL mapping keeps (no underscore). */
|
|
95
|
+
const CURIE = /^([A-Za-z][A-Za-z0-9.-]*):(.+)$/;
|
|
96
|
+
/**
|
|
97
|
+
* The records an OBO Graphs import kept under `meta.extra.obographs`.
|
|
98
|
+
* @param snapshot - the snapshot
|
|
99
|
+
* @returns the records, empty when the snapshot did not come from OBO Graphs
|
|
100
|
+
*/
|
|
101
|
+
function keptOf(snapshot) {
|
|
102
|
+
const raw = snapshot.meta.extra.obographs;
|
|
103
|
+
const r = isJsonObject(raw) ? raw : {};
|
|
104
|
+
const properties = {};
|
|
105
|
+
if (isJsonObject(r.properties)) {
|
|
106
|
+
for (const [iri, entry] of Object.entries(r.properties)) {
|
|
107
|
+
if (isJsonObject(entry)) {
|
|
108
|
+
properties[iri] = entry;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
ids: r.ids === "iri" ? "iri" : "curie",
|
|
114
|
+
graph: isJsonObject(r.graph) ? r.graph : {},
|
|
115
|
+
document: isJsonObject(r.document) ? r.document : {},
|
|
116
|
+
properties,
|
|
117
|
+
propertyEdges: Array.isArray(r.propertyEdges) ? r.propertyEdges : [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The shorthand a property's meta declares (the importer names the property by it).
|
|
122
|
+
* @param meta - the property's meta
|
|
123
|
+
* @returns the shorthand, or null
|
|
124
|
+
*/
|
|
125
|
+
function shorthandOf(meta) {
|
|
126
|
+
if (!isJsonObject(meta) || !Array.isArray(meta.basicPropertyValues)) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
for (const pv of meta.basicPropertyValues) {
|
|
130
|
+
if (isJsonObject(pv) &&
|
|
131
|
+
typeof pv.pred === "string" &&
|
|
132
|
+
OBOGRAPHS_PREDICATE_TAGS.get(pv.pred) === "shorthand" &&
|
|
133
|
+
typeof pv.val === "string") {
|
|
134
|
+
return pv.val;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The ontology IRI unprefixed ids are written under: the option, the kept graph id, else the OBO
|
|
141
|
+
* PURL of the ontology id (the kept OBO header's, or the graph name's).
|
|
142
|
+
* @param snapshot - the snapshot
|
|
143
|
+
* @param kept - the kept records
|
|
144
|
+
* @param option - the ontologyIri option, or null
|
|
145
|
+
* @returns the IRI
|
|
146
|
+
*/
|
|
147
|
+
function ontologyIriOf(snapshot, kept, option) {
|
|
148
|
+
if (option !== null) {
|
|
149
|
+
return option;
|
|
150
|
+
}
|
|
151
|
+
if (typeof kept.graph.id === "string") {
|
|
152
|
+
return kept.graph.id;
|
|
153
|
+
}
|
|
154
|
+
const { obo } = snapshot.meta.extra;
|
|
155
|
+
const header = isJsonObject(obo) && isJsonObject(obo.header) ? obo.header : {};
|
|
156
|
+
const ontology = Array.isArray(header.ontology) && typeof header.ontology[0] === "string" ? header.ontology[0].trim() : null;
|
|
157
|
+
const name = ontology ?? snapshot.meta.name;
|
|
158
|
+
const id = name === null || name.length === 0 ? "graph" : name.replaceAll(/[^A-Za-z0-9_.\-/]/g, "_");
|
|
159
|
+
return `${OBO_PURL}${id}.owl`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* JSON text of a value with -0 kept and the non-finite numbers written as null (counted).
|
|
163
|
+
* @param value - the value
|
|
164
|
+
* @param nonfinite - the counter
|
|
165
|
+
* @param nonfinite.count - the count
|
|
166
|
+
* @returns the JSON text
|
|
167
|
+
*/
|
|
168
|
+
function json(value, nonfinite) {
|
|
169
|
+
if (typeof value === "number") {
|
|
170
|
+
if (!Number.isFinite(value)) {
|
|
171
|
+
nonfinite.count++;
|
|
172
|
+
return "null";
|
|
173
|
+
}
|
|
174
|
+
return Object.is(value, -0) ? "-0" : exponentIfUnsafe(JSON.stringify(value));
|
|
175
|
+
}
|
|
176
|
+
if (Array.isArray(value)) {
|
|
177
|
+
return `[${value.map((v) => json(v, nonfinite)).join(",")}]`;
|
|
178
|
+
}
|
|
179
|
+
if (isJsonObject(value)) {
|
|
180
|
+
return `{${Object.entries(value)
|
|
181
|
+
.filter(([, v]) => v !== undefined)
|
|
182
|
+
.map(([k, v]) => `${JSON.stringify(k)}:${json(v, nonfinite)}`)
|
|
183
|
+
.join(",")}}`;
|
|
184
|
+
}
|
|
185
|
+
return JSON.stringify(value) ?? "null";
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Whether a value is a non-empty array of strings.
|
|
189
|
+
* @param value - the value
|
|
190
|
+
* @param empty - whether an empty array is allowed
|
|
191
|
+
* @returns true for such an array
|
|
192
|
+
*/
|
|
193
|
+
function strings(value, empty = false) {
|
|
194
|
+
return Array.isArray(value) && (empty || value.length > 0) && value.every((v) => typeof v === "string");
|
|
195
|
+
}
|
|
196
|
+
/** One OBO Graphs export: the plan (ids, columns, notes) and the writer. */
|
|
197
|
+
/**
|
|
198
|
+
* The basicPropertyValue texts a property column gives one node: one per item of a list, JSON text
|
|
199
|
+
* for nested values, none when unset.
|
|
200
|
+
* @param column - the column
|
|
201
|
+
* @param i - the node
|
|
202
|
+
* @returns the texts
|
|
203
|
+
*/
|
|
204
|
+
function propertyTexts(column, i) {
|
|
205
|
+
const v = cellOf(column, i);
|
|
206
|
+
if (v === undefined) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
if (column.dtype === "list") {
|
|
210
|
+
return v.map((item) => textOf(item, column.child.dtype));
|
|
211
|
+
}
|
|
212
|
+
const nested = column.dtype === "json" || column.meta.components > 1;
|
|
213
|
+
return [nested ? (JSON.stringify(v) ?? "null") : textOf(v, column.dtype)];
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The graph columns as basicPropertyValues of the graph's meta.
|
|
217
|
+
* @param snapshot - the snapshot
|
|
218
|
+
* @returns one record per value
|
|
219
|
+
*/
|
|
220
|
+
function graphPropertyValues(snapshot) {
|
|
221
|
+
const values = [];
|
|
222
|
+
for (const column of snapshot.graph) {
|
|
223
|
+
const dtype = column.dtype === "list" ? column.child.dtype : column.dtype;
|
|
224
|
+
for (const item of valuesOf(cellOf(column, 0))) {
|
|
225
|
+
values.push({ pred: column.meta.name, val: typeof item === "string" ? item : textOf(item, dtype) });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return values;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Note a placed node column whose dtype reads back as another.
|
|
232
|
+
* @param note - records a note
|
|
233
|
+
* @param want - the dtype the column reads back as
|
|
234
|
+
* @param column - the column
|
|
235
|
+
*/
|
|
236
|
+
function dtypeNote(note, want, column) {
|
|
237
|
+
const listItems = column.dtype === "list" && column.child.dtype !== "string";
|
|
238
|
+
if (((want === "string" || want === "dict") && column.dtype !== want) || listItems) {
|
|
239
|
+
note(LOSS.DTYPE, `node column "${column.meta.name}" holds ${listItems ? "non-string items" : column.dtype}; it reads back as ${listItems ? "string items" : want}`, column.meta.name, column.length - column.nullCount);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* The property values of the written nodes that carry an xsd datatype.
|
|
244
|
+
* @param pv - the property_value column
|
|
245
|
+
* @param rows - the written nodes
|
|
246
|
+
* @returns the count
|
|
247
|
+
*/
|
|
248
|
+
function countDatatypes(pv, rows) {
|
|
249
|
+
let datatypes = 0;
|
|
250
|
+
for (const i of rows) {
|
|
251
|
+
for (const item of (cellOf(pv, i) ?? [])) {
|
|
252
|
+
datatypes += item.datatype === null ? 0 : 1;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return datatypes;
|
|
256
|
+
}
|
|
257
|
+
class ObographsExport {
|
|
258
|
+
/**
|
|
259
|
+
* Plan the export.
|
|
260
|
+
* @param snapshot - the snapshot
|
|
261
|
+
* @param settings - the resolved settings
|
|
262
|
+
*/
|
|
263
|
+
constructor(snapshot, settings) {
|
|
264
|
+
this.snapshot = snapshot;
|
|
265
|
+
this.notes = [];
|
|
266
|
+
this.note = (code, message, column = null, count = null) => {
|
|
267
|
+
this.notes.push(Object.freeze({ code, message, column, count }));
|
|
268
|
+
};
|
|
269
|
+
/** IRI to the shorthand the importer names it by. */
|
|
270
|
+
this.shorthands = new Map();
|
|
271
|
+
/** Shorthand to the IRI of its property. */
|
|
272
|
+
this.shorthandIris = new Map();
|
|
273
|
+
/** The IRI written for each node. */
|
|
274
|
+
this.iris = [];
|
|
275
|
+
/** The nodes whose IRI reads back as another id. */
|
|
276
|
+
this.changedRows = new Set();
|
|
277
|
+
/** The Typedef nodes written with a shorthand, by node. */
|
|
278
|
+
this.typedefShorthands = new Map();
|
|
279
|
+
this.written = [];
|
|
280
|
+
this.rows = [];
|
|
281
|
+
this.frameless = new Uint8Array(0);
|
|
282
|
+
this.label = null;
|
|
283
|
+
this.placed = new Map();
|
|
284
|
+
this.properties = [];
|
|
285
|
+
this.metaColumn = null;
|
|
286
|
+
this.edgeColumns = [];
|
|
287
|
+
this.preds = new Map();
|
|
288
|
+
this.nonfinite = { count: 0 };
|
|
289
|
+
this.kept = keptOf(snapshot);
|
|
290
|
+
this.ontologyIri = ontologyIriOf(snapshot, this.kept, settings.ontologyIri);
|
|
291
|
+
this.indent = settings.indent !== "" ? `\n${settings.indent}` : "";
|
|
292
|
+
for (const [iri, entry] of Object.entries(this.kept.properties)) {
|
|
293
|
+
const shorthand = shorthandOf(entry.meta);
|
|
294
|
+
if (shorthand !== null) {
|
|
295
|
+
this.shorthands.set(iri, shorthand);
|
|
296
|
+
this.shorthandIris.set(shorthand, iri);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
this.folding = pairFolding(snapshot);
|
|
300
|
+
this.ends = snapshot.edgeList();
|
|
301
|
+
for (let e = 0; e < snapshot.edgeCount; e++) {
|
|
302
|
+
if (!this.folding.folded(e)) {
|
|
303
|
+
this.written.push(e);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
this.weights = explicitWeights(snapshot);
|
|
307
|
+
this.planIds();
|
|
308
|
+
this.planNodes();
|
|
309
|
+
this.fatal =
|
|
310
|
+
capabilityNotes(snapshot, settings.common, {
|
|
311
|
+
caps: dialectCapabilities("obographs"),
|
|
312
|
+
label: this.label,
|
|
313
|
+
labelAssumed: slotColumn(snapshot.nodes, "label", "name").assumed,
|
|
314
|
+
edgeSlot: "edge meta",
|
|
315
|
+
note: this.note,
|
|
316
|
+
}) ?? this.emptyIdError();
|
|
317
|
+
this.planColumnNotes();
|
|
318
|
+
this.planEdges(settings.common);
|
|
319
|
+
emptyColumnNotes(snapshot, this.rows, this.frameless, this.written, this.note);
|
|
320
|
+
// a dry run counts the non-finite numbers the document writes as null
|
|
321
|
+
if (this.fatal === null) {
|
|
322
|
+
const parts = this.write();
|
|
323
|
+
while (parts.next().done !== true) {
|
|
324
|
+
// only the counts the writing leaves behind are wanted
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (this.nonfinite.count > 0) {
|
|
328
|
+
this.note(NONFINITE_AS_NULL_CODE, `${this.nonfinite.count} NaN or infinite value${plural(this.nonfinite.count)} ${agree(this.nonfinite.count, "is", "are")} written as null`, null, this.nonfinite.count);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* The id the importer reads an IRI back as: the shorthand of the property it names, else the
|
|
333
|
+
* compacted IRI.
|
|
334
|
+
* @param iri - the IRI
|
|
335
|
+
* @returns the id
|
|
336
|
+
*/
|
|
337
|
+
reread(iri) {
|
|
338
|
+
return this.shorthands.get(iri) ?? compactOboIri(iri);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* An id as an IRI: an IRI as it is, a CURIE as its OBO PURL, anything else under the
|
|
342
|
+
* ontology IRI.
|
|
343
|
+
* @param id - the id
|
|
344
|
+
* @returns the IRI
|
|
345
|
+
*/
|
|
346
|
+
expand(id) {
|
|
347
|
+
if (IRI.test(id)) {
|
|
348
|
+
return id;
|
|
349
|
+
}
|
|
350
|
+
const curie = CURIE.exec(id);
|
|
351
|
+
if (curie !== null && !curie[1].includes("_")) {
|
|
352
|
+
return `${OBO_PURL}${curie[1]}_${curie[2]}`;
|
|
353
|
+
}
|
|
354
|
+
return `${this.ontologyIri}#${id}`;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* The IRI to write for an id: the first form that reads back as the id (the property of a
|
|
358
|
+
* shorthand, the expanded IRI, the id itself); the id as it stands for a snapshot read with
|
|
359
|
+
* oboIds "iri".
|
|
360
|
+
* @param id - the id
|
|
361
|
+
* @returns the IRI and whether it reads back as the id
|
|
362
|
+
*/
|
|
363
|
+
iriOf(id) {
|
|
364
|
+
const candidates = this.kept.ids === "iri"
|
|
365
|
+
? [id]
|
|
366
|
+
: [this.shorthandIris.get(id), this.expand(id), id].filter((c) => c !== undefined);
|
|
367
|
+
const found = candidates.find((c) => this.reread(c) === id);
|
|
368
|
+
return found === undefined ? { iri: candidates[0], exact: false } : { iri: found, exact: true };
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* The pred to write for a relation: `is_a`, `type` for instance_of, the property of a
|
|
372
|
+
* shorthand, the expanded IRI or the relation itself, whichever reads back as the relation.
|
|
373
|
+
* @param r - the relation
|
|
374
|
+
* @returns the pred and whether it reads back as the relation
|
|
375
|
+
*/
|
|
376
|
+
predOf(r) {
|
|
377
|
+
const reverse = REVERSE_PREDICATES[r];
|
|
378
|
+
const candidates = [reverse, this.shorthandIris.get(r), this.expand(r), r].filter((c) => c !== undefined && !PROPERTY_PREDICATES.has(c));
|
|
379
|
+
const reread = (c) => BUILTIN_PREDICATES[c] ?? this.shorthands.get(c) ?? compactOboIri(c);
|
|
380
|
+
const found = this.kept.ids === "iri"
|
|
381
|
+
? candidates.find((c) => c === r && reread(c) === r)
|
|
382
|
+
: candidates.find((c) => reread(c) === r);
|
|
383
|
+
if (found !== undefined) {
|
|
384
|
+
return { pred: found, exact: true };
|
|
385
|
+
}
|
|
386
|
+
return { pred: this.kept.ids === "iri" ? r : candidates[0], exact: false };
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* An empty node id: OBO Graphs gives every node a non-empty id, and the importer skips a node
|
|
390
|
+
* without one, so the export is refused.
|
|
391
|
+
* @returns the error, or null when every id has text
|
|
392
|
+
*/
|
|
393
|
+
emptyIdError() {
|
|
394
|
+
const { snapshot } = this;
|
|
395
|
+
let count = 0;
|
|
396
|
+
let first = -1;
|
|
397
|
+
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
398
|
+
if (String(snapshot.ids.idOf(i)) === "") {
|
|
399
|
+
count++;
|
|
400
|
+
first = first < 0 ? i : first;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (count === 0) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
const message = `${count} node id${plural(count)} ${agree(count, "is", "are")} empty; an OBO Graphs node needs an id, so the save fails`;
|
|
407
|
+
this.note(LOSS.ID_CHARSET, message, null, count);
|
|
408
|
+
return new GraphFormatError("E_INVALID_ID", message, { reason: "charset", count, id: "", index: first });
|
|
409
|
+
}
|
|
410
|
+
/** The IRI of every node, the Typedefs named by a shorthand, and the numeric-id note. */
|
|
411
|
+
planIds() {
|
|
412
|
+
const { snapshot } = this;
|
|
413
|
+
const typeColumn = snapshot.nodes.get("type");
|
|
414
|
+
let numeric = 0;
|
|
415
|
+
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
416
|
+
const id = snapshot.ids.idOf(i);
|
|
417
|
+
numeric += typeof id === "number" ? 1 : 0;
|
|
418
|
+
const text = String(id);
|
|
419
|
+
let { iri, exact } = this.iriOf(text);
|
|
420
|
+
const typedef = typeColumn !== null && typeColumn.isSet(i) && typeColumn.value(i) === "Typedef";
|
|
421
|
+
if (!exact && typedef && !IRI.test(text) && this.kept.ids === "curie") {
|
|
422
|
+
// a Typedef named by its shorthand: written under an IRI with the shorthand declared
|
|
423
|
+
iri = this.expand(text);
|
|
424
|
+
this.shorthands.set(iri, text);
|
|
425
|
+
this.shorthandIris.set(text, iri);
|
|
426
|
+
this.typedefShorthands.set(i, text);
|
|
427
|
+
exact = true;
|
|
428
|
+
}
|
|
429
|
+
this.iris.push(iri);
|
|
430
|
+
if (!exact) {
|
|
431
|
+
this.changedRows.add(i);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (numeric > 0) {
|
|
435
|
+
this.note(LOSS.ID_TEXT_TYPE, `${numeric} numeric node id${plural(numeric)} ${agree(numeric, "is", "are")} written as text and read back as strings`, null, numeric);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/** The written nodes (placeholders aside), the node order, and the columns with a place. */
|
|
439
|
+
planNodes() {
|
|
440
|
+
const { snapshot } = this;
|
|
441
|
+
const { src, dst } = this.ends;
|
|
442
|
+
this.frameless = framelessNodes(snapshot, this.written, {
|
|
443
|
+
outgoingAllowed: true,
|
|
444
|
+
changed: (i) => this.changedRows.has(i),
|
|
445
|
+
});
|
|
446
|
+
const moved = movedNodes(this.frameless, this.written.flatMap((e) => [src[e], dst[e]]));
|
|
447
|
+
if (moved > 0) {
|
|
448
|
+
this.note(NODE_ORDER_CODE, `${moved} node${plural(moved)} ${agree(moved, "reads", "read")} back at another position: placeholder nodes are not written and read back after the written nodes`, null, moved);
|
|
449
|
+
}
|
|
450
|
+
this.rows = [];
|
|
451
|
+
for (let i = 0; i < snapshot.nodeCount; i++) {
|
|
452
|
+
if (this.frameless[i] === 0) {
|
|
453
|
+
this.rows.push(i);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
this.label = slotColumn(snapshot.nodes, "label", "name").column;
|
|
457
|
+
this.placeColumns();
|
|
458
|
+
this.planProperties();
|
|
459
|
+
}
|
|
460
|
+
/** The node columns written in their own places of a node (def, synonyms, xrefs...), not as property values. */
|
|
461
|
+
placeColumns() {
|
|
462
|
+
const { snapshot } = this;
|
|
463
|
+
const reproducible = (id) => typeof id === "string" && this.iriOf(id).exact;
|
|
464
|
+
for (const name of PLACED) {
|
|
465
|
+
const column = snapshot.nodes.get(name);
|
|
466
|
+
if (column !== null &&
|
|
467
|
+
column !== this.label &&
|
|
468
|
+
column.meta.role === null &&
|
|
469
|
+
carries(name, column, this.rows, reproducible)) {
|
|
470
|
+
this.placed.set(name, column);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const def = this.placed.get("def");
|
|
474
|
+
const defXrefs = this.placed.get("def.xrefs");
|
|
475
|
+
if (defXrefs !== undefined &&
|
|
476
|
+
(def === undefined || this.rows.some((i) => def.isSet(i) !== defXrefs.isSet(i)))) {
|
|
477
|
+
this.placed.delete("def.xrefs");
|
|
478
|
+
}
|
|
479
|
+
if (def !== undefined && !this.placed.has("def.xrefs") && snapshot.nodes.get("def.xrefs") !== null) {
|
|
480
|
+
this.placed.delete("def");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/** The node columns written as property values, each with its note. */
|
|
484
|
+
planProperties() {
|
|
485
|
+
const { snapshot } = this;
|
|
486
|
+
const slotted = new Set([...this.placed.values(), ...(this.label === null ? [] : [this.label])]);
|
|
487
|
+
for (const column of snapshot.nodes) {
|
|
488
|
+
const { role, name } = column.meta;
|
|
489
|
+
if (slotted.has(column) || (role !== null && UNWRITTEN_ROLES.has(role))) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (name === PLACEHOLDER_COLUMN && this.rows.every((i) => !column.isSet(i))) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
this.properties.push(column);
|
|
496
|
+
notePropertyColumn(this.note, column, this.rows, `basicPropertyValues (pred ${JSON.stringify(name)})`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/** The notes about node and graph columns: Typedef nodes, dtypes, datatypes, graph columns. */
|
|
500
|
+
planColumnNotes() {
|
|
501
|
+
const { snapshot, rows, label, note } = this;
|
|
502
|
+
const type = this.placed.get("type");
|
|
503
|
+
const typedefs = type === undefined ? 0 : rows.filter((i) => type.isSet(i) && type.value(i) === "Typedef").length;
|
|
504
|
+
if (typedefs > 0) {
|
|
505
|
+
note(TYPEDEF_NODES_CODE, `${typedefs} node${plural(typedefs)} ${agree(typedefs, "is", "are")} written as PROPERTY nodes; they read back as nodes only when imported with typedefs: "nodes", and then their edges with them`, "type", typedefs);
|
|
506
|
+
}
|
|
507
|
+
for (const [name, column] of [...this.placed, ...(label === null ? [] : [["name", label]])]) {
|
|
508
|
+
dtypeNote(note, name === "name" ? "string" : OBO_NODE_COLUMNS[name].dtype, column);
|
|
509
|
+
}
|
|
510
|
+
const pv = this.placed.get("property_value");
|
|
511
|
+
const datatypes = pv === undefined ? 0 : countDatatypes(pv, rows);
|
|
512
|
+
if (datatypes > 0) {
|
|
513
|
+
note(OBOGRAPHS_LOSS.DATATYPE_DROPPED, `${datatypes} property value${plural(datatypes)} ${agree(datatypes, "carries", "carry")} an xsd datatype; OBO Graphs basicPropertyValues have none, so they read back without it`, "property_value", datatypes);
|
|
514
|
+
}
|
|
515
|
+
for (const column of snapshot.graph) {
|
|
516
|
+
note(GRAPH_COLUMN_AS_METADATA_CODE, `graph column "${column.meta.name}" is written as a basicPropertyValue of the graph's meta and reads back in meta.extra.obographs, not as a column`, column.meta.name, column.length - column.nullCount);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* The edges' preds, meta and other columns, and their notes (relation, direction, ids that
|
|
521
|
+
* change).
|
|
522
|
+
* @param common - the common options
|
|
523
|
+
*/
|
|
524
|
+
planEdges(common) {
|
|
525
|
+
const { snapshot, written, note } = this;
|
|
526
|
+
const slot = slotColumn(snapshot.edges, "kind", "relation");
|
|
527
|
+
const relation = slot.column;
|
|
528
|
+
if (slot.assumed && relation !== null) {
|
|
529
|
+
note(LOSS.ROLE_ASSUMED, `edge column "relation" has no role, so it is taken as the relation of each edge: it is written as each edge's pred, and reads back with the relation role ("kind")`, "relation", relation.length - relation.nullCount);
|
|
530
|
+
}
|
|
531
|
+
const meta = snapshot.edges.get("meta");
|
|
532
|
+
const metaOk = meta !== null &&
|
|
533
|
+
meta.dtype === "json" &&
|
|
534
|
+
meta.meta.role === null &&
|
|
535
|
+
written.every((e) => !meta.isSet(e) || isJsonObject(cellOf(meta, e)));
|
|
536
|
+
this.metaColumn = metaOk ? meta : null;
|
|
537
|
+
for (const column of snapshot.edges) {
|
|
538
|
+
const { role } = column.meta;
|
|
539
|
+
if (column === relation ||
|
|
540
|
+
column === this.metaColumn ||
|
|
541
|
+
role === "id" ||
|
|
542
|
+
(role !== null && UNWRITTEN_ROLES.has(role))) {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
this.edgeColumns.push(column);
|
|
546
|
+
const count = written.filter((e) => column.isSet(e)).length;
|
|
547
|
+
if (count > 0) {
|
|
548
|
+
note(OBOGRAPHS_LOSS.EDGE_COLUMN_AS_META, `edge column "${column.meta.name}" is written into each edge's meta and reads back inside the meta column`, column.meta.name, count);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
const { weights } = this;
|
|
552
|
+
const weighted = weights.weighted ? written.filter((e) => weights.isExplicit(e)).length : 0;
|
|
553
|
+
if (weighted > 0) {
|
|
554
|
+
note(OBOGRAPHS_LOSS.EDGE_COLUMN_AS_META, `${weighted} explicit edge weight${plural(weighted)} ${agree(weighted, "is", "are")} written as "weight" in each edge's meta and read back inside the meta column, not as weights`, snapshot.edges.byRole("weight")?.meta.name ?? null, weighted);
|
|
555
|
+
}
|
|
556
|
+
this.planPreds(relation);
|
|
557
|
+
this.directionNotes(common);
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* The pred of every written edge, with the relation and id notes.
|
|
561
|
+
* @param relation - the relation column, or null
|
|
562
|
+
*/
|
|
563
|
+
planPreds(relation) {
|
|
564
|
+
let assumed = 0;
|
|
565
|
+
let relationChanges = 0;
|
|
566
|
+
for (const e of this.written) {
|
|
567
|
+
const value = relation === null ? undefined : cellOf(relation, e);
|
|
568
|
+
if (typeof value !== "string") {
|
|
569
|
+
assumed++;
|
|
570
|
+
this.preds.set(e, "is_a");
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
const { pred, exact } = this.predOf(value);
|
|
574
|
+
this.preds.set(e, pred);
|
|
575
|
+
relationChanges += exact ? 0 : 1;
|
|
576
|
+
}
|
|
577
|
+
if (assumed > 0) {
|
|
578
|
+
this.note(RELATION_ASSUMED_CODE, `${assumed} edge${plural(assumed)} ${agree(assumed, "has", "have")} no relation; written with the pred is_a (an ontology reads is_a as subclassing)`, relation?.meta.name ?? null, assumed);
|
|
579
|
+
}
|
|
580
|
+
const idChanges = this.rows.filter((i) => this.changedRows.has(i)).length;
|
|
581
|
+
if (idChanges + relationChanges > 0) {
|
|
582
|
+
this.note(OBOGRAPHS_LOSS.ID_CHANGED, `${idChanges} node id${plural(idChanges)} and ${relationChanges} relation${plural(relationChanges)} are written as IRIs the importer reads back as other ids under its default oboIds "curie"`, null, idChanges + relationChanges);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* The direction notes: every OBO Graphs edge is directed.
|
|
587
|
+
* @param common - the common options
|
|
588
|
+
*/
|
|
589
|
+
directionNotes(common) {
|
|
590
|
+
const { snapshot, written, folding, note } = this;
|
|
591
|
+
if (!snapshot.directed) {
|
|
592
|
+
note(DIRECTION_DROPPED_CODE, `the snapshot is undirected; OBO Graphs edges are directed and read back directed (${written.length} edge${plural(written.length)})`, null, written.length);
|
|
593
|
+
}
|
|
594
|
+
else if (common.onMixedDirection !== "error") {
|
|
595
|
+
const undirected = written.filter((e) => !folding.sourceDirected(e)).length;
|
|
596
|
+
if (undirected > 0) {
|
|
597
|
+
note(DIRECTION_DROPPED_CODE, `${undirected} undirected edge${plural(undirected)} ${agree(undirected, "is", "are")} written as one directed edge each`, null, undirected);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (folding.mutualCount > 0) {
|
|
601
|
+
note(LOSS.MUTUAL_EXPANDED, `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two edges; the mutual mark is lost`, null, folding.mutualCount);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* A placed column's cell.
|
|
606
|
+
* @param name - the vocabulary name
|
|
607
|
+
* @param i - the node
|
|
608
|
+
* @returns the value, or undefined
|
|
609
|
+
*/
|
|
610
|
+
at(name, i) {
|
|
611
|
+
const column = this.placed.get(name);
|
|
612
|
+
return column === undefined ? undefined : cellOf(column, i);
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* One node record as JSON.
|
|
616
|
+
* @param i - the node
|
|
617
|
+
* @returns the JSON text
|
|
618
|
+
*/
|
|
619
|
+
nodeRecord(i) {
|
|
620
|
+
const node = { id: this.iris[i] };
|
|
621
|
+
const lbl = this.label === null ? undefined : cellOf(this.label, i);
|
|
622
|
+
if (typeof lbl === "string") {
|
|
623
|
+
node.lbl = lbl;
|
|
624
|
+
}
|
|
625
|
+
// without a type column every node is a class; the type also marks the document as OBO Graphs
|
|
626
|
+
const untyped = this.snapshot.nodes.get("type") === null ? "Term" : undefined;
|
|
627
|
+
const type = this.placed.has("type") ? this.at("type", i) : untyped;
|
|
628
|
+
if (typeof type === "string") {
|
|
629
|
+
node.type = NODE_TYPES[type] ?? type;
|
|
630
|
+
}
|
|
631
|
+
const propertyType = this.at("propertyType", i);
|
|
632
|
+
if (propertyType !== undefined) {
|
|
633
|
+
node.propertyType = propertyType;
|
|
634
|
+
}
|
|
635
|
+
const meta = this.nodeMeta(i);
|
|
636
|
+
const extra = this.at("obo.unrecognized", i);
|
|
637
|
+
if (isJsonObject(extra)) {
|
|
638
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
639
|
+
if (key.startsWith("meta.")) {
|
|
640
|
+
meta[key.slice(5)] = value;
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
node[key] = value;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (Object.keys(meta).length > 0) {
|
|
648
|
+
node.meta = meta;
|
|
649
|
+
}
|
|
650
|
+
return json(node, this.nonfinite);
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* One node's meta: definition, comments, subsets, xrefs, synonyms, deprecated and the
|
|
654
|
+
* basicPropertyValues.
|
|
655
|
+
* @param i - the node
|
|
656
|
+
* @returns the meta record
|
|
657
|
+
*/
|
|
658
|
+
nodeMeta(i) {
|
|
659
|
+
const meta = {};
|
|
660
|
+
const def = this.at("def", i);
|
|
661
|
+
if (typeof def === "string") {
|
|
662
|
+
meta.definition = { val: def, xrefs: this.at("def.xrefs", i) ?? [] };
|
|
663
|
+
}
|
|
664
|
+
const comment = this.at("comment", i);
|
|
665
|
+
if (typeof comment === "string") {
|
|
666
|
+
meta.comments = [comment];
|
|
667
|
+
}
|
|
668
|
+
const subsets = this.at("subset", i);
|
|
669
|
+
if (Array.isArray(subsets)) {
|
|
670
|
+
meta.subsets = subsets.map((s) => this.iriOf(String(s)).iri);
|
|
671
|
+
}
|
|
672
|
+
const xrefs = this.at("xref", i);
|
|
673
|
+
if (Array.isArray(xrefs)) {
|
|
674
|
+
meta.xrefs = xrefs.map((val) => ({ val }));
|
|
675
|
+
}
|
|
676
|
+
const synonyms = this.at("synonym", i);
|
|
677
|
+
if (Array.isArray(synonyms)) {
|
|
678
|
+
meta.synonyms = synonyms.map((s) => this.synonymRecord(s));
|
|
679
|
+
}
|
|
680
|
+
const obsolete = this.at("is_obsolete", i);
|
|
681
|
+
if (typeof obsolete === "boolean") {
|
|
682
|
+
meta.deprecated = obsolete;
|
|
683
|
+
}
|
|
684
|
+
const values = this.propertyValues(i);
|
|
685
|
+
if (values.length > 0) {
|
|
686
|
+
meta.basicPropertyValues = values;
|
|
687
|
+
}
|
|
688
|
+
return meta;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* One synonym record.
|
|
692
|
+
* @param s - the synonym
|
|
693
|
+
* @returns the record
|
|
694
|
+
*/
|
|
695
|
+
synonymRecord(s) {
|
|
696
|
+
const out = {
|
|
697
|
+
pred: s.scope === null ? "hasSynonym" : `has${s.scope[0]}${s.scope.slice(1).toLowerCase()}Synonym`,
|
|
698
|
+
};
|
|
699
|
+
if (s.text !== null) {
|
|
700
|
+
out.val = s.text;
|
|
701
|
+
}
|
|
702
|
+
if (s.xrefs.length > 0) {
|
|
703
|
+
out.xrefs = s.xrefs;
|
|
704
|
+
}
|
|
705
|
+
if (s.type !== null) {
|
|
706
|
+
out.synonymType = this.iriOf(s.type).iri;
|
|
707
|
+
}
|
|
708
|
+
if (s.meta !== undefined) {
|
|
709
|
+
out.meta = s.meta;
|
|
710
|
+
}
|
|
711
|
+
return out;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* One node's basicPropertyValues: the tags OBO Graphs writes as annotations, the Typedef
|
|
715
|
+
* shorthand, the property values, then the columns outside the vocabulary.
|
|
716
|
+
* @param i - the node
|
|
717
|
+
* @returns the records
|
|
718
|
+
*/
|
|
719
|
+
propertyValues(i) {
|
|
720
|
+
const values = [];
|
|
721
|
+
for (const tag of PROPERTY_TAGS) {
|
|
722
|
+
const v = this.at(tag, i);
|
|
723
|
+
const pred = TAG_PREDICATES.get(tag) ?? tag;
|
|
724
|
+
for (const item of valuesOf(v)) {
|
|
725
|
+
const text = String(item);
|
|
726
|
+
values.push({ pred, val: tag === "replaced_by" || tag === "consider" ? this.iriOf(text).iri : text });
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
const shorthand = this.typedefShorthands.get(i);
|
|
730
|
+
if (shorthand !== undefined) {
|
|
731
|
+
values.push({ pred: `${OBO_IN_OWL}shorthand`, val: shorthand });
|
|
732
|
+
}
|
|
733
|
+
for (const item of (this.at("property_value", i) ?? [])) {
|
|
734
|
+
values.push({ pred: this.iriOf(item.relation).iri, val: item.value });
|
|
735
|
+
}
|
|
736
|
+
for (const column of this.properties) {
|
|
737
|
+
for (const val of propertyTexts(column, i)) {
|
|
738
|
+
values.push({ pred: column.meta.name, val });
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return values;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* One edge record as JSON.
|
|
745
|
+
* @param e - the edge
|
|
746
|
+
* @returns the JSON text
|
|
747
|
+
*/
|
|
748
|
+
edgeRecord(e) {
|
|
749
|
+
const { src, dst } = this.ends;
|
|
750
|
+
const edge = {
|
|
751
|
+
sub: this.iris[src[e]],
|
|
752
|
+
pred: this.preds.get(e),
|
|
753
|
+
obj: this.iris[dst[e]],
|
|
754
|
+
};
|
|
755
|
+
const base = this.metaColumn === null ? undefined : cellOf(this.metaColumn, e);
|
|
756
|
+
const meta = isJsonObject(base) ? { ...base } : {};
|
|
757
|
+
for (const column of this.edgeColumns) {
|
|
758
|
+
const v = cellOf(column, e);
|
|
759
|
+
if (v !== undefined) {
|
|
760
|
+
meta[column.meta.name] = v;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
if (this.weights.weighted && this.weights.isExplicit(e)) {
|
|
764
|
+
meta.weight = this.weights.value(e);
|
|
765
|
+
}
|
|
766
|
+
if (Object.keys(meta).length > 0 || base !== undefined) {
|
|
767
|
+
edge.meta = meta;
|
|
768
|
+
}
|
|
769
|
+
return json(edge, this.nonfinite);
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* The graph record up to its nodes: the id, the label and the meta (the graph columns as
|
|
773
|
+
* basicPropertyValues).
|
|
774
|
+
* @returns the JSON text without its closing brace
|
|
775
|
+
*/
|
|
776
|
+
graphHead() {
|
|
777
|
+
const { kept, snapshot } = this;
|
|
778
|
+
const graph = {
|
|
779
|
+
id: typeof kept.graph.id === "string" ? kept.graph.id : this.ontologyIri,
|
|
780
|
+
};
|
|
781
|
+
const named = snapshot.meta.name !== null && kept.graph.id === undefined;
|
|
782
|
+
const lbl = kept.graph.lbl ?? (named ? snapshot.meta.name : undefined);
|
|
783
|
+
if (lbl !== undefined) {
|
|
784
|
+
graph.lbl = lbl;
|
|
785
|
+
}
|
|
786
|
+
const meta = isJsonObject(kept.graph.meta) ? { ...kept.graph.meta } : {};
|
|
787
|
+
const values = Array.isArray(meta.basicPropertyValues)
|
|
788
|
+
? [...meta.basicPropertyValues]
|
|
789
|
+
: [];
|
|
790
|
+
values.push(...graphPropertyValues(snapshot));
|
|
791
|
+
if (values.length > 0) {
|
|
792
|
+
meta.basicPropertyValues = values;
|
|
793
|
+
}
|
|
794
|
+
if (Object.keys(meta).length > 0) {
|
|
795
|
+
graph.meta = meta;
|
|
796
|
+
}
|
|
797
|
+
return json(graph, this.nonfinite).slice(0, -1);
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* The graph keys after the edges (the kept axioms and other keys).
|
|
801
|
+
* @returns the JSON text from the comma to the closing brace
|
|
802
|
+
*/
|
|
803
|
+
graphTail() {
|
|
804
|
+
const rest = {};
|
|
805
|
+
for (const [key, value] of Object.entries(this.kept.graph)) {
|
|
806
|
+
if (key !== "id" && key !== "lbl" && key !== "meta" && key !== "nodes" && key !== "edges") {
|
|
807
|
+
rest[key] = value;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
const text = json(rest, this.nonfinite);
|
|
811
|
+
return text === "{}" ? "}" : `,${text.slice(1)}`;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* The kept PROPERTY nodes no written node stands for.
|
|
815
|
+
* @returns their JSON texts
|
|
816
|
+
*/
|
|
817
|
+
propertyNodes() {
|
|
818
|
+
const writtenIris = new Set(this.rows.map((i) => this.iris[i]));
|
|
819
|
+
const out = [];
|
|
820
|
+
for (const [iri, entry] of Object.entries(this.kept.properties)) {
|
|
821
|
+
if (writtenIris.has(iri)) {
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
const node = { id: iri, lbl: entry.lbl, type: "PROPERTY" };
|
|
825
|
+
node.propertyType = entry.propertyType;
|
|
826
|
+
node.meta = entry.meta;
|
|
827
|
+
out.push(json(node, this.nonfinite));
|
|
828
|
+
}
|
|
829
|
+
return out;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* The document's text parts.
|
|
833
|
+
* @yields the graph head, one part per node and edge, the tail
|
|
834
|
+
* @returns nothing
|
|
835
|
+
*/
|
|
836
|
+
*write() {
|
|
837
|
+
if (this.fatal !== null) {
|
|
838
|
+
throw this.fatal;
|
|
839
|
+
}
|
|
840
|
+
const { indent } = this;
|
|
841
|
+
yield `{"graphs":[${this.graphHead()},"nodes":[`;
|
|
842
|
+
let first = true;
|
|
843
|
+
const item = (text) => {
|
|
844
|
+
const out = `${first ? "" : ","}${indent}${text}`;
|
|
845
|
+
first = false;
|
|
846
|
+
return out;
|
|
847
|
+
};
|
|
848
|
+
for (const i of this.rows) {
|
|
849
|
+
yield item(this.nodeRecord(i));
|
|
850
|
+
}
|
|
851
|
+
for (const node of this.propertyNodes()) {
|
|
852
|
+
yield item(node);
|
|
853
|
+
}
|
|
854
|
+
yield `],"edges":[`;
|
|
855
|
+
first = true;
|
|
856
|
+
for (const e of this.written) {
|
|
857
|
+
yield item(this.edgeRecord(e));
|
|
858
|
+
}
|
|
859
|
+
for (const edge of this.kept.propertyEdges) {
|
|
860
|
+
yield item(json(edge, this.nonfinite));
|
|
861
|
+
}
|
|
862
|
+
yield `]${this.graphTail()}]`;
|
|
863
|
+
const document = json(this.kept.document, this.nonfinite);
|
|
864
|
+
yield document === "{}" ? "}\n" : `,${document.slice(1)}\n`;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Plan an OBO Graphs export.
|
|
869
|
+
* @param snapshot - the snapshot
|
|
870
|
+
* @param settings - the resolved settings
|
|
871
|
+
* @returns the notes and the writer
|
|
872
|
+
* @category Plugin helpers
|
|
873
|
+
*/
|
|
874
|
+
export function planObographs(snapshot, settings) {
|
|
875
|
+
const plan = new ObographsExport(snapshot, settings);
|
|
876
|
+
return { notes: plan.notes, write: () => plan.write() };
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Whether a vocabulary column is written into its OBO Graphs place and read back unchanged on
|
|
880
|
+
* every written node.
|
|
881
|
+
* @param name - the column name (a PLACED name)
|
|
882
|
+
* @param column - the column
|
|
883
|
+
* @param rows - the written nodes
|
|
884
|
+
* @param reproducible - whether an id is written as an IRI that reads back as itself
|
|
885
|
+
* @returns true when the place carries the column
|
|
886
|
+
*/
|
|
887
|
+
function carries(name, column, rows, reproducible) {
|
|
888
|
+
const spec = OBO_NODE_COLUMNS[name];
|
|
889
|
+
if (!fitsVocabulary(spec.dtype, column) || column.meta.components > 1) {
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
const valid = (v) => {
|
|
893
|
+
switch (name) {
|
|
894
|
+
case "type":
|
|
895
|
+
return typeof v === "string" && !Object.hasOwn(FRAME_TYPES, v);
|
|
896
|
+
case "propertyType":
|
|
897
|
+
case "def":
|
|
898
|
+
case "comment":
|
|
899
|
+
case "namespace":
|
|
900
|
+
case "created_by":
|
|
901
|
+
case "creation_date":
|
|
902
|
+
return typeof v === "string";
|
|
903
|
+
case "is_obsolete":
|
|
904
|
+
return typeof v === "boolean";
|
|
905
|
+
case "def.xrefs":
|
|
906
|
+
return strings(v, true);
|
|
907
|
+
case "xref":
|
|
908
|
+
case "alt_id":
|
|
909
|
+
return strings(v);
|
|
910
|
+
case "subset":
|
|
911
|
+
case "replaced_by":
|
|
912
|
+
case "consider":
|
|
913
|
+
return strings(v) && v.every(reproducible);
|
|
914
|
+
case "synonym":
|
|
915
|
+
return (Array.isArray(v) &&
|
|
916
|
+
v.length > 0 &&
|
|
917
|
+
v.every((s) => isJsonObject(s) &&
|
|
918
|
+
Object.keys(s).length === ("meta" in s ? 5 : 4) &&
|
|
919
|
+
(s.text === null || typeof s.text === "string") &&
|
|
920
|
+
(s.scope === null || (typeof s.scope === "string" && SYNONYM_SCOPES.has(s.scope))) &&
|
|
921
|
+
(s.type === null || reproducible(s.type)) &&
|
|
922
|
+
strings(s.xrefs, true)));
|
|
923
|
+
case "property_value":
|
|
924
|
+
return (Array.isArray(v) &&
|
|
925
|
+
v.length > 0 &&
|
|
926
|
+
v.every((x) => isJsonObject(x) &&
|
|
927
|
+
Object.keys(x).length === 3 &&
|
|
928
|
+
reproducible(x.relation) &&
|
|
929
|
+
!OBOGRAPHS_PREDICATE_TAGS.has(String(x.relation)) &&
|
|
930
|
+
typeof x.value === "string" &&
|
|
931
|
+
(x.datatype === null || typeof x.datatype === "string")));
|
|
932
|
+
case "obo.unrecognized":
|
|
933
|
+
return (isJsonObject(v) &&
|
|
934
|
+
Object.keys(v).every((key) => key.startsWith("meta.") ? !META_KEYS.has(key.slice(5)) && key.length > 5 : !NODE_KEYS.has(key)));
|
|
935
|
+
default:
|
|
936
|
+
return false;
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
return rows.every((i) => !column.isSet(i) || valid(cellOf(column, i)));
|
|
940
|
+
}
|
|
941
|
+
//# sourceMappingURL=obographs-export.js.map
|