@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
package/dist/gml.js CHANGED
@@ -1,9 +1,8 @@
1
- import { t as SYNTAX_CODE, X as pairFolding, V as resolveExportOptions, _ as DictHeuristic, aV as DICT_SAMPLE_ROWS, R as ROLE_TAKEN_CODE$1, P as PRECISION_CODE$1, d as DUPLICATE_NODE_CODE$1, e as MISSING_ENDPOINT_CODE$1, f as MISSING_ID_CODE$1, M as MULTIPLE_GRAPHS_CODE, N as NO_GRAPH_CODE$1, v as resolveImportOptions, w as ImportReportBuilder, z as reportUnusedOptions, aG as readText, y as throwIfAborted, F as reportSinkOptions, K as IdCoercer, J as DirectionResolver, Q as uniqueColumnName, L as declareResolved, 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, C as COLUMN_RENAMED_CODE, q as UNKNOWN_ENCODING_CODE, E as ENCODING_FALLBACK_CODE, r as INVALID_ENCODING_CODE, s as INVALID_UTF8_CODE } from "./chunks/report-B1z4WT9e.js";
1
+ import { ak as SYNTAX_CODE, b as plural, a as checkCapabilities, L as LOSS, p as pairFolding, $ as agree, c as capabilities, r as resolveExportOptions, ac as DictHeuristic, aG as formatInteger, bw as formatGmlReal, aE as sanitizeIds, bE as countMixedEdges, e as explicitWeights, bV as DICT_SAMPLE_ROWS, R as ROLE_TAKEN_CODE$1, aj as WIDENED_CODE$1, P as PRECISION_CODE$1, n as DUPLICATE_NODE_CODE$1, s as MISSING_ENDPOINT_CODE$1, t as MISSING_ID_CODE$1, l as MULTIPLE_GRAPHS_CODE, N as NO_GRAPH_CODE$1, al as resolveImportOptions, a8 as ImportReportBuilder, an as reportUnusedOptions, bC as readText, am as throwIfAborted, ao as reportSinkOptions, ap as graphChosen, ar as IdCoercer, aq as DirectionResolver, a0 as uniqueColumnName, C as COLUMN_RENAMED_CODE, as as weightFromValue, bW as reportWeightPrecision, aL as parseWeightText, a1 as declareResolved, 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, ae as AMBIGUOUS_GRAPH_NAME_CODE, af as GRAPH_NOT_FOUND_CODE, w as UNKNOWN_ENCODING_CODE, x as ENCODING_FALLBACK_CODE, y as INVALID_ENCODING_CODE, z as INVALID_UTF8_CODE, F as ELEMENT_ISSUE, G as INPUT_ISSUE } from "./chunks/export-CHd4tQE2.js";
2
2
  import { GraphFormatError, INVALID_INDEX } from "@graphty/graph-format";
3
- import { j as decodeGmlString, k as quoteGmlString } from "./chunks/escape-B-tkk_Cl.js";
4
- import { a as checkCapabilities, L as LOSS, c as capabilities, s as sanitizeIds, d as countMixedEdges } from "./chunks/export-Bh60Dv-n.js";
5
- import { d as formatInteger, c as formatGmlReal, e as explicitWeights, w as weightFromValue, p as parseWeightText } from "./chunks/weights-Dzba96G3.js";
6
- import { j as joinText, e as encodeChunks } from "./chunks/writer-C7flM-Ih.js";
3
+ import { k as decodeGmlString, m as quoteGmlString } from "./chunks/escape-D1HPTUrP.js";
4
+ import { j as joinText, e as encodeChunks } from "./chunks/writer-DxjgHwSe.js";
5
+ import { i as importChosenGraph } from "./chunks/choose-DrXtu_96.js";
7
6
  const TOKEN_WORD = 0;
8
7
  const TOKEN_INT = 1;
9
8
  const TOKEN_REAL = 2;
