@graphty/graph-io 0.3.25 → 0.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-BbJI55dx.js +56 -0
  4. package/dist/chunks/choose-BbJI55dx.js.map +1 -0
  5. package/dist/chunks/constants-BCsFsMj4.js +231 -0
  6. package/dist/chunks/constants-BCsFsMj4.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D0g6NNUy.js} +382 -92
  8. package/dist/chunks/escape-D0g6NNUy.js.map +1 -0
  9. package/dist/chunks/export-BTI4yQgy.js +4333 -0
  10. package/dist/chunks/export-BTI4yQgy.js.map +1 -0
  11. package/dist/chunks/exporter-BMqk5oxW.js +3465 -0
  12. package/dist/chunks/exporter-BMqk5oxW.js.map +1 -0
  13. package/dist/chunks/{importer-eUREhBGj.js → exporter-Cra2GYcN.js} +4969 -3201
  14. package/dist/chunks/exporter-Cra2GYcN.js.map +1 -0
  15. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-Dxh231ZF.js} +38 -229
  16. package/dist/chunks/exporter-Dxh231ZF.js.map +1 -0
  17. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-tne475KK.js} +22 -20
  18. package/dist/chunks/exporter-tne475KK.js.map +1 -0
  19. package/dist/chunks/importer-90YWhJoF.js +2811 -0
  20. package/dist/chunks/importer-90YWhJoF.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-Bcl1d4xH.js} +398 -145
  22. package/dist/chunks/importer-Bcl1d4xH.js.map +1 -0
  23. package/dist/chunks/{importer-BWY2FFc5.js → importer-BfIsp1f9.js} +255 -77
  24. package/dist/chunks/importer-BfIsp1f9.js.map +1 -0
  25. package/dist/chunks/{importer-zGLo8Dg_.js → importer-C_TEA1zJ.js} +484 -157
  26. package/dist/chunks/importer-C_TEA1zJ.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-DCjOvO7U.js} +1687 -310
  28. package/dist/chunks/importer-DCjOvO7U.js.map +1 -0
  29. package/dist/chunks/{importer-vi3bSdtw.js → importer-DfVu6j59.js} +509 -76
  30. package/dist/chunks/importer-DfVu6j59.js.map +1 -0
  31. package/dist/chunks/{importer-DIrbbnAf.js → importer-Dku_VAIY.js} +585 -226
  32. package/dist/chunks/importer-Dku_VAIY.js.map +1 -0
  33. package/dist/chunks/json-elements-3tnyt5uZ.js +1225 -0
  34. package/dist/chunks/json-elements-3tnyt5uZ.js.map +1 -0
  35. package/dist/chunks/ontology-export-B9Tcf37D.js +357 -0
  36. package/dist/chunks/ontology-export-B9Tcf37D.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CQXT__mY.js} +298 -114
  38. package/dist/chunks/records-CQXT__mY.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DmcUs5_Q.js} +29 -11
  40. package/dist/chunks/text-DmcUs5_Q.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +951 -261
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +342 -85
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +564 -157
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +19 -1
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +33 -17
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +868 -188
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +2 -0
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +400 -83
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +145 -32
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +680 -285
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +226 -79
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +98 -24
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +108 -26
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +238 -85
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +66 -34
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +183 -51
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +20 -21
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +7 -2
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +38 -4
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +33 -17
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1034 -198
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +6 -1
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +477 -88
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +201 -46
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +888 -300
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +61 -338
  498. package/src/formats/cx2/importer.ts +317 -86
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +139 -31
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +111 -26
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +320 -101
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +89 -41
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +213 -52
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +35 -27
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +11 -3
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
package/README.md CHANGED
@@ -1,436 +1,71 @@
1
1
  # @graphty/graph-io
2
2
 
