@graphty/graph-io 0.3.25 → 0.3.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/README.md +49 -414
  2. package/dist/chunks/children-CL3Cy0ez.js.map +1 -1
  3. package/dist/chunks/choose-DrXtu_96.js +56 -0
  4. package/dist/chunks/choose-DrXtu_96.js.map +1 -0
  5. package/dist/chunks/constants-ikG85dT8.js +231 -0
  6. package/dist/chunks/constants-ikG85dT8.js.map +1 -0
  7. package/dist/chunks/{escape-B-tkk_Cl.js → escape-D1HPTUrP.js} +390 -99
  8. package/dist/chunks/escape-D1HPTUrP.js.map +1 -0
  9. package/dist/chunks/export-CHd4tQE2.js +4333 -0
  10. package/dist/chunks/export-CHd4tQE2.js.map +1 -0
  11. package/dist/chunks/{importer-eUREhBGj.js → exporter-D23CKNqF.js} +4969 -3201
  12. package/dist/chunks/exporter-D23CKNqF.js.map +1 -0
  13. package/dist/chunks/{exporter-DIeGJXAZ.js → exporter-DfWTgrti.js} +23 -21
  14. package/dist/chunks/exporter-DfWTgrti.js.map +1 -0
  15. package/dist/chunks/exporter-DhtW6FxK.js +3465 -0
  16. package/dist/chunks/exporter-DhtW6FxK.js.map +1 -0
  17. package/dist/chunks/{exporter-BGrsWamJ.js → exporter-IHv4nkCm.js} +38 -229
  18. package/dist/chunks/exporter-IHv4nkCm.js.map +1 -0
  19. package/dist/chunks/{importer-BWY2FFc5.js → importer-B1wmPQjr.js} +255 -77
  20. package/dist/chunks/importer-B1wmPQjr.js.map +1 -0
  21. package/dist/chunks/{importer-D_e7e7LX.js → importer-B2W_58pz.js} +399 -146
  22. package/dist/chunks/importer-B2W_58pz.js.map +1 -0
  23. package/dist/chunks/importer-BSALvkui.js +2811 -0
  24. package/dist/chunks/importer-BSALvkui.js.map +1 -0
  25. package/dist/chunks/{importer-vi3bSdtw.js → importer-BVRE--Un.js} +510 -77
  26. package/dist/chunks/importer-BVRE--Un.js.map +1 -0
  27. package/dist/chunks/{importer-DET1tg6s.js → importer-CIAzt-wo.js} +1689 -312
  28. package/dist/chunks/importer-CIAzt-wo.js.map +1 -0
  29. package/dist/chunks/{importer-DIrbbnAf.js → importer-DpEW5zeG.js} +585 -226
  30. package/dist/chunks/importer-DpEW5zeG.js.map +1 -0
  31. package/dist/chunks/{importer-zGLo8Dg_.js → importer-z_FL4VMb.js} +488 -161
  32. package/dist/chunks/importer-z_FL4VMb.js.map +1 -0
  33. package/dist/chunks/json-elements-BAmNBZok.js +1225 -0
  34. package/dist/chunks/json-elements-BAmNBZok.js.map +1 -0
  35. package/dist/chunks/ontology-export-Bab4eUA8.js +357 -0
  36. package/dist/chunks/ontology-export-Bab4eUA8.js.map +1 -0
  37. package/dist/chunks/{records-dbRkxwaq.js → records-CdlvL4RO.js} +298 -114
  38. package/dist/chunks/records-CdlvL4RO.js.map +1 -0
  39. package/dist/chunks/{text-Dr0Ifpag.js → text-DzXjAiTl.js} +29 -11
  40. package/dist/chunks/text-DzXjAiTl.js.map +1 -0
  41. package/dist/chunks/{writer-C7flM-Ih.js → writer-DxjgHwSe.js} +19 -1
  42. package/dist/chunks/writer-DxjgHwSe.js.map +1 -0
  43. package/dist/csv.js +952 -262
  44. package/dist/csv.js.map +1 -1
  45. package/dist/cx.js +6 -3
  46. package/dist/cx2.js +2 -2
  47. package/dist/cys.js +6 -3
  48. package/dist/dot.js +1 -1
  49. package/dist/gexf.js +554 -122
  50. package/dist/gexf.js.map +1 -1
  51. package/dist/gml.js +344 -87
  52. package/dist/gml.js.map +1 -1
  53. package/dist/graph-io.js +1105 -213
  54. package/dist/graph-io.js.map +1 -1
  55. package/dist/graphml.js +3 -2
  56. package/dist/graphml.js.map +1 -1
  57. package/dist/json.js +3 -2
  58. package/dist/neo4j.js +565 -158
  59. package/dist/neo4j.js.map +1 -1
  60. package/dist/obo.js +6 -3
  61. package/dist/pajek.js +1 -1
  62. package/dist/src/children.d.ts +18 -6
  63. package/dist/src/children.d.ts.map +1 -1
  64. package/dist/src/children.js +6 -3
  65. package/dist/src/children.js.map +1 -1
  66. package/dist/src/common/attributes.d.ts +29 -11
  67. package/dist/src/common/attributes.d.ts.map +1 -1
  68. package/dist/src/common/attributes.js +25 -7
  69. package/dist/src/common/attributes.js.map +1 -1
  70. package/dist/src/common/cell-budget.d.ts +9 -2
  71. package/dist/src/common/cell-budget.d.ts.map +1 -1
  72. package/dist/src/common/cell-budget.js +11 -3
  73. package/dist/src/common/cell-budget.js.map +1 -1
  74. package/dist/src/common/choose.d.ts +19 -0
  75. package/dist/src/common/choose.d.ts.map +1 -0
  76. package/dist/src/common/choose.js +72 -0
  77. package/dist/src/common/choose.js.map +1 -0
  78. package/dist/src/common/codes.d.ts +456 -66
  79. package/dist/src/common/codes.d.ts.map +1 -1
  80. package/dist/src/common/codes.js +458 -66
  81. package/dist/src/common/codes.js.map +1 -1
  82. package/dist/src/common/compare.d.ts +81 -0
  83. package/dist/src/common/compare.d.ts.map +1 -0
  84. package/dist/src/common/compare.js +394 -0
  85. package/dist/src/common/compare.js.map +1 -0
  86. package/dist/src/common/cx-export.d.ts +123 -0
  87. package/dist/src/common/cx-export.d.ts.map +1 -0
  88. package/dist/src/common/cx-export.js +334 -0
  89. package/dist/src/common/cx-export.js.map +1 -0
  90. package/dist/src/common/declared-types.d.ts +22 -2
  91. package/dist/src/common/declared-types.d.ts.map +1 -1
  92. package/dist/src/common/declared-types.js +21 -3
  93. package/dist/src/common/declared-types.js.map +1 -1
  94. package/dist/src/common/direction.d.ts +74 -50
  95. package/dist/src/common/direction.d.ts.map +1 -1
  96. package/dist/src/common/direction.js +47 -27
  97. package/dist/src/common/direction.js.map +1 -1
  98. package/dist/src/common/escape.d.ts +21 -9
  99. package/dist/src/common/escape.d.ts.map +1 -1
  100. package/dist/src/common/escape.js +39 -22
  101. package/dist/src/common/escape.js.map +1 -1
  102. package/dist/src/common/export.d.ts +144 -32
  103. package/dist/src/common/export.d.ts.map +1 -1
  104. package/dist/src/common/export.js +216 -42
  105. package/dist/src/common/export.js.map +1 -1
  106. package/dist/src/common/format.d.ts +23 -1
  107. package/dist/src/common/format.d.ts.map +1 -1
  108. package/dist/src/common/format.js +26 -1
  109. package/dist/src/common/format.js.map +1 -1
  110. package/dist/src/common/ids.d.ts +9 -2
  111. package/dist/src/common/ids.d.ts.map +1 -1
  112. package/dist/src/common/ids.js +6 -2
  113. package/dist/src/common/ids.js.map +1 -1
  114. package/dist/src/common/input.d.ts +122 -28
  115. package/dist/src/common/input.d.ts.map +1 -1
  116. package/dist/src/common/input.js +890 -124
  117. package/dist/src/common/input.js.map +1 -1
  118. package/dist/src/common/json-elements.d.ts +144 -20
  119. package/dist/src/common/json-elements.d.ts.map +1 -1
  120. package/dist/src/common/json-elements.js +869 -189
  121. package/dist/src/common/json-elements.js.map +1 -1
  122. package/dist/src/common/line-format.d.ts +90 -0
  123. package/dist/src/common/line-format.d.ts.map +1 -0
  124. package/dist/src/common/line-format.js +185 -0
  125. package/dist/src/common/line-format.js.map +1 -0
  126. package/dist/src/common/lists.d.ts +6 -1
  127. package/dist/src/common/lists.d.ts.map +1 -1
  128. package/dist/src/common/lists.js +3 -1
  129. package/dist/src/common/lists.js.map +1 -1
  130. package/dist/src/common/ontology-export.d.ts +167 -0
  131. package/dist/src/common/ontology-export.d.ts.map +1 -0
  132. package/dist/src/common/ontology-export.js +359 -0
  133. package/dist/src/common/ontology-export.js.map +1 -0
  134. package/dist/src/common/ontology.d.ts +25 -3
  135. package/dist/src/common/ontology.d.ts.map +1 -1
  136. package/dist/src/common/ontology.js +30 -9
  137. package/dist/src/common/ontology.js.map +1 -1
  138. package/dist/src/common/options.d.ts +62 -12
  139. package/dist/src/common/options.d.ts.map +1 -1
  140. package/dist/src/common/options.js +89 -11
  141. package/dist/src/common/options.js.map +1 -1
  142. package/dist/src/common/plural.d.ts +31 -0
  143. package/dist/src/common/plural.d.ts.map +1 -0
  144. package/dist/src/common/plural.js +46 -0
  145. package/dist/src/common/plural.js.map +1 -0
  146. package/dist/src/common/report.d.ts +72 -14
  147. package/dist/src/common/report.d.ts.map +1 -1
  148. package/dist/src/common/report.js +146 -22
  149. package/dist/src/common/report.js.map +1 -1
  150. package/dist/src/common/temporal.d.ts +22 -5
  151. package/dist/src/common/temporal.d.ts.map +1 -1
  152. package/dist/src/common/temporal.js +13 -2
  153. package/dist/src/common/temporal.js.map +1 -1
  154. package/dist/src/common/text.d.ts +39 -23
  155. package/dist/src/common/text.d.ts.map +1 -1
  156. package/dist/src/common/text.js +51 -21
  157. package/dist/src/common/text.js.map +1 -1
  158. package/dist/src/common/weights.d.ts +37 -4
  159. package/dist/src/common/weights.d.ts.map +1 -1
  160. package/dist/src/common/weights.js +61 -2
  161. package/dist/src/common/weights.js.map +1 -1
  162. package/dist/src/common/writer.d.ts +19 -3
  163. package/dist/src/common/writer.d.ts.map +1 -1
  164. package/dist/src/common/writer.js +30 -2
  165. package/dist/src/common/writer.js.map +1 -1
  166. package/dist/src/common/xml.d.ts +125 -9
  167. package/dist/src/common/xml.d.ts.map +1 -1
  168. package/dist/src/common/xml.js +402 -85
  169. package/dist/src/common/xml.js.map +1 -1
  170. package/dist/src/common/zip.d.ts +44 -4
  171. package/dist/src/common/zip.d.ts.map +1 -1
  172. package/dist/src/common/zip.js +134 -5
  173. package/dist/src/common/zip.js.map +1 -1
  174. package/dist/src/formats/csv/exporter.d.ts +80 -24
  175. package/dist/src/formats/csv/exporter.d.ts.map +1 -1
  176. package/dist/src/formats/csv/exporter.js +146 -33
  177. package/dist/src/formats/csv/exporter.js.map +1 -1
  178. package/dist/src/formats/csv/header.d.ts +38 -9
  179. package/dist/src/formats/csv/header.d.ts.map +1 -1
  180. package/dist/src/formats/csv/header.js +46 -10
  181. package/dist/src/formats/csv/header.js.map +1 -1
  182. package/dist/src/formats/csv/importer.d.ts +187 -37
  183. package/dist/src/formats/csv/importer.d.ts.map +1 -1
  184. package/dist/src/formats/csv/importer.js +835 -204
  185. package/dist/src/formats/csv/importer.js.map +1 -1
  186. package/dist/src/formats/csv/index.d.ts +100 -19
  187. package/dist/src/formats/csv/index.d.ts.map +1 -1
  188. package/dist/src/formats/csv/index.js +94 -21
  189. package/dist/src/formats/csv/index.js.map +1 -1
  190. package/dist/src/formats/csv/records.d.ts +95 -10
  191. package/dist/src/formats/csv/records.d.ts.map +1 -1
  192. package/dist/src/formats/csv/records.js +333 -122
  193. package/dist/src/formats/csv/records.js.map +1 -1
  194. package/dist/src/formats/csv/values.d.ts +1 -0
  195. package/dist/src/formats/csv/values.d.ts.map +1 -1
  196. package/dist/src/formats/csv/values.js +1 -0
  197. package/dist/src/formats/csv/values.js.map +1 -1
  198. package/dist/src/formats/cx/exporter.d.ts +102 -0
  199. package/dist/src/formats/cx/exporter.d.ts.map +1 -0
  200. package/dist/src/formats/cx/exporter.js +1217 -0
  201. package/dist/src/formats/cx/exporter.js.map +1 -0
  202. package/dist/src/formats/cx/importer.d.ts +79 -32
  203. package/dist/src/formats/cx/importer.d.ts.map +1 -1
  204. package/dist/src/formats/cx/importer.js +682 -287
  205. package/dist/src/formats/cx/importer.js.map +1 -1
  206. package/dist/src/formats/cx/index.d.ts +4 -3
  207. package/dist/src/formats/cx/index.d.ts.map +1 -1
  208. package/dist/src/formats/cx/index.js +4 -3
  209. package/dist/src/formats/cx/index.js.map +1 -1
  210. package/dist/src/formats/cx2/exporter.d.ts +29 -11
  211. package/dist/src/formats/cx2/exporter.d.ts.map +1 -1
  212. package/dist/src/formats/cx2/exporter.js +39 -268
  213. package/dist/src/formats/cx2/exporter.js.map +1 -1
  214. package/dist/src/formats/cx2/importer.d.ts +78 -28
  215. package/dist/src/formats/cx2/importer.d.ts.map +1 -1
  216. package/dist/src/formats/cx2/importer.js +227 -80
  217. package/dist/src/formats/cx2/importer.js.map +1 -1
  218. package/dist/src/formats/cx2/index.d.ts +2 -1
  219. package/dist/src/formats/cx2/index.d.ts.map +1 -1
  220. package/dist/src/formats/cx2/index.js +2 -1
  221. package/dist/src/formats/cx2/index.js.map +1 -1
  222. package/dist/src/formats/cys/constants.d.ts +66 -17
  223. package/dist/src/formats/cys/constants.d.ts.map +1 -1
  224. package/dist/src/formats/cys/constants.js +59 -18
  225. package/dist/src/formats/cys/constants.js.map +1 -1
  226. package/dist/src/formats/cys/exporter.d.ts +118 -0
  227. package/dist/src/formats/cys/exporter.d.ts.map +1 -0
  228. package/dist/src/formats/cys/exporter.js +1072 -0
  229. package/dist/src/formats/cys/exporter.js.map +1 -0
  230. package/dist/src/formats/cys/importer.d.ts +22 -8
  231. package/dist/src/formats/cys/importer.d.ts.map +1 -1
  232. package/dist/src/formats/cys/importer.js +510 -149
  233. package/dist/src/formats/cys/importer.js.map +1 -1
  234. package/dist/src/formats/cys/index.d.ts +4 -2
  235. package/dist/src/formats/cys/index.d.ts.map +1 -1
  236. package/dist/src/formats/cys/index.js +4 -2
  237. package/dist/src/formats/cys/index.js.map +1 -1
  238. package/dist/src/formats/cys/session.d.ts +46 -7
  239. package/dist/src/formats/cys/session.d.ts.map +1 -1
  240. package/dist/src/formats/cys/session.js +101 -27
  241. package/dist/src/formats/cys/session.js.map +1 -1
  242. package/dist/src/formats/cys/tables.d.ts +9 -2
  243. package/dist/src/formats/cys/tables.d.ts.map +1 -1
  244. package/dist/src/formats/cys/tables.js +29 -7
  245. package/dist/src/formats/cys/tables.js.map +1 -1
  246. package/dist/src/formats/dot/exporter.d.ts +42 -14
  247. package/dist/src/formats/dot/exporter.d.ts.map +1 -1
  248. package/dist/src/formats/dot/exporter.js +56 -29
  249. package/dist/src/formats/dot/exporter.js.map +1 -1
  250. package/dist/src/formats/dot/importer.d.ts +91 -29
  251. package/dist/src/formats/dot/importer.d.ts.map +1 -1
  252. package/dist/src/formats/dot/importer.js +190 -39
  253. package/dist/src/formats/dot/importer.js.map +1 -1
  254. package/dist/src/formats/dot/index.d.ts +2 -1
  255. package/dist/src/formats/dot/index.d.ts.map +1 -1
  256. package/dist/src/formats/dot/index.js +2 -1
  257. package/dist/src/formats/dot/index.js.map +1 -1
  258. package/dist/src/formats/dot/names.d.ts +44 -11
  259. package/dist/src/formats/dot/names.d.ts.map +1 -1
  260. package/dist/src/formats/dot/names.js +44 -11
  261. package/dist/src/formats/dot/names.js.map +1 -1
  262. package/dist/src/formats/dot/tokenizer.d.ts +9 -2
  263. package/dist/src/formats/dot/tokenizer.d.ts.map +1 -1
  264. package/dist/src/formats/dot/tokenizer.js +20 -5
  265. package/dist/src/formats/dot/tokenizer.js.map +1 -1
  266. package/dist/src/formats/gexf/exporter.d.ts +46 -15
  267. package/dist/src/formats/gexf/exporter.d.ts.map +1 -1
  268. package/dist/src/formats/gexf/exporter.js +45 -15
  269. package/dist/src/formats/gexf/exporter.js.map +1 -1
  270. package/dist/src/formats/gexf/importer.d.ts +87 -23
  271. package/dist/src/formats/gexf/importer.d.ts.map +1 -1
  272. package/dist/src/formats/gexf/importer.js +471 -90
  273. package/dist/src/formats/gexf/importer.js.map +1 -1
  274. package/dist/src/formats/gexf/index.d.ts +84 -21
  275. package/dist/src/formats/gexf/index.d.ts.map +1 -1
  276. package/dist/src/formats/gexf/index.js +80 -23
  277. package/dist/src/formats/gexf/index.js.map +1 -1
  278. package/dist/src/formats/gexf/schema.d.ts +67 -15
  279. package/dist/src/formats/gexf/schema.d.ts.map +1 -1
  280. package/dist/src/formats/gexf/schema.js +59 -13
  281. package/dist/src/formats/gexf/schema.js.map +1 -1
  282. package/dist/src/formats/gml/exporter.d.ts +69 -21
  283. package/dist/src/formats/gml/exporter.d.ts.map +1 -1
  284. package/dist/src/formats/gml/exporter.js +74 -29
  285. package/dist/src/formats/gml/exporter.js.map +1 -1
  286. package/dist/src/formats/gml/importer.d.ts +116 -25
  287. package/dist/src/formats/gml/importer.d.ts.map +1 -1
  288. package/dist/src/formats/gml/importer.js +290 -61
  289. package/dist/src/formats/gml/importer.js.map +1 -1
  290. package/dist/src/formats/gml/index.d.ts +87 -24
  291. package/dist/src/formats/gml/index.d.ts.map +1 -1
  292. package/dist/src/formats/gml/index.js +79 -26
  293. package/dist/src/formats/gml/index.js.map +1 -1
  294. package/dist/src/formats/gml/syntax.d.ts +67 -18
  295. package/dist/src/formats/gml/syntax.d.ts.map +1 -1
  296. package/dist/src/formats/gml/syntax.js +110 -28
  297. package/dist/src/formats/gml/syntax.js.map +1 -1
  298. package/dist/src/formats/graphml/constants.d.ts +174 -44
  299. package/dist/src/formats/graphml/constants.d.ts.map +1 -1
  300. package/dist/src/formats/graphml/constants.js +165 -44
  301. package/dist/src/formats/graphml/constants.js.map +1 -1
  302. package/dist/src/formats/graphml/exporter.d.ts +17 -9
  303. package/dist/src/formats/graphml/exporter.d.ts.map +1 -1
  304. package/dist/src/formats/graphml/exporter.js +33 -12
  305. package/dist/src/formats/graphml/exporter.js.map +1 -1
  306. package/dist/src/formats/graphml/importer.d.ts +19 -7
  307. package/dist/src/formats/graphml/importer.d.ts.map +1 -1
  308. package/dist/src/formats/graphml/importer.js +466 -39
  309. package/dist/src/formats/graphml/importer.js.map +1 -1
  310. package/dist/src/formats/graphml/index.d.ts +2 -1
  311. package/dist/src/formats/graphml/index.d.ts.map +1 -1
  312. package/dist/src/formats/graphml/index.js +2 -1
  313. package/dist/src/formats/graphml/index.js.map +1 -1
  314. package/dist/src/formats/graphml/tree.d.ts +6 -2
  315. package/dist/src/formats/graphml/tree.d.ts.map +1 -1
  316. package/dist/src/formats/graphml/tree.js +6 -2
  317. package/dist/src/formats/graphml/tree.js.map +1 -1
  318. package/dist/src/formats/graphml/yfiles.d.ts +8 -3
  319. package/dist/src/formats/graphml/yfiles.d.ts.map +1 -1
  320. package/dist/src/formats/graphml/yfiles.js +36 -15
  321. package/dist/src/formats/graphml/yfiles.js.map +1 -1
  322. package/dist/src/formats/json/dialect.d.ts +88 -24
  323. package/dist/src/formats/json/dialect.d.ts.map +1 -1
  324. package/dist/src/formats/json/dialect.js +109 -19
  325. package/dist/src/formats/json/dialect.js.map +1 -1
  326. package/dist/src/formats/json/exporter.d.ts +134 -22
  327. package/dist/src/formats/json/exporter.d.ts.map +1 -1
  328. package/dist/src/formats/json/exporter.js +135 -54
  329. package/dist/src/formats/json/exporter.js.map +1 -1
  330. package/dist/src/formats/json/importer.d.ts +173 -52
  331. package/dist/src/formats/json/importer.d.ts.map +1 -1
  332. package/dist/src/formats/json/importer.js +899 -220
  333. package/dist/src/formats/json/importer.js.map +1 -1
  334. package/dist/src/formats/json/index.d.ts +3 -2
  335. package/dist/src/formats/json/index.d.ts.map +1 -1
  336. package/dist/src/formats/json/index.js +3 -2
  337. package/dist/src/formats/json/index.js.map +1 -1
  338. package/dist/src/formats/json/obographs-export.d.ts +68 -0
  339. package/dist/src/formats/json/obographs-export.d.ts.map +1 -0
  340. package/dist/src/formats/json/obographs-export.js +941 -0
  341. package/dist/src/formats/json/obographs-export.js.map +1 -0
  342. package/dist/src/formats/json/obographs.d.ts +26 -0
  343. package/dist/src/formats/json/obographs.d.ts.map +1 -1
  344. package/dist/src/formats/json/obographs.js +297 -80
  345. package/dist/src/formats/json/obographs.js.map +1 -1
  346. package/dist/src/formats/neo4j/exporter.d.ts +109 -21
  347. package/dist/src/formats/neo4j/exporter.d.ts.map +1 -1
  348. package/dist/src/formats/neo4j/exporter.js +239 -86
  349. package/dist/src/formats/neo4j/exporter.js.map +1 -1
  350. package/dist/src/formats/neo4j/header.d.ts +17 -4
  351. package/dist/src/formats/neo4j/header.d.ts.map +1 -1
  352. package/dist/src/formats/neo4j/header.js +36 -4
  353. package/dist/src/formats/neo4j/header.js.map +1 -1
  354. package/dist/src/formats/neo4j/importer.d.ts +107 -27
  355. package/dist/src/formats/neo4j/importer.d.ts.map +1 -1
  356. package/dist/src/formats/neo4j/importer.js +415 -63
  357. package/dist/src/formats/neo4j/importer.js.map +1 -1
  358. package/dist/src/formats/neo4j/index.d.ts +73 -23
  359. package/dist/src/formats/neo4j/index.d.ts.map +1 -1
  360. package/dist/src/formats/neo4j/index.js +65 -25
  361. package/dist/src/formats/neo4j/index.js.map +1 -1
  362. package/dist/src/formats/obo/exporter.d.ts +150 -0
  363. package/dist/src/formats/obo/exporter.d.ts.map +1 -0
  364. package/dist/src/formats/obo/exporter.js +1736 -0
  365. package/dist/src/formats/obo/exporter.js.map +1 -0
  366. package/dist/src/formats/obo/importer.d.ts +95 -19
  367. package/dist/src/formats/obo/importer.d.ts.map +1 -1
  368. package/dist/src/formats/obo/importer.js +475 -104
  369. package/dist/src/formats/obo/importer.js.map +1 -1
  370. package/dist/src/formats/obo/index.d.ts +6 -3
  371. package/dist/src/formats/obo/index.d.ts.map +1 -1
  372. package/dist/src/formats/obo/index.js +6 -3
  373. package/dist/src/formats/obo/index.js.map +1 -1
  374. package/dist/src/formats/obo/syntax.d.ts +108 -4
  375. package/dist/src/formats/obo/syntax.d.ts.map +1 -1
  376. package/dist/src/formats/obo/syntax.js +211 -34
  377. package/dist/src/formats/obo/syntax.js.map +1 -1
  378. package/dist/src/formats/pajek/exporter.d.ts +54 -16
  379. package/dist/src/formats/pajek/exporter.d.ts.map +1 -1
  380. package/dist/src/formats/pajek/exporter.js +67 -35
  381. package/dist/src/formats/pajek/exporter.js.map +1 -1
  382. package/dist/src/formats/pajek/importer.d.ts +84 -22
  383. package/dist/src/formats/pajek/importer.d.ts.map +1 -1
  384. package/dist/src/formats/pajek/importer.js +303 -83
  385. package/dist/src/formats/pajek/importer.js.map +1 -1
  386. package/dist/src/formats/pajek/index.d.ts +2 -1
  387. package/dist/src/formats/pajek/index.d.ts.map +1 -1
  388. package/dist/src/formats/pajek/index.js +2 -1
  389. package/dist/src/formats/pajek/index.js.map +1 -1
  390. package/dist/src/formats/pajek/syntax.d.ts +77 -14
  391. package/dist/src/formats/pajek/syntax.d.ts.map +1 -1
  392. package/dist/src/formats/pajek/syntax.js +186 -54
  393. package/dist/src/formats/pajek/syntax.js.map +1 -1
  394. package/dist/src/formats/xgmml/columns.d.ts +1 -0
  395. package/dist/src/formats/xgmml/columns.d.ts.map +1 -1
  396. package/dist/src/formats/xgmml/columns.js +4 -0
  397. package/dist/src/formats/xgmml/columns.js.map +1 -1
  398. package/dist/src/formats/xgmml/constants.d.ts +186 -56
  399. package/dist/src/formats/xgmml/constants.d.ts.map +1 -1
  400. package/dist/src/formats/xgmml/constants.js +181 -57
  401. package/dist/src/formats/xgmml/constants.js.map +1 -1
  402. package/dist/src/formats/xgmml/document.d.ts +65 -11
  403. package/dist/src/formats/xgmml/document.d.ts.map +1 -1
  404. package/dist/src/formats/xgmml/document.js +157 -28
  405. package/dist/src/formats/xgmml/document.js.map +1 -1
  406. package/dist/src/formats/xgmml/emit.d.ts +61 -3
  407. package/dist/src/formats/xgmml/emit.d.ts.map +1 -1
  408. package/dist/src/formats/xgmml/emit.js +129 -26
  409. package/dist/src/formats/xgmml/emit.js.map +1 -1
  410. package/dist/src/formats/xgmml/exporter.d.ts +13 -6
  411. package/dist/src/formats/xgmml/exporter.d.ts.map +1 -1
  412. package/dist/src/formats/xgmml/exporter.js +21 -22
  413. package/dist/src/formats/xgmml/exporter.js.map +1 -1
  414. package/dist/src/formats/xgmml/importer.d.ts +33 -12
  415. package/dist/src/formats/xgmml/importer.d.ts.map +1 -1
  416. package/dist/src/formats/xgmml/importer.js +35 -72
  417. package/dist/src/formats/xgmml/importer.js.map +1 -1
  418. package/dist/src/formats/xgmml/index.d.ts +1 -0
  419. package/dist/src/formats/xgmml/index.d.ts.map +1 -1
  420. package/dist/src/formats/xgmml/index.js +1 -0
  421. package/dist/src/formats/xgmml/index.js.map +1 -1
  422. package/dist/src/formats/xgmml/values.d.ts +8 -1
  423. package/dist/src/formats/xgmml/values.d.ts.map +1 -1
  424. package/dist/src/formats/xgmml/values.js +8 -3
  425. package/dist/src/formats/xgmml/values.js.map +1 -1
  426. package/dist/src/index.d.ts +23 -18
  427. package/dist/src/index.d.ts.map +1 -1
  428. package/dist/src/index.js +28 -16
  429. package/dist/src/index.js.map +1 -1
  430. package/dist/src/registry.d.ts +478 -92
  431. package/dist/src/registry.d.ts.map +1 -1
  432. package/dist/src/registry.js +807 -88
  433. package/dist/src/registry.js.map +1 -1
  434. package/dist/src/sniff.d.ts +61 -19
  435. package/dist/src/sniff.d.ts.map +1 -1
  436. package/dist/src/sniff.js +121 -29
  437. package/dist/src/sniff.js.map +1 -1
  438. package/dist/src/types.d.ts +362 -112
  439. package/dist/src/types.d.ts.map +1 -1
  440. package/dist/src/types.js +28 -7
  441. package/dist/src/types.js.map +1 -1
  442. package/dist/xgmml.js +2 -2
  443. package/docs/samples/README.md +25 -0
  444. package/docs/samples/got-edges.csv +353 -0
  445. package/docs/samples/got-network.graphml +1384 -0
  446. package/docs/samples/got-nodes.csv +108 -0
  447. package/docs/samples/got.cx +930 -0
  448. package/docs/samples/got.cx2 +465 -0
  449. package/docs/samples/got.gexf +471 -0
  450. package/docs/samples/got.gml +2650 -0
  451. package/docs/samples/got.json +2546 -0
  452. package/docs/samples/got.net +461 -0
  453. package/docs/samples/movies-nodes.csv +9 -0
  454. package/docs/samples/movies-rels.csv +8 -0
  455. package/docs/samples/networks.cys +0 -0
  456. package/docs/samples/proteins.xgmml +9 -0
  457. package/docs/samples/teams.gv +24 -0
  458. package/docs/samples/vehicles.obo +25 -0
  459. package/package.json +9 -4
  460. package/src/children.ts +18 -6
  461. package/src/common/attributes.ts +29 -11
  462. package/src/common/cell-budget.ts +11 -3
  463. package/src/common/choose.ts +89 -0
  464. package/src/common/codes.ts +490 -66
  465. package/src/common/compare.ts +472 -0
  466. package/src/common/cx-export.ts +432 -0
  467. package/src/common/declared-types.ts +40 -6
  468. package/src/common/direction.ts +78 -51
  469. package/src/common/escape.ts +39 -22
  470. package/src/common/export.ts +284 -47
  471. package/src/common/format.ts +30 -1
  472. package/src/common/ids.ts +14 -3
  473. package/src/common/input.ts +1057 -134
  474. package/src/common/json-elements.ts +1035 -199
  475. package/src/common/line-format.ts +249 -0
  476. package/src/common/lists.ts +7 -2
  477. package/src/common/ontology-export.ts +461 -0
  478. package/src/common/ontology.ts +31 -9
  479. package/src/common/options.ts +110 -15
  480. package/src/common/plural.ts +49 -0
  481. package/src/common/report.ts +168 -25
  482. package/src/common/temporal.ts +22 -5
  483. package/src/common/text.ts +62 -23
  484. package/src/common/weights.ts +74 -4
  485. package/src/common/writer.ts +37 -3
  486. package/src/common/xml.ts +479 -90
  487. package/src/common/zip.ts +169 -7
  488. package/src/formats/csv/exporter.ts +202 -47
  489. package/src/formats/csv/header.ts +50 -11
  490. package/src/formats/csv/importer.ts +1133 -245
  491. package/src/formats/csv/index.ts +106 -19
  492. package/src/formats/csv/records.ts +396 -122
  493. package/src/formats/csv/values.ts +1 -0
  494. package/src/formats/cx/exporter.ts +1483 -0
  495. package/src/formats/cx/importer.ts +890 -302
  496. package/src/formats/cx/index.ts +4 -3
  497. package/src/formats/cx2/exporter.ts +62 -339
  498. package/src/formats/cx2/importer.ts +318 -87
  499. package/src/formats/cx2/index.ts +2 -1
  500. package/src/formats/cys/constants.ts +62 -17
  501. package/src/formats/cys/exporter.ts +1368 -0
  502. package/src/formats/cys/importer.ts +659 -157
  503. package/src/formats/cys/index.ts +4 -2
  504. package/src/formats/cys/session.ts +142 -34
  505. package/src/formats/cys/tables.ts +47 -9
  506. package/src/formats/dot/exporter.ts +83 -37
  507. package/src/formats/dot/importer.ts +248 -54
  508. package/src/formats/dot/index.ts +2 -1
  509. package/src/formats/dot/names.ts +44 -11
  510. package/src/formats/dot/tokenizer.ts +25 -6
  511. package/src/formats/gexf/exporter.ts +57 -18
  512. package/src/formats/gexf/importer.ts +636 -105
  513. package/src/formats/gexf/index.ts +90 -21
  514. package/src/formats/gexf/schema.ts +67 -15
  515. package/src/formats/gml/exporter.ts +90 -36
  516. package/src/formats/gml/importer.ts +388 -67
  517. package/src/formats/gml/index.ts +85 -24
  518. package/src/formats/gml/syntax.ts +113 -28
  519. package/src/formats/graphml/constants.ts +178 -44
  520. package/src/formats/graphml/exporter.ts +52 -18
  521. package/src/formats/graphml/importer.ts +640 -60
  522. package/src/formats/graphml/index.ts +2 -1
  523. package/src/formats/graphml/tree.ts +6 -2
  524. package/src/formats/graphml/yfiles.ts +37 -15
  525. package/src/formats/json/dialect.ts +128 -29
  526. package/src/formats/json/exporter.ts +205 -68
  527. package/src/formats/json/importer.ts +1163 -253
  528. package/src/formats/json/index.ts +3 -1
  529. package/src/formats/json/obographs-export.ts +1197 -0
  530. package/src/formats/json/obographs.ts +353 -92
  531. package/src/formats/neo4j/exporter.ts +321 -102
  532. package/src/formats/neo4j/header.ts +44 -6
  533. package/src/formats/neo4j/importer.ts +512 -73
  534. package/src/formats/neo4j/index.ts +75 -23
  535. package/src/formats/obo/exporter.ts +2210 -0
  536. package/src/formats/obo/importer.ts +622 -109
  537. package/src/formats/obo/index.ts +6 -3
  538. package/src/formats/obo/syntax.ts +232 -37
  539. package/src/formats/pajek/exporter.ts +90 -42
  540. package/src/formats/pajek/importer.ts +407 -93
  541. package/src/formats/pajek/index.ts +2 -1
  542. package/src/formats/pajek/syntax.ts +216 -55
  543. package/src/formats/xgmml/columns.ts +10 -0
  544. package/src/formats/xgmml/constants.ts +183 -56
  545. package/src/formats/xgmml/document.ts +212 -34
  546. package/src/formats/xgmml/emit.ts +175 -34
  547. package/src/formats/xgmml/exporter.ts +36 -28
  548. package/src/formats/xgmml/importer.ts +64 -86
  549. package/src/formats/xgmml/index.ts +1 -0
  550. package/src/formats/xgmml/values.ts +12 -4
  551. package/src/index.ts +81 -11
  552. package/src/registry.ts +1121 -135
  553. package/src/sniff.ts +163 -32
  554. package/src/types.ts +385 -114
  555. package/dist/chunks/escape-B-tkk_Cl.js.map +0 -1
  556. package/dist/chunks/export-Bh60Dv-n.js +0 -582
  557. package/dist/chunks/export-Bh60Dv-n.js.map +0 -1
  558. package/dist/chunks/exporter-BGrsWamJ.js.map +0 -1
  559. package/dist/chunks/exporter-DIeGJXAZ.js.map +0 -1
  560. package/dist/chunks/importer-BWY2FFc5.js.map +0 -1
  561. package/dist/chunks/importer-DD-xv9_Y.js +0 -1471
  562. package/dist/chunks/importer-DD-xv9_Y.js.map +0 -1
  563. package/dist/chunks/importer-DET1tg6s.js.map +0 -1
  564. package/dist/chunks/importer-DEcKhsmQ.js +0 -1614
  565. package/dist/chunks/importer-DEcKhsmQ.js.map +0 -1
  566. package/dist/chunks/importer-DIrbbnAf.js.map +0 -1
  567. package/dist/chunks/importer-D_e7e7LX.js.map +0 -1
  568. package/dist/chunks/importer-eUREhBGj.js.map +0 -1
  569. package/dist/chunks/importer-vi3bSdtw.js.map +0 -1
  570. package/dist/chunks/importer-zGLo8Dg_.js.map +0 -1
  571. package/dist/chunks/json-elements-DDS8N2Dd.js +0 -779
  572. package/dist/chunks/json-elements-DDS8N2Dd.js.map +0 -1
  573. package/dist/chunks/ontology-BnrJ4I98.js +0 -113
  574. package/dist/chunks/ontology-BnrJ4I98.js.map +0 -1
  575. package/dist/chunks/records-dbRkxwaq.js.map +0 -1
  576. package/dist/chunks/report-B1z4WT9e.js +0 -2372
  577. package/dist/chunks/report-B1z4WT9e.js.map +0 -1
  578. package/dist/chunks/text-Dr0Ifpag.js.map +0 -1
  579. package/dist/chunks/weights-Dzba96G3.js +0 -176
  580. package/dist/chunks/weights-Dzba96G3.js.map +0 -1
  581. package/dist/chunks/writer-C7flM-Ih.js.map +0 -1
