@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.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-BbJI55dx.js +56 -0
  4. package/dist/chunks/choose-BbJI55dx.js.map +1 -0
  5. package/dist/chunks/constants-BCsFsMj4.js +231 -0
  6. package/dist/chunks/constants-BCsFsMj4.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D0g6NNUy.js} +382 -92
  8. package/dist/chunks/escape-D0g6NNUy.js.map +1 -0
  9. package/dist/chunks/export-BTI4yQgy.js +4333 -0
  10. package/dist/chunks/export-BTI4yQgy.js.map +1 -0
  11. package/dist/chunks/exporter-BMqk5oxW.js +3465 -0
  12. package/dist/chunks/exporter-BMqk5oxW.js.map +1 -0
  13. package/dist/chunks/{importer-eUREhBGj.js → exporter-Cra2GYcN.js} +4969 -3201
  14. package/dist/chunks/exporter-Cra2GYcN.js.map +1 -0
  15. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-Dxh231ZF.js} +38 -229
  16. package/dist/chunks/exporter-Dxh231ZF.js.map +1 -0
  17. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-tne475KK.js} +22 -20
  18. package/dist/chunks/exporter-tne475KK.js.map +1 -0
  19. package/dist/chunks/importer-90YWhJoF.js +2811 -0
  20. package/dist/chunks/importer-90YWhJoF.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-Bcl1d4xH.js} +398 -145
  22. package/dist/chunks/importer-Bcl1d4xH.js.map +1 -0
  23. package/dist/chunks/{importer-BWY2FFc5.js → importer-BfIsp1f9.js} +255 -77
  24. package/dist/chunks/importer-BfIsp1f9.js.map +1 -0
  25. package/dist/chunks/{importer-zGLo8Dg_.js → importer-C_TEA1zJ.js} +484 -157
  26. package/dist/chunks/importer-C_TEA1zJ.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-DCjOvO7U.js} +1687 -310
  28. package/dist/chunks/importer-DCjOvO7U.js.map +1 -0
  29. package/dist/chunks/{importer-vi3bSdtw.js → importer-DfVu6j59.js} +509 -76
  30. package/dist/chunks/importer-DfVu6j59.js.map +1 -0
  31. package/dist/chunks/{importer-DIrbbnAf.js → importer-Dku_VAIY.js} +585 -226
  32. package/dist/chunks/importer-Dku_VAIY.js.map +1 -0
  33. package/dist/chunks/json-elements-3tnyt5uZ.js +1225 -0
  34. package/dist/chunks/json-elements-3tnyt5uZ.js.map +1 -0
  35. package/dist/chunks/ontology-export-B9Tcf37D.js +357 -0
  36. package/dist/chunks/ontology-export-B9Tcf37D.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CQXT__mY.js} +298 -114
  38. package/dist/chunks/records-CQXT__mY.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DmcUs5_Q.js} +29 -11
  40. package/dist/chunks/text-DmcUs5_Q.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +951 -261
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +342 -85
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +564 -157
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +19 -1
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +33 -17
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +868 -188
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +2 -0
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +400 -83
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +145 -32
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +680 -285
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +226 -79
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +98 -24
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +108 -26
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +238 -85
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +66 -34
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +183 -51
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +20 -21
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +7 -2
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +38 -4
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +33 -17
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1034 -198
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +6 -1
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +477 -88
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +201 -46
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +888 -300
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +61 -338
  498. package/src/formats/cx2/importer.ts +317 -86
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +139 -31
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +111 -26
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +320 -101
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +89 -41
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +213 -52
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +35 -27
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +11 -3
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -23,14 +23,21 @@ import {
23
23
  PLACEHOLDER_COLUMN,
24
24
  synonymScopeOf,
25
25
  } from "../../common/ontology.js";
26
+ import { agree, plural } from "../../common/plural.js";
26
27
  import { hasKey, isJsonObject } from "./dialect.js";
27
28
  import { chosenGraph, type ImportContext, JSON_ISSUE, type JsonRecord } from "./importer.js";
28
29
 
29
- /** The node keys the schema defines; any other key goes to `obo.unrecognized`. */
30
- const NODE_KEYS: ReadonlySet<string> = new Set(["id", "lbl", "type", "propertyType", "meta"]);
30
+ /**
31
+ * The node keys the schema defines; any other key goes to `obo.unrecognized`.
32
+ * @category Plugin helpers
33
+ */
34
+ export const NODE_KEYS: ReadonlySet<string> = new Set(["id", "lbl", "type", "propertyType", "meta"]);
31
35
 