3
- [![CI](https://github.com/graphty-org/graphty-monorepo/actions/workflows/ci.yml/badge.svg)](https://github.com/graphty-org/graphty-monorepo/actions/workflows/ci.yml)
4
- [![Coverage Status](https://coveralls.io/repos/github/graphty-org/graphty-monorepo/badge.svg?branch=master)](https://coveralls.io/github/graphty-org/graphty-monorepo?branch=master)
5
3
  [![npm version](https://img.shields.io/npm/v/@graphty/graph-io.svg)](https://www.npmjs.com/package/@graphty/graph-io)
6
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
5
 
8
- Importers and exporters for the [@graphty/graph-format](https://www.npmjs.com/package/@graphty/graph-format)
9
- snapshot: GEXF, GraphML, GML, DOT (Graphviz), Pajek NET, CSV / TSV, JSON (NetworkX node-link, d3,
10
- JSON Graph Format, Cytoscape, graphology, vis.js; NetworkX adjacency_data and tree_data and OBO
11
- Graphs are read only), Neo4j (`neo4j-admin import` CSV), XGMML (Cytoscape's XML format), CX2 (the
12
- NDEx / Cytoscape exchange format; its version 1, CX, is read only), Cytoscape sessions (`.cys`, read
13
- only) and OBO, the ontology format of the Gene Ontology (read only).
14
-
15
- Every importer streams its input into a `GraphSink` (a `GraphBuilder` or your own sink) one scalar at
16
- a time and reports what it could not represent instead of dropping it; every exporter says what it
17
- would lose before it writes a byte. The core format package stays zero-dependency; this package owns
18
- the parsers and the io contract types.
19
-
20
- ## Installation
6
+ Read and write 13 graph file formats, from GraphML and GEXF to CSV, JSON and Cytoscape sessions, as
7
+ [@graphty/graph-format](https://www.npmjs.com/package/@graphty/graph-format) snapshots. graph-io
8
+ streams large files, runs in browsers and in Node, and tells you what it could not read or could
9
+ not save instead of dropping it.
21
10
 
22
11
  ```bash
23
- npm install @graphty/graph-io @graphty/graph-format
12
+ npm install @graphty/graph-io
24
13
  ```
25
14
 
26
- ESM only. Node >= 18.19.0 or any browser with ES2020 support. `@graphty/graph-format` is a peer
27
- dependency so an application that installs several consumers gets one copy of the format.
15
+ Its one dependency, graph-format, is installed with it, and graph-io exports what you need from it
16
+ (the `GraphSnapshot` type and `GraphBuilder`), so you do not add it yourself.
28
17
 
29
- ## Quick start
18
+ This reads
19
+ [got-network.graphml](https://raw.githubusercontent.com/melaniewalsh/sample-social-network-datasets/master/sample-datasets/game-of-thrones/got-network.graphml),
20
+ a public-domain Game of Thrones network. The package holds a copy, with the other sample files the
21
+ guide uses: `cp node_modules/@graphty/graph-io/docs/samples/* .` puts them where the example
22
+ expects them.
30
23
 
31
- `importGraph()` sniffs the format from the file name, the MIME type and the first bytes, creates a
32
- builder, imports and freezes:
24
+ <!-- generated:begin example:quick-start/readme -->
33
25
 
34
26
  ```ts
35
- import { importGraph, exportGraphToString, ImportError } from "@graphty/graph-io";
36
-
37
- const bytes = await fetch("/data/lesmiserables.gexf").then((r) => r.arrayBuffer());
38
- try {
39
- const { snapshot, report, freeze, format } = await importGraph(new Uint8Array(bytes), {
40
- filename: "lesmiserables.gexf", // a hint; the content decides
41
- ids: "canonical", // "1" becomes the number 1, "01" stays a string (the default for text formats)
42
- weightDtype: "f64", // the default: 0.1 and 16777217 survive the round trip
43
- errorLimit: 100, // recoverable errors tolerated before ImportError
44
- });
45
- console.log(format, snapshot.nodeCount, snapshot.edgeCount, report.warningCount, freeze.compacted);
46
- for (const issue of report.issues) {
47
- console.log(issue.severity, issue.code, issue.line, issue.message);
48
- }
49
- const gml = await exportGraphToString(snapshot, "gml");
50
- } catch (err) {
51
- if (err instanceof ImportError) {
52
- // the input could not be read at all, or the error limit was reached
53
- console.log(err.report.issues);
54
- }
55
- }
56
- ```
27
+ import { readFile, writeFile } from "node:fs/promises";
57
28
 
58
- A caller who owns a builder (an application that appends several files into one graph) uses an
59
- importer directly through its subpath, so a CSV-only bundle never loads the XML formats:
29
+ import { exportGraphToBytes, importGraph } from "@graphty/graph-io";
60
30
 
61
- ```ts
62
- import { GraphBuilder } from "@graphty/graph-format";
63
- import { csvImporter, csvExporter } from "@graphty/graph-io/csv";
64
-
65
- const builder = new GraphBuilder({ directed: true, weightDtype: "f64" });
66
- const report = await csvImporter.import(file.stream(), builder, {
67
- delimiter: ",",
68
- nodes: nodeTableText, // an optional paired node table (Gephi's nodes.csv + edges.csv)
69
- onProgress: (done, total) => console.log(done, total),
70
- signal: controller.signal,
31
+ const { snapshot, format, report } = await importGraph(await readFile("got-network.graphml"), {
32
+ filename: "got-network.graphml",
71
33
  });
72
- const snapshot = builder.freeze();
73
-
74
- const notes = csvExporter.check(snapshot, { dialect: "gephi" }); // what export() would lose; [] when exact
75
- for await (const chunk of csvExporter.export(snapshot, { dialect: "gephi" })) {
76
- writable.write(chunk); // Uint8Array chunks
77
- }
78
- ```
79
-
80
- Inputs may be a `string`, a `Uint8Array`, a `ReadableStream<Uint8Array>` (a `File.stream()`, a fetch
81
- body) or an async iterable of text or byte chunks. Bytes are decoded by one shared layer, whatever
82
- the format. The encoding is, in order: the `encoding` option (any WHATWG label, such as
83
- `"windows-1252"` or `"utf-16le"`); a byte order mark (UTF-8, UTF-16LE, UTF-16BE); the encoding the
84
- file declares (the XML prolog of GEXF and GraphML, DOT's `charset` attribute); else UTF-8. Decoding
85
- is strict, never a silent U+FFFD. Undeclared bytes that are not UTF-8 are read as windows-1252 with
86
- the warning `W_ENCODING_FALLBACK` (Excel, Pajek and older tools write it); invalid UTF-8 after valid
87
- non-ASCII UTF-8, or binary data, is the `parse-error` `E_INVALID_UTF8`.
88
-
89
- Some files hold several graphs: a DOT file with several `graph { }` blocks, a Pajek project (`.paj`)
90
- with several networks, a GML file with several `graph [ ]` blocks, a JGF document with a `graphs`
91
- array. `importGraph()` (and each importer's `import()`) reads the first and records the warning
92
- `W_MULTIPLE_GRAPHS`, which says how many it skipped. `importAllGraphs()` (and `importer.importAll()`
93
- where a format can hold several) returns every graph, each frozen on its own:
94
-
95
- ```ts
96
- import { importAllGraphs } from "@graphty/graph-io";
97
-
98
- for (const { snapshot, report } of await importAllGraphs(bytes, { filename: "project.paj" })) {
99
- console.log(snapshot.meta.name, snapshot.nodeCount, report.warningCount);
100
- }
101
- ```
102
-
103
- ### Common import options
104
-
105
- | Option | Default | Meaning |
106
- | ----------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
107
- | `ids` | `"canonical"` (text formats), `"keep"` (JSON) | How an id cell becomes a `NodeId`: canonical integer text becomes a number, everything else stays a string; `"string"`, `"number"` and `"keep"` too. |
108
- | `nodeIdFrom` | `"id"` | `"label"` or `"index"` for GML / Pajek / d3 files whose ids are ambiguous. |
109
- | `weightFrom` | `"weight"` (GML `"value"`) | The attribute that becomes THE edge weight; `null` = unweighted. |
110
- | `weightDtype` | `"f64"` | Weight staging precision; `"f32"` is an explicit opt-in. |
111
- | `onMixedDirection` | `"expand"` | A file whose edges disagree on direction: expand into a directed graph with `graphty.directed` / `graphty.pair` columns, force `"directed"` / `"undirected"`, or `"error"`. |
112
- | `defaultDirected` | per format (GEXF / GML / JSON undirected, DOT / CSV / Pajek directed) | The direction assumed when the file says nothing. |
113
- | `addMissingNodes` | `true` (GEXF `false`) | Whether an edge may name a node the file never declared. |
114
- | `duplicateEdges`, `selfLoops` | `"keep"` | Builder policies, applied at freeze. |
115
- | `long` | `"f64"` | How a declared 64-bit integer column is stored (`"string"` keeps every digit). |
116
- | `restoreMangledIds` | `true` | Restore ids an exporter rewrote under `sanitizeIds: "mangle"` from the `graphty:originalId` attribute. |
117
- | `hyperedges` | `"skip"` | GraphML / JGF hyperedges: `"error"`, `"skip"` with a report entry, `"star"` or `"clique"`. |
118
- | `errorLimit` | `100` | Recoverable errors tolerated before the importer throws `ImportError` with the partial report. |
119
- | `signal`, `onProgress` | | Cancellation (rejects with the signal's reason) and byte progress (`bytesTotal` known for in-memory input). |
120
- | `encoding` | detected | The encoding of byte input; overrides the byte order mark and the file's declaration. Ignored for text input. |
121
-
122
- On a caller's builder the builder-policy options (`addMissingNodes`, `duplicateEdges`, `selfLoops`,
123
- `weightDtype`) are read from the sink; an explicit request the sink does not honour is reported once
124
- as a `W_SINK_OPTION` warning. `importGraph()` seeds its own builder from them.
125
-
126
- Every attribute is stored as a column with one slot per node (or edge), so a file whose nodes each
127
- carry a differently named attribute would need nodes x attributes memory: a few hundred kilobytes
128
- could take gigabytes. `importGraph()` and `importAllGraphs()` therefore stop with an `ImportError`
129
- (code `E_TOO_MANY_EMPTY_CELLS`) once the columns would hold more than `maxEmptyCells` slots without
130
- a value (default 2^24, 16,777,216; `Infinity` turns the check off). A file where most elements have
131
- most attributes is never stopped, however large. An importer used directly on a caller's builder
132
- does not apply the limit.
133
-
134
- ### Common export options
135
-
136
- `sanitizeIds: "error" | "mangle"` (default `"error"`: an exporter never silently renames a node;
137
- `"mangle"` rewrites ids the format cannot hold and keeps the original in `graphty:originalId`) and
138
- `onMixedDirection: "error" | "directed" | "undirected"` for formats without mixed-direction support.
139
- `check(snapshot, options)` returns the `LossNote[]` that `export()` would incur; the shared codes
140
- are in `LOSS` (for example `LOSS.MIXED_DIRECTION`, `LOSS.DTYPE`, `LOSS.LIST`, `LOSS.ID_MANGLED`),
141
- the per-format ones in `<FORMAT>_LOSS`.
142
-
143
- ## Formats
144
-
145
- Subpath, extensions, and what each exporter keeps as declared (its `capabilities` table; `check()`
146
- reports every column or feature outside it):
147
-
148
- | Format | Subpath | Extensions | Mixed dir. | Multi-edges | Edge ids | Id charset | Dtypes kept | Lists | json | Defaults | Hierarchy | Temporal | Graph attrs | Positions | Viz |
149
- | ------- | --------------------------- | ---------------------------------- | ----------- | ----------- | ----------- | ------------- | -------------------------------------- | ----- | ---- | -------- | --------- | -------------- | ----------- | --------- | --- |
150
- | GEXF | `@graphty/graph-io/gexf` | `.gexf` | yes | yes (1.3) | optional | any | f32 f64 i32 bool dict string | yes | no | yes | yes | dynamic-values | no | yes | yes |
151
- | GraphML | `@graphty/graph-io/graphml` | `.graphml` `.xml` | yes | yes | optional | NMTOKEN | bool i32 f32 f64 string (long as text) | no | no | yes | yes | none | yes | no | no |
152
- | GML | `@graphty/graph-io/gml` | `.gml` | no | yes | optional | integer | i32 f64 string dict json | yes | yes | no | no | none | yes | yes | no |
153
- | DOT | `@graphty/graph-io/dot` | `.dot` `.gv` | no | yes | optional | any | bool i32 f64 string | no | no | no | yes | none | yes | yes | no |
154
- | Pajek | `@graphty/graph-io/pajek` | `.net` `.paj` | yes | yes | none | dense 1-based | f64 i32 bool string | no | no | no | no | spells | no | yes | no |
155
- | CSV | `@graphty/graph-io/csv` | `.csv` `.tsv` `.edges` `.edgelist` | yes | yes | optional | any | bool i32 f64 string dict | no | no | no | no | none | no | no | no |
156
- | JSON | `@graphty/graph-io/json` | `.json` | per dialect | yes | per dialect | any | f64 i32 bool string (no declarations) | no | yes | no | Cytoscape | none | per dialect | Cytoscape | no |
157
- | Neo4j | `@graphty/graph-io/neo4j` | `.csv` `.tsv` | no | yes | none | any | f32 f64 i32 bool string | yes | no | no | no | none | no | no | no |
158
- | XGMML | `@graphty/graph-io/xgmml` | `.xgmml` `.xml` | yes | yes | optional | any | f64 i32 bool string (long as Long) | yes | no | no | yes | none | yes | yes | no |
159
- | CX2 | `@graphty/graph-io/cx2` | `.cx2` | no | yes | required | integer | f64 i32 bool string | yes | no | yes | no | none | yes | yes | no |
160
- | Session | `@graphty/graph-io/cys` | `.cys` | read only | read only | read only | read only | read only | - | - | - | - | - | - | - | - |
161
- | OBO | `@graphty/graph-io/obo` | `.obo` | read only | - | - | - | - | - | - | - | - | - | - | - | - |
162
-
163
- Every importer reads the whole corpus of research note 07 with the manifest counts and every
164
- exporter round-trips it (import -> export -> import gives the same ids, topology, orientation,
165
- weights and declared columns; the per-format caveats, such as Pajek's 0-based files or JSON's
166
- untyped columns, are listed in the staging STATUS.md). `check()` predicts every difference the
167
- format's own importer produces on re-import, including the importer's own rules, with one code per
168
- concept across the formats (`W_ROLE_DROPPED` a role column written as a plain attribute,
169
- `W_COLUMN_NAME_CHANGED` a role column read back under the importer's fixed name, `W_ROLE_ASSUMED` a
170
- role-less column read back with a role, `W_WEIGHT_KEY_CLASH` a plain `weight` column read back as
171
- THE weight, `W_ID_TEXT_TYPE` ids whose text reads back as the other type, `W_STORAGE_CLASS_CHANGED`
172
- a string / dict column read back as the other, `W_INTEGRAL_F64_AS_I32`, `W_TEXT_INFERRED`,
173
- `W_EMPTY_COLUMN_DROPPED`, `W_OPTIONS_GAINED`, `W_TEMPORAL_TEXT_DROPPED`, `W_MUTUAL_EXPANDED` /
174
- `W_MUTUAL_AS_UNDIRECTED`, `E_XML_ILLEGAL_CHAR`, `E_ID_TEXT_COLLISION`). Every subpath exports its
175
- `<FMT>_ISSUE` and `<FMT>_LOSS` tables; a key is the code without its `E_` / `W_` and format
176
- prefixes. Under `onMixedDirection: "directed"` every exporter without mixed direction folds an
177
- expanded pair back to one directed edge; `"undirected"` writes the whole graph undirected. Known
178
- losses and format rules, in addition to the table:
179
-
180
- - **GEXF**: 1.3 by default, 1.2 on request (`version: "1.2"`, no parallel edges, edge ids required).
181
- Dynamic attribute values become `temporal:<node|edge>:<name>` extension tables; `viz:color` is an
182
- f32 x4 rgba column in 0..1, `viz:position` an f32 x3 column; XML-derived column names (`label`,
183
- `parent`, `start`, ...) are reserved, a declared attribute with such a title is renamed
184
- `<title>#<id>`. Node ids that are non-integer numbers read back as text and string ids of integer
185
- text as numbers (`W_ID_TEXT_TYPE`; the importer reads ids by the canonical rule whatever `idtype`
186
- says, `ids: "string"` keeps the texts). A dict column without declared options gains one from
187
- its dictionary (`W_OPTIONS_GAINED`); text with a character XML 1.0 forbids is refused
188
- (`E_XML_ILLEGAL_CHAR`, `export()` throws).
189
- - **GraphML**: parsed by the shared streaming XML tokenizer (no whole-document tree). `key for="all"`
190
- is declared in the node, edge and graph tables; a key's `name` / `type` are read when `attr.name`
191
- / `attr.type` are absent; yFiles trees are kept as `json` columns (structure preserved, not
192
- byte-exact), and a `y:ShapeNode` / `y:PolyLineEdge` in them is also read into `yfiles.*` columns
193
- (node `yfiles.position` with the position role, `yfiles.width`, `yfiles.height`, `yfiles.color`,
194
- `yfiles.borderColor`, `yfiles.borderWidth`, `yfiles.label` with the label role, `yfiles.shape`;
195
- edge `yfiles.color`, `yfiles.width`, `yfiles.directed` (the target arrow, not topology),
196
- `yfiles.targetArrow`, `yfiles.sourceArrow`), which the exporter never writes because the tree
197
- holds them (an edited value, such as a layout's new position, is reported by `check()` as
198
- `W_GRAPHML_YFILES_GRAPHICS_STALE` and lost); any other `json` column is written as JSON text and reads back as
199
- string (`W_JSON_UNSUPPORTED`). Ids outside NMTOKEN need `sanitizeIds: "mangle"` (restored on
200
- re-import). A label role column is written as the key titled `label` (the importer's label slot;
201
- `W_COLUMN_NAME_CHANGED` when it was named otherwise); edge ids and ports are the XML attributes
202
- (`id`, `sourceport`, `targetport`); a plain column titled like one of them reads back renamed
203
- `<name>#<key>`. A mutual pair is written as one undirected edge (`W_MUTUAL_AS_UNDIRECTED`).
204
- Lists, positions, viz and temporal columns are written as JSON text or reported.
205
- - **GML**: NetworkX conventions (`_networkx_list_start`, `#` comments, `+INF` / `-INF` / `NAN`);
206
- `real` columns are written with a decimal point so the dtype survives; `graphics [ x y z ]` maps
207
- to the position role; records map to `json` and `check()` reports `W_GML_RECORD_NUMBER_TYPE` for
208
- numbers inside them (GML cannot keep int versus real inside a record). The spec's node ids are
209
- integers; a string id is imported under the `ids` rule with one `W_GML_STRING_ID` per file, and
210
- the exporter writes integers only (`sanitizeIds: "mangle"` renumbers and keeps the original in `graphty_originalId`); column names
211
- outside `[A-Za-z][0-9A-Za-z_]*` are refused or mangled (`sanitizeKeys`). A `directed` or
212
- `multigraph` flag written as a quoted integer (`directed "1"`) is read as that integer with a
213
- `W_GML_FLAG_VALUE` warning. The `directed` key's value as the file wrote it is kept in
214
- `meta.extra.gml.directed` (absent when the file has no `directed` key), so a reader can tell
215
- `directed 0` from a file that relies on the specification's default.
216
- - **DOT**: a Graphviz-faithful parser (grammar violations are fatal, as in Graphviz); clusters are
217
- container nodes with the `parent` role; ports are kept; HTML strings keep their brackets; `pos`
218
- maps to the position role (and a trailing `!` to `pin`) unless `positions: false` keeps it as the
219
- text the file wrote, like any other attribute. Mixed direction is folded per `onMixedDirection`; a text with a
220
- backslash before a quote or a line break, or at its end, cannot be written (`E_DOT_TRAILING_BACKSLASH`: Graphviz's
221
- scanner consumes backslash pairs, so such a text has no quoted spelling).
222
- - **Pajek**: `*Vertices N` bounds the id space (ids 1..N; a 0-based file is detected and reported;
223
- a count the sink cannot reserve is fatal); `*Arcs` / `*Edges` sections give per-section
224
- direction; time intervals map to the spells role; vertex / line parameters are plain columns read
225
- through the 5.1 text grammar (`2.0` stays f64, lexical forms of a string column are kept); a
226
- `.paj` project file's `*Partition` / `*Vector` objects become the node columns `partition` (i32)
227
- and `vector` (f64) (a second one `partition#2`, ...; their Pajek names in
228
- `meta.extra.pajek.objects`), and other project sections (`*Events`, ...) are skipped with a
229
- warning; a two-mode `*Vertices N N1` reads its `*Matrix` as N1 rows of N - N1 columns. Nodes are
230
- always written 1..N (`W_ID_RENUMBERED`: the id text is kept as the label of a node without a
231
- label value, a node with one loses its id; `W_PAJEK_LABEL_GAINED` when a line's parameters force
232
- a label); `sanitizeIds: "mangle"` also writes every renumbered vertex's original id as a
233
- `graphty_originalId` parameter, which the importer restores under `restoreMangledIds` (the
234
- default; `W_ID_TEXT_TYPE` when a string id of integer text reads back as a number); a `shape`
235
- column whose values are not all shape keywords is written as a parameter; labels holding a
236
- double quote or a line break cannot be written.
237
- - **CSV**: header names resolve the endpoints (`source` / `target`, `from` / `to`, Gephi `Source` /
238
- `Target` / `Type` / `Id` / `Label` / `Weight`); a paired node table comes through the `nodes`
239
- option; the delimiter is sniffed. Leading `#` (SNAP) and `%` (KONECT) comment lines are skipped
240
- and read for the direction they declare (`# Directed graph`, `% sym` / `% asym`). A quoted empty
241
- cell is a set empty string, a bare one is unset; text after a closing quote is a fatal
242
- `E_CSV_QUOTE`. The Gephi dialect keeps per-row direction, the generic dialect drops it
243
- (`W_CSV_DIRECTION_DROPPED`). Untyped cells follow the 5.1 text grammar per column (`2.0` stays
244
- f64, `1e5` and `-0` keep their spelling in a string column). An edge table cannot carry an
245
- isolated node or the node order (`W_CSV_ISOLATED_NODES`, `W_CSV_NODE_ORDER`; write the node table).
246
- `table: "adjacency"` reads (and writes) an adjacency table: each row is a node followed by its
247
- neighbours, `neighbour:weight` giving the edge's weight when the text after the last colon is a
248
- number, and a row holding only its node adding an isolated node. It is never sniffed: nothing in
249
- its rows tells it from an edge list. The exported table keeps ids, the node order, isolated nodes,
250
- the edge order and explicit weights (a neighbour id holding a colon is written `id:` when it has no
251
- weight, and a cell holding a space, tab, `;` or `|` is quoted so the delimiter sniff still finds
252
- the comma); it holds no direction and no columns (`W_CSV_DIRECTION_DROPPED`, `W_CSV_EDGE_COLUMNS`).
253
- An empty adjacency table is the empty graph. Column options and `rowNumberIds` are refused with it
254
- (`E_UNSUPPORTED`). A node table without an id column is refused (`E_CSV_NO_ID_COLUMN`) unless
255
- `rowNumberIds: true`, which makes each data row's 0-based number its id, coerced by `ids` like any
256
- other id cell. The option applies to the node table only -- the `nodes` input when one is given,
257
- else the input itself -- and makes its first row a header even under `header: "auto"`.
258
- - **JSON**: the dialect is sniffed from the document (`dialect` forces it); the importer records the
259
- shape under `meta.extra.json` so a re-export keeps it (a d3 document is written back bare, a
260
- graphology one with only the options it declared). JSON declares no types: the capability table
261
- lists the inferred dtypes only, and `check()` names every f32 / u32 / u8 / dict / list / vector
262
- column (they come back f64 / i32 / string / json), integral f64 columns (i32) and every role the
263
- dialect has no slot for. Edge ids exist in JGF, Cytoscape, graphology and vis only; positions in
264
- Cytoscape only, stored y-up as for every Cytoscape-family format (Cytoscape's y grows downward,
265
- so it is negated at import and negated back on export). A repeated node id is merged with `W_DUPLICATE_NODE`, a repeated edge id skipped
266
- with `E_DUPLICATE_EDGE_ID`; an out-of-range d3 index link is `E_BAD_INDEX`. Non-finite numbers
267
- are written as `null` and reported. NetworkX `adjacency_data` (`nodes` plus an `adjacency` list
268
- per node; an undirected file lists each edge from both ends and it is read once) and `tree_data`
269
- (nested `id` / `children`, read as a directed tree) are read but not written: a re-export writes
270
- node-link. The bare `NaN`, `Infinity` and `-Infinity` that Python's json module writes are read as
271
- numbers (`W_JSON_NONSTANDARD_NUMBER`), and an integer literal beyond 2^53 keeps its exact digits as
272
- a string (`W_JSON_BIG_INTEGER`), so two large ids never round to one; the exporter writes an
273
- integral number that large in exponent form (`1e+20`) so it re-imports as a number. `nodesPath`
274
- and `edgesPath` point at node and edge arrays nested anywhere in the document as dotted key paths
275
- (`{ nodesPath: "data.nodes", edgesPath: "data.relationships" }`) for the node-link, d3, vis and
276
- graphology dialects; the object holding the nodes supplies the graph flags, and a path that names
277
- nothing is an `E_MISSING_SECTION` issue, not an abort. OBO Graphs (`dialect: "obographs"`, the
278
- JSON the Gene Ontology and the OBO Foundry publish: `graphs[]` of `sub` / `pred` / `obj` edges) is
279
- read only, into the same columns as the OBO importer: IRIs become the ids the `.obo` file writes
280
- (`GO:0008150`; `oboIds: "iri"` keeps them), a relation is named by its shorthand (`part_of`),
281
- PROPERTY nodes and the axiom arrays go to `meta.extra.obographs` (`typedefs: "nodes"` makes the
282
- properties nodes), and an edge endpoint missing from `nodes` becomes a placeholder node
283
- (`W_DANGLING_REFERENCE`). For a JGF or OBO Graphs `graphs` array, `graphIndex` / `graphName` (a
284
- graph's `id`, else its label) choose the graph and `listGraphs()` lists them. A document longer
285
- than one JavaScript string (about 512 MB, such as ncbitaxon.json) fails with `E_TOO_LARGE`.
286
- - **OBO** (read only): OBO 1.0, 1.2 and 1.4 read as their union, streamed line by line. `[Term]`
287
- and `[Instance]` frames are nodes; `is_a`, `relationship` and `instance_of` clauses are directed
288
- edges, child to parent, with the relation in a `relation` column (role `kind`) and a trailing
289
- `{...}` qualifier block in `qualifiers`. `[Typedef]` frames go to `meta.extra.obo.typedefs`
290
- (`typedefs: "nodes"` makes them nodes with their `is_a` edges); the header goes to
291
- `meta.extra.obo.header`. Every other tag fills the column of its name (`name` with the label
292
- role, `namespace`, `def` and `def.xrefs`, `synonym` as `{ text, scope, type, xrefs }` records,
293
- `xref`, `alt_id`, `subset`, `is_obsolete`, `property_value`, `intersection_of`, ...); an unknown
294
- tag is kept in `obo.unrecognized`, qualifiers with no other home in `obo.qualifiers` (those of
295
- one xref of a `def` or `synonym` list under `def.xrefs` / `synonym.xrefs`), a frame of
296
- an unknown type in `meta.extra.obo.unknownFrames`. Frames that share an id are merged (lists
297
- take the union, a single value keeps the first). A target no frame declares becomes a placeholder node (`graphty.placeholder`; `addMissingNodes: false` drops
298
- the edge instead). Obsolete terms are kept (`obsolete: "drop"` leaves them and their edges out).
299
- Imports and the treat-xrefs macros are kept but not applied (`W_OBO_HEADER_NOT_APPLIED`). The
300
- `\W` escape is a space, as the OBO guides define it. There is no OBO exporter: write GraphML or
301
- the graph-format container instead.
302
- - **Neo4j**: `neo4j-admin import` headers (`:ID`, `:LABEL`, `:START_ID`, `:END_ID`, `:TYPE`, typed
303
- properties, id spaces, arrays); one file may hold several sections; a `weight` property becomes
304
- THE weight; a quoted empty `:ID` is the id `""`. A node of an id space (`:ID(Product)`) is stored
305
- under the string id `Product:1`, with its id text in the `originalId` column and its space in
306
- `idSpace`, so the same id in two spaces stays two nodes; `:START_ID(Space)` / `:END_ID(Space)`
307
- resolve inside their space, and the exporter writes the id text back. Everything is directed (an undirected snapshot,
308
- or the folded pairs of a mixed one under `onMixedDirection: "directed"` / `"undirected"`, is
309
- written with a `W_NEO4J_UNDIRECTED_AS_DIRECTED` note); `.text` companions keep the source text of
310
- temporal values whose canonical form differs; a dict column reads back as string and a position
311
- or visual column as a plain property.
312
- - **XGMML**: one reader for the 1.0 draft, the Cytoscape 2.x and 3.x exports and the Cytoscape 3
313
- session network files. Direction follows the DTD (root `directed`, default 0), then `cy:directed`
314
- per edge; ids stay strings (`"1"` and `"01"` are two nodes); atts are typed by `cy:type`, then
315
- `type` (the XGMML `integer` is `i32`, widening to `f64` with `W_WIDENED` because pre-3.3
316
- Cytoscape wrote Longs that way, while a value beyond i32 under `cy:type="Integer"` or in a
317
- session's `java.lang.Integer` column is `E_BAD_VALUE`; Long `f64` or a string under
318
- `long: "string"`, lists of their element type, record lists, lists of lists and RDF as `json`);
319
- groups become `parent` / `parents`, other node-nested graphs the `cytoscape.nestedNetwork`
320
- pointer; `graphics` x and y are the position, stored y-up (Cytoscape writes screen coordinates;
321
- the exporter flips y back), z the separate `z` column (`zAs: "position"` makes it a coordinate),
322
- every other graphics value a `json` column `graphics`. Cytoscape's `\n` / `\t` escapes, label
323
- aliases (`a (pp) b`) and the two writer bugs Cytoscape repairs (`repairBareAmpersands`,
324
- `pairSurrogateReferences`, both off by default) are options. A session network document lists
325
- its registered networks through `listGraphs()`; `graphIndex` / `graphName` choose one. Dangling
326
- endpoints are `E_UNKNOWN_NODE` unless `addMissingNodes: true`. The exporter writes the Cytoscape
327
- 3 dialect (`type` plus `cy:type` on every att): f32, u8, u32 and dict are written as wider
328
- Cytoscape types, json as text, and graphty's visual roles are not translated into graphics.
329
- - **Cytoscape sessions (`.cys`)**: read only (Cytoscape opens the XGMML graph-io writes). A
330
- session is a zip of every network of a Cytoscape desktop, read with no dependency (the central
331
- directory, zip64, data descriptors, stored and deflate entries inflated through
332
- `DecompressionStream`; encryption and other methods are refused by name). One snapshot per
333
- registered network: `import()` reads the first (`graphIndex` / `graphName` choose another,
334
- `listGraphs()` lists them with their counts), `importAll()` every one. 3.x: the network file's
335
- topology, the network's CyCSV tables as columns (shared columns joined in by `cytables.xml`,
336
- HIDDEN and app tables as hidden columns under their namespace), positions from its first view
337
- (y-up; further views as `position@2`, ...) and the view's per-element values as the `graphics`
338
- column; 2.x: one XGMML per network, with `cysession.xml`'s selection and hidden state as
339
- `cytoscape.selected` / `cytoscape.hidden`. Expanded groups become `parent` / `parents`, a
340
- collapsed group's members are listed in `meta.extra.cytoscape.groups`, nested-network pointers
341
- name their network in `cytoscape.nestedNetwork`. Styles are not applied (`W_STYLES_NOT_IMPORTED`,
342
- issue #706); apps, properties and images are skipped with `W_CYS_ENTRY_SKIPPED`. Text input is
343
- refused (`E_CYS_NOT_ZIP`: pass the bytes). `maxUncompressedBytes` (default 2 GiB) and a 1000:1
344
- ratio limit stop zip bombs (`E_TOO_LARGE`).
345
-
346
- - **CX2**: the JSON exchange format of NDEx, Cytoscape 3.10+ and Cytoscape Web, read element by
347
- element so a document longer than one JavaScript string still loads. Every edge is directed;
348
- node ids are integers (an id beyond 2^53 keeps its digits as a string id, `W_PRECISION`; `"5"` and
349
- `5.0` read as 5, `W_ID_TEXT_TYPE`). Declared attributes become typed columns under their full
350
- names (the alias in `origin.id`, the default in `meta.default`); an undeclared attribute is typed
351
- from its values (`W_CX2_UNDECLARED_ATTRIBUTE`), a value of the wrong type is `E_BAD_VALUE` and its
352
- cell is unset. `name` is the label; `x` / `y` are the position, stored y-up (y negated, as for every
353
- Cytoscape-family format) and negated back on export; `z` is a stacking order in the `z` column
354
- (`zAs: "position"` puts it in the position). Per-element visual values (`nodeBypasses`,
355
- `edgeBypasses`) are one column per visual property (origin namespace `cx2.bypass`); style rules
356
- (`visualProperties`, `visualEditorProperties`) and opaque aspects are kept verbatim in
357
- `meta.extra.cx2.opaque` and written back, but not applied (`W_STYLES_NOT_IMPORTED`). A missing
358
- `status` is `E_CX2_NO_STATUS`, `success: false` is fatal (`E_STATUS_FAILED`), an edge to an unknown
359
- node is `E_UNKNOWN_NODE` (`addMissingNodes: true` creates it, as Cytoscape does). The exporter
360
- refuses non-integer node ids unless `sanitizeIds: "mangle"`, which keeps the original in a
361
- `graphty:originalId` attribute the importer turns back into the id; NaN and the infinities are
362
- written as null (`W_CX2_NONFINITE_AS_NULL`), nested values as JSON text (`W_CX2_JSON_AS_STRING`).
363
-
364
- - **CX** (version 1, `@graphty/graph-io/cx`, `.cx`; read only -- CX2 is what NDEx and Cytoscape
365
- write today): aspect fragments in any order, read element by element. Ids follow the CX2 rule;
366
- `n` is the `name` label, `r` is `represents`, `i` is `interaction`; attributes are typed by their
367
- `d` with Cytoscape's value rule (`""` and `"null"` are unset, `"NaN"` is NaN in a double), several
368
- types for one name widen (`W_WIDENED`). A collection (several `cySubNetworks`) is one graph per
369
- subnetwork: `listGraphs()` lists them, `import()` reads the one `graphIndex` / `graphName` picks
370
- (the first by default, `W_MULTIPLE_GRAPHS`), `importAll()` reads them all; a subnetwork's own
371
- values (`s`) beat the shared ones, and nodes or edges no subnetwork holds are not read
372
- (`W_CX_ROOT_ONLY`). Positions come from the subnetwork's view (y negated to y-up,
373
- other views as `position@2`, ...); `cyGroups` give `parent` or `parents` (a group whose id is
374
- not a node gets one, `W_CX_GROUP_NODE_ADDED`); per-element `cyVisualProperties` of that view are
375
- one column per property (origin namespace `cx.bypass`) and style rules are kept in `meta.extra.cx`
376
- (`W_STYLES_NOT_IMPORTED`); citations and supports become the extension tables `cx:citations` /
377
- `cx:supports`. Old aspect names (`visualProperties`, `subNetworks`, ...) are read with
378
- `W_CX_OLD_ASPECT_NAME`; a CX2 document is refused naming the CX2 importer (`E_CX_NOT_CX`).
379
-
380
- ## Format detection
381
-
382
- `sniff({ filename?, mimeType?, head? })` ranks the registered importers: a content match scores
383
- at least 0.5 (`0.5 + 0.35 * content + 0.1 * extension + 0.05 * MIME`), a hint alone at most 0.4,
384
- so the content always beats a misleading extension (a `.csv` with a neo4j-admin header is Neo4j, a
385
- `.xml` is GEXF or GraphML by its root element). `sniffJsonDialectHead()` reports the JSON dialect a
386
- head suggests. `importGraph()` reads at most `SNIFF_HEAD_BYTES` (8 KiB) of a stream before deciding
387
- and replays them to the importer.
388
-
389
- ## The import report
390
-
391
- Every import returns an `ImportReport` (design section 8.6):
392
-
393
- ```ts
394
- interface ImportReport {
395
- format: string; // "gexf", ...
396
- counts: { nodes; edges; skippedNodes; skippedEdges; expandedMixed }; // edges counts both halves of an expanded edge
397
- issues: ImportIssue[]; // in order: { category, severity, code, message, line, element }
398
- errorCount: number; // issues with severity "error"; they count toward errorLimit
399
- warningCount: number;
400
- truncated: boolean; // the error limit was reached and the import aborted
401
- lossy: LossNote[]; // what the importer could not represent: { code, message, column, count }
402
- durationMs: number; // the parse phase; the freeze reports separately
34
+ console.log(`${format}: ${snapshot.nodeCount} nodes, ${snapshot.edgeCount} edges`);
35
+ for (const issue of report.issues) {
36
+ console.warn(`${issue.code} line ${issue.line ?? "-"}: ${issue.message}`);
403
37
  }
38
+ await writeFile("got-network.gexf", await exportGraphToBytes(snapshot, "gexf"));
404
39
  ```
405
40
 
406
- Issue categories are `parse-error`, `missing-value`, `validation-error`, `unsupported`, `precision`,
407
- `coercion` and `merged`. Codes are stable strings (`E_*` errors, `W_*` warnings) exported per format
408
- (`GEXF_ISSUE`, `GRAPHML_ISSUE`, `GML_ISSUE`, `DOT_ISSUE`, `PAJEK_ISSUE`, `CSV_ISSUE`,
409
- `JSON_ISSUE`, `NEO4J_ISSUE`) and shared across formats (`SINK_OPTION_CODE`, `ID_MERGED_CODE`,
410
- `DIRECTION_REFUSED_CODE`, `DIRECTION_FORCED_CODE`, `RENAMED_CODE`, `PRECISION_CODE`,
411
- `INVALID_UTF8_CODE`, `INVALID_ENCODING_CODE`, `ENCODING_FALLBACK_CODE`, `UNKNOWN_ENCODING_CODE`,
412
- `PARSE_ERROR_CODE`). The builder throws on the first hard error; the importer
413
- catches it per element, records an issue, skips the element and continues until `errorLimit`, then
414
- throws `ImportError` (`code === "E_IMPORT"`) carrying the partial report. An input that cannot be
415
- read at all (bytes invalid in the chosen encoding, malformed XML, no recognisable format) is an
416
- `ImportError` at once.
417
-
418
- ## Writing a plugin
419
-
420
- `GraphImporter` and `GraphExporter` (design section 12.4) are plain objects; the helpers every
421
- built-in format is built on are exported for third-party plugins: `ImportReportBuilder` (issues,
422
- error limit, `warnOnce`, `ImportError`), `textChunks` / `readText` / `LineReader` (streaming
423
- input decoded by the shared encoding rules, with cancellation and progress), `tokenizeXml` / `XmlTokenizer` (the streaming XML tokenizer
424
- behind GEXF and GraphML), `resolveImportOptions` / `resolveExportOptions` / `reportSinkOptions` /
425
- `reportUnusedOptions`, `DirectionResolver` (the mixed-direction rules of section 8.4) and
426
- `pairFolding` (its inverse for exporters), `IdCoercer`, `parseTextCell` and `TextCellWriter` (the
427
- text grammar of section 5.1, per column, with the lexical forms kept), `declareResolved` (the 5.6
428
- collision rule), `explicitWeights` (the weight role column's validity, section 3.7),
429
- `checkCapabilities` (with `CheckExtras` for the roles a format has a slot for) / `sanitizeIds` /
430
- `LOSS` / `xmlIllegalTextNotes`, the shared issue and loss codes of `codes.ts`, `formatDecimal` and
431
- `encodeChunks` / `joinText`. Register a plugin with `registry.registerImporter()` /
432
- `registerExporter()` or build a registry of your own with `new FormatRegistry()`. The `children`
433
- CSR helper (`childrenCsr`) inverts a `parent` / `parents` containment column for nested writers.
41
+ <!-- generated:end -->
42
+
43
+ **Start with the
44
+ [Quick start](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/quick-start.md)**:
45
+ load files from URLs and file pickers, use the graph data, check what a save would lose, and
46
+ handle errors. The rest of the guide, including how to add a format of your own, is in the same
47
+ [docs/guide](https://github.com/graphty-org/graphty-monorepo/tree/master/graph-io/docs/guide)
48
+ directory, and the sample files its examples read are in
49
+ [docs/samples](https://github.com/graphty-org/graphty-monorepo/tree/master/graph-io/docs/samples)
50
+ and in the package's `docs/samples/` directory.
51
+ The guide and the API reference are also published at
52
+ [graphty.app/docs/graph-io](https://graphty.app/docs/graph-io/).
53
+
54
+ Formats: [JSON](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/json.md) (NetworkX, d3, JGF,
55
+ Cytoscape.js, graphology, vis.js, OBO Graphs),
56
+ [GraphML](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/graphml.md),
57
+ [GEXF](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/gexf.md),
58
+ [CSV and TSV](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/csv.md),
59
+ [GML](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/gml.md),
60
+ [DOT](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/dot.md),
61
+ [Pajek](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/pajek.md),
62
+ [Neo4j CSV](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/neo4j.md),
63
+ [XGMML](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/xgmml.md),
64
+ [CX2](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/cx2.md),
65
+ [CX](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/cx.md),
66
+ [OBO](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/obo.md) and
67
+ [Cytoscape sessions](https://github.com/graphty-org/graphty-monorepo/blob/master/graph-io/docs/guide/formats/cys.md). Each one is read and
68
+ written.
434
69
 
435
70
  ## License
436
71
 
@@ -1 +1 @@
1
- {"version":3,"file":"children-CL3Cy0ez.js","sources":["../../src/children.ts"],"sourcesContent":["/**\n * The children CSR over a containment column (design sections 5.10, 7.1 and 8.2): containment\n * (GEXF `pid` / `<parents>`, Cytoscape `parent`, DOT clusters, GraphML nested graphs) is a node\n * column with the `parent` role (u32, refersTo node) or the `parents` role (list of u32) and never\n * enters the CSR of the snapshot. Importers and exporters that need to walk containers top-down\n * (nested subgraphs, cluster blocks, parent lists) build this inverse index once: for every node\n * `u`, `children[rowPtr[u] .. rowPtr[u + 1])` are its children in ascending index order, `roots`\n * are the nodes with no parent, and `depthFirst()` is the pre-order the nested writers use.\n *\n * The helper is deliberately outside the core (7.1: it computes a property the arrays do not\n * already imply and only io needs it). A reference is ignored when it is unset, INVALID_INDEX, out\n * of range, or the node itself; a cycle (a parent chain that never reaches a root) is reported\n * through `unreachable` and its members are appended to the depth-first order in index order so\n * every node is written exactly once.\n */\n\nimport { type Column, type GraphSnapshot, INVALID_INDEX } from \"@graphty/graph-format\";\n\n/** The role of the column a children CSR is built over. */\nexport type ContainmentRole = \"parent\" | \"parents\";\n\n/** How the CSR is built: from a role column of the snapshot (default `parent`, then `parents`) or an explicit column. */\nexport interface ChildrenOptions {\n /**\n * The column to read: a role name (`parent` for the u32 single-parent column, `parents` for\n * the list column) or a column object of either shape; \"auto\" (default) takes the `parent`\n * role column when the snapshot has one, else `parents`, else no containment; null builds\n * the empty CSR (every node a root) whatever the snapshot holds.\n */\n readonly column?: ContainmentRole | Column | \"auto\" | null | undefined;\n}\n\n/** One depth-first traversal of the containment forest. */\nexport interface DepthFirstOrder {\n /** Every node index exactly once: roots in index order, each followed by its descendants, cycle members last. */\n readonly order: Uint32Array;\n /** The depth of every node in the traversal (0 for a root or a cycle member forced to the top). */\n readonly depth: Uint32Array;\n /** Whether `order` differs from `0..n-1`. */\n readonly reordered: boolean;\n}\n\n/**\n * The children CSR of a snapshot's containment column (design sections 5.10 and 7.1): the inverse\n * of the parent relation as a compressed sparse row structure over node indices.\n */\nexport class ChildrenCsr {\n /** The number of nodes (the row count of the CSR). */\n readonly nodeCount: number;\n /** `rowPtr[u] .. rowPtr[u + 1]` is the range of `children` holding the children of `u`; length nodeCount + 1. */\n readonly rowPtr: Uint32Array;\n /** Child node indices, ascending within each parent's range. */\n readonly children: Uint32Array;\n /** The nodes with no (valid) parent, in index order. */\n readonly roots: Uint32Array;\n /** Every (child, parent) reference kept; equal to `children.length`. */\n readonly edgeCount: number;\n /** References dropped because they were INVALID_INDEX, out of range or self-references. */\n readonly dropped: number;\n /** Nodes whose parent chain never reaches a root (members of a cycle), counted once each. */\n readonly unreachable: number;\n /** The column the CSR was built from, or null when the snapshot has no containment. */\n readonly column: Column | null;\n\n private readonly parentCount: Uint32Array;\n\n /**\n * Build the CSR; use childrenCsr() rather than the constructor.\n * @param nodeCount - the node count\n * @param rowPtr - the row pointers\n * @param children - the child list\n * @param parentCount - parents per node (0 for a root)\n * @param dropped - references ignored\n * @param column - the source column, or null\n */\n constructor(\n nodeCount: number,\n rowPtr: Uint32Array,\n children: Uint32Array,\n parentCount: Uint32Array,\n dropped: number,\n column: Column | null,\n ) {\n this.nodeCount = nodeCount;\n this.rowPtr = rowPtr;\n this.children = children;\n this.parentCount = parentCount;\n this.edgeCount = children.length;\n this.dropped = dropped;\n this.column = column;\n let rootCount = 0;\n for (let u = 0; u < nodeCount; u++) {\n if (parentCount[u] === 0) {\n rootCount++;\n }\n }\n const roots = new Uint32Array(rootCount);\n let r = 0;\n for (let u = 0; u < nodeCount; u++) {\n if (parentCount[u] === 0) {\n roots[r++] = u;\n }\n }\n this.roots = roots;\n this.unreachable = nodeCount - this.reachableCount();\n }\n\n /**\n * The children of a node, as a view into `children` (do not modify).\n * @param node - the node index\n * @returns the child indices in ascending order; empty for a leaf\n */\n childrenOf(node: number): Uint32Array {\n return this.children.subarray(this.rowPtr[node], this.rowPtr[node + 1]);\n }\n\n /**\n * How many children a node has.\n * @param node - the node index\n * @returns the count\n */\n childCount(node: number): number {\n return this.rowPtr[node + 1] - this.rowPtr[node];\n }\n\n /**\n * Whether a node is a container (has at least one child).\n * @param node - the node index\n * @returns true when it has children\n */\n hasChildren(node: number): boolean {\n return this.rowPtr[node + 1] > this.rowPtr[node];\n }\n\n /**\n * How many parents a node has: 0 for a root, 1 under a `parent` column, any number under `parents`.\n * @param node - the node index\n * @returns the parent count\n */\n parentCountOf(node: number): number {\n return this.parentCount[node];\n }\n\n /**\n * Whether a node has no parent.\n * @param node - the node index\n * @returns true for a root\n */\n isRoot(node: number): boolean {\n return this.parentCount[node] === 0;\n }\n\n /**\n * Whether the snapshot has any containment at all.\n * @returns true when at least one child reference was kept\n */\n isEmpty(): boolean {\n return this.edgeCount === 0;\n }\n\n /**\n * A pre-order depth-first traversal from the roots in index order (children in ascending\n * order), then every node not yet visited (a cycle member, or a multi-parent node reached\n * only through a cycle) in index order at depth 0. Each node appears exactly once, so nested\n * writers emit every element once even for a `parents` column that shares a child.\n * @returns the order, the depth of every node and whether the order differs from index order\n */\n depthFirst(): DepthFirstOrder {\n const n = this.nodeCount;\n const order = new Uint32Array(n);\n const depth = new Uint32Array(n);\n const visited = new Uint8Array(n);\n const stackNode: number[] = [];\n const stackCursor: number[] = [];\n let position = 0;\n let reordered = false;\n const place = (u: number, d: number): void => {\n visited[u] = 1;\n if (u !== position) {\n reordered = true;\n }\n order[position++] = u;\n depth[u] = d;\n };\n const visit = (root: number): void => {\n place(root, 0);\n stackNode.push(root);\n stackCursor.push(this.rowPtr[root]);\n while (stackNode.length > 0) {\n const top = stackNode.length - 1;\n const u = stackNode[top];\n const cursor = stackCursor[top];\n if (cursor >= this.rowPtr[u + 1]) {\n stackNode.pop();\n stackCursor.pop();\n continue;\n }\n stackCursor[top] = cursor + 1;\n const v = this.children[cursor];\n if (visited[v] === 1) {\n continue;\n }\n place(v, stackNode.length);\n stackNode.push(v);\n stackCursor.push(this.rowPtr[v]);\n }\n };\n for (const root of this.roots) {\n visit(root);\n }\n for (let u = 0; u < n; u++) {\n if (visited[u] === 0) {\n visit(u);\n }\n }\n return { order, depth, reordered };\n }\n\n /**\n * The nodes reachable from the roots by following child references.\n * @returns how many nodes a traversal from the roots reaches\n */\n private reachableCount(): number {\n const visited = new Uint8Array(this.nodeCount);\n // every node is pushed at most once, so a stack of nodeCount entries never overflows\n const stack = new Uint32Array(this.nodeCount);\n let top = 0;\n let count = 0;\n for (const root of this.roots) {\n visited[root] = 1;\n count++;\n stack[top++] = root;\n while (top > 0) {\n const u = stack[--top];\n for (let k = this.rowPtr[u]; k < this.rowPtr[u + 1]; k++) {\n const v = this.children[k];\n if (visited[v] === 0) {\n visited[v] = 1;\n count++;\n stack[top++] = v;\n }\n }\n }\n }\n return count;\n }\n}\n\n/**\n * Build the children CSR of a snapshot (design section 7.1: a graph-io helper, not a core view).\n * @param snapshot - the snapshot\n * @param options - which column to read; the `parent` role, then `parents`, by default\n * @returns the CSR; empty (every node a root) when the snapshot has no containment column\n */\nexport function childrenCsr(snapshot: GraphSnapshot, options: ChildrenOptions = {}): ChildrenCsr {\n const column = resolveColumn(snapshot, options.column === undefined ? \"auto\" : options.column);\n return childrenFromColumn(snapshot.nodeCount, column);\n}\n\n/**\n * Build the children CSR over one containment column without a snapshot (an importer that holds\n * the column before freezing, a test).\n * @param nodeCount - the node count the references index into\n * @param column - a u32 `parent`-shaped column, a list-of-u32 `parents`-shaped column, or null for none\n * @returns the CSR\n */\nexport function childrenFromColumn(nodeCount: number, column: Column | null): ChildrenCsr {\n const rowPtr = new Uint32Array(nodeCount + 1);\n const parentCount = new Uint32Array(nodeCount);\n let dropped = 0;\n const references: number[] = [];\n if (column !== null) {\n const rows = Math.min(column.length, nodeCount);\n const keep = (child: number, parent: number): void => {\n if (!Number.isInteger(parent) || parent === INVALID_INDEX || parent >= nodeCount || parent === child) {\n dropped++;\n return;\n }\n references.push(child, parent);\n rowPtr[parent + 1]++;\n parentCount[child]++;\n };\n if (column.dtype === \"u32\") {\n const { data } = column;\n for (let i = 0; i < rows; i++) {\n if (column.isSet(i)) {\n keep(i, data[i]);\n }\n }\n } else if (column.dtype === \"list\") {\n for (let i = 0; i < rows; i++) {\n if (!column.isSet(i)) {\n continue;\n }\n for (const item of column.sliceOf(i)) {\n if (typeof item === \"number\") {\n keep(i, item);\n } else {\n dropped++;\n }\n }\n }\n } else {\n throw new TypeError(\n `a containment column must be u32 or a list of u32, found ${column.dtype} column \"${column.meta.name}\"`,\n );\n }\n }\n for (let u = 0; u < nodeCount; u++) {\n rowPtr[u + 1] += rowPtr[u];\n }\n const children = new Uint32Array(rowPtr[nodeCount]);\n const fill = rowPtr.slice(0, nodeCount);\n // references were collected in ascending child order, so each parent's range fills ascending\n for (let k = 0; k < references.length; k += 2) {\n children[fill[references[k + 1]]++] = references[k];\n }\n return new ChildrenCsr(nodeCount, rowPtr, children, parentCount, dropped, column);\n}\n\n/**\n * The column a ChildrenOptions selects.\n * @param snapshot - the snapshot\n * @param choice - the option value\n * @returns the column, or null when the snapshot has none of that shape\n */\nfunction resolveColumn(snapshot: GraphSnapshot, choice: ContainmentRole | Column | \"auto\" | null): Column | null {\n if (typeof choice !== \"string\") {\n return choice;\n }\n if (choice === \"parent\" || choice === \"parents\") {\n return snapshot.nodes.byRole(choice);\n }\n return snapshot.nodes.byRole(\"parent\") ?? snapshot.nodes.byRole(\"parents\");\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"children-CL3Cy0ez.js","sources":["../../src/children.ts"],"sourcesContent":["/**\n * The children CSR over a containment column: containment\n * (GEXF `pid` / `<parents>`, Cytoscape `parent`, DOT clusters, GraphML nested graphs) is a node\n * column with the `parent` role (u32, refersTo node) or the `parents` role (list of u32) and never\n * enters the CSR of the snapshot. Importers and exporters that need to walk containers top-down\n * (nested subgraphs, cluster blocks, parent lists) build this inverse index once: for every node\n * `u`, `children[rowPtr[u] .. rowPtr[u + 1])` are its children in ascending index order, `roots`\n * are the nodes with no parent, and `depthFirst()` is the pre-order the nested writers use.\n *\n * The helper is deliberately outside the core (7.1: it computes a property the arrays do not\n * already imply and only io needs it). A reference is ignored when it is unset, INVALID_INDEX, out\n * of range, or the node itself; a cycle (a parent chain that never reaches a root) is reported\n * through `unreachable` and its members are appended to the depth-first order in index order so\n * every node is written exactly once.\n */\n\nimport { type Column, type GraphSnapshot, INVALID_INDEX } from \"@graphty/graph-format\";\n\n/**\n * The role of the column a children CSR is built over.\n * @category Plugin helpers\n */\nexport type ContainmentRole = \"parent\" | \"parents\";\n\n/**\n * How the CSR is built: from a role column of the snapshot (default `parent`, then `parents`) or an explicit column.\n * @category Plugin helpers\n */\nexport interface ChildrenOptions {\n /**\n * The column to read: a role name (`parent` for the u32 single-parent column, `parents` for\n * the list column) or a column object of either shape; \"auto\" (default) takes the `parent`\n * role column when the snapshot has one, else `parents`, else no containment; null builds\n * the empty CSR (every node a root) whatever the snapshot holds.\n */\n readonly column?: ContainmentRole | Column | \"auto\" | null | undefined;\n}\n\n/**\n * One depth-first traversal of the containment forest.\n * @category Plugin helpers\n */\nexport interface DepthFirstOrder {\n /** Every node index exactly once: roots in index order, each followed by its descendants, cycle members last. */\n readonly order: Uint32Array;\n /** The depth of every node in the traversal (0 for a root or a cycle member forced to the top). */\n readonly depth: Uint32Array;\n /** Whether `order` differs from `0..n-1`. */\n readonly reordered: boolean;\n}\n\n/**\n * The children CSR of a snapshot's containment column: the inverse\n * of the parent relation as a compressed sparse row structure over node indices.\n * @category Plugin helpers\n */\nexport class ChildrenCsr {\n /** The number of nodes (the row count of the CSR). */\n readonly nodeCount: number;\n /** `rowPtr[u] .. rowPtr[u + 1]` is the range of `children` holding the children of `u`; length nodeCount + 1. */\n readonly rowPtr: Uint32Array;\n /** Child node indices, ascending within each parent's range. */\n readonly children: Uint32Array;\n /** The nodes with no (valid) parent, in index order. */\n readonly roots: Uint32Array;\n /** Every (child, parent) reference kept; equal to `children.length`. */\n readonly edgeCount: number;\n /** References dropped because they were INVALID_INDEX, out of range or self-references. */\n readonly dropped: number;\n /** Nodes whose parent chain never reaches a root (members of a cycle), counted once each. */\n readonly unreachable: number;\n /** The column the CSR was built from, or null when the snapshot has no containment. */\n readonly column: Column | null;\n\n private readonly parentCount: Uint32Array;\n\n /**\n * Build the CSR; use childrenCsr() rather than the constructor.\n * @param nodeCount - the node count\n * @param rowPtr - the row pointers\n * @param children - the child list\n * @param parentCount - parents per node (0 for a root)\n * @param dropped - references ignored\n * @param column - the source column, or null\n */\n constructor(\n nodeCount: number,\n rowPtr: Uint32Array,\n children: Uint32Array,\n parentCount: Uint32Array,\n dropped: number,\n column: Column | null,\n ) {\n this.nodeCount = nodeCount;\n this.rowPtr = rowPtr;\n this.children = children;\n this.parentCount = parentCount;\n this.edgeCount = children.length;\n this.dropped = dropped;\n this.column = column;\n let rootCount = 0;\n for (let u = 0; u < nodeCount; u++) {\n if (parentCount[u] === 0) {\n rootCount++;\n }\n }\n const roots = new Uint32Array(rootCount);\n let r = 0;\n for (let u = 0; u < nodeCount; u++) {\n if (parentCount[u] === 0) {\n roots[r++] = u;\n }\n }\n this.roots = roots;\n this.unreachable = nodeCount - this.reachableCount();\n }\n\n /**\n * The children of a node, as a view into `children` (do not modify).\n * @param node - the node index\n * @returns the child indices in ascending order; empty for a leaf\n */\n childrenOf(node: number): Uint32Array {\n return this.children.subarray(this.rowPtr[node], this.rowPtr[node + 1]);\n }\n\n /**\n * How many children a node has.\n * @param node - the node index\n * @returns the count\n */\n childCount(node: number): number {\n return this.rowPtr[node + 1] - this.rowPtr[node];\n }\n\n /**\n * Whether a node is a container (has at least one child).\n * @param node - the node index\n * @returns true when it has children\n */\n hasChildren(node: number): boolean {\n return this.rowPtr[node + 1] > this.rowPtr[node];\n }\n\n /**\n * How many parents a node has: 0 for a root, 1 under a `parent` column, any number under `parents`.\n * @param node - the node index\n * @returns the parent count\n */\n parentCountOf(node: number): number {\n return this.parentCount[node];\n }\n\n /**\n * Whether a node has no parent.\n * @param node - the node index\n * @returns true for a root\n */\n isRoot(node: number): boolean {\n return this.parentCount[node] === 0;\n }\n\n /**\n * Whether the snapshot has any containment at all.\n * @returns true when at least one child reference was kept\n */\n isEmpty(): boolean {\n return this.edgeCount === 0;\n }\n\n /**\n * A pre-order depth-first traversal from the roots in index order (children in ascending\n * order), then every node not yet visited (a cycle member, or a multi-parent node reached\n * only through a cycle) in index order at depth 0. Each node appears exactly once, so nested\n * writers emit every element once even for a `parents` column that shares a child.\n * @returns the order, the depth of every node and whether the order differs from index order\n */\n depthFirst(): DepthFirstOrder {\n const n = this.nodeCount;\n const order = new Uint32Array(n);\n const depth = new Uint32Array(n);\n const visited = new Uint8Array(n);\n const stackNode: number[] = [];\n const stackCursor: number[] = [];\n let position = 0;\n let reordered = false;\n const place = (u: number, d: number): void => {\n visited[u] = 1;\n if (u !== position) {\n reordered = true;\n }\n order[position++] = u;\n depth[u] = d;\n };\n const visit = (root: number): void => {\n place(root, 0);\n stackNode.push(root);\n stackCursor.push(this.rowPtr[root]);\n while (stackNode.length > 0) {\n const top = stackNode.length - 1;\n const u = stackNode[top];\n const cursor = stackCursor[top];\n if (cursor >= this.rowPtr[u + 1]) {\n stackNode.pop();\n stackCursor.pop();\n continue;\n }\n stackCursor[top] = cursor + 1;\n const v = this.children[cursor];\n if (visited[v] === 1) {\n continue;\n }\n place(v, stackNode.length);\n stackNode.push(v);\n stackCursor.push(this.rowPtr[v]);\n }\n };\n for (const root of this.roots) {\n visit(root);\n }\n for (let u = 0; u < n; u++) {\n if (visited[u] === 0) {\n visit(u);\n }\n }\n return { order, depth, reordered };\n }\n\n /**\n * The nodes reachable from the roots by following child references.\n * @returns how many nodes a traversal from the roots reaches\n */\n private reachableCount(): number {\n const visited = new Uint8Array(this.nodeCount);\n // every node is pushed at most once, so a stack of nodeCount entries never overflows\n const stack = new Uint32Array(this.nodeCount);\n let top = 0;\n let count = 0;\n for (const root of this.roots) {\n visited[root] = 1;\n count++;\n stack[top++] = root;\n while (top > 0) {\n const u = stack[--top];\n for (let k = this.rowPtr[u]; k < this.rowPtr[u + 1]; k++) {\n const v = this.children[k];\n if (visited[v] === 0) {\n visited[v] = 1;\n count++;\n stack[top++] = v;\n }\n }\n }\n }\n return count;\n }\n}\n\n/**\n * Build the children CSR of a snapshot.\n * @param snapshot - the snapshot\n * @param options - which column to read; the `parent` role, then `parents`, by default\n * @returns the CSR; empty (every node a root) when the snapshot has no containment column\n * @category Plugin helpers\n */\nexport function childrenCsr(snapshot: GraphSnapshot, options: ChildrenOptions = {}): ChildrenCsr {\n const column = resolveColumn(snapshot, options.column === undefined ? \"auto\" : options.column);\n return childrenFromColumn(snapshot.nodeCount, column);\n}\n\n/**\n * Build the children CSR over one containment column without a snapshot (an importer that holds\n * the column before freezing, a test).\n * @param nodeCount - the node count the references index into\n * @param column - a u32 `parent`-shaped column, a list-of-u32 `parents`-shaped column, or null for none\n * @returns the CSR\n * @category Plugin helpers\n */\nexport function childrenFromColumn(nodeCount: number, column: Column | null): ChildrenCsr {\n const rowPtr = new Uint32Array(nodeCount + 1);\n const parentCount = new Uint32Array(nodeCount);\n let dropped = 0;\n const references: number[] = [];\n if (column !== null) {\n const rows = Math.min(column.length, nodeCount);\n const keep = (child: number, parent: number): void => {\n if (!Number.isInteger(parent) || parent === INVALID_INDEX || parent >= nodeCount || parent === child) {\n dropped++;\n return;\n }\n references.push(child, parent);\n rowPtr[parent + 1]++;\n parentCount[child]++;\n };\n if (column.dtype === \"u32\") {\n const { data } = column;\n for (let i = 0; i < rows; i++) {\n if (column.isSet(i)) {\n keep(i, data[i]);\n }\n }\n } else if (column.dtype === \"list\") {\n for (let i = 0; i < rows; i++) {\n if (!column.isSet(i)) {\n continue;\n }\n for (const item of column.sliceOf(i)) {\n if (typeof item === \"number\") {\n keep(i, item);\n } else {\n dropped++;\n }\n }\n }\n } else {\n throw new TypeError(\n `a containment column must be u32 or a list of u32, found ${column.dtype} column \"${column.meta.name}\"`,\n );\n }\n }\n for (let u = 0; u < nodeCount; u++) {\n rowPtr[u + 1] += rowPtr[u];\n }\n const children = new Uint32Array(rowPtr[nodeCount]);\n const fill = rowPtr.slice(0, nodeCount);\n // references were collected in ascending child order, so each parent's range fills ascending\n for (let k = 0; k < references.length; k += 2) {\n children[fill[references[k + 1]]++] = references[k];\n }\n return new ChildrenCsr(nodeCount, rowPtr, children, parentCount, dropped, column);\n}\n\n/**\n * The column a ChildrenOptions selects.\n * @param snapshot - the snapshot\n * @param choice - the option value\n * @returns the column, or null when the snapshot has none of that shape\n */\nfunction resolveColumn(snapshot: GraphSnapshot, choice: ContainmentRole | Column | \"auto\" | null): Column | null {\n if (typeof choice !== \"string\") {\n return choice;\n }\n if (choice === \"parent\" || choice === \"parents\") {\n return snapshot.nodes.byRole(choice);\n }\n return snapshot.nodes.byRole(\"parent\") ?? snapshot.nodes.byRole(\"parents\");\n}\n"],"names":[],"mappings":"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"}