@@ -1,8 +1,7 @@
1
1
  import { INVALID_INDEX, GraphFormatError } from "@graphty/graph-format";
2
- import { 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, I as ID_MERGED_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, A as AMBIGUOUS_GRAPH_NAME_CODE, G as GRAPH_NOT_FOUND_CODE, M as MULTIPLE_GRAPHS_CODE, au as STRAY_TEXT_CODE, Y as UNKNOWN_ELEMENT_CODE, k as UNKNOWN_ATTR_TYPE_CODE, am as EQUATION_AS_TEXT_CODE, h as PARENT_CYCLE_CODE, U as UNKNOWN_PARENT_CODE, i as DUPLICATE_ATTRIBUTE_CODE, j as DANGLING_REFERENCE_CODE, P as PRECISION_CODE, W as WIDENED_CODE, B as BAD_VALUE_CODE, c as DUPLICATE_EDGE_ID_CODE, d as DUPLICATE_NODE_CODE, e as MISSING_ENDPOINT_CODE, f as MISSING_ID_CODE, N as NO_GRAPH_CODE, q as UNKNOWN_ENCODING_CODE, E as ENCODING_FALLBACK_CODE, r as INVALID_ENCODING_CODE, s as INVALID_UTF8_CODE, u as EMPTY_INPUT_CODE, aw as XML_SYNTAX_CODE, a3 as STORAGE_CLASS_CODE, a7 as WEIGHT_KEY_CLASH_CODE, a6 as ROLE_ASSUMED_CODE, a5 as COLUMN_RENAMED_LOSS_CODE, b as ID_TEXT_TYPE_CODE, aa as MUTUAL_EXPANDED_CODE, ab as PARENTS_DROPPED_CODE, ac as ROLE_DROPPED_CODE, ad as TEMPORAL_TEXT_DROPPED_CODE, ae as TEMPORAL_DROPPED_CODE, a0 as XML_ILLEGAL_CHAR_CODE, Q as uniqueColumnName, L as declareResolved, _ as DictHeuristic, K as IdCoercer, J as DirectionResolver, y as throwIfAborted, F as reportSinkOptions, z as reportUnusedOptions, H as chooseGraph, v as resolveImportOptions, w as ImportReportBuilder, x as textChunks } from "./report-B1z4WT9e.js";
3
- import { l as localName, a as escapeXmlText, g as isWhitespace, e as escapeXmlAttribute, t as tokenizeXml, f as xmlDeclaredEncoding, X as XmlSyntaxError } from "./escape-B-tkk_Cl.js";
4
- import { p as parseWeightText } from "./weights-Dzba96G3.js";
5
- import { p as parseTextCell, i as inferTextDtype } from "./text-Dr0Ifpag.js";
2
+ import { 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, I as ID_MERGED_CODE, R as ROLE_TAKEN_CODE, C as COLUMN_RENAMED_CODE, ae as AMBIGUOUS_GRAPH_NAME_CODE, af as GRAPH_NOT_FOUND_CODE, l as MULTIPLE_GRAPHS_CODE, f as STRAY_TEXT_CODE, g as UNKNOWN_ELEMENT_CODE, U as UNKNOWN_ATTR_TYPE_CODE, b7 as EQUATION_AS_TEXT_CODE, ai as PARENT_CYCLE_CODE, q as UNKNOWN_PARENT_CODE, o as DUPLICATE_ATTRIBUTE_CODE, i as DANGLING_REFERENCE_CODE, P as PRECISION_CODE, aj as WIDENED_CODE, a3 as BAD_VALUE_CODE, m as DUPLICATE_EDGE_ID_CODE, n as DUPLICATE_NODE_CODE, s as MISSING_ENDPOINT_CODE, t as MISSING_ID_CODE, N as NO_GRAPH_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, E as EMPTY_INPUT_CODE, X as XML_SYNTAX_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE, bk as STORAGE_CLASS_CODE, bq as WEIGHT_KEY_CLASH_CODE, au as ROLE_ASSUMED_CODE, b0 as COLUMN_RENAMED_LOSS_CODE, J as ID_TEXT_TYPE_CODE, bd as MUTUAL_EXPANDED_CODE, Q as PARENTS_DROPPED_CODE, K as ROLE_DROPPED_CODE, bm as TEMPORAL_TEXT_DROPPED_CODE, bl as TEMPORAL_DROPPED_CODE, ax as XML_ILLEGAL_CHAR_CODE, a0 as uniqueColumnName, a1 as declareResolved, ac as DictHeuristic, ar as IdCoercer, aq as DirectionResolver, b as plural, $ as agree, am as throwIfAborted, aL as parseWeightText, ao as reportSinkOptions, an as reportUnusedOptions, a7 as chooseGraph, ap as graphChosen, al as resolveImportOptions, a8 as ImportReportBuilder, a4 as textChunks, c1 as elementCount } from "./export-CHd4tQE2.js";
3
+ import { l as localName, a as escapeXmlText, j as isWhitespace, e as escapeXmlAttribute, t as tokenizeXml, f as xmlDeclaredEncoding, X as XmlSyntaxError } from "./escape-D1HPTUrP.js";
4
+ import { p as parseTextCell, i as inferTextDtype } from "./text-DzXjAiTl.js";
6
5
  const FORMAT = "xgmml";
