@graphty/graph-io 0.3.24 → 0.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-BbJI55dx.js +56 -0
  4. package/dist/chunks/choose-BbJI55dx.js.map +1 -0
  5. package/dist/chunks/constants-BCsFsMj4.js +231 -0
  6. package/dist/chunks/constants-BCsFsMj4.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D0g6NNUy.js} +382 -92
  8. package/dist/chunks/escape-D0g6NNUy.js.map +1 -0
  9. package/dist/chunks/export-BTI4yQgy.js +4333 -0
  10. package/dist/chunks/export-BTI4yQgy.js.map +1 -0
  11. package/dist/chunks/exporter-BMqk5oxW.js +3465 -0
  12. package/dist/chunks/exporter-BMqk5oxW.js.map +1 -0
  13. package/dist/chunks/{importer-eUREhBGj.js → exporter-Cra2GYcN.js} +4969 -3201
  14. package/dist/chunks/exporter-Cra2GYcN.js.map +1 -0
  15. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-Dxh231ZF.js} +38 -229
  16. package/dist/chunks/exporter-Dxh231ZF.js.map +1 -0
  17. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-tne475KK.js} +22 -20
  18. package/dist/chunks/exporter-tne475KK.js.map +1 -0
  19. package/dist/chunks/importer-90YWhJoF.js +2811 -0
  20. package/dist/chunks/importer-90YWhJoF.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-Bcl1d4xH.js} +398 -145
  22. package/dist/chunks/importer-Bcl1d4xH.js.map +1 -0
  23. package/dist/chunks/{importer-BWY2FFc5.js → importer-BfIsp1f9.js} +255 -77
  24. package/dist/chunks/importer-BfIsp1f9.js.map +1 -0
  25. package/dist/chunks/{importer-zGLo8Dg_.js → importer-C_TEA1zJ.js} +484 -157
  26. package/dist/chunks/importer-C_TEA1zJ.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-DCjOvO7U.js} +1687 -310
  28. package/dist/chunks/importer-DCjOvO7U.js.map +1 -0
  29. package/dist/chunks/{importer-vi3bSdtw.js → importer-DfVu6j59.js} +509 -76
  30. package/dist/chunks/importer-DfVu6j59.js.map +1 -0
  31. package/dist/chunks/{importer-DIrbbnAf.js → importer-Dku_VAIY.js} +585 -226
  32. package/dist/chunks/importer-Dku_VAIY.js.map +1 -0
  33. package/dist/chunks/json-elements-3tnyt5uZ.js +1225 -0
  34. package/dist/chunks/json-elements-3tnyt5uZ.js.map +1 -0
  35. package/dist/chunks/ontology-export-B9Tcf37D.js +357 -0
  36. package/dist/chunks/ontology-export-B9Tcf37D.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CQXT__mY.js} +298 -114
  38. package/dist/chunks/records-CQXT__mY.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DmcUs5_Q.js} +29 -11
  40. package/dist/chunks/text-DmcUs5_Q.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +951 -261
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +342 -85
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +564 -157
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +19 -1
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +33 -17
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +868 -188
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +2 -0
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +400 -83
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +145 -32
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +680 -285
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +226 -79
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +98 -24
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +108 -26
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +238 -85
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +66 -34
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +183 -51
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +20 -21
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +7 -2
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +38 -4
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +33 -17
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1034 -198
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +6 -1
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +477 -88
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +201 -46
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +888 -300
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +61 -338
  498. package/src/formats/cx2/importer.ts +317 -86
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +139 -31
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +111 -26
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +320 -101
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +89 -41
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +213 -52
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +35 -27
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +11 -3
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -39,6 +39,7 @@ import { capabilities, checkCapabilities, LOSS } from "../../common/export.js";
39
39
  import { formatF32, formatF64, formatInteger } from "../../common/format.js";
40
40
  import { isCanonicalIntegerText } from "../../common/ids.js";
41
41
  import { type ResolvedExportOptions, resolveExportOptions } from "../../common/options.js";
42
+ import { agree, plural } from "../../common/plural.js";
42
43
  import { formatTemporal, type TemporalKind } from "../../common/temporal.js";
43
44
  import { type ExplicitWeights, explicitWeights } from "../../common/weights.js";
44
45
  import { encodeChunks, joinText } from "../../common/writer.js";
@@ -47,50 +48,100 @@ import { checkRecordSyntax, type RecordSyntax } from "../csv/records.js";
47
48
  import { formatHeaderField } from "./header.js";
