@graphty/graph-io 0.3.25 → 0.3.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-DrXtu_96.js +56 -0
  4. package/dist/chunks/choose-DrXtu_96.js.map +1 -0
  5. package/dist/chunks/constants-ikG85dT8.js +231 -0
  6. package/dist/chunks/constants-ikG85dT8.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D1HPTUrP.js} +390 -99
  8. package/dist/chunks/escape-D1HPTUrP.js.map +1 -0
  9. package/dist/chunks/export-CHd4tQE2.js +4333 -0
  10. package/dist/chunks/export-CHd4tQE2.js.map +1 -0
  11. package/dist/chunks/{importer-eUREhBGj.js → exporter-D23CKNqF.js} +4969 -3201
  12. package/dist/chunks/exporter-D23CKNqF.js.map +1 -0
  13. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-DfWTgrti.js} +23 -21
  14. package/dist/chunks/exporter-DfWTgrti.js.map +1 -0
  15. package/dist/chunks/exporter-DhtW6FxK.js +3465 -0
  16. package/dist/chunks/exporter-DhtW6FxK.js.map +1 -0
  17. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-IHv4nkCm.js} +38 -229
  18. package/dist/chunks/exporter-IHv4nkCm.js.map +1 -0
  19. package/dist/chunks/{importer-BWY2FFc5.js → importer-B1wmPQjr.js} +255 -77
  20. package/dist/chunks/importer-B1wmPQjr.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-B2W_58pz.js} +399 -146
  22. package/dist/chunks/importer-B2W_58pz.js.map +1 -0
  23. package/dist/chunks/importer-BSALvkui.js +2811 -0
  24. package/dist/chunks/importer-BSALvkui.js.map +1 -0
  25. package/dist/chunks/{importer-vi3bSdtw.js → importer-BVRE--Un.js} +510 -77
  26. package/dist/chunks/importer-BVRE--Un.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-CIAzt-wo.js} +1689 -312
  28. package/dist/chunks/importer-CIAzt-wo.js.map +1 -0
  29. package/dist/chunks/{importer-DIrbbnAf.js → importer-DpEW5zeG.js} +585 -226
  30. package/dist/chunks/importer-DpEW5zeG.js.map +1 -0
  31. package/dist/chunks/{importer-zGLo8Dg_.js → importer-z_FL4VMb.js} +488 -161
  32. package/dist/chunks/importer-z_FL4VMb.js.map +1 -0
  33. package/dist/chunks/json-elements-BAmNBZok.js +1225 -0
  34. package/dist/chunks/json-elements-BAmNBZok.js.map +1 -0
  35. package/dist/chunks/ontology-export-Bab4eUA8.js +357 -0
  36. package/dist/chunks/ontology-export-Bab4eUA8.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CdlvL4RO.js} +298 -114
  38. package/dist/chunks/records-CdlvL4RO.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DzXjAiTl.js} +29 -11
  40. package/dist/chunks/text-DzXjAiTl.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +952 -262
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +344 -87
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +565 -158
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +21 -3
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +39 -22
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +869 -189
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +3 -1
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +402 -85
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +146 -33
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +682 -287
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +227 -80
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +101 -27
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +110 -28
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +239 -86
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +67 -35
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +186 -54
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +21 -22
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +8 -3
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +40 -6
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +39 -22
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1035 -199
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +7 -2
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +479 -90
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +202 -47
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +890 -302
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +62 -339
  498. package/src/formats/cx2/importer.ts +318 -87
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +142 -34
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +113 -28
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +321 -102
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +90 -42
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +216 -55
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +36 -28
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +12 -4
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -0,0 +1,1217 @@
1
+ /**
2
+ * The CX version 1 exporter (design/graph-io/cytoscape-and-obo/design.md section 1.2): writes a
3
+ * snapshot as the NDEx form of a CX document -- one network with at most one view, no
4
+ * `cySubNetworks` -- which NDEx, ndex2 and Cytoscape's CX import all read.
5
+ *
6
+ * Aspects, in the order Cytoscape and NDEx write them: `numberVerification`, the pre-`metaData`
7
+ * (element counts, `idCounter` on nodes, edges, citations and supports), `nodes` (`n` the label,
8
+ * `r` the `represents` column), `edges` (`i` the `interaction` column), `nodeAttributes`,
9
+ * `edgeAttributes` and `networkAttributes` (values as JSON strings, the spec's form), `cyTableColumn`
10
+ * (so a column no element fills is still declared), `cartesianLayout` (y negated back to screen
11
+ * coordinates), `cyGroups` from the parent / parents column, `cyVisualProperties` from the
12
+ * `cx.bypass` columns, the provenance aspects a CX import created, the style rules and unknown
13
+ * aspects a CX import kept, and `status`.
14
+ *
15
+ * What CX cannot hold is announced by check() before anything is written: every edge is directed
16
+ * (W_CX_UNDIRECTED_AS_DIRECTED, W_MUTUAL_EXPANDED), node ids are integers (E_ID_CHARSET unless
17
+ * `sanitizeIds: "mangle"`, which keeps the original in the `graphty:originalId` attribute the
18
+ * importer restores), nested values are written as JSON text (W_CX_JSON_AS_STRING), and the generic
19
+ * notes of checkCapabilities(). NaN and the infinities are written as "NaN" / "Infinity" in double
20
+ * attributes, which read back as they were.
21
+ */
22
+ import { GraphFormatError } from "@graphty/graph-format";
23
+ import { childrenCsr } from "../../children.js";
24
+ import { aspectBlock, declaredType, directionNotes, nextNodeId, noteList, planEdgeIds, planNodeIds, stringify, } from "../../common/cx-export.js";
25
+ import { pairFolding } from "../../common/direction.js";
26
+ import { capabilities, checkCapabilities, LOSS } from "../../common/export.js";
27
+ import { isRecord, POSITION_COLUMN } from "../../common/json-elements.js";
28
+ import { resolveExportOptions } from "../../common/options.js";
29
+ import { plural } from "../../common/plural.js";
30
+ import { explicitWeights } from "../../common/weights.js";
31
+ import { encodeChunks, joinText } from "../../common/writer.js";
32
+ import { ORIGINAL_ID_ATTRIBUTE } from "../cx2/importer.js";
33
+ /** The format name. */
34
+ const CX_FORMAT = "cx";
35
+ /**
36
+ * The loss notes the CX exporter's check() returns, by name. A key is the code without its
37
+ * severity and format prefixes.
38
+ * @category Built-in formats
39
+ */
40
+ export const CX_LOSS = Object.freeze({
41
+ /**
42
+ * Every edge is written as directed, so an undirected graph, or the undirected edges of a mixed graph, read back
43
+ * as directed.
44
+ */
45
+ UNDIRECTED_AS_DIRECTED: "W_CX_UNDIRECTED_AS_DIRECTED",
46
+ /** A nested (json) column is written as a string attribute holding its JSON text. */
47
+ JSON_AS_STRING: "W_CX_JSON_AS_STRING",
48
+ /** A mutual pair is written as two directed edges without its mark. */
49
+ MUTUAL_EXPANDED: LOSS.MUTUAL_EXPANDED,
50
+ /**
51
+ * An attribute named `weight` without the weight role reads back as the edge weight, or is not written when the
52
+ * graph has weights of its own.
53
+ */
54
+ WEIGHT_KEY_CLASH: LOSS.WEIGHT_KEY_CLASH,
55
+ /** A start / end / timestamp column: CX has no time. */
56
+ TEMPORAL_DROPPED: LOSS.TEMPORAL,
57
+ /** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */
58
+ ROLE_DROPPED: LOSS.ROLE,
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
+ /**
65
+ * An attribute type CX stores as another (a 32-bit float as double, an unsigned integer as long, a byte as
66
+ * integer, a dictionary as string); it reads back with that type.
67
+ */
68
+ DTYPE_UNSUPPORTED: LOSS.DTYPE,
69
+ /** A multi-component column (a second view's `position@2`, a vector) is written as a list of doubles. */
70
+ COMPONENTS_FLATTENED: LOSS.COMPONENTS,
71
+ /** A declared default: CX has none. */
72
+ DEFAULT_DROPPED: LOSS.DEFAULT,
73
+ /** Declared options: CX has no enumerations. */
74
+ OPTIONS_DROPPED: LOSS.OPTIONS,
75
+ /**
76
+ * Node ids the format cannot write, under `sanitizeIds: "error"`; the save fails with E_INVALID_ID. Pass
77
+ * `sanitizeIds: "mangle"` to rewrite them.
78
+ */
79
+ ID_CHARSET: LOSS.ID_CHARSET,
80
+ /** Node ids that are not integers under sanitizeIds "mangle": renumbered, originals kept. */
81
+ ID_MANGLED: LOSS.ID_MANGLED,
82
+ /** Edges without a usable integer id get generated ids. */
83
+ EDGE_IDS_GENERATED: LOSS.EDGE_IDS_GENERATED,
84
+ /**
85
+ * An attribute with a role (for example, the label) is written where the format keeps that role, and reads back under the
86
+ * name the format's importer gives it.
87
+ */
88
+ COLUMN_NAME_CHANGED: LOSS.COLUMN_NAME_CHANGED,
89
+ /** An extension table other than the `cx:citations` / `cx:supports` tables a CX import creates. */
90
+ EXTENSION_TABLE_DROPPED: LOSS.EXTENSION_TABLE,
91
+ /** A position, stacking order or weight that is NaN or infinite: CX spells no such number there. */
92
+ NONFINITE_AS_NULL: LOSS.NONFINITE_AS_NULL,
93
+ /** Visual columns (color, size, shape, thickness roles): CX keeps style as visual properties, not roles. */
94
+ VIZ_DROPPED: LOSS.VIZ,
95
+ });
96
+ /**
97
+ * What CX version 1 keeps: directed multigraphs with self-loops, integer node ids, required
98
+ * integer edge ids, typed string / double / integer / boolean attributes and lists of them, network
99
+ * attributes, the position role (one view), and containment as `cyGroups`. f32, u32, u8 and dict
100
+ * columns are written as the nearest declared type and read back as it.
101
+ * @category Built-in formats
102
+ */
103
+ export const CX_CAPABILITIES = capabilities({
104
+ mixedDirection: false,
105
+ multiEdges: true,
106
+ selfLoops: true,
107
+ edgeIds: "required",
108
+ idCharset: "integer",
109
+ dtypes: ["string", "f64", "i32", "bool"],
110
+ components: false,
111
+ lists: true,
112
+ json: false,
113
+ defaults: false,
114
+ options: false,
115
+ hierarchy: true,
116
+ temporal: "none",
117
+ graphAttributes: true,
118
+ positions: true,
119
+ viz: false,
120
+ });
121
+ /** The roles CX has a slot for, and the column names its importer gives them. */
122
+ const SLOT_ROLES = new Set(["label", "position", "id"]);
123
+ const ROLE_NAMES = Object.freeze({
124
+ label: "name",
125
+ position: POSITION_COLUMN,
126
+ id: "id",
127
+ parent: "parent",
128
+ });
129
+ /** Roles whose columns are never written as attributes. */
130
+ const SKIPPED_ROLES = new Set([
131
+ "directed",
132
+ "pair",
133
+ "mutual",
134
+ "weight",
135
+ "timeText",
136
+ "originalId",
137
+ "parent",
138
+ "parents",
139
+ "start",
140
+ "end",
141
+ "timestamp",
142
+ "timestamps",
143
+ "spells",
144
+ "open",
145
+ "spellsOpen",
146
+ "position",
147
+ "color",
148
+ "size",
149
+ "shape",
150
+ "thickness",
151
+ "id",
152
+ ]);
153
+ /** The origin namespace of the per-element visual property columns of a CX import. */
154
+ const BYPASS_NAMESPACE = "cx.bypass";
155
+ /** The extension tables a CX import creates from the citations and supports aspects. */
156
+ const PROVENANCE_TABLES = Object.freeze({
157
+ "cx:citations": "citations",
158
+ "cx:supports": "supports",
159
+ });
160
+ /**
161
+ * Kept aspects never written back: they describe the collection, views and SUIDs of the file the
162
+ * snapshot came from, or are written by the exporter itself.
163
+ */
164
+ const NEVER_WRITTEN = new Set([
165
+ "nodes",
166
+ "edges",
167
+ "nodeAttributes",
168
+ "edgeAttributes",
169
+ "networkAttributes",
170
+ "cartesianLayout",
171
+ "cyGroups",
172
+ "cyVisualProperties",
173
+ "cyTableColumn",
174
+ "cySubNetworks",
175
+ "cyNetworkRelations",
176
+ "cyViews",
177
+ "CX Element ID",
178
+ "citations",
179
+ "supports",
180
+ "nodeCitations",
181
+ "edgeCitations",
182
+ "nodeSupports",
183
+ "edgeSupports",
184
+ "functionTerms",
185
+ "reifiedEdges",
186
+ "numberVerification",
187
+ "metaData",
188
+ "status",
189
+ "groups",
190
+ "subnetwork",
191
+ ]);
192
+ /** The weight attribute name (the CX importer's weightFrom default). */
193
+ const WEIGHT_ATTRIBUTE = "weight";
194
+ /** The dtypes a plain `weight` column may have to be written as the weight. */
195
+ const NUMERIC_DTYPES = new Set(["f32", "f64", "i32", "u32", "u8"]);
196
+ /**
197
+ * Whether a column was created by the CX importer in an origin namespace.
198
+ * @param column - the column
199
+ * @param namespace - the namespace
200
+ * @returns true when it was
201
+ */
202
+ function fromCx(column, namespace) {
203
+ return column.meta.origin?.format === CX_FORMAT && column.meta.origin.namespace === namespace;
204
+ }
205
+ /**
206
+ * Whether a column is a bypass column of a CX import.
207
+ * @param column - the column
208
+ * @returns true for the cx.bypass namespace
209
+ */
210
+ function isBypass(column) {
211
+ return column.meta.origin?.namespace === BYPASS_NAMESPACE;
212
+ }
213
+ /**
214
+ * Whether a column is the z (stacking order) column.
215
+ * @param column - the column
216
+ * @returns true for the column marked by a Cytoscape-family importer
217
+ */
218
+ function isZ(column) {
219
+ return column.meta.extra.cytoscape === "z";
220
+ }
221
+ /**
222
+ * Whether a column is a provenance list column (citations / supports) of a CX import.
223
+ * @param column - the column
224
+ * @returns true for one
225
+ */
226
+ function isLink(column) {
227
+ return (fromCx(column, "provenance") &&
228
+ column.meta.dtype === "list" &&
229
+ (column.meta.name === "citations" || column.meta.name === "supports"));
230
+ }
231
+ /**
232
+ * Whether a column holds a text the core fields (n, r, i) cannot hold as itself.
233
+ * @param column - the column
234
+ * @returns true for every dtype but string (dict and json have their own notes)
235
+ */
236
+ function coreNeedsText(column) {
237
+ const { dtype } = column.meta;
238
+ return dtype !== "string" && dtype !== "dict" && dtype !== "json";
239
+ }
240
+ /**
241
+ * The notes of checkCapabilities(), adapted to CX: json columns are written as JSON text, the id
242
+ * notes are counted by planNodeIds(), the provenance tables and columns a CX import made are
243
+ * written back.
244
+ * @param snapshot - the snapshot
245
+ * @param common - the resolved common options
246
+ * @param several - whether the parents column gives some node several parents
247
+ * @param own - the functionTerm and reifiedEdge columns written as their own aspects
248
+ * @param notes - the notes so far
249
+ * @param note - records a note
250
+ * @returns the error export() throws for mixed direction, or null
251
+ */
252
+ function genericNotes(snapshot, common, several, own, notes, note) {
253
+ let fatal = null;
254
+ const edgeLabel = snapshot.edges.byRole("label")?.meta.name;
255
+ const ownNames = new Set(own.filter((c) => c !== null).map((c) => c.meta.name));
256
+ for (const gen of checkCapabilities(snapshot, CX_CAPABILITIES, common, {
257
+ roles: SLOT_ROLES,
258
+ // a parents column reads back as parents only when some node has several parents
259
+ roleNames: several ? { ...ROLE_NAMES, parents: "parents" } : ROLE_NAMES,
260
+ })) {
261
+ if (writtenOtherwise(gen, ownNames)) {
262
+ continue;
263
+ }
264
+ if (gen.code === LOSS.JSON) {
265
+ const which = gen.column === null ? "a column" : `column "${gen.column}"`;
266
+ note(CX_LOSS.JSON_AS_STRING, `${which} holds nested values; written as a string attribute holding their JSON text`, gen.column, gen.count);
267
+ continue;
268
+ }
269
+ if (isEdgeLabelRename(gen, edgeLabel)) {
270
+ // only nodes have a label slot (n); an edge label is a plain attribute
271
+ note(LOSS.ROLE, `edge column "${edgeLabel ?? ""}" (label) is written as a plain attribute; CX edges have no label slot and the role is lost`, gen.column, gen.count);
272
+ continue;
273
+ }
274
+ if (gen.code === LOSS.MIXED_DIRECTION_ERROR && fatal === null) {
275
+ fatal = new GraphFormatError("E_DIRECTED", gen.message, { reason: "mixed direction" });
276
+ }
277
+ notes.push(gen);
278
+ }
279
+ if (edgeLabel === "name") {
280
+ note(LOSS.ROLE, `edge column "name" (label) is written as a plain attribute; CX edges have no label slot and the role is lost`, "name", null);
281
+ }
282
+ return fatal;
283
+ }
284
+ /**
285
+ * Whether a generic note is about something CX writes another way: the functionTerm and
286
+ * reifiedEdge columns (their own aspects), ids (counted by planNodeIds(), since CX also keeps
287
+ * integer ids beyond 2^53, which the generic rule refuses) and the provenance tables.
288
+ * @param gen - the generic note
289
+ * @param ownNames - the names of the columns written as their own aspects
290
+ * @returns true when the note does not apply
291
+ */
292
+ function writtenOtherwise(gen, ownNames) {
293
+ if (gen.column !== null && ownNames.has(gen.column) && (gen.code === LOSS.JSON || gen.code === LOSS.DTYPE)) {
294
+ return true;
295
+ }
296
+ if (gen.code === LOSS.ID_CHARSET || gen.code === LOSS.ID_MANGLED) {
297
+ return true;
298
+ }
299
+ return gen.code === LOSS.EXTENSION_TABLE && gen.column !== null && gen.column in PROVENANCE_TABLES;
300
+ }
301
+ /**
302
+ * Whether a generic note is the rename of the edge label column.
303
+ * @param gen - the generic note
304
+ * @param edgeLabel - the edge label column's name, if any
305
+ * @returns true when it is
306
+ */
307
+ function isEdgeLabelRename(gen, edgeLabel) {
308
+ return gen.code === LOSS.COLUMN_NAME_CHANGED && gen.column === edgeLabel && gen.message.startsWith("edge column");
309
+ }
310
+ /**
311
+ * The node positions to write: the position column, the z column (when it fits the layout), whether
312
+ * the position's third coordinate is written as z, and the count of non-finite values left out.
313
+ * @param snapshot - the snapshot
314
+ * @param note - records a note
315
+ * @returns the position plan
316
+ */
317
+ function planPositions(snapshot, note) {
318
+ const position = snapshot.nodes.byRole("position");
319
+ const zColumn = [...snapshot.nodes].find(isZ) ?? null;
320
+ const z = zColumn !== null && zFitsLayout(zColumn, position) ? zColumn : null;
321
+ if (position === null) {
322
+ return { position, z, positionZ: false, nonfinite: 0 };
323
+ }
324
+ let nonfinite = nonFiniteCells(position, (v) => [v[0], v[1]]);
325
+ const depth = nonFiniteCells(position, (v) => (v[2] === 0 ? [] : [Number.NaN]));
326
+ const positionZ = zColumn === null && (position.meta.extra.sourceDims === 3 || depth > 0);
327
+ if (positionZ) {
328
+ nonfinite += nonFiniteCells(position, (v) => (Number.isFinite(v[0]) && Number.isFinite(v[1]) ? [v[2]] : []));
329
+ note(LOSS.COMPONENTS, `node column "${position.meta.name}" (position) has a third coordinate; CX writes it as the layout's z, which reads back in the z column (a stacking order), not in the position`, position.meta.name, depth);
330
+ }
331
+ return { position, z, positionZ, nonfinite };
332
+ }
333
+ /**
334
+ * Note the graph columns that read back as the graph's name or description.
335
+ * @param snapshot - the snapshot
336
+ * @param note - records a note
337
+ */
338
+ function graphColumnNotes(snapshot, note) {
339
+ for (const c of snapshot.graph) {
340
+ const named = c.meta.name === "name" || c.meta.name === "description";
341
+ if (!isBypass(c) && named && (c.dtype === "string" || c.dtype === "dict")) {
342
+ note(LOSS.ROLE_ASSUMED, `graph column "${c.meta.name}" is written as the network attribute ${c.meta.name}, which reads back as the graph's ${c.meta.name}, not as a column`, c.meta.name, null);
343
+ }
344
+ }
345
+ }
346
+ /**
347
+ * Plan an export: the notes, the fatal condition and what is written.
348
+ * @param snapshot - the snapshot
349
+ * @param common - the resolved common options
350
+ * @returns the plan
351
+ */
352
+ function plan(snapshot, common) {
353
+ const { notes, note } = noteList();
354
+ const functionTerm = [...snapshot.nodes].find((c) => fromCx(c, "provenance") && c.meta.name === "functionTerm") ?? null;
355
+ const reifiedEdge = [...snapshot.nodes].find((c) => fromCx(c, "reifiedEdges") && c.dtype === "u32") ?? null;
356
+ const children = childrenCsr(snapshot);
357
+ const several = children.column?.meta.role === "parents" && severalParents(children.column);
358
+ let fatal = genericNotes(snapshot, common, several, [functionTerm, reifiedEdge], notes, note);
359
+ const folding = pairFolding(snapshot);
360
+ directionNotes(snapshot, folding, common, CX_LOSS.UNDIRECTED_AS_DIRECTED, note);
361
+ const planned = planNodeIds(snapshot, common, "CX", ORIGINAL_ID_ATTRIBUTE, note);
362
+ const ids = planned instanceof GraphFormatError ? null : planned;
363
+ if (planned instanceof GraphFormatError) {
364
+ fatal ?? (fatal = planned);
365
+ }
366
+ const edgeIds = planEdgeIds(snapshot, note);
367
+ if (snapshot.nodes.has(ORIGINAL_ID_ATTRIBUTE)) {
368
+ note(LOSS.ROLE_ASSUMED, `node column "${ORIGINAL_ID_ATTRIBUTE}" is the importer's record of mangled ids: it reads back as the node ids unless restoreMangledIds is false`, ORIGINAL_ID_ATTRIBUTE, null);
369
+ }
370
+ // nodes: n, r, the z column, the groups' collapsed flags, provenance
371
+ const positions = planPositions(snapshot, note);
372
+ const { position, z, positionZ } = positions;
373
+ let { nonfinite } = positions;
374
+ const collapsed = [...snapshot.nodes].find((c) => fromCx(c, "cyGroups") && c.dtype === "bool") ?? null;
375
+ const nodeCore = corePlans(snapshot, note);
376
+ const edgeCore = [];
377
+ const interaction = snapshot.edges.get("interaction");
378
+ if (interaction !== null && (interaction.meta.role === null || !SKIPPED_ROLES.has(interaction.meta.role))) {
379
+ edgeCore.push({ key: "i", column: interaction });
380
+ coreTextNote(interaction, "edge", note);
381
+ }
382
+ const coreColumns = new Set([...nodeCore, ...edgeCore].map((c) => c.column));
383
+ const special = (c) => coreColumns.has(c) ||
384
+ isBypass(c) ||
385
+ isLink(c) ||
386
+ c === z ||
387
+ c === collapsed ||
388
+ c === functionTerm ||
389
+ c === reifiedEdge ||
390
+ (c.meta.role !== null && SKIPPED_ROLES.has(c.meta.role));
391
+ const label = snapshot.nodes.byRole("label");
392
+ const renamedName = label !== null && label.meta.name !== "name" ? snapshot.nodes.get("name") : null;
393
+ if (renamedName !== null) {
394
+ note(LOSS.COLUMN_NAME_CHANGED, `node column "name" is written as the attribute "name#2": the label column "${label?.meta.name ?? ""}" is written as n, which reads back as "name"`, "name", renamedName.length - renamedName.nullCount);
395
+ }
396
+ const nodeAttrs = attributePlans(snapshot.nodes, special, (c) => (c === renamedName ? "name#2" : c.meta.name));
397
+ const weight = planWeight(snapshot, folding, note);
398
+ const plainWeight = snapshot.edges.get(WEIGHT_ATTRIBUTE);
399
+ const edgeAttrs = attributePlans(snapshot.edges, (c) => special(c) || (c === plainWeight && c.meta.role === null), (c) => c.meta.name);
400
+ nonfinite += weight.nonfinite;
401
+ graphColumnNotes(snapshot, note);
402
+ const graphAttrs = attributePlans(snapshot.graph, isBypass, (c) => c.meta.name);
403
+ if (children.column !== null && children.column.meta.role === "parents" && !several) {
404
+ note(LOSS.COLUMN_NAME_CHANGED, `node column "${children.column.meta.name}" (parents) holds at most one parent per node; it reads back as the single-parent column "parent"`, children.column.meta.name, children.column.length - children.column.nullCount);
405
+ }
406
+ if (nonfinite > 0) {
407
+ note(LOSS.NONFINITE_AS_NULL, `${nonfinite} NaN or infinite position${plural(nonfinite)}, stacking orders or weights cannot be written in CX; they read back unset`, null, nonfinite);
408
+ }
409
+ return {
410
+ notes,
411
+ fatal,
412
+ ids,
413
+ folding,
414
+ edgeIds,
415
+ weight: weight.plan,
416
+ nodeCore,
417
+ edgeCore,
418
+ nodeAttrs,
419
+ edgeAttrs,
420
+ graphAttrs,
421
+ position,
422
+ positionZ,
423
+ z,
424
+ bypass: {
425
+ node: [...snapshot.nodes].filter(isBypass),
426
+ edge: [...snapshot.edges].filter(isBypass),
427
+ graph: [...snapshot.graph].filter(isBypass),
428
+ },
429
+ collapsed,
430
+ links: linkPlans(snapshot),
431
+ functionTerm,
432
+ reifiedEdge,
433
+ };
434
+ }
435
+ /**
436
+ * The node core fields: n from the label column (else a plain `name` column, which then reads back
437
+ * as the label), r from a `represents` column.
438
+ * @param snapshot - the snapshot
439
+ * @param note - records a note
440
+ * @returns the plans
441
+ */
442
+ function corePlans(snapshot, note) {
443
+ const out = [];
444
+ const label = snapshot.nodes.byRole("label");
445
+ const plainName = snapshot.nodes.get("name");
446
+ const n = label ?? (plainName !== null && plainName.meta.role === null ? plainName : null);
447
+ if (n !== null) {
448
+ out.push({ key: "n", column: n });
449
+ coreTextNote(n, "node", note);
450
+ if (n !== label) {
451
+ note(LOSS.ROLE_ASSUMED, `node column "name" is written as n and reads back as the label`, "name", n.length - n.nullCount);
452
+ }
453
+ }
454
+ const represents = snapshot.nodes.get("represents");
455
+ if (represents !== null &&
456
+ represents !== n &&
457
+ (represents.meta.role === null || !SKIPPED_ROLES.has(represents.meta.role))) {
458
+ out.push({ key: "r", column: represents });
459
+ coreTextNote(represents, "node", note);
460
+ }
461
+ return out;
462
+ }
463
+ /**
464
+ * The note of a core field column that is not text: n, r and i are strings in CX.
465
+ * @param column - the column
466
+ * @param domain - node or edge
467
+ * @param note - records a note
468
+ */
469
+ function coreTextNote(column, domain, note) {
470
+ if (coreNeedsText(column)) {
471
+ note(LOSS.DTYPE, `${domain} column "${column.meta.name}" is ${column.dtype}; CX writes it as text and it reads back as string`, column.meta.name, column.length - column.nullCount);
472
+ }
473
+ }
474
+ /**
475
+ * The attribute plans of one table.
476
+ * @param table - the table
477
+ * @param skip - columns not written as attributes
478
+ * @param rename - the written name of a column
479
+ * @returns the plans
480
+ */
481
+ function attributePlans(table, skip, rename) {
482
+ return [...table]
483
+ .filter((c) => !skip(c))
484
+ .map((column) => ({ column, name: rename(column), d: declaredType(column) }));
485
+ }
486
+ /**
487
+ * The weights to write: the explicit weights, else a plain numeric `weight` column (which then
488
+ * reads back as THE weight); a plain `weight` column that is not written is noted.
489
+ * @param snapshot - the snapshot
490
+ * @param folding - the pair folding
491
+ * @param note - records a note
492
+ * @returns the plan, or null for no weight attribute, and the count of non-finite weights skipped
493
+ */
494
+ function planWeight(snapshot, folding, note) {
495
+ const weights = explicitWeights(snapshot);
496
+ const plain = snapshot.edges.get(WEIGHT_ATTRIBUTE);
497
+ const clash = plain !== null && plain.meta.role === null;
498
+ let plan = null;
499
+ if (weights.weighted) {
500
+ plan = { value: (e) => (weights.isExplicit(e) ? weights.value(e) : undefined) };
501
+ if (clash) {
502
+ note(LOSS.WEIGHT_KEY_CLASH, `edge column "${WEIGHT_ATTRIBUTE}" is not written: the explicit weights are written under that name`, WEIGHT_ATTRIBUTE, null);
503
+ }
504
+ }
505
+ else if (clash) {
506
+ const numeric = NUMERIC_DTYPES.has(plain.dtype);
507
+ note(LOSS.WEIGHT_KEY_CLASH, numeric
508
+ ? `edge column "${WEIGHT_ATTRIBUTE}" is written as the weight attribute and reads back as the edge weight`
509
+ : `edge column "${WEIGHT_ATTRIBUTE}" is ${plain.dtype}, and CX reads that attribute as the edge weight; it is not written`, WEIGHT_ATTRIBUTE, null);
510
+ if (numeric) {
511
+ plan = { value: (e) => (plain.isSet(e) ? plain.value(e) : undefined) };
512
+ }
513
+ }
514
+ return { plan, nonfinite: plan === null ? 0 : nanWeights(snapshot.edgeCount, plan, folding) };
515
+ }
516
+ /**
517
+ * The written weights that are NaN, which is not a weight on re-import (the infinities are).
518
+ * @param edgeCount - the number of edges
519
+ * @param plan - the weight plan
520
+ * @param folding - the pair folding
521
+ * @returns the count
522
+ */
523
+ function nanWeights(edgeCount, plan, folding) {
524
+ let nan = 0;
525
+ for (let e = 0; e < edgeCount; e++) {
526
+ const w = plan.value(e);
527
+ if (!folding.folded(e) && w !== undefined && Number.isNaN(w)) {
528
+ nan++;
529
+ }
530
+ }
531
+ return nan;
532
+ }
533
+ /**
534
+ * Whether the z column can go into cartesianLayout: every set z is finite and its node has a
535
+ * finite position (a layout entry needs x and y). Otherwise it is written as an ordinary attribute.
536
+ * @param z - the z column
537
+ * @param position - the position column
538
+ * @returns true when every z fits a layout entry
539
+ */
540
+ function zFitsLayout(z, position) {
541
+ for (let i = 0; i < z.length; i++) {
542
+ if (!z.isSet(i)) {
543
+ continue;
544
+ }
545
+ const value = z.value(i);
546
+ const point = position?.isSet(i) === true ? position.value(i) : null;
547
+ if (typeof value !== "number" ||
548
+ !Number.isFinite(value) ||
549
+ point === null ||
550
+ !Number.isFinite(point[0]) ||
551
+ !Number.isFinite(point[1])) {
552
+ return false;
553
+ }
554
+ }
555
+ return true;
556
+ }
557
+ /**
558
+ * Count the set cells of a multi-component column with a non-finite component among those picked.
559
+ * @param column - the column
560
+ * @param pick - the components that are written
561
+ * @returns the count
562
+ */
563
+ function nonFiniteCells(column, pick) {
564
+ let count = 0;
565
+ for (let i = 0; i < column.length; i++) {
566
+ if (column.isSet(i) && pick(column.value(i)).some((v) => !Number.isFinite(v))) {
567
+ count++;
568
+ }
569
+ }
570
+ return count;
571
+ }
572
+ /**
573
+ * Whether a parents column gives some node more than one parent.
574
+ * @param column - the parents list column
575
+ * @returns true when one does
576
+ */
577
+ function severalParents(column) {
578
+ for (let i = 0; i < column.length; i++) {
579
+ if (column.isSet(i) && column.value(i).length > 1) {
580
+ return true;
581
+ }
582
+ }
583
+ return false;
584
+ }
585
+ /**
586
+ * The citations / supports list columns of a CX import and the aspects they go to.
587
+ * @param snapshot - the snapshot
588
+ * @returns the plans
589
+ */
590
+ function linkPlans(snapshot) {
591
+ const out = [];
592
+ for (const [domain, table] of [
593
+ ["node", snapshot.nodes],
594
+ ["edge", snapshot.edges],
595
+ ]) {
596
+ for (const column of table) {
597
+ if (isLink(column)) {
598
+ const key = column.meta.name;
599
+ out.push({ aspect: `${domain}${key === "citations" ? "Citations" : "Supports"}`, key, domain, column });
600
+ }
601
+ }
602
+ }
603
+ return out;
604
+ }
605
+ // ============================================================ writing
606
+ /**
607
+ * The text of a scalar the way Cytoscape writes CX values: numbers by their shortest decimal
608
+ * ("-0", "NaN", "Infinity" included), booleans as "true" / "false".
609
+ * @param value - the value
610
+ * @returns the text
611
+ */
612
+ function scalarText(value) {
613
+ if (typeof value === "number") {
614
+ return Object.is(value, -0) ? "-0" : String(value);
615
+ }
616
+ if (typeof value === "string") {
617
+ return value;
618
+ }
619
+ return typeof value === "boolean" ? String(value) : JSON.stringify(value);
620
+ }
621
+ /**
622
+ * The v of one cell: a JSON string, or an array of strings for a list type.
623
+ * @param column - the column
624
+ * @param d - its declared type
625
+ * @param row - the row
626
+ * @returns the value, or undefined for an unset cell
627
+ */
628
+ function cellValue(column, d, row) {
629
+ if (!column.isSet(row)) {
630
+ return undefined;
631
+ }
632
+ const value = column.value(row);
633
+ if (column.meta.dtype === "json") {
634
+ return JSON.stringify(value);
635
+ }
636
+ if (column.meta.dtype === "list" || column.meta.components > 1) {
637
+ const items = Array.from(value);
638
+ return d === "string" ? JSON.stringify(items) : items.map(scalarText);
639
+ }
640
+ return scalarText(value);
641
+ }
642
+ /**
643
+ * The text a core field (n, r, i) holds for one row.
644
+ * @param column - the column
645
+ * @param row - the row
646
+ * @returns the text, or undefined for an unset cell
647
+ */
648
+ function coreText(column, row) {
649
+ if (!column.isSet(row)) {
650
+ return undefined;
651
+ }
652
+ const value = column.value(row);
653
+ if (column.meta.dtype === "json" || column.meta.dtype === "list" || column.meta.components > 1) {
654
+ return JSON.stringify(column.meta.dtype === "json" ? value : Array.from(value));
655
+ }
656
+ return scalarText(value);
657
+ }
658
+ /**
659
+ * The written edges: every logical edge but the folded halves of pairs.
660
+ * @param snapshot - the snapshot
661
+ * @param folding - the pair folding
662
+ * @returns the edge indexes
663
+ */
664
+ function writtenEdges(snapshot, folding) {
665
+ const out = [];
666
+ for (let e = 0; e < snapshot.edgeCount; e++) {
667
+ if (!folding.folded(e)) {
668
+ out.push(e);
669
+ }
670
+ }
671
+ return out;
672
+ }
673
+ /**
674
+ * Build every aspect of the document, in the order Cytoscape and NDEx write them.
675
+ * @param snapshot - the snapshot
676
+ * @param p - the plan
677
+ * @param ids - the written node ids
678
+ * @returns the aspects (those without elements included; the writer skips them)
679
+ */
680
+ function aspects(snapshot, p, ids) {
681
+ const { src, dst } = snapshot.edgeList();
682
+ const edges = writtenEdges(snapshot, p.folding);
683
+ const nodeRange = () => Array.from({ length: snapshot.nodeCount }, (_, i) => i);
684
+ const nodeCore = (key) => p.nodeCore.find((c) => c.key === key)?.column ?? null;
685
+ const n = nodeCore("n");
686
+ const r = nodeCore("r");
687
+ const i = p.edgeCore[0]?.column ?? null;
688
+ const kept = snapshot.meta.sourceFormat === CX_FORMAT && isRecord(snapshot.meta.extra.cx) ? snapshot.meta.extra.cx : {};
689
+ const out = [
690
+ {
691
+ name: "nodes",
692
+ idCounter: nextNodeId(ids, snapshot.nodeCount),
693
+ *elements() {
694
+ for (let row = 0; row < snapshot.nodeCount; row++) {
695
+ const element = { "@id": ids.idAt(row) };
696
+ const name = n === null ? undefined : coreText(n, row);
697
+ const represents = r === null ? undefined : coreText(r, row);
698
+ if (name !== undefined) {
699
+ element.n = name;
700
+ }
701
+ if (represents !== undefined) {
702
+ element.r = represents;
703
+ }
704
+ yield element;
705
+ }
706
+ },
707
+ },
708
+ {
709
+ name: "edges",
710
+ idCounter: edges.reduce((max, e) => Math.max(max, p.edgeIds[e] + 1), 0),
711
+ *elements() {
712
+ for (const e of edges) {
713
+ const element = {
714
+ "@id": p.edgeIds[e],
715
+ s: ids.idAt(src[e]),
716
+ t: ids.idAt(dst[e]),
717
+ };
718
+ const interaction = i === null ? undefined : coreText(i, e);
719
+ if (interaction !== undefined) {
720
+ element.i = interaction;
721
+ }
722
+ yield element;
723
+ }
724
+ },
725
+ },
726
+ {
727
+ name: "nodeAttributes",
728
+ *elements() {
729
+ for (const a of p.nodeAttrs) {
730
+ for (let row = 0; row < snapshot.nodeCount; row++) {
731
+ const v = cellValue(a.column, a.d, row);
732
+ if (v !== undefined) {
733
+ yield { po: ids.idAt(row), n: a.name, v, d: a.d };
734
+ }
735
+ }
736
+ }
737
+ for (let row = 0; row < snapshot.nodeCount; row++) {
738
+ if (ids.isChanged(row)) {
739
+ yield {
740
+ po: ids.idAt(row),
741
+ n: ORIGINAL_ID_ATTRIBUTE,
742
+ v: String(ids.originalAt(row)),
743
+ d: "string",
744
+ };
745
+ }
746
+ }
747
+ },
748
+ },
749
+ {
750
+ name: "edgeAttributes",
751
+ *elements() {
752
+ for (const a of p.edgeAttrs) {
753
+ for (const e of edges) {
754
+ const v = cellValue(a.column, a.d, e);
755
+ if (v !== undefined) {
756
+ yield { po: p.edgeIds[e], n: a.name, v, d: a.d };
757
+ }
758
+ }
759
+ }
760
+ if (p.weight !== null) {
761
+ for (const e of edges) {
762
+ const w = p.weight.value(e);
763
+ if (w !== undefined && !Number.isNaN(w)) {
764
+ yield { po: p.edgeIds[e], n: WEIGHT_ATTRIBUTE, v: scalarText(w), d: "double" };
765
+ }
766
+ }
767
+ }
768
+ },
769
+ },
770
+ {
771
+ name: "networkAttributes",
772
+ *elements() {
773
+ for (const a of p.graphAttrs) {
774
+ const v = cellValue(a.column, a.d, 0);
775
+ if (v !== undefined) {
776
+ yield { n: a.name, v, d: a.d };
777
+ }
778
+ }
779
+ const { meta } = snapshot;
780
+ for (const [key, value] of [
781
+ ["name", meta.name],
782
+ ["description", meta.description],
783
+ ]) {
784
+ if (value !== null && !p.graphAttrs.some((a) => a.name === key)) {
785
+ yield { n: key, v: value, d: "string" };
786
+ }
787
+ }
788
+ },
789
+ },
790
+ { name: "cyTableColumn", elements: () => tableColumns(p, ids) },
791
+ { name: "cartesianLayout", elements: () => layoutElements(p, ids, nodeRange()) },
792
+ { name: "cyGroups", elements: () => groupElements(snapshot, p, ids, edges) },
793
+ { name: "cyVisualProperties", elements: () => visualProperties(p, ids, nodeRange(), edges, kept) },
794
+ ];
795
+ out.push(...provenanceAspects(snapshot, p, ids, edges));
796
+ for (const [name, value] of Object.entries(kept)) {
797
+ if (!NEVER_WRITTEN.has(name) && Array.isArray(value)) {
798
+ out.push({ name, elements: () => keptElements(value, kept.subnetwork, STYLE_ASPECTS.has(name)) });
799
+ }
800
+ }
801
+ return out;
802
+ }
803
+ /**
804
+ * The cyTableColumn entries: every written column with its type, so a column no element fills is
805
+ * still declared on re-import.
806
+ * @param p - the plan
807
+ * @param ids - the written ids
808
+ * @yields the entries
809
+ */
810
+ function* tableColumns(p, ids) {
811
+ for (const { key, column } of [...p.nodeCore, ...p.edgeCore]) {
812
+ const n = { n: "name", r: "represents", i: "interaction" }[key];
813
+ if (n !== undefined && column !== null) {
814
+ yield { applies_to: key === "i" ? "edge_table" : "node_table", n, d: "string" };
815
+ }
816
+ }
817
+ for (const a of p.nodeAttrs) {
818
+ yield { applies_to: "node_table", n: a.name, d: a.d };
819
+ }
820
+ if (ids.changed > 0) {
821
+ yield { applies_to: "node_table", n: ORIGINAL_ID_ATTRIBUTE, d: "string" };
822
+ }
823
+ for (const a of p.edgeAttrs) {
824
+ yield { applies_to: "edge_table", n: a.name, d: a.d };
825
+ }
826
+ if (p.weight !== null) {
827
+ yield { applies_to: "edge_table", n: WEIGHT_ATTRIBUTE, d: "double" };
828
+ }
829
+ for (const a of p.graphAttrs) {
830
+ yield { applies_to: "network_table", n: a.name, d: a.d };
831
+ }
832
+ }
833
+ /** Kept aspects whose view references are rewritten to the one view of the written file. */
834
+ const STYLE_ASPECTS = new Set(["tableVisualProperties", "cyTableVisualProperties"]);
835
+ /**
836
+ * The elements of a kept aspect: those of the snapshot's own subnetwork (or unscoped), with the
837
+ * scope dropped; style elements get their view references rewritten to view 0.
838
+ * @param elements - the kept elements
839
+ * @param subnetwork - the subnetwork the snapshot was read from, if any
840
+ * @param style - whether the aspect is a style aspect
841
+ * @yields the elements to write
842
+ */
843
+ function* keptElements(elements, subnetwork, style) {
844
+ for (const element of elements) {
845
+ if (!isRecord(element)) {
846
+ yield element;
847
+ continue;
848
+ }
849
+ if (element.s !== undefined && element.s !== null && element.s !== subnetwork) {
850
+ continue;
851
+ }
852
+ const { s: _scope, ...rest } = element;
853
+ yield style ? rewriteView(rest) : rest;
854
+ }
855
+ }
856
+ /**
857
+ * A style element with its view and subnetwork references rewritten to 0, the written network.
858
+ * @param element - the element
859
+ * @returns the rewritten element
860
+ */
861
+ function rewriteView(element) {
862
+ const out = { ...element };
863
+ if ("view" in out) {
864
+ out.view = 0;
865
+ }
866
+ if (typeof out.applies_to === "number") {
867
+ out.applies_to = 0;
868
+ }
869
+ return out;
870
+ }
871
+ /**
872
+ * The cartesianLayout entries: x / y (y negated back to screen coordinates) and z.
873
+ * @param p - the plan
874
+ * @param ids - the written ids
875
+ * @param rows - every node row
876
+ * @yields the entries
877
+ */
878
+ function* layoutElements(p, ids, rows) {
879
+ const { position } = p;
880
+ if (position === null) {
881
+ return;
882
+ }
883
+ for (const row of rows) {
884
+ if (!position.isSet(row)) {
885
+ continue;
886
+ }
887
+ const point = position.value(row);
888
+ if (!Number.isFinite(point[0]) || !Number.isFinite(point[1])) {
889
+ continue;
890
+ }
891
+ const entry = { node: ids.idAt(row), x: point[0], y: point[1] === 0 ? 0 : -point[1] };
892
+ if (p.z?.isSet(row) === true) {
893
+ entry.z = p.z.value(row);
894
+ }
895
+ else if (p.positionZ && Number.isFinite(point[2])) {
896
+ entry.z = point[2];
897
+ }
898
+ yield entry;
899
+ }
900
+ }
901
+ /**
902
+ * The cyGroups entries: one per node that has members (or a collapsed flag), its members, and the
903
+ * edges with both ends (internal) or one end (external) among them.
904
+ * @param snapshot - the snapshot
905
+ * @param p - the plan
906
+ * @param ids - the written ids
907
+ * @param edges - the written edges
908
+ * @yields the entries
909
+ */
910
+ function* groupElements(snapshot, p, ids, edges) {
911
+ const children = childrenCsr(snapshot);
912
+ const groupsOf = new Map();
913
+ const groups = [];
914
+ for (let g = 0; g < snapshot.nodeCount; g++) {
915
+ const members = children.childrenOf(g);
916
+ if (members.length > 0 || p.collapsed?.isSet(g) === true) {
917
+ groups.push(g);
918
+ }
919
+ for (const c of members) {
920
+ groupsOf.set(c, [...(groupsOf.get(c) ?? []), g]);
921
+ }
922
+ }
923
+ if (groups.length === 0) {
924
+ return;
925
+ }
926
+ const { internal, external } = groupEdges(snapshot, p, groupsOf, edges);
927
+ const label = p.nodeCore.find((c) => c.key === "n")?.column ?? null;
928
+ for (const g of groups) {
929
+ const entry = { "@id": ids.idAt(g) };
930
+ const name = label === null ? undefined : coreText(label, g);
931
+ if (name !== undefined) {
932
+ entry.n = name;
933
+ }
934
+ entry.nodes = Array.from(children.childrenOf(g), (c) => ids.idAt(c));
935
+ entry.internal_edges = internal.get(g) ?? [];
936
+ entry.external_edges = external.get(g) ?? [];
937
+ if (p.collapsed?.isSet(g) === true) {
938
+ entry.collapsed = p.collapsed.value(g);
939
+ }
940
+ yield entry;
941
+ }
942
+ }
943
+ /**
944
+ * The written edges of each group: internal (both ends among its members) and external (one end).
945
+ * @param snapshot - the snapshot
946
+ * @param p - the plan
947
+ * @param groupsOf - the groups each member node is in
948
+ * @param edges - the written edges
949
+ * @returns the edge ids by group
950
+ */
951
+ function groupEdges(snapshot, p, groupsOf, edges) {
952
+ const internal = new Map();
953
+ const external = new Map();
954
+ const add = (table, g, id) => {
955
+ table.set(g, [...(table.get(g) ?? []), id]);
956
+ };
957
+ const { src, dst } = snapshot.edgeList();
958
+ for (const e of edges) {
959
+ const ofSource = groupsOf.get(src[e]) ?? [];
960
+ const ofTarget = groupsOf.get(dst[e]) ?? [];
961
+ for (const g of ofSource) {
962
+ add(ofTarget.includes(g) ? internal : external, g, p.edgeIds[e]);
963
+ }
964
+ for (const g of ofTarget.filter((t) => !ofSource.includes(t))) {
965
+ add(external, g, p.edgeIds[e]);
966
+ }
967
+ }
968
+ return { internal, external };
969
+ }
970
+ /**
971
+ * The visual property values of one row: property -> value text.
972
+ * @param columns - the bypass columns
973
+ * @param row - the row
974
+ * @returns the properties, or null when none is set
975
+ */
976
+ function bypassValues(columns, row) {
977
+ let out = null;
978
+ for (const column of columns) {
979
+ if (column.isSet(row)) {
980
+ // the visual property's own name: a column renamed for a clash with an attribute keeps it in origin.id
981
+ const property = column.meta.origin?.id;
982
+ out ?? (out = {});
983
+ out[typeof property === "string" && property.length > 0 ? property : column.meta.name] = scalarText(column.value(row));
984
+ }
985
+ }
986
+ return out;
987
+ }
988
+ /**
989
+ * The cyVisualProperties entries: the network values, the style rules a CX import kept (its own
990
+ * view's, rewritten to view 0) and the per-element values.
991
+ * @param p - the plan
992
+ * @param ids - the written ids
993
+ * @param rows - every node row
994
+ * @param edges - the written edges
995
+ * @param kept - meta.extra.cx of a CX import, else empty
996
+ * @yields the entries
997
+ */
998
+ function* visualProperties(p, ids, rows, edges, kept) {
999
+ const network = bypassValues(p.bypass.graph, 0);
1000
+ if (network !== null) {
1001
+ yield { properties_of: "network", properties: network };
1002
+ }
1003
+ const view = ownView(kept);
1004
+ for (const entry of Array.isArray(kept.cyVisualProperties) ? kept.cyVisualProperties : []) {
1005
+ if (isRecord(entry) &&
1006
+ !["nodes", "edges", "network"].includes(String(entry.properties_of)) &&
1007
+ (view === null || entry.view === undefined || entry.view === null || entry.view === view)) {
1008
+ yield rewriteView(entry);
1009
+ }
1010
+ }
1011
+ for (const row of rows) {
1012
+ const properties = bypassValues(p.bypass.node, row);
1013
+ if (properties !== null) {
1014
+ yield { properties_of: "nodes", applies_to: ids.idAt(row), properties };
1015
+ }
1016
+ }
1017
+ for (const e of edges) {
1018
+ const properties = bypassValues(p.bypass.edge, e);
1019
+ if (properties !== null) {
1020
+ yield { properties_of: "edges", applies_to: p.edgeIds[e], properties };
1021
+ }
1022
+ }
1023
+ }
1024
+ /**
1025
+ * The view of the subnetwork a CX import read (the one its style rules belong to).
1026
+ * @param kept - meta.extra.cx
1027
+ * @returns the view id, or null when the file named none
1028
+ */
1029
+ function ownView(kept) {
1030
+ const sub = kept.subnetwork;
1031
+ for (const r of Array.isArray(kept.cyNetworkRelations) ? kept.cyNetworkRelations : []) {
1032
+ if (isRecord(r) && r.r === "view" && (sub === undefined || r.p === sub)) {
1033
+ return r.c;
1034
+ }
1035
+ }
1036
+ for (const v of Array.isArray(kept.cyViews) ? kept.cyViews : []) {
1037
+ if (isRecord(v) && (sub === undefined || v.s === sub)) {
1038
+ return v["@id"];
1039
+ }
1040
+ }
1041
+ return null;
1042
+ }
1043
+ /**
1044
+ * The provenance aspects a CX import turned into extension tables and columns, written back:
1045
+ * citations, supports, their node / edge links, functionTerms and reifiedEdges.
1046
+ * @param snapshot - the snapshot
1047
+ * @param p - the plan
1048
+ * @param ids - the written ids
1049
+ * @param edges - the written edges
1050
+ * @returns the aspects
1051
+ */
1052
+ function provenanceAspects(snapshot, p, ids, edges) {
1053
+ const out = [];
1054
+ for (const [table, aspect] of Object.entries(PROVENANCE_TABLES)) {
1055
+ const ext = snapshot.extensions.get(table);
1056
+ if (ext === undefined) {
1057
+ continue;
1058
+ }
1059
+ const idColumn = ext.get("id");
1060
+ const fields = [...ext].filter((c) => c !== idColumn);
1061
+ let max = -1;
1062
+ for (let row = 0; row < ext.rowCount; row++) {
1063
+ if (idColumn?.isSet(row) === true) {
1064
+ max = Math.max(max, Number(idColumn.value(row)));
1065
+ }
1066
+ }
1067
+ out.push({
1068
+ name: aspect,
1069
+ idCounter: max + 1,
1070
+ *elements() {
1071
+ for (let row = 0; row < ext.rowCount; row++) {
1072
+ const element = {};
1073
+ if (idColumn?.isSet(row) === true) {
1074
+ element["@id"] = idColumn.value(row);
1075
+ }
1076
+ for (const field of fields) {
1077
+ if (field.isSet(row)) {
1078
+ element[field.meta.name] = field.value(row);
1079
+ }
1080
+ }
1081
+ yield element;
1082
+ }
1083
+ },
1084
+ });
1085
+ }
1086
+ for (const link of p.links) {
1087
+ out.push({
1088
+ name: link.aspect,
1089
+ *elements() {
1090
+ const rows = link.domain === "node" ? Array.from({ length: snapshot.nodeCount }, (_, i) => i) : edges;
1091
+ for (const row of rows) {
1092
+ if (link.column.isSet(row)) {
1093
+ const po = link.domain === "node" ? ids.idAt(row) : p.edgeIds[row];
1094
+ yield { po: [po], [link.key]: Array.from(link.column.value(row)) };
1095
+ }
1096
+ }
1097
+ },
1098
+ });
1099
+ }
1100
+ const terms = p.functionTerm;
1101
+ if (terms !== null) {
1102
+ out.push({
1103
+ name: "functionTerms",
1104
+ *elements() {
1105
+ for (let row = 0; row < snapshot.nodeCount; row++) {
1106
+ const term = terms.isSet(row) ? terms.value(row) : null;
1107
+ if (isRecord(term)) {
1108
+ yield { po: ids.idAt(row), ...term };
1109
+ }
1110
+ }
1111
+ },
1112
+ });
1113
+ }
1114
+ const reified = p.reifiedEdge;
1115
+ if (reified !== null) {
1116
+ out.push({
1117
+ name: "reifiedEdges",
1118
+ *elements() {
1119
+ for (let row = 0; row < snapshot.nodeCount; row++) {
1120
+ const edge = reified.isSet(row) ? reified.value(row) : -1;
1121
+ if (edge >= 0 && edge < snapshot.edgeCount) {
1122
+ yield { node: ids.idAt(row), edge: p.edgeIds[edge] };
1123
+ }
1124
+ }
1125
+ },
1126
+ });
1127
+ }
1128
+ return out;
1129
+ }
1130
+ /**
1131
+ * Write the document as text parts.
1132
+ * @param snapshot - the snapshot
1133
+ * @param p - the plan
1134
+ * @yields the document's text
1135
+ * @returns nothing
1136
+ */
1137
+ function* write(snapshot, p) {
1138
+ if (p.fatal !== null) {
1139
+ throw p.fatal;
1140
+ }
1141
+ const { ids } = p;
1142
+ if (ids === null) {
1143
+ throw new GraphFormatError("E_INVALID_ID", "node ids cannot be written as CX integers", { reason: "charset" });
1144
+ }
1145
+ const all = aspects(snapshot, p, ids);
1146
+ const written = [];
1147
+ for (const aspect of all) {
1148
+ let count = 0;
1149
+ for (const _ of aspect.elements()) {
1150
+ count++;
1151
+ }
1152
+ if (count > 0 || aspect.name === "nodes") {
1153
+ written.push({ aspect, count });
1154
+ }
1155
+ }
1156
+ const metaData = written.map(({ aspect, count }) => ({
1157
+ name: aspect.name,
1158
+ version: "1.0",
1159
+ ...(aspect.idCounter === undefined ? {} : { idCounter: aspect.idCounter }),
1160
+ elementCount: count,
1161
+ consistencyGroup: 1,
1162
+ }));
1163
+ yield '[{"numberVerification":[{"longNumber":281474976710655}]},\n';
1164
+ yield `{"metaData":${stringify(metaData)}},\n`;
1165
+ for (const { aspect } of written) {
1166
+ yield* aspectBlock(aspect.name, mapIterable(aspect.elements(), stringify));
1167
+ }
1168
+ yield '{"status":[{"error":"","success":true}]}]\n';
1169
+ }
1170
+ /**
1171
+ * Map an iterable lazily.
1172
+ * @param items - the items
1173
+ * @param fn - the mapping
1174
+ * @yields the mapped items
1175
+ */
1176
+ function* mapIterable(items, fn) {
1177
+ for (const item of items) {
1178
+ yield fn(item);
1179
+ }
1180
+ }
1181
+ /**
1182
+ * The CX version 1 exporter plugin.
1183
+ * @category Built-in formats
1184
+ */
1185
+ export const cxExporter = Object.freeze({
1186
+ format: CX_FORMAT,
1187
+ options: Object.freeze([]),
1188
+ capabilities: CX_CAPABILITIES,
1189
+ /**
1190
+ * Pre-flight: what export() would lose, without writing anything.
1191
+ * @param snapshot - the snapshot
1192
+ * @param options - the common options
1193
+ * @returns the notes, empty when the export is exact
1194
+ */
1195
+ check(snapshot, options) {
1196
+ return Object.freeze([...plan(snapshot, resolveExportOptions(options)).notes]);
1197
+ },
1198
+ /**
1199
+ * Write the document as UTF-8 chunks.
1200
+ * @param snapshot - the snapshot
1201
+ * @param options - the common options
1202
+ * @returns the chunks
1203
+ */
1204
+ export(snapshot, options) {
1205
+ return encodeChunks(write(snapshot, plan(snapshot, resolveExportOptions(options))));
1206
+ },
1207
+ /**
1208
+ * Write the document as one string.
1209
+ * @param snapshot - the snapshot
1210
+ * @param options - the common options
1211
+ * @returns the document
1212
+ */
1213
+ exportToString(snapshot, options) {
1214
+ return joinText(write(snapshot, plan(snapshot, resolveExportOptions(options))));
1215
+ },
1216
+ });
1217
+ //# sourceMappingURL=exporter.js.map