7
6
  const EXTENSIONS = Object.freeze([".xgmml", ".xml"]);
8
7
  const MIME_TYPES = Object.freeze(["application/xgmml", "text/xgmml", "text/xgmml+xml"]);
@@ -25,26 +24,41 @@ const INTERACTION_COLUMN = "interaction";
25
24
  const XGMML_ORIGIN_NAMESPACE = "xgmml";
26
25
  const CYTOSCAPE_ORIGIN_NAMESPACE = "cytoscape";
27
26
  const XGMML_ISSUE = Object.freeze({
28
- /** Fatal: the input is not well-formed XML. */
27
+ ...INPUT_ISSUE,
28
+ ...ELEMENT_ISSUE,
29
+ /** The input is not well-formed XML. The import stops. */
29
30
  XML_SYNTAX: XML_SYNTAX_CODE,
30
- /** Fatal: the input is empty or whitespace only. */
31
+ /** The input is empty or whitespace only. The import stops. */
31
32
  EMPTY_INPUT: EMPTY_INPUT_CODE,
32
- /** Fatal: the input holds invalid UTF-8. */
33
+ /** The input is not valid UTF-8. The import stops. */
33
34
  INVALID_UTF8: INVALID_UTF8_CODE,
34
- /** Fatal: bytes invalid in the encoding a BOM, a declaration or the option chose. */
35
+ /**
36
+ * Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
37
+ * `encoding` option). The import stops.
38
+ */
35
39
  INVALID_ENCODING: INVALID_ENCODING_CODE,
36
40
  /** Undeclared non-UTF-8 bytes were read as windows-1252. */
37
41
  ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
38
42
  /** A declared encoding the platform cannot decode was ignored. */
39
43
  UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
40
- /** Fatal: the root element is not `<graph>` (an XHTML page embedding one, a GraphML file). */
44
+ /** A declared encoding the byte order mark contradicts (the mark wins). */
45
+ ENCODING_CONFLICT: ENCODING_CONFLICT_CODE,
46
+ /**
47
+ * The root element is not `<graph>` (it may be an XHTML page with a graph inside, or a GraphML file). The import
48
+ * stops.
49
+ */
41
50
  NO_GRAPH: NO_GRAPH_CODE,
42
- /** Fatal: a session view document (`cy:view="1"`): view SUIDs and no topology. */
51
+ /**
52
+ * The file is a Cytoscape session view (`cy:view="1"`), which holds only view settings and no nodes or edges. The
53
+ * import stops.
54
+ */
43
55
  VIEW_DOCUMENT: "E_XGMML_VIEW_DOCUMENT",
44
56
  /** A node with neither an id nor a label; it is skipped with its subtree. */
45
57
  MISSING_ID: MISSING_ID_CODE,
46
58
  /** A node without an id; its label is used as the id. */
47
59
  ID_FROM_LABEL: "W_XGMML_ID_FROM_LABEL",
60
+ /** A node or edge with both an id and an `xlink:href`; it is read as the reference. */
61
+ ID_AND_HREF: "W_XGMML_ID_AND_HREF",
48
62
  /** An edge without a source or a target that no label alias resolves. */
49
63
  MISSING_ENDPOINT: MISSING_ENDPOINT_CODE,
50
64
  /** An edge endpoint that names no node (addMissingNodes false); the edge is skipped. */
@@ -55,7 +69,10 @@ const XGMML_ISSUE = Object.freeze({
55
69
  DUPLICATE_NODE: DUPLICATE_NODE_CODE,
56
70
  /** An edge id used twice; the second edge is skipped. */
57
71
  DUPLICATE_EDGE_ID: DUPLICATE_EDGE_ID_CODE,
58
- /** A meta-edge the 2.x writer repeats inside a group; the copy is dropped. */
72
+ /**
73
+ * Cytoscape 2.x writes each edge of a group a second time, inside the group. The repeats are dropped, so every edge
74
+ * is read once; nothing is lost.
75
+ */
59
76
  GROUP_DUPLICATE_EDGE: "W_XGMML_GROUP_DUPLICATE_EDGE",
60
77
  /** A `directed` or `cy:directed` value other than 0 / 1. */
61
78
  BAD_DIRECTED: "W_XGMML_BAD_DIRECTED",
@@ -71,19 +88,28 @@ const XGMML_ISSUE = Object.freeze({
71
88
  SURROGATE_PAIRED: "W_XGMML_SURROGATE_PAIRED",
72
89
  /** An empty list whose element type nothing states; a list of strings is assumed. */
73
90
  EMPTY_LIST_TYPE: "W_XGMML_EMPTY_LIST_TYPE",
74
- /** A record list, a list of lists, a 2.x map or foreign XML in an att, kept as json. */
91
+ /**
92
+ * An attribute holds a structure a single column cannot (a list of records, a list of lists, a Cytoscape 2.x map
93
+ * or XML from another tool). Its value is kept as a JSON value, which a save as XGMML writes back.
94
+ */
75
95
  RECORD_LIST: "W_XGMML_RECORD_LIST",
76
96
  /** A pointer into another file (`file.xgmml#id`); kept as text. */
77
97
  CROSS_FILE_REFERENCE: "W_XGMML_CROSS_FILE_REFERENCE",
78
98
  /** A graph nested in an edge's att; there is no model for it. */
79
99
  EDGE_NESTED_GRAPH: "W_XGMML_EDGE_NESTED_GRAPH",
80
- /** Elements of a session network declared outside every registered subnetwork. */
100
+ /**
101
+ * Some nodes or edges of a Cytoscape session belong to none of its networks (Cytoscape keeps group meta-edges and
102
+ * the members of collapsed groups this way). They are not read; the message counts them.
103
+ */
81
104
  ROOT_ONLY_ELEMENTS: "W_XGMML_ROOT_ONLY_ELEMENTS",
82
105
  /** A value that does not parse as its declared type; the cell is unset. */
83
106
  BAD_VALUE: BAD_VALUE_CODE,
84
- /** A column widened because its values or declared types disagree. */
107
+ /**
108
+ * An attribute's type was widened because a later value did not fit: an integer above 2^31 in an integer column,
109
+ * or two declared types for one attribute.
110
+ */
85
111
  WIDENED: WIDENED_CODE,
86
- /** A long or real beyond what a double holds exactly. */
112
+ /** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
87
113
  PRECISION: PRECISION_CODE,
88
114
  /** A reference (xlink:href, nested-network pointer) that names nothing. */
89
115
  DANGLING_REFERENCE: DANGLING_REFERENCE_CODE,
@@ -101,49 +127,73 @@ const XGMML_ISSUE = Object.freeze({
101
127
  UNKNOWN_ELEMENT: UNKNOWN_ELEMENT_CODE,
102
128
  /** Character data where XGMML allows only elements, or inside an att. */
103
129
  STRAY_TEXT: STRAY_TEXT_CODE,
104
- /** A session network document holds several registered networks; one was read. */
130
+ /**
131
+ * The file holds several graphs and only the first was read. It is not added when `graphIndex` or `graphName` chose the graph.
132
+ * `importAllGraphs()` reads every one.
133
+ */
105
134
  MULTIPLE_GRAPHS: MULTIPLE_GRAPHS_CODE,
106
- /** graphIndex / graphName names no network (fatal). */
135
+ /** `graphIndex` or `graphName` matches no network in the session. The import stops. */
107
136
  GRAPH_NOT_FOUND: GRAPH_NOT_FOUND_CODE,
108
- /** graphName names several networks (fatal). */
137
+ /** `graphName` matches several networks in the session. The import stops. */
109
138
  AMBIGUOUS_GRAPH_NAME: AMBIGUOUS_GRAPH_NAME_CODE,
110
- /** A column renamed `<name>#<n>` because its name was taken. */
139
+ /**
140
+ * An attribute was renamed `<name>#<suffix>` because another attribute already has its name, for example
141
+ * two attributes declared with the same name.
142
+ */
111
143
  COLUMN_RENAMED: COLUMN_RENAMED_CODE,
112
- /** A column declared without its role because the table already holds it. */
144
+ /**
145
+ * You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
146
+ * a plain attribute.
147
+ */
113
148
  ROLE_TAKEN: ROLE_TAKEN_CODE,
114
- /** Two id texts merged into one number under ids "number". */
149
+ /** Two different id texts became the same number because `ids` is "number", so their nodes were merged. */
115
150
  ID_MERGED: ID_MERGED_CODE,
116
- /** An option the format has no use for. */
151
+ /** You set an option this format does not use; it had no effect. The message names the option. */
117
152
  OPTION_IGNORED: OPTION_IGNORED_CODE,
118
- /** A builder-policy option the sink does not honour. */
153
+ /**
154
+ * You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
155
+ * `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
156
+ */
119
157
  SINK_OPTION: SINK_OPTION_CODE,
120
- /** The sink refused the file's direction. */
158
+ /**
159
+ * You read into a graph builder whose direction is already set, or which already holds edges, so the file is read
160
+ * with the builder's direction instead of its own.
161
+ */
121
162
  DIRECTION_REFUSED: DIRECTION_REFUSED_CODE,
122
- /** Edges forced to the policy's direction. */
163
+ /** Edges of the other direction were read with the direction `onMixedDirection` chose. */
123
164
  DIRECTION_FORCED: DIRECTION_FORCED_CODE,
124
- /** A mixed file under onMixedDirection "error" (fatal). */
165
+ /**
166
+ * The graph has both directed and undirected edges and `onMixedDirection` is "error". An import stops; a save to a
167
+ * format that holds one direction per file fails with E_DIRECTED. Pass "directed" or "undirected" to read or write
168
+ * it anyway.
169
+ */
125
170
  MIXED_DIRECTION: MIXED_DIRECTION_CODE
126
171
  });
127
172
  const XGMML_LOSS = Object.freeze({
128
173
  /** A json or nested-list column written as a string att. */
129
174
  JSON_AS_STRING: "W_XGMML_JSON_AS_STRING",
130
- /** A dtype written as a wider Cytoscape type (f32 as Double, u32 above i32 as Long, u8 as Integer, dict as String). */
175
+ /**
176
+ * An attribute type Cytoscape does not have is written as a wider one (a 32-bit float as Double, a large unsigned
177
+ * integer as Long, a byte as Integer, a dictionary as String).
178
+ */
131
179
  WIDENED_TYPE: "W_XGMML_WIDENED_TYPE",
132
- /** A string holding a character XML 1.0 cannot carry; export() throws. */
180
+ /** A text value holds a character XML 1.0 forbids (most control characters); the save fails with E_COLUMN_TYPE. */
133
181
  XML_ILLEGAL_CHAR: XML_ILLEGAL_CHAR_CODE,
134
182
  /** A temporal column written as plain numbers. */
135
183
  TEMPORAL_DROPPED: TEMPORAL_DROPPED_CODE,
136
184
  /** A temporal text companion written as a plain string att. */
137
185
  TEMPORAL_TEXT_DROPPED: TEMPORAL_TEXT_DROPPED_CODE,
138
- /** A role the format has no slot for, written as a plain att. */
186
+ /** An attribute with a role the format has no place for is written as a plain attribute; the role is lost. */
139
187
  ROLE_DROPPED: ROLE_DROPPED_CODE,
140
- /** A parents column not written because the snapshot also has a parent column. */
188
+ /**
189
+ * A `parents` attribute (several parents per node) is not written because the graph also has a `parent` attribute.
190
+ */
141
191
  PARENTS_DROPPED: PARENTS_DROPPED_CODE,
142
192
  /** A mutual pair written as two directed edges. */
143
193
  MUTUAL_EXPANDED: MUTUAL_EXPANDED_CODE,
144
194
  /** Node ids whose text reads back as the other type. */
145
195
  ID_TEXT_TYPE: ID_TEXT_TYPE_CODE,
146
- /** An edge id column of another dtype written as text; it reads back as strings. */
196
+ /** Edge ids that are not text are written as text and read back as text. */
147
197
  EDGE_ID_TEXT: "W_XGMML_EDGE_ID_TEXT",
148
198
  /** Strings holding a literal backslash-n or backslash-t read back as newline / tab (Cytoscape's escapes). */
149
199
  BACKSLASH_ESCAPE: "W_XGMML_BACKSLASH_ESCAPE",
@@ -151,13 +201,22 @@ const XGMML_LOSS = Object.freeze({
151
201
  POSITION: "W_XGMML_POSITION",
152
202
  /** Nodes whose parent chain never reaches a root are written at the top level. */
153
203
  PARENT_CYCLE: "W_XGMML_PARENT_CYCLE",
154
- /** A column named like a column the importer owns reads back renamed. */
204
+ /**
205
+ * An attribute with a role (for example, the label) is written where the format keeps that role, and reads back under the
206
+ * name the format's importer gives it.
207
+ */
155
208
  COLUMN_NAME_CHANGED: COLUMN_RENAMED_LOSS_CODE,
156
- /** A role-less column written into a slot reads back with the slot's role. */
209
+ /**
210
+ * An attribute without a role is written where the format keeps a role (for example, a `name` column as the label), and
211
+ * reads back with that role.
212
+ */
157
213
  ROLE_ASSUMED: ROLE_ASSUMED_CODE,
158
- /** A plain `weight` edge column reads back as THE weight. */
214
+ /** An attribute named `weight` without the weight role reads back as the edge weight. */
159
215
  WEIGHT_KEY_CLASH: WEIGHT_KEY_CLASH_CODE,
160
- /** A string / dict column that reads back as the other storage class. */
216
+ /**
217
+ * A text attribute reads back as a dictionary attribute, or the reverse, because the importer chooses by how often
218
+ * its values repeat. The values are the same.
219
+ */
161
220
  STORAGE_CLASS_CHANGED: STORAGE_CLASS_CODE,
162
221
  /** Edge labels shaped `a (i) b` read back with an `interaction` column (Cytoscape's label alias). */
163
222
  INTERACTION_FROM_LABEL: "W_XGMML_INTERACTION_FROM_LABEL"
@@ -189,13 +248,18 @@ const TRUE_TEXT = /^(1|true|yes)$/i;
189
248
  function isCyTrue(text) {
190
249
  return text !== null && text !== void 0 && TRUE_TEXT.test(text.trim());
191
250
  }
192
- function normaliseName(name, xlinkPrefixes) {
251
+ function normaliseName(name, scope) {
193
252
  const colon = name.indexOf(":");
194
- if (colon > 0 && xlinkPrefixes.has(name.slice(0, colon))) {
253
+ if (colon <= 0) {
254
+ return name;
255
+ }
256
+ const prefix = name.slice(0, colon);
257
+ if (prefix === "xlink" || scope.get(prefix) === XLINK_NAMESPACE) {
195
258
  return `xlink:${name.slice(colon + 1)}`;
196
259
  }
197
260
  return name;
198
261
  }
262
+ const NO_SCOPE = /* @__PURE__ */ new Map();
199
263
  class XgmmlParser {
200
264
  /**
201
265
  * Create a parser.
@@ -203,7 +267,7 @@ class XgmmlParser {
203
267
  */
204
268
  constructor(report) {
205
269
  this.frames = [];
206
- this.xlinkPrefixes = /* @__PURE__ */ new Set(["xlink"]);
270
+ this.scopes = [];
207
271
  this.rootGraph = null;
208
272
  this.nodes = [];
209
273
  this.edges = [];
@@ -213,6 +277,7 @@ class XgmmlParser {
213
277
  this.rootPrefix = null;
214
278
  this.rdf = {};
215
279
  this.rdfXml = null;
280
+ this.doctypeText = null;
216
281
  this.rdfElement = null;
217
282
  this.report = report;
218
283
  }
@@ -233,9 +298,17 @@ class XgmmlParser {
233
298
  cytoscape: this.cytoscape,
234
299
  xgmmlNamespace: this.xgmmlNamespace,
235
300
  rdf: this.rdf,
236
- rdfXml: this.rdfXml
301
+ rdfXml: this.rdfXml,
302
+ doctype: this.doctypeText
237
303
  };
238
304
  }
305
+ /**
306
+ * The DOCTYPE declaration.
307
+ * @param text - the declaration as written
308
+ */
309
+ doctype(text) {
310
+ this.doctypeText ??= text;
311
+ }
239
312
  /**
240
313
  * An element starts.
241
314
  * @param rawName - the element name as written
@@ -243,6 +316,7 @@ class XgmmlParser {
243
316
  * @param line - the line
244
317
  */
245
318
  start(rawName, rawAttrs, line) {
319
+ this.enterScope(rawAttrs);
246
320
  const top = this.frames.length === 0 ? null : this.frames[this.frames.length - 1];
247
321
  if (top === null) {
248
322
  this.startRoot(rawName, rawAttrs, line);
@@ -256,8 +330,8 @@ class XgmmlParser {
256
330
  this.capture(top, rawName, rawAttrs);
257
331
  return;
258
332
  }
259
- const attrs = this.normalise(rawAttrs);
260
- const name = localName(rawName);
333
+ const attrs = this.normalize(rawAttrs);
334
+ const name = this.isXgmmlName(rawName) ? localName(rawName) : rawName;
261
335
  switch (top.kind) {
262
336
  case "graph":
263
337
  this.startInGraph(top.graph, rawName, name, attrs, line);
@@ -294,6 +368,7 @@ class XgmmlParser {
294
368
  * @param _line - the line
295
369
  */
296
370
  end(name, _line) {
371
+ this.scopes.pop();
297
372
  const frame = this.frames.pop();
298
373
  const below = this.frames.length === 0 ? null : this.frames[this.frames.length - 1];
299
374
  switch (frame?.kind) {
@@ -302,7 +377,11 @@ class XgmmlParser {
302
377
  frame.depth--;
303
378
  if (frame.depth > 0) {
304
379
  this.frames.push(frame);
305
- } else if (frame.att.name === "networkMetadata") {
380
+ this.rdfElement = null;
381
+ return;
382
+ }
383
+ frame.att.xml = bindPrefixes(frame.att.xml, frame.start, frame.scope);
384
+ if (frame.att.name === "networkMetadata") {
306
385
  this.rdfXml = frame.att.xml;
307
386
  }
308
387
  this.rdfElement = null;
@@ -348,15 +427,40 @@ class XgmmlParser {
348
427
  );
349
428
  }
350
429
  // ------------------------------------------------------------------ structure
430
+ /**
431
+ * Open the namespace scope of an element: its parent's, plus the prefixes it declares.
432
+ * @param attrs - the element's attributes as written
433
+ */
434
+ enterScope(attrs) {
435
+ const parent = this.scopes.at(-1) ?? NO_SCOPE;
436
+ let scope = parent;
437
+ for (const [key2, value] of attrs) {
438
+ if (key2 === "xmlns" || key2.startsWith("xmlns:")) {
439
+ if (scope === parent) {
440
+ scope = new Map(parent);
441
+ }
442
+ scope.set(key2 === "xmlns" ? "" : key2.slice(6), value);
443
+ }
444
+ }
445
+ this.scopes.push(scope);
446
+ }
447
+ /**
448
+ * The namespace prefixes in scope at the innermost open element.
449
+ * @returns prefix to URI
450
+ */
451
+ get scope() {
452
+ return this.scopes.at(-1) ?? NO_SCOPE;
453
+ }
351
454
  /**
352
455
  * The XML attribute map with every XLink prefix written `xlink:`.
353
456
  * @param attrs - the attributes as written
354
- * @returns the normalised map
457
+ * @returns the normalized map
355
458
  */
356
- normalise(attrs) {
459
+ normalize(attrs) {
357
460
  const out = /* @__PURE__ */ new Map();
461
+ const { scope } = this;
358
462
  for (const [key2, value] of attrs) {
359
- out.set(normaliseName(key2, this.xlinkPrefixes), value);
463
+ out.set(normaliseName(key2, scope), value);
360
464
  }
361
465
  return out;
362
466
  }
@@ -369,10 +473,7 @@ class XgmmlParser {
369
473
  startRoot(rawName, rawAttrs, line) {
370
474
  const local = localName(rawName);
371
475
  const prefix = rawName.includes(":") ? rawName.slice(0, rawName.indexOf(":")) : null;
372
- for (const [key2, value] of rawAttrs) {
373
- if (key2.startsWith("xmlns:") && value === "http://www.w3.org/1999/xlink") {
374
- this.xlinkPrefixes.add(key2.slice(6));
375
- }
476
+ for (const key2 of rawAttrs.keys()) {
376
477
  if (key2 === "xmlns:cy" || key2.startsWith("cy:")) {
377
478
  this.cytoscape = true;
378
479
  }
@@ -387,7 +488,7 @@ class XgmmlParser {
387
488
  { line }
388
489
  );
389
490
  }
390
- const graph = this.newGraph(this.normalise(rawAttrs), line, null, null);
491
+ const graph = this.newGraph(this.normalize(rawAttrs), line, null, null);
391
492
  this.rootGraph = graph;
392
493
  this.frames.push({ kind: "graph", graph });
393
494
  }
@@ -447,7 +548,7 @@ class XgmmlParser {
447
548
  return;
448
549
  }
449
550
  case "graphics":
450
- this.beginGraphics(graph, attrs);
551
+ this.beginGraphics(graph, attrs, line);
451
552
  return;
452
553
  default:
453
554
  this.unknownElement(rawName, line);
@@ -470,7 +571,7 @@ class XgmmlParser {
470
571
  return;
471
572
  }
472
573
  case "graphics":
473
- this.beginGraphics(element, attrs);
574
+ this.beginGraphics(element, attrs, line);
474
575
  return;
475
576
  default:
476
577
  this.unknownElement(rawName, line);
@@ -499,19 +600,30 @@ class XgmmlParser {
499
600
  return;
500
601
  }
501
602
  att.xml ??= "";
502
- const capture = { kind: "capture", att, depth: 0 };
603
+ const capture = {
604
+ kind: "capture",
605
+ att,
606
+ depth: 0,
607
+ start: att.xml.length,
608
+ scope: this.scope
609
+ };
503
610
  this.frames.push(capture);
504
611
  this.capture(capture, rawName, attrs);
505
612
  }
506
613
  /**
507
- * Whether an element name inside an att is XGMML's own (unprefixed, or with the root's prefix,
508
- * as in a document whose root is `<xgmml:graph>`) rather than foreign XML such as `rdf:RDF`.
614
+ * Whether an element name is XGMML's own (unprefixed, with the root's prefix as in a document
615
+ * whose root is `<xgmml:graph>`, or with any prefix bound to the XGMML namespace) rather than
616
+ * foreign XML such as `rdf:RDF` or `svg:node`.
509
617
  * @param rawName - the name as written
510
618
  * @returns true for an XGMML element name
511
619
  */
512
620
  isXgmmlName(rawName) {
513
621
  const colon = rawName.indexOf(":");
514
- return colon < 0 || this.rootPrefix !== null && rawName.slice(0, colon) === this.rootPrefix;
622
+ if (colon < 0) {
623
+ return true;
624
+ }
625
+ const prefix = rawName.slice(0, colon);
626
+ return prefix === this.rootPrefix || this.scope.get(prefix) === XGMML_NAMESPACE;
515
627
  }
516
628
  /**
517
629
  * A `<graph>` inside an `<att>`: a subnetwork of the root, a group or nested-network pointer
@@ -583,6 +695,9 @@ class XgmmlParser {
583
695
  const labelAttr = attrs.get("label") ?? null;
584
696
  const nameAttr = attrs.get("name") ?? null;
585
697
  const label = labelAttr ?? nameAttr;
698
+ if (href !== null && id !== null) {
699
+ this.idAndHref("node", id, href, line);
700
+ }
586
701
  if (href === null && id === null) {
587
702
  if (label === null || label.length === 0) {
588
703
  this.report.counts.skippedNodes++;
@@ -631,9 +746,13 @@ class XgmmlParser {
631
746
  */
632
747
  beginEdge(graph, attrs, line) {
633
748
  const href = attrs.get("xlink:href") ?? null;
749
+ const id = attrs.get("id") ?? null;
750
+ if (href !== null && id !== null) {
751
+ this.idAndHref("edge", id, href, line);
752
+ }
634
753
  const edge = {
635
754
  kind: "edge",
636
- id: href === null ? attrs.get("id") ?? null : null,
755
+ id: href === null ? id : null,
637
756
  href,
638
757
  source: attrs.get("source") ?? null,
639
758
  target: attrs.get("target") ?? null,
@@ -654,6 +773,21 @@ class XgmmlParser {
654
773
  }
655
774
  this.frames.push({ kind: "edge", edge });
656
775
  }
776
+ /**
777
+ * W_XGMML_ID_AND_HREF: an element that both declares an id and references another element.
778
+ * @param kind - node or edge
779
+ * @param id - the id
780
+ * @param href - the reference
781
+ * @param line - the line
782
+ */
783
+ idAndHref(kind, id, href, line) {
784
+ this.report.warning(
785
+ "validation-error",
786
+ XGMML_ISSUE.ID_AND_HREF,
787
+ `<${kind}> has both id "${id}" and xlink:href "${href}"; it is read as a reference to ${href} and the id is not used`,
788
+ { line, element: id }
789
+ );
790
+ }
657
791
  // ------------------------------------------------------------------ atts
658
792
  /**
659
793
  * An att record from its XML attributes.
@@ -707,7 +841,17 @@ class XgmmlParser {
707
841
  frame.att.xml = `${frame.att.xml ?? ""}${tag}>`;
708
842
  frame.depth++;
709
843
  if (frame.att.name === "networkMetadata") {
710
- this.rdfElement = localName(rawName);
844
+ const field = localName(rawName);
845
+ this.rdfElement = field;
846
+ if (this.rdf[field] !== void 0) {
847
+ this.rdfElement = null;
848
+ this.report.warning(
849
+ "validation-error",
850
+ XGMML_ISSUE.DUPLICATE_ATTRIBUTE,
851
+ `the network metadata gives <${rawName}> twice; the first ("${this.rdf[field]}") is kept`,
852
+ { line: frame.att.line, element: field }
853
+ );
854
+ }
711
855
  }
712
856
  }
713
857
  /**
@@ -725,13 +869,20 @@ class XgmmlParser {
725
869
  * attribute is kept as written, merged key by key with an earlier `<graphics>`.
726
870
  * @param target - the node, edge or graph
727
871
  * @param attrs - its attributes
872
+ * @param line - the line
728
873
  */
729
- beginGraphics(target, attrs) {
874
+ beginGraphics(target, attrs, line) {
730
875
  const graphics = { ...target.graphics ?? {} };
731
876
  for (const [key2, value] of attrs) {
732
877
  if ("x" in target && (key2 === "x" || key2 === "y" || key2 === "z")) {
878
+ if (target[key2] !== null && target[key2] !== void 0) {
879
+ this.duplicateGraphics(key2, line);
880
+ }
733
881
  target[key2] = value;
734
882
  } else if (key2 !== "xmlns" && !key2.startsWith("xmlns:")) {
883
+ if (key2 in graphics) {
884
+ this.duplicateGraphics(key2, line);
885
+ }
735
886
  graphics[key2] = value;
736
887
  }
737
888
  }
@@ -789,8 +940,25 @@ class XgmmlParser {
789
940
  );
790
941
  return;
791
942
  }
943
+ if (target.graphics !== null && att.name in target.graphics) {
944
+ this.duplicateGraphics(att.name, att.line);
945
+ }
792
946
  target.graphics = { ...target.graphics ?? {}, [att.name]: attJson(att) };
793
947
  }
948
+ /**
949
+ * W_DUPLICATE_ATTRIBUTE for a graphics property given twice on one element (once per name).
950
+ * @param key - the property
951
+ * @param line - the line
952
+ */
953
+ duplicateGraphics(key2, line) {
954
+ this.report.warnOnce(
955
+ "validation-error",
956
+ XGMML_ISSUE.DUPLICATE_ATTRIBUTE,
957
+ `the graphics property "${key2}" is given twice on one element; the later value is kept`,
958
+ { line, element: key2 },
959
+ `${XGMML_ISSUE.DUPLICATE_ATTRIBUTE}:graphics:${key2}`
960
+ );
961
+ }
794
962
  }
795
963
  function isListLike(att) {
796
964
  const names = new Set(att.children.map((c) => c.name));
@@ -816,6 +984,26 @@ function attJson(att) {
816
984
  }
817
985
  return out;
818
986
  }
987
+ function bindPrefixes(xml, start, scope) {
988
+ const segment = xml.slice(start);
989
+ const used = /* @__PURE__ */ new Set();
990
+ for (const match of segment.matchAll(/<\/?([A-Za-z_][\w.-]*):|\s([A-Za-z_][\w.-]*):[\w.-]+="/g)) {
991
+ used.add(match[1] ?? match[2]);
992
+ }
993
+ let declarations = "";
994
+ for (const prefix of used) {
995
+ const uri = scope.get(prefix);
996
+ if (prefix !== "xmlns" && prefix !== "xml" && uri !== void 0 && !segment.includes(` xmlns:${prefix}="`)) {
997
+ declarations += ` xmlns:${prefix}="${escapeXmlAttribute(uri)}"`;
998
+ }
999
+ }
1000
+ if (declarations.length === 0) {
1001
+ return xml;
1002
+ }
1003
+ const nameEnd = xml.slice(start).search(/[\s>]/);
1004
+ const at = start + (nameEnd < 0 ? segment.length : nameEnd);
1005
+ return `${xml.slice(0, at)}${declarations}${xml.slice(at)}`;
1006
+ }
819
1007
  function otherAttributes(attrs, read) {
820
1008
  const out = [];
821
1009
  for (const [key2, value] of attrs) {
@@ -881,7 +1069,8 @@ function widenScalar(a, b) {
881
1069
  return "long";
882
1070
  }
883
1071
  const INTEGER_TEXT = /^[+-]?[0-9]+$/;
884
- const REAL_TEXT = /^[+-]?(NaN|Infinity|([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?)$/;
1072
+ const REAL_TEXT = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
1073
+ const NON_FINITE_TEXT = /^[+-]?(?:NaN|Infinity)$/;
885
1074
  const I32_MIN = -2147483648;
886
1075
  const I32_MAX = 2147483647;
887
1076
  function parseScalar(text, kind, unescape) {
@@ -912,7 +1101,7 @@ function parseScalar(text, kind, unescape) {
912
1101
  }
913
1102
  case "real": {
914
1103
  const t = text.trim();
915
- if (!REAL_TEXT.test(t)) {
1104
+ if (!REAL_TEXT.test(t) && !NON_FINITE_TEXT.test(t)) {
916
1105
  return null;
917
1106
  }
918
1107
  const n = Number(t);
@@ -926,7 +1115,7 @@ function parseScalar(text, kind, unescape) {
926
1115
  }
927
1116
  }
928
1117
  function unescapeCytoscape(text) {
929
- return text.includes("\\") ? text.replace(/\\t/g, " ").replace(/\\n/g, "\n") : text;
1118
+ return text.includes("\\") ? text.replaceAll(String.raw`\t`, " ").replaceAll(String.raw`\n`, "\n") : text;
930
1119
  }
931
1120
  const DTYPES = {
932
1121
  bool: "bool",
@@ -1167,6 +1356,15 @@ class ColumnSet {
1167
1356
  return jsonCell(names.size > 1 ? recordOf(att) : children.map(jsonOfAtt));
1168
1357
  }
1169
1358
  let itemKind = elementKind(att.elementType);
1359
+ if (itemKind === null && att.elementType !== null && att.elementType.trim().length > 0) {
1360
+ this.report.warnOnce(
1361
+ "unsupported",
1362
+ XGMML_ISSUE.UNKNOWN_ATTR_TYPE,
1363
+ `list element type "${att.elementType}" of "${name}" is not a Cytoscape type; the items are read by their own types`,
1364
+ at,
1365
+ `${XGMML_ISSUE.UNKNOWN_ATTR_TYPE}:${this.domain}:${name}:items`
1366
+ );
1367
+ }
1170
1368
  if (itemKind === null) {
1171
1369
  const kinds = /* @__PURE__ */ new Set();
1172
1370
  for (const child of children) {
@@ -1519,7 +1717,7 @@ function dialectOf(doc, report) {
1519
1717
  let version = 0;
1520
1718
  if (versionText !== null) {
1521
1719
  version = Number(versionText.trim());
1522
- if (!Number.isFinite(version) || versionText.trim().length === 0) {
1720
+ if (!Number.isFinite(version) || version < 0 || versionText.trim().length === 0) {
1523
1721
  report.warning(
1524
1722
  "validation-error",
1525
1723
  XGMML_ISSUE.DOCUMENT_VERSION,
@@ -1542,6 +1740,10 @@ function dialectOf(doc, report) {
1542
1740
  function graphsOf(doc, dialect) {
1543
1741
  return dialect.session ? doc.root.subgraphs.filter((g) => isCyTrue(g.registered)) : [doc.root];
1544
1742
  }
1743
+ function parseCoordinate(text) {
1744
+ const parsed = parseScalar(text, "real", false);
1745
+ return parsed === null || !Number.isFinite(parsed.value) ? null : parsed.value;
1746
+ }
1545
1747
  function localRef(href) {
1546
1748
  return href.startsWith("#") ? href.slice(1) : null;
1547
1749
  }
@@ -1607,6 +1809,7 @@ class XgmmlEmitter {
1607
1809
  this.aliasInteractions = 0;
1608
1810
  this.weighted = false;
1609
1811
  this.directions = /* @__PURE__ */ new Map();
1812
+ this.nameLabel = { node: false, edge: false };
1610
1813
  this.labelRows = null;
1611
1814
  this.doc = doc;
1612
1815
  this.dialect = dialect;
@@ -1618,10 +1821,11 @@ class XgmmlEmitter {
1618
1821
  this.coercer = new IdCoercer(options.ids);
1619
1822
  this.direction = new DirectionResolver(sink, report, options.onMixedDirection);
1620
1823
  const base = { unescape: settings.cytoscapeEscapes, long: options.long };
1824
+ const label = extras.labelFromName === true ? [] : [LABEL_COLUMN];
1621
1825
  this.nodeColumns = new ColumnSet("node", report, {
1622
1826
  ...base,
1623
1827
  reserved: /* @__PURE__ */ new Set([
1624
- LABEL_COLUMN,
1828
+ ...label,
1625
1829
  POSITION_COLUMN,
1626
1830
  Z_COLUMN,
1627
1831
  GRAPHICS_COLUMN,
@@ -1635,7 +1839,7 @@ class XgmmlEmitter {
1635
1839
  });
1636
1840
  this.edgeColumns = new ColumnSet("edge", report, {
1637
1841
  ...base,
1638
- reserved: /* @__PURE__ */ new Set([EDGE_ID_COLUMN, LABEL_COLUMN, GRAPHICS_COLUMN])
1842
+ reserved: /* @__PURE__ */ new Set([EDGE_ID_COLUMN, ...label, GRAPHICS_COLUMN])
1639
1843
  });
1640
1844
  this.graphColumns = new ColumnSet("graph", report, { ...base, reserved: /* @__PURE__ */ new Set([GRAPHICS_COLUMN]) });
1641
1845
  }
@@ -1649,7 +1853,7 @@ class XgmmlEmitter {
1649
1853
  this.report.warning(
1650
1854
  "validation-error",
1651
1855
  XGMML_ISSUE.DANGLING_REFERENCE,
1652
- `${this.prefix()}${members.dangling} xlink:href member reference(s) name no node or edge of the document`,
1856
+ `${this.prefix()}${members.dangling} xlink:href member reference${plural(members.dangling)} ${agree(members.dangling, "names", "name")} no node or edge of the document`,
1653
1857
  { line: graph?.line ?? null }
1654
1858
  );
1655
1859
  }
@@ -1775,11 +1979,28 @@ class XgmmlEmitter {
1775
1979
  edgeDirection(record, header) {
1776
1980
  let directed = this.directions.get(record);
1777
1981
  if (directed === void 0) {
1778
- directed = record.directed === null ? header : this.flag(record.directed, header, { line: record.line, element: record.id ?? record.label });
1982
+ const fallback = this.graphDirected(record.graph, header);
1983
+ directed = record.directed === null ? fallback : this.flag(record.directed, fallback, { line: record.line, element: record.id ?? record.label });
1779
1984
  this.directions.set(record, directed);
1780
1985
  }
1781
1986
  return directed;
1782
1987
  }
1988
+ /**
1989
+ * The default direction of the edges of a graph: the `directed` attribute of the graph or of
1990
+ * the nearest graph it is nested in that has one, else the header.
1991
+ * @param graph - the graph that holds the edge
1992
+ * @param header - the header direction
1993
+ * @returns whether the graph's edges are directed by default
1994
+ */
1995
+ graphDirected(graph, header) {
1996
+ for (let g = graph; g !== null && g !== this.doc.root; g = g.parent) {
1997
+ const text = g.attrs.get("directed");
1998
+ if (text !== void 0) {
1999
+ return this.flag(text, header, { line: g.line, element: "directed" });
2000
+ }
2001
+ }
2002
+ return header;
2003
+ }
1783
2004
  /**
1784
2005
  * The direction the sink starts with: the one every edge has when they all agree (a
1785
2006
  * Cytoscape file writes cy:directed on every edge and may omit the root attribute), else the
@@ -1858,6 +2079,33 @@ class XgmmlEmitter {
1858
2079
  this.checkAbort();
1859
2080
  }
1860
2081
  }
2082
+ /**
2083
+ * The sink id of a node's written id: the restored original, else the written id, coerced.
2084
+ * @param text - the written id
2085
+ * @returns the id
2086
+ */
2087
+ idOf(text) {
2088
+ return this.coercer.text(this.extras.restoredIds?.get(text) ?? text);
2089
+ }
2090
+ /**
2091
+ * Decide whether a table's label comes from its `name` atts.
2092
+ * @param domain - node or edge
2093
+ * @param records - the table's records
2094
+ */
2095
+ decideNameLabel(domain, records) {
2096
+ this.nameLabel[domain] = this.extras.labelFromName === true && records.some((r) => r.atts.some(isNameAtt));
2097
+ }
2098
+ /**
2099
+ * The label of a record: its `name` att, or its XGMML label.
2100
+ * @param record - the node or edge
2101
+ * @returns the label, or undefined
2102
+ */
2103
+ labelOf(record) {
2104
+ if (this.nameLabel[record.kind]) {
2105
+ return record.atts.find(isNameAtt)?.value ?? void 0;
2106
+ }
2107
+ return record.label ?? void 0;
2108
+ }
1861
2109
  /**
1862
2110
  * The coerced id of a node text.
1863
2111
  * @param text - the id text
@@ -1865,7 +2113,7 @@ class XgmmlEmitter {
1865
2113
  * @returns the id
1866
2114
  */
1867
2115
  nodeId(text, line) {
1868
- const id = this.coercer.text(text);
2116
+ const id = this.idOf(text);
1869
2117
  const merge = this.coercer.lastMerge;
1870
2118
  if (merge !== null) {
1871
2119
  this.report.warning(
@@ -1923,7 +2171,7 @@ class XgmmlEmitter {
1923
2171
  this.report.warning(
1924
2172
  "validation-error",
1925
2173
  XGMML_ISSUE.DANGLING_REFERENCE,
1926
- `${this.prefix()}${dangling} xlink:href reference(s) name no node or edge of the document`
2174
+ `${this.prefix()}${dangling} xlink:href reference${plural(dangling)} ${agree(dangling, "names", "name")} no node or edge of the document`
1927
2175
  );
1928
2176
  }
1929
2177
  }
@@ -1937,11 +2185,15 @@ class XgmmlEmitter {
1937
2185
  const positions = new Positions(this, this.dialect.cytoscape ? this.settings.zAs : "position");
1938
2186
  const graphics = new JsonColumn(this, "node", GRAPHICS_COLUMN, XGMML_ORIGIN_NAMESPACE, "graphics");
1939
2187
  const pointers = new Pointers(this, this.groupTest());
2188
+ this.decideNameLabel(
2189
+ "node",
2190
+ this.rowList.flatMap((r) => r.records)
2191
+ );
1940
2192
  for (const row of this.rowList) {
1941
2193
  const where = { line: row.records[0].line, element: row.id };
1942
2194
  const seen = /* @__PURE__ */ new Set();
1943
2195
  for (const record of row.records) {
1944
- labels[row.row] ??= record.label ?? void 0;
2196
+ labels[row.row] ??= this.labelOf(record);
1945
2197
  this.addElementColumns(this.nodeColumns, row.row, record, seen, where);
1946
2198
  positions.add(row, record);
1947
2199
  if (record.graphics !== null && Object.keys(record.graphics).length > 0) {
@@ -1983,7 +2235,7 @@ class XgmmlEmitter {
1983
2235
  names.add(key2);
1984
2236
  }
1985
2237
  for (const att of record.atts) {
1986
- if (this.skipAtt(record, att) || merging && att.name !== null && seen.has(att.name)) {
2238
+ if (this.skipAtt(record, att) || this.nameLabel[record.kind] && isNameAtt(att) || merging && att.name !== null && seen.has(att.name)) {
1987
2239
  continue;
1988
2240
  }
1989
2241
  if (record.kind === "node" && att.name === "__isGroup" && record.nested.length > 0 && isCyTrue(att.value)) {
@@ -2008,7 +2260,19 @@ class XgmmlEmitter {
2008
2260
  * @returns true to skip it
2009
2261
  */
2010
2262
  skipAtt(record, att) {
2011
- return record.kind === "edge" && record.weight === null && att.name === this.options.weightFrom;
2263
+ if (record.kind !== "edge" || att.name !== this.options.weightFrom) {
2264
+ return false;
2265
+ }
2266
+ if (record.weight === null || att.name !== "weight" || att.children.length > 0) {
2267
+ return record.weight === null;
2268
+ }
2269
+ this.report.warning(
2270
+ "validation-error",
2271
+ XGMML_ISSUE.DUPLICATE_ATTRIBUTE,
2272
+ `${this.prefix()}an edge has weight="${record.weight}" and a weight att "${att.value ?? ""}"; the weight attribute is the weight and the att is not read`,
2273
+ { line: att.line, element: record.id ?? record.label ?? "weight" }
2274
+ );
2275
+ return true;
2012
2276
  }
2013
2277
  /**
2014
2278
  * Write a label column (role label).
@@ -2021,7 +2285,7 @@ class XgmmlEmitter {
2021
2285
  return;
2022
2286
  }
2023
2287
  const handle = this.declare(domain, {
2024
- name: LABEL_COLUMN,
2288
+ name: this.nameLabel[domain] ? "name" : LABEL_COLUMN,
2025
2289
  dtype: "string",
2026
2290
  role: "label",
2027
2291
  nullable: true,
@@ -2085,21 +2349,20 @@ class XgmmlEmitter {
2085
2349
  addEdges(records, header) {
2086
2350
  const ids = /* @__PURE__ */ new Set();
2087
2351
  const dedupe = this.dialect.cy2 && this.doc.nodes.some((n) => n.nested.length > 0) ? /* @__PURE__ */ new Set() : null;
2352
+ let repeats = 0;
2353
+ let firstRepeat = null;
2088
2354
  const labels = [];
2089
2355
  const edgeIds = [];
2090
2356
  const graphics = [];
2091
2357
  let row = 0;
2358
+ this.decideNameLabel("edge", records);
2092
2359
  for (const record of records) {
2093
2360
  const where = { line: record.line, element: record.id ?? record.label };
2094
- const key2 = record.id ?? record.label;
2361
+ const key2 = record.id ?? (record.label === null ? null : JSON.stringify([record.label, record.source, record.target]));
2095
2362
  if (dedupe !== null && key2 !== null) {
2096
2363
  if (dedupe.has(key2)) {
2097
- this.report.warnOnce(
2098
- "merged",
2099
- XGMML_ISSUE.GROUP_DUPLICATE_EDGE,
2100
- `${this.prefix()}the Cytoscape 2.x writer repeats the edges of a group; each repeat is dropped`,
2101
- where
2102
- );
2364
+ repeats++;
2365
+ firstRepeat ??= where;
2103
2366
  continue;
2104
2367
  }
2105
2368
  dedupe.add(key2);
@@ -2110,7 +2373,7 @@ class XgmmlEmitter {
2110
2373
  continue;
2111
2374
  }
2112
2375
  this.edgeIndex[row] = index;
2113
- labels[row] = record.label ?? void 0;
2376
+ labels[row] = this.labelOf(record);
2114
2377
  edgeIds[row] = record.id ?? void 0;
2115
2378
  this.addElementColumns(this.edgeColumns, row, record, /* @__PURE__ */ new Set(), where);
2116
2379
  this.fillInteraction(record, row, where);
@@ -2119,6 +2382,14 @@ class XgmmlEmitter {
2119
2382
  }
2120
2383
  row++;
2121
2384
  }
2385
+ if (repeats > 0) {
2386
+ this.report.warning(
2387
+ "merged",
2388
+ XGMML_ISSUE.GROUP_DUPLICATE_EDGE,
2389
+ `${this.prefix()}the Cytoscape 2.x writer repeats the edges of a group; ${repeats} repeat${plural(repeats)} ${agree(repeats, "was", "were")} dropped`,
2390
+ firstRepeat ?? void 0
2391
+ );
2392
+ }
2122
2393
  this.writeEdgeIds(edgeIds);
2123
2394
  this.writeLabels("edge", labels, (r) => this.edgeIndex[r] ?? -1);
2124
2395
  const column = new JsonColumn(this, "edge", GRAPHICS_COLUMN, XGMML_ORIGIN_NAMESPACE, "graphics");
@@ -2195,7 +2466,7 @@ class XgmmlEmitter {
2195
2466
  if (text === null) {
2196
2467
  return void 0;
2197
2468
  }
2198
- const weight = parseWeightText(text);
2469
+ const weight = parseWeightText(text, this.report);
2199
2470
  this.weighted ||= weight !== void 0;
2200
2471
  return weight;
2201
2472
  }
@@ -2213,21 +2484,22 @@ class XgmmlEmitter {
2213
2484
  if (text !== null) {
2214
2485
  const row = this.rows.get(text);
2215
2486
  if (row !== void 0 && row.index >= 0) {
2216
- return this.coercer.text(text);
2487
+ return this.idOf(text);
2217
2488
  }
2218
2489
  }
2219
2490
  if (alias !== null) {
2220
2491
  const resolved = this.aliasRow(alias);
2221
2492
  if (resolved !== null) {
2222
2493
  this.aliasResolved++;
2223
- return this.coercer.text(resolved.id);
2494
+ return this.idOf(resolved.id);
2224
2495
  }
2225
2496
  }
2226
2497
  if (text === null) {
2498
+ const ambiguous = alias !== null && this.aliasRow(alias) === null && this.labelRows?.get(alias) === null;
2227
2499
  this.report.error(
2228
2500
  "missing-value",
2229
2501
  XGMML_ISSUE.MISSING_ENDPOINT,
2230
- `${this.prefix()}<edge> without a ${side}`,
2502
+ ambiguous ? `${this.prefix()}<edge> without a ${side}: its label alias "${alias}" is ambiguous (several nodes have that label); the edge is skipped` : `${this.prefix()}<edge> without a ${side}`,
2231
2503
  where
2232
2504
  );
2233
2505
  return null;
@@ -2293,7 +2565,7 @@ class XgmmlEmitter {
2293
2565
  this.report.warning(
2294
2566
  "coercion",
2295
2567
  XGMML_ISSUE.LABEL_ALIAS,
2296
- `${this.prefix()}Cytoscape label aliases ("a (pp) b"): ${this.aliasResolved} endpoint(s) resolved, ${this.aliasInteractions} interaction(s) filled from edge labels`
2568
+ `${this.prefix()}Cytoscape label aliases ("a (pp) b"): ${this.aliasResolved} endpoint${plural(this.aliasResolved)} resolved, ${this.aliasInteractions} interaction${plural(this.aliasInteractions)} filled from edge labels`
2297
2569
  );
2298
2570
  }
2299
2571
  /**
@@ -2391,6 +2663,9 @@ class XgmmlEmitter {
2391
2663
  });
2392
2664
  }
2393
2665
  }
2666
+ function isNameAtt(att) {
2667
+ return att.name === "name" && (att.namespace ?? null) === null && att.value !== null && att.children.length === 0 && (att.cyType ?? "String") === "String";
2668
+ }
2394
2669
  function aliasesOf(label) {
2395
2670
  if (label === null) {
2396
2671
  return null;
@@ -2491,8 +2766,8 @@ class Positions {
2491
2766
  if (text === null) {
2492
2767
  return null;
2493
2768
  }
2494
- const n = Number(text.trim());
2495
- if (text.trim().length === 0 || !Number.isFinite(n)) {
2769
+ const n = parseCoordinate(text);
2770
+ if (n === null) {
2496
2771
  this.emitter.issues.error(
2497
2772
  "validation-error",
2498
2773
  XGMML_ISSUE.BAD_VALUE,
@@ -2595,7 +2870,7 @@ class Pointers {
2595
2870
  this.emitter.issues.warning(
2596
2871
  "validation-error",
2597
2872
  XGMML_ISSUE.DANGLING_REFERENCE,
2598
- `${prefix}${this.dangling} nested-network pointer(s) name no graph of the document`
2873
+ `${prefix}${this.dangling} nested-network pointer${plural(this.dangling)} ${agree(this.dangling, "names", "name")} no graph of the document`
2599
2874
  );
2600
2875
  }
2601
2876
  const names = new JsonColumn(
@@ -2613,7 +2888,7 @@ class Pointers {
2613
2888
  this.emitter.issues.warning(
2614
2889
  "unsupported",
2615
2890
  XGMML_ISSUE.CROSS_FILE_REFERENCE,
2616
- `${prefix}${this.crossFile.size} nested-network pointer(s) point into another file; each is kept as text in ${NETWORK_POINTER_COLUMN}`
2891
+ `${prefix}${this.crossFile.size} nested-network pointer${plural(this.crossFile.size)} ${agree(this.crossFile.size, "points", "point")} into another file; each is kept as text in ${NETWORK_POINTER_COLUMN}`
2617
2892
  );
2618
2893
  const column = new JsonColumn(
2619
2894
  this.emitter,
@@ -2638,6 +2913,7 @@ class Containment {
2638
2913
  this.emitter = emitter;
2639
2914
  this.parents = /* @__PURE__ */ new Map();
2640
2915
  this.subgraphs = /* @__PURE__ */ new Map();
2916
+ this.groups = /* @__PURE__ */ new Set();
2641
2917
  }
2642
2918
  /**
2643
2919
  * Collect the memberships of every group node of the graph.
@@ -2683,7 +2959,7 @@ class Containment {
2683
2959
  this.emitter.issues.error(
2684
2960
  "missing-value",
2685
2961
  XGMML_ISSUE.UNKNOWN_PARENT,
2686
- `${this.emitter.prefix()}${unknown} group member(s) name no node of this graph`
2962
+ `${this.emitter.prefix()}${unknown} group member${plural(unknown)} ${agree(unknown, "names", "name")} no node of this graph`
2687
2963
  );
2688
2964
  }
2689
2965
  }
@@ -2694,7 +2970,7 @@ class Containment {
2694
2970
  * @param line - the line
2695
2971
  */
2696
2972
  link(child, parent, line) {
2697
- if (child === parent || this.isAncestor(child, parent)) {
2973
+ if (child === parent || this.groups.has(child) && this.isAncestor(child, parent)) {
2698
2974
  this.emitter.issues.error(
2699
2975
  "validation-error",
2700
2976
  XGMML_ISSUE.PARENT_CYCLE,
@@ -2708,6 +2984,7 @@ class Containment {
2708
2984
  list.push(parent);
2709
2985
  }
2710
2986
  this.parents.set(child, list);
2987
+ this.groups.add(parent);
2711
2988
  }
2712
2989
  /**
2713
2990
  * Whether a node is an ancestor of another through the memberships so far.
@@ -2780,8 +3057,6 @@ const USED_OPTIONS = /* @__PURE__ */ new Set([
2780
3057
  "onProgress",
2781
3058
  "encoding"
2782
3059
  ]);
2783
- const SNIFF_BYTES = 4096;
2784
- const HEAD_CHARS = 2048;
2785
3060
  const XGMML_DOCTYPE = /<!DOCTYPE\s+graph\s[^<>]*xgmml\.dtd/i;
2786
3061
  function resolveSettings(options, cytoscape) {
2787
3062
  const zAs = options?.zAs ?? "column";
@@ -2828,10 +3103,10 @@ async function parseXgmml(input, report, common, options) {
2828
3103
  } : void 0
2829
3104
  };
2830
3105
  const parser = new XgmmlParser(report);
2831
- const seen = { head: "", content: false };
3106
+ const seen = { content: false };
2832
3107
  try {
2833
3108
  await tokenizeXml(
2834
- watch(textChunks(input, report, { ...common, declaredEncoding: xmlDeclaredEncoding }), seen),
3109
+ watch(textChunks(input, report, { ...common, declaredEncoding: xmlDeclaredEncoding, xml: true }), seen),
2835
3110
  parser,
2836
3111
  repairs
2837
3112
  );
@@ -2845,7 +3120,7 @@ async function parseXgmml(input, report, common, options) {
2845
3120
  throw err;
2846
3121
  }
2847
3122
  const doc = parser.document();
2848
- if (!doc.xgmmlNamespace && !XGMML_DOCTYPE.test(seen.head)) {
3123
+ if (!doc.xgmmlNamespace && !XGMML_DOCTYPE.test(doc.doctype ?? "")) {
2849
3124
  report.warning(
2850
3125
  "validation-error",
2851
3126
  XGMML_ISSUE.NO_NAMESPACE,
@@ -2857,9 +3132,6 @@ async function parseXgmml(input, report, common, options) {
2857
3132
  }
2858
3133
  async function* watch(chunks, seen) {
2859
3134
  for await (const chunk of chunks) {
2860
- if (seen.head.length < HEAD_CHARS) {
2861
- seen.head += chunk.slice(0, HEAD_CHARS - seen.head.length);
2862
- }
2863
3135
  seen.content ||= !isWhitespace(chunk);
2864
3136
  yield chunk;
2865
3137
  }
@@ -2913,7 +3185,7 @@ function reportRootOnly(prepared) {
2913
3185
  prepared.report.warning(
2914
3186
  "unsupported",
2915
3187
  XGMML_ISSUE.ROOT_ONLY_ELEMENTS,
2916
- `${nodes} node(s) and ${edges} edge(s) belong to no registered network (group meta-edges, collapsed group members) and were not read`
3188
+ `${elementCount(nodes, edges)} ${agree(nodes + edges, "belongs", "belong")} to none of the file's networks (group meta-edges or collapsed group members) and ${agree(nodes + edges, "was", "were")} not read`
2917
3189
  );
2918
3190
  }
2919
3191
  }
@@ -2924,22 +3196,22 @@ async function importXgmml(input, sink, options) {
2924
3196
  options,
2925
3197
  prepared.report
2926
3198
  );
2927
- if (prepared.graphs.length > 1) {
3199
+ if (prepared.graphs.length > 1 && !graphChosen(options)) {
2928
3200
  prepared.report.warning(
2929
3201
  "unsupported",
2930
3202
  XGMML_ISSUE.MULTIPLE_GRAPHS,
2931
- `the session network document holds ${prepared.graphs.length} registered networks; ${prepared.graphs.length - 1} were not read (use importAll, graphIndex or graphName)`
3203
+ `the session network document holds ${prepared.graphs.length} registered networks; only the first is read (importAllGraphs() reads every one; graphIndex or graphName chooses one)`
2932
3204
  );
2933
3205
  }
2934
3206
  return emitOne(prepared, prepared.graphs[index], sink);
2935
3207
  }
2936
3208
  async function importAllXgmml(input, sinkFor, options) {
2937
- const bytes = await reread(input);
2938
- const first = await prepare(bytes, null, options);
3209
+ const first = await prepare(input, null, options);
3210
+ const parsed = first.report.fork();
2939
3211
  const reports = [];
2940
3212
  for (let i = 0; i < first.graphs.length; i++) {
2941
3213
  const sink = sinkFor(i);
2942
- const prepared = i === 0 ? first : await prepare(bytes, null, options);
3214
+ const prepared = i === 0 ? first : { ...first, report: parsed.fork() };
2943
3215
  reportSinkOptions(sink, options, prepared.report, true);
2944
3216
  reportUnusedOptions(options, prepared.report, USED_OPTIONS);
2945
3217
  reports.push(emitOne(prepared, prepared.graphs[i], sink));
@@ -2961,50 +3233,23 @@ async function listXgmmlGraphs(input, options) {
2961
3233
  function graphName(graph, doc) {
2962
3234
  return graph.label ?? (graph === doc.root ? doc.rdf.title ?? null : null) ?? graph.id ?? null;
2963
3235
  }
2964
- async function reread(input) {
2965
- if (typeof input === "string" || input instanceof Uint8Array) {
2966
- return input;
2967
- }
2968
- const parts = [];
2969
- const iterable = typeof input.getReader === "function" ? streamIterable(input) : input;
2970
- for await (const chunk of iterable) {
2971
- parts.push(chunk);
2972
- }
2973
- if (parts.every((p) => typeof p === "string")) {
2974
- return parts.join("");
2975
- }
2976
- const bytes = parts.map((p) => typeof p === "string" ? new TextEncoder().encode(p) : p);
2977
- const out = new Uint8Array(bytes.reduce((n, b) => n + b.byteLength, 0));
2978
- let at = 0;
2979
- for (const b of bytes) {
2980
- out.set(b, at);
2981
- at += b.byteLength;
2982
- }
2983
- return out;
2984
- }
2985
- async function* streamIterable(stream) {
2986
- const reader = stream.getReader();
2987
- try {
2988
- for (; ; ) {
2989
- const { done, value } = await reader.read();
2990
- if (done) {
2991
- return;
2992
- }
2993
- yield value;
2994
- }
2995
- } finally {
2996
- reader.releaseLock();
2997
- }
2998
- }
2999
3236
  function sniffXgmml(head) {
3000
- const text = new TextDecoder("utf-8", { fatal: false }).decode(head.subarray(0, SNIFF_BYTES));
3237
+ let encoding = "utf-8";
3238
+ if (head[0] === 255 && head[1] === 254 || head[0] === 60 && head[1] === 0 && head[2] === 63) {
3239
+ encoding = "utf-16le";
3240
+ } else if (head[0] === 254 && head[1] === 255 || head[0] === 0 && head[1] === 60 && head[2] === 0) {
3241
+ encoding = "utf-16be";
3242
+ }
3243
+ const text = new TextDecoder(encoding, { fatal: false }).decode(head);
3001
3244
  if (!/^\uFEFF?\s*</.test(text)) {
3002
3245
  return 0;
3003
3246
  }
3004
3247
  if (XGMML_DOCTYPE.test(text)) {
3005
3248
  return 0.95;
3006
3249
  }
3007
- const root = /<(?!\?|!)([A-Za-z_][\w.-]*:)?([A-Za-z_][\w.-]*)[\s/>]/.exec(text.replace(/<!--[\s\S]*?-->/g, ""));
3250
+ const root = /<(?![?!])([A-Za-z_][\w.-]*:)?([A-Za-z_][\w.-]*)[\s/>]/.exec(
3251
+ text.replaceAll(/<!--[\s\S]*?(-->|$)/g, "")
3252
+ );
3008
3253
  if (root === null || root[2] !== "graph") {
3009
3254
  return 0;
3010
3255
  }
@@ -3014,6 +3259,13 @@ function sniffXgmml(head) {
3014
3259
  }
3015
3260
  const xgmmlImporter = Object.freeze({
3016
3261
  format: FORMAT,
3262
+ options: Object.freeze([
3263
+ "cytoscapeEscapes",
3264
+ "labelAliases",
3265
+ "pairSurrogateReferences",
3266
+ "repairBareAmpersands",
3267
+ "zAs"
3268
+ ]),
3017
3269
  extensions: EXTENSIONS,
3018
3270
  mimeTypes: MIME_TYPES,
3019
3271
  sniff: sniffXgmml,
@@ -3044,12 +3296,13 @@ export {
3044
3296
  PARENTS_COLUMN as h,
3045
3297
  XGMML_ORIGIN_NAMESPACE as i,
3046
3298
  CYTOSCAPE_ORIGIN_NAMESPACE as j,
3047
- isCyTrue as k,
3048
- XgmmlEmitter as l,
3299
+ XgmmlEmitter as k,
3300
+ isCyTrue as l,
3049
3301
  membersOf as m,
3050
3302
  dialectOf as n,
3303
+ parseCoordinate as o,
3051
3304
  parseXgmml as p,
3052
3305
  resolveSettings as r,
3053
3306
  xgmmlImporter as x
3054
3307
  };
3055
- //# sourceMappingURL=importer-D_e7e7LX.js.map
3308
+ //# sourceMappingURL=importer-B2W_58pz.js.map