@graphty/graph-io 0.3.25 → 0.3.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-DrXtu_96.js +56 -0
  4. package/dist/chunks/choose-DrXtu_96.js.map +1 -0
  5. package/dist/chunks/constants-ikG85dT8.js +231 -0
  6. package/dist/chunks/constants-ikG85dT8.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D1HPTUrP.js} +390 -99
  8. package/dist/chunks/escape-D1HPTUrP.js.map +1 -0
  9. package/dist/chunks/export-CHd4tQE2.js +4333 -0
  10. package/dist/chunks/export-CHd4tQE2.js.map +1 -0
  11. package/dist/chunks/{importer-eUREhBGj.js → exporter-D23CKNqF.js} +4969 -3201
  12. package/dist/chunks/exporter-D23CKNqF.js.map +1 -0
  13. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-DfWTgrti.js} +23 -21
  14. package/dist/chunks/exporter-DfWTgrti.js.map +1 -0
  15. package/dist/chunks/exporter-DhtW6FxK.js +3465 -0
  16. package/dist/chunks/exporter-DhtW6FxK.js.map +1 -0
  17. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-IHv4nkCm.js} +38 -229
  18. package/dist/chunks/exporter-IHv4nkCm.js.map +1 -0
  19. package/dist/chunks/{importer-BWY2FFc5.js → importer-B1wmPQjr.js} +255 -77
  20. package/dist/chunks/importer-B1wmPQjr.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-B2W_58pz.js} +399 -146
  22. package/dist/chunks/importer-B2W_58pz.js.map +1 -0
  23. package/dist/chunks/importer-BSALvkui.js +2811 -0
  24. package/dist/chunks/importer-BSALvkui.js.map +1 -0
  25. package/dist/chunks/{importer-vi3bSdtw.js → importer-BVRE--Un.js} +510 -77
  26. package/dist/chunks/importer-BVRE--Un.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-CIAzt-wo.js} +1689 -312
  28. package/dist/chunks/importer-CIAzt-wo.js.map +1 -0
  29. package/dist/chunks/{importer-DIrbbnAf.js → importer-DpEW5zeG.js} +585 -226
  30. package/dist/chunks/importer-DpEW5zeG.js.map +1 -0
  31. package/dist/chunks/{importer-zGLo8Dg_.js → importer-z_FL4VMb.js} +488 -161
  32. package/dist/chunks/importer-z_FL4VMb.js.map +1 -0
  33. package/dist/chunks/json-elements-BAmNBZok.js +1225 -0
  34. package/dist/chunks/json-elements-BAmNBZok.js.map +1 -0
  35. package/dist/chunks/ontology-export-Bab4eUA8.js +357 -0
  36. package/dist/chunks/ontology-export-Bab4eUA8.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CdlvL4RO.js} +298 -114
  38. package/dist/chunks/records-CdlvL4RO.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DzXjAiTl.js} +29 -11
  40. package/dist/chunks/text-DzXjAiTl.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +952 -262
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +344 -87
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +565 -158
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +21 -3
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +39 -22
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +869 -189
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +3 -1
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +402 -85
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +146 -33
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +682 -287
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +227 -80
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +101 -27
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +110 -28
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +239 -86
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +67 -35
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +186 -54
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +21 -22
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +8 -3
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +40 -6
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +39 -22
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1035 -199
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +7 -2
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +479 -90
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +202 -47
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +890 -302
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +62 -339
  498. package/src/formats/cx2/importer.ts +318 -87
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +142 -34
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +113 -28
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +321 -102
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +90 -42
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +216 -55
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +36 -28
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +12 -4
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -35,52 +35,113 @@
35
35
  */
36
36
  import { GraphFormatError, INVALID_INDEX, } from "@graphty/graph-format";
37
37
  import { declareAttribute, declareCompanion, declareOn, losesPrecision, parseDeclaredTemporal, parseDeclaredValue, PRECISION_CODE, RENAMED_CODE, takenIn, uniqueColumnName, } from "../../common/attributes.js";
38
- import { DUPLICATE_NODE_CODE as SHARED_DUPLICATE_NODE_CODE, MISSING_ENDPOINT_CODE as SHARED_MISSING_ENDPOINT_CODE, MISSING_ID_CODE as SHARED_MISSING_ID_CODE, ROLE_TAKEN_CODE as SHARED_ROLE_TAKEN_CODE, } from "../../common/codes.js";
38
+ import { DANGLING_REFERENCE_CODE as SHARED_DANGLING_REFERENCE_CODE, DUPLICATE_NODE_CODE as SHARED_DUPLICATE_NODE_CODE, MISSING_ENDPOINT_CODE as SHARED_MISSING_ENDPOINT_CODE, MISSING_ID_CODE as SHARED_MISSING_ID_CODE, ROLE_TAKEN_CODE as SHARED_ROLE_TAKEN_CODE, } from "../../common/codes.js";
39
39
  import { DirectionResolver } from "../../common/direction.js";
40
40
  import { ID_MERGED_CODE as SHARED_ID_MERGED_CODE, IdCoercer } from "../../common/ids.js";
41
41
  import { inputLength, isImportInput, throwIfAborted } from "../../common/input.js";
42
42
  import { splitListText } from "../../common/lists.js";
43
43
  import { reportSinkOptions, reportUnusedOptions, resolveImportOptions, } from "../../common/options.js";
44
+ import { agree, plural, withArticle } from "../../common/plural.js";
44
45
  import { ImportReportBuilder } from "../../common/report.js";