48
49
  import { ID_SPACE_COLUMN, LABELS_COLUMN, TYPE_COLUMN } from "./importer.js";
49
50
 
50
- /** The format-specific options of the Neo4j exporter. */
51
- export interface Neo4jExportOptions {
52
- /** Which tables to write: both (node sections first; default), the node sections or the relationship sections. */
51
+ /**
52
+ * The format-specific options of the Neo4j exporter.
53
+ * @category Built-in formats
54
+ */
55
+ export interface Neo4jExportOptions extends CommonExportOptions {
56
+ /**
57
+ * Which tables to write: "all" (the node sections, then the relationship sections), "nodes" or
58
+ * "relationships".
59
+ * @defaultValue "all"
60
+ */
53
61
  part?: "all" | "nodes" | "relationships" | undefined;
54
- /** The field delimiter; one character; "," by default. */
62
+ /**
63
+ * The field delimiter, one character. It must differ from `arrayDelimiter`: with
64
+ * `delimiter: ";"`, also pass `arrayDelimiter: ","` or `"|"`.
65
+ * @defaultValue ","
66
+ */
55
67
  delimiter?: string | undefined;
56
- /** The array delimiter of list values and `:LABEL` cells; ";" by default. */
68
+ /**
69
+ * The delimiter inside list values and `:LABEL` cells. It must differ from `delimiter`.
70
+ * @defaultValue ";"
71
+ */
57
72
  arrayDelimiter?: ";" | "," | "|" | undefined;
58
- /** The quote character; one character; a double quote by default. */
73
+ /**
74
+ * The quote character, one character. Cells that hold the delimiter, the quote character or a
75
+ * line break are quoted with it. Pass the same value as the `quote` import option to read the
76
+ * file back.
77
+ * @defaultValue '"'
78
+ */
59
79
  quote?: string | undefined;
60
80
  /**
61
- * The property that receives explicit edge weights (`<name>:double`); "weight" by default (the
62
- * importer's `weightFrom` default); null writes no weights.
81
+ * The relationship property that holds the edge weights, written as `<name>:double`; null
82
+ * writes no weights (checkExport() then returns W_WEIGHTS_DROPPED). graph-io reads the
83
+ * "weight" property back as the weight; for any other name, pass the same name as the
84
+ * `weightFrom` import option to read the weights back (`weightColumn: "strength"` with
85
+ * `weightFrom: "strength"`), or they come back as a plain edge attribute. A graph read from Neo4j
86
+ * CSV with `weightFrom` writes its weights back under the property they were read from.
87
+ * @defaultValue "weight", or the property a Neo4j import read the weights from
63
88
  */
64
89
  weightColumn?: string | null | undefined;
65
90
  /**
66
- * The property name of the `:ID` column for nodes that have no stored-id column of their own
67
- * (`<name>:ID`); null (default) writes a bare `:ID`.
91
+ * The property name of the `:ID` column (`<name>:ID`) for nodes that have no id property of
92
+ * their own; null writes a bare `:ID`.
93
+ * @defaultValue null
68
94
  */
69
95
  idColumn?: string | null | undefined;
70
96
  }
71
97
 
72
- /** Loss code: undirected edges (an undirected snapshot, or the folded pairs of a mixed one) written as directed relationships. */
98
+ /**
99
+ * Neo4j relationships are always directed, so the edges of an undirected graph, and the undirected edges of a mixed
100
+ * graph, read back as directed.
101
+ * @category Built-in formats
102
+ */
73
103
  export const UNDIRECTED_LOSS = "W_NEO4J_UNDIRECTED_AS_DIRECTED";
74
104
 
75
- /** Loss code: node ids whose text re-imports as another type under the canonical id rule. */
105
+ /**
106
+ * Node ids that read back as a different type, such as the text "7" as the number 7.
107
+ * @category Built-in formats
108
+ */
76
109
  export const ID_TEXT_TYPE_LOSS = ID_TEXT_TYPE_CODE;
77
110
 
78
- /** Loss code: two node ids share one text; export() throws E_INVALID_ID. */
111
+ /**
112
+ * Two node ids share one text; export() throws E_INVALID_ID.
113
+ * @category Built-in formats
114
+ */
79
115
  export const ID_TEXT_COLLISION_LOSS = ID_TEXT_COLLISION_CODE;
80
116
 
81
- /** Loss code: an edge property column already uses the weight column name; export() throws E_COLUMN_EXISTS. */
117
+ /**
118
+ * The `weightColumn` name is already an edge attribute; the save fails.
119
+ * @category Built-in formats
120
+ */
82
121
  export const WEIGHT_COLUMN_TAKEN_LOSS = "E_NEO4J_WEIGHT_COLUMN_TAKEN";
83
122
 
84
- /** Loss code: a node property column already uses the idColumn name; export() throws E_COLUMN_EXISTS. */
123
+ /**
124
+ * The `idColumn` name is already a node attribute; the save fails.
125
+ * @category Built-in formats
126
+ */
85
127
  export const ID_COLUMN_TAKEN_LOSS = "E_NEO4J_ID_COLUMN_TAKEN";
86
128
 
87
- /** Loss code: a node has more than one stored-id column set; only the first is written. */
129
+ /**
130
+ * A node has more than one stored-id column set; only the first is written.
131
+ * @category Built-in formats
132
+ */
88
133
  export const MULTIPLE_ID_PROPERTIES_LOSS = "W_NEO4J_MULTIPLE_ID_PROPERTIES";
89
134
 
90
- /** Loss code: a declared integer type holds non-integral values and is written as double. */
135
+ /**
136
+ * A declared integer type holds non-integral values and is written as double.
137
+ * @category Built-in formats
138
+ */
91
139
  export const DECLARED_TYPE_CHANGED_LOSS = "W_NEO4J_DECLARED_TYPE_CHANGED";
92
140
 
93
- /** Loss code: a list item contains the array delimiter, which Neo4j cannot escape. */
141
+ /**
142
+ * A list item contains the array delimiter, which Neo4j cannot escape.
143
+ * @category Built-in formats
144
+ */
94
145
  export const ARRAY_DELIMITER_LOSS = "W_NEO4J_ARRAY_DELIMITER";
95
146
 
96
147
  /** The roles Neo4j has a slot for: `:TYPE`, `:LABEL` and the id space of `:ID(Space)`. */
@@ -110,10 +161,11 @@ const ROLE_NAMES: Readonly<Record<string, string>> = Object.freeze({
110
161
  });
111
162
 
112
163
  /**
113
- * The capabilities of neo4j-admin CSV (research note 07 section 9): declared scalar types and
164
+ * The capabilities of neo4j-admin CSV: declared scalar types and
114
165
  * arrays; a dict column reads back as string (the header has no enumeration type); a position or
115
166
  * visual column is written as a plain property (a point for a 2- or 3-component position) and
116
167
  * reads back without its role.
168
+ * @category Built-in formats
117
169
  */
118
170
  export const NEO4J_CAPABILITIES: ExportCapabilities = capabilities({
119
171
  mixedDirection: false,
@@ -211,9 +263,13 @@ interface ColumnPlan {
211
263
  /**
212
264
  * Resolve the format options.
213
265
  * @param options - the caller's options
266
+ * @param readFrom - the property a Neo4j import read the weights from, the default weightColumn
214
267
  * @returns the resolved options; E_UNSUPPORTED for an invalid value
215
268
  */
216
- function resolveNeo4jExportOptions(options: Neo4jExportOptions | undefined): ResolvedNeo4jExportOptions {
269
+ function resolveNeo4jExportOptions(
270
+ options: Neo4jExportOptions | undefined,
271
+ readFrom: string | null,
272
+ ): ResolvedNeo4jExportOptions {
217
273
  const o: Neo4jExportOptions = options ?? {};
218
274
  const part = o.part ?? "all";
219
275
  if (!PARTS.has(part)) {
@@ -237,12 +293,16 @@ function resolveNeo4jExportOptions(options: Neo4jExportOptions | undefined): Res
237
293
  const delimiter = o.delimiter ?? ",";
238
294
  const syntax = { ...checkRecordSyntax({ delimiter, quote: o.quote ?? '"' }), delimiter };
239
295
  if (syntax.delimiter === arrayDelimiter) {
240
- throw new GraphFormatError("E_UNSUPPORTED", "options delimiter and arrayDelimiter must differ", {
241
- option: "arrayDelimiter",
242
- found: arrayDelimiter,
243
- });
296
+ throw new GraphFormatError(
297
+ "E_UNSUPPORTED",
298
+ `options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`,
299
+ {
300
+ option: "arrayDelimiter",
301
+ found: arrayDelimiter,
302
+ },
303
+ );
244
304
  }
245
- const weightColumn = o.weightColumn === undefined ? "weight" : o.weightColumn;
305
+ const weightColumn = o.weightColumn === undefined ? (readFrom ?? "weight") : o.weightColumn;
246
306
  if (weightColumn !== null && (typeof weightColumn !== "string" || weightColumn.length === 0)) {
247
307
  throw new GraphFormatError("E_UNSUPPORTED", "option weightColumn: expected a non-empty name or null", {
248
308
  option: "weightColumn",
@@ -329,6 +389,7 @@ class ExportPlan {
329
389
  roles: SLOT_ROLES,
330
390
  roleNames: ROLE_NAMES,
331
391
  temporalText: true,
392
+ weights: options.weightColumn !== null,
332
393
  });
333
394
  this.planColumns("node", snapshot.nodes, this.nodeColumns);
334
395
  this.planColumns("edge", snapshot.edges, this.edgeColumns);
@@ -380,7 +441,7 @@ class ExportPlan {
380
441
  if (!snapshot.directed) {
381
442
  this.note(
382
443
  UNDIRECTED_LOSS,
383
- `the snapshot is undirected; every edge is written as a directed relationship (${snapshot.edgeCount} edge(s))`,
444
+ `the snapshot is undirected; every edge is written as a directed relationship (${snapshot.edgeCount} edge${plural(snapshot.edgeCount)})`,
384
445
  null,
385
446
  snapshot.edgeCount,
386
447
  );
@@ -394,7 +455,7 @@ class ExportPlan {
394
455
  if (undirected > 0) {
395
456
  this.note(
396
457
  UNDIRECTED_LOSS,
397
- `${undirected} undirected edge(s) are written as one directed relationship each (source to target, a pair folded to its primary); Neo4j has no undirected relationship`,
458
+ `${undirected} undirected edge${plural(undirected)} ${agree(undirected, "is", "are")} written as one directed relationship each (source to target, a pair folded to its primary); Neo4j has no undirected relationship`,
398
459
  null,
399
460
  undirected,
400
461
  );
@@ -403,7 +464,7 @@ class ExportPlan {
403
464
  if (folding.mutualCount > 0) {
404
465
  this.note(
405
466
  LOSS.MUTUAL_EXPANDED,
406
- `${folding.mutualCount} mutual pair(s) are written as two directed relationships; the mutual mark is lost`,
467
+ `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two directed relationships; the mutual mark is lost`,
407
468
  null,
408
469
  folding.mutualCount,
409
470
  );
@@ -612,7 +673,7 @@ class ExportPlan {
612
673
  if (rows > 0) {
613
674
  this.note(
614
675
  ARRAY_DELIMITER_LOSS,
615
- `${label}: ${rows} row(s) hold an item containing the array delimiter "${arrayDelimiter}", which Neo4j cannot escape`,
676
+ `${label}: ${rows} row${plural(rows)} ${agree(rows, "holds", "hold")} an item containing the array delimiter "${arrayDelimiter}", which Neo4j cannot escape`,
616
677
  column.meta.name,
617
678
  rows,
618
679
  );
@@ -648,7 +709,7 @@ class ExportPlan {
648
709
  } else if (taken !== undefined && name === DEFAULT_WEIGHT_COLUMN) {
649
710
  this.note(
650
711
  LOSS.WEIGHT_KEY_CLASH,
651
- `edge column "${name}" is written under the property the importer reads THE weight from (weightFrom "${name}"); it reads back as the weight, not as a column`,
712
+ `edge column "${name}" is written under the property the importer reads edge weights from (weightFrom "${name}"); it reads back as the weight, not as a column`,
652
713
  name,
653
714
  taken.column.length - taken.column.nullCount,
654
715
  );
@@ -703,7 +764,7 @@ class ExportPlan {
703
764
  if (typeChanges > 0) {
704
765
  this.note(
705
766
  ID_TEXT_TYPE_LOSS,
706
- `${typeChanges} node id(s) re-import as another type under the canonical id rule (a string of canonical integer text, or a non-integer number)`,
767
+ `${typeChanges} node id${plural(typeChanges)} re-import as another type under the canonical id rule (a string of canonical integer text, or a non-integer number)`,
707
768
  null,
708
769
  typeChanges,
709
770
  );
@@ -711,13 +772,13 @@ class ExportPlan {
711
772
  if (collisions > 0) {
712
773
  this.note(
713
774
  ID_TEXT_COLLISION_LOSS,
714
- `${collisions} node id(s) share their text with another id (a number and a string); export() will throw`,
775
+ `${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id (a number and a string); the save fails`,
715
776
  null,
716
777
  collisions,
717
778
  );
718
779
  this.fatalAll = new GraphFormatError(
719
780
  "E_INVALID_ID",
720
- `${collisions} node id(s) share their text with another id; Neo4j ids are text`,
781
+ `${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id; Neo4j ids are text`,
721
782
  { reason: "text collision", count: collisions },
722
783
  );
723
784
  }
@@ -770,7 +831,7 @@ class ExportPlan {
770
831
  if (count > 0) {
771
832
  this.note(
772
833
  MULTIPLE_ID_PROPERTIES_LOSS,
773
- `${count} node(s) have more than one stored-id column set; only the first in declaration order is written`,
834
+ `${count} node${plural(count)} ${agree(count, "has", "have")} more than one stored-id column set; only the first in declaration order is written`,
774
835
  null,
775
836
  count,
776
837
  );
@@ -877,6 +938,17 @@ class ExportPlan {
877
938
  * @returns nothing
878
939
  */
879
940
  *lines(): Generator<string, void, undefined> {
941
+ for (const row of this.rows()) {
942
+ yield row.line;
943
+ }
944
+ }
945
+
946
+ /**
947
+ * The lines of the requested part, each header line tagged with the file it starts.
948
+ * @yields one line at a time, with the file name on a header line
949
+ * @returns nothing
950
+ */
951
+ *rows(): Generator<SectionLine, void, undefined> {
880
952
  if (this.fatal !== null) {
881
953
  throw this.fatal;
882
954
  }
@@ -889,19 +961,53 @@ class ExportPlan {
889
961
  }
890
962
  }
891
963
 
964
+ /**
965
+ * The requested part as one file per section kind: a node file per id space (and stored-id
966
+ * property), a relationship file per pair of endpoint id spaces, rows of one kind gathered
967
+ * under one header.
968
+ * @returns the files, node files first
969
+ */
970
+ files(): Neo4jFile[] {
971
+ // keyed by the header row: sections with the same header are one file
972
+ const files = new Map<string, { name: string; kind: "nodes" | "relationships"; rows: string[] }>();
973
+ const names = new Set<string>();
974
+ let current: { rows: string[] } | null = null;
975
+ for (const row of this.rows()) {
976
+ if (row.file !== null) {
977
+ let file = files.get(row.line);
978
+ if (file === undefined) {
979
+ let name = `${row.file.name}.csv`;
980
+ let k = 2;
981
+ while (names.has(name)) {
982
+ name = `${row.file.name}-${k}.csv`;
983
+ k++;
984
+ }
985
+ names.add(name);
986
+ file = { name, kind: row.file.kind, rows: [] };
987
+ files.set(row.line, file);
988
+ }
989
+ current = file;
990
+ } else if (current !== null) {
991
+ current.rows.push(row.line);
992
+ }
993
+ }
994
+ // a part with no rows (a graph without edges) is a header alone, which neo4j-admin does not need
995
+ const written = [...files].filter(([, f], i) => f.rows.length > 0 || (i === 0 && files.size === 1));
996
+ return written.map(([header, f]) =>
997
+ Object.freeze({ name: f.name, kind: f.kind, text: header + f.rows.join("") }),
998
+ );
999
+ }
1000
+
892
1001
  /**
893
1002
  * The node sections.
894
1003
  * @yields one line at a time
895
1004
  * @returns nothing
896
1005
  */
897
- private *nodeLines(): Generator<string, void, undefined> {
898
- const { snapshot, labels, nodeColumns } = this;
899
- const { delimiter } = this.options.syntax;
900
- const propertyHeaders = nodeColumns.map((plan) => plan.header).join(delimiter);
1006
+ private *nodeLines(): Generator<SectionLine, void, undefined> {
1007
+ const { snapshot } = this;
901
1008
  let sections = 0;
902
1009
  let sectionSpace: string | null = null;
903
1010
  let sectionIdName: string | null = null;
904
- const cells: string[] = [];
905
1011
  for (let i = 0; i < snapshot.nodeCount; i++) {
906
1012
  const space = this.spaceOf(i);
907
1013
  const stored = this.storedIdOf(i);
@@ -910,36 +1016,50 @@ class ExportPlan {
910
1016
  sections++;
911
1017
  sectionSpace = space;
912
1018
  sectionIdName = idName;
913
- const header = [formatHeaderField(idName, ID_TYPE, space)];
914
- if (labels !== null) {
915
- header.push(":LABEL");
916
- }
917
- if (propertyHeaders.length > 0) {
918
- header.push(propertyHeaders);
919
- }
920
- yield `${header.join(delimiter)}\n`;
1019
+ yield this.nodeHeader(idName, space, space ?? idName);
921
1020
  }
922
- cells.length = 0;
923
- cells.push(this.cell(this.idTextOf(i)));
924
- if (labels !== null) {
925
- cells.push(this.cell(this.labelsText(i)));
926
- }
927
- for (const plan of nodeColumns) {
928
- cells.push(this.cell(this.valueText(plan, i)));
929
- }
930
- yield `${cells.join(delimiter)}\n`;
1021
+ yield { line: this.nodeRow(i), file: null };
931
1022
  }
932
1023
  if (sections === 0) {
933
1024
  // no nodes: one header so the section (and its columns) still exists
934
- const header = [formatHeaderField(this.options.idColumn ?? "", ID_TYPE, null)];
935
- if (labels !== null) {
936
- header.push(":LABEL");
937
- }
938
- if (propertyHeaders.length > 0) {
939
- header.push(propertyHeaders);
940
- }
941
- yield `${header.join(delimiter)}\n`;
1025
+ yield this.nodeHeader(this.options.idColumn ?? "", null, null);
1026
+ }
1027
+ }
1028
+
1029
+ /**
1030
+ * The header line of a node section, which starts its file.
1031
+ * @param idName - the id column's name
1032
+ * @param space - the id space, or null
1033
+ * @param fileKey - what names the file, or null for the default name
1034
+ * @returns the line
1035
+ */
1036
+ private nodeHeader(idName: string, space: string | null, fileKey: string | null): SectionLine {
1037
+ const { delimiter } = this.options.syntax;
1038
+ const header = [formatHeaderField(idName, ID_TYPE, space)];
1039
+ if (this.labels !== null) {
1040
+ header.push(":LABEL");
1041
+ }
1042
+ const properties = this.nodeColumns.map((plan) => plan.header).join(delimiter);
1043
+ if (properties.length > 0) {
1044
+ header.push(properties);
942
1045
  }
1046
+ return { line: `${header.join(delimiter)}\n`, file: { kind: "nodes", name: fileName("nodes", fileKey, null) } };
1047
+ }
1048
+
1049
+ /**
1050
+ * One node's line: the id, the labels, the properties.
1051
+ * @param i - the node
1052
+ * @returns the line
1053
+ */
1054
+ private nodeRow(i: number): string {
1055
+ const cells = [this.cell(this.idTextOf(i))];
1056
+ if (this.labels !== null) {
1057
+ cells.push(this.cell(this.labelsText(i)));
1058
+ }
1059
+ for (const plan of this.nodeColumns) {
1060
+ cells.push(this.cell(this.valueText(plan, i)));
1061
+ }
1062
+ return `${cells.join(this.options.syntax.delimiter)}\n`;
943
1063
  }
944
1064
 
945
1065
  /**
@@ -947,30 +1067,12 @@ class ExportPlan {
947
1067
  * @yields one line at a time
948
1068
  * @returns nothing
949
1069
  */
950
- private *relationshipLines(): Generator<string, void, undefined> {
951
- const { snapshot, kind, weights, edgeColumns, folding } = this;
952
- const { delimiter } = this.options.syntax;
1070
+ private *relationshipLines(): Generator<SectionLine, void, undefined> {
1071
+ const { snapshot, folding } = this;
953
1072
  const list = snapshot.edgeList();
954
- const propertyHeaders = edgeColumns.map((plan) => plan.header).join(delimiter);
955
- const weightHeader =
956
- weights === null ? null : formatHeaderField(this.options.weightColumn ?? "weight", "double", null);
957
1073
  let sections = 0;
958
1074
  let sectionStart: string | null = null;
959
1075
  let sectionEnd: string | null = null;
960
- const cells: string[] = [];
961
- const headerOf = (startSpace: string | null, endSpace: string | null): string => {
962
- const header = [formatHeaderField("", "START_ID", startSpace), formatHeaderField("", "END_ID", endSpace)];
963
- if (kind !== null) {
964
- header.push(":TYPE");
965
- }
966
- if (weightHeader !== null) {
967
- header.push(weightHeader);
968
- }
969
- if (propertyHeaders.length > 0) {
970
- header.push(propertyHeaders);
971
- }
972
- return `${header.join(delimiter)}\n`;
973
- };
974
1076
  for (let e = 0; e < snapshot.edgeCount; e++) {
975
1077
  if (folding.folded(e)) {
976
1078
  continue;
@@ -983,24 +1085,60 @@ class ExportPlan {
983
1085
  sections++;
984
1086
  sectionStart = startSpace;
985
1087
  sectionEnd = endSpace;
986
- yield headerOf(startSpace, endSpace);
987
- }
988
- cells.length = 0;
989
- cells.push(this.cell(this.idTextOf(u)), this.cell(this.idTextOf(v)));
990
- if (kind !== null) {
991
- cells.push(this.cell(kind.isSet(e) ? textOf(kind, e) : null));
992
- }
993
- if (weights !== null) {
994
- cells.push(this.cell(weights.text(e)));
995
- }
996
- for (const plan of edgeColumns) {
997
- cells.push(this.cell(this.valueText(plan, e)));
1088
+ yield this.relationshipHeader(startSpace, endSpace);
998
1089
  }
999
- yield `${cells.join(delimiter)}\n`;
1090
+ yield { line: this.relationshipRow(e, u, v), file: null };
1000
1091
  }
1001
1092
  if (sections === 0) {
1002
- yield headerOf(null, null);
1093
+ yield this.relationshipHeader(null, null);
1094
+ }
1095
+ }
1096
+
1097
+ /**
1098
+ * The header line of a relationship section, which starts its file.
1099
+ * @param startSpace - the id space of the start nodes, or null
1100
+ * @param endSpace - the id space of the end nodes, or null
1101
+ * @returns the line
1102
+ */
1103
+ private relationshipHeader(startSpace: string | null, endSpace: string | null): SectionLine {
1104
+ const { delimiter } = this.options.syntax;
1105
+ const header = [formatHeaderField("", "START_ID", startSpace), formatHeaderField("", "END_ID", endSpace)];
1106
+ if (this.kind !== null) {
1107
+ header.push(":TYPE");
1108
+ }
1109
+ if (this.weights !== null) {
1110
+ header.push(formatHeaderField(this.options.weightColumn ?? "weight", "double", null));
1111
+ }
1112
+ const properties = this.edgeColumns.map((plan) => plan.header).join(delimiter);
1113
+ if (properties.length > 0) {
1114
+ header.push(properties);
1115
+ }
1116
+ return {
1117
+ line: `${header.join(delimiter)}\n`,
1118
+ file: { kind: "relationships", name: fileName("relationships", startSpace, endSpace) },
1119
+ };
1120
+ }
1121
+
1122
+ /**
1123
+ * One relationship's line: the ends, the type, the weight, the properties.
1124
+ * @param e - the edge
1125
+ * @param u - its source
1126
+ * @param v - its target
1127
+ * @returns the line
1128
+ */
1129
+ private relationshipRow(e: number, u: number, v: number): string {
1130
+ const { kind, weights } = this;
1131
+ const cells = [this.cell(this.idTextOf(u)), this.cell(this.idTextOf(v))];
1132
+ if (kind !== null) {
1133
+ cells.push(this.cell(kind.isSet(e) ? textOf(kind, e) : null));
1003
1134
  }
1135
+ if (weights !== null) {
1136
+ cells.push(this.cell(weights.text(e)));
1137
+ }
1138
+ for (const plan of this.edgeColumns) {
1139
+ cells.push(this.cell(this.valueText(plan, e)));
1140
+ }
1141
+ return `${cells.join(this.options.syntax.delimiter)}\n`;
1004
1142
  }
1005
1143
 
1006
1144
  /**
@@ -1017,7 +1155,7 @@ class ExportPlan {
1017
1155
  if (text.length === 0) {
1018
1156
  return quote + quote;
1019
1157
  }
1020
- return quoteCsvCell(text, this.options.syntax.delimiter);
1158
+ return quoteCsvCell(text, this.options.syntax.delimiter, quote);
1021
1159
  }
1022
1160
 
1023
1161
  /**
@@ -1281,9 +1419,13 @@ function textOf(column: Column, row: number): string {
1281
1419
  }
1282
1420
  }
1283
1421
 
1284
- /** The Neo4j exporter. */
1422
+ /**
1423
+ * The Neo4j exporter.
1424
+ * @category Built-in formats
1425
+ */
1285
1426
  export const neo4jExporter: GraphExporter<Neo4jExportOptions> = Object.freeze({
1286
1427
  format: NEO4J,
1428
+ options: Object.freeze(["arrayDelimiter", "delimiter", "idColumn", "part", "quote", "weightColumn"]),
1287
1429
  capabilities: NEO4J_CAPABILITIES,
1288
1430
  /**
1289
1431
  * Pre-flight: what export() would lose.
@@ -1314,6 +1456,68 @@ export const neo4jExporter: GraphExporter<Neo4jExportOptions> = Object.freeze({
1314
1456
  },
1315
1457
  });
1316
1458
 
1459
+ /** One line of the export; a header line names the file it starts. */
1460
+ interface SectionLine {
1461
+ readonly line: string;
1462
+ readonly file: { readonly kind: "nodes" | "relationships"; readonly name: string } | null;
1463
+ }
1464
+
1465
+ /**
1466
+ * One file of exportNeo4jFiles(): the header row and the rows of one section kind.
1467
+ * @category Built-in formats
1468
+ */
1469
+ export interface Neo4jFile {
1470
+ /** A file name made from the section: `nodes-Movie.csv`, `relationships-Person-Movie.csv`, or `nodes.csv` and `relationships.csv` without id spaces. */
1471
+ readonly name: string;
1472
+ /** Whether neo4j-admin takes the file with `--nodes` or with `--relationships`. */
1473
+ readonly kind: "nodes" | "relationships";
1474
+ /** The CSV text, one header row first. */
1475
+ readonly text: string;
1476
+ }
1477
+
1478
+ /**
1479
+ * The file name of a section, without ".csv": the kind, then the id spaces that set it apart.
1480
+ * @param kind - "nodes" or "relationships"
1481
+ * @param first - the id space or id property (nodes), or the start id space (relationships)
1482
+ * @param second - the end id space (relationships)
1483
+ * @returns the name, with characters outside letters, digits, "." , "_" and "-" replaced by "_"
1484
+ */
1485
+ function fileName(kind: string, first: string | null, second: string | null): string {
1486
+ const parts = [kind, first ?? "", second ?? ""].filter((p) => p !== "");
1487
+ return parts.join("-").replaceAll(/[^\w.-]/g, "_");
1488
+ }
1489
+
1490
+ /**
1491
+ * Write a graph as the separate CSV files `neo4j-admin database import` takes: one node file per id
1492
+ * space and one relationship file per pair of endpoint id spaces, each with a single header row.
1493
+ * `exportGraph(snapshot, "neo4j")` writes the same sections into one file, which graph-io reads
1494
+ * back but neo4j-admin does not, since it reads one header per file. The options are the Neo4j
1495
+ * export options (`part` limits the result to the node or the relationship files), and
1496
+ * `checkExport(snapshot, "neo4j", options)` returns what the files lose.
1497
+ * @param snapshot - the graph to write
1498
+ * @param options - the Neo4j export options
1499
+ * @returns the files, node files first
1500
+ * @category Built-in formats
1501
+ * @example
1502
+ * ```ts
1503
+ * for (const file of await exportNeo4jFiles(snapshot)) {
1504
+ * await writeFile(file.name, file.text);
1505
+ * }
1506
+ * // neo4j-admin database import full --nodes=nodes-Movie.csv --nodes=nodes-Person.csv \
1507
+ * // --relationships=relationships-Person-Movie.csv neo4j
1508
+ * ```
1509
+ */
1510
+ export function exportNeo4jFiles(
1511
+ snapshot: GraphSnapshot,
1512
+ options?: Neo4jExportOptions & CommonExportOptions,
1513
+ ): Promise<Neo4jFile[]> {
1514
+ try {
1515
+ return Promise.resolve(plan(snapshot, options).files());
1516
+ } catch (err) {
1517
+ return Promise.reject(err as Error);
1518
+ }
1519
+ }
1520
+
1317
1521
  /**
1318
1522
  * Build the export plan of a snapshot.
1319
1523
  * @param snapshot - the snapshot
@@ -1321,5 +1525,20 @@ export const neo4jExporter: GraphExporter<Neo4jExportOptions> = Object.freeze({
1321
1525
  * @returns the plan
1322
1526
  */
1323
1527
  function plan(snapshot: GraphSnapshot, options: (Neo4jExportOptions & CommonExportOptions) | undefined): ExportPlan {
1324
- return new ExportPlan(snapshot, resolveNeo4jExportOptions(options), resolveExportOptions(options));
1528
+ return new ExportPlan(
1529
+ snapshot,
1530
+ resolveNeo4jExportOptions(options, weightPropertyOf(snapshot)),
1531
+ resolveExportOptions(options),
1532
+ );
1533
+ }
1534
+
1535
+ /**
1536
+ * The relationship property a Neo4j import read the weights from, when it was not "weight".
1537
+ * @param snapshot - the snapshot
1538
+ * @returns the property name, or null
1539
+ */
1540
+ function weightPropertyOf(snapshot: GraphSnapshot): string | null {
1541
+ const neo4j = (snapshot.meta.extra as { neo4j?: { weightProperty?: unknown } } | null)?.neo4j;
1542
+ const name = neo4j?.weightProperty;
1543
+ return typeof name === "string" && name !== "" ? name : null;
1325
1544
  }