@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/dist/neo4j.js CHANGED
@@ -1,22 +1,37 @@
1
- import { R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, d as DUPLICATE_NODE_CODE$1, e as MISSING_ENDPOINT_CODE$1, f as MISSING_ID_CODE$1, v as resolveImportOptions, w as ImportReportBuilder, F as reportSinkOptions, z as reportUnusedOptions, y as throwIfAborted, K as IdCoercer, J as DirectionResolver, ao as ImportError, aK as declareAttribute, aW as declareOn, Q as uniqueColumnName, at as RENAMED_CODE, aL as parseDeclaredTemporal, aM as parseDeclaredValue, aN as losesPrecision, aA as declareCompanion, P as PRECISION_CODE, aP as splitListText, aF as isImportInput, aX as takenIn, aC as inputLength, a8 as ID_TEXT_COLLISION_CODE, b as ID_TEXT_TYPE_CODE, V as resolveExportOptions, X as pairFolding, aS as mapDeclaredType, aE as isCanonicalIntegerText, aU as formatTemporal, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, C as COLUMN_RENAMED_CODE, k as UNKNOWN_ATTR_TYPE_CODE, q as UNKNOWN_ENCODING_CODE, E as ENCODING_FALLBACK_CODE, r as INVALID_ENCODING_CODE, s as INVALID_UTF8_CODE, a7 as WEIGHT_KEY_CLASH_CODE, ac as ROLE_DROPPED_CODE, aa as MUTUAL_EXPANDED_CODE } from "./chunks/report-B1z4WT9e.js";
2
- import { c as checkRecordSyntax, R as RecordReader, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-dbRkxwaq.js";
1
+ import { i as DANGLING_REFERENCE_CODE$1, R as ROLE_TAKEN_CODE$1, I as ID_MERGED_CODE$1, n as DUPLICATE_NODE_CODE$1, s as MISSING_ENDPOINT_CODE$1, t as MISSING_ID_CODE$1, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, am as throwIfAborted, ar as IdCoercer, aq as DirectionResolver, b as plural, $ as agree, aT as ImportError, bI as declareAttribute, bY as declareOn, a0 as uniqueColumnName, ay as RENAMED_CODE, aL as parseWeightText, bK as parseDeclaredTemporal, bL as parseDeclaredValue, bM as losesPrecision, bs as declareCompanion, P as PRECISION_CODE, bO as splitListText, bz as isImportInput, bX as takenIn, bx as inputLength, bZ as parseTemporal, b_ as withArticle, c as capabilities, b9 as ID_TEXT_COLLISION_CODE, J as ID_TEXT_TYPE_CODE, r as resolveExportOptions, a as checkCapabilities, p as pairFolding, L as LOSS, bS as mapDeclaredType, e as explicitWeights, by as isCanonicalIntegerText, bU as formatTemporal, ab as formatF64, aa as formatF32, aG as formatInteger, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, C as COLUMN_RENAMED_CODE, U as UNKNOWN_ATTR_TYPE_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, A as COLUMN_TYPE_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE, bq as WEIGHT_KEY_CLASH_CODE, K as ROLE_DROPPED_CODE, bd as MUTUAL_EXPANDED_CODE } from "./chunks/export-BTI4yQgy.js";
2
+ import { c as checkRecordSyntax, R as RecordReader, B as BAD_QUOTE_CODE, U as UNCLOSED_QUOTE_CODE } from "./chunks/records-CQXT__mY.js";
3
3
  import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
4
- import { m as quoteCsvCell } from "./chunks/escape-B-tkk_Cl.js";
5
- import { c as capabilities, a as checkCapabilities, L as LOSS } from "./chunks/export-Bh60Dv-n.js";
6
- import { p as parseWeightText, e as explicitWeights, a as formatF64, f as formatF32, d as formatInteger } from "./chunks/weights-Dzba96G3.js";
7
- import { j as joinText, e as encodeChunks } from "./chunks/writer-C7flM-Ih.js";
4
+ import { o as quoteCsvCell } from "./chunks/escape-D0g6NNUy.js";
5
+ import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
8
6
  const STRUCTURAL = /* @__PURE__ */ new Set(["ID", "LABEL", "START_ID", "END_ID", "TYPE", "IGNORE"]);
9
7
  const SPACE_KINDS = /* @__PURE__ */ new Set(["ID", "START_ID", "END_ID"]);
10
8
  const HEADER_MARKER = /^[^:{}()]*:\s*(ID|START_ID|END_ID)\s*(\(|\{|$)/i;
11
9
  const CELL = /^([^:(){}]*)(?::([^:(){}]*))?(?:\(([^)]*)\))?(?:\{([^}]*)\})?$/;
12
- function isHeaderRecord(cells, count) {
10
+ function isHeaderRecord(cells, count, quoted) {
11
+ let quotedMarker = false;
13
12
  for (let i = 0; i < count; i++) {
14
13
  const cell = cells[i];
15
14
  if (cell.indexOf(":") >= 0 && HEADER_MARKER.test(cell.trim())) {
16
- return true;
15
+ if (quoted?.[i] !== true) {
16
+ return true;
17
+ }
18
+ quotedMarker = true;
19
+ }
20
+ }
21
+ return quotedMarker && quoted !== void 0 && isQuotedHeader(cells, count, quoted);
22
+ }
23
+ function isQuotedHeader(cells, count, quoted) {
24
+ for (let i = 0; i < count; i++) {
25
+ if (!quoted[i]) {
26
+ return false;
27
+ }
28
+ try {
29
+ parseHeaderField(cells[i]);
30
+ } catch {
31
+ return false;
17
32
  }
18
33
  }
19
- return false;
34
+ return true;
20
35
  }
21
36
  function parseHeaderField(text) {
22
37
  const trimmed = text.trim();
@@ -103,6 +118,9 @@ const ENDPOINT_SPACE_CODE = "E_NEO4J_ENDPOINT_SPACE";
103
118
  const ID_MERGED_CODE = ID_MERGED_CODE$1;
104
119
  const HEADER_OPTION_CODE = "W_NEO4J_HEADER_OPTION_IGNORED";
105
120
  const ROLE_TAKEN_CODE = ROLE_TAKEN_CODE$1;
121
+ const MISSING_TYPE_CODE = "W_NEO4J_MISSING_TYPE";
122
+ const SECTION_KIND_CODE = "W_NEO4J_SECTION_KIND";
123
+ const DANGLING_REFERENCE_CODE = DANGLING_REFERENCE_CODE$1;
106
124
  const IGNORED_COLUMNS_LOSS = "W_NEO4J_IGNORED_COLUMNS";
107
125
  const USED_OPTIONS = /* @__PURE__ */ new Set([
108
126
  "ids",
@@ -161,16 +179,27 @@ function resolveNeo4jOptions(options) {
161
179
  { option: "arrayDelimiter", found: arrayDelimiter }
162
180
  );
163
181
  }
182
+ if (arrayDelimiter === "," && o.delimiter === void 0) {
183
+ throw new GraphFormatError(
184
+ "E_UNSUPPORTED",
185
+ 'option arrayDelimiter "," needs the delimiter option: the field delimiter is a comma unless another is given',
186
+ { option: "arrayDelimiter", found: arrayDelimiter }
187
+ );
188
+ }
164
189
  const syntax = checkRecordSyntax({
165
190
  delimiter: o.delimiter ?? null,
166
191
  quote: o.quote ?? '"',
167
192
  candidates: NEO4J_DELIMITER_CANDIDATES.filter((d) => d !== arrayDelimiter)
168
193
  });
169
194
  if (syntax.delimiter === arrayDelimiter) {
170
- throw new GraphFormatError("E_UNSUPPORTED", "options delimiter and arrayDelimiter must differ", {
171
- option: "arrayDelimiter",
172
- found: arrayDelimiter
173
- });
195
+ throw new GraphFormatError(
196
+ "E_UNSUPPORTED",
197
+ `options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`,
198
+ {
199
+ option: "arrayDelimiter",
200
+ found: arrayDelimiter
201
+ }
202
+ );
174
203
  }
175
204
  return {
176
205
  nodes: inputList("nodes", o.nodes),
@@ -299,6 +328,7 @@ class Neo4jImportSession {
299
328
  */
300
329
  constructor(sink, report, common, options) {
301
330
  this.registry = new NodeRegistry();
331
+ this.weightProperty = null;
302
332
  this.labelsHandle = INVALID_INDEX;
303
333
  this.typeHandle = INVALID_INDEX;
304
334
  this.idSpaceHandle = INVALID_INDEX;
@@ -308,6 +338,10 @@ class Neo4jImportSession {
308
338
  this.values = [];
309
339
  this.texts = [];
310
340
  this.precisionSlots = [];
341
+ this.overflows = [];
342
+ this.expectedKind = null;
343
+ this.nodeRows = false;
344
+ this.placeholders = [];
311
345
  this.sink = sink;
312
346
  this.report = report;
313
347
  this.common = common;
@@ -316,38 +350,69 @@ class Neo4jImportSession {
316
350
  this.direction = new DirectionResolver(sink, report, common.onMixedDirection);
317
351
  }
318
352
  /**
319
- * Read every input.
320
- * @param inputs - the inputs in reading order
353
+ * Read every input. A header-only input lends its header to the headerless input after it (the
354
+ * neo4j-admin convention `--nodes=header.csv,part1.csv`); an empty input is an error only when
355
+ * it is the only one.
356
+ * @param inputs - the inputs in reading order, each with the kind of section its option names (null for the primary input)
321
357
  */
322
358
  async run(inputs) {
323
- const progress = new ProgressTracker(this.common.onProgress, inputs);
324
- for (const input of inputs) {
325
- await this.readInput(input, { ...progress.optionsFor(this.common.signal), encoding: this.common.encoding });
359
+ const progress = new ProgressTracker(
360
+ this.common.onProgress,
361
+ inputs.map((i) => i.input)
362
+ );
363
+ let carried = null;
364
+ for (const { input, kind } of inputs) {
365
+ this.expectedKind = kind;
366
+ if (carried !== null && kind !== null && carried.kind !== kind) {
367
+ carried = null;
368
+ }
369
+ carried = await this.readInput(
370
+ input,
371
+ { ...progress.optionsFor(this.common.signal), encoding: this.common.encoding },
372
+ carried,
373
+ inputs.length > 1
374
+ );
326
375
  progress.finishInput();
327
376
  }
328
377
  if (this.ignoredColumns > 0) {
329
378
  this.report.loss(
330
379
  IGNORED_COLUMNS_LOSS,
331
- `${this.ignoredColumns} :IGNORE column(s) were skipped as the header instructs`,
380
+ `${this.ignoredColumns} :IGNORE column${plural(this.ignoredColumns)} ${agree(this.ignoredColumns, "was", "were")} skipped as the header instructs`,
332
381
  null,
333
382
  this.ignoredColumns
334
383
  );
335
384
  }
385
+ this.reportDangling();
336
386
  }
337
387
  /**
338
388
  * Read one input: a header row, then data rows until the next header row.
339
389
  * @param input - the input
340
390
  * @param readOptions - cancellation and progress
391
+ * @param carried - the section of a header-only input just before this one, or null
392
+ * @param mayBeEmpty - whether an input without any record is allowed (other inputs exist)
393
+ * @returns this input's section when it held a header and no data row (lent to the next input), else null
341
394
  */
342
- async readInput(input, readOptions) {
343
- const reader = new RecordReader(input, this.report, this.options.syntax, readOptions);
344
- let section = null;
395
+ async readInput(input, readOptions, carried, mayBeEmpty) {
396
+ const reader = new RecordReader(input, this.report, this.options.syntax, {
397
+ ...readOptions,
398
+ allowEmpty: mayBeEmpty
399
+ });
400
+ let section = carried;
401
+ let records = 0;
402
+ let rows = 0;
345
403
  let sinceCheck = 0;
346
404
  for await (const count of reader) {
347
- if (section === null || isHeaderRecord(reader.cells, count)) {
405
+ const { cells, quoted } = reader;
406
+ if (records === 0 && count === 1 && !quoted[0] && cells[0].trim().length === 0) {
407
+ continue;
408
+ }
409
+ records++;
410
+ if (section === null || isHeaderRecord(cells, count, quoted)) {
348
411
  section = this.declareSection(reader, count);
412
+ rows = 0;
349
413
  continue;
350
414
  }
415
+ rows++;
351
416
  if (section.kind === "node") {
352
417
  this.nodeRow(section, reader, count);
353
418
  } else {
@@ -358,9 +423,13 @@ class Neo4jImportSession {
358
423
  throwIfAborted(readOptions.signal);
359
424
  }
360
425
  }
361
- if (section === null) {
426
+ if (records === 0 && carried === null && !mayBeEmpty) {
362
427
  this.report.fail(HEADER_CODE, "the input has no header row", { line: 1 });
363
428
  }
429
+ if (section === carried) {
430
+ return carried;
431
+ }
432
+ return rows === 0 ? section : null;
364
433
  }
365
434
  /**
366
435
  * Interpret a header row: parse every cell, check the section shape, declare its columns.
@@ -393,8 +462,17 @@ class Neo4jImportSession {
393
462
  throw headerError("a header mixes :ID with :START_ID / :END_ID");
394
463
  }
395
464
  if (!isNode && !isRelationship) {
465
+ const apoc = fields.some((f) => f.name === "_id" || f.name === "_start");
396
466
  throw headerError(
397
- "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)"
467
+ apoc ? "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships); this is the apoc.export.csv layout (_id, _labels, _start, _end, _type), which is not the neo4j-admin import format" : "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)"
468
+ );
469
+ }
470
+ if (this.expectedKind !== null && this.expectedKind !== (isNode ? "node" : "relationship")) {
471
+ this.report.warning(
472
+ "validation-error",
473
+ SECTION_KIND_CODE,
474
+ `a ${isNode ? "node" : "relationship"} header in a file given as ${this.expectedKind === "node" ? "nodes" : "relationships"}; read by its header`,
475
+ { line }
398
476
  );
399
477
  }
400
478
  checkPropertyNames(fields);
@@ -427,7 +505,11 @@ class Neo4jImportSession {
427
505
  );
428
506
  } catch (err) {
429
507
  if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
430
- this.report.fail(HEADER_CODE, `line ${line}: ${err.message}`, { line }, { cause: err.code });
508
+ const other = [";", "|", " ", ","].find(
509
+ (d) => d !== reader.delimiter && reader.cells.slice(0, count).some((c) => c.includes(d))
510
+ );
511
+ const hint = other === void 0 ? "" : `; if the file is delimited by ${JSON.stringify(other)}, pass the delimiter option`;
512
+ this.report.fail(HEADER_CODE, `${err.message}${hint}`, { line }, { cause: err.code });
431
513
  }
432
514
  throw err;
433
515
  }
@@ -513,6 +595,9 @@ class Neo4jImportSession {
513
595
  let weightCell = -1;
514
596
  if (weightFrom !== null) {
515
597
  weightCell = fields.findIndex((field) => field.kind === "PROPERTY" && field.name === weightFrom);
598
+ if (weightCell >= 0 && weightFrom !== "weight") {
599
+ this.weightProperty = weightFrom;
600
+ }
516
601
  }
517
602
  const properties = this.declareProperties("edge", fields, line, weightCell);
518
603
  const { space: startSpace } = fields[startCell];
@@ -675,7 +760,7 @@ class Neo4jImportSession {
675
760
  report.error(
676
761
  "validation-error",
677
762
  COLUMN_COUNT_CODE,
678
- `row has ${count} cell(s) but the header has ${section.width}`,
763
+ `row has ${count} cell${plural(count)} but the header has ${section.width}`,
679
764
  { line }
680
765
  );
681
766
  report.counts.skippedNodes++;
@@ -697,7 +782,16 @@ class Neo4jImportSession {
697
782
  if (section.labelCells.length > 0 || section.extraLabels.length > 0) {
698
783
  labels = this.labelsOf(section, cells, quoted);
699
784
  }
700
- const index = sink.addNode(id);
785
+ this.nodeRows = true;
786
+ const existed = sink.indexOf(id) !== INVALID_INDEX;
787
+ let index;
788
+ try {
789
+ index = sink.addNode(id);
790
+ } catch (err) {
791
+ report.recordError(err, { line, element: idText2 });
792
+ report.counts.skippedNodes++;
793
+ return;
794
+ }
701
795
  const status = this.registry.declare(index, section.spaceCode);
702
796
  if (status === "collision") {
703
797
  report.error(
@@ -720,19 +814,61 @@ class Neo4jImportSession {
720
814
  }
721
815
  );
722
816
  }
817
+ const set = (column, value) => {
818
+ this.guarded(line, idText2, () => {
819
+ sink.setNodeValue(column, index, value);
820
+ });
821
+ };
723
822
  if (section.idHandle !== INVALID_INDEX) {
724
- sink.setNodeValue(section.idHandle, index, idText2);
823
+ set(section.idHandle, idText2);
725
824
  }
726
825
  if (section.space !== null) {
727
- sink.setNodeValue(this.idSpaceHandle, index, section.space);
728
- sink.setNodeValue(this.originalIdHandle, index, idText2);
826
+ set(this.idSpaceHandle, section.space);
827
+ set(this.originalIdHandle, idText2);
729
828
  }
730
829
  if (labels !== void 0) {
731
- sink.setNodeValue(this.labelsHandle, index, labels);
830
+ set(this.labelsHandle, labels);
732
831
  }
733
- this.writeProperties("node", section.properties, index);
832
+ this.writeProperties("node", section.properties, index, line, idText2);
734
833
  this.reportPrecision(line, idText2);
735
- report.counts.nodes++;
834
+ if (!existed) {
835
+ report.counts.nodes++;
836
+ }
837
+ }
838
+ /**
839
+ * Run one sink write, recording a refusal (a GraphFormatError) on the row's line instead of
840
+ * letting it escape the import.
841
+ * @param line - the row's line
842
+ * @param element - the row's element name
843
+ * @param write - the write
844
+ */
845
+ guarded(line, element, write) {
846
+ try {
847
+ write();
848
+ } catch (err) {
849
+ if (!(err instanceof GraphFormatError) || err instanceof ImportError) {
850
+ throw err;
851
+ }
852
+ this.report.recordError(err, { line, element });
853
+ }
854
+ }
855
+ /**
856
+ * Report the relationship endpoints no node row declared (the shared W_DANGLING_REFERENCE,
857
+ * once) when the input has node rows: each became a node, where neo4j-admin refuses the
858
+ * relationship.
859
+ */
860
+ reportDangling() {
861
+ const dangling = this.placeholders.filter((p) => this.registry.codeAt(p.index) === 0);
862
+ if (dangling.length === 0 || !this.nodeRows) {
863
+ return;
864
+ }
865
+ const shown = dangling.slice(0, 5).map((p) => String(p.id)).join(", ");
866
+ this.report.warning(
867
+ "validation-error",
868
+ DANGLING_REFERENCE_CODE,
869
+ `${dangling.length} relationship endpoint${plural(dangling.length)} ${agree(dangling.length, "names", "name")} no node row and became nodes: ${shown}${dangling.length > 5 ? ", ..." : ""} (neo4j-admin refuses such relationships)`,
870
+ { element: String(dangling[0].id) }
871
+ );
736
872
  }
737
873
  /**
738
874
  * Push one relationship row.
@@ -751,7 +887,7 @@ class Neo4jImportSession {
751
887
  report.error(
752
888
  "validation-error",
753
889
  COLUMN_COUNT_CODE,
754
- `row has ${count} cell(s) but the header has ${section.width}`,
890
+ `row has ${count} cell${plural(count)} but the header has ${section.width}`,
755
891
  { line }
756
892
  );
757
893
  report.counts.skippedEdges++;
@@ -800,7 +936,7 @@ class Neo4jImportSession {
800
936
  let weight;
801
937
  if (section.weightCell >= 0) {
802
938
  try {
803
- weight = parseWeightText(cells[section.weightCell]);
939
+ weight = parseWeightText(cells[section.weightCell], this.report);
804
940
  } catch (err) {
805
941
  report.recordError(err, { line, element });
806
942
  report.counts.skippedEdges++;
@@ -811,6 +947,9 @@ class Neo4jImportSession {
811
947
  report.counts.skippedEdges++;
812
948
  return;
813
949
  }
950
+ const created = [source, target].filter(
951
+ (id, k) => (k === 0 || id !== source) && sink.indexOf(id) === INVALID_INDEX
952
+ );
814
953
  let edge;
815
954
  try {
816
955
  edge = this.direction.addEdge(source, target, "directed", weight, { line, element });
@@ -819,13 +958,26 @@ class Neo4jImportSession {
819
958
  report.counts.skippedEdges++;
820
959
  return;
821
960
  }
961
+ for (const id of created) {
962
+ report.counts.nodes++;
963
+ this.placeholders.push({ id, index: sink.indexOf(id) });
964
+ }
822
965
  if (section.typeCell >= 0) {
823
966
  const type = cells[section.typeCell];
824
967
  if (type.length > 0) {
825
- sink.setEdgeValue(this.typeHandle, edge, type);
968
+ this.guarded(line, element, () => {
969
+ sink.setEdgeValue(this.typeHandle, edge, type);
970
+ });
971
+ } else {
972
+ report.warning(
973
+ "missing-value",
974
+ MISSING_TYPE_CODE,
975
+ "empty :TYPE cell; neo4j-admin requires a relationship type, the relationship is kept without one",
976
+ { line, element }
977
+ );
826
978
  }
827
979
  }
828
- this.writeProperties("edge", section.properties, edge);
980
+ this.writeProperties("edge", section.properties, edge, line, element);
829
981
  this.reportPrecision(line, element);
830
982
  report.counts.edges++;
831
983
  }
@@ -886,6 +1038,7 @@ class Neo4jImportSession {
886
1038
  parseProperties(slots, cells, quoted, line, element) {
887
1039
  const { values, texts, precisionSlots } = this;
888
1040
  precisionSlots.length = 0;
1041
+ this.overflows.length = 0;
889
1042
  for (const slot of slots) {
890
1043
  const text = cells[slot.cell];
891
1044
  texts[slot.cell] = null;
@@ -896,16 +1049,21 @@ class Neo4jImportSession {
896
1049
  const { spec } = slot;
897
1050
  try {
898
1051
  if (spec.temporal !== null && !spec.list) {
899
- const parsed = parseDeclaredTemporal(text, spec);
1052
+ const zoned = withZoneOffset(text, spec);
1053
+ const parsed = parseDeclaredTemporal(zoned, spec);
900
1054
  values[slot.cell] = parsed.value;
901
- texts[slot.cell] = parsed.text;
1055
+ texts[slot.cell] = zoned === text ? parsed.text : text;
902
1056
  } else {
903
1057
  values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
1058
+ checkNeo4jRange(spec, values[slot.cell], text);
904
1059
  }
905
1060
  } catch (err) {
906
1061
  this.report.recordError(err, { line, element: `${element} ${slot.name}` });
907
1062
  return false;
908
1063
  }
1064
+ if (overflows(spec, values[slot.cell], text)) {
1065
+ this.overflows.push(slot.name);
1066
+ }
909
1067
  if (spec.precision && losesPrecision(spec, text)) {
910
1068
  precisionSlots.push(slot);
911
1069
  }
@@ -917,8 +1075,10 @@ class Neo4jImportSession {
917
1075
  * @param domain - node or edge
918
1076
  * @param slots - the section's property slots
919
1077
  * @param row - the node or edge index
1078
+ * @param line - the row's line
1079
+ * @param element - the row's element name for issues
920
1080
  */
921
- writeProperties(domain, slots, row) {
1081
+ writeProperties(domain, slots, row, line, element) {
922
1082
  const { sink, values, texts } = this;
923
1083
  for (const slot of slots) {
924
1084
  const value = values[slot.cell];
@@ -926,20 +1086,22 @@ class Neo4jImportSession {
926
1086
  continue;
927
1087
  }
928
1088
  const text = texts[slot.cell];
929
- if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
930
- slot.companion = declareCompanion(sink, domain, slot.companionDecl);
931
- }
932
- if (domain === "node") {
933
- sink.setNodeValue(slot.handle, row, value);
934
- if (text !== null) {
935
- sink.setNodeValue(slot.companion, row, text);
1089
+ this.guarded(line, `${element} ${slot.name}`, () => {
1090
+ if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
1091
+ slot.companion = declareCompanion(sink, domain, slot.companionDecl);
936
1092
  }
937
- } else {
938
- sink.setEdgeValue(slot.handle, row, value);
939
- if (text !== null) {
940
- sink.setEdgeValue(slot.companion, row, text);
1093
+ if (domain === "node") {
1094
+ sink.setNodeValue(slot.handle, row, value);
1095
+ if (text !== null) {
1096
+ sink.setNodeValue(slot.companion, row, text);
1097
+ }
1098
+ } else {
1099
+ sink.setEdgeValue(slot.handle, row, value);
1100
+ if (text !== null) {
1101
+ sink.setEdgeValue(slot.companion, row, text);
1102
+ }
941
1103
  }
942
- }
1104
+ });
943
1105
  }
944
1106
  }
945
1107
  /**
@@ -957,6 +1119,15 @@ class Neo4jImportSession {
957
1119
  );
958
1120
  }
959
1121
  this.precisionSlots.length = 0;
1122
+ for (const name of this.overflows) {
1123
+ this.report.warning(
1124
+ "precision",
1125
+ PRECISION_CODE,
1126
+ `the value of "${name}" is beyond the range of its float / double type and was stored as the nearest representable value`,
1127
+ { line, element }
1128
+ );
1129
+ }
1130
+ this.overflows.length = 0;
960
1131
  }
961
1132
  /**
962
1133
  * The labels of a node row: every `:LABEL` cell split by the array delimiter (empty items
@@ -994,6 +1165,101 @@ class Neo4jImportSession {
994
1165
  function qualify(id, space) {
995
1166
  return space === null ? id : `${space}:${String(id)}`;
996
1167
  }
1168
+ const INTEGER_RANGES = {
1169
+ byte: [-128, 127],
1170
+ short: [-32768, 32767]
1171
+ };
1172
+ function isDuration(text) {
1173
+ if (DURATION_DATE_TIME.test(text)) {
1174
+ return true;
1175
+ }
1176
+ const m = /^[+-]?P([^T]*)(?:T(.*))?$/i.exec(text);
1177
+ if (m === null || m[2] === "" || m[1] === "" && m[2] === void 0) {
1178
+ return false;
1179
+ }
1180
+ return unitsInOrder(m[1], "YMWD") && unitsInOrder(m[2] ?? "", "HMS");
1181
+ }
1182
+ const DURATION_DATE_TIME = /^[+-]?P\d{4}-?\d{2}-?\d{2}T\d{2}:?\d{2}:?\d{2}(?:\.\d+)?$/i;
1183
+ function unitsInOrder(text, units) {
1184
+ let rest = text.toUpperCase();
1185
+ let from = 0;
1186
+ while (rest !== "") {
1187
+ const m = /^[-+]?\d+(?:\.\d+)?([A-Z])/.exec(rest);
1188
+ const at = m === null ? -1 : units.indexOf(m[1], from);
1189
+ if (m === null || at < 0) {
1190
+ return false;
1191
+ }
1192
+ from = at + 1;
1193
+ rest = rest.slice(m[0].length);
1194
+ }
1195
+ return true;
1196
+ }
1197
+ function checkNeo4jRange(spec, value, text) {
1198
+ const base = spec.declared.trim().toLowerCase().replace(/\[\]$/, "");
1199
+ const items = spec.list && Array.isArray(value) ? value : [value];
1200
+ const range = INTEGER_RANGES[base];
1201
+ for (const item of items) {
1202
+ let bad = false;
1203
+ if (range !== void 0) {
1204
+ bad = typeof item === "number" && (item < range[0] || item > range[1]);
1205
+ } else if (base === "char") {
1206
+ bad = typeof item === "string" && item.length !== 1;
1207
+ } else if (base === "duration") {
1208
+ bad = typeof item === "string" && !isDuration(item.trim());
1209
+ }
1210
+ if (bad) {
1211
+ const span = range === void 0 ? "" : ` (${range[0]} to ${range[1]})`;
1212
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not ${withArticle(base)}${span}`, {
1213
+ value: text,
1214
+ kind: base
1215
+ });
1216
+ }
1217
+ }
1218
+ }
1219
+ const F32_MAX = 34028234663852886e22;
1220
+ function overflows(spec, value, text) {
1221
+ if (spec.kind !== "float" && spec.kind !== "double" || /inf|nan/i.test(text)) {
1222
+ return false;
1223
+ }
1224
+ const items = spec.list && Array.isArray(value) ? value : [value];
1225
+ return items.some(
1226
+ (v) => typeof v === "number" && (!Number.isFinite(v) || spec.kind === "float" && Math.abs(v) > F32_MAX)
1227
+ );
1228
+ }
1229
+ function withZoneOffset(text, spec) {
1230
+ const trimmed = text.trim();
1231
+ const open = trimmed.lastIndexOf("[");
1232
+ if (spec.temporal !== "dateTime" || open < 0 || !trimmed.endsWith("]")) {
1233
+ return text;
1234
+ }
1235
+ const local = trimmed.slice(0, open);
1236
+ const zone = trimmed.slice(open + 1, -1);
1237
+ if (zone === "" || zone.includes("]") || /[\n\r\u2028\u2029]/.test(local)) {
1238
+ return text;
1239
+ }
1240
+ let format;
1241
+ try {
1242
+ format = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" });
1243
+ } catch {
1244
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" names an unknown time zone ${zone}`, { value: text });
1245
+ }
1246
+ if (/(Z|z|[+-]\d{2}(:?\d{2})?)$/.test(local)) {
1247
+ return local;
1248
+ }
1249
+ const wall = parseTemporal(local, "localDateTime").value;
1250
+ const offsetAt = (ms) => {
1251
+ const name = format.formatToParts(new Date(ms)).find((p) => p.type === "timeZoneName")?.value ?? "GMT";
1252
+ const o = /GMT([+-])(\d{2}):(\d{2})/.exec(name);
1253
+ if (o === null) {
1254
+ return 0;
1255
+ }
1256
+ return (o[1] === "-" ? -1 : 1) * (Number(o[2]) * 60 + Number(o[3]));
1257
+ };
1258
+ const minutes = offsetAt(wall - offsetAt(wall) * 6e4);
1259
+ const sign = minutes < 0 ? "-" : "+";
1260
+ const abs = Math.abs(minutes);
1261
+ return `${local}${sign}${String(Math.floor(abs / 60)).padStart(2, "0")}:${String(abs % 60).padStart(2, "0")}`;
1262
+ }
997
1263
  function emptyValue(spec) {
998
1264
  if (spec.list) {
999
1265
  return [];
@@ -1027,6 +1293,7 @@ function sniffNeo4j(head) {
1027
1293
  }
1028
1294
  const neo4jImporter = Object.freeze({
1029
1295
  format: NEO4J$1,
1296
+ options: Object.freeze(["arrayDelimiter", "delimiter", "nodes", "quote", "relationships"]),
1030
1297
  extensions: Object.freeze([".csv", ".tsv"]),
1031
1298
  mimeTypes: Object.freeze(["text/csv", "text/tab-separated-values"]),
1032
1299
  sniff: sniffNeo4j,
@@ -1044,7 +1311,14 @@ const neo4jImporter = Object.freeze({
1044
1311
  reportSinkOptions(sink, options, report);
1045
1312
  reportUnusedOptions(options, report, USED_OPTIONS);
1046
1313
  const session = new Neo4jImportSession(sink, report, common, format);
1047
- await session.run([input, ...format.nodes, ...format.relationships]);
1314
+ await session.run([
1315
+ { input, kind: null },
1316
+ ...format.nodes.map((file) => ({ input: file, kind: "node" })),
1317
+ ...format.relationships.map((file) => ({ input: file, kind: "relationship" }))
1318
+ ]);
1319
+ if (session.weightProperty !== null) {
1320
+ sink.setMeta({ extra: { neo4j: { weightProperty: session.weightProperty } } });
1321
+ }
1048
1322
  throwIfAborted(common.signal);
1049
1323
  return report.finish();
1050
1324
  }
@@ -1121,7 +1395,7 @@ const NODE_NOTE_CODES = /* @__PURE__ */ new Set([
1121
1395
  ]);
1122
1396
  const ARRAY_SYNTAXES = /* @__PURE__ */ new Set([";", ",", "|"]);
1123
1397
  const PARTS = /* @__PURE__ */ new Set(["all", "nodes", "relationships"]);
1124
- function resolveNeo4jExportOptions(options) {
1398
+ function resolveNeo4jExportOptions(options, readFrom) {
1125
1399
  const o = options ?? {};
1126
1400
  const part = o.part ?? "all";
1127
1401
  if (!PARTS.has(part)) {
@@ -1145,12 +1419,16 @@ function resolveNeo4jExportOptions(options) {
1145
1419
  const delimiter = o.delimiter ?? ",";
1146
1420
  const syntax = { ...checkRecordSyntax({ delimiter, quote: o.quote ?? '"' }), delimiter };
1147
1421
  if (syntax.delimiter === arrayDelimiter) {
1148
- throw new GraphFormatError("E_UNSUPPORTED", "options delimiter and arrayDelimiter must differ", {
1149
- option: "arrayDelimiter",
1150
- found: arrayDelimiter
1151
- });
1422
+ throw new GraphFormatError(
1423
+ "E_UNSUPPORTED",
1424
+ `options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`,
1425
+ {
1426
+ option: "arrayDelimiter",
1427
+ found: arrayDelimiter
1428
+ }
1429
+ );
1152
1430
  }
1153
- const weightColumn = o.weightColumn === void 0 ? "weight" : o.weightColumn;
1431
+ const weightColumn = o.weightColumn === void 0 ? readFrom ?? "weight" : o.weightColumn;
1154
1432
  if (weightColumn !== null && (typeof weightColumn !== "string" || weightColumn.length === 0)) {
1155
1433
  throw new GraphFormatError("E_UNSUPPORTED", "option weightColumn: expected a non-empty name or null", {
1156
1434
  option: "weightColumn",
@@ -1197,7 +1475,8 @@ class ExportPlan {
1197
1475
  const generic = checkCapabilities(snapshot, NEO4J_CAPABILITIES, common, {
1198
1476
  roles: SLOT_ROLES,
1199
1477
  roleNames: ROLE_NAMES,
1200
- temporalText: true
1478
+ temporalText: true,
1479
+ weights: options.weightColumn !== null
1201
1480
  });
1202
1481
  this.planColumns("node", snapshot.nodes, this.nodeColumns);
1203
1482
  this.planColumns("edge", snapshot.edges, this.edgeColumns);
@@ -1246,7 +1525,7 @@ class ExportPlan {
1246
1525
  if (!snapshot.directed) {
1247
1526
  this.note(
1248
1527
  UNDIRECTED_LOSS,
1249
- `the snapshot is undirected; every edge is written as a directed relationship (${snapshot.edgeCount} edge(s))`,
1528
+ `the snapshot is undirected; every edge is written as a directed relationship (${snapshot.edgeCount} edge${plural(snapshot.edgeCount)})`,
1250
1529
  null,
1251
1530
  snapshot.edgeCount
1252
1531
  );
@@ -1260,7 +1539,7 @@ class ExportPlan {
1260
1539
  if (undirected > 0) {
1261
1540
  this.note(
1262
1541
  UNDIRECTED_LOSS,
1263
- `${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`,
1542
+ `${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`,
1264
1543
  null,
1265
1544
  undirected
1266
1545
  );
@@ -1269,7 +1548,7 @@ class ExportPlan {
1269
1548
  if (folding.mutualCount > 0) {
1270
1549
  this.note(
1271
1550
  LOSS.MUTUAL_EXPANDED,
1272
- `${folding.mutualCount} mutual pair(s) are written as two directed relationships; the mutual mark is lost`,
1551
+ `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two directed relationships; the mutual mark is lost`,
1273
1552
  null,
1274
1553
  folding.mutualCount
1275
1554
  );
@@ -1461,7 +1740,7 @@ class ExportPlan {
1461
1740
  if (rows > 0) {
1462
1741
  this.note(
1463
1742
  ARRAY_DELIMITER_LOSS,
1464
- `${label}: ${rows} row(s) hold an item containing the array delimiter "${arrayDelimiter}", which Neo4j cannot escape`,
1743
+ `${label}: ${rows} row${plural(rows)} ${agree(rows, "holds", "hold")} an item containing the array delimiter "${arrayDelimiter}", which Neo4j cannot escape`,
1465
1744
  column.meta.name,
1466
1745
  rows
1467
1746
  );
@@ -1496,7 +1775,7 @@ class ExportPlan {
1496
1775
  } else if (taken !== void 0 && name === DEFAULT_WEIGHT_COLUMN) {
1497
1776
  this.note(
1498
1777
  LOSS.WEIGHT_KEY_CLASH,
1499
- `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`,
1778
+ `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`,
1500
1779
  name,
1501
1780
  taken.column.length - taken.column.nullCount
1502
1781
  );
@@ -1550,7 +1829,7 @@ class ExportPlan {
1550
1829
  if (typeChanges > 0) {
1551
1830
  this.note(
1552
1831
  ID_TEXT_TYPE_LOSS,
1553
- `${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)`,
1832
+ `${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)`,
1554
1833
  null,
1555
1834
  typeChanges
1556
1835
  );
@@ -1558,13 +1837,13 @@ class ExportPlan {
1558
1837
  if (collisions > 0) {
1559
1838
  this.note(
1560
1839
  ID_TEXT_COLLISION_LOSS,
1561
- `${collisions} node id(s) share their text with another id (a number and a string); export() will throw`,
1840
+ `${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id (a number and a string); the save fails`,
1562
1841
  null,
1563
1842
  collisions
1564
1843
  );
1565
1844
  this.fatalAll = new GraphFormatError(
1566
1845
  "E_INVALID_ID",
1567
- `${collisions} node id(s) share their text with another id; Neo4j ids are text`,
1846
+ `${collisions} node id${plural(collisions)} ${agree(collisions, "shares", "share")} their text with another id; Neo4j ids are text`,
1568
1847
  { reason: "text collision", count: collisions }
1569
1848
  );
1570
1849
  }
@@ -1613,7 +1892,7 @@ class ExportPlan {
1613
1892
  if (count > 0) {
1614
1893
  this.note(
1615
1894
  MULTIPLE_ID_PROPERTIES_LOSS,
1616
- `${count} node(s) have more than one stored-id column set; only the first in declaration order is written`,
1895
+ `${count} node${plural(count)} ${agree(count, "has", "have")} more than one stored-id column set; only the first in declaration order is written`,
1617
1896
  null,
1618
1897
  count
1619
1898
  );
@@ -1713,6 +1992,16 @@ class ExportPlan {
1713
1992
  * @returns nothing
1714
1993
  */
1715
1994
  *lines() {
1995
+ for (const row of this.rows()) {
1996
+ yield row.line;
1997
+ }
1998
+ }
1999
+ /**
2000
+ * The lines of the requested part, each header line tagged with the file it starts.
2001
+ * @yields one line at a time, with the file name on a header line
2002
+ * @returns nothing
2003
+ */
2004
+ *rows() {
1716
2005
  if (this.fatal !== null) {
1717
2006
  throw this.fatal;
1718
2007
  }
@@ -1724,19 +2013,50 @@ class ExportPlan {
1724
2013
  yield* this.relationshipLines();
1725
2014
  }
1726
2015
  }
2016
+ /**
2017
+ * The requested part as one file per section kind: a node file per id space (and stored-id
2018
+ * property), a relationship file per pair of endpoint id spaces, rows of one kind gathered
2019
+ * under one header.
2020
+ * @returns the files, node files first
2021
+ */
2022
+ files() {
2023
+ const files = /* @__PURE__ */ new Map();
2024
+ const names = /* @__PURE__ */ new Set();
2025
+ let current = null;
2026
+ for (const row of this.rows()) {
2027
+ if (row.file !== null) {
2028
+ let file = files.get(row.line);
2029
+ if (file === void 0) {
2030
+ let name = `${row.file.name}.csv`;
2031
+ let k = 2;
2032
+ while (names.has(name)) {
2033
+ name = `${row.file.name}-${k}.csv`;
2034
+ k++;
2035
+ }
2036
+ names.add(name);
2037
+ file = { name, kind: row.file.kind, rows: [] };
2038
+ files.set(row.line, file);
2039
+ }
2040
+ current = file;
2041
+ } else if (current !== null) {
2042
+ current.rows.push(row.line);
2043
+ }
2044
+ }
2045
+ const written = [...files].filter(([, f], i) => f.rows.length > 0 || i === 0 && files.size === 1);
2046
+ return written.map(
2047
+ ([header, f]) => Object.freeze({ name: f.name, kind: f.kind, text: header + f.rows.join("") })
2048
+ );
2049
+ }
1727
2050
  /**
1728
2051
  * The node sections.
1729
2052
  * @yields one line at a time
1730
2053
  * @returns nothing
1731
2054
  */
1732
2055
  *nodeLines() {
1733
- const { snapshot, labels, nodeColumns } = this;
1734
- const { delimiter } = this.options.syntax;
1735
- const propertyHeaders = nodeColumns.map((plan2) => plan2.header).join(delimiter);
2056
+ const { snapshot } = this;
1736
2057
  let sections = 0;
1737
2058
  let sectionSpace = null;
1738
2059
  let sectionIdName = null;
1739
- const cells = [];
1740
2060
  for (let i = 0; i < snapshot.nodeCount; i++) {
1741
2061
  const space = this.spaceOf(i);
1742
2062
  const stored = this.storedIdOf(i);
@@ -1745,38 +2065,49 @@ class ExportPlan {
1745
2065
  sections++;
1746
2066
  sectionSpace = space;
1747
2067
  sectionIdName = idName;
1748
- const header = [formatHeaderField(idName, ID_TYPE, space)];
1749
- if (labels !== null) {
1750
- header.push(":LABEL");
1751
- }
1752
- if (propertyHeaders.length > 0) {
1753
- header.push(propertyHeaders);
1754
- }
1755
- yield `${header.join(delimiter)}
1756
- `;
1757
- }
1758
- cells.length = 0;
1759
- cells.push(this.cell(this.idTextOf(i)));
1760
- if (labels !== null) {
1761
- cells.push(this.cell(this.labelsText(i)));
1762
- }
1763
- for (const plan2 of nodeColumns) {
1764
- cells.push(this.cell(this.valueText(plan2, i)));
2068
+ yield this.nodeHeader(idName, space, space ?? idName);
1765
2069
  }
1766
- yield `${cells.join(delimiter)}
1767
- `;
2070
+ yield { line: this.nodeRow(i), file: null };
1768
2071
  }
1769
2072
  if (sections === 0) {
1770
- const header = [formatHeaderField(this.options.idColumn ?? "", ID_TYPE, null)];
1771
- if (labels !== null) {
1772
- header.push(":LABEL");
1773
- }
1774
- if (propertyHeaders.length > 0) {
1775
- header.push(propertyHeaders);
1776
- }
1777
- yield `${header.join(delimiter)}
1778
- `;
2073
+ yield this.nodeHeader(this.options.idColumn ?? "", null, null);
2074
+ }
2075
+ }
2076
+ /**
2077
+ * The header line of a node section, which starts its file.
2078
+ * @param idName - the id column's name
2079
+ * @param space - the id space, or null
2080
+ * @param fileKey - what names the file, or null for the default name
2081
+ * @returns the line
2082
+ */
2083
+ nodeHeader(idName, space, fileKey) {
2084
+ const { delimiter } = this.options.syntax;
2085
+ const header = [formatHeaderField(idName, ID_TYPE, space)];
2086
+ if (this.labels !== null) {
2087
+ header.push(":LABEL");
2088
+ }
2089
+ const properties = this.nodeColumns.map((plan2) => plan2.header).join(delimiter);
2090
+ if (properties.length > 0) {
2091
+ header.push(properties);
2092
+ }
2093
+ return { line: `${header.join(delimiter)}
2094
+ `, file: { kind: "nodes", name: fileName("nodes", fileKey, null) } };
2095
+ }
2096
+ /**
2097
+ * One node's line: the id, the labels, the properties.
2098
+ * @param i - the node
2099
+ * @returns the line
2100
+ */
2101
+ nodeRow(i) {
2102
+ const cells = [this.cell(this.idTextOf(i))];
2103
+ if (this.labels !== null) {
2104
+ cells.push(this.cell(this.labelsText(i)));
2105
+ }
2106
+ for (const plan2 of this.nodeColumns) {
2107
+ cells.push(this.cell(this.valueText(plan2, i)));
1779
2108
  }
2109
+ return `${cells.join(this.options.syntax.delimiter)}
2110
+ `;
1780
2111
  }
1781
2112
  /**
1782
2113
  * The relationship sections.
@@ -1784,29 +2115,11 @@ class ExportPlan {
1784
2115
  * @returns nothing
1785
2116
  */
1786
2117
  *relationshipLines() {
1787
- const { snapshot, kind, weights, edgeColumns, folding } = this;
1788
- const { delimiter } = this.options.syntax;
2118
+ const { snapshot, folding } = this;
1789
2119
  const list = snapshot.edgeList();
1790
- const propertyHeaders = edgeColumns.map((plan2) => plan2.header).join(delimiter);
1791
- const weightHeader = weights === null ? null : formatHeaderField(this.options.weightColumn ?? "weight", "double", null);
1792
2120
  let sections = 0;
1793
2121
  let sectionStart = null;
1794
2122
  let sectionEnd = null;
1795
- const cells = [];
1796
- const headerOf = (startSpace, endSpace) => {
1797
- const header = [formatHeaderField("", "START_ID", startSpace), formatHeaderField("", "END_ID", endSpace)];
1798
- if (kind !== null) {
1799
- header.push(":TYPE");
1800
- }
1801
- if (weightHeader !== null) {
1802
- header.push(weightHeader);
1803
- }
1804
- if (propertyHeaders.length > 0) {
1805
- header.push(propertyHeaders);
1806
- }
1807
- return `${header.join(delimiter)}
1808
- `;
1809
- };
1810
2123
  for (let e = 0; e < snapshot.edgeCount; e++) {
1811
2124
  if (folding.folded(e)) {
1812
2125
  continue;
@@ -1819,25 +2132,60 @@ class ExportPlan {
1819
2132
  sections++;
1820
2133
  sectionStart = startSpace;
1821
2134
  sectionEnd = endSpace;
1822
- yield headerOf(startSpace, endSpace);
1823
- }
1824
- cells.length = 0;
1825
- cells.push(this.cell(this.idTextOf(u)), this.cell(this.idTextOf(v)));
1826
- if (kind !== null) {
1827
- cells.push(this.cell(kind.isSet(e) ? textOf(kind, e) : null));
2135
+ yield this.relationshipHeader(startSpace, endSpace);
1828
2136
  }
1829
- if (weights !== null) {
1830
- cells.push(this.cell(weights.text(e)));
1831
- }
1832
- for (const plan2 of edgeColumns) {
1833
- cells.push(this.cell(this.valueText(plan2, e)));
1834
- }
1835
- yield `${cells.join(delimiter)}
1836
- `;
2137
+ yield { line: this.relationshipRow(e, u, v), file: null };
1837
2138
  }
1838
2139
  if (sections === 0) {
1839
- yield headerOf(null, null);
2140
+ yield this.relationshipHeader(null, null);
2141
+ }
2142
+ }
2143
+ /**
2144
+ * The header line of a relationship section, which starts its file.
2145
+ * @param startSpace - the id space of the start nodes, or null
2146
+ * @param endSpace - the id space of the end nodes, or null
2147
+ * @returns the line
2148
+ */
2149
+ relationshipHeader(startSpace, endSpace) {
2150
+ const { delimiter } = this.options.syntax;
2151
+ const header = [formatHeaderField("", "START_ID", startSpace), formatHeaderField("", "END_ID", endSpace)];
2152
+ if (this.kind !== null) {
2153
+ header.push(":TYPE");
2154
+ }
2155
+ if (this.weights !== null) {
2156
+ header.push(formatHeaderField(this.options.weightColumn ?? "weight", "double", null));
1840
2157
  }
2158
+ const properties = this.edgeColumns.map((plan2) => plan2.header).join(delimiter);
2159
+ if (properties.length > 0) {
2160
+ header.push(properties);
2161
+ }
2162
+ return {
2163
+ line: `${header.join(delimiter)}
2164
+ `,
2165
+ file: { kind: "relationships", name: fileName("relationships", startSpace, endSpace) }
2166
+ };
2167
+ }
2168
+ /**
2169
+ * One relationship's line: the ends, the type, the weight, the properties.
2170
+ * @param e - the edge
2171
+ * @param u - its source
2172
+ * @param v - its target
2173
+ * @returns the line
2174
+ */
2175
+ relationshipRow(e, u, v) {
2176
+ const { kind, weights } = this;
2177
+ const cells = [this.cell(this.idTextOf(u)), this.cell(this.idTextOf(v))];
2178
+ if (kind !== null) {
2179
+ cells.push(this.cell(kind.isSet(e) ? textOf(kind, e) : null));
2180
+ }
2181
+ if (weights !== null) {
2182
+ cells.push(this.cell(weights.text(e)));
2183
+ }
2184
+ for (const plan2 of this.edgeColumns) {
2185
+ cells.push(this.cell(this.valueText(plan2, e)));
2186
+ }
2187
+ return `${cells.join(this.options.syntax.delimiter)}
2188
+ `;
1841
2189
  }
1842
2190
  /**
1843
2191
  * A CSV cell: empty for an unset value, a quoted empty string for a set empty string, the
@@ -1853,7 +2201,7 @@ class ExportPlan {
1853
2201
  if (text.length === 0) {
1854
2202
  return quote + quote;
1855
2203
  }
1856
- return quoteCsvCell(text, this.options.syntax.delimiter);
2204
+ return quoteCsvCell(text, this.options.syntax.delimiter, quote);
1857
2205
  }
1858
2206
  /**
1859
2207
  * The `:LABEL` cell of a node.
@@ -2033,6 +2381,7 @@ function textOf(column, row) {
2033
2381
  }
2034
2382
  const neo4jExporter = Object.freeze({
2035
2383
  format: NEO4J,
2384
+ options: Object.freeze(["arrayDelimiter", "delimiter", "idColumn", "part", "quote", "weightColumn"]),
2036
2385
  capabilities: NEO4J_CAPABILITIES,
2037
2386
  /**
2038
2387
  * Pre-flight: what export() would lose.
@@ -2062,23 +2411,56 @@ const neo4jExporter = Object.freeze({
2062
2411
  return joinText(plan(snapshot, options).lines());
2063
2412
  }
2064
2413
  });
2414
+ function fileName(kind, first, second) {
2415
+ const parts = [kind, first ?? "", second ?? ""].filter((p) => p !== "");
2416
+ return parts.join("-").replaceAll(/[^\w.-]/g, "_");
2417
+ }
2418
+ function exportNeo4jFiles(snapshot, options) {
2419
+ try {
2420
+ return Promise.resolve(plan(snapshot, options).files());
2421
+ } catch (err) {
2422
+ return Promise.reject(err);
2423
+ }
2424
+ }
2065
2425
  function plan(snapshot, options) {
2066
- return new ExportPlan(snapshot, resolveNeo4jExportOptions(options), resolveExportOptions(options));
2426
+ return new ExportPlan(
2427
+ snapshot,
2428
+ resolveNeo4jExportOptions(options, weightPropertyOf(snapshot)),
2429
+ resolveExportOptions(options)
2430
+ );
2431
+ }
2432
+ function weightPropertyOf(snapshot) {
2433
+ const neo4j = snapshot.meta.extra?.neo4j;
2434
+ const name = neo4j?.weightProperty;
2435
+ return typeof name === "string" && name !== "" ? name : null;
2067
2436
  }
2068
2437
  const NEO4J_ISSUE = Object.freeze({
2069
- /** The input holds invalid UTF-8 (fatal). */
2438
+ ...INPUT_ISSUE,
2439
+ ...ELEMENT_ISSUE,
2440
+ /**
2441
+ * A cell that does not parse as its column's declared type ("x" in an `:int` column, a `:byte` beyond 127). The
2442
+ * row is skipped.
2443
+ */
2444
+ COLUMN_TYPE: COLUMN_TYPE_CODE,
2445
+ /** The input is not valid UTF-8. The import stops. */
2070
2446
  INVALID_UTF8: INVALID_UTF8_CODE,
2071
- /** Invalid bytes in the encoding a BOM, a declaration or the encoding option chose (fatal). */
2447
+ /**
2448
+ * Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
2449
+ * `encoding` option). The import stops.
2450
+ */
2072
2451
  INVALID_ENCODING: INVALID_ENCODING_CODE,
2073
2452
  /** Bytes that are not UTF-8 and declare no encoding were read as windows-1252. */
2074
2453
  ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
2075
2454
  /** A declared encoding the platform cannot decode was ignored. */
2076
2455
  UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
2077
- /** An unterminated quoted field (fatal). */
2456
+ /** A quoted field is never closed. The import stops. */
2078
2457
  CSV_UNCLOSED_QUOTE: UNCLOSED_QUOTE_CODE,
2079
- /** Text after a closing quote (fatal). */
2458
+ /**
2459
+ * There is text after a closing quote, such as `"a"b`. Inside a quoted field, write a quote as two quotes. The
2460
+ * import stops.
2461
+ */
2080
2462
  CSV_QUOTE: BAD_QUOTE_CODE,
2081
- /** No header or a malformed header (fatal). */
2463
+ /** The file has no header, or a header neo4j-admin would refuse. The import stops. */
2082
2464
  HEADER: HEADER_CODE,
2083
2465
  /** A row with a different field count than the header. */
2084
2466
  COLUMN_COUNT: COLUMN_COUNT_CODE,
@@ -2092,41 +2474,65 @@ const NEO4J_ISSUE = Object.freeze({
2092
2474
  ID_SPACE_COLLISION: ID_SPACE_COLLISION_CODE,
2093
2475
  /** A spaced relationship endpoint `Space:id` that names a node declared without a space; the row is skipped. */
2094
2476
  ENDPOINT_SPACE: ENDPOINT_SPACE_CODE,
2095
- /** Two id texts merged into one number under ids "number". */
2477
+ /** Two different id texts became the same number because `ids` is "number", so their nodes were merged. */
2096
2478
  ID_MERGED: ID_MERGED_CODE,
2097
2479
  /** A header brace option the importer does not apply. */
2098
2480
  HEADER_OPTION_IGNORED: HEADER_OPTION_CODE,
2099
2481
  /** A declared type the format does not define (kept as string). */
2100
2482
  UNKNOWN_ATTR_TYPE: UNKNOWN_ATTR_TYPE_CODE,
2101
- /** A long value beyond 2^53 rounded. */
2483
+ /** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
2102
2484
  PRECISION: PRECISION_CODE,
2103
- /** A column renamed `<name>#<id>` because the name was taken (design section 5.6). */
2485
+ /**
2486
+ * An attribute was renamed `<name>#<suffix>` because another attribute already has its name, for example a
2487
+ * repeated column header.
2488
+ */
2104
2489
  COLUMN_RENAMED: COLUMN_RENAMED_CODE,
2105
- /** A role the caller's sink already holds. */
2490
+ /**
2491
+ * You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
2492
+ * a plain attribute.
2493
+ */
2106
2494
  ROLE_TAKEN: ROLE_TAKEN_CODE,
2107
- /** A common option the importer has no use for (nodeIdFrom, defaultDirected, ...). */
2495
+ /** You set an option this format does not use; it had no effect. The message names the option. */
2108
2496
  OPTION_IGNORED: OPTION_IGNORED_CODE,
2109
- /** A builder-policy option the sink does not honour. */
2110
- SINK_OPTION: SINK_OPTION_CODE
2497
+ /**
2498
+ * You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
2499
+ * `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
2500
+ */
2501
+ SINK_OPTION: SINK_OPTION_CODE,
2502
+ /** A relationship with an empty :TYPE cell (neo4j-admin requires one); kept without a type. */
2503
+ MISSING_TYPE: MISSING_TYPE_CODE,
2504
+ /** A file under the nodes option holds a relationship header, or the reverse; read by its header. */
2505
+ SECTION_KIND: SECTION_KIND_CODE,
2506
+ /** Relationship endpoints no node row declares became nodes (neo4j-admin refuses them). */
2507
+ DANGLING_REFERENCE: DANGLING_REFERENCE_CODE
2111
2508
  });
2112
2509
  const NEO4J_LOSS = Object.freeze({
2113
2510
  /** `:IGNORE` columns skipped on import. */
2114
2511
  IGNORED_COLUMNS: IGNORED_COLUMNS_LOSS,
2115
- /** Undirected edges (an undirected snapshot, the folded pairs of a mixed one) written as directed relationships. */
2512
+ /**
2513
+ * Neo4j relationships are always directed, so the edges of an undirected graph, and the undirected edges of a
2514
+ * mixed graph, read back as directed.
2515
+ */
2116
2516
  UNDIRECTED_AS_DIRECTED: UNDIRECTED_LOSS,
2117
2517
  /** A mutual pair written as two directed relationships without its mark. */
2118
2518
  MUTUAL_EXPANDED: MUTUAL_EXPANDED_CODE,
2119
- /** A role column Neo4j has no slot for (label, ...) written as a plain property. */
2519
+ /** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */
2120
2520
  ROLE_DROPPED: ROLE_DROPPED_CODE,
2121
- /** A plain `weight` edge column reads back as THE weight (the importer's weightFrom default). */
2521
+ /**
2522
+ * An edge attribute named `weight` that is not the graph's weight reads back as the edge weight, because the
2523
+ * Neo4j importer reads weights from the `weight` property by default.
2524
+ */
2122
2525
  WEIGHT_KEY_CLASH: WEIGHT_KEY_CLASH_CODE,
2123
- /** A node id whose text re-imports as another type under the canonical rule. */
2526
+ /**
2527
+ * A node id that reads back as a different type, such as the text "7" as the number 7. Read the file with `ids:
2528
+ * "string"` or `ids: "keep"` to keep the type.
2529
+ */
2124
2530
  ID_TEXT_TYPE: ID_TEXT_TYPE_LOSS,
2125
- /** A number and a string id with the same text; export() throws. */
2531
+ /** Two node ids would be written as the same text (the number 5 and the text "5"); the save fails with E_INVALID_ID. */
2126
2532
  ID_TEXT_COLLISION: ID_TEXT_COLLISION_LOSS,
2127
- /** The weight column name is taken by an edge column; export() throws. */
2533
+ /** The `weightColumn` name is already an edge attribute; the save fails. */
2128
2534
  WEIGHT_COLUMN_TAKEN: WEIGHT_COLUMN_TAKEN_LOSS,
2129
- /** The id column name is taken by a node column; export() throws. */
2535
+ /** The `idColumn` name is already a node attribute; the save fails. */
2130
2536
  ID_COLUMN_TAKEN: ID_COLUMN_TAKEN_LOSS,
2131
2537
  /** Several stored-id properties; one becomes the `:ID` column. */
2132
2538
  MULTIPLE_ID_PROPERTIES: MULTIPLE_ID_PROPERTIES_LOSS,
@@ -2143,6 +2549,7 @@ export {
2143
2549
  NEO4J_LOSS,
2144
2550
  ORIGINAL_ID_COLUMN,
2145
2551
  TYPE_COLUMN,
2552
+ exportNeo4jFiles,
2146
2553
  neo4jExporter,
2147
2554
  neo4jImporter
2148
2555
  };