@graphty/graph-io 0.3.25 → 0.3.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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-DrXtu_96.js +56 -0
  4. package/dist/chunks/choose-DrXtu_96.js.map +1 -0
  5. package/dist/chunks/constants-ikG85dT8.js +231 -0
  6. package/dist/chunks/constants-ikG85dT8.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D1HPTUrP.js} +390 -99
  8. package/dist/chunks/escape-D1HPTUrP.js.map +1 -0
  9. package/dist/chunks/export-CHd4tQE2.js +4333 -0
  10. package/dist/chunks/export-CHd4tQE2.js.map +1 -0
  11. package/dist/chunks/{importer-eUREhBGj.js → exporter-D23CKNqF.js} +4969 -3201
  12. package/dist/chunks/exporter-D23CKNqF.js.map +1 -0
  13. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-DfWTgrti.js} +23 -21
  14. package/dist/chunks/exporter-DfWTgrti.js.map +1 -0
  15. package/dist/chunks/exporter-DhtW6FxK.js +3465 -0
  16. package/dist/chunks/exporter-DhtW6FxK.js.map +1 -0
  17. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-IHv4nkCm.js} +38 -229
  18. package/dist/chunks/exporter-IHv4nkCm.js.map +1 -0
  19. package/dist/chunks/{importer-BWY2FFc5.js → importer-B1wmPQjr.js} +255 -77
  20. package/dist/chunks/importer-B1wmPQjr.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-B2W_58pz.js} +399 -146
  22. package/dist/chunks/importer-B2W_58pz.js.map +1 -0
  23. package/dist/chunks/importer-BSALvkui.js +2811 -0
  24. package/dist/chunks/importer-BSALvkui.js.map +1 -0
  25. package/dist/chunks/{importer-vi3bSdtw.js → importer-BVRE--Un.js} +510 -77
  26. package/dist/chunks/importer-BVRE--Un.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-CIAzt-wo.js} +1689 -312
  28. package/dist/chunks/importer-CIAzt-wo.js.map +1 -0
  29. package/dist/chunks/{importer-DIrbbnAf.js → importer-DpEW5zeG.js} +585 -226
  30. package/dist/chunks/importer-DpEW5zeG.js.map +1 -0
  31. package/dist/chunks/{importer-zGLo8Dg_.js → importer-z_FL4VMb.js} +488 -161
  32. package/dist/chunks/importer-z_FL4VMb.js.map +1 -0
  33. package/dist/chunks/json-elements-BAmNBZok.js +1225 -0
  34. package/dist/chunks/json-elements-BAmNBZok.js.map +1 -0
  35. package/dist/chunks/ontology-export-Bab4eUA8.js +357 -0
  36. package/dist/chunks/ontology-export-Bab4eUA8.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CdlvL4RO.js} +298 -114
  38. package/dist/chunks/records-CdlvL4RO.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DzXjAiTl.js} +29 -11
  40. package/dist/chunks/text-DzXjAiTl.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 +952 -262
  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 +344 -87
  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 +565 -158
  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 +21 -3
  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 +39 -22
  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 +869 -189
  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 +3 -1
  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 +402 -85
  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 +146 -33
  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 +682 -287
  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 +227 -80
  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 +101 -27
  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 +110 -28
  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 +239 -86
  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 +67 -35
  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 +186 -54
  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 +21 -22
  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 +8 -3
  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 +40 -6
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +39 -22
  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 +1035 -199
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +7 -2
  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 +479 -90
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +202 -47
  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 +890 -302
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +62 -339
  498. package/src/formats/cx2/importer.ts +318 -87
  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 +142 -34
  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 +113 -28
  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 +321 -102
  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 +90 -42
  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 +216 -55
  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 +36 -28
  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 +12 -4
  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