32
- /** The `meta` keys mapped onto columns; any other key goes to `obo.unrecognized` as `meta.<key>`. */
33
- const META_KEYS: ReadonlySet<string> = new Set([
36
+ /**
37
+ * The `meta` keys mapped onto columns; any other key goes to `obo.unrecognized` as `meta.<key>`.
38
+ * @category Plugin helpers
39
+ */
40
+ export const META_KEYS: ReadonlySet<string> = new Set([
34
41
  "definition",
35
42
  "comments",
36
43
  "subsets",
@@ -40,23 +47,32 @@ const META_KEYS: ReadonlySet<string> = new Set([
40
47
  "deprecated",
41
48
  ]);
42
49
 
43
- /** The OBO frame type of an OBO Graphs node type. */
44
- const FRAME_TYPES: Readonly<Record<string, string>> = Object.freeze({
50
+ /**
51
+ * The OBO frame type of an OBO Graphs node type.
52
+ * @category Plugin helpers
53
+ */
54
+ export const FRAME_TYPES: Readonly<Record<string, string>> = Object.freeze({
45
55
  CLASS: "Term",
46
56
  INDIVIDUAL: "Instance",
47
57
  PROPERTY: "Typedef",
48
58
  });
49
59
 
50
- /** The OBO name of the predicates OBO Graphs writes without an IRI. */
51
- const BUILTIN_PREDICATES: Readonly<Record<string, string>> = Object.freeze({
60
+ /**
61
+ * The OBO name of the predicates OBO Graphs writes without an IRI.
62
+ * @category Plugin helpers
63
+ */
64
+ export const BUILTIN_PREDICATES: Readonly<Record<string, string>> = Object.freeze({
52
65
  is_a: "is_a",
53
66
  subPropertyOf: "is_a",
54
67
  type: "instance_of",
55
68
  inverseOf: "inverse_of",
56
69
  });
57
70
 
58
- /** Predicates that relate two properties (metadata under typedefs "metadata"). */
59
- const PROPERTY_PREDICATES: ReadonlySet<string> = new Set(["subPropertyOf", "inverseOf"]);
71
+ /**
72
+ * Predicates that relate two properties (metadata under typedefs "metadata").
73
+ * @category Plugin helpers
74
+ */
75
+ export const PROPERTY_PREDICATES: ReadonlySet<string> = new Set(["subPropertyOf", "inverseOf"]);
60
76
 
61
77
  /** Writes the OBO vocabulary columns, declaring each on first use. */
62
78
  class ColumnWriter {
@@ -116,12 +132,27 @@ interface Vocabulary {
116
132
  readonly id: (iri: string) => string;
117
133
  /** A predicate as the relation name the edge column holds. */
118
134
  readonly relation: (pred: string) => string;
119
- /** Whether an IRI names a PROPERTY node. */
135
+ /** Whether an IRI names a PROPERTY node and no node of another type. */
120
136
  readonly isProperty: (iri: string) => boolean;
121
- /** The PROPERTY nodes kept as metadata, by IRI. */
137
+ /** Whether an IRI names a node that is not a PROPERTY (a class, an individual). */
138
+ readonly isClass: (iri: string) => boolean;
139
+ /** The PROPERTY nodes kept as metadata, by IRI (a null-prototype record: an IRI may be `__proto__`). */
122
140
  readonly properties: Record<string, unknown>;
141
+ /** The first id as written of each node id as read (two ids may meet only after IRI compaction). */
142
+ readonly written: Map<string, string>;
123
143
  }
124
144
 
145
+ /** The axiom sections of an OBO Graphs graph, each an array (kept verbatim in the metadata). */
146
+ const AXIOM_KEYS: readonly string[] = [
147
+ "logicalDefinitionAxioms",
148
+ "equivalentNodesSets",
149
+ "domainRangeAxioms",
150
+ "propertyChainAxioms",
151
+ ];
152
+
153
+ /** The edge keys the schema defines (`subj` is the README's outdated spelling of `sub`). */
154
+ const EDGE_KEYS: ReadonlySet<string> = new Set(["sub", "subj", "pred", "obj", "meta"]);
155
+
125
156
  /**
126
157
  * The id rule and the property table of one graph: PROPERTY nodes are found first, so an edge's
127
158
  * predicate is named by the shorthand of the property it names wherever that property stands.
@@ -132,8 +163,13 @@ interface Vocabulary {
132
163
  function vocabularyOf(nodes: readonly unknown[], oboIds: "curie" | "iri"): Vocabulary {
133
164
  const shorthands = new Map<string, string>();
134
165
  const propertyIds = new Set<string>();
166
+ const classIds = new Set<string>();
135
167
  for (const node of nodes) {
136
- if (!isJsonObject(node) || typeof node.id !== "string" || node.type !== "PROPERTY") {
168
+ if (!isJsonObject(node) || typeof node.id !== "string") {
169
+ continue;
170
+ }
171
+ if (node.type !== "PROPERTY") {
172
+ classIds.add(node.id);
137
173
  continue;
138
174
  }
139
175
  propertyIds.add(node.id);
@@ -146,8 +182,10 @@ function vocabularyOf(nodes: readonly unknown[], oboIds: "curie" | "iri"): Vocab
146
182
  return {
147
183
  id: (iri) => (oboIds === "curie" ? (shorthands.get(iri) ?? compactOboIri(iri)) : iri),
148
184
  relation: (pred) => BUILTIN_PREDICATES[pred] ?? shorthands.get(pred) ?? compact(pred),
149
- isProperty: (iri) => propertyIds.has(iri),
150
- properties: {},
185
+ isProperty: (iri) => propertyIds.has(iri) && !classIds.has(iri),
186
+ isClass: (iri) => classIds.has(iri),
187
+ properties: Object.create(null) as Record<string, unknown>,
188
+ written: new Map(),
151
189
  };
152
190
  }
153
191
 
@@ -155,43 +193,73 @@ function vocabularyOf(nodes: readonly unknown[], oboIds: "curie" | "iri"): Vocab
155
193
  interface PropertyValue {
156
194
  readonly pred: string;
157
195
  readonly val: string;
196
+ readonly meta?: unknown;
158
197
  }
159
198
 
160
199
  /**
161
- * The well-formed `basicPropertyValues` of a node's meta.
200
+ * The well-formed `basicPropertyValues` of a node's meta, each malformed entry reported when a
201
+ * context is given (the vocabulary pre-pass reads them silently; writeMeta reports them).
162
202
  * @param meta - the node's meta, or anything
203
+ * @param ctx - the context to report through, or null
204
+ * @param element - the node's name in messages
163
205
  * @returns the entries with a string pred and val
164
206
  */
165
- function basicValues(meta: unknown): PropertyValue[] {
166
- if (!isJsonObject(meta) || !Array.isArray(meta.basicPropertyValues)) {
207
+ function basicValues(meta: unknown, ctx: ImportContext | null = null, element = ""): PropertyValue[] {
208
+ if (!isJsonObject(meta) || meta.basicPropertyValues === undefined || meta.basicPropertyValues === null) {
167
209
  return [];
168
210
  }
169
- return meta.basicPropertyValues.filter(
170
- (pv): pv is PropertyValue => isJsonObject(pv) && typeof pv.pred === "string" && typeof pv.val === "string",
171
- );
211
+ const path = `${element}.meta.basicPropertyValues`;
212
+ if (!Array.isArray(meta.basicPropertyValues)) {
213
+ if (ctx !== null) {
214
+ badValue(ctx, `${path} must be an array; it is dropped`, path);
215
+ }
216
+ return [];
217
+ }
218
+ const out: PropertyValue[] = [];
219
+ meta.basicPropertyValues.forEach((pv: unknown, j: number) => {
220
+ if (isJsonObject(pv) && typeof pv.pred === "string" && typeof pv.val === "string") {
221
+ out.push(pv as unknown as PropertyValue);
222
+ } else if (ctx !== null) {
223
+ badValue(ctx, `${path}[${j}] needs a string pred and a string val; it is dropped`, `${path}[${j}]`);
224
+ }
225
+ });
226
+ return out;
172
227
  }
173
228
 
174
229
  /**
175
- * The strings of an array, or of an array of `{ val }` records.
176
- * @param value - the array, or anything
230
+ * The strings of an array, or of an array of `{ val }` records, each item that is neither
231
+ * reported (E_BAD_VALUE) and dropped, and a value that is not an array reported whole.
232
+ * @param ctx - the context
233
+ * @param value - the array, or anything (undefined and null: none)
234
+ * @param path - the field's path in messages
177
235
  * @returns the strings
178
236
  */
179
- function strings(value: unknown): string[] {
237
+ function strings(ctx: ImportContext, value: unknown, path: string): string[] {
238
+ if (value === undefined || value === null) {
239
+ return [];
240
+ }
180
241
  if (!Array.isArray(value)) {
242
+ badValue(ctx, `${path} must be an array; it is dropped`, path);
181
243
  return [];
182
244
  }
183
- return value.flatMap((item: unknown) => {
245
+ const out: string[] = [];
246
+ value.forEach((item: unknown, j: number) => {
184
247
  if (typeof item === "string") {
185
- return [item];
248
+ out.push(item);
249
+ } else if (isJsonObject(item) && typeof item.val === "string") {
250
+ out.push(item.val);
251
+ } else {
252
+ badValue(ctx, `${path}[${j}] is not a string or a { val } record; it is dropped`, `${path}[${j}]`);
186
253
  }
187
- return isJsonObject(item) && typeof item.val === "string" ? [item.val] : [];
188
254
  });
255
+ return out;
189
256
  }
190
257
 
191
258
  /**
192
259
  * Read the chosen graph of an OBO Graphs document into the sink.
193
260
  * @param ctx - the import context
194
261
  * @param root - the document
262
+ * @category Plugin helpers
195
263
  */
196
264
  export function importObographs(ctx: ImportContext, root: JsonRecord): void {
197
265
  const graph = chosenGraph(ctx, root, "OBO Graphs");
@@ -212,6 +280,12 @@ export function importObographs(ctx: ImportContext, root: JsonRecord): void {
212
280
  graphMeta[key] = graph[key];
213
281
  }
214
282
  }
283
+ for (const key of AXIOM_KEYS) {
284
+ const axioms = graph[key];
285
+ if (axioms !== undefined && axioms !== null && !Array.isArray(axioms)) {
286
+ badValue(ctx, `the graph's ${key} must be an array; it is kept as written`, key);
287
+ }
288
+ }
215
289
  const document: JsonRecord = {};
216
290
  for (const key of Object.keys(root)) {
217
291
  if (key !== "graphs") {
@@ -274,33 +348,44 @@ function readNode(
274
348
  ctx.badElement("node", element);
275
349
  return;
276
350
  }
277
- if (typeof record.id !== "string") {
351
+ if (typeof record.id !== "string" || record.id.length === 0) {
278
352
  if (record.id === undefined) {
279
353
  ctx.coerceId(undefined, element);
354
+ } else if (record.id === "") {
355
+ ctx.report.error("missing-value", JSON_ISSUE.MISSING_ID, `${element} has an empty id; it is skipped`, {
356
+ element,
357
+ });
280
358
  } else {
281
359
  badValue(ctx, `${element}.id must be a string; the node is skipped`);
282
360
  }
283
361
  ctx.countSkipped("node");
284
362
  return;
285
363
  }
364
+ if (typeof record.type === "string" && FRAME_TYPES[record.type] === undefined) {
365
+ ctx.report.warnOnce(
366
+ "unsupported",
367
+ JSON_ISSUE.UNKNOWN_ELEMENT,
368
+ `${element}: node type ${JSON.stringify(record.type)} is not CLASS, INDIVIDUAL or PROPERTY; kept as written`,
369
+ { element: record.type },
370
+ `${JSON_ISSUE.UNKNOWN_ELEMENT}:type:${record.type}`,
371
+ );
372
+ }
286
373
  if (record.type === "PROPERTY" && ctx.json.typedefs === "metadata") {
287
- const shorthand = vocabulary.id(record.id) === record.id ? undefined : vocabulary.id(record.id);
288
- const entry: JsonRecord = {};
289
- for (const [key, value] of Object.entries({
290
- lbl: record.lbl,
291
- propertyType: record.propertyType,
292
- shorthand,
293
- meta: record.meta,
294
- })) {
295
- if (value !== undefined) {
296
- entry[key] = value;
297
- }
298
- }
299
- vocabulary.properties[record.id] = entry;
374
+ readProperty(ctx, vocabulary, record, record.id, element);
300
375
  return;
301
376
  }
302
- const id = ctx.coerceId(vocabulary.id(record.id), element);
303
- const row = id === null ? -1 : ctx.pushNode(id, element);
377
+ const compacted = vocabulary.id(record.id);
378
+ const id = ctx.coerceId(compacted, element);
379
+ // two ids that differ only by IRI compaction (the PURL and its CURIE) meet here
380
+ const earlier = vocabulary.written.get(compacted);
381
+ if (earlier === undefined) {
382
+ vocabulary.written.set(compacted, record.id);
383
+ }
384
+ const why =
385
+ earlier === undefined || earlier === record.id
386
+ ? ""
387
+ : ` (${earlier} and ${record.id} meet only after IRI compaction; oboIds "iri" keeps them apart)`;
388
+ const row = id === null ? -1 : ctx.pushNode(id, element, why);
304
389
  if (row < 0) {
305
390
  return;
306
391
  }
@@ -311,6 +396,45 @@ function readNode(
311
396
  }
312
397
  }
313
398
 
399
+ /**
400
+ * Keep a PROPERTY node in the metadata (typedefs "metadata"), the first of a repeated id.
401
+ * @param ctx - the context
402
+ * @param vocabulary - the graph's vocabulary
403
+ * @param record - the node record
404
+ * @param iri - its id
405
+ * @param element - its name in messages
406
+ */
407
+ function readProperty(
408
+ ctx: ImportContext,
409
+ vocabulary: Vocabulary,
410
+ record: JsonRecord,
411
+ iri: string,
412
+ element: string,
413
+ ): void {
414
+ if (Object.hasOwn(vocabulary.properties, iri)) {
415
+ ctx.report.warning(
416
+ "merged",
417
+ JSON_ISSUE.DUPLICATE_NODE,
418
+ `${element}: property ${JSON.stringify(iri)} is declared again; the first declaration is kept`,
419
+ { element },
420
+ );
421
+ return;
422
+ }
423
+ const shorthand = vocabulary.id(iri) === iri ? undefined : vocabulary.id(iri);
424
+ const entry: JsonRecord = {};
425
+ for (const [key, value] of Object.entries({
426
+ lbl: record.lbl,
427
+ propertyType: record.propertyType,
428
+ shorthand,
429
+ meta: record.meta,
430
+ })) {
431
+ if (value !== undefined) {
432
+ entry[key] = value;
433
+ }
434
+ }
435
+ vocabulary.properties[iri] = entry;
436
+ }
437
+
314
438
  /**
315
439
  * Write a node's fields and meta onto the OBO columns.
316
440
  * @param ctx - the context
@@ -347,7 +471,7 @@ function writeNode(
347
471
  }
348
472
  const { meta } = record;
349
473
  if (isJsonObject(meta)) {
350
- writeMeta(columns, vocabulary, meta, row, unrecognized);
474
+ writeMeta(ctx, columns, vocabulary, meta, row, unrecognized, element);
351
475
  } else if (meta !== undefined && meta !== null) {
352
476
  badValue(ctx, `${element}.meta must be an object`);
353
477
  }
@@ -358,53 +482,64 @@ function writeNode(
358
482
 
359
483
  /**
360
484
  * Write a node's `meta` onto the OBO columns (design 4.6): definition, comments, subsets, xrefs,
361
- * synonyms, deprecated, and the basicPropertyValues mapped back to the OBO tag they came from.
485
+ * synonyms, deprecated, and the basicPropertyValues mapped back to the OBO tag they came from. A
486
+ * field of the wrong JSON type is reported and dropped; a nested `meta` (axiom annotations) of
487
+ * a definition or a property value is kept in `obo.unrecognized`.
488
+ * @param ctx - the context
362
489
  * @param columns - the column writer
363
490
  * @param vocabulary - the graph's vocabulary
364
491
  * @param meta - the meta record
365
492
  * @param row - the node index
366
493
  * @param unrecognized - where keys without a column go
494
+ * @param element - the node's name in messages
367
495
  */
368
496
  function writeMeta(
497
+ ctx: ImportContext,
369
498
  columns: ColumnWriter,
370
499
  vocabulary: Vocabulary,
371
500
  meta: JsonRecord,
372
501
  row: number,
373
502
  unrecognized: JsonRecord,
503
+ element: string,
374
504
  ): void {
505
+ const path = `${element}.meta`;
375
506
  const { definition } = meta;
376
- if (isJsonObject(definition) && typeof definition.val === "string") {
377
- columns.node("def", row, definition.val);
378
- columns.node("def.xrefs", row, strings(definition.xrefs));
507
+ if (isJsonObject(definition)) {
508
+ const xrefs = strings(ctx, definition.xrefs, `${path}.definition.xrefs`);
509
+ if (typeof definition.val === "string") {
510
+ columns.node("def", row, definition.val);
511
+ columns.node("def.xrefs", row, xrefs);
512
+ } else {
513
+ badValue(ctx, `${path}.definition has no string val; it is dropped`, `${path}.definition.val`);
514
+ }
515
+ if (definition.meta !== undefined) {
516
+ unrecognized["meta.definition.meta"] = definition.meta;
517
+ }
518
+ } else if (definition !== undefined && definition !== null) {
519
+ badValue(ctx, `${path}.definition must be an object with a val; it is dropped`, `${path}.definition`);
379
520
  }
380
- const comments = strings(meta.comments);
521
+ const comments = strings(ctx, meta.comments, `${path}.comments`);
381
522
  if (comments.length > 0) {
382
523
  columns.node("comment", row, comments.join("\n"));
383
524
  }
384
- const subsets = strings(meta.subsets).map((s) => vocabulary.id(s));
525
+ const subsets = strings(ctx, meta.subsets, `${path}.subsets`).map((s) => vocabulary.id(s));
385
526
  if (subsets.length > 0) {
386
527
  columns.node("subset", row, subsets);
387
528
  }
388
- const xrefs = strings(meta.xrefs);
529
+ const xrefs = strings(ctx, meta.xrefs, `${path}.xrefs`);
389
530
  if (xrefs.length > 0) {
390
531
  columns.node("xref", row, xrefs);
391
532
  }
392
- if (Array.isArray(meta.synonyms) && meta.synonyms.length > 0) {
393
- columns.node(
394
- "synonym",
395
- row,
396
- meta.synonyms.filter(isJsonObject).map((s) => ({
397
- text: typeof s.val === "string" ? s.val : null,
398
- scope: typeof s.pred === "string" ? synonymScopeOf(s.pred) : null,
399
- type: typeof s.synonymType === "string" ? vocabulary.id(s.synonymType) : null,
400
- xrefs: strings(s.xrefs),
401
- })),
402
- );
533
+ const synonyms = synonymsOf(ctx, vocabulary, meta.synonyms, `${path}.synonyms`);
534
+ if (synonyms.length > 0) {
535
+ columns.node("synonym", row, synonyms);
403
536
  }
404
537
  if (typeof meta.deprecated === "boolean") {
405
538
  columns.node("is_obsolete", row, meta.deprecated);
539
+ } else if (meta.deprecated !== undefined && meta.deprecated !== null) {
540
+ badValue(ctx, `${path}.deprecated must be a boolean; it is dropped`, `${path}.deprecated`);
406
541
  }
407
- writePropertyValues(columns, vocabulary, basicValues(meta), row);
542
+ writePropertyValues(ctx, columns, vocabulary, meta, row, unrecognized, element);
408
543
  for (const key of Object.keys(meta)) {
409
544
  if (!META_KEYS.has(key)) {
410
545
  unrecognized[`meta.${key}`] = meta[key];
@@ -412,37 +547,118 @@ function writeMeta(
412
547
  }
413
548
  }
414
549
 
550
+ /**
551
+ * The synonyms of a node's meta as the OBO `synonym` items: each entry that is not an object or
552
+ * has no string val reported and dropped, a predicate that is not one of the four scopes kept with
553
+ * scope null (W_UNKNOWN_ELEMENT once per predicate), a nested `meta` kept on the item.
554
+ * @param ctx - the context
555
+ * @param vocabulary - the graph's vocabulary
556
+ * @param value - the `synonyms` field
557
+ * @param path - its path in messages
558
+ * @returns the items
559
+ */
560
+ function synonymsOf(ctx: ImportContext, vocabulary: Vocabulary, value: unknown, path: string): JsonRecord[] {
561
+ if (value === undefined || value === null) {
562
+ return [];
563
+ }
564
+ if (!Array.isArray(value)) {
565
+ badValue(ctx, `${path} must be an array; it is dropped`, path);
566
+ return [];
567
+ }
568
+ const out: JsonRecord[] = [];
569
+ value.forEach((s: unknown, j: number) => {
570
+ const at = `${path}[${j}]`;
571
+ if (!isJsonObject(s)) {
572
+ badValue(ctx, `${at} is not an object; it is dropped`, at);
573
+ return;
574
+ }
575
+ if (typeof s.val !== "string") {
576
+ badValue(ctx, `${at} has no string val; it is dropped`, `${at}.val`);
577
+ return;
578
+ }
579
+ const scope = typeof s.pred === "string" ? synonymScopeOf(s.pred) : null;
580
+ if (scope === null && typeof s.pred === "string") {
581
+ ctx.report.warnOnce(
582
+ "unsupported",
583
+ JSON_ISSUE.UNKNOWN_ELEMENT,
584
+ `${at}: synonym predicate ${JSON.stringify(s.pred)} is not one of the four scopes; kept with scope null`,
585
+ { element: s.pred },
586
+ `${JSON_ISSUE.UNKNOWN_ELEMENT}:pred:${s.pred}`,
587
+ );
588
+ }
589
+ const item: JsonRecord = { text: s.val, scope, type: null, xrefs: strings(ctx, s.xrefs, `${at}.xrefs`) };
590
+ if (typeof s.synonymType === "string") {
591
+ item.type = vocabulary.id(s.synonymType);
592
+ } else if (s.synonymType !== undefined && s.synonymType !== null) {
593
+ badValue(ctx, `${at}.synonymType must be a string; it is dropped`, `${at}.synonymType`);
594
+ }
595
+ if (s.meta !== undefined) {
596
+ item.meta = s.meta;
597
+ }
598
+ out.push(item);
599
+ });
600
+ return out;
601
+ }
602
+
415
603
  /**
416
604
  * Write the basicPropertyValues: the ones an OBO tag maps to onto that tag's column (lists for
417
- * alt_id, replaced_by, consider), the rest into `property_value`.
605
+ * alt_id, replaced_by, consider; the first value of a single-valued tag, a repeat warned as the
606
+ * .obo importer warns it), the rest into `property_value`.
607
+ * @param ctx - the context
418
608
  * @param columns - the column writer
419
609
  * @param vocabulary - the graph's vocabulary
420
- * @param values - the entries
610
+ * @param meta - the node's meta
421
611
  * @param row - the node index
612
+ * @param unrecognized - where the nested meta of a mapped value goes
613
+ * @param element - the node's name in messages
422
614
  */
423
615
  function writePropertyValues(
616
+ ctx: ImportContext,
424
617
  columns: ColumnWriter,
425
618
  vocabulary: Vocabulary,
426
- values: readonly PropertyValue[],
619
+ meta: JsonRecord,
427
620
  row: number,
621
+ unrecognized: JsonRecord,
622
+ element: string,
428
623
  ): void {
429
624
  const lists = new Map<string, string[]>();
625
+ const singles = new Map<string, string>();
430
626
  const others: JsonRecord[] = [];
431
- for (const { pred, val } of values) {
627
+ const values = basicValues(meta, ctx, element);
628
+ values.forEach(({ pred, val, meta: nested }, j) => {
432
629
  const tag = OBOGRAPHS_PREDICATE_TAGS.get(pred);
433
630
  if (tag === "shorthand") {
434
- continue;
631
+ return;
435
632
  }
436
633
  if (tag === undefined) {
437
- others.push({ relation: vocabulary.id(pred), value: val, datatype: null });
438
- } else if (OBO_NODE_COLUMNS[tag].dtype === "list") {
634
+ const item: JsonRecord = { relation: vocabulary.id(pred), value: val, datatype: null };
635
+ if (nested !== undefined) {
636
+ item.meta = nested;
637
+ }
638
+ others.push(item);
639
+ return;
640
+ }
641
+ if (nested !== undefined) {
642
+ unrecognized[`meta.basicPropertyValues[${j}].meta`] = nested;
643
+ }
644
+ if (OBO_NODE_COLUMNS[tag].dtype === "list") {
439
645
  const list = lists.get(tag) ?? [];
440
646
  list.push(tag === "alt_id" ? val : vocabulary.id(val));
441
647
  lists.set(tag, list);
648
+ } else if (singles.get(tag) === val) {
649
+ // an identical value counts once, as an identical .obo clause does
650
+ } else if (singles.has(tag)) {
651
+ ctx.report.warning(
652
+ "validation-error",
653
+ JSON_ISSUE.DUPLICATE_ATTRIBUTE,
654
+ `${element}: a second ${tag} (${JSON.stringify(val)}); the first is kept`,
655
+ { element: tag },
656
+ );
442
657
  } else {
658
+ singles.set(tag, val);
443
659
  columns.node(tag, row, val);
444
660
  }
445
- }
661
+ });
446
662
  for (const [tag, list] of lists) {
447
663
  columns.node(tag, row, list);
448
664
  }
@@ -455,9 +671,60 @@ function writePropertyValues(
455
671
  * Report a field of the wrong JSON type (the field is left unset, the element kept).
456
672
  * @param ctx - the context
457
673
  * @param message - what is wrong
674
+ * @param element - the field's path, when known
675
+ */
676
+ function badValue(ctx: ImportContext, message: string, element?: string): void {
677
+ ctx.report.error(
678
+ "validation-error",
679
+ JSON_ISSUE.BAD_VALUE,
680
+ message,
681
+ element === undefined ? undefined : { element },
682
+ );
683
+ }
684
+
685
+ /**
686
+ * An edge's subject: `sub`, else the README's outdated `subj` (warned once), and a warning when
687
+ * both are present and differ; every key outside the schema warned once per key name.
688
+ * @param ctx - the context
689
+ * @param record - the edge record
690
+ * @param element - its name in messages
691
+ * @returns the subject value, unchecked
458
692
  */
459
- function badValue(ctx: ImportContext, message: string): void {
460
- ctx.report.error("validation-error", JSON_ISSUE.BAD_VALUE, message);
693
+ function subjectOf(ctx: ImportContext, record: JsonRecord, element: string): unknown {
694
+ const { report } = ctx;
695
+ for (const key of Object.keys(record)) {
696
+ if (!EDGE_KEYS.has(key)) {
697
+ report.warnOnce(
698
+ "unsupported",
699
+ JSON_ISSUE.UNREAD_KEY,
700
+ `${element}: the key ${JSON.stringify(key)} is not part of an OBO Graphs edge; it is not read`,
701
+ { element: `${element}.${key}` },
702
+ `${JSON_ISSUE.UNREAD_KEY}:edge:${key}`,
703
+ );
704
+ }
705
+ }
706
+ if (!hasKey(record, "sub")) {
707
+ if (hasKey(record, "subj")) {
708
+ report.warnOnce(
709
+ "coercion",
710
+ JSON_ISSUE.OBOGRAPHS_SUBJ,
711
+ `${element} uses the outdated key subj; read as sub`,
712
+ {
713
+ element,
714
+ },
715
+ );
716
+ }
717
+ return record.subj;
718
+ }
719
+ if (hasKey(record, "subj") && record.subj !== record.sub) {
720
+ report.warning(
721
+ "coercion",
722
+ JSON_ISSUE.OBOGRAPHS_SUBJ,
723
+ `${element} has both sub and the outdated subj, which differ; sub is read and subj ignored`,
724
+ { element },
725
+ );
726
+ }
727
+ return record.sub;
461
728
  }
462
729
 
463
730
  /**
@@ -501,27 +768,19 @@ function readEdges(
501
768
  ctx.badElement("edge", element);
502
769
  continue;
503
770
  }
504
- const subKey = hasKey(record, "sub") ? "sub" : "subj";
505
- if (subKey === "subj" && hasKey(record, "subj")) {
506
- report.warnOnce(
507
- "coercion",
508
- JSON_ISSUE.OBOGRAPHS_SUBJ,
509
- `${element} uses the outdated key subj; read as sub`,
510
- {
511
- element,
512
- },
513
- );
514
- }
515
- const sub = record[subKey];
771
+ const sub = subjectOf(ctx, record, element);
516
772
  const { obj, pred } = record;
517
- if (typeof sub !== "string" || typeof obj !== "string") {
518
- ctx.missingEndpoint(element, typeof sub === "string" ? "obj" : "sub");
773
+ if (typeof sub !== "string" || typeof obj !== "string" || sub.length === 0 || obj.length === 0) {
774
+ ctx.missingEndpoint(element, typeof sub === "string" && sub.length > 0 ? "obj" : "sub");
519
775
  continue;
520
776
  }
777
+ // only an edge between two properties is property metadata; one that touches a class stays
521
778
  const between =
522
- (typeof pred === "string" && PROPERTY_PREDICATES.has(pred)) ||
523
- vocabulary.isProperty(sub) ||
524
- vocabulary.isProperty(obj);
779
+ (vocabulary.isProperty(sub) && vocabulary.isProperty(obj)) ||
780
+ (typeof pred === "string" &&
781
+ PROPERTY_PREDICATES.has(pred) &&
782
+ !vocabulary.isClass(sub) &&
783
+ !vocabulary.isClass(obj));
525
784
  if (between && ctx.json.typedefs === "metadata") {
526
785
  propertyEdges.push(record);
527
786
  continue;
@@ -542,6 +801,8 @@ function readEdges(
542
801
  }
543
802
  if (isJsonObject(record.meta)) {
544
803
  columns.edge("meta", edge, record.meta);
804
+ } else if (record.meta !== undefined && record.meta !== null) {
805
+ badValue(ctx, `${element}.meta must be an object; it is dropped`, `${element}.meta`);
545
806
  }
546
807
  } catch (err) {
547
808
  ctx.skip(err, "edge", element);
@@ -551,11 +812,11 @@ function readEdges(
551
812
  const shown = [...new Set(dangling)].slice(0, 5).join(", ");
552
813
  const action = ctx.options.addMissingNodes
553
814
  ? "each became a placeholder node (graphty.placeholder)"
554
- : `${dropped} edge(s) to them were dropped (addMissingNodes false)`;
815
+ : `${dropped} edge${plural(dropped)} to them ${agree(dropped, "was", "were")} dropped (addMissingNodes false)`;
555
816
  report.warning(
556
817
  "validation-error",
557
818
  JSON_ISSUE.DANGLING_REFERENCE,
558
- `${new Set(dangling).size} edge endpoint(s) missing from nodes: ${shown}; ${action}`,
819
+ `${new Set(dangling).size} edge endpoint${plural(new Set(dangling).size)} missing from nodes: ${shown}; ${action}`,
559
820
  { element: dangling[0] },
560
821
  );
561
822
  }