@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
|
@@ -20,21 +20,30 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { GraphFormatError, INVALID_INDEX, } from "@graphty/graph-format";
|
|
22
22
|
import { declareResolved, RENAMED_CODE, ROLE_TAKEN_CODE } from "../../common/attributes.js";
|
|
23
|
-
import { BAD_VALUE_CODE, DANGLING_REFERENCE_CODE, DUPLICATE_ATTRIBUTE_CODE, DUPLICATE_NODE_CODE, EMPTY_INPUT_CODE, ENCODING_FALLBACK_CODE, INVALID_ENCODING_CODE, INVALID_UTF8_CODE, MISSING_ID_CODE, OPTION_IGNORED_CODE, UNKNOWN_ELEMENT_CODE, UNKNOWN_ENCODING_CODE, } from "../../common/codes.js";
|
|
23
|
+
import { BAD_VALUE_CODE, DANGLING_REFERENCE_CODE, DUPLICATE_ATTRIBUTE_CODE, DUPLICATE_NODE_CODE, ELEMENT_ISSUE, EMPTY_INPUT_CODE, ENCODING_FALLBACK_CODE, INPUT_ISSUE, INVALID_ENCODING_CODE, INVALID_UTF8_CODE, MISSING_ID_CODE, OPTION_IGNORED_CODE, UNKNOWN_ELEMENT_CODE, UNKNOWN_ENCODING_CODE, } from "../../common/codes.js";
|
|
24
24
|
import { DirectionResolver } from "../../common/direction.js";
|
|
25
25
|
import { ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
|
|
26
26
|
import { LineReader, throwIfAborted } from "../../common/input.js";
|
|
27
27
|
import { OBO_NODE_COLUMNS, oboColumnDecl, PLACEHOLDER_COLUMN, SYNONYM_SCOPES } from "../../common/ontology.js";
|
|
28
28
|
import { reportSinkOptions, reportUnusedOptions, resolveImportOptions, SINK_OPTION_CODE, } from "../../common/options.js";
|
|
29
|
+
import { agree, plural } from "../../common/plural.js";
|
|
29
30
|
import { ImportReportBuilder } from "../../common/report.js";
|
|
30
|
-
import { endsWithContinuation, hasStrayBrace, parseXref, parseXrefList, splitQualifiers, splitTagValue, stripComment, tokenize, unescapeObo, } from "./syntax.js";
|
|
31
|
-
/**
|
|
31
|
+
import { endsWithContinuation, hasStrayBrace, parseXref, parseXrefList, splitFormFeeds, splitQualifiers, splitTagValue, stripComment, tokenize, unclosedBlock, unescapeObo, } from "./syntax.js";
|
|
32
|
+
/**
|
|
33
|
+
* Issue codes of the OBO importer.
|
|
34
|
+
* @category Built-in formats
|
|
35
|
+
*/
|
|
32
36
|
export const OBO_ISSUE = Object.freeze({
|
|
33
|
-
|
|
37
|
+
...INPUT_ISSUE,
|
|
38
|
+
...ELEMENT_ISSUE,
|
|
39
|
+
/** The input is empty or whitespace. The import stops. */
|
|
34
40
|
EMPTY_INPUT: EMPTY_INPUT_CODE,
|
|
35
|
-
/** The input
|
|
41
|
+
/** The input is not valid UTF-8. The import stops. */
|
|
36
42
|
INVALID_UTF8: INVALID_UTF8_CODE,
|
|
37
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Some bytes are not valid in the encoding that was chosen (by a byte order mark or the `encoding` option). The
|
|
45
|
+
* import stops.
|
|
46
|
+
*/
|
|
38
47
|
INVALID_ENCODING: INVALID_ENCODING_CODE,
|
|
39
48
|
/** Bytes that are not UTF-8 were read as windows-1252. */
|
|
40
49
|
ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
|
|
@@ -44,9 +53,9 @@ export const OBO_ISSUE = Object.freeze({
|
|
|
44
53
|
MISSING_ID: MISSING_ID_CODE,
|
|
45
54
|
/** A clause whose value cannot be read (a boolean other than true / false, a relationship with one or three values); the clause is skipped. */
|
|
46
55
|
BAD_VALUE: BAD_VALUE_CODE,
|
|
47
|
-
/** Two frames
|
|
56
|
+
/** Two frames have the same id, so they were merged into one node. */
|
|
48
57
|
DUPLICATE_NODE: DUPLICATE_NODE_CODE,
|
|
49
|
-
/** A
|
|
58
|
+
/** A tag that may appear once per frame appears twice; the first value is kept. */
|
|
50
59
|
DUPLICATE_ATTRIBUTE: DUPLICATE_ATTRIBUTE_CODE,
|
|
51
60
|
/** An unknown tag (kept in `obo.unrecognized`) or frame type (skipped), once per name. */
|
|
52
61
|
UNKNOWN_ELEMENT: UNKNOWN_ELEMENT_CODE,
|
|
@@ -54,6 +63,16 @@ export const OBO_ISSUE = Object.freeze({
|
|
|
54
63
|
DANGLING_REFERENCE: DANGLING_REFERENCE_CODE,
|
|
55
64
|
/** A line without a colon, an unterminated quote, a def without its xref list, a qualifier block that does not parse, an unescaped brace. */
|
|
56
65
|
SYNTAX: "W_OBO_SYNTAX",
|
|
66
|
+
/**
|
|
67
|
+
* Nothing in the input looks like OBO: there is no frame header and no header tag. It may be an HTML page, a JSON
|
|
68
|
+
* or GML file, or UTF-16 text without a byte order mark. The import stops.
|
|
69
|
+
*/
|
|
70
|
+
NOT_OBO: "E_OBO_NOT_OBO",
|
|
71
|
+
/**
|
|
72
|
+
* The header has no `format-version` (OBO 1.2 and 1.4 require one), or names a version other than 1.0, 1.2 or 1.4.
|
|
73
|
+
* The file is read accepting the tags of every version.
|
|
74
|
+
*/
|
|
75
|
+
FORMAT_VERSION: "W_OBO_FORMAT_VERSION",
|
|
57
76
|
/** The frame's `id` is not its first clause; it is used anyway. */
|
|
58
77
|
ID_NOT_FIRST: "W_OBO_ID_NOT_FIRST",
|
|
59
78
|
/** A synonym without a scope in a file that does not say 1.2, or with a scope that is not one of the four. */
|
|
@@ -62,7 +81,7 @@ export const OBO_ISSUE = Object.freeze({
|
|
|
62
81
|
UNDECLARED: "W_OBO_UNDECLARED",
|
|
63
82
|
/** One id for a Term and a Typedef (or an Instance); the Term (the first node frame) is the node. */
|
|
64
83
|
ID_KIND_CLASH: "W_OBO_ID_KIND_CLASH",
|
|
65
|
-
/**
|
|
84
|
+
/** A frame has only one `intersection_of` or `union_of` clause, where OBO needs at least two. */
|
|
66
85
|
CARDINALITY: "W_OBO_CARDINALITY",
|
|
67
86
|
/** An obsolete term with is_a / relationship, or replaced_by / consider on a term that is not obsolete. */
|
|
68
87
|
OBSOLETION: "W_OBO_OBSOLETION",
|
|
@@ -70,19 +89,31 @@ export const OBO_ISSUE = Object.freeze({
|
|
|
70
89
|
DEPRECATED_TAG: "W_OBO_DEPRECATED_TAG",
|
|
71
90
|
/** A backslash line continuation (deprecated in 1.4). */
|
|
72
91
|
DEPRECATED_SYNTAX: "W_OBO_DEPRECATED_SYNTAX",
|
|
73
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* A header clause whose meaning graph-io does not apply (`import`, `id-mapping`, the `treat-xrefs` macros,
|
|
94
|
+
* `owl-axioms`); it is kept in `snapshot.meta.extra.obo.header`.
|
|
95
|
+
*/
|
|
74
96
|
HEADER_NOT_APPLIED: "W_OBO_HEADER_NOT_APPLIED",
|
|
75
97
|
/** Obsolete terms and their edges left out under obsolete: "drop". */
|
|
76
98
|
OBSOLETE_DROPPED: "W_OBO_OBSOLETE_DROPPED",
|
|
77
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Two different id texts became the same number because `ids` is "number" (for example, "042" and "42"), so their nodes
|
|
101
|
+
* were merged.
|
|
102
|
+
*/
|
|
78
103
|
ID_MERGED: ID_MERGED_CODE,
|
|
79
|
-
/**
|
|
104
|
+
/** An OBO attribute was renamed `<name>#obo` because another attribute already has its name. */
|
|
80
105
|
COLUMN_RENAMED: RENAMED_CODE,
|
|
81
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
|
|
108
|
+
* a plain attribute.
|
|
109
|
+
*/
|
|
82
110
|
ROLE_TAKEN: ROLE_TAKEN_CODE,
|
|
83
|
-
/**
|
|
111
|
+
/** You set an option this format does not use; it had no effect. The message names the option. */
|
|
84
112
|
OPTION_IGNORED: OPTION_IGNORED_CODE,
|
|
85
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
|
|
115
|
+
* `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
|
|
116
|
+
*/
|
|
86
117
|
SINK_OPTION: SINK_OPTION_CODE,
|
|
87
118
|
});
|
|
88
119
|
/** The common options the OBO importer reads. */
|
|
@@ -97,7 +128,10 @@ const USED_OPTIONS = new Set([
|
|
|
97
128
|
"signal",
|
|
98
129
|
"onProgress",
|
|
99
130
|
"encoding",
|
|
131
|
+
"restoreMangledIds",
|
|
100
132
|
]);
|
|
133
|
+
/** The property_value relation under which the exporter keeps an id it rewrote (`sanitizeIds: "mangle"`). */
|
|
134
|
+
const ORIGINAL_ID = "graphty:originalId";
|
|
101
135
|
const DEFAULTS = { ids: "keep", defaultDirected: true, weightFrom: null };
|
|
102
136
|
/** Frames between two checks of the cancellation signal. */
|
|
103
137
|
const ABORT_CHECK_INTERVAL = 64;
|
|
@@ -111,8 +145,11 @@ const DEPRECATED_HEADER = new Map([
|
|
|
111
145
|
["typeref", "import"],
|
|
112
146
|
["version", "data-version"],
|
|
113
147
|
]);
|
|
114
|
-
/**
|
|
115
|
-
|
|
148
|
+
/**
|
|
149
|
+
* The 1.0 / 1.2 frame tags read as their 1.4 meaning: tag to [1.4 tag, synonym scope].
|
|
150
|
+
* @category Plugin helpers
|
|
151
|
+
*/
|
|
152
|
+
export const DEPRECATED_TAGS = new Map([
|
|
116
153
|
["exact_synonym", ["synonym", "EXACT"]],
|
|
117
154
|
["narrow_synonym", ["synonym", "NARROW"]],
|
|
118
155
|
["broad_synonym", ["synonym", "BROAD"]],
|
|
@@ -131,8 +168,11 @@ const BUILTIN_RELATIONS = new Set([
|
|
|
131
168
|
"union_of",
|
|
132
169
|
"intersection_of",
|
|
133
170
|
]);
|
|
134
|
-
/**
|
|
135
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Single-valued text tags (first value kept).
|
|
173
|
+
* @category Plugin helpers
|
|
174
|
+
*/
|
|
175
|
+
export const TEXT_TAGS = new Set([
|
|
136
176
|
"name",
|
|
137
177
|
"namespace",
|
|
138
178
|
"comment",
|
|
@@ -142,10 +182,16 @@ const TEXT_TAGS = new Set([
|
|
|
142
182
|
"range",
|
|
143
183
|
"inverse_of",
|
|
144
184
|
]);
|
|
145
|
-
/**
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Single-valued boolean tags.
|
|
187
|
+
* @category Plugin helpers
|
|
188
|
+
*/
|
|
189
|
+
export const BOOL_TAGS = new Set(Object.keys(OBO_NODE_COLUMNS).filter((name) => OBO_NODE_COLUMNS[name].dtype === "bool"));
|
|
190
|
+
/**
|
|
191
|
+
* Tags whose value is one id, collected in a list column.
|
|
192
|
+
* @category Plugin helpers
|
|
193
|
+
*/
|
|
194
|
+
export const ID_LIST_TAGS = new Set([
|
|
149
195
|
"alt_id",
|
|
150
196
|
"subset",
|
|
151
197
|
"replaced_by",
|
|
@@ -156,8 +202,80 @@ const ID_LIST_TAGS = new Set([
|
|
|
156
202
|
"transitive_over",
|
|
157
203
|
"disjoint_over",
|
|
158
204
|
]);
|
|
159
|
-
/**
|
|
160
|
-
const
|
|
205
|
+
/** Header tags the specification allows once (the first is kept). */
|
|
206
|
+
const SINGLE_HEADER_TAGS = new Set([
|
|
207
|
+
"format-version",
|
|
208
|
+
"data-version",
|
|
209
|
+
"version",
|
|
210
|
+
"date",
|
|
211
|
+
"saved-by",
|
|
212
|
+
"auto-generated-by",
|
|
213
|
+
"default-namespace",
|
|
214
|
+
"ontology",
|
|
215
|
+
"default-relationship-id-prefix",
|
|
216
|
+
]);
|
|
217
|
+
/** The format versions the importer knows (it reads their union). */
|
|
218
|
+
const KNOWN_VERSION = /^(GO_)?1\.[024]$/;
|
|
219
|
+
/** Tags whose value is an id, where a qualifier block cut short by a truncated file is dropped. */
|
|
220
|
+
const ID_VALUE_TAGS = new Set([
|
|
221
|
+
...ID_LIST_TAGS,
|
|
222
|
+
"is_a",
|
|
223
|
+
"instance_of",
|
|
224
|
+
"relationship",
|
|
225
|
+
"intersection_of",
|
|
226
|
+
]);
|
|
227
|
+
/** Warnings listed per code before the rest are summed up in one (a file of 50k unknown tags). */
|
|
228
|
+
const MAX_TALLIES_PER_CODE = 100;
|
|
229
|
+
/**
|
|
230
|
+
* Whether a text holds a control character other than tab, line feed, form feed (a line end in
|
|
231
|
+
* the 1.4 grammar, text inside quotes) and carriage return.
|
|
232
|
+
* @param text - the text
|
|
233
|
+
* @returns true when it does
|
|
234
|
+
*/
|
|
235
|
+
function hasControl(text) {
|
|
236
|
+
for (const ch of text) {
|
|
237
|
+
if ((ch < " " && ch !== "\t" && ch !== "\n" && ch !== "\f" && ch !== "\r") || ch === "\x7f") {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Whether a tag could name an OBO tag: no whitespace, control characters or the punctuation of
|
|
245
|
+
* other formats (`{`, `"`, `<`, brackets, parentheses).
|
|
246
|
+
* @param tag - the tag
|
|
247
|
+
* @returns true for a plausible tag
|
|
248
|
+
*/
|
|
249
|
+
function isTagName(tag) {
|
|
250
|
+
return tag.length > 0 && !hasControl(tag) && !/[\s{}"<>[\]()]/.test(tag);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* A record with no prototype, so a key named after an Object.prototype member (`__proto__`,
|
|
254
|
+
* `constructor`, `toString`) is an own key like any other.
|
|
255
|
+
* @returns the empty record
|
|
256
|
+
*/
|
|
257
|
+
function ownRecord() {
|
|
258
|
+
return Object.create(null);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Append a value to the list of a key in a null-prototype record.
|
|
262
|
+
* @param map - the record
|
|
263
|
+
* @param key - the key
|
|
264
|
+
* @param value - the value
|
|
265
|
+
*/
|
|
266
|
+
function append(map, key, value) {
|
|
267
|
+
if (Object.hasOwn(map, key)) {
|
|
268
|
+
map[key].push(value);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
map[key] = [value];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Tags that only a Typedef frame may carry (elsewhere they are unrecognized).
|
|
276
|
+
* @category Plugin helpers
|
|
277
|
+
*/
|
|
278
|
+
export const TYPEDEF_TAGS = new Set([
|
|
161
279
|
"domain",
|
|
162
280
|
"range",
|
|
163
281
|
"inverse_of",
|
|
@@ -214,10 +332,17 @@ class OboReader {
|
|
|
214
332
|
* Create a reader.
|
|
215
333
|
* @param report - the report
|
|
216
334
|
* @param signal - the cancellation signal
|
|
335
|
+
* @param typedefsAsNodes - whether `[Typedef]` frames are nodes
|
|
217
336
|
*/
|
|
218
|
-
constructor(report, signal) {
|
|
337
|
+
constructor(report, signal, typedefsAsNodes) {
|
|
219
338
|
/** Header clauses by tag, raw, in order. */
|
|
220
|
-
this.header =
|
|
339
|
+
this.header = ownRecord();
|
|
340
|
+
/** Whether any frame header was read. */
|
|
341
|
+
this.frameSeen = false;
|
|
342
|
+
/** Header clauses whose tag could be an OBO tag. */
|
|
343
|
+
this.tagClauses = 0;
|
|
344
|
+
/** The first line that is not a frame header, a comment or a tag-value line with a plausible tag. */
|
|
345
|
+
this.firstBadLine = null;
|
|
221
346
|
this.version = null;
|
|
222
347
|
this.defaultNamespace = null;
|
|
223
348
|
this.subsets = new Set();
|
|
@@ -237,6 +362,7 @@ class OboReader {
|
|
|
237
362
|
this.significant = false;
|
|
238
363
|
this.report = report;
|
|
239
364
|
this.signal = signal;
|
|
365
|
+
this.typedefsAsNodes = typedefsAsNodes;
|
|
240
366
|
}
|
|
241
367
|
/**
|
|
242
368
|
* Read one logical line.
|
|
@@ -252,32 +378,71 @@ class OboReader {
|
|
|
252
378
|
if (t.startsWith("!")) {
|
|
253
379
|
return;
|
|
254
380
|
}
|
|
255
|
-
|
|
256
|
-
if (header !== null) {
|
|
257
|
-
this.startFrame(header[1].trim(), line);
|
|
381
|
+
if (t.startsWith("[") && this.frameHeader(t, line)) {
|
|
258
382
|
return;
|
|
259
383
|
}
|
|
260
384
|
// the comment goes first, so a colon inside it never makes `foo ! a:b` a tag-value line
|
|
261
385
|
const tv = splitTagValue(stripComment(t));
|
|
262
|
-
if (tv === null) {
|
|
263
|
-
this.
|
|
386
|
+
if (tv === null || tv.tag.length === 0) {
|
|
387
|
+
this.firstBadLine ?? (this.firstBadLine = line);
|
|
388
|
+
const what = tv === null ? "a line without a colon was skipped" : "a line without a tag was skipped";
|
|
389
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, what, "line", line);
|
|
264
390
|
return;
|
|
265
391
|
}
|
|
266
392
|
const clause = { tag: tv.tag, value: stripComment(tv.rest), line };
|
|
267
393
|
if (this.frame === null) {
|
|
394
|
+
if (isTagName(tv.tag)) {
|
|
395
|
+
this.tagClauses++;
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
this.firstBadLine ?? (this.firstBadLine = line);
|
|
399
|
+
}
|
|
268
400
|
this.headerClause(clause);
|
|
269
401
|
}
|
|
270
402
|
else {
|
|
271
403
|
this.frame.clauses.push(clause);
|
|
272
404
|
}
|
|
273
405
|
}
|
|
406
|
+
/**
|
|
407
|
+
* Start a frame at a line opening with `[`: a well-formed header, or one damaged so that only a
|
|
408
|
+
* frame header can be meant (a known frame name, or no colon: `[Term`, `[Term] extra`), with a
|
|
409
|
+
* warning, so the clauses after it never merge into the frame before.
|
|
410
|
+
* @param t - the trimmed line
|
|
411
|
+
* @param line - its number
|
|
412
|
+
* @returns false when the line is not a frame header
|
|
413
|
+
*/
|
|
414
|
+
frameHeader(t, line) {
|
|
415
|
+
const close = t.indexOf("]");
|
|
416
|
+
const name = (close < 0 ? t.slice(1) : t.slice(1, close)).trim();
|
|
417
|
+
const after = close < 0 ? "" : t.slice(close + 1).trim();
|
|
418
|
+
const clean = close >= 0 && (after.length === 0 || after.startsWith("!"));
|
|
419
|
+
if (!clean && !FRAME_KINDS.has(name) && t.includes(":")) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
if (!clean) {
|
|
423
|
+
const what = close < 0
|
|
424
|
+
? "a frame header without its closing ] starts the frame"
|
|
425
|
+
: "text after a frame header was ignored";
|
|
426
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, what, `[${name}]`, line);
|
|
427
|
+
}
|
|
428
|
+
// a known frame name, or a clean header with a name: anything else (`[`, `[{"id": 1}]`, a JSON
|
|
429
|
+
// array) is read as a damaged header but is no proof the input is OBO
|
|
430
|
+
const proof = FRAME_KINDS.has(name) || (clean && /^[A-Za-z]/.test(name) && isTagName(name));
|
|
431
|
+
if (!proof) {
|
|
432
|
+
this.firstBadLine ?? (this.firstBadLine = line);
|
|
433
|
+
}
|
|
434
|
+
this.startFrame(name, line, proof);
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
274
437
|
/**
|
|
275
438
|
* Start a frame, finishing the one before.
|
|
276
439
|
* @param name - the frame type
|
|
277
440
|
* @param line - the header's line
|
|
441
|
+
* @param proof - whether the header shows the input is OBO
|
|
278
442
|
*/
|
|
279
|
-
startFrame(name, line) {
|
|
443
|
+
startFrame(name, line, proof) {
|
|
280
444
|
this.finishFrame();
|
|
445
|
+
this.frameSeen || (this.frameSeen = proof);
|
|
281
446
|
const kind = FRAME_KINDS.has(name) ? name : null;
|
|
282
447
|
if (kind === null) {
|
|
283
448
|
this.tally("validation-error", OBO_ISSUE.UNKNOWN_ELEMENT, "frames of an unknown type are not nodes; kept in meta.extra.obo.unknownFrames", `[${name}]`, line);
|
|
@@ -289,9 +454,11 @@ class OboReader {
|
|
|
289
454
|
* @param clause - the clause
|
|
290
455
|
*/
|
|
291
456
|
headerClause(clause) {
|
|
292
|
-
|
|
293
|
-
((_a = this.header)[_b = clause.tag] ?? (_a[_b] = [])).push(clause.value);
|
|
457
|
+
append(this.header, clause.tag, clause.value);
|
|
294
458
|
const { tag } = clause;
|
|
459
|
+
if (SINGLE_HEADER_TAGS.has(tag) && this.header[tag].length > 1) {
|
|
460
|
+
this.tally("validation-error", OBO_ISSUE.DUPLICATE_ATTRIBUTE, "a single-valued header tag given twice; the first is kept", tag, clause.line);
|
|
461
|
+
}
|
|
295
462
|
const tokens = tokenize(splitQualifiers(clause.value).value);
|
|
296
463
|
const first = tokens.length > 0 && tokens[0].kind === "word" ? tokens[0].text : null;
|
|
297
464
|
if (tag === "format-version") {
|
|
@@ -300,6 +467,9 @@ class OboReader {
|
|
|
300
467
|
else if (tag === "default-namespace") {
|
|
301
468
|
this.defaultNamespace ?? (this.defaultNamespace = first);
|
|
302
469
|
}
|
|
470
|
+
else if ((tag === "subsetdef" || tag === "synonymtypedef") && first === null) {
|
|
471
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "a declaration whose name is not a word declares nothing", tag, clause.line);
|
|
472
|
+
}
|
|
303
473
|
else if (tag === "subsetdef" && first !== null) {
|
|
304
474
|
this.subsets.add(first);
|
|
305
475
|
}
|
|
@@ -317,7 +487,6 @@ class OboReader {
|
|
|
317
487
|
}
|
|
318
488
|
/** Finish the frame being read: find its id and merge its clauses into the record of that id. */
|
|
319
489
|
finishFrame() {
|
|
320
|
-
var _a, _b;
|
|
321
490
|
const { frame } = this;
|
|
322
491
|
this.frame = null;
|
|
323
492
|
if (frame === null) {
|
|
@@ -325,9 +494,9 @@ class OboReader {
|
|
|
325
494
|
}
|
|
326
495
|
if (frame.kind === null) {
|
|
327
496
|
// the guides: an unrecognized frame must survive, so its clauses are kept, raw
|
|
328
|
-
const clauses =
|
|
497
|
+
const clauses = ownRecord();
|
|
329
498
|
for (const clause of frame.clauses) {
|
|
330
|
-
(clauses
|
|
499
|
+
append(clauses, clause.tag, clause.value);
|
|
331
500
|
}
|
|
332
501
|
this.unknownFrames.push({ type: frame.name, clauses });
|
|
333
502
|
return;
|
|
@@ -337,18 +506,34 @@ class OboReader {
|
|
|
337
506
|
throwIfAborted(this.signal);
|
|
338
507
|
}
|
|
339
508
|
const idAt = frame.clauses.findIndex((c) => c.tag === "id");
|
|
340
|
-
const
|
|
509
|
+
const idParts = idAt < 0 ? null : splitQualifiers(frame.clauses[idAt].value);
|
|
510
|
+
const rawId = idParts === null ? "" : idParts.value.trim();
|
|
511
|
+
const id = unescapeObo(rawId).trim();
|
|
512
|
+
// a Typedef is metadata unless typedefs "nodes": it would never have been a node
|
|
513
|
+
const wouldBeNode = frame.kind !== "Typedef" || this.typedefsAsNodes;
|
|
341
514
|
if (id.length === 0) {
|
|
342
515
|
this.report.error("missing-value", OBO_ISSUE.MISSING_ID, `a [${frame.kind}] frame has no id; it is skipped`, {
|
|
343
516
|
line: frame.line,
|
|
344
517
|
});
|
|
345
|
-
|
|
518
|
+
if (wouldBeNode) {
|
|
519
|
+
this.report.counts.skippedNodes++;
|
|
520
|
+
}
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
if (tokenize(rawId).length > 1 || hasControl(id)) {
|
|
524
|
+
// a reference cannot name such an id (is_a needs one word), so the frame is refused
|
|
525
|
+
// rather than made a node no edge can reach
|
|
526
|
+
this.report.error("validation-error", OBO_ISSUE.BAD_VALUE, `a [${frame.kind}] frame's id ${JSON.stringify(id)} holds unescaped whitespace or a control character; the frame is skipped`, { line: frame.clauses[idAt].line, element: id });
|
|
527
|
+
if (wouldBeNode) {
|
|
528
|
+
this.report.counts.skippedNodes++;
|
|
529
|
+
}
|
|
346
530
|
return;
|
|
347
531
|
}
|
|
348
532
|
if (idAt > 0) {
|
|
349
533
|
this.tally("validation-error", OBO_ISSUE.ID_NOT_FIRST, "the id clause is not the frame's first; it is used", "id", frame.clauses[idAt].line);
|
|
350
534
|
}
|
|
351
|
-
const
|
|
535
|
+
const target = this.recordFor(frame.kind, id, frame.line);
|
|
536
|
+
this.extraQualifiers(target, "id", id, idParts?.qualifiers ?? null);
|
|
352
537
|
for (let i = 0; i < frame.clauses.length; i++) {
|
|
353
538
|
const clause = frame.clauses[i];
|
|
354
539
|
if (clause.tag === "id") {
|
|
@@ -357,10 +542,10 @@ class OboReader {
|
|
|
357
542
|
}
|
|
358
543
|
continue;
|
|
359
544
|
}
|
|
360
|
-
this.applyClause(
|
|
545
|
+
this.applyClause(target, clause);
|
|
361
546
|
}
|
|
362
|
-
if (
|
|
363
|
-
|
|
547
|
+
if (target.kind === "Typedef" && !Object.hasOwn(target.raw, "id")) {
|
|
548
|
+
target.raw.id = [id];
|
|
364
549
|
}
|
|
365
550
|
}
|
|
366
551
|
/**
|
|
@@ -378,14 +563,11 @@ class OboReader {
|
|
|
378
563
|
this.tally("validation-error", OBO_ISSUE.ID_KIND_CLASH, `an id names both a ${existing.kind} and an ${kind}; the ${existing.kind} is the node`, id, line);
|
|
379
564
|
}
|
|
380
565
|
else {
|
|
381
|
-
this.
|
|
382
|
-
line,
|
|
383
|
-
element: id,
|
|
384
|
-
});
|
|
566
|
+
this.tally("merged", OBO_ISSUE.DUPLICATE_NODE, `[${kind}] frames with this id are merged (spec 4.1.1)`, id, line);
|
|
385
567
|
}
|
|
386
568
|
return existing;
|
|
387
569
|
}
|
|
388
|
-
const
|
|
570
|
+
const created = {
|
|
389
571
|
id,
|
|
390
572
|
kind,
|
|
391
573
|
line,
|
|
@@ -393,10 +575,10 @@ class OboReader {
|
|
|
393
575
|
lists: new Map(),
|
|
394
576
|
edges: [],
|
|
395
577
|
seen: new Set(),
|
|
396
|
-
raw:
|
|
578
|
+
raw: ownRecord(),
|
|
397
579
|
};
|
|
398
|
-
map.set(id,
|
|
399
|
-
return
|
|
580
|
+
map.set(id, created);
|
|
581
|
+
return created;
|
|
400
582
|
}
|
|
401
583
|
/**
|
|
402
584
|
* A clause's tag (a 1.0 tag read as its current one), the synonym scope that tag implies, its
|
|
@@ -412,7 +594,12 @@ class OboReader {
|
|
|
412
594
|
this.tally("coercion", OBO_ISSUE.DEPRECATED_TAG, `the 1.0 tag is read as ${deprecated[0]}`, tag, clause.line);
|
|
413
595
|
[tag, scope] = deprecated;
|
|
414
596
|
}
|
|
415
|
-
|
|
597
|
+
let split = splitQualifiers(clause.value);
|
|
598
|
+
const open = ID_VALUE_TAGS.has(tag) ? unclosedBlock(split.value) : -1;
|
|
599
|
+
if (open >= 0) {
|
|
600
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "a qualifier block without its closing brace was dropped", tag, clause.line);
|
|
601
|
+
split = splitQualifiers(split.value.slice(0, open).trimEnd());
|
|
602
|
+
}
|
|
416
603
|
const { qualifiers } = split;
|
|
417
604
|
if (split.badBlock !== null) {
|
|
418
605
|
this.tally("parse-error", OBO_ISSUE.SYNTAX, "a closing brace that is not a qualifier block was kept as text", tag, clause.line);
|
|
@@ -454,24 +641,23 @@ class OboReader {
|
|
|
454
641
|
* @param clause - the clause
|
|
455
642
|
*/
|
|
456
643
|
applyClause(record, clause) {
|
|
457
|
-
var _a, _b;
|
|
458
644
|
const key = `${clause.tag}\u0000${clause.value}`;
|
|
459
645
|
if (record.seen.has(key)) {
|
|
460
646
|
return;
|
|
461
647
|
}
|
|
462
648
|
record.seen.add(key);
|
|
463
649
|
if (record.kind === "Typedef") {
|
|
464
|
-
(
|
|
650
|
+
append(record.raw, clause.tag, clause.value);
|
|
465
651
|
}
|
|
466
652
|
const { tag, scope, qualifiers, value } = this.clauseParts(clause);
|
|
653
|
+
// a control character kept in the value is the shared W_CONTROL_CHARACTER of the text check
|
|
467
654
|
const where = { line: clause.line, element: record.id };
|
|
468
655
|
if (TYPEDEF_TAGS.has(tag) && record.kind !== "Typedef") {
|
|
469
656
|
this.unrecognized(record, clause);
|
|
470
657
|
return;
|
|
471
658
|
}
|
|
472
659
|
if (TEXT_TAGS.has(tag)) {
|
|
473
|
-
this.
|
|
474
|
-
this.extraQualifiers(record, tag, unescapeObo(value).trim(), qualifiers);
|
|
660
|
+
this.text(record, tag, value, qualifiers, clause.line);
|
|
475
661
|
return;
|
|
476
662
|
}
|
|
477
663
|
if (BOOL_TAGS.has(tag)) {
|
|
@@ -553,7 +739,7 @@ class OboReader {
|
|
|
553
739
|
return;
|
|
554
740
|
}
|
|
555
741
|
this.push(record, "xref", xref.id);
|
|
556
|
-
this.describe(record, [xref]);
|
|
742
|
+
this.describe(record, [xref], tag, clause.line);
|
|
557
743
|
this.extraQualifiers(record, tag, xref.id, qualifiers ?? xref.qualifiers);
|
|
558
744
|
return;
|
|
559
745
|
}
|
|
@@ -564,6 +750,23 @@ class OboReader {
|
|
|
564
750
|
this.unrecognized(record, clause);
|
|
565
751
|
}
|
|
566
752
|
}
|
|
753
|
+
/**
|
|
754
|
+
* A single-valued text clause (name, comment, ...), warning about a quote that never closes
|
|
755
|
+
* (stripComment() then keeps a `!` comment after it as text).
|
|
756
|
+
* @param record - the record
|
|
757
|
+
* @param tag - the tag
|
|
758
|
+
* @param value - the raw value
|
|
759
|
+
* @param qualifiers - its qualifier block
|
|
760
|
+
* @param line - its line
|
|
761
|
+
*/
|
|
762
|
+
text(record, tag, value, qualifiers, line) {
|
|
763
|
+
if (tokenize(value).some((t) => t.kind === "quoted" && t.unterminated)) {
|
|
764
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "an unterminated quote; the text after it, a comment included, is kept", tag, line);
|
|
765
|
+
}
|
|
766
|
+
const text = unescapeObo(value).trim();
|
|
767
|
+
this.single(record, tag, text, line);
|
|
768
|
+
this.extraQualifiers(record, tag, text, qualifiers);
|
|
769
|
+
}
|
|
567
770
|
/**
|
|
568
771
|
* Read a value that must be one word.
|
|
569
772
|
* @param tokens - the value's tokens
|
|
@@ -602,8 +805,14 @@ class OboReader {
|
|
|
602
805
|
this.tally("parse-error", OBO_ISSUE.SYNTAX, "the xref list is missing", tag, line);
|
|
603
806
|
return { text: tokens[0].text, xrefs: [] };
|
|
604
807
|
}
|
|
808
|
+
if (list.unterminated) {
|
|
809
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "an xref list without its closing ]; kept as read", tag, line);
|
|
810
|
+
}
|
|
811
|
+
if (tokens.length > 2) {
|
|
812
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "text after the xref list was ignored", tag, line);
|
|
813
|
+
}
|
|
605
814
|
const xrefs = parseXrefList(list.text);
|
|
606
|
-
this.describe(record, xrefs);
|
|
815
|
+
this.describe(record, xrefs, tag, line);
|
|
607
816
|
this.xrefQualifiers(record, tag, xrefs);
|
|
608
817
|
return { text: tokens[0].text, xrefs: xrefs.map((x) => x.id) };
|
|
609
818
|
}
|
|
@@ -668,8 +877,16 @@ class OboReader {
|
|
|
668
877
|
if (words.length > 2 || list === undefined) {
|
|
669
878
|
this.tally("parse-error", OBO_ISSUE.SYNTAX, list === undefined ? "a synonym without its xref list" : "extra words after the synonym type", "synonym", line);
|
|
670
879
|
}
|
|
880
|
+
const listAt = list === undefined ? -1 : tokens.indexOf(list);
|
|
881
|
+
const stray = tokens.some((t, k) => k > 0 && (t.kind === "quoted" || (t.kind === "list" && k !== listAt) || (listAt >= 0 && k > listAt)));
|
|
882
|
+
if (stray) {
|
|
883
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "a second quoted string, a second xref list or text after the list was ignored", "synonym", line);
|
|
884
|
+
}
|
|
885
|
+
if (list?.unterminated === true) {
|
|
886
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "an xref list without its closing ]; kept as read", "synonym", line);
|
|
887
|
+
}
|
|
671
888
|
const xrefs = list === undefined ? [] : parseXrefList(list.text);
|
|
672
|
-
this.describe(record, xrefs);
|
|
889
|
+
this.describe(record, xrefs, "synonym", line);
|
|
673
890
|
this.xrefQualifiers(record, "synonym", xrefs);
|
|
674
891
|
this.push(record, "synonym", withQualifiers({ text: tokens[0].text, scope, type, xrefs: xrefs.map((x) => x.id) }, qualifiers));
|
|
675
892
|
}
|
|
@@ -692,7 +909,14 @@ class OboReader {
|
|
|
692
909
|
this.report.error("validation-error", OBO_ISSUE.BAD_VALUE, "property_value needs a relation and a value; the clause is skipped", where);
|
|
693
910
|
return;
|
|
694
911
|
}
|
|
695
|
-
|
|
912
|
+
if (tokens.some((t) => t.unterminated)) {
|
|
913
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "an unterminated quote; the text runs to the end of the line", "property_value", where.line);
|
|
914
|
+
}
|
|
915
|
+
let datatype = tokens.length === 3 ? tokens[2].text : null;
|
|
916
|
+
if (tokens.length === 3 && tokens[2].kind !== "word") {
|
|
917
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "a datatype that is not a word was ignored", "property_value", where.line);
|
|
918
|
+
datatype = null;
|
|
919
|
+
}
|
|
696
920
|
this.push(record, "property_value", withQualifiers({ relation: tokens[0].text, value: tokens[1].text, datatype }, qualifiers));
|
|
697
921
|
}
|
|
698
922
|
/**
|
|
@@ -729,17 +953,27 @@ class OboReader {
|
|
|
729
953
|
}
|
|
730
954
|
}
|
|
731
955
|
/**
|
|
732
|
-
* Record xref descriptions in `xref.descriptions
|
|
733
|
-
*
|
|
956
|
+
* Record xref descriptions in `xref.descriptions` (the first description of an id is kept),
|
|
957
|
+
* warning about a description whose quote never closes.
|
|
958
|
+
* @param target - the record
|
|
734
959
|
* @param xrefs - the xrefs
|
|
960
|
+
* @param tag - the clause's tag
|
|
961
|
+
* @param line - the clause's line
|
|
735
962
|
*/
|
|
736
|
-
describe(
|
|
737
|
-
var _a;
|
|
963
|
+
describe(target, xrefs, tag, line) {
|
|
738
964
|
for (const xref of xrefs) {
|
|
965
|
+
if (xref.unterminated) {
|
|
966
|
+
this.tally("parse-error", OBO_ISSUE.SYNTAX, "an xref description whose quote never closes runs to the end", tag, line);
|
|
967
|
+
}
|
|
739
968
|
if (xref.description !== null) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
969
|
+
let map = target.values.get("xref.descriptions");
|
|
970
|
+
if (map === undefined) {
|
|
971
|
+
map = ownRecord();
|
|
972
|
+
target.values.set("xref.descriptions", map);
|
|
973
|
+
}
|
|
974
|
+
if (!Object.hasOwn(map, xref.id)) {
|
|
975
|
+
map[xref.id] = xref.description;
|
|
976
|
+
}
|
|
743
977
|
}
|
|
744
978
|
}
|
|
745
979
|
}
|
|
@@ -766,7 +1000,7 @@ class OboReader {
|
|
|
766
1000
|
if (qualifiers === null) {
|
|
767
1001
|
return;
|
|
768
1002
|
}
|
|
769
|
-
const map =
|
|
1003
|
+
const map = record.values.get("obo.qualifiers") ?? {};
|
|
770
1004
|
(map[tag] ?? (map[tag] = [])).push({ value, qualifiers });
|
|
771
1005
|
record.values.set("obo.qualifiers", map);
|
|
772
1006
|
}
|
|
@@ -776,10 +1010,12 @@ class OboReader {
|
|
|
776
1010
|
* @param clause - the clause
|
|
777
1011
|
*/
|
|
778
1012
|
unrecognized(record, clause) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
1013
|
+
let map = record.values.get("obo.unrecognized");
|
|
1014
|
+
if (map === undefined) {
|
|
1015
|
+
map = ownRecord();
|
|
1016
|
+
record.values.set("obo.unrecognized", map);
|
|
1017
|
+
}
|
|
1018
|
+
append(map, clause.tag, unescapeObo(clause.value));
|
|
783
1019
|
this.tally("validation-error", OBO_ISSUE.UNKNOWN_ELEMENT, "an unknown tag was kept in obo.unrecognized", clause.tag, clause.line);
|
|
784
1020
|
}
|
|
785
1021
|
/**
|
|
@@ -800,16 +1036,60 @@ class OboReader {
|
|
|
800
1036
|
found.count++;
|
|
801
1037
|
}
|
|
802
1038
|
}
|
|
803
|
-
/**
|
|
1039
|
+
/**
|
|
1040
|
+
* Record the counted warnings, in the order they were first seen; past MAX_TALLIES_PER_CODE
|
|
1041
|
+
* of one code, the rest are summed up in one warning.
|
|
1042
|
+
*/
|
|
804
1043
|
flushTallies() {
|
|
1044
|
+
const listed = new Map();
|
|
1045
|
+
const over = new Map();
|
|
805
1046
|
for (const t of this.tallies.values()) {
|
|
806
|
-
|
|
1047
|
+
const n = (listed.get(t.code) ?? 0) + 1;
|
|
1048
|
+
listed.set(t.code, n);
|
|
1049
|
+
if (n > MAX_TALLIES_PER_CODE) {
|
|
1050
|
+
const rest = over.get(t.code) ?? [];
|
|
1051
|
+
rest.push(t);
|
|
1052
|
+
over.set(t.code, rest);
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
this.report.warning(t.category, t.code, `${t.element}: ${t.what} (${t.count} time${plural(t.count)}, first at line ${t.line})`, {
|
|
807
1056
|
line: t.line,
|
|
808
1057
|
element: t.element,
|
|
809
1058
|
});
|
|
810
1059
|
}
|
|
1060
|
+
for (const [code, rest] of over) {
|
|
1061
|
+
this.report.warning(rest[0].category, code, `${rest.length} more element${plural(rest.length)} with this warning, not listed (first: ${rest[0].element}: ${rest[0].what}, line ${rest[0].line})`, { line: rest[0].line });
|
|
1062
|
+
}
|
|
811
1063
|
this.tallies.clear();
|
|
812
1064
|
}
|
|
1065
|
+
/**
|
|
1066
|
+
* The first line that makes the input not OBO: null unless no frame header and no plausible
|
|
1067
|
+
* header tag was read while some line was neither (an HTML page, a JSON, GML, DOT or CSV file,
|
|
1068
|
+
* UTF-16 read without its BOM). A file of only comments is OBO, if an empty one.
|
|
1069
|
+
* @returns the line, or null
|
|
1070
|
+
*/
|
|
1071
|
+
notObo() {
|
|
1072
|
+
return this.frameSeen || this.tagClauses > 0 ? null : this.firstBadLine;
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Warn about the header once the file is read: a missing or unknown format-version (the
|
|
1076
|
+
* synonym-scope rule depends on it), a date that is not a real calendar date.
|
|
1077
|
+
*/
|
|
1078
|
+
checkHeader() {
|
|
1079
|
+
if (this.version === null) {
|
|
1080
|
+
const empty = this.frameSeen ? "" : " and the file has no frames: nothing was read";
|
|
1081
|
+
this.tally("validation-error", OBO_ISSUE.FORMAT_VERSION, `the header has no format-version (required by 1.2 and 1.4)${empty}; read as the 1.0 / 1.2 / 1.4 union`, "format-version", 1);
|
|
1082
|
+
}
|
|
1083
|
+
else if (!KNOWN_VERSION.test(this.version)) {
|
|
1084
|
+
this.tally("validation-error", OBO_ISSUE.FORMAT_VERSION, `format-version ${JSON.stringify(this.version)} is not 1.0, 1.2 or 1.4; read as 1.4`, "format-version", 1);
|
|
1085
|
+
}
|
|
1086
|
+
const date = this.header.date?.[0];
|
|
1087
|
+
if (date !== undefined &&
|
|
1088
|
+
/^\d{2}:\d{2}:\d{4}\s+\d{2}:\d{2}$/.test(date.trim()) &&
|
|
1089
|
+
oboDate(date.trim()) === null) {
|
|
1090
|
+
this.tally("validation-error", OBO_ISSUE.SYNTAX, "the header date is not a real calendar date; created is null", "date", 1);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
813
1093
|
/**
|
|
814
1094
|
* The header as GraphMeta fields (design 4.2): name from `ontology`, the version, `created` from
|
|
815
1095
|
* the `dd:MM:yyyy HH:mm` date, `creator` from `saved-by`.
|
|
@@ -863,7 +1143,9 @@ function oboDate(text) {
|
|
|
863
1143
|
return null;
|
|
864
1144
|
}
|
|
865
1145
|
const [, dd, mm, yyyy, hh, min] = m;
|
|
866
|
-
|
|
1146
|
+
// a real calendar date: 31:02 and 31:04 do not survive the round trip through Date
|
|
1147
|
+
const day = new Date(Date.UTC(Number(yyyy), Number(mm) - 1, Number(dd)));
|
|
1148
|
+
if (Number(mm) < 1 || Number(mm) > 12 || day.getUTCDate() !== Number(dd) || Number(hh) > 23 || Number(min) > 59) {
|
|
867
1149
|
return null;
|
|
868
1150
|
}
|
|
869
1151
|
return `${yyyy}-${mm}-${dd}T${hh}:${min}`;
|
|
@@ -946,9 +1228,9 @@ function planGraph(reader, report, addMissingNodes, obo) {
|
|
|
946
1228
|
}
|
|
947
1229
|
}
|
|
948
1230
|
reader.flushTallies();
|
|
949
|
-
reportDangling(records, dangling, addMissingNodes, danglingEdges, report);
|
|
1231
|
+
reportDangling(records, dangling, addMissingNodes, danglingEdges, report, new Set(reader.typedefs.keys()));
|
|
950
1232
|
if (dropped.size > 0) {
|
|
951
|
-
report.warning("merged", OBO_ISSUE.OBSOLETE_DROPPED, `${dropped.size} obsolete term(
|
|
1233
|
+
report.warning("merged", OBO_ISSUE.OBSOLETE_DROPPED, `${dropped.size} obsolete term${plural(dropped.size)} and ${droppedEdges} edge${plural(droppedEdges)} to or from them were left out (obsolete: "drop")`, { element: [...dropped][0] });
|
|
952
1234
|
}
|
|
953
1235
|
return {
|
|
954
1236
|
nodes: records.filter((record) => kept.has(record.id)),
|
|
@@ -964,8 +1246,9 @@ function planGraph(reader, report, addMissingNodes, obo) {
|
|
|
964
1246
|
* @param addMissingNodes - whether they became placeholder nodes
|
|
965
1247
|
* @param droppedEdges - the edges dropped under addMissingNodes false
|
|
966
1248
|
* @param report - the report
|
|
1249
|
+
* @param typedefs - the ids of the Typedef frames (kept as metadata, so not nodes)
|
|
967
1250
|
*/
|
|
968
|
-
function reportDangling(records, dangling, addMissingNodes, droppedEdges, report) {
|
|
1251
|
+
function reportDangling(records, dangling, addMissingNodes, droppedEdges, report, typedefs) {
|
|
969
1252
|
if (dangling.length === 0) {
|
|
970
1253
|
return;
|
|
971
1254
|
}
|
|
@@ -977,13 +1260,16 @@ function reportDangling(records, dangling, addMissingNodes, droppedEdges, report
|
|
|
977
1260
|
}
|
|
978
1261
|
const shown = dangling.slice(0, 5).map((id) => {
|
|
979
1262
|
const primary = altOf.get(id);
|
|
1263
|
+
if (typedefs.has(id)) {
|
|
1264
|
+
return `${id} (a Typedef, kept as metadata, not a node)`;
|
|
1265
|
+
}
|
|
980
1266
|
return primary === undefined ? id : `${id} (an alt_id of ${primary})`;
|
|
981
1267
|
});
|
|
982
1268
|
const more = dangling.length > 5 ? `, ... (${dangling.length - 5} more)` : "";
|
|
983
1269
|
const action = addMissingNodes
|
|
984
1270
|
? "each became a placeholder node (graphty.placeholder)"
|
|
985
|
-
: `${droppedEdges} edge(
|
|
986
|
-
report.warning("validation-error", OBO_ISSUE.DANGLING_REFERENCE, `${dangling.length} target(
|
|
1271
|
+
: `${droppedEdges} edge${plural(droppedEdges)} to them ${agree(droppedEdges, "was", "were")} dropped (addMissingNodes false)`;
|
|
1272
|
+
report.warning("validation-error", OBO_ISSUE.DANGLING_REFERENCE, `${dangling.length} target${plural(dangling.length)} no frame declares: ${shown.join(", ")}${more}; ${action}`, { element: dangling[0] });
|
|
987
1273
|
}
|
|
988
1274
|
/** Pushes ids into a sink: the id coercion rule and the cancellation check. */
|
|
989
1275
|
class Pusher {
|
|
@@ -994,6 +1280,8 @@ class Pusher {
|
|
|
994
1280
|
* @param options - the resolved common options
|
|
995
1281
|
*/
|
|
996
1282
|
constructor(sink, report, options) {
|
|
1283
|
+
/** The original ids restored under restoreMangledIds, by the id the file wrote. */
|
|
1284
|
+
this.restored = new Map();
|
|
997
1285
|
this.since = 0;
|
|
998
1286
|
this.sink = sink;
|
|
999
1287
|
this.report = report;
|
|
@@ -1006,7 +1294,7 @@ class Pusher {
|
|
|
1006
1294
|
* @returns the node id
|
|
1007
1295
|
*/
|
|
1008
1296
|
id(text) {
|
|
1009
|
-
const id = this.coercer.text(text);
|
|
1297
|
+
const id = this.coercer.text(this.restored.get(text) ?? text);
|
|
1010
1298
|
const merge = this.coercer.lastMerge;
|
|
1011
1299
|
if (merge !== null) {
|
|
1012
1300
|
this.report.warning("coercion", OBO_ISSUE.ID_MERGED, `id text ${JSON.stringify(merge.text)} merged with ${JSON.stringify(merge.previousText)} as ${merge.id}`, { element: text });
|
|
@@ -1056,6 +1344,9 @@ class Pusher {
|
|
|
1056
1344
|
function writeGraph(reader, sink, report, options, obo) {
|
|
1057
1345
|
const plan = planGraph(reader, report, options.addMissingNodes, obo);
|
|
1058
1346
|
const push = new Pusher(sink, report, options);
|
|
1347
|
+
if (options.restoreMangledIds) {
|
|
1348
|
+
restoreIds(plan.nodes, push.restored);
|
|
1349
|
+
}
|
|
1059
1350
|
const namespace = reader.namespaceDefault();
|
|
1060
1351
|
// columns, declared only when used, in the vocabulary's order
|
|
1061
1352
|
const used = new Set(["type"]);
|
|
@@ -1101,6 +1392,49 @@ function writeGraph(reader, sink, report, options, obo) {
|
|
|
1101
1392
|
}
|
|
1102
1393
|
writeEdges(plan, push, options);
|
|
1103
1394
|
}
|
|
1395
|
+
/**
|
|
1396
|
+
* Take back the ids the exporter rewrote under `sanitizeIds: "mangle"`: a frame's
|
|
1397
|
+
* `property_value: graphty:originalId "..."` names its original id, which replaces the written one
|
|
1398
|
+
* wherever the file names it (the property value itself is dropped). An original that another
|
|
1399
|
+
* frame already uses as its id is not restored.
|
|
1400
|
+
* @param records - the node records
|
|
1401
|
+
* @param restored - receives written id to original id
|
|
1402
|
+
*/
|
|
1403
|
+
function restoreIds(records, restored) {
|
|
1404
|
+
const taken = new Set(records.map((r) => r.id));
|
|
1405
|
+
for (const record of records) {
|
|
1406
|
+
const values = record.lists.get("property_value");
|
|
1407
|
+
const at = values?.findIndex((v) => v.relation === ORIGINAL_ID) ?? -1;
|
|
1408
|
+
if (values === undefined || at < 0) {
|
|
1409
|
+
continue;
|
|
1410
|
+
}
|
|
1411
|
+
const original = originalText(values[at].value);
|
|
1412
|
+
if (taken.has(original)) {
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
taken.add(original);
|
|
1416
|
+
restored.set(record.id, original);
|
|
1417
|
+
values.splice(at, 1);
|
|
1418
|
+
if (values.length === 0) {
|
|
1419
|
+
record.lists.delete("property_value");
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* The original id of a `graphty:originalId` property value: the exporter writes it as JSON text (so
|
|
1425
|
+
* every character survives); a value that is not a JSON string is the id as it stands.
|
|
1426
|
+
* @param value - the property value
|
|
1427
|
+
* @returns the original id
|
|
1428
|
+
*/
|
|
1429
|
+
function originalText(value) {
|
|
1430
|
+
try {
|
|
1431
|
+
const parsed = JSON.parse(value);
|
|
1432
|
+
return typeof parsed === "string" ? parsed : value;
|
|
1433
|
+
}
|
|
1434
|
+
catch {
|
|
1435
|
+
return value;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1104
1438
|
/**
|
|
1105
1439
|
* Push the planned edges through the direction resolver, with their relation and qualifiers.
|
|
1106
1440
|
* @param plan - the plan
|
|
@@ -1141,6 +1475,54 @@ function writeEdges(plan, push, options) {
|
|
|
1141
1475
|
}
|
|
1142
1476
|
}
|
|
1143
1477
|
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Feed the physical lines to the reader as logical lines: backslash continuations joined (the parts
|
|
1480
|
+
* collected and joined once, so a value continued over many lines costs its length), form feeds
|
|
1481
|
+
* outside quotes split. A backslash inside a `!` comment never continues a line, and a continuation
|
|
1482
|
+
* never swallows a frame header or a blank line.
|
|
1483
|
+
* @param lines - the line reader
|
|
1484
|
+
* @param reader - the OBO reader
|
|
1485
|
+
*/
|
|
1486
|
+
async function readLines(lines, reader) {
|
|
1487
|
+
const parts = [];
|
|
1488
|
+
let partLine = 0;
|
|
1489
|
+
const feed = (text, line) => {
|
|
1490
|
+
for (const piece of splitFormFeeds(text)) {
|
|
1491
|
+
reader.line(piece, line);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
for await (const physical of lines) {
|
|
1495
|
+
const { line } = lines;
|
|
1496
|
+
if (parts.length > 0) {
|
|
1497
|
+
const head = physical.trimStart();
|
|
1498
|
+
if (head.length === 0 || head.startsWith("[")) {
|
|
1499
|
+
reader.tally("parse-error", OBO_ISSUE.SYNTAX, "a line continuation before a frame header or a blank line was ignored", "\\", partLine);
|
|
1500
|
+
feed(parts.join(""), partLine);
|
|
1501
|
+
parts.length = 0;
|
|
1502
|
+
}
|
|
1503
|
+
else {
|
|
1504
|
+
reader.tally("coercion", OBO_ISSUE.DEPRECATED_SYNTAX, "a backslash line continuation was joined (deprecated in 1.4)", "\\", partLine);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
if (endsWithContinuation(physical) && stripComment(physical) === physical) {
|
|
1508
|
+
parts.push(physical.slice(0, -1));
|
|
1509
|
+
partLine = line;
|
|
1510
|
+
continue;
|
|
1511
|
+
}
|
|
1512
|
+
if (parts.length > 0) {
|
|
1513
|
+
parts.push(physical);
|
|
1514
|
+
feed(parts.join(""), line);
|
|
1515
|
+
parts.length = 0;
|
|
1516
|
+
}
|
|
1517
|
+
else {
|
|
1518
|
+
feed(physical, line);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
if (parts.length > 0) {
|
|
1522
|
+
reader.tally("coercion", OBO_ISSUE.DEPRECATED_SYNTAX, "a backslash line continuation was joined (deprecated in 1.4)", "\\", partLine);
|
|
1523
|
+
feed(parts.join(""), partLine);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1144
1526
|
/**
|
|
1145
1527
|
* Confidence that a head is OBO (design 1.5): after a BOM, blank lines and `!` comment lines, 0.9
|
|
1146
1528
|
* when the first significant line is `format-version:` or a `[Term]` / `[Typedef]` / `[Instance]`
|
|
@@ -1179,10 +1561,12 @@ function sniffObo(head) {
|
|
|
1179
1561
|
return tagLines > 0 ? 0.4 : 0;
|
|
1180
1562
|
}
|
|
1181
1563
|
/**
|
|
1182
|
-
* The OBO importer plugin
|
|
1564
|
+
* The OBO importer plugin.
|
|
1565
|
+
* @category Built-in formats
|
|
1183
1566
|
*/
|
|
1184
1567
|
export const oboImporter = Object.freeze({
|
|
1185
1568
|
format: "obo",
|
|
1569
|
+
options: Object.freeze(["obsolete", "typedefs"]),
|
|
1186
1570
|
extensions: Object.freeze([".obo"]),
|
|
1187
1571
|
mimeTypes: Object.freeze(["text/obo", "application/obo"]),
|
|
1188
1572
|
/**
|
|
@@ -1206,33 +1590,20 @@ export const oboImporter = Object.freeze({
|
|
|
1206
1590
|
const report = new ImportReportBuilder("obo", resolved.errorLimit);
|
|
1207
1591
|
reportSinkOptions(sink, options, report, true);
|
|
1208
1592
|
reportUnusedOptions(options, report, USED_OPTIONS);
|
|
1209
|
-
const reader = new OboReader(report, resolved.signal);
|
|
1210
|
-
|
|
1211
|
-
let pending = null;
|
|
1212
|
-
for await (const physical of lines) {
|
|
1213
|
-
const { line } = lines;
|
|
1214
|
-
const text = pending === null ? physical : pending + physical;
|
|
1215
|
-
pending = null;
|
|
1216
|
-
if (endsWithContinuation(text)) {
|
|
1217
|
-
reader.tally("coercion", OBO_ISSUE.DEPRECATED_SYNTAX, "a backslash line continuation was joined (deprecated in 1.4)", "\\", line);
|
|
1218
|
-
pending = text.slice(0, -1);
|
|
1219
|
-
continue;
|
|
1220
|
-
}
|
|
1221
|
-
// the 1.4 grammar counts form feed as a line end; LineReader does not
|
|
1222
|
-
for (const piece of text.includes("\f") ? text.split("\f") : [text]) {
|
|
1223
|
-
reader.line(piece, line);
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
if (pending !== null) {
|
|
1227
|
-
reader.line(pending, lines.line);
|
|
1228
|
-
}
|
|
1593
|
+
const reader = new OboReader(report, resolved.signal, obo.typedefs === "nodes");
|
|
1594
|
+
await readLines(new LineReader(input, report, resolved), reader);
|
|
1229
1595
|
reader.finishFrame();
|
|
1230
1596
|
if (!reader.significant) {
|
|
1231
1597
|
report.fail(OBO_ISSUE.EMPTY_INPUT, "the input is empty");
|
|
1232
1598
|
}
|
|
1599
|
+
const notObo = reader.notObo();
|
|
1600
|
+
if (notObo !== null) {
|
|
1601
|
+
report.fail(OBO_ISSUE.NOT_OBO, `the input is not OBO: it has no frame header and no header tag, and line ${notObo} is not a tag-value line`, { line: notObo });
|
|
1602
|
+
}
|
|
1233
1603
|
throwIfAborted(resolved.signal);
|
|
1604
|
+
reader.checkHeader();
|
|
1234
1605
|
writeGraph(reader, sink, report, resolved, obo);
|
|
1235
|
-
const typedefs =
|
|
1606
|
+
const typedefs = ownRecord();
|
|
1236
1607
|
for (const [id, record] of reader.typedefs) {
|
|
1237
1608
|
typedefs[id] = record.raw;
|
|
1238
1609
|
}
|