@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/gexf.js CHANGED
@@ -1,9 +1,7 @@
1
- import { aI as TIME_TEXT_ROLE, aJ as TIME_TEXT_SUFFIX, v as resolveImportOptions, w as ImportReportBuilder, F as reportSinkOptions, z as reportUnusedOptions, x as textChunks, aw as XML_SYNTAX_CODE, y as throwIfAborted, K as IdCoercer, J as DirectionResolver, au as STRAY_TEXT_CODE, N as NO_GRAPH_CODE, ai as COUNT_HINT_CODE, i as DUPLICATE_ATTRIBUTE_CODE, aK as declareAttribute, L as declareResolved, f as MISSING_ID_CODE, d as DUPLICATE_NODE_CODE, U as UNKNOWN_PARENT_CODE, e as MISSING_ENDPOINT_CODE, c as DUPLICATE_EDGE_ID_CODE, aL as parseDeclaredTemporal, aA as declareCompanion, aM as parseDeclaredValue, aN as losesPrecision, P as PRECISION_CODE, aO as parseTimeText, aP as splitListText, Y as UNKNOWN_ELEMENT_CODE, I as ID_MERGED_CODE, aQ as timeTextCompanion, aH as parseDecimalText, X as pairFolding, V as resolveExportOptions, aR as formatTimeValue, aS as mapDeclaredType, aT as joinListText, aU as formatTemporal, aE as isCanonicalIntegerText, af as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, a as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, ah as BAD_OPTIONS_CODE, Z as BAD_DEFAULT_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 } from "./chunks/report-B1z4WT9e.js";
1
+ import { bG as TIME_TEXT_ROLE, bH as TIME_TEXT_SUFFIX, al as resolveImportOptions, a8 as ImportReportBuilder, ao as reportSinkOptions, an as reportUnusedOptions, a4 as textChunks, E as EMPTY_INPUT_CODE, X as XML_SYNTAX_CODE, am as throwIfAborted, ar as IdCoercer, aq as DirectionResolver, f as STRAY_TEXT_CODE, N as NO_GRAPH_CODE, h as UNKNOWN_XML_ATTRIBUTE_CODE, l as MULTIPLE_GRAPHS_CODE, j as COUNT_MISMATCH_CODE, k as COUNT_HINT_CODE, o as DUPLICATE_ATTRIBUTE_CODE, aK as isWeightField, bI as declareAttribute, a1 as declareResolved, t as MISSING_ID_CODE, n as DUPLICATE_NODE_CODE, q as UNKNOWN_PARENT_CODE, ai as PARENT_CYCLE_CODE, s as MISSING_ENDPOINT_CODE, m as DUPLICATE_EDGE_ID_CODE, aL as parseWeightText, bJ as overflowsToInfinity, P as PRECISION_CODE, bK as parseDeclaredTemporal, bs as declareCompanion, bL as parseDeclaredValue, bM as losesPrecision, bN as parseTimeText, a3 as BAD_VALUE_CODE, bO as splitListText, g as UNKNOWN_ELEMENT_CODE, I as ID_MERGED_CODE, bP as timeTextCompanion, bQ as parseDecimalText, c as capabilities, L as LOSS, aE as sanitizeIds, p as pairFolding, e as explicitWeights, r as resolveExportOptions, a as checkCapabilities, bR as formatTimeValue, aa as formatF32, ab as formatF64, bS as mapDeclaredType, bT as joinListText, bU as formatTemporal, aG as formatInteger, b as plural, $ as agree, by as isCanonicalIntegerText, M as MIXED_DIRECTION_CODE, D as DIRECTION_FORCED_CODE, d as DIRECTION_REFUSED_CODE, S as SINK_OPTION_CODE, O as OPTION_IGNORED_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, a_ as BAD_OPTIONS_CODE, B as BAD_DEFAULT_CODE, U as UNKNOWN_ATTR_TYPE_CODE, v as ENCODING_CONFLICT_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 } from "./chunks/export-BTI4yQgy.js";
2
2
  import { GraphFormatError, INVALID_INDEX, MAX_COUNT } from "@graphty/graph-format";
3
- import { i as isWeightField, p as parseWeightText, e as explicitWeights, f as formatF32, a as formatF64, d as formatInteger } from "./chunks/weights-Dzba96G3.js";
4
- import { t as tokenizeXml, f as xmlDeclaredEncoding, X as XmlSyntaxError, l as localName, g as isWhitespace, x as xmlIllegalTextNotes, a as escapeXmlText, e as escapeXmlAttribute } from "./chunks/escape-B-tkk_Cl.js";
5
- import { c as capabilities, L as LOSS, s as sanitizeIds, a as checkCapabilities } from "./chunks/export-Bh60Dv-n.js";
6
- import { j as joinText, e as encodeChunks } from "./chunks/writer-C7flM-Ih.js";
3
+ import { t as tokenizeXml, f as xmlDeclaredEncoding, g as XmlEmptyInputError, X as XmlSyntaxError, s as sniffXmlText, l as localName, j as isWhitespace, x as xmlIllegalTextNotes, a as escapeXmlText, e as escapeXmlAttribute } from "./chunks/escape-D0g6NNUy.js";
4
+ import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
7
5
  const GEXF_FORMAT = "gexf";