@@ -1,7 +1,10 @@
1
1
  /**
2
- * The OBO subpath entry (`@graphty/graph-io/obo`, design section 1.5): the importer of the OBO
3
- * flat file format (the Gene Ontology and the OBO Foundry ontologies), its options and its issue
4
- * codes. OBO is read-only: there is no exporter.
2
+ * The OBO subpath entry (`@graphty/graph-io/obo`): the importer and exporter of the OBO flat file
3
+ * format (the Gene Ontology and the OBO Foundry ontologies), their options and their issue and
4
+ * loss codes. The JSON form of the same ontologies, OBO Graphs, is the `obographs` dialect of
5
+ * `@graphty/graph-io/json`.
6
+ * @module @graphty/graph-io/obo
5
7
  */
6
8
 
9
+ export { OBO_CAPABILITIES, OBO_LOSS, oboExporter, type OboExportOptions } from "./exporter.js";
7
10
  export { OBO_ISSUE, oboImporter, type OboImportOptions } from "./importer.js";
@@ -21,6 +21,7 @@ const ESCAPES: Readonly<Record<string, string>> = Object.freeze({
21
21
  * backslash at the very end is dropped.
22
22
  * @param text - raw text
23
23
  * @returns the unescaped text
24
+ * @category Plugin helpers
24
25
  */
25
26
  export function unescapeObo(text: string): string {
26
27
  if (!text.includes("\\")) {
@@ -56,10 +57,38 @@ function isEscaped(text: string, index: number): boolean {
56
57
  return run % 2 === 1;
57
58
  }
58
59
 
60
+ /**
61
+ * Split a line at the form feeds outside quotes (the 1.4 grammar counts a form feed as a line end;
62
+ * one inside a quoted value is text).
63
+ * @param line - the raw line
64
+ * @returns the pieces, the line itself when it holds no such form feed
65
+ * @category Plugin helpers
66
+ */
67
+ export function splitFormFeeds(line: string): string[] {
68
+ if (!line.includes("\f")) {
69
+ return [line];
70
+ }
71
+ const pieces: string[] = [];
72
+ let quoted = false;
73
+ let start = 0;
74
+ for (let i = 0; i < line.length; i += line[i] === "\\" ? 2 : 1) {
75
+ const ch = line[i];
76
+ if (ch === '"') {
77
+ quoted = !quoted;
78
+ } else if (ch === "\f" && !quoted) {
79
+ pieces.push(line.slice(start, i));
80
+ start = i + 1;
81
+ }
82
+ }
83
+ pieces.push(line.slice(start));
84
+ return pieces;
85
+ }
86
+
59
87
  /**
60
88
  * Whether a raw line ends with an unescaped backslash (the 1.0 / 1.2 line continuation).
61
89
  * @param line - the raw line, trailing whitespace included
62
90
  * @returns true when the line continues on the next one
91
+ * @category Plugin helpers
63
92
  */
64
93
  export function endsWithContinuation(line: string): boolean {
65
94
  return line.endsWith("\\") && !isEscaped(line, line.length - 1);
@@ -77,6 +106,7 @@ interface TagValue {
77
106
  * Split a line at its first unescaped colon (values contain colons freely: `is_a: GO:0000001`).
78
107
  * @param line - the raw line, trimmed
79
108
  * @returns the tag and the rest, or null when the line has no colon
109
+ * @category Plugin helpers
80
110
  */
81
111
  export function splitTagValue(line: string): TagValue | null {
82
112
  for (let i = 0; i < line.length; i++) {
@@ -99,6 +129,7 @@ export function splitTagValue(line: string): TagValue | null {
99
129
  * hide the comment after it.
100
130
  * @param rest - the raw value
101
131
  * @returns the value before the comment, trailing whitespace removed
132
+ * @category Plugin helpers
102
133
  */
103
134
  export function stripComment(rest: string): string {
104
135
  let quoted = false;
@@ -118,7 +149,10 @@ export function stripComment(rest: string): string {
118
149
  return rest.trimEnd();
119
150
  }
120
151
 
121
- /** The qualifiers of a clause: name to value (a list when a name repeats). */
152
+ /**
153
+ * The qualifiers of a clause: name to value (a list when a name repeats).
154
+ * @category Plugin helpers
155
+ */
122
156
  export type Qualifiers = Record<string, string | string[]>;
123
157
 
124
158
  /** A value with its trailing qualifier blocks split off. */
@@ -134,37 +168,55 @@ interface QualifiedValue {
134
168
  /**
135
169
  * Split the trailing qualifier blocks off a value: a `{...}` is a block only when it closes the
136
170
  * value (after the comment was stripped); several blocks (`{a="1"}{b="2"}`, 1.2 examples) are
137
- * merged. A closing brace whose block does not parse is left in the value and reported.
171
+ * merged. A closing brace whose block does not parse is left in the value and reported. The value
172
+ * is scanned once, so a value of many blocks costs its length, not its length times its blocks.
138
173
  * @param value - the raw value without its comment
139
174
  * @returns the value and its qualifiers
175
+ * @category Plugin helpers
140
176
  */
141
177
  export function splitQualifiers(value: string): QualifiedValue {
142
- let rest = value;
178
+ if (!value.endsWith("}")) {
179
+ return { value, qualifiers: null, badBlock: null };
180
+ }
181
+ const blocks = braceBlocks(value);
182
+ // the blocks read right to left, merged left to right below
183
+ const parsed: Qualifiers[] = [];
184
+ let end = value.length;
185
+ let badBlock: string | null = null;
186
+ while (end > 0 && value[end - 1] === "}" && !isEscaped(value, end - 1)) {
187
+ const open = blocks.get(end - 1) ?? -1;
188
+ const block = open < 0 ? null : parseQualifiers(value.slice(open + 1, end - 1));
189
+ if (block === null) {
190
+ badBlock = value.slice(Math.max(open, 0), end);
191
+ break;
192
+ }
193
+ parsed.push(block);
194
+ end = open;
195
+ while (end > 0 && /\s/.test(value[end - 1])) {
196
+ end--;
197
+ }
198
+ }
143
199
  let qualifiers: Qualifiers | null = null;
144
- for (;;) {
145
- if (!rest.endsWith("}") || isEscaped(rest, rest.length - 1)) {
146
- return { value: rest, qualifiers, badBlock: null };
147
- }
148
- const open = openingBrace(rest);
149
- const parsed = open < 0 ? null : parseQualifiers(rest.slice(open + 1, -1));
150
- if (parsed === null) {
151
- return { value: rest, qualifiers, badBlock: open < 0 ? rest : rest.slice(open) };
152
- }
153
- // a block read right to left: an earlier block's names come first
154
- qualifiers = qualifiers === null ? parsed : mergeQualifiers(parsed, qualifiers);
155
- rest = rest.slice(0, open).trimEnd();
200
+ for (let i = parsed.length - 1; i >= 0; i--) {
201
+ qualifiers ??= Object.create(null) as Qualifiers;
202
+ for (const [name, v] of Object.entries(parsed[i])) {
203
+ addQualifier(qualifiers, name, v);
204
+ }
156
205
  }
206
+ return { value: value.slice(0, end), qualifiers, badBlock };
157
207
  }
158
208
 
159
209
  /**
160
- * The index of the unescaped `{` outside quotes that opens the block closing the value.
161
- * @param value - a raw value ending with `}`
162
- * @returns the index, or -1 when there is none
210
+ * The qualifier blocks of a value in one scan: for every unescaped `}` outside quotes, the index of
211
+ * the unescaped `{` outside quotes that opens it (-1 when a `}` came after that `{`, or none did).
212
+ * @param value - a raw value
213
+ * @returns the opening index by closing index
163
214
  */
164
- function openingBrace(value: string): number {
215
+ function braceBlocks(value: string): Map<number, number> {
216
+ const blocks = new Map<number, number>();
165
217
  let quoted = false;
166
218
  let open = -1;
167
- for (let i = 0; i < value.length - 1; i++) {
219
+ for (let i = 0; i < value.length; i++) {
168
220
  const ch = value[i];
169
221
  if (ch === "\\") {
170
222
  i++;
@@ -175,39 +227,60 @@ function openingBrace(value: string): number {
175
227
  } else if (!quoted && ch === "{") {
176
228
  open = i;
177
229
  } else if (!quoted && ch === "}") {
230
+ blocks.set(i, open);
178
231
  open = -1;
179
232
  }
180
233
  }
181
- return quoted ? -1 : open;
234
+ return blocks;
182
235
  }
183
236
 
184
237
  /**
185
- * Merge two qualifier records, a repeated name becoming a list.
186
- * @param first - the earlier record
187
- * @param second - the later record
188
- * @returns the merged record
238
+ * The index of an unescaped `{` outside quotes that no `}` closes: a qualifier block cut short (a
239
+ * file truncated inside it).
240
+ * @param value - a raw value, closing blocks already split off
241
+ * @returns the index, or -1 when every brace is closed
242
+ * @category Plugin helpers
189
243
  */
190
- function mergeQualifiers(first: Qualifiers, second: Qualifiers): Qualifiers {
191
- const out: Qualifiers = { ...first };
192
- for (const [name, value] of Object.entries(second)) {
193
- addQualifier(out, name, value);
244
+ export function unclosedBlock(value: string): number {
245
+ let quoted = false;
246
+ let open = -1;
247
+ for (let i = 0; i < value.length; i += value[i] === "\\" ? 2 : 1) {
248
+ const ch = value[i];
249
+ if (ch === "\\") {
250
+ continue;
251
+ }
252
+ if (ch === '"' && open < 0) {
253
+ quoted = !quoted;
254
+ } else if (!quoted && ch === "{") {
255
+ open = i;
256
+ } else if (!quoted && ch === "}") {
257
+ open = -1;
258
+ }
194
259
  }
195
- return out;
260
+ return open;
196
261
  }
197
262
 
198
263
  /**
199
- * Add one qualifier, turning a repeated name into a list.
264
+ * Add one qualifier, turning a repeated name into a list (a list the record owns, appended to in
265
+ * place). The record must have a null prototype, so a name such as `__proto__` is an own key.
200
266
  * @param record - the record
201
267
  * @param name - the name
202
268
  * @param value - the value (or values)
203
269
  */
204
270
  function addQualifier(record: Qualifiers, name: string, value: string | string[]): void {
271
+ const values = Array.isArray(value) ? value : [value];
205
272
  if (!Object.prototype.hasOwnProperty.call(record, name)) {
206
- record[name] = value;
273
+ record[name] = Array.isArray(value) ? [...value] : value;
207
274
  return;
208
275
  }
209
276
  const before = record[name];
210
- record[name] = [...(Array.isArray(before) ? before : [before]), ...(Array.isArray(value) ? value : [value])];
277
+ if (Array.isArray(before)) {
278
+ for (const v of values) {
279
+ before.push(v);
280
+ }
281
+ } else {
282
+ record[name] = [before, ...values];
283
+ }
211
284
  }
212
285
 
213
286
  /**
@@ -216,6 +289,7 @@ function addQualifier(record: Qualifiers, name: string, value: string | string[]
216
289
  * (qualifier names may be IRIs with colons).
217
290
  * @param inner - the text between the braces
218
291
  * @returns the qualifiers, or null when the block does not parse (a pair without `=`, an unclosed quote)
292
+ * @category Plugin helpers
219
293
  */
220
294
  export function parseQualifiers(inner: string): Qualifiers | null {
221
295
  const out: Qualifiers = Object.create(null) as Qualifiers;
@@ -260,7 +334,7 @@ export function parseQualifiers(inner: string): Qualifiers | null {
260
334
  addQualifier(out, name, value);
261
335
  any = true;
262
336
  }
263
- return any ? { ...out } : null;
337
+ return any ? out : null;
264
338
  }
265
339
 
266
340
  /**
@@ -280,7 +354,10 @@ function closingQuote(text: string, from: number): number {
280
354
  return -1;
281
355
  }
282
356
 
283
- /** One token of a value. */
357
+ /**
358
+ * One token of a value.
359
+ * @category Plugin helpers
360
+ */
284
361
  export interface Token {
285
362
  /** A bare word, a quoted string or a bracketed list. */
286
363
  readonly kind: "word" | "quoted" | "list";
@@ -295,6 +372,7 @@ export interface Token {
295
372
  * Whitespace separates tokens; an escaped space belongs to its word.
296
373
  * @param value - the raw value
297
374
  * @returns the tokens
375
+ * @category Plugin helpers
298
376
  */
299
377
  export function tokenize(value: string): Token[] {
300
378
  const tokens: Token[] = [];
@@ -364,7 +442,10 @@ function closingBracket(text: string, from: number): number {
364
442
  return -1;
365
443
  }
366
444
 
367
- /** One cross-reference: `ID "description" {qualifiers}`. */
445
+ /**
446
+ * One cross-reference: `ID "description" {qualifiers}`.
447
+ * @category Plugin helpers
448
+ */
368
449
  export interface Xref {
369
450
  /** The id (may hold spaces: `NIST Chemistry WebBook:110-63-4`, which owlapi reads). */
370
451
  readonly id: string;
@@ -372,6 +453,8 @@ export interface Xref {
372
453
  readonly description: string | null;
373
454
  /** Per-xref qualifiers (OBO 1.2 inside a list), or null. */
374
455
  readonly qualifiers: Qualifiers | null;
456
+ /** Whether the description's quote was never closed (it runs to the end). */
457
+ readonly unterminated: boolean;
375
458
  }
376
459
 
377
460
  /**
@@ -379,6 +462,7 @@ export interface Xref {
379
462
  * string its description, a closing block its qualifiers.
380
463
  * @param raw - the raw text of one xref
381
464
  * @returns the xref, or null when it has no id
465
+ * @category Plugin helpers
382
466
  */
383
467
  export function parseXref(raw: string): Xref | null {
384
468
  const { value, qualifiers } = splitQualifiers(raw.trim());
@@ -396,11 +480,13 @@ export function parseXref(raw: string): Xref | null {
396
480
  return null;
397
481
  }
398
482
  let description: string | null = null;
483
+ let unterminated = false;
399
484
  if (quote >= 0) {
400
485
  const end = closingQuote(value, quote + 1);
486
+ unterminated = end < 0;
401
487
  description = unescapeObo(value.slice(quote + 1, end < 0 ? value.length : end));
402
488
  }
403
- return { id, description, qualifiers };
489
+ return { id, description, qualifiers, unterminated };
404
490
  }
405
491
 
406
492
  /**
@@ -408,6 +494,7 @@ export function parseXref(raw: string): Xref | null {
408
494
  * braces (a solitary xref needs no escaping of its commas only outside a list).
409
495
  * @param inner - the raw text between the brackets
410
496
  * @returns the xrefs, in order
497
+ * @category Plugin helpers
411
498
  */
412
499
  export function parseXrefList(inner: string): Xref[] {
413
500
  const out: Xref[] = [];
@@ -445,6 +532,7 @@ export function parseXrefList(inner: string): Xref[] {
445
532
  * have escaped).
446
533
  * @param value - the raw value, qualifiers already split off
447
534
  * @returns true when a stray brace is present
535
+ * @category Plugin helpers
448
536
  */
449
537
  export function hasStrayBrace(value: string): boolean {
450
538
  let quoted = false;
@@ -464,3 +552,110 @@ export function hasStrayBrace(value: string): boolean {
464
552
  }
465
553
  return false;
466
554
  }
555
+
556
+ // ============================================================ the writer side
557
+
558
+ /** A carriage return, a CRLF pair or a form feed: line ends OBO text cannot carry. */
559
+ const LINE_ENDS = /\r\n|\r|\f/g;
560
+
561
+ /**
562
+ * Whether a text holds a carriage return or a form feed, which the OBO line grammar reads as a line
563
+ * end wherever it stands and no escape can spell; the writers turn them into `\n`.
564
+ * @param text - the text
565
+ * @returns true when the text loses a character on the way through an OBO file
566
+ * @category Plugin helpers
567
+ */
568
+ export function hasLineEnd(text: string): boolean {
569
+ return text.includes("\r") || text.includes("\f");
570
+ }
571
+
572
+ /**
573
+ * Escape text for a quoted OBO string (`def: "..."`, a synonym, a qualifier value): backslash,
574
+ * quote, newline and tab. A carriage return or form feed becomes a newline (see hasLineEnd()).
575
+ * `\W` is never written: graph-io reads it as a space, fastobo and the 1.4 BNF as the letter W.
576
+ * @param text - the text
577
+ * @returns the escaped text, without the quotes
578
+ * @category Plugin helpers
579
+ */
580
+ export function escapeOboQuoted(text: string): string {
581
+ return text.replaceAll(LINE_ENDS, "\n").replaceAll(/[\\"\n\t]/g, (ch) => {
582
+ switch (ch) {
583
+ case "\n":
584
+ return String.raw`\n`;
585
+ case "\t":
586
+ return String.raw`\t`;
587
+ default:
588
+ return `\\${ch}`;
589
+ }
590
+ });
591
+ }
592
+
593
+ /**
594
+ * Escape text for an unquoted OBO value (`name:`, `comment:`, an xref id, an unknown tag): what
595
+ * escapeOboQuoted() escapes plus `!` (a comment), `{` and `}` (a qualifier block), `[`, `]` and `,`
596
+ * (an xref list) and `"` (a quoted string). The reader trims an unquoted value, so its leading
597
+ * and trailing spaces cannot be kept.
598
+ * @param text - the text
599
+ * @returns the escaped text
600
+ * @category Plugin helpers
601
+ */
602
+ export function escapeOboValue(text: string): string {
603
+ return escapeOboQuoted(text).replaceAll(/[!{}[\],]/g, (ch) => `\\${ch}`);
604
+ }
605
+
606
+ /**
607
+ * Whether a text can stand as one OBO word (an id, a relation, a subset or synonym type name): not
608
+ * empty, no whitespace, no control character (the importer refuses an id holding one), no `!`, `{`
609
+ * or `}`. escapeOboWord() escapes what else would end it or turn
610
+ * it into another token (a backslash, a quote, a leading `[`).
611
+ * @param text - the text
612
+ * @returns true when the text is a word
613
+ * @category Plugin helpers
614
+ */
615
+ export function isOboWord(text: string): boolean {
616
+ return text.length > 0 && !NOT_IN_WORD.test(text);
617
+ }
618
+
619
+ /**
620
+ * A character an OBO word cannot hold: whitespace, a control character, `!`, `{` or `}`.
621
+ * @category Plugin helpers
622
+ */
623
+ export const NOT_IN_WORD = /[\s!{}\p{Cc}]/u;
624
+
625
+ /**
626
+ * Write a word (see isOboWord()): a backslash and a quote escaped, and a leading `[` (which would
627
+ * open an xref list).
628
+ * @param word - a text isOboWord() accepts
629
+ * @returns the text to write
630
+ * @category Plugin helpers
631
+ */
632
+ export function escapeOboWord(word: string): string {
633
+ const out = word.replaceAll(/[\\"]/g, (ch) => `\\${ch}`);
634
+ return out.startsWith("[") ? `\\${out}` : out;
635
+ }
636
+
637
+ /**
638
+ * Whether a text can be a qualifier name: not empty, no surrounding space, none of `=`, `"`, `,`,
639
+ * `{`, `}`, `[`, `]`, `!`, a backslash or a line end (the reader takes a name as everything up to
640
+ * the first `=`, unescaped only after the split).
641
+ * @param name - the name
642
+ * @returns true when the name is written as it is
643
+ * @category Plugin helpers
644
+ */
645
+ export function isQualifierName(name: string): boolean {
646
+ return name.length > 0 && name === name.trim() && !/[=",{}[\]!\\\n\r\t\f]/.test(name);
647
+ }
648
+
649
+ /**
650
+ * A qualifier block: `{name="value", ...}`, a list value as one pair per item.
651
+ * @param pairs - the name / value pairs, in order (names isQualifierName() accepts)
652
+ * @returns the block with a leading space, or "" when there are no pairs
653
+ * @category Plugin helpers
654
+ */
655
+ export function qualifierBlock(pairs: readonly (readonly [string, string])[]): string {
656
+ if (pairs.length === 0) {
657
+ return "";
658
+ }
659
+ const items = pairs.map(([name, value]) => `${name}="${escapeOboQuoted(value)}"`);
660
+ return ` {${items.join(", ")}}`;
661
+ }