@@ -85,14 +84,20 @@ class GmlTokens {
85
84
  * @returns the body with character references decoded
86
85
  */
87
86
  stringOf(i) {
88
- const text = this.textOf(i);
87
+ let text = this.textOf(i);
88
+ if (text.includes("\r")) {
89
+ text = text.replaceAll(/\r\n?/g, "\n");
90
+ }
89
91
  if (text.indexOf("&") < 0) {
90
92
  return text;
91
93
  }
92
94
  const report = this.onUnknownEntity;
93
- return decodeGmlString(text, report === null ? void 0 : (entity) => {
94
- report(entity, this.line[i]);
95
- });
95
+ return decodeGmlString(
96
+ text,
97
+ report === null ? void 0 : (entity) => {
98
+ report(entity, this.line[i]);
99
+ }
100
+ );
96
101
  }
97
102
  /**
98
103
  * Whether a token is a `[` or `]`.
@@ -133,6 +138,7 @@ function tokenizeGml(text) {
133
138
  const n = text.length;
134
139
  let i = 0;
135
140
  let line = 1;
141
+ let spanningLine = 0;
136
142
  while (i < n) {
137
143
  const c = text.charCodeAt(i);
138
144
  if (c === 10) {
@@ -146,6 +152,8 @@ function tokenizeGml(text) {
146
152
  }
147
153
  } else if (c === 32 || c === 9 || c === 11 || c === 12) {
148
154
  i++;
155
+ } else if (c === 65279) {
156
+ i++;
149
157
  } else if (c === 35) {
150
158
  i = endOfLine(text, i);
151
159
  } else if (c === 91) {
@@ -156,11 +164,21 @@ function tokenizeGml(text) {
156
164
  i++;
157
165
  } else if (c === 34) {
158
166
  const close = text.indexOf('"', i + 1);
159
- const eol = endOfLine(text, i + 1);
160
- if (close < 0 || close > eol) {
161
- throw new GmlSyntaxError(SYNTAX_STRING_CODE, `unclosed string at line ${line}`, line);
167
+ if (close < 0) {
168
+ const hint = spanningLine === 0 ? "" : `; the string opened at line ${spanningLine} spans lines, so a quote may be missing there`;
169
+ throw new GmlSyntaxError(SYNTAX_STRING_CODE, `unclosed string opened at line ${line}${hint}`, line);
162
170
  }
163
171
  tokens.push(TOKEN_STRING, i + 1, close, line);
172
+ const opened = line;
173
+ for (let k = i + 1; k < close; k++) {
174
+ const d = text.codePointAt(k);
175
+ if (d === 10 || d === 13 && text.codePointAt(k + 1) !== 10) {
176
+ line++;
177
+ }
178
+ }
179
+ if (line !== opened && spanningLine === 0) {
180
+ spanningLine = opened;
181
+ }
164
182
  i = close + 1;
165
183
  } else {
166
184
  let j = i + 1;
@@ -198,8 +216,12 @@ function classifyBare(text, start, end, line) {
198
216
  if (REAL_TEXT.test(token) || NON_FINITE_TEXT.test(token)) {
199
217
  return TOKEN_REAL;
200
218
  }
201
- const shown = token.length > 20 ? `${token.slice(0, 20)}...` : token;
202
- throw new GmlSyntaxError(SYNTAX_TOKEN_CODE, `cannot tokenize "${shown}" at line ${line}`, line);
219
+ const hex = (c) => (c.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0");
220
+ const head = token.length > 20 ? `${token.slice(0, 20)}...` : token;
221
+ const shown = head.replaceAll(/[^\x20-\x7e]/gu, (c) => String.raw`\u` + hex(c));
222
+ const odd = /[^\x21-\x7e]/u.exec(token);
223
+ const note2 = odd === null ? "" : ` (it holds U+${hex(odd[0])}, which GML allows only inside a string)`;
224
+ throw new GmlSyntaxError(SYNTAX_TOKEN_CODE, `cannot tokenize "${shown}" at line ${line}${note2}`, line);
203
225
  }
204
226
  function validateStructure(tokens) {
205
227
  const { count, kind } = tokens;
@@ -252,7 +274,7 @@ function validateStructure(tokens) {
252
274
  const open = stack[stack.length - 1];
253
275
  throw new GmlSyntaxError(
254
276
  SYNTAX_BRACKET_CODE,
255
- `unexpected end of input: ${stack.length} bracket(s) still open, the last opened at line ${tokens.line[open]}`,
277
+ `unexpected end of input: ${stack.length} bracket${plural(stack.length)} still open, the last opened at line ${tokens.line[open]}`,
256
278
  tokens.line[open]
257
279
  );
258
280
  }
@@ -274,7 +296,7 @@ function numberOfText(text) {
274
296
  if (NON_FINITE_TEXT.test(text)) {
275
297
  const lower = text.toLowerCase();
276
298
  if (lower.endsWith("nan")) {
277
- return NaN;
299
+ return Number.NaN;
278
300
  }
279
301
  return lower.startsWith("-") ? -Infinity : Infinity;
280
302
  }
@@ -284,7 +306,7 @@ function isGmlKey(text) {
284
306
  return STRICT_KEY_TEXT.test(text);
285
307
  }
286
308
  function mangleGmlKey(text) {
287
- const body = text.replace(/[^0-9A-Za-z_]/g, "_");
309
+ const body = text.replaceAll(/\W/g, "_");
288
310
  return /^[A-Za-z]/.test(body) ? body : `x${body}`;
289
311
  }
290
312
  function parseRecord(tokens, open) {
@@ -436,8 +458,11 @@ function isWritten(column) {
436
458
  return role === null || !SKIPPED_ROLES.has(role);
437
459
  }
438
460
  function preferredKey(meta) {
439
- const { origin } = meta;
440
- return origin !== null && origin.format === "gml" && origin.id !== null ? origin.id : meta.name;
461
+ const { origin, name } = meta;
462
+ if (origin?.format !== "gml" || origin.id === null) {
463
+ return name;
464
+ }
465
+ return name === origin.id || name.startsWith(`${origin.id}#`) ? origin.id : name;
441
466
  }
442
467
  function hasWeights(snapshot) {
443
468
  return snapshot.flags.weighted;
@@ -480,7 +505,7 @@ function selectColumns(table, reserved, label, plan, notes, filter = () => true)
480
505
  notes.push(
481
506
  note(
482
507
  code,
483
- `${label} column "${column.meta.name}" ${why}; export() will throw unless sanitizeKeys is "mangle"`,
508
+ `${label} column "${column.meta.name}" ${why}; the save fails unless sanitizeKeys is "mangle"`,
484
509
  column.meta.name
485
510
  )
486
511
  );
@@ -564,7 +589,7 @@ function jsonNotes(columns, label, plan, notes) {
564
589
  notes.push(
565
590
  note(
566
591
  RECORD_NUMBER_TYPE_CODE,
567
- `${where} holds numbers in ${stats.numbers} row(s); GML records cannot keep the int / real distinction`,
592
+ `${where} holds numbers in ${stats.numbers} row${plural(stats.numbers)}; GML records cannot keep the int / real distinction`,
568
593
  name,
569
594
  stats.numbers
570
595
  )
@@ -574,7 +599,7 @@ function jsonNotes(columns, label, plan, notes) {
574
599
  notes.push(
575
600
  note(
576
601
  RECORD_BOOLEAN_CODE,
577
- `${where} holds booleans in ${stats.booleans} row(s); written as 1 / 0`,
602
+ `${where} holds booleans in ${stats.booleans} row${plural(stats.booleans)}; written as 1 / 0`,
578
603
  name,
579
604
  stats.booleans
580
605
  )
@@ -584,7 +609,7 @@ function jsonNotes(columns, label, plan, notes) {
584
609
  notes.push(
585
610
  note(
586
611
  RECORD_NULL_CODE,
587
- `${where} holds nulls in ${stats.nulls} row(s); GML has no null, the key is omitted`,
612
+ `${where} holds nulls in ${stats.nulls} row${plural(stats.nulls)}; GML has no null, the key is omitted`,
588
613
  name,
589
614
  stats.nulls
590
615
  )
@@ -594,7 +619,7 @@ function jsonNotes(columns, label, plan, notes) {
594
619
  notes.push(
595
620
  note(
596
621
  JSON_ARRAY_CODE,
597
- `${where} holds arrays as values in ${stats.arrays} row(s); written as repeated keys, they re-import as a list`,
622
+ `${where} holds arrays as values in ${stats.arrays} row${plural(stats.arrays)}; written as repeated keys, they re-import as a list`,
598
623
  name,
599
624
  stats.arrays
600
625
  )
@@ -604,7 +629,7 @@ function jsonNotes(columns, label, plan, notes) {
604
629
  notes.push(
605
630
  note(
606
631
  NESTED_ARRAY_CODE,
607
- `${where} holds arrays nested in arrays in ${stats.nestedArrays} row(s); GML cannot write them and export() will throw`,
632
+ `${where} holds arrays nested in arrays in ${stats.nestedArrays} row${plural(stats.nestedArrays)}; GML cannot write them and the save fails`,
608
633
  name,
609
634
  stats.nestedArrays
610
635
  )
@@ -614,12 +639,12 @@ function jsonNotes(columns, label, plan, notes) {
614
639
  notes.push(
615
640
  plan.mangle ? note(
616
641
  KEY_MANGLED_CODE,
617
- `${where}: ${stats.invalidKeys} record key(s) are not GML keys and are rewritten`,
642
+ `${where}: ${stats.invalidKeys} record key${plural(stats.invalidKeys)} ${agree(stats.invalidKeys, "is", "are")} not GML keys and are rewritten`,
618
643
  name,
619
644
  stats.invalidKeys
620
645
  ) : note(
621
646
  INVALID_KEY_CODE,
622
- `${where}: ${stats.invalidKeys} record key(s) are not GML keys; export() will throw unless sanitizeKeys is "mangle"`,
647
+ `${where}: ${stats.invalidKeys} record key${plural(stats.invalidKeys)} ${agree(stats.invalidKeys, "is", "are")} not GML keys; the save fails unless sanitizeKeys is "mangle"`,
623
648
  name,
624
649
  stats.invalidKeys
625
650
  )
@@ -716,7 +741,7 @@ function graphicsNotes(snapshot, notes) {
716
741
  notes.push(
717
742
  note(
718
743
  GRAPHICS_OVERRIDDEN_CODE,
719
- `${overridden} node graphics record(s) have x / y / z keys the position column replaces`,
744
+ `${overridden} node graphics record${plural(overridden)} ${agree(overridden, "has", "have")} x / y / z keys the position column replaces`,
720
745
  "graphics",
721
746
  overridden
722
747
  )
@@ -726,7 +751,7 @@ function graphicsNotes(snapshot, notes) {
726
751
  notes.push(
727
752
  note(
728
753
  GRAPHICS_CONFLICT_CODE,
729
- `${conflicts} node graphics value(s) are not records and cannot hold the position; export() will throw`,
754
+ `${conflicts} node graphics value${plural(conflicts)} ${agree(conflicts, "is", "are")} not records and cannot hold the position; the save fails`,
730
755
  "graphics",
731
756
  conflicts
732
757
  )
@@ -841,7 +866,7 @@ function check(snapshot, options) {
841
866
  notes.push(
842
867
  note(
843
868
  LOSS.WEIGHT_KEY_CLASH,
844
- `edge column "${clash.column.meta.name}" is written under "${plan.weightKey}", the key the importer reads THE weight from; it reads back as the weight, not as a column`,
869
+ `edge column "${clash.column.meta.name}" is written under "${plan.weightKey}", the key the importer reads edge weights from; it reads back as the weight, not as a column`,
845
870
  clash.column.meta.name,
846
871
  clash.column.length - clash.column.nullCount
847
872
  )
@@ -853,7 +878,7 @@ function check(snapshot, options) {
853
878
  notes.push(
854
879
  note(
855
880
  LOSS.MUTUAL_EXPANDED,
856
- `${folding.mutualCount} mutual pair(s) are written as two directed edges; the mutual mark is lost`,
881
+ `${folding.mutualCount} mutual pair${plural(folding.mutualCount)} ${agree(folding.mutualCount, "is", "are")} written as two directed edges; the mutual mark is lost`,
857
882
  null,
858
883
  folding.mutualCount
859
884
  )
@@ -1159,7 +1184,7 @@ function contextOf(snapshot, options) {
1159
1184
  if (mixed > 0 && plan.common.onMixedDirection === "error") {
1160
1185
  throw new GraphFormatError(
1161
1186
  "E_DIRECTED",
1162
- `${mixed} undirected edge(s) in a directed graph; GML has no mixed direction (onMixedDirection: "error")`,
1187
+ `${mixed} undirected edge${plural(mixed)} in a directed graph, and GML holds one direction per file, so the save fails unless onMixedDirection is "directed" or "undirected"`,
1163
1188
  {
1164
1189
  reason: "mixed direction",
1165
1190
  count: mixed
@@ -1319,6 +1344,7 @@ function writeGraphics(w, context, i) {
1319
1344
  }
1320
1345
  const gmlExporter = Object.freeze({
1321
1346
  format: "gml",
1347
+ options: Object.freeze(["sanitizeKeys", "weightKey"]),
1322
1348
  capabilities: GML_CAPABILITIES,
1323
1349
  check,
1324
1350
  /**
@@ -1358,7 +1384,12 @@ const FLAG_TYPE_CODE = "E_GML_FLAG_TYPE";
1358
1384
  const FLAG_VALUE_CODE = "W_GML_FLAG_VALUE";
1359
1385
  const QUOTED_INT = /^\s*[+-]?[0-9]+\s*$/;
1360
1386
  const UNKNOWN_ENTITY_CODE = "W_GML_UNKNOWN_ENTITY";
1387
+ const GRAPHICS_CODE = "W_GML_GRAPHICS";
1388
+ const NESTED_ELEMENT_CODE = "W_GML_NESTED_ELEMENT";
1389
+ const GROUPS_CODE = "W_GML_GROUPS";
1390
+ const WIDENED_CODE = WIDENED_CODE$1;
1361
1391
  const PRECISION_CODE = PRECISION_CODE$1;
1392
+ const COLUMN_RENAMED_CODE_GML = COLUMN_RENAMED_CODE;
1362
1393
  const ROLE_TAKEN_CODE = ROLE_TAKEN_CODE$1;
1363
1394
  const ID_DROPPED_CODE = "W_GML_ID_DROPPED";
1364
1395
  const FORMAT_DEFAULTS = { ids: "canonical", defaultDirected: false, weightFrom: "value" };
@@ -1380,12 +1411,19 @@ const USED_OPTIONS = /* @__PURE__ */ new Set([
1380
1411
  "weightFrom",
1381
1412
  "weightDtype",
1382
1413
  "restoreMangledIds",
1414
+ "long",
1383
1415
  "errorLimit",
1384
1416
  "signal",
1385
1417
  "onProgress"
1386
1418
  ]);
1387
1419
  const GRAPH_SEQ = -1;
1388
1420
  const TOP_SEQ = -2;
1421
+ function isLabel(domain, key) {
1422
+ return roleOf(domain, key) === "label";
1423
+ }
1424
+ function isRecord(value) {
1425
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1426
+ }
1389
1427
  function roleOf(domain, key) {
1390
1428
  if (key === "label" && domain !== "graph") {
1391
1429
  return "label";
@@ -1437,6 +1475,7 @@ class GmlImport {
1437
1475
  this.nodeOrdinal = 0;
1438
1476
  this.elementsSinceCheck = 0;
1439
1477
  this.idMap = null;
1478
+ this.skippedIds = /* @__PURE__ */ new Set();
1440
1479
  this.declared = new Uint32Array(64);
1441
1480
  this.touched = [];
1442
1481
  this.graphTouched = [];
@@ -1458,7 +1497,7 @@ class GmlImport {
1458
1497
  this.report.warnOnce(
1459
1498
  "parse-error",
1460
1499
  UNKNOWN_ENTITY_CODE,
1461
- `unknown character entity ${entity} is kept as written`,
1500
+ `character entity ${entity} cannot be decoded; it is kept as written`,
1462
1501
  { line, element: entity },
1463
1502
  `${UNKNOWN_ENTITY_CODE}:${entity}`
1464
1503
  );
@@ -1473,10 +1512,14 @@ class GmlImport {
1473
1512
  */
1474
1513
  scan() {
1475
1514
  const t = this.requireTokens();
1515
+ let scalarGraph = -1;
1476
1516
  for (let p = 0; p < t.count; p = t.nextPair(p)) {
1477
1517
  const key = t.textOf(p);
1478
1518
  const v = p + 1;
1479
1519
  const record = t.kind[v] === TOKEN_OPEN;
1520
+ if (key === "graph" && !record && scalarGraph < 0) {
1521
+ scalarGraph = v;
1522
+ }
1480
1523
  if (key === "graph" && record) {
1481
1524
  if (this.graphCount++ === this.which) {
1482
1525
  this.graphOpen = v;
@@ -1491,6 +1534,13 @@ class GmlImport {
1491
1534
  }
1492
1535
  }
1493
1536
  if (this.graphOpen < 0) {
1537
+ if (scalarGraph >= 0) {
1538
+ this.report.fail(
1539
+ NO_GRAPH_CODE,
1540
+ `the graph key at line ${t.line[scalarGraph]} holds ${describeValue(t, scalarGraph)}, not a [ ... ] block; the input contains no graph block`,
1541
+ { line: t.line[scalarGraph] }
1542
+ );
1543
+ }
1494
1544
  this.report.fail(NO_GRAPH_CODE, "the input contains no graph [ ... ] block", { line: null });
1495
1545
  }
1496
1546
  }
@@ -1576,7 +1626,9 @@ class GmlImport {
1576
1626
  */
1577
1627
  observe(schema, domain, key, v, seq) {
1578
1628
  const t = this.requireTokens();
1629
+ this.noteStructure(domain, key, v);
1579
1630
  let entry = schema.get(key);
1631
+ const graphics = domain === "node" && key === "graphics" && this.positions;
1580
1632
  if (entry === void 0) {
1581
1633
  entry = {
1582
1634
  key,
@@ -1592,13 +1644,17 @@ class GmlImport {
1592
1644
  schema.set(key, entry);
1593
1645
  } else if (entry.lastSeq === seq) {
1594
1646
  entry.list = true;
1647
+ entry.rest ||= graphics;
1595
1648
  } else {
1596
1649
  entry.lastSeq = seq;
1597
1650
  }
1651
+ if (graphics && t.kind[v] !== TOKEN_OPEN) {
1652
+ entry.rest = true;
1653
+ }
1598
1654
  switch (t.kind[v]) {
1599
1655
  case TOKEN_STRING: {
1600
1656
  const raw = t.textOf(v);
1601
- if (raw === LIST_START_MARKER || raw === EMPTY_LIST_TEXT || raw === EMPTY_TUPLE_TEXT) {
1657
+ if (raw === LIST_START_MARKER || !isLabel(domain, key) && (raw === EMPTY_LIST_TEXT || raw === EMPTY_TUPLE_TEXT)) {
1602
1658
  entry.list = true;
1603
1659
  return;
1604
1660
  }
@@ -1625,8 +1681,48 @@ class GmlImport {
1625
1681
  this.inspectGraphics(entry, v);
1626
1682
  }
1627
1683
  return;
1628
- default:
1684
+ default: {
1629
1685
  entry.kinds |= KIND_REAL;
1686
+ const text = t.textOf(v);
1687
+ if (/\d/.test(text) && !Number.isFinite(Number(text))) {
1688
+ this.report.warnOnce(
1689
+ "precision",
1690
+ PRECISION_CODE,
1691
+ `${domain} key "${key}" holds the real ${text}, beyond the f64 range; it is stored as ${numberOfText(text) > 0 ? "" : "-"}Infinity`,
1692
+ { line: t.line[v], element: key },
1693
+ `${PRECISION_CODE}:overflow:${domain}:${key}`
1694
+ );
1695
+ }
1696
+ }
1697
+ }
1698
+ }
1699
+ /**
1700
+ * Warn about keys of a node or edge whose meaning GML readers give but this import does not:
1701
+ * a nested graph / node / edge record, and yEd's group hierarchy.
1702
+ * @param domain - the table
1703
+ * @param key - the key
1704
+ * @param v - the value token
1705
+ */
1706
+ noteStructure(domain, key, v) {
1707
+ const t = this.requireTokens();
1708
+ if (domain === "graph") {
1709
+ return;
1710
+ }
1711
+ if ((key === "graph" || key === "node" || key === "edge") && t.kind[v] === TOKEN_OPEN) {
1712
+ this.report.warnOnce(
1713
+ "unsupported",
1714
+ NESTED_ELEMENT_CODE,
1715
+ `a nested ${key} record inside a ${domain} is kept as the json column "${key}"; it is not read as structure`,
1716
+ { line: t.line[v], element: key },
1717
+ `${NESTED_ELEMENT_CODE}:${domain}:${key}`
1718
+ );
1719
+ } else if (domain === "node" && (key === "isGroup" || key === "gid")) {
1720
+ this.report.warnOnce(
1721
+ "unsupported",
1722
+ GROUPS_CODE,
1723
+ "yEd group keys (isGroup, gid) are kept as plain node columns; the group hierarchy is not read as containment",
1724
+ { line: t.line[v], element: key }
1725
+ );
1630
1726
  }
1631
1727
  }
1632
1728
  /**
@@ -1708,16 +1804,26 @@ class GmlImport {
1708
1804
  * @returns the plan
1709
1805
  */
1710
1806
  planOf(domain, entry, top = false) {
1711
- const kind = kindOf(entry);
1807
+ const asText = entry.unsafe && this.options.long === "string" && kindOf(entry) === "int";
1808
+ const kind = asText ? "string" : kindOf(entry);
1712
1809
  let scalar = dtypeOfKind(kind, entry);
1713
1810
  if (scalar === "string" && !entry.list && entry.dict !== null && entry.kinds === KIND_STRING && entry.dict.decide() === "dict") {
1714
1811
  scalar = "dict";
1715
1812
  }
1716
- if (entry.unsafe) {
1813
+ if ((entry.kinds & KIND_STRING) !== 0 && (entry.kinds & (KIND_INT | KIND_REAL)) !== 0 && (entry.kinds & KIND_RECORD) === 0) {
1814
+ this.report.warnOnce(
1815
+ "coercion",
1816
+ WIDENED_CODE,
1817
+ `${domain} key "${entry.key}" mixes numbers and strings; the column is string and the numbers are kept as written`,
1818
+ { element: entry.key },
1819
+ `${WIDENED_CODE}:${domain}:${entry.key}`
1820
+ );
1821
+ }
1822
+ if (entry.unsafe && !asText) {
1717
1823
  this.report.warnOnce(
1718
1824
  "precision",
1719
1825
  PRECISION_CODE,
1720
- `${domain} key "${entry.key}" holds integers beyond 2^53; they are stored as the nearest f64`,
1826
+ `${domain} key "${entry.key}" holds integers beyond 2^53; they are stored as the nearest f64 (pass long: "string" to keep every digit as text)`,
1721
1827
  { element: entry.key },
1722
1828
  `${PRECISION_CODE}:${domain}:${entry.key}`
1723
1829
  );
@@ -1743,7 +1849,7 @@ class GmlImport {
1743
1849
  items: null,
1744
1850
  seq: Number.NEGATIVE_INFINITY
1745
1851
  };
1746
- if (domain === "node" && entry.key === "graphics" && entry.position && entry.kinds === KIND_RECORD && !entry.list) {
1852
+ if (domain === "node" && entry.key === "graphics" && this.positions && (entry.kinds & KIND_RECORD) !== 0) {
1747
1853
  const taken = (candidate) => this.nodeSchema.has(candidate) || this.sink.nodeColumn(candidate) !== INVALID_INDEX;
1748
1854
  const position = {
1749
1855
  ...plan,
@@ -1751,9 +1857,10 @@ class GmlImport {
1751
1857
  dtype: "f64",
1752
1858
  itemDtype: null,
1753
1859
  kind: "real",
1860
+ list: false,
1754
1861
  role: "position"
1755
1862
  };
1756
- const rest = entry.rest ? { ...plan } : null;
1863
+ const rest = entry.rest ? { ...plan, dtype: "json", itemDtype: null, kind: "record", list: false } : null;
1757
1864
  return { ...plan, position, rest };
1758
1865
  }
1759
1866
  return plan;
@@ -1766,6 +1873,14 @@ class GmlImport {
1766
1873
  uniqueGraphName(key) {
1767
1874
  const name = uniqueColumnName(key, key, (candidate) => this.graphNames.has(candidate));
1768
1875
  this.graphNames.add(name);
1876
+ if (name !== key) {
1877
+ this.report.warning(
1878
+ "coercion",
1879
+ COLUMN_RENAMED_CODE_GML,
1880
+ `the top-level key "${key}" and a key of the graph block share the graph column name; the top-level value is stored as "${name}"`,
1881
+ { element: key }
1882
+ );
1883
+ }
1769
1884
  return name;
1770
1885
  }
1771
1886
  /** Set the graph metadata: source format, creator, version, multigraph flag, weight origin. */
@@ -1930,6 +2045,7 @@ class GmlImport {
1930
2045
  this.checkAbort();
1931
2046
  let index;
1932
2047
  let sinkId;
2048
+ let fileId;
1933
2049
  try {
1934
2050
  let idTok = -1;
1935
2051
  let labelTok = -1;
@@ -1947,7 +2063,7 @@ class GmlImport {
1947
2063
  if (idTok < 0) {
1948
2064
  throw new GraphFormatError("E_INVALID_ID", "node has no id", { reason: "missing id" });
1949
2065
  }
1950
- const fileId = this.coerceFileId(idTok, this.fileIdOf(idTok, "id"));
2066
+ fileId = this.coerceFileId(idTok, this.fileIdOf(idTok, "id"));
1951
2067
  if (originalTok >= 0) {
1952
2068
  sinkId = this.restoredId(originalTok);
1953
2069
  } else {
@@ -1967,13 +2083,25 @@ class GmlImport {
1967
2083
  sinkId = fileId;
1968
2084
  }
1969
2085
  }
2086
+ index = sink.addNode(sinkId);
1970
2087
  if (this.idMap !== null) {
2088
+ const before = this.idMap.get(fileId);
2089
+ if (before !== void 0 && before !== sinkId) {
2090
+ report.warning(
2091
+ "merged",
2092
+ DUPLICATE_NODE_CODE,
2093
+ `file id ${JSON.stringify(fileId)} is declared twice (nodes ${JSON.stringify(before)} and ${JSON.stringify(sinkId)}); edges to it resolve to the later`,
2094
+ { line, element: String(fileId) }
2095
+ );
2096
+ }
1971
2097
  this.idMap.set(fileId, sinkId);
1972
2098
  }
1973
- index = sink.addNode(sinkId);
1974
2099
  } catch (err) {
1975
2100
  this.recordNodeError(err, line);
1976
2101
  report.counts.skippedNodes++;
2102
+ if (fileId !== void 0) {
2103
+ this.skippedIds.add(fileId);
2104
+ }
1977
2105
  return;
1978
2106
  }
1979
2107
  if (this.isDeclared(index)) {
@@ -1989,16 +2117,27 @@ class GmlImport {
1989
2117
  }
1990
2118
  this.beginElement(this.seq++);
1991
2119
  try {
2120
+ const graphics = [];
2121
+ let graphicsPlan = null;
1992
2122
  for (let p = open + 1; p < close; p = t.nextPair(p)) {
1993
2123
  const key = t.textOf(p);
1994
2124
  if (key === "id" || key === ORIGINAL_ID_KEY && options.restoreMangledIds) {
1995
2125
  continue;
1996
2126
  }
1997
2127
  const plan = this.nodePlans.get(key);
1998
- if (plan !== void 0) {
2128
+ if (plan !== void 0 && plan.position !== null) {
2129
+ graphicsPlan = plan;
2130
+ graphics.push(p + 1);
2131
+ } else if (plan !== void 0) {
1999
2132
  this.writeNode(plan, index, p + 1);
2000
2133
  }
2001
2134
  }
2135
+ if (graphicsPlan !== null) {
2136
+ this.writeGraphics(graphicsPlan, index, graphics, {
2137
+ line: t.line[graphics[0]],
2138
+ element: String(sinkId)
2139
+ });
2140
+ }
2002
2141
  this.flushLists("node", index);
2003
2142
  } catch (err) {
2004
2143
  this.touched.length = 0;
@@ -2194,7 +2333,18 @@ class GmlImport {
2194
2333
  */
2195
2334
  endpoint(v, key) {
2196
2335
  const id = this.coerceFileId(v, this.fileIdOf(v, key));
2197
- return this.idMap?.get(id) ?? id;
2336
+ const mapped = this.idMap?.get(id);
2337
+ if (mapped !== void 0) {
2338
+ return mapped;
2339
+ }
2340
+ if (this.skippedIds.has(id)) {
2341
+ throw new GraphFormatError(
2342
+ "E_UNKNOWN_NODE",
2343
+ `${key} ${JSON.stringify(id)} names a node block that was skipped after an error`,
2344
+ { reason: "skipped node", id }
2345
+ );
2346
+ }
2347
+ return id;
2198
2348
  }
2199
2349
  /**
2200
2350
  * The weight of an edge from its weight token.
@@ -2205,11 +2355,17 @@ class GmlImport {
2205
2355
  const t = this.requireTokens();
2206
2356
  switch (t.kind[v]) {
2207
2357
  case TOKEN_STRING:
2208
- return parseWeightText(t.stringOf(v));
2358
+ return parseWeightText(t.stringOf(v), this.report);
2209
2359
  case TOKEN_OPEN:
2210
2360
  throw new GraphFormatError("E_INVALID_WEIGHT", "edge weight is a record", { value: "[...]" });
2211
- default:
2212
- return weightFromValue(numberOfText(t.textOf(v)));
2361
+ default: {
2362
+ const text = t.textOf(v);
2363
+ const weight = weightFromValue(numberOfText(text));
2364
+ if (weight !== void 0) {
2365
+ reportWeightPrecision(text, weight, this.report);
2366
+ }
2367
+ return weight;
2368
+ }
2213
2369
  }
2214
2370
  }
2215
2371
  /**
@@ -2271,10 +2427,6 @@ class GmlImport {
2271
2427
  * @param v - the value token
2272
2428
  */
2273
2429
  writeNode(plan, index, v) {
2274
- if (plan.position !== null) {
2275
- this.writeGraphics(plan, index, v);
2276
- return;
2277
- }
2278
2430
  if (plan.list) {
2279
2431
  this.collectItem(plan, v, this.seqNow, this.touched);
2280
2432
  return;
@@ -2305,36 +2457,89 @@ class GmlImport {
2305
2457
  this.collectItem(plan, v, seq, this.graphTouched);
2306
2458
  return;
2307
2459
  }
2308
- this.sink.setGraphValue(plan.name, this.scalarOf(plan, v), graphDecl(plan));
2460
+ const value = this.scalarOf(plan, v);
2461
+ this.sink.setGraphValue(plan.name, value, graphDecl(plan));
2462
+ if (seq === GRAPH_SEQ && plan.key === "name" && typeof value === "string") {
2463
+ this.sink.setMeta({ name: value });
2464
+ }
2309
2465
  }
2310
2466
  /**
2311
- * Write a node's graphics record: the position column from x / y / z, the remaining keys to
2312
- * the json column.
2467
+ * Write a node's graphics values: the position column from the x / y / z of the first record,
2468
+ * everything else (the remaining keys, a value that is not a record, a repeated record) to the
2469
+ * json column, with a warning when the value cannot give a position as written.
2313
2470
  * @param plan - the graphics plan
2314
2471
  * @param index - the node index
2315
- * @param v - the value token (a record)
2472
+ * @param vs - the value tokens of the node's graphics keys, in order
2473
+ * @param where - the line and the node, for issues
2316
2474
  */
2317
- writeGraphics(plan, index, v) {
2475
+ writeGraphics(plan, index, vs, where) {
2318
2476
  const t = this.requireTokens();
2319
2477
  const { sink } = this;
2320
- const record = parseRecord(t, v);
2321
- const { x, y, z } = record;
2478
+ const values = vs.map((v) => t.kind[v] === TOKEN_OPEN ? parseRecord(t, v) : this.scalarOf(plan, v));
2479
+ const first = values[0];
2322
2480
  const positionPlan = plan.position;
2323
- if (positionPlan !== null && typeof x === "number" && typeof y === "number") {
2324
- sink.setNodeValue(this.handleOf(positionPlan, "node"), index, [x, y, typeof z === "number" ? z : 0]);
2481
+ let rest = first;
2482
+ if (isRecord(first) && positionPlan !== null) {
2483
+ rest = this.writePosition(positionPlan, index, first, where);
2484
+ } else if (!isRecord(first)) {
2485
+ this.graphicsWarning("scalar", `node ${where.element}'s graphics is not a record`, where);
2486
+ }
2487
+ if (values.length > 1) {
2488
+ this.graphicsWarning(
2489
+ "repeated",
2490
+ `node ${where.element} has ${values.length} graphics records; the position comes from the first`,
2491
+ where
2492
+ );
2493
+ rest = values;
2494
+ }
2495
+ if (rest !== void 0 && plan.rest !== null) {
2496
+ sink.setNodeValue(this.handleOf(plan.rest, "node"), index, rest);
2497
+ }
2498
+ }
2499
+ /**
2500
+ * Write a node's position from the x / y / z of its graphics record, taking them out of it.
2501
+ * @param positionPlan - the position column's plan
2502
+ * @param index - the node index
2503
+ * @param record - the graphics record
2504
+ * @param where - the line and the node, for issues
2505
+ * @returns what is left of the record for the json column, or undefined when nothing is
2506
+ */
2507
+ writePosition(positionPlan, index, record, where) {
2508
+ const { x, y, z } = record;
2509
+ let rest = record;
2510
+ if (typeof x === "number" && typeof y === "number") {
2511
+ const depth = typeof z === "number" ? z : 0;
2512
+ this.sink.setNodeValue(this.handleOf(positionPlan, "node"), index, [x, y, depth]);
2325
2513
  delete record.x;
2326
2514
  delete record.y;
2327
2515
  if (typeof z === "number") {
2328
2516
  delete record.z;
2329
2517
  }
2330
- if (plan.rest !== null && Object.keys(record).length > 0) {
2331
- sink.setNodeValue(this.handleOf(plan.rest, "node"), index, record);
2332
- }
2333
- return;
2518
+ rest = Object.keys(record).length > 0 ? record : void 0;
2334
2519
  }
2335
- if (plan.rest !== null) {
2336
- sink.setNodeValue(this.handleOf(plan.rest, "node"), index, record);
2520
+ if ("x" in record || "y" in record || "z" in record) {
2521
+ this.graphicsWarning(
2522
+ "coordinate",
2523
+ `node ${where.element}'s graphics x / y / z is not one number each`,
2524
+ where
2525
+ );
2337
2526
  }
2527
+ return rest;
2528
+ }
2529
+ /**
2530
+ * Warn once per kind of graphics problem.
2531
+ * @param kind - the problem
2532
+ * @param what - the message start, naming the node
2533
+ * @param where - the line and the node
2534
+ */
2535
+ graphicsWarning(kind, what, where) {
2536
+ this.report.warnOnce(
2537
+ "validation-error",
2538
+ GRAPHICS_CODE,
2539
+ `${what}; the value is kept in the graphics json column (warned once for every such node)`,
2540
+ where,
2541
+ `${GRAPHICS_CODE}:${kind}`
2542
+ );
2338
2543
  }
2339
2544
  /**
2340
2545
  * Collect one list item.
@@ -2586,6 +2791,7 @@ function sniffGml(head) {
2586
2791
  }
2587
2792
  const gmlImporter = Object.freeze({
2588
2793
  format: "gml",
2794
+ options: Object.freeze(["dictionaries", "positions"]),
2589
2795
  extensions: Object.freeze([".gml"]),
2590
2796
  mimeTypes: Object.freeze(["text/x-gml", "text/plain"]),
2591
2797
  sniff: sniffGml,
@@ -2597,6 +2803,9 @@ const gmlImporter = Object.freeze({
2597
2803
  * @returns the report
2598
2804
  */
2599
2805
  async import(input, sink, options) {
2806
+ if (graphChosen(options)) {
2807
+ return importChosenGraph(gmlImporter, input, sink, options);
2808
+ }
2600
2809
  const resolved = resolveImportOptions(options, FORMAT_DEFAULTS);
2601
2810
  const report = new ImportReportBuilder("gml", resolved.errorLimit);
2602
2811
  reportSinkOptions(sink, options, report);
@@ -2609,7 +2818,7 @@ const gmlImporter = Object.freeze({
2609
2818
  report.warning(
2610
2819
  "unsupported",
2611
2820
  SECOND_GRAPH_CODE,
2612
- `the input holds ${gml.graphCount - 1} more graph block(s) after the first; import() reads the first, importAll() reads every one`
2821
+ `the input holds ${gml.graphCount - 1} more graph block${plural(gml.graphCount - 1)} after the first; the first is read (graphIndex or graphName chooses another; importAllGraphs() reads every one)`
2613
2822
  );
2614
2823
  }
2615
2824
  throwIfAborted(resolved.signal);
@@ -2655,20 +2864,32 @@ function tokenize(text, report) {
2655
2864
  }
2656
2865
  }
2657
2866
  const GML_ISSUE = Object.freeze({
2658
- /** A grammar violation: an untokenisable bare token, an unclosed string or `[`, a stray `]`, a key without a value (fatal). */
2867
+ ...INPUT_ISSUE,
2868
+ ...ELEMENT_ISSUE,
2869
+ /**
2870
+ * The text breaks GML's syntax: a word that is not a key or a value, an unclosed string or `[`, a stray `]`, or a
2871
+ * key without a value. The import stops.
2872
+ */
2659
2873
  SYNTAX: SYNTAX_CODE,
2660
- /** The input holds invalid UTF-8 (fatal). */
2874
+ /** The input is not valid UTF-8. The import stops. */
2661
2875
  INVALID_UTF8: INVALID_UTF8_CODE,
2662
- /** Invalid bytes in the encoding a BOM, a declaration or the encoding option chose (fatal). */
2876
+ /**
2877
+ * Some bytes are not valid in the encoding that was chosen (by a byte order mark, the file's declaration or the
2878
+ * `encoding` option). The import stops.
2879
+ */
2663
2880
  INVALID_ENCODING: INVALID_ENCODING_CODE,
2664
2881
  /** Bytes that are not UTF-8 and declare no encoding were read as windows-1252. */
2665
2882
  ENCODING_FALLBACK: ENCODING_FALLBACK_CODE,
2666
2883
  /** A declared encoding the platform cannot decode was ignored. */
2667
2884
  UNKNOWN_ENCODING: UNKNOWN_ENCODING_CODE,
2668
- /** No `graph [` block (fatal). */
2885
+ /** There is no `graph [` block. The import stops. */
2669
2886
  NO_GRAPH: NO_GRAPH_CODE,
2670
- /** More than one `graph` block (fatal). */
2887
+ /** The file holds more than one `graph` block and only the first was read. It is not added when `graphIndex` or `graphName` chose the graph. */
2671
2888
  MULTIPLE_GRAPHS: SECOND_GRAPH_CODE,
2889
+ /** `graphIndex` or `graphName` names no graph of the file; the message lists the graphs it holds. The import stops. */
2890
+ GRAPH_NOT_FOUND: GRAPH_NOT_FOUND_CODE,
2891
+ /** `graphName` matches more than one graph; pass `graphIndex`. The import stops. */
2892
+ AMBIGUOUS_GRAPH_NAME: AMBIGUOUS_GRAPH_NAME_CODE,
2672
2893
  /** A node without an `id`. */
2673
2894
  MISSING_ID: MISSING_ID_CODE,
2674
2895
  /** A node without a `label` under nodeIdFrom "label". */
@@ -2677,7 +2898,10 @@ const GML_ISSUE = Object.freeze({
2677
2898
  MISSING_ENDPOINT: MISSING_ENDPOINT_CODE,
2678
2899
  /** A node id, source or target that is neither an integer nor a string. */
2679
2900
  ID_TYPE: ID_TYPE_CODE,
2680
- /** String node ids, sources or targets (outside the spec's integers), kept under the ids rule; warned once. */
2901
+ /**
2902
+ * Node ids, sources or targets are text, where GML expects integers. They are read under the `ids` option.
2903
+ * Reported once per file.
2904
+ */
2681
2905
  STRING_ID: STRING_ID_CODE,
2682
2906
  /** A node id declared twice (later keys overwrite). */
2683
2907
  DUPLICATE_NODE: DUPLICATE_NODE_CODE,
@@ -2689,41 +2913,74 @@ const GML_ISSUE = Object.freeze({
2689
2913
  FLAG_TYPE: FLAG_TYPE_CODE,
2690
2914
  /** A `directed` / `multigraph` flag outside 0 / 1, or repeated. */
2691
2915
  FLAG_VALUE: FLAG_VALUE_CODE,
2692
- /** A named entity in a string that no table decodes; kept as written. */
2916
+ /** A named entity no table decodes, or a numeric reference beyond U+10FFFF; kept as written. */
2693
2917
  UNKNOWN_ENTITY: UNKNOWN_ENTITY_CODE,
2694
- /** An integer beyond 2^53 rounded to f64. */
2918
+ /** An integer beyond 2^53 was stored as the nearest 64-bit float; pass `long: "string"` to keep every digit. */
2695
2919
  PRECISION: PRECISION_CODE,
2696
- /** A column renamed `<name>#<key>` because the sink held the name with another shape. */
2920
+ /** A node's graphics value that cannot give a position as written; kept in the graphics json column. */
2921
+ GRAPHICS: GRAPHICS_CODE,
2922
+ /** A graph, node or edge record nested in a node or edge; kept as json, not read as structure. */
2923
+ NESTED_ELEMENT: NESTED_ELEMENT_CODE,
2924
+ /** YEd's isGroup / gid keys, kept as plain columns; the hierarchy is not read as containment. */
2925
+ GROUPS: GROUPS_CODE,
2926
+ /**
2927
+ * An attribute's type was widened because a later value did not fit: an integer above 2^31 in an integer column,
2928
+ * or two declared types for one attribute.
2929
+ */
2930
+ WIDENED: WIDENED_CODE,
2931
+ /**
2932
+ * An attribute was renamed `<name>#<suffix>` because another attribute already has its name, for example
2933
+ * two attributes declared with the same name.
2934
+ */
2697
2935
  COLUMN_RENAMED: COLUMN_RENAMED_CODE,
2698
- /** A column declared without its role because the sink already holds it. */
2936
+ /**
2937
+ * You read into a graph builder that already has an id, label or position attribute, so this file's one is kept as
2938
+ * a plain attribute.
2939
+ */
2699
2940
  ROLE_TAKEN: ROLE_TAKEN_CODE,
2700
- /** Two id texts merged into one number under ids "number". */
2941
+ /** Two different id texts became the same number because `ids` is "number", so their nodes were merged. */
2701
2942
  ID_MERGED: ID_MERGED_CODE,
2702
- /** A common option the importer has no use for was given. */
2943
+ /** You set an option this format does not use; it had no effect. The message names the option. */
2703
2944
  OPTION_IGNORED: OPTION_IGNORED_CODE,
2704
- /** A builder-policy option the sink does not honour. */
2945
+ /**
2946
+ * You read into your own graph builder, which was created with a different `addMissingNodes`, `duplicateEdges`,
2947
+ * `selfLoops` or `weightDtype` than the option you passed; the builder's setting applies.
2948
+ */
2705
2949
  SINK_OPTION: SINK_OPTION_CODE,
2706
- /** The sink refused the file's direction. */
2950
+ /**
2951
+ * You read into a graph builder whose direction is already set, or which already holds edges, so the file is read
2952
+ * with the builder's direction instead of its own.
2953
+ */
2707
2954
  DIRECTION_REFUSED: DIRECTION_REFUSED_CODE,
2708
- /** Edges forced to the policy's direction. */
2955
+ /** Edges of the other direction were read with the direction `onMixedDirection` chose. */
2709
2956
  DIRECTION_FORCED: DIRECTION_FORCED_CODE,
2710
- /** A mixed file under onMixedDirection "error" (fatal). */
2957
+ /**
2958
+ * The graph has both directed and undirected edges and `onMixedDirection` is "error". An import stops; a save to a
2959
+ * format that holds one direction per file fails with E_DIRECTED. Pass "directed" or "undirected" to read or write
2960
+ * it anyway.
2961
+ */
2711
2962
  MIXED_DIRECTION: MIXED_DIRECTION_CODE,
2712
- /** Under nodeIdFrom "label" / "index" the integer ids are not kept (a loss note). */
2963
+ /**
2964
+ * Under `nodeIdFrom: "label"` or `"index"` the file's integer ids are not kept. It is listed in `report.lossy`, not
2965
+ * in `report.issues`.
2966
+ */
2713
2967
  ID_DROPPED: ID_DROPPED_CODE
2714
2968
  });
2715
2969
  const GML_LOSS = Object.freeze({
2716
- /** A json column holds numbers; GML records cannot keep int versus real (design section 8.5). */
2970
+ /** A json column holds numbers; GML records cannot keep int versus real. */
2717
2971
  RECORD_NUMBER_TYPE: RECORD_NUMBER_TYPE_CODE,
2718
2972
  /** A json column holds booleans, written 1 / 0. */
2719
2973
  RECORD_BOOLEAN: RECORD_BOOLEAN_CODE,
2720
2974
  /** A json column holds nulls, omitted. */
2721
2975
  RECORD_NULL: RECORD_NULL_CODE,
2722
- /** An array inside an array; export() throws. */
2976
+ /** An attribute holds an array inside an array, which GML cannot write; the save fails. */
2723
2977
  NESTED_ARRAY: NESTED_ARRAY_CODE,
2724
2978
  /** A json row that is an array, written as repeated keys. */
2725
2979
  JSON_ARRAY: JSON_ARRAY_CODE,
2726
- /** A column name or record key outside the GML key grammar. */
2980
+ /**
2981
+ * An attribute name GML cannot use as a key (keys are letters and digits, starting with a letter). The save fails
2982
+ * unless `sanitizeKeys` is "mangle".
2983
+ */
2727
2984
  INVALID_KEY: INVALID_KEY_CODE,
2728
2985
  /** A column named like a structural key. */
2729
2986
  RESERVED_KEY: RESERVED_KEY_CODE,