@graphty/graph-io 0.3.24 → 0.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-BbJI55dx.js +56 -0
  4. package/dist/chunks/choose-BbJI55dx.js.map +1 -0
  5. package/dist/chunks/constants-BCsFsMj4.js +231 -0
  6. package/dist/chunks/constants-BCsFsMj4.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D0g6NNUy.js} +382 -92
  8. package/dist/chunks/escape-D0g6NNUy.js.map +1 -0
  9. package/dist/chunks/export-BTI4yQgy.js +4333 -0
  10. package/dist/chunks/export-BTI4yQgy.js.map +1 -0
  11. package/dist/chunks/exporter-BMqk5oxW.js +3465 -0
  12. package/dist/chunks/exporter-BMqk5oxW.js.map +1 -0
  13. package/dist/chunks/{importer-eUREhBGj.js → exporter-Cra2GYcN.js} +4969 -3201
  14. package/dist/chunks/exporter-Cra2GYcN.js.map +1 -0
  15. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-Dxh231ZF.js} +38 -229
  16. package/dist/chunks/exporter-Dxh231ZF.js.map +1 -0
  17. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-tne475KK.js} +22 -20
  18. package/dist/chunks/exporter-tne475KK.js.map +1 -0
  19. package/dist/chunks/importer-90YWhJoF.js +2811 -0
  20. package/dist/chunks/importer-90YWhJoF.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-Bcl1d4xH.js} +398 -145
  22. package/dist/chunks/importer-Bcl1d4xH.js.map +1 -0
  23. package/dist/chunks/{importer-BWY2FFc5.js → importer-BfIsp1f9.js} +255 -77
  24. package/dist/chunks/importer-BfIsp1f9.js.map +1 -0
  25. package/dist/chunks/{importer-zGLo8Dg_.js → importer-C_TEA1zJ.js} +484 -157
  26. package/dist/chunks/importer-C_TEA1zJ.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-DCjOvO7U.js} +1687 -310
  28. package/dist/chunks/importer-DCjOvO7U.js.map +1 -0
  29. package/dist/chunks/{importer-vi3bSdtw.js → importer-DfVu6j59.js} +509 -76
  30. package/dist/chunks/importer-DfVu6j59.js.map +1 -0
  31. package/dist/chunks/{importer-DIrbbnAf.js → importer-Dku_VAIY.js} +585 -226
  32. package/dist/chunks/importer-Dku_VAIY.js.map +1 -0
  33. package/dist/chunks/json-elements-3tnyt5uZ.js +1225 -0
  34. package/dist/chunks/json-elements-3tnyt5uZ.js.map +1 -0
  35. package/dist/chunks/ontology-export-B9Tcf37D.js +357 -0
  36. package/dist/chunks/ontology-export-B9Tcf37D.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CQXT__mY.js} +298 -114
  38. package/dist/chunks/records-CQXT__mY.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DmcUs5_Q.js} +29 -11
  40. package/dist/chunks/text-DmcUs5_Q.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +951 -261
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +342 -85
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +564 -157
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +19 -1
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +33 -17
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +868 -188
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +2 -0
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +400 -83
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +145 -32
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +680 -285
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +226 -79
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +98 -24
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +108 -26
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +238 -85
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +66 -34
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +183 -51
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +20 -21
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +7 -2
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +38 -4
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +33 -17
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1034 -198
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +6 -1
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +477 -88
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +201 -46
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +888 -300
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +61 -338
  498. package/src/formats/cx2/importer.ts +317 -86
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +139 -31
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +111 -26
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +320 -101
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +89 -41
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +213 -52
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +35 -27
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +11 -3
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -19,19 +19,39 @@
19
19
  */
20
20
  import { GraphFormatError, INVALID_INDEX, MAX_COUNT, } from "@graphty/graph-format";
21
21
  import { declareAttribute, declareResolved, losesPrecision, parseDeclaredValue, PRECISION_CODE, takenIn, uniqueColumnName, } from "../../common/attributes.js";
22
+ import { overflowsToInfinity } from "../../common/declared-types.js";
22
23
  import { DirectionResolver } from "../../common/direction.js";
23
24
  import { IdCoercer } from "../../common/ids.js";
24
25
  import { textChunks, throwIfAborted } from "../../common/input.js";
25
26
  import { reportSinkOptions, reportUnusedOptions, resolveImportOptions, } from "../../common/options.js";
27
+ import { agree, plural } from "../../common/plural.js";
26
28
  import { ImportReportBuilder } from "../../common/report.js";
27
29
  import { isWeightField, parseWeightText } from "../../common/weights.js";
28
- import { isWhitespace, localName, tokenizeXml, xmlDeclaredEncoding, XmlSyntaxError, } from "../../common/xml.js";
30
+ import { isWhitespace, localName, sniffXmlText, tokenizeXml, xmlDeclaredEncoding, XmlEmptyInputError, XmlSyntaxError, } from "../../common/xml.js";
29
31
  import { EDGE_ID_COLUMN, EXTENSIONS, FORMAT, GRAPHML_ISSUE, GRAPHML_LOSS, GRAPHML_NAMESPACE, HYPEREDGE_HUB_COLUMN, LABEL_COLUMN, META_KEY, MIME_TYPES, ORIGINAL_ID_ATTRIBUTE, ORIGINAL_ID_COLUMN, PARENT_COLUMN, RESERVED_EDGE_NAMES, RESERVED_NODE_NAMES, SOURCE_PORT_COLUMN, TARGET_PORT_COLUMN, XSI_NAMESPACE, } from "./constants.js";
30
32
  import { XmlTreeBuilder } from "./tree.js";
31
33
  import { graphicsDecl, graphicsValues } from "./yfiles.js";
32
- /** The XML attributes the importer reads on `<graph>`, `<node>` and `<edge>`; any other is reported. */
34
+ /** The XML attributes the importer reads on each element; any other is reported (once per element and name). */
33
35
  const GRAPH_ATTRIBUTES = new Set(["id", "edgedefault", "parse.nodes", "parse.edges"]);
34
36
  const NODE_ATTRIBUTES = new Set(["id"]);
37
+ const KEY_ATTRIBUTES = new Set([
38
+ "id",
39
+ "for",
40
+ "attr.name",
41
+ "attr.type",
42
+ "name",
43
+ "type",
44
+ "yfiles.type",
45
+ ]);
46
+ const DATA_ATTRIBUTES = new Set(["key"]);
47
+ const HYPEREDGE_ATTRIBUTES = new Set(["id"]);
48
+ const ENDPOINT_ATTRIBUTES = new Set(["node", "type"]);
49
+ const PORT_ATTRIBUTES = new Set(["name"]);
50
+ const NO_ATTRIBUTES = new Set();
51
+ /** Attributes the GraphML schema defines that the importer does not keep: reported as not kept, not as foreign. */
52
+ const SCHEMA_ATTRIBUTES = new Set(["id", "port", "parse.order", "parse.nodeids", "parse.edgeids"]);
53
+ /** Distinct unknown attribute names reported one by one per element kind; the rest are counted in one issue. */
54
+ const MAX_UNKNOWN_ATTRIBUTE_NAMES = 16;
35
55
  const EDGE_ATTRIBUTES = new Set([
36
56
  "id",
37
57
  "source",
@@ -78,6 +98,10 @@ var Ctx;
78
98
  Ctx[Ctx["Data"] = 8] = "Data";
79
99
  Ctx[Ctx["Capture"] = 9] = "Capture";
80
100
  Ctx[Ctx["Skip"] = 10] = "Skip";
101
+ /** A `<port>` (ports nest; their names are collected for the edge port check). */
102
+ Ctx[Ctx["Port"] = 11] = "Port";
103
+ /** Inside a `<graph>` held by an `<edge>`: dropped, its nodes and edges counted as skipped. */
104
+ Ctx[Ctx["Dropped"] = 12] = "Dropped";
81
105
  })(Ctx || (Ctx = {}));