46
+ import { parseTemporal } from "../../common/temporal.js";
45
47
  import { parseWeightText } from "../../common/weights.js";
46
48
  import { ImportError, } from "../../types.js";
47
49
  import { checkRecordSyntax, RecordReader } from "../csv/records.js";
48
50
  import { isHeaderRecord, parseHeaderField } from "./header.js";
49
- /** The name of the node list column holding `:LABEL` values. */
51
+ /**
52
+ * The name of the node list column holding `:LABEL` values.
53
+ * @category Built-in formats
54
+ */
50
55
  export const LABELS_COLUMN = "labels";
51
- /** The name of the edge dict column holding `:TYPE` values. */
56
+ /**
57
+ * The name of the edge dict column holding `:TYPE` values.
58
+ * @category Built-in formats
59
+ */
52
60
  export const TYPE_COLUMN = "type";
53
- /** The name of the node dict column holding the id space of `:ID(Space)`. */
61
+ /**
62
+ * The name of the node dict column holding the id space of `:ID(Space)`.
63
+ * @category Built-in formats
64
+ */
54
65
  export const ID_SPACE_COLUMN = "idSpace";
55
- /** The name of the node string column holding the id text of a node of an id space (its id is `Space:id`). */
66
+ /**
67
+ * Neo4j CSV: the name of the node column that holds a node's id as the file wrote it, for a node of an id
68
+ * space (`:ID(Person)`), whose node id is `Person:<id>`. It has nothing to do with the `originalId` role that
69
+ * `sanitizeIds: "mangle"` uses.
70
+ * @category Built-in formats
71
+ */
56
72
  export const ORIGINAL_ID_COLUMN = "originalId";
57
- /** Issue code: a header row (or a whole section) is malformed; the import aborts. */
73
+ /**
74
+ * A header row (or a whole section) is malformed; the import aborts.
75
+ * @category Issue and loss codes
76
+ */
58
77
  export const HEADER_CODE = "E_NEO4J_HEADER";
59
- /** Issue code: a row has a different number of cells than its header. */
78
+ /**
79
+ * A row has a different number of cells than its header.
80
+ * @category Issue and loss codes
81
+ */
60
82
  export const COLUMN_COUNT_CODE = "E_NEO4J_COLUMN_COUNT";
61
- /** Issue code: a node row has an unquoted empty `:ID` cell (a quoted empty cell is the id ""). */
83
+ /**
84
+ * A node row has an unquoted empty `:ID` cell (a quoted empty cell is the id "").
85
+ * @category Issue and loss codes
86
+ */
62
87
  export const MISSING_ID_CODE = SHARED_MISSING_ID_CODE;
63
- /** Issue code: a relationship row has an unquoted empty `:START_ID` or `:END_ID` cell. */
88
+ /**
89
+ * A relationship row has an unquoted empty `:START_ID` or `:END_ID` cell.
90
+ * @category Issue and loss codes
91
+ */
64
92
  export const MISSING_ENDPOINT_CODE = SHARED_MISSING_ENDPOINT_CODE;
65
- /** Issue code: a node id was declared twice (same id space); the later row's properties win. */
93
+ /**
94
+ * A node id was declared twice (same id space); the later row's properties win.
95
+ * @category Issue and loss codes
96
+ */
66
97
  export const DUPLICATE_NODE_CODE = SHARED_DUPLICATE_NODE_CODE;
67
98
  /**
68
- * Issue code: a node id was declared in two id spaces -- a spaced id `Space:id` equals the text of an
69
- * id declared without a space; the later row is skipped.
99
+ * A node id was declared in two id spaces -- a spaced id `Space:id` equals the text of an id declared without a space;
100
+ * the later row is skipped.
101
+ * @category Issue and loss codes
70
102
  */
71
103
  export const ID_SPACE_COLLISION_CODE = "E_NEO4J_ID_SPACE_COLLISION";
72
104
  /**
73
- * Issue code: a `:START_ID(Space)` / `:END_ID(Space)` endpoint's qualified id `Space:id` names a node a
74
- * node row declared in another id space (without a space); the row is skipped.
105
+ * A `:START_ID(Space)` / `:END_ID(Space)` endpoint's qualified id `Space:id` names a node a node row declared in
106
+ * another id space (without a space); the row is skipped.
107
+ * @category Issue and loss codes
75
108
  */
76
109
  export const ENDPOINT_SPACE_CODE = "E_NEO4J_ENDPOINT_SPACE";
77
- /** Issue code: two different id cells became one id under `ids: "number"`. */
110
+ /**
111
+ * Two different id cells became one id under `ids: "number"`.
112
+ * @category Issue and loss codes
113
+ */
78
114
  export const ID_MERGED_CODE = SHARED_ID_MERGED_CODE;
79
- /** Issue code: a header brace option the importer does not act on. */
115
+ /**
116
+ * A header brace option the importer does not act on.
117
+ * @category Issue and loss codes
118
+ */
80
119
  export const HEADER_OPTION_CODE = "W_NEO4J_HEADER_OPTION_IGNORED";
81
- /** Issue code: a reserved column (labels / type / idSpace) lost its role because the sink already holds it. */
120
+ /**
121
+ * You read into a graph builder that already has the labels, type or id space attribute, so this file's one is kept
122
+ * without its role.
123
+ * @category Issue and loss codes
124
+ */
82
125
  export const ROLE_TAKEN_CODE = SHARED_ROLE_TAKEN_CODE;
