@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
@@ -0,0 +1,1072 @@
1
+ /**
2
+ * The Cytoscape session exporter: writes a snapshot as a `.cys` file that Cytoscape Desktop 3.x
3
+ * opens as a session holding one network (one collection with one registered subnetwork).
4
+ *
5
+ * The archive holds what Cytoscape's session reader needs and nothing more:
6
+ * - `CytoscapeSession/3.0.0.version`, the empty marker that makes Cytoscape read a 3.x session;
7
+ * - `networks/<root>-<name>.xgmml`, the topology: one root network holding one registered
8
+ * subnetwork, its nodes and edges by SUID, each edge with `cy:directed`;
9
+ * - `tables/<subnetwork>-<name>/LOCAL_ATTRS-org.cytoscape.model.Cy{Node,Edge,Network}-*.cytable`,
10
+ * every column as a CyCSV table keyed by SUID (a session network file carries no attributes:
11
+ * Cytoscape ignores atts on the nodes and edges of a 3.x session), with the label in `name`,
12
+ * which Cytoscape's default style shows; plus the root network's own table with its name;
13
+ * - `views/<subnetwork>-<view>-<name>.xgmml`, the node coordinates (y negated back to screen
14
+ * coordinates), only when the snapshot has positions: graph-io computes no layout.
15
+ *
16
+ * Styles, the network list, properties and thumbnails are not written; Cytoscape gives the view
17
+ * its default style. Entries are stored, not compressed. Every SUID comes from one counter, above
18
+ * the node ids that are kept as SUIDs; Cytoscape renumbers them all on load.
19
+ */
20
+ import { GraphFormatError } from "@graphty/graph-format";
21
+ import { DictHeuristic } from "../../common/attributes.js";
22
+ import { pairFolding } from "../../common/direction.js";
23
+ import { escapeXmlAttribute, quoteCsvCell } from "../../common/escape.js";
24
+ import { capabilities, checkCapabilities, LOSS } from "../../common/export.js";
25
+ import { formatDecimal, formatF32, formatF64 } from "../../common/format.js";
26
+ import { resolveExportOptions } from "../../common/options.js";
27
+ import { agree, plural } from "../../common/plural.js";
28
+ import { explicitWeights } from "../../common/weights.js";
29
+ import { hasIllegalXmlChar } from "../../common/xml.js";
30
+ import { writeZip } from "../../common/zip.js";
31
+ import { ORIGINAL_ID_ATTRIBUTE } from "../graphml/constants.js";
32
+ import { CY_NAMESPACE, EDGE_ID_COLUMN, GRAPHICS_COLUMN, NESTED_NETWORK_COLUMN, NETWORK_POINTER_COLUMN, NETWORKS_COLUMN, PARENT_COLUMN, PARENTS_COLUMN, POSITION_COLUMN, SUBGRAPH_COLUMN, XGMML_NAMESPACE, XLINK_NAMESPACE, Z_COLUMN, } from "../xgmml/constants.js";
33
+ import { FORMAT } from "./constants.js";
34
+ /**
35
+ * The loss notes the session exporter's check() returns, by name. A key is the code without its
36
+ * severity and format prefixes.
37
+ * @category Built-in formats
38
+ */
39
+ export const CYS_LOSS = Object.freeze({
40
+ /** CyCSV has no unset text cell: an unset cell of a text column reads back as "". */
41
+ UNSET_AS_EMPTY_STRING: "W_CYS_UNSET_AS_EMPTY_STRING",
42
+ /**
43
+ * List cells CyCSV cannot hold exactly: an unset or empty list of text reads back as [""], an
44
+ * empty list of numbers or booleans reads back unset, trailing empty text items vanish, and an
45
+ * item holding a newline splits in two.
46
+ */
47
+ LIST_ITEMS: "W_CYS_LIST_ITEMS",
48
+ /** A text cell starting with "=" is a formula to Cytoscape (an error cell there); graph-io reads it back as text. */
49
+ TEXT_AS_EQUATION: "W_CYS_TEXT_AS_EQUATION",
50
+ /** A nested (json) column is written as a text column holding its JSON text. */
51
+ JSON_AS_STRING: "W_CYS_JSON_AS_STRING",
52
+ /** A position that cannot be written as it is: another shape, a non-finite coordinate, a z read back in the z column. */
53
+ POSITION: "W_CYS_POSITION",
54
+ /**
55
+ * An attribute with a role (for example, the label) is written where the format keeps that role, and reads back under the
56
+ * name the format's importer gives it.
57
+ */
58
+ COLUMN_NAME_CHANGED: LOSS.COLUMN_NAME_CHANGED,
59
+ /**
60
+ * An attribute without a role is written where the format keeps a role (for example, a `name` column as the label), and
61
+ * reads back with that role.
62
+ */
63
+ ROLE_ASSUMED: LOSS.ROLE_ASSUMED,
64
+ /** A mutual pair is written as two directed edges without its mark. */
65
+ MUTUAL_EXPANDED: LOSS.MUTUAL_EXPANDED,
66
+ /** Node ids that are numbers read back as their text. */
67
+ ID_TEXT_TYPE: LOSS.ID_TEXT_TYPE,
68
+ /**
69
+ * Two node ids would be written as the same text (the number 5 and the text "5"); the save fails with
70
+ * E_INVALID_ID.
71
+ */
72
+ ID_TEXT_COLLISION: LOSS.ID_TEXT_COLLISION,
73
+ /**
74
+ * Node ids the format cannot write, under `sanitizeIds: "error"`; the save fails with E_INVALID_ID. Pass
75
+ * `sanitizeIds: "mangle"` to rewrite them.
76
+ */
77
+ ID_CHARSET: LOSS.ID_CHARSET,
78
+ /** Node ids that are not positive integers under sanitizeIds "mangle": renumbered, originals kept. */
79
+ ID_MANGLED: LOSS.ID_MANGLED,
80
+ /** Edges without a usable id get generated SUIDs. */
81
+ EDGE_IDS_GENERATED: LOSS.EDGE_IDS_GENERATED,
82
+ /**
83
+ * An attribute type Cytoscape stores as a wider one (a 32-bit float as Double, a byte as Integer), or a label that
84
+ * is not text and is written as text; it reads back with the Cytoscape type.
85
+ */
86
+ DTYPE_UNSUPPORTED: LOSS.DTYPE,
87
+ /** A column whose every cell is unset (and which is not text) vanishes. */
88
+ EMPTY_COLUMN_DROPPED: LOSS.EMPTY_COLUMN,
89
+ /**
90
+ * A text attribute reads back as a dictionary attribute, or the reverse, because the importer chooses by how often
91
+ * its values repeat. The values are the same.
92
+ */
93
+ STORAGE_CLASS_CHANGED: LOSS.STORAGE_CLASS,
94
+ /** A plain `weight` edge column reads back as the edge weight. */
95
+ WEIGHT_KEY_CLASH: LOSS.WEIGHT_KEY_CLASH,
96
+ /** A parent / parents column: groups are not written. */
97
+ HIERARCHY_DROPPED: LOSS.HIERARCHY,
98
+ /** A start / end / timestamp column: sessions have no time. */
99
+ TEMPORAL_DROPPED: LOSS.TEMPORAL,
100
+ /** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */
101
+ ROLE_DROPPED: LOSS.ROLE,
102
+ /** An extension table the session cannot carry. */
103
+ EXTENSION_TABLE_DROPPED: LOSS.EXTENSION_TABLE,
104
+ });
105
+ /**
106
+ * What a Cytoscape session keeps: mixed direction, parallel edges and self-loops, integer SUIDs
107
+ * for nodes and edges, String / Double / Integer / Long / Boolean columns and lists of them,
108
+ * graph columns and positions. Groups, defaults, styles and time are not written.
109
+ * @category Built-in formats
110
+ */
111
+ export const CYS_CAPABILITIES = capabilities({
112
+ mixedDirection: true,
113
+ multiEdges: true,
114
+ selfLoops: true,
115
+ edgeIds: "required",
116
+ idCharset: "integer",
117
+ dtypes: ["string", "dict", "f64", "i32", "bool", "list"],
118
+ components: false,
119
+ lists: true,
120
+ json: false,
121
+ defaults: false,
122
+ options: false,
123
+ hierarchy: false,
124
+ temporal: "none",
125
+ graphAttributes: true,
126
+ positions: true,
127
+ viz: false,
128
+ });
129
+ /** The roles with a slot (the label as `name`, the edge id as the SUID, positions in the view) and their read-back names. */
130
+ const SLOT_ROLES = new Set(["label", "id", "position"]);
131
+ const ROLE_NAMES = Object.freeze({
132
+ label: "name",
133
+ id: EDGE_ID_COLUMN,
134
+ position: POSITION_COLUMN,
135
+ });
136
+ /** Roles whose columns are not written as table columns (structure, or reported dropped by checkCapabilities). */
137
+ const SKIPPED_ROLES = new Set([
138
+ "directed",
139
+ "pair",
140
+ "mutual",
141
+ "weight",
142
+ "timeText",
143
+ "parent",
144
+ "parents",
145
+ "start",
146
+ "end",
147
+ "timestamp",
148
+ "timestamps",
149
+ "spells",
150
+ "open",
151
+ "spellsOpen",
152
+ "position",
153
+ "color",
154
+ "size",
155
+ "shape",
156
+ "thickness",
157
+ ]);
158
+ /** The Java classes of the columns Cytoscape creates in every table, by lower-case name. */
159
+ const BUILT_IN = {
160
+ node: new Map([
161
+ ["name", "java.lang.String"],
162
+ ["shared name", "java.lang.String"],
163
+ ["selected", "java.lang.Boolean"],
164
+ ]),
165
+ edge: new Map([
166
+ ["name", "java.lang.String"],
167
+ ["shared name", "java.lang.String"],
168
+ ["interaction", "java.lang.String"],
169
+ ["shared interaction", "java.lang.String"],
170
+ ["selected", "java.lang.Boolean"],
171
+ ]),
172
+ network: new Map([
173
+ ["name", "java.lang.String"],
174
+ ["shared name", "java.lang.String"],
175
+ ["selected", "java.lang.Boolean"],
176
+ ["__annotations", "java.util.List<java.lang.String>"],
177
+ ]),
178
+ };
179
+ /** Column names graph-io's session importer gives its own columns; a table column of such a name reads back renamed. */
180
+ const IMPORTER_NAMES = {
181
+ node: new Set([
182
+ POSITION_COLUMN,
183
+ Z_COLUMN,
184
+ GRAPHICS_COLUMN,
185
+ PARENT_COLUMN,
186
+ PARENTS_COLUMN,
187
+ SUBGRAPH_COLUMN,
188
+ NESTED_NETWORK_COLUMN,
189
+ NETWORK_POINTER_COLUMN,
190
+ NETWORKS_COLUMN,
191
+ ]),
192
+ edge: new Set([EDGE_ID_COLUMN, GRAPHICS_COLUMN]),
193
+ network: new Set([GRAPHICS_COLUMN]),
194
+ };
195
+ const STRING = "java.lang.String";
196
+ const DOUBLE = "java.lang.Double";
197
+ const INTEGER = "java.lang.Integer";
198
+ const LONG = "java.lang.Long";
199
+ const BOOLEAN = "java.lang.Boolean";
200
+ const I32_MAX = 2147483647;
201
+ /** The folder every entry lives under (Cytoscape needs one; the name is free). */
202
+ const ROOT_FOLDER = "CytoscapeSession/";
203
+ /** The default network name. */
204
+ const DEFAULT_NAME = "Network";
205
+ // ============================================================ ids
206
+ /** Positive integer text a Long holds exactly. */
207
+ const SUID_TEXT = /^[1-9]\d*$/;
208
+ /**
209
+ * The SUID a node id can keep, or null: a positive safe integer, or its canonical digits.
210
+ * @param id - the id
211
+ * @returns the SUID, or null
212
+ */
213
+ function suidOf(id) {
214
+ if (typeof id === "number") {
215
+ return Number.isSafeInteger(id) && id > 0 ? id : null;
216
+ }
217
+ if (SUID_TEXT.test(id)) {
218
+ const n = Number(id);
219
+ return Number.isSafeInteger(n) ? n : null;
220
+ }
221
+ return null;
222
+ }
223
+ /**
224
+ * The SUIDs node ids keep (the first of two ids naming one SUID keeps it).
225
+ * @param snapshot - the snapshot
226
+ * @returns the kept SUIDs and the nodes without one
227
+ */
228
+ function keptNodeSuids(snapshot) {
229
+ const kept = [];
230
+ const bad = [];
231
+ const used = new Set();
232
+ for (let i = 0; i < snapshot.nodeCount; i++) {
233
+ const suid = suidOf(snapshot.ids.idOf(i));
234
+ if (suid === null || used.has(suid)) {
235
+ kept.push(0);
236
+ bad.push(i);
237
+ }
238
+ else {
239
+ used.add(suid);
240
+ kept.push(suid);
241
+ }
242
+ }
243
+ return { kept, bad };
244
+ }
245
+ /**
246
+ * The edge SUIDs the id role column keeps: positive integers, distinct, and not node SUIDs.
247
+ * @param snapshot - the snapshot
248
+ * @param nodeSuids - the SUIDs nodes keep
249
+ * @returns the kept SUID of each edge, 0 where one is generated
250
+ */
251
+ function keptEdgeSuids(snapshot, nodeSuids) {
252
+ const column = snapshot.edges.byRole("id");
253
+ const out = new Array(snapshot.edgeCount).fill(0);
254
+ if (column === null) {
255
+ return out;
256
+ }
257
+ const used = new Set();
258
+ for (let e = 0; e < snapshot.edgeCount; e++) {
259
+ const value = column.isSet(e) ? column.value(e) : null;
260
+ const suid = typeof value === "number" || typeof value === "string" ? suidOf(value) : null;
261
+ if (suid !== null && !used.has(suid) && !nodeSuids.has(suid)) {
262
+ used.add(suid);
263
+ out[e] = suid;
264
+ }
265
+ }
266
+ return out;
267
+ }
268
+ // ============================================================ columns
269
+ /**
270
+ * The Java class of a scalar dtype.
271
+ * @param column - the column (for the long origin and the u32 range)
272
+ * @param dtype - the dtype (a list's item dtype)
273
+ * @returns the class text
274
+ */
275
+ function scalarClass(column, dtype) {
276
+ switch (dtype) {
277
+ case "bool":
278
+ return BOOLEAN;
279
+ case "i32":
280
+ case "u8":
281
+ return INTEGER;
282
+ case "u32":
283
+ return maxValue(column) > I32_MAX ? LONG : INTEGER;
284
+ case "f32":
285
+ case "f64":
286
+ return /long$/i.test(column.meta.origin?.type ?? "") && allSafeIntegers(column) ? LONG : DOUBLE;
287
+ default:
288
+ return STRING;
289
+ }
290
+ }
291
+ /**
292
+ * The items of a set cell: a list's items, or the scalar itself.
293
+ * @param column - the column
294
+ * @param row - the row
295
+ * @returns the values
296
+ */
297
+ function itemsOf(column, row) {
298
+ return column.dtype === "list" ? [...column.sliceOf(row)] : [column.value(row)];
299
+ }
300
+ /**
301
+ * Whether every set value of a numeric column (or of its list items) is a safe integer.
302
+ * @param column - the column
303
+ * @returns true when Long can carry every value
304
+ */
305
+ function allSafeIntegers(column) {
306
+ for (let r = 0; r < column.length; r++) {
307
+ if (column.isSet(r) && !itemsOf(column, r).every((v) => typeof v === "number" && Number.isSafeInteger(v))) {
308
+ return false;
309
+ }
310
+ }
311
+ return true;
312
+ }
313
+ /**
314
+ * The largest value of a numeric column (or of its list items).
315
+ * @param column - the column
316
+ * @returns the maximum, 0 when empty
317
+ */
318
+ function maxValue(column) {
319
+ let max = 0;
320
+ for (let r = 0; r < column.length; r++) {
321
+ if (column.isSet(r)) {
322
+ for (const v of itemsOf(column, r)) {
323
+ if (typeof v === "number" && v > max) {
324
+ max = v;
325
+ }
326
+ }
327
+ }
328
+ }
329
+ return max;
330
+ }
331
+ /**
332
+ * The CyCSV text of one value of a class.
333
+ * @param value - the value
334
+ * @param javaClass - the scalar class
335
+ * @param dtype - the dtype it came from
336
+ * @returns the text Cytoscape's `valueOf` reads back
337
+ */
338
+ function valueText(value, javaClass, dtype) {
339
+ if (javaClass === BOOLEAN) {
340
+ return value === true ? "true" : "false";
341
+ }
342
+ if (javaClass === DOUBLE) {
343
+ return formatDecimal(value, dtype === "f32" ? "f32" : "f64");
344
+ }
345
+ if (javaClass === INTEGER || javaClass === LONG) {
346
+ return String(value);
347
+ }
348
+ return textOf(value);
349
+ }
350
+ /**
351
+ * A value as text: strings as they are, numbers in their shortest form, anything else as JSON.
352
+ * @param value - the value
353
+ * @returns the text
354
+ */
355
+ function textOf(value) {
356
+ if (typeof value === "string") {
357
+ return value;
358
+ }
359
+ if (typeof value === "number") {
360
+ return formatF64(value);
361
+ }
362
+ if (typeof value === "boolean") {
363
+ return value ? "true" : "false";
364
+ }
365
+ if (ArrayBuffer.isView(value)) {
366
+ return JSON.stringify(Array.from(value).map(finiteOrText));
367
+ }
368
+ return JSON.stringify(value) ?? "";
369
+ }
370
+ /**
371
+ * A number for JSON text (JSON has no NaN or infinities: those are written as their names).
372
+ * @param v - the number
373
+ * @returns the number or its name
374
+ */
375
+ function finiteOrText(v) {
376
+ return Number.isFinite(v) ? v : String(v);
377
+ }
378
+ /**
379
+ * A snapshot column as a table candidate: its class and cell texts.
380
+ * @param column - the column
381
+ * @param name - the name it wants
382
+ * @returns the candidate
383
+ */
384
+ function candidateOf(column, name) {
385
+ const { meta } = column;
386
+ if (column.dtype === "list") {
387
+ const item = meta.itemDtype;
388
+ const itemClass = scalarClass(column, item === "json" ? null : item);
389
+ return {
390
+ name,
391
+ source: column,
392
+ javaClass: `java.util.List<${itemClass}>`,
393
+ cell: (row) => column.isSet(row)
394
+ ? [...column.sliceOf(row)].map((v) => valueText(v, itemClass, item)).join("\n")
395
+ : null,
396
+ };
397
+ }
398
+ const javaClass = meta.dtype === "json" || meta.components > 1 ? STRING : scalarClass(column, meta.dtype);
399
+ return {
400
+ name,
401
+ source: column,
402
+ javaClass,
403
+ cell: (row) => (column.isSet(row) ? valueText(column.value(row), javaClass, meta.dtype) : null),
404
+ };
405
+ }
406
+ /**
407
+ * Settle the names of a table's columns: case-insensitively unique, `SUID` and Cytoscape's own
408
+ * columns of another class renamed `<name>#2`, `#3`...
409
+ * @param domain - the table
410
+ * @param candidates - the columns in order
411
+ * @param note - the recorder
412
+ * @returns the table's columns (the SUID key first)
413
+ */
414
+ function settleNames(domain, candidates, note) {
415
+ const taken = new Set(["suid"]);
416
+ const out = [];
417
+ for (const c of candidates) {
418
+ const lower = c.name.toLowerCase();
419
+ const builtIn = BUILT_IN[domain].get(lower);
420
+ let { name } = c;
421
+ const clash = builtIn !== undefined && builtIn !== c.javaClass ? builtIn : null;
422
+ if (taken.has(lower) || clash !== null) {
423
+ let k = 2;
424
+ while (taken.has(`${lower}#${k}`)) {
425
+ k++;
426
+ }
427
+ name = `${c.name}#${k}`;
428
+ const why = renameReason(lower, clash);
429
+ const set = c.source === null ? null : c.source.length - c.source.nullCount;
430
+ note(LOSS.COLUMN_NAME_CHANGED, `${domain} column "${c.name}" is written as "${name}": ${why}`, c.name, set);
431
+ }
432
+ else if (c.source !== null && IMPORTER_NAMES[domain].has(c.name)) {
433
+ note(LOSS.COLUMN_NAME_CHANGED, `${domain} column "${c.name}" is written to the session's table and reads back as "${c.name}#2": graph-io's session reader makes a "${c.name}" column of its own`, c.name, c.source.length - c.source.nullCount);
434
+ }
435
+ taken.add(name.toLowerCase());
436
+ out.push({ name, javaClass: c.javaClass, cell: c.cell });
437
+ }
438
+ return out;
439
+ }
440
+ /**
441
+ * Why a column is renamed.
442
+ * @param lower - the column name, lower-cased
443
+ * @param clash - the Java class of Cytoscape's own column of that name when it holds another, else null
444
+ * @returns the reason
445
+ */
446
+ function renameReason(lower, clash) {
447
+ if (lower === "suid") {
448
+ return "SUID is Cytoscape's key column";
449
+ }
450
+ if (clash !== null) {
451
+ return `Cytoscape's own "${lower}" column holds ${clash}`;
452
+ }
453
+ return "its name is taken (Cytoscape column names ignore case)";
454
+ }
455
+ /**
456
+ * Java's `String.split("\n")`: trailing empty items are removed.
457
+ * @param text - the cell
458
+ * @returns the items
459
+ */
460
+ function javaSplit(text) {
461
+ if (!text.includes("\n")) {
462
+ return [text];
463
+ }
464
+ const items = text.split("\n");
465
+ while (items.at(-1) === "") {
466
+ items.pop();
467
+ }
468
+ return items;
469
+ }
470
+ /**
471
+ * The notes of one written column: what CyCSV cannot hold of its cells.
472
+ * @param domain - the table
473
+ * @param c - the candidate
474
+ * @param rows - the row count
475
+ * @param note - the recorder
476
+ */
477
+ function cellNotes(domain, c, rows, note) {
478
+ const { source } = c;
479
+ if (source === null) {
480
+ return;
481
+ }
482
+ const label = `${domain} column "${source.meta.name}"`;
483
+ const { name } = source.meta;
484
+ const text = c.javaClass === STRING;
485
+ const { unset, equations, lists, set, heuristic } = cellCounts(c, source, rows);
486
+ if (source.dtype === "json") {
487
+ note(CYS_LOSS.JSON_AS_STRING, `${label} holds nested values; written as their JSON text`, name, set);
488
+ }
489
+ if (set === 0 && (!text || rows === 0)) {
490
+ note(LOSS.EMPTY_COLUMN, `${label} has no value; it is not in the re-import`, name, null);
491
+ return;
492
+ }
493
+ if (text && unset > 0) {
494
+ note(CYS_LOSS.UNSET_AS_EMPTY_STRING, `${label}: ${unset} unset cell${plural(unset)} ${agree(unset, "is", "are")} written empty and read back as ""`, name, unset);
495
+ }
496
+ if (lists > 0) {
497
+ note(CYS_LOSS.LIST_ITEMS, `${label}: ${lists} list cell${plural(lists)} ${agree(lists, "reads", "read")} back changed (an unset or empty list of text as [""], an empty list of numbers unset, trailing empty items dropped, items holding a newline split)`, name, lists);
498
+ }
499
+ if (equations > 0) {
500
+ note(CYS_LOSS.TEXT_AS_EQUATION, `${label}: ${equations} cell${plural(equations)} start with "=", which Cytoscape reads as a formula (an error cell); graph-io reads them back as text`, name, equations);
501
+ }
502
+ if (text && (source.dtype === "string" || source.dtype === "dict")) {
503
+ const readsAs = heuristic.decide();
504
+ if (readsAs !== source.dtype) {
505
+ note(LOSS.STORAGE_CLASS, `${label} reads back as ${readsAs} (the cardinality heuristic)`, name, null);
506
+ }
507
+ }
508
+ }
509
+ /**
510
+ * Count what CyCSV changes in a column's cells: unset cells, text read as a formula, lists that
511
+ * read back changed; and feed the text cells to the dict heuristic.
512
+ * @param c - the candidate
513
+ * @param source - its column
514
+ * @param rows - the row count
515
+ * @returns the counts and the heuristic
516
+ */
517
+ function cellCounts(c, source, rows) {
518
+ const text = c.javaClass === STRING;
519
+ const stringList = c.javaClass === `java.util.List<${STRING}>`;
520
+ const counts = { unset: 0, equations: 0, lists: 0, set: 0, heuristic: new DictHeuristic() };
521
+ for (let r = 0; r < rows; r++) {
522
+ const cell = c.cell(r);
523
+ if (cell === null) {
524
+ counts.unset++;
525
+ }
526
+ else {
527
+ counts.set++;
528
+ }
529
+ const written = cell ?? "";
530
+ if (text && !counts.heuristic.decided) {
531
+ counts.heuristic.observe(written);
532
+ }
533
+ if (written.startsWith("=")) {
534
+ counts.equations++;
535
+ }
536
+ else if (source.dtype === "list" && listChanges(source, r, cell, stringList)) {
537
+ counts.lists++;
538
+ }
539
+ }
540
+ return counts;
541
+ }
542
+ /**
543
+ * Whether a list cell reads back changed from the text CyCSV writes for it.
544
+ * @param source - the list column
545
+ * @param r - the row
546
+ * @param cell - the written text, or null when unset
547
+ * @param stringList - whether Cytoscape reads the column as a list of text
548
+ * @returns true when it changes
549
+ */
550
+ function listChanges(source, r, cell, stringList) {
551
+ const written = cell ?? "";
552
+ let back = null;
553
+ if (stringList) {
554
+ back = written.length === 0 ? [""] : javaSplit(written);
555
+ }
556
+ else if (written.length > 0) {
557
+ back = javaSplit(written).filter((item) => item.length > 0);
558
+ }
559
+ const items = cell === null ? null : [...source.sliceOf(r)].map((v) => valueText(v, "", null));
560
+ if (back === null || items === null) {
561
+ return back !== items;
562
+ }
563
+ return back.length !== items.length || (stringList && back.some((b, i) => b !== items[i]));
564
+ }
565
+ /**
566
+ * Whether a column is the z slot (a role-less f64 `z` column, as the importer makes it).
567
+ * @param column - the column
568
+ * @returns true for the z column
569
+ */
570
+ function isZ(column) {
571
+ return column.meta.name === Z_COLUMN && column.meta.dtype === "f64" && column.meta.role === null;
572
+ }
573
+ /**
574
+ * The candidates of the node or edge table: the label as `name`, then the exporter's own columns,
575
+ * then every other column in order.
576
+ * @param snapshot - the snapshot
577
+ * @param domain - node or edge
578
+ * @param own - the exporter's columns after the label
579
+ * @param skip - columns written elsewhere
580
+ * @param note - the recorder
581
+ * @returns the candidates
582
+ */
583
+ function elementCandidates(snapshot, domain, own, skip, note) {
584
+ const table = domain === "node" ? snapshot.nodes : snapshot.edges;
585
+ const label = table.byRole("label");
586
+ const out = [];
587
+ if (label !== null) {
588
+ const c = candidateOf(label, "name");
589
+ out.push({ ...c, javaClass: STRING, cell: (row) => (label.isSet(row) ? textOf(label.value(row)) : null) });
590
+ if (label.dtype !== "string" && label.dtype !== "dict") {
591
+ note(LOSS.DTYPE, `${domain} label column "${label.meta.name}" (${label.dtype}) is written as text and reads back as string`, label.meta.name, label.length - label.nullCount);
592
+ }
593
+ }
594
+ out.push(...own);
595
+ for (const column of table) {
596
+ const { role } = column.meta;
597
+ if (column === label || (role !== null && (SKIPPED_ROLES.has(role) || role === "id")) || skip(column)) {
598
+ continue;
599
+ }
600
+ out.push(candidateOf(column, column.meta.name));
601
+ if (label === null &&
602
+ role === null &&
603
+ column.meta.name === "name" &&
604
+ scalarClass(column, column.dtype) === STRING) {
605
+ note(LOSS.ROLE_ASSUMED, `${domain} column "name" is Cytoscape's name and reads back as the label`, "name", column.length - column.nullCount);
606
+ }
607
+ }
608
+ return out;
609
+ }
610
+ /**
611
+ * Settle a table and record the notes of its cells.
612
+ * @param domain - the table
613
+ * @param candidates - its columns
614
+ * @param rows - its row count
615
+ * @param note - the recorder
616
+ * @returns the columns
617
+ */
618
+ function planTable(domain, candidates, rows, note) {
619
+ for (const c of candidates) {
620
+ cellNotes(domain, c, rows, note);
621
+ }
622
+ return settleNames(domain, candidates, note);
623
+ }
624
+ /**
625
+ * Note the node ids whose text changes on the way back: numbers read back as text, and the error
626
+ * for two ids with the same text.
627
+ * @param snapshot - the snapshot
628
+ * @param note - the recorder
629
+ * @returns the error the save throws for a collision, or null
630
+ */
631
+ function idTextNotes(snapshot, note) {
632
+ let collisions = 0;
633
+ let numeric = 0;
634
+ const texts = new Set();
635
+ for (let i = 0; i < snapshot.nodeCount; i++) {
636
+ const id = snapshot.ids.idOf(i);
637
+ numeric += typeof id === "number" ? 1 : 0;
638
+ const text = String(id);
639
+ if (texts.has(text)) {
640
+ collisions++;
641
+ }
642
+ texts.add(text);
643
+ }
644
+ let fatal = null;
645
+ if (collisions > 0) {
646
+ note(LOSS.ID_TEXT_COLLISION, `${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id (a number and a string); the save fails with E_INVALID_ID`, null, collisions);
647
+ fatal = new GraphFormatError("E_INVALID_ID", `${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id`, { reason: "collision", count: collisions });
648
+ }
649
+ if (numeric > 0) {
650
+ note(LOSS.ID_TEXT_TYPE, `${numeric} numeric node id${plural(numeric)} ${agree(numeric, "reads", "read")} back as their text`, null, numeric);
651
+ }
652
+ return fatal;
653
+ }
654
+ /**
655
+ * Note the node ids that are not positive integers: renumbered under "mangle", else refused.
656
+ * @param snapshot - the snapshot
657
+ * @param bad - the indices of those ids
658
+ * @param mangle - whether sanitizeIds is "mangle"
659
+ * @param note - the recorder
660
+ * @returns the error the save throws, or null under "mangle"
661
+ */
662
+ function badIdNotes(snapshot, bad, mangle, note) {
663
+ if (mangle) {
664
+ note(LOSS.ID_MANGLED, `${bad.length} node id${plural(bad.length)} that ${agree(bad.length, "is", "are")} not positive integers ${agree(bad.length, "is", "are")} renumbered, since Cytoscape ids are positive integers; the originals are kept in the "${ORIGINAL_ID_ATTRIBUTE}" column (restored by restoreMangledIds)`, null, bad.length);
665
+ return null;
666
+ }
667
+ note(LOSS.ID_CHARSET, `${bad.length} node id${plural(bad.length)} ${agree(bad.length, "is", "are")} not positive integers, which Cytoscape requires; the save fails unless sanitizeIds is "mangle"`, null, bad.length);
668
+ const first = snapshot.ids.idOf(bad[0]);
669
+ return new GraphFormatError("E_INVALID_ID", `${bad.length} node id${plural(bad.length)} cannot be written as Cytoscape ids, which are positive integers (first: ${JSON.stringify(first)} at index ${bad[0]}); pass sanitizeIds: "mangle" to rewrite them`, { reason: "charset", charset: "integer", count: bad.length, index: bad[0] });
670
+ }
671
+ /**
672
+ * The SUIDs: node ids that are positive integers keep them, the others get new ones (or refuse
673
+ * under sanitizeIds "error"); edge ids likewise, from the id role column. Every new SUID comes
674
+ * from one counter above the kept ones.
675
+ * @param snapshot - the snapshot
676
+ * @param common - the resolved common options
677
+ * @param note - the recorder
678
+ * @returns the SUIDs
679
+ */
680
+ function planIds(snapshot, common, note) {
681
+ const { kept, bad } = keptNodeSuids(snapshot);
682
+ const collision = idTextNotes(snapshot, note);
683
+ const charset = bad.length > 0 ? badIdNotes(snapshot, bad, common.sanitizeIds === "mangle", note) : null;
684
+ const fatal = collision ?? charset;
685
+ const nodeSet = new Set(kept.filter((s) => s > 0));
686
+ const edgeKept = keptEdgeSuids(snapshot, nodeSet);
687
+ let next = 1;
688
+ for (const s of [...nodeSet, ...edgeKept]) {
689
+ next = Math.max(next, s + 1);
690
+ }
691
+ const nodeSuids = kept.map((s) => (s > 0 ? s : next++));
692
+ const idColumn = snapshot.edges.byRole("id");
693
+ let generated = 0;
694
+ const edgeSuids = edgeKept.map((s) => {
695
+ if (s > 0) {
696
+ return s;
697
+ }
698
+ generated++;
699
+ return next++;
700
+ });
701
+ if (idColumn !== null && generated > 0) {
702
+ note(LOSS.EDGE_IDS_GENERATED, `${generated} edge${plural(generated)} ${agree(generated, "has", "have")} no distinct positive integer id in "${idColumn.meta.name}"; they are written with new positive integer ids`, idColumn.meta.name, generated);
703
+ }
704
+ if (idColumn !== null && idColumn.dtype !== "string") {
705
+ note(LOSS.DTYPE, `edge id column "${idColumn.meta.name}" is ${idColumn.dtype}; edge ids read back as text`, idColumn.meta.name, snapshot.edgeCount - idColumn.nullCount);
706
+ }
707
+ return { nodeSuids, edgeSuids, next, fatal, mangled: common.sanitizeIds === "mangle" && bad.length > 0 };
708
+ }
709
+ /**
710
+ * The columns of the network's own table: its name (from meta.name unless a text graph column
711
+ * holds it), its description, and the graph columns.
712
+ * @param snapshot - the snapshot
713
+ * @param name - the network name
714
+ * @returns the candidates
715
+ */
716
+ function networkCandidates(snapshot, name) {
717
+ const out = [];
718
+ const graphName = snapshot.graph.get("name");
719
+ if (graphName === null || (graphName.dtype !== "string" && graphName.dtype !== "dict")) {
720
+ out.push({ name: "name", source: null, javaClass: STRING, cell: () => name });
721
+ }
722
+ const { description } = snapshot.meta;
723
+ if (description !== null && snapshot.graph.get("description") === null) {
724
+ out.push({ name: "description", source: null, javaClass: STRING, cell: () => description });
725
+ }
726
+ for (const column of snapshot.graph) {
727
+ out.push(candidateOf(column, column.meta.name));
728
+ }
729
+ return out;
730
+ }
731
+ /**
732
+ * Plan an export: the notes, the fatal condition, the SUIDs and the tables.
733
+ * @param snapshot - the snapshot
734
+ * @param common - the resolved common options
735
+ * @returns the plan
736
+ */
737
+ function plan(snapshot, common) {
738
+ const notes = [];
739
+ const note = (code, message, column = null, count = null) => {
740
+ notes.push(Object.freeze({ code, message, column, count }));
741
+ };
742
+ for (const gen of checkCapabilities(snapshot, CYS_CAPABILITIES, common, {
743
+ roles: SLOT_ROLES,
744
+ roleNames: ROLE_NAMES,
745
+ positionDtype: "f32",
746
+ })) {
747
+ // json is reported per column below; ids by the SUID rule (positive integers)
748
+ if (gen.code !== LOSS.JSON && gen.code !== LOSS.ID_CHARSET && gen.code !== LOSS.ID_MANGLED) {
749
+ notes.push(gen);
750
+ }
751
+ }
752
+ const ids = planIds(snapshot, common, note);
753
+ const { nodeSuids, edgeSuids, mangled, fatal } = ids;
754
+ let { next } = ids;
755
+ const rootSuid = next++;
756
+ const subSuid = next++;
757
+ // direction
758
+ const folding = pairFolding(snapshot);
759
+ if (folding.mutualCount > 0) {
760
+ note(LOSS.MUTUAL_EXPANDED, `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two directed edges; the mutual mark is lost`, null, folding.mutualCount);
761
+ }
762
+ // positions
763
+ const position = snapshot.nodes.byRole("position");
764
+ const z = [...snapshot.nodes].find(isZ) ?? null;
765
+ const positionZ = position !== null && z === null;
766
+ if (position !== null) {
767
+ positionNotes(position, z, note);
768
+ }
769
+ const placed = (position !== null && position.nullCount < position.length) || (z !== null && z.nullCount < z.length);
770
+ const viewSuid = placed ? next++ : null;
771
+ const viewNodeBase = next;
772
+ // node table
773
+ const nodeOwn = mangled
774
+ ? [
775
+ {
776
+ name: ORIGINAL_ID_ATTRIBUTE,
777
+ source: null,
778
+ javaClass: STRING,
779
+ // every node carries its original, so an empty id ("") is told apart from an unset cell
780
+ cell: (row) => String(snapshot.ids.idOf(row)),
781
+ },
782
+ ]
783
+ : [];
784
+ const nodeTable = planTable("node", elementCandidates(snapshot, "node", nodeOwn, (c) => placed && c === z, note), snapshot.nodeCount, note);
785
+ // edge table
786
+ const weights = explicitWeights(snapshot);
787
+ const plainWeight = snapshot.edges.get("weight");
788
+ if (plainWeight !== null && plainWeight.meta.role === null && !weights.weighted) {
789
+ note(LOSS.WEIGHT_KEY_CLASH, `edge column "weight" reads back as the edge weight`, "weight", null);
790
+ }
791
+ const edgeOwn = weights.weighted
792
+ ? [
793
+ {
794
+ name: "weight",
795
+ source: null,
796
+ javaClass: DOUBLE,
797
+ cell: (e) => (weights.isExplicit(e) ? formatDecimal(weights.value(e)) : null),
798
+ },
799
+ ]
800
+ : [];
801
+ const edgeRows = snapshot.edgeCount;
802
+ const edgeTable = planTable("edge", elementCandidates(snapshot, "edge", edgeOwn, () => false, note), edgeRows, note);
803
+ const name = snapshot.meta.name ?? DEFAULT_NAME;
804
+ const networkTable = planTable("network", networkCandidates(snapshot, name), 1, note);
805
+ const rootTable = [{ name: "name", javaClass: STRING, cell: () => name }];
806
+ return {
807
+ notes,
808
+ fatal,
809
+ nodeSuids,
810
+ edgeSuids,
811
+ rootSuid,
812
+ subSuid,
813
+ viewSuid,
814
+ viewNodeBase,
815
+ name,
816
+ folding,
817
+ nodeTable,
818
+ edgeTable,
819
+ networkTable,
820
+ rootTable,
821
+ position,
822
+ z: placed ? z : null,
823
+ positionZ,
824
+ };
825
+ }
826
+ /**
827
+ * The notes of the position column: its shape, non-finite coordinates, and a z that reads back
828
+ * in the z column.
829
+ * @param position - the position column
830
+ * @param z - the z column, or null
831
+ * @param note - the recorder
832
+ */
833
+ function positionNotes(position, z, note) {
834
+ const { name, components } = position.meta;
835
+ if (components !== 3) {
836
+ note(CYS_LOSS.POSITION, `position column "${name}" has ${components} component${plural(components)} and reads back with 3`, name, null);
837
+ }
838
+ let nonFinite = 0;
839
+ let depth = 0;
840
+ for (let r = 0; r < position.length; r++) {
841
+ if (!position.isSet(r)) {
842
+ continue;
843
+ }
844
+ const xyz = Array.from(position.value(r));
845
+ if (xyz.slice(0, 2).some((v) => !Number.isFinite(v))) {
846
+ nonFinite++;
847
+ }
848
+ else if ((xyz[2] ?? 0) !== 0) {
849
+ depth++;
850
+ }
851
+ }
852
+ if (nonFinite > 0) {
853
+ note(CYS_LOSS.POSITION, `${nonFinite} position${plural(nonFinite)} with a non-finite coordinate ${agree(nonFinite, "is", "are")} not written`, name, nonFinite);
854
+ }
855
+ if (depth > 0) {
856
+ note(CYS_LOSS.POSITION, z === null
857
+ ? `${depth} position${plural(depth)} ${agree(depth, "has", "have")} a z; it is written as the view's z and reads back in the z column`
858
+ : `${depth} position${plural(depth)} ${agree(depth, "has", "have")} a z, but the view's z holds the z column; the position z is lost`, name, depth);
859
+ }
860
+ }
861
+ // ============================================================ writing
862
+ /**
863
+ * Cytoscape's `SessionUtil.escape`: Java's `URLEncoder.encode(text, "UTF-8")` (letters, digits
864
+ * and `.-*_` kept, space as `+`, everything else `%XX`), then `-` as `%2D`.
865
+ * @param text - the text
866
+ * @returns the escaped text
867
+ * @category Plugin helpers
868
+ */
869
+ export function sessionEscape(text) {
870
+ const wellFormed = text.replaceAll(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "�");
871
+ return encodeURIComponent(wellFormed)
872
+ .replaceAll(/[!~'()]/g, (c) => `%${(c.codePointAt(0) ?? 0).toString(16).toUpperCase()}`)
873
+ .replaceAll("%20", "+")
874
+ .replaceAll("-", "%2D");
875
+ }
876
+ /**
877
+ * One CyCSV table (schema version 1): the key column SUID, then the columns.
878
+ * @param title - the table title
879
+ * @param columns - the columns
880
+ * @param rows - the SUID of each row, with its row index
881
+ * @yields the table text
882
+ * @returns nothing
883
+ */
884
+ function* cyTable(title, columns, rows) {
885
+ const line = (cells) => `${cells.map((c) => quoteCsvCell(c)).join(",")}\n`;
886
+ yield line(["CyCSV-Version", "1"]);
887
+ yield line(["SUID", ...columns.map((c) => c.name)]);
888
+ yield line([LONG, ...columns.map((c) => c.javaClass)]);
889
+ yield line(["", ...columns.map(() => "mutable")]);
890
+ yield line([title, ""]);
891
+ for (const [suid, row] of rows) {
892
+ yield line([String(suid), ...columns.map((c) => c.cell(row) ?? "")]);
893
+ }
894
+ }
895
+ /** The XML declaration and the namespaces of a session XGMML document. */
896
+ const XML_DECLARATION = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
897
+ const NAMESPACES = `xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="${XLINK_NAMESPACE}" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cy="${CY_NAMESPACE}" xmlns="${XGMML_NAMESPACE}"`;
898
+ /**
899
+ * The network file: the root network holding the one registered subnetwork, nodes and edges by
900
+ * SUID. No attributes: a 3.x session keeps them in the tables.
901
+ * @param snapshot - the snapshot
902
+ * @param p - the plan
903
+ * @yields the document's text
904
+ * @returns nothing
905
+ */
906
+ function* networkFile(snapshot, p) {
907
+ const label = !hasIllegalXmlChar(p.name) ? ` label="${escapeXmlAttribute(p.name)}"` : "";
908
+ yield XML_DECLARATION;
909
+ yield `<graph id="${p.rootSuid}"${label} directed="${snapshot.directed ? "1" : "0"}" cy:view="0" cy:registered="0" cy:documentVersion="3.0" ${NAMESPACES}>\n`;
910
+ yield ` <att>\n <graph id="${p.subSuid}"${label} cy:registered="1">\n`;
911
+ for (let i = 0; i < snapshot.nodeCount; i++) {
912
+ yield ` <node id="${p.nodeSuids[i]}"/>\n`;
913
+ }
914
+ const { src, dst } = snapshot.edgeList();
915
+ for (let e = 0; e < snapshot.edgeCount; e++) {
916
+ if (p.folding.folded(e)) {
917
+ continue;
918
+ }
919
+ const directed = snapshot.directed && p.folding.sourceDirected(e);
920
+ yield ` <edge id="${p.edgeSuids[e]}" source="${p.nodeSuids[src[e]]}" target="${p.nodeSuids[dst[e]]}" cy:directed="${directed ? "1" : "0"}"/>\n`;
921
+ }
922
+ yield " </graph>\n </att>\n</graph>\n";
923
+ }
924
+ /**
925
+ * The view file: one view node per placed node, x and y (y negated back to screen coordinates)
926
+ * and z.
927
+ * @param snapshot - the snapshot
928
+ * @param p - the plan
929
+ * @param viewSuid - the view's SUID
930
+ * @yields the document's text
931
+ * @returns nothing
932
+ */
933
+ function* viewFile(snapshot, p, viewSuid) {
934
+ yield XML_DECLARATION;
935
+ yield `<graph id="${viewSuid}" label="${viewSuid}" cy:view="1" cy:networkId="${p.subSuid}" cy:visualStyle="default" cy:rendererId="org.cytoscape.ding" cy:documentVersion="3.0" ${NAMESPACES}>\n`;
936
+ let view = p.viewNodeBase;
937
+ for (let i = 0; i < snapshot.nodeCount; i++) {
938
+ const coords = viewCoords(p, i);
939
+ if (coords.length > 0) {
940
+ yield ` <node id="${view++}" cy:nodeId="${p.nodeSuids[i]}">\n <graphics ${coords.join(" ")}/>\n </node>\n`;
941
+ }
942
+ }
943
+ yield "</graph>\n";
944
+ }
945
+ /**
946
+ * The graphics attributes of one node's view: x and y (y down, as Cytoscape draws), and z.
947
+ * @param p - the plan
948
+ * @param i - the node
949
+ * @returns the attributes, none when the node has no position
950
+ */
951
+ function viewCoords(p, i) {
952
+ const coords = [];
953
+ if (p.position?.isSet(i) === true) {
954
+ const [x, y, z] = Array.from(p.position.value(i));
955
+ if (Number.isFinite(x) && Number.isFinite(y)) {
956
+ coords.push(`x="${formatF32(x)}"`, `y="${formatF32(y === 0 ? 0 : -y)}"`);
957
+ }
958
+ if (Number.isFinite(x) &&
959
+ Number.isFinite(y) &&
960
+ p.positionZ &&
961
+ z !== undefined &&
962
+ z !== 0 &&
963
+ Number.isFinite(z)) {
964
+ coords.push(`z="${formatF32(z)}"`);
965
+ }
966
+ }
967
+ if (p.z?.isSet(i) === true) {
968
+ coords.push(`z="${formatDecimal(p.z.value(i))}"`);
969
+ }
970
+ return coords;
971
+ }
972
+ /**
973
+ * The text of string parts, UTF-8 encoded.
974
+ * @param parts - the parts
975
+ * @returns the bytes
976
+ */
977
+ function encode(parts) {
978
+ let text = "";
979
+ for (const part of parts) {
980
+ text += part;
981
+ }
982
+ return new TextEncoder().encode(text);
983
+ }
984
+ /**
985
+ * The archive's entries, each built when the zip writer asks for it.
986
+ * @param snapshot - the snapshot
987
+ * @param p - the plan
988
+ * @yields the entries
989
+ * @returns nothing
990
+ */
991
+ function* entries(snapshot, p) {
992
+ if (p.fatal !== null) {
993
+ throw p.fatal;
994
+ }
995
+ const name = sessionEscape(p.name);
996
+ const tables = `${ROOT_FOLDER}tables/${p.subSuid}-${name}/LOCAL_ATTRS-org.cytoscape.model.`;
997
+ const rowsOf = (suids, skip) => suids.flatMap((suid, row) => (skip?.(row) === true ? [] : [[suid, row]]));
998
+ const nodeTable = `${p.name} default node`;
999
+ const edgeTable = `${p.name} default edge`;
1000
+ const networkTable = `${p.name} default network`;
1001
+ yield { name: `${ROOT_FOLDER}3.0.0.version`, data: new Uint8Array(0) };
1002
+ yield { name: `${ROOT_FOLDER}networks/${p.rootSuid}-${name}.xgmml`, data: encode(networkFile(snapshot, p)) };
1003
+ yield {
1004
+ name: `${tables}CyNode-${sessionEscape(nodeTable)}.cytable`,
1005
+ data: encode(cyTable(nodeTable, p.nodeTable, rowsOf(p.nodeSuids))),
1006
+ };
1007
+ yield {
1008
+ name: `${tables}CyEdge-${sessionEscape(edgeTable)}.cytable`,
1009
+ data: encode(cyTable(edgeTable, p.edgeTable, rowsOf(p.edgeSuids, (e) => p.folding.folded(e)))),
1010
+ };
1011
+ yield {
1012
+ name: `${tables}CyNetwork-${sessionEscape(networkTable)}.cytable`,
1013
+ data: encode(cyTable(networkTable, p.networkTable, [[p.subSuid, 0]])),
1014
+ };
1015
+ yield {
1016
+ name: `${ROOT_FOLDER}tables/${p.rootSuid}-${name}/LOCAL_ATTRS-org.cytoscape.model.CyNetwork-${p.rootSuid}+default+network.cytable`,
1017
+ data: encode(cyTable(`${p.rootSuid} default network`, p.rootTable, [[p.rootSuid, 0]])),
1018
+ };
1019
+ if (p.viewSuid !== null) {
1020
+ yield {
1021
+ name: `${ROOT_FOLDER}views/${p.subSuid}-${p.viewSuid}-${name}.xgmml`,
1022
+ data: encode(viewFile(snapshot, p, p.viewSuid)),
1023
+ };
1024
+ }
1025
+ }
1026
+ /**
1027
+ * The archive as byte chunks.
1028
+ * @param snapshot - the snapshot
1029
+ * @param options - the options
1030
+ * @yields the bytes
1031
+ * @returns nothing
1032
+ */
1033
+ async function* write(snapshot, options) {
1034
+ const p = plan(snapshot, resolveExportOptions(options));
1035
+ await Promise.resolve();
1036
+ yield* writeZip(entries(snapshot, p));
1037
+ }
1038
+ /**
1039
+ * The Cytoscape session exporter.
1040
+ * @category Built-in formats
1041
+ */
1042
+ export const cysExporter = Object.freeze({
1043
+ format: FORMAT,
1044
+ options: Object.freeze([]),
1045
+ capabilities: CYS_CAPABILITIES,
1046
+ /**
1047
+ * Pre-flight: what export() would lose, without writing anything.
1048
+ * @param snapshot - the snapshot
1049
+ * @param options - the common options
1050
+ * @returns the notes, empty when the export is exact
1051
+ */
1052
+ check(snapshot, options) {
1053
+ return Object.freeze([...plan(snapshot, resolveExportOptions(options)).notes]);
1054
+ },
1055
+ /**
1056
+ * Write the session as zip bytes (stored entries, one at a time).
1057
+ * @param snapshot - the snapshot
1058
+ * @param options - the common options
1059
+ * @returns the bytes
1060
+ */
1061
+ export(snapshot, options) {
1062
+ return write(snapshot, options);
1063
+ },
1064
+ /**
1065
+ * A session is a zip archive, not text: always rejects with E_UNSUPPORTED (use exportGraphToBytes() or exportGraphToBlob()).
1066
+ * @returns never
1067
+ */
1068
+ exportToString() {
1069
+ return Promise.reject(new GraphFormatError("E_UNSUPPORTED", "a Cytoscape session is a zip file, not text; use exportGraphToBytes() or exportGraphToBlob()", { reason: "binary" }));
1070
+ },
1071
+ });
1072
+ //# sourceMappingURL=exporter.js.map