82
106
  /**
83
107
  * A growable bit set over node indices, marking the indices declared by a `<node>` element so a
@@ -133,6 +157,10 @@ class GraphmlReader {
133
157
  this.nodes = [];
134
158
  this.declared = new IndexFlags();
135
159
  this.edgeIds = new Set();
160
+ /** The keys `<data>` referenced before any `<key>` declared them (E_GRAPHML_UNKNOWN_KEY). */
161
+ this.unknownKeyIds = new Set();
162
+ /** The ids of the edges waiting in {@link deferred}. */
163
+ this.deferredEdgeIds = new Set();
136
164
  this.elementsSinceCheck = 0;
137
165
  /** Mangled id text -> the original id restored from `graphty:originalId`, for edge endpoints. */
138
166
  this.restored = new Map();
@@ -150,6 +178,9 @@ class GraphmlReader {
150
178
  };
151
179
  this.descTarget = null;
152
180
  this.descText = "";
181
+ this.descLine = 0;
182
+ /** The keys of the graph-level `<data>` read so far, for the duplicate check. */
183
+ this.graphKeys = { keys: null };
153
184
  this.description = null;
154
185
  this.graphSeen = false;
155
186
  this.graphId = null;
@@ -165,6 +196,24 @@ class GraphmlReader {
165
196
  this.targetPortHandle = INVALID_INDEX;
166
197
  this.parentHandle = INVALID_INDEX;
167
198
  this.hubHandle = INVALID_INDEX;
199
+ /** The hub nodes of star-expanded hyperedges, so a later `<node>` of the same id is reported as a clash. */
200
+ this.hubs = new IndexFlags();
201
+ /** Edges and hyperedges whose endpoints were not declared yet under addMissingNodes: false, added at the end. */
202
+ this.deferred = [];
203
+ /** The ids of the `<graph>` elements read so far, for the endpoint-names-a-graph check. */
204
+ this.graphIds = new Set();
205
+ /** How many top-level `<graph>` elements were opened. */
206
+ this.topGraphs = 0;
207
+ /** The namespace of the `<graphml>` root (children in it are GraphML even when it is not GraphML's). */
208
+ this.rootNs = GRAPHML_NAMESPACE;
209
+ /** Whether a graph-level `<desc>` was kept, so a second one is reported. */
210
+ this.graphDescSeen = false;
211
+ /** Unknown attribute names reported per element kind, and how many more were not listed. */
212
+ this.unknownNames = new Map();
213
+ this.unknownOverflow = new Map();
214
+ /** The port names each node declares, and the ports edges reference, checked at the end. */
215
+ this.ports = new Map();
216
+ this.portRefs = [];
168
217
  this.sink = sink;
169
218
  this.report = report;
170
219
  this.options = options;
@@ -178,8 +227,9 @@ class GraphmlReader {
178
227
  * @param name - the element name
179
228
  * @param attrs - its attributes
180
229
  * @param line - the line
230
+ * @param ns - the element's namespace (null: an undeclared prefix)
181
231
  */
182
- start(name, attrs, line) {
232
+ start(name, attrs, line, ns = "") {
183
233
  const parent = this.ctx.length === 0 ? null : this.ctx[this.ctx.length - 1];
184
234
  switch (parent) {
185
235
  case Ctx.Capture:
@@ -193,10 +243,18 @@ class GraphmlReader {
193
243
  case Ctx.Default:
194
244
  this.captureStart(name, attrs);
195
245
  return;
246
+ case Ctx.Dropped:
247
+ this.dropStart(localName(name));
248
+ return;
196
249
  default:
197
250
  break;
198
251
  }
199
252
  const local = localName(name);
253
+ if (parent !== null && ns !== GRAPHML_NAMESPACE && ns !== "" && ns !== this.rootNs) {
254
+ // a vendor element whose local name happens to be node, edge or data is not GraphML
255
+ this.unknownElement(name, line);
256
+ return;
257
+ }
200
258
  switch (parent) {
201
259
  case null:
202
260
  if (local !== "graphml") {
@@ -204,6 +262,13 @@ class GraphmlReader {
204
262
  line,
205
263
  });
206
264
  }
265
+ if (ns !== GRAPHML_NAMESPACE && ns !== "") {
266
+ this.report.warning("validation-error", GRAPHML_ISSUE.NAMESPACE, ns === null
267
+ ? `the root <${name}> uses an undeclared prefix; read as GraphML`
268
+ : `the root <${name}> is in the namespace ${JSON.stringify(ns)}, not ${GRAPHML_NAMESPACE}; read as GraphML`, { line, element: ns });
269
+ }
270
+ this.rootNs = ns;
271
+ this.reportUnreadAttributes("graphml", attrs, NO_ATTRIBUTES, line);
207
272
  this.readRoot(attrs);
208
273
  this.ctx.push(Ctx.Graphml);
209
274
  return;
@@ -211,7 +276,7 @@ class GraphmlReader {
211
276
  this.startInGraphml(name, local, attrs, line);
212
277
  return;
213
278
  case Ctx.Key:
214
- this.startInKey(name, local, line);
279
+ this.startInKey(name, local, attrs, line);
215
280
  return;
216
281
  case Ctx.Graph:
217
282
  this.startInGraph(name, local, attrs, line);
@@ -225,6 +290,9 @@ class GraphmlReader {
225
290
  case Ctx.Hyperedge:
226
291
  this.startInHyperedge(name, local, attrs, line);
227
292
  return;
293
+ case Ctx.Port:
294
+ this.startInPort(name, local, attrs, line);
295
+ return;
228
296
  default:
229
297
  this.unknownElement(name, line);
230
298
  }
@@ -242,6 +310,8 @@ class GraphmlReader {
242
310
  return;
243
311
  case Ctx.Skip:
244
312
  case Ctx.Graphml:
313
+ case Ctx.Port:
314
+ case Ctx.Dropped:
245
315
  case undefined:
246
316
  return;
247
317
  case Ctx.Desc:
@@ -266,7 +336,7 @@ class GraphmlReader {
266
336
  this.finishHyperedge();
267
337
  return;
268
338
  case Ctx.Graph:
269
- this.graphs.pop();
339
+ this.finishGraph();
270
340
  return;
271
341
  default: {
272
342
  const value = ctx;
@@ -298,6 +368,7 @@ class GraphmlReader {
298
368
  this.descText += text;
299
369
  return;
300
370
  case Ctx.Skip:
371
+ case Ctx.Dropped:
301
372
  return;
302
373
  default:
303
374
  if (!isWhitespace(text)) {
@@ -312,6 +383,20 @@ class GraphmlReader {
312
383
  if (!this.graphSeen) {
313
384
  this.report.fail(GRAPHML_ISSUE.NO_GRAPH, "the document has no <graph> element");
314
385
  }
386
+ // GraphML allows an edge before the nodes it joins: what waited for them is added now
387
+ for (const edge of this.deferred) {
388
+ if ("endpoints" in edge) {
389
+ this.expandHyperedge(edge);
390
+ }
391
+ else {
392
+ this.addEdge(edge);
393
+ }
394
+ }
395
+ this.deferred.length = 0;
396
+ this.checkPorts();
397
+ for (const [kind, more] of this.unknownOverflow) {
398
+ this.report.warning("unsupported", GRAPHML_ISSUE.UNKNOWN_XML_ATTRIBUTE, `${more} more distinct attribute names on <${kind}> are not GraphML attributes and are not kept (not listed one by one)`, { element: kind });
399
+ }
315
400
  const meta = { graphId: this.graphId, edgedefault: this.edgedefault, namespaces: this.namespaces };
316
401
  this.sink.setMeta({
317
402
  sourceFormat: FORMAT,
@@ -350,7 +435,7 @@ class GraphmlReader {
350
435
  startInGraphml(name, local, attrs, line) {
351
436
  switch (local) {
352
437
  case "desc":
353
- this.beginDesc("graph");
438
+ this.beginDesc("graph", line);
354
439
  return;
355
440
  case "key":
356
441
  this.beginKey(attrs, line);
@@ -369,14 +454,20 @@ class GraphmlReader {
369
454
  * A child of `<key>`.
370
455
  * @param name - the element name
371
456
  * @param local - its local name
457
+ * @param attrs - its attributes
372
458
  * @param line - the line
373
459
  */
374
- startInKey(name, local, line) {
460
+ startInKey(name, local, attrs, line) {
375
461
  switch (local) {
376
462
  case "desc":
377
- this.beginDesc("key");
463
+ this.beginDesc("key", line);
378
464
  return;
379
465
  case "default":
466
+ this.reportUnreadAttributes("default", attrs, NO_ATTRIBUTES, line);
467
+ if (this.pendingKey !== null &&
468
+ (this.pendingKey.defaultText !== null || this.pendingKey.defaultTree !== undefined)) {
469
+ this.report.warning("validation-error", GRAPHML_ISSUE.DUPLICATE_ATTRIBUTE, `key "${this.pendingKey.id ?? ""}" has a second <default>; the later one is kept`, { line, element: this.pendingKey.id });
470
+ }
380
471
  this.content.key = null;
381
472
  this.content.pendingKey = this.pendingKey;
382
473
  this.content.text = "";
@@ -396,21 +487,25 @@ class GraphmlReader {
396
487
  * @param line - the line
397
488
  */
398
489
  startInGraph(name, local, attrs, line) {
490
+ const first = this.graphs.length === 1 && this.topGraphs === 1;
399
491
  switch (local) {
400
492
  case "desc":
401
- if (this.graphs.length === 1) {
402
- this.beginDesc("graph");
493
+ if (first) {
494
+ this.beginDesc("graph", line);
403
495
  }
404
496
  else {
497
+ this.report.warnOnce("unsupported", GRAPHML_ISSUE.DESC_DROPPED, `the <desc> of a ${this.graphs.length === 1 ? "second top-level" : "nested"} <graph> is not kept`, { line }, `${GRAPHML_ISSUE.DESC_DROPPED}:graph`);
405
498
  this.ctx.push(Ctx.Skip);
406
499
  }
407
500
  return;
408
501
  case "data":
409
- if (this.graphs.length === 1) {
502
+ if (first) {
410
503
  this.beginData(attrs, line, "graph");
411
504
  }
412
505
  else {
413
- this.report.warnOnce("unsupported", GRAPHML_ISSUE.NESTED_GRAPH_DATA, "data of a nested <graph> cannot be kept; only the top-level graph has attributes", { line });
506
+ this.report.warnOnce("unsupported", GRAPHML_ISSUE.NESTED_GRAPH_DATA, this.graphs.length === 1
507
+ ? "data of a second top-level <graph> cannot be kept; the graphs are merged and only the first one's attributes are kept"
508
+ : "data of a nested <graph> cannot be kept; only the top-level graph has attributes", { line });
414
509
  this.ctx.push(Ctx.Skip);
415
510
  }
416
511
  return;
@@ -451,11 +546,14 @@ class GraphmlReader {
451
546
  return;
452
547
  case "port":
453
548
  this.report.warnOnce("unsupported", GRAPHML_ISSUE.PORT_DECLARATION, "<port> declarations are not kept; sourceport / targetport edge attributes are", { line });
454
- this.ctx.push(Ctx.Skip);
549
+ this.beginPort(attrs, line);
455
550
  return;
456
551
  case "graph": {
457
552
  const node = this.nodes[this.nodes.length - 1];
458
553
  this.materializeNode(node);
554
+ if (node.index === INVALID_INDEX) {
555
+ this.report.error("missing-value", GRAPHML_ISSUE.UNKNOWN_PARENT, "the nodes of this nested <graph> lose their parent: the node holding it was skipped; they are read as top-level nodes", { line });
556
+ }
459
557
  this.beginGraph(attrs, line, node.index);
460
558
  return;
461
559
  }
@@ -485,10 +583,84 @@ class GraphmlReader {
485
583
  case "data":
486
584
  this.beginData(attrs, line, "edge");
487
585
  return;
586
+ case "graph":
587
+ this.report.warnOnce("unsupported", GRAPHML_ISSUE.EDGE_GRAPH_DROPPED, "a <graph> inside an <edge> is not supported; it is dropped with the nodes and edges it holds (counted as skipped)", { line, element: attrs.get("id") ?? null });
588
+ this.ctx.push(Ctx.Dropped);
589
+ return;
590
+ default:
591
+ this.unknownElement(name, line);
592
+ }
593
+ }
594
+ /**
595
+ * An element inside a dropped `<graph>` (one held by an edge): counted as skipped.
596
+ * @param local - its local name
597
+ */
598
+ dropStart(local) {
599
+ if (local === "node") {
600
+ this.report.counts.skippedNodes++;
601
+ }
602
+ else if (local === "edge" || local === "hyperedge") {
603
+ this.report.counts.skippedEdges++;
604
+ }
605
+ this.ctx.push(local === "data" || local === "desc" ? Ctx.Skip : Ctx.Dropped);
606
+ }
607
+ /**
608
+ * Open a `<port>`: its name is kept for the edge port check, its content is skipped.
609
+ * @param attrs - its attributes
610
+ * @param line - the line
611
+ */
612
+ beginPort(attrs, line) {
613
+ this.reportUnreadAttributes("port", attrs, PORT_ATTRIBUTES, line);
614
+ const node = this.nodes[this.nodes.length - 1];
615
+ const name = attrs.get("name");
616
+ if (node.id !== null && name !== undefined) {
617
+ const id = node.restoredId ?? node.id;
618
+ let names = this.ports.get(id);
619
+ if (names === undefined) {
620
+ names = new Set();
621
+ this.ports.set(id, names);
622
+ }
623
+ names.add(name);
624
+ }
625
+ this.ctx.push(Ctx.Port);
626
+ }
627
+ /**
628
+ * A child of `<port>`: a nested port declares a name too; data and desc are skipped.
629
+ * @param name - the element name
630
+ * @param local - its local name
631
+ * @param attrs - its attributes
632
+ * @param line - the line
633
+ */
634
+ startInPort(name, local, attrs, line) {
635
+ switch (local) {
636
+ case "port":
637
+ this.beginPort(attrs, line);
638
+ return;
639
+ case "data":
640
+ case "desc":
641
+ this.ctx.push(Ctx.Skip);
642
+ return;
488
643
  default:
489
644
  this.unknownElement(name, line);
490
645
  }
491
646
  }
647
+ /**
648
+ * Report the `sourceport` / `targetport` values that name a port their node never declares
649
+ * (once, with the count), now that every node has been read.
650
+ */
651
+ checkPorts() {
652
+ let dangling = 0;
653
+ let first = null;
654
+ for (const [node, port] of this.portRefs) {
655
+ if (this.ports.get(node)?.has(port) !== true) {
656
+ dangling++;
657
+ first ?? (first = `${String(node)}:${port}`);
658
+ }
659
+ }
660
+ if (dangling > 0) {
661
+ this.report.warning("missing-value", GRAPHML_ISSUE.DANGLING_REFERENCE, `${dangling} edge port reference${plural(dangling)} ${agree(dangling, "names", "name")} a port their node does not declare (first: ${first ?? ""}); the values are kept`, { element: first });
662
+ }
663
+ }
492
664
  /**
493
665
  * A child of `<hyperedge>` (under the star / clique policies).
494
666
  * @param name - the element name
@@ -499,6 +671,7 @@ class GraphmlReader {
499
671
  startInHyperedge(name, local, attrs, line) {
500
672
  switch (local) {
501
673
  case "endpoint":
674
+ this.reportUnreadAttributes("endpoint", attrs, ENDPOINT_ATTRIBUTES, line);
502
675
  this.readEndpoint(attrs, line);
503
676
  this.ctx.push(Ctx.Skip);
504
677
  return;
@@ -507,6 +680,7 @@ class GraphmlReader {
507
680
  this.ctx.push(Ctx.Skip);
508
681
  return;
509
682
  case "desc":
683
+ this.report.warnOnce("unsupported", GRAPHML_ISSUE.DESC_DROPPED, "the <desc> of a hyperedge is not kept by the star / clique expansions", { line }, `${GRAPHML_ISSUE.DESC_DROPPED}:hyperedge`);
510
684
  this.ctx.push(Ctx.Skip);
511
685
  return;
512
686
  default:
@@ -519,7 +693,7 @@ class GraphmlReader {
519
693
  * @param line - the line
520
694
  */
521
695
  unknownElement(name, line) {
522
- this.report.warnOnce("unsupported", GRAPHML_ISSUE.UNKNOWN_ELEMENT, `element <${name}> is not GraphML and was skipped`, {
696
+ this.report.warnOnce("unsupported", GRAPHML_ISSUE.UNKNOWN_ELEMENT, unknownElementMessage(name), {
523
697
  line,
524
698
  element: name,
525
699
  });
@@ -528,10 +702,12 @@ class GraphmlReader {
528
702
  /**
529
703
  * Open a `<desc>`.
530
704
  * @param target - what the text describes
705
+ * @param line - the line
531
706
  */
532
- beginDesc(target) {
707
+ beginDesc(target, line) {
533
708
  this.descTarget = target;
534
709
  this.descText = "";
710
+ this.descLine = line;
535
711
  this.ctx.push(Ctx.Desc);
536
712
  }
537
713
  /** Close a `<desc>`. */
@@ -541,6 +717,11 @@ class GraphmlReader {
541
717
  this.pendingKey.desc = text;
542
718
  }
543
719
  else if (this.descTarget === "graph" && text.length > 0) {
720
+ if (this.graphDescSeen) {
721
+ // a <graphml> and a <graph> description: the graph has one description field
722
+ this.report.warning("unsupported", GRAPHML_ISSUE.DESC_DROPPED, "a second graph-level <desc> replaces the first; the earlier text is not kept", { line: this.descLine });
723
+ }
724
+ this.graphDescSeen = true;
544
725
  this.description = text;
545
726
  }
546
727
  this.descTarget = null;
@@ -549,23 +730,51 @@ class GraphmlReader {
549
730
  // ------------------------------------------------------------------ graphs
550
731
  /**
551
732
  * Report, once per element kind and attribute name, an XML attribute the importer does not read:
552
- * a GraphML `parse.*` hint as ignored, anything else as unknown. Namespace declarations and
553
- * `xml:` / `xsi:` attributes are not data and pass silently.
733
+ * a GraphML `parse.*` hint as ignored, anything else as not kept. Namespace declarations and
734
+ * `xml:` / `xsi:` attributes are not data and pass silently. Beyond MAX_UNKNOWN_ATTRIBUTE_NAMES
735
+ * distinct names per element kind the rest are counted and reported once at the end, so a file
736
+ * with thousands of vendor attributes does not grow the report without bound.
554
737
  * @param kind - the element name
555
738
  * @param attrs - the element's attributes
556
739
  * @param known - the attributes the importer reads on that element
557
740
  * @param line - the line
558
741
  */
559
742
  reportUnreadAttributes(kind, attrs, known, line) {
743
+ if (attrs.size === 0) {
744
+ return;
745
+ }
560
746
  for (const name of attrs.keys()) {
561
747
  if (known.has(name) || name === "xmlns" || /^(xmlns|xml|xsi):/.test(name)) {
562
748
  continue;
563
749
  }
564
750
  const hint = name.startsWith("parse.");
565
751
  const code = hint ? GRAPHML_ISSUE.PARSE_HINT_IGNORED : GRAPHML_ISSUE.UNKNOWN_XML_ATTRIBUTE;
566
- this.report.warnOnce("unsupported", code, hint
567
- ? `the <${kind}> parse hint ${name} is ignored`
568
- : `the <${kind}> attribute ${name} is not a GraphML attribute; it is not kept`, { line, element: name }, `${code}:${kind}:${name}`);
752
+ let names = this.unknownNames.get(kind);
753
+ if (names === undefined) {
754
+ names = new Set();
755
+ this.unknownNames.set(kind, names);
756
+ }
757
+ if (names.has(name)) {
758
+ continue;
759
+ }
760
+ if (names.size >= MAX_UNKNOWN_ATTRIBUTE_NAMES && !hint) {
761
+ this.unknownOverflow.set(kind, (this.unknownOverflow.get(kind) ?? 0) + 1);
762
+ }
763
+ names.add(name);
764
+ if (names.size > MAX_UNKNOWN_ATTRIBUTE_NAMES && !hint) {
765
+ continue;
766
+ }
767
+ let message;
768
+ if (hint) {
769
+ message = `the <${kind}> parse hint ${name} is ignored`;
770
+ }
771
+ else if (SCHEMA_ATTRIBUTES.has(name)) {
772
+ message = `the <${kind}> attribute ${name} is not kept`;
773
+ }
774
+ else {
775
+ message = `the <${kind}> attribute ${name} is not a GraphML attribute; it is not kept`;
776
+ }
777
+ this.report.warning("unsupported", code, message, { line, element: name });
569
778
  }
570
779
  }
571
780
  /**
@@ -578,6 +787,13 @@ class GraphmlReader {
578
787
  beginGraph(attrs, line, parent) {
579
788
  this.reportUnreadAttributes("graph", attrs, GRAPH_ATTRIBUTES, line);
580
789
  const top = this.graphs.length === 0;
790
+ if (top) {
791
+ this.topGraphs++;
792
+ }
793
+ const graphId = attrs.get("id");
794
+ if (graphId !== undefined && graphId.length > 0) {
795
+ this.graphIds.add(graphId);
796
+ }
581
797
  const edgedefault = attrs.get("edgedefault");
582
798
  let directed;
583
799
  if (edgedefault === "directed" || edgedefault === "undirected") {
@@ -585,14 +801,24 @@ class GraphmlReader {
585
801
  }
586
802
  else if (edgedefault === undefined) {
587
803
  directed = top ? this.options.defaultDirected : this.graphs[this.graphs.length - 1].directed;
588
- this.report.warning("validation-error", GRAPHML_ISSUE.EDGEDEFAULT_MISSING, `<graph> has no edgedefault; read as ${directed ? "directed" : "undirected"}`, { line });
804
+ // once per kind: a file of thousands of nested graphs without edgedefault is one finding
805
+ const direction = directed ? "directed" : "undirected";
806
+ this.report.warnOnce("validation-error", GRAPHML_ISSUE.EDGEDEFAULT_MISSING, top
807
+ ? `<graph> has no edgedefault; read as ${direction}`
808
+ : `a nested <graph> has no edgedefault; it takes its container's (${direction})`, { line }, `${GRAPHML_ISSUE.EDGEDEFAULT_MISSING}:${top ? "top" : "nested"}`);
589
809
  }
590
810
  else {
591
811
  directed = top ? this.options.defaultDirected : this.graphs[this.graphs.length - 1].directed;
592
812
  this.report.error("validation-error", GRAPHML_ISSUE.INVALID_EDGEDEFAULT, `edgedefault "${edgedefault}" is neither directed nor undirected; read as ${directed ? "directed" : "undirected"}`, { line });
593
813
  }
814
+ let hints = null;
594
815
  if (top && this.graphSeen) {
595
816
  this.report.warnOnce("unsupported", GRAPHML_ISSUE.MULTIPLE_GRAPHS, "the document holds more than one top-level <graph>; their nodes and edges are merged into one graph", { line, element: attrs.get("id") ?? null });
817
+ for (const name of ["parse.nodes", "parse.edges"]) {
818
+ if (attrs.has(name)) {
819
+ this.report.warnOnce("unsupported", GRAPHML_ISSUE.PARSE_HINT_IGNORED, `the ${name} hint of a second top-level <graph> is ignored`, { line, element: name }, `${GRAPHML_ISSUE.PARSE_HINT_IGNORED}:second:${name}`);
820
+ }
821
+ }
596
822
  }
597
823
  else if (top) {
598
824
  this.graphSeen = true;
@@ -601,6 +827,7 @@ class GraphmlReader {
601
827
  this.direction.setHeader(directed, { line });
602
828
  const nodes = this.hint(attrs.get("parse.nodes"), "parse.nodes", line);
603
829
  const edges = this.hint(attrs.get("parse.edges"), "parse.edges", line);
830
+ hints = nodes === null && edges === null ? null : { nodes, edges };
604
831
  if (nodes !== null || edges !== null) {
605
832
  try {
606
833
  this.sink.reserve(nodes ?? undefined, edges ?? undefined);
@@ -615,9 +842,24 @@ class GraphmlReader {
615
842
  }
616
843
  }
617
844
  }
618
- this.graphs.push({ directed, parent });
845
+ this.graphs.push({ directed, parent, hints, nodes: 0, edges: 0, line });
619
846
  this.ctx.push(Ctx.Graph);
620
847
  }
848
+ /** Close a `<graph>`: a top-level graph's count hints are checked against what it held. */
849
+ finishGraph() {
850
+ const graph = this.graphs.pop();
851
+ if (graph?.hints === null || graph === undefined) {
852
+ return;
853
+ }
854
+ for (const [name, hint, found] of [
855
+ ["parse.nodes", graph.hints.nodes, graph.nodes],
856
+ ["parse.edges", graph.hints.edges, graph.edges],
857
+ ]) {
858
+ if (hint !== null && hint !== found) {
859
+ this.report.warning("validation-error", GRAPHML_ISSUE.COUNT_MISMATCH, `<graph ${name}="${hint}"> but the graph holds ${found} ${name === "parse.nodes" ? "<node>" : "<edge>"} elements`, { line: graph.line, element: name });
860
+ }
861
+ }
862
+ }
621
863
  /**
622
864
  * A `parse.nodes` / `parse.edges` hint the sink can reserve; anything else is reported and ignored.
623
865
  * @param text - the attribute text, or undefined
@@ -643,7 +885,12 @@ class GraphmlReader {
643
885
  * @param line - the line
644
886
  */
645
887
  beginKey(attrs, line) {
888
+ // attr.list (a list extension of some writers) and yEd's yfiles.foldertype are reported here
889
+ this.reportUnreadAttributes("key", attrs, KEY_ATTRIBUTES, line);
646
890
  const id = attrs.get("id") ?? null;
891
+ if (id !== null && this.unknownKeyIds.delete(id)) {
892
+ this.report.warning("missing-value", GRAPHML_ISSUE.KEY_DECLARED_LATE, `key "${id}" is declared after data that uses it; those values were dropped (declare <key> before <graph>)`, { line, element: id });
893
+ }
647
894
  const forText = attrs.get("for") ?? "all";
648
895
  let domains;
649
896
  switch (forText) {
@@ -712,6 +959,8 @@ class GraphmlReader {
712
959
  continue;
713
960
  }
714
961
  if (domain === "edge" && !yfiles && isWeightField(name, this.options.weightFrom)) {
962
+ // networkx writes one weight key per value type (long and double): every key of
963
+ // that name is the weight; two of them on one edge are reported in finishData
715
964
  weight = true;
716
965
  this.weightOrigin ?? (this.weightOrigin = { id: key.id, title: key.attrName, type: key.attrType });
717
966
  continue;
@@ -877,8 +1126,12 @@ class GraphmlReader {
877
1126
  * @param domain - the domain of the element holding it
878
1127
  */
879
1128
  beginData(attrs, line, domain) {
1129
+ this.reportUnreadAttributes("data", attrs, DATA_ATTRIBUTES, line);
880
1130
  const keyId = attrs.get("key");
881
1131
  const { content } = this;
1132
+ if (keyId !== undefined) {
1133
+ this.checkDuplicateData(keyId, domain, line);
1134
+ }
882
1135
  content.key = null;
883
1136
  content.pendingKey = null;
884
1137
  content.domain = domain;
@@ -894,6 +1147,7 @@ class GraphmlReader {
894
1147
  const entries = this.keys.get(keyId);
895
1148
  const key = entries?.find((entry) => entry.domains.includes(domain)) ?? entries?.[0];
896
1149
  if (key === undefined) {
1150
+ this.unknownKeyIds.add(keyId);
897
1151
  this.report.error("validation-error", GRAPHML_ISSUE.UNKNOWN_KEY, `<data> references undeclared key "${keyId}"`, { line, element: keyId });
898
1152
  }
899
1153
  else if (!key.skipped && !key.domains.includes(domain)) {
@@ -905,6 +1159,32 @@ class GraphmlReader {
905
1159
  }
906
1160
  this.ctx.push(Ctx.Data);
907
1161
  }
1162
+ /**
1163
+ * Report a second `<data>` of one key on one element; the later value is kept (it overwrites).
1164
+ * @param keyId - the key
1165
+ * @param domain - the domain of the element holding it
1166
+ * @param line - the line
1167
+ */
1168
+ checkDuplicateData(keyId, domain, line) {
1169
+ let holder = null;
1170
+ if (domain === "node") {
1171
+ holder = this.nodes.at(-1) ?? null;
1172
+ }
1173
+ else if (domain === "edge") {
1174
+ holder = this.edge;
1175
+ }
1176
+ else {
1177
+ holder = this.graphKeys;
1178
+ }
1179
+ if (holder === null) {
1180
+ return;
1181
+ }
1182
+ holder.keys ?? (holder.keys = new Set());
1183
+ if (holder.keys.has(keyId)) {
1184
+ this.report.warning("validation-error", GRAPHML_ISSUE.DUPLICATE_ATTRIBUTE, `a second <data key="${keyId}"> on one ${domain}; the later value is kept`, { line, element: keyId });
1185
+ }
1186
+ holder.keys.add(keyId);
1187
+ }
908
1188
  /**
909
1189
  * A child element inside `<data>` / `<default>`: the content becomes a tree.
910
1190
  * @param name - the element name
@@ -959,9 +1239,13 @@ class GraphmlReader {
959
1239
  case "node": {
960
1240
  const node = this.nodes[this.nodes.length - 1];
961
1241
  if (key.originalId) {
962
- if (typeof value === "string") {
963
- node.restoredId = value;
1242
+ if (typeof value !== "string" || node.index !== INVALID_INDEX) {
1243
+ this.report.warning("validation-error", GRAPHML_ISSUE.ORIGINAL_ID_IGNORED, typeof value === "string"
1244
+ ? `the ${ORIGINAL_ID_ATTRIBUTE} value comes after the node's nested <graph>, which added the node under its written id; it is not restored`
1245
+ : `the ${ORIGINAL_ID_ATTRIBUTE} value holds elements, not text; it is not restored`, where);
1246
+ return;
964
1247
  }
1248
+ node.restoredId = value;
965
1249
  return;
966
1250
  }
967
1251
  if (key.yfiles) {
@@ -988,8 +1272,13 @@ class GraphmlReader {
988
1272
  this.report.error("validation-error", GRAPHML_ISSUE.DATA_NESTED, "a weight value must be text", where);
989
1273
  return;
990
1274
  }
1275
+ if (edge.weightKey !== null && edge.weightKey !== key.id) {
1276
+ this.report.warning("validation-error", GRAPHML_ISSUE.DUPLICATE_ATTRIBUTE, `the edge has values of two weight keys ("${edge.weightKey}" and "${key.id}"); the later one is kept`, where);
1277
+ }
1278
+ edge.weightKey = key.id;
991
1279
  try {
992
- edge.weight = parseWeightText(value);
1280
+ edge.weight = parseWeightText(value, this.report);
1281
+ this.checkOverflow(value, edge.weight, key.name, where);
993
1282
  }
994
1283
  catch (err) {
995
1284
  this.skipEdge(edge);
@@ -1057,7 +1346,12 @@ class GraphmlReader {
1057
1346
  */
1058
1347
  graphics(domain, key, tree, where) {
1059
1348
  const out = [];
1060
- for (const [field, value] of graphicsValues(domain, tree)) {
1349
+ const unmapped = [];
1350
+ const values = graphicsValues(domain, tree, unmapped);
1351
+ for (const field of unmapped) {
1352
+ this.report.warnOnce("validation-error", GRAPHML_ISSUE.YFILES_VALUE, `a yFiles ${domain} ${field} that is not a number is not mapped to its yfiles column (the graphics tree is kept)`, where, `${GRAPHML_ISSUE.YFILES_VALUE}:${domain}:${field}`);
1353
+ }
1354
+ for (const [field, value] of values) {
1061
1355
  const id = `${domain}:${field}`;
1062
1356
  let handle = this.graphicsColumns.get(id);
1063
1357
  if (handle === undefined) {
@@ -1102,6 +1396,7 @@ class GraphmlReader {
1102
1396
  if (spec.precision && losesPrecision(spec, value)) {
1103
1397
  this.report.warnOnce("precision", PRECISION_CODE, `long values of "${target.name}" beyond 2^53 are stored as the nearest double`, { line: where.line, element: target.name });
1104
1398
  }
1399
+ this.checkOverflow(value, parsed, target.name, where);
1105
1400
  return parsed;
1106
1401
  }
1107
1402
  catch (err) {
@@ -1109,6 +1404,18 @@ class GraphmlReader {
1109
1404
  return undefined;
1110
1405
  }
1111
1406
  }
1407
+ /**
1408
+ * Report (once per column) a finite number text too large for a double, stored as Infinity.
1409
+ * @param text - the value text
1410
+ * @param value - the parsed value
1411
+ * @param column - the column name
1412
+ * @param where - the location
1413
+ */
1414
+ checkOverflow(text, value, column, where) {
1415
+ if (typeof value === "number" && overflowsToInfinity(text)) {
1416
+ this.report.warnOnce("precision", PRECISION_CODE, `values of "${column}" beyond the double range (${text.trim()}) are stored as Infinity`, { line: where.line, element: column }, `${PRECISION_CODE}:overflow:${column}`);
1417
+ }
1418
+ }
1112
1419
  // ------------------------------------------------------------------ nodes
1113
1420
  /**
1114
1421
  * Open a `<node>`; it is added to the sink when its data is complete (or a nested graph
@@ -1119,6 +1426,7 @@ class GraphmlReader {
1119
1426
  beginNode(attrs, line) {
1120
1427
  this.reportUnreadAttributes("node", attrs, NODE_ATTRIBUTES, line);
1121
1428
  const graph = this.graphs[this.graphs.length - 1];
1429
+ graph.nodes++;
1122
1430
  const state = {
1123
1431
  id: null,
1124
1432
  idText: null,
@@ -1128,6 +1436,7 @@ class GraphmlReader {
1128
1436
  restoredId: null,
1129
1437
  failed: false,
1130
1438
  line,
1439
+ keys: null,
1131
1440
  };
1132
1441
  const idText = attrs.get("id");
1133
1442
  if (idText === undefined || idText.length === 0) {
@@ -1167,7 +1476,10 @@ class GraphmlReader {
1167
1476
  try {
1168
1477
  const existing = this.sink.indexOf(id);
1169
1478
  const index = this.sink.addNode(id);
1170
- if (existing !== INVALID_INDEX && this.declared.has(index)) {
1479
+ if (existing !== INVALID_INDEX && this.hubs.has(index)) {
1480
+ this.report.warning("validation-error", GRAPHML_ISSUE.HUB_ID_CLASH, `node "${String(id)}" has the id of the hub a star-expanded hyperedge created earlier; the node is merged into the hub`, { line: node.line, element: String(id) });
1481
+ }
1482
+ else if (existing !== INVALID_INDEX && this.declared.has(index)) {
1171
1483
  this.report.warning("validation-error", GRAPHML_ISSUE.DUPLICATE_NODE, `node "${String(id)}" is declared twice; the declarations are merged`, { line: node.line, element: String(id) });
1172
1484
  }
1173
1485
  else {
@@ -1234,10 +1546,15 @@ class GraphmlReader {
1234
1546
  beginEdge(attrs, line) {
1235
1547
  this.reportUnreadAttributes("edge", attrs, EDGE_ATTRIBUTES, line);
1236
1548
  const graph = this.graphs[this.graphs.length - 1];
1549
+ graph.edges++;
1550
+ const idText = attrs.get("id");
1551
+ const sourceText = attrs.get("source");
1552
+ const targetText = attrs.get("target");
1237
1553
  const edge = {
1238
1554
  source: null,
1239
1555
  target: null,
1240
- id: attrs.get("id") ?? null,
1556
+ // an exporter that writes id="" for an edge without one: the same as no id
1557
+ id: idText === undefined || idText.length === 0 ? null : idText,
1241
1558
  kind: graph.directed ? "directed" : "undirected",
1242
1559
  sourcePort: attrs.get("sourceport") ?? null,
1243
1560
  targetPort: attrs.get("targetport") ?? null,
@@ -1245,10 +1562,12 @@ class GraphmlReader {
1245
1562
  pending: [],
1246
1563
  failed: false,
1247
1564
  line,
1565
+ keys: null,
1566
+ weightKey: null,
1567
+ sourceText: sourceText ?? null,
1568
+ targetText: targetText ?? null,
1248
1569
  };
1249
1570
  const where = { line, element: edge.id };
1250
- const sourceText = attrs.get("source");
1251
- const targetText = attrs.get("target");
1252
1571
  if (sourceText === undefined || sourceText.length === 0) {
1253
1572
  this.skipEdge(edge);
1254
1573
  this.report.error("missing-value", GRAPHML_ISSUE.MISSING_ENDPOINT, "<edge> without a source", where);
@@ -1269,15 +1588,16 @@ class GraphmlReader {
1269
1588
  }
1270
1589
  const directedText = attrs.get("directed");
1271
1590
  if (directedText !== undefined) {
1272
- if (directedText === "true") {
1591
+ // the schema types directed as xs:boolean: true, false, 1 or 0
1592
+ if (directedText === "true" || directedText === "1") {
1273
1593
  edge.kind = "directed";
1274
1594
  }
1275
- else if (directedText === "false") {
1595
+ else if (directedText === "false" || directedText === "0") {
1276
1596
  edge.kind = "undirected";
1277
1597
  }
1278
1598
  else {
1279
1599
  this.skipEdge(edge);
1280
- this.report.error("validation-error", GRAPHML_ISSUE.INVALID_DIRECTED, `directed="${directedText}" is neither true nor false`, where);
1600
+ this.report.error("validation-error", GRAPHML_ISSUE.INVALID_DIRECTED, `directed="${directedText}" is neither true nor false (nor 1 or 0)`, where);
1281
1601
  }
1282
1602
  }
1283
1603
  this.edge = edge;
@@ -1296,6 +1616,28 @@ class GraphmlReader {
1296
1616
  this.skipEdge(edge);
1297
1617
  return;
1298
1618
  }
1619
+ if ((!this.options.addMissingNodes &&
1620
+ (this.sink.indexOf(edge.source) === INVALID_INDEX ||
1621
+ this.sink.indexOf(edge.target) === INVALID_INDEX)) ||
1622
+ (edge.id !== null && this.deferredEdgeIds.has(edge.id))) {
1623
+ // GraphML allows nodes and edges in any order: wait for the end of the document. An
1624
+ // edge reusing a waiting edge's id waits behind it, so the first one keeps the id.
1625
+ if (edge.id !== null) {
1626
+ this.deferredEdgeIds.add(edge.id);
1627
+ }
1628
+ this.deferred.push(edge);
1629
+ return;
1630
+ }
1631
+ this.addEdge(edge);
1632
+ }
1633
+ /**
1634
+ * Push an edge through the direction resolver and write its values.
1635
+ * @param edge - the edge, its endpoints known
1636
+ */
1637
+ addEdge(edge) {
1638
+ if (edge.source === null || edge.target === null) {
1639
+ return;
1640
+ }
1299
1641
  const element = edge.id ?? `${String(edge.source)} -> ${String(edge.target)}`;
1300
1642
  const where = { line: edge.line, element };
1301
1643
  try {
@@ -1303,6 +1645,8 @@ class GraphmlReader {
1303
1645
  this.requireNode(edge.source);
1304
1646
  this.requireNode(edge.target);
1305
1647
  }
1648
+ this.checkGraphEndpoint(edge.source, edge.sourceText, where);
1649
+ this.checkGraphEndpoint(edge.target, edge.targetText, where);
1306
1650
  if (edge.id !== null && this.edgeIds.has(edge.id)) {
1307
1651
  throw new GraphFormatError("E_DUPLICATE_EDGE_ID", `edge id "${edge.id}" is used twice`, {
1308
1652
  id: edge.id,
@@ -1319,9 +1663,11 @@ class GraphmlReader {
1319
1663
  }
1320
1664
  if (edge.sourcePort !== null) {
1321
1665
  this.sink.setEdgeValue(this.portColumn("source"), e, edge.sourcePort);
1666
+ this.portRefs.push([edge.source, edge.sourcePort]);
1322
1667
  }
1323
1668
  if (edge.targetPort !== null) {
1324
1669
  this.sink.setEdgeValue(this.portColumn("target"), e, edge.targetPort);
1670
+ this.portRefs.push([edge.target, edge.targetPort]);
1325
1671
  }
1326
1672
  const { pending } = edge;
1327
1673
  for (let i = 0; i < pending.length; i += 2) {
@@ -1343,6 +1689,18 @@ class GraphmlReader {
1343
1689
  this.report.counts.skippedEdges++;
1344
1690
  }
1345
1691
  }
1692
+ /**
1693
+ * Report an endpoint that names a nested `<graph>` rather than a node (a node of that id is
1694
+ * then created under addMissingNodes).
1695
+ * @param id - the endpoint id
1696
+ * @param text - the endpoint as written, or null
1697
+ * @param where - the edge's location
1698
+ */
1699
+ checkGraphEndpoint(id, text, where) {
1700
+ if (text !== null && this.graphIds.has(text) && this.sink.indexOf(id) === INVALID_INDEX) {
1701
+ this.report.warning("validation-error", GRAPHML_ISSUE.GRAPH_ENDPOINT, `edge endpoint "${text}" names a <graph>, not a node; a node "${text}" is created`, where);
1702
+ }
1703
+ }
1346
1704
  /**
1347
1705
  * E_UNKNOWN_NODE when an endpoint was never declared (addMissingNodes false enforced by the
1348
1706
  * importer, whatever the sink allows).
@@ -1408,6 +1766,7 @@ class GraphmlReader {
1408
1766
  * @param line - the line
1409
1767
  */
1410
1768
  beginHyperedge(attrs, line) {
1769
+ this.reportUnreadAttributes("hyperedge", attrs, HYPEREDGE_ATTRIBUTES, line);
1411
1770
  const id = attrs.get("id") ?? null;
1412
1771
  const where = { line, element: id };
1413
1772
  switch (this.options.hyperedges) {
@@ -1474,13 +1833,40 @@ class GraphmlReader {
1474
1833
  if (hyperedge.failed) {
1475
1834
  return;
1476
1835
  }
1836
+ if (hyperedge.endpoints.length === 0) {
1837
+ this.skipEdge(hyperedge);
1838
+ this.report.error("missing-value", GRAPHML_ISSUE.HYPEREDGE_ENDPOINT, "<hyperedge> without endpoints yields no edge", { line: hyperedge.line, element: hyperedge.id });
1839
+ return;
1840
+ }
1841
+ if (!this.options.addMissingNodes &&
1842
+ hyperedge.endpoints.some((endpoint) => this.sink.indexOf(endpoint.node) === INVALID_INDEX)) {
1843
+ this.deferred.push(hyperedge);
1844
+ return;
1845
+ }
1846
+ this.expandHyperedge(hyperedge);
1847
+ }
1848
+ /**
1849
+ * Expand a hyperedge to a star or a clique; under addMissingNodes false every endpoint must be
1850
+ * a declared node.
1851
+ * @param hyperedge - the hyperedge, its endpoints read
1852
+ */
1853
+ expandHyperedge(hyperedge) {
1477
1854
  const where = { line: hyperedge.line, element: hyperedge.id };
1478
1855
  try {
1856
+ for (const endpoint of hyperedge.endpoints) {
1857
+ if (!this.options.addMissingNodes) {
1858
+ this.requireNode(endpoint.node);
1859
+ }
1860
+ }
1861
+ for (const node of new Set(hyperedge.endpoints.map((endpoint) => endpoint.node))) {
1862
+ this.countEndpoints(node, node);
1863
+ }
1479
1864
  if (this.options.hyperedges === "star") {
1480
1865
  this.expandStar(hyperedge, where);
1481
1866
  }
1482
- else {
1483
- this.expandClique(hyperedge, where);
1867
+ else if (this.expandClique(hyperedge, where) === 0) {
1868
+ this.skipEdge(hyperedge);
1869
+ this.report.error("validation-error", GRAPHML_ISSUE.HYPEREDGE_ENDPOINT, "no two endpoints of this hyperedge can be joined (all in, all out, or only one); it yields no edge", where);
1484
1870
  }
1485
1871
  }
1486
1872
  catch (err) {
@@ -1503,6 +1889,7 @@ class GraphmlReader {
1503
1889
  }
1504
1890
  const hub = this.sink.addNode(hubId);
1505
1891
  this.declared.add(hub);
1892
+ this.hubs.add(hub);
1506
1893
  this.report.counts.nodes++;
1507
1894
  if (this.hubHandle === INVALID_INDEX) {
1508
1895
  this.hubHandle = this.sink.declareNodeColumn({
@@ -1538,9 +1925,11 @@ class GraphmlReader {
1538
1925
  * joined undirected to every other endpoint; two endpoints of the same direction are not joined.
1539
1926
  * @param hyperedge - the hyperedge
1540
1927
  * @param where - the location for issues
1928
+ * @returns the number of edge elements added
1541
1929
  */
1542
1930
  expandClique(hyperedge, where) {
1543
1931
  const { endpoints } = hyperedge;
1932
+ let added = 0;
1544
1933
  for (let i = 0; i < endpoints.length; i++) {
1545
1934
  for (let j = i + 1; j < endpoints.length; j++) {
1546
1935
  const a = endpoints[i];
@@ -1558,9 +1947,11 @@ class GraphmlReader {
1558
1947
  else {
1559
1948
  continue;
1560
1949
  }
1950
+ added++;
1561
1951
  this.report.counts.edges += this.sink.edgeCount - before;
1562
1952
  }
1563
1953
  }
1954
+ return added;
1564
1955
  }
1565
1956
  // ------------------------------------------------------------------ options and ids
1566
1957
  /**
@@ -1655,12 +2046,13 @@ function resolveYfiles(options) {
1655
2046
  * or when the head does not start with markup
1656
2047
  */
1657
2048
  function sniffGraphml(head) {
1658
- const text = new TextDecoder("utf-8", { fatal: false }).decode(head.subarray(0, SNIFF_BYTES));
2049
+ const text = sniffXmlText(head.subarray(0, SNIFF_BYTES));
1659
2050
  // Only a document that starts as markup: a JSON or CSV value may mention a `<graphml>` tag.
1660
2051
  if (!/^\uFEFF?\s*</.test(text)) {
1661
2052
  return 0;
1662
2053
  }
1663
- const root = text.indexOf("<graphml");
2054
+ // the root may carry a namespace prefix (<g:graphml xmlns:g="...">)
2055
+ const root = text.search(/<([\w.-]+:)?graphml[\s>/]/);
1664
2056
  if (root >= 0) {
1665
2057
  return text.includes(GRAPHML_NAMESPACE, root) ? 1 : 0.9;
1666
2058
  }
@@ -1681,9 +2073,12 @@ async function importGraphml(input, sink, options) {
1681
2073
  reportUnusedOptions(options, report, USED_OPTIONS);
1682
2074
  const reader = new GraphmlReader(sink, report, common, yfilesMode);
1683
2075
  try {
1684
- await tokenizeXml(textChunks(input, report, { ...common, declaredEncoding: xmlDeclaredEncoding }), reader);
2076
+ await tokenizeXml(textChunks(input, report, { ...common, declaredEncoding: xmlDeclaredEncoding, xml: true }), reader);
1685
2077
  }
1686
2078
  catch (err) {
2079
+ if (err instanceof XmlEmptyInputError) {
2080
+ report.fail(GRAPHML_ISSUE.EMPTY_INPUT, "the input is empty (no markup at all)", { line: err.line });
2081
+ }
1687
2082
  if (err instanceof XmlSyntaxError) {
1688
2083
  report.fail(GRAPHML_ISSUE.XML_SYNTAX, err.message, { line: err.line });
1689
2084
  }
@@ -1693,12 +2088,44 @@ async function importGraphml(input, sink, options) {
1693
2088
  throwIfAborted(common.signal);
1694
2089
  return report.finish();
1695
2090
  }
1696
- /** The GraphML importer (design section 8.4). */
2091
+ /**
2092
+ * The GraphML importer.
2093
+ * @category Built-in formats
2094
+ */
1697
2095
  export const graphmlImporter = Object.freeze({
1698
2096
  format: FORMAT,
2097
+ options: Object.freeze(["yfiles"]),
1699
2098
  extensions: EXTENSIONS,
1700
2099
  mimeTypes: MIME_TYPES,
1701
2100
  sniff: sniffGraphml,
1702
2101
  import: importGraphml,
1703
2102
  });
2103
+ /** The elements GraphML defines, for telling a misplaced one from a foreign one. */
2104
+ const GRAPHML_ELEMENTS = new Set([
2105
+ "graphml",
2106
+ "key",
2107
+ "default",
2108
+ "graph",
2109
+ "node",
2110
+ "edge",
2111
+ "hyperedge",
2112
+ "endpoint",
2113
+ "port",
2114
+ "data",
2115
+ "desc",
2116
+ "locator",
2117
+ ]);
2118
+ /**
2119
+ * The message of an element skipped where it stands.
2120
+ * @param name - the element name
2121
+ * @returns a message that says where a GraphML element belongs, or that a foreign one is not GraphML
2122
+ */
2123
+ function unknownElementMessage(name) {
2124
+ if (name === "key") {
2125
+ return "element <key> is only allowed as a child of <graphml>, before the first <graph>; it was skipped";
2126
+ }
2127
+ return GRAPHML_ELEMENTS.has(name)
2128
+ ? `element <${name}> is not allowed at this place in a GraphML file and was skipped`
2129
+ : `element <${name}> is not GraphML and was skipped`;
2130
+ }
1704
2131
  //# sourceMappingURL=importer.js.map