83
- /** Loss code: `:IGNORE` columns were skipped. */
126
+ /**
127
+ * A relationship row with an empty `:TYPE` cell (neo4j-admin requires a type); the relationship is kept.
128
+ * @category Issue and loss codes
129
+ */
130
+ export const MISSING_TYPE_CODE = "W_NEO4J_MISSING_TYPE";
131
+ /**
132
+ * A file given under the `nodes` option holds a relationship header, or the reverse.
133
+ * @category Issue and loss codes
134
+ */
135
+ export const SECTION_KIND_CODE = "W_NEO4J_SECTION_KIND";
136
+ /**
137
+ * Relationship endpoints that no node row declares became nodes (the shared W_DANGLING_REFERENCE).
138
+ * @category Issue and loss codes
139
+ */
140
+ export const DANGLING_REFERENCE_CODE = SHARED_DANGLING_REFERENCE_CODE;
141
+ /**
142
+ * `:IGNORE` columns were skipped.
143
+ * @category Built-in formats
144
+ */
84
145
  export const IGNORED_COLUMNS_LOSS = "W_NEO4J_IGNORED_COLUMNS";
85
146
  /** The common options the Neo4j importer reads (the rest is reported by reportUnusedOptions). */
86
147
  const USED_OPTIONS = new Set([
@@ -143,13 +204,16 @@ function resolveNeo4jOptions(options) {
143
204
  if (typeof arrayDelimiter !== "string" || listSyntax === undefined) {
144
205
  throw new GraphFormatError("E_UNSUPPORTED", `option arrayDelimiter: ${JSON.stringify(arrayDelimiter)} is not one of ";", ",", "|"`, { option: "arrayDelimiter", found: arrayDelimiter });
145
206
  }
207
+ if (arrayDelimiter === "," && o.delimiter === undefined) {
208
+ throw new GraphFormatError("E_UNSUPPORTED", 'option arrayDelimiter "," needs the delimiter option: the field delimiter is a comma unless another is given', { option: "arrayDelimiter", found: arrayDelimiter });
209
+ }
146
210
  const syntax = checkRecordSyntax({
147
211
  delimiter: o.delimiter ?? null,
148
212
  quote: o.quote ?? '"',
149
213
  candidates: NEO4J_DELIMITER_CANDIDATES.filter((d) => d !== arrayDelimiter),
150
214
  });
151
215
  if (syntax.delimiter === arrayDelimiter) {
152
- throw new GraphFormatError("E_UNSUPPORTED", "options delimiter and arrayDelimiter must differ", {
216
+ throw new GraphFormatError("E_UNSUPPORTED", `options delimiter and arrayDelimiter must differ: both are ${JSON.stringify(arrayDelimiter)}; pass another arrayDelimiter (";", "," or "|")`, {
153
217
  option: "arrayDelimiter",
154
218
  found: arrayDelimiter,
155
219
  });
@@ -162,7 +226,7 @@ function resolveNeo4jOptions(options) {
162
226
  };
163
227
  }
164
228
  /**
165
- * Normalise an input-list option.
229
+ * Normalize an input-list option.
166
230
  * @param name - the option name
167
231
  * @param value - one input, a list of inputs, or undefined
168
232
  * @returns the inputs; E_UNSUPPORTED for anything else
@@ -299,6 +363,8 @@ class Neo4jImportSession {
299
363
  */
300
364
  constructor(sink, report, common, options) {
301
365
  this.registry = new NodeRegistry();
366
+ /** The relationship property the weights were read from, when it is not "weight"; the exporter writes it back under that name. */
367
+ this.weightProperty = null;
302
368
  this.labelsHandle = INVALID_INDEX;
303
369
  this.typeHandle = INVALID_INDEX;
304
370
  this.idSpaceHandle = INVALID_INDEX;
@@ -312,6 +378,14 @@ class Neo4jImportSession {
312
378
  this.texts = [];
313
379
  /** Scratch: the property slots of the current row that lost precision. */
314
380
  this.precisionSlots = [];
381
+ /** Scratch: the values of the current row that overflowed their float / double type. */
382
+ this.overflows = [];
383
+ /** The section kind the option of the input being read names, or null for the primary input. */
384
+ this.expectedKind = null;
385
+ /** Whether any node row was read. */
386
+ this.nodeRows = false;
387
+ /** Nodes relationship endpoints created (no node row declared them yet), the first few by id. */
388
+ this.placeholders = [];
315
389
  this.sink = sink;
316
390
  this.report = report;
317
391
  this.common = common;
@@ -320,33 +394,59 @@ class Neo4jImportSession {
320
394
  this.direction = new DirectionResolver(sink, report, common.onMixedDirection);
321
395
  }
322
396
  /**
323
- * Read every input.
324
- * @param inputs - the inputs in reading order
397
+ * Read every input. A header-only input lends its header to the headerless input after it (the
398
+ * neo4j-admin convention `--nodes=header.csv,part1.csv`); an empty input is an error only when
399
+ * it is the only one.
400
+ * @param inputs - the inputs in reading order, each with the kind of section its option names (null for the primary input)
325
401
  */
326
402
  async run(inputs) {
327
- const progress = new ProgressTracker(this.common.onProgress, inputs);
328
- for (const input of inputs) {
329
- await this.readInput(input, { ...progress.optionsFor(this.common.signal), encoding: this.common.encoding });
403
+ const progress = new ProgressTracker(this.common.onProgress, inputs.map((i) => i.input));
404
+ let carried = null;
405
+ for (const { input, kind } of inputs) {
406
+ this.expectedKind = kind;
407
+ if (carried !== null && kind !== null && carried.kind !== kind) {
408
+ // a nodes header never lends itself to a relationships file, nor the reverse
409
+ carried = null;
410
+ }
411
+ carried = await this.readInput(input, { ...progress.optionsFor(this.common.signal), encoding: this.common.encoding }, carried, inputs.length > 1);
330
412
  progress.finishInput();
331
413
  }
332
414
  if (this.ignoredColumns > 0) {
333
- this.report.loss(IGNORED_COLUMNS_LOSS, `${this.ignoredColumns} :IGNORE column(s) were skipped as the header instructs`, null, this.ignoredColumns);
415
+ this.report.loss(IGNORED_COLUMNS_LOSS, `${this.ignoredColumns} :IGNORE column${plural(this.ignoredColumns)} ${agree(this.ignoredColumns, "was", "were")} skipped as the header instructs`, null, this.ignoredColumns);
334
416
  }
417
+ this.reportDangling();
335
418
  }
336
419
  /**
337
420
  * Read one input: a header row, then data rows until the next header row.
338
421
  * @param input - the input
339
422
  * @param readOptions - cancellation and progress
423
+ * @param carried - the section of a header-only input just before this one, or null
424
+ * @param mayBeEmpty - whether an input without any record is allowed (other inputs exist)
425
+ * @returns this input's section when it held a header and no data row (lent to the next input), else null
340
426
  */
341
- async readInput(input, readOptions) {
342
- const reader = new RecordReader(input, this.report, this.options.syntax, readOptions);
343
- let section = null;
427
+ async readInput(input, readOptions, carried, mayBeEmpty) {
428
+ const reader = new RecordReader(input, this.report, this.options.syntax, {
429
+ ...readOptions,
430
+ allowEmpty: mayBeEmpty,
431
+ });
432
+ let section = carried;
433
+ let records = 0;
434
+ let rows = 0;
344
435
  let sinceCheck = 0;
345
436
  for await (const count of reader) {
346
- if (section === null || isHeaderRecord(reader.cells, count)) {
437
+ const { cells, quoted } = reader;
438
+ if (records === 0 && count === 1 && !quoted[0] && cells[0].trim().length === 0) {
439
+ // a whitespace-only line before anything else is a blank line, not an empty header
440
+ continue;
441
+ }
442
+ records++;
443
+ // a quoted marker cell is data ("ref:id") unless the whole record is a quoted header
444
+ if (section === null || isHeaderRecord(cells, count, quoted)) {
347
445
  section = this.declareSection(reader, count);
446
+ rows = 0;
348
447
  continue;
349
448
  }
449
+ rows++;
350
450
  if (section.kind === "node") {
351
451
  this.nodeRow(section, reader, count);
352
452
  }
@@ -358,9 +458,14 @@ class Neo4jImportSession {
358
458
  throwIfAborted(readOptions.signal);
359
459
  }
360
460
  }
361
- if (section === null) {
461
+ if (records === 0 && carried === null && !mayBeEmpty) {
362
462
  this.report.fail(HEADER_CODE, "the input has no header row", { line: 1 });
363
463
  }
464
+ // the header lent on: a header-only input's, or the one lent to this input when it had none
465
+ if (section === carried) {
466
+ return carried;
467
+ }
468
+ return rows === 0 ? section : null;
364
469
  }
365
470
  /**
366
471
  * Interpret a header row: parse every cell, check the section shape, declare its columns.
@@ -394,7 +499,13 @@ class Neo4jImportSession {
394
499
  throw headerError("a header mixes :ID with :START_ID / :END_ID");
395
500
  }
396
501
  if (!isNode && !isRelationship) {
397
- throw headerError("a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)");
502
+ const apoc = fields.some((f) => f.name === "_id" || f.name === "_start");
503
+ throw headerError(apoc
504
+ ? "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"
505
+ : "a header needs an :ID column (nodes) or :START_ID and :END_ID columns (relationships)");
506
+ }
507
+ if (this.expectedKind !== null && this.expectedKind !== (isNode ? "node" : "relationship")) {
508
+ this.report.warning("validation-error", SECTION_KIND_CODE, `a ${isNode ? "node" : "relationship"} header in a file given as ${this.expectedKind === "node" ? "nodes" : "relationships"}; read by its header`, { line });
398
509
  }
399
510
  checkPropertyNames(fields);
400
511
  this.ignoredColumns += (kinds.get("IGNORE") ?? []).length;
@@ -421,7 +532,12 @@ class Neo4jImportSession {
421
532
  }
422
533
  catch (err) {
423
534
  if (err instanceof GraphFormatError && !(err instanceof ImportError)) {
424
- this.report.fail(HEADER_CODE, `line ${line}: ${err.message}`, { line }, { cause: err.code });
535
+ // a header written with another delimiter reads as one cell holding it
536
+ const other = [";", "|", "\t", ","].find((d) => d !== reader.delimiter && reader.cells.slice(0, count).some((c) => c.includes(d)));
537
+ const hint = other === undefined
538
+ ? ""
539
+ : `; if the file is delimited by ${JSON.stringify(other)}, pass the delimiter option`;
540
+ this.report.fail(HEADER_CODE, `${err.message}${hint}`, { line }, { cause: err.code });
425
541
  }
426
542
  throw err;
427
543
  }
@@ -492,6 +608,9 @@ class Neo4jImportSession {
492
608
  let weightCell = -1;
493
609
  if (weightFrom !== null) {
494
610
  weightCell = fields.findIndex((field) => field.kind === "PROPERTY" && field.name === weightFrom);
611
+ if (weightCell >= 0 && weightFrom !== "weight") {
612
+ this.weightProperty = weightFrom;
613
+ }
495
614
  }
496
615
  const properties = this.declareProperties("edge", fields, line, weightCell);
497
616
  const { space: startSpace } = fields[startCell];
@@ -645,7 +764,7 @@ class Neo4jImportSession {
645
764
  const { sink, report } = this;
646
765
  const { cells, quoted, line } = reader;
647
766
  if (count !== section.width) {
648
- report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell(s) but the header has ${section.width}`, { line });
767
+ report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell${plural(count)} but the header has ${section.width}`, { line });
649
768
  report.counts.skippedNodes++;
650
769
  return;
651
770
  }
@@ -666,7 +785,17 @@ class Neo4jImportSession {
666
785
  if (section.labelCells.length > 0 || section.extraLabels.length > 0) {
667
786
  labels = this.labelsOf(section, cells, quoted);
668
787
  }
669
- const index = sink.addNode(id);
788
+ this.nodeRows = true;
789
+ const existed = sink.indexOf(id) !== INVALID_INDEX;
790
+ let index;
791
+ try {
792
+ index = sink.addNode(id);
793
+ }
794
+ catch (err) {
795
+ report.recordError(err, { line, element: idText });
796
+ report.counts.skippedNodes++;
797
+ return;
798
+ }
670
799
  const status = this.registry.declare(index, section.spaceCode);
671
800
  if (status === "collision") {
672
801
  report.error("validation-error", ID_SPACE_COLLISION_CODE, `node ${idText} is declared in id space ${section.space ?? "(none)"} and in another id space; the core has one id space and this row is skipped`, { line, element: idText });
@@ -679,19 +808,63 @@ class Neo4jImportSession {
679
808
  element: idText,
680
809
  });
681
810
  }
811
+ // a write the sink refuses is recorded and the rest of the row is still written
812
+ const set = (column, value) => {
813
+ this.guarded(line, idText, () => {
814
+ sink.setNodeValue(column, index, value);
815
+ });
816
+ };
682
817
  if (section.idHandle !== INVALID_INDEX) {
683
- sink.setNodeValue(section.idHandle, index, idText);
818
+ set(section.idHandle, idText);
684
819
  }
685
820
  if (section.space !== null) {
686
- sink.setNodeValue(this.idSpaceHandle, index, section.space);
687
- sink.setNodeValue(this.originalIdHandle, index, idText);
821
+ set(this.idSpaceHandle, section.space);
822
+ set(this.originalIdHandle, idText);
688
823
  }
689
824
  if (labels !== undefined) {
690
- sink.setNodeValue(this.labelsHandle, index, labels);
825
+ set(this.labelsHandle, labels);
691
826
  }
692
- this.writeProperties("node", section.properties, index);
827
+ this.writeProperties("node", section.properties, index, line, idText);
693
828
  this.reportPrecision(line, idText);
694
- report.counts.nodes++;
829
+ // a node a relationship created before its row (or an earlier row) is counted once
830
+ if (!existed) {
831
+ report.counts.nodes++;
832
+ }
833
+ }
834
+ /**
835
+ * Run one sink write, recording a refusal (a GraphFormatError) on the row's line instead of
836
+ * letting it escape the import.
837
+ * @param line - the row's line
838
+ * @param element - the row's element name
839
+ * @param write - the write
840
+ */
841
+ guarded(line, element, write) {
842
+ try {
843
+ write();
844
+ }
845
+ catch (err) {
846
+ if (!(err instanceof GraphFormatError) || err instanceof ImportError) {
847
+ throw err;
848
+ }
849
+ this.report.recordError(err, { line, element });
850
+ }
851
+ }
852
+ /**
853
+ * Report the relationship endpoints no node row declared (the shared W_DANGLING_REFERENCE,
854
+ * once) when the input has node rows: each became a node, where neo4j-admin refuses the
855
+ * relationship.
856
+ */
857
+ reportDangling() {
858
+ const dangling = this.placeholders.filter((p) => this.registry.codeAt(p.index) === 0);
859
+ // without any node row, every node comes from the relationships (a relationships-only file)
860
+ if (dangling.length === 0 || !this.nodeRows) {
861
+ return;
862
+ }
863
+ const shown = dangling
864
+ .slice(0, 5)
865
+ .map((p) => String(p.id))
866
+ .join(", ");
867
+ this.report.warning("validation-error", DANGLING_REFERENCE_CODE, `${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)`, { element: String(dangling[0].id) });
695
868
  }
696
869
  /**
697
870
  * Push one relationship row.
@@ -709,7 +882,7 @@ class Neo4jImportSession {
709
882
  this.direction.setHeader(true, { line });
710
883
  }
711
884
  if (count !== section.width) {
712
- report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell(s) but the header has ${section.width}`, { line });
885
+ report.error("validation-error", COLUMN_COUNT_CODE, `row has ${count} cell${plural(count)} but the header has ${section.width}`, { line });
713
886
  report.counts.skippedEdges++;
714
887
  return;
715
888
  }
@@ -747,7 +920,7 @@ class Neo4jImportSession {
747
920
  let weight;
748
921
  if (section.weightCell >= 0) {
749
922
  try {
750
- weight = parseWeightText(cells[section.weightCell]);
923
+ weight = parseWeightText(cells[section.weightCell], this.report);
751
924
  }
752
925
  catch (err) {
753
926
  report.recordError(err, { line, element });
@@ -759,6 +932,7 @@ class Neo4jImportSession {
759
932
  report.counts.skippedEdges++;
760
933
  return;
761
934
  }
935
+ const created = [source, target].filter((id, k) => (k === 0 || id !== source) && sink.indexOf(id) === INVALID_INDEX);
762
936
  let edge;
763
937
  try {
764
938
  edge = this.direction.addEdge(source, target, "directed", weight, { line, element });
@@ -768,13 +942,23 @@ class Neo4jImportSession {
768
942
  report.counts.skippedEdges++;
769
943
  return;
770
944
  }
945
+ for (const id of created) {
946
+ // a node no row declared yet: counted now; reported at the end unless a node row follows
947
+ report.counts.nodes++;
948
+ this.placeholders.push({ id, index: sink.indexOf(id) });
949
+ }
771
950
  if (section.typeCell >= 0) {
772
951
  const type = cells[section.typeCell];
773
952
  if (type.length > 0) {
774
- sink.setEdgeValue(this.typeHandle, edge, type);
953
+ this.guarded(line, element, () => {
954
+ sink.setEdgeValue(this.typeHandle, edge, type);
955
+ });
956
+ }
957
+ else {
958
+ report.warning("missing-value", MISSING_TYPE_CODE, "empty :TYPE cell; neo4j-admin requires a relationship type, the relationship is kept without one", { line, element });
775
959
  }
776
960
  }
777
- this.writeProperties("edge", section.properties, edge);
961
+ this.writeProperties("edge", section.properties, edge, line, element);
778
962
  this.reportPrecision(line, element);
779
963
  report.counts.edges++;
780
964
  }
@@ -831,6 +1015,7 @@ class Neo4jImportSession {
831
1015
  parseProperties(slots, cells, quoted, line, element) {
832
1016
  const { values, texts, precisionSlots } = this;
833
1017
  precisionSlots.length = 0;
1018
+ this.overflows.length = 0;
834
1019
  for (const slot of slots) {
835
1020
  const text = cells[slot.cell];
836
1021
  texts[slot.cell] = null;
@@ -841,18 +1026,24 @@ class Neo4jImportSession {
841
1026
  const { spec } = slot;
842
1027
  try {
843
1028
  if (spec.temporal !== null && !spec.list) {
844
- const parsed = parseDeclaredTemporal(text, spec);
1029
+ const zoned = withZoneOffset(text, spec);
1030
+ const parsed = parseDeclaredTemporal(zoned, spec);
845
1031
  values[slot.cell] = parsed.value;
846
- texts[slot.cell] = parsed.text;
1032
+ // a zone name is kept in the companion text, the value is its instant
1033
+ texts[slot.cell] = zoned === text ? parsed.text : text;
847
1034
  }
848
1035
  else {
849
1036
  values[slot.cell] = parseDeclaredValue(text, spec, this.options.listSyntax);
1037
+ checkNeo4jRange(spec, values[slot.cell], text);
850
1038
  }
851
1039
  }
852
1040
  catch (err) {
853
1041
  this.report.recordError(err, { line, element: `${element} ${slot.name}` });
854
1042
  return false;
855
1043
  }
1044
+ if (overflows(spec, values[slot.cell], text)) {
1045
+ this.overflows.push(slot.name);
1046
+ }
856
1047
  if (spec.precision && losesPrecision(spec, text)) {
857
1048
  precisionSlots.push(slot);
858
1049
  }
@@ -864,8 +1055,10 @@ class Neo4jImportSession {
864
1055
  * @param domain - node or edge
865
1056
  * @param slots - the section's property slots
866
1057
  * @param row - the node or edge index
1058
+ * @param line - the row's line
1059
+ * @param element - the row's element name for issues
867
1060
  */
868
- writeProperties(domain, slots, row) {
1061
+ writeProperties(domain, slots, row, line, element) {
869
1062
  const { sink, values, texts } = this;
870
1063
  for (const slot of slots) {
871
1064
  const value = values[slot.cell];
@@ -873,21 +1066,24 @@ class Neo4jImportSession {
873
1066
  continue;
874
1067
  }
875
1068
  const text = texts[slot.cell];
876
- if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
877
- slot.companion = declareCompanion(sink, domain, slot.companionDecl);
878
- }
879
- if (domain === "node") {
880
- sink.setNodeValue(slot.handle, row, value);
881
- if (text !== null) {
882
- sink.setNodeValue(slot.companion, row, text);
1069
+ // a value the sink refuses is recorded on the row's line; the other properties are written
1070
+ this.guarded(line, `${element} ${slot.name}`, () => {
1071
+ if (text !== null && slot.companion === INVALID_INDEX && slot.companionDecl !== null) {
1072
+ slot.companion = declareCompanion(sink, domain, slot.companionDecl);
883
1073
  }
884
- }
885
- else {
886
- sink.setEdgeValue(slot.handle, row, value);
887
- if (text !== null) {
888
- sink.setEdgeValue(slot.companion, row, text);
1074
+ if (domain === "node") {
1075
+ sink.setNodeValue(slot.handle, row, value);
1076
+ if (text !== null) {
1077
+ sink.setNodeValue(slot.companion, row, text);
1078
+ }
889
1079
  }
890
- }
1080
+ else {
1081
+ sink.setEdgeValue(slot.handle, row, value);
1082
+ if (text !== null) {
1083
+ sink.setEdgeValue(slot.companion, row, text);
1084
+ }
1085
+ }
1086
+ });
891
1087
  }
892
1088
  }
893
1089
  /**
@@ -900,6 +1096,10 @@ class Neo4jImportSession {
900
1096
  this.report.warning("precision", PRECISION_CODE, `long value of "${slot.name}" is beyond 2^53 and was stored as the nearest f64`, { line, element });
901
1097
  }
902
1098
  this.precisionSlots.length = 0;
1099
+ for (const name of this.overflows) {
1100
+ this.report.warning("precision", PRECISION_CODE, `the value of "${name}" is beyond the range of its float / double type and was stored as the nearest representable value`, { line, element });
1101
+ }
1102
+ this.overflows.length = 0;
903
1103
  }
904
1104
  /**
905
1105
  * The labels of a node row: every `:LABEL` cell split by the array delimiter (empty items
@@ -944,6 +1144,147 @@ class Neo4jImportSession {
944
1144
  function qualify(id, space) {
945
1145
  return space === null ? id : `${space}:${String(id)}`;
946
1146
  }
1147
+ /** The integer range of the narrow neo4j-admin types (Java byte and short). */
1148
+ const INTEGER_RANGES = {
1149
+ byte: [-128, 127],
1150
+ short: [-32768, 32767],
1151
+ };
1152
+ /**
1153
+ * A Cypher duration (ISO 8601): unit form `P14DT16H12M` / `PT0.75M` / `P2.5W` (components may be
1154
+ * signed or fractional) or the date-time form `P2012-02-02T14:37:21.545`.
1155
+ */
1156
+ /**
1157
+ * Whether a text is a Cypher duration (ISO 8601): unit form `P14DT16H12M` / `PT0.75M` / `P2.5W`
1158
+ * (components may be signed or fractional) or the date-time form `P2012-02-02T14:37:21.545`.
1159
+ * @param text - the text, trimmed
1160
+ * @returns true when it is
1161
+ */
1162
+ function isDuration(text) {
1163
+ if (DURATION_DATE_TIME.test(text)) {
1164
+ return true;
1165
+ }
1166
+ const m = /^[+-]?P([^T]*)(?:T(.*))?$/i.exec(text);
1167
+ if (m === null || m[2] === "" || (m[1] === "" && m[2] === undefined)) {
1168
+ return false;
1169
+ }
1170
+ return unitsInOrder(m[1], "YMWD") && unitsInOrder(m[2] ?? "", "HMS");
1171
+ }
1172
+ /** The date-time form of a Cypher duration, `P2012-02-02T14:37:21.545`. */
1173
+ const DURATION_DATE_TIME = /^[+-]?P\d{4}-?\d{2}-?\d{2}T\d{2}:?\d{2}:?\d{2}(?:\.\d+)?$/i;
1174
+ /**
1175
+ * Whether a run of duration components (`14D`, `-1.5H30M`) names its units in the order given,
1176
+ * each at most once.
1177
+ * @param text - the components
1178
+ * @param units - the unit letters in their order
1179
+ * @returns true when it does
1180
+ */
1181
+ function unitsInOrder(text, units) {
1182
+ let rest = text.toUpperCase();
1183
+ let from = 0;
1184
+ while (rest !== "") {
1185
+ const m = /^[-+]?\d+(?:\.\d+)?([A-Z])/.exec(rest);
1186
+ const at = m === null ? -1 : units.indexOf(m[1], from);
1187
+ if (m === null || at < 0) {
1188
+ return false;
1189
+ }
1190
+ from = at + 1;
1191
+ rest = rest.slice(m[0].length);
1192
+ }
1193
+ return true;
1194
+ }
1195
+ /**
1196
+ * Check the neo4j-admin types the shared parser maps to a wider dtype: byte and short values within
1197
+ * their Java range, a char of one character, a duration in Cypher's syntax.
1198
+ * @param spec - the declared type
1199
+ * @param value - the parsed value (a list of items for an array type)
1200
+ * @param text - the cell text, for the error
1201
+ */
1202
+ function checkNeo4jRange(spec, value, text) {
1203
+ const base = spec.declared.trim().toLowerCase().replace(/\[\]$/, "");
1204
+ const items = spec.list && Array.isArray(value) ? value : [value];
1205
+ const range = INTEGER_RANGES[base];
1206
+ for (const item of items) {
1207
+ let bad = false;
1208
+ if (range !== undefined) {
1209
+ bad = typeof item === "number" && (item < range[0] || item > range[1]);
1210
+ }
1211
+ else if (base === "char") {
1212
+ // a Java char: one UTF-16 code unit
1213
+ bad = typeof item === "string" && item.length !== 1;
1214
+ }
1215
+ else if (base === "duration") {
1216
+ bad = typeof item === "string" && !isDuration(item.trim());
1217
+ }
1218
+ if (bad) {
1219
+ const span = range === undefined ? "" : ` (${range[0]} to ${range[1]})`;
1220
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" is not ${withArticle(base)}${span}`, {
1221
+ value: text,
1222
+ kind: base,
1223
+ });
1224
+ }
1225
+ }
1226
+ }
1227
+ /** The largest finite f32. */
1228
+ const F32_MAX = 3.4028234663852886e38;
1229
+ /**
1230
+ * Whether a float / double cell overflowed: a finite literal read as an infinity, or a float beyond
1231
+ * the f32 range (Java's Double.parseDouble accepts both silently; the value changes).
1232
+ * @param spec - the declared type
1233
+ * @param value - the parsed value
1234
+ * @param text - the cell text
1235
+ * @returns true when the stored value is not the one written
1236
+ */
1237
+ function overflows(spec, value, text) {
1238
+ if ((spec.kind !== "float" && spec.kind !== "double") || /inf|nan/i.test(text)) {
1239
+ return false;
1240
+ }
1241
+ const items = spec.list && Array.isArray(value) ? value : [value];
1242
+ return items.some((v) => typeof v === "number" && (!Number.isFinite(v) || (spec.kind === "float" && Math.abs(v) > F32_MAX)));
1243
+ }
1244
+ /**
1245
+ * A Cypher date-time with a zone name (`2020-01-01T00:00:00[Europe/Berlin]`) as one with a UTC
1246
+ * offset the temporal parser reads: the offset the text gives, else the zone's offset at that wall
1247
+ * time. Any other text is returned unchanged.
1248
+ * @param text - the cell text
1249
+ * @param spec - the declared type
1250
+ * @returns the text to parse
1251
+ */
1252
+ function withZoneOffset(text, spec) {
1253
+ const trimmed = text.trim();
1254
+ const open = trimmed.lastIndexOf("[");
1255
+ if (spec.temporal !== "dateTime" || open < 0 || !trimmed.endsWith("]")) {
1256
+ return text;
1257
+ }
1258
+ const local = trimmed.slice(0, open);
1259
+ const zone = trimmed.slice(open + 1, -1);
1260
+ if (zone === "" || zone.includes("]") || /[\n\r\u2028\u2029]/.test(local)) {
1261
+ return text;
1262
+ }
1263
+ let format;
1264
+ try {
1265
+ format = new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName: "longOffset" });
1266
+ }
1267
+ catch {
1268
+ throw new GraphFormatError("E_COLUMN_TYPE", `"${text}" names an unknown time zone ${zone}`, { value: text });
1269
+ }
1270
+ if (/(Z|z|[+-]\d{2}(:?\d{2})?)$/.test(local)) {
1271
+ return local;
1272
+ }
1273
+ const wall = parseTemporal(local, "localDateTime").value;
1274
+ const offsetAt = (ms) => {
1275
+ const name = format.formatToParts(new Date(ms)).find((p) => p.type === "timeZoneName")?.value ?? "GMT";
1276
+ const o = /GMT([+-])(\d{2}):(\d{2})/.exec(name);
1277
+ if (o === null) {
1278
+ return 0;
1279
+ }
1280
+ return (o[1] === "-" ? -1 : 1) * (Number(o[2]) * 60 + Number(o[3]));
1281
+ };
1282
+ // the offset at the instant the wall time names (twice, so a wall time near a transition settles)
1283
+ const minutes = offsetAt(wall - offsetAt(wall) * 60000);
1284
+ const sign = minutes < 0 ? "-" : "+";
1285
+ const abs = Math.abs(minutes);
1286
+ return `${local}${sign}${String(Math.floor(abs / 60)).padStart(2, "0")}:${String(abs % 60).padStart(2, "0")}`;
1287
+ }
947
1288
  /**
948
1289
  * The value of a quoted empty cell: an empty string for a string-kind property, an empty list for
949
1290
  * a list property, unset for anything else (neo4j-admin's default `--ignore-empty-strings=false`).
@@ -996,9 +1337,13 @@ function sniffNeo4j(head) {
996
1337
  const cells = first.split(/[,;|\t]/);
997
1338
  return isHeaderRecord(cells, cells.length) ? 0.95 : 0;
998
1339
  }
999
- /** The Neo4j importer. */
1340
+ /**
1341
+ * The Neo4j importer.
1342
+ * @category Built-in formats
1343
+ */
1000
1344
  export const neo4jImporter = Object.freeze({
1001
1345
  format: NEO4J,
1346
+ options: Object.freeze(["arrayDelimiter", "delimiter", "nodes", "quote", "relationships"]),
1002
1347
  extensions: Object.freeze([".csv", ".tsv"]),
1003
1348
  mimeTypes: Object.freeze(["text/csv", "text/tab-separated-values"]),
1004
1349
  sniff: sniffNeo4j,
@@ -1018,7 +1363,14 @@ export const neo4jImporter = Object.freeze({
1018
1363
  // column and every relationship is directed
1019
1364
  reportUnusedOptions(options, report, USED_OPTIONS);
1020
1365
  const session = new Neo4jImportSession(sink, report, common, format);
1021
- await session.run([input, ...format.nodes, ...format.relationships]);
1366
+ await session.run([
1367
+ { input, kind: null },
1368
+ ...format.nodes.map((file) => ({ input: file, kind: "node" })),
1369
+ ...format.relationships.map((file) => ({ input: file, kind: "relationship" })),
1370
+ ]);
1371
+ if (session.weightProperty !== null) {
1372
+ sink.setMeta({ extra: { neo4j: { weightProperty: session.weightProperty } } });
1373
+ }
1022
1374
  throwIfAborted(common.signal);
1023
1375
  return report.finish();
1024
1376
  },