@graphty/graph-io 0.3.24 → 0.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -12,6 +12,7 @@ import { DirectionResolver, type EdgeKind } from "../../common/direction.js";
12
12
  import { IdCoercer } from "../../common/ids.js";
13
13
  import { throwIfAborted } from "../../common/input.js";
14
14
  import { type ResolvedImportOptions } from "../../common/options.js";
15
+ import { agree, plural } from "../../common/plural.js";
15
16
  import { type ImportReportBuilder, type IssueLocation } from "../../common/report.js";
16
17
  import { parseWeightText } from "../../common/weights.js";
17
18
  import { ColumnSet } from "./columns.js";
@@ -43,8 +44,12 @@ import {
43
44
  type NodeRec,
44
45
  type XgmmlDocument,
45
46
  } from "./document.js";
47
+ import { parseScalar } from "./values.js";
46
48
 
47
- /** The XGMML-specific options, resolved. */
49
+ /**
50
+ * The XGMML-specific options, resolved.
51
+ * @category Plugin helpers
52
+ */
48
53
  export interface XgmmlSettings {
49
54
  /** Resolve missing or unknown endpoints through `"a (pp) b"` edge labels. */
50
55
  readonly labelAliases: boolean;
@@ -54,7 +59,10 @@ export interface XgmmlSettings {
54
59
  readonly zAs: "column" | "position";
55
60
  }
56
61
 
57
- /** What a session adds to the document's own rules. */
62
+ /**
63
+ * What a session adds to the document's own rules.
64
+ * @category Plugin helpers
65
+ */
58
66
  export interface EmitExtras {
59
67
  /** Ids of nodes the session's group bookkeeping lists as groups. */
60
68
  readonly groupNodes?: ReadonlySet<string> | undefined;
@@ -75,9 +83,20 @@ export interface EmitExtras {
75
83
  * session): the session records it instead of E_UNKNOWN_PARENT.
76
84
  */
77
85
  readonly onMissingMember?: ((group: string, member: string) => void) | undefined;
86
+ /**
87
+ * A 3.x session: the label of a node or edge is its table's `name` (what Cytoscape shows), in
88
+ * a label column named `name`; the XGMML `label` attribute is read only when no element of
89
+ * the table has a `name`.
90
+ */
91
+ readonly labelFromName?: boolean | undefined;
92
+ /** Node ids to read in place of the written ones (ids an exporter mangled, by written id). */
93
+ readonly restoredIds?: ReadonlyMap<string, string> | undefined;
78
94
  }
79
95
 
80
- /** The dialect facts the rules depend on. */
96
+ /**
97
+ * The dialect facts the rules depend on.
98
+ * @category Plugin helpers
99
+ */
81
100
  export interface Dialect {
82
101
  /** The documentVersion as written, or null. */
83
102
  readonly versionText: string | null;
@@ -121,6 +140,7 @@ const ALIAS_SPLIT = /[()]/;
121
140
  * @param doc - the document
122
141
  * @param report - the report the unparseable-version warning goes to
123
142
  * @returns the dialect
143
+ * @category Plugin helpers
124
144
  */
125
145
  export function dialectOf(doc: XgmmlDocument, report: ImportReportBuilder): Dialect {
126
146
  const { root } = doc;
@@ -133,7 +153,7 @@ export function dialectOf(doc: XgmmlDocument, report: ImportReportBuilder): Dial
133
153
  let version = 0;
134
154
  if (versionText !== null) {
135
155
  version = Number(versionText.trim());
136
- if (!Number.isFinite(version) || versionText.trim().length === 0) {
156
+ if (!Number.isFinite(version) || version < 0 || versionText.trim().length === 0) {
137
157
  report.warning(
138
158
  "validation-error",
139
159
  XGMML_ISSUE.DOCUMENT_VERSION,
@@ -160,11 +180,24 @@ export function dialectOf(doc: XgmmlDocument, report: ImportReportBuilder): Dial
160
180
  * @param doc - the document
161
181
  * @param dialect - its dialect
162
182
  * @returns the graphs, in document order
183
+ * @category Plugin helpers
163
184
  */
164
185
  export function graphsOf(doc: XgmmlDocument, dialect: Dialect): GraphRec[] {
165
186
  return dialect.session ? doc.root.subgraphs.filter((g) => isCyTrue(g.registered)) : [doc.root];
166
187
  }
167
188
 
189
+ /**
190
+ * A graphics coordinate as Java's `Double.parseDouble` reads Cytoscape's (no hex, no `_`), and
191
+ * finite.
192
+ * @param text - the text
193
+ * @returns the number, or null when it does not parse or is not finite
194
+ * @category Plugin helpers
195
+ */
196
+ export function parseCoordinate(text: string): number | null {
197
+ const parsed = parseScalar(text, "real", false);
198
+ return parsed === null || !Number.isFinite(parsed.value) ? null : (parsed.value as number);
199
+ }
200
+
168
201
  /**
169
202
  * The id a `#id` reference names, or null for a cross-file or malformed reference.
170
203
  * @param href - the xlink:href text
@@ -179,6 +212,7 @@ function localRef(href: string): string | null {
179
212
  * @param doc - the document
180
213
  * @param graph - the graph (a registered subnetwork), or null for the whole document
181
214
  * @returns the declared node and edge records it holds, references resolved, in order
215
+ * @category Plugin helpers
182
216
  */
183
217
  export function membersOf(
184
218
  doc: XgmmlDocument,
@@ -242,6 +276,7 @@ interface NodeRow {
242
276
 
243
277
  /**
244
278
  * Pushes one graph of a document into a sink.
279
+ * @category Plugin helpers
245
280
  */
246
281
  export class XgmmlEmitter {
247
282
  private readonly doc: XgmmlDocument;
@@ -311,10 +346,11 @@ export class XgmmlEmitter {
311
346
  this.coercer = new IdCoercer(options.ids);
312
347
  this.direction = new DirectionResolver(sink, report, options.onMixedDirection);
313
348
  const base = { unescape: settings.cytoscapeEscapes, long: options.long };
349
+ const label = extras.labelFromName === true ? [] : [LABEL_COLUMN];
314
350
  this.nodeColumns = new ColumnSet("node", report, {
315
351
  ...base,
316
352
  reserved: new Set([
317
- LABEL_COLUMN,
353
+ ...label,
318
354
  POSITION_COLUMN,
319
355
  Z_COLUMN,
320
356
  GRAPHICS_COLUMN,
@@ -328,7 +364,7 @@ export class XgmmlEmitter {
328
364
  });
329
365
  this.edgeColumns = new ColumnSet("edge", report, {
330
366
  ...base,
331
- reserved: new Set([EDGE_ID_COLUMN, LABEL_COLUMN, GRAPHICS_COLUMN]),
367
+ reserved: new Set([EDGE_ID_COLUMN, ...label, GRAPHICS_COLUMN]),
332
368
  });
333
369
  this.graphColumns = new ColumnSet("graph", report, { ...base, reserved: new Set([GRAPHICS_COLUMN]) });
334
370
  }
@@ -343,7 +379,7 @@ export class XgmmlEmitter {
343
379
  this.report.warning(
344
380
  "validation-error",
345
381
  XGMML_ISSUE.DANGLING_REFERENCE,
346
- `${this.prefix()}${members.dangling} xlink:href member reference(s) name no node or edge of the document`,
382
+ `${this.prefix()}${members.dangling} xlink:href member reference${plural(members.dangling)} ${agree(members.dangling, "names", "name")} no node or edge of the document`,
347
383
  { line: graph?.line ?? null },
348
384
  );
349
385
  }
@@ -485,15 +521,33 @@ export class XgmmlEmitter {
485
521
  private edgeDirection(record: EdgeRec, header: boolean): boolean {
486
522
  let directed = this.directions.get(record);
487
523
  if (directed === undefined) {
524
+ const fallback = this.graphDirected(record.graph, header);
488
525
  directed =
489
526
  record.directed === null
490
- ? header
491
- : this.flag(record.directed, header, { line: record.line, element: record.id ?? record.label });
527
+ ? fallback
528
+ : this.flag(record.directed, fallback, { line: record.line, element: record.id ?? record.label });
492
529
  this.directions.set(record, directed);
493
530
  }
494
531
  return directed;
495
532
  }
496
533
 
534
+ /**
535
+ * The default direction of the edges of a graph: the `directed` attribute of the graph or of
536
+ * the nearest graph it is nested in that has one, else the header.
537
+ * @param graph - the graph that holds the edge
538
+ * @param header - the header direction
539
+ * @returns whether the graph's edges are directed by default
540
+ */
541
+ private graphDirected(graph: GraphRec, header: boolean): boolean {
542
+ for (let g: GraphRec | null = graph; g !== null && g !== this.doc.root; g = g.parent) {
543
+ const text = g.attrs.get("directed");
544
+ if (text !== undefined) {
545
+ return this.flag(text, header, { line: g.line, element: "directed" });
546
+ }
547
+ }
548
+ return header;
549
+ }
550
+
497
551
  /**
498
552
  * The direction the sink starts with: the one every edge has when they all agree (a
499
553
  * Cytoscape file writes cy:directed on every edge and may omit the root attribute), else the
@@ -578,6 +632,39 @@ export class XgmmlEmitter {
578
632
  }
579
633
  }
580
634
 
635
+ /**
636
+ * The sink id of a node's written id: the restored original, else the written id, coerced.
637
+ * @param text - the written id
638
+ * @returns the id
639
+ */
640
+ private idOf(text: string): NodeId {
641
+ return this.coercer.text(this.extras.restoredIds?.get(text) ?? text);
642
+ }
643
+
644
+ /** Per table: the label is the `name` att (labelFromName and some element has one). */
645
+ private readonly nameLabel = { node: false, edge: false };
646
+
647
+ /**
648
+ * Decide whether a table's label comes from its `name` atts.
649
+ * @param domain - node or edge
650
+ * @param records - the table's records
651
+ */
652
+ private decideNameLabel(domain: "node" | "edge", records: readonly (NodeRec | EdgeRec)[]): void {
653
+ this.nameLabel[domain] = this.extras.labelFromName === true && records.some((r) => r.atts.some(isNameAtt));
654
+ }
655
+
656
+ /**
657
+ * The label of a record: its `name` att, or its XGMML label.
658
+ * @param record - the node or edge
659
+ * @returns the label, or undefined
660
+ */
661
+ private labelOf(record: NodeRec | EdgeRec): string | undefined {
662
+ if (this.nameLabel[record.kind]) {
663
+ return record.atts.find(isNameAtt)?.value ?? undefined;
664
+ }
665
+ return record.label ?? undefined;
666
+ }
667
+
581
668
  /**
582
669
  * The coerced id of a node text.
583
670
  * @param text - the id text
@@ -585,7 +672,7 @@ export class XgmmlEmitter {
585
672
  * @returns the id
586
673
  */
587
674
  private nodeId(text: string, line: number): NodeId {
588
- const id = this.coercer.text(text);
675
+ const id = this.idOf(text);
589
676
  const merge = this.coercer.lastMerge;
590
677
  if (merge !== null) {
591
678
  this.report.warning(
@@ -645,7 +732,7 @@ export class XgmmlEmitter {
645
732
  this.report.warning(
646
733
  "validation-error",
647
734
  XGMML_ISSUE.DANGLING_REFERENCE,
648
- `${this.prefix()}${dangling} xlink:href reference(s) name no node or edge of the document`,
735
+ `${this.prefix()}${dangling} xlink:href reference${plural(dangling)} ${agree(dangling, "names", "name")} no node or edge of the document`,
649
736
  );
650
737
  }
651
738
  }
@@ -660,11 +747,15 @@ export class XgmmlEmitter {
660
747
  const positions = new Positions(this, this.dialect.cytoscape ? this.settings.zAs : "position");
661
748
  const graphics = new JsonColumn(this, "node", GRAPHICS_COLUMN, XGMML_ORIGIN_NAMESPACE, "graphics");
662
749
  const pointers = new Pointers(this, this.groupTest());
750
+ this.decideNameLabel(
751
+ "node",
752
+ this.rowList.flatMap((r) => r.records),
753
+ );
663
754
  for (const row of this.rowList) {
664
755
  const where = { line: row.records[0].line, element: row.id };
665
756
  const seen = new Set<string>();
666
757
  for (const record of row.records) {
667
- labels[row.row] ??= record.label ?? undefined;
758
+ labels[row.row] ??= this.labelOf(record);
668
759
  this.addElementColumns(this.nodeColumns, row.row, record, seen, where);
669
760
  positions.add(row, record);
670
761
  if (record.graphics !== null && Object.keys(record.graphics).length > 0) {
@@ -713,7 +804,11 @@ export class XgmmlEmitter {
713
804
  names.add(key);
714
805
  }
715
806
  for (const att of record.atts) {
716
- if (this.skipAtt(record, att) || (merging && att.name !== null && seen.has(att.name))) {
807
+ if (
808
+ this.skipAtt(record, att) ||
809
+ (this.nameLabel[record.kind] && isNameAtt(att)) ||
810
+ (merging && att.name !== null && seen.has(att.name))
811
+ ) {
717
812
  continue;
718
813
  }
719
814
  if (record.kind === "node" && att.name === "__isGroup" && record.nested.length > 0 && isCyTrue(att.value)) {
@@ -740,7 +835,20 @@ export class XgmmlEmitter {
740
835
  * @returns true to skip it
741
836
  */
742
837
  private skipAtt(record: NodeRec | EdgeRec, att: AttRec): boolean {
743
- return record.kind === "edge" && record.weight === null && att.name === this.options.weightFrom;
838
+ if (record.kind !== "edge" || att.name !== this.options.weightFrom) {
839
+ return false;
840
+ }
841
+ if (record.weight === null || att.name !== "weight" || att.children.length > 0) {
842
+ return record.weight === null;
843
+ }
844
+ // weight="2" and <att name="weight" value="3">: the attribute is THE weight
845
+ this.report.warning(
846
+ "validation-error",
847
+ XGMML_ISSUE.DUPLICATE_ATTRIBUTE,
848
+ `${this.prefix()}an edge has weight="${record.weight}" and a weight att "${att.value ?? ""}"; the weight attribute is the weight and the att is not read`,
849
+ { line: att.line, element: record.id ?? record.label ?? "weight" },
850
+ );
851
+ return true;
744
852
  }
745
853
 
746
854
  /**
@@ -758,7 +866,7 @@ export class XgmmlEmitter {
758
866
  return;
759
867
  }
760
868
  const handle = this.declare(domain, {
761
- name: LABEL_COLUMN,
869
+ name: this.nameLabel[domain] ? "name" : LABEL_COLUMN,
762
870
  dtype: "string",
763
871
  role: "label",
764
872
  nullable: true,
@@ -825,21 +933,23 @@ export class XgmmlEmitter {
825
933
  private addEdges(records: readonly EdgeRec[], header: boolean): void {
826
934
  const ids = new Set<string>();
827
935
  const dedupe = this.dialect.cy2 && this.doc.nodes.some((n) => n.nested.length > 0) ? new Set<string>() : null;
936
+ let repeats = 0;
937
+ let firstRepeat: IssueLocation | null = null;
828
938
  const labels: (string | undefined)[] = [];
829
939
  const edgeIds: (string | undefined)[] = [];
830
940
  const graphics: [number, Record<string, unknown>][] = [];
831
941
  let row = 0;
942
+ this.decideNameLabel("edge", records);
832
943
  for (const record of records) {
833
944
  const where = { line: record.line, element: record.id ?? record.label };
834
- const key = record.id ?? record.label;
945
+ // a repeat has the same id, or without one the same label and endpoints
946
+ const key =
947
+ record.id ??
948
+ (record.label === null ? null : JSON.stringify([record.label, record.source, record.target]));
835
949
  if (dedupe !== null && key !== null) {
836
950
  if (dedupe.has(key)) {
837
- this.report.warnOnce(
838
- "merged",
839
- XGMML_ISSUE.GROUP_DUPLICATE_EDGE,
840
- `${this.prefix()}the Cytoscape 2.x writer repeats the edges of a group; each repeat is dropped`,
841
- where,
842
- );
951
+ repeats++;
952
+ firstRepeat ??= where;
843
953
  continue;
844
954
  }
845
955
  dedupe.add(key);
@@ -850,7 +960,7 @@ export class XgmmlEmitter {
850
960
  continue;
851
961
  }
852
962
  this.edgeIndex[row] = index;
853
- labels[row] = record.label ?? undefined;
963
+ labels[row] = this.labelOf(record);
854
964
  edgeIds[row] = record.id ?? undefined;
855
965
  this.addElementColumns(this.edgeColumns, row, record, new Set(), where);
856
966
  this.fillInteraction(record, row, where);
@@ -859,6 +969,14 @@ export class XgmmlEmitter {
859
969
  }
860
970
  row++;
861
971
  }
972
+ if (repeats > 0) {
973
+ this.report.warning(
974
+ "merged",
975
+ XGMML_ISSUE.GROUP_DUPLICATE_EDGE,
976
+ `${this.prefix()}the Cytoscape 2.x writer repeats the edges of a group; ${repeats} repeat${plural(repeats)} ${agree(repeats, "was", "were")} dropped`,
977
+ firstRepeat ?? undefined,
978
+ );
979
+ }
862
980
  this.writeEdgeIds(edgeIds);
863
981
  this.writeLabels("edge", labels, (r) => this.edgeIndex[r] ?? -1);
864
982
  const column = new JsonColumn(this, "edge", GRAPHICS_COLUMN, XGMML_ORIGIN_NAMESPACE, "graphics");
@@ -938,7 +1056,7 @@ export class XgmmlEmitter {
938
1056
  if (text === null) {
939
1057
  return undefined;
940
1058
  }
941
- const weight = parseWeightText(text);
1059
+ const weight = parseWeightText(text, this.report);
942
1060
  this.weighted ||= weight !== undefined;
943
1061
  return weight;
944
1062
  }
@@ -957,21 +1075,24 @@ export class XgmmlEmitter {
957
1075
  if (text !== null) {
958
1076
  const row = this.rows.get(text);
959
1077
  if (row !== undefined && row.index >= 0) {
960
- return this.coercer.text(text);
1078
+ return this.idOf(text);
961
1079
  }
962
1080
  }
963
1081
  if (alias !== null) {
964
1082
  const resolved = this.aliasRow(alias);
965
1083
  if (resolved !== null) {
966
1084
  this.aliasResolved++;
967
- return this.coercer.text(resolved.id);
1085
+ return this.idOf(resolved.id);
968
1086
  }
969
1087
  }
970
1088
  if (text === null) {
1089
+ const ambiguous = alias !== null && this.aliasRow(alias) === null && this.labelRows?.get(alias) === null;
971
1090
  this.report.error(
972
1091
  "missing-value",
973
1092
  XGMML_ISSUE.MISSING_ENDPOINT,
974
- `${this.prefix()}<edge> without a ${side}`,
1093
+ ambiguous
1094
+ ? `${this.prefix()}<edge> without a ${side}: its label alias "${alias}" is ambiguous (several nodes have that label); the edge is skipped`
1095
+ : `${this.prefix()}<edge> without a ${side}`,
975
1096
  where,
976
1097
  );
977
1098
  return null;
@@ -1047,7 +1168,7 @@ export class XgmmlEmitter {
1047
1168
  this.report.warning(
1048
1169
  "coercion",
1049
1170
  XGMML_ISSUE.LABEL_ALIAS,
1050
- `${this.prefix()}Cytoscape label aliases ("a (pp) b"): ${this.aliasResolved} endpoint(s) resolved, ${this.aliasInteractions} interaction(s) filled from edge labels`,
1171
+ `${this.prefix()}Cytoscape label aliases ("a (pp) b"): ${this.aliasResolved} endpoint${plural(this.aliasResolved)} resolved, ${this.aliasInteractions} interaction${plural(this.aliasInteractions)} filled from edge labels`,
1051
1172
  );
1052
1173
  }
1053
1174
 
@@ -1152,10 +1273,26 @@ export class XgmmlEmitter {
1152
1273
  }
1153
1274
  }
1154
1275
 
1276
+ /**
1277
+ * Whether an att is a session table's own `name` cell (a text value; a formula is kept as its text).
1278
+ * @param att - the att
1279
+ * @returns true for the name
1280
+ */
1281
+ function isNameAtt(att: AttRec): boolean {
1282
+ return (
1283
+ att.name === "name" &&
1284
+ (att.namespace ?? null) === null &&
1285
+ att.value !== null &&
1286
+ att.children.length === 0 &&
1287
+ (att.cyType ?? "String") === "String"
1288
+ );
1289
+ }
1290
+
1155
1291
  /**
1156
1292
  * The three parts of a Cytoscape edge label (`source (interaction) target`).
1157
1293
  * @param label - the label, or null
1158
1294
  * @returns source alias, interaction, target alias; null when the label has another shape
1295
+ * @category Plugin helpers
1159
1296
  */
1160
1297
  export function aliasesOf(label: string | null): [string, string, string] | null {
1161
1298
  if (label === null) {
@@ -1274,8 +1411,8 @@ class Positions {
1274
1411
  if (text === null) {
1275
1412
  return null;
1276
1413
  }
1277
- const n = Number(text.trim());
1278
- if (text.trim().length === 0 || !Number.isFinite(n)) {
1414
+ const n = parseCoordinate(text);
1415
+ if (n === null) {
1279
1416
  this.emitter.issues.error(
1280
1417
  "validation-error",
1281
1418
  XGMML_ISSUE.BAD_VALUE,
@@ -1388,7 +1525,7 @@ class Pointers {
1388
1525
  this.emitter.issues.warning(
1389
1526
  "validation-error",
1390
1527
  XGMML_ISSUE.DANGLING_REFERENCE,
1391
- `${prefix}${this.dangling} nested-network pointer(s) name no graph of the document`,
1528
+ `${prefix}${this.dangling} nested-network pointer${plural(this.dangling)} ${agree(this.dangling, "names", "name")} no graph of the document`,
1392
1529
  );
1393
1530
  }
1394
1531
  const names = new JsonColumn(
@@ -1406,7 +1543,7 @@ class Pointers {
1406
1543
  this.emitter.issues.warning(
1407
1544
  "unsupported",
1408
1545
  XGMML_ISSUE.CROSS_FILE_REFERENCE,
1409
- `${prefix}${this.crossFile.size} nested-network pointer(s) point into another file; each is kept as text in ${NETWORK_POINTER_COLUMN}`,
1546
+ `${prefix}${this.crossFile.size} nested-network pointer${plural(this.crossFile.size)} ${agree(this.crossFile.size, "points", "point")} into another file; each is kept as text in ${NETWORK_POINTER_COLUMN}`,
1410
1547
  );
1411
1548
  const column = new JsonColumn(
1412
1549
  this.emitter,
@@ -1432,6 +1569,9 @@ class Containment {
1432
1569
 
1433
1570
  private readonly subgraphs = new Map<number, Record<string, unknown>>();
1434
1571
 
1572
+ /** The nodes that are some node's parent: only those can be an ancestor, so close a cycle. */
1573
+ private readonly groups = new Set<number>();
1574
+
1435
1575
  /**
1436
1576
  * Create the resolver.
1437
1577
  * @param emitter - the emitter
@@ -1482,7 +1622,7 @@ class Containment {
1482
1622
  this.emitter.issues.error(
1483
1623
  "missing-value",
1484
1624
  XGMML_ISSUE.UNKNOWN_PARENT,
1485
- `${this.emitter.prefix()}${unknown} group member(s) name no node of this graph`,
1625
+ `${this.emitter.prefix()}${unknown} group member${plural(unknown)} ${agree(unknown, "names", "name")} no node of this graph`,
1486
1626
  );
1487
1627
  }
1488
1628
  }
@@ -1494,7 +1634,7 @@ class Containment {
1494
1634
  * @param line - the line
1495
1635
  */
1496
1636
  private link(child: number, parent: number, line: number): void {
1497
- if (child === parent || this.isAncestor(child, parent)) {
1637
+ if (child === parent || (this.groups.has(child) && this.isAncestor(child, parent))) {
1498
1638
  this.emitter.issues.error(
1499
1639
  "validation-error",
1500
1640
  XGMML_ISSUE.PARENT_CYCLE,
@@ -1508,6 +1648,7 @@ class Containment {
1508
1648
  list.push(parent);
1509
1649
  }
1510
1650
  this.parents.set(child, list);
1651
+ this.groups.add(parent);
1511
1652
  }
1512
1653
 
1513
1654
  /**
@@ -11,15 +11,16 @@
11
11
  * form. It writes the graph's structure and columns, never styles.
12
12
  */
13
13
 
14
- import { type Column, GraphFormatError, type GraphSnapshot, type NodeId } from "@graphty/graph-format";
14
+ import { type Column, GraphFormatError, type GraphSnapshot } from "@graphty/graph-format";
15
15
 
16
16
  import { type ChildrenCsr, childrenCsr } from "../../children.js";
17
17
  import { DictHeuristic } from "../../common/attributes.js";
18
18
  import { type PairFolding, pairFolding } from "../../common/direction.js";
19
19
  import { escapeXmlAttribute, escapeXmlText } from "../../common/escape.js";
20
20
  import { capabilities, checkCapabilities, LOSS } from "../../common/export.js";
21
- import { formatF32, formatF64 } from "../../common/format.js";
21
+ import { formatF32, formatF64, idText } from "../../common/format.js";
22
22
  import { type ResolvedExportOptions, resolveExportOptions } from "../../common/options.js";
23
+ import { agree, plural } from "../../common/plural.js";
23
24
  import { type ExplicitWeights, explicitWeights } from "../../common/weights.js";
24
25
  import { encodeChunks, joinText } from "../../common/writer.js";
25
26
  import { xmlIllegalTextNotes } from "../../common/xml.js";
@@ -48,11 +49,18 @@ import {
48
49
  } from "./constants.js";
49
50
  import { aliasesOf } from "./emit.js";
50
51
 
51
- /** The format-specific options of the XGMML exporter. */
52
- export interface XgmmlExportOptions {
52
+ /** The two escapes Cytoscape reads back as a newline and a tab, as a message writes them. */
53
+ const LITERAL_ESCAPES = String.raw`\n or \t`;
54
+
55
+ /**
56
+ * The format-specific options of the XGMML exporter.
57
+ * @category Built-in formats
58
+ */
59
+ export interface XgmmlExportOptions extends CommonExportOptions {
53
60
  /**
54
- * Write newline and tab in string values as Cytoscape's two-character `\n` and `\t` (what the
55
- * Cytoscape writer does) instead of the character references `&#10;` and `&#9;` (default).
61
+ * Write line breaks and tabs in text values as Cytoscape's two-character `\n` and `\t`, as
62
+ * Cytoscape does, instead of the XML character references `&#10;` and `&#9;`.
63
+ * @defaultValue false
56
64
  */
57
65
  cytoscapeEscapes?: boolean | undefined;
58
66
  }
@@ -481,7 +489,7 @@ function attNotes(column: Column, domain: string, note: NoteFn): void {
481
489
  if (escapes > 0) {
482
490
  note(
483
491
  XGMML_LOSS.BACKSLASH_ESCAPE,
484
- `${label}: ${escapes} value(s) hold a literal \\n or \\t, which Cytoscape's escape convention reads back as a newline or tab`,
492
+ `${label}: ${escapes} value${plural(escapes)} ${agree(escapes, "holds", "hold")} a literal ${LITERAL_ESCAPES}, which Cytoscape's escape convention reads back as a newline or tab`,
485
493
  meta.name,
486
494
  escapes,
487
495
  );
@@ -498,7 +506,7 @@ function attNotes(column: Column, domain: string, note: NoteFn): void {
498
506
  if (readsAs !== meta.dtype) {
499
507
  note(
500
508
  XGMML_LOSS.STORAGE_CLASS_CHANGED,
501
- `${label} reads back as ${readsAs} (the cardinality heuristic)`,
509
+ `${label} reads back as ${readsAs}: the importer stores text with few distinct values as dict and other text as string; the values are the same`,
502
510
  meta.name,
503
511
  null,
504
512
  );
@@ -540,7 +548,7 @@ function planExport(snapshot: GraphSnapshot, options: ResolvedExportOptions, esc
540
548
  if (folding.mutualCount > 0) {
541
549
  note(
542
550
  XGMML_LOSS.MUTUAL_EXPANDED,
543
- `${folding.mutualCount} mutual pair(s) are written as two directed edges; the mutual mark is lost`,
551
+ `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two directed edges; the mutual mark is lost`,
544
552
  null,
545
553
  folding.mutualCount,
546
554
  );
@@ -549,7 +557,7 @@ function planExport(snapshot: GraphSnapshot, options: ResolvedExportOptions, esc
549
557
  if (numericIds > 0) {
550
558
  note(
551
559
  XGMML_LOSS.ID_TEXT_TYPE,
552
- `${numericIds} numeric node id(s) are written as text and read back as strings`,
560
+ `${numericIds} numeric node id${plural(numericIds)} ${agree(numericIds, "is", "are")} written as text and read back as strings`,
553
561
  null,
554
562
  numericIds,
555
563
  );
@@ -567,7 +575,7 @@ function planExport(snapshot: GraphSnapshot, options: ResolvedExportOptions, esc
567
575
  if (hierarchy.unreachable > 0) {
568
576
  note(
569
577
  XGMML_LOSS.PARENT_CYCLE,
570
- `${hierarchy.unreachable} node(s) whose parent chain never reaches a root are written at the top level and lose their parent`,
578
+ `${hierarchy.unreachable} node${plural(hierarchy.unreachable)} whose parent chain never reaches a root ${agree(hierarchy.unreachable, "is", "are")} written at the top level and lose their parent`,
571
579
  null,
572
580
  hierarchy.unreachable,
573
581
  );
@@ -596,7 +604,12 @@ function planExport(snapshot: GraphSnapshot, options: ResolvedExportOptions, esc
596
604
  const weights = explicitWeights(snapshot);
597
605
  for (const column of snapshot.edges) {
598
606
  if (column.meta.name === "weight" && column.meta.role === null && !weights.weighted) {
599
- note(LOSS.WEIGHT_KEY_CLASH, `edge column "weight" reads back as THE weight`, "weight", null);
607
+ note(
608
+ LOSS.WEIGHT_KEY_CLASH,
609
+ `edge column "weight" reads back as the edge weight, not as a column`,
610
+ "weight",
611
+ null,
612
+ );
600
613
  }
601
614
  }
602
615
  return {
@@ -635,7 +648,7 @@ function interactionNote(snapshot: GraphSnapshot, note: NoteFn): void {
635
648
  if (shaped > 0) {
636
649
  note(
637
650
  XGMML_LOSS.INTERACTION_FROM_LABEL,
638
- `${shaped} edge label(s) have Cytoscape's "a (i) b" shape and read back with an "${INTERACTION_COLUMN}" column`,
651
+ `${shaped} edge label${plural(shaped)} ${agree(shaped, "has", "have")} Cytoscape's "a (i) b" shape and read back with an "${INTERACTION_COLUMN}" column`,
639
652
  INTERACTION_COLUMN,
640
653
  shaped,
641
654
  );
@@ -691,7 +704,7 @@ function positionNotes(position: Column, snapshot: GraphSnapshot, note: NoteFn):
691
704
  if (meta.components !== 3) {
692
705
  note(
693
706
  XGMML_LOSS.POSITION,
694
- `position column "${meta.name}" has ${meta.components} component(s) and reads back with 3`,
707
+ `position column "${meta.name}" has ${meta.components} component${plural(meta.components)} and reads back with 3`,
695
708
  meta.name,
696
709
  null,
697
710
  );
@@ -712,7 +725,7 @@ function positionNotes(position: Column, snapshot: GraphSnapshot, note: NoteFn):
712
725
  if (nonFinite > 0) {
713
726
  note(
714
727
  XGMML_LOSS.POSITION,
715
- `${nonFinite} position(s) with a non-finite coordinate are not written`,
728
+ `${nonFinite} position${plural(nonFinite)} with a non-finite coordinate ${agree(nonFinite, "is", "are")} not written`,
716
729
  meta.name,
717
730
  nonFinite,
718
731
  );
@@ -722,8 +735,8 @@ function positionNotes(position: Column, snapshot: GraphSnapshot, note: NoteFn):
722
735
  note(
723
736
  XGMML_LOSS.POSITION,
724
737
  zColumn === null
725
- ? `${depth} position(s) have a z; it is written as graphics z and reads back in the z column (zAs: "position" reads it as a coordinate)`
726
- : `${depth} position(s) have a z, but graphics z holds the z column; the position z is lost`,
738
+ ? `${depth} position${plural(depth)} ${agree(depth, "has", "have")} a z; it is written as graphics z and reads back in the z column (zAs: "position" reads it as a coordinate)`
739
+ : `${depth} position${plural(depth)} ${agree(depth, "has", "have")} a z, but graphics z holds the z column; the position z is lost`,
727
740
  meta.name,
728
741
  depth,
729
742
  );
@@ -787,15 +800,6 @@ function scalarText(value: unknown): string {
787
800
  return JSON.stringify(value) ?? "";
788
801
  }
789
802
 
790
- /**
791
- * The text of an id.
792
- * @param id - the id
793
- * @returns the text
794
- */
795
- function idText(id: NodeId): string {
796
- return typeof id === "number" ? formatF64(id) : id;
797
- }
798
-
799
803
  /**
800
804
  * The XML attributes of one row: the columns that came from XML attributes (`untypedAttribute`).
801
805
  * @param writes - the column writes of the table
@@ -1202,9 +1206,13 @@ function planFor(snapshot: GraphSnapshot, options: (XgmmlExportOptions & CommonE
1202
1206
  return plan;
1203
1207
  }
1204
1208
 
1205
- /** The XGMML exporter. */
1209
+ /**
1210
+ * The XGMML exporter.
1211
+ * @category Built-in formats
1212
+ */
1206
1213
  export const xgmmlExporter: GraphExporter<XgmmlExportOptions> = Object.freeze({
1207
1214
  format: FORMAT,
1215
+ options: Object.freeze(["cytoscapeEscapes"]),
1208
1216
  capabilities: CAPABILITIES,
1209
1217
  check: (snapshot: GraphSnapshot, options?: XgmmlExportOptions & CommonExportOptions): readonly LossNote[] =>
1210
1218
  Object.freeze(planExport(snapshot, resolveExportOptions(options), resolveEscapes(options)).notes),