8
6
  const GEXF_NAMESPACES = {
9
7
  "1.2": { gexf: "http://www.gexf.net/1.2draft", viz: "http://www.gexf.net/1.2draft/viz" },
@@ -287,6 +285,54 @@ const VIZ_DYNAMIC_CODE = "W_GEXF_VIZ_DYNAMIC_DROPPED";
287
285
  const SPELL_OPEN_CODE = "W_GEXF_SPELL_OPEN_DROPPED";
288
286
  const VIZ_VALUE_CODE = "W_GEXF_VIZ_VALUE";
289
287
  const OPEN_BOUND_CONFLICT_CODE = "W_GEXF_OPEN_BOUND_CONFLICT";
288
+ const TIMESTAMP_CONFLICT_CODE = "W_GEXF_TIMESTAMP_CONFLICT";
289
+ const VALUE_OUTSIDE_OPTIONS_CODE = "W_GEXF_VALUE_OUTSIDE_OPTIONS";
290
+ const VERSIONS = /* @__PURE__ */ new Set(["1.0", "1.1", "1.2", "1.3"]);
291
+ function namespaceVersion(ns) {
292
+ const match = ns === null ? null : /gexf\.net\/(1\.[0-3])/.exec(ns);
293
+ return match === null ? null : match[1];
294
+ }
295
+ function isVizNamespace(ns) {
296
+ return ns !== null && /(gexf\.net\/.*viz|gephi\.org\/gexf\/viz)\/?$/.test(ns);
297
+ }
298
+ const MAX_UNKNOWN_ATTRIBUTE_NAMES = 16;
299
+ const ELEMENT_ATTRIBUTES = {
300
+ gexf: /* @__PURE__ */ new Set(["version", "variant"]),
301
+ meta: /* @__PURE__ */ new Set(["lastmodifieddate"]),
302
+ graph: /* @__PURE__ */ new Set([
303
+ "defaultedgetype",
304
+ "mode",
305
+ "type",
306
+ "timeformat",
307
+ "timerepresentation",
308
+ "idtype",
309
+ "start",
310
+ "end",
311
+ "timestamp",
312
+ "startopen",
313
+ "endopen"
314
+ ]),
315
+ // `type` is GEXF 1.0's name for `mode` (static | dynamic)
316
+ attributes: /* @__PURE__ */ new Set(["class", "mode", "type", "start", "end", "startopen", "endopen"]),
317
+ attribute: /* @__PURE__ */ new Set(["id", "title", "type"]),
318
+ attvalue: /* @__PURE__ */ new Set(["for", "value", "start", "end", "timestamp", "startopen", "endopen", "id"]),
319
+ spell: /* @__PURE__ */ new Set(["start", "end", "timestamp", "startopen", "endopen"]),
320
+ parent: /* @__PURE__ */ new Set(["for"]),
321
+ nodes: /* @__PURE__ */ new Set(["count"]),
322
+ edges: /* @__PURE__ */ new Set(["count"])
323
+ };
324
+ const COUNT_TEXT = /^\d+$/;
325
+ const DATE_TEXT = /^-?\d{4,}-\d{2}-\d{2}(.*)$/s;
326
+ const TIME_TEXT = /^T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?/;
327
+ const ZONE_TEXT = /^(?:Z|[+-]\d{2}:\d{2})?$/;
328
+ function isDateText(text) {
329
+ const m = DATE_TEXT.exec(text);
330
+ if (m === null) {
331
+ return false;
332
+ }
333
+ const time = TIME_TEXT.exec(m[1])?.[0] ?? "";
334
+ return ZONE_TEXT.test(m[1].slice(time.length));
335
+ }
290
336
  const EDGE_TYPES = /* @__PURE__ */ new Set(["directed", "undirected", "mutual"]);
291
337
  function edgeTypeKeyword(text) {
292
338
  return text.trim().toLowerCase();
@@ -448,8 +494,13 @@ class GexfReader {
448
494
  this.edgeFrame = {
449
495
  index: INVALID_INDEX,
450
496
  mirror: INVALID_INDEX,
451
- where: { line: 0, element: null }
497
+ where: { line: 0, element: null },
498
+ xmlWeight: null
452
499
  };
500
+ this.attvalueIds = /* @__PURE__ */ new Set();
501
+ this.sections = [];
502
+ this.unknownNames = /* @__PURE__ */ new Map();
503
+ this.unknownOverflow = /* @__PURE__ */ new Map();
453
504
  this.valueWhere = { line: 0, element: null };
454
505
  this.attributeGroup = null;
455
506
  this.pendingAttribute = null;
@@ -494,15 +545,20 @@ class GexfReader {
494
545
  };
495
546
  }
496
547
  // ---------------------------------------------------------------- events
497
- start(name, attrs, line) {
548
+ start(name, attrs, line, ns = "") {
498
549
  const parent = this.ctx.length === 0 ? null : this.ctx[this.ctx.length - 1];
499
550
  const local = localName(name);
551
+ if (ns === null && parent !== null && parent !== 14 && parent !== 2 && parent !== 6 && !name.startsWith("viz:")) {
552
+ this.unknownElement(name, line);
553
+ return;
554
+ }
500
555
  switch (parent) {
501
556
  case null:
502
557
  if (local !== "gexf") {
503
558
  this.report.fail(NOT_GEXF_CODE, `the root element is <${name}>, not <gexf>`, { line });
504
559
  }
505
- this.readRoot(attrs);
560
+ this.checkAttributes("gexf", attrs, line);
561
+ this.readRoot(attrs, ns, line);
506
562
  this.ctx.push(
507
563
  0
508
564
  /* Gexf */
@@ -527,7 +583,7 @@ class GexfReader {
527
583
  this.startInNodes(name, local, attrs, line);
528
584
  return;
529
585
  case 8:
530
- this.startInNode(name, local, attrs, line);
586
+ this.startInNode(name, local, attrs, line, ns);
531
587
  return;
532
588
  case 9:
533
589
  this.startInAttvalues(name, local, attrs, line);
@@ -542,7 +598,7 @@ class GexfReader {
542
598
  this.startInEdges(name, local, attrs, line);
543
599
  return;
544
600
  case 13:
545
- this.startInEdge(name, local, attrs, line);
601
+ this.startInEdge(name, local, attrs, line, ns);
546
602
  return;
547
603
  case 2:
548
604
  case 6:
@@ -585,6 +641,10 @@ class GexfReader {
585
641
  case 8:
586
642
  this.nodeStack.pop();
587
643
  return;
644
+ case 7:
645
+ case 12:
646
+ this.finishSection();
647
+ return;
588
648
  case 13:
589
649
  this.edge = null;
590
650
  return;
@@ -595,8 +655,6 @@ class GexfReader {
595
655
  this.finishSpells();
596
656
  return;
597
657
  case 0:
598
- case 7:
599
- case 12:
600
658
  case 9:
601
659
  case 14:
602
660
  case void 0:
@@ -642,16 +700,40 @@ class GexfReader {
642
700
  if (!this.graphSeen) {
643
701
  this.report.fail(NO_GRAPH_CODE, "the document has no <graph> element");
644
702
  }
703
+ for (const [kind, more] of this.unknownOverflow) {
704
+ this.report.warning(
705
+ "unsupported",
706
+ UNKNOWN_XML_ATTRIBUTE_CODE,
707
+ `${more} more distinct attribute names on <${kind}> are not GEXF attributes and are not kept (not listed one by one)`,
708
+ { element: kind }
709
+ );
710
+ }
645
711
  }
646
712
  // ---------------------------------------------------------------- root, meta, graph
647
713
  /**
648
- * Record the root's version.
714
+ * Record the root's version: as written when known; the namespace's when absent; an unknown
715
+ * one is kept as written and reported.
649
716
  * @param attrs - the `<gexf>` attributes
717
+ * @param ns - the root's namespace
718
+ * @param line - the line
650
719
  */
651
- readRoot(attrs) {
720
+ readRoot(attrs, ns, line) {
652
721
  const version = attrs.get("version");
653
722
  if (version !== void 0 && version.length > 0) {
654
723
  this.meta.sourceVersion = version;
724
+ if (!VERSIONS.has(version)) {
725
+ this.report.warning(
726
+ "validation-error",
727
+ HEADER_VALUE_CODE,
728
+ `<gexf version="${version}"> is not a GEXF version graph-io knows (1.0 to 1.3); read as GEXF 1.3`,
729
+ { line, element: "version" }
730
+ );
731
+ }
732
+ return;
733
+ }
734
+ const implied = namespaceVersion(ns);
735
+ if (implied !== null) {
736
+ this.meta.sourceVersion = implied;
655
737
  }
656
738
  }
657
739
  /**
@@ -664,9 +746,18 @@ class GexfReader {
664
746
  startInGexf(name, local, attrs, line) {
665
747
  switch (local) {
666
748
  case "meta": {
749
+ this.checkAttributes("meta", attrs, line);
667
750
  const modified = attrs.get("lastmodifieddate");
668
751
  if (modified !== void 0 && modified.length > 0) {
669
752
  this.meta.modified = modified;
753
+ if (!isDateText(modified.trim())) {
754
+ this.report.warning(
755
+ "validation-error",
756
+ HEADER_VALUE_CODE,
757
+ `<meta lastmodifieddate="${modified}"> is not an xs:date; kept as written`,
758
+ { line, element: "lastmodifieddate" }
759
+ );
760
+ }
670
761
  }
671
762
  this.ctx.push(
672
763
  1
@@ -675,13 +766,18 @@ class GexfReader {
675
766
  return;
676
767
  }
677
768
  case "graph":
769
+ this.checkAttributes("graph", attrs, line);
678
770
  if (this.graphSeen) {
679
- this.report.fail(NO_GRAPH_CODE, "a second <graph> element; a GEXF document has one graph", {
680
- line
681
- });
771
+ this.report.warnOnce(
772
+ "unsupported",
773
+ MULTIPLE_GRAPHS_CODE,
774
+ "a second <graph> element; its nodes and edges are merged into the first and its header is ignored",
775
+ { line }
776
+ );
777
+ } else {
778
+ this.graphSeen = true;
779
+ this.readHeader(attrs, line);
682
780
  }
683
- this.graphSeen = true;
684
- this.readHeader(attrs, line);
685
781
  this.ctx.push(
686
782
  3
687
783
  /* Graph */
@@ -726,8 +822,11 @@ class GexfReader {
726
822
  this.metaField = null;
727
823
  this.metaText = "";
728
824
  }
729
- /** Close `<meta>`: nothing more to do (the patch is applied at `<graph>`). */
825
+ /** Close `<meta>`: the patch is applied with the graph header, or now when `<meta>` follows the graph. */
730
826
  finishMeta() {
827
+ if (this.graphSeen) {
828
+ this.sink.setMeta(this.meta);
829
+ }
731
830
  }
732
831
  /**
733
832
  * Read `<graph defaultedgetype mode timeformat timerepresentation idtype start end timestamp>`
@@ -824,11 +923,7 @@ class GexfReader {
824
923
  return;
825
924
  case "nodes":
826
925
  this.nodesSeen = true;
827
- this.reserve(attrs, "node", line);
828
- this.ctx.push(
829
- 7
830
- /* Nodes */
831
- );
926
+ this.beginSection(attrs, "node", line);
832
927
  return;
833
928
  case "edges":
834
929
  if (!this.nodesSeen) {
@@ -840,39 +935,64 @@ class GexfReader {
840
935
  );
841
936
  }
842
937
  this.resolveParents();
843
- this.reserve(attrs, "edge", line);
844
- this.ctx.push(
845
- 12
846
- /* Edges */
847
- );
938
+ this.beginSection(attrs, "edge", line);
848
939
  return;
849
940
  default:
850
941
  this.unknownElement(name, line);
851
942
  }
852
943
  }
944
+ /**
945
+ * Open a `<nodes>` / `<edges>` section: its count hint is reserved and later compared with the
946
+ * elements the section holds.
947
+ * @param attrs - the section's attributes
948
+ * @param domain - node or edge
949
+ * @param line - the line
950
+ */
951
+ beginSection(attrs, domain, line) {
952
+ this.checkAttributes(`${domain}s`, attrs, line);
953
+ this.sections.push({ domain, hint: this.reserve(attrs, domain, line), seen: 0, line });
954
+ this.ctx.push(
955
+ domain === "node" ? 7 : 12
956
+ /* Edges */
957
+ );
958
+ }
959
+ /** Close a `<nodes>` / `<edges>` section: a count hint that disagrees is reported. */
960
+ finishSection() {
961
+ const section = this.sections.pop();
962
+ if (section?.hint === void 0 || section.hint === null || section.hint === section.seen) {
963
+ return;
964
+ }
965
+ this.report.warning(
966
+ "validation-error",
967
+ COUNT_MISMATCH_CODE,
968
+ `<${section.domain}s count="${section.hint}"> but the section holds ${section.seen} <${section.domain}> elements (nested ones included)`,
969
+ { line: section.line, element: "count" }
970
+ );
971
+ }
853
972
  /**
854
973
  * Pass a section's `count` hint to the sink; a hint the sink cannot reserve is a warning.
855
974
  * @param attrs - the `<nodes>` or `<edges>` attributes
856
975
  * @param domain - which count it is
857
976
  * @param line - the line
977
+ * @returns the hint, or null when absent or ignored
858
978
  */
859
979
  reserve(attrs, domain, line) {
860
980
  const text = attrs.get("count");
861
981
  if (text === void 0) {
862
- return;
982
+ return null;
863
983
  }
864
- const count = Number(text);
865
- if (!Number.isInteger(count) || count < 0 || count > MAX_COUNT) {
984
+ const count = COUNT_TEXT.test(text) ? Number(text) : Number.NaN;
985
+ if (!Number.isSafeInteger(count) || count > MAX_COUNT) {
866
986
  this.report.warning(
867
987
  "validation-error",
868
988
  COUNT_HINT_CODE,
869
989
  `<${domain}s count="${text}"> is not a count the sink can reserve; ignored`,
870
990
  { line, element: "count" }
871
991
  );
872
- return;
992
+ return null;
873
993
  }
874
994
  if (count === 0) {
875
- return;
995
+ return count;
876
996
  }
877
997
  try {
878
998
  if (domain === "node") {
@@ -889,6 +1009,7 @@ class GexfReader {
889
1009
  element: "count"
890
1010
  });
891
1011
  }
1012
+ return count;
892
1013
  }
893
1014
  // ---------------------------------------------------------------- attribute declarations
894
1015
  /**
@@ -897,6 +1018,7 @@ class GexfReader {
897
1018
  * @param line - the line
898
1019
  */
899
1020
  beginAttributes(attrs, line) {
1021
+ this.checkAttributes("attributes", attrs, line);
900
1022
  const cls = attrs.get("class");
901
1023
  const where = { line };
902
1024
  let domain = null;
@@ -910,7 +1032,7 @@ class GexfReader {
910
1032
  where
911
1033
  );
912
1034
  }
913
- const mode = attrs.get("mode");
1035
+ const mode = attrs.get("mode") ?? attrs.get("type");
914
1036
  if (mode !== void 0 && mode !== "static" && mode !== "dynamic") {
915
1037
  this.warnHeader("mode", mode, where);
916
1038
  }
@@ -932,6 +1054,7 @@ class GexfReader {
932
1054
  this.unknownElement(name, line);
933
1055
  return;
934
1056
  }
1057
+ this.checkAttributes("attribute", attrs, line);
935
1058
  const group = this.attributeGroup;
936
1059
  if (group === null || group.domain === null) {
937
1060
  this.ctx.push(
@@ -1022,6 +1145,14 @@ class GexfReader {
1022
1145
  );
1023
1146
  return;
1024
1147
  }
1148
+ if (this.unknownAttributes.has(`${domain}:${id}`)) {
1149
+ report.warning(
1150
+ "missing-value",
1151
+ UNKNOWN_ATTRIBUTE_CODE,
1152
+ `${domain} attribute "${id}" is declared after values that use it; those values were dropped (declare <attributes> before <nodes>)`,
1153
+ where
1154
+ );
1155
+ }
1025
1156
  const title = attrs.get("title") ?? null;
1026
1157
  const type = attrs.get("type") ?? null;
1027
1158
  if (type === null) {
@@ -1033,7 +1164,14 @@ class GexfReader {
1033
1164
  );
1034
1165
  }
1035
1166
  const name = title !== null && title.length > 0 ? title : id;
1036
- if (domain === "edge" && isWeightField(name, options.weightFrom)) {
1167
+ if (domain === "edge" && this.weightAttr !== null && isWeightField(name, options.weightFrom)) {
1168
+ report.warning(
1169
+ "validation-error",
1170
+ DUPLICATE_ATTRIBUTE_CODE,
1171
+ `edge attribute "${id}" is also titled ${name}; attribute "${this.weightAttr.id}" is the weight, "${id}" is kept as a column`,
1172
+ where
1173
+ );
1174
+ } else if (domain === "edge" && isWeightField(name, options.weightFrom)) {
1037
1175
  const declared2 = declareAttribute({ format: GEXF_FORMAT, id, title, type, long: options.long });
1038
1176
  for (const issue of declared2.issues) {
1039
1177
  report.warning(issue.category, issue.code, issue.message, where);
@@ -1044,7 +1182,8 @@ class GexfReader {
1044
1182
  }
1045
1183
  const declaredNames = domain === "node" ? this.declaredNodeNames : this.declaredEdgeNames;
1046
1184
  const reserved = domain === "node" ? RESERVED_NODE_NAMES : RESERVED_EDGE_NAMES;
1047
- const taken = (candidate) => reserved.has(candidate) || declaredNames.has(candidate);
1185
+ const weightName = domain === "edge" && this.weightAttr !== null ? options.weightFrom : null;
1186
+ const taken = (candidate) => reserved.has(candidate) || declaredNames.has(candidate) || candidate === weightName;
1048
1187
  const input = {
1049
1188
  format: GEXF_FORMAT,
1050
1189
  id,
@@ -1117,6 +1256,7 @@ class GexfReader {
1117
1256
  const enclosing = this.nodeStack.length === 0 ? INVALID_INDEX : this.nodeStack[this.nodeStack.length - 1].index;
1118
1257
  const idText = attrs.get("id");
1119
1258
  const where = { line, element: idText ?? attrs.get("label") ?? null };
1259
+ this.countInSection("node");
1120
1260
  this.checkAttributeNames(attrs, NODE_ATTRIBUTES, "node", where);
1121
1261
  if (idText === void 0) {
1122
1262
  report.error("missing-value", MISSING_ID_CODE, "<node> without an id", where);
@@ -1128,6 +1268,15 @@ class GexfReader {
1128
1268
  );
1129
1269
  return;
1130
1270
  }
1271
+ if (this.meta.idType === "integer" && !/^\s*[+-]?\d+\s*$/.test(idText)) {
1272
+ report.warnOnce(
1273
+ "validation-error",
1274
+ HEADER_VALUE_CODE,
1275
+ `node id "${idText}" is not an integer although the graph declares idtype="integer"; ids follow the ids option`,
1276
+ where,
1277
+ `${HEADER_VALUE_CODE}:idtype`
1278
+ );
1279
+ }
1131
1280
  let index;
1132
1281
  try {
1133
1282
  const id = this.coerceId(idText, where);
@@ -1164,6 +1313,10 @@ class GexfReader {
1164
1313
  if (label !== void 0) {
1165
1314
  this.nodeColumns.label.set(sink, report, index, label, where);
1166
1315
  }
1316
+ } catch (err) {
1317
+ report.recordError(err, where);
1318
+ }
1319
+ try {
1167
1320
  const pid = attrs.get("pid");
1168
1321
  if (pid !== void 0) {
1169
1322
  this.parentRefs.push({
@@ -1175,19 +1328,36 @@ class GexfReader {
1175
1328
  } else if (enclosing !== INVALID_INDEX) {
1176
1329
  this.parentRefs.push({ child: index, parentId: null, parentIndex: enclosing, where });
1177
1330
  }
1331
+ } catch (err) {
1332
+ report.recordError(err, where);
1333
+ }
1334
+ try {
1178
1335
  this.writeLifetime(attrs, index, this.nodeColumns, where);
1179
1336
  } catch (err) {
1180
1337
  report.recordError(err, where);
1181
1338
  }
1182
1339
  }
1340
+ /**
1341
+ * Count a `<node>` / `<edge>` element in the open sections of its kind, for the count hint
1342
+ * check: a `<nodes count>` counts the nodes nested in its nodes too.
1343
+ * @param domain - node or edge
1344
+ */
1345
+ countInSection(domain) {
1346
+ for (const section of this.sections) {
1347
+ if (section.domain === domain) {
1348
+ section.seen++;
1349
+ }
1350
+ }
1351
+ }
1183
1352
  /**
1184
1353
  * A child of `<node>`.
1185
1354
  * @param name - the element name
1186
1355
  * @param local - its local name
1187
1356
  * @param attrs - its attributes
1188
1357
  * @param line - the line
1358
+ * @param ns - the element's namespace
1189
1359
  */
1190
- startInNode(name, local, attrs, line) {
1360
+ startInNode(name, local, attrs, line, ns) {
1191
1361
  const frame = this.nodeStack[this.nodeStack.length - 1];
1192
1362
  if (frame.index === INVALID_INDEX && local !== "nodes") {
1193
1363
  this.ctx.push(
@@ -1196,8 +1366,17 @@ class GexfReader {
1196
1366
  );
1197
1367
  return;
1198
1368
  }
1369
+ if (frame.index === INVALID_INDEX) {
1370
+ this.report.error(
1371
+ "missing-value",
1372
+ UNKNOWN_PARENT_CODE,
1373
+ "the nodes nested in this skipped <node> lose their parent; they are read as top-level nodes",
1374
+ { line }
1375
+ );
1376
+ }
1199
1377
  switch (local) {
1200
1378
  case "attvalues":
1379
+ this.attvalueIds.clear();
1201
1380
  this.ctx.push(
1202
1381
  9
1203
1382
  /* Attvalues */
@@ -1220,16 +1399,16 @@ class GexfReader {
1220
1399
  );
1221
1400
  return;
1222
1401
  case "nodes":
1223
- this.reserve(attrs, "node", line);
1224
- this.ctx.push(
1225
- 7
1226
- /* Nodes */
1227
- );
1402
+ this.beginSection(attrs, "node", line);
1228
1403
  return;
1229
1404
  case "color":
1230
1405
  case "position":
1231
1406
  case "size":
1232
1407
  case "shape":
1408
+ if (!isViz(name, ns)) {
1409
+ this.unknownElement(name, line);
1410
+ return;
1411
+ }
1233
1412
  this.writeViz(name, local, attrs, "node", frame.index, frame.where);
1234
1413
  this.ctx.push(
1235
1414
  14
@@ -1256,10 +1435,16 @@ class GexfReader {
1256
1435
  14
1257
1436
  /* Skip */
1258
1437
  );
1438
+ this.checkAttributes("parent", attrs, line);
1259
1439
  const frame = this.nodeStack[this.nodeStack.length - 1];
1260
1440
  const text = attrs.get("for");
1261
1441
  if (text === void 0) {
1262
- this.report.warning("missing-value", ATTVALUE_SHAPE_CODE, "<parent> without a for attribute", frame.where);
1442
+ this.report.error(
1443
+ "missing-value",
1444
+ UNKNOWN_PARENT_CODE,
1445
+ "<parent> without a for attribute names no parent",
1446
+ frame.where
1447
+ );
1263
1448
  return;
1264
1449
  }
1265
1450
  try {
@@ -1286,6 +1471,15 @@ class GexfReader {
1286
1471
  const lists = this.parentsRefs;
1287
1472
  this.parentRefs = [];
1288
1473
  this.parentsRefs = [];
1474
+ const parentOf = /* @__PURE__ */ new Map();
1475
+ const isAncestorOrSelf = (candidate, of) => {
1476
+ for (let at = of; at !== void 0; at = parentOf.get(at)) {
1477
+ if (at === candidate) {
1478
+ return true;
1479
+ }
1480
+ }
1481
+ return false;
1482
+ };
1289
1483
  for (const ref of refs) {
1290
1484
  let parent = ref.parentIndex;
1291
1485
  if (ref.parentId !== null) {
@@ -1300,8 +1494,21 @@ class GexfReader {
1300
1494
  continue;
1301
1495
  }
1302
1496
  }
1497
+ if (parentOf.get(ref.child) === parent) {
1498
+ continue;
1499
+ }
1500
+ if (isAncestorOrSelf(ref.child, parent)) {
1501
+ report.error(
1502
+ "validation-error",
1503
+ PARENT_CYCLE_CODE,
1504
+ `the parent link of node "${ref.where.element ?? "?"}" would close a parent cycle; it is dropped`,
1505
+ ref.where
1506
+ );
1507
+ continue;
1508
+ }
1303
1509
  try {
1304
1510
  this.parentColumn.set(sink, report, ref.child, parent, ref.where);
1511
+ parentOf.set(ref.child, parent);
1305
1512
  } catch (err) {
1306
1513
  report.recordError(err, ref.where);
1307
1514
  }
@@ -1362,6 +1569,7 @@ class GexfReader {
1362
1569
  const { where } = this.edgeFrame;
1363
1570
  where.line = line;
1364
1571
  where.element = idText ?? edgeElement(sourceText, targetText);
1572
+ this.countInSection("edge");
1365
1573
  this.checkAttributeNames(attrs, EDGE_ATTRIBUTES, "edge", where);
1366
1574
  if (sourceText === void 0 || targetText === void 0) {
1367
1575
  report.error(
@@ -1389,18 +1597,15 @@ class GexfReader {
1389
1597
  }
1390
1598
  kind = type;
1391
1599
  }
1392
- if (idText !== void 0) {
1393
- if (this.edgeIds.has(idText)) {
1394
- report.error(
1395
- "validation-error",
1396
- DUPLICATE_EDGE_ID_CODE,
1397
- `edge id "${idText}" is declared more than once; the edge is skipped`,
1398
- where
1399
- );
1400
- report.counts.skippedEdges++;
1401
- return;
1402
- }
1403
- this.edgeIds.add(idText);
1600
+ if (idText !== void 0 && this.edgeIds.has(idText)) {
1601
+ report.error(
1602
+ "validation-error",
1603
+ DUPLICATE_EDGE_ID_CODE,
1604
+ `edge id "${idText}" is declared more than once; the edge is skipped`,
1605
+ where
1606
+ );
1607
+ report.counts.skippedEdges++;
1608
+ return;
1404
1609
  }
1405
1610
  let index;
1406
1611
  try {
@@ -1427,9 +1632,13 @@ class GexfReader {
1427
1632
  report.counts.skippedEdges++;
1428
1633
  return;
1429
1634
  }
1635
+ if (idText !== void 0) {
1636
+ this.edgeIds.add(idText);
1637
+ }
1430
1638
  const frame = this.edgeFrame;
1431
1639
  frame.index = index;
1432
1640
  frame.mirror = this.resolver.lastMirror;
1641
+ frame.xmlWeight = attrs.get("weight") ?? null;
1433
1642
  this.edge = frame;
1434
1643
  try {
1435
1644
  if (idText !== void 0) {
@@ -1469,7 +1678,26 @@ class GexfReader {
1469
1678
  );
1470
1679
  return void 0;
1471
1680
  }
1472
- return parseWeightText(text);
1681
+ const weight = parseWeightText(text, this.report);
1682
+ this.checkOverflow(text, where);
1683
+ return weight;
1684
+ }
1685
+ /**
1686
+ * Report (once) a weight text too large for a double, stored as Infinity; `INF` itself is a
1687
+ * legal weight (design section 3.7) and is not reported.
1688
+ * @param text - the weight text
1689
+ * @param where - the location
1690
+ */
1691
+ checkOverflow(text, where) {
1692
+ if (overflowsToInfinity(text)) {
1693
+ this.report.warnOnce(
1694
+ "precision",
1695
+ PRECISION_CODE,
1696
+ `weight ${text.trim()} is beyond the double range and is stored as Infinity`,
1697
+ where,
1698
+ `${PRECISION_CODE}:weight`
1699
+ );
1700
+ }
1473
1701
  }
1474
1702
  /**
1475
1703
  * A child of `<edge>`.
@@ -1477,8 +1705,9 @@ class GexfReader {
1477
1705
  * @param local - its local name
1478
1706
  * @param attrs - its attributes
1479
1707
  * @param line - the line
1708
+ * @param ns - the element's namespace
1480
1709
  */
1481
- startInEdge(name, local, attrs, line) {
1710
+ startInEdge(name, local, attrs, line, ns) {
1482
1711
  const { edge } = this;
1483
1712
  if (edge === null) {
1484
1713
  this.ctx.push(
@@ -1489,6 +1718,7 @@ class GexfReader {
1489
1718
  }
1490
1719
  switch (local) {
1491
1720
  case "attvalues":
1721
+ this.attvalueIds.clear();
1492
1722
  this.ctx.push(
1493
1723
  9
1494
1724
  /* Attvalues */
@@ -1506,6 +1736,10 @@ class GexfReader {
1506
1736
  case "color":
1507
1737
  case "thickness":
1508
1738
  case "shape":
1739
+ if (!isViz(name, ns)) {
1740
+ this.unknownElement(name, line);
1741
+ return;
1742
+ }
1509
1743
  this.writeViz(name, local, attrs, "edge", edge.index, edge.where);
1510
1744
  this.ctx.push(
1511
1745
  14
@@ -1534,6 +1768,7 @@ class GexfReader {
1534
1768
  14
1535
1769
  /* Skip */
1536
1770
  );
1771
+ this.checkAttributes("attvalue", attrs, line);
1537
1772
  const { report, edge } = this;
1538
1773
  const domain = edge === null ? "node" : "edge";
1539
1774
  let index;
@@ -1567,6 +1802,17 @@ class GexfReader {
1567
1802
  );
1568
1803
  return;
1569
1804
  }
1805
+ if (!isTimed(attrs)) {
1806
+ if (this.attvalueIds.has(forId)) {
1807
+ report.warning(
1808
+ "validation-error",
1809
+ DUPLICATE_ATTRIBUTE_CODE,
1810
+ `a second static <attvalue for="${forId}"> on one ${domain}; the later value "${value}" is kept`,
1811
+ { ...valueWhere, element: forId }
1812
+ );
1813
+ }
1814
+ this.attvalueIds.add(forId);
1815
+ }
1570
1816
  try {
1571
1817
  if (domain === "edge" && this.weightAttr !== null && this.weightAttr.id === forId) {
1572
1818
  if (isTimed(attrs)) {
@@ -1611,12 +1857,18 @@ class GexfReader {
1611
1857
  if (edge === null) {
1612
1858
  return;
1613
1859
  }
1614
- const weight = parseWeightText(text);
1860
+ const weight = parseWeightText(text, this.report);
1615
1861
  if (weight === void 0) {
1616
- throw new GraphFormatError("E_INVALID_WEIGHT", "an edge weight cannot be blank", {
1617
- value: text,
1618
- line: where.line ?? null
1619
- });
1862
+ return;
1863
+ }
1864
+ this.checkOverflow(text, where);
1865
+ if (edge.xmlWeight !== null) {
1866
+ this.report.warning(
1867
+ "validation-error",
1868
+ DUPLICATE_ATTRIBUTE_CODE,
1869
+ `the edge has both weight="${edge.xmlWeight}" and a weight attvalue "${text}"; the attvalue is kept`,
1870
+ where
1871
+ );
1620
1872
  }
1621
1873
  sink.setEdgeWeight(edge.index, weight);
1622
1874
  if (edge.mirror !== INVALID_INDEX) {
@@ -1653,9 +1905,42 @@ class GexfReader {
1653
1905
  `long value ${text.trim()} of "${attribute.name}" exceeds 2^53 and was rounded`,
1654
1906
  where
1655
1907
  );
1908
+ } else if (typeof value === "number" && overflowsToInfinity(text)) {
1909
+ this.report.warnOnce(
1910
+ "precision",
1911
+ PRECISION_CODE,
1912
+ `values of "${attribute.name}" beyond the double range (${text.trim()}) are stored as Infinity`,
1913
+ where,
1914
+ `${PRECISION_CODE}:overflow:${attribute.name}`
1915
+ );
1656
1916
  }
1917
+ this.checkOptions(attribute, value, where);
1657
1918
  this.setCell(domain, attribute.handle, index, value);
1658
1919
  }
1920
+ /**
1921
+ * Report (once per attribute) a value outside the `<options>` the attribute declares; the
1922
+ * value is kept.
1923
+ * @param attribute - the declaration
1924
+ * @param value - the parsed value (a list checks each item)
1925
+ * @param where - the value's location
1926
+ */
1927
+ checkOptions(attribute, value, where) {
1928
+ const { options } = attribute.valueDecl;
1929
+ if (options === void 0 || options.length === 0) {
1930
+ return;
1931
+ }
1932
+ const items = Array.isArray(value) ? value : [value];
1933
+ const outside = items.find((item) => !options.includes(item));
1934
+ if (typeof outside === "string" || typeof outside === "number" || typeof outside === "boolean") {
1935
+ this.report.warnOnce(
1936
+ "validation-error",
1937
+ VALUE_OUTSIDE_OPTIONS_CODE,
1938
+ `"${outside}" is not among the options of attribute "${attribute.name}"; the value is kept`,
1939
+ where,
1940
+ `${VALUE_OUTSIDE_OPTIONS_CODE}:${attribute.name}`
1941
+ );
1942
+ }
1943
+ }
1659
1944
  /**
1660
1945
  * Append a timed value to the attribute's temporal table (design section 5.10), creating the
1661
1946
  * table on first use.
@@ -1702,6 +1987,9 @@ class GexfReader {
1702
1987
  }
1703
1988
  }
1704
1989
  const row = this.temporalRow(attrs, index, value, where);
1990
+ if (row === null) {
1991
+ return;
1992
+ }
1705
1993
  if (temporalValue) {
1706
1994
  row.push(valueText ?? void 0);
1707
1995
  }
@@ -1733,14 +2021,14 @@ class GexfReader {
1733
2021
  )
1734
2022
  );
1735
2023
  }
1736
- const value = parseWeightText(text);
2024
+ const value = parseWeightText(text, this.report);
1737
2025
  if (value === void 0) {
1738
- throw new GraphFormatError("E_INVALID_WEIGHT", "a timed edge weight cannot be blank", {
1739
- value: text,
1740
- line: where.line ?? null
1741
- });
2026
+ return;
2027
+ }
2028
+ const row = this.temporalRow(attrs, index, value, where);
2029
+ if (row !== null) {
2030
+ sink.addExtensionRow(weightAttr.table, row);
1742
2031
  }
1743
- sink.addExtensionRow(weightAttr.table, this.temporalRow(attrs, index, value, where));
1744
2032
  }
1745
2033
  /**
1746
2034
  * The row of a temporal table for one timed value: element, bounds, value, bound texts, open bits.
@@ -1748,10 +2036,13 @@ class GexfReader {
1748
2036
  * @param index - the element's index
1749
2037
  * @param value - the parsed value
1750
2038
  * @param where - the value's location
1751
- * @returns the row, without the optional value text
2039
+ * @returns the row, without the optional value text; null when the interval is inverted (recorded)
1752
2040
  */
1753
2041
  temporalRow(attrs, index, value, where) {
1754
2042
  const bounds = this.readBounds(attrs, where);
2043
+ if (bounds === null) {
2044
+ return null;
2045
+ }
1755
2046
  return [
1756
2047
  index,
1757
2048
  bounds.start.value,
@@ -1768,7 +2059,7 @@ class GexfReader {
1768
2059
  * section 5.1); missing bounds are unbounded.
1769
2060
  * @param attrs - the attributes
1770
2061
  * @param where - the location, for the conflict warning
1771
- * @returns the bounds and the open bits
2062
+ * @returns the bounds and the open bits; null (recorded as E_BAD_VALUE) when the interval is inverted
1772
2063
  */
1773
2064
  readBounds(attrs, where) {
1774
2065
  let start = { value: -Infinity, text: null };
@@ -1778,6 +2069,14 @@ class GexfReader {
1778
2069
  if (timestamp !== void 0) {
1779
2070
  start = parseTimeText(timestamp, this.timeFormat);
1780
2071
  end = start;
2072
+ if (attrs.has("start") || attrs.has("end") || attrs.has("startopen") || attrs.has("endopen")) {
2073
+ this.report.warnOnce(
2074
+ "validation-error",
2075
+ TIMESTAMP_CONFLICT_CODE,
2076
+ "both timestamp and start / end are given; start / end set the interval and the timestamp is kept as written",
2077
+ where
2078
+ );
2079
+ }
1781
2080
  }
1782
2081
  const startText = attrs.get("start");
1783
2082
  const startOpen = attrs.get("startopen");
@@ -1801,6 +2100,15 @@ class GexfReader {
1801
2100
  end = parseTimeText(endOpen, this.timeFormat);
1802
2101
  open |= OPEN_END;
1803
2102
  }
2103
+ if (start.value > end.value) {
2104
+ this.report.error(
2105
+ "validation-error",
2106
+ BAD_VALUE_CODE,
2107
+ `the interval starts after it ends (${start.text ?? String(start.value)} > ${end.text ?? String(end.value)}); it is not kept`,
2108
+ where
2109
+ );
2110
+ return null;
2111
+ }
1804
2112
  return { start, end, open };
1805
2113
  }
1806
2114
  /**
@@ -1829,9 +2137,12 @@ class GexfReader {
1829
2137
  const { sink, report } = this;
1830
2138
  if (attrs.has("start") || attrs.has("end") || attrs.has("timestamp") || attrs.has("startopen") || attrs.has("endopen")) {
1831
2139
  const bounds = this.readBounds(attrs, where);
2140
+ if (bounds === null) {
2141
+ return;
2142
+ }
1832
2143
  const timestamp = attrs.get("timestamp");
1833
2144
  if (timestamp !== void 0) {
1834
- columns.timestamp.set(sink, report, index, bounds.start, where);
2145
+ columns.timestamp.set(sink, report, index, parseTimeText(timestamp, this.timeFormat), where);
1835
2146
  }
1836
2147
  if (attrs.has("start") || attrs.has("startopen")) {
1837
2148
  columns.start.set(sink, report, index, bounds.start, where);
@@ -1878,10 +2189,20 @@ class GexfReader {
1878
2189
  line: where.line ?? null
1879
2190
  });
1880
2191
  }
1881
- pairs.push([
2192
+ const pair = [
1882
2193
  parseTimeText(items[0], this.timeFormat).value,
1883
2194
  parseTimeText(items[1], this.timeFormat).value
1884
- ]);
2195
+ ];
2196
+ if (pair[0] > pair[1]) {
2197
+ this.report.error(
2198
+ "validation-error",
2199
+ BAD_VALUE_CODE,
2200
+ `interval "${part.trim()}" starts after it ends; it is not kept`,
2201
+ where
2202
+ );
2203
+ continue;
2204
+ }
2205
+ pairs.push(pair);
1885
2206
  }
1886
2207
  return pairs;
1887
2208
  }
@@ -1901,9 +2222,13 @@ class GexfReader {
1901
2222
  14
1902
2223
  /* Skip */
1903
2224
  );
2225
+ this.checkAttributes("spell", attrs, line);
1904
2226
  const where = this.spellsWhere ?? { line };
1905
2227
  try {
1906
2228
  const bounds = this.readBounds(attrs, where);
2229
+ if (bounds === null) {
2230
+ return;
2231
+ }
1907
2232
  this.spellPairs?.push([bounds.start.value, bounds.end.value]);
1908
2233
  this.spellOpen.push(bounds.open);
1909
2234
  } catch (err) {
@@ -2024,28 +2349,52 @@ class GexfReader {
2024
2349
  );
2025
2350
  }
2026
2351
  /**
2027
- * Report XML attributes the importer does not read (once per attribute name and domain).
2352
+ * Report XML attributes the importer does not read (once per attribute name and element kind;
2353
+ * beyond MAX_UNKNOWN_ATTRIBUTE_NAMES distinct names per kind the rest are counted and reported
2354
+ * once at the end). Namespace declarations and `xml:` / `xsi:` attributes are not data.
2028
2355
  * @param attrs - the element's attributes
2029
2356
  * @param known - the attribute names read
2030
- * @param domain - node or edge
2357
+ * @param kind - the element name
2031
2358
  * @param where - the element's location
2032
2359
  */
2033
- checkAttributeNames(attrs, known, domain, where) {
2360
+ checkAttributeNames(attrs, known, kind, where) {
2361
+ if (attrs.size === 0) {
2362
+ return;
2363
+ }
2034
2364
  for (const key of attrs.keys()) {
2035
- if (!known.has(key)) {
2036
- const seen = `${domain}@${key}`;
2037
- if (!this.unknownAttributes.has(seen)) {
2038
- this.unknownAttributes.add(seen);
2039
- this.report.warning(
2040
- "unsupported",
2041
- UNKNOWN_ELEMENT_CODE,
2042
- `attribute ${key} of <${domain}> is not GEXF and was ignored`,
2043
- { ...where, element: key }
2044
- );
2045
- }
2365
+ if (known.has(key) || key === "xmlns" || /^(xmlns|xml|xsi):/.test(key)) {
2366
+ continue;
2367
+ }
2368
+ let names = this.unknownNames.get(kind);
2369
+ if (names === void 0) {
2370
+ names = /* @__PURE__ */ new Set();
2371
+ this.unknownNames.set(kind, names);
2046
2372
  }
2373
+ if (names.has(key)) {
2374
+ continue;
2375
+ }
2376
+ names.add(key);
2377
+ if (names.size > MAX_UNKNOWN_ATTRIBUTE_NAMES) {
2378
+ this.unknownOverflow.set(kind, (this.unknownOverflow.get(kind) ?? 0) + 1);
2379
+ continue;
2380
+ }
2381
+ this.report.warning(
2382
+ "unsupported",
2383
+ UNKNOWN_XML_ATTRIBUTE_CODE,
2384
+ `attribute ${key} of <${kind}> is not GEXF and was ignored`,
2385
+ { ...where, element: key }
2386
+ );
2047
2387
  }
2048
2388
  }
2389
+ /**
2390
+ * Report the XML attributes the importer does not read on an element other than node / edge.
2391
+ * @param kind - the element's local name (a key of ELEMENT_ATTRIBUTES)
2392
+ * @param attrs - its attributes
2393
+ * @param line - the line
2394
+ */
2395
+ checkAttributes(kind, attrs, line) {
2396
+ this.checkAttributeNames(attrs, ELEMENT_ATTRIBUTES[kind] ?? /* @__PURE__ */ new Set(), kind, { line });
2397
+ }
2049
2398
  /**
2050
2399
  * Write one cell of a domain.
2051
2400
  * @param domain - node or edge
@@ -2087,6 +2436,9 @@ class GexfReader {
2087
2436
  }
2088
2437
  }
2089
2438
  }
2439
+ function isViz(name, ns) {
2440
+ return isVizNamespace(ns) || ns === null && name.startsWith("viz:");
2441
+ }
2090
2442
  function edgeElement(source, target) {
2091
2443
  return `${source ?? "?"}->${target ?? "?"}`;
2092
2444
  }
@@ -2122,7 +2474,7 @@ function parseColor(attrs) {
2122
2474
  if (hex !== void 0 && !attrs.has("r")) {
2123
2475
  const digits = hex.startsWith("#") ? hex.slice(1) : hex;
2124
2476
  if (!/^[0-9a-fA-F]{6}$/.test(digits)) {
2125
- throw new GraphFormatError("E_COLUMN_TYPE", `viz hex="${hex}" is not a #RRGGBB colour`, {
2477
+ throw new GraphFormatError("E_COLUMN_TYPE", `viz hex="${hex}" is not a #RRGGBB color`, {
2126
2478
  attribute: "hex"
2127
2479
  });
2128
2480
  }
@@ -2139,7 +2491,7 @@ function parseColor(attrs) {
2139
2491
  }
2140
2492
  const XML_START = /^\uFEFF?\s*</;
2141
2493
  function sniffGexf(head) {
2142
- const text = new TextDecoder("utf-8", { fatal: false }).decode(head);
2494
+ const text = sniffXmlText(head);
2143
2495
  if (!XML_START.test(text)) {
2144
2496
  return 0;
2145
2497
  }
@@ -2163,6 +2515,7 @@ function resolveGexfOptions(options) {
2163
2515
  }
2164
2516
  const gexfImporter = Object.freeze({
2165
2517
  format: GEXF_FORMAT,
2518
+ options: Object.freeze(["viz"]),
2166
2519
  extensions: Object.freeze([".gexf"]),
2167
2520
  mimeTypes: Object.freeze(["application/gexf+xml", "application/xml", "text/xml"]),
2168
2521
  sniff: sniffGexf,
@@ -2187,10 +2540,13 @@ const gexfImporter = Object.freeze({
2187
2540
  const reader = new GexfReader(sink, report, resolved, viz);
2188
2541
  try {
2189
2542
  await tokenizeXml(
2190
- textChunks(input, report, { ...resolved, declaredEncoding: xmlDeclaredEncoding }),
2543
+ textChunks(input, report, { ...resolved, declaredEncoding: xmlDeclaredEncoding, xml: true }),
2191
2544
  reader
2192
2545
  );
2193
2546
  } catch (err) {
2547
+ if (err instanceof XmlEmptyInputError) {
2548
+ report.fail(EMPTY_INPUT_CODE, "the input is empty (no markup at all)", { line: err.line });
2549
+ }
2194
2550
  if (err instanceof XmlSyntaxError) {
2195
2551
  report.fail(XML_SYNTAX_CODE, err.message, { line: err.line });
2196
2552
  }
@@ -2210,25 +2566,41 @@ const GEXF_LOSS = Object.freeze({
2210
2566
  LIST_SEPARATOR: "W_LIST_SEPARATOR",
2211
2567
  /** A role column of a shape GEXF cannot map (a string `start`, a 2-component color); written as a plain attribute. */
2212
2568
  ROLE_SHAPE: "W_ROLE_SHAPE",
2213
- /** A temporal extension table without the element / start / end / value columns of design section 5.10. */
2569
+ /** A temporal extension table without the element / start / end / value columns. */
2214
2570
  TEMPORAL_TABLE_SHAPE: "W_TEMPORAL_TABLE_SHAPE",
2215
- /** An attribute whose title the importer would rename on re-import (a reserved name). */
2571
+ /** An attribute's name is one GEXF reserves, so a GEXF import would give it another name. */
2216
2572
  ATTRIBUTE_RENAMED: "W_ATTRIBUTE_RENAMED",
2217
2573
  /** A cell, default or option the declared type cannot express (skipped). */
2218
2574
  VALUE_UNWRITABLE: "W_VALUE_UNWRITABLE",
2219
- /** A declared type the target version lacks (1.2: date, dateTime, typed lists...); the canonical type is written. */
2575
+ /**
2576
+ * An attribute type that this GEXF version does not have (GEXF 1.2 has no date, dateTime or typed lists) is
2577
+ * written as the nearest type it has.
2578
+ */
2220
2579
  DECLARED_TYPE: "W_DECLARED_TYPE",
2221
- /** A node id whose text reads back as the other type under the canonical rule (design section 4.1): a non-integer number, a string of integer text. */
2580
+ /**
2581
+ * A node id that reads back as a different type: a number that is not an integer comes back as text, and text that
2582
+ * looks like an integer ("42") comes back as a number, unless you read the file with `ids: "string"` or `ids:
2583
+ * "keep"`.
2584
+ */
2222
2585
  ID_TEXT_TYPE: LOSS.ID_TEXT_TYPE,
2223
2586
  /** A numeric edge id column: GEXF edge ids read back as strings. */
2224
2587
  EDGE_ID_TEXT: "W_GEXF_EDGE_ID_TEXT",
2225
- /** A viz role column (position, color, size, thickness) that is not f32; the importer reads viz values as f32. */
2588
+ /**
2589
+ * A visual attribute (position, color, size, thickness) is stored at more precision than GEXF keeps; it reads back
2590
+ * as a 32-bit float.
2591
+ */
2226
2592
  VIZ_DTYPE: "W_GEXF_VIZ_DTYPE",
2227
- /** A plain `weight` edge column reads back as THE weight (the importer's weightFrom default). */
2593
+ /**
2594
+ * An attribute named `weight` without the weight role reads back as the edge weight, because GEXF reads weights
2595
+ * from `weight` by default.
2596
+ */
2228
2597
  WEIGHT_KEY_CLASH: LOSS.WEIGHT_KEY_CLASH,
2229
- /** A dict column without declared options gains one from its dictionary on re-import. */
2598
+ /**
2599
+ * A text attribute stored as a dictionary, without a declared list of allowed values, reads back with its distinct
2600
+ * values as that list.
2601
+ */
2230
2602
  OPTIONS_GAINED: LOSS.OPTIONS_GAINED,
2231
- /** A string cell holding a character XML 1.0 forbids; export() throws E_COLUMN_TYPE. */
2603
+ /** A text value holds a character XML 1.0 forbids (most control characters); the save fails with E_COLUMN_TYPE. */
2232
2604
  XML_ILLEGAL_CHAR: LOSS.XML_ILLEGAL_CHAR
2233
2605
  });
2234
2606
  const DTYPES_KEPT = ["f32", "f64", "i32", "bool", "dict", "string"];
@@ -2284,7 +2656,8 @@ function planExport(snapshot, options) {
2284
2656
  temporalText: true,
2285
2657
  positionDtype: "f32",
2286
2658
  roles: MAPPED_ROLES,
2287
- roleNames: ROLE_NAMES
2659
+ // GEXF 1.2 has no edge kind: the kind column is dropped (W_GEXF_KIND_DROPPED), not renamed
2660
+ roleNames: version === "1.2" ? ROLE_NAMES_1_2 : ROLE_NAMES
2288
2661
  })
2289
2662
  ];
2290
2663
  const note = (code, message, column = null, count = null) => {
@@ -2301,7 +2674,7 @@ function planExport(snapshot, options) {
2301
2674
  if (typeChanges > 0) {
2302
2675
  note(
2303
2676
  GEXF_LOSS.ID_TEXT_TYPE,
2304
- `${typeChanges} node id(s) change type when read back under ids: "canonical" (string ids that are integer text, non-integer numbers); the file's idtype is not honoured by the importer`,
2677
+ `${typeChanges} node id${plural(typeChanges)} ${agree(typeChanges, "changes", "change")} type when read back under ids: "canonical" (string ids that are integer text, non-integer numbers); the file's idtype is not honored by the importer`,
2305
2678
  null,
2306
2679
  typeChanges
2307
2680
  );
@@ -2461,6 +2834,9 @@ const ROLE_NAMES = Object.freeze({
2461
2834
  parent: NODE_COLUMNS.parent,
2462
2835
  parents: NODE_COLUMNS.parents
2463
2836
  });
2837
+ const ROLE_NAMES_1_2 = Object.freeze(
2838
+ Object.fromEntries(Object.entries(ROLE_NAMES).filter(([role]) => role !== "kind"))
2839
+ );
2464
2840
  function collectRoles(table, domain, note) {
2465
2841
  const companions = /* @__PURE__ */ new Map();
2466
2842
  const roles = {
@@ -2792,7 +3168,7 @@ function collectAttributes(snapshot, domain, roles, tables, version, note) {
2792
3168
  if (domain === "edge" && column !== null && column.meta.role === null && title === DEFAULT_WEIGHT_TITLE) {
2793
3169
  note(
2794
3170
  GEXF_LOSS.WEIGHT_KEY_CLASH,
2795
- `edge column "${name}" is written as an attribute titled "${title}", which the importer reads as THE weight (weightFrom); it reads back as the weight, not as a column`,
3171
+ `edge column "${name}" is written as an attribute titled "${title}", which the importer reads as the edge weight (weightFrom); it reads back as the weight, not as a column`,
2796
3172
  name,
2797
3173
  column.length - column.nullCount
2798
3174
  );
@@ -2929,7 +3305,7 @@ function declaredTexts(column, domain, typed, version, note) {
2929
3305
  if (count > 0) {
2930
3306
  note(
2931
3307
  GEXF_LOSS.LIST_SEPARATOR,
2932
- `${domain} column "${name}": ${count} row(s) hold an item containing "|", the 1.2 list separator`,
3308
+ `${domain} column "${name}": ${count} row${plural(count)} ${agree(count, "holds", "hold")} an item containing "|", the 1.2 list separator`,
2933
3309
  name,
2934
3310
  count
2935
3311
  );
@@ -3426,6 +3802,7 @@ function graphExtraText(snapshot, key) {
3426
3802
  }
3427
3803
  const gexfExporter = Object.freeze({
3428
3804
  format: GEXF_FORMAT,
3805
+ options: Object.freeze(["version"]),
3429
3806
  capabilities: CAPABILITIES_1_3,
3430
3807
  /**
3431
3808
  * Pre-flight: what export() would lose.
@@ -3457,38 +3834,71 @@ const gexfExporter = Object.freeze({
3457
3834
  });
3458
3835
  const GEXF_1_2_CAPABILITIES = CAPABILITIES_1_2;
3459
3836
  const GEXF_ISSUE = Object.freeze({
3460
- /** The XML is not well-formed (fatal). */
3837
+ ...INPUT_ISSUE,
3838
+ ...ELEMENT_ISSUE,
3839
+ /**
3840
+ * A value that does not parse as the type its attribute declares ("x" in an integer attribute). The value is
3841
+ * left unset; the node or edge is kept.
3842
+ */
3843
+ COLUMN_TYPE: COLUMN_TYPE_CODE,
3844
+ /** The XML is not well-formed. The import stops. */
3461
3845
  XML_SYNTAX: XML_SYNTAX_CODE,
3462
- /** The input holds invalid UTF-8 (fatal). */
3846
+ /** The input is not valid UTF-8. The import stops. */
3463
3847
  INVALID_UTF8: INVALID_UTF8_CODE,
3464
- /** Invalid bytes in the encoding a BOM, a declaration or the encoding option chose (fatal). */
3848
+ /**
3849
+ * Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
3850
+ * `encoding` option). The import stops.
3851
+ */
3465
3852
  INVALID_ENCODING: INVALID_ENCODING_CODE,
3466
3853
  /** Bytes that are not UTF-8 and declare no encoding were read as windows-1252. */
3467
3854
  ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
3468
3855
  /** A declared encoding the platform cannot decode was ignored. */
3469
3856
  UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
3470
- /** The root element is not `<gexf>` (fatal). */
3857
+ /** A declared encoding the byte order mark contradicts (the mark wins). */
3858
+ ENCODING_CONFLICT: ENCODING_CONFLICT_CODE,
3859
+ /** The input holds no XML at all: it is empty, whitespace or a byte order mark only. The import stops. */
3860
+ EMPTY_INPUT: EMPTY_INPUT_CODE,
3861
+ /** The root element is not `<gexf>`. The import stops. */
3471
3862
  NOT_GEXF: NOT_GEXF_CODE,
3472
- /** The document has no `<graph>` (fatal). */
3863
+ /** The document has no `<graph>`. The import stops. */
3473
3864
  NO_GRAPH: NO_GRAPH_CODE,
3865
+ /**
3866
+ * The file holds more than one `<graph>` element; their nodes and edges are merged into one graph.
3867
+ * `importAllGraphs()` reads every one.
3868
+ */
3869
+ MULTIPLE_GRAPHS: MULTIPLE_GRAPHS_CODE,
3474
3870
  /** `<edges>` without `<nodes>`. */
3475
3871
  MISSING_NODES: MISSING_NODES_CODE,
3476
3872
  /** A node without an id. */
3477
3873
  MISSING_ID: MISSING_ID_CODE,
3478
3874
  /** An edge without a source or target. */
3479
3875
  MISSING_ENDPOINT: MISSING_ENDPOINT_CODE,
3876
+ /** An edge endpoint that names no declared node (addMissingNodes false, the GEXF default). */
3877
+ UNKNOWN_NODE: "E_UNKNOWN_NODE",
3480
3878
  /** An edge `type` outside directed / undirected / mutual. */
3481
3879
  EDGE_TYPE: EDGE_TYPE_CODE,
3482
- /** A `pid` / `<parent for>` naming an unknown node. */
3880
+ /** A `pid` / `<parent for>` naming an unknown node, a `<parent>` without for, or the children of a skipped node. */
3483
3881
  UNKNOWN_PARENT: UNKNOWN_PARENT_CODE,
3882
+ /** A `pid` / nested containment that would close a parent cycle; that link is dropped. */
3883
+ PARENT_CYCLE: PARENT_CYCLE_CODE,
3884
+ /** An inverted interval (start after end) of an element, a spell or a value; it is not kept. */
3885
+ BAD_VALUE: BAD_VALUE_CODE,
3484
3886
  /** An `<attributes class>` outside node / edge. */
3485
3887
  ATTRIBUTES_CLASS: ATTRIBUTES_CLASS_CODE,
3486
3888
  /** An `<attribute>` without an id. */
3487
3889
  ATTRIBUTE_ID: ATTRIBUTE_ID_CODE,
3488
3890
  /** A `<graph>` header attribute with an unknown value. */
3489
3891
  HEADER_VALUE: HEADER_VALUE_CODE,
3490
- /** A `count` hint the sink cannot reserve (ignored). */
3892
+ /**
3893
+ * A node or edge count the file announces is too large to reserve room for; it is ignored and the elements are
3894
+ * read as they come.
3895
+ */
3491
3896
  COUNT_HINT: COUNT_HINT_CODE,
3897
+ /**
3898
+ * A `count` attribute disagrees with the number of nodes or edges actually in its section. The elements are read
3899
+ * as they are.
3900
+ */
3901
+ COUNT_MISMATCH: COUNT_MISMATCH_CODE,
3492
3902
  /** A node id declared twice. */
3493
3903
  DUPLICATE_NODE: DUPLICATE_NODE_CODE,
3494
3904
  /** An edge id declared twice (the second edge is skipped). */
@@ -3503,9 +3913,15 @@ const GEXF_ISSUE = Object.freeze({
3503
3913
  BAD_DEFAULT: BAD_DEFAULT_CODE,
3504
3914
  /** Options that do not parse as the declared type. */
3505
3915
  BAD_OPTIONS: BAD_OPTIONS_CODE,
3506
- /** A column renamed `<name>#<id>` because the name was taken (design section 5.6). */
3916
+ /**
3917
+ * An attribute was renamed `<name>#<suffix>` because another attribute already has its name, for example
3918
+ * two attributes declared with the same name.
3919
+ */
3507
3920
  COLUMN_RENAMED: COLUMN_RENAMED_CODE,
3508
- /** A column declared without its role because the table already holds it. */
3921
+ /**
3922
+ * You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
3923
+ * a plain attribute.
3924
+ */
3509
3925
  ROLE_TAKEN: ROLE_TAKEN_CODE,
3510
3926
  /** An `<attvalue for>` naming an undeclared attribute. */
3511
3927
  UNKNOWN_ATTRIBUTE: UNKNOWN_ATTRIBUTE_CODE,
@@ -3513,13 +3929,13 @@ const GEXF_ISSUE = Object.freeze({
3513
3929
  ATTVALUE_SHAPE: ATTVALUE_SHAPE_CODE,
3514
3930
  /** A timed value on an attribute of a static group. */
3515
3931
  TIMED_VALUE_ON_STATIC: TIMED_STATIC_CODE,
3516
- /** A long value beyond 2^53 rounded. */
3932
+ /** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
3517
3933
  PRECISION: PRECISION_CODE,
3518
- /** Two id texts merged into one number under ids "number". */
3934
+ /** Two different id texts became the same number because `ids` is "number", so their nodes were merged. */
3519
3935
  ID_MERGED: ID_MERGED_CODE,
3520
3936
  /** The XML weight attribute ignored under weightFrom null. */
3521
3937
  WEIGHT_IGNORED: WEIGHT_IGNORED_CODE,
3522
- /** viz elements skipped under viz: false. */
3938
+ /** Viz elements skipped under viz: false. */
3523
3939
  VIZ_SKIPPED: VIZ_SKIPPED_CODE,
3524
3940
  /** A 1.2 dynamic viz element whose bounds were dropped. */
3525
3941
  VIZ_DYNAMIC_DROPPED: VIZ_DYNAMIC_CODE,
@@ -3529,19 +3945,35 @@ const GEXF_ISSUE = Object.freeze({
3529
3945
  VIZ_VALUE: VIZ_VALUE_CODE,
3530
3946
  /** Both `start` and `startopen` (or `end` and `endopen`) on one element. */
3531
3947
  OPEN_BOUND_CONFLICT: OPEN_BOUND_CONFLICT_CODE,
3532
- /** An element or attribute GEXF does not define was skipped. */
3948
+ /** Both `timestamp` and `start` / `end` on one element or value. */
3949
+ TIMESTAMP_CONFLICT: TIMESTAMP_CONFLICT_CODE,
3950
+ /** A value outside the declared `<options>` (kept). */
3951
+ VALUE_OUTSIDE_OPTIONS: VALUE_OUTSIDE_OPTIONS_CODE,
3952
+ /** An element GEXF does not define at that place was skipped. */
3533
3953
  UNKNOWN_ELEMENT: UNKNOWN_ELEMENT_CODE,
3954
+ /** An XML attribute GEXF does not define on that element was ignored. */
3955
+ UNKNOWN_XML_ATTRIBUTE: UNKNOWN_XML_ATTRIBUTE_CODE,
3534
3956
  /** Text where GEXF allows only elements was ignored. */
3535
3957
  STRAY_TEXT: STRAY_TEXT_CODE,
3536
- /** A common option the importer has no use for was given. */
3958
+ /** You set an option this format does not use; it had no effect. The message names the option. */
3537
3959
  OPTION_IGNORED: OPTION_IGNORED_CODE,
3538
- /** A builder-policy option the sink does not honour. */
3960
+ /**
3961
+ * You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
3962
+ * `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
3963
+ */
3539
3964
  SINK_OPTION: SINK_OPTION_CODE,
3540
- /** The sink refused the file's direction. */
3965
+ /**
3966
+ * You read into a graph builder whose direction is already set, or which already holds edges, so the file is read
3967
+ * with the builder's direction instead of its own.
3968
+ */
3541
3969
  DIRECTION_REFUSED: DIRECTION_REFUSED_CODE,
3542
- /** Edges forced to the policy's direction. */
3970
+ /** Edges of the other direction were read with the direction `onMixedDirection` chose. */
3543
3971
  DIRECTION_FORCED: DIRECTION_FORCED_CODE,
3544
- /** A mixed file under onMixedDirection "error" (fatal). */
3972
+ /**
3973
+ * The graph has both directed and undirected edges and `onMixedDirection` is "error". An import stops; a save to a
3974
+ * format that holds one direction per file fails with E_DIRECTED. Pass "directed" or "undirected" to read or write
3975
+ * it anyway.
3976
+ */
3545
3977
  MIXED_DIRECTION: MIXED_DIRECTION_CODE
3546
3978
  });
3547
3979
  export {